<commit_before>package it.unibz.inf.ontop.iq.optimizer.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import it.unibz.inf.ontop.injection.CoreSingletons;
import it.unibz.inf.ontop.injection.IntermediateQueryFactory;
import it.unibz.inf.ontop.injection.OptimizationSingletons;
import it.unibz.inf.ontop.iq.IQ;
import it.unibz.inf.ontop.iq.IQTree;
import it.unibz.inf.ontop.iq.UnaryIQTree;
import it.unibz.inf.ontop.iq.node.AggregationNode;
import it.unibz.inf.ontop.iq.node.ConstructionNode;
import it.unibz.inf.ontop.iq.optimizer.AggregationSimplifier;
import it.unibz.inf.ontop.iq.request.DefinitionPushDownRequest;
import it.unibz.inf.ontop.iq.transform.IQTreeTransformer;
import it.unibz.inf.ontop.iq.transformer.impl.RDFTypeDependentSimplifyingTransformer;
import it.unibz.inf.ontop.model.term.*;
import it.unibz.inf.ontop.model.term.functionsymbol.FunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.RDFTermFunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.SPARQLAggregationFunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.SPARQLAggregationFunctionSymbol.AggregationSimplification;
import it.unibz.inf.ontop.model.type.RDFTermType;
import it.unibz.inf.ontop.substitution.ImmutableSubstitution;
import it.unibz.inf.ontop.substitution.SubstitutionFactory;
import it.unibz.inf.ontop.utils.ImmutableCollectors;
import it.unibz.inf.ontop.utils.VariableGenerator;

import javax.inject.Inject;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

public class AggregationSimplifierImpl implements AggregationSimplifier {

    private final IntermediateQueryFactory iqFactory;
    private final OptimizationSingletons optimizationSingletons;

    @Inject
    private AggregationSimplifierImpl(IntermediateQueryFactory iqFactory, OptimizationSingletons optimizationSingletons) {
        this.iqFactory = iqFactory;
        this.optimizationSingletons = optimizationSingletons;
    }

    @Override
    public IQ optimize(IQ query) {
        VariableGenerator variableGenerator = query.getVariableGenerator();
        IQTreeTransformer transformer = createTransformer(variableGenerator);
        IQTree newTree = transformer.transform(query.getTree())
                .normalizeForOptimization(variableGenerator);
        return iqFactory.createIQ(query.getProjectionAtom(), newTree);
    }

    protected IQTreeTransformer createTransformer(VariableGenerator variableGenerator) {
        return new AggregationSimplifyingTransformer(variableGenerator, optimizationSingletons);
    }

    /**
     * Recursive
     */
    protected static class AggregationSimplifyingTransformer extends RDFTypeDependentSimplifyingTransformer {

        private final VariableGenerator variableGenerator;
        private final SubstitutionFactory substitutionFactory;
        private final TermFactory termFactory;

        protected AggregationSimplifyingTransformer(VariableGenerator variableGenerator,
                                                    OptimizationSingletons optimizationSingletons) {
            super(optimizationSingletons);
            this.variableGenerator = variableGenerator;
            CoreSingletons coreSingletons = optimizationSingletons.getCoreSingletons();
            this.substitutionFactory = coreSingletons.getSubstitutionFactory();
            this.termFactory = coreSingletons.getTermFactory();
        }

        @Override
        public IQTree transformAggregation(IQTree tree, AggregationNode rootNode, IQTree child) {
            // In case of aggregation nodes in the sub-tree
            IQTree normalizedChild = child.acceptTransformer(this)
                    .normalizeForOptimization(variableGenerator);

            // May need to renormalize the tree (RECURSIVE)
            if (normalizedChild.getRootNode() instanceof ConstructionNode)
                return transform(
                        iqFactory.createUnaryIQTree(rootNode, normalizedChild).normalizeForOptimization(variableGenerator));

            ImmutableSubstitution<ImmutableFunctionalTerm> initialSubstitution = rootNode.getSubstitution();

            // With the GROUP BY clause, groups are never empty
            boolean hasGroupBy = !rootNode.getGroupingVariables().isEmpty();<commit_msg>Infinite loop fixed.<commit_after>package it.unibz.inf.ontop.iq.optimizer.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import it.unibz.inf.ontop.injection.CoreSingletons;
import it.unibz.inf.ontop.injection.IntermediateQueryFactory;
import it.unibz.inf.ontop.injection.OptimizationSingletons;
import it.unibz.inf.ontop.iq.IQ;
import it.unibz.inf.ontop.iq.IQTree;
import it.unibz.inf.ontop.iq.UnaryIQTree;
import it.unibz.inf.ontop.iq.node.AggregationNode;
import it.unibz.inf.ontop.iq.node.ConstructionNode;
import it.unibz.inf.ontop.iq.node.QueryNode;
import it.unibz.inf.ontop.iq.optimizer.AggregationSimplifier;
import it.unibz.inf.ontop.iq.request.DefinitionPushDownRequest;
import it.unibz.inf.ontop.iq.transform.IQTreeTransformer;
import it.unibz.inf.ontop.iq.transformer.impl.RDFTypeDependentSimplifyingTransformer;
import it.unibz.inf.ontop.model.term.*;
import it.unibz.inf.ontop.model.term.functionsymbol.FunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.RDFTermFunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.SPARQLAggregationFunctionSymbol;
import it.unibz.inf.ontop.model.term.functionsymbol.SPARQLAggregationFunctionSymbol.AggregationSimplification;
import it.unibz.inf.ontop.model.type.RDFTermType;
import it.unibz.inf.ontop.substitution.ImmutableSubstitution;
import it.unibz.inf.ontop.substitution.SubstitutionFactory;
import it.unibz.inf.ontop.utils.ImmutableCollectors;
import it.unibz.inf.ontop.utils.VariableGenerator;

import javax.inject.Inject;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

public class AggregationSimplifierImpl implements AggregationSimplifier {

    private final IntermediateQueryFactory iqFactory;
    private final OptimizationSingletons optimizationSingletons;

    @Inject
    private AggregationSimplifierImpl(IntermediateQueryFactory iqFactory, OptimizationSingletons optimizationSingletons) {
        this.iqFactory = iqFactory;
        this.optimizationSingletons = optimizationSingletons;
    }

    @Override
    public IQ optimize(IQ query) {
        VariableGenerator variableGenerator = query.getVariableGenerator();
        IQTreeTransformer transformer = createTransformer(variableGenerator);
        IQTree newTree = transformer.transform(query.getTree())
                .normalizeForOptimization(variableGenerator);
        return iqFactory.createIQ(query.getProjectionAtom(), newTree);
    }

    protected IQTreeTransformer createTransformer(VariableGenerator variableGenerator) {
        return new AggregationSimplifyingTransformer(variableGenerator, optimizationSingletons);
    }

    /**
     * Recursive
     */
    protected static class AggregationSimplifyingTransformer extends RDFTypeDependentSimplifyingTransformer {

        private final VariableGenerator variableGenerator;
        private final SubstitutionFactory substitutionFactory;
        private final TermFactory termFactory;

        protected AggregationSimplifyingTransformer(VariableGenerator variableGenerator,
                                                    OptimizationSingletons optimizationSingletons) {
            super(optimizationSingletons);
            this.variableGenerator = variableGenerator;
            CoreSingletons coreSingletons = optimizationSingletons.getCoreSingletons();
            this.substitutionFactory = coreSingletons.getSubstitutionFactory();
            this.termFactory = coreSingletons.getTermFactory();
        }

        @Override
        public IQTree transformAggregation(IQTree tree, AggregationNode rootNode, IQTree child) {
            // In case of aggregation nodes in the sub-tree
            IQTree normalizedChild = child.acceptTransformer(this)
                    .normalizeForOptimization(variableGenerator);

            QueryNode newChildRoot = normalizedChild.getRootNode();

            // May need to renormalize the tree (RECURSIVE)
            if ((newChildRoot instanceof ConstructionNode) && (!child.getRootNode().equals(newChildRoot)))
                return transform(
                        iqFactory.createUnaryIQTree(rootNode, normalizedChild).normalizeForOptimization(variableGenerator));

            ImmutableSubstitution<ImmutableFunctionalTerm> initialSubstitution = rootNode.getSubstitution();

            // With the GROUP BY clause, groups are never empty
            boolean hasGroupBy = !rootNode.getGroupingVariables().isEmpty();
{'fraction_non_alphanumeric': 0.07890929326655537, 'fraction_numerical': 0.0, 'mean_word_length': 4.068245910885505, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2775473', 'n_tokens_mistral': 2579, 'n_tokens_neox': 2417, 'n_words': 399}