From 8a2a7efaaee2616beea139d816aafcdc57699aee Mon Sep 17 00:00:00 2001 From: Ficsor Attila Date: Tue, 12 Oct 2021 23:35:43 +0200 Subject: Add DNF to PQuery translator Also added tests for the translator --- .../refinery/store/query/internal/DNF2PQuery.java | 184 +++++++++++ .../tools/refinery/store/query/test/QueryTest.java | 351 +++++++++++++++++++++ 2 files changed, 535 insertions(+) create mode 100644 store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java (limited to 'store/src') diff --git a/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java b/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java new file mode 100644 index 00000000..c9c8245b --- /dev/null +++ b/store/src/main/java/tools/refinery/store/query/internal/DNF2PQuery.java @@ -0,0 +1,184 @@ +package tools.refinery.store.query.internal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.InputMismatchException; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; +import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; +import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; +import org.eclipse.viatra.query.runtime.api.scope.QueryScope; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; +import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; + +import tools.refinery.store.query.RelationalScope; +import tools.refinery.store.query.building.DNFAnd; +import tools.refinery.store.query.building.DNFAtom; +import tools.refinery.store.query.building.DNFPredicate; +import tools.refinery.store.query.building.EquivalenceAtom; +import tools.refinery.store.query.building.PredicateAtom; +import tools.refinery.store.query.building.RelationAtom; +import tools.refinery.store.query.building.Variable; + +public class DNF2PQuery { + private static Map DNF2PQueryMap = new HashMap<>(); + + public static SimplePQuery translate(DNFPredicate predicate) { + SimplePQuery query = DNF2PQueryMap.get(predicate); + if (query != null) { + return query; + } + query = new DNF2PQuery().new SimplePQuery(predicate.getName()); + Map parameters = new HashMap<>(); + + predicate.getVariables().forEach(variable -> parameters.put(variable, new PParameter(variable.getName()))); + query.setParameter(new ArrayList<>(parameters.values())); + for (DNFAnd clause : predicate.getClauses()) { + PBody body = new PBody(query); + List symbolicParameters = new ArrayList<>(); + parameters.forEach((variable, parameter) -> { + PVariable pVar = body.getOrCreateVariableByName(variable.getName()); + symbolicParameters.add(new ExportedParameter(body, pVar, parameter)); + }); + body.setSymbolicParameters(symbolicParameters); + query.addBody(body); + for (DNFAtom constraint : clause.getConstraints()) { + translateDNFAtom(constraint, body); + } + } + DNF2PQueryMap.put(predicate, query); + return query; + } + + private static void translateDNFAtom(DNFAtom constraint, PBody body) { + if (constraint instanceof EquivalenceAtom equivalence) { + translateEquivalenceAtom(equivalence, body); + } + if (constraint instanceof RelationAtom relation) { + translateRelationAtom(relation, body); + } + if (constraint instanceof PredicateAtom predicate) { + translatePredicateAtom(predicate, body); + } + } + + private static void translateEquivalenceAtom(EquivalenceAtom equivalence, PBody body) { + PVariable varSource = body.getOrCreateVariableByName(equivalence.getLeft().getName()); + PVariable varTarget = body.getOrCreateVariableByName(equivalence.getRight().getName()); + if (equivalence.isPositive()) + new Equality(body, varSource, varTarget); + else + new Inequality(body, varSource, varTarget); + } + + private static void translateRelationAtom(RelationAtom relation, PBody body) { + if (relation.getSubstitution().size() != relation.getView().getArity()) { + throw new IllegalArgumentException("Arity (" + relation.getView().getArity() + + ") does not match parameter numbers (" + relation.getSubstitution().size() + ")"); + } + Object[] variables = new Object[relation.getSubstitution().size()]; + for (int i = 0; i < relation.getSubstitution().size(); i++) { + variables[i] = body.getOrCreateVariableByName(relation.getSubstitution().get(i).getName()); + } + new TypeConstraint(body, Tuples.flatTupleOf(variables), relation.getView()); + } + + private static void translatePredicateAtom(PredicateAtom predicate, PBody body) { + Object[] variables = new Object[predicate.getSubstitution().size()]; + for (int i = 0; i < predicate.getSubstitution().size(); i++) { + variables[i] = body.getOrCreateVariableByName(predicate.getSubstitution().get(i).getName()); + } + if (predicate.isPositive()) { + if (predicate.isTransitive()) { + if (predicate.getSubstitution().size() != 2) { + throw new IllegalArgumentException("Transitive Predicate Atoms must be binary."); + } + new BinaryTransitiveClosure(body, Tuples.flatTupleOf(variables), + DNF2PQuery.translate(predicate.getReferred())); + } else { + new PositivePatternCall(body, Tuples.flatTupleOf(variables), + DNF2PQuery.translate(predicate.getReferred())); + } + } else { + if (predicate.isTransitive()) { + throw new InputMismatchException("Transitive Predicate Atoms cannot be negative."); + } else { + new NegativePatternCall(body, Tuples.flatTupleOf(variables), + DNF2PQuery.translate(predicate.getReferred())); + } + } + } + + public class SimplePQuery extends BasePQuery { + + private String fullyQualifiedName; + private List parameters; + private LinkedHashSet bodies = new LinkedHashSet<>(); + + public SimplePQuery(String name) { + super(PVisibility.PUBLIC); + fullyQualifiedName = name; + } + + @Override + public String getFullyQualifiedName() { + return fullyQualifiedName; + } + + public void setParameter(List parameters) { + this.parameters = parameters; + } + + @Override + public List getParameters() { + return parameters; + } + + public void addBody(PBody body) { + bodies.add(body); + } + + @Override + protected Set doGetContainedBodies() { + setEvaluationHints(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.UNSPECIFIED)); + return bodies; + } + + public GenericQuerySpecification build() { + return new GenericQuerySpecification(this) { + + @Override + public Class getPreferredScopeClass() { + return RelationalScope.class; + } + + @Override + protected GenericPatternMatcher instantiate(ViatraQueryEngine engine) { + return defaultInstantiate(engine); + } + + @Override + public GenericPatternMatcher instantiate() { + return new GenericPatternMatcher(this); + } + + }; + } + } +} \ No newline at end of file diff --git a/store/src/test/java/tools/refinery/store/query/test/QueryTest.java b/store/src/test/java/tools/refinery/store/query/test/QueryTest.java index 38aa130a..b1014700 100644 --- a/store/src/test/java/tools/refinery/store/query/test/QueryTest.java +++ b/store/src/test/java/tools/refinery/store/query/test/QueryTest.java @@ -4,7 +4,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; +import java.util.List; import java.util.Set; import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; @@ -12,6 +15,7 @@ import org.eclipse.viatra.query.runtime.api.GenericPatternMatch; import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.model.Model; @@ -21,6 +25,13 @@ import tools.refinery.store.model.Tuple; import tools.refinery.store.model.representation.Relation; import tools.refinery.store.model.representation.TruthValue; import tools.refinery.store.query.RelationalScope; +import tools.refinery.store.query.building.DNFAnd; +import tools.refinery.store.query.building.DNFPredicate; +import tools.refinery.store.query.building.EquivalenceAtom; +import tools.refinery.store.query.building.PredicateAtom; +import tools.refinery.store.query.building.RelationAtom; +import tools.refinery.store.query.building.Variable; +import tools.refinery.store.query.internal.DNF2PQuery; import tools.refinery.store.query.internal.PredicateTranslator; import tools.refinery.store.query.view.FilteredRelationView; import tools.refinery.store.query.view.FunctionalRelationView; @@ -87,4 +98,344 @@ class QueryTest { System.out.println(personMatch); } } + + @Test + @Disabled + void typeConstraintTest() { + Relation person = new Relation<>("Person", 1, false); + Relation asset = new Relation<>("Asset", 1, false); + RelationView persionView = new KeyOnlyRelationView(person); + + List parameters = Arrays.asList(new Variable("p1")); + RelationAtom personRelationAtom = new RelationAtom(persionView, parameters); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), Arrays.asList(personRelationAtom)); + DNFPredicate predicate = new DNFPredicate("TypeConstraint", parameters, Arrays.asList(clause)); + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, asset)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(asset, Tuple.of(1), true); + model.put(asset, Tuple.of(2), true); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(2, matcher.countMatches()); + } + + @Test + @Disabled + void relationConstraintTest() { + Relation person = new Relation("Person", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom)); + DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(3, matcher.countMatches()); + } + + @Test + @Disabled + void patternCallTest() { + Relation person = new Relation("Person", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom)); + DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause)); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + List substitution = Arrays.asList(p3, p4); + RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3)); + RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4)); + PredicateAtom friendPredicateAtom = new PredicateAtom(true, false, friendPredicate, substitution); + DNFAnd patternCallClause = new DNFAnd(new HashSet<>(substitution), + Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom)); + DNFPredicate predicate = new DNFPredicate("PatternCall", substitution, Arrays.asList(patternCallClause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(3, matcher.countMatches()); + } + + @Test + @Disabled + void negativePatternCallTest() { + Relation person = new Relation("Person", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom)); + DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause)); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + List substitution = Arrays.asList(p3, p4); + RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3)); + RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4)); + PredicateAtom friendPredicateAtom = new PredicateAtom(false, false, friendPredicate, substitution); + DNFAnd negativePatternCallClause = new DNFAnd(new HashSet<>(substitution), + Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom)); + DNFPredicate predicate = new DNFPredicate("NegativePatternCall", substitution, + Arrays.asList(negativePatternCallClause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(6, matcher.countMatches()); + } + + @Test + @Disabled + void equalityTest() { + Relation person = new Relation("Person", 1, false); + RelationView persionView = new KeyOnlyRelationView(person); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + EquivalenceAtom equivalenceAtom = new EquivalenceAtom(true, p1, p2); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, equivalenceAtom)); + DNFPredicate predicate = new DNFPredicate("Equality", parameters, Arrays.asList(clause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(3, matcher.countMatches()); + } + + @Test + @Disabled + void inequalityTest() { + Relation person = new Relation("Person", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + Variable p3 = new Variable("p3"); + List parameters = Arrays.asList(p1, p2, p3); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p3)); + RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p2, p3)); + EquivalenceAtom inequivalenceAtom = new EquivalenceAtom(false, p1, p2); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), Arrays.asList(personRelationAtom1, personRelationAtom2, + friendRelationAtom1, friendRelationAtom2, inequivalenceAtom)); + DNFPredicate predicate = new DNFPredicate("Inequality", parameters, Arrays.asList(clause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(2, matcher.countMatches()); + } + + @Test + @Disabled + void transitivePatternCallTest() { + Relation person = new Relation("Person", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom)); + DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause)); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + List substitution = Arrays.asList(p3, p4); + RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3)); + RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4)); + PredicateAtom friendPredicateAtom = new PredicateAtom(true, true, friendPredicate, substitution); + DNFAnd patternCallClause = new DNFAnd(new HashSet<>(substitution), + Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom)); + DNFPredicate predicate = new DNFPredicate("TransitivePatternCall", substitution, + Arrays.asList(patternCallClause)); + + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(3, matcher.countMatches()); + } + + @Test + @Disabled + void orTest() { + Relation person = new Relation<>("Person", 1, false); + Relation animal = new Relation<>("Animal", 1, false); + Relation friend = new Relation<>("friend", 2, TruthValue.FALSE); + RelationView persionView = new KeyOnlyRelationView(person); + RelationView animalView = new KeyOnlyRelationView(animal); + RelationView friendMustView = new FilteredRelationView(friend, (k, v) -> v.must()); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + List parameters = Arrays.asList(p1, p2); + + RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1)); + RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2)); + RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause1 = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom1)); + + RelationAtom animalRelationAtom1 = new RelationAtom(animalView, Arrays.asList(p1)); + RelationAtom animalRelationAtom2 = new RelationAtom(animalView, Arrays.asList(p2)); + RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p1, p2)); + DNFAnd clause2 = new DNFAnd(new HashSet<>(parameters), + Arrays.asList(animalRelationAtom1, animalRelationAtom2, friendRelationAtom2)); + + DNFPredicate predicate = new DNFPredicate("Or", parameters, Arrays.asList(clause1, clause2)); + GenericQuerySpecification query = DNF2PQuery.translate(predicate).build(); + + ModelStore store = new ModelStoreImpl(Set.of(person, animal, friend)); + Model model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(animal, Tuple.of(2), true); + model.put(animal, Tuple.of(3), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + model.put(friend, Tuple.of(2, 3), TruthValue.TRUE); + model.put(friend, Tuple.of(3, 0), TruthValue.TRUE); + + RelationalScope scope = new RelationalScope(model, Set.of(persionView, animalView, friendMustView)); + + ViatraQueryEngine engine = AdvancedViatraQueryEngine.on(scope); + GenericPatternMatcher matcher = engine.getMatcher(query); + + assertEquals(2, matcher.countMatches()); + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2