diff options
Diffstat (limited to 'subprojects/store-query-viatra/src')
3 files changed, 170 insertions, 9 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java index 2b5618d2..eb815588 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java | |||
@@ -12,10 +12,12 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.Consta | |||
12 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; | 12 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; |
13 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; | 13 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; |
14 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; | 14 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; |
15 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | 16 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; |
16 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | 17 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; |
17 | import tools.refinery.store.query.DNF; | 18 | import tools.refinery.store.query.DNF; |
18 | import tools.refinery.store.query.DNFAnd; | 19 | import tools.refinery.store.query.DNFAnd; |
20 | import tools.refinery.store.query.DNFUtils; | ||
19 | import tools.refinery.store.query.Variable; | 21 | import tools.refinery.store.query.Variable; |
20 | import tools.refinery.store.query.atom.*; | 22 | import tools.refinery.store.query.atom.*; |
21 | import tools.refinery.store.query.view.AnyRelationView; | 23 | import tools.refinery.store.query.view.AnyRelationView; |
@@ -124,8 +126,19 @@ public class DNF2PQuery { | |||
124 | } | 126 | } |
125 | 127 | ||
126 | private void translateRelationViewAtom(RelationViewAtom relationViewAtom, PBody body) { | 128 | private void translateRelationViewAtom(RelationViewAtom relationViewAtom, PBody body) { |
127 | new TypeConstraint(body, translateSubstitution(relationViewAtom.getSubstitution(), body), | 129 | var substitution = translateSubstitution(relationViewAtom.getSubstitution(), body); |
128 | wrapView(relationViewAtom.getTarget())); | 130 | var polarity = relationViewAtom.getPolarity(); |
131 | var relationView = relationViewAtom.getTarget(); | ||
132 | if (polarity == CallPolarity.POSITIVE) { | ||
133 | new TypeConstraint(body, substitution, wrapView(relationView)); | ||
134 | } else { | ||
135 | var embeddedPQuery = translateEmbeddedRelationViewPQuery(relationView); | ||
136 | switch (polarity) { | ||
137 | case TRANSITIVE -> new BinaryTransitiveClosure(body, substitution, embeddedPQuery); | ||
138 | case NEGATIVE -> new NegativePatternCall(body, substitution, embeddedPQuery); | ||
139 | default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); | ||
140 | } | ||
141 | } | ||
129 | } | 142 | } |
130 | 143 | ||
131 | private static Tuple translateSubstitution(List<Variable> substitution, PBody body) { | 144 | private static Tuple translateSubstitution(List<Variable> substitution, PBody body) { |
@@ -138,16 +151,36 @@ public class DNF2PQuery { | |||
138 | return Tuples.flatTupleOf(variables); | 151 | return Tuples.flatTupleOf(variables); |
139 | } | 152 | } |
140 | 153 | ||
154 | private RawPQuery translateEmbeddedRelationViewPQuery(AnyRelationView relationView) { | ||
155 | var embeddedPQuery = new RawPQuery(DNFUtils.generateUniqueName(relationView.name()), PVisibility.EMBEDDED); | ||
156 | var body = new PBody(embeddedPQuery); | ||
157 | int arity = relationView.arity(); | ||
158 | var parameters = new ArrayList<PParameter>(arity); | ||
159 | var arguments = new Object[arity]; | ||
160 | var symbolicParameters = new ArrayList<ExportedParameter>(arity); | ||
161 | for (int i = 0; i < arity; i++) { | ||
162 | var parameterName = "p" + i; | ||
163 | var parameter = new PParameter(parameterName); | ||
164 | parameters.add(parameter); | ||
165 | var variable = body.getOrCreateVariableByName(parameterName); | ||
166 | arguments[i] = variable; | ||
167 | symbolicParameters.add(new ExportedParameter(body, variable, parameter)); | ||
168 | } | ||
169 | embeddedPQuery.setParameters(parameters); | ||
170 | body.setSymbolicParameters(symbolicParameters); | ||
171 | var argumentTuple = Tuples.flatTupleOf(arguments); | ||
172 | new TypeConstraint(body, argumentTuple, wrapView(relationView)); | ||
173 | embeddedPQuery.addBody(body); | ||
174 | return embeddedPQuery; | ||
175 | } | ||
176 | |||
141 | private RelationViewWrapper wrapView(AnyRelationView relationView) { | 177 | private RelationViewWrapper wrapView(AnyRelationView relationView) { |
142 | return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); | 178 | return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); |
143 | } | 179 | } |
144 | 180 | ||
145 | private void translateCallAtom(CallAtom<?> callAtom, PBody body) { | 181 | private void translateCallAtom(DNFCallAtom callAtom, PBody body) { |
146 | if (!(callAtom.getTarget() instanceof DNF target)) { | ||
147 | throw new IllegalArgumentException("Only calls to DNF are supported"); | ||
148 | } | ||
149 | var variablesTuple = translateSubstitution(callAtom.getSubstitution(), body); | 182 | var variablesTuple = translateSubstitution(callAtom.getSubstitution(), body); |
150 | var translatedReferred = translate(target); | 183 | var translatedReferred = translate(callAtom.getTarget()); |
151 | var polarity = callAtom.getPolarity(); | 184 | var polarity = callAtom.getPolarity(); |
152 | switch (polarity) { | 185 | switch (polarity) { |
153 | case POSITIVE -> new PositivePatternCall(body, variablesTuple, translatedReferred); | 186 | case POSITIVE -> new PositivePatternCall(body, variablesTuple, translatedReferred); |
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java index 5d0b9e82..830495b2 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java | |||
@@ -18,11 +18,15 @@ public class RawPQuery extends BasePQuery { | |||
18 | private List<PParameter> parameters; | 18 | private List<PParameter> parameters; |
19 | private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>(); | 19 | private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>(); |
20 | 20 | ||
21 | public RawPQuery(String name) { | 21 | public RawPQuery(String name, PVisibility visibility) { |
22 | super(PVisibility.PUBLIC); | 22 | super(visibility); |
23 | fullyQualifiedName = name; | 23 | fullyQualifiedName = name; |
24 | } | 24 | } |
25 | 25 | ||
26 | public RawPQuery(String name) { | ||
27 | this(name, PVisibility.PUBLIC); | ||
28 | } | ||
29 | |||
26 | @Override | 30 | @Override |
27 | public String getFullyQualifiedName() { | 31 | public String getFullyQualifiedName() { |
28 | return fullyQualifiedName; | 32 | return fullyQualifiedName; |
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java index 72e8d7e5..ba0abca0 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java | |||
@@ -391,6 +391,48 @@ class QueryTest { | |||
391 | } | 391 | } |
392 | 392 | ||
393 | @Test | 393 | @Test |
394 | void negativeRelationViewTest() { | ||
395 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
396 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
397 | var personView = new KeyOnlyRelationView<>(person); | ||
398 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | ||
399 | |||
400 | var p1 = new Variable("p1"); | ||
401 | var p2 = new Variable("p2"); | ||
402 | var predicate = DNF.builder("NegativePatternCall") | ||
403 | .parameters(p1, p2) | ||
404 | .clause( | ||
405 | new RelationViewAtom(personView, p1), | ||
406 | new RelationViewAtom(personView, p2), | ||
407 | new RelationViewAtom(false, friendMustView, p1, p2) | ||
408 | ) | ||
409 | .build(); | ||
410 | |||
411 | var store = ModelStore.builder() | ||
412 | .symbols(person, friend) | ||
413 | .with(ViatraModelQuery.ADAPTER) | ||
414 | .queries(predicate) | ||
415 | .build(); | ||
416 | |||
417 | var model = store.createModel(); | ||
418 | var personInterpretation = model.getInterpretation(person); | ||
419 | var friendInterpretation = model.getInterpretation(friend); | ||
420 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | ||
421 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
422 | |||
423 | personInterpretation.put(Tuple.of(0), true); | ||
424 | personInterpretation.put(Tuple.of(1), true); | ||
425 | personInterpretation.put(Tuple.of(2), true); | ||
426 | |||
427 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
428 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
429 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
430 | |||
431 | queryEngine.flushChanges(); | ||
432 | assertEquals(6, predicateResultSet.countResults()); | ||
433 | } | ||
434 | |||
435 | @Test | ||
394 | void negativePatternCallTest() { | 436 | void negativePatternCallTest() { |
395 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 437 | var person = new Symbol<>("Person", 1, Boolean.class, false); |
396 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 438 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); |
@@ -444,6 +486,47 @@ class QueryTest { | |||
444 | } | 486 | } |
445 | 487 | ||
446 | @Test | 488 | @Test |
489 | void negativeRelationViewWithQuantificationTest() { | ||
490 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
491 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
492 | var personView = new KeyOnlyRelationView<>(person); | ||
493 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | ||
494 | |||
495 | var p1 = new Variable("p1"); | ||
496 | var p2 = new Variable("p2"); | ||
497 | |||
498 | var predicate = DNF.builder("Count") | ||
499 | .parameters(p1) | ||
500 | .clause( | ||
501 | new RelationViewAtom(personView, p1), | ||
502 | new RelationViewAtom(false, friendMustView, p1, p2) | ||
503 | ) | ||
504 | .build(); | ||
505 | |||
506 | var store = ModelStore.builder() | ||
507 | .symbols(person, friend) | ||
508 | .with(ViatraModelQuery.ADAPTER) | ||
509 | .queries(predicate) | ||
510 | .build(); | ||
511 | |||
512 | var model = store.createModel(); | ||
513 | var personInterpretation = model.getInterpretation(person); | ||
514 | var friendInterpretation = model.getInterpretation(friend); | ||
515 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | ||
516 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
517 | |||
518 | personInterpretation.put(Tuple.of(0), true); | ||
519 | personInterpretation.put(Tuple.of(1), true); | ||
520 | personInterpretation.put(Tuple.of(2), true); | ||
521 | |||
522 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
523 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); | ||
524 | |||
525 | queryEngine.flushChanges(); | ||
526 | assertEquals(2, predicateResultSet.countResults()); | ||
527 | } | ||
528 | |||
529 | @Test | ||
447 | void negativeWithQuantificationTest() { | 530 | void negativeWithQuantificationTest() { |
448 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 531 | var person = new Symbol<>("Person", 1, Boolean.class, false); |
449 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 532 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); |
@@ -494,6 +577,47 @@ class QueryTest { | |||
494 | } | 577 | } |
495 | 578 | ||
496 | @Test | 579 | @Test |
580 | void transitiveRelationViewTest() { | ||
581 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
582 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
583 | var personView = new KeyOnlyRelationView<>(person); | ||
584 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | ||
585 | |||
586 | var p1 = new Variable("p1"); | ||
587 | var p2 = new Variable("p2"); | ||
588 | var predicate = DNF.builder("TransitivePatternCall") | ||
589 | .parameters(p1, p2) | ||
590 | .clause( | ||
591 | new RelationViewAtom(personView, p1), | ||
592 | new RelationViewAtom(personView, p2), | ||
593 | new RelationViewAtom(CallPolarity.TRANSITIVE, friendMustView, p1, p2) | ||
594 | ) | ||
595 | .build(); | ||
596 | |||
597 | var store = ModelStore.builder() | ||
598 | .symbols(person, friend) | ||
599 | .with(ViatraModelQuery.ADAPTER) | ||
600 | .queries(predicate) | ||
601 | .build(); | ||
602 | |||
603 | var model = store.createModel(); | ||
604 | var personInterpretation = model.getInterpretation(person); | ||
605 | var friendInterpretation = model.getInterpretation(friend); | ||
606 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | ||
607 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
608 | |||
609 | personInterpretation.put(Tuple.of(0), true); | ||
610 | personInterpretation.put(Tuple.of(1), true); | ||
611 | personInterpretation.put(Tuple.of(2), true); | ||
612 | |||
613 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
614 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
615 | |||
616 | queryEngine.flushChanges(); | ||
617 | assertEquals(3, predicateResultSet.countResults()); | ||
618 | } | ||
619 | |||
620 | @Test | ||
497 | void transitivePatternCallTest() { | 621 | void transitivePatternCallTest() { |
498 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 622 | var person = new Symbol<>("Person", 1, Boolean.class, false); |
499 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 623 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); |