aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-11 19:22:26 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-11 19:22:26 +0200
commit4d365b54dad8d066bba2a2b1a05092b4802b9970 (patch)
tree12e5ae36b0041463ded54e7a69dcdc9f3662794f
parentfix: build failures after integrating generation (diff)
downloadrefinery-4d365b54dad8d066bba2a2b1a05092b4802b9970.tar.gz
refinery-4d365b54dad8d066bba2a2b1a05092b4802b9970.tar.zst
refinery-4d365b54dad8d066bba2a2b1a05092b4802b9970.zip
feat: cancellation token for ModelStore
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/ModelGenerationTest.java2
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/CancellableSeed.java99
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java9
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java3
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java3
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java9
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java1
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java4
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java3
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java10
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/BoundScopePropagator.java7
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectInitializer.java16
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java4
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java3
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java16
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java21
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java15
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java6
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java3
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java6
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java6
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/util/CancellationToken.java13
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java3
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java3
28 files changed, 131 insertions, 153 deletions
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 ecd5d39c..d756099c 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
@@ -209,7 +209,7 @@ 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, Region = 5..10, Statechart = 1. 212 scope node = 200..210, Region = 10..*, Choice = 1..*, Statechart = 1.
213 """); 213 """);
214 assertThat(parsedProblem.errors(), empty()); 214 assertThat(parsedProblem.errors(), empty());
215 var problem = parsedProblem.problem(); 215 var problem = parsedProblem.problem();
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/CancellableSeed.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/CancellableSeed.java
deleted file mode 100644
index aa14f39d..00000000
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/CancellableSeed.java
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics;
7
8import tools.refinery.store.map.AnyVersionedMap;
9import tools.refinery.store.map.Cursor;
10import tools.refinery.store.reasoning.representation.PartialSymbol;
11import tools.refinery.store.reasoning.seed.ModelSeed;
12import tools.refinery.store.reasoning.seed.Seed;
13import tools.refinery.store.tuple.Tuple;
14import tools.refinery.viatra.runtime.CancellationToken;
15
16import java.util.Set;
17
18class CancellableSeed<T> implements Seed<T> {
19 private final CancellationToken cancellationToken;
20 private final Seed<T> seed;
21
22 private CancellableSeed(CancellationToken cancellationToken, Seed<T> seed) {
23 this.cancellationToken = cancellationToken;
24 this.seed = seed;
25 }
26
27 @Override
28 public int arity() {
29 return seed.arity();
30 }
31
32 @Override
33 public Class<T> valueType() {
34 return seed.valueType();
35 }
36
37 @Override
38 public T reducedValue() {
39 return seed.reducedValue();
40 }
41
42 @Override
43 public T get(Tuple key) {
44 return seed.get(key);
45 }
46
47 @Override
48 public Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount) {
49 return new CancellableCursor<>(cancellationToken, seed.getCursor(defaultValue, nodeCount));
50 }
51
52 public static ModelSeed wrap(CancellationToken cancellationToken, ModelSeed modelSeed) {
53 var builder = ModelSeed.builder(modelSeed.getNodeCount());
54 for (var partialSymbol : modelSeed.getSeededSymbols()) {
55 wrap(cancellationToken, (PartialSymbol<?, ?>) partialSymbol, modelSeed, builder);
56 }
57 return builder.build();
58 }
59
60 private static <A, C> void wrap(CancellationToken cancellationToken, PartialSymbol<A, C> partialSymbol,
61 ModelSeed originalModelSeed, ModelSeed.Builder builder) {
62 var originalSeed = originalModelSeed.getSeed(partialSymbol);
63 builder.seed(partialSymbol, new CancellableSeed<>(cancellationToken, originalSeed));
64 }
65
66 private record CancellableCursor<T>(CancellationToken cancellationToken, Cursor<Tuple, T> cursor)
67 implements Cursor<Tuple, T> {
68 @Override
69 public Tuple getKey() {
70 return cursor.getKey();
71 }
72
73 @Override
74 public T getValue() {
75 return cursor.getValue();
76 }
77
78 @Override
79 public boolean isTerminated() {
80 return cursor.isTerminated();
81 }
82
83 @Override
84 public boolean move() {
85 cancellationToken.checkCancelled();
86 return cursor.move();
87 }
88
89 @Override
90 public boolean isDirty() {
91 return cursor.isDirty();
92 }
93
94 @Override
95 public Set<AnyVersionedMap> getDependingMaps() {
96 return cursor.getDependingMaps();
97 }
98 }
99}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
index c745d86e..33b1c4fb 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
@@ -34,7 +34,7 @@ import tools.refinery.store.reasoning.representation.PartialRelation;
34import tools.refinery.store.reasoning.translator.TranslationException; 34import tools.refinery.store.reasoning.translator.TranslationException;
35import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; 35import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
36import tools.refinery.store.tuple.Tuple; 36import tools.refinery.store.tuple.Tuple;
37import tools.refinery.viatra.runtime.CancellationToken; 37import tools.refinery.store.util.CancellationToken;
38 38
39import java.util.ArrayList; 39import java.util.ArrayList;
40import java.util.TreeMap; 40import java.util.TreeMap;
@@ -74,8 +74,8 @@ class SemanticsWorker implements Callable<SemanticsResult> {
74 @Override 74 @Override
75 public SemanticsResult call() { 75 public SemanticsResult call() {
76 var builder = ModelStore.builder() 76 var builder = ModelStore.builder()
77 .with(ViatraModelQueryAdapter.builder() 77 .cancellationToken(cancellationToken)
78 .cancellationToken(cancellationToken)) 78 .with(ViatraModelQueryAdapter.builder())
79 .with(PropagationAdapter.builder()) 79 .with(PropagationAdapter.builder())
80 .with(ReasoningAdapter.builder() 80 .with(ReasoningAdapter.builder()
81 .requiredInterpretations(Concreteness.PARTIAL)); 81 .requiredInterpretations(Concreteness.PARTIAL));
@@ -91,8 +91,7 @@ class SemanticsWorker implements Callable<SemanticsResult> {
91 cancellationToken.checkCancelled(); 91 cancellationToken.checkCancelled();
92 var store = builder.build(); 92 var store = builder.build();
93 cancellationToken.checkCancelled(); 93 cancellationToken.checkCancelled();
94 var cancellableModelSeed = CancellableSeed.wrap(cancellationToken, modelSeed); 94 var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(modelSeed);
95 var model = store.getAdapter(ReasoningStoreAdapter.class).createInitialModel(cancellableModelSeed);
96 cancellationToken.checkCancelled(); 95 cancellationToken.checkCancelled();
97 var partialInterpretation = getPartialInterpretation(initializer, model); 96 var partialInterpretation = getPartialInterpretation(initializer, model);
98 97
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
index 586a8d7a..fdd19217 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
@@ -31,6 +31,7 @@ class PropagationAdapterImpl implements PropagationAdapter {
31 PropagationResult result = PropagationResult.UNCHANGED; 31 PropagationResult result = PropagationResult.UNCHANGED;
32 PropagationResult lastResult; 32 PropagationResult lastResult;
33 do { 33 do {
34 model.checkCancelled();
34 lastResult = propagateOne(); 35 lastResult = propagateOne();
35 result = result.andThen(lastResult); 36 result = result.andThen(lastResult);
36 } while (lastResult.isChanged()); 37 } while (lastResult.isChanged());
@@ -40,6 +41,7 @@ class PropagationAdapterImpl implements PropagationAdapter {
40 private PropagationResult propagateOne() { 41 private PropagationResult propagateOne() {
41 PropagationResult result = PropagationResult.UNCHANGED; 42 PropagationResult result = PropagationResult.UNCHANGED;
42 for (int i = 0; i < boundPropagators.length; i++) { 43 for (int i = 0; i < boundPropagators.length; i++) {
44 model.checkCancelled();
43 var lastResult = propagateUntilFixedPoint(i); 45 var lastResult = propagateUntilFixedPoint(i);
44 result = result.andThen(lastResult); 46 result = result.andThen(lastResult);
45 if (result.isRejected()) { 47 if (result.isRejected()) {
@@ -54,6 +56,7 @@ class PropagationAdapterImpl implements PropagationAdapter {
54 PropagationResult result = PropagationResult.UNCHANGED; 56 PropagationResult result = PropagationResult.UNCHANGED;
55 PropagationResult lastResult; 57 PropagationResult lastResult;
56 do { 58 do {
59 model.checkCancelled();
57 lastResult = propagator.propagateOne(); 60 lastResult = propagator.propagateOne();
58 result = result.andThen(lastResult); 61 result = result.andThen(lastResult);
59 } while (lastResult.isChanged()); 62 } while (lastResult.isChanged());
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java
index 6e6a78d2..a70292ad 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java
@@ -13,10 +13,12 @@ import tools.refinery.store.query.ModelQueryAdapter;
13import tools.refinery.store.query.resultset.ResultSet; 13import tools.refinery.store.query.resultset.ResultSet;
14 14
15class BoundPropagationRule { 15class BoundPropagationRule {
16 private final Model model;
16 private final ResultSet<Boolean> resultSet; 17 private final ResultSet<Boolean> resultSet;
17 private final BoundAction action; 18 private final BoundAction action;
18 19
19 public BoundPropagationRule(Model model, Rule rule) { 20 public BoundPropagationRule(Model model, Rule rule) {
21 this.model = model;
20 resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(rule.getPrecondition()); 22 resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(rule.getPrecondition());
21 action = rule.createAction(model); 23 action = rule.createAction(model);
22 } 24 }
@@ -27,6 +29,7 @@ class BoundPropagationRule {
27 } 29 }
28 var cursor = resultSet.getAll(); 30 var cursor = resultSet.getAll();
29 while (cursor.move()) { 31 while (cursor.move()) {
32 model.checkCancelled();
30 var result = action.fire(cursor.getKey()); 33 var result = action.fire(cursor.getKey());
31 if (!result) { 34 if (!result) {
32 return PropagationResult.REJECTED; 35 return PropagationResult.REJECTED;
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
index 4a75a3a6..5e2f8fa9 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
@@ -19,14 +19,9 @@ public class BestFirstExplorer extends BestFirstWorker {
19 this.random = new Random(id); 19 this.random = new Random(id);
20 } 20 }
21 21
22 private boolean interrupted = false;
23
24 public void interrupt() {
25 this.interrupted = true;
26 }
27
28 private boolean shouldRun() { 22 private boolean shouldRun() {
29 return !interrupted && !hasEnoughSolution(); 23 model.checkCancelled();
24 return !hasEnoughSolution();
30 } 25 }
31 26
32 public void explore() { 27 public void explore() {
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java
index ed2ff33d..4da609fa 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java
@@ -23,6 +23,7 @@ public class BoundAction {
23 } 23 }
24 24
25 public boolean fire(Tuple activation) { 25 public boolean fire(Tuple activation) {
26 model.checkCancelled();
26 if (this.activation != null) { 27 if (this.activation != null) {
27 throw new IllegalStateException("Reentrant firing is not allowed"); 28 throw new IllegalStateException("Reentrant firing is not allowed");
28 } 29 }
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java
index e1a29d40..23325a1f 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java
@@ -56,6 +56,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
56 @Override 56 @Override
57 public boolean checkAccept() { 57 public boolean checkAccept() {
58 for (var accept : this.accepts) { 58 for (var accept : this.accepts) {
59 model.checkCancelled();
59 if (!accept.isSatisfied()) { 60 if (!accept.isSatisfied()) {
60 return false; 61 return false;
61 } 62 }
@@ -66,6 +67,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
66 @Override 67 @Override
67 public boolean checkExclude() { 68 public boolean checkExclude() {
68 for (var exclude : this.excludes) { 69 for (var exclude : this.excludes) {
70 model.checkCancelled();
69 if (exclude.isSatisfied()) { 71 if (exclude.isSatisfied()) {
70 return true; 72 return true;
71 } 73 }
@@ -75,6 +77,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
75 77
76 @Override 78 @Override
77 public ObjectiveValue getObjectiveValue() { 79 public ObjectiveValue getObjectiveValue() {
80 model.checkCancelled();
78 if (objectives.size() == 1) { 81 if (objectives.size() == 1) {
79 return ObjectiveValue.of(objectives.get(0).getValue()); 82 return ObjectiveValue.of(objectives.get(0).getValue());
80 } else if (objectives.size() == 2) { 83 } else if (objectives.size() == 2) {
@@ -82,6 +85,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration
82 } else { 85 } else {
83 double[] res = new double[objectives.size()]; 86 double[] res = new double[objectives.size()];
84 for (int i = 0; i < objectives.size(); i++) { 87 for (int i = 0; i < objectives.size(); i++) {
88 model.checkCancelled();
85 res[i] = objectives.get(i).getValue(); 89 res[i] = objectives.get(i).getValue();
86 } 90 }
87 return ObjectiveValue.of(res); 91 return ObjectiveValue.of(res);
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 6b3be115..d19c3bb4 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
@@ -10,7 +10,6 @@ import tools.refinery.store.query.ModelQueryBuilder;
10import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.store.query.dnf.AnyQuery;
11import tools.refinery.store.query.dnf.Dnf; 11import tools.refinery.store.query.dnf.Dnf;
12import tools.refinery.store.query.rewriter.DnfRewriter; 12import tools.refinery.store.query.rewriter.DnfRewriter;
13import tools.refinery.viatra.runtime.CancellationToken;
14import tools.refinery.viatra.runtime.api.ViatraQueryEngineOptions; 13import tools.refinery.viatra.runtime.api.ViatraQueryEngineOptions;
15import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory; 14import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
16import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint; 15import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
@@ -30,8 +29,6 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder {
30 29
31 ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory); 30 ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory);
32 31
33 ViatraModelQueryBuilder cancellationToken(CancellationToken cancellationToken);
34
35 @Override 32 @Override
36 default ViatraModelQueryBuilder queries(AnyQuery... queries) { 33 default ViatraModelQueryBuilder queries(AnyQuery... queries) {
37 ModelQueryBuilder.super.queries(queries); 34 ModelQueryBuilder.super.queries(queries);
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 bb0630f3..c68152e3 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
@@ -17,7 +17,6 @@ import tools.refinery.store.query.viatra.ViatraModelQueryBuilder;
17import tools.refinery.store.query.viatra.internal.localsearch.FlatCostFunction; 17import tools.refinery.store.query.viatra.internal.localsearch.FlatCostFunction;
18import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; 18import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher;
19import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; 19import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery;
20import tools.refinery.viatra.runtime.CancellationToken;
21import tools.refinery.viatra.runtime.api.IQuerySpecification; 20import tools.refinery.viatra.runtime.api.IQuerySpecification;
22import tools.refinery.viatra.runtime.api.ViatraQueryEngineOptions; 21import tools.refinery.viatra.runtime.api.ViatraQueryEngineOptions;
23import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory; 22import tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory;
@@ -36,7 +35,6 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<Via
36 // 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.
37 LocalSearchHintOptions.PLANNER_COST_FUNCTION, new FlatCostFunction() 36 LocalSearchHintOptions.PLANNER_COST_FUNCTION, new FlatCostFunction()
38 ), (IQueryBackendFactory) null); 37 ), (IQueryBackendFactory) null);
39 private CancellationToken cancellationToken = CancellationToken.NONE;
40 private final CompositeRewriter rewriter; 38 private final CompositeRewriter rewriter;
41 private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); 39 private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery();
42 private final Set<AnyQuery> queries = new LinkedHashSet<>(); 40 private final Set<AnyQuery> queries = new LinkedHashSet<>();
@@ -87,12 +85,6 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<Via
87 } 85 }
88 86
89 @Override 87 @Override
90 public ViatraModelQueryBuilder cancellationToken(CancellationToken cancellationToken) {
91 this.cancellationToken = cancellationToken;
92 return this;
93 }
94
95 @Override
96 public ViatraModelQueryBuilder queries(Collection<? extends AnyQuery> queries) { 88 public ViatraModelQueryBuilder queries(Collection<? extends AnyQuery> queries) {
97 checkNotConfigured(); 89 checkNotConfigured();
98 this.queries.addAll(queries); 90 this.queries.addAll(queries);
@@ -144,7 +136,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<Via
144 validateSymbols(store); 136 validateSymbols(store);
145 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(), 137 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(),
146 Collections.unmodifiableMap(canonicalQueryMap), Collections.unmodifiableMap(querySpecifications), 138 Collections.unmodifiableMap(canonicalQueryMap), Collections.unmodifiableMap(querySpecifications),
147 Collections.unmodifiableSet(vacuousQueries), cancellationToken); 139 Collections.unmodifiableSet(vacuousQueries), store::checkCancelled);
148 } 140 }
149 141
150 private ViatraQueryEngineOptions buildEngineOptions() { 142 private ViatraQueryEngineOptions buildEngineOptions() {
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/BoundScopePropagator.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/BoundScopePropagator.java
index 62aadb4a..3ae4d84b 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/BoundScopePropagator.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/BoundScopePropagator.java
@@ -22,6 +22,7 @@ import tools.refinery.store.representation.cardinality.*;
22import tools.refinery.store.tuple.Tuple; 22import tools.refinery.store.tuple.Tuple;
23 23
24class BoundScopePropagator implements BoundPropagator { 24class BoundScopePropagator implements BoundPropagator {
25 private final Model model;
25 private final ModelQueryAdapter queryEngine; 26 private final ModelQueryAdapter queryEngine;
26 private final Interpretation<CardinalityInterval> countInterpretation; 27 private final Interpretation<CardinalityInterval> countInterpretation;
27 private final MPSolver solver; 28 private final MPSolver solver;
@@ -32,6 +33,7 @@ class BoundScopePropagator implements BoundPropagator {
32 private boolean changed = true; 33 private boolean changed = true;
33 34
34 public BoundScopePropagator(Model model, ScopePropagator storeAdapter) { 35 public BoundScopePropagator(Model model, ScopePropagator storeAdapter) {
36 this.model = model;
35 queryEngine = model.getAdapter(ModelQueryAdapter.class); 37 queryEngine = model.getAdapter(ModelQueryAdapter.class);
36 countInterpretation = model.getInterpretation(storeAdapter.getCountSymbol()); 38 countInterpretation = model.getInterpretation(storeAdapter.getCountSymbol());
37 solver = MPSolver.createSolver("GLOP"); 39 solver = MPSolver.createSolver("GLOP");
@@ -41,6 +43,7 @@ class BoundScopePropagator implements BoundPropagator {
41 var propagatorFactories = storeAdapter.getTypeScopePropagatorFactories(); 43 var propagatorFactories = storeAdapter.getTypeScopePropagatorFactories();
42 propagators = new TypeScopePropagator[propagatorFactories.size()]; 44 propagators = new TypeScopePropagator[propagatorFactories.size()];
43 for (int i = 0; i < propagators.length; i++) { 45 for (int i = 0; i < propagators.length; i++) {
46 model.checkCancelled();
44 propagators[i] = propagatorFactories.get(i).createPropagator(this); 47 propagators[i] = propagatorFactories.get(i).createPropagator(this);
45 } 48 }
46 } 49 }
@@ -145,6 +148,7 @@ class BoundScopePropagator implements BoundPropagator {
145 } 148 }
146 changed = false; 149 changed = false;
147 for (var propagator : propagators) { 150 for (var propagator : propagators) {
151 model.checkCancelled();
148 propagator.updateBounds(); 152 propagator.updateBounds();
149 } 153 }
150 var result = PropagationResult.UNCHANGED; 154 var result = PropagationResult.UNCHANGED;
@@ -167,6 +171,7 @@ class BoundScopePropagator implements BoundPropagator {
167 } 171 }
168 172
169 private PropagationResult checkEmptiness() { 173 private PropagationResult checkEmptiness() {
174 model.checkCancelled();
170 var emptinessCheckingResult = solver.solve(); 175 var emptinessCheckingResult = solver.solve();
171 return switch (emptinessCheckingResult) { 176 return switch (emptinessCheckingResult) {
172 case OPTIMAL, UNBOUNDED -> PropagationResult.UNCHANGED; 177 case OPTIMAL, UNBOUNDED -> PropagationResult.UNCHANGED;
@@ -178,6 +183,7 @@ class BoundScopePropagator implements BoundPropagator {
178 private PropagationResult propagateNode(int nodeId, MPVariable variable) { 183 private PropagationResult propagateNode(int nodeId, MPVariable variable) {
179 objective.setCoefficient(variable, 1); 184 objective.setCoefficient(variable, 1);
180 try { 185 try {
186 model.checkCancelled();
181 objective.setMinimization(); 187 objective.setMinimization();
182 var minimizationResult = solver.solve(); 188 var minimizationResult = solver.solve();
183 int lowerBound; 189 int lowerBound;
@@ -191,6 +197,7 @@ class BoundScopePropagator implements BoundPropagator {
191 .formatted(variable, minimizationResult)); 197 .formatted(variable, minimizationResult));
192 } 198 }
193 199
200 model.checkCancelled();
194 objective.setMaximization(); 201 objective.setMaximization();
195 var maximizationResult = solver.solve(); 202 var maximizationResult = solver.solve();
196 UpperCardinality upperBound; 203 UpperCardinality upperBound;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectInitializer.java
index f11ab46b..89918155 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectInitializer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectInitializer.java
@@ -30,9 +30,9 @@ class MultiObjectInitializer implements PartialModelInitializer {
30 30
31 @Override 31 @Override
32 public void initialize(Model model, ModelSeed modelSeed) { 32 public void initialize(Model model, ModelSeed modelSeed) {
33 var intervals = initializeIntervals(modelSeed); 33 var intervals = initializeIntervals(model, modelSeed);
34 initializeExists(intervals, modelSeed); 34 initializeExists(intervals, model, modelSeed);
35 initializeEquals(intervals, modelSeed); 35 initializeEquals(intervals, model, modelSeed);
36 var countInterpretation = model.getInterpretation(countSymbol); 36 var countInterpretation = model.getInterpretation(countSymbol);
37 var uniqueTable = new HashMap<CardinalityInterval, CardinalityInterval>(); 37 var uniqueTable = new HashMap<CardinalityInterval, CardinalityInterval>();
38 for (int i = 0; i < intervals.length; i++) { 38 for (int i = 0; i < intervals.length; i++) {
@@ -47,12 +47,13 @@ class MultiObjectInitializer implements PartialModelInitializer {
47 } 47 }
48 48
49 @NotNull 49 @NotNull
50 private CardinalityInterval[] initializeIntervals(ModelSeed modelSeed) { 50 private CardinalityInterval[] initializeIntervals(Model model, ModelSeed modelSeed) {
51 var intervals = new CardinalityInterval[modelSeed.getNodeCount()]; 51 var intervals = new CardinalityInterval[modelSeed.getNodeCount()];
52 if (modelSeed.containsSeed(MultiObjectTranslator.COUNT_SYMBOL)) { 52 if (modelSeed.containsSeed(MultiObjectTranslator.COUNT_SYMBOL)) {
53 Arrays.fill(intervals, CardinalityIntervals.ONE); 53 Arrays.fill(intervals, CardinalityIntervals.ONE);
54 var cursor = modelSeed.getCursor(MultiObjectTranslator.COUNT_SYMBOL, CardinalityIntervals.ONE); 54 var cursor = modelSeed.getCursor(MultiObjectTranslator.COUNT_SYMBOL, CardinalityIntervals.ONE);
55 while (cursor.move()) { 55 while (cursor.move()) {
56 model.checkCancelled();
56 int i = cursor.getKey().get(0); 57 int i = cursor.getKey().get(0);
57 checkNodeId(intervals, i); 58 checkNodeId(intervals, i);
58 intervals[i] = cursor.getValue(); 59 intervals[i] = cursor.getValue();
@@ -70,12 +71,13 @@ class MultiObjectInitializer implements PartialModelInitializer {
70 return intervals; 71 return intervals;
71 } 72 }
72 73
73 private void initializeExists(CardinalityInterval[] intervals, ModelSeed modelSeed) { 74 private void initializeExists(CardinalityInterval[] intervals, Model model, ModelSeed modelSeed) {
74 if (!modelSeed.containsSeed(ReasoningAdapter.EXISTS_SYMBOL)) { 75 if (!modelSeed.containsSeed(ReasoningAdapter.EXISTS_SYMBOL)) {
75 return; 76 return;
76 } 77 }
77 var cursor = modelSeed.getCursor(ReasoningAdapter.EXISTS_SYMBOL, TruthValue.UNKNOWN); 78 var cursor = modelSeed.getCursor(ReasoningAdapter.EXISTS_SYMBOL, TruthValue.UNKNOWN);
78 while (cursor.move()) { 79 while (cursor.move()) {
80 model.checkCancelled();
79 int i = cursor.getKey().get(0); 81 int i = cursor.getKey().get(0);
80 checkNodeId(intervals, i); 82 checkNodeId(intervals, i);
81 switch (cursor.getValue()) { 83 switch (cursor.getValue()) {
@@ -89,13 +91,14 @@ class MultiObjectInitializer implements PartialModelInitializer {
89 } 91 }
90 } 92 }
91 93
92 private void initializeEquals(CardinalityInterval[] intervals, ModelSeed modelSeed) { 94 private void initializeEquals(CardinalityInterval[] intervals, Model model, ModelSeed modelSeed) {
93 if (!modelSeed.containsSeed(ReasoningAdapter.EQUALS_SYMBOL)) { 95 if (!modelSeed.containsSeed(ReasoningAdapter.EQUALS_SYMBOL)) {
94 return; 96 return;
95 } 97 }
96 var seed = modelSeed.getSeed(ReasoningAdapter.EQUALS_SYMBOL); 98 var seed = modelSeed.getSeed(ReasoningAdapter.EQUALS_SYMBOL);
97 var cursor = seed.getCursor(TruthValue.FALSE, modelSeed.getNodeCount()); 99 var cursor = seed.getCursor(TruthValue.FALSE, modelSeed.getNodeCount());
98 while (cursor.move()) { 100 while (cursor.move()) {
101 model.checkCancelled();
99 var key = cursor.getKey(); 102 var key = cursor.getKey();
100 int i = key.get(0); 103 int i = key.get(0);
101 int otherIndex = key.get(1); 104 int otherIndex = key.get(1);
@@ -116,6 +119,7 @@ class MultiObjectInitializer implements PartialModelInitializer {
116 } 119 }
117 } 120 }
118 for (int i = 0; i < intervals.length; i++) { 121 for (int i = 0; i < intervals.length; i++) {
122 model.checkCancelled();
119 if (seed.get(Tuple.of(i, i)) == TruthValue.FALSE) { 123 if (seed.get(Tuple.of(i, i)) == TruthValue.FALSE) {
120 throw new TranslationException(ReasoningAdapter.EQUALS_SYMBOL, "Inconsistent equality for node " + i); 124 throw new TranslationException(ReasoningAdapter.EQUALS_SYMBOL, "Inconsistent equality for node " + i);
121 } 125 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java
index c74f1e78..233e43f0 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java
@@ -31,20 +31,23 @@ public class TypeHierarchyInitializer implements PartialModelInitializer {
31 var inferredTypes = new InferredType[modelSeed.getNodeCount()]; 31 var inferredTypes = new InferredType[modelSeed.getNodeCount()];
32 Arrays.fill(inferredTypes, typeHierarchy.getUnknownType()); 32 Arrays.fill(inferredTypes, typeHierarchy.getUnknownType());
33 for (var type : typeHierarchy.getAllTypes()) { 33 for (var type : typeHierarchy.getAllTypes()) {
34 initializeType(type, inferredTypes, modelSeed); 34 model.checkCancelled();
35 initializeType(type, inferredTypes, model, modelSeed);
35 } 36 }
36 var typeInterpretation = model.getInterpretation(typeSymbol); 37 var typeInterpretation = model.getInterpretation(typeSymbol);
37 var uniqueTable = new HashMap<InferredType, InferredType>(); 38 var uniqueTable = new HashMap<InferredType, InferredType>();
38 for (int i = 0; i < inferredTypes.length; i++) { 39 for (int i = 0; i < inferredTypes.length; i++) {
40 model.checkCancelled();
39 var uniqueType = uniqueTable.computeIfAbsent(inferredTypes[i], Function.identity()); 41 var uniqueType = uniqueTable.computeIfAbsent(inferredTypes[i], Function.identity());
40 typeInterpretation.put(Tuple.of(i), uniqueType); 42 typeInterpretation.put(Tuple.of(i), uniqueType);
41 } 43 }
42 } 44 }
43 45
44 private void initializeType(PartialRelation type, InferredType[] inferredTypes, ModelSeed modelSeed) { 46 private void initializeType(PartialRelation type, InferredType[] inferredTypes, Model model, ModelSeed modelSeed) {
45 var cursor = modelSeed.getCursor(type, TruthValue.UNKNOWN); 47 var cursor = modelSeed.getCursor(type, TruthValue.UNKNOWN);
46 var analysisResult = typeHierarchy.getAnalysisResult(type); 48 var analysisResult = typeHierarchy.getAnalysisResult(type);
47 while (cursor.move()) { 49 while (cursor.move()) {
50 model.checkCancelled();
48 var i = cursor.getKey().get(0); 51 var i = cursor.getKey().get(0);
49 checkNodeId(inferredTypes, i); 52 checkNodeId(inferredTypes, i);
50 var value = cursor.getValue(); 53 var value = cursor.getValue();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
index e2ab72e7..c4ce5207 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
@@ -8,11 +8,9 @@ package tools.refinery.store.model;
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.map.Version; 9import tools.refinery.store.map.Version;
10import tools.refinery.store.map.Versioned; 10import tools.refinery.store.map.Versioned;
11import tools.refinery.store.model.internal.VersionedInterpretation;
12import tools.refinery.store.representation.AnySymbol; 11import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
14 13
15import java.util.Map;
16import java.util.Optional; 14import java.util.Optional;
17 15
18public interface Model extends Versioned { 16public interface Model extends Versioned {
@@ -38,4 +36,6 @@ public interface Model extends Versioned {
38 void addListener(ModelListener listener); 36 void addListener(ModelListener listener);
39 37
40 void removeListener(ModelListener listener); 38 void removeListener(ModelListener listener);
39
40 void checkCancelled();
41} 41}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
index 89382b3a..61abf126 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
@@ -26,6 +26,8 @@ public interface ModelStore {
26 26
27 <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType); 27 <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType);
28 28
29 void checkCancelled();
30
29 static ModelStoreBuilder builder() { 31 static ModelStoreBuilder builder() {
30 return new ModelStoreBuilderImpl(); 32 return new ModelStoreBuilderImpl();
31 } 33 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
index 8f652762..9b2b38c3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
@@ -8,12 +8,15 @@ package tools.refinery.store.model;
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.representation.AnySymbol; 9import tools.refinery.store.representation.AnySymbol;
10import tools.refinery.store.representation.Symbol; 10import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.util.CancellationToken;
11 12
12import java.util.Collection; 13import java.util.Collection;
13import java.util.List; 14import java.util.List;
14import java.util.Optional; 15import java.util.Optional;
15 16
16public interface ModelStoreBuilder { 17public interface ModelStoreBuilder {
18 ModelStoreBuilder cancellationToken(CancellationToken cancellationToken);
19
17 default ModelStoreBuilder symbols(AnySymbol... symbols) { 20 default ModelStoreBuilder symbols(AnySymbol... symbols) {
18 return symbols(List.of(symbols)); 21 return symbols(List.of(symbols));
19 } 22 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
index 2b12d5a6..d11e431b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
@@ -13,23 +13,26 @@ import tools.refinery.store.model.*;
13import tools.refinery.store.representation.AnySymbol; 13import tools.refinery.store.representation.AnySymbol;
14import tools.refinery.store.representation.Symbol; 14import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.tuple.Tuple; 15import tools.refinery.store.tuple.Tuple;
16import tools.refinery.store.util.CancellationToken;
16 17
17import java.util.*; 18import java.util.*;
18 19
19public class ModelImpl implements Model { 20public class ModelImpl implements Model {
20 private final ModelStore store; 21 private final ModelStoreImpl store;
21 private Version state; 22 private Version state;
22 private LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations; 23 private LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
23 private final List<ModelAdapter> adapters; 24 private final List<ModelAdapter> adapters;
24 private final List<ModelListener> listeners = new ArrayList<>(); 25 private final List<ModelListener> listeners = new ArrayList<>();
26 private final CancellationToken cancellationToken;
25 private boolean uncommittedChanges; 27 private boolean uncommittedChanges;
26 private ModelAction pendingAction = ModelAction.NONE; 28 private ModelAction pendingAction = ModelAction.NONE;
27 private Version restoringToState = null; 29 private Version restoringToState = null;
28 30
29 ModelImpl(ModelStore store, Version state, int adapterCount) { 31 ModelImpl(ModelStoreImpl store, Version state, int adapterCount) {
30 this.store = store; 32 this.store = store;
31 this.state = state; 33 this.state = state;
32 adapters = new ArrayList<>(adapterCount); 34 adapters = new ArrayList<>(adapterCount);
35 cancellationToken = store.getCancellationToken();
33 } 36 }
34 37
35 void setInterpretations(LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) { 38 void setInterpretations(LinkedHashMap<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
@@ -88,6 +91,7 @@ public class ModelImpl implements Model {
88 91
89 @Override 92 @Override
90 public Version commit() { 93 public Version commit() {
94 checkCancelled();
91 if (hasPendingAction()) { 95 if (hasPendingAction()) {
92 throw pendingActionError("commit"); 96 throw pendingActionError("commit");
93 } 97 }
@@ -106,6 +110,7 @@ public class ModelImpl implements Model {
106 Version[] interpretationVersions = new Version[interpretations.size()]; 110 Version[] interpretationVersions = new Version[interpretations.size()];
107 int j = 0; 111 int j = 0;
108 for (var interpretationEntry : interpretations.entrySet()) { 112 for (var interpretationEntry : interpretations.entrySet()) {
113 checkCancelled();
109 interpretationVersions[j++] = interpretationEntry.getValue().commit(); 114 interpretationVersions[j++] = interpretationEntry.getValue().commit();
110 } 115 }
111 ModelVersion modelVersion = new ModelVersion(interpretationVersions); 116 ModelVersion modelVersion = new ModelVersion(interpretationVersions);
@@ -125,6 +130,7 @@ public class ModelImpl implements Model {
125 130
126 @Override 131 @Override
127 public void restore(Version version) { 132 public void restore(Version version) {
133 checkCancelled();
128 if (hasPendingAction()) { 134 if (hasPendingAction()) {
129 throw pendingActionError("restore to %s".formatted(version)); 135 throw pendingActionError("restore to %s".formatted(version));
130 } 136 }
@@ -140,6 +146,7 @@ public class ModelImpl implements Model {
140 } 146 }
141 int j = 0; 147 int j = 0;
142 for (var interpretation : interpretations.values()) { 148 for (var interpretation : interpretations.values()) {
149 checkCancelled();
143 interpretation.restore(ModelVersion.getInternalVersion(version, j++)); 150 interpretation.restore(ModelVersion.getInternalVersion(version, j++));
144 } 151 }
145 152
@@ -187,4 +194,9 @@ public class ModelImpl implements Model {
187 public void removeListener(ModelListener listener) { 194 public void removeListener(ModelListener listener) {
188 listeners.remove(listener); 195 listeners.remove(listener);
189 } 196 }
197
198 @Override
199 public void checkCancelled() {
200 cancellationToken.checkCancelled();
201 }
190} 202}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
index 2dde7a4c..53ecde5e 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -16,15 +16,29 @@ import tools.refinery.store.model.ModelStoreConfiguration;
16import tools.refinery.store.representation.AnySymbol; 16import tools.refinery.store.representation.AnySymbol;
17import tools.refinery.store.representation.Symbol; 17import tools.refinery.store.representation.Symbol;
18import tools.refinery.store.tuple.Tuple; 18import tools.refinery.store.tuple.Tuple;
19import tools.refinery.store.util.CancellationToken;
19 20
20import java.util.*; 21import java.util.*;
21 22
22public class ModelStoreBuilderImpl implements ModelStoreBuilder { 23public class ModelStoreBuilderImpl implements ModelStoreBuilder {
24 private CancellationToken cancellationToken;
23 private final LinkedHashSet<AnySymbol> allSymbols = new LinkedHashSet<>(); 25 private final LinkedHashSet<AnySymbol> allSymbols = new LinkedHashSet<>();
24 private final LinkedHashMap<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new LinkedHashMap<>(); 26 private final LinkedHashMap<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new LinkedHashMap<>();
25 private final List<ModelAdapterBuilder> adapters = new ArrayList<>(); 27 private final List<ModelAdapterBuilder> adapters = new ArrayList<>();
26 28
27 @Override 29 @Override
30 public ModelStoreBuilder cancellationToken(CancellationToken cancellationToken) {
31 if (this.cancellationToken != null) {
32 throw new IllegalStateException("Cancellation token was already set");
33 }
34 if (cancellationToken == null) {
35 throw new IllegalStateException("Cancellation token must not be null");
36 }
37 this.cancellationToken = cancellationToken;
38 return this;
39 }
40
41 @Override
28 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) { 42 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) {
29 if (!allSymbols.add(symbol)) { 43 if (!allSymbols.add(symbol)) {
30 // No need to add symbol twice. 44 // No need to add symbol twice.
@@ -75,7 +89,8 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
75 for (var entry : equivalenceClasses.entrySet()) { 89 for (var entry : equivalenceClasses.entrySet()) {
76 createStores(stores, entry.getKey(), entry.getValue()); 90 createStores(stores, entry.getKey(), entry.getValue());
77 } 91 }
78 var modelStore = new ModelStoreImpl(stores, adapters.size()); 92 var modelStore = new ModelStoreImpl(stores, adapters.size(), cancellationToken == null ?
93 CancellationToken.NONE : cancellationToken);
79 for (var adapterBuilder : adapters) { 94 for (var adapterBuilder : adapters) {
80 var storeAdapter = adapterBuilder.build(modelStore); 95 var storeAdapter = adapterBuilder.build(modelStore);
81 modelStore.addAdapter(storeAdapter); 96 modelStore.addAdapter(storeAdapter);
@@ -86,8 +101,8 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
86 private <T> void createStores(Map<AnySymbol, VersionedMapStore<Tuple, ?>> stores, 101 private <T> void createStores(Map<AnySymbol, VersionedMapStore<Tuple, ?>> stores,
87 SymbolEquivalenceClass<T> equivalenceClass, List<AnySymbol> symbols) { 102 SymbolEquivalenceClass<T> equivalenceClass, List<AnySymbol> symbols) {
88 int size = symbols.size(); 103 int size = symbols.size();
89 VersionedMapStoreFactory<Tuple,T> mapFactory = VersionedMapStore 104 VersionedMapStoreFactory<Tuple, T> mapFactory = VersionedMapStore
90 .<Tuple,T>builder() 105 .<Tuple, T>builder()
91 .strategy(VersionedMapStoreFactoryBuilder.StoreStrategy.DELTA) 106 .strategy(VersionedMapStoreFactoryBuilder.StoreStrategy.DELTA)
92 .defaultValue(equivalenceClass.defaultValue()) 107 .defaultValue(equivalenceClass.defaultValue())
93 .build(); 108 .build();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
index a320a618..fd4cc160 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -14,16 +14,20 @@ import tools.refinery.store.model.ModelDiffCursor;
14import tools.refinery.store.model.ModelStore; 14import tools.refinery.store.model.ModelStore;
15import tools.refinery.store.representation.AnySymbol; 15import tools.refinery.store.representation.AnySymbol;
16import tools.refinery.store.tuple.Tuple; 16import tools.refinery.store.tuple.Tuple;
17import tools.refinery.store.util.CancellationToken;
17 18
18import java.util.*; 19import java.util.*;
19 20
20public class ModelStoreImpl implements ModelStore { 21public class ModelStoreImpl implements ModelStore {
21 private final LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores; 22 private final LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
22 private final List<ModelStoreAdapter> adapters; 23 private final List<ModelStoreAdapter> adapters;
24 private final CancellationToken cancellationToken;
23 25
24 ModelStoreImpl(LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) { 26 ModelStoreImpl(LinkedHashMap<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount,
27 CancellationToken cancellationToken) {
25 this.stores = stores; 28 this.stores = stores;
26 adapters = new ArrayList<>(adapterCount); 29 adapters = new ArrayList<>(adapterCount);
30 this.cancellationToken = cancellationToken;
27 } 31 }
28 32
29 @Override 33 @Override
@@ -100,4 +104,13 @@ public class ModelStoreImpl implements ModelStore {
100 void addAdapter(ModelStoreAdapter adapter) { 104 void addAdapter(ModelStoreAdapter adapter) {
101 adapters.add(adapter); 105 adapters.add(adapter);
102 } 106 }
107
108 @Override
109 public void checkCancelled() {
110 cancellationToken.checkCancelled();
111 }
112
113 CancellationToken getCancellationToken() {
114 return cancellationToken;
115 }
103} 116}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
index 71df3962..dcf0ad08 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
@@ -75,6 +75,7 @@ public abstract class VersionedInterpretation<T> implements Interpretation<T> {
75 @Override 75 @Override
76 public T put(Tuple key, T value) { 76 public T put(Tuple key, T value) {
77 checkKey(key); 77 checkKey(key);
78 model.checkCancelled();
78 model.markAsChanged(); 79 model.markAsChanged();
79 var oldValue = map.put(key, value); 80 var oldValue = map.put(key, value);
80 valueChanged(key, oldValue, value, false); 81 valueChanged(key, oldValue, value, false);
@@ -83,15 +84,12 @@ public abstract class VersionedInterpretation<T> implements Interpretation<T> {
83 84
84 @Override 85 @Override
85 public void putAll(Cursor<Tuple, T> cursor) { 86 public void putAll(Cursor<Tuple, T> cursor) {
86 if (listeners.isEmpty()) {
87 map.putAll(cursor);
88 return;
89 }
90 model.markAsChanged(); 87 model.markAsChanged();
91 if (cursor.getDependingMaps().contains(map)) { 88 if (cursor.getDependingMaps().contains(map)) {
92 List<Tuple> keys = new ArrayList<>(); 89 List<Tuple> keys = new ArrayList<>();
93 List<T> values = new ArrayList<>(); 90 List<T> values = new ArrayList<>();
94 while (cursor.move()) { 91 while (cursor.move()) {
92 model.checkCancelled();
95 keys.add(cursor.getKey()); 93 keys.add(cursor.getKey());
96 values.add(cursor.getValue()); 94 values.add(cursor.getValue());
97 } 95 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java
index 04e17a13..809205e4 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java
@@ -7,9 +7,10 @@ package tools.refinery.store.statecoding;
7 7
8import org.eclipse.collections.api.set.primitive.IntSet; 8import org.eclipse.collections.api.set.primitive.IntSet;
9import tools.refinery.store.model.Interpretation; 9import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.model.Model;
10 11
11import java.util.List; 12import java.util.List;
12 13
13public interface StateCodeCalculatorFactory { 14public interface StateCodeCalculatorFactory {
14 StateCodeCalculator create(List<? extends Interpretation<?>> interpretations, IntSet individuals); 15 StateCodeCalculator create(Model model, List<? extends Interpretation<?>> interpretations, IntSet individuals);
15} 16}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
index 89586bfb..2cb6f3c1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
@@ -68,7 +68,7 @@ public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter {
68 @Override 68 @Override
69 public StateCoderAdapter createModelAdapter(Model model) { 69 public StateCoderAdapter createModelAdapter(Model model) {
70 var interpretations = symbols.stream().map(model::getInterpretation).toList(); 70 var interpretations = symbols.stream().map(model::getInterpretation).toList();
71 var coder = codeCalculatorFactory.create(interpretations, individuals); 71 var coder = codeCalculatorFactory.create(model, interpretations, individuals);
72 return new StateCoderAdapterImpl(this, coder, model); 72 return new StateCoderAdapterImpl(this, coder, model);
73 } 73 }
74} 74}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
index 5d390da2..4cef6786 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
@@ -10,6 +10,7 @@ import org.eclipse.collections.api.map.primitive.MutableIntLongMap;
10import org.eclipse.collections.api.set.primitive.IntSet; 10import org.eclipse.collections.api.set.primitive.IntSet;
11import tools.refinery.store.model.AnyInterpretation; 11import tools.refinery.store.model.AnyInterpretation;
12import tools.refinery.store.model.Interpretation; 12import tools.refinery.store.model.Interpretation;
13import tools.refinery.store.model.Model;
13import tools.refinery.store.statecoding.ObjectCode; 14import tools.refinery.store.statecoding.ObjectCode;
14import tools.refinery.store.tuple.Tuple; 15import tools.refinery.store.tuple.Tuple;
15import tools.refinery.store.tuple.Tuple0; 16import tools.refinery.store.tuple.Tuple0;
@@ -17,13 +18,16 @@ import tools.refinery.store.tuple.Tuple0;
17import java.util.*; 18import java.util.*;
18 19
19public abstract class AbstractNeighbourhoodCalculator { 20public abstract class AbstractNeighbourhoodCalculator {
21 protected final Model model;
20 protected final List<AnyInterpretation> nullImpactValues; 22 protected final List<AnyInterpretation> nullImpactValues;
21 protected final LinkedHashMap<AnyInterpretation, long[]> impactValues; 23 protected final LinkedHashMap<AnyInterpretation, long[]> impactValues;
22 protected final MutableIntLongMap individualHashValues = IntLongMaps.mutable.empty(); 24 protected final MutableIntLongMap individualHashValues = IntLongMaps.mutable.empty();
23 25
24 protected static final long PRIME = 31; 26 protected static final long PRIME = 31;
25 27
26 protected AbstractNeighbourhoodCalculator(List<? extends AnyInterpretation> interpretations, IntSet individuals) { 28 protected AbstractNeighbourhoodCalculator(Model model, List<? extends AnyInterpretation> interpretations,
29 IntSet individuals) {
30 this.model = model;
27 this.nullImpactValues = new ArrayList<>(); 31 this.nullImpactValues = new ArrayList<>();
28 this.impactValues = new LinkedHashMap<>(); 32 this.impactValues = new LinkedHashMap<>();
29 // Random isn't used for cryptographical purposes but just to assign distinguishable identifiers to symbols. 33 // Random isn't used for cryptographical purposes but just to assign distinguishable identifiers to symbols.
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
index c188a839..04335141 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
@@ -12,6 +12,7 @@ import org.eclipse.collections.api.set.primitive.IntSet;
12import tools.refinery.store.map.Cursor; 12import tools.refinery.store.map.Cursor;
13import tools.refinery.store.model.AnyInterpretation; 13import tools.refinery.store.model.AnyInterpretation;
14import tools.refinery.store.model.Interpretation; 14import tools.refinery.store.model.Interpretation;
15import tools.refinery.store.model.Model;
15import tools.refinery.store.statecoding.StateCodeCalculator; 16import tools.refinery.store.statecoding.StateCodeCalculator;
16import tools.refinery.store.statecoding.StateCoderResult; 17import tools.refinery.store.statecoding.StateCoderResult;
17import tools.refinery.store.tuple.Tuple; 18import tools.refinery.store.tuple.Tuple;
@@ -19,8 +20,9 @@ import tools.refinery.store.tuple.Tuple;
19import java.util.List; 20import java.util.List;
20 21
21public class LazyNeighbourhoodCalculator extends AbstractNeighbourhoodCalculator implements StateCodeCalculator { 22public class LazyNeighbourhoodCalculator extends AbstractNeighbourhoodCalculator implements StateCodeCalculator {
22 public LazyNeighbourhoodCalculator(List<? extends AnyInterpretation> interpretations, IntSet individuals) { 23 public LazyNeighbourhoodCalculator(Model model, List<? extends AnyInterpretation> interpretations,
23 super(interpretations, individuals); 24 IntSet individuals) {
25 super(model, interpretations, individuals);
24 } 26 }
25 27
26 public StateCoderResult calculateCodes() { 28 public StateCoderResult calculateCodes() {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
index 1442c915..5e6de53b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
@@ -8,6 +8,7 @@ package tools.refinery.store.statecoding.neighbourhood;
8import org.eclipse.collections.api.set.primitive.IntSet; 8import org.eclipse.collections.api.set.primitive.IntSet;
9import tools.refinery.store.map.Cursor; 9import tools.refinery.store.map.Cursor;
10import tools.refinery.store.model.Interpretation; 10import tools.refinery.store.model.Interpretation;
11import tools.refinery.store.model.Model;
11import tools.refinery.store.statecoding.ObjectCode; 12import tools.refinery.store.statecoding.ObjectCode;
12import tools.refinery.store.statecoding.StateCodeCalculator; 13import tools.refinery.store.statecoding.StateCodeCalculator;
13import tools.refinery.store.statecoding.StateCoderResult; 14import tools.refinery.store.statecoding.StateCoderResult;
@@ -21,17 +22,19 @@ public class NeighbourhoodCalculator extends AbstractNeighbourhoodCalculator imp
21 private ObjectCodeImpl previousObjectCode = new ObjectCodeImpl(); 22 private ObjectCodeImpl previousObjectCode = new ObjectCodeImpl();
22 private ObjectCodeImpl nextObjectCode = new ObjectCodeImpl(); 23 private ObjectCodeImpl nextObjectCode = new ObjectCodeImpl();
23 24
24 public NeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations, IntSet individuals) { 25 public NeighbourhoodCalculator(Model model, List<? extends Interpretation<?>> interpretations, IntSet individuals) {
25 super(interpretations, individuals); 26 super(model, interpretations, individuals);
26 } 27 }
27 28
28 public StateCoderResult calculateCodes() { 29 public StateCoderResult calculateCodes() {
30 model.checkCancelled();
29 previousObjectCode.clear(); 31 previousObjectCode.clear();
30 nextObjectCode.clear(); 32 nextObjectCode.clear();
31 initializeWithIndividuals(previousObjectCode); 33 initializeWithIndividuals(previousObjectCode);
32 34
33 int rounds = 0; 35 int rounds = 0;
34 do { 36 do {
37 model.checkCancelled();
35 constructNextObjectCodes(previousObjectCode, nextObjectCode); 38 constructNextObjectCodes(previousObjectCode, nextObjectCode);
36 var tempObjectCode = previousObjectCode; 39 var tempObjectCode = previousObjectCode;
37 previousObjectCode = nextObjectCode; 40 previousObjectCode = nextObjectCode;
@@ -60,6 +63,7 @@ public class NeighbourhoodCalculator extends AbstractNeighbourhoodCalculator imp
60 63
61 private void constructNextObjectCodes(ObjectCodeImpl previous, ObjectCodeImpl next) { 64 private void constructNextObjectCodes(ObjectCodeImpl previous, ObjectCodeImpl next) {
62 for (var impactValueEntry : this.impactValues.entrySet()) { 65 for (var impactValueEntry : this.impactValues.entrySet()) {
66 model.checkCancelled();
63 Interpretation<?> interpretation = (Interpretation<?>) impactValueEntry.getKey(); 67 Interpretation<?> interpretation = (Interpretation<?>) impactValueEntry.getKey();
64 var cursor = interpretation.getAll(); 68 var cursor = interpretation.getAll();
65 int arity = interpretation.getSymbol().arity(); 69 int arity = interpretation.getSymbol().arity();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CancellationToken.java b/subprojects/store/src/main/java/tools/refinery/store/util/CancellationToken.java
new file mode 100644
index 00000000..be294013
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/util/CancellationToken.java
@@ -0,0 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.util;
7
8@FunctionalInterface
9public interface CancellationToken {
10 CancellationToken NONE = () -> {};
11
12 void checkCancelled();
13}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
index 3c35849e..f2d2f7b5 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
@@ -192,7 +192,8 @@ class EquivalenceTest {
192 ModelStore store = ModelStore.builder() 192 ModelStore store = ModelStore.builder()
193 .symbols(person, age, friend, parents, population) 193 .symbols(person, age, friend, parents, population)
194 .with(StateCoderAdapter.builder() 194 .with(StateCoderAdapter.builder()
195 .stateCodeCalculatorFactory((p1, p2) -> calculator)) 195 .stateCodeCalculatorFactory((ignoredModel, ignoredInterpretations, ignoredIndividuals) ->
196 calculator))
196 .build(); 197 .build();
197 198
198 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); 199 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
index 0b738005..0928aa8e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
@@ -124,7 +124,8 @@ class StateCoderBuildTest {
124 var store = ModelStore.builder() 124 var store = ModelStore.builder()
125 .symbols(friend) 125 .symbols(friend)
126 .with(StateCoderAdapter.builder() 126 .with(StateCoderAdapter.builder()
127 .stateCodeCalculatorFactory((interpretations, individuals) -> mock)) 127 .stateCodeCalculatorFactory((ignoredModel, ignoredInterpretations, ignoredIndividuals) ->
128 mock))
128 .build(); 129 .build();
129 130
130 var model = store.createEmptyModel(); 131 var model = store.createEmptyModel();