diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-09-29 17:54:03 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-10-03 20:06:52 +0200 |
commit | 7218308c9be553c3e0d2af0dabde853d0dab27cd (patch) | |
tree | 44ba305c993689235c6599aa0d40d4d883e6f687 /subprojects/language-semantics/src/main | |
parent | fix: make Tuple1 cache thread safe (diff) | |
download | refinery-7218308c9be553c3e0d2af0dabde853d0dab27cd.tar.gz refinery-7218308c9be553c3e0d2af0dabde853d0dab27cd.tar.zst refinery-7218308c9be553c3e0d2af0dabde853d0dab27cd.zip |
feat: data structure for default assertions
Diffstat (limited to 'subprojects/language-semantics/src/main')
5 files changed, 116 insertions, 30 deletions
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 index d743ee2b..3893f396 100644 --- 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 | |||
@@ -20,21 +20,41 @@ public class DecisionTree { | |||
20 | root = node; | 20 | root = node; |
21 | } | 21 | } |
22 | 22 | ||
23 | public DecisionTree(int levels) { | ||
24 | this(levels, null); | ||
25 | } | ||
26 | |||
23 | public TruthValue get(Tuple tuple) { | 27 | public TruthValue get(Tuple tuple) { |
24 | return root.getValue(levels - 1, tuple).getTruthValue(); | 28 | return root.getValue(levels - 1, tuple).getTruthValue(); |
25 | } | 29 | } |
26 | 30 | ||
27 | public void mergeValue(Tuple tuple, TruthValue truthValue) { | 31 | public void mergeValue(Tuple tuple, TruthValue truthValue) { |
28 | if (truthValue == null) { | 32 | if (truthValue != null) { |
29 | return; | 33 | root.mergeValue(levels - 1, tuple, truthValue); |
34 | } | ||
35 | } | ||
36 | |||
37 | public void setIfMissing(Tuple tuple, TruthValue truthValue) { | ||
38 | if (truthValue != null) { | ||
39 | root.setIfMissing(levels - 1, tuple, truthValue); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | public void setAllMissing(TruthValue truthValue) { | ||
44 | if (truthValue != null) { | ||
45 | root.setAllMissing(truthValue); | ||
30 | } | 46 | } |
31 | root.mergeValue(levels - 1, tuple, truthValue); | ||
32 | } | 47 | } |
33 | 48 | ||
34 | public void overwriteValues(DecisionTree values) { | 49 | public void overwriteValues(DecisionTree values) { |
35 | root.overwriteValues(values.root); | 50 | root.overwriteValues(values.root); |
36 | } | 51 | } |
37 | 52 | ||
53 | public TruthValue getReducedValue() { | ||
54 | var reducedValue = root.getReducedValue(); | ||
55 | return reducedValue == null ? null : reducedValue.getTruthValue(); | ||
56 | } | ||
57 | |||
38 | public Cursor<Tuple, TruthValue> getCursor(TruthValue defaultValue, int nodeCount) { | 58 | public Cursor<Tuple, TruthValue> getCursor(TruthValue defaultValue, int nodeCount) { |
39 | return new DecisionTreeCursor(levels, defaultValue, nodeCount, root); | 59 | return new DecisionTreeCursor(levels, defaultValue, nodeCount, root); |
40 | } | 60 | } |
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 index 7f38fc79..8ca54969 100644 --- 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 | |||
@@ -33,6 +33,24 @@ abstract class DecisionTreeNode { | |||
33 | return copy; | 33 | return copy; |
34 | } | 34 | } |
35 | 35 | ||
36 | public void setIfMissing(int level, Tuple tuple, TruthValue value) { | ||
37 | var key = tuple.get(level); | ||
38 | if (key < 0) { | ||
39 | throw new IllegalArgumentException("Not allowed set a missing wildcard"); | ||
40 | } | ||
41 | doSetIfMissing(key, level - 1, tuple, value); | ||
42 | } | ||
43 | |||
44 | protected abstract void doSetIfMissing(int key, int nextLevel, Tuple tuple, TruthValue value); | ||
45 | |||
46 | public DecisionTreeNode withValueSetIfMissing(int level, Tuple tuple, TruthValue value) { | ||
47 | var copy = deepCopy(); | ||
48 | copy.setIfMissing(level, tuple, value); | ||
49 | return copy; | ||
50 | } | ||
51 | |||
52 | public abstract void setAllMissing(TruthValue value); | ||
53 | |||
36 | public abstract void overwriteValues(DecisionTreeNode values); | 54 | public abstract void overwriteValues(DecisionTreeNode values); |
37 | 55 | ||
38 | public DecisionTreeNode withOverwrittenValues(DecisionTreeNode values) { | 56 | public DecisionTreeNode withOverwrittenValues(DecisionTreeNode values) { |
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 index 1bf3c8b8..993987f5 100644 --- 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 | |||
@@ -19,14 +19,18 @@ public enum DecisionTreeValue { | |||
19 | return truthValue; | 19 | return truthValue; |
20 | } | 20 | } |
21 | 21 | ||
22 | public DecisionTreeValue merge(TruthValue other) { | 22 | public TruthValue merge(TruthValue other) { |
23 | return truthValue == null ? fromTruthValue(other) : fromTruthValue(truthValue.merge(other)); | 23 | return truthValue == null ? other : truthValue.merge(other); |
24 | } | 24 | } |
25 | 25 | ||
26 | public DecisionTreeValue overwrite(DecisionTreeValue other) { | 26 | public DecisionTreeValue overwrite(DecisionTreeValue other) { |
27 | return other == UNSET ? this : other; | 27 | return other == UNSET ? this : other; |
28 | } | 28 | } |
29 | 29 | ||
30 | public TruthValue getTruthValueOrElse(TruthValue other) { | ||
31 | return this == UNSET ? other : truthValue; | ||
32 | } | ||
33 | |||
30 | public static DecisionTreeValue fromTruthValue(TruthValue truthValue) { | 34 | public static DecisionTreeValue fromTruthValue(TruthValue truthValue) { |
31 | if (truthValue == null) { | 35 | if (truthValue == null) { |
32 | return DecisionTreeValue.UNSET; | 36 | return DecisionTreeValue.UNSET; |
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 index 7165197c..a7486ecb 100644 --- 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 | |||
@@ -62,19 +62,43 @@ final class IntermediateNode extends DecisionTreeNode { | |||
62 | } | 62 | } |
63 | 63 | ||
64 | @Override | 64 | @Override |
65 | public void overwriteValues(DecisionTreeNode values) { | 65 | protected void doSetIfMissing(int key, int nextLevel, Tuple tuple, TruthValue value) { |
66 | if (values instanceof IntermediateNode intermediateValues) { | 66 | var child = children.get(key); |
67 | otherwise.overwriteValues(intermediateValues.otherwise); | 67 | if (child == null) { |
68 | for (var pair : children.keyValuesView()) { | 68 | var otherwiseReducedValue = getOtherwiseReducedValue(); |
69 | pair.getTwo().overwriteValues(intermediateValues.getChild(pair.getOne())); | 69 | if (otherwiseReducedValue != null && otherwiseReducedValue != DecisionTreeValue.UNSET) { |
70 | } | 70 | // Value already set. |
71 | for (var pair : intermediateValues.children.keyValuesView()) { | 71 | return; |
72 | children.getIfAbsentPut(pair.getOne(), () -> otherwise.withOverwrittenValues(pair.getTwo())); | ||
73 | } | 72 | } |
74 | reduceChildren(); | 73 | var newChild = otherwise.withValueSetIfMissing(nextLevel, tuple, value); |
75 | } else { | 74 | children.put(key, newChild); |
75 | return; | ||
76 | } | ||
77 | child.setIfMissing(nextLevel, tuple, value); | ||
78 | } | ||
79 | |||
80 | @Override | ||
81 | public void setAllMissing(TruthValue value) { | ||
82 | otherwise.setAllMissing(value); | ||
83 | for (var child : children) { | ||
84 | child.setAllMissing(value); | ||
85 | } | ||
86 | reduceChildren(); | ||
87 | } | ||
88 | |||
89 | @Override | ||
90 | public void overwriteValues(DecisionTreeNode values) { | ||
91 | if (!(values instanceof IntermediateNode intermediateValues)) { | ||
76 | throw new IllegalArgumentException("Level mismatch"); | 92 | throw new IllegalArgumentException("Level mismatch"); |
77 | } | 93 | } |
94 | otherwise.overwriteValues(intermediateValues.otherwise); | ||
95 | for (var pair : children.keyValuesView()) { | ||
96 | pair.getTwo().overwriteValues(intermediateValues.getChild(pair.getOne())); | ||
97 | } | ||
98 | for (var pair : intermediateValues.children.keyValuesView()) { | ||
99 | children.getIfAbsentPut(pair.getOne(), () -> otherwise.withOverwrittenValues(pair.getTwo())); | ||
100 | } | ||
101 | reduceChildren(); | ||
78 | } | 102 | } |
79 | 103 | ||
80 | private void reduceChildren() { | 104 | private void reduceChildren() { |
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 index f3adea61..c0197e89 100644 --- 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 | |||
@@ -8,18 +8,18 @@ import tools.refinery.store.tuple.Tuple; | |||
8 | import tools.refinery.store.model.representation.TruthValue; | 8 | import tools.refinery.store.model.representation.TruthValue; |
9 | 9 | ||
10 | class TerminalNode extends DecisionTreeNode { | 10 | class TerminalNode extends DecisionTreeNode { |
11 | private MutableIntObjectMap<DecisionTreeValue> children; | 11 | private MutableIntObjectMap<TruthValue> children; |
12 | 12 | ||
13 | private DecisionTreeValue otherwise; | 13 | private DecisionTreeValue otherwise; |
14 | 14 | ||
15 | TerminalNode(MutableIntObjectMap<DecisionTreeValue> children, DecisionTreeValue otherwise) { | 15 | TerminalNode(MutableIntObjectMap<TruthValue> children, DecisionTreeValue otherwise) { |
16 | this.children = children; | 16 | this.children = children; |
17 | this.otherwise = otherwise; | 17 | this.otherwise = otherwise; |
18 | } | 18 | } |
19 | 19 | ||
20 | private DecisionTreeValue getChild(int index) { | 20 | private DecisionTreeValue getChild(int index) { |
21 | var child = children.get(index); | 21 | var child = children.get(index); |
22 | return child == null ? otherwise : child; | 22 | return child == null ? otherwise : DecisionTreeValue.fromTruthValue(child); |
23 | } | 23 | } |
24 | 24 | ||
25 | @Override | 25 | @Override |
@@ -41,7 +41,7 @@ class TerminalNode extends DecisionTreeNode { | |||
41 | 41 | ||
42 | @Override | 42 | @Override |
43 | protected void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value) { | 43 | protected void mergeAllValues(int nextLevel, Tuple tuple, TruthValue value) { |
44 | otherwise = otherwise.merge(value); | 44 | otherwise = DecisionTreeValue.fromTruthValue(otherwise.merge(value)); |
45 | children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne, | 45 | children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne, |
46 | pair -> pair.getTwo().merge(value)); | 46 | pair -> pair.getTwo().merge(value)); |
47 | reduceChildren(); | 47 | reduceChildren(); |
@@ -50,7 +50,7 @@ class TerminalNode extends DecisionTreeNode { | |||
50 | @Override | 50 | @Override |
51 | protected void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value) { | 51 | protected void mergeSingleValue(int key, int nextLevel, Tuple tuple, TruthValue value) { |
52 | var newChild = getChild(key).merge(value); | 52 | var newChild = getChild(key).merge(value); |
53 | if (newChild == otherwise) { | 53 | if (otherwise.getTruthValue() == newChild) { |
54 | children.remove(key); | 54 | children.remove(key); |
55 | } else { | 55 | } else { |
56 | children.put(key, newChild); | 56 | children.put(key, newChild); |
@@ -58,25 +58,45 @@ class TerminalNode extends DecisionTreeNode { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | @Override | 60 | @Override |
61 | public void overwriteValues(DecisionTreeNode values) { | 61 | public void setIfMissing(int level, Tuple tuple, TruthValue value) { |
62 | if (values instanceof TerminalNode terminalValues) { | 62 | assertLevel(level); |
63 | otherwise = otherwise.overwrite(terminalValues.otherwise); | 63 | super.setIfMissing(level, tuple, value); |
64 | children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne, | 64 | } |
65 | pair -> pair.getTwo().overwrite(terminalValues.getChild(pair.getOne()))); | 65 | |
66 | for (var pair : terminalValues.children.keyValuesView()) { | 66 | @Override |
67 | children.getIfAbsentPut(pair.getOne(), otherwise.overwrite(pair.getTwo())); | 67 | protected void doSetIfMissing(int key, int nextLevel, Tuple tuple, TruthValue value) { |
68 | } | 68 | if (otherwise == DecisionTreeValue.UNSET) { |
69 | children.getIfAbsentPut(key, value); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | @Override | ||
74 | public void setAllMissing(TruthValue value) { | ||
75 | if (otherwise == DecisionTreeValue.UNSET) { | ||
76 | otherwise = DecisionTreeValue.fromTruthValue(value); | ||
69 | reduceChildren(); | 77 | reduceChildren(); |
70 | } else { | 78 | } |
79 | } | ||
80 | |||
81 | @Override | ||
82 | public void overwriteValues(DecisionTreeNode values) { | ||
83 | if (!(values instanceof TerminalNode terminalValues)) { | ||
71 | throw new IllegalArgumentException("Level mismatch"); | 84 | throw new IllegalArgumentException("Level mismatch"); |
72 | } | 85 | } |
86 | otherwise = otherwise.overwrite(terminalValues.otherwise); | ||
87 | children = IntObjectMaps.mutable.from(children.keyValuesView(), IntObjectPair::getOne, | ||
88 | pair -> terminalValues.getChild(pair.getOne()).getTruthValueOrElse(pair.getTwo())); | ||
89 | for (var pair : terminalValues.children.keyValuesView()) { | ||
90 | children.getIfAbsentPut(pair.getOne(), pair.getTwo()); | ||
91 | } | ||
92 | reduceChildren(); | ||
73 | } | 93 | } |
74 | 94 | ||
75 | private void reduceChildren() { | 95 | private void reduceChildren() { |
76 | var iterator = children.iterator(); | 96 | var iterator = children.iterator(); |
77 | while (iterator.hasNext()) { | 97 | while (iterator.hasNext()) { |
78 | var child = iterator.next(); | 98 | var child = iterator.next(); |
79 | if (child == otherwise) { | 99 | if (otherwise.getTruthValue() == child) { |
80 | iterator.remove(); | 100 | iterator.remove(); |
81 | } | 101 | } |
82 | } | 102 | } |