All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unibz.inf.ontop.substitution.impl.AbstractSubstitutionOperations Maven / Gradle / Ivy

package it.unibz.inf.ontop.substitution.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import it.unibz.inf.ontop.exception.MinorOntopInternalBugException;
import it.unibz.inf.ontop.iq.node.ExtensionalDataNode;
import it.unibz.inf.ontop.model.term.*;
import it.unibz.inf.ontop.model.term.functionsymbol.BooleanFunctionSymbol;
import it.unibz.inf.ontop.substitution.Substitution;
import it.unibz.inf.ontop.substitution.SubstitutionOperations;
import it.unibz.inf.ontop.substitution.UnifierBuilder;
import it.unibz.inf.ontop.utils.ImmutableCollectors;

import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collector;

public abstract class AbstractSubstitutionOperations extends AbstractSubstitutionBasicOperations implements SubstitutionOperations {

    private final Function typeCast;
    private final Function, Substitution> substitutionTypeCast;
    private final Function, T> keyMapper;

    /**
     * @param typeCast             effectively ensures that Variable is a subtype of T (normally, it's simply v -> v)
     * @param substitutionTypeCast effectively ensures that Variable is a subtype of T (normally, it's simply s -> s)
     */
    AbstractSubstitutionOperations(TermFactory termFactory,
                                   Function typeCast,
                                   Function, Substitution> substitutionTypeCast) {
        super(termFactory);
        this.typeCast = typeCast;
        this.substitutionTypeCast = substitutionTypeCast;
        this.keyMapper = e -> typeCast.apply(e.getKey());
    }

    @Override
    public T apply(Substitution substitution, Variable variable) {
        return applyToVariable(substitution, variable, typeCast);
    }

    @Override
    public ImmutableFunctionalTerm apply(Substitution substitution, ImmutableFunctionalTerm term) {
        if (term.getFunctionSymbol() instanceof BooleanFunctionSymbol)
            return apply(substitution, (ImmutableExpression)term);

        if (substitution.isEmpty())
            return term;

        return termFactory.getImmutableFunctionalTerm(term.getFunctionSymbol(), substitution.applyToTerms(term.getTerms()));
    }

    @Override
    public ImmutableExpression apply(Substitution substitution, ImmutableExpression expression) {
        if (substitution.isEmpty())
            return expression;

        return termFactory.getImmutableExpression(expression.getFunctionSymbol(), substitution.applyToTerms(expression.getTerms()));
    }

    @Override
    public ImmutableList apply(Substitution substitution, ImmutableList variables) {
        return variables.stream()
                .map(v -> apply(substitution, v))
                .collect(ImmutableCollectors.toList());
    }

    @Override
    public ImmutableSet apply(Substitution substitution, ImmutableSet terms) {
        return terms.stream()
                .map(v -> apply(substitution, v))
                .collect(ImmutableCollectors.toSet());
    }

    @Override
    public T rename(Substitution renaming, T t) {
        return applyToTerm(substitutionTypeCast.apply(renaming), t);
    }


    protected Substitution emptySubstitution() {
        return termFactory.getSubstitution(ImmutableMap.of());
    }

    @Override
    public AbstractUnifierBuilder unifierBuilder() {
        return unifierBuilder(emptySubstitution());
    }

    @Override // ensures that there is no cast in toUnifier()
    public abstract AbstractUnifierBuilder unifierBuilder(Substitution substitution);

    @Override
    public Collector, ?, Optional>> toUnifier() {
        return Collector.of(
                this::unifierBuilder,
                (a, s) -> a.unify(s.stream(), keyMapper, Map.Entry::getValue),
                AbstractUnifierBuilder::merge,
                UnifierBuilder::build);
    }


    private static final class ArgumentMapUnifierImpl implements ArgumentMapUnifier {
        private final ImmutableMap argumentMap;
        private final Substitution substitution;

        ArgumentMapUnifierImpl(ImmutableMap argumentMap, Substitution substitution) {
            this.argumentMap = argumentMap;
            this.substitution = substitution;
        }

        @Override
        public  ImmutableMap getArgumentMap() {
            return argumentMap;
        }

        @Override
        public Substitution getSubstitution() {
            return substitution;
        }

        @Override
        public String toString() { return argumentMap + " with " + substitution; }
    }


    private final class ArgumentMapUnifierBuilder {
        @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
        private Optional> optional;

        ArgumentMapUnifierBuilder() {
            optional = Optional.of(new ArgumentMapUnifierImpl<>(ImmutableMap.of(), emptySubstitution()));
        }

        void unify(ImmutableMap argumentMap) {
            if (optional.isEmpty())
                return;

            ArgumentMapUnifier unifier = optional.get();

            ImmutableMap updatedArgumentMap = applyToTerms(unifier.getSubstitution(), argumentMap);

            Optional> optionalUpdatedSubstitution = unifierBuilder()
                    .unify(
                            Sets.intersection(unifier.getArgumentMap().keySet(), updatedArgumentMap.keySet()).stream(),
                            unifier.getArgumentMap()::get,
                            updatedArgumentMap::get)
                    .build();

            optional = optionalUpdatedSubstitution
                    .flatMap(u -> unifierBuilder(unifier.getSubstitution())
                            .unify(u.stream(), keyMapper, Map.Entry::getValue)
                            .build()
                            .map(s -> new ArgumentMapUnifierImpl<>(
                                    applyToTerms(u, ExtensionalDataNode.union(unifier.getArgumentMap(), updatedArgumentMap)),
                                    s)));
        }

        ArgumentMapUnifierBuilder merge(ArgumentMapUnifierBuilder another) {
            throw new MinorOntopInternalBugException("Not expected to be run in parallel");
        }

        Optional> build() {
            return optional;
        }
     }

    @Override
    public Collector, ?, Optional>> toArgumentMapUnifier() {
        return Collector.of(ArgumentMapUnifierBuilder::new, ArgumentMapUnifierBuilder::unify, ArgumentMapUnifierBuilder::merge, ArgumentMapUnifierBuilder::build);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy