aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java')
-rw-r--r--subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java107
1 files changed, 107 insertions, 0 deletions
diff --git a/subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java b/subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java
new file mode 100644
index 00000000..ee932598
--- /dev/null
+++ b/subprojects/logic/src/main/java/tools/refinery/logic/literal/AbstractCountLiteral.java
@@ -0,0 +1,107 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.literal;
7
8import tools.refinery.logic.Constraint;
9import tools.refinery.logic.InvalidQueryException;
10import tools.refinery.logic.equality.LiteralEqualityHelper;
11import tools.refinery.logic.equality.LiteralHashCodeHelper;
12import tools.refinery.logic.term.ConstantTerm;
13import tools.refinery.logic.term.DataVariable;
14import tools.refinery.logic.term.Variable;
15
16import java.util.List;
17import java.util.Objects;
18import java.util.Set;
19
20// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
21@SuppressWarnings("squid:S2160")
22public abstract class AbstractCountLiteral<T> extends AbstractCallLiteral {
23 private final Class<T> resultType;
24 private final DataVariable<T> resultVariable;
25
26 protected AbstractCountLiteral(Class<T> resultType, DataVariable<T> resultVariable, Constraint target,
27 List<Variable> arguments) {
28 super(target, arguments);
29 if (!resultVariable.getType().equals(resultType)) {
30 throw new InvalidQueryException("Count result variable %s must be of type %s, got %s instead".formatted(
31 resultVariable, resultType, resultVariable.getType().getName()));
32 }
33 if (arguments.contains(resultVariable)) {
34 throw new InvalidQueryException("Count result variable %s must not appear in the argument list"
35 .formatted(resultVariable));
36 }
37 this.resultType = resultType;
38 this.resultVariable = resultVariable;
39 }
40
41 public Class<T> getResultType() {
42 return resultType;
43 }
44
45 public DataVariable<T> getResultVariable() {
46 return resultVariable;
47 }
48
49 @Override
50 public Set<Variable> getOutputVariables() {
51 return Set.of(resultVariable);
52 }
53
54 protected abstract T zero();
55
56 protected abstract T one();
57
58 @Override
59 public Literal reduce() {
60 var reduction = getTarget().getReduction();
61 return switch (reduction) {
62 case ALWAYS_FALSE -> getResultVariable().assign(new ConstantTerm<>(resultType, zero()));
63 // The only way a constant {@code true} predicate can be called in a negative position is to have all of
64 // its arguments bound as input variables. Thus, there will only be a single match.
65 case ALWAYS_TRUE -> getResultVariable().assign(new ConstantTerm<>(resultType, one()));
66 case NOT_REDUCIBLE -> this;
67 };
68 }
69
70 @Override
71 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
72 if (!super.equalsWithSubstitution(helper, other)) {
73 return false;
74 }
75 var otherCountLiteral = (AbstractCountLiteral<?>) other;
76 return Objects.equals(resultType, otherCountLiteral.resultType) &&
77 helper.variableEqual(resultVariable, otherCountLiteral.resultVariable);
78 }
79
80 @Override
81 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
82 return Objects.hash(super.hashCodeWithSubstitution(helper), resultType,
83 helper.getVariableHashCode(resultVariable));
84 }
85
86 protected abstract String operatorName();
87
88 @Override
89 public String toString() {
90 var builder = new StringBuilder();
91 builder.append(resultVariable);
92 builder.append(" is ");
93 builder.append(operatorName());
94 builder.append(' ');
95 builder.append(getTarget().toReferenceString());
96 builder.append('(');
97 var argumentIterator = getArguments().iterator();
98 if (argumentIterator.hasNext()) {
99 builder.append(argumentIterator.next());
100 while (argumentIterator.hasNext()) {
101 builder.append(", ").append(argumentIterator.next());
102 }
103 }
104 builder.append(')');
105 return builder.toString();
106 }
107}