aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-10 23:07:11 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-10 23:07:11 +0200
commitc7a86623b1589a3bd68a84a8d54a1eadc1aacefb (patch)
tree16fb5eb3d3b1282fecedefd9c7ae519162c540da
parentfeat: integrate DSE with partial interpretation (diff)
downloadrefinery-c7a86623b1589a3bd68a84a8d54a1eadc1aacefb.tar.gz
refinery-c7a86623b1589a3bd68a84a8d54a1eadc1aacefb.tar.zst
refinery-c7a86623b1589a3bd68a84a8d54a1eadc1aacefb.zip
fix: VIATRA projection indexer error
When a projection indexer is constructed for a production node, the projection memory is only populated if changes are being propagated. The cache doesn't get populated even if changes are flushed afterwards. This not only returns invalid query results, but also a duplicate deletion exception will be thrown when the production node tries to delete a tuple from the index memory. To counteract this issue, we enable update propagation while a matcher (and its associated indexers) are being created.
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/CountPropagationTest.java11
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java91
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java4
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java9
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java3
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java51
6 files changed, 129 insertions, 40 deletions
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/CountPropagationTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/CountPropagationTest.java
index a383d043..eee2c4ae 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/CountPropagationTest.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/CountPropagationTest.java
@@ -67,15 +67,12 @@ class CountPropagationTest {
67 .put(Tuple.of(3), TruthValue.TRUE)) 67 .put(Tuple.of(3), TruthValue.TRUE))
68 .build(); 68 .build();
69 69
70 var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed); 70 var initialModel = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed);
71 var initialState = initialModel.commit();
72
73 var model = store.createModelForState(initialState);
71 var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); 74 var reasoningAdapter = model.getAdapter(ReasoningAdapter.class);
72 var propagationAdapter = model.getAdapter(PropagationAdapter.class); 75 var propagationAdapter = model.getAdapter(PropagationAdapter.class);
73 model.commit();
74
75 reasoningAdapter.split(0);
76 assertThat(propagationAdapter.propagate(), is(PropagationResult.UNCHANGED));
77 model.commit();
78
79 reasoningAdapter.split(0); 76 reasoningAdapter.split(0);
80 assertThat(propagationAdapter.propagate(), is(PropagationResult.UNCHANGED)); 77 assertThat(propagationAdapter.propagate(), is(PropagationResult.UNCHANGED));
81 } 78 }
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java
index 779e18ab..ecd5d39c 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java
@@ -122,30 +122,30 @@ class ModelGenerationTest {
122 122
123 abstract class Vertex { 123 abstract class Vertex {
124 container Region[0..1] region opposite vertices 124 container Region[0..1] region opposite vertices
125 Transition[] outgoingTransition opposite source 125 contains Transition[] outgoingTransition opposite source
126 Transition[] incomingTransition opposite target 126 Transition[] incomingTransition opposite target
127 } 127 }
128 128
129 class Transition { 129 class Transition {
130 Vertex source opposite outgoingTransition 130 container Vertex[0..1] source opposite outgoingTransition
131 Vertex target opposite incomingTransition 131 Vertex target opposite incomingTransition
132 } 132 }
133 133
134 abstract class Pseudostate extends Vertex {} 134 abstract class Pseudostate extends Vertex.
135 135
136 abstract class RegularState extends Vertex {} 136 abstract class RegularState extends Vertex.
137 137
138 class Entry extends Pseudostate {} 138 class Entry extends Pseudostate.
139 139
140 class Exit extends Pseudostate {} 140 class Exit extends Pseudostate.
141 141
142 class Choice extends Pseudostate {} 142 class Choice extends Pseudostate.
143 143
144 class FinalState extends RegularState {} 144 class FinalState extends RegularState.
145 145
146 class State extends RegularState, CompositeElement {} 146 class State extends RegularState, CompositeElement.
147 147
148 class Statechart extends CompositeElement {} 148 class Statechart extends CompositeElement.
149 149
150 // Constraints 150 // Constraints
151 151
@@ -209,7 +209,74 @@ class ModelGenerationTest {
209 error choiceHasNoIncoming(Choice c) <-> 209 error choiceHasNoIncoming(Choice c) <->
210 !target(_, c). 210 !target(_, c).
211 211
212 scope node = 50..60, Statechart = 1. 212 scope node = 50..60, Region = 5..10, Statechart = 1.
213 """);
214 assertThat(parsedProblem.errors(), empty());
215 var problem = parsedProblem.problem();
216
217 var storeBuilder = ModelStore.builder()
218 .with(ViatraModelQueryAdapter.builder())
219// .with(ModelVisualizerAdapter.builder()
220// .withOutputPath("test_output")
221// .withFormat(FileFormat.DOT)
222// .withFormat(FileFormat.SVG)
223// .saveStates()
224// .saveDesignSpace())
225 .with(PropagationAdapter.builder())
226 .with(StateCoderAdapter.builder())
227 .with(DesignSpaceExplorationAdapter.builder())
228 .with(ReasoningAdapter.builder());
229
230 var modelSeed = modelInitializer.createModel(problem, storeBuilder);
231
232 var store = storeBuilder.build();
233
234 var initialModel = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed);
235
236 var initialVersion = initialModel.commit();
237
238 var bestFirst = new BestFirstStoreManager(store, 1);
239 bestFirst.startExploration(initialVersion);
240 var resultStore = bestFirst.getSolutionStore();
241 System.out.println("states size: " + resultStore.getSolutions().size());
242
243 var model = store.createModelForState(resultStore.getSolutions().get(0).version());
244 var interpretation = model.getAdapter(ReasoningAdapter.class)
245 .getPartialInterpretation(Concreteness.CANDIDATE, ReasoningAdapter.EXISTS_SYMBOL);
246 var cursor = interpretation.getAll();
247 int max = -1;
248 var types = new LinkedHashMap<PartialRelation, Integer>();
249 var typeInterpretation = model.getInterpretation(TypeHierarchyTranslator.TYPE_SYMBOL);
250 while (cursor.move()) {
251 max = Math.max(max, cursor.getKey().get(0));
252 var type = typeInterpretation.get(cursor.getKey());
253 if (type != null) {
254 types.compute(type.candidateType(), (ignoredKey, oldValue) -> oldValue == null ? 1 : oldValue + 1);
255 }
256 }
257 System.out.println("Model size: " + (max + 1));
258 System.out.println(types);
259// initialModel.getAdapter(ModelVisualizerAdapter.class).visualize(bestFirst.getVisualizationStore());
260 }
261
262 @Test
263 void filesystemTest() {
264 var parsedProblem = parseHelper.parse("""
265 class Filesystem {
266 contains Entry root
267 }
268
269 abstract class Entry.
270
271 class Directory extends Entry {
272 contains Entry[] entries
273 }
274
275 class File extends Entry.
276
277 Filesystem(fs).
278
279 scope Filesystem += 0, Entry = 100.
213 """); 280 """);
214 assertThat(parsedProblem.errors(), empty()); 281 assertThat(parsedProblem.errors(), empty());
215 var problem = parsedProblem.problem(); 282 var problem = parsedProblem.problem();
@@ -265,7 +332,7 @@ class ModelGenerationTest {
265 var test = injector.getInstance(ModelGenerationTest.class); 332 var test = injector.getInstance(ModelGenerationTest.class);
266 try { 333 try {
267 test.statechartTest(); 334 test.statechartTest();
268 } catch (AssertionError e) { 335 } catch (Throwable e) {
269 e.printStackTrace(); 336 e.printStackTrace();
270 } 337 }
271 } 338 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
index 5df861a6..d064ff2c 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
@@ -5,10 +5,10 @@
5 */ 5 */
6package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
7 7
8import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
9import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
10import tools.refinery.store.query.term.Term; 8import tools.refinery.store.query.term.Term;
11import tools.refinery.store.query.term.Variable; 9import tools.refinery.store.query.term.Variable;
10import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
11import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
12 12
13import java.util.stream.Collectors; 13import java.util.stream.Collectors;
14 14
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java
index 9dc739f1..5577faa3 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java
@@ -5,11 +5,11 @@
5 */ 5 */
6package tools.refinery.store.query.viatra.internal.update; 6package tools.refinery.store.query.viatra.internal.update;
7 7
8import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
9import tools.refinery.store.model.Interpretation; 8import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 9import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
11import tools.refinery.store.query.view.SymbolView; 10import tools.refinery.store.query.view.SymbolView;
12import tools.refinery.store.tuple.Tuple; 11import tools.refinery.store.tuple.Tuple;
12import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
13 13
14import java.util.Arrays; 14import java.util.Arrays;
15 15
@@ -27,18 +27,19 @@ public class TupleChangingViewUpdateListener<T> extends SymbolViewUpdateListener
27 boolean fromPresent = view.filter(key, fromValue); 27 boolean fromPresent = view.filter(key, fromValue);
28 boolean toPresent = view.filter(key, toValue); 28 boolean toPresent = view.filter(key, toValue);
29 if (fromPresent) { 29 if (fromPresent) {
30 var fromArray = view.forwardMap(key, fromValue);
30 if (toPresent) { // value change 31 if (toPresent) { // value change
31 var fromArray = view.forwardMap(key, fromValue);
32 var toArray = view.forwardMap(key, toValue); 32 var toArray = view.forwardMap(key, toValue);
33 if (!Arrays.equals(fromArray, toArray)) { 33 if (!Arrays.equals(fromArray, toArray)) {
34 processUpdate(Tuples.flatTupleOf(fromArray), false); 34 processUpdate(Tuples.flatTupleOf(fromArray), false);
35 processUpdate(Tuples.flatTupleOf(toArray), true); 35 processUpdate(Tuples.flatTupleOf(toArray), true);
36 } 36 }
37 } else { // fromValue disappears 37 } else { // fromValue disappears
38 processUpdate(Tuples.flatTupleOf(view.forwardMap(key, fromValue)), false); 38 processUpdate(Tuples.flatTupleOf(fromArray), false);
39 } 39 }
40 } else if (toPresent) { // toValue appears 40 } else if (toPresent) { // toValue appears
41 processUpdate(Tuples.flatTupleOf(view.forwardMap(key, toValue)), true); 41 var toArray = view.forwardMap(key, toValue);
42 processUpdate(Tuples.flatTupleOf(toArray), true);
42 } 43 }
43 } 44 }
44} 45}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
index 4c603a47..0f402b49 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
@@ -15,6 +15,7 @@ import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
16 16
17import java.util.Set; 17import java.util.Set;
18import java.util.function.Supplier;
18import java.util.stream.Collectors; 19import java.util.stream.Collectors;
19 20
20/** 21/**
@@ -147,4 +148,6 @@ public abstract class ViatraQueryEngine {
147 public abstract QueryScope getScope(); 148 public abstract QueryScope getScope();
148 149
149 public abstract void flushChanges(); 150 public abstract void flushChanges();
151
152 public abstract <T> T withFlushingChanges(Supplier<T> supplier);
150} 153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
index 47a51629..5317a79e 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
@@ -41,6 +41,7 @@ import java.lang.ref.WeakReference;
41import java.lang.reflect.InvocationTargetException; 41import java.lang.reflect.InvocationTargetException;
42import java.util.*; 42import java.util.*;
43import java.util.concurrent.Callable; 43import java.util.concurrent.Callable;
44import java.util.function.Supplier;
44import java.util.stream.Collectors; 45import java.util.stream.Collectors;
45 46
46import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument; 47import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
@@ -164,9 +165,27 @@ public final class ViatraQueryEngineImpl extends AdvancedViatraQueryEngine
164 } 165 }
165 delayMessageDelivery = false; 166 delayMessageDelivery = false;
166 try { 167 try {
167 for (IQueryBackend backend : this.queryBackends.values()) { 168 flushAllBackends();
168 backend.flushUpdates(); 169 } finally {
169 } 170 delayMessageDelivery = true;
171 }
172 }
173
174 private void flushAllBackends() {
175 for (IQueryBackend backend : this.queryBackends.values()) {
176 backend.flushUpdates();
177 }
178 }
179
180 @Override
181 public <T> T withFlushingChanges(Supplier<T> callback) {
182 if (!delayMessageDelivery) {
183 return callback.get();
184 }
185 delayMessageDelivery = false;
186 try {
187 flushAllBackends();
188 return callback.get();
170 } finally { 189 } finally {
171 delayMessageDelivery = true; 190 delayMessageDelivery = true;
172 } 191 }
@@ -186,18 +205,20 @@ public final class ViatraQueryEngineImpl extends AdvancedViatraQueryEngine
186 @Override 205 @Override
187 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher( 206 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(
188 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalEvaluationHints) { 207 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalEvaluationHints) {
189 IMatcherCapability capability = getRequestedCapability(querySpecification, optionalEvaluationHints); 208 return withFlushingChanges(() -> {
190 Matcher matcher = doGetExistingMatcher(querySpecification, capability); 209 IMatcherCapability capability = getRequestedCapability(querySpecification, optionalEvaluationHints);
191 if (matcher != null) { 210 Matcher matcher = doGetExistingMatcher(querySpecification, capability);
192 return matcher; 211 if (matcher != null) {
193 } 212 return matcher;
194 matcher = querySpecification.instantiate(); 213 }
195 214 matcher = querySpecification.instantiate();
196 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher; 215
197 ((QueryResultWrapper) baseMatcher).setBackend(this, 216 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher;
198 getResultProvider(querySpecification, optionalEvaluationHints), capability); 217 ((QueryResultWrapper) baseMatcher).setBackend(this,
199 internalRegisterMatcher(querySpecification, baseMatcher); 218 getResultProvider(querySpecification, optionalEvaluationHints), capability);
200 return matcher; 219 internalRegisterMatcher(querySpecification, baseMatcher);
220 return matcher;
221 });
201 } 222 }
202 223
203 @Override 224 @Override