diff options
Diffstat (limited to 'subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java')
-rw-r--r-- | subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java | 130 |
1 files changed, 130 insertions, 0 deletions
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 | } | ||