aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java')
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java159
1 files changed, 159 insertions, 0 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java
new file mode 100644
index 00000000..0e2f5d18
--- /dev/null
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/internal/IntermediateNode.java
@@ -0,0 +1,159 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.semantics.internal;
7
8import org.eclipse.collections.api.LazyIntIterable;
9import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
10import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
11import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
12import tools.refinery.store.tuple.Tuple;
13import tools.refinery.store.representation.TruthValue;
14
15final class IntermediateNode extends DecisionTreeNode {
16 private final MutableIntObjectMap<DecisionTreeNode> children;
17
18 private final DecisionTreeNode otherwise;
19
20 IntermediateNode(MutableIntObjectMap<DecisionTreeNode> children, DecisionTreeNode otherwise) {
21 this.children = children;
22 this.otherwise = otherwise;
23 }
24
25 private DecisionTreeNode getChild(int index) {
26 var child = children.get(index);
27 return child == null ? otherwise : child;
28 }
29
30 @Override
31 public DecisionTreeValue getValue(int level, Tuple tuple) {
32 return getChild(tuple.get(level)).getValue(level - 1, tuple);
33 }
34
35 @Override
36 public DecisionTreeNode deepCopy() {
37 var newChildren = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne,
38 pair -> pair.getTwo().deepCopy());
39 var newOtherwise = otherwise.deepCopy();
40 return new IntermediateNode(newChildren, newOtherwise);
41 }
42
43 @Override
44 protected void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value) {
45 otherwise.mergeValue(nextLevel, tuple, value);
46 for (var child : children) {
47 child.mergeValue(nextLevel, tuple, value);
48 }
49 reduceChildren();
50 }
51
52 @Override
53 protected void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value) {
54 var otherwiseReduced = getOtherwiseReducedValue();
55 var child = children.get(key);
56 if (child == null) {
57 var newChild = otherwise.withMergedValue(nextLevel, tuple, value);
58 if (otherwiseReduced == null || newChild.getReducedValue() != otherwiseReduced) {
59 children.put(key, newChild);
60 }
61 return;
62 }
63 child.mergeValue(nextLevel, tuple, value);
64 if (otherwiseReduced != null && child.getReducedValue() == otherwiseReduced) {
65 children.remove(key);
66 }
67 }
68
69 @Override
70 protected void doSetIfMissing(int key, int nextLevel, Tuple tuple, TruthValue value) {
71 var child = children.get(key);
72 if (child == null) {
73 var otherwiseReducedValue = getOtherwiseReducedValue();
74 if (otherwiseReducedValue != null && otherwiseReducedValue != DecisionTreeValue.UNSET) {
75 // Value already set.
76 return;
77 }
78 var newChild = otherwise.withValueSetIfMissing(nextLevel, tuple, value);
79 children.put(key, newChild);
80 return;
81 }
82 child.setIfMissing(nextLevel, tuple, value);
83 }
84
85 @Override
86 public void setAllMissing(TruthValue value) {
87 otherwise.setAllMissing(value);
88 for (var child : children) {
89 child.setAllMissing(value);
90 }
91 reduceChildren();
92 }
93
94 @Override
95 public void overwriteValues(DecisionTreeNode values) {
96 if (!(values instanceof IntermediateNode intermediateValues)) {
97 throw new IllegalArgumentException("Level mismatch");
98 }
99 otherwise.overwriteValues(intermediateValues.otherwise);
100 for (var pair : children.keyValuesView()) {
101 pair.getTwo().overwriteValues(intermediateValues.getChild(pair.getOne()));
102 }
103 for (var pair : intermediateValues.children.keyValuesView()) {
104 children.getIfAbsentPut(pair.getOne(), () -> otherwise.withOverwrittenValues(pair.getTwo()));
105 }
106 reduceChildren();
107 }
108
109 private void reduceChildren() {
110 var otherwiseReduced = getOtherwiseReducedValue();
111 if (otherwiseReduced == null) {
112 return;
113 }
114 var iterator = children.iterator();
115 while (iterator.hasNext()) {
116 var child = iterator.next();
117 if (child.getReducedValue() == otherwiseReduced) {
118 iterator.remove();
119 }
120 }
121 }
122
123 @Override
124 protected DecisionTreeValue getOtherwiseReducedValue() {
125 return otherwise.getReducedValue();
126 }
127
128 @Override
129 protected LazyIntIterable getChildKeys() {
130 return children.keysView();
131 }
132
133 protected boolean moveNextSparse(int level, DecisionTreeCursor cursor, int startIndex, int[] sortedChildren) {
134 for (int i = startIndex; i < sortedChildren.length; i++) {
135 var key = sortedChildren[i];
136 var child = getChild(key);
137 var found = child.moveNext(level - 1, cursor);
138 if (found) {
139 cursor.iterationState[level] = i;
140 cursor.rawTuple[level] = key;
141 return true;
142 }
143 }
144 return false;
145 }
146
147 protected boolean moveNextDense(int level, DecisionTreeCursor cursor, int startIndex) {
148 for (int i = startIndex; i < cursor.nodeCount; i++) {
149 var child = getChild(i);
150 var found = child.moveNext(level - 1, cursor);
151 if (found) {
152 cursor.iterationState[level] = i;
153 cursor.rawTuple[level] = i;
154 return true;
155 }
156 }
157 return false;
158 }
159}