diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-01-23 20:27:55 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-01-29 00:02:28 +0100 |
commit | d91acf3690682d243dbc150df902525b6e545c2f (patch) | |
tree | f39695cc193828df0b78030b5a56bd968e277457 /subprojects | |
parent | chore(deps): bump dependencies (diff) | |
download | refinery-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')
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.*; | |||
7 | import tools.refinery.language.semantics.model.internal.DecisionTree; | 7 | import tools.refinery.language.semantics.model.internal.DecisionTree; |
8 | import tools.refinery.language.utils.ProblemDesugarer; | 8 | import tools.refinery.language.utils.ProblemDesugarer; |
9 | import tools.refinery.language.utils.RelationInfo; | 9 | import tools.refinery.language.utils.RelationInfo; |
10 | import tools.refinery.store.model.representation.Relation; | 10 | import tools.refinery.store.representation.Symbol; |
11 | import tools.refinery.store.model.representation.TruthValue; | 11 | import tools.refinery.store.representation.TruthValue; |
12 | import tools.refinery.store.tuple.Tuple; | 12 | import tools.refinery.store.tuple.Tuple; |
13 | 13 | ||
14 | import java.util.HashMap; | 14 | import 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; | |||
3 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | 3 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; |
4 | import tools.refinery.store.map.Cursor; | 4 | import tools.refinery.store.map.Cursor; |
5 | import tools.refinery.store.tuple.Tuple; | 5 | import tools.refinery.store.tuple.Tuple; |
6 | import tools.refinery.store.model.representation.TruthValue; | 6 | import tools.refinery.store.representation.TruthValue; |
7 | 7 | ||
8 | public class DecisionTree { | 8 | public 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | 1 | package tools.refinery.language.semantics.model.internal; |
2 | 2 | ||
3 | import tools.refinery.store.map.Cursor; | 3 | import tools.refinery.store.map.Cursor; |
4 | import tools.refinery.store.model.representation.TruthValue; | 4 | import tools.refinery.store.representation.TruthValue; |
5 | import tools.refinery.store.tuple.Tuple; | 5 | import tools.refinery.store.tuple.Tuple; |
6 | 6 | ||
7 | import java.util.ArrayDeque; | 7 | import 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 | ||
3 | import org.eclipse.collections.api.LazyIntIterable; | 3 | import org.eclipse.collections.api.LazyIntIterable; |
4 | import tools.refinery.store.tuple.Tuple; | 4 | import tools.refinery.store.tuple.Tuple; |
5 | import tools.refinery.store.model.representation.TruthValue; | 5 | import tools.refinery.store.representation.TruthValue; |
6 | 6 | ||
7 | abstract class DecisionTreeNode { | 7 | abstract 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | 1 | package tools.refinery.language.semantics.model.internal; |
2 | 2 | ||
3 | import tools.refinery.store.model.representation.TruthValue; | 3 | import tools.refinery.store.representation.TruthValue; |
4 | 4 | ||
5 | public enum DecisionTreeValue { | 5 | public 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; | |||
5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | 5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; |
6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; | 6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; |
7 | import tools.refinery.store.tuple.Tuple; | 7 | import tools.refinery.store.tuple.Tuple; |
8 | import tools.refinery.store.model.representation.TruthValue; | 8 | import tools.refinery.store.representation.TruthValue; |
9 | 9 | ||
10 | final class IntermediateNode extends DecisionTreeNode { | 10 | final 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; | |||
5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | 5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; |
6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; | 6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; |
7 | import tools.refinery.store.tuple.Tuple; | 7 | import tools.refinery.store.tuple.Tuple; |
8 | import tools.refinery.store.model.representation.TruthValue; | 8 | import tools.refinery.store.representation.TruthValue; |
9 | 9 | ||
10 | class TerminalNode extends DecisionTreeNode { | 10 | class 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 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.language.semantics.model.internal.DecisionTree; | 4 | import tools.refinery.language.semantics.model.internal.DecisionTree; |
5 | import tools.refinery.store.model.representation.TruthValue; | 5 | import tools.refinery.store.representation.TruthValue; |
6 | import tools.refinery.store.tuple.Tuple; | 6 | import tools.refinery.store.tuple.Tuple; |
7 | 7 | ||
8 | import java.util.LinkedHashMap; | 8 | import 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 | ||
10 | dependencies { | 10 | dependencies { |
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 @@ | |||
1 | package tools.refinery.store.query.viatra; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelAdapterBuilderFactory; | ||
4 | import tools.refinery.store.model.ModelStoreBuilder; | ||
5 | import tools.refinery.store.query.ModelQuery; | ||
6 | import tools.refinery.store.query.ModelQueryAdapter; | ||
7 | import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
6 | import tools.refinery.store.model.ModelStore; | ||
7 | import tools.refinery.store.query.DNF; | ||
8 | import tools.refinery.store.query.ModelQueryBuilder; | ||
9 | |||
10 | import java.util.Collection; | ||
11 | import java.util.function.Function; | ||
12 | |||
13 | @SuppressWarnings("UnusedReturnValue") | ||
14 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; | ||
4 | import tools.refinery.store.query.ModelQueryStoreAdapter; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
4 | import tools.refinery.store.model.ModelDiffCursor; | ||
5 | import tools.refinery.store.model.ModelStore; | ||
6 | import tools.refinery.store.model.ModelStoreImpl; | ||
7 | import tools.refinery.store.model.RelationLike; | ||
8 | import tools.refinery.store.model.representation.AnyDataRepresentation; | ||
9 | import tools.refinery.store.model.representation.DataRepresentation; | ||
10 | import tools.refinery.store.query.DNF; | ||
11 | import tools.refinery.store.query.DNFAnd; | ||
12 | import tools.refinery.store.query.QueryableModel; | ||
13 | import tools.refinery.store.query.QueryableModelStore; | ||
14 | import tools.refinery.store.query.atom.*; | ||
15 | import tools.refinery.store.query.viatra.internal.RawPatternMatcher; | ||
16 | import tools.refinery.store.query.viatra.internal.ViatraQueryableModel; | ||
17 | import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery; | ||
18 | import tools.refinery.store.query.view.AnyRelationView; | ||
19 | |||
20 | import java.util.Collections; | ||
21 | import java.util.HashMap; | ||
22 | import java.util.Map; | ||
23 | import java.util.Set; | ||
24 | |||
25 | public 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; | |||
6 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | 6 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; |
7 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | 7 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; |
8 | import tools.refinery.store.model.Model; | 8 | import tools.refinery.store.model.Model; |
9 | import tools.refinery.store.model.representation.Relation; | ||
10 | import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext; | 9 | import tools.refinery.store.query.viatra.internal.context.RelationalEngineContext; |
11 | import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; | 10 | import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; |
12 | import tools.refinery.store.query.view.AnyRelationView; | 11 | import tools.refinery.store.query.view.AnyRelationView; |
13 | import tools.refinery.store.tuple.Tuple; | ||
14 | 12 | ||
15 | import java.util.Set; | 13 | import java.util.Collection; |
16 | 14 | ||
17 | public class RelationalScope extends QueryScope { | 15 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
4 | import org.eclipse.viatra.query.runtime.api.GenericQueryGroup; | ||
5 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
6 | import org.eclipse.viatra.query.runtime.internal.apiimpl.ViatraQueryEngineImpl; | ||
7 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; | ||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.query.DNF; | ||
11 | import tools.refinery.store.query.ModelQueryAdapter; | ||
12 | import tools.refinery.store.query.ModelQueryStoreAdapter; | ||
13 | import tools.refinery.store.query.ResultSet; | ||
14 | |||
15 | import java.lang.invoke.MethodHandle; | ||
16 | import java.lang.invoke.MethodHandles; | ||
17 | import java.util.*; | ||
18 | |||
19 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
4 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; | ||
5 | import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory; | ||
6 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; | ||
7 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
8 | import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory; | ||
9 | import tools.refinery.store.adapter.AbstractModelAdapterBuilder; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.model.ModelStoreBuilder; | ||
12 | import tools.refinery.store.query.DNF; | ||
13 | import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; | ||
14 | import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery; | ||
15 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; | ||
16 | |||
17 | import java.util.Collections; | ||
18 | import java.util.LinkedHashMap; | ||
19 | import java.util.Map; | ||
20 | import java.util.function.Function; | ||
21 | |||
22 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification; | ||
4 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; | ||
5 | import tools.refinery.store.model.Model; | ||
6 | import tools.refinery.store.model.ModelStore; | ||
7 | import tools.refinery.store.query.DNF; | ||
8 | import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; | ||
9 | import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; | ||
10 | import tools.refinery.store.query.view.AnyRelationView; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | |||
15 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; | ||
4 | import org.eclipse.viatra.query.runtime.api.GenericQueryGroup; | ||
5 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
6 | import org.eclipse.viatra.query.runtime.api.IQueryGroup; | ||
7 | import tools.refinery.store.map.Cursor; | ||
8 | import tools.refinery.store.map.DiffCursor; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.model.ModelDiffCursor; | ||
11 | import tools.refinery.store.model.representation.AnyDataRepresentation; | ||
12 | import tools.refinery.store.model.representation.DataRepresentation; | ||
13 | import tools.refinery.store.model.representation.Relation; | ||
14 | import tools.refinery.store.query.QueryableModel; | ||
15 | import tools.refinery.store.query.QueryableModelStore; | ||
16 | import tools.refinery.store.query.DNF; | ||
17 | import tools.refinery.store.tuple.Tuple; | ||
18 | import tools.refinery.store.tuple.TupleLike; | ||
19 | |||
20 | import java.util.HashMap; | ||
21 | import java.util.Map; | ||
22 | import java.util.Optional; | ||
23 | import java.util.Set; | ||
24 | import java.util.stream.Stream; | ||
25 | |||
26 | public 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 | ||
3 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; | 3 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; |
4 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; | 4 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; |
5 | import tools.refinery.store.model.representation.cardinality.FiniteUpperCardinality; | 5 | import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; |
6 | import tools.refinery.store.model.representation.cardinality.UnboundedUpperCardinality; | 6 | import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; |
7 | import tools.refinery.store.model.representation.cardinality.UpperCardinalities; | 7 | import tools.refinery.store.representation.cardinality.UpperCardinalities; |
8 | import tools.refinery.store.model.representation.cardinality.UpperCardinality; | 8 | import tools.refinery.store.representation.cardinality.UpperCardinality; |
9 | 9 | ||
10 | import java.util.stream.Stream; | 10 | import 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; | |||
5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; | 5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; |
6 | 6 | ||
7 | import tools.refinery.store.model.Model; | 7 | import tools.refinery.store.model.Model; |
8 | import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; | 8 | import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; |
9 | 9 | ||
10 | public class RelationalEngineContext implements IEngineContext { | 10 | public 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; | |||
8 | import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; | 8 | import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; |
9 | import tools.refinery.store.model.Model; | 9 | import tools.refinery.store.model.Model; |
10 | import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; | 10 | import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; |
11 | import tools.refinery.store.query.viatra.internal.viewupdate.ModelUpdateListener; | 11 | import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; |
12 | import tools.refinery.store.query.view.AnyRelationView; | 12 | import tools.refinery.store.query.view.AnyRelationView; |
13 | import tools.refinery.store.query.view.RelationView; | 13 | import 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.pquery; | 1 | package tools.refinery.store.query.viatra.internal.pquery; |
2 | 2 | ||
3 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
3 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; | 4 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; |
4 | import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; | 5 | import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; |
5 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; | 6 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; |
@@ -20,20 +21,28 @@ import tools.refinery.store.query.atom.*; | |||
20 | import tools.refinery.store.query.view.AnyRelationView; | 21 | import tools.refinery.store.query.view.AnyRelationView; |
21 | 22 | ||
22 | import java.util.*; | 23 | import java.util.*; |
24 | import java.util.function.Function; | ||
23 | import java.util.stream.Collectors; | 25 | import java.util.stream.Collectors; |
24 | 26 | ||
25 | public class DNF2PQuery { | 27 | public 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; | |||
3 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | 3 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; |
4 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | 4 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; |
5 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | 5 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; |
6 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
7 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; | 6 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; |
8 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; | 7 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; |
9 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; | 8 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; |
10 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; | 9 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; |
11 | import tools.refinery.store.query.viatra.internal.RawPatternMatcher; | ||
12 | import tools.refinery.store.query.viatra.internal.RelationalScope; | 10 | import tools.refinery.store.query.viatra.internal.RelationalScope; |
13 | 11 | ||
14 | import java.util.LinkedHashSet; | 12 | import java.util.LinkedHashSet; |
15 | import java.util.List; | 13 | import java.util.List; |
16 | import java.util.Set; | 14 | import java.util.Set; |
17 | 15 | ||
18 | public class SimplePQuery extends BasePQuery { | 16 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal; | 1 | package tools.refinery.store.query.viatra.internal.pquery; |
2 | 2 | ||
3 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; | 3 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; |
4 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | 4 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; |
5 | import tools.refinery.store.query.ResultSet; | ||
5 | import tools.refinery.store.query.viatra.ViatraTupleLike; | 6 | import tools.refinery.store.query.viatra.ViatraTupleLike; |
6 | import tools.refinery.store.tuple.Tuple; | 7 | import tools.refinery.store.tuple.Tuple; |
7 | import tools.refinery.store.tuple.TupleLike; | 8 | import tools.refinery.store.tuple.TupleLike; |
@@ -9,7 +10,7 @@ import tools.refinery.store.tuple.TupleLike; | |||
9 | import java.util.Optional; | 10 | import java.util.Optional; |
10 | import java.util.stream.Stream; | 11 | import java.util.stream.Stream; |
11 | 12 | ||
12 | public class RawPatternMatcher extends GenericPatternMatcher { | 13 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.update; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
6 | import tools.refinery.store.model.Model; | ||
7 | import tools.refinery.store.query.view.AnyRelationView; | ||
8 | import tools.refinery.store.query.view.RelationView; | ||
9 | |||
10 | import java.util.Collection; | ||
11 | import java.util.HashMap; | ||
12 | import java.util.Map; | ||
13 | |||
14 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.update; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
6 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
7 | |||
8 | import java.util.Arrays; | ||
9 | import java.util.Objects; | ||
10 | |||
11 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.update; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
6 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
7 | import tools.refinery.store.model.InterpretationListener; | ||
8 | import tools.refinery.store.query.view.RelationView; | ||
9 | import tools.refinery.store.query.view.TuplePreservingRelationView; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.List; | ||
13 | |||
14 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.update; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
4 | import tools.refinery.store.query.view.RelationView; | ||
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | |||
7 | import java.util.Arrays; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.update; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
4 | import tools.refinery.store.query.view.TuplePreservingRelationView; | ||
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | |||
7 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.viewupdate; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
6 | import tools.refinery.store.model.representation.AnyRelation; | ||
7 | import tools.refinery.store.query.view.AnyRelationView; | ||
8 | import tools.refinery.store.tuple.Tuple; | ||
9 | import tools.refinery.store.model.representation.Relation; | ||
10 | import tools.refinery.store.query.view.RelationView; | ||
11 | |||
12 | import java.util.HashMap; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.Map; | ||
15 | import java.util.Set; | ||
16 | |||
17 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.viewupdate; | ||
2 | |||
3 | import java.util.Arrays; | ||
4 | import java.util.Objects; | ||
5 | |||
6 | record 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.viewupdate; | ||
2 | |||
3 | import tools.refinery.store.tuple.Tuple; | ||
4 | |||
5 | import java.util.ArrayList; | ||
6 | import java.util.Arrays; | ||
7 | import java.util.List; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.viewupdate; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
4 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
6 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
7 | import tools.refinery.store.query.view.AnyRelationView; | ||
8 | import tools.refinery.store.query.view.RelationView; | ||
9 | import tools.refinery.store.tuple.Tuple; | ||
10 | |||
11 | import java.util.Objects; | ||
12 | |||
13 | public 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 @@ | |||
1 | package tools.refinery.store.query.viatra; | 1 | package tools.refinery.store.query.viatra; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.model.representation.Relation; | 4 | import tools.refinery.store.model.ModelStore; |
5 | import tools.refinery.store.model.representation.TruthValue; | 5 | import tools.refinery.store.query.DNF; |
6 | import tools.refinery.store.query.*; | 6 | import tools.refinery.store.query.ModelQuery; |
7 | import tools.refinery.store.query.Variable; | ||
7 | import tools.refinery.store.query.atom.*; | 8 | import tools.refinery.store.query.atom.*; |
8 | import tools.refinery.store.query.view.FilteredRelationView; | 9 | import tools.refinery.store.query.view.FilteredRelationView; |
9 | import tools.refinery.store.query.view.KeyOnlyRelationView; | 10 | import tools.refinery.store.query.view.KeyOnlyRelationView; |
10 | import tools.refinery.store.query.view.RelationView; | 11 | import tools.refinery.store.representation.Symbol; |
12 | import tools.refinery.store.representation.TruthValue; | ||
11 | import tools.refinery.store.tuple.Tuple; | 13 | import tools.refinery.store.tuple.Tuple; |
12 | import tools.refinery.store.tuple.TupleLike; | 14 | import tools.refinery.store.tuple.TupleLike; |
13 | 15 | ||
14 | import java.util.*; | 16 | import java.util.HashSet; |
17 | import java.util.Set; | ||
15 | import java.util.stream.Stream; | 18 | import java.util.stream.Stream; |
16 | 19 | ||
17 | import static org.junit.jupiter.api.Assertions.assertEquals; | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; |
@@ -19,41 +22,49 @@ import static org.junit.jupiter.api.Assertions.assertEquals; | |||
19 | class QueryTest { | 22 | class 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 @@ | |||
1 | package tools.refinery.store.query.viatra; | 1 | package tools.refinery.store.query.viatra; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.model.representation.Relation; | 4 | import tools.refinery.store.model.ModelStore; |
5 | import tools.refinery.store.query.DNF; | 5 | import tools.refinery.store.query.DNF; |
6 | import tools.refinery.store.query.QueryableModel; | 6 | import tools.refinery.store.query.ModelQuery; |
7 | import tools.refinery.store.query.QueryableModelStore; | ||
8 | import tools.refinery.store.query.Variable; | 7 | import tools.refinery.store.query.Variable; |
9 | import tools.refinery.store.query.atom.RelationViewAtom; | 8 | import tools.refinery.store.query.atom.RelationViewAtom; |
10 | import tools.refinery.store.query.viatra.ViatraQueryableModelStore; | ||
11 | import tools.refinery.store.query.view.KeyOnlyRelationView; | 9 | import tools.refinery.store.query.view.KeyOnlyRelationView; |
12 | import tools.refinery.store.query.view.RelationView; | 10 | import tools.refinery.store.representation.Symbol; |
13 | import tools.refinery.store.tuple.Tuple; | 11 | import tools.refinery.store.tuple.Tuple; |
14 | 12 | ||
15 | import java.util.Set; | ||
16 | |||
17 | import static org.junit.jupiter.api.Assertions.assertEquals; | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; |
18 | 14 | ||
19 | class QueryTransactionTest { | 15 | class 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; | |||
3 | import org.junit.jupiter.params.ParameterizedTest; | 3 | import org.junit.jupiter.params.ParameterizedTest; |
4 | import org.junit.jupiter.params.provider.Arguments; | 4 | import org.junit.jupiter.params.provider.Arguments; |
5 | import org.junit.jupiter.params.provider.MethodSource; | 5 | import org.junit.jupiter.params.provider.MethodSource; |
6 | import tools.refinery.store.model.representation.cardinality.UpperCardinalities; | 6 | import tools.refinery.store.representation.cardinality.UpperCardinalities; |
7 | import tools.refinery.store.model.representation.cardinality.UpperCardinality; | 7 | import tools.refinery.store.representation.cardinality.UpperCardinality; |
8 | 8 | ||
9 | import java.util.stream.Stream; | 9 | import 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 | ||
3 | import org.junit.jupiter.api.BeforeEach; | 3 | import org.junit.jupiter.api.BeforeEach; |
4 | import org.junit.jupiter.api.Test; | 4 | import org.junit.jupiter.api.Test; |
5 | import tools.refinery.store.model.representation.cardinality.UpperCardinalities; | 5 | import tools.refinery.store.representation.cardinality.UpperCardinalities; |
6 | import tools.refinery.store.model.representation.cardinality.UpperCardinality; | 6 | import tools.refinery.store.representation.cardinality.UpperCardinality; |
7 | 7 | ||
8 | import static org.hamcrest.MatcherAssert.assertThat; | 8 | import static org.hamcrest.MatcherAssert.assertThat; |
9 | import static org.hamcrest.Matchers.equalTo; | 9 | import 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.ModelStore; | ||
4 | import tools.refinery.store.model.ModelStoreBuilder; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import org.jetbrains.annotations.NotNull; | ||
4 | |||
5 | import java.util.*; | ||
6 | import java.util.function.Consumer; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import java.util.Collection; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.ModelStore; | ||
4 | import tools.refinery.store.model.ModelStoreBuilder; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.ModelStoreBuilder; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | |||
6 | import java.lang.reflect.Method; | ||
7 | import java.util.Collection; | ||
8 | import java.util.Collections; | ||
9 | import java.util.HashSet; | ||
10 | import java.util.Set; | ||
11 | |||
12 | public 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 @@ | |||
1 | package tools.refinery.store.adapter; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | import tools.refinery.store.representation.AnySymbol; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | import tools.refinery.store.map.Cursor; | ||
4 | import tools.refinery.store.map.DiffCursor; | ||
5 | import tools.refinery.store.representation.Symbol; | ||
6 | import tools.refinery.store.tuple.Tuple; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | import tools.refinery.store.tuple.Tuple; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.model; | 1 | package tools.refinery.store.model; |
2 | 2 | ||
3 | import tools.refinery.store.map.Cursor; | 3 | import tools.refinery.store.adapter.ModelAdapter; |
4 | import tools.refinery.store.adapter.ModelAdapterType; | ||
4 | import tools.refinery.store.map.Versioned; | 5 | import tools.refinery.store.map.Versioned; |
5 | import tools.refinery.store.model.representation.AnyDataRepresentation; | 6 | import tools.refinery.store.representation.AnySymbol; |
6 | import tools.refinery.store.model.representation.DataRepresentation; | 7 | import tools.refinery.store.representation.Symbol; |
7 | 8 | ||
8 | import java.util.Set; | 9 | import java.util.Optional; |
9 | 10 | ||
10 | public interface Model extends Versioned { | 11 | public 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 @@ | |||
1 | package tools.refinery.store.model; | 1 | package tools.refinery.store.model; |
2 | 2 | ||
3 | import tools.refinery.store.map.Cursor; | ||
4 | import tools.refinery.store.map.DiffCursor; | 3 | import tools.refinery.store.map.DiffCursor; |
5 | import tools.refinery.store.model.representation.AnyDataRepresentation; | 4 | import tools.refinery.store.representation.AnySymbol; |
6 | import tools.refinery.store.model.representation.DataRepresentation; | 5 | import tools.refinery.store.representation.Symbol; |
6 | import tools.refinery.store.tuple.Tuple; | ||
7 | 7 | ||
8 | import java.util.Map; | 8 | import java.util.Map; |
9 | 9 | ||
10 | public class ModelDiffCursor { | 10 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.model; | 1 | package tools.refinery.store.model; |
2 | 2 | ||
3 | import tools.refinery.store.model.representation.AnyDataRepresentation; | 3 | import tools.refinery.store.adapter.ModelAdapterType; |
4 | import tools.refinery.store.adapter.ModelStoreAdapter; | ||
5 | import tools.refinery.store.model.internal.ModelStoreBuilderImpl; | ||
6 | import tools.refinery.store.representation.AnySymbol; | ||
4 | 7 | ||
8 | import java.util.Collection; | ||
9 | import java.util.Optional; | ||
5 | import java.util.Set; | 10 | import java.util.Set; |
6 | 11 | ||
7 | public interface ModelStore { | 12 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelAdapterBuilder; | ||
4 | import tools.refinery.store.adapter.ModelAdapterBuilderFactory; | ||
5 | import tools.refinery.store.adapter.ModelAdapterType; | ||
6 | import tools.refinery.store.representation.AnySymbol; | ||
7 | import tools.refinery.store.representation.Symbol; | ||
8 | |||
9 | import java.util.Collection; | ||
10 | import java.util.List; | ||
11 | import java.util.Optional; | ||
12 | |||
13 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | import tools.refinery.store.map.*; | ||
4 | import tools.refinery.store.model.internal.ModelImpl; | ||
5 | import tools.refinery.store.model.internal.SimilarRelationEquivalenceClass; | ||
6 | import tools.refinery.store.model.representation.AnyDataRepresentation; | ||
7 | import tools.refinery.store.model.representation.AuxiliaryData; | ||
8 | import tools.refinery.store.model.representation.DataRepresentation; | ||
9 | import tools.refinery.store.model.representation.Relation; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | |||
12 | import java.util.*; | ||
13 | import java.util.Map.Entry; | ||
14 | |||
15 | public 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 @@ | |||
1 | package tools.refinery.store.model; | ||
2 | |||
3 | public 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; | |||
4 | import tools.refinery.store.tuple.Tuple; | 4 | import tools.refinery.store.tuple.Tuple; |
5 | 5 | ||
6 | public class TupleHashProvider implements ContinousHashProvider<Tuple> { | 6 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | 1 | package tools.refinery.store.model.internal; |
2 | 2 | ||
3 | import tools.refinery.store.map.ContinousHashProvider; | 3 | import tools.refinery.store.adapter.AdapterList; |
4 | import tools.refinery.store.map.Cursor; | 4 | import tools.refinery.store.adapter.AnyModelAdapterType; |
5 | import tools.refinery.store.adapter.ModelAdapter; | ||
6 | import tools.refinery.store.adapter.ModelAdapterType; | ||
5 | import tools.refinery.store.map.DiffCursor; | 7 | import tools.refinery.store.map.DiffCursor; |
6 | import tools.refinery.store.map.VersionedMap; | 8 | import tools.refinery.store.model.*; |
7 | import tools.refinery.store.map.internal.MapDiffCursor; | 9 | import tools.refinery.store.representation.AnySymbol; |
8 | import tools.refinery.store.model.Model; | 10 | import tools.refinery.store.representation.Symbol; |
9 | import tools.refinery.store.model.ModelDiffCursor; | 11 | import tools.refinery.store.tuple.Tuple; |
10 | import tools.refinery.store.model.ModelStore; | 12 | |
11 | import tools.refinery.store.model.representation.AnyDataRepresentation; | 13 | import java.util.*; |
12 | import tools.refinery.store.model.representation.DataRepresentation; | ||
13 | |||
14 | import java.util.HashMap; | ||
15 | import java.util.Map; | ||
16 | import java.util.Set; | ||
17 | 14 | ||
18 | public class ModelImpl implements Model { | 15 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | import tools.refinery.store.adapter.AdapterList; | ||
4 | import tools.refinery.store.adapter.ModelAdapterBuilder; | ||
5 | import tools.refinery.store.adapter.ModelAdapterBuilderFactory; | ||
6 | import tools.refinery.store.adapter.ModelAdapterType; | ||
7 | import tools.refinery.store.map.VersionedMapStore; | ||
8 | import tools.refinery.store.map.VersionedMapStoreImpl; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.model.ModelStoreBuilder; | ||
11 | import tools.refinery.store.model.TupleHashProvider; | ||
12 | import tools.refinery.store.representation.AnySymbol; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | import tools.refinery.store.tuple.Tuple; | ||
15 | |||
16 | import java.util.*; | ||
17 | |||
18 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | import tools.refinery.store.adapter.AdapterList; | ||
4 | import tools.refinery.store.adapter.AnyModelAdapterType; | ||
5 | import tools.refinery.store.adapter.ModelAdapterType; | ||
6 | import tools.refinery.store.adapter.ModelStoreAdapter; | ||
7 | import tools.refinery.store.map.DiffCursor; | ||
8 | import tools.refinery.store.map.VersionedMapStore; | ||
9 | import tools.refinery.store.model.ModelDiffCursor; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.representation.AnySymbol; | ||
12 | import tools.refinery.store.tuple.Tuple; | ||
13 | |||
14 | import java.util.*; | ||
15 | |||
16 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | import tools.refinery.store.map.ContinousHashProvider; | ||
4 | import tools.refinery.store.model.representation.Relation; | ||
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | |||
7 | import java.util.Objects; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | import tools.refinery.store.representation.Symbol; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.model.internal; | ||
2 | |||
3 | import tools.refinery.store.map.Cursor; | ||
4 | import tools.refinery.store.map.DiffCursor; | ||
5 | import tools.refinery.store.map.VersionedMap; | ||
6 | import tools.refinery.store.map.VersionedMapStore; | ||
7 | import tools.refinery.store.map.internal.MapDiffCursor; | ||
8 | import tools.refinery.store.model.Interpretation; | ||
9 | import tools.refinery.store.model.InterpretationListener; | ||
10 | import tools.refinery.store.model.Model; | ||
11 | import tools.refinery.store.model.TupleHashProvider; | ||
12 | import tools.refinery.store.representation.AnySymbol; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | import tools.refinery.store.tuple.Tuple; | ||
15 | |||
16 | import java.util.ArrayList; | ||
17 | import java.util.List; | ||
18 | |||
19 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | import tools.refinery.store.model.RelationLike; | ||
4 | import tools.refinery.store.tuple.Tuple; | ||
5 | |||
6 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | import tools.refinery.store.map.ContinousHashProvider; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | import tools.refinery.store.map.ContinousHashProvider; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | ||
2 | |||
3 | import tools.refinery.store.map.ContinousHashProvider; | ||
4 | import tools.refinery.store.model.TupleHashProvider; | ||
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | |||
7 | public 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 @@ | |||
1 | package tools.refinery.store.query; | 1 | package tools.refinery.store.query; |
2 | 2 | ||
3 | import tools.refinery.store.model.RelationLike; | 3 | import tools.refinery.store.representation.SymbolLike; |
4 | import tools.refinery.store.query.atom.DNFAtom; | 4 | import tools.refinery.store.query.atom.DNFAtom; |
5 | 5 | ||
6 | import java.util.*; | 6 | import java.util.*; |
7 | 7 | ||
8 | public class DNF implements RelationLike { | 8 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelAdapterType; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelAdapter; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelAdapterBuilder; | ||
4 | import tools.refinery.store.model.ModelStore; | ||
5 | |||
6 | import java.util.Collection; | ||
7 | import java.util.List; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.adapter.ModelStoreAdapter; | ||
4 | import tools.refinery.store.model.Model; | ||
5 | import tools.refinery.store.query.view.AnyRelationView; | ||
6 | |||
7 | import java.util.Collection; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.tuple.Tuple; | ||
5 | import tools.refinery.store.tuple.TupleLike; | ||
6 | |||
7 | import java.util.Optional; | ||
8 | import java.util.Set; | ||
9 | import java.util.stream.Stream; | ||
10 | |||
11 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.model.ModelStore; | ||
4 | import tools.refinery.store.model.representation.AnyDataRepresentation; | ||
5 | import tools.refinery.store.query.view.AnyRelationView; | ||
6 | |||
7 | import java.util.Set; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import tools.refinery.store.tuple.Tuple; | ||
4 | import tools.refinery.store.tuple.TupleLike; | ||
5 | |||
6 | import java.util.Optional; | ||
7 | import java.util.stream.Stream; | ||
8 | |||
9 | public 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 @@ | |||
1 | package tools.refinery.store.query.atom; | 1 | package tools.refinery.store.query.atom; |
2 | 2 | ||
3 | import tools.refinery.store.model.RelationLike; | 3 | import tools.refinery.store.representation.SymbolLike; |
4 | import tools.refinery.store.query.Variable; | 4 | import tools.refinery.store.query.Variable; |
5 | 5 | ||
6 | import java.util.List; | 6 | import java.util.List; |
7 | import java.util.Set; | 7 | import java.util.Set; |
8 | 8 | ||
9 | public abstract class AbstractSubstitutionAtom<T extends RelationLike> implements DNFAtom { | 9 | public 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 @@ | |||
1 | package tools.refinery.store.query.atom; | 1 | package tools.refinery.store.query.atom; |
2 | 2 | ||
3 | import tools.refinery.store.model.RelationLike; | 3 | import tools.refinery.store.representation.SymbolLike; |
4 | import tools.refinery.store.query.Variable; | 4 | import tools.refinery.store.query.Variable; |
5 | 5 | ||
6 | import java.util.List; | 6 | import java.util.List; |
7 | import java.util.Objects; | 7 | import java.util.Objects; |
8 | import java.util.Set; | 8 | import java.util.Set; |
9 | 9 | ||
10 | public final class CallAtom<T extends RelationLike> extends AbstractSubstitutionAtom<T> { | 10 | public 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 @@ | |||
1 | package tools.refinery.store.query.atom; | ||
2 | |||
3 | import tools.refinery.store.query.DNF; | ||
4 | import tools.refinery.store.query.Variable; | ||
5 | |||
6 | import java.util.List; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.store.query.atom; | 1 | package tools.refinery.store.query.atom; |
2 | 2 | ||
3 | import tools.refinery.store.model.RelationLike; | 3 | import tools.refinery.store.representation.SymbolLike; |
4 | import tools.refinery.store.model.representation.Relation; | 4 | import tools.refinery.store.representation.Symbol; |
5 | import tools.refinery.store.model.representation.TruthValue; | 5 | import tools.refinery.store.representation.TruthValue; |
6 | 6 | ||
7 | public record ModalRelation(Modality modality, Relation<TruthValue> relation) implements RelationLike { | 7 | public 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 @@ | |||
1 | package tools.refinery.store.query.view; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.tuple.Tuple; | ||
5 | import tools.refinery.store.tuple.Tuple1; | ||
6 | import tools.refinery.store.model.representation.Relation; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.store.query.view; | 1 | package tools.refinery.store.query.view; |
2 | 2 | ||
3 | import tools.refinery.store.model.Model; | 3 | import tools.refinery.store.model.Model; |
4 | import tools.refinery.store.model.RelationLike; | 4 | import tools.refinery.store.representation.SymbolLike; |
5 | import tools.refinery.store.model.representation.AnyRelation; | 5 | import tools.refinery.store.representation.AnySymbol; |
6 | 6 | ||
7 | public sealed interface AnyRelationView extends RelationLike permits RelationView { | 7 | public 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 @@ | |||
1 | package tools.refinery.store.query.view; | 1 | package tools.refinery.store.query.view; |
2 | 2 | ||
3 | import tools.refinery.store.tuple.Tuple; | 3 | import tools.refinery.store.tuple.Tuple; |
4 | import tools.refinery.store.model.representation.Relation; | 4 | import tools.refinery.store.representation.Symbol; |
5 | 5 | ||
6 | import java.util.Objects; | 6 | import java.util.Objects; |
7 | import java.util.function.BiPredicate; | 7 | import java.util.function.BiPredicate; |
8 | import java.util.function.Predicate; | 8 | import java.util.function.Predicate; |
9 | 9 | ||
10 | public class FilteredRelationView<D> extends AbstractFilteredRelationView<D> { | 10 | public 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; | |||
3 | import tools.refinery.store.model.Model; | 3 | import tools.refinery.store.model.Model; |
4 | import tools.refinery.store.tuple.Tuple; | 4 | import tools.refinery.store.tuple.Tuple; |
5 | import tools.refinery.store.tuple.Tuple1; | 5 | import tools.refinery.store.tuple.Tuple1; |
6 | import tools.refinery.store.model.representation.Relation; | 6 | import tools.refinery.store.representation.Symbol; |
7 | 7 | ||
8 | public class FunctionalRelationView<D> extends RelationView<D> { | 8 | public 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 @@ | |||
1 | package tools.refinery.store.query.view; | 1 | package tools.refinery.store.query.view; |
2 | 2 | ||
3 | import tools.refinery.store.representation.Symbol; | ||
3 | import tools.refinery.store.tuple.Tuple; | 4 | import tools.refinery.store.tuple.Tuple; |
4 | import tools.refinery.store.model.representation.Relation; | ||
5 | 5 | ||
6 | import java.util.Objects; | 6 | import java.util.Objects; |
7 | 7 | ||
8 | public class KeyOnlyRelationView extends AbstractFilteredRelationView<Boolean> { | 8 | public 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 | ||
3 | import tools.refinery.store.map.CursorAsIterator; | 3 | import tools.refinery.store.map.CursorAsIterator; |
4 | import tools.refinery.store.model.Model; | 4 | import tools.refinery.store.model.Model; |
5 | import tools.refinery.store.model.representation.Relation; | 5 | import tools.refinery.store.representation.Symbol; |
6 | import tools.refinery.store.tuple.Tuple; | 6 | import tools.refinery.store.tuple.Tuple; |
7 | 7 | ||
8 | import java.util.Objects; | 8 | import java.util.Objects; |
9 | import java.util.UUID; | 9 | import 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 | */ |
17 | public abstract non-sealed class RelationView<D> implements AnyRelationView { | 17 | public 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 @@ | |||
1 | package tools.refinery.store.query.view; | ||
2 | |||
3 | import tools.refinery.store.model.Model; | ||
4 | import tools.refinery.store.tuple.Tuple; | ||
5 | import tools.refinery.store.tuple.Tuple1; | ||
6 | import tools.refinery.store.representation.Symbol; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.store.representation; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.representation; | ||
2 | |||
3 | import java.util.Objects; | ||
4 | |||
5 | // Deliberately not a record, because we want equality by reference. | ||
6 | @SuppressWarnings({"squid:S6206", "ClassCanBeRecord"}) | ||
7 | public 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 @@ | |||
1 | package tools.refinery.store.representation; | ||
2 | |||
3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation; | 1 | package tools.refinery.store.representation; |
2 | 2 | ||
3 | public enum TruthValue { | 3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval { | 3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | public final class CardinalityIntervals { | 3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | public final class EmptyCardinalityInterval implements CardinalityInterval { | 3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.jetbrains.annotations.NotNull; | 3 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import java.util.function.BinaryOperator; | 3 | import java.util.function.BinaryOperator; |
4 | import java.util.function.IntBinaryOperator; | 4 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.jetbrains.annotations.NotNull; | 3 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | public final class UpperCardinalities { | 3 | public 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality, | 3 | public 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 @@ | |||
1 | package tools.refinery.store.map.tests; | 1 | package tools.refinery.store.map.tests; |
2 | 2 | ||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | |||
5 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
6 | |||
7 | import tools.refinery.store.map.VersionedMapStore; | 4 | import tools.refinery.store.map.VersionedMapStore; |
8 | import tools.refinery.store.map.VersionedMapStoreImpl; | 5 | import tools.refinery.store.map.VersionedMapStoreImpl; |
9 | import tools.refinery.store.tuple.Tuple; | ||
10 | import tools.refinery.store.model.TupleHashProvider; | 6 | import tools.refinery.store.model.TupleHashProvider; |
7 | import tools.refinery.store.tuple.Tuple; | ||
8 | |||
9 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
11 | 10 | ||
12 | class MapUnitTests { | 11 | class 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 @@ | |||
1 | package tools.refinery.store.model.hashTests; | 1 | package tools.refinery.store.model.hashtests; |
2 | 2 | ||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | 3 | import 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 @@ | |||
1 | package tools.refinery.store.model.tests; | 1 | package tools.refinery.store.model.tests; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.model.Model; | ||
5 | import tools.refinery.store.model.ModelStore; | 4 | import tools.refinery.store.model.ModelStore; |
6 | import tools.refinery.store.model.ModelStoreImpl; | 5 | import tools.refinery.store.representation.Symbol; |
7 | import tools.refinery.store.model.representation.Relation; | ||
8 | import tools.refinery.store.tuple.Tuple; | 6 | import tools.refinery.store.tuple.Tuple; |
9 | 7 | ||
10 | import java.util.Set; | ||
11 | |||
12 | import static org.junit.jupiter.api.Assertions.*; | 8 | import static org.junit.jupiter.api.Assertions.*; |
13 | 9 | ||
14 | class ModelTest { | 10 | class 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.params.ParameterizedTest; | 3 | import org.junit.jupiter.params.ParameterizedTest; |
4 | import org.junit.jupiter.params.provider.Arguments; | 4 | import org.junit.jupiter.params.provider.Arguments; |
5 | import org.junit.jupiter.params.provider.MethodSource; | 5 | import org.junit.jupiter.params.provider.MethodSource; |
6 | import tools.refinery.store.representation.cardinality.CardinalityInterval; | ||
6 | 7 | ||
7 | import java.util.stream.Stream; | 8 | import java.util.stream.Stream; |
8 | 9 | ||
9 | import static org.hamcrest.MatcherAssert.assertThat; | 10 | import static org.hamcrest.MatcherAssert.assertThat; |
10 | import static org.hamcrest.Matchers.equalTo; | 11 | import static org.hamcrest.Matchers.equalTo; |
11 | import static tools.refinery.store.model.representation.cardinality.CardinalityIntervals.*; | 12 | import static tools.refinery.store.representation.cardinality.CardinalityIntervals.*; |
12 | 13 | ||
13 | class CardinalityIntervalTest { | 14 | class 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
5 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
4 | 6 | ||
5 | import static org.hamcrest.MatcherAssert.assertThat; | 7 | import static org.hamcrest.MatcherAssert.assertThat; |
6 | import static org.hamcrest.Matchers.*; | 8 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.representation.cardinality.CardinalityIntervals; | ||
4 | 5 | ||
5 | import static org.hamcrest.MatcherAssert.assertThat; | 6 | import static org.hamcrest.MatcherAssert.assertThat; |
6 | import static org.hamcrest.Matchers.lessThan; | 7 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.representation.cardinality.NonEmptyCardinalityInterval; | ||
5 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
6 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
4 | 7 | ||
5 | import static org.junit.jupiter.api.Assertions.assertThrows; | 8 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; | ||
4 | 5 | ||
5 | import static org.junit.jupiter.api.Assertions.assertThrows; | 6 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.api.Test; | 3 | import org.junit.jupiter.api.Test; |
4 | import org.junit.jupiter.params.ParameterizedTest; | 4 | import org.junit.jupiter.params.ParameterizedTest; |
5 | import org.junit.jupiter.params.provider.ValueSource; | 5 | import org.junit.jupiter.params.provider.ValueSource; |
6 | import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; | ||
7 | import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; | ||
8 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
6 | 9 | ||
7 | import static org.hamcrest.MatcherAssert.assertThat; | 10 | import static org.hamcrest.MatcherAssert.assertThat; |
8 | import static org.hamcrest.Matchers.equalTo; | 11 | import 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 @@ | |||
1 | package tools.refinery.store.model.representation.cardinality; | 1 | package tools.refinery.store.representation.cardinality; |
2 | 2 | ||
3 | import org.junit.jupiter.params.ParameterizedTest; | 3 | import org.junit.jupiter.params.ParameterizedTest; |
4 | import org.junit.jupiter.params.provider.Arguments; | 4 | import org.junit.jupiter.params.provider.Arguments; |
5 | import org.junit.jupiter.params.provider.MethodSource; | 5 | import org.junit.jupiter.params.provider.MethodSource; |
6 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
7 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
6 | 8 | ||
7 | import java.util.stream.Stream; | 9 | import java.util.stream.Stream; |
8 | 10 | ||