aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query/src/main/java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-07-09 19:53:46 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-07-09 19:53:46 +0200
commitf6440ff43e2e7497116c2cf762f61e07834b229f (patch)
tree0c5719408fcf061aa72781424af1002d6bbabe39 /subprojects/store-query/src/main/java
parentrefactor: Dnf lifter (diff)
downloadrefinery-f6440ff43e2e7497116c2cf762f61e07834b229f.tar.gz
refinery-f6440ff43e2e7497116c2cf762f61e07834b229f.tar.zst
refinery-f6440ff43e2e7497116c2cf762f61e07834b229f.zip
refactor: enable data variable unification
This is needed for demand set transformation of DNFs with input data parameters, where the result of the transformation has an out data parameter that has to be unified with the variable in the parent clause.
Diffstat (limited to 'subprojects/store-query/src/main/java')
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java32
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java25
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java21
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java2
8 files changed, 36 insertions, 67 deletions
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
index f2749094..5d77b9aa 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
@@ -11,7 +11,6 @@ import tools.refinery.store.query.literal.*;
11import tools.refinery.store.query.substitution.MapBasedSubstitution; 11import tools.refinery.store.query.substitution.MapBasedSubstitution;
12import tools.refinery.store.query.substitution.StatelessSubstitution; 12import tools.refinery.store.query.substitution.StatelessSubstitution;
13import tools.refinery.store.query.substitution.Substitution; 13import tools.refinery.store.query.substitution.Substitution;
14import tools.refinery.store.query.term.NodeVariable;
15import tools.refinery.store.query.term.ParameterDirection; 14import tools.refinery.store.query.term.ParameterDirection;
16import tools.refinery.store.query.term.Variable; 15import tools.refinery.store.query.term.Variable;
17 16
@@ -21,8 +20,8 @@ import java.util.function.Function;
21class ClausePostProcessor { 20class ClausePostProcessor {
22 private final Map<Variable, ParameterInfo> parameters; 21 private final Map<Variable, ParameterInfo> parameters;
23 private final List<Literal> literals; 22 private final List<Literal> literals;
24 private final Map<NodeVariable, NodeVariable> representatives = new LinkedHashMap<>(); 23 private final Map<Variable, Variable> representatives = new LinkedHashMap<>();
25 private final Map<NodeVariable, Set<NodeVariable>> equivalencePartition = new HashMap<>(); 24 private final Map<Variable, Set<Variable>> equivalencePartition = new HashMap<>();
26 private List<Literal> substitutedLiterals; 25 private List<Literal> substitutedLiterals;
27 private final Set<Variable> existentiallyQuantifiedVariables = new LinkedHashSet<>(); 26 private final Set<Variable> existentiallyQuantifiedVariables = new LinkedHashSet<>();
28 private Set<Variable> positiveVariables; 27 private Set<Variable> positiveVariables;
@@ -78,7 +77,7 @@ class ClausePostProcessor {
78 return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive(); 77 return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive();
79 } 78 }
80 79
81 private void mergeVariables(NodeVariable left, NodeVariable right) { 80 private void mergeVariables(Variable left, Variable right) {
82 var leftRepresentative = getRepresentative(left); 81 var leftRepresentative = getRepresentative(left);
83 var rightRepresentative = getRepresentative(right); 82 var rightRepresentative = getRepresentative(right);
84 var leftInfo = parameters.get(leftRepresentative); 83 var leftInfo = parameters.get(leftRepresentative);
@@ -91,7 +90,7 @@ class ClausePostProcessor {
91 } 90 }
92 } 91 }
93 92
94 private void doMergeVariables(NodeVariable parentRepresentative, NodeVariable newChildRepresentative) { 93 private void doMergeVariables(Variable parentRepresentative, Variable newChildRepresentative) {
95 var parentSet = getEquivalentVariables(parentRepresentative); 94 var parentSet = getEquivalentVariables(parentRepresentative);
96 var childSet = getEquivalentVariables(newChildRepresentative); 95 var childSet = getEquivalentVariables(newChildRepresentative);
97 parentSet.addAll(childSet); 96 parentSet.addAll(childSet);
@@ -101,18 +100,18 @@ class ClausePostProcessor {
101 } 100 }
102 } 101 }
103 102
104 private NodeVariable getRepresentative(NodeVariable variable) { 103 private Variable getRepresentative(Variable variable) {
105 return representatives.computeIfAbsent(variable, Function.identity()); 104 return representatives.computeIfAbsent(variable, Function.identity());
106 } 105 }
107 106
108 private Set<NodeVariable> getEquivalentVariables(NodeVariable variable) { 107 private Set<Variable> getEquivalentVariables(Variable variable) {
109 var representative = getRepresentative(variable); 108 var representative = getRepresentative(variable);
110 if (!representative.equals(variable)) { 109 if (!representative.equals(variable)) {
111 throw new AssertionError("NodeVariable %s already has a representative %s" 110 throw new AssertionError("NodeVariable %s already has a representative %s"
112 .formatted(variable, representative)); 111 .formatted(variable, representative));
113 } 112 }
114 return equivalencePartition.computeIfAbsent(variable, key -> { 113 return equivalencePartition.computeIfAbsent(variable, key -> {
115 var set = new HashSet<NodeVariable>(1); 114 var set = new HashSet<Variable>(1);
116 set.add(key); 115 set.add(key);
117 return set; 116 return set;
118 }); 117 });
@@ -123,7 +122,7 @@ class ClausePostProcessor {
123 var left = pair.getKey(); 122 var left = pair.getKey();
124 var right = pair.getValue(); 123 var right = pair.getValue();
125 if (!left.equals(right) && parameters.containsKey(left) && parameters.containsKey(right)) { 124 if (!left.equals(right) && parameters.containsKey(left) && parameters.containsKey(right)) {
126 substitutedLiterals.add(left.isEquivalent(right)); 125 substitutedLiterals.add(new EquivalenceLiteral(true, left, right));
127 } 126 }
128 } 127 }
129 } 128 }
@@ -149,20 +148,7 @@ class ClausePostProcessor {
149 148
150 private void computeExistentiallyQuantifiedVariables() { 149 private void computeExistentiallyQuantifiedVariables() {
151 for (var literal : substitutedLiterals) { 150 for (var literal : substitutedLiterals) {
152 for (var variable : literal.getOutputVariables()) { 151 existentiallyQuantifiedVariables.addAll(literal.getOutputVariables());
153 boolean added = existentiallyQuantifiedVariables.add(variable);
154 if (!variable.isUnifiable()) {
155 var parameterInfo = parameters.get(variable);
156 if (parameterInfo != null && parameterInfo.direction() == ParameterDirection.IN) {
157 throw new IllegalArgumentException("Trying to bind %s parameter %s"
158 .formatted(ParameterDirection.IN, variable));
159 }
160 if (!added) {
161 throw new IllegalArgumentException("Variable %s has multiple assigned values"
162 .formatted(variable));
163 }
164 }
165 }
166 } 152 }
167 } 153 }
168 154
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
index 1e96cf27..fe9cefcc 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
@@ -24,10 +24,6 @@ public final class SymbolicParameter extends Parameter {
24 return variable; 24 return variable;
25 } 25 }
26 26
27 public boolean isUnifiable() {
28 return variable.isUnifiable();
29 }
30
31 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { 27 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
32 return Objects.hash(super.hashCode(), helper.getVariableHashCode(variable)); 28 return Objects.hash(super.hashCode(), helper.getVariableHashCode(variable));
33 } 29 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
index a355dc3b..263c2e20 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
@@ -14,6 +14,8 @@ import tools.refinery.store.query.term.Variable;
14 14
15import java.util.*; 15import java.util.*;
16 16
17// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
18@SuppressWarnings("squid:S2160")
17public abstract class AbstractCallLiteral extends AbstractLiteral { 19public abstract class AbstractCallLiteral extends AbstractLiteral {
18 private final Constraint target; 20 private final Constraint target;
19 private final List<Variable> arguments; 21 private final List<Variable> arguments;
@@ -42,16 +44,12 @@ public abstract class AbstractCallLiteral extends AbstractLiteral {
42 } 44 }
43 switch (parameter.getDirection()) { 45 switch (parameter.getDirection()) {
44 case IN -> { 46 case IN -> {
45 if (mutableOutArguments.remove(argument)) { 47 mutableOutArguments.remove(argument);
46 checkInOutUnifiable(argument);
47 }
48 mutableInArguments.add(argument); 48 mutableInArguments.add(argument);
49 } 49 }
50 case OUT -> { 50 case OUT -> {
51 if (mutableInArguments.contains(argument)) { 51 if (!mutableInArguments.contains(argument)) {
52 checkInOutUnifiable(argument); 52 mutableOutArguments.add(argument);
53 } else if (!mutableOutArguments.add(argument)) {
54 checkDuplicateOutUnifiable(argument);
55 } 53 }
56 } 54 }
57 } 55 }
@@ -60,19 +58,6 @@ public abstract class AbstractCallLiteral extends AbstractLiteral {
60 outArguments = Collections.unmodifiableSet(mutableOutArguments); 58 outArguments = Collections.unmodifiableSet(mutableOutArguments);
61 } 59 }
62 60
63 private static void checkInOutUnifiable(Variable argument) {
64 if (!argument.isUnifiable()) {
65 throw new IllegalArgumentException("Argument %s cannot appear with both %s and %s direction"
66 .formatted(argument, ParameterDirection.IN, ParameterDirection.OUT));
67 }
68 }
69
70 private static void checkDuplicateOutUnifiable(Variable argument) {
71 if (!argument.isUnifiable()) {
72 throw new IllegalArgumentException("Argument %s cannot be bound multiple times".formatted(argument));
73 }
74 }
75
76 public Constraint getTarget() { 61 public Constraint getTarget() {
77 return target; 62 return target;
78 } 63 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
index 61b7344f..9a0c22d1 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
@@ -8,18 +8,23 @@ package tools.refinery.store.query.literal;
8import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper; 9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.substitution.Substitution; 10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.Variable; 11import tools.refinery.store.query.term.Variable;
13 12
14import java.util.Objects; 13import java.util.Objects;
15import java.util.Set; 14import java.util.Set;
16 15
16// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
17@SuppressWarnings("squid:S2160")
17public final class EquivalenceLiteral extends AbstractLiteral implements CanNegate<EquivalenceLiteral> { 18public final class EquivalenceLiteral extends AbstractLiteral implements CanNegate<EquivalenceLiteral> {
18 private final boolean positive; 19 private final boolean positive;
19 private final NodeVariable left; 20 private final Variable left;
20 private final NodeVariable right; 21 private final Variable right;
21 22
22 public EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) { 23 public EquivalenceLiteral(boolean positive, Variable left, Variable right) {
24 if (!left.tryGetType().equals(right.tryGetType())) {
25 throw new IllegalArgumentException("Variables %s and %s of different type cannot be equivalent"
26 .formatted(left, right));
27 }
23 this.positive = positive; 28 this.positive = positive;
24 this.left = left; 29 this.left = left;
25 this.right = right; 30 this.right = right;
@@ -29,11 +34,11 @@ public final class EquivalenceLiteral extends AbstractLiteral implements CanNega
29 return positive; 34 return positive;
30 } 35 }
31 36
32 public NodeVariable getLeft() { 37 public Variable getLeft() {
33 return left; 38 return left;
34 } 39 }
35 40
36 public NodeVariable getRight() { 41 public Variable getRight() {
37 return right; 42 return right;
38 } 43 }
39 44
@@ -59,8 +64,8 @@ public final class EquivalenceLiteral extends AbstractLiteral implements CanNega
59 64
60 @Override 65 @Override
61 public EquivalenceLiteral substitute(Substitution substitution) { 66 public EquivalenceLiteral substitute(Substitution substitution) {
62 return new EquivalenceLiteral(positive, substitution.getTypeSafeSubstitute(left), 67 return new EquivalenceLiteral(positive, substitution.getSubstitute(left),
63 substitution.getTypeSafeSubstitute(right)); 68 substitution.getSubstitute(right));
64 } 69 }
65 70
66 @Override 71 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
index ed6941da..4d88051b 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
@@ -47,11 +47,6 @@ public abstract sealed class AnyDataVariable extends Variable implements AnyTerm
47 } 47 }
48 48
49 @Override 49 @Override
50 public boolean isUnifiable() {
51 return false;
52 }
53
54 @Override
55 public abstract AnyDataVariable renew(@Nullable String name); 50 public abstract AnyDataVariable renew(@Nullable String name);
56 51
57 @Override 52 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
index e71c69ac..9b62e545 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
@@ -8,6 +8,7 @@ package tools.refinery.store.query.term;
8import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper; 10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.literal.EquivalenceLiteral;
11import tools.refinery.store.query.literal.Literal; 12import tools.refinery.store.query.literal.Literal;
12import tools.refinery.store.query.substitution.Substitution; 13import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.valuation.Valuation; 14import tools.refinery.store.query.valuation.Valuation;
@@ -90,4 +91,12 @@ public final class DataVariable<T> extends AnyDataVariable implements Term<T> {
90 public int hashCode() { 91 public int hashCode() {
91 return Objects.hash(super.hashCode(), type); 92 return Objects.hash(super.hashCode(), type);
92 } 93 }
94
95 public EquivalenceLiteral isEquivalent(DataVariable<T> other) {
96 return new EquivalenceLiteral(true, this, other);
97 }
98
99 public EquivalenceLiteral notEquivalent(DataVariable<T> other) {
100 return new EquivalenceLiteral(false, this, other);
101 }
93} 102}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
index e466f1c9..2f9c8bf1 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
@@ -22,11 +22,6 @@ public final class NodeVariable extends Variable {
22 } 22 }
23 23
24 @Override 24 @Override
25 public boolean isUnifiable() {
26 return true;
27 }
28
29 @Override
30 public NodeVariable renew(@Nullable String name) { 25 public NodeVariable renew(@Nullable String name) {
31 return Variable.of(name); 26 return Variable.of(name);
32 } 27 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
index 89ef0d89..1b553704 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
@@ -38,8 +38,6 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable {
38 return uniqueName; 38 return uniqueName;
39 } 39 }
40 40
41 public abstract boolean isUnifiable();
42
43 public abstract Variable renew(@Nullable String name); 41 public abstract Variable renew(@Nullable String name);
44 42
45 public abstract Variable renew(); 43 public abstract Variable renew();