aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-23 20:27:55 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-01-29 00:02:28 +0100
commitd91acf3690682d243dbc150df902525b6e545c2f (patch)
treef39695cc193828df0b78030b5a56bd968e277457 /subprojects/store
parentchore(deps): bump dependencies (diff)
downloadrefinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.gz
refinery-d91acf3690682d243dbc150df902525b6e545c2f.tar.zst
refinery-d91acf3690682d243dbc150df902525b6e545c2f.zip
refactor: Model store and query API
Use Adapters to simplify API usage.
Diffstat (limited to 'subprojects/store')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java27
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java94
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java79
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java29
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java15
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java36
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java115
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java211
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java104
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java100
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java35
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java159
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java4
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java23
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java43
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/DNF.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java23
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java16
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java18
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java32
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java18
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java34
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java47
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java)2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java (renamed from subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java)2
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java9
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java)2
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java190
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java)4
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java)3
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java)3
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java)5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java (renamed from subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java)4
73 files changed, 1344 insertions, 691 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
new file mode 100644
index 00000000..4c142217
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
@@ -0,0 +1,27 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder;
5
6public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder {
7 private final ModelStoreBuilder storeBuilder;
8
9 protected AbstractModelAdapterBuilder(ModelStoreBuilder storeBuilder) {
10 this.storeBuilder = storeBuilder;
11 }
12
13 @Override
14 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
15 return storeBuilder.with(adapterBuilderFactory);
16 }
17
18 @Override
19 public ModelStoreBuilder getStoreBuilder() {
20 return storeBuilder;
21 }
22
23 @Override
24 public ModelStore build() {
25 return storeBuilder.build();
26 }
27}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
new file mode 100644
index 00000000..2783675f
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
@@ -0,0 +1,94 @@
1package tools.refinery.store.adapter;
2
3import org.jetbrains.annotations.NotNull;
4
5import java.util.*;
6import java.util.function.Consumer;
7
8public class AdapterList<T> implements Iterable<T> {
9 private final List<AnyModelAdapterType> adapterTypes;
10 private final List<T> adapters;
11
12 public AdapterList() {
13 adapterTypes = new ArrayList<>();
14 adapters = new ArrayList<>();
15 }
16
17 public AdapterList(int adapterCount) {
18 adapterTypes = new ArrayList<>(adapterCount);
19 adapters = new ArrayList<>(adapterCount);
20 }
21
22 public int size() {
23 return adapters.size();
24 }
25
26 public void add(AnyModelAdapterType adapterType, T adapter) {
27 adapterTypes.add(adapterType);
28 adapters.add(adapter);
29 }
30
31 public <U extends T> Optional<U> tryGet(AnyModelAdapterType adapterType, Class<? extends U> adapterClass) {
32 int size = size();
33 for (int i = 0; i < size; i++) {
34 if (getType(i).supports(adapterType)) {
35 return Optional.of(adapterClass.cast(get(i)));
36 }
37 }
38 return Optional.empty();
39 }
40
41 public <U extends T> U get(AnyModelAdapterType adapterType, Class<U> adapterClass) {
42 return tryGet(adapterType, adapterClass).orElseThrow(() -> new IllegalArgumentException(
43 "No %s was configured".formatted(adapterType)));
44 }
45
46 public AnyModelAdapterType getType(int i) {
47 return adapterTypes.get(i);
48 }
49
50 public T get(int i) {
51 return adapters.get(i);
52 }
53
54 public Collection<AnyModelAdapterType> getAdapterTypes() {
55 return Collections.unmodifiableCollection(adapterTypes);
56 }
57
58 public Iterable<Entry<T>> withAdapterTypes() {
59 return () -> new Iterator<>() {
60 private int i = 0;
61
62 @Override
63 public boolean hasNext() {
64 return i < size();
65 }
66
67 @Override
68 public Entry<T> next() {
69 var entry = new Entry<>(getType(i), get(i));
70 i++;
71 return entry;
72 }
73 };
74 }
75
76 @NotNull
77 @Override
78 public Iterator<T> iterator() {
79 return adapters.iterator();
80 }
81
82 @Override
83 public void forEach(Consumer<? super T> action) {
84 adapters.forEach(action);
85 }
86
87 @Override
88 public Spliterator<T> spliterator() {
89 return adapters.spliterator();
90 }
91
92 public record Entry<T>(AnyModelAdapterType adapterType, T adapter) {
93 }
94}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
new file mode 100644
index 00000000..37a247fe
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
@@ -0,0 +1,19 @@
1package tools.refinery.store.adapter;
2
3import java.util.Collection;
4
5public sealed interface AnyModelAdapterType permits ModelAdapterType {
6 Class<? extends ModelAdapter> getModelAdapterClass();
7
8 Class<? extends ModelStoreAdapter> getModelStoreAdapterClass();
9
10 Class<? extends ModelAdapterBuilder> getModelAdapterBuilderClass();
11
12 Collection<AnyModelAdapterType> getSupportedAdapterTypes();
13
14 default boolean supports(AnyModelAdapterType targetAdapter) {
15 return getSupportedAdapterTypes().contains(targetAdapter);
16 }
17
18 String getName();
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
new file mode 100644
index 00000000..aa079e01
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4
5public interface ModelAdapter {
6 Model getModel();
7
8 ModelStoreAdapter getStoreAdapter();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
new file mode 100644
index 00000000..64b3e59f
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
@@ -0,0 +1,17 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder;
5
6public interface ModelAdapterBuilder {
7 ModelStoreAdapter createStoreAdapter(ModelStore store);
8
9 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory);
10
11 ModelStoreBuilder getStoreBuilder();
12
13 default void configure() {
14 }
15
16 ModelStore build();
17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
new file mode 100644
index 00000000..7c9b01bc
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
@@ -0,0 +1,14 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStoreBuilder;
4
5public abstract class ModelAdapterBuilderFactory<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
6 T3 extends ModelAdapterBuilder> extends ModelAdapterType<T1, T2, T3> {
7
8 protected ModelAdapterBuilderFactory(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
9 Class<T3> modelAdapterBuilderClass) {
10 super(modelAdapterClass, modelStoreAdapterClass, modelAdapterBuilderClass);
11 }
12
13 public abstract T3 createBuilder(ModelStoreBuilder storeBuilder);
14}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
new file mode 100644
index 00000000..82ddeb12
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
@@ -0,0 +1,79 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStore;
5
6import java.lang.reflect.Method;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Set;
11
12public abstract non-sealed class ModelAdapterType<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
13 T3 extends ModelAdapterBuilder> implements AnyModelAdapterType {
14 private final Class<? extends T1> modelAdapterClass;
15 private final Class<? extends T2> modelStoreAdapterClass;
16 private final Class<? extends T3> modelAdapterBuilderClass;
17 private final Set<AnyModelAdapterType> supportedAdapters = new HashSet<>();
18
19 protected ModelAdapterType(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
20 Class<T3> modelAdapterBuilderClass) {
21 checkReturnType(modelAdapterClass, modelStoreAdapterClass, "createModelAdapter", Model.class);
22 checkReturnType(modelStoreAdapterClass, modelAdapterBuilderClass, "createStoreAdapter", ModelStore.class);
23 this.modelAdapterClass = modelAdapterClass;
24 this.modelStoreAdapterClass = modelStoreAdapterClass;
25 this.modelAdapterBuilderClass = modelAdapterBuilderClass;
26 supportedAdapters.add(this);
27 }
28
29 private void checkReturnType(Class<?> expectedReturnType, Class<?> ownerClass, String methodName,
30 Class<?>... argumentTypes) {
31 Method method;
32 try {
33 method = ownerClass.getMethod(methodName, argumentTypes);
34 } catch (NoSuchMethodException e) {
35 throw new IllegalStateException("Invalid %s: %s#%s method is required"
36 .formatted(this, ownerClass.getName(), methodName), e);
37 }
38 var returnType = method.getReturnType();
39 if (!expectedReturnType.isAssignableFrom(returnType)) {
40 throw new IllegalStateException("Invalid %s: %s is not assignable from the return type %s of %s#%s"
41 .formatted(this, expectedReturnType.getName(), returnType.getCanonicalName(),
42 ownerClass.getName(), methodName));
43 }
44 }
45
46 protected void extendsAdapter(ModelAdapterType<? super T1, ? super T2, ? super T3> superAdapter) {
47 supportedAdapters.addAll(superAdapter.supportedAdapters);
48 }
49
50 @Override
51 public final Class<? extends T1> getModelAdapterClass() {
52 return modelAdapterClass;
53 }
54
55 @Override
56 public final Class<? extends T2> getModelStoreAdapterClass() {
57 return modelStoreAdapterClass;
58 }
59
60 @Override
61 public final Class<? extends T3> getModelAdapterBuilderClass() {
62 return modelAdapterBuilderClass;
63 }
64
65 @Override
66 public Collection<AnyModelAdapterType> getSupportedAdapterTypes() {
67 return Collections.unmodifiableCollection(supportedAdapters);
68 }
69
70 @Override
71 public String getName() {
72 return "%s.ADAPTER".formatted(this.getClass().getName());
73 }
74
75 @Override
76 public String toString() {
77 return getName();
78 }
79}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
new file mode 100644
index 00000000..1eb40ada
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
@@ -0,0 +1,10 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStore;
5
6public interface ModelStoreAdapter {
7 ModelStore getStore();
8
9 ModelAdapter createModelAdapter(Model model);
10}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
new file mode 100644
index 00000000..d18ba71d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.representation.AnySymbol;
4
5public sealed interface AnyInterpretation permits Interpretation {
6 Model getModel();
7
8 AnySymbol getSymbol();
9
10 long getSize();
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
new file mode 100644
index 00000000..55949d0c
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
@@ -0,0 +1,25 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple;
7
8public non-sealed interface Interpretation<T> extends AnyInterpretation {
9 @Override
10 Symbol<T> getSymbol();
11
12 T get(Tuple key);
13
14 Cursor<Tuple, T> getAll();
15
16 T put(Tuple key, T value);
17
18 void putAll(Cursor<Tuple, T> cursor);
19
20 DiffCursor<Tuple, T> getDiffCursor(long to);
21
22 void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring);
23
24 void removeListener(InterpretationListener<T> listener);
25}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
new file mode 100644
index 00000000..73950779
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.tuple.Tuple;
4
5public interface InterpretationListener<T> {
6 void put(Tuple key, T fromValue, T toValue, boolean restoring);
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
index 69f57389..8d2a4614 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
@@ -1,24 +1,31 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.map.Cursor; 3import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.adapter.ModelAdapterType;
4import tools.refinery.store.map.Versioned; 5import tools.refinery.store.map.Versioned;
5import tools.refinery.store.model.representation.AnyDataRepresentation; 6import tools.refinery.store.representation.AnySymbol;
6import tools.refinery.store.model.representation.DataRepresentation; 7import tools.refinery.store.representation.Symbol;
7 8
8import java.util.Set; 9import java.util.Optional;
9 10
10public interface Model extends Versioned { 11public interface Model extends Versioned {
11 Set<AnyDataRepresentation> getDataRepresentations(); 12 ModelStore getStore();
12 13
13 <K, V> V get(DataRepresentation<K, V> representation, K key); 14 long getState();
14 15
15 <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation); 16 default AnyInterpretation getInterpretation(AnySymbol symbol) {
17 return getInterpretation((Symbol<?>) symbol);
18 }
16 19
17 <K, V> V put(DataRepresentation<K, V> representation, K key, V value); 20 <T> Interpretation<T> getInterpretation(Symbol<T> symbol);
18 21
19 <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor); 22 ModelDiffCursor getDiffCursor(long to);
20 23
21 long getSize(AnyDataRepresentation representation); 24 <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType);
22 25
23 ModelDiffCursor getDiffCursor(long to); 26 <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType);
27
28 void addListener(ModelListener listener);
29
30 void removeListener(ModelListener listener);
24} 31}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
index d5bb541b..97bf2039 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
@@ -1,27 +1,27 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor; 3import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.model.representation.AnyDataRepresentation; 4import tools.refinery.store.representation.AnySymbol;
6import tools.refinery.store.model.representation.DataRepresentation; 5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple;
7 7
8import java.util.Map; 8import java.util.Map;
9 9
10public class ModelDiffCursor { 10public class ModelDiffCursor {
11 final Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors; 11 private final Map<? extends AnySymbol, ? extends DiffCursor<?, ?>> diffCursors;
12 12
13 public ModelDiffCursor(Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors) { 13 public ModelDiffCursor(Map<? extends AnySymbol, ? extends DiffCursor<?, ?>> diffCursors) {
14 super(); 14 super();
15 this.diffCursors = diffCursors; 15 this.diffCursors = diffCursors;
16 } 16 }
17 17
18 @SuppressWarnings("unchecked") 18 public <T> DiffCursor<Tuple, T> getCursor(Symbol<T> symbol) {
19 public <K, V> DiffCursor<K, V> getCursor(DataRepresentation<K, V> representation) { 19 var cursor = diffCursors.get(symbol);
20 Cursor<?, ?> cursor = diffCursors.get(representation); 20 if (cursor == null) {
21 if (cursor != null) { 21 throw new IllegalArgumentException("No cursor for symbol %s".formatted(symbol));
22 return (DiffCursor<K, V>) cursor;
23 } else {
24 throw new IllegalArgumentException("ModelCursor does not contain cursor for representation " + representation);
25 } 22 }
23 @SuppressWarnings("unchecked")
24 var typedCursor = (DiffCursor<Tuple, T>) cursor;
25 return typedCursor;
26 } 26 }
27} 27}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
new file mode 100644
index 00000000..f67540bb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
@@ -0,0 +1,15 @@
1package tools.refinery.store.model;
2
3public interface ModelListener {
4 default void beforeCommit() {
5 }
6
7 default void afterCommit() {
8 }
9
10 default void beforeRestore(long state) {
11 }
12
13 default void afterRestore() {
14 }
15}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
index 84b67765..bc863d4b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
@@ -1,11 +1,16 @@
1package tools.refinery.store.model; 1package tools.refinery.store.model;
2 2
3import tools.refinery.store.model.representation.AnyDataRepresentation; 3import tools.refinery.store.adapter.ModelAdapterType;
4import tools.refinery.store.adapter.ModelStoreAdapter;
5import tools.refinery.store.model.internal.ModelStoreBuilderImpl;
6import tools.refinery.store.representation.AnySymbol;
4 7
8import java.util.Collection;
9import java.util.Optional;
5import java.util.Set; 10import java.util.Set;
6 11
7public interface ModelStore { 12public interface ModelStore {
8 Set<AnyDataRepresentation> getDataRepresentations(); 13 Collection<AnySymbol> getSymbols();
9 14
10 Model createModel(); 15 Model createModel();
11 16
@@ -14,4 +19,12 @@ public interface ModelStore {
14 Set<Long> getStates(); 19 Set<Long> getStates();
15 20
16 ModelDiffCursor getDiffCursor(long from, long to); 21 ModelDiffCursor getDiffCursor(long from, long to);
22
23 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType);
24
25 <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType);
26
27 static ModelStoreBuilder builder() {
28 return new ModelStoreBuilderImpl();
29 }
17} 30}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
new file mode 100644
index 00000000..289099da
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
@@ -0,0 +1,36 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.representation.AnySymbol;
7import tools.refinery.store.representation.Symbol;
8
9import java.util.Collection;
10import java.util.List;
11import java.util.Optional;
12
13public interface ModelStoreBuilder {
14 default ModelStoreBuilder symbols(AnySymbol... symbols) {
15 return symbols(List.of(symbols));
16 }
17
18 default ModelStoreBuilder symbols(Collection<? extends AnySymbol> symbols) {
19 symbols.forEach(this::symbol);
20 return this;
21 }
22
23 default ModelStoreBuilder symbol(AnySymbol symbol) {
24 return symbol((Symbol<?>) symbol);
25 }
26
27 <T> ModelStoreBuilder symbol(Symbol<T> symbol);
28
29 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory);
30
31 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType);
32
33 <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType);
34
35 ModelStore build();
36}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java
deleted file mode 100644
index 2f73a0e5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreImpl.java
+++ /dev/null
@@ -1,115 +0,0 @@
1package tools.refinery.store.model;
2
3import tools.refinery.store.map.*;
4import tools.refinery.store.model.internal.ModelImpl;
5import tools.refinery.store.model.internal.SimilarRelationEquivalenceClass;
6import tools.refinery.store.model.representation.AnyDataRepresentation;
7import tools.refinery.store.model.representation.AuxiliaryData;
8import tools.refinery.store.model.representation.DataRepresentation;
9import tools.refinery.store.model.representation.Relation;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.*;
13import java.util.Map.Entry;
14
15public class ModelStoreImpl implements ModelStore {
16
17 private final Map<AnyDataRepresentation, VersionedMapStore<?, ?>> stores;
18
19 public ModelStoreImpl(Set<AnyDataRepresentation> dataRepresentations) {
20 stores = initStores(dataRepresentations);
21 }
22
23 private Map<AnyDataRepresentation, VersionedMapStore<?, ?>> initStores(
24 Set<AnyDataRepresentation> dataRepresentations) {
25 Map<AnyDataRepresentation, VersionedMapStore<?, ?>> result = new HashMap<>();
26
27 Map<SimilarRelationEquivalenceClass, List<Relation<?>>> symbolRepresentationsPerHashPerArity = new HashMap<>();
28
29 for (AnyDataRepresentation dataRepresentation : dataRepresentations) {
30 if (dataRepresentation instanceof Relation<?> symbolRepresentation) {
31 addOrCreate(symbolRepresentationsPerHashPerArity,
32 new SimilarRelationEquivalenceClass(symbolRepresentation), symbolRepresentation);
33 } else if (dataRepresentation instanceof AuxiliaryData<?, ?> auxiliaryData) {
34 VersionedMapStoreImpl<?, ?> store = new VersionedMapStoreImpl<>(auxiliaryData.getHashProvider(),
35 auxiliaryData.getDefaultValue());
36 result.put(auxiliaryData, store);
37 } else {
38 throw new UnsupportedOperationException(
39 "Model store does not have strategy to use " + dataRepresentation.getClass() + "!");
40 }
41 }
42 for (List<Relation<?>> symbolGroup : symbolRepresentationsPerHashPerArity.values()) {
43 initRepresentationGroup(result, symbolGroup);
44 }
45
46 return result;
47 }
48
49 private void initRepresentationGroup(Map<AnyDataRepresentation, VersionedMapStore<?, ?>> result,
50 List<Relation<?>> symbolGroup) {
51 final ContinousHashProvider<Tuple> hashProvider = symbolGroup.get(0).getHashProvider();
52 final Object defaultValue = symbolGroup.get(0).getDefaultValue();
53
54 List<VersionedMapStore<Tuple, Object>> maps = VersionedMapStoreImpl
55 .createSharedVersionedMapStores(symbolGroup.size(), hashProvider, defaultValue);
56
57 for (int i = 0; i < symbolGroup.size(); i++) {
58 result.put(symbolGroup.get(i), maps.get(i));
59 }
60 }
61
62 private static <K, V> void addOrCreate(Map<K, List<V>> map, K key, V value) {
63 List<V> list;
64 if (map.containsKey(key)) {
65 list = map.get(key);
66 } else {
67 list = new LinkedList<>();
68 map.put(key, list);
69 }
70 list.add(value);
71 }
72
73 @Override
74 public Set<AnyDataRepresentation> getDataRepresentations() {
75 return this.stores.keySet();
76 }
77
78 @Override
79 public ModelImpl createModel() {
80 Map<AnyDataRepresentation, VersionedMap<?, ?>> maps = new HashMap<>();
81 for (var entry : this.stores.entrySet()) {
82 maps.put(entry.getKey(), entry.getValue().createMap());
83 }
84 return new ModelImpl(this, maps);
85 }
86
87 @Override
88 public synchronized ModelImpl createModel(long state) {
89 Map<AnyDataRepresentation, VersionedMap<?, ?>> maps = new HashMap<>();
90 for (var entry : this.stores.entrySet()) {
91 maps.put(entry.getKey(), entry.getValue().createMap(state));
92 }
93 return new ModelImpl(this, maps);
94 }
95
96 @Override
97 public synchronized Set<Long> getStates() {
98 var iterator = stores.values().iterator();
99 if (iterator.hasNext()) {
100 return Set.copyOf(iterator.next().getStates());
101 }
102 return Set.of(0l);
103 }
104
105 @Override
106 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
107 Map<AnyDataRepresentation, DiffCursor<?, ?>> diffcursors = new HashMap<>();
108 for (var entry : stores.entrySet()) {
109 var representation = entry.getKey();
110 var diffCursor = entry.getValue().getDiffCursor(from, to);
111 diffcursors.put(representation, diffCursor);
112 }
113 return new ModelDiffCursor(diffcursors);
114 }
115}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java b/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java
deleted file mode 100644
index 6a5fdcd5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/RelationLike.java
+++ /dev/null
@@ -1,7 +0,0 @@
1package tools.refinery.store.model;
2
3public interface RelationLike {
4 String getName();
5
6 int getArity();
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
index 24ec3b59..4bcf9ff4 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
@@ -4,15 +4,6 @@ import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
5 5
6public class TupleHashProvider implements ContinousHashProvider<Tuple> { 6public class TupleHashProvider implements ContinousHashProvider<Tuple> {
7 protected static TupleHashProvider instance;
8
9 public static TupleHashProvider singleton() {
10 if (instance == null) {
11 instance = new TupleHashProvider();
12 }
13 return instance;
14 }
15
16 protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 7 protected static final int[] primes = new int[] { 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
17 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 8 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
18 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 9 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
@@ -45,6 +36,8 @@ public class TupleHashProvider implements ContinousHashProvider<Tuple> {
45 36
46 public static final int MAX_MODEL_SIZE = (int) LARGEST_PRIME_30_BITS; 37 public static final int MAX_MODEL_SIZE = (int) LARGEST_PRIME_30_BITS;
47 38
39 public static final TupleHashProvider INSTANCE = new TupleHashProvider();
40
48 public TupleHashProvider() { 41 public TupleHashProvider() {
49 if (primes.length < MAX_PRACTICAL_DEPTH) { 42 if (primes.length < MAX_PRACTICAL_DEPTH) {
50 throw new UnsupportedOperationException( 43 throw new UnsupportedOperationException(
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
new file mode 100644
index 00000000..f68859db
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.model.internal;
2
3public enum ModelAction {
4 NONE,
5 COMMIT,
6 RESTORE
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
index 795a891b..10331e28 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
@@ -1,131 +1,166 @@
1package tools.refinery.store.model.internal; 1package tools.refinery.store.model.internal;
2 2
3import tools.refinery.store.map.ContinousHashProvider; 3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.map.Cursor; 4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapter;
6import tools.refinery.store.adapter.ModelAdapterType;
5import tools.refinery.store.map.DiffCursor; 7import tools.refinery.store.map.DiffCursor;
6import tools.refinery.store.map.VersionedMap; 8import tools.refinery.store.model.*;
7import tools.refinery.store.map.internal.MapDiffCursor; 9import tools.refinery.store.representation.AnySymbol;
8import tools.refinery.store.model.Model; 10import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.model.ModelDiffCursor; 11import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.model.ModelStore; 12
11import tools.refinery.store.model.representation.AnyDataRepresentation; 13import java.util.*;
12import tools.refinery.store.model.representation.DataRepresentation;
13
14import java.util.HashMap;
15import java.util.Map;
16import java.util.Set;
17 14
18public class ModelImpl implements Model { 15public class ModelImpl implements Model {
19 private final ModelStore store; 16 private final ModelStore store;
20 17 private long state;
21 private final Map<AnyDataRepresentation, VersionedMap<?, ?>> maps; 18 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
22 19 private final AdapterList<ModelAdapter> adapters;
23 public ModelImpl(ModelStore store, Map<AnyDataRepresentation, VersionedMap<?, ?>> maps) { 20 private final List<ModelListener> listeners = new ArrayList<>();
21 private ModelAction pendingAction = ModelAction.NONE;
22 private long restoringToState = -1;
23
24 ModelImpl(ModelStore store, long state, int adapterCount) {
24 this.store = store; 25 this.store = store;
25 this.maps = maps; 26 this.state = state;
27 adapters = new AdapterList<>(adapterCount);
26 } 28 }
27 29
28 @Override 30 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
29 public Set<AnyDataRepresentation> getDataRepresentations() { 31 this.interpretations = interpretations;
30 return maps.keySet();
31 } 32 }
32 33
33 private VersionedMap<?, ?> getMap(AnyDataRepresentation representation) { 34 @Override
34 if (maps.containsKey(representation)) { 35 public ModelStore getStore() {
35 return maps.get(representation); 36 return store;
36 } else {
37 throw new IllegalArgumentException("Model does have representation " + representation);
38 }
39 } 37 }
40 38
41 @SuppressWarnings("unchecked") 39 @Override
42 private <K, V> VersionedMap<K, V> getMap(DataRepresentation<K, V> representation) { 40 public long getState() {
43 return (VersionedMap<K, V>) maps.get(representation); 41 return state;
44 } 42 }
45 43
46 private <K, V> VersionedMap<K, V> getMapValidateKey(DataRepresentation<K, V> representation, K key) { 44 @Override
47 if (representation.isValidKey(key)) { 45 public <T> Interpretation<T> getInterpretation(Symbol<T> symbol) {
48 return getMap(representation); 46 var interpretation = interpretations.get(symbol);
49 } else { 47 if (interpretation == null) {
50 throw new IllegalArgumentException( 48 throw new IllegalArgumentException("No interpretation for symbol %s in model".formatted(symbol));
51 "Key is not valid for representation! (representation=" + representation + ", key=" + key + ");");
52 } 49 }
50 @SuppressWarnings("unchecked")
51 var typedInterpretation = (Interpretation<T>) interpretation;
52 return typedInterpretation;
53 } 53 }
54 54
55 @Override 55 @Override
56 public <K, V> V get(DataRepresentation<K, V> representation, K key) { 56 public ModelDiffCursor getDiffCursor(long to) {
57 return getMapValidateKey(representation, key).get(key); 57 var diffCursors = new HashMap<AnySymbol, DiffCursor<Tuple, ?>>(interpretations.size());
58 for (var entry : interpretations.entrySet()) {
59 diffCursors.put(entry.getKey(), entry.getValue().getDiffCursor(to));
60 }
61 return new ModelDiffCursor(diffCursors);
58 } 62 }
59 63
60 @Override 64 @Override
61 public <K, V> Cursor<K, V> getAll(DataRepresentation<K, V> representation) { 65 public long commit() {
62 return getMap(representation).getAll(); 66 if (pendingAction != ModelAction.NONE) {
67 throw pendingActionError("commit");
68 }
69 pendingAction = ModelAction.COMMIT;
70 try {
71 int listenerCount = listeners.size();
72 int i = listenerCount;
73 long version = 0;
74 while (i > 0) {
75 i--;
76 listeners.get(i).beforeCommit();
77 }
78 boolean versionSet = false;
79 for (var interpretation : interpretations.values()) {
80 long newVersion = interpretation.commit();
81 if (versionSet) {
82 if (version != newVersion) {
83 throw new IllegalStateException("Interpretations in model have different versions (%d and %d)"
84 .formatted(version, newVersion));
85 }
86 } else {
87 version = newVersion;
88 versionSet = true;
89 }
90 }
91 state = version;
92 while (i < listenerCount) {
93 listeners.get(i).afterCommit();
94 i++;
95 }
96 return version;
97 } finally {
98 pendingAction = ModelAction.NONE;
99 }
63 } 100 }
64 101
65 @Override 102 @Override
66 public <K, V> V put(DataRepresentation<K, V> representation, K key, V value) { 103 public void restore(long version) {
67 return getMapValidateKey(representation, key).put(key, value); 104 if (pendingAction != ModelAction.NONE) {
105 throw pendingActionError("restore to %d".formatted(version));
106 }
107 if (!store.getStates().contains(version)) {
108 throw new IllegalArgumentException("Store does not contain state %d".formatted(version));
109 }
110 pendingAction = ModelAction.RESTORE;
111 restoringToState = version;
112 try {
113 int listenerCount = listeners.size();
114 int i = listenerCount;
115 while (i > 0) {
116 i--;
117 listeners.get(i).beforeRestore(version);
118 }
119 for (var interpretation : interpretations.values()) {
120 interpretation.restore(version);
121 }
122 state = version;
123 while (i < listenerCount) {
124 listeners.get(i).afterRestore();
125 i++;
126 }
127 } finally {
128 pendingAction = ModelAction.NONE;
129 restoringToState = -1;
130 }
68 } 131 }
69 132
70 @Override 133 public RuntimeException pendingActionError(String currentActionName) {
71 public <K, V> void putAll(DataRepresentation<K, V> representation, Cursor<K, V> cursor) { 134 var pendingActionName = switch (pendingAction) {
72 getMap(representation).putAll(cursor); 135 case NONE -> throw new IllegalArgumentException("Trying to throw pending action error when there is no " +
136 "pending action");
137 case COMMIT -> "commit";
138 case RESTORE -> "restore to %d".formatted(restoringToState);
139 };
140 return new IllegalStateException("Cannot %s due to pending %s".formatted(currentActionName, pendingActionName));
73 } 141 }
74 142
75 @Override 143 @Override
76 public long getSize(AnyDataRepresentation representation) { 144 public <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType) {
77 return getMap(representation).getSize(); 145 return adapters.tryGet(adapterType, adapterType.getModelAdapterClass());
78 } 146 }
79 147
80 @Override 148 @Override
81 public ModelDiffCursor getDiffCursor(long to) { 149 public <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType) {
82 Model toModel = store.createModel(to); 150 return adapters.get(adapterType, adapterType.getModelAdapterClass());
83 Map<AnyDataRepresentation, DiffCursor<?, ?>> diffCursors = new HashMap<>();
84 for (AnyDataRepresentation anyDataRepresentation : this.maps.keySet()) {
85 var dataRepresentation = (DataRepresentation<?, ?>) anyDataRepresentation;
86 MapDiffCursor<?, ?> diffCursor = constructDiffCursor(toModel, dataRepresentation);
87 diffCursors.put(dataRepresentation, diffCursor);
88 }
89 return new ModelDiffCursor(diffCursors);
90 } 151 }
91 152
92 private <K, V> MapDiffCursor<K, V> constructDiffCursor(Model toModel, DataRepresentation<K, V> representation) { 153 void addAdapter(AnyModelAdapterType adapterType, ModelAdapter adapter) {
93 @SuppressWarnings("unchecked") 154 adapters.add(adapterType, adapter);
94 Cursor<K, V> fromCursor = (Cursor<K, V>) this.maps.get(representation).getAll();
95 Cursor<K, V> toCursor = toModel.getAll(representation);
96
97 ContinousHashProvider<K> hashProvider = representation.getHashProvider();
98 V defaultValue = representation.getDefaultValue();
99 return new MapDiffCursor<>(hashProvider, defaultValue, fromCursor, toCursor);
100 } 155 }
101 156
102 @Override 157 @Override
103 public long commit() { 158 public void addListener(ModelListener listener) {
104 long version = 0; 159 listeners.add(listener);
105 boolean versionSet = false;
106 for (VersionedMap<?, ?> map : maps.values()) {
107 long newVersion = map.commit();
108 if (versionSet) {
109 if (version != newVersion) {
110 throw new IllegalStateException(
111 "Maps in model have different versions! (" + version + " and" + newVersion + ")");
112 }
113 } else {
114 version = newVersion;
115 versionSet = true;
116 }
117 }
118 return version;
119 } 160 }
120 161
121 @Override 162 @Override
122 public void restore(long state) { 163 public void removeListener(ModelListener listener) {
123 if (store.getStates().contains(state)) { 164 listeners.remove(listener);
124 for (VersionedMap<?, ?> map : maps.values()) {
125 map.restore(state);
126 }
127 } else {
128 throw new IllegalArgumentException("Map does not contain state " + state + "!");
129 }
130 } 165 }
131} 166}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
new file mode 100644
index 00000000..79f7195d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -0,0 +1,104 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.adapter.ModelAdapterBuilder;
5import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
6import tools.refinery.store.adapter.ModelAdapterType;
7import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.model.TupleHashProvider;
12import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.*;
17
18public class ModelStoreBuilderImpl implements ModelStoreBuilder {
19 private final Set<AnySymbol> allSymbols = new HashSet<>();
20 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>();
21 private final AdapterList<ModelAdapterBuilder> adapters = new AdapterList<>();
22
23 @Override
24 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) {
25 if (!allSymbols.add(symbol)) {
26 throw new IllegalArgumentException("Symbol %s already added".formatted(symbol));
27 }
28 var equivalenceClass = new SymbolEquivalenceClass<>(symbol);
29 var symbolsInEquivalenceClass = equivalenceClasses.computeIfAbsent(equivalenceClass,
30 ignored -> new ArrayList<>());
31 symbolsInEquivalenceClass.add(symbol);
32 return this;
33 }
34
35 @Override
36 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
37 return adapters.<T>tryGet(adapterBuilderFactory, adapterBuilderFactory.getModelAdapterBuilderClass())
38 .orElseGet(() -> addAdapter(adapterBuilderFactory));
39 }
40
41 private <T extends ModelAdapterBuilder> T addAdapter(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
42 for (var configuredAdapterType : adapters.getAdapterTypes()) {
43 var intersection = new HashSet<>(adapterBuilderFactory.getSupportedAdapterTypes());
44 intersection.retainAll(configuredAdapterType.getSupportedAdapterTypes());
45 if (!intersection.isEmpty()) {
46 if (configuredAdapterType.supports(adapterBuilderFactory)) {
47 // Impossible to end up here from <code>#with</code>, because we should have returned
48 // the existing adapter there instead of adding a new one.
49 throw new IllegalArgumentException(
50 "Cannot add %s, because it is already provided by configured adapter %s"
51 .formatted(adapterBuilderFactory, configuredAdapterType));
52 } else if (adapterBuilderFactory.supports(configuredAdapterType)) {
53 throw new IllegalArgumentException(
54 "Cannot add %s, because it provides already configured adapter %s"
55 .formatted(adapterBuilderFactory, configuredAdapterType));
56 } else {
57 throw new IllegalArgumentException(
58 "Cannot add %s, because configured adapter %s already provides %s"
59 .formatted(adapterBuilderFactory, configuredAdapterType, intersection));
60 }
61 }
62 }
63 var newAdapter = adapterBuilderFactory.createBuilder(this);
64 adapters.add(adapterBuilderFactory, newAdapter);
65 return newAdapter;
66 }
67
68 @Override
69 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType) {
70 return adapters.tryGet(adapterType, adapterType.getModelAdapterBuilderClass());
71 }
72
73 @Override
74 public <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType) {
75 return adapters.get(adapterType, adapterType.getModelAdapterBuilderClass());
76 }
77
78 @Override
79 public ModelStore build() {
80 var stores = new HashMap<AnySymbol, VersionedMapStore<Tuple, ?>>(allSymbols.size());
81 for (var entry : equivalenceClasses.entrySet()) {
82 createStores(stores, entry.getKey(), entry.getValue());
83 }
84 var modelStore = new ModelStoreImpl(stores, adapters.size());
85 for (int i = adapters.size() - 1; i >= 0; i--) {
86 adapters.get(i).configure();
87 }
88 for (var entry : adapters.withAdapterTypes()) {
89 var adapter = entry.adapter().createStoreAdapter(modelStore);
90 modelStore.addAdapter(entry.adapterType(), adapter);
91 }
92 return modelStore;
93 }
94
95 private <T> void createStores(Map<AnySymbol, VersionedMapStore<Tuple, ?>> stores,
96 SymbolEquivalenceClass<T> equivalenceClass, List<AnySymbol> symbols) {
97 int size = symbols.size();
98 var storeGroup = VersionedMapStoreImpl.createSharedVersionedMapStores(size, TupleHashProvider.INSTANCE,
99 equivalenceClass.defaultValue());
100 for (int i = 0; i < size; i++) {
101 stores.put(symbols.get(i), storeGroup.get(i));
102 }
103 }
104}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
new file mode 100644
index 00000000..8aab57af
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -0,0 +1,100 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.adapter.AdapterList;
4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.adapter.ModelStoreAdapter;
7import tools.refinery.store.map.DiffCursor;
8import tools.refinery.store.map.VersionedMapStore;
9import tools.refinery.store.model.ModelDiffCursor;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.AnySymbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.*;
15
16public class ModelStoreImpl implements ModelStore {
17 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
18 private final AdapterList<ModelStoreAdapter> adapters;
19
20 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) {
21 this.stores = stores;
22 adapters = new AdapterList<>(adapterCount);
23 }
24
25 @Override
26 public Collection<AnySymbol> getSymbols() {
27 return Collections.unmodifiableCollection(stores.keySet());
28 }
29
30 private ModelImpl createEmptyModel(long state) {
31 return new ModelImpl(this, state, adapters.size());
32 }
33
34 @Override
35 public ModelImpl createModel() {
36 var model = createEmptyModel(-1);
37 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
38 for (var entry : this.stores.entrySet()) {
39 var symbol = entry.getKey();
40 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue()));
41 }
42 model.setInterpretations(interpretations);
43 adaptModel(model);
44 return model;
45 }
46
47 @Override
48 public synchronized ModelImpl createModel(long state) {
49 var model = createEmptyModel(state);
50 var interpretations = new HashMap<AnySymbol, VersionedInterpretation<?>>(stores.size());
51 for (var entry : this.stores.entrySet()) {
52 var symbol = entry.getKey();
53 interpretations.put(symbol, VersionedInterpretation.of(model, symbol, entry.getValue(), state));
54 }
55 model.setInterpretations(interpretations);
56 adaptModel(model);
57 return model;
58 }
59
60 private void adaptModel(ModelImpl model) {
61 for (var entry : adapters.withAdapterTypes()) {
62 var adapter = entry.adapter().createModelAdapter(model);
63 model.addAdapter(entry.adapterType(), adapter);
64 }
65 }
66
67 @Override
68 public synchronized Set<Long> getStates() {
69 var iterator = stores.values().iterator();
70 if (iterator.hasNext()) {
71 return Set.copyOf(iterator.next().getStates());
72 }
73 return Set.of(0L);
74 }
75
76 @Override
77 public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
78 var diffCursors = new HashMap<AnySymbol, DiffCursor<?, ?>>();
79 for (var entry : stores.entrySet()) {
80 var representation = entry.getKey();
81 var diffCursor = entry.getValue().getDiffCursor(from, to);
82 diffCursors.put(representation, diffCursor);
83 }
84 return new ModelDiffCursor(diffCursors);
85 }
86
87 @Override
88 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType) {
89 return adapters.tryGet(adapterType, adapterType.getModelStoreAdapterClass());
90 }
91
92 @Override
93 public <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType) {
94 return adapters.get(adapterType, adapterType.getModelStoreAdapterClass());
95 }
96
97 void addAdapter(AnyModelAdapterType adapterType, ModelStoreAdapter adapter) {
98 adapters.add(adapterType, adapter);
99 }
100}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java
deleted file mode 100644
index 79e4c9f9..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SimilarRelationEquivalenceClass.java
+++ /dev/null
@@ -1,35 +0,0 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.model.representation.Relation;
5import tools.refinery.store.tuple.Tuple;
6
7import java.util.Objects;
8
9public class SimilarRelationEquivalenceClass {
10 final ContinousHashProvider<Tuple> hashProvider;
11 final Object defaultValue;
12 final int arity;
13
14 public SimilarRelationEquivalenceClass(Relation<?> representation) {
15 this.hashProvider = representation.getHashProvider();
16 this.defaultValue = representation.getDefaultValue();
17 this.arity = representation.getArity();
18 }
19
20 @Override
21 public int hashCode() {
22 return Objects.hash(arity, defaultValue, hashProvider);
23 }
24
25 @Override
26 public boolean equals(Object obj) {
27 if (this == obj)
28 return true;
29 if (!(obj instanceof SimilarRelationEquivalenceClass other))
30 return false;
31 return arity == other.arity && Objects.equals(defaultValue, other.defaultValue)
32 && Objects.equals(hashProvider, other.hashProvider);
33 }
34
35}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
new file mode 100644
index 00000000..5bf1b90d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
@@ -0,0 +1,9 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.representation.Symbol;
4
5public record SymbolEquivalenceClass<T>(int arity, Class<T> valueType, T defaultValue) {
6 public SymbolEquivalenceClass(Symbol<T> symbol) {
7 this(symbol.arity(), symbol.valueType(), symbol.defaultValue());
8 }
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
new file mode 100644
index 00000000..1bdb1cdf
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
@@ -0,0 +1,159 @@
1package tools.refinery.store.model.internal;
2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.DiffCursor;
5import tools.refinery.store.map.VersionedMap;
6import tools.refinery.store.map.VersionedMapStore;
7import tools.refinery.store.map.internal.MapDiffCursor;
8import tools.refinery.store.model.Interpretation;
9import tools.refinery.store.model.InterpretationListener;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.TupleHashProvider;
12import tools.refinery.store.representation.AnySymbol;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.ArrayList;
17import java.util.List;
18
19public class VersionedInterpretation<T> implements Interpretation<T> {
20 private final ModelImpl model;
21 private final Symbol<T> symbol;
22 private final VersionedMapStore<Tuple, T> store;
23 private final VersionedMap<Tuple, T> map;
24 private final List<InterpretationListener<T>> listeners = new ArrayList<>();
25 private final List<InterpretationListener<T>> restoreListeners = new ArrayList<>();
26
27 private VersionedInterpretation(ModelImpl model, Symbol<T> symbol, VersionedMapStore<Tuple, T> store,
28 VersionedMap<Tuple, T> map) {
29 this.model = model;
30 this.symbol = symbol;
31 this.store = store;
32 this.map = map;
33 }
34
35 @Override
36 public Model getModel() {
37 return model;
38 }
39
40 @Override
41 public Symbol<T> getSymbol() {
42 return symbol;
43 }
44
45 @Override
46 public long getSize() {
47 return map.getSize();
48 }
49
50 private void checkKey(Tuple key) {
51 if (key == null || key.getSize() != symbol.arity()) {
52 throw new IllegalArgumentException("Key for %s must be a tuple with arity %s"
53 .formatted(symbol, symbol.arity()));
54 }
55 }
56 @Override
57 public T get(Tuple key) {
58 checkKey(key);
59 return map.get(key);
60 }
61
62 @Override
63 public Cursor<Tuple, T> getAll() {
64 return map.getAll();
65 }
66
67 private void notifyListeners(Tuple key, T fromValue, T toValue, boolean restoring) {
68 var listenerList = restoring ? restoreListeners : listeners;
69 int listenerCount = listenerList.size();
70 // Use a for loop instead of a for-each loop to avoid <code>Iterator</code> allocation overhead.
71 //noinspection ForLoopReplaceableByForEach
72 for (int i = 0; i < listenerCount; i++) {
73 listenerList.get(i).put(key, fromValue, toValue, restoring);
74 }
75 }
76
77 @Override
78 public T put(Tuple key, T value) {
79 checkKey(key);
80 var oldValue = map.put(key, value);
81 notifyListeners(key, oldValue, value, false);
82 return oldValue;
83 }
84
85 @Override
86 public void putAll(Cursor<Tuple, T> cursor) {
87 if (listeners.isEmpty()) {
88 map.putAll(cursor);
89 return;
90 }
91 if (cursor.getDependingMaps().contains(map)) {
92 List<Tuple> keys = new ArrayList<>();
93 List<T> values = new ArrayList<>();
94 while (cursor.move()) {
95 keys.add(cursor.getKey());
96 values.add(cursor.getValue());
97 }
98 var keyIterator = keys.iterator();
99 var valueIterator = values.iterator();
100 while (keyIterator.hasNext()) {
101 put(keyIterator.next(), valueIterator.next());
102 }
103 } else {
104 while (cursor.move()) {
105 put(cursor.getKey(), cursor.getValue());
106 }
107 }
108 }
109
110 @Override
111 public DiffCursor<Tuple, T> getDiffCursor(long to) {
112 var fromCursor = getAll();
113 var toCursor = store.createMap(to).getAll();
114 return new MapDiffCursor<>(TupleHashProvider.INSTANCE, symbol.defaultValue(), fromCursor, toCursor);
115 }
116
117 public long commit() {
118 return map.commit();
119 }
120
121 public void restore(long state) {
122 if (!restoreListeners.isEmpty()) {
123 var diffCursor = getDiffCursor(state);
124 while (diffCursor.move()) {
125 notifyListeners(diffCursor.getKey(), diffCursor.getFromValue(), diffCursor.getToValue(), true);
126 }
127 }
128 map.restore(state);
129 }
130
131 @Override
132 public void addListener(InterpretationListener<T> listener, boolean alsoWhenRestoring) {
133 listeners.add(listener);
134 if (alsoWhenRestoring) {
135 restoreListeners.add(listener);
136 }
137 }
138
139 @Override
140 public void removeListener(InterpretationListener<T> listener) {
141 listeners.remove(listener);
142 restoreListeners.remove(listener);
143 }
144
145 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store) {
146 @SuppressWarnings("unchecked")
147 var typedSymbol = (Symbol<T>) symbol;
148 var map = store.createMap();
149 return new VersionedInterpretation<>(model, typedSymbol, store, map);
150 }
151
152 static <T> VersionedInterpretation<T> of(ModelImpl model, AnySymbol symbol, VersionedMapStore<Tuple, T> store,
153 long state) {
154 @SuppressWarnings("unchecked")
155 var typedSymbol = (Symbol<T>) symbol;
156 var map = store.createMap(state);
157 return new VersionedInterpretation<>(model, typedSymbol, store, map);
158 }
159}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java
deleted file mode 100644
index 951952e5..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyAuxiliaryData.java
+++ /dev/null
@@ -1,4 +0,0 @@
1package tools.refinery.store.model.representation;
2
3public sealed interface AnyAuxiliaryData extends AnyDataRepresentation permits AuxiliaryData {
4}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java
deleted file mode 100644
index ea74a625..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyDataRepresentation.java
+++ /dev/null
@@ -1,9 +0,0 @@
1package tools.refinery.store.model.representation;
2
3public sealed interface AnyDataRepresentation permits DataRepresentation, AnyRelation, AnyAuxiliaryData {
4 String getName();
5
6 Class<?> getKeyType();
7
8 Class<?> getValueType();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java
deleted file mode 100644
index 1d698c28..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AnyRelation.java
+++ /dev/null
@@ -1,9 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.model.RelationLike;
4import tools.refinery.store.tuple.Tuple;
5
6public sealed interface AnyRelation extends AnyDataRepresentation, RelationLike permits Relation {
7 @Override
8 Class<Tuple> getKeyType();
9}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java
deleted file mode 100644
index dad1ccf4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/AuxiliaryData.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4
5public final class AuxiliaryData<K, V> extends DataRepresentation<K, V> implements AnyAuxiliaryData {
6 private final ContinousHashProvider<K> hashProvider;
7
8 public AuxiliaryData(String name, Class<K> keyType, ContinousHashProvider<K> hashProvider, Class<V> valueType,
9 V defaultValue) {
10 super(name, keyType, valueType, defaultValue);
11 this.hashProvider = hashProvider;
12 }
13
14 @Override
15 public ContinousHashProvider<K> getHashProvider() {
16 return hashProvider;
17 }
18
19 @Override
20 public boolean isValidKey(K key) {
21 return true;
22 }
23}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java
deleted file mode 100644
index 2bf498b9..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/DataRepresentation.java
+++ /dev/null
@@ -1,43 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4
5public abstract sealed class DataRepresentation<K, V> implements AnyDataRepresentation permits Relation, AuxiliaryData {
6 private final String name;
7
8 private final V defaultValue;
9
10 private final Class<K> keyType;
11
12 private final Class<V> valueType;
13
14 protected DataRepresentation(String name, Class<K> keyType, Class<V> valueType, V defaultValue) {
15 this.name = name;
16 this.defaultValue = defaultValue;
17 this.keyType = keyType;
18 this.valueType = valueType;
19 }
20
21 @Override
22 public String getName() {
23 return name;
24 }
25
26 public abstract ContinousHashProvider<K> getHashProvider();
27
28 public abstract boolean isValidKey(K key);
29
30 public V getDefaultValue() {
31 return defaultValue;
32 }
33
34 @Override
35 public Class<K> getKeyType() {
36 return keyType;
37 }
38
39 @Override
40 public Class<V> getValueType() {
41 return valueType;
42 }
43}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java
deleted file mode 100644
index 47a07536..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/Relation.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.model.representation;
2
3import tools.refinery.store.map.ContinousHashProvider;
4import tools.refinery.store.model.TupleHashProvider;
5import tools.refinery.store.tuple.Tuple;
6
7public final class Relation<D> extends DataRepresentation<Tuple, D> implements AnyRelation {
8 private final int arity;
9
10 public Relation(String name, int arity, Class<D> valueType, D defaultValue) {
11 super(name, Tuple.class, valueType, defaultValue);
12 this.arity = arity;
13 }
14
15 @Override
16 public int getArity() {
17 return arity;
18 }
19
20 @Override
21 public ContinousHashProvider<Tuple> getHashProvider() {
22 return TupleHashProvider.singleton();
23 }
24
25 @Override
26 public boolean isValidKey(Tuple key) {
27 if (key == null) {
28 return false;
29 } else {
30 return key.getSize() == getArity();
31 }
32 }
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java b/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
index 7d4b3091..336c25a1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java
@@ -1,11 +1,11 @@
1package tools.refinery.store.query; 1package tools.refinery.store.query;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.atom.DNFAtom; 4import tools.refinery.store.query.atom.DNFAtom;
5 5
6import java.util.*; 6import java.util.*;
7 7
8public class DNF implements RelationLike { 8public class DNF implements SymbolLike {
9 private final String name; 9 private final String name;
10 10
11 private final String uniqueName; 11 private final String uniqueName;
@@ -22,7 +22,7 @@ public class DNF implements RelationLike {
22 } 22 }
23 23
24 @Override 24 @Override
25 public String getName() { 25 public String name() {
26 return name; 26 return name;
27 } 27 }
28 28
@@ -35,7 +35,7 @@ public class DNF implements RelationLike {
35 } 35 }
36 36
37 @Override 37 @Override
38 public int getArity() { 38 public int arity() {
39 return parameters.size(); 39 return parameters.size();
40 } 40 }
41 41
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java
new file mode 100644
index 00000000..6a1aeabb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQuery.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapterType;
4
5public final class ModelQuery extends ModelAdapterType<ModelQueryAdapter, ModelQueryStoreAdapter, ModelQueryBuilder> {
6 public static final ModelQuery ADAPTER = new ModelQuery();
7
8 private ModelQuery() {
9 super(ModelQueryAdapter.class, ModelQueryStoreAdapter.class, ModelQueryBuilder.class);
10 }
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
new file mode 100644
index 00000000..d0cdf02d
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
@@ -0,0 +1,11 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapter;
4
5public interface ModelQueryAdapter extends ModelAdapter {
6 ModelQueryStoreAdapter getStoreAdapter();
7
8 ResultSet getResultSet(DNF query);
9
10 void flushChanges();
11}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
new file mode 100644
index 00000000..853a1796
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
@@ -0,0 +1,23 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.model.ModelStore;
5
6import java.util.Collection;
7import java.util.List;
8
9public interface ModelQueryBuilder extends ModelAdapterBuilder {
10 default ModelQueryBuilder queries(DNF... queries) {
11 return queries(List.of(queries));
12 }
13
14 default ModelQueryBuilder queries(Collection<? extends DNF> queries) {
15 queries.forEach(this::query);
16 return this;
17 }
18
19 ModelQueryBuilder query(DNF query);
20
21 @Override
22 ModelQueryStoreAdapter createStoreAdapter(ModelStore store);
23}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
new file mode 100644
index 00000000..ef5a4587
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
@@ -0,0 +1,16 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelStoreAdapter;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.query.view.AnyRelationView;
6
7import java.util.Collection;
8
9public interface ModelQueryStoreAdapter extends ModelStoreAdapter {
10 Collection<AnyRelationView> getRelationViews();
11
12 Collection<DNF> getQueries();
13
14 @Override
15 ModelQueryAdapter createModelAdapter(Model model);
16}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
deleted file mode 100644
index 9655d1a1..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModel.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.TupleLike;
6
7import java.util.Optional;
8import java.util.Set;
9import java.util.stream.Stream;
10
11public interface QueryableModel extends Model {
12 Set<DNF> getPredicates();
13
14 boolean hasChanges();
15
16 void flushChanges();
17
18 boolean hasResult(DNF predicate);
19
20 boolean hasResult(DNF predicate, Tuple parameters);
21
22 Optional<TupleLike> oneResult(DNF predicate);
23
24 Optional<TupleLike> oneResult(DNF predicate, Tuple parameters);
25
26 Stream<TupleLike> allResults(DNF predicate);
27
28 Stream<TupleLike> allResults(DNF predicate, Tuple parameters);
29
30 int countResults(DNF predicate);
31
32 int countResults(DNF predicate, Tuple parameters);
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
deleted file mode 100644
index 3a69f3a4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/QueryableModelStore.java
+++ /dev/null
@@ -1,19 +0,0 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.representation.AnyDataRepresentation;
5import tools.refinery.store.query.view.AnyRelationView;
6
7import java.util.Set;
8
9public interface QueryableModelStore extends ModelStore {
10 Set<AnyDataRepresentation> getDataRepresentations();
11
12 Set<AnyRelationView> getViews();
13
14 Set<DNF> getPredicates();
15
16 QueryableModel createModel();
17
18 QueryableModel createModel(long state);
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java
new file mode 100644
index 00000000..3542e252
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/ResultSet.java
@@ -0,0 +1,25 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.tuple.TupleLike;
5
6import java.util.Optional;
7import java.util.stream.Stream;
8
9public interface ResultSet {
10 boolean hasResult();
11
12 boolean hasResult(Tuple parameters);
13
14 Optional<TupleLike> oneResult();
15
16 Optional<TupleLike> oneResult(Tuple parameters);
17
18 Stream<TupleLike> allResults();
19
20 Stream<TupleLike> allResults(Tuple parameters);
21
22 int countResults();
23
24 int countResults(Tuple parameters);
25}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
index e8a8b5e1..af6a8f5a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/AbstractSubstitutionAtom.java
@@ -1,20 +1,20 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.Variable; 4import tools.refinery.store.query.Variable;
5 5
6import java.util.List; 6import java.util.List;
7import java.util.Set; 7import java.util.Set;
8 8
9public abstract class AbstractSubstitutionAtom<T extends RelationLike> implements DNFAtom { 9public abstract class AbstractSubstitutionAtom<T extends SymbolLike> implements DNFAtom {
10 private final T target; 10 private final T target;
11 11
12 private final List<Variable> substitution; 12 private final List<Variable> substitution;
13 13
14 protected AbstractSubstitutionAtom(T target, List<Variable> substitution) { 14 protected AbstractSubstitutionAtom(T target, List<Variable> substitution) {
15 if (substitution.size() != target.getArity()) { 15 if (substitution.size() != target.arity()) {
16 throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.getName(), 16 throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(),
17 target.getArity(), substitution.size())); 17 target.arity(), substitution.size()));
18 } 18 }
19 this.target = target; 19 this.target = target;
20 this.substitution = substitution; 20 this.substitution = substitution;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
index 9e289a8a..2e855246 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java
@@ -1,40 +1,40 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.query.Variable; 4import tools.refinery.store.query.Variable;
5 5
6import java.util.List; 6import java.util.List;
7import java.util.Objects; 7import java.util.Objects;
8import java.util.Set; 8import java.util.Set;
9 9
10public final class CallAtom<T extends RelationLike> extends AbstractSubstitutionAtom<T> { 10public abstract class CallAtom<T extends SymbolLike> extends AbstractSubstitutionAtom<T> {
11 private final CallPolarity polarity; 11 private final CallPolarity polarity;
12 12
13 public CallAtom(CallPolarity polarity, T target, List<Variable> substitution) { 13 protected CallAtom(CallPolarity polarity, T target, List<Variable> substitution) {
14 super(target, substitution); 14 super(target, substitution);
15 if (polarity.isTransitive() && target.getArity() != 2) { 15 if (polarity.isTransitive() && target.arity() != 2) {
16 throw new IllegalArgumentException("Transitive closures can only take binary relations"); 16 throw new IllegalArgumentException("Transitive closures can only take binary relations");
17 } 17 }
18 this.polarity = polarity; 18 this.polarity = polarity;
19 } 19 }
20 20
21 public CallAtom(CallPolarity polarity, T target, Variable... substitution) { 21 protected CallAtom(CallPolarity polarity, T target, Variable... substitution) {
22 this(polarity, target, List.of(substitution)); 22 this(polarity, target, List.of(substitution));
23 } 23 }
24 24
25 public CallAtom(boolean positive, T target, List<Variable> substitution) { 25 protected CallAtom(boolean positive, T target, List<Variable> substitution) {
26 this(CallPolarity.fromBoolean(positive), target, substitution); 26 this(CallPolarity.fromBoolean(positive), target, substitution);
27 } 27 }
28 28
29 public CallAtom(boolean positive, T target, Variable... substitution) { 29 protected CallAtom(boolean positive, T target, Variable... substitution) {
30 this(positive, target, List.of(substitution)); 30 this(positive, target, List.of(substitution));
31 } 31 }
32 32
33 public CallAtom(T target, List<Variable> substitution) { 33 protected CallAtom(T target, List<Variable> substitution) {
34 this(true, target, substitution); 34 this(true, target, substitution);
35 } 35 }
36 36
37 public CallAtom(T target, Variable... substitution) { 37 protected CallAtom(T target, Variable... substitution) {
38 this(target, List.of(substitution)); 38 this(target, List.of(substitution));
39 } 39 }
40 40
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java
new file mode 100644
index 00000000..3b4f5cd1
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java
@@ -0,0 +1,32 @@
1package tools.refinery.store.query.atom;
2
3import tools.refinery.store.query.DNF;
4import tools.refinery.store.query.Variable;
5
6import java.util.List;
7
8public class DNFCallAtom extends CallAtom<DNF> {
9 public DNFCallAtom(CallPolarity polarity, DNF target, List<Variable> substitution) {
10 super(polarity, target, substitution);
11 }
12
13 public DNFCallAtom(CallPolarity polarity, DNF target, Variable... substitution) {
14 super(polarity, target, substitution);
15 }
16
17 public DNFCallAtom(boolean positive, DNF target, List<Variable> substitution) {
18 super(positive, target, substitution);
19 }
20
21 public DNFCallAtom(boolean positive, DNF target, Variable... substitution) {
22 super(positive, target, substitution);
23 }
24
25 public DNFCallAtom(DNF target, List<Variable> substitution) {
26 super(target, substitution);
27 }
28
29 public DNFCallAtom(DNF target, Variable... substitution) {
30 super(target, substitution);
31 }
32}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
index 1e4f8f55..c2ca1fdb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/atom/ModalRelation.java
@@ -1,17 +1,17 @@
1package tools.refinery.store.query.atom; 1package tools.refinery.store.query.atom;
2 2
3import tools.refinery.store.model.RelationLike; 3import tools.refinery.store.representation.SymbolLike;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.representation.Symbol;
5import tools.refinery.store.model.representation.TruthValue; 5import tools.refinery.store.representation.TruthValue;
6 6
7public record ModalRelation(Modality modality, Relation<TruthValue> relation) implements RelationLike { 7public record ModalRelation(Modality modality, Symbol<TruthValue> relation) implements SymbolLike {
8 @Override 8 @Override
9 public String getName() { 9 public String name() {
10 return "%s %s".formatted(modality, relation); 10 return "%s %s".formatted(modality, relation);
11 } 11 }
12 12
13 @Override 13 @Override
14 public int getArity() { 14 public int arity() {
15 return relation.getArity(); 15 return relation.arity();
16 } 16 }
17} 17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java
deleted file mode 100644
index 79de1c4d..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/AbstractFilteredRelationView.java
+++ /dev/null
@@ -1,44 +0,0 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.model.representation.Relation;
7
8public abstract class AbstractFilteredRelationView<D> extends RelationView<D> {
9 protected AbstractFilteredRelationView(Relation<D> representation, String name) {
10 super(representation, name);
11 }
12
13 protected AbstractFilteredRelationView(Relation<D> representation) {
14 super(representation);
15 }
16
17 @Override
18 public Object[] forwardMap(Tuple key, D value) {
19 return toTuple1Array(key);
20 }
21
22 @Override
23 public boolean get(Model model, Object[] tuple) {
24 int[] content = new int[tuple.length];
25 for (int i = 0; i < tuple.length; i++) {
26 content[i] = ((Tuple1) tuple[i]).value0();
27 }
28 Tuple key = Tuple.of(content);
29 D value = model.get(getRepresentation(), key);
30 return filter(key, value);
31 }
32
33 public int getArity() {
34 return this.getRepresentation().getArity();
35 }
36
37 private static Object[] toTuple1Array(Tuple t) {
38 Object[] result = new Object[t.getSize()];
39 for (int i = 0; i < t.getSize(); i++) {
40 result[i] = Tuple.of(t.get(i));
41 }
42 return result;
43 }
44}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
index df5e0d72..9df1038b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
@@ -1,11 +1,11 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.model.Model; 3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.RelationLike; 4import tools.refinery.store.representation.SymbolLike;
5import tools.refinery.store.model.representation.AnyRelation; 5import tools.refinery.store.representation.AnySymbol;
6 6
7public sealed interface AnyRelationView extends RelationLike permits RelationView { 7public sealed interface AnyRelationView extends SymbolLike permits RelationView {
8 AnyRelation getRepresentation(); 8 AnySymbol getSymbol();
9 9
10 boolean get(Model model, Object[] tuple); 10 boolean get(Model model, Object[] tuple);
11 11
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
index 5b892cc6..64c601bb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
@@ -1,35 +1,35 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.tuple.Tuple; 3import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.model.representation.Relation; 4import tools.refinery.store.representation.Symbol;
5 5
6import java.util.Objects; 6import java.util.Objects;
7import java.util.function.BiPredicate; 7import java.util.function.BiPredicate;
8import java.util.function.Predicate; 8import java.util.function.Predicate;
9 9
10public class FilteredRelationView<D> extends AbstractFilteredRelationView<D> { 10public class FilteredRelationView<T> extends TuplePreservingRelationView<T> {
11 private final BiPredicate<Tuple, D> predicate; 11 private final BiPredicate<Tuple, T> predicate;
12 12
13 public FilteredRelationView(Relation<D> representation, String name, BiPredicate<Tuple, D> predicate) { 13 public FilteredRelationView(Symbol<T> symbol, String name, BiPredicate<Tuple, T> predicate) {
14 super(representation, name); 14 super(symbol, name);
15 this.predicate = predicate; 15 this.predicate = predicate;
16 } 16 }
17 17
18 public FilteredRelationView(Relation<D> representation, BiPredicate<Tuple, D> predicate) { 18 public FilteredRelationView(Symbol<T> symbol, BiPredicate<Tuple, T> predicate) {
19 super(representation); 19 super(symbol);
20 this.predicate = predicate; 20 this.predicate = predicate;
21 } 21 }
22 22
23 public FilteredRelationView(Relation<D> representation, String name, Predicate<D> predicate) { 23 public FilteredRelationView(Symbol<T> symbol, String name, Predicate<T> predicate) {
24 this(representation, name, (k, v) -> predicate.test(v)); 24 this(symbol, name, (k, v) -> predicate.test(v));
25 } 25 }
26 26
27 public FilteredRelationView(Relation<D> representation, Predicate<D> predicate) { 27 public FilteredRelationView(Symbol<T> symbol, Predicate<T> predicate) {
28 this(representation, (k, v) -> predicate.test(v)); 28 this(symbol, (k, v) -> predicate.test(v));
29 } 29 }
30 30
31 @Override 31 @Override
32 public boolean filter(Tuple key, D value) { 32 public boolean filter(Tuple key, T value) {
33 return this.predicate.test(key, value); 33 return this.predicate.test(key, value);
34 } 34 }
35 35
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
index ef3954a4..d263679a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
@@ -3,24 +3,24 @@ package tools.refinery.store.query.view;
3import tools.refinery.store.model.Model; 3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1; 5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.model.representation.Relation; 6import tools.refinery.store.representation.Symbol;
7 7
8public class FunctionalRelationView<D> extends RelationView<D> { 8public class FunctionalRelationView<T> extends RelationView<T> {
9 public FunctionalRelationView(Relation<D> representation, String name) { 9 public FunctionalRelationView(Symbol<T> symbol, String name) {
10 super(representation, name); 10 super(symbol, name);
11 } 11 }
12 12
13 public FunctionalRelationView(Relation<D> representation) { 13 public FunctionalRelationView(Symbol<T> symbol) {
14 super(representation); 14 super(symbol);
15 } 15 }
16 16
17 @Override 17 @Override
18 public boolean filter(Tuple key, D value) { 18 public boolean filter(Tuple key, T value) {
19 return true; 19 return true;
20 } 20 }
21 21
22 @Override 22 @Override
23 public Object[] forwardMap(Tuple key, D value) { 23 public Object[] forwardMap(Tuple key, T value) {
24 return toTuple1ArrayPlusValue(key, value); 24 return toTuple1ArrayPlusValue(key, value);
25 } 25 }
26 26
@@ -32,14 +32,14 @@ public class FunctionalRelationView<D> extends RelationView<D> {
32 } 32 }
33 Tuple key = Tuple.of(content); 33 Tuple key = Tuple.of(content);
34 @SuppressWarnings("unchecked") 34 @SuppressWarnings("unchecked")
35 D valueInTuple = (D) tuple[tuple.length - 1]; 35 T valueInTuple = (T) tuple[tuple.length - 1];
36 D valueInMap = model.get(getRepresentation(), key); 36 T valueInMap = model.getInterpretation(getSymbol()).get(key);
37 return valueInTuple.equals(valueInMap); 37 return valueInTuple.equals(valueInMap);
38 } 38 }
39 39
40 @Override 40 @Override
41 public int getArity() { 41 public int arity() {
42 return getRepresentation().getArity() + 1; 42 return getSymbol().arity() + 1;
43 } 43 }
44 44
45 private static <D> Object[] toTuple1ArrayPlusValue(Tuple t, D value) { 45 private static <D> Object[] toTuple1ArrayPlusValue(Tuple t, D value) {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
index f7e7d28a..fdfcdf28 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
@@ -1,23 +1,23 @@
1package tools.refinery.store.query.view; 1package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.representation.Symbol;
3import tools.refinery.store.tuple.Tuple; 4import tools.refinery.store.tuple.Tuple;
4import tools.refinery.store.model.representation.Relation;
5 5
6import java.util.Objects; 6import java.util.Objects;
7 7
8public class KeyOnlyRelationView extends AbstractFilteredRelationView<Boolean> { 8public class KeyOnlyRelationView<T> extends TuplePreservingRelationView<T> {
9 public static final String VIEW_NAME = "key"; 9 public static final String VIEW_NAME = "key";
10 10
11 private final Boolean defaultValue; 11 private final T defaultValue;
12 12
13 public KeyOnlyRelationView(Relation<Boolean> representation) { 13 public KeyOnlyRelationView(Symbol<T> symbol) {
14 super(representation, VIEW_NAME); 14 super(symbol, VIEW_NAME);
15 defaultValue = representation.getDefaultValue(); 15 defaultValue = symbol.defaultValue();
16 } 16 }
17 17
18 @Override 18 @Override
19 public boolean filter(Tuple key, Boolean value) { 19 public boolean filter(Tuple key, T value) {
20 return !value.equals(defaultValue); 20 return !Objects.equals(value, defaultValue);
21 } 21 }
22 22
23 @Override 23 @Override
@@ -25,7 +25,7 @@ public class KeyOnlyRelationView extends AbstractFilteredRelationView<Boolean> {
25 if (this == o) return true; 25 if (this == o) return true;
26 if (o == null || getClass() != o.getClass()) return false; 26 if (o == null || getClass() != o.getClass()) return false;
27 if (!super.equals(o)) return false; 27 if (!super.equals(o)) return false;
28 KeyOnlyRelationView that = (KeyOnlyRelationView) o; 28 KeyOnlyRelationView<?> that = (KeyOnlyRelationView<?>) o;
29 return Objects.equals(defaultValue, that.defaultValue); 29 return Objects.equals(defaultValue, that.defaultValue);
30 } 30 }
31 31
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
index 1224076c..bbec1e73 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java
@@ -2,49 +2,49 @@ package tools.refinery.store.query.view;
2 2
3import tools.refinery.store.map.CursorAsIterator; 3import tools.refinery.store.map.CursorAsIterator;
4import tools.refinery.store.model.Model; 4import tools.refinery.store.model.Model;
5import tools.refinery.store.model.representation.Relation; 5import tools.refinery.store.representation.Symbol;
6import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.Tuple;
7 7
8import java.util.Objects; 8import java.util.Objects;
9import java.util.UUID; 9import java.util.UUID;
10 10
11/** 11/**
12 * Represents a view of a {@link Relation} that can be queried. 12 * Represents a view of a {@link Symbol} that can be queried.
13 * 13 *
14 * @param <D> 14 * @param <T>
15 * @author Oszkar Semerath 15 * @author Oszkar Semerath
16 */ 16 */
17public abstract non-sealed class RelationView<D> implements AnyRelationView { 17public abstract non-sealed class RelationView<T> implements AnyRelationView {
18 private final Relation<D> representation; 18 private final Symbol<T> symbol;
19 19
20 private final String name; 20 private final String name;
21 21
22 protected RelationView(Relation<D> representation, String name) { 22 protected RelationView(Symbol<T> symbol, String name) {
23 this.representation = representation; 23 this.symbol = symbol;
24 this.name = name; 24 this.name = name;
25 } 25 }
26 26
27 protected RelationView(Relation<D> representation) { 27 protected RelationView(Symbol<T> representation) {
28 this(representation, UUID.randomUUID().toString()); 28 this(representation, UUID.randomUUID().toString());
29 } 29 }
30 30
31 @Override 31 @Override
32 public Relation<D> getRepresentation() { 32 public Symbol<T> getSymbol() {
33 return representation; 33 return symbol;
34 } 34 }
35 35
36 @Override 36 @Override
37 public String getName() { 37 public String name() {
38 return representation.getName() + "#" + name; 38 return symbol.name() + "#" + name;
39 } 39 }
40 40
41 public abstract boolean filter(Tuple key, D value); 41 public abstract boolean filter(Tuple key, T value);
42 42
43 public abstract Object[] forwardMap(Tuple key, D value); 43 public abstract Object[] forwardMap(Tuple key, T value);
44 44
45 @Override 45 @Override
46 public Iterable<Object[]> getAll(Model model) { 46 public Iterable<Object[]> getAll(Model model) {
47 return (() -> new CursorAsIterator<>(model.getAll(representation), this::forwardMap, this::filter)); 47 return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter));
48 } 48 }
49 49
50 @Override 50 @Override
@@ -52,11 +52,11 @@ public abstract non-sealed class RelationView<D> implements AnyRelationView {
52 if (this == o) return true; 52 if (this == o) return true;
53 if (o == null || getClass() != o.getClass()) return false; 53 if (o == null || getClass() != o.getClass()) return false;
54 RelationView<?> that = (RelationView<?>) o; 54 RelationView<?> that = (RelationView<?>) o;
55 return Objects.equals(representation, that.representation) && Objects.equals(name, that.name); 55 return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name);
56 } 56 }
57 57
58 @Override 58 @Override
59 public int hashCode() { 59 public int hashCode() {
60 return Objects.hash(representation, name); 60 return Objects.hash(symbol, name);
61 } 61 }
62} 62}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
new file mode 100644
index 00000000..8cc4986e
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
@@ -0,0 +1,44 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.tuple.Tuple;
5import tools.refinery.store.tuple.Tuple1;
6import tools.refinery.store.representation.Symbol;
7
8public abstract class TuplePreservingRelationView<T> extends RelationView<T> {
9 protected TuplePreservingRelationView(Symbol<T> symbol, String name) {
10 super(symbol, name);
11 }
12
13 protected TuplePreservingRelationView(Symbol<T> symbol) {
14 super(symbol);
15 }
16
17 public Object[] forwardMap(Tuple key) {
18 Object[] result = new Object[key.getSize()];
19 for (int i = 0; i < key.getSize(); i++) {
20 result[i] = Tuple.of(key.get(i));
21 }
22 return result;
23 }
24
25 @Override
26 public Object[] forwardMap(Tuple key, T value) {
27 return forwardMap(key);
28 }
29
30 @Override
31 public boolean get(Model model, Object[] tuple) {
32 int[] content = new int[tuple.length];
33 for (int i = 0; i < tuple.length; i++) {
34 content[i] = ((Tuple1) tuple[i]).value0();
35 }
36 Tuple key = Tuple.of(content);
37 T value = model.getInterpretation(getSymbol()).get(key);
38 return filter(key, value);
39 }
40
41 public int arity() {
42 return this.getSymbol().arity();
43 }
44}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
new file mode 100644
index 00000000..12a45bed
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
@@ -0,0 +1,5 @@
1package tools.refinery.store.representation;
2
3public sealed interface AnySymbol extends SymbolLike permits Symbol {
4 Class<?> valueType();
5}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
new file mode 100644
index 00000000..404b5ddb
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
@@ -0,0 +1,47 @@
1package tools.refinery.store.representation;
2
3import java.util.Objects;
4
5// Deliberately not a record, because we want equality by reference.
6@SuppressWarnings({"squid:S6206", "ClassCanBeRecord"})
7public final class Symbol<T> implements AnySymbol {
8 private final String name;
9 private final int arity;
10 private final Class<T> valueType;
11 private final T defaultValue;
12
13 public Symbol(String name, int arity, Class<T> valueType, T defaultValue) {
14 this.name = name;
15 this.arity = arity;
16 this.valueType = valueType;
17 this.defaultValue = defaultValue;
18 }
19
20 @Override
21 public String name() {
22 return name;
23 }
24
25 @Override
26 public int arity() {
27 return arity;
28 }
29
30 @Override
31 public Class<T> valueType() {
32 return valueType;
33 }
34
35 public T defaultValue() {
36 return defaultValue;
37 }
38
39 public boolean isDefaultValue(T value) {
40 return Objects.equals(defaultValue, value);
41 }
42
43 @Override
44 public String toString() {
45 return "%s/%d".formatted(name, arity);
46 }
47}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java b/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java
new file mode 100644
index 00000000..8c84500c
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/SymbolLike.java
@@ -0,0 +1,7 @@
1package tools.refinery.store.representation;
2
3public interface SymbolLike {
4 String name();
5
6 int arity();
7}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
index a5ba825b..b7893fd3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation; 1package tools.refinery.store.representation;
2 2
3public enum TruthValue { 3public enum TruthValue {
4 TRUE("true"), 4 TRUE("true"),
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
index 1f252b4c..273d0de7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval { 3public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval {
4 int lowerBound(); 4 int lowerBound();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
index b7c52bd1..e1a08bf9 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervals.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class CardinalityIntervals { 3public final class CardinalityIntervals {
4 public static final CardinalityInterval NONE = exactly(0); 4 public static final CardinalityInterval NONE = exactly(0);
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
index 127651df..ab3ad9d1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class EmptyCardinalityInterval implements CardinalityInterval { 3public final class EmptyCardinalityInterval implements CardinalityInterval {
4 static final EmptyCardinalityInterval INSTANCE = new EmptyCardinalityInterval(); 4 static final EmptyCardinalityInterval INSTANCE = new EmptyCardinalityInterval();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
index ec643a97..381c8a57 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.jetbrains.annotations.NotNull; 3import org.jetbrains.annotations.NotNull;
4 4
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
index b534f2e3..32b3786f 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/NonEmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import java.util.function.BinaryOperator; 3import java.util.function.BinaryOperator;
4import java.util.function.IntBinaryOperator; 4import java.util.function.IntBinaryOperator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
index 4199d44f..593bc322 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UnboundedUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.jetbrains.annotations.NotNull; 3import org.jetbrains.annotations.NotNull;
4 4
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
index b433cda2..d850fdc9 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinalities.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public final class UpperCardinalities { 3public final class UpperCardinalities {
4 public static final UpperCardinality UNBOUNDED = UnboundedUpperCardinality.INSTANCE; 4 public static final UpperCardinality UNBOUNDED = UnboundedUpperCardinality.INSTANCE;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
index 91dd40b0..c6e31cb7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/cardinality/UpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality, 3public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality,
4 UnboundedUpperCardinality { 4 UnboundedUpperCardinality {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
index 081112cc..77c62305 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
@@ -1,18 +1,17 @@
1package tools.refinery.store.map.tests; 1package tools.refinery.store.map.tests;
2 2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
6
7import tools.refinery.store.map.VersionedMapStore; 4import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl; 5import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.model.TupleHashProvider; 6import tools.refinery.store.model.TupleHashProvider;
7import tools.refinery.store.tuple.Tuple;
8
9import static org.junit.jupiter.api.Assertions.assertEquals;
11 10
12class MapUnitTests { 11class MapUnitTests {
13 @Test 12 @Test
14 void defaultTest() { 13 void defaultTest() {
15 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<Tuple, Boolean>(TupleHashProvider.singleton(), false); 14 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<>(TupleHashProvider.INSTANCE, false);
16 var map = store.createMap(); 15 var map = store.createMap();
17 var out1 = map.put(Tuple.of(0), true); 16 var out1 = map.put(Tuple.of(0), true);
18 assertEquals(false, out1); 17 assertEquals(false, out1);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
index ceec40f5..bb083805 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
@@ -1,4 +1,4 @@
1package tools.refinery.store.model.hashTests; 1package tools.refinery.store.model.hashtests;
2 2
3import static org.junit.jupiter.api.Assertions.assertEquals; 3import static org.junit.jupiter.api.Assertions.assertEquals;
4 4
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
index 7a89daeb..e7bff1f9 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -1,145 +1,149 @@
1package tools.refinery.store.model.tests; 1package tools.refinery.store.model.tests;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.model.Model;
5import tools.refinery.store.model.ModelStore; 4import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.model.ModelStoreImpl; 5import tools.refinery.store.representation.Symbol;
7import tools.refinery.store.model.representation.Relation;
8import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.Tuple;
9 7
10import java.util.Set;
11
12import static org.junit.jupiter.api.Assertions.*; 8import static org.junit.jupiter.api.Assertions.*;
13 9
14class ModelTest { 10class ModelTest {
15
16 @Test 11 @Test
17 void modelConstructionTest() { 12 void modelConstructionTest() {
18 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 13 var person = new Symbol<>("Person", 1, Boolean.class, false);
19 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 14 var friend = new Symbol<>("friend", 2, Boolean.class, false);
20 15
21 ModelStore store = new ModelStoreImpl(Set.of(person, friend)); 16 var store = ModelStore.builder().symbols(person, friend).build();
22 Model model = store.createModel(); 17 var symbols = store.getSymbols();
23 18
24 assertTrue(store.getDataRepresentations().contains(person)); 19 assertTrue(symbols.contains(person));
25 assertTrue(store.getDataRepresentations().contains(friend)); 20 assertTrue(symbols.contains(friend));
26 assertTrue(model.getDataRepresentations().contains(person));
27 assertTrue(model.getDataRepresentations().contains(friend));
28 21
29 Relation<Integer> other = new Relation<Integer>("other", 2, Integer.class, null); 22 var other = new Symbol<>("other", 2, Integer.class, null);
30 assertFalse(model.getDataRepresentations().contains(other)); 23 assertFalse(symbols.contains(other));
31 } 24 }
32 25
33 @Test 26 @Test
34 void modelBuildingTest() { 27 void modelBuildingTest() {
35 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 28 var person = new Symbol<>("Person", 1, Boolean.class, false);
36 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 29 var age = new Symbol<>("age", 1, Integer.class, null);
37 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 30 var friend = new Symbol<>("friend", 2, Boolean.class, false);
38 31
39 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); 32 var store = ModelStore.builder().symbols(person, age, friend).build();
40 Model model = store.createModel(); 33 var model = store.createModel();
41 34 var personInterpretation = model.getInterpretation(person);
42 model.put(person, Tuple.of(0), true); 35 var ageInterpretation = model.getInterpretation(age);
43 model.put(person, Tuple.of(1), true); 36 var friendInterpretation = model.getInterpretation(friend);
44 model.put(age, Tuple.of(0), 3); 37
45 model.put(age, Tuple.of(1), 1); 38 personInterpretation.put(Tuple.of(0), true);
46 model.put(friend, Tuple.of(0, 1), true); 39 personInterpretation.put(Tuple.of(1), true);
47 model.put(friend, Tuple.of(1, 0), true); 40 ageInterpretation.put(Tuple.of(0), 3);
48 41 ageInterpretation.put(Tuple.of(1), 1);
49 assertTrue(model.get(person, Tuple.of(0))); 42 friendInterpretation.put(Tuple.of(0, 1), true);
50 assertTrue(model.get(person, Tuple.of(1))); 43 friendInterpretation.put(Tuple.of(1, 0), true);
51 assertFalse(model.get(person, Tuple.of(2))); 44
52 45 assertTrue(personInterpretation.get(Tuple.of(0)));
53 assertEquals(3, model.get(age, Tuple.of(0))); 46 assertTrue(personInterpretation.get(Tuple.of(1)));
54 assertEquals(1, model.get(age, Tuple.of(1))); 47 assertFalse(personInterpretation.get(Tuple.of(2)));
55 assertNull(model.get(age, Tuple.of(2))); 48
56 49 assertEquals(3, ageInterpretation.get(Tuple.of(0)));
57 assertTrue(model.get(friend, Tuple.of(0, 1))); 50 assertEquals(1, ageInterpretation.get(Tuple.of(1)));
58 assertFalse(model.get(friend, Tuple.of(0, 5))); 51 assertNull(ageInterpretation.get( Tuple.of(2)));
52
53 assertTrue(friendInterpretation.get(Tuple.of(0, 1)));
54 assertFalse(friendInterpretation.get(Tuple.of(0, 5)));
59 } 55 }
60 56
61 @Test 57 @Test
62 void modelBuildingArityFailTest() { 58 void modelBuildingArityFailTest() {
63 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 59 var person = new Symbol<>("Person", 1, Boolean.class, false);
64 60
65 ModelStore store = new ModelStoreImpl(Set.of(person)); 61 var store = ModelStore.builder().symbols(person).build();
66 Model model = store.createModel(); 62 var model = store.createModel();
63 var personInterpretation = model.getInterpretation(person);
67 64
68 final Tuple tuple3 = Tuple.of(1, 1, 1); 65 final Tuple tuple3 = Tuple.of(1, 1, 1);
69 assertThrows(IllegalArgumentException.class, () -> model.put(person, tuple3, true)); 66 assertThrows(IllegalArgumentException.class, () -> personInterpretation.put(tuple3, true));
70 assertThrows(IllegalArgumentException.class, () -> model.get(person, tuple3)); 67 assertThrows(IllegalArgumentException.class, () -> personInterpretation.get(tuple3));
71 } 68 }
72 69
73 @Test 70 @Test
74 void modelBuildingNullFailTest() { 71 void modelBuildingNullFailTest() {
75 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 72 var age = new Symbol<>("age", 1, Integer.class, null);
76 ModelStore store = new ModelStoreImpl(Set.of(age)); 73
77 Model model = store.createModel(); 74 var store = ModelStore.builder().symbols(age).build();
75 var model = store.createModel();
76 var ageInterpretation = model.getInterpretation(age);
78 77
79 model.put(age, Tuple.of(1), null); // valid 78 ageInterpretation.put(Tuple.of(1), null); // valid
80 assertThrows(IllegalArgumentException.class, () -> model.put(age, null, 1)); 79 assertThrows(IllegalArgumentException.class, () -> ageInterpretation.put(null, 1));
81 assertThrows(IllegalArgumentException.class, () -> model.get(age, null)); 80 assertThrows(IllegalArgumentException.class, () -> ageInterpretation.get(null));
82 81
83 } 82 }
84 83
85 @Test 84 @Test
86 void modelUpdateTest() { 85 void modelUpdateTest() {
87 Relation<Boolean> person = new Relation<>("Person", 1, Boolean.class, false); 86 var person = new Symbol<>("Person", 1, Boolean.class, false);
88 Relation<Integer> age = new Relation<Integer>("age", 1, Integer.class, null); 87 var age = new Symbol<>("age", 1, Integer.class, null);
89 Relation<Boolean> friend = new Relation<>("friend", 2, Boolean.class, false); 88 var friend = new Symbol<>("friend", 2, Boolean.class, false);
90 89
91 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend)); 90 var store = ModelStore.builder().symbols(person, age, friend).build();
92 Model model = store.createModel(); 91 var model = store.createModel();
93 92 var personInterpretation = model.getInterpretation(person);
94 model.put(person, Tuple.of(0), true); 93 var ageInterpretation = model.getInterpretation(age);
95 model.put(person, Tuple.of(1), true); 94 var friendInterpretation = model.getInterpretation(friend);
96 model.put(age, Tuple.of(0), 3); 95
97 model.put(age, Tuple.of(1), 1); 96 personInterpretation.put(Tuple.of(0), true);
98 model.put(friend, Tuple.of(0, 1), true); 97 personInterpretation.put(Tuple.of(1), true);
99 model.put(friend, Tuple.of(1, 0), true); 98 ageInterpretation.put(Tuple.of(0), 3);
100 99 ageInterpretation.put(Tuple.of(1), 1);
101 assertEquals(3, model.get(age, Tuple.of(0))); 100 friendInterpretation.put(Tuple.of(0, 1), true);
102 assertTrue(model.get(friend, Tuple.of(0, 1))); 101 friendInterpretation.put(Tuple.of(1, 0), true);
103 102
104 model.put(age, Tuple.of(0), 4); 103 assertEquals(3, ageInterpretation.get(Tuple.of(0)));
105 model.put(friend, Tuple.of(0, 1), false); 104 assertTrue(friendInterpretation.get(Tuple.of(0, 1)));
106 105
107 assertEquals(4, model.get(age, Tuple.of(0))); 106 ageInterpretation.put(Tuple.of(0), 4);
108 assertFalse(model.get(friend, Tuple.of(0, 1))); 107 friendInterpretation.put(Tuple.of(0, 1), false);
108
109 assertEquals(4, ageInterpretation.get(Tuple.of(0)));
110 assertFalse(friendInterpretation.get(Tuple.of(0, 1)));
109 } 111 }
110 112
111 @Test 113 @Test
112 void restoreTest() { 114 void restoreTest() {
113 Relation<Boolean> person = new Relation<Boolean>("Person", 1, Boolean.class, false); 115 var person = new Symbol<>("Person", 1, Boolean.class, false);
114 Relation<Boolean> friend = new Relation<Boolean>("friend", 2, Boolean.class, false); 116 var friend = new Symbol<>("friend", 2, Boolean.class, false);
115 117
116 ModelStore store = new ModelStoreImpl(Set.of(person, friend)); 118 var store = ModelStore.builder().symbols(person, friend).build();
117 Model model = store.createModel(); 119 var model = store.createModel();
118 120 var personInterpretation = model.getInterpretation(person);
119 model.put(person, Tuple.of(0), true); 121 var friendInterpretation = model.getInterpretation(friend);
120 model.put(person, Tuple.of(1), true); 122
121 model.put(friend, Tuple.of(0, 1), true); 123 personInterpretation.put(Tuple.of(0), true);
122 model.put(friend, Tuple.of(1, 0), true); 124 personInterpretation.put(Tuple.of(1), true);
125 friendInterpretation.put(Tuple.of(0, 1), true);
126 friendInterpretation.put(Tuple.of(1, 0), true);
123 long state1 = model.commit(); 127 long state1 = model.commit();
124 128
125 assertFalse(model.get(person, Tuple.of(2))); 129 assertFalse(personInterpretation.get(Tuple.of(2)));
126 assertFalse(model.get(friend, Tuple.of(0, 2))); 130 assertFalse(friendInterpretation.get(Tuple.of(0, 2)));
127 131
128 model.put(person, Tuple.of(2), true); 132 personInterpretation.put(Tuple.of(2), true);
129 model.put(friend, Tuple.of(0, 2), true); 133 friendInterpretation.put(Tuple.of(0, 2), true);
130 long state2 = model.commit(); 134 long state2 = model.commit();
131 135
132 assertTrue(model.get(person, Tuple.of(2))); 136 assertTrue(personInterpretation.get(Tuple.of(2)));
133 assertTrue(model.get(friend, Tuple.of(0, 2))); 137 assertTrue(friendInterpretation.get(Tuple.of(0, 2)));
134 138
135 model.restore(state1); 139 model.restore(state1);
136 140
137 assertFalse(model.get(person, Tuple.of(2))); 141 assertFalse(personInterpretation.get(Tuple.of(2)));
138 assertFalse(model.get(friend, Tuple.of(0, 2))); 142 assertFalse(friendInterpretation.get(Tuple.of(0, 2)));
139 143
140 model.restore(state2); 144 model.restore(state2);
141 145
142 assertTrue(model.get(person, Tuple.of(2))); 146 assertTrue(personInterpretation.get(Tuple.of(2)));
143 assertTrue(model.get(friend, Tuple.of(0, 2))); 147 assertTrue(friendInterpretation.get(Tuple.of(0, 2)));
144 } 148 }
145} 149}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
index 8a39b9b5..96fdc49e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
@@ -1,14 +1,15 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.representation.cardinality.CardinalityInterval;
6 7
7import java.util.stream.Stream; 8import java.util.stream.Stream;
8 9
9import static org.hamcrest.MatcherAssert.assertThat; 10import static org.hamcrest.MatcherAssert.assertThat;
10import static org.hamcrest.Matchers.equalTo; 11import static org.hamcrest.Matchers.equalTo;
11import static tools.refinery.store.model.representation.cardinality.CardinalityIntervals.*; 12import static tools.refinery.store.representation.cardinality.CardinalityIntervals.*;
12 13
13class CardinalityIntervalTest { 14class CardinalityIntervalTest {
14 @ParameterizedTest(name = "min({0}, {1}) == {2}") 15 @ParameterizedTest(name = "min({0}, {1}) == {2}")
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
index ef68a607..4a9ef8da 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/CardinalityIntervalsTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
@@ -1,6 +1,8 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.CardinalityIntervals;
5import tools.refinery.store.representation.cardinality.UpperCardinalities;
4 6
5import static org.hamcrest.MatcherAssert.assertThat; 7import static org.hamcrest.MatcherAssert.assertThat;
6import static org.hamcrest.Matchers.*; 8import static org.hamcrest.Matchers.*;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
index 41c884ec..e8b77b9f 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/EmptyCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
@@ -1,6 +1,7 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.CardinalityIntervals;
4 5
5import static org.hamcrest.MatcherAssert.assertThat; 6import static org.hamcrest.MatcherAssert.assertThat;
6import static org.hamcrest.Matchers.lessThan; 7import static org.hamcrest.Matchers.lessThan;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
index dfb37786..9a190818 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
@@ -1,6 +1,9 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.NonEmptyCardinalityInterval;
5import tools.refinery.store.representation.cardinality.UpperCardinalities;
6import tools.refinery.store.representation.cardinality.UpperCardinality;
4 7
5import static org.junit.jupiter.api.Assertions.assertThrows; 8import static org.junit.jupiter.api.Assertions.assertThrows;
6 9
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
index 3f0f7a4a..90c21759 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/FiniteUpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
@@ -1,6 +1,7 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
4 5
5import static org.junit.jupiter.api.Assertions.assertThrows; 6import static org.junit.jupiter.api.Assertions.assertThrows;
6 7
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
index 13171ae5..3c7c0320 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalitiesTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
@@ -1,8 +1,11 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.api.Test; 3import org.junit.jupiter.api.Test;
4import org.junit.jupiter.params.ParameterizedTest; 4import org.junit.jupiter.params.ParameterizedTest;
5import org.junit.jupiter.params.provider.ValueSource; 5import org.junit.jupiter.params.provider.ValueSource;
6import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
7import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
8import tools.refinery.store.representation.cardinality.UpperCardinalities;
6 9
7import static org.hamcrest.MatcherAssert.assertThat; 10import static org.hamcrest.MatcherAssert.assertThat;
8import static org.hamcrest.Matchers.equalTo; 11import static org.hamcrest.Matchers.equalTo;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
index f5763c2d..e87ce29b 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/representation/cardinality/UpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
@@ -1,8 +1,10 @@
1package tools.refinery.store.model.representation.cardinality; 1package tools.refinery.store.representation.cardinality;
2 2
3import org.junit.jupiter.params.ParameterizedTest; 3import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 4import org.junit.jupiter.params.provider.Arguments;
5import org.junit.jupiter.params.provider.MethodSource; 5import org.junit.jupiter.params.provider.MethodSource;
6import tools.refinery.store.representation.cardinality.UpperCardinalities;
7import tools.refinery.store.representation.cardinality.UpperCardinality;
6 8
7import java.util.stream.Stream; 9import java.util.stream.Stream;
8 10