diff options
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.java | 159 |
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 | */ | ||
6 | package tools.refinery.language.semantics.internal; | ||
7 | |||
8 | import org.eclipse.collections.api.LazyIntIterable; | ||
9 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
10 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | ||
11 | import org.eclipse.collections.api.tuple.primitive.IntObjectPair; | ||
12 | import tools.refinery.store.tuple.Tuple; | ||
13 | import tools.refinery.store.representation.TruthValue; | ||
14 | |||
15 | final 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 | } | ||