fr.boreal.backward_chaining.homomorphism.QueryHomomorphism Maven / Gradle / Ivy
package fr.boreal.backward_chaining.homomorphism;
import com.google.common.collect.Sets;
import fr.boreal.model.formula.FOFormulas;
import fr.boreal.model.formula.api.FOFormula;
import fr.boreal.model.kb.api.FactBase;
import fr.boreal.model.logicalElements.api.Predicate;
import fr.boreal.model.logicalElements.api.Substitution;
import fr.boreal.model.logicalElements.api.Term;
import fr.boreal.model.logicalElements.api.Variable;
import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
import fr.boreal.model.query.api.FOQuery;
import fr.boreal.model.ruleCompilation.NoRuleCompilation;
import fr.boreal.model.ruleCompilation.api.RuleCompilation;
import fr.boreal.query_evaluation.generic.GenericFOQueryEvaluator;
import fr.boreal.storage.natives.SimpleInMemoryGraphStore;
import java.util.Iterator;
import java.util.Set;
/**
* Homomorphism computing specialized for queries
* Takes into account answer variables and initial substitutions
* Use the fact that queries are small to perform some quick checks that would cost a lot on a whole factbase
* Also uses a rule compilation
*
* @author Florent Tornil
*/
public class QueryHomomorphism {
private final RuleCompilation compilation;
/**
* Default constructor.
* Uses no compilation
*/
public QueryHomomorphism() {
this(NoRuleCompilation.instance());
}
/**
* Constructor with compilation
* @param compilation the compilation to use
*/
public QueryHomomorphism(RuleCompilation compilation) {
this.compilation = compilation;
}
/**
* @param q1 a query
* @param q2 a query
* @return true iff there is a homomorphism from q1 to q2
*/
public boolean exists(FOQuery extends FOFormula> q1, FOQuery extends FOFormula> q2) {
// First failure point
// If the predicates of q1 are not compatible with the predicates of q2
Set q1Predicates = q1.getFormula().getPredicates();
Set q2Predicates = q2.getFormula().getPredicates();
boolean compatible = true;
for(Predicate q1Predicate : q1Predicates) {
compatible = compatible &&
!Sets.intersection(
compilation.getCompatiblePredicates(q1Predicate),
q2Predicates).isEmpty();
}
if(!compatible) {
return false;
}
// equalities on answer variables
Substitution preAffectation = new SubstitutionImpl();
Iterator qAnswerVariables = q1.getAnswerVariables().iterator();
Iterator q2AnswerVariables = q2.getAnswerVariables().iterator();
while(qAnswerVariables.hasNext()) {
Variable v1 = qAnswerVariables.next();
Term v1Image = q1.getVariableEqualities().getRepresentative(v1);
Variable v2 = q2AnswerVariables.next();
Term v2Image = q2.getVariableEqualities().getRepresentative(v2);
// Second failure point
// If v1 is affected to a Term and v2 is not
// Example :
// [Q1] ?(X) :- p(X) X=a
// [Q2] ?(Y) :- p(Y)
// [Q2'] ?(Y) :- p(Y) Y=b
if(v1Image.isFrozen(null) && !v1Image.equals(v2Image)) {
return false;
}
// Third failure point
// If v1 appear multiple times in the answer variables but with different v2
// Example :
// [Q1] ?(X, X) :- p(X, X)
// [Q2] ?(Y, Z) :- p(Y, Z)
// Note : Q2' must still work
// [Q2'] ?(Y, Z) :- p(Y, Z) Y=a, Z=a
// [Q2'] ?(Y, Z) :- p(Y, Z) Y=Z
if(preAffectation.keys().contains(v1)) {
if(! preAffectation.createImageOf(v1).equals(v2Image)) {
return false;
}
} else {
preAffectation.add(v1, v2Image);
}
}
// If no failure point have stopped the homomorphism
// Use the generic homomorphism to finish
FactBase q2AsFactBase = new SimpleInMemoryGraphStore(
FOFormulas.createImageWith(q2.getFormula(),
q2.getVariableEqualities().getAssociatedSubstitution(q2).orElseThrow())
.asAtomSet());
if(this.compilation.equals(NoRuleCompilation.instance())) {
return GenericFOQueryEvaluator.defaultInstance().existHomomorphism(q1, q2AsFactBase, preAffectation);
} else {
return GenericFOQueryEvaluator.defaultInstanceWithInfCompilation(this.compilation).existHomomorphism(q1, q2AsFactBase, preAffectation);
}
}
}