aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gradle/libs.versions.toml3
-rw-r--r--settings.gradle2
-rw-r--r--subprojects/language-semantics/build.gradle (renamed from subprojects/language-to-store/build.gradle)3
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java9
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java41
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java94
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java84
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java41
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java130
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java129
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java187
-rw-r--r--subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapper.java239
-rw-r--r--subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapperDTO.java54
-rw-r--r--subprojects/language-to-store/src/test/java/tools/refinery/language/mapping/tests/PartialModelMapperTest.xtend438
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java23
15 files changed, 736 insertions, 741 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 9d569197..80327821 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,4 +1,5 @@
1[versions] 1[versions]
2eclipseCollections = "11.1.0"
2jetty = "11.0.12" 3jetty = "11.0.12"
3jmh = "1.35" 4jmh = "1.35"
4junit = "5.9.1" 5junit = "5.9.1"
@@ -8,6 +9,8 @@ slf4j = "2.0.3"
8xtext = "2.29.0.M1" 9xtext = "2.29.0.M1"
9 10
10[libraries] 11[libraries]
12eclipseCollections = { group = "org.eclipse.collections", name = "eclipse-collections", version.ref = "eclipseCollections" }
13eclipseCollections-api = { group = "org.eclipse.collections", name = "eclipse-collections-api", version.ref = "eclipseCollections" }
11ecore = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore", version = "2.28.0" } 14ecore = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore", version = "2.28.0" }
12ecore-xmi = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore.xmi", version = "2.17.0" } 15ecore-xmi = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore.xmi", version = "2.17.0" }
13ecore-codegen = { group = "org.eclipse.emf", name = "org.eclipse.emf.codegen.ecore", version = "2.31.0" } 16ecore-codegen = { group = "org.eclipse.emf", name = "org.eclipse.emf.codegen.ecore", version = "2.31.0" }
diff --git a/settings.gradle b/settings.gradle
index cf8c6e2b..36721f4b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,7 +4,7 @@ include 'frontend'
4include 'language' 4include 'language'
5include 'language-ide' 5include 'language-ide'
6include 'language-model' 6include 'language-model'
7include 'language-to-store' 7include 'language-semantics'
8include 'language-web' 8include 'language-web'
9include 'store' 9include 'store'
10 10
diff --git a/subprojects/language-to-store/build.gradle b/subprojects/language-semantics/build.gradle
index edaeb48e..4f43ad24 100644
--- a/subprojects/language-to-store/build.gradle
+++ b/subprojects/language-semantics/build.gradle
@@ -1,9 +1,10 @@
1plugins { 1plugins {
2 id 'refinery-java-library' 2 id 'refinery-java-library'
3 id 'refinery-xtext-conventions'
4} 3}
5 4
6dependencies { 5dependencies {
6 implementation libs.eclipseCollections
7 implementation libs.eclipseCollections.api
7 api project(':refinery-language') 8 api project(':refinery-language')
8 api project(':refinery-store') 9 api project(':refinery-store')
9 testImplementation testFixtures(project(':refinery-language')) 10 testImplementation testFixtures(project(':refinery-language'))
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
new file mode 100644
index 00000000..830d4a2c
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
@@ -0,0 +1,9 @@
1package tools.refinery.language.semantics.model;
2
3import tools.refinery.language.utils.CollectedSymbols;
4
5public class ModelInitializer {
6 public void createModel(CollectedSymbols symbols) {
7
8 }
9}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
new file mode 100644
index 00000000..8c185509
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
@@ -0,0 +1,41 @@
1package tools.refinery.language.semantics.model.internal;
2
3import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.model.Tuple;
6import tools.refinery.store.model.representation.TruthValue;
7
8public class DecisionTree {
9 private final int levels;
10
11 private final DecisionTreeNode root;
12
13 public DecisionTree(int levels, TruthValue initialValue) {
14 this.levels = levels;
15 DecisionTreeNode node = new TerminalNode(IntObjectMaps.mutable.empty(),
16 DecisionTreeValue.fromTruthValue(initialValue));
17 for (int level = 1; level < levels; level++) {
18 node = new IntermediateNode(IntObjectMaps.mutable.empty(), node);
19 }
20 root = node;
21 }
22
23 public TruthValue get(Tuple tuple) {
24 return root.getValue(levels - 1, tuple).getTruthValue();
25 }
26
27 public void mergeValue(Tuple tuple, TruthValue truthValue) {
28 if (truthValue == null) {
29 return;
30 }
31 root.mergeValue(levels - 1, tuple, truthValue);
32 }
33
34 public void overwriteValues(DecisionTree values) {
35 root.overwriteValues(values.root);
36 }
37
38 public Cursor<Tuple, TruthValue> getCursor(TruthValue defaultValue, int nodeCount) {
39 return new DecisionTreeCursor(levels, defaultValue, nodeCount, root);
40 }
41}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
new file mode 100644
index 00000000..8b02ba39
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
@@ -0,0 +1,94 @@
1package tools.refinery.language.semantics.model.internal;
2
3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.VersionedMap;
5import tools.refinery.store.model.Tuple;
6import tools.refinery.store.model.representation.TruthValue;
7
8import java.util.ArrayDeque;
9import java.util.Deque;
10import java.util.List;
11
12class DecisionTreeCursor implements Cursor<Tuple, TruthValue> {
13 static final int STATE_FINISH = Integer.MAX_VALUE;
14
15 private final int levels;
16
17 final DecisionTreeValue defaultValue;
18
19 final int nodeCount;
20
21 private final DecisionTreeNode root;
22
23 final int[][] sortedChildren;
24
25 final int[] iterationState;
26
27 final int[] rawTuple;
28
29 final Deque<DecisionTreeNode> path = new ArrayDeque<>();
30
31 private Tuple key;
32
33 DecisionTreeValue value = DecisionTreeValue.UNSET;
34
35 private boolean terminated;
36
37 public DecisionTreeCursor(int levels, TruthValue defaultValue, int nodeCount, DecisionTreeNode root) {
38 this.levels = levels;
39 this.defaultValue = DecisionTreeValue.fromTruthValue(defaultValue);
40 this.nodeCount = nodeCount;
41 this.root = root;
42 sortedChildren = new int[levels][];
43 iterationState = new int[levels];
44 for (int i = 0; i < levels; i++) {
45 iterationState[i] = STATE_FINISH;
46 }
47 rawTuple = new int[levels];
48 }
49
50 @Override
51 public Tuple getKey() {
52 return key;
53 }
54
55 @Override
56 public TruthValue getValue() {
57 return value.getTruthValue();
58 }
59
60 @Override
61 public boolean isTerminated() {
62 return terminated;
63 }
64
65 @Override
66 public boolean move() {
67 boolean found = false;
68 if (path.isEmpty() && !terminated) {
69 found = root.moveNext(levels - 1, this);
70 }
71 while (!found && !path.isEmpty()) {
72 int level = levels - path.size();
73 found = path.peek().moveNext(level, this);
74 }
75 if (!found) {
76 key = null;
77 value = DecisionTreeValue.UNSET;
78 terminated = true;
79 return false;
80 }
81 key = Tuple.of(rawTuple);
82 return true;
83 }
84
85 @Override
86 public boolean isDirty() {
87 return false;
88 }
89
90 @Override
91 public List<VersionedMap<?, ?>> getDependingMaps() {
92 return List.of();
93 }
94}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
new file mode 100644
index 00000000..53954d62
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
@@ -0,0 +1,84 @@
1package tools.refinery.language.semantics.model.internal;
2
3import org.eclipse.collections.api.LazyIntIterable;
4import tools.refinery.store.model.Tuple;
5import tools.refinery.store.model.representation.TruthValue;
6
7abstract class DecisionTreeNode {
8 public DecisionTreeValue getReducedValue() {
9 return getChildKeys().isEmpty() ? getOtherwiseReducedValue() : null;
10 }
11
12 public abstract DecisionTreeValue getValue(int level, Tuple tuple);
13
14 public abstract DecisionTreeNode deepCopy();
15
16 public void mergeValue(int level, Tuple tuple, TruthValue value) {
17 int nextLevel = level - 1;
18 var key = tuple.get(level);
19 if (key < 0) {
20 mergeAllValues(nextLevel, tuple, value);
21 } else {
22 mergeSingleValue(key, nextLevel, tuple, value);
23 }
24 }
25
26 protected abstract void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value);
27
28 protected abstract void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value);
29
30 public DecisionTreeNode withMergedValue(int level, Tuple tuple, TruthValue value) {
31 var copy = deepCopy();
32 copy.mergeValue(level, tuple, value);
33 return copy;
34 }
35
36 public abstract void overwriteValues(DecisionTreeNode values);
37
38 public DecisionTreeNode withOverwrittenValues(DecisionTreeNode values) {
39 var copy = deepCopy();
40 copy.overwriteValues(values);
41 return copy;
42 }
43
44 public boolean moveNext(int level, DecisionTreeCursor cursor) {
45 var currentState = cursor.iterationState[level];
46 boolean found;
47 if (currentState == DecisionTreeCursor.STATE_FINISH) {
48 // Entering this node for the first time.
49 cursor.path.push(this);
50 if (cursor.defaultValue == getOtherwiseReducedValue()) {
51 var sortedChildren = getChildKeys().toSortedArray();
52 cursor.sortedChildren[level] = sortedChildren;
53 found = moveNextSparse(level, cursor, 0, sortedChildren);
54 } else {
55 found = moveNextDense(level, cursor, 0);
56 }
57 } else {
58 var sortedChildren = cursor.sortedChildren[level];
59 if (sortedChildren == null) {
60 found = moveNextDense(level, cursor, currentState + 1);
61 } else {
62 found = moveNextSparse(level, cursor, currentState + 1, sortedChildren);
63 }
64 }
65 if (!found) {
66 cursor.sortedChildren[level] = null;
67 cursor.iterationState[level] = DecisionTreeCursor.STATE_FINISH;
68 var popped = cursor.path.pop();
69 if (popped != this) {
70 throw new IllegalStateException("Invalid decision diagram cursor");
71 }
72 }
73 return found;
74 }
75
76 protected abstract DecisionTreeValue getOtherwiseReducedValue();
77
78 protected abstract LazyIntIterable getChildKeys();
79
80 protected abstract boolean moveNextSparse(int level, DecisionTreeCursor cursor, int startIndex,
81 int[] sortedChildren);
82
83 protected abstract boolean moveNextDense(int level, DecisionTreeCursor cursor, int startIndex);
84}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
new file mode 100644
index 00000000..1bf3c8b8
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
@@ -0,0 +1,41 @@
1package tools.refinery.language.semantics.model.internal;
2
3import tools.refinery.store.model.representation.TruthValue;
4
5public enum DecisionTreeValue {
6 UNSET(null),
7 TRUE(TruthValue.TRUE),
8 FALSE(TruthValue.FALSE),
9 UNKNOWN(TruthValue.UNKNOWN),
10 ERROR(TruthValue.ERROR);
11
12 final TruthValue truthValue;
13
14 DecisionTreeValue(TruthValue truthValue) {
15 this.truthValue = truthValue;
16 }
17
18 public TruthValue getTruthValue() {
19 return truthValue;
20 }
21
22 public DecisionTreeValue merge(TruthValue other) {
23 return truthValue == null ? fromTruthValue(other) : fromTruthValue(truthValue.merge(other));
24 }
25
26 public DecisionTreeValue overwrite(DecisionTreeValue other) {
27 return other == UNSET ? this : other;
28 }
29
30 public static DecisionTreeValue fromTruthValue(TruthValue truthValue) {
31 if (truthValue == null) {
32 return DecisionTreeValue.UNSET;
33 }
34 return switch (truthValue) {
35 case TRUE -> TRUE;
36 case FALSE -> FALSE;
37 case UNKNOWN -> UNKNOWN;
38 case ERROR -> ERROR;
39 };
40 }
41}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
new file mode 100644
index 00000000..acc53e73
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
@@ -0,0 +1,130 @@
1package tools.refinery.language.semantics.model.internal;
2
3import org.eclipse.collections.api.LazyIntIterable;
4import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
6import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
7import tools.refinery.store.model.Tuple;
8import tools.refinery.store.model.representation.TruthValue;
9
10final class IntermediateNode extends DecisionTreeNode {
11 private final MutableIntObjectMap<DecisionTreeNode> children;
12
13 private final DecisionTreeNode otherwise;
14
15 IntermediateNode(MutableIntObjectMap<DecisionTreeNode> children, DecisionTreeNode otherwise) {
16 this.children = children;
17 this.otherwise = otherwise;
18 }
19
20 private DecisionTreeNode getChild(int index) {
21 var child = children.get(index);
22 return child == null ? otherwise : child;
23 }
24
25 @Override
26 public DecisionTreeValue getValue(int level, Tuple tuple) {
27 return getChild(tuple.get(level)).getValue(level - 1, tuple);
28 }
29
30 @Override
31 public DecisionTreeNode deepCopy() {
32 var newChildren = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne,
33 pair -> pair.getTwo().deepCopy());
34 var newOtherwise = otherwise.deepCopy();
35 return new IntermediateNode(newChildren, newOtherwise);
36 }
37
38 @Override
39 protected void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value) {
40 otherwise.mergeValue(nextLevel, tuple, value);
41 for (var child : children) {
42 child.mergeValue(nextLevel, tuple, value);
43 }
44 reduceChildren();
45 }
46
47 @Override
48 protected void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value) {
49 var otherwiseReduced = getOtherwiseReducedValue();
50 var child = children.get(key);
51 if (child == null) {
52 var newChild = otherwise.withMergedValue(nextLevel, tuple, value);
53 if (otherwiseReduced == null || newChild.getReducedValue() != otherwiseReduced) {
54 children.put(key, newChild);
55 }
56 return;
57 }
58 child.mergeValue(nextLevel, tuple, value);
59 if (otherwiseReduced != null && child.getReducedValue() == otherwiseReduced) {
60 children.remove(key);
61 }
62 }
63
64 @Override
65 public void overwriteValues(DecisionTreeNode values) {
66 if (values instanceof IntermediateNode intermediateValues) {
67 otherwise.overwriteValues(intermediateValues.otherwise);
68 for (var pair : children.keyValuesView()) {
69 pair.getTwo().overwriteValues(intermediateValues.getChild(pair.getOne()));
70 }
71 for (var pair : intermediateValues.children.keyValuesView()) {
72 children.getIfAbsentPut(pair.getOne(), () -> otherwise.withOverwrittenValues(pair.getTwo()));
73 }
74 reduceChildren();
75 } else {
76 throw new IllegalArgumentException("Level mismatch");
77 }
78 }
79
80 private void reduceChildren() {
81 var otherwiseReduced = getOtherwiseReducedValue();
82 if (otherwiseReduced == null) {
83 return;
84 }
85 var iterator = children.iterator();
86 while (iterator.hasNext()) {
87 var child = iterator.next();
88 if (child.getReducedValue() == otherwiseReduced) {
89 iterator.remove();
90 }
91 }
92 }
93
94 @Override
95 protected DecisionTreeValue getOtherwiseReducedValue() {
96 return otherwise.getReducedValue();
97 }
98
99 @Override
100 protected LazyIntIterable getChildKeys() {
101 return children.keysView();
102 }
103
104 protected boolean moveNextSparse(int level, DecisionTreeCursor cursor, int startIndex, int[] sortedChildren) {
105 for (int i = startIndex; i < sortedChildren.length; i++) {
106 var key = sortedChildren[i];
107 var child = getChild(key);
108 var found = child.moveNext(level - 1, cursor);
109 if (found) {
110 cursor.iterationState[level] = i;
111 cursor.rawTuple[level] = key;
112 return true;
113 }
114 }
115 return false;
116 }
117
118 protected boolean moveNextDense(int level, DecisionTreeCursor cursor, int startIndex) {
119 for (int i = startIndex; i < cursor.nodeCount; i++) {
120 var child = getChild(i);
121 var found = child.moveNext(level - 1, cursor);
122 if (found) {
123 cursor.iterationState[level] = i;
124 cursor.rawTuple[level] = i;
125 return true;
126 }
127 }
128 return false;
129 }
130}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
new file mode 100644
index 00000000..20dd6b20
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
@@ -0,0 +1,129 @@
1package tools.refinery.language.semantics.model.internal;
2
3import org.eclipse.collections.api.LazyIntIterable;
4import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
5import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
6import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
7import tools.refinery.store.model.Tuple;
8import tools.refinery.store.model.representation.TruthValue;
9
10class TerminalNode extends DecisionTreeNode {
11 private MutableIntObjectMap<DecisionTreeValue> children;
12
13 private DecisionTreeValue otherwise;
14
15 TerminalNode(MutableIntObjectMap<DecisionTreeValue> children, DecisionTreeValue otherwise) {
16 this.children = children;
17 this.otherwise = otherwise;
18 }
19
20 private DecisionTreeValue getChild(int index) {
21 var child = children.get(index);
22 return child == null ? otherwise : child;
23 }
24
25 @Override
26 public DecisionTreeValue getValue(int level, Tuple tuple) {
27 assertLevel(level);
28 return getChild(tuple.get(level));
29 }
30
31 @Override
32 public DecisionTreeNode deepCopy() {
33 return new TerminalNode(IntObjectMaps.mutable.ofAll(children), otherwise);
34 }
35
36 @Override
37 public void mergeValue(int level, Tuple tuple, TruthValue value) {
38 assertLevel(level);
39 super.mergeValue(level, tuple, value);
40 }
41
42 @Override
43 protected void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value) {
44 otherwise = otherwise.merge(value);
45 children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne,
46 pair -> pair.getTwo().merge(value));
47 reduceChildren();
48 }
49
50 @Override
51 protected void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value) {
52 var newChild = getChild(key).merge(value);
53 if (newChild == otherwise) {
54 children.remove(key);
55 } else {
56 children.put(key, newChild);
57 }
58 }
59
60 @Override
61 public void overwriteValues(DecisionTreeNode values) {
62 if (values instanceof TerminalNode terminalValues) {
63 otherwise = otherwise.overwrite(terminalValues.otherwise);
64 children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne,
65 pair -> pair.getTwo().overwrite(terminalValues.getChild(pair.getOne())));
66 for (var pair : terminalValues.children.keyValuesView()) {
67 children.getIfAbsentPut(pair.getOne(), otherwise.overwrite(pair.getTwo()));
68 }
69 reduceChildren();
70 } else {
71 throw new IllegalArgumentException("Level mismatch");
72 }
73 }
74
75 private void reduceChildren() {
76 var iterator = children.iterator();
77 while (iterator.hasNext()) {
78 var child = iterator.next();
79 if (child == otherwise) {
80 iterator.remove();
81 }
82 }
83 }
84
85 @Override
86 public boolean moveNext(int level, DecisionTreeCursor cursor) {
87 assertLevel(level);
88 return super.moveNext(level, cursor);
89 }
90
91 @Override
92 protected DecisionTreeValue getOtherwiseReducedValue() {
93 return otherwise;
94 }
95
96 @Override
97 protected LazyIntIterable getChildKeys() {
98 return children.keysView();
99 }
100
101 @Override
102 protected boolean moveNextSparse(int level, DecisionTreeCursor cursor, int startIndex, int[] sortedChildren) {
103 if (startIndex >= sortedChildren.length) {
104 return false;
105 }
106 var key = sortedChildren[startIndex];
107 cursor.iterationState[level] = startIndex;
108 cursor.rawTuple[level] = key;
109 cursor.value = getChild(key);
110 return true;
111 }
112
113 @Override
114 protected boolean moveNextDense(int level, DecisionTreeCursor cursor, int startIndex) {
115 if (startIndex >= cursor.nodeCount) {
116 return false;
117 }
118 cursor.iterationState[level] = startIndex;
119 cursor.rawTuple[level] = startIndex;
120 cursor.value = getChild(startIndex);
121 return true;
122 }
123
124 private static void assertLevel(int level) {
125 if (level != 0) {
126 throw new IllegalArgumentException("Invalid decision tree level: " + level);
127 }
128 }
129}
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
new file mode 100644
index 00000000..8fe866af
--- /dev/null
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
@@ -0,0 +1,187 @@
1package tools.refinery.language.semantics.model.tests;
2
3import org.junit.jupiter.api.Test;
4import tools.refinery.language.semantics.model.internal.DecisionTree;
5import tools.refinery.store.model.Tuple;
6import tools.refinery.store.model.representation.TruthValue;
7
8import java.util.LinkedHashMap;
9import java.util.Map;
10
11import static org.hamcrest.MatcherAssert.assertThat;
12import static org.hamcrest.Matchers.*;
13
14class DecisionTreeTests {
15 @Test
16 void initialValueTest() {
17 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
18 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.UNKNOWN));
19 }
20
21 @Test
22 void mergeValueTest() {
23 var sut = new DecisionTree(3, TruthValue.FALSE);
24 sut.mergeValue(Tuple.of(3, 4, 5), TruthValue.TRUE);
25 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.ERROR));
26 assertThat(sut.get(Tuple.of(3, 4, 6)), is(TruthValue.FALSE));
27 }
28
29 @Test
30 void mergeUnknownValueTest() {
31 var sut = new DecisionTree(3, TruthValue.FALSE);
32 sut.mergeValue(Tuple.of(3, 4, 5), TruthValue.UNKNOWN);
33 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.FALSE));
34 }
35
36 @Test
37 void mergeWildcardTest() {
38 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
39 sut.mergeValue(Tuple.of(3, -1, 5), TruthValue.TRUE);
40 sut.mergeValue(Tuple.of(-1, 4, 5), TruthValue.FALSE);
41 assertThat(sut.get(Tuple.of(2, 4, 5)), is(TruthValue.FALSE));
42 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.ERROR));
43 assertThat(sut.get(Tuple.of(3, 6, 5)), is(TruthValue.TRUE));
44 assertThat(sut.get(Tuple.of(3, 4, 6)), is(TruthValue.UNKNOWN));
45 }
46
47 @Test
48 void mergeWildcardTest2() {
49 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
50 sut.mergeValue(Tuple.of(-1, 4, -1), TruthValue.FALSE);
51 sut.mergeValue(Tuple.of(3, -1, 5), TruthValue.TRUE);
52 assertThat(sut.get(Tuple.of(2, 4, 5)), is(TruthValue.FALSE));
53 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.ERROR));
54 assertThat(sut.get(Tuple.of(3, 6, 5)), is(TruthValue.TRUE));
55 assertThat(sut.get(Tuple.of(3, 4, 6)), is(TruthValue.FALSE));
56 assertThat(sut.get(Tuple.of(3, 5, 6)), is(TruthValue.UNKNOWN));
57 }
58
59 @Test
60 void mergeWildcardTest3() {
61 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
62 sut.mergeValue(Tuple.of(-1, 4, -1), TruthValue.FALSE);
63 sut.mergeValue(Tuple.of(3, -1, 5), TruthValue.TRUE);
64 sut.mergeValue(Tuple.of(-1, -1, -1), TruthValue.ERROR);
65 assertThat(sut.get(Tuple.of(2, 4, 5)), is(TruthValue.ERROR));
66 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.ERROR));
67 assertThat(sut.get(Tuple.of(3, 6, 5)), is(TruthValue.ERROR));
68 assertThat(sut.get(Tuple.of(3, 4, 6)), is(TruthValue.ERROR));
69 assertThat(sut.get(Tuple.of(3, 5, 6)), is(TruthValue.ERROR));
70 }
71
72 @Test
73 void mergeOverUnsetTest() {
74 var sut = new DecisionTree(3, null);
75 sut.mergeValue(Tuple.of(-1, 4, 5), TruthValue.UNKNOWN);
76 sut.mergeValue(Tuple.of(3, -1, 5), TruthValue.FALSE);
77 assertThat(sut.get(Tuple.of(2, 4, 5)), is(TruthValue.UNKNOWN));
78 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.FALSE));
79 assertThat(sut.get(Tuple.of(3, 6, 5)), is(TruthValue.FALSE));
80 assertThat(sut.get(Tuple.of(3, 4, 6)), is(nullValue()));
81 }
82
83 @Test
84 void emptyIterationTest() {
85 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
86 var map = iterateAll(sut, TruthValue.UNKNOWN, 2);
87 assertThat(map.keySet(), hasSize(0));
88 }
89
90 @Test
91 void completeIterationTest() {
92 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
93 var map = iterateAll(sut, TruthValue.FALSE, 2);
94 assertThat(map.keySet(), hasSize(8));
95 assertThat(map, hasEntry(Tuple.of(0, 0, 0), TruthValue.UNKNOWN));
96 assertThat(map, hasEntry(Tuple.of(0, 0, 1), TruthValue.UNKNOWN));
97 assertThat(map, hasEntry(Tuple.of(0, 1, 0), TruthValue.UNKNOWN));
98 assertThat(map, hasEntry(Tuple.of(0, 1, 1), TruthValue.UNKNOWN));
99 assertThat(map, hasEntry(Tuple.of(1, 0, 0), TruthValue.UNKNOWN));
100 assertThat(map, hasEntry(Tuple.of(1, 0, 1), TruthValue.UNKNOWN));
101 assertThat(map, hasEntry(Tuple.of(1, 1, 0), TruthValue.UNKNOWN));
102 assertThat(map, hasEntry(Tuple.of(1, 1, 1), TruthValue.UNKNOWN));
103 }
104
105 @Test
106 void mergedIterationTest() {
107 var sut = new DecisionTree(2, TruthValue.UNKNOWN);
108 sut.mergeValue(Tuple.of(1, -1), TruthValue.TRUE);
109 sut.mergeValue(Tuple.of(-1, 2), TruthValue.FALSE);
110 var map = iterateAll(sut, TruthValue.UNKNOWN, 3);
111 assertThat(map.keySet(), hasSize(5));
112 assertThat(map, hasEntry(Tuple.of(0, 2), TruthValue.FALSE));
113 assertThat(map, hasEntry(Tuple.of(1, 0), TruthValue.TRUE));
114 assertThat(map, hasEntry(Tuple.of(1, 1), TruthValue.TRUE));
115 assertThat(map, hasEntry(Tuple.of(1, 2), TruthValue.ERROR));
116 assertThat(map, hasEntry(Tuple.of(2, 2), TruthValue.FALSE));
117 }
118
119 @Test
120 void sparseIterationTest() {
121 var sut = new DecisionTree(2, null);
122 sut.mergeValue(Tuple.of(0, 0), TruthValue.TRUE);
123 sut.mergeValue(Tuple.of(1, 1), TruthValue.FALSE);
124 var map = iterateAll(sut, null, 10);
125 assertThat(map.keySet(), hasSize(2));
126 assertThat(map, hasEntry(Tuple.of(0, 0), TruthValue.TRUE));
127 assertThat(map, hasEntry(Tuple.of(1, 1), TruthValue.FALSE));
128 }
129
130 @Test
131 void overwriteNothingTest() {
132 var sut = new DecisionTree(2, TruthValue.UNKNOWN);
133 var values = new DecisionTree(2, null);
134 sut.overwriteValues(values);
135 assertThat(sut.get(Tuple.of(0, 0)), is(TruthValue.UNKNOWN));
136 }
137
138 @Test
139 void overwriteEverythingTest() {
140 var sut = new DecisionTree(2, TruthValue.FALSE);
141 sut.mergeValue(Tuple.of(0, 0), TruthValue.ERROR);
142 var values = new DecisionTree(2, TruthValue.TRUE);
143 sut.overwriteValues(values);
144 assertThat(sut.get(Tuple.of(0, 0)), is(TruthValue.TRUE));
145 assertThat(sut.get(Tuple.of(0, 1)), is(TruthValue.TRUE));
146 }
147
148 @Test
149 void overwriteWildcardTest() {
150 var sut = new DecisionTree(3, TruthValue.UNKNOWN);
151 sut.mergeValue(Tuple.of(1, 1, 1), TruthValue.FALSE);
152 sut.mergeValue(Tuple.of(-1, 4, 5), TruthValue.FALSE);
153 sut.mergeValue(Tuple.of(3, -1, 5), TruthValue.TRUE);
154 var values = new DecisionTree(3, null);
155 values.mergeValue(Tuple.of(2, 2, 2), TruthValue.TRUE);
156 values.mergeValue(Tuple.of(-1, 4, 5), TruthValue.UNKNOWN);
157 values.mergeValue(Tuple.of(3, -1, 5), TruthValue.FALSE);
158 sut.overwriteValues(values);
159 assertThat(sut.get(Tuple.of(1, 1, 1)), is(TruthValue.FALSE));
160 assertThat(sut.get(Tuple.of(2, 2, 2)), is(TruthValue.TRUE));
161 assertThat(sut.get(Tuple.of(2, 4, 5)), is(TruthValue.UNKNOWN));
162 assertThat(sut.get(Tuple.of(3, 4, 5)), is(TruthValue.FALSE));
163 assertThat(sut.get(Tuple.of(3, 6, 5)), is(TruthValue.FALSE));
164 assertThat(sut.get(Tuple.of(3, 4, 6)), is(TruthValue.UNKNOWN));
165 }
166
167 @Test
168 void removeIntermediateChildTest() {
169 var sut = new DecisionTree(3, TruthValue.TRUE);
170 var values = new DecisionTree(3, null);
171 values.mergeValue(Tuple.of(1, 1, 1), TruthValue.UNKNOWN);
172 sut.overwriteValues(values);
173 sut.mergeValue(Tuple.of(1, 1, 1), TruthValue.TRUE);
174 assertThat(sut.get(Tuple.of(1, 1, 1)), is(TruthValue.TRUE));
175 }
176
177 private Map<Tuple, TruthValue> iterateAll(DecisionTree sut, TruthValue defaultValue, int nodeCount) {
178 var cursor = sut.getCursor(defaultValue, nodeCount);
179 var map = new LinkedHashMap<Tuple, TruthValue>();
180 while (cursor.move()) {
181 map.put(cursor.getKey(), cursor.getValue());
182 }
183 assertThat(cursor.isDirty(), is(false));
184 assertThat(cursor.isTerminated(), is(true));
185 return map;
186 }
187}
diff --git a/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapper.java b/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapper.java
deleted file mode 100644
index 1f972e0f..00000000
--- a/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapper.java
+++ /dev/null
@@ -1,239 +0,0 @@
1package tools.refinery.language.mapping;
2
3import java.util.HashMap;
4import java.util.HashSet;
5import java.util.Map;
6import java.util.Optional;
7
8import org.eclipse.emf.common.util.EList;
9
10import tools.refinery.language.ProblemUtil;
11import tools.refinery.language.model.problem.Assertion;
12import tools.refinery.language.model.problem.AssertionArgument;
13import tools.refinery.language.model.problem.ClassDeclaration;
14import tools.refinery.language.model.problem.EnumDeclaration;
15import tools.refinery.language.model.problem.IndividualDeclaration;
16import tools.refinery.language.model.problem.LogicValue;
17import tools.refinery.language.model.problem.Node;
18import tools.refinery.language.model.problem.NodeAssertionArgument;
19import tools.refinery.language.model.problem.PredicateDefinition;
20import tools.refinery.language.model.problem.Problem;
21import tools.refinery.language.model.problem.ReferenceDeclaration;
22import tools.refinery.language.model.problem.Statement;
23import tools.refinery.store.model.Model;
24import tools.refinery.store.model.ModelStore;
25import tools.refinery.store.model.ModelStoreImpl;
26import tools.refinery.store.model.Tuple;
27import tools.refinery.store.model.representation.Relation;
28import tools.refinery.store.model.representation.TruthValue;
29
30public class PartialModelMapper {
31 public PartialModelMapperDTO transformProblem(Problem problem) throws PartialModelMapperException {
32 // Defining an integer in order to assign different values to all the nodes
33 int[] nodeIter = new int[] { 0 };
34
35 // Getting the relations and the nodes from the given problem
36 PartialModelMapperDTO pmmDTO = initTransform(problem, nodeIter);
37
38 // Getting the relations and the nodes from the built in problem
39 Optional<Problem> builtinProblem = ProblemUtil.getBuiltInLibrary(problem);
40 if (builtinProblem.isEmpty())
41 throw new PartialModelMapperException("builtin.problem not found");
42 PartialModelMapperDTO builtinProblemDTO = initTransform(builtinProblem.get(), nodeIter);
43
44 // Merging the relation and the nodes from the given problem and from the built
45 // in problem
46 pmmDTO.getRelationMap().putAll(builtinProblemDTO.getRelationMap());
47 pmmDTO.getNodeMap().putAll(builtinProblemDTO.getNodeMap());
48 pmmDTO.getEnumNodeMap().putAll(builtinProblemDTO.getEnumNodeMap());
49 pmmDTO.getNewNodeMap().putAll(builtinProblemDTO.getNewNodeMap());
50 pmmDTO.getUniqueNodeMap().putAll(builtinProblemDTO.getUniqueNodeMap());
51
52 // Definition of store and model
53 ModelStore store = new ModelStoreImpl(new HashSet<>(pmmDTO.getRelationMap().values()));
54 Model model = store.createModel();
55 pmmDTO.setModel(model);
56
57 // Collecting all the nodes in one map
58 Map<Node, Integer> allNodesMap = mergeNodeMaps(pmmDTO.getEnumNodeMap(), pmmDTO.getUniqueNodeMap(),
59 pmmDTO.getNewNodeMap(), pmmDTO.getNodeMap());
60
61 // Filling up the relations with unknown truth values
62 for (tools.refinery.language.model.problem.Relation relation : pmmDTO.getRelationMap().keySet()) {
63 if (!(relation instanceof PredicateDefinition pd && pd.isError())) {
64 Relation<TruthValue> r = pmmDTO.getRelationMap().get(relation);
65 if (r.getArity() == 1)
66 for (Integer i : allNodesMap.values()) {
67 pmmDTO.getModel().put(r, Tuple.of(i), TruthValue.UNKNOWN);
68 }
69 else if (r.getArity() == 2)
70 for (Integer i : allNodesMap.values()) {
71 for (Integer j : allNodesMap.values()) {
72 pmmDTO.getModel().put(r, Tuple.of(i, j), TruthValue.UNKNOWN);
73 }
74 }
75 else
76 throw new PartialModelMapperException("Relation with arity above 2 is not supported");
77 }
78 }
79
80 // Filling up the exists
81 tools.refinery.language.model.problem.Relation existsRelation = findingRelationInDTO(builtinProblemDTO,
82 "exists", "The exists not found in built in problem");
83 for (Node n : allNodesMap.keySet()) {
84 if (pmmDTO.getNewNodeMap().containsKey(n)) {
85 pmmDTO.getModel().put(builtinProblemDTO.getRelationMap().get(existsRelation),
86 Tuple.of(allNodesMap.get(n)), TruthValue.UNKNOWN);
87 } else {
88 pmmDTO.getModel().put(builtinProblemDTO.getRelationMap().get(existsRelation),
89 Tuple.of(allNodesMap.get(n)), TruthValue.TRUE);
90 }
91 }
92
93 // Filling up the equals
94 tools.refinery.language.model.problem.Relation equalsRelation = findingRelationInDTO(builtinProblemDTO,
95 "equals", "The equals not found in built in problem");
96 for (Node n1 : allNodesMap.keySet()) {
97 for (Node n2 : allNodesMap.keySet()) {
98 if (n1.equals(n2)) {
99 if (pmmDTO.getNewNodeMap().containsKey(n1)) {
100 pmmDTO.getModel().put(builtinProblemDTO.getRelationMap().get(equalsRelation),
101 Tuple.of(allNodesMap.get(n1), allNodesMap.get(n2)), TruthValue.UNKNOWN);
102 } else {
103 pmmDTO.getModel().put(builtinProblemDTO.getRelationMap().get(equalsRelation),
104 Tuple.of(allNodesMap.get(n1), allNodesMap.get(n2)), TruthValue.TRUE);
105 }
106 } else {
107 pmmDTO.getModel().put(builtinProblemDTO.getRelationMap().get(equalsRelation),
108 Tuple.of(allNodesMap.get(n1), allNodesMap.get(n2)), TruthValue.FALSE);
109 }
110 }
111 }
112
113 // Transforming the assertions
114 processAssertions(problem, pmmDTO, allNodesMap);
115 processAssertions(builtinProblem.get(), pmmDTO, allNodesMap);
116
117 return pmmDTO;
118 }
119
120 // Searches for and gives back a relation in a PartialModelMapperDTO
121 private tools.refinery.language.model.problem.Relation findingRelationInDTO(
122 PartialModelMapperDTO partialModelMapperDTO, String searchedRelation, String errorText)
123 throws PartialModelMapperException {
124 for (tools.refinery.language.model.problem.Relation r : partialModelMapperDTO.getRelationMap().keySet()) {
125 if (searchedRelation.equals(r.getName()))
126 return r;
127 }
128 throw new PartialModelMapperException(errorText);
129 }
130
131 // Processing assertions and placing them in the model
132 private void processAssertions(Problem problem, PartialModelMapperDTO pmmDTO, Map<Node, Integer> allNodesMap) {
133 for (Statement s : problem.getStatements()) {
134 if (s instanceof Assertion assertion) {
135 Relation<TruthValue> r1 = pmmDTO.getRelationMap().get(assertion.getRelation());
136 int i = 0;
137 int[] integers = new int[assertion.getArguments().size()];
138 for (AssertionArgument aa : assertion.getArguments()) {
139 if (aa instanceof NodeAssertionArgument nas) {
140 integers[i] = allNodesMap.get(nas.getNode());
141 i++;
142 }
143 }
144 pmmDTO.getModel().put(r1, Tuple.of(integers), logicValueToTruthValue(assertion.getValue()));
145 } else if (s instanceof ClassDeclaration cd) {
146 if (!cd.isAbstract())
147 pmmDTO.getModel().put(pmmDTO.getRelationMap().get(cd),
148 Tuple.of(pmmDTO.getNewNodeMap().get(cd.getNewNode())), TruthValue.TRUE);
149 } else if (s instanceof EnumDeclaration ed) {
150 for (Node n : ed.getLiterals()) {
151 pmmDTO.getModel().put(pmmDTO.getRelationMap().get(ed), Tuple.of(pmmDTO.getEnumNodeMap().get(n)),
152 TruthValue.TRUE);
153 }
154 }
155 }
156 }
157
158 // Getting the relations and nodes from the problem
159 private PartialModelMapperDTO initTransform(Problem problem, int[] nodeIter) {
160 // Defining needed Maps
161 Map<tools.refinery.language.model.problem.Relation, Relation<TruthValue>> relationMap = new HashMap<>();
162 Map<Node, Integer> enumNodeMap = new HashMap<>();
163 Map<Node, Integer> uniqueNodeMap = new HashMap<>();
164 Map<Node, Integer> newNodeMap = new HashMap<>();
165
166 // Definition of Relations, filling up the enumNodeMap, uniqueNodeMap,
167 // newNodeMap
168 EList<Statement> statements = problem.getStatements();
169 for (Statement s : statements) {
170 if (s instanceof ClassDeclaration cd) {
171 Relation<TruthValue> r1 = new Relation<>(cd.getName(), 1, TruthValue.FALSE);
172 relationMap.put(cd, r1);
173 if (!cd.isAbstract())
174 newNodeMap.put(cd.getNewNode(), nodeIter[0]++);
175 EList<ReferenceDeclaration> refDeclList = cd.getReferenceDeclarations();
176 for (ReferenceDeclaration refDec : refDeclList) {
177 Relation<TruthValue> r2 = new Relation<>(refDec.getName(), 2, TruthValue.FALSE);
178 relationMap.put(refDec, r2);
179 }
180 } else if (s instanceof EnumDeclaration ed) {
181 Relation<TruthValue> r = new Relation<>(ed.getName(), 1, TruthValue.FALSE);
182 relationMap.put(ed, r);
183 for (Node n : ed.getLiterals()) {
184 enumNodeMap.put(n, nodeIter[0]++);
185 }
186 } else if (s instanceof IndividualDeclaration ud) {
187 for (Node n : ud.getNodes()) {
188 uniqueNodeMap.put(n, nodeIter[0]++);
189 }
190 } else if (s instanceof PredicateDefinition pd) {
191 Relation<TruthValue> r = new Relation<>(pd.getName(), 1, TruthValue.FALSE);
192 relationMap.put(pd, r);
193 }
194 }
195
196 // Filling the nodeMap up
197 Map<Node, Integer> nodeMap = new HashMap<>();
198 for (Node n : problem.getNodes()) {
199 nodeMap.put(n, nodeIter[0]++);
200 }
201
202 return new PartialModelMapperDTO(null, relationMap, nodeMap, enumNodeMap, uniqueNodeMap, newNodeMap);
203 }
204
205 // Merging the maps of nodes into one map
206 private Map<Node, Integer> mergeNodeMaps(Map<Node, Integer> enumNodeMap, Map<Node, Integer> uniqueNodeMap,
207 Map<Node, Integer> newNodeMap, Map<Node, Integer> nodeMap) {
208 Map<Node, Integer> out = new HashMap<>();
209 out.putAll(enumNodeMap);
210 out.putAll(uniqueNodeMap);
211 out.putAll(newNodeMap);
212 out.putAll(nodeMap);
213 return out;
214 }
215
216 // Exchange method from LogicValue to TruthValue
217 private TruthValue logicValueToTruthValue(LogicValue value) {
218 if (value.equals(LogicValue.TRUE))
219 return TruthValue.TRUE;
220 else if (value.equals(LogicValue.FALSE))
221 return TruthValue.FALSE;
222 else if (value.equals(LogicValue.UNKNOWN))
223 return TruthValue.UNKNOWN;
224 else
225 return TruthValue.ERROR;
226 }
227
228 public class PartialModelMapperException extends Exception {
229 private static final long serialVersionUID = 1L;
230
231 public PartialModelMapperException(String errorText) {
232 super(errorText);
233 }
234
235 public PartialModelMapperException() {
236 super();
237 }
238 }
239}
diff --git a/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapperDTO.java b/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapperDTO.java
deleted file mode 100644
index 3397b4bd..00000000
--- a/subprojects/language-to-store/src/main/java/tools/refinery/language/mapping/PartialModelMapperDTO.java
+++ /dev/null
@@ -1,54 +0,0 @@
1package tools.refinery.language.mapping;
2
3import java.util.Map;
4
5import tools.refinery.language.model.problem.Node;
6import tools.refinery.store.model.Model;
7import tools.refinery.store.model.representation.Relation;
8import tools.refinery.store.model.representation.TruthValue;
9
10public class PartialModelMapperDTO {
11 private Model model;
12 private Map<tools.refinery.language.model.problem.Relation, Relation<TruthValue>> relationMap;
13 private Map<Node, Integer> nodeMap;
14 private Map<Node, Integer> enumNodeMap;
15 private Map<Node, Integer> uniqueNodeMap;
16 private Map<Node, Integer> newNodeMap;
17
18 public PartialModelMapperDTO(Model model,
19 Map<tools.refinery.language.model.problem.Relation, Relation<TruthValue>> relationMap,
20 Map<Node, Integer> nodeMap,
21 Map<Node, Integer> enumNodeMap,
22 Map<Node, Integer> uniqueNodeMap,
23 Map<Node, Integer> newNodeMap) {
24 this.model = model;
25 this.relationMap = relationMap;
26 this.nodeMap = nodeMap;
27 this.enumNodeMap = enumNodeMap;
28 this.uniqueNodeMap = uniqueNodeMap;
29 this.newNodeMap = newNodeMap;
30 }
31
32 public Model getModel() {
33 return this.model;
34 }
35 public Map<tools.refinery.language.model.problem.Relation, Relation<TruthValue>> getRelationMap(){
36 return this.relationMap;
37 }
38 public Map<Node, Integer> getNodeMap() {
39 return this.nodeMap;
40 }
41 public Map<Node, Integer> getEnumNodeMap() {
42 return this.enumNodeMap;
43 }
44 public Map<Node, Integer> getUniqueNodeMap() {
45 return this.uniqueNodeMap;
46 }
47 public Map<Node, Integer> getNewNodeMap() {
48 return this.newNodeMap;
49 }
50
51 public void setModel(Model model) {
52 this.model = model;
53 }
54}
diff --git a/subprojects/language-to-store/src/test/java/tools/refinery/language/mapping/tests/PartialModelMapperTest.xtend b/subprojects/language-to-store/src/test/java/tools/refinery/language/mapping/tests/PartialModelMapperTest.xtend
deleted file mode 100644
index b2fcbaa9..00000000
--- a/subprojects/language-to-store/src/test/java/tools/refinery/language/mapping/tests/PartialModelMapperTest.xtend
+++ /dev/null
@@ -1,438 +0,0 @@
1package tools.refinery.language.mapping.tests
2
3import com.google.inject.Inject
4import org.eclipse.emf.ecore.util.EcoreUtil
5import org.eclipse.xtext.testing.InjectWith
6import org.eclipse.xtext.testing.extensions.InjectionExtension
7import org.eclipse.xtext.testing.util.ParseHelper
8import org.junit.jupiter.api.BeforeEach
9import org.junit.jupiter.api.Test
10import org.junit.jupiter.api.^extension.ExtendWith
11import tools.refinery.language.mapping.PartialModelMapper
12import tools.refinery.language.model.problem.Problem
13import tools.refinery.language.model.tests.ProblemTestUtil
14import tools.refinery.language.tests.ProblemInjectorProvider
15import tools.refinery.store.model.Tuple
16import tools.refinery.store.model.representation.TruthValue
17
18import static org.hamcrest.MatcherAssert.assertThat
19import static org.hamcrest.Matchers.*
20import static org.junit.jupiter.api.Assertions.assertTrue
21
22@ExtendWith(InjectionExtension)
23@InjectWith(ProblemInjectorProvider)
24class PartialModelMapperTest {
25 @Inject
26 ParseHelper<Problem> parseHelper
27
28 @Inject
29 extension ProblemTestUtil
30
31 PartialModelMapper mapper
32
33 @BeforeEach
34 def void beforeEach() {
35 mapper = new PartialModelMapper
36 }
37
38 //Testing the relation
39 @Test
40 def void relationTest() {
41 val problem = parseHelper.parse('''
42 class Person {
43 Person[0..*] friend
44 }
45
46 friend(a, b).
47 ''')
48 EcoreUtil.resolveAll(problem)
49
50 val modelAndMaps = mapper.transformProblem(problem)
51 assertThat(modelAndMaps, notNullValue())
52
53 val model = modelAndMaps.model
54 val relationMap = modelAndMaps.relationMap
55 val nodeMap = modelAndMaps.nodeMap
56
57 val person = problem.findClass("Person")
58 val friend = problem.findClass("Person").reference("friend")
59 val a = problem.node("a")
60 val b = problem.node("b")
61
62 assertTrue(model.getDataRepresentations().contains(relationMap.get(person)))
63 assertTrue(model.getDataRepresentations().contains(relationMap.get(friend)))
64 assertTrue(model.get(relationMap.get(friend), Tuple.of(nodeMap.get(a),nodeMap.get(b))).equals(TruthValue.TRUE))
65 }
66
67 //Testing the class
68 @Test
69 def void classTest() {
70 val problem = parseHelper.parse('''
71 class Person {
72 Person[0..*] friend
73 }
74
75 Person(a).
76 ''')
77 EcoreUtil.resolveAll(problem)
78
79 val modelAndMaps = mapper.transformProblem(problem)
80 assertThat(modelAndMaps, notNullValue())
81
82 val model = modelAndMaps.model
83 val relationMap = modelAndMaps.relationMap
84 val nodeMap = modelAndMaps.nodeMap
85
86 val person = problem.findClass("Person")
87 val friend = problem.findClass("Person").reference("friend")
88 val a = problem.node("a")
89
90 assertTrue(model.getDataRepresentations().contains(relationMap.get(person)))
91 assertTrue(model.getDataRepresentations().contains(relationMap.get(friend)))
92
93 assertTrue(model.get(relationMap.get(person), Tuple.of(nodeMap.get(a))).equals(TruthValue.TRUE))
94 }
95
96 //Testing the equals and exists from the built in problem
97 @Test
98 def void equalsAndExistTest() {
99 val problem = parseHelper.parse('''
100 node(a).
101 node(b).
102
103 class Person.
104 ''')
105 EcoreUtil.resolveAll(problem)
106 val builtin = problem.builtin
107
108 val modelAndMaps = mapper.transformProblem(problem)
109 assertThat(modelAndMaps, notNullValue())
110
111 val model = modelAndMaps.model
112 val relationMap = modelAndMaps.relationMap
113 val nodeMap = modelAndMaps.nodeMap
114 val newNodeMap = modelAndMaps.newNodeMap
115
116 val a = problem.node("a")
117 val b = problem.node("b")
118 val Person = problem.findClass("Person")
119 val PersonNew = problem.findClass("Person").newNode
120 val exists = builtin.pred("exists")
121 val equals = builtin.findClass("node").reference("equals")
122
123 assertTrue(model.getDataRepresentations().contains(relationMap.get(Person)))
124 assertTrue(model.getDataRepresentations().contains(relationMap.get(exists)))
125 assertTrue(model.getDataRepresentations().contains(relationMap.get(equals)))
126
127 assertTrue(model.get(relationMap.get(exists), Tuple.of(nodeMap.get(a))).equals(TruthValue.TRUE))
128 assertTrue(model.get(relationMap.get(exists), Tuple.of(nodeMap.get(b))).equals(TruthValue.TRUE))
129 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), nodeMap.get(a))).equals(TruthValue.TRUE))
130 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), nodeMap.get(b))).equals(TruthValue.TRUE))
131 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), nodeMap.get(b))).equals(TruthValue.FALSE))
132 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), nodeMap.get(a))).equals(TruthValue.FALSE))
133
134 assertTrue(model.get(relationMap.get(exists), Tuple.of(newNodeMap.get(PersonNew))).equals(TruthValue.UNKNOWN))
135 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), newNodeMap.get(PersonNew))).equals(TruthValue.UNKNOWN))
136 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), nodeMap.get(a))).equals(TruthValue.FALSE))
137 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), nodeMap.get(b))).equals(TruthValue.FALSE))
138 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), newNodeMap.get(PersonNew))).equals(TruthValue.FALSE))
139 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), newNodeMap.get(PersonNew))).equals(TruthValue.FALSE))
140 }
141
142 //Testing the equals and exists from the built in problem with a different example
143 @Test
144 def void equalsAndExistTest2() {
145 val problem = parseHelper.parse('''
146 class Person.
147
148 Person(a).
149 Person(b).
150 ''')
151 val builtin = problem.builtin
152 EcoreUtil.resolveAll(problem)
153
154 val modelAndMaps = mapper.transformProblem(problem)
155 assertThat(modelAndMaps, notNullValue())
156
157 val model = modelAndMaps.model
158 val relationMap = modelAndMaps.relationMap
159 val nodeMap = modelAndMaps.nodeMap
160 val newNodeMap = modelAndMaps.newNodeMap
161
162 val a = problem.node("a")
163 val b = problem.node("b")
164 val Person = problem.findClass("Person")
165 val PersonNew = problem.findClass("Person").newNode
166 val exists = builtin.pred("exists")
167 val equals = builtin.findClass("node").reference("equals")
168
169 assertTrue(model.getDataRepresentations().contains(relationMap.get(Person)))
170 assertTrue(model.getDataRepresentations().contains(relationMap.get(exists)))
171 assertTrue(model.getDataRepresentations().contains(relationMap.get(equals)))
172
173 assertTrue(model.get(relationMap.get(exists), Tuple.of(nodeMap.get(a))).equals(TruthValue.TRUE))
174 assertTrue(model.get(relationMap.get(exists), Tuple.of(nodeMap.get(b))).equals(TruthValue.TRUE))
175 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), nodeMap.get(a))).equals(TruthValue.TRUE))
176 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), nodeMap.get(b))).equals(TruthValue.TRUE))
177 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), nodeMap.get(b))).equals(TruthValue.FALSE))
178 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), nodeMap.get(a))).equals(TruthValue.FALSE))
179
180 assertTrue(model.get(relationMap.get(exists), Tuple.of(newNodeMap.get(PersonNew))).equals(TruthValue.UNKNOWN))
181 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), newNodeMap.get(PersonNew))).equals(TruthValue.UNKNOWN))
182 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), nodeMap.get(a))).equals(TruthValue.FALSE))
183 assertTrue(model.get(relationMap.get(equals), Tuple.of(newNodeMap.get(PersonNew), nodeMap.get(b))).equals(TruthValue.FALSE))
184 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(a), newNodeMap.get(PersonNew))).equals(TruthValue.FALSE))
185 assertTrue(model.get(relationMap.get(equals), Tuple.of(nodeMap.get(b), newNodeMap.get(PersonNew))).equals(TruthValue.FALSE))
186 }
187
188 //Testing the behavior of the newNodes
189 @Test
190 def void newNodeTest(){
191 val problem = parseHelper.parse('''
192 class Person.
193 abstract class Family.
194 ''')
195 EcoreUtil.resolveAll(problem)
196
197 val modelAndMaps = mapper.transformProblem(problem)
198 assertThat(modelAndMaps, notNullValue())
199
200 val model = modelAndMaps.model
201 val relationMap = modelAndMaps.relationMap
202 val newNodeMap = modelAndMaps.newNodeMap
203
204 val Person = problem.findClass("Person")
205 val Family = problem.findClass("Family")
206 val PersonNew = problem.findClass("Person").newNode
207
208
209 assertTrue(model.getDataRepresentations().contains(relationMap.get(Person)))
210 assertTrue(model.getDataRepresentations().contains(relationMap.get(Family)))
211
212 assertTrue(newNodeMap.size.equals(4)) //3 from builtin.problem, 1 from Person
213 assertTrue(model.get(relationMap.get(Person), Tuple.of(newNodeMap.get(PersonNew))).equals(TruthValue.TRUE))
214 }
215
216 //Testing the behavior of enumerations
217 @Test
218 def void enumTest(){
219 val problem = parseHelper.parse('''
220 enum TaxStatus {
221 child, student, adult, retired
222 }
223 ''')
224 EcoreUtil.resolveAll(problem)
225
226 val modelAndMaps = mapper.transformProblem(problem)
227 assertThat(modelAndMaps, notNullValue())
228
229 val model = modelAndMaps.model
230 val relationMap = modelAndMaps.relationMap
231 val enumNodeMap = modelAndMaps.enumNodeMap
232
233 val TaxStatus = problem.findEnum("TaxStatus")
234 val child = problem.findEnum("TaxStatus").literal("child")
235 val student = problem.findEnum("TaxStatus").literal("student")
236 val adult = problem.findEnum("TaxStatus").literal("adult")
237 val retired = problem.findEnum("TaxStatus").literal("retired")
238
239 assertTrue(model.getDataRepresentations().contains(relationMap.get(TaxStatus)))
240 assertTrue(model.get(relationMap.get(TaxStatus), Tuple.of(enumNodeMap.get(child))).equals(TruthValue.TRUE))
241 assertTrue(model.get(relationMap.get(TaxStatus), Tuple.of(enumNodeMap.get(student))).equals(TruthValue.TRUE))
242 assertTrue(model.get(relationMap.get(TaxStatus), Tuple.of(enumNodeMap.get(adult))).equals(TruthValue.TRUE))
243 assertTrue(model.get(relationMap.get(TaxStatus), Tuple.of(enumNodeMap.get(retired))).equals(TruthValue.TRUE))
244 }
245
246 //Testing the bool from the built in problem
247 @Test
248 def void builtinBoolTest(){
249 val problem = parseHelper.parse('''
250 class Person.
251 ''')
252 EcoreUtil.resolveAll(problem)
253 val builtin = problem.builtin
254
255 val modelAndMaps = mapper.transformProblem(problem)
256 assertThat(modelAndMaps, notNullValue())
257
258 val model = modelAndMaps.model
259 val relationMap = modelAndMaps.relationMap
260 val enumNodeMap = modelAndMaps.enumNodeMap
261
262 val bool = builtin.findEnum("bool")
263 val trueEnum = builtin.findEnum("bool").literal("true") //Emiatt nem sikerül a teszt
264 val falseEnum = builtin.findEnum("bool").literal("false")
265
266 assertTrue(model.getDataRepresentations().contains(relationMap.get(bool)))
267 assertTrue(model.get(relationMap.get(bool), Tuple.of(enumNodeMap.get(trueEnum))).equals(TruthValue.TRUE))
268 assertTrue(model.get(relationMap.get(bool), Tuple.of(enumNodeMap.get(falseEnum))).equals(TruthValue.TRUE))
269 }
270
271 //Testing different aspects of the behavior
272 @Test
273 def void compositeTest() {
274 val problem = parseHelper.parse('''
275 class Family {
276 contains Person[] members
277 }
278
279 class Person {
280 Person[0..*] children
281 Person[0..1] parent
282 TaxStatus taxStatus
283 }
284
285 enum TaxStatus {
286 child, student, adult, retired
287 }
288
289 % A child cannot have any dependents.
290 error invalidTaxStatus(Person p) <->
291 taxStatus(p, child), children(p, _q).
292
293 indiv family.
294 Family(family).
295 members(family, anne): true.
296 members(family, bob).
297 members(family, ciri).
298 children(anne, ciri).
299 ?children(bob, ciri).
300 taxStatus(anne, adult).
301 ''')
302 EcoreUtil.resolveAll(problem)
303
304 val modelAndMaps = mapper.transformProblem(problem)
305 assertThat(modelAndMaps, notNullValue())
306
307 val model = modelAndMaps.model
308 val relationMap = modelAndMaps.relationMap
309 val nodeMap = modelAndMaps.nodeMap
310 val uniqueNodeMap = modelAndMaps.uniqueNodeMap
311 val enumNodeMap = modelAndMaps.enumNodeMap
312
313 val Family = problem.findClass("Family")
314 val members = problem.findClass("Family").reference("members")
315 val Person = problem.findClass("Person")
316 val children = problem.findClass("Person").reference("children")
317 val parent = problem.findClass("Person").reference("parent")
318 val taxStatus = problem.findClass("Person").reference("taxStatus")
319 val TaxStatus = problem.findEnum("TaxStatus")
320 val invalidTaxStatus = problem.pred("invalidTaxStatus")
321
322 val anne = problem.node("anne")
323 val bob = problem.node("bob")
324 val ciri = problem.node("ciri")
325 val family = problem.individualNode("family")
326 val adult = problem.findEnum("TaxStatus").literal("adult")
327
328 assertTrue(model.getDataRepresentations().contains(relationMap.get(Family)))
329 assertTrue(model.getDataRepresentations().contains(relationMap.get(members)))
330 assertTrue(model.getDataRepresentations().contains(relationMap.get(Person)))
331 assertTrue(model.getDataRepresentations().contains(relationMap.get(children)))
332 assertTrue(model.getDataRepresentations().contains(relationMap.get(parent)))
333 assertTrue(model.getDataRepresentations().contains(relationMap.get(taxStatus)))
334 assertTrue(model.getDataRepresentations().contains(relationMap.get(TaxStatus)))
335 assertTrue(model.getDataRepresentations().contains(relationMap.get(invalidTaxStatus)))
336
337 assertTrue(model.get(relationMap.get(Family), Tuple.of(uniqueNodeMap.get(family))).equals(TruthValue.TRUE))
338 assertTrue(model.get(relationMap.get(members), Tuple.of(uniqueNodeMap.get(family),nodeMap.get(anne))).equals(TruthValue.TRUE))
339 assertTrue(model.get(relationMap.get(members), Tuple.of(uniqueNodeMap.get(family),nodeMap.get(bob))).equals(TruthValue.TRUE))
340 assertTrue(model.get(relationMap.get(members), Tuple.of(uniqueNodeMap.get(family),nodeMap.get(ciri))).equals(TruthValue.TRUE))
341 assertTrue(model.get(relationMap.get(children), Tuple.of(nodeMap.get(anne),nodeMap.get(ciri))).equals(TruthValue.TRUE))
342 assertTrue(model.get(relationMap.get(children), Tuple.of(nodeMap.get(bob),nodeMap.get(ciri))).equals(TruthValue.UNKNOWN))
343 assertTrue(model.get(relationMap.get(taxStatus), Tuple.of(nodeMap.get(anne),enumNodeMap.get(adult))).equals(TruthValue.TRUE))
344 }
345
346 @Test
347 def void carCaseStudyTest(){
348 val problem = parseHelper.parse('''
349 abstract class DynamicComponent {
350 contains StaticComponent[1..1] placedOn
351 }
352 abstract class StaticComponent.
353 class Car extends DynamicComponent.
354 class Pedestrian extends DynamicComponent.
355 class Road extends StaticComponent {
356 contains LaneSegment[0..*] lanes
357 }
358 class LaneSegment extends StaticComponent {
359 Lane[0..*] adjacentLanes
360 Lane[0..*] sameDirLanes
361 }
362
363 Car(c1).
364 Car(c2).
365 Pedestrian(p1).
366 Road(r1).
367 LaneSegment(l1).
368 LaneSegment(l2).
369 LaneSegment(l3).
370 placedOn(c1,l1).
371 placedOn(c2,l2).
372 placedOn(p1,l3).
373 lanes(r1,l1).
374 lanes(r1,l2).
375 lanes(r1,l3).
376 adjacentLanes(l1,l2).
377 adjacentLanes(l2,l1).
378 sameDirLanes(l1,l3).
379 sameDirLanes(l3,l1).
380 ''')
381 EcoreUtil.resolveAll(problem)
382
383 val modelAndMaps = mapper.transformProblem(problem)
384 assertThat(modelAndMaps, notNullValue())
385
386 val model = modelAndMaps.model
387 val relationMap = modelAndMaps.relationMap
388 val nodeMap = modelAndMaps.nodeMap
389
390 val DynamicComponent = problem.findClass("DynamicComponent")
391 val placedOn = problem.findClass("DynamicComponent").reference("placedOn")
392 val StaticComponent = problem.findClass("StaticComponent")
393 val Car = problem.findClass("Car")
394 val Pedestrian = problem.findClass("Pedestrian")
395 val Road = problem.findClass("Road")
396 val lanes = problem.findClass("Road").reference("lanes")
397 val LaneSegment = problem.findClass("LaneSegment")
398 val adjacentLanes = problem.findClass("LaneSegment").reference("adjacentLanes")
399 val sameDirLanes = problem.findClass("LaneSegment").reference("sameDirLanes")
400
401 val c1 = problem.node("c1")
402 val c2 = problem.node("c2")
403 val p1 = problem.node("p1")
404 val r1 = problem.node("r1")
405 val l1 = problem.node("l1")
406 val l2 = problem.node("l2")
407 val l3 = problem.node("l3")
408
409 assertTrue(model.getDataRepresentations().contains(relationMap.get(DynamicComponent)))
410 assertTrue(model.getDataRepresentations().contains(relationMap.get(placedOn)))
411 assertTrue(model.getDataRepresentations().contains(relationMap.get(StaticComponent)))
412 assertTrue(model.getDataRepresentations().contains(relationMap.get(Car)))
413 assertTrue(model.getDataRepresentations().contains(relationMap.get(Pedestrian)))
414 assertTrue(model.getDataRepresentations().contains(relationMap.get(Road)))
415 assertTrue(model.getDataRepresentations().contains(relationMap.get(lanes)))
416 assertTrue(model.getDataRepresentations().contains(relationMap.get(LaneSegment)))
417 assertTrue(model.getDataRepresentations().contains(relationMap.get(adjacentLanes)))
418 assertTrue(model.getDataRepresentations().contains(relationMap.get(sameDirLanes)))
419
420 assertTrue(model.get(relationMap.get(Car), Tuple.of(nodeMap.get(c1))).equals(TruthValue.TRUE))
421 assertTrue(model.get(relationMap.get(Car), Tuple.of(nodeMap.get(c2))).equals(TruthValue.TRUE))
422 assertTrue(model.get(relationMap.get(Pedestrian), Tuple.of(nodeMap.get(p1))).equals(TruthValue.TRUE))
423 assertTrue(model.get(relationMap.get(Road), Tuple.of(nodeMap.get(r1))).equals(TruthValue.TRUE))
424 assertTrue(model.get(relationMap.get(LaneSegment), Tuple.of(nodeMap.get(l1))).equals(TruthValue.TRUE))
425 assertTrue(model.get(relationMap.get(LaneSegment), Tuple.of(nodeMap.get(l2))).equals(TruthValue.TRUE))
426 assertTrue(model.get(relationMap.get(LaneSegment), Tuple.of(nodeMap.get(l3))).equals(TruthValue.TRUE))
427 assertTrue(model.get(relationMap.get(placedOn), Tuple.of(nodeMap.get(c1),nodeMap.get(l1))).equals(TruthValue.TRUE))
428 assertTrue(model.get(relationMap.get(placedOn), Tuple.of(nodeMap.get(c2),nodeMap.get(l2))).equals(TruthValue.TRUE))
429 assertTrue(model.get(relationMap.get(placedOn), Tuple.of(nodeMap.get(p1),nodeMap.get(l3))).equals(TruthValue.TRUE))
430 assertTrue(model.get(relationMap.get(lanes), Tuple.of(nodeMap.get(r1),nodeMap.get(l1))).equals(TruthValue.TRUE))
431 assertTrue(model.get(relationMap.get(lanes), Tuple.of(nodeMap.get(r1),nodeMap.get(l2))).equals(TruthValue.TRUE))
432 assertTrue(model.get(relationMap.get(lanes), Tuple.of(nodeMap.get(r1),nodeMap.get(l3))).equals(TruthValue.TRUE))
433 assertTrue(model.get(relationMap.get(adjacentLanes), Tuple.of(nodeMap.get(l1),nodeMap.get(l2))).equals(TruthValue.TRUE))
434 assertTrue(model.get(relationMap.get(adjacentLanes), Tuple.of(nodeMap.get(l2),nodeMap.get(l1))).equals(TruthValue.TRUE))
435 assertTrue(model.get(relationMap.get(sameDirLanes), Tuple.of(nodeMap.get(l1),nodeMap.get(l3))).equals(TruthValue.TRUE))
436 assertTrue(model.get(relationMap.get(sameDirLanes), Tuple.of(nodeMap.get(l3),nodeMap.get(l1))).equals(TruthValue.TRUE))
437 }
438}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java
index 610713f3..a5ba825b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/representation/TruthValue.java
@@ -11,7 +11,7 @@ public enum TruthValue {
11 11
12 private final String name; 12 private final String name;
13 13
14 private TruthValue(String name) { 14 TruthValue(String name) {
15 this.name = name; 15 this.name = name;
16 } 16 }
17 17
@@ -40,12 +40,19 @@ public enum TruthValue {
40 } 40 }
41 41
42 public TruthValue not() { 42 public TruthValue not() {
43 if (this == TRUE) { 43 return switch (this) {
44 return FALSE; 44 case TRUE -> FALSE;
45 } else if (this == FALSE) { 45 case FALSE -> TRUE;
46 return TRUE; 46 default -> this;
47 } else { 47 };
48 return this; 48 }
49 } 49
50 public TruthValue merge(TruthValue other) {
51 return switch (this) {
52 case TRUE -> other == UNKNOWN || other == TRUE ? TRUE : ERROR;
53 case FALSE -> other == TruthValue.UNKNOWN || other == TruthValue.FALSE ? FALSE : ERROR;
54 case UNKNOWN -> other;
55 default -> ERROR;
56 };
50 } 57 }
51} 58}