aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-semantics/src/main
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-09-22 22:40:33 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-10-03 20:06:52 +0200
commitdb03801ae5eaa67f8c150413f483905184f5bdaa (patch)
treede96e12fc7d7f4006949ecaf0af535e3e5f1f59d /subprojects/language-semantics/src/main
parentchore(deps): bump dependencies (diff)
downloadrefinery-db03801ae5eaa67f8c150413f483905184f5bdaa.tar.gz
refinery-db03801ae5eaa67f8c150413f483905184f5bdaa.tar.zst
refinery-db03801ae5eaa67f8c150413f483905184f5bdaa.zip
feat: data structure for assertion merging
Diffstat (limited to 'subprojects/language-semantics/src/main')
-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
7 files changed, 528 insertions, 0 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
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}