diff options
Diffstat (limited to 'subprojects/store-query-viatra/src')
4 files changed, 83 insertions, 14 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java index e5d8e2f6..e0341598 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java | |||
@@ -8,6 +8,7 @@ import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; | |||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; | 8 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; |
9 | import tools.refinery.store.model.Model; | 9 | import tools.refinery.store.model.Model; |
10 | import tools.refinery.store.query.Dnf; | 10 | import tools.refinery.store.query.Dnf; |
11 | import tools.refinery.store.query.EmptyResultSet; | ||
11 | import tools.refinery.store.query.ResultSet; | 12 | import tools.refinery.store.query.ResultSet; |
12 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; | 13 | import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; |
13 | 14 | ||
@@ -15,7 +16,7 @@ import java.lang.invoke.MethodHandle; | |||
15 | import java.lang.invoke.MethodHandles; | 16 | import java.lang.invoke.MethodHandles; |
16 | import java.util.Collection; | 17 | import java.util.Collection; |
17 | import java.util.Collections; | 18 | import java.util.Collections; |
18 | import java.util.HashMap; | 19 | import java.util.LinkedHashMap; |
19 | import java.util.Map; | 20 | import java.util.Map; |
20 | 21 | ||
21 | public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { | 22 | public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { |
@@ -51,11 +52,15 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { | |||
51 | GenericQueryGroup.of( | 52 | GenericQueryGroup.of( |
52 | Collections.<IQuerySpecification<?>>unmodifiableCollection(querySpecifications.values()).stream() | 53 | Collections.<IQuerySpecification<?>>unmodifiableCollection(querySpecifications.values()).stream() |
53 | ).prepare(queryEngine); | 54 | ).prepare(queryEngine); |
54 | resultSets = new HashMap<>(querySpecifications.size()); | 55 | var vacuousQueries = storeAdapter.getVacuousQueries(); |
56 | resultSets = new LinkedHashMap<>(querySpecifications.size() + vacuousQueries.size()); | ||
55 | for (var entry : querySpecifications.entrySet()) { | 57 | for (var entry : querySpecifications.entrySet()) { |
56 | var matcher = queryEngine.getMatcher(entry.getValue()); | 58 | var matcher = queryEngine.getMatcher(entry.getValue()); |
57 | resultSets.put(entry.getKey(), matcher); | 59 | resultSets.put(entry.getKey(), matcher); |
58 | } | 60 | } |
61 | for (var vacuousQuery : vacuousQueries) { | ||
62 | resultSets.put(vacuousQuery, new EmptyResultSet()); | ||
63 | } | ||
59 | 64 | ||
60 | setUpdatePropagationDelayed(true); | 65 | setUpdatePropagationDelayed(true); |
61 | } | 66 | } |
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java index af20033a..13641ace 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java | |||
@@ -14,14 +14,13 @@ import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; | |||
14 | import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; | 14 | import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; |
15 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; | 15 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; |
16 | 16 | ||
17 | import java.util.Collections; | 17 | import java.util.*; |
18 | import java.util.LinkedHashMap; | ||
19 | import java.util.Map; | ||
20 | import java.util.function.Function; | 18 | import java.util.function.Function; |
21 | 19 | ||
22 | public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { | 20 | public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { |
23 | private ViatraQueryEngineOptions.Builder engineOptionsBuilder; | 21 | private ViatraQueryEngineOptions.Builder engineOptionsBuilder; |
24 | private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); | 22 | private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); |
23 | private final Set<Dnf> vacuousQueries = new LinkedHashSet<>(); | ||
25 | private final Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>(); | 24 | private final Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>(); |
26 | 25 | ||
27 | public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { | 26 | public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { |
@@ -64,11 +63,21 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp | |||
64 | 63 | ||
65 | @Override | 64 | @Override |
66 | public ViatraModelQueryBuilder query(Dnf query) { | 65 | public ViatraModelQueryBuilder query(Dnf query) { |
67 | if (querySpecifications.containsKey(query)) { | 66 | if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { |
68 | throw new IllegalArgumentException("%s was already added to the query engine".formatted(query.name())); | 67 | // Ignore duplicate queries. |
68 | return this; | ||
69 | } | ||
70 | var reduction = query.getReduction(); | ||
71 | switch (reduction) { | ||
72 | case NOT_REDUCIBLE -> { | ||
73 | var pQuery = dnf2PQuery.translate(query); | ||
74 | querySpecifications.put(query, pQuery.build()); | ||
75 | } | ||
76 | case ALWAYS_FALSE -> vacuousQueries.add(query); | ||
77 | case ALWAYS_TRUE -> throw new IllegalArgumentException( | ||
78 | "Query %s is relationally unsafe (it matches every tuple)".formatted(query.name())); | ||
79 | default -> throw new IllegalArgumentException("Unknown reduction: " + reduction); | ||
69 | } | 80 | } |
70 | var pQuery = dnf2PQuery.translate(query); | ||
71 | querySpecifications.put(query, pQuery.build()); | ||
72 | return this; | 81 | return this; |
73 | } | 82 | } |
74 | 83 | ||
@@ -89,6 +98,10 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp | |||
89 | public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { | 98 | public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { |
90 | var pQuery = dnf2PQuery.getAlreadyTranslated(dnf); | 99 | var pQuery = dnf2PQuery.getAlreadyTranslated(dnf); |
91 | if (pQuery == null) { | 100 | if (pQuery == null) { |
101 | if (vacuousQueries.contains(dnf)) { | ||
102 | // Ignore hits for queries that will never be executed by the query engine. | ||
103 | return this; | ||
104 | } | ||
92 | throw new IllegalArgumentException( | 105 | throw new IllegalArgumentException( |
93 | "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name())); | 106 | "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name())); |
94 | } | 107 | } |
@@ -100,7 +113,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp | |||
100 | public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { | 113 | public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { |
101 | validateSymbols(store); | 114 | validateSymbols(store); |
102 | return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(), | 115 | return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(), |
103 | Collections.unmodifiableMap(querySpecifications)); | 116 | Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); |
104 | } | 117 | } |
105 | 118 | ||
106 | private void validateSymbols(ModelStore store) { | 119 | private void validateSymbols(ModelStore store) { |
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java index 8323118b..00660d0b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java | |||
@@ -10,22 +10,29 @@ import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; | |||
10 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; | 10 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; |
11 | import tools.refinery.store.query.view.AnyRelationView; | 11 | import tools.refinery.store.query.view.AnyRelationView; |
12 | 12 | ||
13 | import java.util.Collection; | 13 | import java.util.*; |
14 | import java.util.Map; | ||
15 | 14 | ||
16 | public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter { | 15 | public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter { |
17 | private final ModelStore store; | 16 | private final ModelStore store; |
18 | private final ViatraQueryEngineOptions engineOptions; | 17 | private final ViatraQueryEngineOptions engineOptions; |
19 | private final Map<AnyRelationView, IInputKey> inputKeys; | 18 | private final Map<AnyRelationView, IInputKey> inputKeys; |
20 | private final Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications; | 19 | private final Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications; |
20 | private final Set<Dnf> vacuousQueries; | ||
21 | private final Set<Dnf> allQueries; | ||
21 | 22 | ||
22 | ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, | 23 | ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, |
23 | Map<AnyRelationView, IInputKey> inputKeys, | 24 | Map<AnyRelationView, IInputKey> inputKeys, |
24 | Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications) { | 25 | Map<Dnf, IQuerySpecification<RawPatternMatcher>> querySpecifications, |
26 | Set<Dnf> vacuousQueries) { | ||
25 | this.store = store; | 27 | this.store = store; |
26 | this.engineOptions = engineOptions; | 28 | this.engineOptions = engineOptions; |
27 | this.inputKeys = inputKeys; | 29 | this.inputKeys = inputKeys; |
28 | this.querySpecifications = querySpecifications; | 30 | this.querySpecifications = querySpecifications; |
31 | this.vacuousQueries = vacuousQueries; | ||
32 | var mutableAllQueries = new LinkedHashSet<Dnf>(querySpecifications.size() + vacuousQueries.size()); | ||
33 | mutableAllQueries.addAll(querySpecifications.keySet()); | ||
34 | mutableAllQueries.addAll(vacuousQueries); | ||
35 | this.allQueries = Collections.unmodifiableSet(mutableAllQueries); | ||
29 | } | 36 | } |
30 | 37 | ||
31 | @Override | 38 | @Override |
@@ -43,13 +50,17 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd | |||
43 | 50 | ||
44 | @Override | 51 | @Override |
45 | public Collection<Dnf> getQueries() { | 52 | public Collection<Dnf> getQueries() { |
46 | return querySpecifications.keySet(); | 53 | return allQueries; |
47 | } | 54 | } |
48 | 55 | ||
49 | Map<Dnf, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() { | 56 | Map<Dnf, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() { |
50 | return querySpecifications; | 57 | return querySpecifications; |
51 | } | 58 | } |
52 | 59 | ||
60 | Set<Dnf> getVacuousQueries() { | ||
61 | return vacuousQueries; | ||
62 | } | ||
63 | |||
53 | @Override | 64 | @Override |
54 | public ViatraQueryEngineOptions getEngineOptions() { | 65 | public ViatraQueryEngineOptions getEngineOptions() { |
55 | return engineOptions; | 66 | return engineOptions; |
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 6a3a62e3..54ae70c3 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 | |||
@@ -17,6 +17,7 @@ import java.util.Set; | |||
17 | import java.util.stream.Stream; | 17 | import java.util.stream.Stream; |
18 | 18 | ||
19 | import static org.junit.jupiter.api.Assertions.assertEquals; | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; |
20 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
20 | import static tools.refinery.store.query.literal.Literals.not; | 21 | import static tools.refinery.store.query.literal.Literals.not; |
21 | 22 | ||
22 | class QueryTest { | 23 | class QueryTest { |
@@ -669,6 +670,45 @@ class QueryTest { | |||
669 | assertEquals(3, predicateResultSet.countResults()); | 670 | assertEquals(3, predicateResultSet.countResults()); |
670 | } | 671 | } |
671 | 672 | ||
673 | @Test | ||
674 | void alwaysFalseTest() { | ||
675 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
676 | |||
677 | var p1 = new Variable("p1"); | ||
678 | var predicate = Dnf.builder("AlwaysFalse").parameters(p1).build(); | ||
679 | |||
680 | var store = ModelStore.builder() | ||
681 | .symbols(person) | ||
682 | .with(ViatraModelQuery.ADAPTER) | ||
683 | .queries(predicate) | ||
684 | .build(); | ||
685 | |||
686 | var model = store.createEmptyModel(); | ||
687 | var personInterpretation = model.getInterpretation(person); | ||
688 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | ||
689 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
690 | |||
691 | personInterpretation.put(Tuple.of(0), true); | ||
692 | personInterpretation.put(Tuple.of(1), true); | ||
693 | personInterpretation.put(Tuple.of(2), true); | ||
694 | |||
695 | queryEngine.flushChanges(); | ||
696 | assertEquals(0, predicateResultSet.countResults()); | ||
697 | } | ||
698 | |||
699 | @Test | ||
700 | void alwaysTrueTest() { | ||
701 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
702 | |||
703 | var p1 = new Variable("p1"); | ||
704 | var predicate = Dnf.builder("AlwaysTrue").parameters(p1).clause().build(); | ||
705 | |||
706 | var storeBuilder = ModelStore.builder().symbols(person); | ||
707 | var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER); | ||
708 | |||
709 | assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); | ||
710 | } | ||
711 | |||
672 | static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { | 712 | static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { |
673 | Set<Tuple> translatedMatchSet = new HashSet<>(); | 713 | Set<Tuple> translatedMatchSet = new HashSet<>(); |
674 | var iterator = matchSet.iterator(); | 714 | var iterator = matchSet.iterator(); |