diff options
author | 2023-06-25 21:42:43 +0200 | |
---|---|---|
committer | 2023-06-29 02:23:00 +0200 | |
commit | 79a3fd092c79efc204d2980b07728258372871c4 (patch) | |
tree | e515ff637c1d1288281284d62d33175dd5d19f35 /subprojects/store-query/src/main/java | |
parent | feat: ordered query ResultSet (diff) | |
download | refinery-79a3fd092c79efc204d2980b07728258372871c4.tar.gz refinery-79a3fd092c79efc204d2980b07728258372871c4.tar.zst refinery-79a3fd092c79efc204d2980b07728258372871c4.zip |
refactor: query equality and hash code
Allow computing hash codes up to the renaming of variables.
Also introduces CheckLiteral instead of AssumeLiteral for more straightforward
naming.
Diffstat (limited to 'subprojects/store-query/src/main/java')
30 files changed, 388 insertions, 211 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 b5e7092b..1a45c20a 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 | |||
@@ -67,13 +67,13 @@ class ClausePostProcessor { | |||
67 | for (var literal : literals) { | 67 | for (var literal : literals) { |
68 | if (isPositiveEquivalence(literal)) { | 68 | if (isPositiveEquivalence(literal)) { |
69 | var equivalenceLiteral = (EquivalenceLiteral) literal; | 69 | var equivalenceLiteral = (EquivalenceLiteral) literal; |
70 | mergeVariables(equivalenceLiteral.left(), equivalenceLiteral.right()); | 70 | mergeVariables(equivalenceLiteral.getLeft(), equivalenceLiteral.getRight()); |
71 | } | 71 | } |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | private static boolean isPositiveEquivalence(Literal literal) { | 75 | private static boolean isPositiveEquivalence(Literal literal) { |
76 | return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.positive(); | 76 | return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive(); |
77 | } | 77 | } |
78 | 78 | ||
79 | private void mergeVariables(NodeVariable left, NodeVariable right) { | 79 | private void mergeVariables(NodeVariable left, NodeVariable right) { |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java index 50b245f7..7a3e2a1e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java | |||
@@ -6,9 +6,11 @@ | |||
6 | package tools.refinery.store.query.dnf; | 6 | package tools.refinery.store.query.dnf; |
7 | 7 | ||
8 | import tools.refinery.store.query.Constraint; | 8 | import tools.refinery.store.query.Constraint; |
9 | import tools.refinery.store.query.literal.Reduction; | ||
10 | import tools.refinery.store.query.equality.DnfEqualityChecker; | 9 | import tools.refinery.store.query.equality.DnfEqualityChecker; |
11 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 10 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
11 | import tools.refinery.store.query.equality.SubstitutingLiteralEqualityHelper; | ||
12 | import tools.refinery.store.query.equality.SubstitutingLiteralHashCodeHelper; | ||
13 | import tools.refinery.store.query.literal.Reduction; | ||
12 | import tools.refinery.store.query.term.Parameter; | 14 | import tools.refinery.store.query.term.Parameter; |
13 | import tools.refinery.store.query.term.Variable; | 15 | import tools.refinery.store.query.term.Variable; |
14 | 16 | ||
@@ -129,7 +131,7 @@ public final class Dnf implements Constraint { | |||
129 | return false; | 131 | return false; |
130 | } | 132 | } |
131 | for (int i = 0; i < numClauses; i++) { | 133 | for (int i = 0; i < numClauses; i++) { |
132 | var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, symbolicParameters, | 134 | var literalEqualityHelper = new SubstitutingLiteralEqualityHelper(callEqualityChecker, symbolicParameters, |
133 | other.symbolicParameters); | 135 | other.symbolicParameters); |
134 | if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { | 136 | if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { |
135 | return false; | 137 | return false; |
@@ -146,6 +148,18 @@ public final class Dnf implements Constraint { | |||
146 | return false; | 148 | return false; |
147 | } | 149 | } |
148 | 150 | ||
151 | public int hashCodeWithSubstitution() { | ||
152 | var helper = new SubstitutingLiteralHashCodeHelper(); | ||
153 | int result = 0; | ||
154 | for (var symbolicParameter : symbolicParameters) { | ||
155 | result = result * 31 + symbolicParameter.hashCodeWithSubstitution(helper); | ||
156 | } | ||
157 | for (var clause : clauses) { | ||
158 | result = result * 31 + clause.hashCodeWithSubstitution(helper); | ||
159 | } | ||
160 | return result; | ||
161 | } | ||
162 | |||
149 | @Override | 163 | @Override |
150 | public String toString() { | 164 | public String toString() { |
151 | return "%s/%d".formatted(name(), arity()); | 165 | return "%s/%d".formatted(name(), arity()); |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java index fdd0d47c..94327bad 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.dnf; | 6 | package tools.refinery.store.query.dnf; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.literal.Literal; | 10 | import tools.refinery.store.query.literal.Literal; |
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
11 | 12 | ||
@@ -25,4 +26,12 @@ public record DnfClause(Set<Variable> positiveVariables, List<Literal> literals) | |||
25 | } | 26 | } |
26 | return true; | 27 | return true; |
27 | } | 28 | } |
29 | |||
30 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
31 | int result = 0; | ||
32 | for (var literal : literals) { | ||
33 | result = result * 31 + literal.hashCodeWithSubstitution(helper); | ||
34 | } | ||
35 | return result; | ||
36 | } | ||
28 | } | 37 | } |
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 e0d3ba1f..1e96cf27 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 | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.query.dnf; | 6 | package tools.refinery.store.query.dnf; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
8 | import tools.refinery.store.query.term.Parameter; | 9 | import tools.refinery.store.query.term.Parameter; |
9 | import tools.refinery.store.query.term.ParameterDirection; | 10 | import tools.refinery.store.query.term.ParameterDirection; |
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
@@ -27,6 +28,10 @@ public final class SymbolicParameter extends Parameter { | |||
27 | return variable.isUnifiable(); | 28 | return variable.isUnifiable(); |
28 | } | 29 | } |
29 | 30 | ||
31 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
32 | return Objects.hash(super.hashCode(), helper.getVariableHashCode(variable)); | ||
33 | } | ||
34 | |||
30 | @Override | 35 | @Override |
31 | public String toString() { | 36 | public String toString() { |
32 | var direction = getDirection(); | 37 | var direction = getDirection(); |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java index 1eeb5723..a212b3f5 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java | |||
@@ -38,7 +38,7 @@ public class DeepDnfEqualityChecker implements DnfEqualityChecker { | |||
38 | return false; | 38 | return false; |
39 | } | 39 | } |
40 | for (int i = 0; i < numClauses; i++) { | 40 | for (int i = 0; i < numClauses; i++) { |
41 | var literalEqualityHelper = new LiteralEqualityHelper(this, symbolicParameters, | 41 | var literalEqualityHelper = new SubstitutingLiteralEqualityHelper(this, symbolicParameters, |
42 | other.getSymbolicParameters()); | 42 | other.getSymbolicParameters()); |
43 | if (!equalsWithSubstitutionRaw(literalEqualityHelper, clauses.get(i), other.getClauses().get(i))) { | 43 | if (!equalsWithSubstitutionRaw(literalEqualityHelper, clauses.get(i), other.getClauses().get(i))) { |
44 | return false; | 44 | return false; |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java index 4a8bee3b..e2cfd79b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java | |||
@@ -7,7 +7,11 @@ package tools.refinery.store.query.equality; | |||
7 | 7 | ||
8 | import tools.refinery.store.query.dnf.Dnf; | 8 | import tools.refinery.store.query.dnf.Dnf; |
9 | 9 | ||
10 | import java.util.Objects; | ||
11 | |||
10 | @FunctionalInterface | 12 | @FunctionalInterface |
11 | public interface DnfEqualityChecker { | 13 | public interface DnfEqualityChecker { |
14 | DnfEqualityChecker DEFAULT = Objects::equals; | ||
15 | |||
12 | boolean dnfEqual(Dnf left, Dnf right); | 16 | boolean dnfEqual(Dnf left, Dnf right); |
13 | } | 17 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java index 9315fb30..5abc76ce 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java | |||
@@ -6,49 +6,22 @@ | |||
6 | package tools.refinery.store.query.equality; | 6 | package tools.refinery.store.query.equality; |
7 | 7 | ||
8 | import tools.refinery.store.query.dnf.Dnf; | 8 | import tools.refinery.store.query.dnf.Dnf; |
9 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
10 | import tools.refinery.store.query.term.Variable; | 9 | import tools.refinery.store.query.term.Variable; |
11 | 10 | ||
12 | import java.util.HashMap; | 11 | import java.util.Objects; |
13 | import java.util.List; | ||
14 | import java.util.Map; | ||
15 | 12 | ||
16 | public class LiteralEqualityHelper { | 13 | public interface LiteralEqualityHelper extends DnfEqualityChecker { |
17 | private final DnfEqualityChecker dnfEqualityChecker; | 14 | LiteralEqualityHelper DEFAULT = new LiteralEqualityHelper() { |
18 | private final Map<Variable, Variable> leftToRight; | 15 | @Override |
19 | private final Map<Variable, Variable> rightToLeft; | 16 | public boolean variableEqual(Variable left, Variable right) { |
20 | 17 | return Objects.equals(left, right); | |
21 | public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List<SymbolicParameter> leftParameters, | ||
22 | List<SymbolicParameter> rightParameters) { | ||
23 | this.dnfEqualityChecker = dnfEqualityChecker; | ||
24 | var arity = leftParameters.size(); | ||
25 | if (arity != rightParameters.size()) { | ||
26 | throw new IllegalArgumentException("Parameter lists have unequal length"); | ||
27 | } | ||
28 | leftToRight = new HashMap<>(arity); | ||
29 | rightToLeft = new HashMap<>(arity); | ||
30 | for (int i = 0; i < arity; i++) { | ||
31 | if (!variableEqual(leftParameters.get(i).getVariable(), rightParameters.get(i).getVariable())) { | ||
32 | throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i); | ||
33 | } | ||
34 | } | 18 | } |
35 | } | ||
36 | |||
37 | public boolean dnfEqual(Dnf left, Dnf right) { | ||
38 | return dnfEqualityChecker.dnfEqual(left, right); | ||
39 | } | ||
40 | 19 | ||
41 | public boolean variableEqual(Variable left, Variable right) { | 20 | @Override |
42 | if (checkMapping(leftToRight, left, right) && checkMapping(rightToLeft, right, left)) { | 21 | public boolean dnfEqual(Dnf left, Dnf right) { |
43 | leftToRight.put(left, right); | 22 | return DnfEqualityChecker.DEFAULT.dnfEqual(left, right); |
44 | rightToLeft.put(right, left); | ||
45 | return true; | ||
46 | } | 23 | } |
47 | return false; | 24 | }; |
48 | } | ||
49 | 25 | ||
50 | private static boolean checkMapping(Map<Variable, Variable> map, Variable key, Variable expectedValue) { | 26 | boolean variableEqual(Variable left, Variable right); |
51 | var currentValue = map.get(key); | ||
52 | return currentValue == null || currentValue.equals(expectedValue); | ||
53 | } | ||
54 | } | 27 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java new file mode 100644 index 00000000..5495160a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.equality; | ||
7 | |||
8 | import tools.refinery.store.query.term.Variable; | ||
9 | |||
10 | import java.util.Objects; | ||
11 | |||
12 | @FunctionalInterface | ||
13 | public interface LiteralHashCodeHelper { | ||
14 | LiteralHashCodeHelper DEFAULT = Objects::hashCode; | ||
15 | |||
16 | int getVariableHashCode(Variable variable); | ||
17 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java new file mode 100644 index 00000000..50a79e07 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.equality; | ||
7 | |||
8 | import tools.refinery.store.query.dnf.Dnf; | ||
9 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
10 | import tools.refinery.store.query.term.Variable; | ||
11 | |||
12 | import java.util.HashMap; | ||
13 | import java.util.List; | ||
14 | import java.util.Map; | ||
15 | |||
16 | public class SubstitutingLiteralEqualityHelper implements LiteralEqualityHelper { | ||
17 | private final DnfEqualityChecker dnfEqualityChecker; | ||
18 | private final Map<Variable, Variable> leftToRight; | ||
19 | private final Map<Variable, Variable> rightToLeft; | ||
20 | |||
21 | public SubstitutingLiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, | ||
22 | List<SymbolicParameter> leftParameters, | ||
23 | List<SymbolicParameter> rightParameters) { | ||
24 | this.dnfEqualityChecker = dnfEqualityChecker; | ||
25 | var arity = leftParameters.size(); | ||
26 | if (arity != rightParameters.size()) { | ||
27 | throw new IllegalArgumentException("Parameter lists have unequal length"); | ||
28 | } | ||
29 | leftToRight = new HashMap<>(arity); | ||
30 | rightToLeft = new HashMap<>(arity); | ||
31 | for (int i = 0; i < arity; i++) { | ||
32 | if (!variableEqual(leftParameters.get(i).getVariable(), rightParameters.get(i).getVariable())) { | ||
33 | throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i); | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public boolean dnfEqual(Dnf left, Dnf right) { | ||
40 | return dnfEqualityChecker.dnfEqual(left, right); | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public boolean variableEqual(Variable left, Variable right) { | ||
45 | if (left.tryGetType().equals(right.tryGetType()) && | ||
46 | checkMapping(leftToRight, left, right) && | ||
47 | checkMapping(rightToLeft, right, left)) { | ||
48 | leftToRight.put(left, right); | ||
49 | rightToLeft.put(right, left); | ||
50 | return true; | ||
51 | } | ||
52 | return false; | ||
53 | } | ||
54 | |||
55 | private static boolean checkMapping(Map<Variable, Variable> map, Variable key, Variable expectedValue) { | ||
56 | var currentValue = map.get(key); | ||
57 | return currentValue == null || currentValue.equals(expectedValue); | ||
58 | } | ||
59 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java new file mode 100644 index 00000000..a40ecd58 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.equality; | ||
7 | |||
8 | import tools.refinery.store.query.term.Variable; | ||
9 | |||
10 | import java.util.LinkedHashMap; | ||
11 | import java.util.Map; | ||
12 | |||
13 | public class SubstitutingLiteralHashCodeHelper implements LiteralHashCodeHelper { | ||
14 | private final Map<Variable, Integer> assignedHashCodes = new LinkedHashMap<>(); | ||
15 | |||
16 | // 0 is for {@code null}, so we start with 1. | ||
17 | private int next = 1; | ||
18 | |||
19 | @Override | ||
20 | public int getVariableHashCode(Variable variable) { | ||
21 | if (variable == null) { | ||
22 | return 0; | ||
23 | } | ||
24 | return assignedHashCodes.computeIfAbsent(variable, key -> { | ||
25 | int sequenceNumber = next; | ||
26 | next++; | ||
27 | return variable.hashCodeWithSubstitution(sequenceNumber); | ||
28 | }); | ||
29 | } | ||
30 | } | ||
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 8ef8e8b4..a355dc3b 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 | |||
@@ -7,13 +7,14 @@ package tools.refinery.store.query.literal; | |||
7 | 7 | ||
8 | import tools.refinery.store.query.Constraint; | 8 | import tools.refinery.store.query.Constraint; |
9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
10 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | import tools.refinery.store.query.substitution.Substitution; | 11 | import tools.refinery.store.query.substitution.Substitution; |
11 | import tools.refinery.store.query.term.ParameterDirection; | 12 | import tools.refinery.store.query.term.ParameterDirection; |
12 | import tools.refinery.store.query.term.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
13 | 14 | ||
14 | import java.util.*; | 15 | import java.util.*; |
15 | 16 | ||
16 | public abstract class AbstractCallLiteral implements Literal { | 17 | public abstract class AbstractCallLiteral extends AbstractLiteral { |
17 | private final Constraint target; | 18 | private final Constraint target; |
18 | private final List<Variable> arguments; | 19 | private final List<Variable> arguments; |
19 | private final Set<Variable> inArguments; | 20 | private final Set<Variable> inArguments; |
@@ -112,7 +113,7 @@ public abstract class AbstractCallLiteral implements Literal { | |||
112 | 113 | ||
113 | @Override | 114 | @Override |
114 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { | 115 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { |
115 | if (other == null || getClass() != other.getClass()) { | 116 | if (!super.equalsWithSubstitution(helper, other)) { |
116 | return false; | 117 | return false; |
117 | } | 118 | } |
118 | var otherCallLiteral = (AbstractCallLiteral) other; | 119 | var otherCallLiteral = (AbstractCallLiteral) other; |
@@ -129,15 +130,11 @@ public abstract class AbstractCallLiteral implements Literal { | |||
129 | } | 130 | } |
130 | 131 | ||
131 | @Override | 132 | @Override |
132 | public boolean equals(Object o) { | 133 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
133 | if (this == o) return true; | 134 | int result = super.hashCodeWithSubstitution(helper) * 31 + target.hashCode(); |
134 | if (o == null || getClass() != o.getClass()) return false; | 135 | for (var argument : arguments) { |
135 | AbstractCallLiteral that = (AbstractCallLiteral) o; | 136 | result = result * 31 + helper.getVariableHashCode(argument); |
136 | return target.equals(that.target) && arguments.equals(that.arguments); | 137 | } |
137 | } | 138 | return result; |
138 | |||
139 | @Override | ||
140 | public int hashCode() { | ||
141 | return Objects.hash(getClass(), target, arguments); | ||
142 | } | 139 | } |
143 | } | 140 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java new file mode 100644 index 00000000..7d3cabd7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.literal; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | |||
11 | public abstract class AbstractLiteral implements Literal { | ||
12 | @Override | ||
13 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { | ||
14 | return other != null && getClass() == other.getClass(); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
19 | return getClass().hashCode(); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public boolean equals(Object o) { | ||
24 | if (this == o) return true; | ||
25 | if (o == null || getClass() != o.getClass()) return false; | ||
26 | AbstractLiteral that = (AbstractLiteral) o; | ||
27 | return equalsWithSubstitution(LiteralEqualityHelper.DEFAULT, that); | ||
28 | } | ||
29 | |||
30 | @Override | ||
31 | public int hashCode() { | ||
32 | return hashCodeWithSubstitution(LiteralHashCodeHelper.DEFAULT); | ||
33 | } | ||
34 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java index 3a5eb5c7..615fd493 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java | |||
@@ -7,6 +7,7 @@ package tools.refinery.store.query.literal; | |||
7 | 7 | ||
8 | import tools.refinery.store.query.Constraint; | 8 | import tools.refinery.store.query.Constraint; |
9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
10 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | import tools.refinery.store.query.substitution.Substitution; | 11 | import tools.refinery.store.query.substitution.Substitution; |
11 | import tools.refinery.store.query.term.*; | 12 | import tools.refinery.store.query.term.*; |
12 | 13 | ||
@@ -14,6 +15,8 @@ import java.util.List; | |||
14 | import java.util.Objects; | 15 | import java.util.Objects; |
15 | import java.util.Set; | 16 | import java.util.Set; |
16 | 17 | ||
18 | // {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}. | ||
19 | @SuppressWarnings("squid:S2160") | ||
17 | public class AggregationLiteral<R, T> extends AbstractCallLiteral { | 20 | public class AggregationLiteral<R, T> extends AbstractCallLiteral { |
18 | private final DataVariable<R> resultVariable; | 21 | private final DataVariable<R> resultVariable; |
19 | private final DataVariable<T> inputVariable; | 22 | private final DataVariable<T> inputVariable; |
@@ -100,18 +103,9 @@ public class AggregationLiteral<R, T> extends AbstractCallLiteral { | |||
100 | } | 103 | } |
101 | 104 | ||
102 | @Override | 105 | @Override |
103 | public boolean equals(Object o) { | 106 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
104 | if (this == o) return true; | 107 | return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(resultVariable), |
105 | if (o == null || getClass() != o.getClass()) return false; | 108 | helper.getVariableHashCode(inputVariable), aggregator); |
106 | if (!super.equals(o)) return false; | ||
107 | AggregationLiteral<?, ?> that = (AggregationLiteral<?, ?>) o; | ||
108 | return resultVariable.equals(that.resultVariable) && inputVariable.equals(that.inputVariable) && | ||
109 | aggregator.equals(that.aggregator); | ||
110 | } | ||
111 | |||
112 | @Override | ||
113 | public int hashCode() { | ||
114 | return Objects.hash(super.hashCode(), resultVariable, inputVariable, aggregator); | ||
115 | } | 109 | } |
116 | 110 | ||
117 | @Override | 111 | @Override |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java index dbf999a2..d8a4b494 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.DataVariable; | 11 | import tools.refinery.store.query.term.DataVariable; |
11 | import tools.refinery.store.query.term.Term; | 12 | import tools.refinery.store.query.term.Term; |
@@ -15,8 +16,11 @@ import java.util.Collections; | |||
15 | import java.util.Objects; | 16 | import java.util.Objects; |
16 | import java.util.Set; | 17 | import java.util.Set; |
17 | 18 | ||
18 | public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implements Literal { | 19 | public class AssignLiteral<T> extends AbstractLiteral { |
19 | public AssignLiteral { | 20 | private final DataVariable<T> variable; |
21 | private final Term<T> term; | ||
22 | |||
23 | public AssignLiteral(DataVariable<T> variable, Term<T> term) { | ||
20 | if (!term.getType().equals(variable.getType())) { | 24 | if (!term.getType().equals(variable.getType())) { |
21 | throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( | 25 | throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( |
22 | term, variable.getType().getName(), term.getType().getName())); | 26 | term, variable.getType().getName(), term.getType().getName())); |
@@ -26,6 +30,16 @@ public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implement | |||
26 | throw new IllegalArgumentException("Result variable %s must not appear in the term %s".formatted( | 30 | throw new IllegalArgumentException("Result variable %s must not appear in the term %s".formatted( |
27 | variable, term)); | 31 | variable, term)); |
28 | } | 32 | } |
33 | this.variable = variable; | ||
34 | this.term = term; | ||
35 | } | ||
36 | |||
37 | public DataVariable<T> getVariable() { | ||
38 | return variable; | ||
39 | } | ||
40 | |||
41 | public Term<T> getTerm() { | ||
42 | return term; | ||
29 | } | 43 | } |
30 | 44 | ||
31 | @Override | 45 | @Override |
@@ -53,27 +67,19 @@ public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implement | |||
53 | if (other == null || getClass() != other.getClass()) { | 67 | if (other == null || getClass() != other.getClass()) { |
54 | return false; | 68 | return false; |
55 | } | 69 | } |
56 | var otherLetLiteral = (AssignLiteral<?>) other; | 70 | var otherAssignLiteral = (AssignLiteral<?>) other; |
57 | return helper.variableEqual(variable, otherLetLiteral.variable) && term.equalsWithSubstitution(helper, | 71 | return helper.variableEqual(variable, otherAssignLiteral.variable) && |
58 | otherLetLiteral.term); | 72 | term.equalsWithSubstitution(helper, otherAssignLiteral.term); |
59 | } | ||
60 | |||
61 | @Override | ||
62 | public String toString() { | ||
63 | return "%s is (%s)".formatted(variable, term); | ||
64 | } | 73 | } |
65 | 74 | ||
66 | @Override | 75 | @Override |
67 | public boolean equals(Object obj) { | 76 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
68 | if (obj == this) return true; | 77 | return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(variable), |
69 | if (obj == null || obj.getClass() != this.getClass()) return false; | 78 | term.hashCodeWithSubstitution(helper)); |
70 | var that = (AssignLiteral<?>) obj; | ||
71 | return Objects.equals(this.variable, that.variable) && | ||
72 | Objects.equals(this.term, that.term); | ||
73 | } | 79 | } |
74 | 80 | ||
75 | @Override | 81 | @Override |
76 | public int hashCode() { | 82 | public String toString() { |
77 | return Objects.hash(getClass(), variable, term); | 83 | return "%s is (%s)".formatted(variable, term); |
78 | } | 84 | } |
79 | } | 85 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index f312d202..6cd320da 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
11 | 12 | ||
@@ -53,6 +54,11 @@ public enum BooleanLiteral implements CanNegate<BooleanLiteral> { | |||
53 | } | 54 | } |
54 | 55 | ||
55 | @Override | 56 | @Override |
57 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
58 | return hashCode(); | ||
59 | } | ||
60 | |||
61 | @Override | ||
56 | public String toString() { | 62 | public String toString() { |
57 | return Boolean.toString(value); | 63 | return Boolean.toString(value); |
58 | } | 64 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 29772aee..a311dada 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java | |||
@@ -7,12 +7,15 @@ package tools.refinery.store.query.literal; | |||
7 | 7 | ||
8 | import tools.refinery.store.query.Constraint; | 8 | import tools.refinery.store.query.Constraint; |
9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
10 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | import tools.refinery.store.query.substitution.Substitution; | 11 | import tools.refinery.store.query.substitution.Substitution; |
11 | import tools.refinery.store.query.term.ParameterDirection; | 12 | import tools.refinery.store.query.term.ParameterDirection; |
12 | import tools.refinery.store.query.term.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
13 | 14 | ||
14 | import java.util.*; | 15 | import java.util.*; |
15 | 16 | ||
17 | // {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}. | ||
18 | @SuppressWarnings("squid:S2160") | ||
16 | public final class CallLiteral extends AbstractCallLiteral implements CanNegate<CallLiteral> { | 19 | public final class CallLiteral extends AbstractCallLiteral implements CanNegate<CallLiteral> { |
17 | private final CallPolarity polarity; | 20 | private final CallPolarity polarity; |
18 | 21 | ||
@@ -85,22 +88,13 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate< | |||
85 | } | 88 | } |
86 | 89 | ||
87 | @Override | 90 | @Override |
88 | public CallLiteral negate() { | 91 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
89 | return new CallLiteral(polarity.negate(), getTarget(), getArguments()); | 92 | return Objects.hash(super.hashCodeWithSubstitution(helper), polarity); |
90 | } | 93 | } |
91 | 94 | ||
92 | @Override | 95 | @Override |
93 | public boolean equals(Object o) { | 96 | public CallLiteral negate() { |
94 | if (this == o) return true; | 97 | return new CallLiteral(polarity.negate(), getTarget(), getArguments()); |
95 | if (o == null || getClass() != o.getClass()) return false; | ||
96 | if (!super.equals(o)) return false; | ||
97 | CallLiteral that = (CallLiteral) o; | ||
98 | return polarity == that.polarity; | ||
99 | } | ||
100 | |||
101 | @Override | ||
102 | public int hashCode() { | ||
103 | return Objects.hash(super.hashCode(), polarity); | ||
104 | } | 98 | } |
105 | 99 | ||
106 | @Override | 100 | @Override |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java index 1ca04c77..1271183a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java | |||
@@ -6,21 +6,31 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.ConstantTerm; | 11 | import tools.refinery.store.query.term.ConstantTerm; |
11 | import tools.refinery.store.query.term.Term; | 12 | import tools.refinery.store.query.term.Term; |
12 | import tools.refinery.store.query.term.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
14 | import tools.refinery.store.query.term.bool.BoolNotTerm; | ||
15 | import tools.refinery.store.query.term.bool.BoolTerms; | ||
13 | 16 | ||
14 | import java.util.Collections; | 17 | import java.util.Collections; |
15 | import java.util.Objects; | 18 | import java.util.Objects; |
16 | import java.util.Set; | 19 | import java.util.Set; |
17 | 20 | ||
18 | public record AssumeLiteral(Term<Boolean> term) implements Literal { | 21 | public class CheckLiteral extends AbstractLiteral implements CanNegate<CheckLiteral> { |
19 | public AssumeLiteral { | 22 | private final Term<Boolean> term; |
23 | |||
24 | public CheckLiteral(Term<Boolean> term) { | ||
20 | if (!term.getType().equals(Boolean.class)) { | 25 | if (!term.getType().equals(Boolean.class)) { |
21 | throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( | 26 | throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( |
22 | term, Boolean.class.getName(), term.getType().getName())); | 27 | term, Boolean.class.getName(), term.getType().getName())); |
23 | } | 28 | } |
29 | this.term = term; | ||
30 | } | ||
31 | |||
32 | public Term<Boolean> getTerm() { | ||
33 | return term; | ||
24 | } | 34 | } |
25 | 35 | ||
26 | @Override | 36 | @Override |
@@ -38,10 +48,17 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal { | |||
38 | return Set.of(); | 48 | return Set.of(); |
39 | } | 49 | } |
40 | 50 | ||
41 | |||
42 | @Override | 51 | @Override |
43 | public Literal substitute(Substitution substitution) { | 52 | public Literal substitute(Substitution substitution) { |
44 | return new AssumeLiteral(term.substitute(substitution)); | 53 | return new CheckLiteral(term.substitute(substitution)); |
54 | } | ||
55 | |||
56 | @Override | ||
57 | public CheckLiteral negate() { | ||
58 | if (term instanceof BoolNotTerm notTerm) { | ||
59 | return new CheckLiteral(notTerm.getBody()); | ||
60 | } | ||
61 | return new CheckLiteral(BoolTerms.not(term)); | ||
45 | } | 62 | } |
46 | 63 | ||
47 | @Override | 64 | @Override |
@@ -49,11 +66,16 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal { | |||
49 | if (other == null || getClass() != other.getClass()) { | 66 | if (other == null || getClass() != other.getClass()) { |
50 | return false; | 67 | return false; |
51 | } | 68 | } |
52 | var otherAssumeLiteral = (AssumeLiteral) other; | 69 | var otherAssumeLiteral = (CheckLiteral) other; |
53 | return term.equalsWithSubstitution(helper, otherAssumeLiteral.term); | 70 | return term.equalsWithSubstitution(helper, otherAssumeLiteral.term); |
54 | } | 71 | } |
55 | 72 | ||
56 | @Override | 73 | @Override |
74 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
75 | return Objects.hash(super.hashCodeWithSubstitution(helper), term.hashCodeWithSubstitution(helper)); | ||
76 | } | ||
77 | |||
78 | @Override | ||
57 | public Literal reduce() { | 79 | public Literal reduce() { |
58 | if (term instanceof ConstantTerm<Boolean> constantTerm) { | 80 | if (term instanceof ConstantTerm<Boolean> constantTerm) { |
59 | // Return {@link BooleanLiteral#FALSE} for {@code false} or {@code null} literals. | 81 | // Return {@link BooleanLiteral#FALSE} for {@code false} or {@code null} literals. |
@@ -67,17 +89,4 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal { | |||
67 | public String toString() { | 89 | public String toString() { |
68 | return "(%s)".formatted(term); | 90 | return "(%s)".formatted(term); |
69 | } | 91 | } |
70 | |||
71 | @Override | ||
72 | public boolean equals(Object obj) { | ||
73 | if (obj == this) return true; | ||
74 | if (obj == null || obj.getClass() != this.getClass()) return false; | ||
75 | var that = (AssumeLiteral) obj; | ||
76 | return Objects.equals(this.term, that.term); | ||
77 | } | ||
78 | |||
79 | @Override | ||
80 | public int hashCode() { | ||
81 | return Objects.hash(getClass(), term); | ||
82 | } | ||
83 | } | 92 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index 73545620..d83bd584 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.NodeVariable; | 11 | import tools.refinery.store.query.term.NodeVariable; |
11 | import tools.refinery.store.query.term.Variable; | 12 | import tools.refinery.store.query.term.Variable; |
@@ -13,7 +14,24 @@ import tools.refinery.store.query.term.Variable; | |||
13 | import java.util.Objects; | 14 | import java.util.Objects; |
14 | import java.util.Set; | 15 | import java.util.Set; |
15 | 16 | ||
16 | public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal { | 17 | public class ConstantLiteral extends AbstractLiteral { |
18 | private final NodeVariable variable; | ||
19 | private final int nodeId; | ||
20 | |||
21 | public ConstantLiteral(NodeVariable variable, int nodeId) { | ||
22 | this.variable = variable; | ||
23 | this.nodeId = nodeId; | ||
24 | } | ||
25 | |||
26 | public NodeVariable getVariable() { | ||
27 | return variable; | ||
28 | } | ||
29 | |||
30 | public int getNodeId() { | ||
31 | return nodeId; | ||
32 | } | ||
33 | |||
34 | |||
17 | @Override | 35 | @Override |
18 | public Set<Variable> getOutputVariables() { | 36 | public Set<Variable> getOutputVariables() { |
19 | return Set.of(variable); | 37 | return Set.of(variable); |
@@ -43,23 +61,13 @@ public record ConstantLiteral(NodeVariable variable, int nodeId) implements Lite | |||
43 | return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId; | 61 | return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId; |
44 | } | 62 | } |
45 | 63 | ||
46 | |||
47 | @Override | ||
48 | public String toString() { | ||
49 | return "%s === @Constant %d".formatted(variable, nodeId); | ||
50 | } | ||
51 | |||
52 | @Override | 64 | @Override |
53 | public boolean equals(Object obj) { | 65 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
54 | if (obj == this) return true; | 66 | return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(variable), nodeId); |
55 | if (obj == null || obj.getClass() != this.getClass()) return false; | ||
56 | var that = (ConstantLiteral) obj; | ||
57 | return Objects.equals(this.variable, that.variable) && | ||
58 | this.nodeId == that.nodeId; | ||
59 | } | 67 | } |
60 | 68 | ||
61 | @Override | 69 | @Override |
62 | public int hashCode() { | 70 | public String toString() { |
63 | return Objects.hash(getClass(), variable, nodeId); | 71 | return "%s === @Constant %d".formatted(variable, nodeId); |
64 | } | 72 | } |
65 | } | 73 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java index 4d4749c8..ac4b8788 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java | |||
@@ -7,6 +7,7 @@ package tools.refinery.store.query.literal; | |||
7 | 7 | ||
8 | import tools.refinery.store.query.Constraint; | 8 | import tools.refinery.store.query.Constraint; |
9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
10 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | import tools.refinery.store.query.substitution.Substitution; | 11 | import tools.refinery.store.query.substitution.Substitution; |
11 | import tools.refinery.store.query.term.DataVariable; | 12 | import tools.refinery.store.query.term.DataVariable; |
12 | import tools.refinery.store.query.term.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
@@ -16,6 +17,8 @@ import java.util.List; | |||
16 | import java.util.Objects; | 17 | import java.util.Objects; |
17 | import java.util.Set; | 18 | import java.util.Set; |
18 | 19 | ||
20 | // {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}. | ||
21 | @SuppressWarnings("squid:S2160") | ||
19 | public class CountLiteral extends AbstractCallLiteral { | 22 | public class CountLiteral extends AbstractCallLiteral { |
20 | private final DataVariable<Integer> resultVariable; | 23 | private final DataVariable<Integer> resultVariable; |
21 | 24 | ||
@@ -68,17 +71,8 @@ public class CountLiteral extends AbstractCallLiteral { | |||
68 | } | 71 | } |
69 | 72 | ||
70 | @Override | 73 | @Override |
71 | public boolean equals(Object o) { | 74 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
72 | if (this == o) return true; | 75 | return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(resultVariable)); |
73 | if (o == null || getClass() != o.getClass()) return false; | ||
74 | if (!super.equals(o)) return false; | ||
75 | CountLiteral that = (CountLiteral) o; | ||
76 | return resultVariable.equals(that.resultVariable); | ||
77 | } | ||
78 | |||
79 | @Override | ||
80 | public int hashCode() { | ||
81 | return Objects.hash(super.hashCode(), resultVariable); | ||
82 | } | 76 | } |
83 | 77 | ||
84 | @Override | 78 | @Override |
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 28ba7625..61b7344f 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 | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.NodeVariable; | 11 | import tools.refinery.store.query.term.NodeVariable; |
11 | import tools.refinery.store.query.term.Variable; | 12 | import tools.refinery.store.query.term.Variable; |
@@ -13,8 +14,29 @@ import tools.refinery.store.query.term.Variable; | |||
13 | import java.util.Objects; | 14 | import java.util.Objects; |
14 | import java.util.Set; | 15 | import java.util.Set; |
15 | 16 | ||
16 | public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) | 17 | public final class EquivalenceLiteral extends AbstractLiteral implements CanNegate<EquivalenceLiteral> { |
17 | implements CanNegate<EquivalenceLiteral> { | 18 | private final boolean positive; |
19 | private final NodeVariable left; | ||
20 | private final NodeVariable right; | ||
21 | |||
22 | public EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) { | ||
23 | this.positive = positive; | ||
24 | this.left = left; | ||
25 | this.right = right; | ||
26 | } | ||
27 | |||
28 | public boolean isPositive() { | ||
29 | return positive; | ||
30 | } | ||
31 | |||
32 | public NodeVariable getLeft() { | ||
33 | return left; | ||
34 | } | ||
35 | |||
36 | public NodeVariable getRight() { | ||
37 | return right; | ||
38 | } | ||
39 | |||
18 | @Override | 40 | @Override |
19 | public Set<Variable> getOutputVariables() { | 41 | public Set<Variable> getOutputVariables() { |
20 | return Set.of(left); | 42 | return Set.of(left); |
@@ -55,27 +77,18 @@ public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariab | |||
55 | return false; | 77 | return false; |
56 | } | 78 | } |
57 | var otherEquivalenceLiteral = (EquivalenceLiteral) other; | 79 | var otherEquivalenceLiteral = (EquivalenceLiteral) other; |
58 | return helper.variableEqual(left, otherEquivalenceLiteral.left) && helper.variableEqual(right, | 80 | return helper.variableEqual(left, otherEquivalenceLiteral.left) && |
59 | otherEquivalenceLiteral.right); | 81 | helper.variableEqual(right, otherEquivalenceLiteral.right); |
60 | } | ||
61 | |||
62 | @Override | ||
63 | public String toString() { | ||
64 | return "%s %s %s".formatted(left, positive ? "===" : "!==", right); | ||
65 | } | 82 | } |
66 | 83 | ||
67 | @Override | 84 | @Override |
68 | public boolean equals(Object obj) { | 85 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
69 | if (obj == this) return true; | 86 | return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(left), |
70 | if (obj == null || obj.getClass() != this.getClass()) return false; | 87 | helper.getVariableHashCode(right)); |
71 | var that = (EquivalenceLiteral) obj; | ||
72 | return this.positive == that.positive && | ||
73 | Objects.equals(this.left, that.left) && | ||
74 | Objects.equals(this.right, that.right); | ||
75 | } | 88 | } |
76 | 89 | ||
77 | @Override | 90 | @Override |
78 | public int hashCode() { | 91 | public String toString() { |
79 | return Objects.hash(getClass(), positive, left, right); | 92 | return "%s %s %s".formatted(left, positive ? "===" : "!==", right); |
80 | } | 93 | } |
81 | } | 94 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index ce6c11fe..cb16ab00 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.literal; | 6 | package tools.refinery.store.query.literal; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
11 | 12 | ||
@@ -26,4 +27,6 @@ public interface Literal { | |||
26 | 27 | ||
27 | @SuppressWarnings("BooleanMethodIsAlwaysInverted") | 28 | @SuppressWarnings("BooleanMethodIsAlwaysInverted") |
28 | boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other); | 29 | boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other); |
30 | |||
31 | int hashCodeWithSubstitution(LiteralHashCodeHelper helper); | ||
29 | } | 32 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java index b3a87811..6056da45 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java | |||
@@ -16,7 +16,7 @@ public final class Literals { | |||
16 | return literal.negate(); | 16 | return literal.negate(); |
17 | } | 17 | } |
18 | 18 | ||
19 | public static AssumeLiteral assume(Term<Boolean> term) { | 19 | public static CheckLiteral check(Term<Boolean> term) { |
20 | return new AssumeLiteral(term); | 20 | return new CheckLiteral(term); |
21 | } | 21 | } |
22 | } | 22 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java index d0ae3c12..5cecc35b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.term; | 6 | package tools.refinery.store.query.term; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | 10 | ||
10 | import java.util.Objects; | 11 | import java.util.Objects; |
11 | 12 | ||
@@ -17,13 +18,18 @@ public abstract class AbstractTerm<T> implements Term<T> { | |||
17 | } | 18 | } |
18 | 19 | ||
19 | @Override | 20 | @Override |
21 | public Class<T> getType() { | ||
22 | return type; | ||
23 | } | ||
24 | |||
25 | @Override | ||
20 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | 26 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { |
21 | return getClass().equals(other.getClass()) && type.equals(other.getType()); | 27 | return other != null && getClass() == other.getClass() && type.equals(other.getType()); |
22 | } | 28 | } |
23 | 29 | ||
24 | @Override | 30 | @Override |
25 | public Class<T> getType() { | 31 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { |
26 | return type; | 32 | return Objects.hash(getClass(), type); |
27 | } | 33 | } |
28 | 34 | ||
29 | @Override | 35 | @Override |
@@ -31,11 +37,11 @@ public abstract class AbstractTerm<T> implements Term<T> { | |||
31 | if (this == o) return true; | 37 | if (this == o) return true; |
32 | if (o == null || getClass() != o.getClass()) return false; | 38 | if (o == null || getClass() != o.getClass()) return false; |
33 | AbstractTerm<?> that = (AbstractTerm<?>) o; | 39 | AbstractTerm<?> that = (AbstractTerm<?>) o; |
34 | return type.equals(that.type); | 40 | return equalsWithSubstitution(LiteralEqualityHelper.DEFAULT, that); |
35 | } | 41 | } |
36 | 42 | ||
37 | @Override | 43 | @Override |
38 | public int hashCode() { | 44 | public int hashCode() { |
39 | return Objects.hash(getClass(), type); | 45 | return hashCodeWithSubstitution(LiteralHashCodeHelper.DEFAULT); |
40 | } | 46 | } |
41 | } | 47 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java index c12c0166..f136b68d 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.term; | 6 | package tools.refinery.store.query.term; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | 11 | ||
11 | import java.util.Set; | 12 | import java.util.Set; |
@@ -17,5 +18,7 @@ public sealed interface AnyTerm permits AnyDataVariable, Term { | |||
17 | 18 | ||
18 | boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other); | 19 | boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other); |
19 | 20 | ||
21 | int hashCodeWithSubstitution(LiteralHashCodeHelper helper); | ||
22 | |||
20 | Set<AnyDataVariable> getInputVariables(); | 23 | Set<AnyDataVariable> getInputVariables(); |
21 | } | 24 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java index 8ad17839..09c86db6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.query.term; | 6 | package tools.refinery.store.query.term; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.valuation.Valuation; | 11 | import tools.refinery.store.query.valuation.Valuation; |
11 | 12 | ||
@@ -14,6 +15,8 @@ import java.util.HashSet; | |||
14 | import java.util.Objects; | 15 | import java.util.Objects; |
15 | import java.util.Set; | 16 | import java.util.Set; |
16 | 17 | ||
18 | // {@link Object#equals(Object)} is implemented by {@link AbstractTerm}. | ||
19 | @SuppressWarnings("squid:S2160") | ||
17 | public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> { | 20 | public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> { |
18 | private final Class<T1> leftType; | 21 | private final Class<T1> leftType; |
19 | private final Class<T2> rightType; | 22 | private final Class<T2> rightType; |
@@ -80,6 +83,12 @@ public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> { | |||
80 | } | 83 | } |
81 | 84 | ||
82 | @Override | 85 | @Override |
86 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
87 | return Objects.hash(super.hashCodeWithSubstitution(helper), leftType.hashCode(), rightType.hashCode(), | ||
88 | left.hashCodeWithSubstitution(helper), right.hashCodeWithSubstitution(helper)); | ||
89 | } | ||
90 | |||
91 | @Override | ||
83 | public Term<R> substitute(Substitution substitution) { | 92 | public Term<R> substitute(Substitution substitution) { |
84 | return doSubstitute(substitution, left.substitute(substitution), right.substitute(substitution)); | 93 | return doSubstitute(substitution, left.substitute(substitution), right.substitute(substitution)); |
85 | } | 94 | } |
@@ -93,21 +102,4 @@ public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> { | |||
93 | inputVariables.addAll(right.getInputVariables()); | 102 | inputVariables.addAll(right.getInputVariables()); |
94 | return Collections.unmodifiableSet(inputVariables); | 103 | return Collections.unmodifiableSet(inputVariables); |
95 | } | 104 | } |
96 | |||
97 | @Override | ||
98 | public boolean equals(Object o) { | ||
99 | if (this == o) return true; | ||
100 | if (o == null || getClass() != o.getClass()) return false; | ||
101 | if (!super.equals(o)) return false; | ||
102 | BinaryTerm<?, ?, ?> that = (BinaryTerm<?, ?, ?>) o; | ||
103 | return Objects.equals(leftType, that.leftType) && | ||
104 | Objects.equals(rightType, that.rightType) && | ||
105 | Objects.equals(left, that.left) && | ||
106 | Objects.equals(right, that.right); | ||
107 | } | ||
108 | |||
109 | @Override | ||
110 | public int hashCode() { | ||
111 | return Objects.hash(super.hashCode(), leftType, rightType, left, right); | ||
112 | } | ||
113 | } | 105 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java index 2f6c56d1..e722c84f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java | |||
@@ -6,12 +6,15 @@ | |||
6 | package tools.refinery.store.query.term; | 6 | package tools.refinery.store.query.term; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.valuation.Valuation; | 11 | import tools.refinery.store.query.valuation.Valuation; |
11 | 12 | ||
12 | import java.util.Objects; | 13 | import java.util.Objects; |
13 | import java.util.Set; | 14 | import java.util.Set; |
14 | 15 | ||
16 | // {@link Object#equals(Object)} is implemented by {@link AbstractTerm}. | ||
17 | @SuppressWarnings("squid:S2160") | ||
15 | public final class ConstantTerm<T> extends AbstractTerm<T> { | 18 | public final class ConstantTerm<T> extends AbstractTerm<T> { |
16 | private final T value; | 19 | private final T value; |
17 | 20 | ||
@@ -47,6 +50,11 @@ public final class ConstantTerm<T> extends AbstractTerm<T> { | |||
47 | } | 50 | } |
48 | 51 | ||
49 | @Override | 52 | @Override |
53 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
54 | return Objects.hash(super.hashCodeWithSubstitution(helper), Objects.hash(value)); | ||
55 | } | ||
56 | |||
57 | @Override | ||
50 | public Set<AnyDataVariable> getInputVariables() { | 58 | public Set<AnyDataVariable> getInputVariables() { |
51 | return Set.of(); | 59 | return Set.of(); |
52 | } | 60 | } |
@@ -55,17 +63,4 @@ public final class ConstantTerm<T> extends AbstractTerm<T> { | |||
55 | public String toString() { | 63 | public String toString() { |
56 | return value.toString(); | 64 | return value.toString(); |
57 | } | 65 | } |
58 | |||
59 | @Override | ||
60 | public boolean equals(Object o) { | ||
61 | if (this == o) return true; | ||
62 | if (o == null || getClass() != o.getClass()) return false; | ||
63 | ConstantTerm<?> that = (ConstantTerm<?>) o; | ||
64 | return Objects.equals(value, that.value); | ||
65 | } | ||
66 | |||
67 | @Override | ||
68 | public int hashCode() { | ||
69 | return Objects.hash(value); | ||
70 | } | ||
71 | } | 66 | } |
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 00950360..e71c69ac 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 | |||
@@ -7,6 +7,7 @@ package tools.refinery.store.query.term; | |||
7 | 7 | ||
8 | import org.jetbrains.annotations.Nullable; | 8 | import org.jetbrains.annotations.Nullable; |
9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 9 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
10 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
10 | import tools.refinery.store.query.literal.Literal; | 11 | import tools.refinery.store.query.literal.Literal; |
11 | import tools.refinery.store.query.substitution.Substitution; | 12 | import tools.refinery.store.query.substitution.Substitution; |
12 | import tools.refinery.store.query.valuation.Valuation; | 13 | import tools.refinery.store.query.valuation.Valuation; |
@@ -62,6 +63,16 @@ public final class DataVariable<T> extends AnyDataVariable implements Term<T> { | |||
62 | return other instanceof DataVariable<?> dataVariable && helper.variableEqual(this, dataVariable); | 63 | return other instanceof DataVariable<?> dataVariable && helper.variableEqual(this, dataVariable); |
63 | } | 64 | } |
64 | 65 | ||
66 | @Override | ||
67 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
68 | return helper.getVariableHashCode(this); | ||
69 | } | ||
70 | |||
71 | @Override | ||
72 | public int hashCodeWithSubstitution(int sequenceNumber) { | ||
73 | return Objects.hash(type, sequenceNumber); | ||
74 | } | ||
75 | |||
65 | public Literal assign(AssignedValue<T> value) { | 76 | public Literal assign(AssignedValue<T> value) { |
66 | return value.toLiteral(this); | 77 | return value.toLiteral(this); |
67 | } | 78 | } |
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 a2f3261f..d679908a 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 | |||
@@ -46,6 +46,11 @@ public final class NodeVariable extends Variable { | |||
46 | throw new IllegalStateException("%s is a node variable".formatted(this)); | 46 | throw new IllegalStateException("%s is a node variable".formatted(this)); |
47 | } | 47 | } |
48 | 48 | ||
49 | @Override | ||
50 | public int hashCodeWithSubstitution(int sequenceNumber) { | ||
51 | return sequenceNumber; | ||
52 | } | ||
53 | |||
49 | public ConstantLiteral isConstant(int value) { | 54 | public ConstantLiteral isConstant(int value) { |
50 | return new ConstantLiteral(this, value); | 55 | return new ConstantLiteral(this, value); |
51 | } | 56 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java index a46ebe31..6451ea00 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java | |||
@@ -6,12 +6,15 @@ | |||
6 | package tools.refinery.store.query.term; | 6 | package tools.refinery.store.query.term; |
7 | 7 | ||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; |
9 | import tools.refinery.store.query.equality.LiteralHashCodeHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | 10 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.valuation.Valuation; | 11 | import tools.refinery.store.query.valuation.Valuation; |
11 | 12 | ||
12 | import java.util.Objects; | 13 | import java.util.Objects; |
13 | import java.util.Set; | 14 | import java.util.Set; |
14 | 15 | ||
16 | // {@link Object#equals(Object)} is implemented by {@link AbstractTerm}. | ||
17 | @SuppressWarnings("squid:S2160") | ||
15 | public abstract class UnaryTerm<R, T> extends AbstractTerm<R> { | 18 | public abstract class UnaryTerm<R, T> extends AbstractTerm<R> { |
16 | private final Class<T> bodyType; | 19 | private final Class<T> bodyType; |
17 | private final Term<T> body; | 20 | private final Term<T> body; |
@@ -52,6 +55,11 @@ public abstract class UnaryTerm<R, T> extends AbstractTerm<R> { | |||
52 | } | 55 | } |
53 | 56 | ||
54 | @Override | 57 | @Override |
58 | public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) { | ||
59 | return Objects.hash(super.hashCodeWithSubstitution(helper), bodyType, body.hashCodeWithSubstitution(helper)); | ||
60 | } | ||
61 | |||
62 | @Override | ||
55 | public Term<R> substitute(Substitution substitution) { | 63 | public Term<R> substitute(Substitution substitution) { |
56 | return doSubstitute(substitution, body.substitute(substitution)); | 64 | return doSubstitute(substitution, body.substitute(substitution)); |
57 | } | 65 | } |
@@ -62,18 +70,4 @@ public abstract class UnaryTerm<R, T> extends AbstractTerm<R> { | |||
62 | public Set<AnyDataVariable> getInputVariables() { | 70 | public Set<AnyDataVariable> getInputVariables() { |
63 | return body.getInputVariables(); | 71 | return body.getInputVariables(); |
64 | } | 72 | } |
65 | |||
66 | @Override | ||
67 | public boolean equals(Object o) { | ||
68 | if (this == o) return true; | ||
69 | if (o == null || getClass() != o.getClass()) return false; | ||
70 | if (!super.equals(o)) return false; | ||
71 | UnaryTerm<?, ?> unaryTerm = (UnaryTerm<?, ?>) o; | ||
72 | return Objects.equals(bodyType, unaryTerm.bodyType) && Objects.equals(body, unaryTerm.body); | ||
73 | } | ||
74 | |||
75 | @Override | ||
76 | public int hashCode() { | ||
77 | return Objects.hash(super.hashCode(), bodyType, body); | ||
78 | } | ||
79 | } | 73 | } |
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 a0268c8e..74384df3 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 | |||
@@ -48,6 +48,8 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable { | |||
48 | 48 | ||
49 | public abstract <T> DataVariable<T> asDataVariable(Class<T> type); | 49 | public abstract <T> DataVariable<T> asDataVariable(Class<T> type); |
50 | 50 | ||
51 | public abstract int hashCodeWithSubstitution(int sequenceNumber); | ||
52 | |||
51 | @Override | 53 | @Override |
52 | public String toString() { | 54 | public String toString() { |
53 | return getName(); | 55 | return getName(); |