aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java8
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java3
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java74
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java15
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java25
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java1
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java49
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java3
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java7
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java3
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java6
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java2
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java20
18 files changed, 154 insertions, 72 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
index 931a07aa..66279c94 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
@@ -9,9 +9,10 @@ import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
9import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; 9import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
10import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 10import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
11import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.query.ModelQueryBuilder;
12import tools.refinery.store.query.dnf.AnyQuery; 13import tools.refinery.store.query.dnf.AnyQuery;
13import tools.refinery.store.query.dnf.Dnf; 14import tools.refinery.store.query.dnf.Dnf;
14import tools.refinery.store.query.ModelQueryBuilder; 15import tools.refinery.store.query.rewriter.DnfRewriter;
15 16
16import java.util.Collection; 17import java.util.Collection;
17import java.util.function.Function; 18import java.util.function.Function;
@@ -43,12 +44,11 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder {
43 @Override 44 @Override
44 ViatraModelQueryBuilder query(AnyQuery query); 45 ViatraModelQueryBuilder query(AnyQuery query);
45 46
46 ViatraModelQueryBuilder query(AnyQuery query, QueryEvaluationHint queryEvaluationHint); 47 @Override
48 ViatraModelQueryBuilder rewriter(DnfRewriter rewriter);
47 49
48 ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint); 50 ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint);
49 51
50 ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint);
51
52 @Override 52 @Override
53 ViatraModelQueryStoreAdapter build(ModelStore store); 53 ViatraModelQueryStoreAdapter build(ModelStore store);
54} 54}
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 5f3e86b4..e17386e1 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
@@ -131,7 +131,8 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter, Mod
131 131
132 @Override 132 @Override
133 public <T> ResultSet<T> getResultSet(Query<T> query) { 133 public <T> ResultSet<T> getResultSet(Query<T> query) {
134 var resultSet = resultSets.get(query); 134 var canonicalQuery = storeAdapter.getCanonicalQuery(query);
135 var resultSet = resultSets.get(canonicalQuery);
135 if (resultSet == null) { 136 if (resultSet == null) {
136 throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name())); 137 throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name()));
137 } 138 }
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 ce2467b4..5ee8bd74 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
@@ -13,9 +13,12 @@ import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
13import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory; 13import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory;
14import tools.refinery.store.adapter.AbstractModelAdapterBuilder; 14import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
15import tools.refinery.store.model.ModelStore; 15import tools.refinery.store.model.ModelStore;
16import tools.refinery.store.model.ModelStoreBuilder;
17import tools.refinery.store.query.dnf.AnyQuery; 16import tools.refinery.store.query.dnf.AnyQuery;
18import tools.refinery.store.query.dnf.Dnf; 17import tools.refinery.store.query.dnf.Dnf;
18import tools.refinery.store.query.rewriter.CompositeRewriter;
19import tools.refinery.store.query.rewriter.DnfRewriter;
20import tools.refinery.store.query.rewriter.DuplicateDnfRemover;
21import tools.refinery.store.query.rewriter.InputParameterResolver;
19import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; 22import tools.refinery.store.query.viatra.ViatraModelQueryBuilder;
20import tools.refinery.store.query.viatra.internal.localsearch.FlatCostFunction; 23import tools.refinery.store.query.viatra.internal.localsearch.FlatCostFunction;
21import tools.refinery.store.query.viatra.internal.localsearch.RelationalLocalSearchBackendFactory; 24import tools.refinery.store.query.viatra.internal.localsearch.RelationalLocalSearchBackendFactory;
@@ -32,15 +35,18 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<Via
32 // Use a cost function that ignores the initial (empty) model but allows higher arity input keys. 35 // Use a cost function that ignores the initial (empty) model but allows higher arity input keys.
33 LocalSearchHintOptions.PLANNER_COST_FUNCTION, new FlatCostFunction() 36 LocalSearchHintOptions.PLANNER_COST_FUNCTION, new FlatCostFunction()
34 ), (IQueryBackendFactory) null); 37 ), (IQueryBackendFactory) null);
38 private final CompositeRewriter rewriter;
35 private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); 39 private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery();
36 private final Set<AnyQuery> vacuousQueries = new LinkedHashSet<>(); 40 private final Set<AnyQuery> queries = new LinkedHashSet<>();
37 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>();
38 41
39 public ViatraModelQueryBuilderImpl() { 42 public ViatraModelQueryBuilderImpl() {
40 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder() 43 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder()
41 .withDefaultBackend(ReteBackendFactory.INSTANCE) 44 .withDefaultBackend(ReteBackendFactory.INSTANCE)
42 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE) 45 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE)
43 .withDefaultSearchBackend(RelationalLocalSearchBackendFactory.INSTANCE); 46 .withDefaultSearchBackend(RelationalLocalSearchBackendFactory.INSTANCE);
47 rewriter = new CompositeRewriter();
48 rewriter.addFirst(new DuplicateDnfRemover());
49 rewriter.addFirst(new InputParameterResolver());
44 } 50 }
45 51
46 @Override 52 @Override
@@ -79,58 +85,58 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<Via
79 } 85 }
80 86
81 @Override 87 @Override
82 public ViatraModelQueryBuilder query(AnyQuery query) { 88 public ViatraModelQueryBuilder queries(Collection<? extends AnyQuery> queries) {
83 checkNotConfigured(); 89 checkNotConfigured();
84 if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { 90 this.queries.addAll(queries);
85 // Ignore duplicate queries.
86 return this;
87 }
88 var dnf = query.getDnf();
89 var reduction = dnf.getReduction();
90 switch (reduction) {
91 case NOT_REDUCIBLE -> {
92 var pQuery = dnf2PQuery.translate(dnf);
93 querySpecifications.put(query, pQuery.build());
94 }
95 case ALWAYS_FALSE -> vacuousQueries.add(query);
96 case ALWAYS_TRUE -> throw new IllegalArgumentException(
97 "Query %s is relationally unsafe (it matches every tuple)".formatted(query.name()));
98 default -> throw new IllegalArgumentException("Unknown reduction: " + reduction);
99 }
100 return this; 91 return this;
101 } 92 }
102 93
103 @Override 94 @Override
104 public ViatraModelQueryBuilder query(AnyQuery query, QueryEvaluationHint queryEvaluationHint) { 95 public ViatraModelQueryBuilder query(AnyQuery query) {
105 hint(query.getDnf(), queryEvaluationHint); 96 checkNotConfigured();
106 query(query); 97 queries.add(query);
107 return this; 98 return this;
108 } 99 }
109 100
110 @Override 101 @Override
111 public ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint) { 102 public ViatraModelQueryBuilder rewriter(DnfRewriter rewriter) {
112 checkNotConfigured(); 103 this.rewriter.addFirst(rewriter);
113 dnf2PQuery.setComputeHint(computeHint);
114 return this; 104 return this;
115 } 105 }
116 106
117 @Override 107 @Override
118 public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { 108 public ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint) {
119 checkNotConfigured(); 109 checkNotConfigured();
120 dnf2PQuery.hint(dnf, queryEvaluationHint); 110 dnf2PQuery.setComputeHint(computeHint);
121 return this; 111 return this;
122 } 112 }
123 113
124 @Override 114 @Override
125 public void doConfigure(ModelStoreBuilder storeBuilder) {
126 dnf2PQuery.assertNoUnusedHints();
127 }
128
129 @Override
130 public ViatraModelQueryStoreAdapterImpl doBuild(ModelStore store) { 115 public ViatraModelQueryStoreAdapterImpl doBuild(ModelStore store) {
116 var canonicalQueryMap = new HashMap<AnyQuery, AnyQuery>();
117 var querySpecifications = new LinkedHashMap<AnyQuery, IQuerySpecification<RawPatternMatcher>>();
118 var vacuousQueries = new LinkedHashSet<AnyQuery>();
119 for (var query : queries) {
120 var canonicalQuery = rewriter.rewrite(query);
121 canonicalQueryMap.put(query, canonicalQuery);
122 var dnf = canonicalQuery.getDnf();
123 var reduction = dnf.getReduction();
124 switch (reduction) {
125 case NOT_REDUCIBLE -> {
126 var pQuery = dnf2PQuery.translate(dnf);
127 querySpecifications.put(canonicalQuery, pQuery.build());
128 }
129 case ALWAYS_FALSE -> vacuousQueries.add(canonicalQuery);
130 case ALWAYS_TRUE -> throw new IllegalArgumentException(
131 "Query %s is relationally unsafe (it matches every tuple)".formatted(query.name()));
132 default -> throw new IllegalArgumentException("Unknown reduction: " + reduction);
133 }
134 }
135
131 validateSymbols(store); 136 validateSymbols(store);
132 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(), 137 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(),
133 Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); 138 Collections.unmodifiableMap(canonicalQueryMap), Collections.unmodifiableMap(querySpecifications),
139 Collections.unmodifiableSet(vacuousQueries));
134 } 140 }
135 141
136 private ViatraQueryEngineOptions buildEngineOptions() { 142 private ViatraQueryEngineOptions buildEngineOptions() {
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 11a3c7fd..25f1cd02 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
@@ -11,6 +11,7 @@ import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
11import tools.refinery.store.model.Model; 11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.ModelStore; 12import tools.refinery.store.model.ModelStore;
13import tools.refinery.store.query.dnf.AnyQuery; 13import tools.refinery.store.query.dnf.AnyQuery;
14import tools.refinery.store.query.dnf.Query;
14import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; 15import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter;
15import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; 16import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher;
16import tools.refinery.store.query.view.AnySymbolView; 17import tools.refinery.store.query.view.AnySymbolView;
@@ -21,17 +22,20 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd
21 private final ModelStore store; 22 private final ModelStore store;
22 private final ViatraQueryEngineOptions engineOptions; 23 private final ViatraQueryEngineOptions engineOptions;
23 private final Map<AnySymbolView, IInputKey> inputKeys; 24 private final Map<AnySymbolView, IInputKey> inputKeys;
25 private final Map<AnyQuery, AnyQuery> canonicalQueryMap;
24 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications; 26 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications;
25 private final Set<AnyQuery> vacuousQueries; 27 private final Set<AnyQuery> vacuousQueries;
26 private final Set<AnyQuery> allQueries; 28 private final Set<AnyQuery> allQueries;
27 29
28 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, 30 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions,
29 Map<AnySymbolView, IInputKey> inputKeys, 31 Map<AnySymbolView, IInputKey> inputKeys,
32 Map<AnyQuery, AnyQuery> canonicalQueryMap,
30 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications, 33 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications,
31 Set<AnyQuery> vacuousQueries) { 34 Set<AnyQuery> vacuousQueries) {
32 this.store = store; 35 this.store = store;
33 this.engineOptions = engineOptions; 36 this.engineOptions = engineOptions;
34 this.inputKeys = inputKeys; 37 this.inputKeys = inputKeys;
38 this.canonicalQueryMap = canonicalQueryMap;
35 this.querySpecifications = querySpecifications; 39 this.querySpecifications = querySpecifications;
36 this.vacuousQueries = vacuousQueries; 40 this.vacuousQueries = vacuousQueries;
37 var mutableAllQueries = new LinkedHashSet<AnyQuery>(querySpecifications.size() + vacuousQueries.size()); 41 var mutableAllQueries = new LinkedHashSet<AnyQuery>(querySpecifications.size() + vacuousQueries.size());
@@ -58,6 +62,17 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd
58 return allQueries; 62 return allQueries;
59 } 63 }
60 64
65 @Override
66 public <T> Query<T> getCanonicalQuery(Query<T> query) {
67 // We know that canonical forms of queries do not change output types.
68 @SuppressWarnings("unchecked")
69 var canonicalQuery = (Query<T>) canonicalQueryMap.get(query);
70 if (canonicalQuery == null) {
71 throw new IllegalArgumentException("Unknown query: " + query);
72 }
73 return canonicalQuery;
74 }
75
61 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() { 76 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() {
62 return querySpecifications; 77 return querySpecifications;
63 } 78 }
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 d51bc9fc..8110a98f 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
@@ -36,14 +36,12 @@ import tools.refinery.store.util.CycleDetectingMapper;
36 36
37import java.util.*; 37import java.util.*;
38import java.util.function.Function; 38import java.util.function.Function;
39import java.util.stream.Collectors;
40 39
41public class Dnf2PQuery { 40public class Dnf2PQuery {
42 private static final Object P_CONSTRAINT_LOCK = new Object(); 41 private static final Object P_CONSTRAINT_LOCK = new Object();
43 private final CycleDetectingMapper<Dnf, RawPQuery> mapper = new CycleDetectingMapper<>(Dnf::name, 42 private final CycleDetectingMapper<Dnf, RawPQuery> mapper = new CycleDetectingMapper<>(Dnf::name,
44 this::doTranslate); 43 this::doTranslate);
45 private final QueryWrapperFactory wrapperFactory = new QueryWrapperFactory(this); 44 private final QueryWrapperFactory wrapperFactory = new QueryWrapperFactory(this);
46 private final Map<Dnf, QueryEvaluationHint> hintOverrides = new LinkedHashMap<>();
47 private Function<Dnf, QueryEvaluationHint> computeHint = dnf -> new QueryEvaluationHint(null, 45 private Function<Dnf, QueryEvaluationHint> computeHint = dnf -> new QueryEvaluationHint(null,
48 (IQueryBackendFactory) null); 46 (IQueryBackendFactory) null);
49 47
@@ -59,30 +57,9 @@ public class Dnf2PQuery {
59 return wrapperFactory.getSymbolViews(); 57 return wrapperFactory.getSymbolViews();
60 } 58 }
61 59
62 public void hint(Dnf dnf, QueryEvaluationHint hint) {
63 hintOverrides.compute(dnf, (ignoredKey, existingHint) ->
64 existingHint == null ? hint : existingHint.overrideBy(hint));
65 }
66
67 private QueryEvaluationHint consumeHint(Dnf dnf) {
68 var defaultHint = computeHint.apply(dnf);
69 var existingHint = hintOverrides.remove(dnf);
70 return defaultHint.overrideBy(existingHint);
71 }
72
73 public void assertNoUnusedHints() {
74 if (hintOverrides.isEmpty()) {
75 return;
76 }
77 var unusedHints = hintOverrides.keySet().stream().map(Dnf::name).collect(Collectors.joining(", "));
78 throw new IllegalStateException(
79 "Unused query evaluation hints for %s. Hints must be set before a query is added to the engine"
80 .formatted(unusedHints));
81 }
82
83 private RawPQuery doTranslate(Dnf dnfQuery) { 60 private RawPQuery doTranslate(Dnf dnfQuery) {
84 var pQuery = new RawPQuery(dnfQuery.getUniqueName()); 61 var pQuery = new RawPQuery(dnfQuery.getUniqueName());
85 pQuery.setEvaluationHints(consumeHint(dnfQuery)); 62 pQuery.setEvaluationHints(computeHint.apply(dnfQuery));
86 63
87 Map<SymbolicParameter, PParameter> parameters = new HashMap<>(); 64 Map<SymbolicParameter, PParameter> parameters = new HashMap<>();
88 List<PParameter> parameterList = new ArrayList<>(); 65 List<PParameter> parameterList = new ArrayList<>();
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
index 6aae2ebe..3d2d5f83 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
@@ -98,6 +98,7 @@ class DiagonalQueryTest {
98 .build(); 98 .build();
99 99
100 var model = store.createEmptyModel(); 100 var model = store.createEmptyModel();
101
101 var personInterpretation = model.getInterpretation(person); 102 var personInterpretation = model.getInterpretation(person);
102 var symbolInterpretation = model.getInterpretation(symbol); 103 var symbolInterpretation = model.getInterpretation(symbol);
103 var queryEngine = model.getAdapter(ModelQueryAdapter.class); 104 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
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 be05b5e6..8ecbe11a 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
@@ -9,7 +9,9 @@ import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
9import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
10import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.query.ModelQueryAdapter; 11import tools.refinery.store.query.ModelQueryAdapter;
12import tools.refinery.store.query.dnf.Dnf;
12import tools.refinery.store.query.dnf.Query; 13import tools.refinery.store.query.dnf.Query;
14import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable; 15import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.viatra.tests.QueryEngineTest; 16import tools.refinery.store.query.viatra.tests.QueryEngineTest;
15import tools.refinery.store.query.view.AnySymbolView; 17import tools.refinery.store.query.view.AnySymbolView;
@@ -312,6 +314,53 @@ class QueryTest {
312 } 314 }
313 315
314 @QueryEngineTest 316 @QueryEngineTest
317 void patternCallInputArgumentTest(QueryEvaluationHint hint) {
318 var friendPredicate = Dnf.of("Friend", builder -> {
319 var p1 = builder.parameter("p1", ParameterDirection.IN);
320 var p2 = builder.parameter("p2", ParameterDirection.IN);
321 builder.clause(
322 personView.call(p1),
323 personView.call(p2),
324 friendMustView.call(p1, p2)
325 );
326 });
327 var predicate = Query.of("PositivePatternCall", (builder, p3, p4) -> builder.clause(
328 personView.call(p3),
329 personView.call(p4),
330 friendPredicate.call(p3, p4)
331 ));
332
333 var store = ModelStore.builder()
334 .symbols(person, friend)
335 .with(ViatraModelQueryAdapter.builder()
336 .defaultHint(hint)
337 .queries(predicate))
338 .build();
339
340 var model = store.createEmptyModel();
341 var personInterpretation = model.getInterpretation(person);
342 var friendInterpretation = model.getInterpretation(friend);
343 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
344 var predicateResultSet = queryEngine.getResultSet(predicate);
345
346 personInterpretation.put(Tuple.of(0), true);
347 personInterpretation.put(Tuple.of(1), true);
348 personInterpretation.put(Tuple.of(2), true);
349
350 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
351 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
352 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
353
354 queryEngine.flushChanges();
355 assertResults(Map.of(
356 Tuple.of(0, 1), true,
357 Tuple.of(1, 0), true,
358 Tuple.of(1, 2), true,
359 Tuple.of(2, 1), false
360 ), predicateResultSet);
361 }
362
363 @QueryEngineTest
315 void negativeRelationViewTest(QueryEvaluationHint hint) { 364 void negativeRelationViewTest(QueryEvaluationHint hint) {
316 var predicate = Query.of("NegativePatternCall", (builder, p1, p2) -> builder.clause( 365 var predicate = Query.of("NegativePatternCall", (builder, p1, p2) -> builder.clause(
317 personView.call(p1), 366 personView.call(p1),
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
index ca089a9d..5c1c4fc1 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
@@ -30,7 +30,7 @@ public final class QueryAssertions {
30 } 30 }
31 31
32 public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) { 32 public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) {
33 var defaultValue = resultSet.getQuery().defaultValue(); 33 var defaultValue = resultSet.getCanonicalQuery().defaultValue();
34 var filteredExpected = new LinkedHashMap<Tuple, T>(); 34 var filteredExpected = new LinkedHashMap<Tuple, T>();
35 var executables = new ArrayList<Executable>(); 35 var executables = new ArrayList<Executable>();
36 for (var entry : expected.entrySet()) { 36 for (var entry : expected.entrySet()) {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
index c62a95b5..332e6381 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
@@ -8,6 +8,7 @@ package tools.refinery.store.query;
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.store.query.dnf.AnyQuery;
11import tools.refinery.store.query.rewriter.DnfRewriter;
11 12
12import java.util.Collection; 13import java.util.Collection;
13import java.util.List; 14import java.util.List;
@@ -25,6 +26,8 @@ public interface ModelQueryBuilder extends ModelAdapterBuilder {
25 26
26 ModelQueryBuilder query(AnyQuery query); 27 ModelQueryBuilder query(AnyQuery query);
27 28
29 ModelQueryBuilder rewriter(DnfRewriter rewriter);
30
28 @Override 31 @Override
29 ModelQueryStoreAdapter build(ModelStore store); 32 ModelQueryStoreAdapter build(ModelStore store);
30} 33}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
index f0a950a6..8b67c5c1 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
@@ -8,6 +8,7 @@ package tools.refinery.store.query;
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.store.query.dnf.AnyQuery;
11import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.query.view.AnySymbolView; 12import tools.refinery.store.query.view.AnySymbolView;
12 13
13import java.util.Collection; 14import java.util.Collection;
@@ -17,6 +18,12 @@ public interface ModelQueryStoreAdapter extends ModelStoreAdapter {
17 18
18 Collection<AnyQuery> getQueries(); 19 Collection<AnyQuery> getQueries();
19 20
21 default AnyQuery getCanonicalQuery(AnyQuery query) {
22 return getCanonicalQuery((Query<?>) query);
23 }
24
25 <T> Query<T> getCanonicalQuery(Query<T> query);
26
20 @Override 27 @Override
21 ModelQueryAdapter createModelAdapter(Model model); 28 ModelQueryAdapter createModelAdapter(Model model);
22} 29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
index 55f748da..83fe6ccd 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
@@ -44,6 +44,9 @@ public abstract sealed class Query<T> implements AnyQuery permits FunctionalQuer
44 public abstract T defaultValue(); 44 public abstract T defaultValue();
45 45
46 public Query<T> withDnf(Dnf newDnf) { 46 public Query<T> withDnf(Dnf newDnf) {
47 if (dnf.equals(newDnf)) {
48 return this;
49 }
47 int arity = dnf.arity(); 50 int arity = dnf.arity();
48 if (newDnf.arity() != arity) { 51 if (newDnf.arity() != arity) {
49 throw new IllegalArgumentException("Arity of %s and %s do not match".formatted(dnf, newDnf)); 52 throw new IllegalArgumentException("Arity of %s and %s do not match".formatted(dnf, newDnf));
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
index a710c64d..dcfe6cc5 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
@@ -28,7 +28,7 @@ public abstract class AbstractResultSet<T> implements ResultSet<T> {
28 } 28 }
29 29
30 @Override 30 @Override
31 public Query<T> getQuery() { 31 public Query<T> getCanonicalQuery() {
32 return query; 32 return query;
33 } 33 }
34 34
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
index 02809477..5b75b103 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
@@ -11,7 +11,7 @@ import tools.refinery.store.query.dnf.AnyQuery;
11public sealed interface AnyResultSet permits ResultSet { 11public sealed interface AnyResultSet permits ResultSet {
12 ModelQueryAdapter getAdapter(); 12 ModelQueryAdapter getAdapter();
13 13
14 AnyQuery getQuery(); 14 AnyQuery getCanonicalQuery();
15 15
16 int size(); 16 int size();
17} 17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
index 2795a44b..991b1e32 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
@@ -18,7 +18,7 @@ public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) imple
18 } 18 }
19 19
20 @Override 20 @Override
21 public Query<T> getQuery() { 21 public Query<T> getCanonicalQuery() {
22 return query; 22 return query;
23 } 23 }
24 24
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
index 39006d65..df12b967 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
@@ -17,7 +17,7 @@ public class OrderedResultSet<T> implements AutoCloseable, ResultSet<T> {
17 private final ResultSet<T> resultSet; 17 private final ResultSet<T> resultSet;
18 private final OrderStatisticTree<Tuple> tree = new OrderStatisticTree<>(); 18 private final OrderStatisticTree<Tuple> tree = new OrderStatisticTree<>();
19 private final ResultSetListener<T> listener = (key, fromValue, toValue) -> { 19 private final ResultSetListener<T> listener = (key, fromValue, toValue) -> {
20 var defaultValue = getQuery().defaultValue(); 20 var defaultValue = getCanonicalQuery().defaultValue();
21 if (Objects.equals(defaultValue, toValue)) { 21 if (Objects.equals(defaultValue, toValue)) {
22 tree.remove(key); 22 tree.remove(key);
23 } else { 23 } else {
@@ -45,8 +45,8 @@ public class OrderedResultSet<T> implements AutoCloseable, ResultSet<T> {
45 } 45 }
46 46
47 @Override 47 @Override
48 public Query<T> getQuery() { 48 public Query<T> getCanonicalQuery() {
49 return resultSet.getQuery(); 49 return resultSet.getCanonicalQuery();
50 } 50 }
51 51
52 @Override 52 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
index 33d1ea95..a6e99784 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
@@ -10,7 +10,7 @@ import tools.refinery.store.query.dnf.Query;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12public non-sealed interface ResultSet<T> extends AnyResultSet { 12public non-sealed interface ResultSet<T> extends AnyResultSet {
13 Query<T> getQuery(); 13 Query<T> getCanonicalQuery();
14 14
15 T get(Tuple parameters); 15 T get(Tuple parameters);
16 16
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java
index bdd07f19..aa06a05a 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java
@@ -53,7 +53,7 @@ class ClauseInputParameterResolver {
53 } 53 }
54 boolean hasInputParameter = hasInputParameter(targetDnf); 54 boolean hasInputParameter = hasInputParameter(targetDnf);
55 if (!hasInputParameter) { 55 if (!hasInputParameter) {
56 targetDnf = rewriter.doRewrite(targetDnf); 56 targetDnf = rewriter.rewrite(targetDnf);
57 } 57 }
58 if (inlinePositiveClause(abstractCallLiteral, targetDnf)) { 58 if (inlinePositiveClause(abstractCallLiteral, targetDnf)) {
59 return; 59 return;
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java
index ddb2a069..ef0077e4 100644
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java
@@ -18,6 +18,7 @@ import tools.refinery.store.representation.Symbol;
18import java.util.List; 18import java.util.List;
19 19
20import static org.hamcrest.MatcherAssert.assertThat; 20import static org.hamcrest.MatcherAssert.assertThat;
21import static org.hamcrest.Matchers.is;
21import static tools.refinery.store.query.literal.Literals.not; 22import static tools.refinery.store.query.literal.Literals.not;
22import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; 23import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
23 24
@@ -205,4 +206,23 @@ class InputParameterResolverTest {
205 206
206 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); 207 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
207 } 208 }
209
210 @Test
211 void identityWhenNoWorkToDoTest() {
212 var dnf = Dnf.of("SubQuery", builder -> {
213 var x = builder.parameter("x", ParameterDirection.OUT);
214 builder.clause(
215 personView.call(x),
216 not(friendView.call(x, Variable.of()))
217 );
218 });
219 var query = Query.of("Actual", (builder, p1) -> builder.clause(
220 personView.call(p1),
221 not(dnf.call(p1))
222 ));
223
224 var actual = sut.rewrite(query);
225
226 assertThat(actual, is(query));
227 }
208} 228}