aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-23 20:27:55 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-29 00:02:28 +0100
commitd91acf3690682d243dbc150df902525b6e545c2f (patch)
treef39695cc193828df0b78030b5a56bd968e277457 /subprojects
parentchore(deps): bump dependencies (diff)
downloadrefinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.gz
refinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.zst
refinery-d91acf3690682d243dbc150df902525b6e545c2f.zip
refactor: Model store and query API
Use Adapters to simplify API usage.
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java8
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java2
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java2
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java2
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java2
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java2
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java2
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java2
-rw-r--r--subprojects/store-query-viatra/build.gradle2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java22
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java48
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java8
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java140
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java22
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java117
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java116
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java58
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java222
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java8
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java2
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java14
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java34
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java)7
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java)13
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java4
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java46
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java66
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java40
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java35
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java24
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java112
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java32
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java47
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java73
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java580
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java57
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java4
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java4
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java27
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java94
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java79
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java29
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java15
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java36
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java115
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java211
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java104
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java100
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java35
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java159
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java4
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java23
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java43
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/DNF.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java23
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java16
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java18
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java32
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java18
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java34
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java47
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java)2
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java9
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java)2
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java190
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java)4
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java)3
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java)3
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java)4
112 files changed, 2364 insertions, 1652 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
index 13bb20d7..a6712a89 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
@@ -7,8 +7,8 @@ import tools.refinery.language.model.problem.*;
7import tools.refinery.language.semantics.model.internal.DecisionTree; 7import tools.refinery.language.semantics.model.internal.DecisionTree;
8import tools.refinery.language.utils.ProblemDesugarer; 8import tools.refinery.language.utils.ProblemDesugarer;
9import tools.refinery.language.utils.RelationInfo; 9import tools.refinery.language.utils.RelationInfo;
10import tools.refinery.store.model.representation.Relation; 10import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.model.representation.TruthValue; 11import tools.refinery.store.representation.TruthValue;
12import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
13 13
14import java.util.HashMap; 14import java.util.HashMap;
@@ -20,7 +20,7 @@ public class ModelInitializer {
20 20
21 private final MutableObjectIntMap<Node> nodeTrace = ObjectIntMaps.mutable.empty(); 21 private final MutableObjectIntMap<Node> nodeTrace = ObjectIntMaps.mutable.empty();
22 22
23 private final Map<tools.refinery.language.model.problem.Relation, Relation<TruthValue>> relationTrace = 23 private final Map<tools.refinery.language.model.problem.Relation, Symbol<TruthValue>> relationTrace =
24 new HashMap<>(); 24 new HashMap<>();
25 25
26 private int nodeCount = 0; 26 private int nodeCount = 0;
@@ -39,7 +39,7 @@ public class ModelInitializer {
39 var isEqualsRelation = relation == builtinSymbols.equals(); 39 var isEqualsRelation = relation == builtinSymbols.equals();
40 var decisionTree = mergeAssertions(relationInfo, isEqualsRelation); 40 var decisionTree = mergeAssertions(relationInfo, isEqualsRelation);
41 var defaultValue = isEqualsRelation ? TruthValue.FALSE : TruthValue.UNKNOWN; 41 var defaultValue = isEqualsRelation ? TruthValue.FALSE : TruthValue.UNKNOWN;
42 relationTrace.put(relation, new Relation<>(relationInfo.name(), relationInfo.arity(), TruthValue.class, defaultValue 42 relationTrace.put(relation, new Symbol<>(relationInfo.name(), relationInfo.arity(), TruthValue.class, defaultValue
43 )); 43 ));
44 } 44 }
45 } 45 }
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
index 3893f396..55edee6d 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
@@ -3,7 +3,7 @@ package tools.refinery.language.semantics.model.internal;
3import org.eclipse.collections.api.factory.primitive.IntObjectMaps; 3import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
4import tools.refinery.store.map.Cursor; 4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.tuple.Tuple; 5import tools.refinery.store.tuple.Tuple;
6import tools.refinery.store.model.representation.TruthValue; 6import tools.refinery.store.representation.TruthValue;
7 7
8public class DecisionTree { 8public class DecisionTree {
9 private final int levels; 9 private final int levels;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
index a1fdc73d..fdf8e452 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
@@ -1,7 +1,7 @@
1package tools.refinery.language.semantics.model.internal; 1package tools.refinery.language.semantics.model.internal;
2 2
3import tools.refinery.store.map.Cursor; 3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.model.representation.TruthValue; 4import tools.refinery.store.representation.TruthValue;
5import tools.refinery.store.tuple.Tuple; 5import tools.refinery.store.tuple.Tuple;
6 6
7import java.util.ArrayDeque; 7import java.util.ArrayDeque;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
index 8ca54969..b81ea3fe 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
@@ -2,7 +2,7 @@ package tools.refinery.language.semantics.model.internal;
2 2
3import org.eclipse.collections.api.LazyIntIterable; 3import org.eclipse.collections.api.LazyIntIterable;
4import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.representation.TruthValue;
6 6
7abstract class DecisionTreeNode { 7abstract class DecisionTreeNode {
8 public DecisionTreeValue getReducedValue() { 8 public DecisionTreeValue getReducedValue() {
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
index 993987f5..495a53dd 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
@@ -1,6 +1,6 @@
1package tools.refinery.language.semantics.model.internal; 1package tools.refinery.language.semantics.model.internal;
2 2
3import tools.refinery.store.model.representation.TruthValue; 3import tools.refinery.store.representation.TruthValue;
4 4
5public enum DecisionTreeValue { 5public enum DecisionTreeValue {
6 UNSET(null), 6 UNSET(null),
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
index a7486ecb..c4200509 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
@@ -5,7 +5,7 @@ import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; 5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
6import org.eclipse.collections.api.tuple.primitive.IntObjectPair; 6import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
7import tools.refinery.store.tuple.Tuple; 7import tools.refinery.store.tuple.Tuple;
8import tools.refinery.store.model.representation.TruthValue; 8import tools.refinery.store.representation.TruthValue;
9 9
10final class IntermediateNode extends DecisionTreeNode { 10final class IntermediateNode extends DecisionTreeNode {
11 private final MutableIntObjectMap<DecisionTreeNode> children; 11 private final MutableIntObjectMap<DecisionTreeNode> children;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
index c0197e89..4af836ff 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
@@ -5,7 +5,7 @@ import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; 5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
6import org.eclipse.collections.api.tuple.primitive.IntObjectPair; 6import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
7import tools.refinery.store.tuple.Tuple; 7import tools.refinery.store.tuple.Tuple;
8import tools.refinery.store.model.representation.TruthValue; 8import tools.refinery.store.representation.TruthValue;
9 9
10class TerminalNode extends DecisionTreeNode { 10class TerminalNode extends DecisionTreeNode {
11 private MutableIntObjectMap<TruthValue> children; 11 private MutableIntObjectMap<TruthValue> children;
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
index f171e5c7..4630bf53 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
@@ -2,7 +2,7 @@ package tools.refinery.language.semantics.model.tests;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.language.semantics.model.internal.DecisionTree; 4import tools.refinery.language.semantics.model.internal.DecisionTree;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.representation.TruthValue;
6import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.Tuple;
7 7
8import java.util.LinkedHashMap; 8import java.util.LinkedHashMap;
diff --git a/subprojects/store-query-viatra/build.gradle b/subprojects/store-query-viatra/build.gradle
index 32a23fe7..c12b48fe 100644
--- a/subprojects/store-query-viatra/build.gradle
+++ b/subprojects/store-query-viatra/build.gradle
@@ -9,7 +9,7 @@ configurations.testRuntimeClasspath {
9 9
10dependencies { 10dependencies {
11 implementation libs.ecore 11 implementation libs.ecore
12 implementation libs.viatra 12 api libs.viatra
13 api project(':refinery-store') 13 api project(':refinery-store')
14 testImplementation libs.slf4j.simple 14 testImplementation libs.slf4j.simple
15 testImplementation libs.slf4j.log4j 15 testImplementation libs.slf4j.log4j
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
new file mode 100644
index 00000000..ecac570b
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
@@ -0,0 +1,22 @@
1package tools.refinery.store.query.viatra;
2
3import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
4import tools.refinery.store.model.ModelStoreBuilder;
5import tools.refinery.store.query.ModelQuery;
6import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl;
8
9public final class ViatraModelQuery extends ModelAdapterBuilderFactory<ModelQueryAdapter, ViatraModelQueryStoreAdapter,
10 ViatraModelQueryBuilder> {
11 public static final ViatraModelQuery ADAPTER = new ViatraModelQuery();
12
13 private ViatraModelQuery() {
14 super(ModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class);
15 extendsAdapter(ModelQuery.ADAPTER);
16 }
17
18 @Override
19 public ViatraModelQueryBuilder createBuilder(ModelStoreBuilder storeBuilder) {
20 return new ViatraModelQueryBuilderImpl(storeBuilder);
21 }
22}
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
new file mode 100644
index 00000000..ee445a79
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
@@ -0,0 +1,48 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
4import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
5import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
6import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.query.DNF;
8import tools.refinery.store.query.ModelQueryBuilder;
9
10import java.util.Collection;
11import java.util.function.Function;
12
13@SuppressWarnings("UnusedReturnValue")
14public interface ViatraModelQueryBuilder extends ModelQueryBuilder {
15 ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions);
16
17 ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint);
18
19 ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory);
20
21 ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory);
22
23 ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory);
24
25 @Override
26 default ViatraModelQueryBuilder queries(DNF... queries) {
27 ModelQueryBuilder.super.queries(queries);
28 return this;
29 }
30
31 @Override
32 default ViatraModelQueryBuilder queries(Collection<? extends DNF> queries) {
33 ModelQueryBuilder.super.queries(queries);
34 return this;
35 }
36
37 @Override
38 ViatraModelQueryBuilder query(DNF query);
39
40 ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint);
41
42 ViatraModelQueryBuilder computeHint(Function<DNF, QueryEvaluationHint> computeHint);
43
44 ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint);
45
46 @Override
47 ViatraModelQueryStoreAdapter createStoreAdapter(ModelStore store);
48}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
new file mode 100644
index 00000000..d52575d2
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
@@ -0,0 +1,8 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
4import tools.refinery.store.query.ModelQueryStoreAdapter;
5
6public interface ViatraModelQueryStoreAdapter extends ModelQueryStoreAdapter {
7 ViatraQueryEngineOptions getEngineOptions();
8}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java
deleted file mode 100644
index 94d2db4f..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java
+++ /dev/null
@@ -1,140 +0,0 @@
1package tools.refinery.store.query.viatra;
2
3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
4import tools.refinery.store.model.ModelDiffCursor;
5import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.model.ModelStoreImpl;
7import tools.refinery.store.model.RelationLike;
8import tools.refinery.store.model.representation.AnyDataRepresentation;
9import tools.refinery.store.model.representation.DataRepresentation;
10import tools.refinery.store.query.DNF;
11import tools.refinery.store.query.DNFAnd;
12import tools.refinery.store.query.QueryableModel;
13import tools.refinery.store.query.QueryableModelStore;
14import tools.refinery.store.query.atom.*;
15import tools.refinery.store.query.viatra.internal.RawPatternMatcher;
16import tools.refinery.store.query.viatra.internal.ViatraQueryableModel;
17import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery;
18import tools.refinery.store.query.view.AnyRelationView;
19
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.Map;
23import java.util.Set;
24
25public class ViatraQueryableModelStore implements QueryableModelStore {
26 protected final ModelStore store;
27
28 protected final Set<AnyRelationView> relationViews;
29
30 protected final Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates;
31
32 public ViatraQueryableModelStore(ModelStore store, Set<AnyRelationView> relationViews,
33 Set<DNF> predicates) {
34 this.store = store;
35 validateViews(store.getDataRepresentations(), relationViews);
36 this.relationViews = Collections.unmodifiableSet(relationViews);
37 validatePredicates(relationViews, predicates);
38 this.predicates = initPredicates(predicates);
39 }
40
41 public ViatraQueryableModelStore(Set<AnyDataRepresentation> dataRepresentations,
42 Set<AnyRelationView> relationViews, Set<DNF> predicates) {
43 this(new ModelStoreImpl(dataRepresentations), relationViews, predicates);
44 }
45
46 private void validateViews(Set<AnyDataRepresentation> dataRepresentations, Set<AnyRelationView> relationViews) {
47 for (var relationView : relationViews) {
48 if (!dataRepresentations.contains(relationView.getRepresentation())) {
49 throw new IllegalArgumentException("%s %s added to %s without a referred representation.".formatted(
50 DataRepresentation.class.getSimpleName(), relationView.getName(),
51 QueryableModelStore.class.getSimpleName()));
52 }
53 }
54 }
55
56 private void validatePredicates(Set<AnyRelationView> relationViews, Set<DNF> predicates) {
57 for (DNF dnfPredicate : predicates) {
58 for (DNFAnd clause : dnfPredicate.getClauses()) {
59 for (DNFAtom atom : clause.constraints()) {
60 if (atom instanceof RelationViewAtom relationViewAtom) {
61 validateRelationAtom(relationViews, dnfPredicate, relationViewAtom);
62 } else if (atom instanceof CallAtom<?> queryCallAtom) {
63 validatePredicateAtom(predicates, dnfPredicate, queryCallAtom);
64 } else if (!(atom instanceof EquivalenceAtom || atom instanceof ConstantAtom)) {
65 throw new IllegalArgumentException("Unknown constraint: " + atom.toString());
66 }
67 }
68 }
69 }
70 }
71
72 private void validateRelationAtom(Set<AnyRelationView> relationViews, DNF dnfPredicate,
73 RelationViewAtom relationViewAtom) {
74 if (!relationViews.contains(relationViewAtom.getTarget())) {
75 throw new IllegalArgumentException(
76 "%s %s contains reference to a view %s that is not in the model.".formatted(
77 DNF.class.getSimpleName(), dnfPredicate.getUniqueName(),
78 relationViewAtom.getTarget().getName()));
79 }
80 }
81
82 private void validatePredicateReference(Set<DNF> predicates, DNF dnfPredicate, RelationLike target) {
83 if (!(target instanceof DNF dnfTarget) || !predicates.contains(dnfTarget)) {
84 throw new IllegalArgumentException(
85 "%s %s contains reference to a predicate %s that is not in the model.".formatted(
86 DNF.class.getSimpleName(), dnfPredicate.getUniqueName(), target.getName()));
87 }
88 }
89
90 private void validatePredicateAtom(Set<DNF> predicates, DNF dnfPredicate, CallAtom<?> queryCallAtom) {
91 validatePredicateReference(predicates, dnfPredicate, queryCallAtom.getTarget());
92 }
93
94
95 private Map<DNF, GenericQuerySpecification<RawPatternMatcher>> initPredicates(Set<DNF> predicates) {
96 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> result = new HashMap<>();
97 var dnf2PQuery = new DNF2PQuery();
98 for (DNF dnfPredicate : predicates) {
99 GenericQuerySpecification<RawPatternMatcher> query = dnf2PQuery.translate(dnfPredicate).build();
100 result.put(dnfPredicate, query);
101 }
102
103 return result;
104 }
105
106 @Override
107 public Set<AnyDataRepresentation> getDataRepresentations() {
108 return store.getDataRepresentations();
109 }
110
111 @Override
112 public Set<AnyRelationView> getViews() {
113 return this.relationViews;
114 }
115
116 @Override
117 public Set<DNF> getPredicates() {
118 return predicates.keySet();
119 }
120
121 @Override
122 public QueryableModel createModel() {
123 return new ViatraQueryableModel(this, this.store.createModel(), predicates);
124 }
125
126 @Override
127 public QueryableModel createModel(long state) {
128 return new ViatraQueryableModel(this, this.store.createModel(state), predicates);
129 }
130
131 @Override
132 public synchronized Set<Long> getStates() {
133 return this.store.getStates();
134 }
135
136 @Override
137 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
138 return this.store.getDiffCursor(from, to);
139 }
140}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
index 133c4c72..21dcaf15 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
@@ -6,34 +6,20 @@ import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
6import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; 6import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener;
7import org.eclipse.viatra.query.runtime.api.scope.QueryScope; 7import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
8import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext; 9import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext;
11import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 10import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
12import tools.refinery.store.query.view.AnyRelationView; 11import tools.refinery.store.query.view.AnyRelationView;
13import tools.refinery.store.tuple.Tuple;
14 12
15import java.util.Set; 13import java.util.Collection;
16 14
17public class RelationalScope extends QueryScope { 15public class RelationalScope extends QueryScope {
18 private final Model model; 16 private final Model model;
19 17
20 private final ModelUpdateListener updateListener; 18 private final ModelUpdateListener updateListener;
21 19
22 public RelationalScope(Model model, Set<AnyRelationView> relationViews) { 20 public RelationalScope(Model model, Collection<AnyRelationView> relationViews) {
23 this.model = model; 21 this.model = model;
24 this.updateListener = new ModelUpdateListener(relationViews); 22 updateListener = new ModelUpdateListener(model, relationViews);
25 }
26
27 public <D> void processUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
28 updateListener.addUpdate(relation, key, oldValue, newValue);
29 }
30
31 public boolean hasChanges() {
32 return updateListener.hasChanges();
33 }
34
35 public void flush() {
36 updateListener.flush();
37 } 23 }
38 24
39 @Override 25 @Override
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
new file mode 100644
index 00000000..3c276935
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
@@ -0,0 +1,117 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
4import org.eclipse.viatra.query.runtime.api.GenericQueryGroup;
5import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
6import org.eclipse.viatra.query.runtime.internal.apiimpl.ViatraQueryEngineImpl;
7import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend;
8import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.DNF;
11import tools.refinery.store.query.ModelQueryAdapter;
12import tools.refinery.store.query.ModelQueryStoreAdapter;
13import tools.refinery.store.query.ResultSet;
14
15import java.lang.invoke.MethodHandle;
16import java.lang.invoke.MethodHandles;
17import java.util.*;
18
19public class ViatraModelQueryAdapterImpl implements ModelQueryAdapter {
20 private static final String DELAY_MESSAGE_DELIVERY_FIELD_NAME = "delayMessageDelivery";
21 private static final String QUERY_BACKENDS_FIELD_NAME = "queryBackends";
22
23 private final Model model;
24 private final ViatraModelQueryStoreAdapterImpl storeAdapter;
25 private final ViatraQueryEngineImpl queryEngine;
26 private final MethodHandle setUpdatePropagationDelayedHandle;
27 private final MethodHandle getQueryBackendsHandle;
28 private final Map<DNF, ResultSet> resultSets;
29
30 ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) {
31 this.model = model;
32 this.storeAdapter = storeAdapter;
33 var scope = new RelationalScope(model, storeAdapter.getRelationViews());
34 queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope);
35
36 try {
37 var lookup = MethodHandles.privateLookupIn(ViatraQueryEngineImpl.class, MethodHandles.lookup());
38 setUpdatePropagationDelayedHandle = lookup.findSetter(ViatraQueryEngineImpl.class,
39 DELAY_MESSAGE_DELIVERY_FIELD_NAME, Boolean.TYPE);
40 getQueryBackendsHandle = lookup.findGetter(ViatraQueryEngineImpl.class, QUERY_BACKENDS_FIELD_NAME,
41 Map.class);
42 } catch (IllegalAccessException | NoSuchFieldException e) {
43 throw new IllegalStateException("Cannot access private members of %s"
44 .formatted(ViatraQueryEngineImpl.class.getName()), e);
45 }
46
47 var querySpecifications = storeAdapter.getQuerySpecifications();
48 GenericQueryGroup.of(
49 Collections.<IQuerySpecification<?>>unmodifiableCollection(querySpecifications.values()).stream()
50 ).prepare(queryEngine);
51 resultSets = new HashMap<>(querySpecifications.size());
52 for (var entry : querySpecifications.entrySet()) {
53 var matcher = queryEngine.getMatcher(entry.getValue());
54 resultSets.put(entry.getKey(), matcher);
55 }
56
57 setUpdatePropagationDelayed(true);
58 }
59
60 private void setUpdatePropagationDelayed(boolean value) {
61 try {
62 setUpdatePropagationDelayedHandle.invokeExact(queryEngine, value);
63 } catch (Error e) {
64 // Fatal JVM errors should not be wrapped.
65 throw e;
66 } catch (Throwable e) {
67 throw new IllegalStateException("Cannot set %s".formatted(DELAY_MESSAGE_DELIVERY_FIELD_NAME), e);
68 }
69 }
70
71 private Collection<IQueryBackend> getQueryBackends() {
72 try {
73 @SuppressWarnings("unchecked")
74 var backendMap = (Map<IQueryBackendFactory, IQueryBackend>) getQueryBackendsHandle.invokeExact(queryEngine);
75 return backendMap.values();
76 } catch (Error e) {
77 // Fatal JVM errors should not be wrapped.
78 throw e;
79 } catch (Throwable e) {
80 throw new IllegalStateException("Cannot get %s".formatted(QUERY_BACKENDS_FIELD_NAME), e);
81 }
82 }
83
84 @Override
85 public Model getModel() {
86 return model;
87 }
88
89 @Override
90 public ModelQueryStoreAdapter getStoreAdapter() {
91 return storeAdapter;
92 }
93
94 @Override
95 public ResultSet getResultSet(DNF query) {
96 var resultSet = resultSets.get(query);
97 if (resultSet == null) {
98 throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name()));
99 }
100 return resultSet;
101 }
102
103 @Override
104 public void flushChanges() {
105 if (!queryEngine.isUpdatePropagationDelayed()) {
106 throw new IllegalStateException("Trying to flush changes while changes are already being flushed");
107 }
108 setUpdatePropagationDelayed(false);
109 try {
110 for (var queryBackend : getQueryBackends()) {
111 queryBackend.flushUpdates();
112 }
113 } finally {
114 setUpdatePropagationDelayed(true);
115 }
116 }
117}
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
new file mode 100644
index 00000000..5105c9a7
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
@@ -0,0 +1,116 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
5import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory;
6import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
7import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
8import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory;
9import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.model.ModelStoreBuilder;
12import tools.refinery.store.query.DNF;
13import tools.refinery.store.query.viatra.ViatraModelQueryBuilder;
14import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery;
15import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher;
16
17import java.util.Collections;
18import java.util.LinkedHashMap;
19import java.util.Map;
20import java.util.function.Function;
21
22public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder {
23 private ViatraQueryEngineOptions.Builder engineOptionsBuilder;
24 private final DNF2PQuery dnf2PQuery = new DNF2PQuery();
25 private final Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>();
26
27 public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) {
28 super(storeBuilder);
29 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder()
30 .withDefaultBackend(ReteBackendFactory.INSTANCE)
31 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE)
32 .withDefaultSearchBackend(LocalSearchGenericBackendFactory.INSTANCE);
33 }
34
35 @Override
36 public ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions) {
37 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder(engineOptions);
38 return this;
39 }
40
41 @Override
42 public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) {
43 engineOptionsBuilder.withDefaultHint(queryEvaluationHint);
44 return this;
45 }
46
47 @Override
48 public ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory) {
49 engineOptionsBuilder.withDefaultBackend(queryBackendFactory);
50 return this;
51 }
52
53 @Override
54 public ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory) {
55 engineOptionsBuilder.withDefaultCachingBackend(queryBackendFactory);
56 return this;
57 }
58
59 @Override
60 public ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory) {
61 engineOptionsBuilder.withDefaultSearchBackend(queryBackendFactory);
62 return this;
63 }
64
65 @Override
66 public ViatraModelQueryBuilder query(DNF query) {
67 if (querySpecifications.containsKey(query)) {
68 throw new IllegalArgumentException("%s was already added to the query engine".formatted(query.name()));
69 }
70 var pQuery = dnf2PQuery.translate(query);
71 querySpecifications.put(query, pQuery.build());
72 return this;
73 }
74
75 @Override
76 public ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint) {
77 query(query);
78 hint(query, queryEvaluationHint);
79 return this;
80 }
81
82 @Override
83 public ViatraModelQueryBuilder computeHint(Function<DNF, QueryEvaluationHint> computeHint) {
84 dnf2PQuery.setComputeHint(computeHint);
85 return this;
86 }
87
88 @Override
89 public ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint) {
90 var pQuery = dnf2PQuery.getAlreadyTranslated(dnf);
91 if (pQuery == null) {
92 throw new IllegalArgumentException(
93 "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name()));
94 }
95 pQuery.setEvaluationHints(queryEvaluationHint);
96 return this;
97 }
98
99 @Override
100 public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) {
101 validateSymbols(store);
102 return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(),
103 Collections.unmodifiableMap(querySpecifications));
104 }
105
106 private void validateSymbols(ModelStore store) {
107 var symbols = store.getSymbols();
108 for (var relationView : dnf2PQuery.getRelationViews()) {
109 var symbol = relationView.getSymbol();
110 if (!symbols.contains(symbol)) {
111 throw new IllegalArgumentException("Cannot query relation view %s: symbol %s is not in the model"
112 .formatted(relationView, symbol));
113 }
114 }
115 }
116}
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
new file mode 100644
index 00000000..d77b7f4b
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
@@ -0,0 +1,58 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
5import tools.refinery.store.model.Model;
6import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.query.DNF;
8import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter;
9import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher;
10import tools.refinery.store.query.view.AnyRelationView;
11
12import java.util.Collection;
13import java.util.Map;
14
15public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter {
16 private final ModelStore store;
17 private final ViatraQueryEngineOptions engineOptions;
18 private final Collection<AnyRelationView> relationViews;
19 private final Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications;
20
21 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions,
22 Collection<AnyRelationView> relationViews,
23 Map<DNF, IQuerySpecification<RawPatternMatcher>> querySpecifications) {
24 this.store = store;
25 this.engineOptions = engineOptions;
26 this.relationViews = relationViews;
27 this.querySpecifications = querySpecifications;
28 }
29
30 @Override
31 public ModelStore getStore() {
32 return store;
33 }
34
35 @Override
36 public Collection<AnyRelationView> getRelationViews() {
37 return relationViews;
38 }
39
40 @Override
41 public Collection<DNF> getQueries() {
42 return querySpecifications.keySet();
43 }
44
45 Map<DNF, IQuerySpecification<RawPatternMatcher>> getQuerySpecifications() {
46 return querySpecifications;
47 }
48
49 @Override
50 public ViatraQueryEngineOptions getEngineOptions() {
51 return engineOptions;
52 }
53
54 @Override
55 public ViatraModelQueryAdapterImpl createModelAdapter(Model model) {
56 return new ViatraModelQueryAdapterImpl(model, this);
57 }
58}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java
deleted file mode 100644
index 5b06e266..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraQueryableModel.java
+++ /dev/null
@@ -1,222 +0,0 @@
1package tools.refinery.store.query.viatra.internal;
2
3import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
4import org.eclipse.viatra.query.runtime.api.GenericQueryGroup;
5import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
6import org.eclipse.viatra.query.runtime.api.IQueryGroup;
7import tools.refinery.store.map.Cursor;
8import tools.refinery.store.map.DiffCursor;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelDiffCursor;
11import tools.refinery.store.model.representation.AnyDataRepresentation;
12import tools.refinery.store.model.representation.DataRepresentation;
13import tools.refinery.store.model.representation.Relation;
14import tools.refinery.store.query.QueryableModel;
15import tools.refinery.store.query.QueryableModelStore;
16import tools.refinery.store.query.DNF;
17import tools.refinery.store.tuple.Tuple;
18import tools.refinery.store.tuple.TupleLike;
19
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Optional;
23import java.util.Set;
24import java.util.stream.Stream;
25
26public class ViatraQueryableModel implements QueryableModel {
27 protected final QueryableModelStore store;
28
29 protected final Model model;
30
31 protected final Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery;
32
33 protected RelationalScope scope;
34
35 protected AdvancedViatraQueryEngine engine;
36
37 protected Map<DNF, RawPatternMatcher> predicate2Matcher;
38
39 public ViatraQueryableModel(QueryableModelStore store, Model model,
40 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2PQuery) {
41 this.store = store;
42 this.model = model;
43 this.predicates2PQuery = predicates2PQuery;
44 initEngine();
45 }
46
47 private void initEngine() {
48 this.scope = new RelationalScope(this.model, this.store.getViews());
49 this.engine = AdvancedViatraQueryEngine.createUnmanagedEngine(this.scope);
50 this.predicate2Matcher = initMatchers(this.engine, this.predicates2PQuery);
51 }
52
53 private Map<DNF, RawPatternMatcher> initMatchers(
54 AdvancedViatraQueryEngine engine,
55 Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates2pQuery) {
56 // 1. prepare group
57 IQueryGroup queryGroup = GenericQueryGroup.of(Set.copyOf(predicates2pQuery.values()));
58 engine.prepareGroup(queryGroup, null);
59
60 // 2. then get all matchers
61 Map<DNF, RawPatternMatcher> result = new HashMap<>();
62 for (var entry : predicates2pQuery.entrySet()) {
63 var matcher = engine.getMatcher(entry.getValue());
64 result.put(entry.getKey(), matcher);
65 }
66 return result;
67 }
68
69 @Override
70 public Set<AnyDataRepresentation> getDataRepresentations() {
71 return model.getDataRepresentations();
72 }
73
74 @Override
75 public Set<DNF> getPredicates() {
76 return store.getPredicates();
77 }
78
79 @Override
80 public <K, V> V get(DataRepresentation<K, V> representation, K key) {
81 return model.get(representation, key);
82 }
83
84 @Override
85 public <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation) {
86 return model.getAll(representation);
87 }
88
89 @SuppressWarnings("unchecked")
90 @Override
91 public <K, V> V put(DataRepresentation<K, V> representation, K key, V value) {
92 V oldValue = this.model.put(representation, key, value);
93 if (representation instanceof Relation<?> relation) {
94 this.scope.processUpdate((Relation<V>) relation, (Tuple) key, oldValue, value);
95 }
96 return oldValue;
97 }
98
99 @Override
100 public <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor) {
101 if (representation instanceof Relation<?>) {
102 //noinspection RedundantSuppression
103 @SuppressWarnings("unchecked")
104 Relation<V> relation = (Relation<V>) representation;
105 while (cursor.move()) {
106 Tuple key = (Tuple) cursor.getKey();
107 V newValue = cursor.getValue();
108 V oldValue = this.model.put(relation, key, newValue);
109 this.scope.processUpdate(relation, key, oldValue, newValue);
110 }
111 } else {
112 this.model.putAll(representation, cursor);
113 }
114 }
115
116 @Override
117 public long getSize(AnyDataRepresentation representation) {
118 return model.getSize(representation);
119 }
120
121 protected RawPatternMatcher getMatcher(DNF predicate) {
122 var result = this.predicate2Matcher.get(predicate);
123 if (result == null) {
124 throw new IllegalArgumentException("Model does not contain predicate %s".formatted(predicate.getName()));
125 } else
126 return result;
127 }
128
129 protected void validateParameters(DNF predicate, Tuple parameters) {
130 int predicateArity = predicate.getParameters().size();
131 int parameterArity = parameters.getSize();
132 if (parameterArity != predicateArity) {
133 throw new IllegalArgumentException(
134 "Predicate %s with %d arity called with different number of parameters (%d)"
135 .formatted(predicate.getName(), predicateArity, parameterArity));
136 }
137 }
138
139 @Override
140 public boolean hasResult(DNF predicate) {
141 return getMatcher(predicate).hasResult();
142 }
143
144 @Override
145 public boolean hasResult(DNF predicate, Tuple parameters) {
146 validateParameters(predicate, parameters);
147 return getMatcher(predicate).hasResult(parameters);
148 }
149
150 @Override
151 public Optional<TupleLike> oneResult(DNF predicate) {
152 return getMatcher(predicate).oneResult();
153 }
154
155 @Override
156 public Optional<TupleLike> oneResult(DNF predicate, Tuple parameters) {
157 validateParameters(predicate, parameters);
158 return getMatcher(predicate).oneResult(parameters);
159 }
160
161 @Override
162 public Stream<TupleLike> allResults(DNF predicate) {
163 return getMatcher(predicate).allResults();
164 }
165
166 @Override
167 public Stream<TupleLike> allResults(DNF predicate, Tuple parameters) {
168 validateParameters(predicate, parameters);
169 return getMatcher(predicate).allResults(parameters);
170 }
171
172 @Override
173 public int countResults(DNF predicate) {
174 return getMatcher(predicate).countResults();
175 }
176
177 @Override
178 public int countResults(DNF predicate, Tuple parameters) {
179 validateParameters(predicate, parameters);
180 return getMatcher(predicate).countResults(parameters);
181
182 }
183
184 @Override
185 public boolean hasChanges() {
186 return scope.hasChanges();
187 }
188
189 @Override
190 public void flushChanges() {
191 this.scope.flush();
192 }
193
194 @Override
195 public ModelDiffCursor getDiffCursor(long to) {
196 return model.getDiffCursor(to);
197 }
198
199 @Override
200 public long commit() {
201 return this.model.commit();
202 }
203
204 @Override
205 public void restore(long state) {
206 restoreWithDiffReplay(state);
207 }
208
209 private void restoreWithDiffReplay(long state) {
210 var modelDiffCursor = getDiffCursor(state);
211 for (AnyDataRepresentation anyDataRepresentation : this.getDataRepresentations()) {
212 var dataRepresentation = (DataRepresentation<?, ?>) anyDataRepresentation;
213 restoreRepresentationWithDiffReplay(modelDiffCursor, dataRepresentation);
214 }
215 }
216
217 private <K, V> void restoreRepresentationWithDiffReplay(ModelDiffCursor modelDiffCursor,
218 DataRepresentation<K, V> dataRepresentation) {
219 DiffCursor<K, V> diffCursor = modelDiffCursor.getCursor(dataRepresentation);
220 this.putAll(dataRepresentation, diffCursor);
221 }
222}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
index ffd5f6de..e0bca9e0 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
@@ -2,10 +2,10 @@ package tools.refinery.store.query.viatra.internal.cardinality;
2 2
3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; 3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator;
4import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; 4import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
5import tools.refinery.store.model.representation.cardinality.FiniteUpperCardinality; 5import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
6import tools.refinery.store.model.representation.cardinality.UnboundedUpperCardinality; 6import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
7import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 7import tools.refinery.store.representation.cardinality.UpperCardinalities;
8import tools.refinery.store.model.representation.cardinality.UpperCardinality; 8import tools.refinery.store.representation.cardinality.UpperCardinality;
9 9
10import java.util.stream.Stream; 10import java.util.stream.Stream;
11 11
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
index d32d49ba..4eb8898b 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
@@ -5,7 +5,7 @@ import org.eclipse.viatra.query.runtime.api.scope.IEngineContext;
5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; 5import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext;
6 6
7import tools.refinery.store.model.Model; 7import tools.refinery.store.model.Model;
8import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 8import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
9 9
10public class RelationalEngineContext implements IEngineContext { 10public class RelationalEngineContext implements IEngineContext {
11 private final IBaseIndex baseIndex = new DummyBaseIndexer(); 11 private final IBaseIndex baseIndex = new DummyBaseIndexer();
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
index eb3c6fbd..47b83634 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
@@ -39,7 +39,7 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext {
39 39
40 public void ensureValidKey(IInputKey key) { 40 public void ensureValidKey(IInputKey key) {
41 if (!(key instanceof RelationViewWrapper)) { 41 if (!(key instanceof RelationViewWrapper)) {
42 throw new IllegalArgumentException("The input key %s is not a valid input key.".formatted(key)); 42 throw new IllegalArgumentException("The input key %s is not a valid input key".formatted(key));
43 } 43 }
44 } 44 }
45} 45}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
index e01525e0..7375b240 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
@@ -8,7 +8,7 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
8import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; 8import org.eclipse.viatra.query.runtime.matchers.util.Accuracy;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; 10import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper;
11import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; 11import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
12import tools.refinery.store.query.view.AnyRelationView; 12import tools.refinery.store.query.view.AnyRelationView;
13import tools.refinery.store.query.view.RelationView; 13import tools.refinery.store.query.view.RelationView;
14 14
@@ -48,12 +48,12 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
48 48
49 @Override 49 @Override
50 public boolean isCoalescing() { 50 public boolean isCoalescing() {
51 return true; 51 return false;
52 } 52 }
53 53
54 @Override 54 @Override
55 public boolean isIndexed(IInputKey key, IndexingService service) { 55 public boolean isIndexed(IInputKey key, IndexingService service) {
56 if (key instanceof RelationView<?> relationalKey) { 56 if (key instanceof AnyRelationView relationalKey) {
57 return this.modelUpdateListener.containsRelationView(relationalKey); 57 return this.modelUpdateListener.containsRelationView(relationalKey);
58 } else { 58 } else {
59 return false; 59 return false;
@@ -63,7 +63,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
63 @Override 63 @Override
64 public void ensureIndexed(IInputKey key, IndexingService service) { 64 public void ensureIndexed(IInputKey key, IndexingService service) {
65 if (!isIndexed(key, service)) { 65 if (!isIndexed(key, service)) {
66 throw new IllegalStateException("Engine tries to index a new key " + key); 66 throw new IllegalStateException("Engine tries to index a new key %s".formatted(key));
67 } 67 }
68 } 68 }
69 69
@@ -73,7 +73,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
73 if (modelUpdateListener.containsRelationView(relationViewKey)) { 73 if (modelUpdateListener.containsRelationView(relationViewKey)) {
74 return relationViewKey; 74 return relationViewKey;
75 } else { 75 } else {
76 throw new IllegalStateException("Query is asking for non-indexed key"); 76 throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(relationViewKey));
77 } 77 }
78 } else { 78 } else {
79 throw new IllegalStateException("Query is asking for non-relational key"); 79 throw new IllegalStateException("Query is asking for non-relational key");
@@ -131,7 +131,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
131 131
132 @Override 132 @Override
133 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { 133 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
134 var relationViewKey = (RelationView<?>) checkKey(key); 134 var relationViewKey = checkKey(key);
135 this.modelUpdateListener.addListener(key, relationViewKey, seed, listener); 135 this.modelUpdateListener.addListener(key, relationViewKey, seed, listener);
136 136
137 } 137 }
@@ -168,7 +168,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
168 } 168 }
169 169
170 @Override 170 @Override
171 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException { 171 public void executeAfterTraversal(Runnable runnable) {
172 runnable.run(); 172 runnable.run();
173 } 173 }
174} 174}
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 aa3fba6e..2b5618d2 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
@@ -1,5 +1,6 @@
1package tools.refinery.store.query.viatra.internal.pquery; 1package tools.refinery.store.query.viatra.internal.pquery;
2 2
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
3import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; 4import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
4import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; 5import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable;
5import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; 6import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality;
@@ -20,20 +21,28 @@ import tools.refinery.store.query.atom.*;
20import tools.refinery.store.query.view.AnyRelationView; 21import tools.refinery.store.query.view.AnyRelationView;
21 22
22import java.util.*; 23import java.util.*;
24import java.util.function.Function;
23import java.util.stream.Collectors; 25import java.util.stream.Collectors;
24 26
25public class DNF2PQuery { 27public class DNF2PQuery {
26 private final Set<DNF> translating = new LinkedHashSet<>(); 28 private final Set<DNF> translating = new LinkedHashSet<>();
27 29
28 private final Map<DNF, SimplePQuery> dnf2PQueryMap = new HashMap<>(); 30 private final Map<DNF, RawPQuery> dnf2PQueryMap = new HashMap<>();
29 31
30 private final Map<AnyRelationView, RelationViewWrapper> view2WrapperMap = new HashMap<>(); 32 private final Map<AnyRelationView, RelationViewWrapper> view2WrapperMap = new LinkedHashMap<>();
31 33
32 public SimplePQuery translate(DNF dnfQuery) { 34 private Function<DNF, QueryEvaluationHint> computeHint = dnf -> new QueryEvaluationHint(null,
35 QueryEvaluationHint.BackendRequirement.UNSPECIFIED);
36
37 public void setComputeHint(Function<DNF, QueryEvaluationHint> computeHint) {
38 this.computeHint = computeHint;
39 }
40
41 public RawPQuery translate(DNF dnfQuery) {
33 if (translating.contains(dnfQuery)) { 42 if (translating.contains(dnfQuery)) {
34 var path = translating.stream().map(DNF::getName).collect(Collectors.joining(" -> ")); 43 var path = translating.stream().map(DNF::name).collect(Collectors.joining(" -> "));
35 throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path, 44 throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path,
36 dnfQuery.getName())); 45 dnfQuery.name()));
37 } 46 }
38 // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant 47 // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant
39 // way, which would cause a ConcurrentModificationException with computeIfAbsent. 48 // way, which would cause a ConcurrentModificationException with computeIfAbsent.
@@ -50,8 +59,17 @@ public class DNF2PQuery {
50 return pQuery; 59 return pQuery;
51 } 60 }
52 61
53 private SimplePQuery doTranslate(DNF dnfQuery) { 62 public Collection<AnyRelationView> getRelationViews() {
54 var pQuery = new SimplePQuery(dnfQuery.getUniqueName()); 63 return Collections.unmodifiableCollection(view2WrapperMap.keySet());
64 }
65
66 public RawPQuery getAlreadyTranslated(DNF dnfQuery) {
67 return dnf2PQueryMap.get(dnfQuery);
68 }
69
70 private RawPQuery doTranslate(DNF dnfQuery) {
71 var pQuery = new RawPQuery(dnfQuery.getUniqueName());
72 pQuery.setEvaluationHints(computeHint.apply(dnfQuery));
55 73
56 Map<Variable, PParameter> parameters = new HashMap<>(); 74 Map<Variable, PParameter> parameters = new HashMap<>();
57 for (Variable variable : dnfQuery.getParameters()) { 75 for (Variable variable : dnfQuery.getParameters()) {
@@ -86,7 +104,7 @@ public class DNF2PQuery {
86 translateEquivalenceAtom(equivalenceAtom, body); 104 translateEquivalenceAtom(equivalenceAtom, body);
87 } else if (constraint instanceof RelationViewAtom relationViewAtom) { 105 } else if (constraint instanceof RelationViewAtom relationViewAtom) {
88 translateRelationViewAtom(relationViewAtom, body); 106 translateRelationViewAtom(relationViewAtom, body);
89 } else if (constraint instanceof CallAtom<?> callAtom) { 107 } else if (constraint instanceof DNFCallAtom callAtom) {
90 translateCallAtom(callAtom, body); 108 translateCallAtom(callAtom, body);
91 } else if (constraint instanceof ConstantAtom constantAtom) { 109 } else if (constraint instanceof ConstantAtom constantAtom) {
92 translateConstantAtom(constantAtom, body); 110 translateConstantAtom(constantAtom, body);
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
index a367cbf2..5d0b9e82 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SimplePQuery.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
@@ -3,27 +3,24 @@ package tools.refinery.store.query.viatra.internal.pquery;
3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; 3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; 4import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
5import org.eclipse.viatra.query.runtime.api.scope.QueryScope; 5import org.eclipse.viatra.query.runtime.api.scope.QueryScope;
6import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
7import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; 6import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
8import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; 7import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery;
9import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; 8import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter;
10import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; 9import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility;
11import tools.refinery.store.query.viatra.internal.RawPatternMatcher;
12import tools.refinery.store.query.viatra.internal.RelationalScope; 10import tools.refinery.store.query.viatra.internal.RelationalScope;
13 11
14import java.util.LinkedHashSet; 12import java.util.LinkedHashSet;
15import java.util.List; 13import java.util.List;
16import java.util.Set; 14import java.util.Set;
17 15
18public class SimplePQuery extends BasePQuery { 16public class RawPQuery extends BasePQuery {
19 private final String fullyQualifiedName; 17 private final String fullyQualifiedName;
20 private List<PParameter> parameters; 18 private List<PParameter> parameters;
21 private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>(); 19 private final LinkedHashSet<PBody> bodies = new LinkedHashSet<>();
22 20
23 public SimplePQuery(String name) { 21 public RawPQuery(String name) {
24 super(PVisibility.PUBLIC); 22 super(PVisibility.PUBLIC);
25 fullyQualifiedName = name; 23 fullyQualifiedName = name;
26 setEvaluationHints(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.UNSPECIFIED));
27 } 24 }
28 25
29 @Override 26 @Override
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java
index 2c488319..e944e873 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RawPatternMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java
@@ -1,7 +1,8 @@
1package tools.refinery.store.query.viatra.internal; 1package tools.refinery.store.query.viatra.internal.pquery;
2 2
3import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; 3import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher;
4import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; 4import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
5import tools.refinery.store.query.ResultSet;
5import tools.refinery.store.query.viatra.ViatraTupleLike; 6import tools.refinery.store.query.viatra.ViatraTupleLike;
6import tools.refinery.store.tuple.Tuple; 7import tools.refinery.store.tuple.Tuple;
7import tools.refinery.store.tuple.TupleLike; 8import tools.refinery.store.tuple.TupleLike;
@@ -9,7 +10,7 @@ import tools.refinery.store.tuple.TupleLike;
9import java.util.Optional; 10import java.util.Optional;
10import java.util.stream.Stream; 11import java.util.stream.Stream;
11 12
12public class RawPatternMatcher extends GenericPatternMatcher { 13public class RawPatternMatcher extends GenericPatternMatcher implements ResultSet {
13 protected final Object[] empty; 14 protected final Object[] empty;
14 15
15 public RawPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) { 16 public RawPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) {
@@ -17,34 +18,42 @@ public class RawPatternMatcher extends GenericPatternMatcher {
17 empty = new Object[specification.getParameterNames().size()]; 18 empty = new Object[specification.getParameterNames().size()];
18 } 19 }
19 20
21 @Override
20 public boolean hasResult() { 22 public boolean hasResult() {
21 return backend.hasMatch(empty); 23 return backend.hasMatch(empty);
22 } 24 }
23 25
26 @Override
24 public boolean hasResult(Tuple parameters) { 27 public boolean hasResult(Tuple parameters) {
25 return backend.hasMatch(toParametersArray(parameters)); 28 return backend.hasMatch(toParametersArray(parameters));
26 } 29 }
27 30
31 @Override
28 public Optional<TupleLike> oneResult() { 32 public Optional<TupleLike> oneResult() {
29 return backend.getOneArbitraryMatch(empty).map(ViatraTupleLike::new); 33 return backend.getOneArbitraryMatch(empty).map(ViatraTupleLike::new);
30 } 34 }
31 35
36 @Override
32 public Optional<TupleLike> oneResult(Tuple parameters) { 37 public Optional<TupleLike> oneResult(Tuple parameters) {
33 return backend.getOneArbitraryMatch(toParametersArray(parameters)).map(ViatraTupleLike::new); 38 return backend.getOneArbitraryMatch(toParametersArray(parameters)).map(ViatraTupleLike::new);
34 } 39 }
35 40
41 @Override
36 public Stream<TupleLike> allResults() { 42 public Stream<TupleLike> allResults() {
37 return backend.getAllMatches(empty).map(ViatraTupleLike::new); 43 return backend.getAllMatches(empty).map(ViatraTupleLike::new);
38 } 44 }
39 45
46 @Override
40 public Stream<TupleLike> allResults(Tuple parameters) { 47 public Stream<TupleLike> allResults(Tuple parameters) {
41 return backend.getAllMatches(toParametersArray(parameters)).map(ViatraTupleLike::new); 48 return backend.getAllMatches(toParametersArray(parameters)).map(ViatraTupleLike::new);
42 } 49 }
43 50
51 @Override
44 public int countResults() { 52 public int countResults() {
45 return backend.countMatches(empty); 53 return backend.countMatches(empty);
46 } 54 }
47 55
56 @Override
48 public int countResults(Tuple parameters) { 57 public int countResults(Tuple parameters) {
49 return backend.countMatches(toParametersArray(parameters)); 58 return backend.countMatches(toParametersArray(parameters));
50 } 59 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
index e48648bf..c442add8 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
@@ -10,7 +10,7 @@ public class RelationViewWrapper extends BaseInputKeyWrapper<AnyRelationView> {
10 10
11 @Override 11 @Override
12 public String getPrettyPrintableName() { 12 public String getPrettyPrintableName() {
13 return wrappedKey.getName(); 13 return wrappedKey.name();
14 } 14 }
15 15
16 @Override 16 @Override
@@ -20,7 +20,7 @@ public class RelationViewWrapper extends BaseInputKeyWrapper<AnyRelationView> {
20 20
21 @Override 21 @Override
22 public int getArity() { 22 public int getArity() {
23 return wrappedKey.getArity(); 23 return wrappedKey.arity();
24 } 24 }
25 25
26 @Override 26 @Override
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
new file mode 100644
index 00000000..1ae3daa7
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
@@ -0,0 +1,46 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import tools.refinery.store.model.Model;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.query.view.RelationView;
9
10import java.util.Collection;
11import java.util.HashMap;
12import java.util.Map;
13
14public class ModelUpdateListener {
15 private final Map<AnyRelationView, RelationViewUpdateListener<?>> relationViewUpdateListeners;
16
17 public ModelUpdateListener(Model model, Collection<AnyRelationView> relationViews) {
18 relationViewUpdateListeners = new HashMap<>(relationViews.size());
19 for (var relationView : relationViews) {
20 registerView(model, (RelationView<?>) relationView);
21 }
22 }
23
24 private <T> void registerView(Model model, RelationView<T> relationView) {
25 var listener = RelationViewUpdateListener.of(relationView);
26 var interpretation = model.getInterpretation(relationView.getSymbol());
27 interpretation.addListener(listener, true);
28 relationViewUpdateListeners.put(relationView, listener);
29 }
30
31 public boolean containsRelationView(AnyRelationView relationView) {
32 return relationViewUpdateListeners.containsKey(relationView);
33 }
34
35 public void addListener(IInputKey key, AnyRelationView relationView, ITuple seed,
36 IQueryRuntimeContextListener listener) {
37 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView);
38 relationViewUpdateListener.addFilter(key, seed, listener);
39 }
40
41 public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed,
42 IQueryRuntimeContextListener listener) {
43 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView);
44 relationViewUpdateListener.removeFilter(key, seed, listener);
45 }
46}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
new file mode 100644
index 00000000..221f1b4a
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
@@ -0,0 +1,66 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
7
8import java.util.Arrays;
9import java.util.Objects;
10
11public final class RelationViewFilter {
12 private final IInputKey inputKey;
13 private final Object[] seed;
14 private final IQueryRuntimeContextListener listener;
15
16 public RelationViewFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
17 this.inputKey = inputKey;
18 this.seed = seedToArray(seed);
19 this.listener = listener;
20 }
21
22 public void update(Tuple updateTuple, boolean isInsertion) {
23 if (isMatching(updateTuple)) {
24 listener.update(inputKey, updateTuple, isInsertion);
25 }
26 }
27
28 private boolean isMatching(ITuple tuple) {
29 if (seed == null) {
30 return true;
31 }
32 int size = seed.length;
33 for (int i = 0; i < size; i++) {
34 var filterElement = seed[i];
35 if (filterElement != null && !filterElement.equals(tuple.get(i))) {
36 return false;
37 }
38 }
39 return true;
40 }
41
42 // Use <code>null</code> instead of an empty array to speed up comparisons.
43 @SuppressWarnings("squid:S1168")
44 private static Object[] seedToArray(ITuple seed) {
45 for (var element : seed.getElements()) {
46 if (element != null) {
47 return seed.getElements();
48 }
49 }
50 return null;
51 }
52
53 @Override
54 public boolean equals(Object obj) {
55 if (obj == this) return true;
56 if (obj == null || obj.getClass() != this.getClass()) return false;
57 var that = (RelationViewFilter) obj;
58 return Objects.equals(this.inputKey, that.inputKey) && Arrays.equals(this.seed, that.seed) &&
59 Objects.equals(this.listener, that.listener);
60 }
61
62 @Override
63 public int hashCode() {
64 return Objects.hash(inputKey, Arrays.hashCode(seed), listener);
65 }
66}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java
new file mode 100644
index 00000000..e0d44e34
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java
@@ -0,0 +1,40 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
7import tools.refinery.store.model.InterpretationListener;
8import tools.refinery.store.query.view.RelationView;
9import tools.refinery.store.query.view.TuplePreservingRelationView;
10
11import java.util.ArrayList;
12import java.util.List;
13
14public abstract class RelationViewUpdateListener<T> implements InterpretationListener<T> {
15 private final List<RelationViewFilter> filters = new ArrayList<>();
16
17 public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
18 filters.add(new RelationViewFilter(inputKey, seed, listener));
19 }
20
21 public void removeFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) {
22 filters.remove(new RelationViewFilter(inputKey, seed, listener));
23 }
24
25 protected void processUpdate(Tuple tuple, boolean isInsertion) {
26 int size = filters.size();
27 // Use a for loop instead of a for-each loop to avoid <code>Iterator</code> allocation overhead.
28 //noinspection ForLoopReplaceableByForEach
29 for (int i = 0; i < size; i++) {
30 filters.get(i).update(tuple, isInsertion);
31 }
32 }
33
34 public static <T> RelationViewUpdateListener<T> of(RelationView<T> relationView) {
35 if (relationView instanceof TuplePreservingRelationView<T> tuplePreservingRelationView) {
36 return new TuplePreservingRelationViewUpdateListener<>(tuplePreservingRelationView);
37 }
38 return new TupleChangingRelationViewUpdateListener<>(relationView);
39 }
40}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
new file mode 100644
index 00000000..c17e826d
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
@@ -0,0 +1,35 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.query.view.RelationView;
5import tools.refinery.store.tuple.Tuple;
6
7import java.util.Arrays;
8
9public class TupleChangingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> {
10 private final RelationView<T> relationView;
11
12 TupleChangingRelationViewUpdateListener(RelationView<T> relationView) {
13 this.relationView = relationView;
14 }
15
16 @Override
17 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
18 boolean fromPresent = relationView.filter(key, fromValue);
19 boolean toPresent = relationView.filter(key, toValue);
20 if (fromPresent) {
21 if (toPresent) { // value change
22 var fromArray = relationView.forwardMap(key, fromValue);
23 var toArray = relationView.forwardMap(key, toValue);
24 if (!Arrays.equals(fromArray, toArray)) {
25 processUpdate(Tuples.flatTupleOf(fromArray), false);
26 processUpdate(Tuples.flatTupleOf(toArray), true);
27 }
28 } else { // fromValue disappears
29 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, fromValue)), false);
30 }
31 } else if (toPresent) { // toValue disappears
32 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, toValue)), true);
33 }
34 }
35}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java
new file mode 100644
index 00000000..9c3ef61c
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java
@@ -0,0 +1,24 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.query.view.TuplePreservingRelationView;
5import tools.refinery.store.tuple.Tuple;
6
7public class TuplePreservingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> {
8 private final TuplePreservingRelationView<T> view;
9
10 TuplePreservingRelationViewUpdateListener(TuplePreservingRelationView<T> view) {
11 this.view = view;
12 }
13
14 @Override
15 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
16 boolean fromPresent = view.filter(key, fromValue);
17 boolean toPresent = view.filter(key, toValue);
18 if (fromPresent == toPresent) {
19 return;
20 }
21 var translated = Tuples.flatTupleOf(view.forwardMap(key));
22 processUpdate(translated, toPresent);
23 }
24}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java
deleted file mode 100644
index 6a1d06a9..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ModelUpdateListener.java
+++ /dev/null
@@ -1,112 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import tools.refinery.store.model.representation.AnyRelation;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.tuple.Tuple;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.query.view.RelationView;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17public class ModelUpdateListener {
18 /**
19 * Collections of Relations and their Views.
20 */
21 private final Map<AnyRelation, Set<AnyRelationView>> relation2View;
22
23 /**
24 * Collection of Views and their buffers.
25 */
26 private final Map<AnyRelationView, Set<ViewUpdateBuffer<?>>> view2Buffers;
27
28 public ModelUpdateListener(Set<AnyRelationView> relationViews) {
29 this.relation2View = new HashMap<>();
30 this.view2Buffers = new HashMap<>();
31
32 for (var relationView : relationViews) {
33 registerView(relationView);
34 }
35 }
36
37 private void registerView(AnyRelationView view) {
38 AnyRelation relation = view.getRepresentation();
39
40 // 1. register views to relations, if necessary
41 var views = relation2View.computeIfAbsent(relation, x -> new HashSet<>());
42 views.add(view);
43
44 // 2. register notifier map to views, if necessary
45 view2Buffers.computeIfAbsent(view, x -> new HashSet<>());
46 }
47
48 public boolean containsRelationView(AnyRelationView relationalKey) {
49 return view2Buffers.containsKey(relationalKey);
50 }
51
52 public <D> void addListener(IInputKey key, RelationView<D> relationView, ITuple seed,
53 IQueryRuntimeContextListener listener) {
54 if (view2Buffers.containsKey(relationView)) {
55 ViewUpdateTranslator<D> updateListener = new ViewUpdateTranslator<>(key, relationView, seed, listener);
56 ViewUpdateBuffer<D> updateBuffer = new ViewUpdateBuffer<>(updateListener);
57 view2Buffers.get(relationView).add(updateBuffer);
58 } else {
59 throw new IllegalArgumentException();
60 }
61 }
62
63 public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed,
64 IQueryRuntimeContextListener listener) {
65 if (view2Buffers.containsKey(relationView)) {
66 Set<ViewUpdateBuffer<?>> buffers = this.view2Buffers.get(relationView);
67 for (var buffer : buffers) {
68 if (buffer.getUpdateListener().equals(key, relationView, seed, listener)) {
69 // remove buffer and terminate immediately, or it will break iterator.
70 buffers.remove(buffer);
71 return;
72 }
73 }
74 } else {
75 throw new IllegalArgumentException("Relation view is not registered for updates");
76 }
77 }
78
79 public <D> void addUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) {
80 var views = this.relation2View.get(relation);
81 if (views == null) {
82 return;
83 }
84 for (var view : views) {
85 var buffers = this.view2Buffers.get(view);
86 for (var buffer : buffers) {
87 @SuppressWarnings("unchecked")
88 var typedBuffer = (ViewUpdateBuffer<D>) buffer;
89 typedBuffer.addChange(key, oldValue, newValue);
90 }
91 }
92 }
93
94 public boolean hasChanges() {
95 for (var bufferCollection : this.view2Buffers.values()) {
96 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
97 if (buffer.hasChanges()) {
98 return true;
99 }
100 }
101 }
102 return false;
103 }
104
105 public void flush() {
106 for (var bufferCollection : this.view2Buffers.values()) {
107 for (ViewUpdateBuffer<?> buffer : bufferCollection) {
108 buffer.flush();
109 }
110 }
111 }
112}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java
deleted file mode 100644
index b9406018..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdate.java
+++ /dev/null
@@ -1,32 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import java.util.Arrays;
4import java.util.Objects;
5
6record ViewUpdate(Object[] tuple, boolean isInsertion) {
7 @Override
8 public int hashCode() {
9 final int prime = 31;
10 int result = 1;
11 result = prime * result + Arrays.deepHashCode(tuple);
12 result = prime * result + Objects.hash(isInsertion);
13 return result;
14 }
15
16 @Override
17 public boolean equals(Object obj) {
18 if (this == obj)
19 return true;
20 if (obj == null)
21 return false;
22 if (getClass() != obj.getClass())
23 return false;
24 ViewUpdate other = (ViewUpdate) obj;
25 return isInsertion == other.isInsertion && Arrays.deepEquals(tuple, other.tuple);
26 }
27
28 @Override
29 public String toString() {
30 return "ViewUpdate [" + Arrays.toString(tuple) + "insertion= " + this.isInsertion + "]";
31 }
32}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java
deleted file mode 100644
index 49f4c501..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateBuffer.java
+++ /dev/null
@@ -1,47 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import tools.refinery.store.tuple.Tuple;
4
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.List;
8
9public class ViewUpdateBuffer<D> {
10 protected final ViewUpdateTranslator<D> updateListener;
11
12 protected final List<ViewUpdate> buffer = new ArrayList<>();
13
14 public ViewUpdateBuffer(ViewUpdateTranslator<D> updateListener) {
15 this.updateListener = updateListener;
16 }
17
18 public ViewUpdateTranslator<D> getUpdateListener() {
19 return updateListener;
20 }
21
22 public boolean hasChanges() {
23 return !buffer.isEmpty();
24 }
25
26 public void addChange(Tuple tuple, D oldValue, D newValue) {
27 if (oldValue != newValue) {
28 Object[] oldTuple = updateListener.isMatching(tuple, oldValue);
29 Object[] newTuple = updateListener.isMatching(tuple, newValue);
30 if (!Arrays.equals(oldTuple, newTuple)) {
31 if (oldTuple != null) {
32 buffer.add(new ViewUpdate(oldTuple, false));
33 }
34 if (newTuple != null) {
35 buffer.add(new ViewUpdate(newTuple, true));
36 }
37 }
38 }
39 }
40
41 public void flush() {
42 for (ViewUpdate viewChange : buffer) {
43 updateListener.processChange(viewChange);
44 }
45 buffer.clear();
46 }
47}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java
deleted file mode 100644
index c324c84a..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/viewupdate/ViewUpdateTranslator.java
+++ /dev/null
@@ -1,73 +0,0 @@
1package tools.refinery.store.query.viatra.internal.viewupdate;
2
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
7import tools.refinery.store.query.view.AnyRelationView;
8import tools.refinery.store.query.view.RelationView;
9import tools.refinery.store.tuple.Tuple;
10
11import java.util.Objects;
12
13public class ViewUpdateTranslator<D> {
14 private final IInputKey wrappedKey;
15
16 private final RelationView<D> key;
17
18 private final ITuple filter;
19
20 private final IQueryRuntimeContextListener listener;
21
22 public ViewUpdateTranslator(IInputKey wrappedKey, RelationView<D> key, ITuple filter,
23 IQueryRuntimeContextListener listener) {
24 super();
25 this.wrappedKey = wrappedKey;
26 this.key = key;
27 this.filter = filter;
28 this.listener = listener;
29 }
30
31 public boolean equals(IInputKey wrappedKey, AnyRelationView relationView, ITuple seed,
32 IQueryRuntimeContextListener listener) {
33 return this.wrappedKey == wrappedKey && key == relationView && filter.equals(seed) && this.listener == listener;
34 }
35
36 public void processChange(ViewUpdate change) {
37 listener.update(wrappedKey, Tuples.flatTupleOf(change.tuple()), change.isInsertion());
38 }
39
40 @SuppressWarnings("squid:S1168")
41 public Object[] isMatching(Tuple tuple, D value) {
42 if (!key.filter(tuple, value)) {
43 return null;
44 }
45 return isMatching(key.forwardMap(tuple, value), filter);
46 }
47
48 @SuppressWarnings("squid:S1168")
49 private Object[] isMatching(Object[] tuple, ITuple filter) {
50 for (int i = 0; i < filter.getSize(); i++) {
51 final Object filterObject = filter.get(i);
52 if (filterObject != null && !filterObject.equals(tuple[i])) {
53 return null;
54 }
55 }
56 return tuple;
57 }
58
59 @Override
60 public int hashCode() {
61 return Objects.hash(filter, key, listener);
62 }
63
64 @Override
65 public boolean equals(Object obj) {
66 if (this == obj)
67 return true;
68 if (!(obj instanceof ViewUpdateTranslator<?> other))
69 return false;
70 return Objects.equals(filter, other.filter) && Objects.equals(key, other.key)
71 && Objects.equals(listener, other.listener);
72 }
73}
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 e82e006c..72e8d7e5 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
@@ -1,17 +1,20 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.query.DNF;
6import tools.refinery.store.query.*; 6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.Variable;
7import tools.refinery.store.query.atom.*; 8import tools.refinery.store.query.atom.*;
8import tools.refinery.store.query.view.FilteredRelationView; 9import tools.refinery.store.query.view.FilteredRelationView;
9import tools.refinery.store.query.view.KeyOnlyRelationView; 10import tools.refinery.store.query.view.KeyOnlyRelationView;
10import tools.refinery.store.query.view.RelationView; 11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.representation.TruthValue;
11import tools.refinery.store.tuple.Tuple; 13import tools.refinery.store.tuple.Tuple;
12import tools.refinery.store.tuple.TupleLike; 14import tools.refinery.store.tuple.TupleLike;
13 15
14import java.util.*; 16import java.util.HashSet;
17import java.util.Set;
15import java.util.stream.Stream; 18import java.util.stream.Stream;
16 19
17import static org.junit.jupiter.api.Assertions.assertEquals; 20import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -19,41 +22,49 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
19class QueryTest { 22class QueryTest {
20 @Test 23 @Test
21 void typeConstraintTest() { 24 void typeConstraintTest() {
22 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 25 var person = new Symbol<>("Person", 1, Boolean.class, false);
23 Relation<Boolean> asset = new Relation<>("Asset", 1, Boolean.class, false); 26 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
24 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 27 var personView = new KeyOnlyRelationView<>(person);
25 28
26 var p1 = new Variable("p1"); 29 var p1 = new Variable("p1");
27 DNF predicate = DNF.builder("TypeConstraint") 30 var predicate = DNF.builder("TypeConstraint")
28 .parameters(p1) 31 .parameters(p1)
29 .clause(new RelationViewAtom(personView, p1)) 32 .clause(new RelationViewAtom(personView, p1))
30 .build(); 33 .build();
31 34
32 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), 35 var store = ModelStore.builder()
33 Set.of(predicate)); 36 .symbols(person, asset)
34 QueryableModel model = store.createModel(); 37 .with(ViatraModelQuery.ADAPTER)
38 .queries(predicate)
39 .build();
40
41 var model = store.createModel();
42 var personInterpretation = model.getInterpretation(person);
43 var assetInterpretation = model.getInterpretation(asset);
44 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
45 var predicateResultSet = queryEngine.getResultSet(predicate);
35 46
36 model.put(person, Tuple.of(0), true); 47 personInterpretation.put(Tuple.of(0), true);
37 model.put(person, Tuple.of(1), true); 48 personInterpretation.put(Tuple.of(1), true);
38 model.put(asset, Tuple.of(1), true);
39 model.put(asset, Tuple.of(2), true);
40 49
41 model.flushChanges(); 50 assetInterpretation.put(Tuple.of(1), true);
42 assertEquals(2, model.countResults(predicate)); 51 assetInterpretation.put(Tuple.of(2), true);
43 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); 52
53 queryEngine.flushChanges();
54 assertEquals(2, predicateResultSet.countResults());
55 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1)));
44 } 56 }
45 57
46 @Test 58 @Test
47 void relationConstraintTest() { 59 void relationConstraintTest() {
48 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 60 var person = new Symbol<>("Person", 1, Boolean.class, false);
49 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 61 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
50 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 62 var personView = new KeyOnlyRelationView<>(person);
51 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 63 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
52 TruthValue::must); 64
53 65 var p1 = new Variable("p1");
54 Variable p1 = new Variable("p1"); 66 var p2 = new Variable("p2");
55 Variable p2 = new Variable("p2"); 67 var predicate = DNF.builder("RelationConstraint")
56 DNF predicate = DNF.builder("RelationConstraint")
57 .parameters(p1, p2) 68 .parameters(p1, p2)
58 .clause( 69 .clause(
59 new RelationViewAtom(personView, p1), 70 new RelationViewAtom(personView, p1),
@@ -62,37 +73,45 @@ class QueryTest {
62 ) 73 )
63 .build(); 74 .build();
64 75
65 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 76 var store = ModelStore.builder()
66 Set.of(personView, friendMustView), Set.of(predicate)); 77 .symbols(person, friend)
67 QueryableModel model = store.createModel(); 78 .with(ViatraModelQuery.ADAPTER)
79 .queries(predicate)
80 .build();
81
82 var model = store.createModel();
83 var personInterpretation = model.getInterpretation(person);
84 var friendInterpretation = model.getInterpretation(friend);
85 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
86 var predicateResultSet = queryEngine.getResultSet(predicate);
68 87
69 assertEquals(0, model.countResults(predicate)); 88 assertEquals(0, predicateResultSet.countResults());
70 89
71 model.put(person, Tuple.of(0), true); 90 personInterpretation.put(Tuple.of(0), true);
72 model.put(person, Tuple.of(1), true); 91 personInterpretation.put(Tuple.of(1), true);
73 model.put(person, Tuple.of(2), true); 92 personInterpretation.put(Tuple.of(2), true);
74 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
75 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
76 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
77 93
78 assertEquals(0, model.countResults(predicate)); 94 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
95 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
96 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
79 97
80 model.flushChanges(); 98 assertEquals(0, predicateResultSet.countResults());
81 assertEquals(3, model.countResults(predicate)); 99
82 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); 100 queryEngine.flushChanges();
101 assertEquals(3, predicateResultSet.countResults());
102 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2)));
83 } 103 }
84 104
85 @Test 105 @Test
86 void andTest() { 106 void andTest() {
87 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 107 var person = new Symbol<>("Person", 1, Boolean.class, false);
88 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 108 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
89 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 109 var personView = new KeyOnlyRelationView<>(person);
90 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 110 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
91 TruthValue::must); 111
92 112 var p1 = new Variable("p1");
93 Variable p1 = new Variable("p1"); 113 var p2 = new Variable("p2");
94 Variable p2 = new Variable("p2"); 114 var predicate = DNF.builder("RelationConstraint")
95 DNF predicate = DNF.builder("RelationConstraint")
96 .parameters(p1, p2) 115 .parameters(p1, p2)
97 .clause( 116 .clause(
98 new RelationViewAtom(personView, p1), 117 new RelationViewAtom(personView, p1),
@@ -102,45 +121,52 @@ class QueryTest {
102 ) 121 )
103 .build(); 122 .build();
104 123
105 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 124 var store = ModelStore.builder()
106 Set.of(personView, friendMustView), Set.of(predicate)); 125 .symbols(person, friend)
107 QueryableModel model = store.createModel(); 126 .with(ViatraModelQuery.ADAPTER)
127 .queries(predicate)
128 .build();
129
130 var model = store.createModel();
131 var personInterpretation = model.getInterpretation(person);
132 var friendInterpretation = model.getInterpretation(friend);
133 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
134 var predicateResultSet = queryEngine.getResultSet(predicate);
108 135
109 assertEquals(0, model.countResults(predicate)); 136 assertEquals(0, predicateResultSet.countResults());
110 137
111 model.put(person, Tuple.of(0), true); 138 personInterpretation.put(Tuple.of(0), true);
112 model.put(person, Tuple.of(1), true); 139 personInterpretation.put(Tuple.of(1), true);
113 model.put(person, Tuple.of(2), true); 140 personInterpretation.put(Tuple.of(2), true);
114 141
115 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); 142 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
116 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); 143 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
117 144
118 model.flushChanges(); 145 queryEngine.flushChanges();
119 assertEquals(0, model.countResults(predicate)); 146 assertEquals(0, predicateResultSet.countResults());
120 147
121 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); 148 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
122 model.flushChanges(); 149 queryEngine.flushChanges();
123 assertEquals(2, model.countResults(predicate)); 150 assertEquals(2, predicateResultSet.countResults());
124 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); 151 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0)));
125 152
126 model.put(friend, Tuple.of(2, 0), TruthValue.TRUE); 153 friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE);
127 model.flushChanges(); 154 queryEngine.flushChanges();
128 assertEquals(4, model.countResults(predicate)); 155 assertEquals(4, predicateResultSet.countResults());
129 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), 156 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2),
130 Tuple.of(2, 0))); 157 Tuple.of(2, 0)));
131 } 158 }
132 159
133 @Test 160 @Test
134 void existTest() { 161 void existTest() {
135 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 162 var person = new Symbol<>("Person", 1, Boolean.class, false);
136 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 163 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
137 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 164 var personView = new KeyOnlyRelationView<>(person);
138 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 165 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
139 TruthValue::must); 166
140 167 var p1 = new Variable("p1");
141 Variable p1 = new Variable("p1"); 168 var p2 = new Variable("p2");
142 Variable p2 = new Variable("p2"); 169 var predicate = DNF.builder("RelationConstraint")
143 DNF predicate = DNF.builder("RelationConstraint")
144 .parameters(p1) 170 .parameters(p1)
145 .clause( 171 .clause(
146 new RelationViewAtom(personView, p1), 172 new RelationViewAtom(personView, p1),
@@ -149,39 +175,45 @@ class QueryTest {
149 ) 175 )
150 .build(); 176 .build();
151 177
152 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 178 var store = ModelStore.builder()
153 Set.of(personView, friendMustView), Set.of(predicate)); 179 .symbols(person, friend)
154 QueryableModel model = store.createModel(); 180 .with(ViatraModelQuery.ADAPTER)
181 .queries(predicate)
182 .build();
183
184 var model = store.createModel();
185 var personInterpretation = model.getInterpretation(person);
186 var friendInterpretation = model.getInterpretation(friend);
187 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
188 var predicateResultSet = queryEngine.getResultSet(predicate);
155 189
156 assertEquals(0, model.countResults(predicate)); 190 personInterpretation.put(Tuple.of(0), true);
191 personInterpretation.put(Tuple.of(1), true);
192 personInterpretation.put(Tuple.of(2), true);
157 193
158 model.put(person, Tuple.of(0), true); 194 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
159 model.put(person, Tuple.of(1), true); 195 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
160 model.put(person, Tuple.of(2), true); 196 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
161 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
162 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
163 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
164 197
165 assertEquals(0, model.countResults(predicate)); 198 assertEquals(0, predicateResultSet.countResults());
166 199
167 model.flushChanges(); 200 queryEngine.flushChanges();
168 assertEquals(2, model.countResults(predicate)); 201 assertEquals(2, predicateResultSet.countResults());
169 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); 202 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1)));
170 } 203 }
171 204
172 @Test 205 @Test
173 void orTest() { 206 void orTest() {
174 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 207 var person = new Symbol<>("Person", 1, Boolean.class, false);
175 Relation<Boolean> animal = new Relation<>("Animal", 1, Boolean.class, false); 208 var animal = new Symbol<>("Animal", 1, Boolean.class, false);
176 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 209 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
177 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 210 var personView = new KeyOnlyRelationView<>(person);
178 RelationView<Boolean> animalView = new KeyOnlyRelationView(animal); 211 var animalView = new KeyOnlyRelationView<>(animal);
179 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 212 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
180 TruthValue::must); 213
181 214 var p1 = new Variable("p1");
182 Variable p1 = new Variable("p1"); 215 var p2 = new Variable("p2");
183 Variable p2 = new Variable("p2"); 216 var predicate = DNF.builder("Or")
184 DNF predicate = DNF.builder("Or")
185 .parameters(p1, p2) 217 .parameters(p1, p2)
186 .clause( 218 .clause(
187 new RelationViewAtom(personView, p1), 219 new RelationViewAtom(personView, p1),
@@ -195,32 +227,43 @@ class QueryTest {
195 ) 227 )
196 .build(); 228 .build();
197 229
198 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, animal, friend), 230 var store = ModelStore.builder()
199 Set.of(personView, animalView, friendMustView), Set.of(predicate)); 231 .symbols(person, animal, friend)
200 QueryableModel model = store.createModel(); 232 .with(ViatraModelQuery.ADAPTER)
201 233 .queries(predicate)
202 model.put(person, Tuple.of(0), true); 234 .build();
203 model.put(person, Tuple.of(1), true); 235
204 model.put(animal, Tuple.of(2), true); 236 var model = store.createModel();
205 model.put(animal, Tuple.of(3), true); 237 var personInterpretation = model.getInterpretation(person);
206 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); 238 var animalInterpretation = model.getInterpretation(animal);
207 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); 239 var friendInterpretation = model.getInterpretation(friend);
208 model.put(friend, Tuple.of(2, 3), TruthValue.TRUE); 240 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
209 model.put(friend, Tuple.of(3, 0), TruthValue.TRUE); 241 var predicateResultSet = queryEngine.getResultSet(predicate);
210 242
211 model.flushChanges(); 243 personInterpretation.put(Tuple.of(0), true);
212 assertEquals(2, model.countResults(predicate)); 244 personInterpretation.put(Tuple.of(1), true);
213 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); 245
246 animalInterpretation.put(Tuple.of(2), true);
247 animalInterpretation.put(Tuple.of(3), true);
248
249 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
250 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
251 friendInterpretation.put(Tuple.of(2, 3), TruthValue.TRUE);
252 friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE);
253
254 queryEngine.flushChanges();
255 assertEquals(2, predicateResultSet.countResults());
256 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(2, 3)));
214 } 257 }
215 258
216 @Test 259 @Test
217 void equalityTest() { 260 void equalityTest() {
218 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 261 var person = new Symbol<>("Person", 1, Boolean.class, false);
219 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 262 var personView = new KeyOnlyRelationView<>(person);
220 263
221 Variable p1 = new Variable("p1"); 264 var p1 = new Variable("p1");
222 Variable p2 = new Variable("p2"); 265 var p2 = new Variable("p2");
223 DNF predicate = DNF.builder("Equality") 266 var predicate = DNF.builder("Equality")
224 .parameters(p1, p2) 267 .parameters(p1, p2)
225 .clause( 268 .clause(
226 new RelationViewAtom(personView, p1), 269 new RelationViewAtom(personView, p1),
@@ -229,30 +272,37 @@ class QueryTest {
229 ) 272 )
230 .build(); 273 .build();
231 274
232 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person), Set.of(personView), Set.of(predicate)); 275 var store = ModelStore.builder()
233 QueryableModel model = store.createModel(); 276 .symbols(person)
277 .with(ViatraModelQuery.ADAPTER)
278 .queries(predicate)
279 .build();
280
281 var model = store.createModel();
282 var personInterpretation = model.getInterpretation(person);
283 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
284 var predicateResultSet = queryEngine.getResultSet(predicate);
234 285
235 model.put(person, Tuple.of(0), true); 286 personInterpretation.put(Tuple.of(0), true);
236 model.put(person, Tuple.of(1), true); 287 personInterpretation.put(Tuple.of(1), true);
237 model.put(person, Tuple.of(2), true); 288 personInterpretation.put(Tuple.of(2), true);
238 289
239 model.flushChanges(); 290 queryEngine.flushChanges();
240 assertEquals(3, model.countResults(predicate)); 291 assertEquals(3, predicateResultSet.countResults());
241 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); 292 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2)));
242 } 293 }
243 294
244 @Test 295 @Test
245 void inequalityTest() { 296 void inequalityTest() {
246 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 297 var person = new Symbol<>("Person", 1, Boolean.class, false);
247 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 298 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
248 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 299 var personView = new KeyOnlyRelationView<>(person);
249 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 300 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
250 TruthValue::must); 301
251 302 var p1 = new Variable("p1");
252 Variable p1 = new Variable("p1"); 303 var p2 = new Variable("p2");
253 Variable p2 = new Variable("p2"); 304 var p3 = new Variable("p3");
254 Variable p3 = new Variable("p3"); 305 var predicate = DNF.builder("Inequality")
255 DNF predicate = DNF.builder("Inequality")
256 .parameters(p1, p2, p3) 306 .parameters(p1, p2, p3)
257 .clause( 307 .clause(
258 new RelationViewAtom(personView, p1), 308 new RelationViewAtom(personView, p1),
@@ -263,32 +313,40 @@ class QueryTest {
263 ) 313 )
264 .build(); 314 .build();
265 315
266 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 316 var store = ModelStore.builder()
267 Set.of(personView, friendMustView), Set.of(predicate)); 317 .symbols(person, friend)
268 QueryableModel model = store.createModel(); 318 .with(ViatraModelQuery.ADAPTER)
319 .queries(predicate)
320 .build();
321
322 var model = store.createModel();
323 var personInterpretation = model.getInterpretation(person);
324 var friendInterpretation = model.getInterpretation(friend);
325 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
326 var predicateResultSet = queryEngine.getResultSet(predicate);
327
328 personInterpretation.put(Tuple.of(0), true);
329 personInterpretation.put(Tuple.of(1), true);
330 personInterpretation.put(Tuple.of(2), true);
269 331
270 model.put(person, Tuple.of(0), true); 332 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
271 model.put(person, Tuple.of(1), true); 333 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
272 model.put(person, Tuple.of(2), true);
273 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
274 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
275 334
276 model.flushChanges(); 335 queryEngine.flushChanges();
277 assertEquals(2, model.countResults(predicate)); 336 assertEquals(2, predicateResultSet.countResults());
278 compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); 337 compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2)));
279 } 338 }
280 339
281 @Test 340 @Test
282 void patternCallTest() { 341 void patternCallTest() {
283 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 342 var person = new Symbol<>("Person", 1, Boolean.class, false);
284 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 343 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
285 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 344 var personView = new KeyOnlyRelationView<>(person);
286 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 345 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
287 TruthValue::must); 346
288 347 var p1 = new Variable("p1");
289 Variable p1 = new Variable("p1"); 348 var p2 = new Variable("p2");
290 Variable p2 = new Variable("p2"); 349 var friendPredicate = DNF.builder("RelationConstraint")
291 DNF friendPredicate = DNF.builder("RelationConstraint")
292 .parameters(p1, p2) 350 .parameters(p1, p2)
293 .clause( 351 .clause(
294 new RelationViewAtom(personView, p1), 352 new RelationViewAtom(personView, p1),
@@ -297,44 +355,51 @@ class QueryTest {
297 ) 355 )
298 .build(); 356 .build();
299 357
300 Variable p3 = new Variable("p3"); 358 var p3 = new Variable("p3");
301 Variable p4 = new Variable("p4"); 359 var p4 = new Variable("p4");
302 DNF predicate = DNF.builder("PositivePatternCall") 360 var predicate = DNF.builder("PositivePatternCall")
303 .parameters(p3, p4) 361 .parameters(p3, p4)
304 .clause( 362 .clause(
305 new RelationViewAtom(personView, p3), 363 new RelationViewAtom(personView, p3),
306 new RelationViewAtom(personView, p4), 364 new RelationViewAtom(personView, p4),
307 new CallAtom<>(friendPredicate, p3, p4) 365 new DNFCallAtom(friendPredicate, p3, p4)
308 ) 366 )
309 .build(); 367 .build();
310 368
311 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 369 var store = ModelStore.builder()
312 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 370 .symbols(person, friend)
313 QueryableModel model = store.createModel(); 371 .with(ViatraModelQuery.ADAPTER)
372 .queries(predicate)
373 .build();
374
375 var model = store.createModel();
376 var personInterpretation = model.getInterpretation(person);
377 var friendInterpretation = model.getInterpretation(friend);
378 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
379 var predicateResultSet = queryEngine.getResultSet(predicate);
314 380
315 model.put(person, Tuple.of(0), true); 381 personInterpretation.put(Tuple.of(0), true);
316 model.put(person, Tuple.of(1), true); 382 personInterpretation.put(Tuple.of(1), true);
317 model.put(person, Tuple.of(2), true); 383 personInterpretation.put(Tuple.of(2), true);
318 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
319 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
320 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
321 384
322 model.flushChanges(); 385 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
386 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
387 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
323 388
324 assertEquals(3, model.countResults(friendPredicate)); 389 queryEngine.flushChanges();
390 assertEquals(3, predicateResultSet.countResults());
325 } 391 }
326 392
327 @Test 393 @Test
328 void negativePatternCallTest() { 394 void negativePatternCallTest() {
329 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 395 var person = new Symbol<>("Person", 1, Boolean.class, false);
330 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 396 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
331 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 397 var personView = new KeyOnlyRelationView<>(person);
332 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 398 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
333 TruthValue::must); 399
334 400 var p1 = new Variable("p1");
335 Variable p1 = new Variable("p1"); 401 var p2 = new Variable("p2");
336 Variable p2 = new Variable("p2"); 402 var friendPredicate = DNF.builder("RelationConstraint")
337 DNF friendPredicate = DNF.builder("RelationConstraint")
338 .parameters(p1, p2) 403 .parameters(p1, p2)
339 .clause( 404 .clause(
340 new RelationViewAtom(personView, p1), 405 new RelationViewAtom(personView, p1),
@@ -343,44 +408,52 @@ class QueryTest {
343 ) 408 )
344 .build(); 409 .build();
345 410
346 Variable p3 = new Variable("p3"); 411 var p3 = new Variable("p3");
347 Variable p4 = new Variable("p4"); 412 var p4 = new Variable("p4");
348 DNF predicate = DNF.builder("NegativePatternCall") 413 var predicate = DNF.builder("NegativePatternCall")
349 .parameters(p3, p4) 414 .parameters(p3, p4)
350 .clause( 415 .clause(
351 new RelationViewAtom(personView, p3), 416 new RelationViewAtom(personView, p3),
352 new RelationViewAtom(personView, p4), 417 new RelationViewAtom(personView, p4),
353 new CallAtom<>(false, friendPredicate, p3, p4) 418 new DNFCallAtom(false, friendPredicate, p3, p4)
354 ) 419 )
355 .build(); 420 .build();
356 421
357 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 422 var store = ModelStore.builder()
358 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 423 .symbols(person, friend)
359 QueryableModel model = store.createModel(); 424 .with(ViatraModelQuery.ADAPTER)
425 .queries(predicate)
426 .build();
427
428 var model = store.createModel();
429 var personInterpretation = model.getInterpretation(person);
430 var friendInterpretation = model.getInterpretation(friend);
431 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
432 var predicateResultSet = queryEngine.getResultSet(predicate);
433
434 personInterpretation.put(Tuple.of(0), true);
435 personInterpretation.put(Tuple.of(1), true);
436 personInterpretation.put(Tuple.of(2), true);
360 437
361 model.put(person, Tuple.of(0), true); 438 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
362 model.put(person, Tuple.of(1), true); 439 friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE);
363 model.put(person, Tuple.of(2), true); 440 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
364 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
365 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
366 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
367 441
368 model.flushChanges(); 442 queryEngine.flushChanges();
369 assertEquals(6, model.countResults(predicate)); 443 assertEquals(6, predicateResultSet.countResults());
370 } 444 }
371 445
372 @Test 446 @Test
373 void negativeWithQuantificationTest() { 447 void negativeWithQuantificationTest() {
374 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 448 var person = new Symbol<>("Person", 1, Boolean.class, false);
375 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 449 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
376 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 450 var personView = new KeyOnlyRelationView<>(person);
377 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 451 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
378 TruthValue::must);
379 452
380 Variable p1 = new Variable("p1"); 453 var p1 = new Variable("p1");
381 Variable p2 = new Variable("p2"); 454 var p2 = new Variable("p2");
382 455
383 DNF called = DNF.builder("Called") 456 var called = DNF.builder("Called")
384 .parameters(p1, p2) 457 .parameters(p1, p2)
385 .clause( 458 .clause(
386 new RelationViewAtom(personView, p1), 459 new RelationViewAtom(personView, p1),
@@ -389,39 +462,47 @@ class QueryTest {
389 ) 462 )
390 .build(); 463 .build();
391 464
392 DNF predicate = DNF.builder("Count") 465 var predicate = DNF.builder("Count")
393 .parameters(p1) 466 .parameters(p1)
394 .clause( 467 .clause(
395 new RelationViewAtom(personView, p1), 468 new RelationViewAtom(personView, p1),
396 new CallAtom<>(false, called, p1, p2) 469 new DNFCallAtom(false, called, p1, p2)
397 ) 470 )
398 .build(); 471 .build();
399 472
400 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 473 var store = ModelStore.builder()
401 Set.of(personView, friendMustView), Set.of(called, predicate)); 474 .symbols(person, friend)
402 QueryableModel model = store.createModel(); 475 .with(ViatraModelQuery.ADAPTER)
476 .queries(predicate)
477 .build();
478
479 var model = store.createModel();
480 var personInterpretation = model.getInterpretation(person);
481 var friendInterpretation = model.getInterpretation(friend);
482 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
483 var predicateResultSet = queryEngine.getResultSet(predicate);
403 484
404 model.put(person, Tuple.of(0), true); 485 personInterpretation.put(Tuple.of(0), true);
405 model.put(person, Tuple.of(1), true); 486 personInterpretation.put(Tuple.of(1), true);
406 model.put(person, Tuple.of(2), true); 487 personInterpretation.put(Tuple.of(2), true);
407 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
408 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
409 488
410 model.flushChanges(); 489 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
411 assertEquals(2, model.countResults(predicate)); 490 friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE);
491
492 queryEngine.flushChanges();
493 assertEquals(2, predicateResultSet.countResults());
412 } 494 }
413 495
414 @Test 496 @Test
415 void transitivePatternCallTest() { 497 void transitivePatternCallTest() {
416 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 498 var person = new Symbol<>("Person", 1, Boolean.class, false);
417 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); 499 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE);
418 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 500 var personView = new KeyOnlyRelationView<>(person);
419 RelationView<TruthValue> friendMustView = new FilteredRelationView<>(friend, "must", 501 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
420 TruthValue::must); 502
421 503 var p1 = new Variable("p1");
422 Variable p1 = new Variable("p1"); 504 var p2 = new Variable("p2");
423 Variable p2 = new Variable("p2"); 505 var friendPredicate = DNF.builder("RelationConstraint")
424 DNF friendPredicate = DNF.builder("RelationConstraint")
425 .parameters(p1, p2) 506 .parameters(p1, p2)
426 .clause( 507 .clause(
427 new RelationViewAtom(personView, p1), 508 new RelationViewAtom(personView, p1),
@@ -430,29 +511,38 @@ class QueryTest {
430 ) 511 )
431 .build(); 512 .build();
432 513
433 Variable p3 = new Variable("p3"); 514 var p3 = new Variable("p3");
434 Variable p4 = new Variable("p4"); 515 var p4 = new Variable("p4");
435 DNF predicate = DNF.builder("TransitivePatternCall") 516 var predicate = DNF.builder("TransitivePatternCall")
436 .parameters(p3, p4) 517 .parameters(p3, p4)
437 .clause( 518 .clause(
438 new RelationViewAtom(personView, p3), 519 new RelationViewAtom(personView, p3),
439 new RelationViewAtom(personView, p4), 520 new RelationViewAtom(personView, p4),
440 new CallAtom<>(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) 521 new DNFCallAtom(CallPolarity.TRANSITIVE, friendPredicate, p3, p4)
441 ) 522 )
442 .build(); 523 .build();
443 524
444 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), 525 var store = ModelStore.builder()
445 Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); 526 .symbols(person, friend)
446 QueryableModel model = store.createModel(); 527 .with(ViatraModelQuery.ADAPTER)
528 .queries(predicate)
529 .build();
530
531 var model = store.createModel();
532 var personInterpretation = model.getInterpretation(person);
533 var friendInterpretation = model.getInterpretation(friend);
534 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
535 var predicateResultSet = queryEngine.getResultSet(predicate);
536
537 personInterpretation.put(Tuple.of(0), true);
538 personInterpretation.put(Tuple.of(1), true);
539 personInterpretation.put(Tuple.of(2), true);
447 540
448 model.put(person, Tuple.of(0), true); 541 friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE);
449 model.put(person, Tuple.of(1), true); 542 friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE);
450 model.put(person, Tuple.of(2), true);
451 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
452 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
453 543
454 model.flushChanges(); 544 queryEngine.flushChanges();
455 assertEquals(3, model.countResults(predicate)); 545 assertEquals(3, predicateResultSet.countResults());
456 } 546 }
457 547
458 static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { 548 static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) {
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
index e8fa6ed1..49087a8d 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
@@ -1,54 +1,59 @@
1package tools.refinery.store.query.viatra; 1package tools.refinery.store.query.viatra;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.DNF; 5import tools.refinery.store.query.DNF;
6import tools.refinery.store.query.QueryableModel; 6import tools.refinery.store.query.ModelQuery;
7import tools.refinery.store.query.QueryableModelStore;
8import tools.refinery.store.query.Variable; 7import tools.refinery.store.query.Variable;
9import tools.refinery.store.query.atom.RelationViewAtom; 8import tools.refinery.store.query.atom.RelationViewAtom;
10import tools.refinery.store.query.viatra.ViatraQueryableModelStore;
11import tools.refinery.store.query.view.KeyOnlyRelationView; 9import tools.refinery.store.query.view.KeyOnlyRelationView;
12import tools.refinery.store.query.view.RelationView; 10import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple; 11import tools.refinery.store.tuple.Tuple;
14 12
15import java.util.Set;
16
17import static org.junit.jupiter.api.Assertions.assertEquals; 13import static org.junit.jupiter.api.Assertions.assertEquals;
18 14
19class QueryTransactionTest { 15class QueryTransactionTest {
20 @Test 16 @Test
21 void flushTest() { 17 void flushTest() {
22 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 18 var person = new Symbol<>("Person", 1, Boolean.class, false);
23 Relation<Boolean> asset = new Relation<>("Asset", 1, Boolean.class, false); 19 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
24 RelationView<Boolean> personView = new KeyOnlyRelationView(person); 20 var personView = new KeyOnlyRelationView<>(person);
25 21
26 var p1 = new Variable("p1"); 22 var p1 = new Variable("p1");
27 DNF predicate = DNF.builder("TypeConstraint") 23 var predicate = DNF.builder("TypeConstraint")
28 .parameters(p1) 24 .parameters(p1)
29 .clause(new RelationViewAtom(personView, p1)) 25 .clause(new RelationViewAtom(personView, p1))
30 .build(); 26 .build();
31 27
32 QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), 28 var store = ModelStore.builder()
33 Set.of(predicate)); 29 .symbols(person, asset)
34 QueryableModel model = store.createModel(); 30 .with(ViatraModelQuery.ADAPTER)
31 .queries(predicate)
32 .build();
33
34 var model = store.createModel();
35 var personInterpretation = model.getInterpretation(person);
36 var assetInterpretation = model.getInterpretation(asset);
37 var queryEngine = model.getAdapter(ModelQuery.ADAPTER);
38 var predicateResultSet = queryEngine.getResultSet(predicate);
39
40 assertEquals(0, predicateResultSet.countResults());
35 41
36 assertEquals(0, model.countResults(predicate)); 42 personInterpretation.put(Tuple.of(0), true);
43 personInterpretation.put(Tuple.of(1), true);
37 44
38 model.put(person, Tuple.of(0), true); 45 assetInterpretation.put(Tuple.of(1), true);
39 model.put(person, Tuple.of(1), true); 46 assetInterpretation.put(Tuple.of(2), true);
40 model.put(asset, Tuple.of(1), true);
41 model.put(asset, Tuple.of(2), true);
42 47
43 assertEquals(0, model.countResults(predicate)); 48 assertEquals(0, predicateResultSet.countResults());
44 49
45 model.flushChanges(); 50 queryEngine.flushChanges();
46 assertEquals(2, model.countResults(predicate)); 51 assertEquals(2, predicateResultSet.countResults());
47 52
48 model.put(person, Tuple.of(4), true); 53 personInterpretation.put(Tuple.of(4), true);
49 assertEquals(2, model.countResults(predicate)); 54 assertEquals(2, predicateResultSet.countResults());
50 55
51 model.flushChanges(); 56 queryEngine.flushChanges();
52 assertEquals(3, model.countResults(predicate)); 57 assertEquals(3, predicateResultSet.countResults());
53 } 58 }
54} 59}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
index 07869050..69491fda 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
@@ -3,8 +3,8 @@ package tools.refinery.store.query.viatra.internal.cardinality;
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 6import tools.refinery.store.representation.cardinality.UpperCardinalities;
7import tools.refinery.store.model.representation.cardinality.UpperCardinality; 7import tools.refinery.store.representation.cardinality.UpperCardinality;
8 8
9import java.util.stream.Stream; 9import java.util.stream.Stream;
10 10
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
index afc4a2f3..20dad543 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
@@ -2,8 +2,8 @@ package tools.refinery.store.query.viatra.internal.cardinality;
2 2
3import org.junit.jupiter.api.BeforeEach; 3import org.junit.jupiter.api.BeforeEach;
4import org.junit.jupiter.api.Test; 4import org.junit.jupiter.api.Test;
5import tools.refinery.store.model.representation.cardinality.UpperCardinalities; 5import tools.refinery.store.representation.cardinality.UpperCardinalities;
6import tools.refinery.store.model.representation.cardinality.UpperCardinality; 6import tools.refinery.store.representation.cardinality.UpperCardinality;
7 7
8import static org.hamcrest.MatcherAssert.assertThat; 8import static org.hamcrest.MatcherAssert.assertThat;
9import static org.hamcrest.Matchers.equalTo; 9import static org.hamcrest.Matchers.equalTo;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
new file mode 100644
index 00000000..4c142217
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
@@ -0,0 +1,27 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder;
5
6public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder {
7 private final ModelStoreBuilder storeBuilder;
8
9 protected AbstractModelAdapterBuilder(ModelStoreBuilder storeBuilder) {
10 this.storeBuilder = storeBuilder;
11 }
12
13 @Override
14 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
15 return storeBuilder.with(adapterBuilderFactory);
16 }
17
18 @Override
19 public ModelStoreBuilder getStoreBuilder() {
20 return storeBuilder;
21 }
22
23 @Override
24 public ModelStore build() {
25 return storeBuilder.build();
26 }
27}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
new file mode 100644
index 00000000..2783675f
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
@@ -0,0 +1,94 @@
1package tools.refinery.store.adapter;
2
3import org.jetbrains.annotations.NotNull;
4
5import java.util.*;
6import java.util.function.Consumer;
7
8public class AdapterList<T> implements Iterable<T> {
9 private final List<AnyModelAdapterType> adapterTypes;
10 private final List<T> adapters;
11
12 public AdapterList() {
13 adapterTypes = new ArrayList<>();
14 adapters = new ArrayList<>();
15 }
16
17 public AdapterList(int adapterCount) {
18 adapterTypes = new ArrayList<>(adapterCount);
19 adapters = new ArrayList<>(adapterCount);
20 }
21
22 public int size() {
23 return adapters.size();
24 }
25
26 public void add(AnyModelAdapterType adapterType, T adapter) {
27 adapterTypes.add(adapterType);
28 adapters.add(adapter);
29 }
30
31 public <U extends T> Optional<U> tryGet(AnyModelAdapterType adapterType, Class<? extends U> adapterClass) {
32 int size = size();
33 for (int i = 0; i < size; i++) {
34 if (getType(i).supports(adapterType)) {
35 return Optional.of(adapterClass.cast(get(i)));
36 }
37 }
38 return Optional.empty();
39 }
40
41 public <U extends T> U get(AnyModelAdapterType adapterType, Class<U> adapterClass) {
42 return tryGet(adapterType, adapterClass).orElseThrow(() -> new IllegalArgumentException(
43 "No %s was configured".formatted(adapterType)));
44 }
45
46 public AnyModelAdapterType getType(int i) {
47 return adapterTypes.get(i);
48 }
49
50 public T get(int i) {
51 return adapters.get(i);
52 }
53
54 public Collection<AnyModelAdapterType> getAdapterTypes() {
55 return Collections.unmodifiableCollection(adapterTypes);
56 }
57
58 public Iterable<Entry<T>> withAdapterTypes() {
59 return () -> new Iterator<>() {
60 private int i = 0;
61
62 @Override
63 public boolean hasNext() {
64 return i < size();
65 }
66
67 @Override
68 public Entry<T> next() {
69 var entry = new Entry<>(getType(i), get(i));
70 i++;
71 return entry;
72 }
73 };
74 }
75
76 @NotNull
77 @Override
78 public Iterator<T> iterator() {
79 return adapters.iterator();
80 }
81
82 @Override
83 public void forEach(Consumer<? super T> action) {
84 adapters.forEach(action);
85 }
86
87 @Override
88 public Spliterator<T> spliterator() {
89 return adapters.spliterator();
90 }
91
92 public record Entry<T>(AnyModelAdapterType adapterType, T adapter) {
93 }
94}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
new file mode 100644
index 00000000..37a247fe
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
@@ -0,0 +1,19 @@
1package tools.refinery.store.adapter;
2
3import java.util.Collection;
4
5public sealed interface AnyModelAdapterType permits ModelAdapterType {
6 Class<? extends ModelAdapter> getModelAdapterClass();
7
8 Class<? extends ModelStoreAdapter> getModelStoreAdapterClass();
9
10 Class<? extends ModelAdapterBuilder> getModelAdapterBuilderClass();
11
12 Collection<AnyModelAdapterType> getSupportedAdapterTypes();
13
14 default boolean supports(AnyModelAdapterType targetAdapter) {
15 return getSupportedAdapterTypes().contains(targetAdapter);
16 }
17
18 String getName();
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
new file mode 100644
index 00000000..aa079e01
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4
5public interface ModelAdapter {
6 Model getModel();
7
8 ModelStoreAdapter getStoreAdapter();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
new file mode 100644
index 00000000..64b3e59f
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
@@ -0,0 +1,17 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder;
5
6public interface ModelAdapterBuilder {
7 ModelStoreAdapter createStoreAdapter(ModelStore store);
8
9 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory);
10
11 ModelStoreBuilder getStoreBuilder();
12
13 default void configure() {
14 }
15
16 ModelStore build();
17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
new file mode 100644
index 00000000..7c9b01bc
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
@@ -0,0 +1,14 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStoreBuilder;
4
5public abstract class ModelAdapterBuilderFactory<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
6 T3 extends ModelAdapterBuilder> extends ModelAdapterType<T1, T2, T3> {
7
8 protected ModelAdapterBuilderFactory(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
9 Class<T3> modelAdapterBuilderClass) {
10 super(modelAdapterClass, modelStoreAdapterClass, modelAdapterBuilderClass);
11 }
12
13 public abstract T3 createBuilder(ModelStoreBuilder storeBuilder);
14}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
new file mode 100644
index 00000000..82ddeb12
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
@@ -0,0 +1,79 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStore;
5
6import java.lang.reflect.Method;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Set;
11
12public abstract non-sealed class ModelAdapterType<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
13 T3 extends ModelAdapterBuilder> implements AnyModelAdapterType {
14 private final Class<? extends T1> modelAdapterClass;
15 private final Class<? extends T2> modelStoreAdapterClass;
16 private final Class<? extends T3> modelAdapterBuilderClass;
17 private final Set<AnyModelAdapterType> supportedAdapters = new HashSet<>();
18
19 protected ModelAdapterType(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
20 Class<T3> modelAdapterBuilderClass) {
21 checkReturnType(modelAdapterClass, modelStoreAdapterClass, "createModelAdapter", Model.class);
22 checkReturnType(modelStoreAdapterClass, modelAdapterBuilderClass, "createStoreAdapter", ModelStore.class);
23 this.modelAdapterClass = modelAdapterClass;
24 this.modelStoreAdapterClass = modelStoreAdapterClass;
25 this.modelAdapterBuilderClass = modelAdapterBuilderClass;
26 supportedAdapters.add(this);
27 }
28
29 private void checkReturnType(Class<?> expectedReturnType, Class<?> ownerClass, String methodName,
30 Class<?>... argumentTypes) {
31 Method method;
32 try {
33 method = ownerClass.getMethod(methodName, argumentTypes);
34 } catch (NoSuchMethodException e) {
35 throw new IllegalStateException("Invalid %s: %s#%s method is required"
36 .formatted(this, ownerClass.getName(), methodName), e);
37 }
38 var returnType = method.getReturnType();
39 if (!expectedReturnType.isAssignableFrom(returnType)) {
40 throw new IllegalStateException("Invalid %s: %s is not assignable from the return type %s of %s#%s"
41 .formatted(this, expectedReturnType.getName(), returnType.getCanonicalName(),
42 ownerClass.getName(), methodName));
43 }
44 }
45
46 protected void extendsAdapter(ModelAdapterType<? super T1, ? super T2, ? super T3> superAdapter) {
47 supportedAdapters.addAll(superAdapter.supportedAdapters);
48 }
49
50 @Override
51 public final Class<? extends T1> getModelAdapterClass() {
52 return modelAdapterClass;
53 }
54
55 @Override
56 public final Class<? extends T2> getModelStoreAdapterClass() {
57 return modelStoreAdapterClass;
58 }
59
60 @Override
61 public final Class<? extends T3> getModelAdapterBuilderClass() {
62 return modelAdapterBuilderClass;
63 }
64
65 @Override
66 public Collection<AnyModelAdapterType> getSupportedAdapterTypes() {
67 return Collections.unmodifiableCollection(supportedAdapters);
68 }
69
70 @Override
71 public String getName() {
72 return "%s.ADAPTER".formatted(this.getClass().getName());
73 }
74
75 @Override
76 public String toString() {
77 return getName();
78 }
79}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
new file mode 100644
index 00000000..1eb40ada
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
@@ -0,0 +1,10 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStore;
5
6public interface ModelStoreAdapter {
7 ModelStore getStore();
8
9 ModelAdapter createModelAdapter(Model model);
10}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
new file mode 100644
index 00000000..d18ba71d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.representation.AnySymbol;
4
5public sealed interface AnyInterpretation permits Interpretation {
6 Model getModel();
7
8 AnySymbol getSymbol();
9
10 long getSize();
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
new file mode 100644
index 00000000..55949d0c
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
@@ -0,0 +1,25 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple;
7
8public non-sealed interface Interpretation<T> extends AnyInterpretation {
9 @Override
10 Symbol<T> getSymbol();
11
12 T get(Tuple key);
13
14 Cursor<Tuple, T> getAll();
15
16 T put(Tuple key, T value);
17
18 void putAll(Cursor<Tuple, T> cursor);
19
20 DiffCursor<Tuple, T> getDiffCursor(long to);
21
22 void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring);
23
24 void removeListener(InterpretationListener<T> listener);
25}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
new file mode 100644
index 00000000..73950779
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.tuple.Tuple;
4
5public interface InterpretationListener<T> {
6 void put(Tuple key, T fromValue, T toValue, boolean restoring);
7}
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 69f57389..8d2a4614 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
@@ -1,24 +1,31 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.map.Cursor; 3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.adapter.ModelAdapterType;
4import tools.refinery.store.map.Versioned; 5import tools.refinery.store.map.Versioned;
5import tools.refinery.store.model.representation.AnyDataRepresentation; 6import tools.refinery.store.representation.AnySymbol;
6import tools.refinery.store.model.representation.DataRepresentation; 7import tools.refinery.store.representation.Symbol;
7 8
8import java.util.Set; 9import java.util.Optional;
9 10
10public interface Model extends Versioned { 11public interface Model extends Versioned {
11 Set<AnyDataRepresentation> getDataRepresentations(); 12 ModelStore getStore();
12 13
13 <K, V> V get(DataRepresentation<K, V> representation, K key); 14 long getState();
14 15
15 <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation); 16 default AnyInterpretation getInterpretation(AnySymbol symbol) {
17 return getInterpretation((Symbol<?>) symbol);
18 }
16 19
17 <K, V> V put(DataRepresentation<K, V> representation, K key, V value); 20 <T> Interpretation<T> getInterpretation(Symbol<T> symbol);
18 21
19 <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor); 22 ModelDiffCursor getDiffCursor(long to);
20 23
21 long getSize(AnyDataRepresentation representation); 24 <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType);
22 25
23 ModelDiffCursor getDiffCursor(long to); 26 <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType);
27
28 void addListener(ModelListener listener);
29
30 void removeListener(ModelListener listener);
24} 31}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
index d5bb541b..97bf2039 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
@@ -1,27 +1,27 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor; 3import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.model.representation.AnyDataRepresentation; 4import tools.refinery.store.representation.AnySymbol;
6import tools.refinery.store.model.representation.DataRepresentation; 5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple;
7 7
8import java.util.Map; 8import java.util.Map;
9 9
10public class ModelDiffCursor { 10public class ModelDiffCursor {
11 final Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors; 11 private final Map<? extends AnySymbol, ? extends DiffCursor<?, ?>> diffCursors;
12 12
13 public ModelDiffCursor(Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors) { 13 public ModelDiffCursor(Map<? extends AnySymbol, ? extends DiffCursor<?, ?>> diffCursors) {
14 super(); 14 super();
15 this.diffCursors = diffCursors; 15 this.diffCursors = diffCursors;
16 } 16 }
17 17
18 @SuppressWarnings("unchecked") 18 public <T> DiffCursor<Tuple, T> getCursor(Symbol<T> symbol) {
19 public <K, V> DiffCursor<K, V> getCursor(DataRepresentation<K, V> representation) { 19 var cursor = diffCursors.get(symbol);
20 Cursor<?, ?> cursor = diffCursors.get(representation); 20 if (cursor == null) {
21 if (cursor != null) { 21 throw new IllegalArgumentException("No cursor for symbol %s".formatted(symbol));
22 return (DiffCursor<K, V>) cursor;
23 } else {
24 throw new IllegalArgumentException("ModelCursor does not contain cursor for representation " + representation);
25 } 22 }
23 @SuppressWarnings("unchecked")
24 var typedCursor = (DiffCursor<Tuple, T>) cursor;
25 return typedCursor;
26 } 26 }
27} 27}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
new file mode 100644
index 00000000..f67540bb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
@@ -0,0 +1,15 @@
1package tools.refinery.store.model;
2
3public interface ModelListener {
4 default void beforeCommit() {
5 }
6
7 default void afterCommit() {
8 }
9
10 default void beforeRestore(long state) {
11 }
12
13 default void afterRestore() {
14 }
15}
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 84b67765..bc863d4b 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
@@ -1,11 +1,16 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.model.representation.AnyDataRepresentation; 3import tools.refinery.store.adapter.ModelAdapterType;
4import tools.refinery.store.adapter.ModelStoreAdapter;
5import tools.refinery.store.model.internal.ModelStoreBuilderImpl;
6import tools.refinery.store.representation.AnySymbol;
4 7
8import java.util.Collection;
9import java.util.Optional;
5import java.util.Set; 10import java.util.Set;
6 11
7public interface ModelStore { 12public interface ModelStore {
8 Set<AnyDataRepresentation> getDataRepresentations(); 13 Collection<AnySymbol> getSymbols();
9 14
10 Model createModel(); 15 Model createModel();
11 16
@@ -14,4 +19,12 @@ public interface ModelStore {
14 Set<Long> getStates(); 19 Set<Long> getStates();
15 20
16 ModelDiffCursor getDiffCursor(long from, long to); 21 ModelDiffCursor getDiffCursor(long from, long to);
22
23 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType);
24
25 <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType);
26
27 static ModelStoreBuilder builder() {
28 return new ModelStoreBuilderImpl();
29 }
17} 30}
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
new file mode 100644
index 00000000..289099da
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
@@ -0,0 +1,36 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.representation.AnySymbol;
7import tools.refinery.store.representation.Symbol;
8
9import java.util.Collection;
10import java.util.List;
11import java.util.Optional;
12
13public interface ModelStoreBuilder {
14 default ModelStoreBuilder symbols(AnySymbol... symbols) {
15 return symbols(List.of(symbols));
16 }
17
18 default ModelStoreBuilder symbols(Collection<? extends AnySymbol> symbols) {
19 symbols.forEach(this::symbol);
20 return this;
21 }
22
23 default ModelStoreBuilder symbol(AnySymbol symbol) {
24 return symbol((Symbol<?>) symbol);
25 }
26
27 <T> ModelStoreBuilder symbol(Symbol<T> symbol);
28
29 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory);
30
31 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType);
32
33 <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType);
34
35 ModelStore build();
36}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java
deleted file mode 100644
index 2f73a0e5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java
+++ /dev/null
@@ -1,115 +0,0 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.map.*;
4import tools.refinery.store.model.internal.ModelImpl;
5import tools.refinery.store.model.internal.SimilarRelationEquivalenceClass;
6import tools.refinery.store.model.representation.AnyDataRepresentation;
7import tools.refinery.store.model.representation.AuxiliaryData;
8import tools.refinery.store.model.representation.DataRepresentation;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.*;
13import java.util.Map.Entry;
14
15public class ModelStoreImpl implements ModelStore {
16
17 private final Map<AnyDataRepresentation, VersionedMapStore<?, ?>> stores;
18
19 public ModelStoreImpl(Set<AnyDataRepresentation> dataRepresentations) {
20 stores = initStores(dataRepresentations);
21 }
22
23 private Map<AnyDataRepresentation, VersionedMapStore<?, ?>> initStores(
24 Set<AnyDataRepresentation> dataRepresentations) {
25 Map<AnyDataRepresentation, VersionedMapStore<?, ?>> result = new HashMap<>();
26
27 Map<SimilarRelationEquivalenceClass, List<Relation<?>>> symbolRepresentationsPerHashPerArity = new HashMap<>();
28
29 for (AnyDataRepresentation dataRepresentation : dataRepresentations) {
30 if (dataRepresentation instanceof Relation<?> symbolRepresentation) {
31 addOrCreate(symbolRepresentationsPerHashPerArity,
32 new SimilarRelationEquivalenceClass(symbolRepresentation), symbolRepresentation);
33 } else if (dataRepresentation instanceof AuxiliaryData<?, ?> auxiliaryData) {
34 VersionedMapStoreImpl<?, ?> store = new VersionedMapStoreImpl<>(auxiliaryData.getHashProvider(),
35 auxiliaryData.getDefaultValue());
36 result.put(auxiliaryData, store);
37 } else {
38 throw new UnsupportedOperationException(
39 "Model store does not have strategy to use " + dataRepresentation.getClass() + "!");
40 }
41 }
42 for (List<Relation<?>> symbolGroup : symbolRepresentationsPerHashPerArity.values()) {
43 initRepresentationGroup(result, symbolGroup);
44 }
45
46 return result;
47 }
48
49 private void initRepresentationGroup(Map<AnyDataRepresentation, VersionedMapStore<?, ?>> result,
50 List<Relation<?>> symbolGroup) {
51 final ContinousHashProvider<Tuple> hashProvider = symbolGroup.get(0).getHashProvider();
52 final Object defaultValue = symbolGroup.get(0).getDefaultValue();
53
54 List<VersionedMapStore<Tuple, Object>> maps = VersionedMapStoreImpl
55 .createSharedVersionedMapStores(symbolGroup.size(), hashProvider, defaultValue);
56
57 for (int i = 0; i < symbolGroup.size(); i++) {
58 result.put(symbolGroup.get(i), maps.get(i));
59 }
60 }
61
62 private static <K, V> void addOrCreate(Map<K, List<V>> map, K key, V value) {
63 List<V> list;
64 if (map.containsKey(key)) {
65 list = map.get(key);
66 } else {
67 list = new LinkedList<>();
68 map.put(key, list);
69 }
70 list.add(value);
71 }
72
73 @Override
74 public Set<AnyDataRepresentation> getDataRepresentations() {
75 return this.stores.keySet();
76 }
77
78 @Override
79 public ModelImpl createModel() {
80 Map<AnyDataRepresentation, VersionedMap<?, ?>> maps = new HashMap<>();
81 for (var entry : this.stores.entrySet()) {
82 maps.put(entry.getKey(), entry.getValue().createMap());
83 }
84 return new ModelImpl(this, maps);
85 }
86
87 @Override
88 public synchronized ModelImpl createModel(long state) {
89 Map<AnyDataRepresentation, VersionedMap<?, ?>> maps = new HashMap<>();
90 for (var entry : this.stores.entrySet()) {
91 maps.put(entry.getKey(), entry.getValue().createMap(state));
92 }
93 return new ModelImpl(this, maps);
94 }
95
96 @Override
97 public synchronized Set<Long> getStates() {
98 var iterator = stores.values().iterator();
99 if (iterator.hasNext()) {
100 return Set.copyOf(iterator.next().getStates());
101 }
102 return Set.of(0l);
103 }
104
105 @Override
106 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
107 Map<AnyDataRepresentation, DiffCursor<?, ?>> diffcursors = new HashMap<>();
108 for (var entry : stores.entrySet()) {
109 var representation = entry.getKey();
110 var diffCursor = entry.getValue().getDiffCursor(from, to);
111 diffcursors.put(representation, diffCursor);
112 }
113 return new ModelDiffCursor(diffcursors);
114 }
115}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java b/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java
deleted file mode 100644
index 6a5fdcd5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java
+++ /dev/null
@@ -1,7 +0,0 @@
1package tools.refinery.store.model;
2
3public interface RelationLike {
4 String getName();
5
6 int getArity();
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
index 24ec3b59..4bcf9ff4 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
@@ -4,15 +4,6 @@ import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
5 5
6public class TupleHashProvider implements ContinousHashProvider<Tuple> { 6public class TupleHashProvider implements ContinousHashProvider<Tuple> {
7 protected static TupleHashProvider instance;
8
9 public static TupleHashProvider singleton() {
10 if (instance == null) {
11 instance = new TupleHashProvider();
12 }
13 return instance;
14 }
15
16 protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 7 protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
17 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 8 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
18 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 9 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
@@ -45,6 +36,8 @@ public class TupleHashProvider implements ContinousHashProvider<Tuple> {
45 36
46 public static final int MAX_MODEL_SIZE = (int) LARGEST_PRIME_30_BITS; 37 public static final int MAX_MODEL_SIZE = (int) LARGEST_PRIME_30_BITS;
47 38
39 public static final TupleHashProvider INSTANCE = new TupleHashProvider();
40
48 public TupleHashProvider() { 41 public TupleHashProvider() {
49 if (primes.length < MAX_PRACTICAL_DEPTH) { 42 if (primes.length < MAX_PRACTICAL_DEPTH) {
50 throw new UnsupportedOperationException( 43 throw new UnsupportedOperationException(
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
new file mode 100644
index 00000000..f68859db
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.model.internal;
2
3public enum ModelAction {
4 NONE,
5 COMMIT,
6 RESTORE
7}
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 795a891b..10331e28 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
@@ -1,131 +1,166 @@
1package tools.refinery.store.model.internal; 1package tools.refinery.store.model.internal;
2 2
3import tools.refinery.store.map.ContinousHashProvider; 3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.map.Cursor; 4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapter;
6import tools.refinery.store.adapter.ModelAdapterType;
5import tools.refinery.store.map.DiffCursor; 7import tools.refinery.store.map.DiffCursor;
6import tools.refinery.store.map.VersionedMap; 8import tools.refinery.store.model.*;
7import tools.refinery.store.map.internal.MapDiffCursor; 9import tools.refinery.store.representation.AnySymbol;
8import tools.refinery.store.model.Model; 10import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.model.ModelDiffCursor; 11import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.model.ModelStore; 12
11import tools.refinery.store.model.representation.AnyDataRepresentation; 13import java.util.*;
12import tools.refinery.store.model.representation.DataRepresentation;
13
14import java.util.HashMap;
15import java.util.Map;
16import java.util.Set;
17 14
18public class ModelImpl implements Model { 15public class ModelImpl implements Model {
19 private final ModelStore store; 16 private final ModelStore store;
20 17 private long state;
21 private final Map<AnyDataRepresentation, VersionedMap<?, ?>> maps; 18 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
22 19 private final AdapterList<ModelAdapter> adapters;
23 public ModelImpl(ModelStore store, Map<AnyDataRepresentation, VersionedMap<?, ?>> maps) { 20 private final List<ModelListener> listeners = new ArrayList<>();
21 private ModelAction pendingAction = ModelAction.NONE;
22 private long restoringToState = -1;
23
24 ModelImpl(ModelStore store, long state, int adapterCount) {
24 this.store = store; 25 this.store = store;
25 this.maps = maps; 26 this.state = state;
27 adapters = new AdapterList<>(adapterCount);
26 } 28 }
27 29
28 @Override 30 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
29 public Set<AnyDataRepresentation> getDataRepresentations() { 31 this.interpretations = interpretations;
30 return maps.keySet();
31 } 32 }
32 33
33 private VersionedMap<?, ?> getMap(AnyDataRepresentation representation) { 34 @Override
34 if (maps.containsKey(representation)) { 35 public ModelStore getStore() {
35 return maps.get(representation); 36 return store;
36 } else {
37 throw new IllegalArgumentException("Model does have representation " + representation);
38 }
39 } 37 }
40 38
41 @SuppressWarnings("unchecked") 39 @Override
42 private <K, V> VersionedMap<K, V> getMap(DataRepresentation<K, V> representation) { 40 public long getState() {
43 return (VersionedMap<K, V>) maps.get(representation); 41 return state;
44 } 42 }
45 43
46 private <K, V> VersionedMap<K, V> getMapValidateKey(DataRepresentation<K, V> representation, K key) { 44 @Override
47 if (representation.isValidKey(key)) { 45 public <T> Interpretation<T> getInterpretation(Symbol<T> symbol) {
48 return getMap(representation); 46 var interpretation = interpretations.get(symbol);
49 } else { 47 if (interpretation == null) {
50 throw new IllegalArgumentException( 48 throw new IllegalArgumentException("No interpretation for symbol %s in model".formatted(symbol));
51 "Key is not valid for representation! (representation=" + representation + ", key=" + key + ");");
52 } 49 }
50 @SuppressWarnings("unchecked")
51 var typedInterpretation = (Interpretation<T>) interpretation;
52 return typedInterpretation;
53 } 53 }
54 54
55 @Override 55 @Override
56 public <K, V> V get(DataRepresentation<K, V> representation, K key) { 56 public ModelDiffCursor getDiffCursor(long to) {
57 return getMapValidateKey(representation, key).get(key); 57 var diffCursors = new HashMap<AnySymbol, DiffCursor<Tuple, ?>>(interpretations.size());
58 for (var entry : interpretations.entrySet()) {
59 diffCursors.put(entry.getKey(), entry.getValue().getDiffCursor(to));
60 }
61 return new ModelDiffCursor(diffCursors);
58 } 62 }
59 63
60 @Override 64 @Override
61 public <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation) { 65 public long commit() {
62 return getMap(representation).getAll(); 66 if (pendingAction != ModelAction.NONE) {
67 throw pendingActionError("commit");
68 }
69 pendingAction = ModelAction.COMMIT;
70 try {
71 int listenerCount = listeners.size();
72 int i = listenerCount;
73 long version = 0;
74 while (i > 0) {
75 i--;
76 listeners.get(i).beforeCommit();
77 }
78 boolean versionSet = false;
79 for (var interpretation : interpretations.values()) {
80 long newVersion = interpretation.commit();
81 if (versionSet) {
82 if (version != newVersion) {
83 throw new IllegalStateException("Interpretations in model have different versions (%d and %d)"
84 .formatted(version, newVersion));
85 }
86 } else {
87 version = newVersion;
88 versionSet = true;
89 }
90 }
91 state = version;
92 while (i < listenerCount) {
93 listeners.get(i).afterCommit();
94 i++;
95 }
96 return version;
97 } finally {
98 pendingAction = ModelAction.NONE;
99 }
63 } 100 }
64 101
65 @Override 102 @Override
66 public <K, V> V put(DataRepresentation<K, V> representation, K key, V value) { 103 public void restore(long version) {
67 return getMapValidateKey(representation, key).put(key, value); 104 if (pendingAction != ModelAction.NONE) {
105 throw pendingActionError("restore to %d".formatted(version));
106 }
107 if (!store.getStates().contains(version)) {
108 throw new IllegalArgumentException("Store does not contain state %d".formatted(version));
109 }
110 pendingAction = ModelAction.RESTORE;
111 restoringToState = version;
112 try {
113 int listenerCount = listeners.size();
114 int i = listenerCount;
115 while (i > 0) {
116 i--;
117 listeners.get(i).beforeRestore(version);
118 }
119 for (var interpretation : interpretations.values()) {
120 interpretation.restore(version);
121 }
122 state = version;
123 while (i < listenerCount) {
124 listeners.get(i).afterRestore();
125 i++;
126 }
127 } finally {
128 pendingAction = ModelAction.NONE;
129 restoringToState = -1;
130 }
68 } 131 }
69 132
70 @Override 133 public RuntimeException pendingActionError(String currentActionName) {
71 public <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor) { 134 var pendingActionName = switch (pendingAction) {
72 getMap(representation).putAll(cursor); 135 case NONE -> throw new IllegalArgumentException("Trying to throw pending action error when there is no " +
136 "pending action");
137 case COMMIT -> "commit";
138 case RESTORE -> "restore to %d".formatted(restoringToState);
139 };
140 return new IllegalStateException("Cannot %s due to pending %s".formatted(currentActionName, pendingActionName));
73 } 141 }
74 142
75 @Override 143 @Override
76 public long getSize(AnyDataRepresentation representation) { 144 public <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType) {
77 return getMap(representation).getSize(); 145 return adapters.tryGet(adapterType, adapterType.getModelAdapterClass());
78 } 146 }
79 147
80 @Override 148 @Override
81 public ModelDiffCursor getDiffCursor(long to) { 149 public <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType) {
82 Model toModel = store.createModel(to); 150 return adapters.get(adapterType, adapterType.getModelAdapterClass());
83 Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors = new HashMap<>();
84 for (AnyDataRepresentation anyDataRepresentation : this.maps.keySet()) {
85 var dataRepresentation = (DataRepresentation<?, ?>) anyDataRepresentation;
86 MapDiffCursor<?, ?> diffCursor = constructDiffCursor(toModel, dataRepresentation);
87 diffCursors.put(dataRepresentation, diffCursor);
88 }
89 return new ModelDiffCursor(diffCursors);
90 } 151 }
91 152
92 private <K, V> MapDiffCursor<K, V> constructDiffCursor(Model toModel, DataRepresentation<K, V> representation) { 153 void addAdapter(AnyModelAdapterType adapterType, ModelAdapter adapter) {
93 @SuppressWarnings("unchecked") 154 adapters.add(adapterType, adapter);
94 Cursor<K, V> fromCursor = (Cursor<K, V>) this.maps.get(representation).getAll();
95 Cursor<K, V> toCursor = toModel.getAll(representation);
96
97 ContinousHashProvider<K> hashProvider = representation.getHashProvider();
98 V defaultValue = representation.getDefaultValue();
99 return new MapDiffCursor<>(hashProvider, defaultValue, fromCursor, toCursor);
100 } 155 }
101 156
102 @Override 157 @Override
103 public long commit() { 158 public void addListener(ModelListener listener) {
104 long version = 0; 159 listeners.add(listener);
105 boolean versionSet = false;
106 for (VersionedMap<?, ?> map : maps.values()) {
107 long newVersion = map.commit();
108 if (versionSet) {
109 if (version != newVersion) {
110 throw new IllegalStateException(
111 "Maps in model have different versions! (" + version + " and" + newVersion + ")");
112 }
113 } else {
114 version = newVersion;
115 versionSet = true;
116 }
117 }
118 return version;
119 } 160 }
120 161
121 @Override 162 @Override
122 public void restore(long state) { 163 public void removeListener(ModelListener listener) {
123 if (store.getStates().contains(state)) { 164 listeners.remove(listener);
124 for (VersionedMap<?, ?> map : maps.values()) {
125 map.restore(state);
126 }
127 } else {
128 throw new IllegalArgumentException("Map does not contain state " + state + "!");
129 }
130 } 165 }
131} 166}
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
new file mode 100644
index 00000000..79f7195d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -0,0 +1,104 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.adapter.ModelAdapterBuilder;
5import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
6import tools.refinery.store.adapter.ModelAdapterType;
7import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.model.TupleHashProvider;
12import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.*;
17
18public class ModelStoreBuilderImpl implements ModelStoreBuilder {
19 private final Set<AnySymbol> allSymbols = new HashSet<>();
20 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>();
21 private final AdapterList<ModelAdapterBuilder> adapters = new AdapterList<>();
22
23 @Override
24 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) {
25 if (!allSymbols.add(symbol)) {
26 throw new IllegalArgumentException("Symbol %s already added".formatted(symbol));
27 }
28 var equivalenceClass = new SymbolEquivalenceClass<>(symbol);
29 var symbolsInEquivalenceClass = equivalenceClasses.computeIfAbsent(equivalenceClass,
30 ignored -> new ArrayList<>());
31 symbolsInEquivalenceClass.add(symbol);
32 return this;
33 }
34
35 @Override
36 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
37 return adapters.<T>tryGet(adapterBuilderFactory, adapterBuilderFactory.getModelAdapterBuilderClass())
38 .orElseGet(() -> addAdapter(adapterBuilderFactory));
39 }
40
41 private <T extends ModelAdapterBuilder> T addAdapter(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
42 for (var configuredAdapterType : adapters.getAdapterTypes()) {
43 var intersection = new HashSet<>(adapterBuilderFactory.getSupportedAdapterTypes());
44 intersection.retainAll(configuredAdapterType.getSupportedAdapterTypes());
45 if (!intersection.isEmpty()) {
46 if (configuredAdapterType.supports(adapterBuilderFactory)) {
47 // Impossible to end up here from <code>#with</code>, because we should have returned
48 // the existing adapter there instead of adding a new one.
49 throw new IllegalArgumentException(
50 "Cannot add %s, because it is already provided by configured adapter %s"
51 .formatted(adapterBuilderFactory, configuredAdapterType));
52 } else if (adapterBuilderFactory.supports(configuredAdapterType)) {
53 throw new IllegalArgumentException(
54 "Cannot add %s, because it provides already configured adapter %s"
55 .formatted(adapterBuilderFactory, configuredAdapterType));
56 } else {
57 throw new IllegalArgumentException(
58 "Cannot add %s, because configured adapter %s already provides %s"
59 .formatted(adapterBuilderFactory, configuredAdapterType, intersection));
60 }
61 }
62 }
63 var newAdapter = adapterBuilderFactory.createBuilder(this);
64 adapters.add(adapterBuilderFactory, newAdapter);
65 return newAdapter;
66 }
67
68 @Override
69 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType) {
70 return adapters.tryGet(adapterType, adapterType.getModelAdapterBuilderClass());
71 }
72
73 @Override
74 public <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType) {
75 return adapters.get(adapterType, adapterType.getModelAdapterBuilderClass());
76 }
77
78 @Override
79 public ModelStore build() {
80 var stores = new HashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size());
81 for (var entry : equivalenceClasses.entrySet()) {
82 createStores(stores, entry.getKey(), entry.getValue());
83 }
84 var modelStore = new ModelStoreImpl(stores, adapters.size());
85 for (int i = adapters.size() - 1; i >= 0; i--) {
86 adapters.get(i).configure();
87 }
88 for (var entry : adapters.withAdapterTypes()) {
89 var adapter = entry.adapter().createStoreAdapter(modelStore);
90 modelStore.addAdapter(entry.adapterType(), adapter);
91 }
92 return modelStore;
93 }
94
95 private <T> void createStores(Map<AnySymbol, VersionedMapStore<Tuple, ?>> stores,
96 SymbolEquivalenceClass<T> equivalenceClass, List<AnySymbol> symbols) {
97 int size = symbols.size();
98 var storeGroup = VersionedMapStoreImpl.createSharedVersionedMapStores(size, TupleHashProvider.INSTANCE,
99 equivalenceClass.defaultValue());
100 for (int i = 0; i < size; i++) {
101 stores.put(symbols.get(i), storeGroup.get(i));
102 }
103 }
104}
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
new file mode 100644
index 00000000..8aab57af
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -0,0 +1,100 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.adapter.ModelStoreAdapter;
7import tools.refinery.store.map.DiffCursor;
8import tools.refinery.store.map.VersionedMapStore;
9import tools.refinery.store.model.ModelDiffCursor;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.AnySymbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.*;
15
16public class ModelStoreImpl implements ModelStore {
17 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
18 private final AdapterList<ModelStoreAdapter> adapters;
19
20 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) {
21 this.stores = stores;
22 adapters = new AdapterList<>(adapterCount);
23 }
24
25 @Override
26 public Collection<AnySymbol> getSymbols() {
27 return Collections.unmodifiableCollection(stores.keySet());
28 }
29
30 private ModelImpl createEmptyModel(long state) {
31 return new ModelImpl(this, state, adapters.size());
32 }
33
34 @Override
35 public ModelImpl createModel() {
36 var model = createEmptyModel(-1);
37 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
38 for (var entry : this.stores.entrySet()) {
39 var symbol = entry.getKey();
40 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue()));
41 }
42 model.setInterpretations(interpretations);
43 adaptModel(model);
44 return model;
45 }
46
47 @Override
48 public synchronized ModelImpl createModel(long state) {
49 var model = createEmptyModel(state);
50 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
51 for (var entry : this.stores.entrySet()) {
52 var symbol = entry.getKey();
53 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue(), state));
54 }
55 model.setInterpretations(interpretations);
56 adaptModel(model);
57 return model;
58 }
59
60 private void adaptModel(ModelImpl model) {
61 for (var entry : adapters.withAdapterTypes()) {
62 var adapter = entry.adapter().createModelAdapter(model);
63 model.addAdapter(entry.adapterType(), adapter);
64 }
65 }
66
67 @Override
68 public synchronized Set<Long> getStates() {
69 var iterator = stores.values().iterator();
70 if (iterator.hasNext()) {
71 return Set.copyOf(iterator.next().getStates());
72 }
73 return Set.of(0L);
74 }
75
76 @Override
77 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
78 var diffCursors = new HashMap<AnySymbol, DiffCursor<?, ?>>();
79 for (var entry : stores.entrySet()) {
80 var representation = entry.getKey();
81 var diffCursor = entry.getValue().getDiffCursor(from, to);
82 diffCursors.put(representation, diffCursor);
83 }
84 return new ModelDiffCursor(diffCursors);
85 }
86
87 @Override
88 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType) {
89 return adapters.tryGet(adapterType, adapterType.getModelStoreAdapterClass());
90 }
91
92 @Override
93 public <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType) {
94 return adapters.get(adapterType, adapterType.getModelStoreAdapterClass());
95 }
96
97 void addAdapter(AnyModelAdapterType adapterType, ModelStoreAdapter adapter) {
98 adapters.add(adapterType, adapter);
99 }
100}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java
deleted file mode 100644
index 79e4c9f9..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java
+++ /dev/null
@@ -1,35 +0,0 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.model.representation.Relation;
5import tools.refinery.store.tuple.Tuple;
6
7import java.util.Objects;
8
9public class SimilarRelationEquivalenceClass {
10 final ContinousHashProvider<Tuple> hashProvider;
11 final Object defaultValue;
12 final int arity;
13
14 public SimilarRelationEquivalenceClass(Relation<?> representation) {
15 this.hashProvider = representation.getHashProvider();
16 this.defaultValue = representation.getDefaultValue();
17 this.arity = representation.getArity();
18 }
19
20 @Override
21 public int hashCode() {
22 return Objects.hash(arity, defaultValue, hashProvider);
23 }
24
25 @Override
26 public boolean equals(Object obj) {
27 if (this == obj)
28 return true;
29 if (!(obj instanceof SimilarRelationEquivalenceClass other))
30 return false;
31 return arity == other.arity && Objects.equals(defaultValue, other.defaultValue)
32 && Objects.equals(hashProvider, other.hashProvider);
33 }
34
35}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
new file mode 100644
index 00000000..5bf1b90d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.representation.Symbol;
4
5public record SymbolEquivalenceClass<T>(int arity, Class<T> valueType, T defaultValue) {
6 public SymbolEquivalenceClass(Symbol<T> symbol) {
7 this(symbol.arity(), symbol.valueType(), symbol.defaultValue());
8 }
9}
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
new file mode 100644
index 00000000..1bdb1cdf
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
@@ -0,0 +1,159 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.map.VersionedMap;
6import tools.refinery.store.map.VersionedMapStore;
7import tools.refinery.store.map.internal.MapDiffCursor;
8import tools.refinery.store.model.Interpretation;
9import tools.refinery.store.model.InterpretationListener;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.TupleHashProvider;
12import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.ArrayList;
17import java.util.List;
18
19public class VersionedInterpretation<T> implements Interpretation<T> {
20 private final ModelImpl model;
21 private final Symbol<T> symbol;
22 private final VersionedMapStore<Tuple, T> store;
23 private final VersionedMap<Tuple, T> map;
24 private final List<InterpretationListener<T>> listeners = new ArrayList<>();
25 private final List<InterpretationListener<T>> restoreListeners = new ArrayList<>();
26
27 private VersionedInterpretation(ModelImpl model, Symbol<T> symbol, VersionedMapStore<Tuple, T> store,
28 VersionedMap<Tuple, T> map) {
29 this.model = model;
30 this.symbol = symbol;
31 this.store = store;
32 this.map = map;
33 }
34
35 @Override
36 public Model getModel() {
37 return model;
38 }
39
40 @Override
41 public Symbol<T> getSymbol() {
42 return symbol;
43 }
44
45 @Override
46 public long getSize() {
47 return map.getSize();
48 }
49
50 private void checkKey(Tuple key) {
51 if (key == null || key.getSize() != symbol.arity()) {
52 throw new IllegalArgumentException("Key for %s must be a tuple with arity %s"
53 .formatted(symbol, symbol.arity()));
54 }
55 }
56 @Override
57 public T get(Tuple key) {
58 checkKey(key);
59 return map.get(key);
60 }
61
62 @Override
63 public Cursor<Tuple, T> getAll() {
64 return map.getAll();
65 }
66
67 private void notifyListeners(Tuple key, T fromValue, T toValue, boolean restoring) {
68 var listenerList = restoring ? restoreListeners : listeners;
69 int listenerCount = listenerList.size();
70 // Use a for loop instead of a for-each loop to avoid <code>Iterator</code> allocation overhead.
71 //noinspection ForLoopReplaceableByForEach
72 for (int i = 0; i < listenerCount; i++) {
73 listenerList.get(i).put(key, fromValue, toValue, restoring);
74 }
75 }
76
77 @Override
78 public T put(Tuple key, T value) {
79 checkKey(key);
80 var oldValue = map.put(key, value);
81 notifyListeners(key, oldValue, value, false);
82 return oldValue;
83 }
84
85 @Override
86 public void putAll(Cursor<Tuple, T> cursor) {
87 if (listeners.isEmpty()) {
88 map.putAll(cursor);
89 return;
90 }
91 if (cursor.getDependingMaps().contains(map)) {
92 List<Tuple> keys = new ArrayList<>();
93 List<T> values = new ArrayList<>();
94 while (cursor.move()) {
95 keys.add(cursor.getKey());
96 values.add(cursor.getValue());
97 }
98 var keyIterator = keys.iterator();
99 var valueIterator = values.iterator();
100 while (keyIterator.hasNext()) {
101 put(keyIterator.next(), valueIterator.next());
102 }
103 } else {
104 while (cursor.move()) {
105 put(cursor.getKey(), cursor.getValue());
106 }
107 }
108 }
109
110 @Override
111 public DiffCursor<Tuple, T> getDiffCursor(long to) {
112 var fromCursor = getAll();
113 var toCursor = store.createMap(to).getAll();
114 return new MapDiffCursor<>(TupleHashProvider.INSTANCE, symbol.defaultValue(), fromCursor, toCursor);
115 }
116
117 public long commit() {
118 return map.commit();
119 }
120
121 public void restore(long state) {
122 if (!restoreListeners.isEmpty()) {
123 var diffCursor = getDiffCursor(state);
124 while (diffCursor.move()) {
125 notifyListeners(diffCursor.getKey(), diffCursor.getFromValue(), diffCursor.getToValue(), true);
126 }
127 }
128 map.restore(state);
129 }
130
131 @Override
132 public void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring) {
133 listeners.add(listener);
134 if (alsoWhenRestoring) {
135 restoreListeners.add(listener);
136 }
137 }
138
139 @Override
140 public void removeListener(InterpretationListener<T> listener) {
141 listeners.remove(listener);
142 restoreListeners.remove(listener);
143 }
144
145 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store) {
146 @SuppressWarnings("unchecked")
147 var typedSymbol = (Symbol<T>) symbol;
148 var map = store.createMap();
149 return new VersionedInterpretation<>(model, typedSymbol, store, map);
150 }
151
152 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store,
153 long state) {
154 @SuppressWarnings("unchecked")
155 var typedSymbol = (Symbol<T>) symbol;
156 var map = store.createMap(state);
157 return new VersionedInterpretation<>(model, typedSymbol, store, map);
158 }
159}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java
deleted file mode 100644
index 951952e5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java
+++ /dev/null
@@ -1,4 +0,0 @@
1package tools.refinery.store.model.representation;
2
3public sealed interface AnyAuxiliaryData extends AnyDataRepresentation permits AuxiliaryData {
4}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java
deleted file mode 100644
index ea74a625..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java
+++ /dev/null
@@ -1,9 +0,0 @@
1package tools.refinery.store.model.representation;
2
3public sealed interface AnyDataRepresentation permits DataRepresentation, AnyRelation, AnyAuxiliaryData {
4 String getName();
5
6 Class<?> getKeyType();
7
8 Class<?> getValueType();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java
deleted file mode 100644
index 1d698c28..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java
+++ /dev/null
@@ -1,9 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.model.RelationLike;
4import tools.refinery.store.tuple.Tuple;
5
6public sealed interface AnyRelation extends AnyDataRepresentation, RelationLike permits Relation {
7 @Override
8 Class<Tuple> getKeyType();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java
deleted file mode 100644
index dad1ccf4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4
5public final class AuxiliaryData<K, V> extends DataRepresentation<K, V> implements AnyAuxiliaryData {
6 private final ContinousHashProvider<K> hashProvider;
7
8 public AuxiliaryData(String name, Class<K> keyType, ContinousHashProvider<K> hashProvider, Class<V> valueType,
9 V defaultValue) {
10 super(name, keyType, valueType, defaultValue);
11 this.hashProvider = hashProvider;
12 }
13
14 @Override
15 public ContinousHashProvider<K> getHashProvider() {
16 return hashProvider;
17 }
18
19 @Override
20 public boolean isValidKey(K key) {
21 return true;
22 }
23}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java
deleted file mode 100644
index 2bf498b9..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java
+++ /dev/null
@@ -1,43 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4
5public abstract sealed class DataRepresentation<K, V> implements AnyDataRepresentation permits Relation, AuxiliaryData {
6 private final String name;
7
8 private final V defaultValue;
9
10 private final Class<K> keyType;
11
12 private final Class<V> valueType;
13
14 protected DataRepresentation(String name, Class<K> keyType, Class<V> valueType, V defaultValue) {
15 this.name = name;
16 this.defaultValue = defaultValue;
17 this.keyType = keyType;
18 this.valueType = valueType;
19 }
20
21 @Override
22 public String getName() {
23 return name;
24 }
25
26 public abstract ContinousHashProvider<K> getHashProvider();
27
28 public abstract boolean isValidKey(K key);
29
30 public V getDefaultValue() {
31 return defaultValue;
32 }
33
34 @Override
35 public Class<K> getKeyType() {
36 return keyType;
37 }
38
39 @Override
40 public Class<V> getValueType() {
41 return valueType;
42 }
43}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java
deleted file mode 100644
index 47a07536..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.model.TupleHashProvider;
5import tools.refinery.store.tuple.Tuple;
6
7public final class Relation<D> extends DataRepresentation<Tuple, D> implements AnyRelation {
8 private final int arity;
9
10 public Relation(String name, int arity, Class<D> valueType, D defaultValue) {
11 super(name, Tuple.class, valueType, defaultValue);
12 this.arity = arity;
13 }
14
15 @Override
16 public int getArity() {
17 return arity;
18 }
19
20 @Override
21 public ContinousHashProvider<Tuple> getHashProvider() {
22 return TupleHashProvider.singleton();
23 }
24
25 @Override
26 public boolean isValidKey(Tuple key) {
27 if (key == null) {
28 return false;
29 } else {
30 return key.getSize() == getArity();
31 }
32 }
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java b/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
index 7d4b3091..336c25a1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
@@ -1,11 +1,11 @@
1package tools.refinery.store.query; 1package tools.refinery.store.query;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.atom.DNFAtom; 4import tools.refinery.store.query.atom.DNFAtom;
5 5
6import java.util.*; 6import java.util.*;
7 7
8public class DNF implements RelationLike { 8public class DNF implements SymbolLike {
9 private final String name; 9 private final String name;
10 10
11 private final String uniqueName; 11 private final String uniqueName;
@@ -22,7 +22,7 @@ public class DNF implements RelationLike {
22 } 22 }
23 23
24 @Override 24 @Override
25 public String getName() { 25 public String name() {
26 return name; 26 return name;
27 } 27 }
28 28
@@ -35,7 +35,7 @@ public class DNF implements RelationLike {
35 } 35 }
36 36
37 @Override 37 @Override
38 public int getArity() { 38 public int arity() {
39 return parameters.size(); 39 return parameters.size();
40 } 40 }
41 41
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java
new file mode 100644
index 00000000..6a1aeabb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapterType;
4
5public final class ModelQuery extends ModelAdapterType<ModelQueryAdapter, ModelQueryStoreAdapter, ModelQueryBuilder> {
6 public static final ModelQuery ADAPTER = new ModelQuery();
7
8 private ModelQuery() {
9 super(ModelQueryAdapter.class, ModelQueryStoreAdapter.class, ModelQueryBuilder.class);
10 }
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
new file mode 100644
index 00000000..d0cdf02d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapter;
4
5public interface ModelQueryAdapter extends ModelAdapter {
6 ModelQueryStoreAdapter getStoreAdapter();
7
8 ResultSet getResultSet(DNF query);
9
10 void flushChanges();
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
new file mode 100644
index 00000000..853a1796
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
@@ -0,0 +1,23 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.model.ModelStore;
5
6import java.util.Collection;
7import java.util.List;
8
9public interface ModelQueryBuilder extends ModelAdapterBuilder {
10 default ModelQueryBuilder queries(DNF... queries) {
11 return queries(List.of(queries));
12 }
13
14 default ModelQueryBuilder queries(Collection<? extends DNF> queries) {
15 queries.forEach(this::query);
16 return this;
17 }
18
19 ModelQueryBuilder query(DNF query);
20
21 @Override
22 ModelQueryStoreAdapter createStoreAdapter(ModelStore store);
23}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
new file mode 100644
index 00000000..ef5a4587
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
@@ -0,0 +1,16 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelStoreAdapter;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.query.view.AnyRelationView;
6
7import java.util.Collection;
8
9public interface ModelQueryStoreAdapter extends ModelStoreAdapter {
10 Collection<AnyRelationView> getRelationViews();
11
12 Collection<DNF> getQueries();
13
14 @Override
15 ModelQueryAdapter createModelAdapter(Model model);
16}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
deleted file mode 100644
index 9655d1a1..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.TupleLike;
6
7import java.util.Optional;
8import java.util.Set;
9import java.util.stream.Stream;
10
11public interface QueryableModel extends Model {
12 Set<DNF> getPredicates();
13
14 boolean hasChanges();
15
16 void flushChanges();
17
18 boolean hasResult(DNF predicate);
19
20 boolean hasResult(DNF predicate, Tuple parameters);
21
22 Optional<TupleLike> oneResult(DNF predicate);
23
24 Optional<TupleLike> oneResult(DNF predicate, Tuple parameters);
25
26 Stream<TupleLike> allResults(DNF predicate);
27
28 Stream<TupleLike> allResults(DNF predicate, Tuple parameters);
29
30 int countResults(DNF predicate);
31
32 int countResults(DNF predicate, Tuple parameters);
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
deleted file mode 100644
index 3a69f3a4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
+++ /dev/null
@@ -1,19 +0,0 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.representation.AnyDataRepresentation;
5import tools.refinery.store.query.view.AnyRelationView;
6
7import java.util.Set;
8
9public interface QueryableModelStore extends ModelStore {
10 Set<AnyDataRepresentation> getDataRepresentations();
11
12 Set<AnyRelationView> getViews();
13
14 Set<DNF> getPredicates();
15
16 QueryableModel createModel();
17
18 QueryableModel createModel(long state);
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java
new file mode 100644
index 00000000..3542e252
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java
@@ -0,0 +1,25 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.tuple.TupleLike;
5
6import java.util.Optional;
7import java.util.stream.Stream;
8
9public interface ResultSet {
10 boolean hasResult();
11
12 boolean hasResult(Tuple parameters);
13
14 Optional<TupleLike> oneResult();
15
16 Optional<TupleLike> oneResult(Tuple parameters);
17
18 Stream<TupleLike> allResults();
19
20 Stream<TupleLike> allResults(Tuple parameters);
21
22 int countResults();
23
24 int countResults(Tuple parameters);
25}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
index e8a8b5e1..af6a8f5a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
@@ -1,20 +1,20 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.Variable; 4import tools.refinery.store.query.Variable;
5 5
6import java.util.List; 6import java.util.List;
7import java.util.Set; 7import java.util.Set;
8 8
9public abstract class AbstractSubstitutionAtom<T extends RelationLike> implements DNFAtom { 9public abstract class AbstractSubstitutionAtom<T extends SymbolLike> implements DNFAtom {
10 private final T target; 10 private final T target;
11 11
12 private final List<Variable> substitution; 12 private final List<Variable> substitution;
13 13
14 protected AbstractSubstitutionAtom(T target, List<Variable> substitution) { 14 protected AbstractSubstitutionAtom(T target, List<Variable> substitution) {
15 if (substitution.size() != target.getArity()) { 15 if (substitution.size() != target.arity()) {
16 throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.getName(), 16 throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(),
17 target.getArity(), substitution.size())); 17 target.arity(), substitution.size()));
18 } 18 }
19 this.target = target; 19 this.target = target;
20 this.substitution = substitution; 20 this.substitution = substitution;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
index 9e289a8a..2e855246 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
@@ -1,40 +1,40 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.Variable; 4import tools.refinery.store.query.Variable;
5 5
6import java.util.List; 6import java.util.List;
7import java.util.Objects; 7import java.util.Objects;
8import java.util.Set; 8import java.util.Set;
9 9
10public final class CallAtom<T extends RelationLike> extends AbstractSubstitutionAtom<T> { 10public abstract class CallAtom<T extends SymbolLike> extends AbstractSubstitutionAtom<T> {
11 private final CallPolarity polarity; 11 private final CallPolarity polarity;
12 12
13 public CallAtom(CallPolarity polarity, T target, List<Variable> substitution) { 13 protected CallAtom(CallPolarity polarity, T target, List<Variable> substitution) {
14 super(target, substitution); 14 super(target, substitution);
15 if (polarity.isTransitive() && target.getArity() != 2) { 15 if (polarity.isTransitive() && target.arity() != 2) {
16 throw new IllegalArgumentException("Transitive closures can only take binary relations"); 16 throw new IllegalArgumentException("Transitive closures can only take binary relations");
17 } 17 }
18 this.polarity = polarity; 18 this.polarity = polarity;
19 } 19 }
20 20
21 public CallAtom(CallPolarity polarity, T target, Variable... substitution) { 21 protected CallAtom(CallPolarity polarity, T target, Variable... substitution) {
22 this(polarity, target, List.of(substitution)); 22 this(polarity, target, List.of(substitution));
23 } 23 }
24 24
25 public CallAtom(boolean positive, T target, List<Variable> substitution) { 25 protected CallAtom(boolean positive, T target, List<Variable> substitution) {
26 this(CallPolarity.fromBoolean(positive), target, substitution); 26 this(CallPolarity.fromBoolean(positive), target, substitution);
27 } 27 }
28 28
29 public CallAtom(boolean positive, T target, Variable... substitution) { 29 protected CallAtom(boolean positive, T target, Variable... substitution) {
30 this(positive, target, List.of(substitution)); 30 this(positive, target, List.of(substitution));
31 } 31 }
32 32
33 public CallAtom(T target, List<Variable> substitution) { 33 protected CallAtom(T target, List<Variable> substitution) {
34 this(true, target, substitution); 34 this(true, target, substitution);
35 } 35 }
36 36
37 public CallAtom(T target, Variable... substitution) { 37 protected CallAtom(T target, Variable... substitution) {
38 this(target, List.of(substitution)); 38 this(target, List.of(substitution));
39 } 39 }
40 40
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java
new file mode 100644
index 00000000..3b4f5cd1
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java
@@ -0,0 +1,32 @@
1package tools.refinery.store.query.atom;
2
3import tools.refinery.store.query.DNF;
4import tools.refinery.store.query.Variable;
5
6import java.util.List;
7
8public class DNFCallAtom extends CallAtom<DNF> {
9 public DNFCallAtom(CallPolarity polarity, DNF target, List<Variable> substitution) {
10 super(polarity, target, substitution);
11 }
12
13 public DNFCallAtom(CallPolarity polarity, DNF target, Variable... substitution) {
14 super(polarity, target, substitution);
15 }
16
17 public DNFCallAtom(boolean positive, DNF target, List<Variable> substitution) {
18 super(positive, target, substitution);
19 }
20
21 public DNFCallAtom(boolean positive, DNF target, Variable... substitution) {
22 super(positive, target, substitution);
23 }
24
25 public DNFCallAtom(DNF target, List<Variable> substitution) {
26 super(target, substitution);
27 }
28
29 public DNFCallAtom(DNF target, Variable... substitution) {
30 super(target, substitution);
31 }
32}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
index 1e4f8f55..c2ca1fdb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
@@ -1,17 +1,17 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.representation.Symbol;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.representation.TruthValue;
6 6
7public record ModalRelation(Modality modality, Relation<TruthValue> relation) implements RelationLike { 7public record ModalRelation(Modality modality, Symbol<TruthValue> relation) implements SymbolLike {
8 @Override 8 @Override
9 public String getName() { 9 public String name() {
10 return "%s %s".formatted(modality, relation); 10 return "%s %s".formatted(modality, relation);
11 } 11 }
12 12
13 @Override 13 @Override
14 public int getArity() { 14 public int arity() {
15 return relation.getArity(); 15 return relation.arity();
16 } 16 }
17} 17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java
deleted file mode 100644
index 79de1c4d..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java
+++ /dev/null
@@ -1,44 +0,0 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.model.representation.Relation;
7
8public abstract class AbstractFilteredRelationView<D> extends RelationView<D> {
9 protected AbstractFilteredRelationView(Relation<D> representation, String name) {
10 super(representation, name);
11 }
12
13 protected AbstractFilteredRelationView(Relation<D> representation) {
14 super(representation);
15 }
16
17 @Override
18 public Object[] forwardMap(Tuple key, D value) {
19 return toTuple1Array(key);
20 }
21
22 @Override
23 public boolean get(Model model, Object[] tuple) {
24 int[] content = new int[tuple.length];
25 for (int i = 0; i < tuple.length; i++) {
26 content[i] = ((Tuple1) tuple[i]).value0();
27 }
28 Tuple key = Tuple.of(content);
29 D value = model.get(getRepresentation(), key);
30 return filter(key, value);
31 }
32
33 public int getArity() {
34 return this.getRepresentation().getArity();
35 }
36
37 private static Object[] toTuple1Array(Tuple t) {
38 Object[] result = new Object[t.getSize()];
39 for (int i = 0; i < t.getSize(); i++) {
40 result[i] = Tuple.of(t.get(i));
41 }
42 return result;
43 }
44}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
index df5e0d72..9df1038b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
@@ -1,11 +1,11 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.model.Model; 3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.RelationLike; 4import tools.refinery.store.representation.SymbolLike;
5import tools.refinery.store.model.representation.AnyRelation; 5import tools.refinery.store.representation.AnySymbol;
6 6
7public sealed interface AnyRelationView extends RelationLike permits RelationView { 7public sealed interface AnyRelationView extends SymbolLike permits RelationView {
8 AnyRelation getRepresentation(); 8 AnySymbol getSymbol();
9 9
10 boolean get(Model model, Object[] tuple); 10 boolean get(Model model, Object[] tuple);
11 11
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
index 5b892cc6..64c601bb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
@@ -1,35 +1,35 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.tuple.Tuple; 3import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.representation.Symbol;
5 5
6import java.util.Objects; 6import java.util.Objects;
7import java.util.function.BiPredicate; 7import java.util.function.BiPredicate;
8import java.util.function.Predicate; 8import java.util.function.Predicate;
9 9
10public class FilteredRelationView<D> extends AbstractFilteredRelationView<D> { 10public class FilteredRelationView<T> extends TuplePreservingRelationView<T> {
11 private final BiPredicate<Tuple, D> predicate; 11 private final BiPredicate<Tuple, T> predicate;
12 12
13 public FilteredRelationView(Relation<D> representation, String name, BiPredicate<Tuple, D> predicate) { 13 public FilteredRelationView(Symbol<T> symbol, String name, BiPredicate<Tuple, T> predicate) {
14 super(representation, name); 14 super(symbol, name);
15 this.predicate = predicate; 15 this.predicate = predicate;
16 } 16 }
17 17
18 public FilteredRelationView(Relation<D> representation, BiPredicate<Tuple, D> predicate) { 18 public FilteredRelationView(Symbol<T> symbol, BiPredicate<Tuple, T> predicate) {
19 super(representation); 19 super(symbol);
20 this.predicate = predicate; 20 this.predicate = predicate;
21 } 21 }
22 22
23 public FilteredRelationView(Relation<D> representation, String name, Predicate<D> predicate) { 23 public FilteredRelationView(Symbol<T> symbol, String name, Predicate<T> predicate) {
24 this(representation, name, (k, v) -> predicate.test(v)); 24 this(symbol, name, (k, v) -> predicate.test(v));
25 } 25 }
26 26
27 public FilteredRelationView(Relation<D> representation, Predicate<D> predicate) { 27 public FilteredRelationView(Symbol<T> symbol, Predicate<T> predicate) {
28 this(representation, (k, v) -> predicate.test(v)); 28 this(symbol, (k, v) -> predicate.test(v));
29 } 29 }
30 30
31 @Override 31 @Override
32 public boolean filter(Tuple key, D value) { 32 public boolean filter(Tuple key, T value) {
33 return this.predicate.test(key, value); 33 return this.predicate.test(key, value);
34 } 34 }
35 35
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
index ef3954a4..d263679a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
@@ -3,24 +3,24 @@ package tools.refinery.store.query.view;
3import tools.refinery.store.model.Model; 3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1; 5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.model.representation.Relation; 6import tools.refinery.store.representation.Symbol;
7 7
8public class FunctionalRelationView<D> extends RelationView<D> { 8public class FunctionalRelationView<T> extends RelationView<T> {
9 public FunctionalRelationView(Relation<D> representation, String name) { 9 public FunctionalRelationView(Symbol<T> symbol, String name) {
10 super(representation, name); 10 super(symbol, name);
11 } 11 }
12 12
13 public FunctionalRelationView(Relation<D> representation) { 13 public FunctionalRelationView(Symbol<T> symbol) {
14 super(representation); 14 super(symbol);
15 } 15 }
16 16
17 @Override 17 @Override
18 public boolean filter(Tuple key, D value) { 18 public boolean filter(Tuple key, T value) {
19 return true; 19 return true;
20 } 20 }
21 21
22 @Override 22 @Override
23 public Object[] forwardMap(Tuple key, D value) { 23 public Object[] forwardMap(Tuple key, T value) {
24 return toTuple1ArrayPlusValue(key, value); 24 return toTuple1ArrayPlusValue(key, value);
25 } 25 }
26 26
@@ -32,14 +32,14 @@ public class FunctionalRelationView<D> extends RelationView<D> {
32 } 32 }
33 Tuple key = Tuple.of(content); 33 Tuple key = Tuple.of(content);
34 @SuppressWarnings("unchecked") 34 @SuppressWarnings("unchecked")
35 D valueInTuple = (D) tuple[tuple.length - 1]; 35 T valueInTuple = (T) tuple[tuple.length - 1];
36 D valueInMap = model.get(getRepresentation(), key); 36 T valueInMap = model.getInterpretation(getSymbol()).get(key);
37 return valueInTuple.equals(valueInMap); 37 return valueInTuple.equals(valueInMap);
38 } 38 }
39 39
40 @Override 40 @Override
41 public int getArity() { 41 public int arity() {
42 return getRepresentation().getArity() + 1; 42 return getSymbol().arity() + 1;
43 } 43 }
44 44
45 private static <D> Object[] toTuple1ArrayPlusValue(Tuple t, D value) { 45 private static <D> Object[] toTuple1ArrayPlusValue(Tuple t, D value) {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
index f7e7d28a..fdfcdf28 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
@@ -1,23 +1,23 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.representation.Symbol;
3import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.model.representation.Relation;
5 5
6import java.util.Objects; 6import java.util.Objects;
7 7
8public class KeyOnlyRelationView extends AbstractFilteredRelationView<Boolean> { 8public class KeyOnlyRelationView<T> extends TuplePreservingRelationView<T> {
9 public static final String VIEW_NAME = "key"; 9 public static final String VIEW_NAME = "key";
10 10
11 private final Boolean defaultValue; 11 private final T defaultValue;
12 12
13 public KeyOnlyRelationView(Relation<Boolean> representation) { 13 public KeyOnlyRelationView(Symbol<T> symbol) {
14 super(representation, VIEW_NAME); 14 super(symbol, VIEW_NAME);
15 defaultValue = representation.getDefaultValue(); 15 defaultValue = symbol.defaultValue();
16 } 16 }
17 17
18 @Override 18 @Override
19 public boolean filter(Tuple key, Boolean value) { 19 public boolean filter(Tuple key, T value) {
20 return !value.equals(defaultValue); 20 return !Objects.equals(value, defaultValue);
21 } 21 }
22 22
23 @Override 23 @Override
@@ -25,7 +25,7 @@ public class KeyOnlyRelationView extends AbstractFilteredRelationView<Boolean> {
25 if (this == o) return true; 25 if (this == o) return true;
26 if (o == null || getClass() != o.getClass()) return false; 26 if (o == null || getClass() != o.getClass()) return false;
27 if (!super.equals(o)) return false; 27 if (!super.equals(o)) return false;
28 KeyOnlyRelationView that = (KeyOnlyRelationView) o; 28 KeyOnlyRelationView<?> that = (KeyOnlyRelationView<?>) o;
29 return Objects.equals(defaultValue, that.defaultValue); 29 return Objects.equals(defaultValue, that.defaultValue);
30 } 30 }
31 31
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
index 1224076c..bbec1e73 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
@@ -2,49 +2,49 @@ package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.map.CursorAsIterator; 3import tools.refinery.store.map.CursorAsIterator;
4import tools.refinery.store.model.Model; 4import tools.refinery.store.model.Model;
5import tools.refinery.store.model.representation.Relation; 5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.Tuple;
7 7
8import java.util.Objects; 8import java.util.Objects;
9import java.util.UUID; 9import java.util.UUID;
10 10
11/** 11/**
12 * Represents a view of a {@link Relation} that can be queried. 12 * Represents a view of a {@link Symbol} that can be queried.
13 * 13 *
14 * @param <D> 14 * @param <T>
15 * @author Oszkar Semerath 15 * @author Oszkar Semerath
16 */ 16 */
17public abstract non-sealed class RelationView<D> implements AnyRelationView { 17public abstract non-sealed class RelationView<T> implements AnyRelationView {
18 private final Relation<D> representation; 18 private final Symbol<T> symbol;
19 19
20 private final String name; 20 private final String name;
21 21
22 protected RelationView(Relation<D> representation, String name) { 22 protected RelationView(Symbol<T> symbol, String name) {
23 this.representation = representation; 23 this.symbol = symbol;
24 this.name = name; 24 this.name = name;
25 } 25 }
26 26
27 protected RelationView(Relation<D> representation) { 27 protected RelationView(Symbol<T> representation) {
28 this(representation, UUID.randomUUID().toString()); 28 this(representation, UUID.randomUUID().toString());
29 } 29 }
30 30
31 @Override 31 @Override
32 public Relation<D> getRepresentation() { 32 public Symbol<T> getSymbol() {
33 return representation; 33 return symbol;
34 } 34 }
35 35
36 @Override 36 @Override
37 public String getName() { 37 public String name() {
38 return representation.getName() + "#" + name; 38 return symbol.name() + "#" + name;
39 } 39 }
40 40
41 public abstract boolean filter(Tuple key, D value); 41 public abstract boolean filter(Tuple key, T value);
42 42
43 public abstract Object[] forwardMap(Tuple key, D value); 43 public abstract Object[] forwardMap(Tuple key, T value);
44 44
45 @Override 45 @Override
46 public Iterable<Object[]> getAll(Model model) { 46 public Iterable<Object[]> getAll(Model model) {
47 return (() -> new CursorAsIterator<>(model.getAll(representation), this::forwardMap, this::filter)); 47 return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter));
48 } 48 }
49 49
50 @Override 50 @Override
@@ -52,11 +52,11 @@ public abstract non-sealed class RelationView<D> implements AnyRelationView {
52 if (this == o) return true; 52 if (this == o) return true;
53 if (o == null || getClass() != o.getClass()) return false; 53 if (o == null || getClass() != o.getClass()) return false;
54 RelationView<?> that = (RelationView<?>) o; 54 RelationView<?> that = (RelationView<?>) o;
55 return Objects.equals(representation, that.representation) && Objects.equals(name, that.name); 55 return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name);
56 } 56 }
57 57
58 @Override 58 @Override
59 public int hashCode() { 59 public int hashCode() {
60 return Objects.hash(representation, name); 60 return Objects.hash(symbol, name);
61 } 61 }
62} 62}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
new file mode 100644
index 00000000..8cc4986e
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
@@ -0,0 +1,44 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.representation.Symbol;
7
8public abstract class TuplePreservingRelationView<T> extends RelationView<T> {
9 protected TuplePreservingRelationView(Symbol<T> symbol, String name) {
10 super(symbol, name);
11 }
12
13 protected TuplePreservingRelationView(Symbol<T> symbol) {
14 super(symbol);
15 }
16
17 public Object[] forwardMap(Tuple key) {
18 Object[] result = new Object[key.getSize()];
19 for (int i = 0; i < key.getSize(); i++) {
20 result[i] = Tuple.of(key.get(i));
21 }
22 return result;
23 }
24
25 @Override
26 public Object[] forwardMap(Tuple key, T value) {
27 return forwardMap(key);
28 }
29
30 @Override
31 public boolean get(Model model, Object[] tuple) {
32 int[] content = new int[tuple.length];
33 for (int i = 0; i < tuple.length; i++) {
34 content[i] = ((Tuple1) tuple[i]).value0();
35 }
36 Tuple key = Tuple.of(content);
37 T value = model.getInterpretation(getSymbol()).get(key);
38 return filter(key, value);
39 }
40
41 public int arity() {
42 return this.getSymbol().arity();
43 }
44}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
new file mode 100644
index 00000000..12a45bed
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
@@ -0,0 +1,5 @@
1package tools.refinery.store.representation;
2
3public sealed interface AnySymbol extends SymbolLike permits Symbol {
4 Class<?> valueType();
5}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
new file mode 100644
index 00000000..404b5ddb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
@@ -0,0 +1,47 @@
1package tools.refinery.store.representation;
2
3import java.util.Objects;
4
5// Deliberately not a record, because we want equality by reference.
6@SuppressWarnings({"squid:S6206", "ClassCanBeRecord"})
7public final class Symbol<T> implements AnySymbol {
8 private final String name;
9 private final int arity;
10 private final Class<T> valueType;
11 private final T defaultValue;
12
13 public Symbol(String name, int arity, Class<T> valueType, T defaultValue) {
14 this.name = name;
15 this.arity = arity;
16 this.valueType = valueType;
17 this.defaultValue = defaultValue;
18 }
19
20 @Override
21 public String name() {
22 return name;
23 }
24
25 @Override
26 public int arity() {
27 return arity;
28 }
29
30 @Override
31 public Class<T> valueType() {
32 return valueType;
33 }
34
35 public T defaultValue() {
36 return defaultValue;
37 }
38
39 public boolean isDefaultValue(T value) {
40 return Objects.equals(defaultValue, value);
41 }
42
43 @Override
44 public String toString() {
45 return "%s/%d".formatted(name, arity);
46 }
47}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java b/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java
new file mode 100644
index 00000000..8c84500c
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.representation;
2
3public interface SymbolLike {
4 String name();
5
6 int arity();
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
index a5ba825b..b7893fd3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation; 1package tools.refinery.store.representation;
2 2
3public enum TruthValue { 3public enum TruthValue {
4 TRUE("true"), 4 TRUE("true"),
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
index 1f252b4c..273d0de7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval { 3public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval {
4 int lowerBound(); 4 int lowerBound();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
index b7c52bd1..e1a08bf9 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class CardinalityIntervals { 3public final class CardinalityIntervals {
4 public static final CardinalityInterval NONE = exactly(0); 4 public static final CardinalityInterval NONE = exactly(0);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
index 127651df..ab3ad9d1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class EmptyCardinalityInterval implements CardinalityInterval { 3public final class EmptyCardinalityInterval implements CardinalityInterval {
4 static final EmptyCardinalityInterval INSTANCE = new EmptyCardinalityInterval(); 4 static final EmptyCardinalityInterval INSTANCE = new EmptyCardinalityInterval();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
index ec643a97..381c8a57 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.jetbrains.annotations.NotNull; 3import org.jetbrains.annotations.NotNull;
4 4
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
index b534f2e3..32b3786f 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import java.util.function.BinaryOperator; 3import java.util.function.BinaryOperator;
4import java.util.function.IntBinaryOperator; 4import java.util.function.IntBinaryOperator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
index 4199d44f..593bc322 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.jetbrains.annotations.NotNull; 3import org.jetbrains.annotations.NotNull;
4 4
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
index b433cda2..d850fdc9 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class UpperCardinalities { 3public final class UpperCardinalities {
4 public static final UpperCardinality UNBOUNDED = UnboundedUpperCardinality.INSTANCE; 4 public static final UpperCardinality UNBOUNDED = UnboundedUpperCardinality.INSTANCE;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
index 91dd40b0..c6e31cb7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality, 3public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality,
4 UnboundedUpperCardinality { 4 UnboundedUpperCardinality {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
index 081112cc..77c62305 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
@@ -1,18 +1,17 @@
1package tools.refinery.store.map.tests; 1package tools.refinery.store.map.tests;
2 2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
6
7import tools.refinery.store.map.VersionedMapStore; 4import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl; 5import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.model.TupleHashProvider; 6import tools.refinery.store.model.TupleHashProvider;
7import tools.refinery.store.tuple.Tuple;
8
9import static org.junit.jupiter.api.Assertions.assertEquals;
11 10
12class MapUnitTests { 11class MapUnitTests {
13 @Test 12 @Test
14 void defaultTest() { 13 void defaultTest() {
15 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<Tuple, Boolean>(TupleHashProvider.singleton(), false); 14 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<>(TupleHashProvider.INSTANCE, false);
16 var map = store.createMap(); 15 var map = store.createMap();
17 var out1 = map.put(Tuple.of(0), true); 16 var out1 = map.put(Tuple.of(0), true);
18 assertEquals(false, out1); 17 assertEquals(false, out1);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
index ceec40f5..bb083805 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.hashTests; 1package tools.refinery.store.model.hashtests;
2 2
3import static org.junit.jupiter.api.Assertions.assertEquals; 3import static org.junit.jupiter.api.Assertions.assertEquals;
4 4
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
index 7a89daeb..e7bff1f9 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -1,145 +1,149 @@
1package tools.refinery.store.model.tests; 1package tools.refinery.store.model.tests;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.model.ModelStore; 4import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.model.ModelStoreImpl; 5import tools.refinery.store.representation.Symbol;
7import tools.refinery.store.model.representation.Relation;
8import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.Tuple;
9 7
10import java.util.Set;
11
12import static org.junit.jupiter.api.Assertions.*; 8import static org.junit.jupiter.api.Assertions.*;
13 9
14class ModelTest { 10class ModelTest {
15
16 @Test 11 @Test
17 void modelConstructionTest() { 12 void modelConstructionTest() {
18 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 13 var person = new Symbol<>("Person", 1, Boolean.class, false);
19 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 14 var friend = new Symbol<>("friend", 2, Boolean.class, false);
20 15
21 ModelStore store = new ModelStoreImpl(Set.of(person, friend)); 16 var store = ModelStore.builder().symbols(person, friend).build();
22 Model model = store.createModel(); 17 var symbols = store.getSymbols();
23 18
24 assertTrue(store.getDataRepresentations().contains(person)); 19 assertTrue(symbols.contains(person));
25 assertTrue(store.getDataRepresentations().contains(friend)); 20 assertTrue(symbols.contains(friend));
26 assertTrue(model.getDataRepresentations().contains(person));
27 assertTrue(model.getDataRepresentations().contains(friend));
28 21
29 Relation<Integer> other = new Relation<Integer>("other", 2, Integer.class, null); 22 var other = new Symbol<>("other", 2, Integer.class, null);
30 assertFalse(model.getDataRepresentations().contains(other)); 23 assertFalse(symbols.contains(other));
31 } 24 }
32 25
33 @Test 26 @Test
34 void modelBuildingTest() { 27 void modelBuildingTest() {
35 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 28 var person = new Symbol<>("Person", 1, Boolean.class, false);
36 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 29 var age = new Symbol<>("age", 1, Integer.class, null);
37 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 30 var friend = new Symbol<>("friend", 2, Boolean.class, false);
38 31
39 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); 32 var store = ModelStore.builder().symbols(person, age, friend).build();
40 Model model = store.createModel(); 33 var model = store.createModel();
41 34 var personInterpretation = model.getInterpretation(person);
42 model.put(person, Tuple.of(0), true); 35 var ageInterpretation = model.getInterpretation(age);
43 model.put(person, Tuple.of(1), true); 36 var friendInterpretation = model.getInterpretation(friend);
44 model.put(age, Tuple.of(0), 3); 37
45 model.put(age, Tuple.of(1), 1); 38 personInterpretation.put(Tuple.of(0), true);
46 model.put(friend, Tuple.of(0, 1), true); 39 personInterpretation.put(Tuple.of(1), true);
47 model.put(friend, Tuple.of(1, 0), true); 40 ageInterpretation.put(Tuple.of(0), 3);
48 41 ageInterpretation.put(Tuple.of(1), 1);
49 assertTrue(model.get(person, Tuple.of(0))); 42 friendInterpretation.put(Tuple.of(0, 1), true);
50 assertTrue(model.get(person, Tuple.of(1))); 43 friendInterpretation.put(Tuple.of(1, 0), true);
51 assertFalse(model.get(person, Tuple.of(2))); 44
52 45 assertTrue(personInterpretation.get(Tuple.of(0)));
53 assertEquals(3, model.get(age, Tuple.of(0))); 46 assertTrue(personInterpretation.get(Tuple.of(1)));
54 assertEquals(1, model.get(age, Tuple.of(1))); 47 assertFalse(personInterpretation.get(Tuple.of(2)));
55 assertNull(model.get(age, Tuple.of(2))); 48
56 49 assertEquals(3, ageInterpretation.get(Tuple.of(0)));
57 assertTrue(model.get(friend, Tuple.of(0, 1))); 50 assertEquals(1, ageInterpretation.get(Tuple.of(1)));
58 assertFalse(model.get(friend, Tuple.of(0, 5))); 51 assertNull(ageInterpretation.get( Tuple.of(2)));
52
53 assertTrue(friendInterpretation.get(Tuple.of(0, 1)));
54 assertFalse(friendInterpretation.get(Tuple.of(0, 5)));
59 } 55 }
60 56
61 @Test 57 @Test
62 void modelBuildingArityFailTest() { 58 void modelBuildingArityFailTest() {
63 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 59 var person = new Symbol<>("Person", 1, Boolean.class, false);
64 60
65 ModelStore store = new ModelStoreImpl(Set.of(person)); 61 var store = ModelStore.builder().symbols(person).build();
66 Model model = store.createModel(); 62 var model = store.createModel();
63 var personInterpretation = model.getInterpretation(person);
67 64
68 final Tuple tuple3 = Tuple.of(1, 1, 1); 65 final Tuple tuple3 = Tuple.of(1, 1, 1);
69 assertThrows(IllegalArgumentException.class, () -> model.put(person, tuple3, true)); 66 assertThrows(IllegalArgumentException.class, () -> personInterpretation.put(tuple3, true));
70 assertThrows(IllegalArgumentException.class, () -> model.get(person, tuple3)); 67 assertThrows(IllegalArgumentException.class, () -> personInterpretation.get(tuple3));
71 } 68 }
72 69
73 @Test 70 @Test
74 void modelBuildingNullFailTest() { 71 void modelBuildingNullFailTest() {
75 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 72 var age = new Symbol<>("age", 1, Integer.class, null);
76 ModelStore store = new ModelStoreImpl(Set.of(age)); 73
77 Model model = store.createModel(); 74 var store = ModelStore.builder().symbols(age).build();
75 var model = store.createModel();
76 var ageInterpretation = model.getInterpretation(age);
78 77
79 model.put(age, Tuple.of(1), null); // valid 78 ageInterpretation.put(Tuple.of(1), null); // valid
80 assertThrows(IllegalArgumentException.class, () -> model.put(age, null, 1)); 79 assertThrows(IllegalArgumentException.class, () -> ageInterpretation.put(null, 1));
81 assertThrows(IllegalArgumentException.class, () -> model.get(age, null)); 80 assertThrows(IllegalArgumentException.class, () -> ageInterpretation.get(null));
82 81
83 } 82 }
84 83
85 @Test 84 @Test
86 void modelUpdateTest() { 85 void modelUpdateTest() {
87 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 86 var person = new Symbol<>("Person", 1, Boolean.class, false);
88 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 87 var age = new Symbol<>("age", 1, Integer.class, null);
89 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 88 var friend = new Symbol<>("friend", 2, Boolean.class, false);
90 89
91 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); 90 var store = ModelStore.builder().symbols(person, age, friend).build();
92 Model model = store.createModel(); 91 var model = store.createModel();
93 92 var personInterpretation = model.getInterpretation(person);
94 model.put(person, Tuple.of(0), true); 93 var ageInterpretation = model.getInterpretation(age);
95 model.put(person, Tuple.of(1), true); 94 var friendInterpretation = model.getInterpretation(friend);
96 model.put(age, Tuple.of(0), 3); 95
97 model.put(age, Tuple.of(1), 1); 96 personInterpretation.put(Tuple.of(0), true);
98 model.put(friend, Tuple.of(0, 1), true); 97 personInterpretation.put(Tuple.of(1), true);
99 model.put(friend, Tuple.of(1, 0), true); 98 ageInterpretation.put(Tuple.of(0), 3);
100 99 ageInterpretation.put(Tuple.of(1), 1);
101 assertEquals(3, model.get(age, Tuple.of(0))); 100 friendInterpretation.put(Tuple.of(0, 1), true);
102 assertTrue(model.get(friend, Tuple.of(0, 1))); 101 friendInterpretation.put(Tuple.of(1, 0), true);
103 102
104 model.put(age, Tuple.of(0), 4); 103 assertEquals(3, ageInterpretation.get(Tuple.of(0)));
105 model.put(friend, Tuple.of(0, 1), false); 104 assertTrue(friendInterpretation.get(Tuple.of(0, 1)));
106 105
107 assertEquals(4, model.get(age, Tuple.of(0))); 106 ageInterpretation.put(Tuple.of(0), 4);
108 assertFalse(model.get(friend, Tuple.of(0, 1))); 107 friendInterpretation.put(Tuple.of(0, 1), false);
108
109 assertEquals(4, ageInterpretation.get(Tuple.of(0)));
110 assertFalse(friendInterpretation.get(Tuple.of(0, 1)));
109 } 111 }
110 112
111 @Test 113 @Test
112 void restoreTest() { 114 void restoreTest() {
113 Relation<Boolean> person = new Relation<Boolean>("Person", 1, Boolean.class, false); 115 var person = new Symbol<>("Person", 1, Boolean.class, false);
114 Relation<Boolean> friend = new Relation<Boolean>("friend", 2, Boolean.class, false); 116 var friend = new Symbol<>("friend", 2, Boolean.class, false);
115 117
116 ModelStore store = new ModelStoreImpl(Set.of(person, friend)); 118 var store = ModelStore.builder().symbols(person, friend).build();
117 Model model = store.createModel(); 119 var model = store.createModel();
118 120 var personInterpretation = model.getInterpretation(person);
119 model.put(person, Tuple.of(0), true); 121 var friendInterpretation = model.getInterpretation(friend);
120 model.put(person, Tuple.of(1), true); 122
121 model.put(friend, Tuple.of(0, 1), true); 123 personInterpretation.put(Tuple.of(0), true);
122 model.put(friend, Tuple.of(1, 0), true); 124 personInterpretation.put(Tuple.of(1), true);
125 friendInterpretation.put(Tuple.of(0, 1), true);
126 friendInterpretation.put(Tuple.of(1, 0), true);
123 long state1 = model.commit(); 127 long state1 = model.commit();
124 128
125 assertFalse(model.get(person, Tuple.of(2))); 129 assertFalse(personInterpretation.get(Tuple.of(2)));
126 assertFalse(model.get(friend, Tuple.of(0, 2))); 130 assertFalse(friendInterpretation.get(Tuple.of(0, 2)));
127 131
128 model.put(person, Tuple.of(2), true); 132 personInterpretation.put(Tuple.of(2), true);
129 model.put(friend, Tuple.of(0, 2), true); 133 friendInterpretation.put(Tuple.of(0, 2), true);
130 long state2 = model.commit(); 134 long state2 = model.commit();
131 135
132 assertTrue(model.get(person, Tuple.of(2))); 136 assertTrue(personInterpretation.get(Tuple.of(2)));
133 assertTrue(model.get(friend, Tuple.of(0, 2))); 137 assertTrue(friendInterpretation.get(Tuple.of(0, 2)));
134 138
135 model.restore(state1); 139 model.restore(state1);
136 140
137 assertFalse(model.get(person, Tuple.of(2))); 141 assertFalse(personInterpretation.get(Tuple.of(2)));
138 assertFalse(model.get(friend, Tuple.of(0, 2))); 142 assertFalse(friendInterpretation.get(Tuple.of(0, 2)));
139 143
140 model.restore(state2); 144 model.restore(state2);
141 145
142 assertTrue(model.get(person, Tuple.of(2))); 146 assertTrue(personInterpretation.get(Tuple.of(2)));
143 assertTrue(model.get(friend, Tuple.of(0, 2))); 147 assertTrue(friendInterpretation.get(Tuple.of(0, 2)));
144 } 148 }
145} 149}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
index 8a39b9b5..96fdc49e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
@@ -1,14 +1,15 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.representation.cardinality.CardinalityInterval;
6 7
7import java.util.stream.Stream; 8import java.util.stream.Stream;
8 9
9import static org.hamcrest.MatcherAssert.assertThat; 10import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.equalTo; 11import static org.hamcrest.Matchers.equalTo;
11import static tools.refinery.store.model.representation.cardinality.CardinalityIntervals.*; 12import static tools.refinery.store.representation.cardinality.CardinalityIntervals.*;
12 13
13class CardinalityIntervalTest { 14class CardinalityIntervalTest {
14 @ParameterizedTest(name = "min({0}, {1}) == {2}") 15 @ParameterizedTest(name = "min({0}, {1}) == {2}")
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
index ef68a607..4a9ef8da 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
@@ -1,6 +1,8 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.CardinalityIntervals;
5import tools.refinery.store.representation.cardinality.UpperCardinalities;
4 6
5import static org.hamcrest.MatcherAssert.assertThat; 7import static org.hamcrest.MatcherAssert.assertThat;
6import static org.hamcrest.Matchers.*; 8import static org.hamcrest.Matchers.*;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
index 41c884ec..e8b77b9f 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
@@ -1,6 +1,7 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.CardinalityIntervals;
4 5
5import static org.hamcrest.MatcherAssert.assertThat; 6import static org.hamcrest.MatcherAssert.assertThat;
6import static org.hamcrest.Matchers.lessThan; 7import static org.hamcrest.Matchers.lessThan;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
index dfb37786..9a190818 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
@@ -1,6 +1,9 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.NonEmptyCardinalityInterval;
5import tools.refinery.store.representation.cardinality.UpperCardinalities;
6import tools.refinery.store.representation.cardinality.UpperCardinality;
4 7
5import static org.junit.jupiter.api.Assertions.assertThrows; 8import static org.junit.jupiter.api.Assertions.assertThrows;
6 9
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
index 3f0f7a4a..90c21759 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
@@ -1,6 +1,7 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
4 5
5import static org.junit.jupiter.api.Assertions.assertThrows; 6import static org.junit.jupiter.api.Assertions.assertThrows;
6 7
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
index 13171ae5..3c7c0320 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
@@ -1,8 +1,11 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import org.junit.jupiter.params.ParameterizedTest; 4import org.junit.jupiter.params.ParameterizedTest;
5import org.junit.jupiter.params.provider.ValueSource; 5import org.junit.jupiter.params.provider.ValueSource;
6import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
7import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
8import tools.refinery.store.representation.cardinality.UpperCardinalities;
6 9
7import static org.hamcrest.MatcherAssert.assertThat; 10import static org.hamcrest.MatcherAssert.assertThat;
8import static org.hamcrest.Matchers.equalTo; 11import static org.hamcrest.Matchers.equalTo;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
index f5763c2d..e87ce29b 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
@@ -1,8 +1,10 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.representation.cardinality.UpperCardinalities;
7import tools.refinery.store.representation.cardinality.UpperCardinality;
6 8
7import java.util.stream.Stream; 9import java.util.stream.Stream;
8 10