<commit_before>package org.semanticweb.ontop.owlrefplatform.core.basicoperations;

import fj.*;
import fj.data.*;
import org.semanticweb.ontop.model.*;
import org.semanticweb.ontop.model.Function;
import org.semanticweb.ontop.model.impl.OBDADataFactoryImpl;
import org.semanticweb.ontop.model.impl.OBDAVocabulary;
import org.semanticweb.ontop.model.impl.VariableImpl;

import java.util.ArrayList;

import static org.semanticweb.ontop.model.impl.DatalogTools.*;

/**
 * Default implementation of PullOutEqualityNormalizer. Is Left-Join aware.
 *
 * Immutable class (instances have no attribute).
 *
 * Main challenge: putting the equalities at the "right" (good) place.
 * Rules for accepting/rejecting to move up boolean conditions:
 *   - Left of the LJ: ACCEPT. Why? If they appeared as ON conditions of the LJ, they would "filter" ONLY the right part,
 *                             NOT THE LEFT.
 *   - Right of the LJ: REJECT. Boolean conditions have to be used as ON conditions of the LOCAL LJ.
 *   - "Real" JOIN (joins between two tables): REJECT. Local ON conditions are (roughly) equivalent to the "global" WHERE
 *     conditions.
 *   - "Fake" JOIN (one data atoms and filter conditions). ACCEPT. Need a JOIN/LJ for being used as ON conditions.
 *                  If not blocked later, they will finish as WHERE conditions (atoms not embedded in a META-one).
 *
 *  TODO: create static "function" objects for performance improving
 *
 */
public class PullOutEqualityNormalizerImpl implements PullOutEqualityNormalizer {

    private final static OBDADataFactory DATA_FACTORY = OBDADataFactoryImpl.getInstance();
    private final static Ord<VariableImpl> VARIABLE_ORD = Ord.hashEqualsOrd();
    private final static List<P2<VariableImpl, Constant>> EMPTY_VARIABLE_CONSTANT_LIST = List.nil();
    private final static List<P2<VariableImpl, VariableImpl>> EMPTY_VARIABLE_RENAMING_LIST = List.nil();
    private final static List<Function> EMPTY_ATOM_LIST = List.nil();
    private final static Function TRUE_EQ = DATA_FACTORY.getFunctionEQ(OBDAVocabulary.TRUE, OBDAVocabulary.TRUE);


    /**
     * High-level method.
     *
     * Returns a new normalized rule.
     */
    @Override
    public CQIE normalizeByPullingOutEqualities(final CQIE initialRule) {
        CQIE newRule = initialRule.clone();

        // Mutable object
        final VariableDispatcher variableDispatcher = new VariableDispatcher(initialRule);

        /**
         * Result for the top atoms of the rule.
         */
        PullOutEqLocalNormResult result = normalizeSameLevelAtoms(List.iterableList(newRule.getBody()), variableDispatcher);

        newRule.updateBody(new ArrayList(result.getAllAtoms().toCollection()));
        return newRule;
    }

    /**
     * Builds out a ExtractEqNormResult by aggregating the results of atoms at one given level
     *    (top level, inside a Join, a LJ).
     *
     */<commit_msg>Flattens some top-level AND boolean atoms (the SQL generator is touchy about it). Hack.<commit_after>package org.semanticweb.ontop.owlrefplatform.core.basicoperations;

import fj.*;
import fj.data.*;
import fj.data.List;
import fj.data.Set;
import fj.data.TreeMap;
import org.semanticweb.ontop.model.*;
import org.semanticweb.ontop.model.Function;
import org.semanticweb.ontop.model.impl.OBDADataFactoryImpl;
import org.semanticweb.ontop.model.impl.OBDAVocabulary;
import org.semanticweb.ontop.model.impl.VariableImpl;

import java.util.*;

import static org.semanticweb.ontop.model.impl.DatalogTools.*;

/**
 * Default implementation of PullOutEqualityNormalizer. Is Left-Join aware.
 *
 * Immutable class (instances have no attribute).
 *
 * Main challenge: putting the equalities at the "right" (good) place.
 * Rules for accepting/rejecting to move up boolean conditions:
 *   - Left of the LJ: ACCEPT. Why? If they appeared as ON conditions of the LJ, they would "filter" ONLY the right part,
 *                             NOT THE LEFT.
 *   - Right of the LJ: REJECT. Boolean conditions have to be used as ON conditions of the LOCAL LJ.
 *   - "Real" JOIN (joins between two tables): REJECT. Local ON conditions are (roughly) equivalent to the "global" WHERE
 *     conditions.
 *   - "Fake" JOIN (one data atoms and filter conditions). ACCEPT. Need a JOIN/LJ for being used as ON conditions.
 *                  If not blocked later, they will finish as WHERE conditions (atoms not embedded in a META-one).
 *
 *  TODO: create static "function" objects for performance improving
 *
 */
public class PullOutEqualityNormalizerImpl implements PullOutEqualityNormalizer {

    private final static OBDADataFactory DATA_FACTORY = OBDADataFactoryImpl.getInstance();
    private final static Ord<VariableImpl> VARIABLE_ORD = Ord.hashEqualsOrd();
    private final static List<P2<VariableImpl, Constant>> EMPTY_VARIABLE_CONSTANT_LIST = List.nil();
    private final static List<P2<VariableImpl, VariableImpl>> EMPTY_VARIABLE_RENAMING_LIST = List.nil();
    private final static List<Function> EMPTY_ATOM_LIST = List.nil();
    private final static Function TRUE_EQ = DATA_FACTORY.getFunctionEQ(OBDAVocabulary.TRUE, OBDAVocabulary.TRUE);


    /**
     * High-level method.
     *
     * Returns a new normalized rule.
     */
    @Override
    public CQIE normalizeByPullingOutEqualities(final CQIE initialRule) {
        CQIE newRule = initialRule.clone();

        // Mutable object
        final VariableDispatcher variableDispatcher = new VariableDispatcher(initialRule);

        /**
         * Result for the top atoms of the rule.
         */
        PullOutEqLocalNormResult result = normalizeSameLevelAtoms(List.iterableList(newRule.getBody()), variableDispatcher);

        /**
         * Minor reshaping of some top-level AND(...) boolean atoms (flattened)
         */
        List<Function> topAtoms = flattenTopBooleanConjunctions(result.getAllAtoms());

        newRule.updateBody(new ArrayList(topAtoms.toCollection()));
        return newRule;
    }

    /**
     * THIS IS A HACK!
     *
     * Flattens some top-level top AND(..) boolean atoms because the SQL generator is bit rigid with them.
     */
    private List<Function> flattenTopBooleanConjunctions(final List<Function> atoms) {
        return atoms.bind(new F<Function, List<Function>>() {
            @Override
            public List<Function> f(Function atom) {
                /**
                 * Only flatten a top-level AND(...) boolean atom
                 * IF ALL ITS SUB-TERMS are FUNCTIONAL.
                 */
                if (atom.getFunctionSymbol().equals(OBDAVocabulary.AND)) {
                    java.util.List<Term> subTerms = atom.getTerms();
                    for (Term subTerm : subTerms) {
                        if (!(subTerm instanceof Function)) {
                            return List.cons(atom, EMPTY_ATOM_LIST);
                        }
                    }
                    return List.iterableList((java.util.List<Function>)(java.util.List<?>)subTerms);
                }
                else {
                    return List.cons(atom, EMPTY_ATOM_LIST);
                }
            }
        });
    }

    /**
     * Builds out a ExtractEqNormResult by aggregating the results of atoms at one given level
     *    (top level, inside a Join, a LJ).
     *
     */
{'fraction_non_alphanumeric': 0.08997675372624094, 'fraction_numerical': 0.0005469711472719814, 'mean_word_length': 2.8780487804878048, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1572375', 'n_tokens_mistral': 2097, 'n_tokens_neox': 2037, 'n_words': 618}