diff options
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] |
2 | eclipseCollections = "11.1.0" | ||
2 | jetty = "11.0.12" | 3 | jetty = "11.0.12" |
3 | jmh = "1.35" | 4 | jmh = "1.35" |
4 | junit = "5.9.1" | 5 | junit = "5.9.1" |
@@ -8,6 +9,8 @@ slf4j = "2.0.3" | |||
8 | xtext = "2.29.0.M1" | 9 | xtext = "2.29.0.M1" |
9 | 10 | ||
10 | [libraries] | 11 | [libraries] |
12 | eclipseCollections = { group = "org.eclipse.collections", name = "eclipse-collections", version.ref = "eclipseCollections" } | ||
13 | eclipseCollections-api = { group = "org.eclipse.collections", name = "eclipse-collections-api", version.ref = "eclipseCollections" } | ||
11 | ecore = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore", version = "2.28.0" } | 14 | ecore = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore", version = "2.28.0" } |
12 | ecore-xmi = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore.xmi", version = "2.17.0" } | 15 | ecore-xmi = { group = "org.eclipse.emf", name = "org.eclipse.emf.ecore.xmi", version = "2.17.0" } |
13 | ecore-codegen = { group = "org.eclipse.emf", name = "org.eclipse.emf.codegen.ecore", version = "2.31.0" } | 16 | ecore-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' | |||
4 | include 'language' | 4 | include 'language' |
5 | include 'language-ide' | 5 | include 'language-ide' |
6 | include 'language-model' | 6 | include 'language-model' |
7 | include 'language-to-store' | 7 | include 'language-semantics' |
8 | include 'language-web' | 8 | include 'language-web' |
9 | include 'store' | 9 | include '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 @@ | |||
1 | plugins { | 1 | plugins { |
2 | id 'refinery-java-library' | 2 | id 'refinery-java-library' |
3 | id 'refinery-xtext-conventions' | ||
4 | } | 3 | } |
5 | 4 | ||
6 | dependencies { | 5 | dependencies { |
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 @@ | |||
1 | package tools.refinery.language.semantics.model; | ||
2 | |||
3 | import tools.refinery.language.utils.CollectedSymbols; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
4 | import tools.refinery.store.map.Cursor; | ||
5 | import tools.refinery.store.model.Tuple; | ||
6 | import tools.refinery.store.model.representation.TruthValue; | ||
7 | |||
8 | public 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import tools.refinery.store.map.Cursor; | ||
4 | import tools.refinery.store.map.VersionedMap; | ||
5 | import tools.refinery.store.model.Tuple; | ||
6 | import tools.refinery.store.model.representation.TruthValue; | ||
7 | |||
8 | import java.util.ArrayDeque; | ||
9 | import java.util.Deque; | ||
10 | import java.util.List; | ||
11 | |||
12 | class 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import org.eclipse.collections.api.LazyIntIterable; | ||
4 | import tools.refinery.store.model.Tuple; | ||
5 | import tools.refinery.store.model.representation.TruthValue; | ||
6 | |||
7 | abstract 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import tools.refinery.store.model.representation.TruthValue; | ||
4 | |||
5 | public 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import org.eclipse.collections.api.LazyIntIterable; | ||
4 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | ||
6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; | ||
7 | import tools.refinery.store.model.Tuple; | ||
8 | import tools.refinery.store.model.representation.TruthValue; | ||
9 | |||
10 | final 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 @@ | |||
1 | package tools.refinery.language.semantics.model.internal; | ||
2 | |||
3 | import org.eclipse.collections.api.LazyIntIterable; | ||
4 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
5 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | ||
6 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; | ||
7 | import tools.refinery.store.model.Tuple; | ||
8 | import tools.refinery.store.model.representation.TruthValue; | ||
9 | |||
10 | class 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 @@ | |||
1 | package tools.refinery.language.semantics.model.tests; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.language.semantics.model.internal.DecisionTree; | ||
5 | import tools.refinery.store.model.Tuple; | ||
6 | import tools.refinery.store.model.representation.TruthValue; | ||
7 | |||
8 | import java.util.LinkedHashMap; | ||
9 | import java.util.Map; | ||
10 | |||
11 | import static org.hamcrest.MatcherAssert.assertThat; | ||
12 | import static org.hamcrest.Matchers.*; | ||
13 | |||
14 | class 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 @@ | |||
1 | package tools.refinery.language.mapping; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.Map; | ||
6 | import java.util.Optional; | ||
7 | |||
8 | import org.eclipse.emf.common.util.EList; | ||
9 | |||
10 | import tools.refinery.language.ProblemUtil; | ||
11 | import tools.refinery.language.model.problem.Assertion; | ||
12 | import tools.refinery.language.model.problem.AssertionArgument; | ||
13 | import tools.refinery.language.model.problem.ClassDeclaration; | ||
14 | import tools.refinery.language.model.problem.EnumDeclaration; | ||
15 | import tools.refinery.language.model.problem.IndividualDeclaration; | ||
16 | import tools.refinery.language.model.problem.LogicValue; | ||
17 | import tools.refinery.language.model.problem.Node; | ||
18 | import tools.refinery.language.model.problem.NodeAssertionArgument; | ||
19 | import tools.refinery.language.model.problem.PredicateDefinition; | ||
20 | import tools.refinery.language.model.problem.Problem; | ||
21 | import tools.refinery.language.model.problem.ReferenceDeclaration; | ||
22 | import tools.refinery.language.model.problem.Statement; | ||
23 | import tools.refinery.store.model.Model; | ||
24 | import tools.refinery.store.model.ModelStore; | ||
25 | import tools.refinery.store.model.ModelStoreImpl; | ||
26 | import tools.refinery.store.model.Tuple; | ||
27 | import tools.refinery.store.model.representation.Relation; | ||
28 | import tools.refinery.store.model.representation.TruthValue; | ||
29 | |||
30 | public 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 @@ | |||
1 | package tools.refinery.language.mapping; | ||
2 | |||
3 | import java.util.Map; | ||
4 | |||
5 | import tools.refinery.language.model.problem.Node; | ||
6 | import tools.refinery.store.model.Model; | ||
7 | import tools.refinery.store.model.representation.Relation; | ||
8 | import tools.refinery.store.model.representation.TruthValue; | ||
9 | |||
10 | public 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 @@ | |||
1 | package tools.refinery.language.mapping.tests | ||
2 | |||
3 | import com.google.inject.Inject | ||
4 | import org.eclipse.emf.ecore.util.EcoreUtil | ||
5 | import org.eclipse.xtext.testing.InjectWith | ||
6 | import org.eclipse.xtext.testing.extensions.InjectionExtension | ||
7 | import org.eclipse.xtext.testing.util.ParseHelper | ||
8 | import org.junit.jupiter.api.BeforeEach | ||
9 | import org.junit.jupiter.api.Test | ||
10 | import org.junit.jupiter.api.^extension.ExtendWith | ||
11 | import tools.refinery.language.mapping.PartialModelMapper | ||
12 | import tools.refinery.language.model.problem.Problem | ||
13 | import tools.refinery.language.model.tests.ProblemTestUtil | ||
14 | import tools.refinery.language.tests.ProblemInjectorProvider | ||
15 | import tools.refinery.store.model.Tuple | ||
16 | import tools.refinery.store.model.representation.TruthValue | ||
17 | |||
18 | import static org.hamcrest.MatcherAssert.assertThat | ||
19 | import static org.hamcrest.Matchers.* | ||
20 | import static org.junit.jupiter.api.Assertions.assertTrue | ||
21 | |||
22 | @ExtendWith(InjectionExtension) | ||
23 | @InjectWith(ProblemInjectorProvider) | ||
24 | class 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 | } |