diff options
87 files changed, 2507 insertions, 1187 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java deleted file mode 100644 index bfd4c049..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra.internal.cardinality; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; | ||
10 | import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; | ||
11 | import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; | ||
12 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
13 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
14 | |||
15 | import java.util.stream.Stream; | ||
16 | |||
17 | public class UpperCardinalitySumAggregationOperator implements IMultisetAggregationOperator<UpperCardinality, | ||
18 | UpperCardinalitySumAggregationOperator.Accumulator, UpperCardinality> { | ||
19 | public static final UpperCardinalitySumAggregationOperator INSTANCE = new UpperCardinalitySumAggregationOperator(); | ||
20 | |||
21 | public static final BoundAggregator BOUND_AGGREGATOR = new BoundAggregator(INSTANCE, UpperCardinality.class, | ||
22 | UpperCardinality.class); | ||
23 | |||
24 | private UpperCardinalitySumAggregationOperator() { | ||
25 | // Singleton constructor. | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | public String getName() { | ||
30 | return "sum<UpperCardinality>"; | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public String getShortDescription() { | ||
35 | return "%s computes the sum of finite or unbounded upper cardinalities".formatted(getName()); | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public Accumulator createNeutral() { | ||
40 | return new Accumulator(); | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public boolean isNeutral(Accumulator result) { | ||
45 | return result.sumFiniteUpperBounds == 0 && result.countUnbounded == 0; | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public Accumulator update(Accumulator oldResult, UpperCardinality updateValue, boolean isInsertion) { | ||
50 | if (updateValue instanceof FiniteUpperCardinality finiteUpperCardinality) { | ||
51 | int finiteUpperBound = finiteUpperCardinality.finiteUpperBound(); | ||
52 | if (isInsertion) { | ||
53 | oldResult.sumFiniteUpperBounds += finiteUpperBound; | ||
54 | } else { | ||
55 | oldResult.sumFiniteUpperBounds -= finiteUpperBound; | ||
56 | } | ||
57 | } else if (updateValue instanceof UnboundedUpperCardinality) { | ||
58 | if (isInsertion) { | ||
59 | oldResult.countUnbounded += 1; | ||
60 | } else { | ||
61 | oldResult.countUnbounded -= 1; | ||
62 | } | ||
63 | } else { | ||
64 | throw new IllegalArgumentException("Unknown UpperCardinality: " + updateValue); | ||
65 | } | ||
66 | return oldResult; | ||
67 | } | ||
68 | |||
69 | @Override | ||
70 | public UpperCardinality getAggregate(Accumulator result) { | ||
71 | return result.countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : | ||
72 | UpperCardinalities.valueOf(result.sumFiniteUpperBounds); | ||
73 | } | ||
74 | |||
75 | @Override | ||
76 | public UpperCardinality aggregateStream(Stream<UpperCardinality> stream) { | ||
77 | var result = stream.collect(this::createNeutral, (accumulator, value) -> update(accumulator, value, true), | ||
78 | (left, right) -> new Accumulator(left.sumFiniteUpperBounds + right.sumFiniteUpperBounds, | ||
79 | left.countUnbounded + right.countUnbounded)); | ||
80 | return getAggregate(result); | ||
81 | } | ||
82 | |||
83 | @Override | ||
84 | public Accumulator clone(Accumulator original) { | ||
85 | return new Accumulator(original.sumFiniteUpperBounds, original.countUnbounded); | ||
86 | } | ||
87 | |||
88 | public static class Accumulator { | ||
89 | private int sumFiniteUpperBounds; | ||
90 | |||
91 | private int countUnbounded; | ||
92 | |||
93 | private Accumulator(int sumFiniteUpperBounds, int countUnbounded) { | ||
94 | this.sumFiniteUpperBounds = sumFiniteUpperBounds; | ||
95 | this.countUnbounded = countUnbounded; | ||
96 | } | ||
97 | |||
98 | private Accumulator() { | ||
99 | this(0, 0); | ||
100 | } | ||
101 | } | ||
102 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java deleted file mode 100644 index 677eeeac..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra.internal.cardinality; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
11 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
12 | |||
13 | import static org.hamcrest.MatcherAssert.assertThat; | ||
14 | import static org.hamcrest.Matchers.equalTo; | ||
15 | |||
16 | class UpperCardinalitySumAggregationOperatorTest { | ||
17 | private UpperCardinalitySumAggregationOperator.Accumulator accumulator; | ||
18 | |||
19 | @BeforeEach | ||
20 | void beforeEach() { | ||
21 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.createNeutral(); | ||
22 | } | ||
23 | |||
24 | @Test | ||
25 | void emptyAggregationTest() { | ||
26 | assertResult(UpperCardinality.of(0)); | ||
27 | } | ||
28 | |||
29 | @Test | ||
30 | void singleBoundedTest() { | ||
31 | insert(UpperCardinality.of(3)); | ||
32 | assertResult(UpperCardinality.of(3)); | ||
33 | } | ||
34 | |||
35 | @Test | ||
36 | void multipleBoundedTest() { | ||
37 | insert(UpperCardinality.of(2)); | ||
38 | insert(UpperCardinality.of(3)); | ||
39 | assertResult(UpperCardinality.of(5)); | ||
40 | } | ||
41 | |||
42 | @Test | ||
43 | void singleUnboundedTest() { | ||
44 | insert(UpperCardinalities.UNBOUNDED); | ||
45 | assertResult(UpperCardinalities.UNBOUNDED); | ||
46 | } | ||
47 | |||
48 | @Test | ||
49 | void multipleUnboundedTest() { | ||
50 | insert(UpperCardinalities.UNBOUNDED); | ||
51 | insert(UpperCardinalities.UNBOUNDED); | ||
52 | assertResult(UpperCardinalities.UNBOUNDED); | ||
53 | } | ||
54 | |||
55 | @Test | ||
56 | void removeBoundedTest() { | ||
57 | insert(UpperCardinality.of(2)); | ||
58 | insert(UpperCardinality.of(3)); | ||
59 | remove(UpperCardinality.of(2)); | ||
60 | assertResult(UpperCardinality.of(3)); | ||
61 | } | ||
62 | |||
63 | @Test | ||
64 | void removeAllUnboundedTest() { | ||
65 | insert(UpperCardinalities.UNBOUNDED); | ||
66 | insert(UpperCardinality.of(3)); | ||
67 | remove(UpperCardinalities.UNBOUNDED); | ||
68 | assertResult(UpperCardinality.of(3)); | ||
69 | } | ||
70 | |||
71 | @Test | ||
72 | void removeSomeUnboundedTest() { | ||
73 | insert(UpperCardinalities.UNBOUNDED); | ||
74 | insert(UpperCardinalities.UNBOUNDED); | ||
75 | insert(UpperCardinality.of(3)); | ||
76 | remove(UpperCardinalities.UNBOUNDED); | ||
77 | assertResult(UpperCardinalities.UNBOUNDED); | ||
78 | } | ||
79 | |||
80 | private void insert(UpperCardinality value) { | ||
81 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, true); | ||
82 | } | ||
83 | |||
84 | private void remove(UpperCardinality value) { | ||
85 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, false); | ||
86 | } | ||
87 | |||
88 | private void assertResult(UpperCardinality expected) { | ||
89 | var result = UpperCardinalitySumAggregationOperator.INSTANCE.getAggregate(accumulator); | ||
90 | assertThat(result, equalTo(expected)); | ||
91 | } | ||
92 | } | ||
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/AssumeLiteral.java index 58d563da..59538831 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/AssumeLiteral.java | |||
@@ -7,9 +7,9 @@ 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.substitution.Substitution; | 9 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.term.ConstantTerm; | ||
10 | import tools.refinery.store.query.term.Term; | 11 | import tools.refinery.store.query.term.Term; |
11 | import tools.refinery.store.query.term.Variable; | 12 | import tools.refinery.store.query.term.Variable; |
12 | import tools.refinery.store.query.term.bool.BoolConstantTerm; | ||
13 | 13 | ||
14 | import java.util.Set; | 14 | import java.util.Set; |
15 | 15 | ||
@@ -42,13 +42,12 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal { | |||
42 | 42 | ||
43 | @Override | 43 | @Override |
44 | public LiteralReduction getReduction() { | 44 | public LiteralReduction getReduction() { |
45 | if (BoolConstantTerm.TRUE.equals(term)) { | 45 | if (term instanceof ConstantTerm<Boolean> constantTerm) { |
46 | return LiteralReduction.ALWAYS_TRUE; | 46 | // Return {@code ALWAYS_FALSE} for {@code false} or {@code null} literals. |
47 | } else if (BoolConstantTerm.FALSE.equals(term)) { | 47 | return Boolean.TRUE.equals(constantTerm.getValue()) ? LiteralReduction.ALWAYS_TRUE : |
48 | return LiteralReduction.ALWAYS_FALSE; | 48 | LiteralReduction.ALWAYS_FALSE; |
49 | } else { | ||
50 | return LiteralReduction.NOT_REDUCIBLE; | ||
51 | } | 49 | } |
50 | return LiteralReduction.NOT_REDUCIBLE; | ||
52 | } | 51 | } |
53 | 52 | ||
54 | @Override | 53 | @Override |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java deleted file mode 100644 index d175130e..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.substitution; | ||
7 | |||
8 | import tools.refinery.store.query.term.Variable; | ||
9 | |||
10 | public record CompositeSubstitution(Substitution first, Substitution second) implements Substitution { | ||
11 | @Override | ||
12 | public Variable getSubstitute(Variable variable) { | ||
13 | return second.getSubstitute(first.getSubstitute(variable)); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java index 5714edf4..834fce12 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java | |||
@@ -5,7 +5,6 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.query.substitution; | 6 | package tools.refinery.store.query.substitution; |
7 | 7 | ||
8 | import tools.refinery.store.query.term.AnyDataVariable; | ||
9 | import tools.refinery.store.query.term.DataVariable; | 8 | import tools.refinery.store.query.term.DataVariable; |
10 | import tools.refinery.store.query.term.NodeVariable; | 9 | import tools.refinery.store.query.term.NodeVariable; |
11 | import tools.refinery.store.query.term.Variable; | 10 | import tools.refinery.store.query.term.Variable; |
@@ -19,16 +18,12 @@ public interface Substitution { | |||
19 | return substitute.asNodeVariable(); | 18 | return substitute.asNodeVariable(); |
20 | } | 19 | } |
21 | 20 | ||
22 | default AnyDataVariable getTypeSafeSubstitute(AnyDataVariable variable) { | ||
23 | return getTypeSafeSubstitute((DataVariable<?>) variable); | ||
24 | } | ||
25 | |||
26 | default <T> DataVariable<T> getTypeSafeSubstitute(DataVariable<T> variable) { | 21 | default <T> DataVariable<T> getTypeSafeSubstitute(DataVariable<T> variable) { |
27 | var substitute = getSubstitute(variable); | 22 | var substitute = getSubstitute(variable); |
28 | return substitute.asDataVariable(variable.getType()); | 23 | return substitute.asDataVariable(variable.getType()); |
29 | } | 24 | } |
30 | 25 | ||
31 | default Substitution andThen(Substitution second) { | 26 | static SubstitutionBuilder builder() { |
32 | return new CompositeSubstitution(this, second); | 27 | return new SubstitutionBuilder(); |
33 | } | 28 | } |
34 | } | 29 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java new file mode 100644 index 00000000..658a26e3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.substitution; | ||
7 | |||
8 | import tools.refinery.store.query.term.DataVariable; | ||
9 | import tools.refinery.store.query.term.NodeVariable; | ||
10 | import tools.refinery.store.query.term.Variable; | ||
11 | |||
12 | import java.util.Collections; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.List; | ||
15 | import java.util.Map; | ||
16 | |||
17 | @SuppressWarnings("UnusedReturnValue") | ||
18 | public class SubstitutionBuilder { | ||
19 | private final Map<Variable, Variable> map = new HashMap<>(); | ||
20 | private Substitution fallback; | ||
21 | |||
22 | SubstitutionBuilder() { | ||
23 | total(); | ||
24 | } | ||
25 | |||
26 | public SubstitutionBuilder put(NodeVariable original, NodeVariable substitute) { | ||
27 | return putChecked(original, substitute); | ||
28 | } | ||
29 | |||
30 | public <T> SubstitutionBuilder put(DataVariable<T> original, DataVariable<T> substitute) { | ||
31 | return putChecked(original, substitute); | ||
32 | } | ||
33 | |||
34 | public SubstitutionBuilder putChecked(Variable original, Variable substitute) { | ||
35 | if (!original.getSort().equals(substitute.getSort())) { | ||
36 | throw new IllegalArgumentException("Cannot substitute variable %s of sort %s with variable %s of sort %s" | ||
37 | .formatted(original, original.getSort(), substitute, substitute.getSort())); | ||
38 | } | ||
39 | if (map.containsKey(original)) { | ||
40 | throw new IllegalArgumentException("Already has substitution for variable %s".formatted(original)); | ||
41 | } | ||
42 | map.put(original, substitute); | ||
43 | return this; | ||
44 | } | ||
45 | |||
46 | public SubstitutionBuilder putManyChecked(List<Variable> originals, List<Variable> substitutes) { | ||
47 | int size = originals.size(); | ||
48 | if (size != substitutes.size()) { | ||
49 | throw new IllegalArgumentException("Cannot substitute %d variables %s with %d variables %s" | ||
50 | .formatted(size, originals, substitutes.size(), substitutes)); | ||
51 | } | ||
52 | for (int i = 0; i < size; i++) { | ||
53 | putChecked(originals.get(i), substitutes.get(i)); | ||
54 | } | ||
55 | return this; | ||
56 | } | ||
57 | |||
58 | public SubstitutionBuilder fallback(Substitution newFallback) { | ||
59 | fallback = newFallback; | ||
60 | return this; | ||
61 | } | ||
62 | |||
63 | public SubstitutionBuilder total() { | ||
64 | return fallback(StatelessSubstitution.FAILING); | ||
65 | } | ||
66 | |||
67 | public SubstitutionBuilder partial() { | ||
68 | return fallback(StatelessSubstitution.IDENTITY); | ||
69 | } | ||
70 | |||
71 | public SubstitutionBuilder renewing() { | ||
72 | return fallback(new RenewingSubstitution()); | ||
73 | } | ||
74 | |||
75 | public Substitution build() { | ||
76 | return map.isEmpty() ? fallback : new MapBasedSubstitution(Collections.unmodifiableMap(map), fallback); | ||
77 | } | ||
78 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java deleted file mode 100644 index c4791bf1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.substitution; | ||
7 | |||
8 | import org.jetbrains.annotations.NotNull; | ||
9 | import org.jetbrains.annotations.Nullable; | ||
10 | import tools.refinery.store.query.term.Variable; | ||
11 | |||
12 | import java.util.Map; | ||
13 | |||
14 | public final class Substitutions { | ||
15 | private Substitutions() { | ||
16 | throw new IllegalStateException("This is a static utility class and should not be instantiate directly"); | ||
17 | } | ||
18 | |||
19 | public static Substitution total(Map<Variable, Variable> map) { | ||
20 | return new MapBasedSubstitution(map, StatelessSubstitution.FAILING); | ||
21 | } | ||
22 | |||
23 | public static Substitution partial(Map<Variable, Variable> map) { | ||
24 | return new MapBasedSubstitution(map, StatelessSubstitution.IDENTITY); | ||
25 | } | ||
26 | |||
27 | public static Substitution renewing(Map<Variable, Variable> map) { | ||
28 | return new MapBasedSubstitution(map, renewing()); | ||
29 | } | ||
30 | |||
31 | public static Substitution renewing() { | ||
32 | return new RenewingSubstitution(); | ||
33 | } | ||
34 | |||
35 | public static Substitution compose(@Nullable Substitution first, @NotNull Substitution second) { | ||
36 | return first == null ? second : first.andThen(second); | ||
37 | } | ||
38 | } | ||
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 new file mode 100644 index 00000000..d0ae3c12 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | |||
10 | import java.util.Objects; | ||
11 | |||
12 | public abstract class AbstractTerm<T> implements Term<T> { | ||
13 | private final Class<T> type; | ||
14 | |||
15 | protected AbstractTerm(Class<T> type) { | ||
16 | this.type = type; | ||
17 | } | ||
18 | |||
19 | @Override | ||
20 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
21 | return getClass().equals(other.getClass()) && type.equals(other.getType()); | ||
22 | } | ||
23 | |||
24 | @Override | ||
25 | public Class<T> getType() { | ||
26 | return type; | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | public boolean equals(Object o) { | ||
31 | if (this == o) return true; | ||
32 | if (o == null || getClass() != o.getClass()) return false; | ||
33 | AbstractTerm<?> that = (AbstractTerm<?>) o; | ||
34 | return type.equals(that.type); | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public int hashCode() { | ||
39 | return Objects.hash(getClass(), type); | ||
40 | } | ||
41 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java deleted file mode 100644 index 5ff7c65c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | public enum ArithmeticBinaryOperator { | ||
9 | ADD("+", true), | ||
10 | SUB("-", true), | ||
11 | MUL("*", true), | ||
12 | DIV("/", true), | ||
13 | POW("**", true), | ||
14 | MIN("min", false), | ||
15 | MAX("max", false); | ||
16 | |||
17 | private final String text; | ||
18 | private final boolean infix; | ||
19 | |||
20 | ArithmeticBinaryOperator(String text, boolean infix) { | ||
21 | this.text = text; | ||
22 | this.infix = infix; | ||
23 | } | ||
24 | |||
25 | public String formatString(String left, String right) { | ||
26 | if (infix) { | ||
27 | return "(%s) %s (%s)".formatted(left, text, right); | ||
28 | } | ||
29 | return "%s(%s, %s)".formatted(text, left, right); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java deleted file mode 100644 index e405df00..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | |||
10 | import java.util.Objects; | ||
11 | |||
12 | public abstract class ArithmeticBinaryTerm<T> extends BinaryTerm<T, T, T> { | ||
13 | private final ArithmeticBinaryOperator operator; | ||
14 | |||
15 | protected ArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<T> left, Term<T> right) { | ||
16 | super(left, right); | ||
17 | this.operator = operator; | ||
18 | } | ||
19 | |||
20 | @Override | ||
21 | public Class<T> getLeftType() { | ||
22 | return getType(); | ||
23 | } | ||
24 | |||
25 | @Override | ||
26 | public Class<T> getRightType() { | ||
27 | return getType(); | ||
28 | } | ||
29 | |||
30 | public ArithmeticBinaryOperator getOperator() { | ||
31 | return operator; | ||
32 | } | ||
33 | |||
34 | @Override | ||
35 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
36 | if (!super.equalsWithSubstitution(helper, other)) { | ||
37 | return false; | ||
38 | } | ||
39 | var otherArithmeticBinaryTerm = (ArithmeticBinaryTerm<?>) other; | ||
40 | return operator == otherArithmeticBinaryTerm.operator; | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public String toString() { | ||
45 | return operator.formatString(getLeft().toString(), getRight().toString()); | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public boolean equals(Object o) { | ||
50 | if (this == o) return true; | ||
51 | if (o == null || getClass() != o.getClass()) return false; | ||
52 | if (!super.equals(o)) return false; | ||
53 | ArithmeticBinaryTerm<?> that = (ArithmeticBinaryTerm<?>) o; | ||
54 | return operator == that.operator; | ||
55 | } | ||
56 | |||
57 | @Override | ||
58 | public int hashCode() { | ||
59 | return Objects.hash(super.hashCode(), operator); | ||
60 | } | ||
61 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java deleted file mode 100644 index d98134f3..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | public enum ArithmeticUnaryOperator { | ||
9 | PLUS("+"), | ||
10 | MINUS("-"); | ||
11 | |||
12 | private final String prefix; | ||
13 | |||
14 | ArithmeticUnaryOperator(String prefix) { | ||
15 | this.prefix = prefix; | ||
16 | } | ||
17 | |||
18 | public String formatString(String body) { | ||
19 | return "%s(%s)".formatted(prefix, body); | ||
20 | } | ||
21 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java deleted file mode 100644 index bdc87545..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | |||
10 | import java.util.Objects; | ||
11 | |||
12 | public abstract class ArithmeticUnaryTerm<T> extends UnaryTerm<T, T> { | ||
13 | private final ArithmeticUnaryOperator operator; | ||
14 | |||
15 | protected ArithmeticUnaryTerm(ArithmeticUnaryOperator operator, Term<T> body) { | ||
16 | super(body); | ||
17 | this.operator = operator; | ||
18 | } | ||
19 | |||
20 | @Override | ||
21 | public Class<T> getBodyType() { | ||
22 | return getType(); | ||
23 | } | ||
24 | |||
25 | public ArithmeticUnaryOperator getOperator() { | ||
26 | return operator; | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
31 | if (!super.equalsWithSubstitution(helper, other)) { | ||
32 | return false; | ||
33 | } | ||
34 | var otherArithmeticUnaryTerm = (ArithmeticUnaryTerm<?>) other; | ||
35 | return operator == otherArithmeticUnaryTerm.operator; | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public String toString() { | ||
40 | return operator.formatString(getBody().toString()); | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public boolean equals(Object o) { | ||
45 | if (this == o) return true; | ||
46 | if (o == null || getClass() != o.getClass()) return false; | ||
47 | if (!super.equals(o)) return false; | ||
48 | ArithmeticUnaryTerm<?> that = (ArithmeticUnaryTerm<?>) o; | ||
49 | return operator == that.operator; | ||
50 | } | ||
51 | |||
52 | @Override | ||
53 | public int hashCode() { | ||
54 | return Objects.hash(super.hashCode(), operator); | ||
55 | } | ||
56 | } | ||
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 b2994d23..8ad17839 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 | |||
@@ -14,26 +14,35 @@ import java.util.HashSet; | |||
14 | import java.util.Objects; | 14 | import java.util.Objects; |
15 | import java.util.Set; | 15 | import java.util.Set; |
16 | 16 | ||
17 | public abstract class BinaryTerm<R, T1, T2> implements Term<R> { | 17 | public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> { |
18 | private final Class<T1> leftType; | ||
19 | private final Class<T2> rightType; | ||
18 | private final Term<T1> left; | 20 | private final Term<T1> left; |
19 | private final Term<T2> right; | 21 | private final Term<T2> right; |
20 | 22 | ||
21 | protected BinaryTerm(Term<T1> left, Term<T2> right) { | 23 | protected BinaryTerm(Class<R> type, Class<T1> leftType, Class<T2> rightType, Term<T1> left, Term<T2> right) { |
22 | if (!left.getType().equals(getLeftType())) { | 24 | super(type); |
23 | throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted(left, | 25 | if (!left.getType().equals(leftType)) { |
24 | getLeftType().getName(), left.getType().getName())); | 26 | throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted( |
27 | left, leftType.getName(), left.getType().getName())); | ||
25 | } | 28 | } |
26 | if (!right.getType().equals(getRightType())) { | 29 | if (!right.getType().equals(rightType)) { |
27 | throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted(right, | 30 | throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted( |
28 | getRightType().getName(), right.getType().getName())); | 31 | right, rightType.getName(), right.getType().getName())); |
29 | } | 32 | } |
33 | this.leftType = leftType; | ||
34 | this.rightType = rightType; | ||
30 | this.left = left; | 35 | this.left = left; |
31 | this.right = right; | 36 | this.right = right; |
32 | } | 37 | } |
33 | 38 | ||
34 | public abstract Class<T1> getLeftType(); | 39 | public Class<T1> getLeftType() { |
40 | return leftType; | ||
41 | } | ||
35 | 42 | ||
36 | public abstract Class<T2> getRightType(); | 43 | public Class<T2> getRightType() { |
44 | return rightType; | ||
45 | } | ||
37 | 46 | ||
38 | public Term<T1> getLeft() { | 47 | public Term<T1> getLeft() { |
39 | return left; | 48 | return left; |
@@ -60,12 +69,14 @@ public abstract class BinaryTerm<R, T1, T2> implements Term<R> { | |||
60 | 69 | ||
61 | @Override | 70 | @Override |
62 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | 71 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { |
63 | if (getClass() != other.getClass()) { | 72 | if (!super.equalsWithSubstitution(helper, other)) { |
64 | return false; | 73 | return false; |
65 | } | 74 | } |
66 | var otherBinaryTerm = (BinaryTerm<?, ?, ?>) other; | 75 | var otherBinaryTerm = (BinaryTerm<?, ?, ?>) other; |
67 | return left.equalsWithSubstitution(helper, otherBinaryTerm.left) && right.equalsWithSubstitution(helper, | 76 | return leftType.equals(otherBinaryTerm.leftType) && |
68 | otherBinaryTerm.right); | 77 | rightType.equals(otherBinaryTerm.rightType) && |
78 | left.equalsWithSubstitution(helper, otherBinaryTerm.left) && | ||
79 | right.equalsWithSubstitution(helper, otherBinaryTerm.right); | ||
69 | } | 80 | } |
70 | 81 | ||
71 | @Override | 82 | @Override |
@@ -87,12 +98,16 @@ public abstract class BinaryTerm<R, T1, T2> implements Term<R> { | |||
87 | public boolean equals(Object o) { | 98 | public boolean equals(Object o) { |
88 | if (this == o) return true; | 99 | if (this == o) return true; |
89 | if (o == null || getClass() != o.getClass()) return false; | 100 | if (o == null || getClass() != o.getClass()) return false; |
101 | if (!super.equals(o)) return false; | ||
90 | BinaryTerm<?, ?, ?> that = (BinaryTerm<?, ?, ?>) o; | 102 | BinaryTerm<?, ?, ?> that = (BinaryTerm<?, ?, ?>) o; |
91 | return left.equals(that.left) && right.equals(that.right); | 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); | ||
92 | } | 107 | } |
93 | 108 | ||
94 | @Override | 109 | @Override |
95 | public int hashCode() { | 110 | public int hashCode() { |
96 | return Objects.hash(getClass(), left, right); | 111 | return Objects.hash(super.hashCode(), leftType, rightType, left, right); |
97 | } | 112 | } |
98 | } | 113 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java deleted file mode 100644 index d04ae22c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | public enum ComparisonOperator { | ||
9 | EQ("=="), | ||
10 | NOT_EQ("!="), | ||
11 | LESS("<"), | ||
12 | LESS_EQ("<="), | ||
13 | GREATER(">"), | ||
14 | GREATER_EQ(">="); | ||
15 | |||
16 | private final String text; | ||
17 | |||
18 | ComparisonOperator(String text) { | ||
19 | this.text = text; | ||
20 | } | ||
21 | |||
22 | public String formatString(String left, String right) { | ||
23 | return "(%s) %s (%s)".formatted(left, text, right); | ||
24 | } | ||
25 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java deleted file mode 100644 index 2c304aef..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | |||
10 | import java.util.Objects; | ||
11 | |||
12 | public abstract class ComparisonTerm<T> extends BinaryTerm<Boolean, T, T> { | ||
13 | private final ComparisonOperator operator; | ||
14 | |||
15 | protected ComparisonTerm(ComparisonOperator operator, Term<T> left, Term<T> right) { | ||
16 | super(left, right); | ||
17 | this.operator = operator; | ||
18 | } | ||
19 | |||
20 | @Override | ||
21 | public Class<Boolean> getType() { | ||
22 | return Boolean.class; | ||
23 | } | ||
24 | |||
25 | public abstract Class<T> getOperandType(); | ||
26 | |||
27 | @Override | ||
28 | public Class<T> getLeftType() { | ||
29 | return getOperandType(); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Class<T> getRightType() { | ||
34 | return getOperandType(); | ||
35 | } | ||
36 | |||
37 | public ComparisonOperator getOperator() { | ||
38 | return operator; | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
43 | if (!super.equalsWithSubstitution(helper, other)) { | ||
44 | return false; | ||
45 | } | ||
46 | var otherComparisonTerm = (ComparisonTerm<?>) other; | ||
47 | return operator == otherComparisonTerm.operator; | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public String toString() { | ||
52 | return operator.formatString(getLeft().toString(), getRight().toString()); | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public boolean equals(Object o) { | ||
57 | if (this == o) return true; | ||
58 | if (o == null || getClass() != o.getClass()) return false; | ||
59 | if (!super.equals(o)) return false; | ||
60 | ComparisonTerm<?> that = (ComparisonTerm<?>) o; | ||
61 | return operator == that.operator; | ||
62 | } | ||
63 | |||
64 | @Override | ||
65 | public int hashCode() { | ||
66 | return Objects.hash(super.hashCode(), operator); | ||
67 | } | ||
68 | } | ||
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 b03f07fd..2f6c56d1 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 | |||
@@ -9,21 +9,18 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; | |||
9 | import tools.refinery.store.query.substitution.Substitution; | 9 | import tools.refinery.store.query.substitution.Substitution; |
10 | import tools.refinery.store.query.valuation.Valuation; | 10 | import tools.refinery.store.query.valuation.Valuation; |
11 | 11 | ||
12 | import java.util.Objects; | ||
12 | import java.util.Set; | 13 | import java.util.Set; |
13 | 14 | ||
14 | public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> { | 15 | public final class ConstantTerm<T> extends AbstractTerm<T> { |
15 | public ConstantTerm { | 16 | private final T value; |
16 | if (value == null) { | ||
17 | throw new IllegalArgumentException("value should not be null"); | ||
18 | } | ||
19 | if (!type.isInstance(value)) { | ||
20 | throw new IllegalArgumentException("value %s is not an instance of %s".formatted(value, type.getName())); | ||
21 | } | ||
22 | } | ||
23 | 17 | ||
24 | @Override | 18 | public ConstantTerm(Class<T> type, T value) { |
25 | public Class<T> getType() { | 19 | super(type); |
26 | return type; | 20 | if (value != null && !type.isInstance(value)) { |
21 | throw new IllegalArgumentException("Value %s is not an instance of %s".formatted(value, type.getName())); | ||
22 | } | ||
23 | this.value = value; | ||
27 | } | 24 | } |
28 | 25 | ||
29 | public T getValue() { | 26 | public T getValue() { |
@@ -42,7 +39,11 @@ public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> { | |||
42 | 39 | ||
43 | @Override | 40 | @Override |
44 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | 41 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { |
45 | return equals(other); | 42 | if (!super.equalsWithSubstitution(helper, other)) { |
43 | return false; | ||
44 | } | ||
45 | var otherConstantTerm = (ConstantTerm<?>) other; | ||
46 | return Objects.equals(value, otherConstantTerm.value); | ||
46 | } | 47 | } |
47 | 48 | ||
48 | @Override | 49 | @Override |
@@ -52,6 +53,19 @@ public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> { | |||
52 | 53 | ||
53 | @Override | 54 | @Override |
54 | public String toString() { | 55 | public String toString() { |
55 | return getValue().toString(); | 56 | return value.toString(); |
57 | } | ||
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); | ||
56 | } | 70 | } |
57 | } | 71 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java deleted file mode 100644 index 6626365f..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | ||
10 | import tools.refinery.store.query.substitution.Substitutions; | ||
11 | import tools.refinery.store.query.valuation.Valuation; | ||
12 | |||
13 | import java.util.Objects; | ||
14 | import java.util.Set; | ||
15 | import java.util.function.Function; | ||
16 | import java.util.stream.Collectors; | ||
17 | |||
18 | public final class OpaqueTerm<T> implements Term<T> { | ||
19 | private final Class<T> type; | ||
20 | private final Function<? super Valuation, ? extends T> evaluator; | ||
21 | private final Set<AnyDataVariable> variables; | ||
22 | private final Substitution substitution; | ||
23 | |||
24 | public OpaqueTerm(Class<T> type, Function<? super Valuation, ? extends T> evaluator, | ||
25 | Set<? extends AnyDataVariable> variables) { | ||
26 | this(type, evaluator, variables, null); | ||
27 | } | ||
28 | |||
29 | private OpaqueTerm(Class<T> type, Function<? super Valuation, ? extends T> evaluator, | ||
30 | Set<? extends AnyDataVariable> variables, Substitution substitution) { | ||
31 | this.type = type; | ||
32 | this.evaluator = evaluator; | ||
33 | this.variables = Set.copyOf(variables); | ||
34 | this.substitution = substitution; | ||
35 | } | ||
36 | |||
37 | @Override | ||
38 | public Class<T> getType() { | ||
39 | return type; | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public Set<AnyDataVariable> getInputVariables() { | ||
44 | return variables; | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public T evaluate(Valuation valuation) { | ||
49 | return evaluator.apply(valuation.substitute(substitution)); | ||
50 | } | ||
51 | |||
52 | @Override | ||
53 | public Term<T> substitute(Substitution newSubstitution) { | ||
54 | var substitutedVariables = variables.stream() | ||
55 | .map(newSubstitution::getTypeSafeSubstitute) | ||
56 | .collect(Collectors.toUnmodifiableSet()); | ||
57 | return new OpaqueTerm<>(type, evaluator, substitutedVariables, | ||
58 | Substitutions.compose(substitution, newSubstitution)); | ||
59 | } | ||
60 | |||
61 | @Override | ||
62 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
63 | // Cannot inspect the opaque evaluator for deep equality. | ||
64 | return equals(other); | ||
65 | } | ||
66 | |||
67 | @Override | ||
68 | public String toString() { | ||
69 | return "<opaque>"; | ||
70 | } | ||
71 | |||
72 | @Override | ||
73 | public boolean equals(Object o) { | ||
74 | if (this == o) return true; | ||
75 | if (o == null || getClass() != o.getClass()) return false; | ||
76 | OpaqueTerm<?> that = (OpaqueTerm<?>) o; | ||
77 | return type.equals(that.type) && evaluator.equals(that.evaluator) && Objects.equals(substitution, | ||
78 | that.substitution); | ||
79 | } | ||
80 | |||
81 | @Override | ||
82 | public int hashCode() { | ||
83 | return Objects.hash(type, evaluator, substitution); | ||
84 | } | ||
85 | } | ||
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 069e0d95..a46ebe31 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 | |||
@@ -12,18 +12,23 @@ import tools.refinery.store.query.valuation.Valuation; | |||
12 | import java.util.Objects; | 12 | import java.util.Objects; |
13 | import java.util.Set; | 13 | import java.util.Set; |
14 | 14 | ||
15 | public abstract class UnaryTerm<R, T> implements Term<R> { | 15 | public abstract class UnaryTerm<R, T> extends AbstractTerm<R> { |
16 | private final Class<T> bodyType; | ||
16 | private final Term<T> body; | 17 | private final Term<T> body; |
17 | 18 | ||
18 | protected UnaryTerm(Term<T> body) { | 19 | protected UnaryTerm(Class<R> type, Class<T> bodyType, Term<T> body) { |
19 | if (!body.getType().equals(getBodyType())) { | 20 | super(type); |
21 | if (!body.getType().equals(bodyType)) { | ||
20 | throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body, | 22 | throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body, |
21 | getBodyType().getName(), body.getType().getName())); | 23 | bodyType.getName(), body.getType().getName())); |
22 | } | 24 | } |
25 | this.bodyType = bodyType; | ||
23 | this.body = body; | 26 | this.body = body; |
24 | } | 27 | } |
25 | 28 | ||
26 | public abstract Class<T> getBodyType(); | 29 | public Class<T> getBodyType() { |
30 | return bodyType; | ||
31 | } | ||
27 | 32 | ||
28 | public Term<T> getBody() { | 33 | public Term<T> getBody() { |
29 | return body; | 34 | return body; |
@@ -39,11 +44,11 @@ public abstract class UnaryTerm<R, T> implements Term<R> { | |||
39 | 44 | ||
40 | @Override | 45 | @Override |
41 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | 46 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { |
42 | if (getClass() != other.getClass()) { | 47 | if (!super.equalsWithSubstitution(helper, other)) { |
43 | return false; | 48 | return false; |
44 | } | 49 | } |
45 | var otherUnaryTerm = (UnaryTerm<?, ?>) other; | 50 | var otherUnaryTerm = (UnaryTerm<?, ?>) other; |
46 | return body.equalsWithSubstitution(helper, otherUnaryTerm.body); | 51 | return bodyType.equals(otherUnaryTerm.bodyType) && body.equalsWithSubstitution(helper, otherUnaryTerm.body); |
47 | } | 52 | } |
48 | 53 | ||
49 | @Override | 54 | @Override |
@@ -62,12 +67,13 @@ public abstract class UnaryTerm<R, T> implements Term<R> { | |||
62 | public boolean equals(Object o) { | 67 | public boolean equals(Object o) { |
63 | if (this == o) return true; | 68 | if (this == o) return true; |
64 | if (o == null || getClass() != o.getClass()) return false; | 69 | if (o == null || getClass() != o.getClass()) return false; |
70 | if (!super.equals(o)) return false; | ||
65 | UnaryTerm<?, ?> unaryTerm = (UnaryTerm<?, ?>) o; | 71 | UnaryTerm<?, ?> unaryTerm = (UnaryTerm<?, ?>) o; |
66 | return body.equals(unaryTerm.body); | 72 | return Objects.equals(bodyType, unaryTerm.bodyType) && Objects.equals(body, unaryTerm.body); |
67 | } | 73 | } |
68 | 74 | ||
69 | @Override | 75 | @Override |
70 | public int hashCode() { | 76 | public int hashCode() { |
71 | return Objects.hash(getClass(), body); | 77 | return Objects.hash(super.hashCode(), bodyType, body); |
72 | } | 78 | } |
73 | } | 79 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java new file mode 100644 index 00000000..f9e1c06f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class BoolAndTerm extends BoolBinaryTerm { | ||
12 | public BoolAndTerm(Term<Boolean> left, Term<Boolean> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft, | ||
18 | Term<Boolean> substitutedRight) { | ||
19 | return new BoolAndTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { | ||
24 | return leftValue && rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s && %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java new file mode 100644 index 00000000..a85aa63a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.term.BinaryTerm; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public abstract class BoolBinaryTerm extends BinaryTerm<Boolean, Boolean, Boolean> { | ||
12 | protected BoolBinaryTerm(Term<Boolean> left, Term<Boolean> right) { | ||
13 | super(Boolean.class, Boolean.class, Boolean.class, left, right); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java deleted file mode 100644 index e5690ab6..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.term.ConstantTerm; | ||
9 | |||
10 | public final class BoolConstantTerm { | ||
11 | public static final ConstantTerm<Boolean> TRUE = new ConstantTerm<>(Boolean.class, true); | ||
12 | public static final ConstantTerm<Boolean> FALSE = new ConstantTerm<>(Boolean.class, false); | ||
13 | |||
14 | private BoolConstantTerm() { | ||
15 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
16 | } | ||
17 | |||
18 | public static ConstantTerm<Boolean> valueOf(boolean boolValue) { | ||
19 | return boolValue ? TRUE : FALSE; | ||
20 | } | ||
21 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java deleted file mode 100644 index 11e764c2..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java +++ /dev/null | |||
@@ -1,83 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
9 | import tools.refinery.store.query.substitution.Substitution; | ||
10 | import tools.refinery.store.query.term.*; | ||
11 | |||
12 | import java.util.Objects; | ||
13 | |||
14 | public class BoolLogicBinaryTerm extends BinaryTerm<Boolean, Boolean, Boolean> { | ||
15 | private final LogicBinaryOperator operator; | ||
16 | |||
17 | protected BoolLogicBinaryTerm(LogicBinaryOperator operator, Term<Boolean> left, Term<Boolean> right) { | ||
18 | super(left, right); | ||
19 | this.operator = operator; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Class<Boolean> getType() { | ||
24 | return Boolean.class; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public Class<Boolean> getLeftType() { | ||
29 | return getType(); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Class<Boolean> getRightType() { | ||
34 | return getType(); | ||
35 | } | ||
36 | |||
37 | public LogicBinaryOperator getOperator() { | ||
38 | return operator; | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { | ||
43 | if (!super.equalsWithSubstitution(helper, other)) { | ||
44 | return false; | ||
45 | } | ||
46 | var otherBoolLogicBinaryTerm = (BoolLogicBinaryTerm) other; | ||
47 | return operator == otherBoolLogicBinaryTerm.operator; | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft, | ||
52 | Term<Boolean> substitutedRight) { | ||
53 | return new BoolLogicBinaryTerm(getOperator(), substitutedLeft, substitutedRight); | ||
54 | } | ||
55 | |||
56 | @Override | ||
57 | protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { | ||
58 | return switch (getOperator()) { | ||
59 | case AND -> leftValue && rightValue; | ||
60 | case OR -> leftValue || rightValue; | ||
61 | case XOR -> leftValue ^ rightValue; | ||
62 | }; | ||
63 | } | ||
64 | |||
65 | @Override | ||
66 | public String toString() { | ||
67 | return operator.formatString(getLeft().toString(), getRight().toString()); | ||
68 | } | ||
69 | |||
70 | @Override | ||
71 | public boolean equals(Object o) { | ||
72 | if (this == o) return true; | ||
73 | if (o == null || getClass() != o.getClass()) return false; | ||
74 | if (!super.equals(o)) return false; | ||
75 | BoolLogicBinaryTerm that = (BoolLogicBinaryTerm) o; | ||
76 | return operator == that.operator; | ||
77 | } | ||
78 | |||
79 | @Override | ||
80 | public int hashCode() { | ||
81 | return Objects.hash(super.hashCode(), operator); | ||
82 | } | ||
83 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java index bb06cf8b..8d3382b3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java | |||
@@ -11,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm; | |||
11 | 11 | ||
12 | public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> { | 12 | public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> { |
13 | protected BoolNotTerm(Term<Boolean> body) { | 13 | protected BoolNotTerm(Term<Boolean> body) { |
14 | super(body); | 14 | super(Boolean.class, Boolean.class, body); |
15 | } | ||
16 | |||
17 | @Override | ||
18 | public Class<Boolean> getType() { | ||
19 | return Boolean.class; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Class<Boolean> getBodyType() { | ||
24 | return getType(); | ||
25 | } | 15 | } |
26 | 16 | ||
27 | @Override | 17 | @Override |
@@ -36,6 +26,6 @@ public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> { | |||
36 | 26 | ||
37 | @Override | 27 | @Override |
38 | public String toString() { | 28 | public String toString() { |
39 | return "!(%s)".formatted(getBody()); | 29 | return "(!%s)".formatted(getBody()); |
40 | } | 30 | } |
41 | } | 31 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java new file mode 100644 index 00000000..b5195d52 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class BoolOrTerm extends BoolBinaryTerm { | ||
12 | public BoolOrTerm(Term<Boolean> left, Term<Boolean> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft, | ||
18 | Term<Boolean> substitutedRight) { | ||
19 | return new BoolOrTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { | ||
24 | return leftValue || rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s || %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java index 55825952..fa54f686 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java | |||
@@ -13,23 +13,23 @@ public final class BoolTerms { | |||
13 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); | 13 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); |
14 | } | 14 | } |
15 | 15 | ||
16 | public static ConstantTerm<Boolean> constant(boolean value) { | 16 | public static Term<Boolean> constant(Boolean value) { |
17 | return BoolConstantTerm.valueOf(value); | 17 | return new ConstantTerm<>(Boolean.class, value); |
18 | } | 18 | } |
19 | 19 | ||
20 | public static BoolNotTerm not(Term<Boolean> body) { | 20 | public static Term<Boolean> not(Term<Boolean> body) { |
21 | return new BoolNotTerm(body); | 21 | return new BoolNotTerm(body); |
22 | } | 22 | } |
23 | 23 | ||
24 | public static BoolLogicBinaryTerm and(Term<Boolean> left, Term<Boolean> right) { | 24 | public static Term<Boolean> and(Term<Boolean> left, Term<Boolean> right) { |
25 | return new BoolLogicBinaryTerm(LogicBinaryOperator.AND, left, right); | 25 | return new BoolAndTerm(left, right); |
26 | } | 26 | } |
27 | 27 | ||
28 | public static BoolLogicBinaryTerm or(Term<Boolean> left, Term<Boolean> right) { | 28 | public static Term<Boolean> or(Term<Boolean> left, Term<Boolean> right) { |
29 | return new BoolLogicBinaryTerm(LogicBinaryOperator.OR, left, right); | 29 | return new BoolOrTerm(left, right); |
30 | } | 30 | } |
31 | 31 | ||
32 | public static BoolLogicBinaryTerm xor(Term<Boolean> left, Term<Boolean> right) { | 32 | public static Term<Boolean> xor(Term<Boolean> left, Term<Boolean> right) { |
33 | return new BoolLogicBinaryTerm(LogicBinaryOperator.XOR, left, right); | 33 | return new BoolXorTerm(left, right); |
34 | } | 34 | } |
35 | } | 35 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java new file mode 100644 index 00000000..7478b8a5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class BoolXorTerm extends BoolBinaryTerm { | ||
12 | public BoolXorTerm(Term<Boolean> left, Term<Boolean> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft, | ||
18 | Term<Boolean> substitutedRight) { | ||
19 | return new BoolXorTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { | ||
24 | return leftValue ^ rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s ^^ %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java deleted file mode 100644 index 93a72f88..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | public enum LogicBinaryOperator { | ||
9 | AND("&&"), | ||
10 | OR("||"), | ||
11 | XOR("^^"); | ||
12 | |||
13 | private final String text; | ||
14 | |||
15 | LogicBinaryOperator(String text) { | ||
16 | this.text = text; | ||
17 | } | ||
18 | |||
19 | public String formatString(String left, String right) { | ||
20 | return "(%s) %s (%s)".formatted(left, text, right); | ||
21 | } | ||
22 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java new file mode 100644 index 00000000..5ca5a0a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.term.BinaryTerm; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public abstract class ComparisonTerm<T> extends BinaryTerm<Boolean, T, T> { | ||
12 | protected ComparisonTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(Boolean.class, argumentType, argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | public Class<T> getArgumentType() { | ||
17 | return getLeftType(); | ||
18 | } | ||
19 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java new file mode 100644 index 00000000..b8cf36f8 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class EqTerm<T> extends ComparisonTerm<T> { | ||
12 | public EqTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return leftValue.equals(rightValue); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new EqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s == %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java new file mode 100644 index 00000000..b109eb1a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class GreaterEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> { | ||
12 | public GreaterEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return leftValue.compareTo(rightValue) >= 0; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new GreaterEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s >= %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java new file mode 100644 index 00000000..1b67f8b5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class GreaterTerm<T extends Comparable<T>> extends ComparisonTerm<T> { | ||
12 | public GreaterTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return leftValue.compareTo(rightValue) > 0; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new GreaterTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s > %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java new file mode 100644 index 00000000..1b34535f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class LessEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> { | ||
12 | public LessEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return leftValue.compareTo(rightValue) <= 0; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new LessEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s <= %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java new file mode 100644 index 00000000..44e70902 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class LessTerm<T extends Comparable<T>> extends ComparisonTerm<T> { | ||
12 | public LessTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return leftValue.compareTo(rightValue) < 0; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new LessTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s < %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java new file mode 100644 index 00000000..1f9734c4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.comparable; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class NotEqTerm<T> extends ComparisonTerm<T> { | ||
12 | public NotEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) { | ||
13 | super(argumentType, left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Boolean doEvaluate(T leftValue, T rightValue) { | ||
18 | return !leftValue.equals(rightValue); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) { | ||
23 | return new NotEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(%s != %s)".formatted(getLeft(), getRight()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java new file mode 100644 index 00000000..dbea3efc --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntAddTerm extends IntBinaryTerm { | ||
12 | public IntAddTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntAddTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return leftValue + rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s + %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java deleted file mode 100644 index 8a76ecbd..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.ArithmeticBinaryOperator; | ||
10 | import tools.refinery.store.query.term.ArithmeticBinaryTerm; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | |||
13 | public class IntArithmeticBinaryTerm extends ArithmeticBinaryTerm<Integer> { | ||
14 | public IntArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<Integer> left, Term<Integer> right) { | ||
15 | super(operator, left, right); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public Class<Integer> getType() { | ||
20 | return Integer.class; | ||
21 | } | ||
22 | |||
23 | @Override | ||
24 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
25 | Term<Integer> substitutedRight) { | ||
26 | return new IntArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
31 | return switch (getOperator()) { | ||
32 | case ADD -> leftValue + rightValue; | ||
33 | case SUB -> leftValue - rightValue; | ||
34 | case MUL -> leftValue * rightValue; | ||
35 | case DIV -> rightValue == 0 ? null : leftValue / rightValue; | ||
36 | case POW -> rightValue < 0 ? null : power(leftValue, rightValue); | ||
37 | case MIN -> Math.min(leftValue, rightValue); | ||
38 | case MAX -> Math.max(leftValue, rightValue); | ||
39 | }; | ||
40 | } | ||
41 | |||
42 | private static int power(int base, int exponent) { | ||
43 | int accum = 1; | ||
44 | while (exponent > 0) { | ||
45 | if (exponent % 2 == 1) { | ||
46 | accum = accum * base; | ||
47 | } | ||
48 | base = base * base; | ||
49 | exponent = exponent / 2; | ||
50 | } | ||
51 | return accum; | ||
52 | } | ||
53 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java deleted file mode 100644 index 8522f2c1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.query.term.ArithmeticUnaryOperator; | ||
11 | import tools.refinery.store.query.term.ArithmeticUnaryTerm; | ||
12 | |||
13 | public class IntArithmeticUnaryTerm extends ArithmeticUnaryTerm<Integer> { | ||
14 | public IntArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term<Integer> body) { | ||
15 | super(operation, body); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public Class<Integer> getType() { | ||
20 | return Integer.class; | ||
21 | } | ||
22 | |||
23 | @Override | ||
24 | protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) { | ||
25 | return new IntArithmeticUnaryTerm(getOperator(), substitutedBody); | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | protected Integer doEvaluate(Integer bodyValue) { | ||
30 | return switch(getOperator()) { | ||
31 | case PLUS -> bodyValue; | ||
32 | case MINUS -> -bodyValue; | ||
33 | }; | ||
34 | } | ||
35 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java new file mode 100644 index 00000000..27ced4e4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.term.BinaryTerm; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public abstract class IntBinaryTerm extends BinaryTerm<Integer, Integer, Integer> { | ||
12 | protected IntBinaryTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(Integer.class, Integer.class, Integer.class, left, right); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java deleted file mode 100644 index 2ce2b2f3..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | import tools.refinery.store.query.substitution.Substitution; | ||
8 | import tools.refinery.store.query.term.ComparisonOperator; | ||
9 | import tools.refinery.store.query.term.ComparisonTerm; | ||
10 | import tools.refinery.store.query.term.Term; | ||
11 | |||
12 | public class IntComparisonTerm extends ComparisonTerm<Integer> { | ||
13 | public IntComparisonTerm(ComparisonOperator operator, Term<Integer> left, Term<Integer> right) { | ||
14 | super(operator, left, right); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | public Class<Integer> getOperandType() { | ||
19 | return Integer.class; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
24 | Term<Integer> substitutedRight) { | ||
25 | return new IntComparisonTerm(getOperator(), substitutedLeft, substitutedRight); | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | protected Boolean doEvaluate(Integer leftValue, Integer rightValue) { | ||
30 | return switch (getOperator()) { | ||
31 | case EQ -> leftValue.equals(rightValue); | ||
32 | case NOT_EQ -> !leftValue.equals(rightValue); | ||
33 | case LESS -> leftValue < rightValue; | ||
34 | case LESS_EQ -> leftValue <= rightValue; | ||
35 | case GREATER -> leftValue > rightValue; | ||
36 | case GREATER_EQ -> leftValue >= rightValue; | ||
37 | }; | ||
38 | } | ||
39 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java new file mode 100644 index 00000000..2a35058c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntDivTerm extends IntBinaryTerm { | ||
12 | public IntDivTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntDivTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return rightValue == 0 ? null : leftValue / rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s / %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java deleted file mode 100644 index 7982f45c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.term.ExtremeValueAggregator; | ||
9 | |||
10 | import java.util.Comparator; | ||
11 | |||
12 | public final class IntExtremeValueAggregator { | ||
13 | public static final ExtremeValueAggregator<Integer> MINIMUM = new ExtremeValueAggregator<>(Integer.class, | ||
14 | Integer.MAX_VALUE); | ||
15 | |||
16 | public static final ExtremeValueAggregator<Integer> MAXIMUM = new ExtremeValueAggregator<>(Integer.class, | ||
17 | Integer.MIN_VALUE, Comparator.reverseOrder()); | ||
18 | |||
19 | private IntExtremeValueAggregator() { | ||
20 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
21 | } | ||
22 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java new file mode 100644 index 00000000..f81fc509 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntMaxTerm extends IntBinaryTerm { | ||
12 | public IntMaxTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntMaxTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return Math.max(rightValue, leftValue); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "max(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java new file mode 100644 index 00000000..89182e26 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntMinTerm extends IntBinaryTerm { | ||
12 | public IntMinTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntMinTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return Math.min(rightValue, leftValue); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "min(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java new file mode 100644 index 00000000..709aa5ba --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntMinusTerm extends IntUnaryTerm { | ||
12 | public IntMinusTerm(Term<Integer> body) { | ||
13 | super(body); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) { | ||
18 | return new IntMinusTerm(substitutedBody); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | protected Integer doEvaluate(Integer bodyValue) { | ||
23 | return -bodyValue; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(-%s)".formatted(getBody()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java new file mode 100644 index 00000000..89d4c5f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntMulTerm extends IntBinaryTerm { | ||
12 | public IntMulTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntMulTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return leftValue * rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s * %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java new file mode 100644 index 00000000..aef83bb4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntPlusTerm extends IntUnaryTerm { | ||
12 | public IntPlusTerm(Term<Integer> body) { | ||
13 | super(body); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) { | ||
18 | return new IntPlusTerm(substitutedBody); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | protected Integer doEvaluate(Integer bodyValue) { | ||
23 | return bodyValue; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(+%s)".formatted(getBody()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java new file mode 100644 index 00000000..d5af97a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntPowTerm extends IntBinaryTerm { | ||
12 | public IntPowTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntPowTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return rightValue < 0 ? null : power(leftValue, rightValue); | ||
25 | } | ||
26 | |||
27 | private static int power(int base, int exponent) { | ||
28 | int accum = 1; | ||
29 | while (exponent > 0) { | ||
30 | if (exponent % 2 == 1) { | ||
31 | accum = accum * base; | ||
32 | } | ||
33 | base = base * base; | ||
34 | exponent = exponent / 2; | ||
35 | } | ||
36 | return accum; | ||
37 | } | ||
38 | |||
39 | @Override | ||
40 | public String toString() { | ||
41 | return "(%s ** %s)".formatted(getLeft(), getRight()); | ||
42 | } | ||
43 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java new file mode 100644 index 00000000..2c27afb1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class IntSubTerm extends IntBinaryTerm { | ||
12 | public IntSubTerm(Term<Integer> left, Term<Integer> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft, | ||
18 | Term<Integer> substitutedRight) { | ||
19 | return new IntSubTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Integer doEvaluate(Integer leftValue, Integer rightValue) { | ||
24 | return leftValue - rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s - %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java index 38f7f449..acb98b94 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java | |||
@@ -5,82 +5,90 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.query.term.int_; | 6 | package tools.refinery.store.query.term.int_; |
7 | 7 | ||
8 | import tools.refinery.store.query.term.*; | 8 | import tools.refinery.store.query.term.Aggregator; |
9 | import tools.refinery.store.query.term.ConstantTerm; | ||
10 | import tools.refinery.store.query.term.ExtremeValueAggregator; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | import tools.refinery.store.query.term.comparable.*; | ||
13 | |||
14 | import java.util.Comparator; | ||
9 | 15 | ||
10 | public final class IntTerms { | 16 | public final class IntTerms { |
11 | public static final Aggregator<Integer, Integer> INT_SUM = IntSumAggregator.INSTANCE; | 17 | public static final Aggregator<Integer, Integer> INT_SUM = IntSumAggregator.INSTANCE; |
12 | public static final Aggregator<Integer, Integer> INT_MIN = IntExtremeValueAggregator.MINIMUM; | 18 | public static final Aggregator<Integer, Integer> INT_MIN = new ExtremeValueAggregator<>(Integer.class, |
13 | public static final Aggregator<Integer, Integer> INT_MAX = IntExtremeValueAggregator.MAXIMUM; | 19 | Integer.MAX_VALUE); |
20 | public static final Aggregator<Integer, Integer> INT_MAX = new ExtremeValueAggregator<>(Integer.class, | ||
21 | Integer.MIN_VALUE, Comparator.reverseOrder()); | ||
14 | 22 | ||
15 | private IntTerms() { | 23 | private IntTerms() { |
16 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); | 24 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); |
17 | } | 25 | } |
18 | 26 | ||
19 | public static ConstantTerm<Integer> constant(int value) { | 27 | public static Term<Integer> constant(Integer value) { |
20 | return new ConstantTerm<>(Integer.class, value); | 28 | return new ConstantTerm<>(Integer.class, value); |
21 | } | 29 | } |
22 | 30 | ||
23 | public static IntArithmeticUnaryTerm plus(Term<Integer> body) { | 31 | public static Term<Integer> plus(Term<Integer> body) { |
24 | return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); | 32 | return new IntPlusTerm(body); |
25 | } | 33 | } |
26 | 34 | ||
27 | public static IntArithmeticUnaryTerm minus(Term<Integer> body) { | 35 | public static Term<Integer> minus(Term<Integer> body) { |
28 | return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); | 36 | return new IntMinusTerm(body); |
29 | } | 37 | } |
30 | 38 | ||
31 | public static IntArithmeticBinaryTerm add(Term<Integer> left, Term<Integer> right) { | 39 | public static Term<Integer> add(Term<Integer> left, Term<Integer> right) { |
32 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); | 40 | return new IntAddTerm(left, right); |
33 | } | 41 | } |
34 | 42 | ||
35 | public static IntArithmeticBinaryTerm sub(Term<Integer> left, Term<Integer> right) { | 43 | public static Term<Integer> sub(Term<Integer> left, Term<Integer> right) { |
36 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); | 44 | return new IntSubTerm(left, right); |
37 | } | 45 | } |
38 | 46 | ||
39 | public static IntArithmeticBinaryTerm mul(Term<Integer> left, Term<Integer> right) { | 47 | public static Term<Integer> mul(Term<Integer> left, Term<Integer> right) { |
40 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); | 48 | return new IntMulTerm(left, right); |
41 | } | 49 | } |
42 | 50 | ||
43 | public static IntArithmeticBinaryTerm div(Term<Integer> left, Term<Integer> right) { | 51 | public static Term<Integer> div(Term<Integer> left, Term<Integer> right) { |
44 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); | 52 | return new IntDivTerm(left, right); |
45 | } | 53 | } |
46 | 54 | ||
47 | public static IntArithmeticBinaryTerm pow(Term<Integer> left, Term<Integer> right) { | 55 | public static Term<Integer> pow(Term<Integer> left, Term<Integer> right) { |
48 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); | 56 | return new IntPowTerm(left, right); |
49 | } | 57 | } |
50 | 58 | ||
51 | public static IntArithmeticBinaryTerm min(Term<Integer> left, Term<Integer> right) { | 59 | public static Term<Integer> min(Term<Integer> left, Term<Integer> right) { |
52 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); | 60 | return new IntMinTerm(left, right); |
53 | } | 61 | } |
54 | 62 | ||
55 | public static IntArithmeticBinaryTerm max(Term<Integer> left, Term<Integer> right) { | 63 | public static Term<Integer> max(Term<Integer> left, Term<Integer> right) { |
56 | return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); | 64 | return new IntMaxTerm(left, right); |
57 | } | 65 | } |
58 | 66 | ||
59 | public static IntComparisonTerm eq(Term<Integer> left, Term<Integer> right) { | 67 | public static Term<Boolean> eq(Term<Integer> left, Term<Integer> right) { |
60 | return new IntComparisonTerm(ComparisonOperator.EQ, left, right); | 68 | return new EqTerm<>(Integer.class, left, right); |
61 | } | 69 | } |
62 | 70 | ||
63 | public static IntComparisonTerm notEq(Term<Integer> left, Term<Integer> right) { | 71 | public static Term<Boolean> notEq(Term<Integer> left, Term<Integer> right) { |
64 | return new IntComparisonTerm(ComparisonOperator.NOT_EQ, left, right); | 72 | return new NotEqTerm<>(Integer.class, left, right); |
65 | } | 73 | } |
66 | 74 | ||
67 | public static IntComparisonTerm less(Term<Integer> left, Term<Integer> right) { | 75 | public static Term<Boolean> less(Term<Integer> left, Term<Integer> right) { |
68 | return new IntComparisonTerm(ComparisonOperator.LESS, left, right); | 76 | return new LessTerm<>(Integer.class, left, right); |
69 | } | 77 | } |
70 | 78 | ||
71 | public static IntComparisonTerm lessEq(Term<Integer> left, Term<Integer> right) { | 79 | public static Term<Boolean> lessEq(Term<Integer> left, Term<Integer> right) { |
72 | return new IntComparisonTerm(ComparisonOperator.LESS_EQ, left, right); | 80 | return new LessEqTerm<>(Integer.class, left, right); |
73 | } | 81 | } |
74 | 82 | ||
75 | public static IntComparisonTerm greater(Term<Integer> left, Term<Integer> right) { | 83 | public static Term<Boolean> greater(Term<Integer> left, Term<Integer> right) { |
76 | return new IntComparisonTerm(ComparisonOperator.GREATER, left, right); | 84 | return new GreaterTerm<>(Integer.class, left, right); |
77 | } | 85 | } |
78 | 86 | ||
79 | public static IntComparisonTerm greaterEq(Term<Integer> left, Term<Integer> right) { | 87 | public static Term<Boolean> greaterEq(Term<Integer> left, Term<Integer> right) { |
80 | return new IntComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); | 88 | return new GreaterEqTerm<>(Integer.class, left, right); |
81 | } | 89 | } |
82 | 90 | ||
83 | public static RealToIntTerm asInt(Term<Double> body) { | 91 | public static Term<Integer> asInt(Term<Double> body) { |
84 | return new RealToIntTerm(body); | 92 | return new RealToIntTerm(body); |
85 | } | 93 | } |
86 | } | 94 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java new file mode 100644 index 00000000..49b4c647 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import tools.refinery.store.query.term.Term; | ||
9 | import tools.refinery.store.query.term.UnaryTerm; | ||
10 | |||
11 | public abstract class IntUnaryTerm extends UnaryTerm<Integer, Integer> { | ||
12 | protected IntUnaryTerm(Term<Integer> body) { | ||
13 | super(Integer.class, Integer.class, body); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java index 399adf4a..7d383562 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java | |||
@@ -11,22 +11,12 @@ import tools.refinery.store.query.term.UnaryTerm; | |||
11 | 11 | ||
12 | public class RealToIntTerm extends UnaryTerm<Integer, Double> { | 12 | public class RealToIntTerm extends UnaryTerm<Integer, Double> { |
13 | protected RealToIntTerm(Term<Double> body) { | 13 | protected RealToIntTerm(Term<Double> body) { |
14 | super(body); | 14 | super(Integer.class, Double.class, body); |
15 | } | ||
16 | |||
17 | @Override | ||
18 | public Class<Integer> getType() { | ||
19 | return Integer.class; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Class<Double> getBodyType() { | ||
24 | return Double.class; | ||
25 | } | 15 | } |
26 | 16 | ||
27 | @Override | 17 | @Override |
28 | protected Integer doEvaluate(Double bodyValue) { | 18 | protected Integer doEvaluate(Double bodyValue) { |
29 | return bodyValue.intValue(); | 19 | return bodyValue.isNaN() ? null : bodyValue.intValue(); |
30 | } | 20 | } |
31 | 21 | ||
32 | @Override | 22 | @Override |
@@ -36,6 +26,6 @@ public class RealToIntTerm extends UnaryTerm<Integer, Double> { | |||
36 | 26 | ||
37 | @Override | 27 | @Override |
38 | public String toString() { | 28 | public String toString() { |
39 | return "(%s) as int".formatted(getBody()); | 29 | return "(%s as int)".formatted(getBody()); |
40 | } | 30 | } |
41 | } | 31 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java index 4f7d5687..2f53117a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java | |||
@@ -11,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm; | |||
11 | 11 | ||
12 | public class IntToRealTerm extends UnaryTerm<Double, Integer> { | 12 | public class IntToRealTerm extends UnaryTerm<Double, Integer> { |
13 | protected IntToRealTerm(Term<Integer> body) { | 13 | protected IntToRealTerm(Term<Integer> body) { |
14 | super(body); | 14 | super(Double.class, Integer.class, body); |
15 | } | ||
16 | |||
17 | @Override | ||
18 | public Class<Double> getType() { | ||
19 | return Double.class; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Class<Integer> getBodyType() { | ||
24 | return Integer.class; | ||
25 | } | 15 | } |
26 | 16 | ||
27 | @Override | 17 | @Override |
@@ -36,6 +26,6 @@ public class IntToRealTerm extends UnaryTerm<Double, Integer> { | |||
36 | 26 | ||
37 | @Override | 27 | @Override |
38 | public String toString() { | 28 | public String toString() { |
39 | return "(%s) as real".formatted(getBody()); | 29 | return "(%s as real)".formatted(getBody()); |
40 | } | 30 | } |
41 | } | 31 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java new file mode 100644 index 00000000..33fc9e41 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealAddTerm extends RealBinaryTerm { | ||
12 | public RealAddTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealAddTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return leftValue + rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s + %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java deleted file mode 100644 index 8d5c9242..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java +++ /dev/null | |||
@@ -1,41 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.ArithmeticBinaryOperator; | ||
10 | import tools.refinery.store.query.term.ArithmeticBinaryTerm; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | |||
13 | public class RealArithmeticBinaryTerm extends ArithmeticBinaryTerm<Double> { | ||
14 | public RealArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<Double> left, Term<Double> right) { | ||
15 | super(operator, left, right); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public Class<Double> getType() { | ||
20 | return Double.class; | ||
21 | } | ||
22 | |||
23 | @Override | ||
24 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
25 | Term<Double> substitutedRight) { | ||
26 | return new RealArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
31 | return switch (getOperator()) { | ||
32 | case ADD -> leftValue + rightValue; | ||
33 | case SUB -> leftValue - rightValue; | ||
34 | case MUL -> leftValue * rightValue; | ||
35 | case DIV -> leftValue / rightValue; | ||
36 | case POW -> Math.pow(leftValue, rightValue); | ||
37 | case MIN -> Math.min(leftValue, rightValue); | ||
38 | case MAX -> Math.max(leftValue, rightValue); | ||
39 | }; | ||
40 | } | ||
41 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java deleted file mode 100644 index 9d233dfc..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.ArithmeticUnaryOperator; | ||
10 | import tools.refinery.store.query.term.ArithmeticUnaryTerm; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | |||
13 | public class RealArithmeticUnaryTerm extends ArithmeticUnaryTerm<Double> { | ||
14 | public RealArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term<Double> body) { | ||
15 | super(operation, body); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public Class<Double> getType() { | ||
20 | return Double.class; | ||
21 | } | ||
22 | |||
23 | @Override | ||
24 | protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) { | ||
25 | return new RealArithmeticUnaryTerm(getOperator(), substitutedBody); | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | protected Double doEvaluate(Double bodyValue) { | ||
30 | return switch(getOperator()) { | ||
31 | case PLUS -> bodyValue; | ||
32 | case MINUS -> -bodyValue; | ||
33 | }; | ||
34 | } | ||
35 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java new file mode 100644 index 00000000..000f3623 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.term.BinaryTerm; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public abstract class RealBinaryTerm extends BinaryTerm<Double, Double, Double> { | ||
12 | protected RealBinaryTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(Double.class, Double.class, Double.class, left, right); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java deleted file mode 100644 index 25c88f89..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.ComparisonOperator; | ||
10 | import tools.refinery.store.query.term.ComparisonTerm; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | |||
13 | public class RealComparisonTerm extends ComparisonTerm<Double> { | ||
14 | public RealComparisonTerm(ComparisonOperator operator, Term<Double> left, Term<Double> right) { | ||
15 | super(operator, left, right); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public Class<Double> getOperandType() { | ||
20 | return Double.class; | ||
21 | } | ||
22 | |||
23 | @Override | ||
24 | public Term<Boolean> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
25 | Term<Double> substitutedRight) { | ||
26 | return new RealComparisonTerm(getOperator(), substitutedLeft, substitutedRight); | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | protected Boolean doEvaluate(Double leftValue, Double rightValue) { | ||
31 | return switch (getOperator()) { | ||
32 | case EQ -> leftValue.equals(rightValue); | ||
33 | case NOT_EQ -> !leftValue.equals(rightValue); | ||
34 | case LESS -> leftValue < rightValue; | ||
35 | case LESS_EQ -> leftValue <= rightValue; | ||
36 | case GREATER -> leftValue > rightValue; | ||
37 | case GREATER_EQ -> leftValue >= rightValue; | ||
38 | }; | ||
39 | } | ||
40 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java new file mode 100644 index 00000000..1e55bf42 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealDivTerm extends RealBinaryTerm { | ||
12 | public RealDivTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealDivTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return leftValue / rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s / %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java deleted file mode 100644 index 526e643b..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.term.ExtremeValueAggregator; | ||
9 | |||
10 | import java.util.Comparator; | ||
11 | |||
12 | public final class RealExtremeValueAggregator { | ||
13 | public static final ExtremeValueAggregator<Double> MINIMUM = new ExtremeValueAggregator<>(Double.class, | ||
14 | Double.POSITIVE_INFINITY); | ||
15 | |||
16 | public static final ExtremeValueAggregator<Double> MAXIMUM = new ExtremeValueAggregator<>(Double.class, | ||
17 | Double.NEGATIVE_INFINITY, Comparator.reverseOrder()); | ||
18 | |||
19 | private RealExtremeValueAggregator() { | ||
20 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
21 | } | ||
22 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java new file mode 100644 index 00000000..2a249496 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealMaxTerm extends RealBinaryTerm { | ||
12 | public RealMaxTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealMaxTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return Math.max(leftValue, rightValue); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "max(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java new file mode 100644 index 00000000..2eb4cc1e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealMinTerm extends RealBinaryTerm { | ||
12 | public RealMinTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealMinTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return Math.min(leftValue, rightValue); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "min(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java new file mode 100644 index 00000000..4afec7a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealMinusTerm extends RealUnaryTerm { | ||
12 | public RealMinusTerm(Term<Double> body) { | ||
13 | super(body); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) { | ||
18 | return new RealMinusTerm(substitutedBody); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | protected Double doEvaluate(Double bodyValue) { | ||
23 | return -bodyValue; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(-%s)".formatted(getBody()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java new file mode 100644 index 00000000..ec95ac6f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealMulTerm extends RealBinaryTerm { | ||
12 | public RealMulTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealMulTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return leftValue * rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s * %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java new file mode 100644 index 00000000..64dd2e70 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealPlusTerm extends RealUnaryTerm { | ||
12 | public RealPlusTerm(Term<Double> body) { | ||
13 | super(body); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) { | ||
18 | return new RealPlusTerm(substitutedBody); | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | protected Double doEvaluate(Double bodyValue) { | ||
23 | return bodyValue; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public String toString() { | ||
28 | return "(+%s)".formatted(getBody()); | ||
29 | } | ||
30 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java new file mode 100644 index 00000000..11c952ea --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealPowTerm extends RealBinaryTerm { | ||
12 | public RealPowTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealPowTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return Math.pow(leftValue, rightValue); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s ** %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java new file mode 100644 index 00000000..8cc701ed --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | |||
11 | public class RealSubTerm extends RealBinaryTerm { | ||
12 | public RealSubTerm(Term<Double> left, Term<Double> right) { | ||
13 | super(left, right); | ||
14 | } | ||
15 | |||
16 | @Override | ||
17 | public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft, | ||
18 | Term<Double> substitutedRight) { | ||
19 | return new RealSubTerm(substitutedLeft, substitutedRight); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | protected Double doEvaluate(Double leftValue, Double rightValue) { | ||
24 | return leftValue - rightValue; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s - %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java index 1240d478..79220358 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java | |||
@@ -5,82 +5,90 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.query.term.real; | 6 | package tools.refinery.store.query.term.real; |
7 | 7 | ||
8 | import tools.refinery.store.query.term.*; | 8 | import tools.refinery.store.query.term.Aggregator; |
9 | import tools.refinery.store.query.term.ConstantTerm; | ||
10 | import tools.refinery.store.query.term.ExtremeValueAggregator; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | import tools.refinery.store.query.term.comparable.*; | ||
13 | |||
14 | import java.util.Comparator; | ||
9 | 15 | ||
10 | public final class RealTerms { | 16 | public final class RealTerms { |
11 | public static final Aggregator<Double, Double> REAL_SUM = RealSumAggregator.INSTANCE; | 17 | public static final Aggregator<Double, Double> REAL_SUM = RealSumAggregator.INSTANCE; |
12 | public static final Aggregator<Double, Double> REAL_MIN = RealExtremeValueAggregator.MINIMUM; | 18 | public static final Aggregator<Double, Double> REAL_MIN = new ExtremeValueAggregator<>(Double.class, |
13 | public static final Aggregator<Double, Double> REAL_MAX = RealExtremeValueAggregator.MAXIMUM; | 19 | Double.POSITIVE_INFINITY); |
20 | public static final Aggregator<Double, Double> REAL_MAX = new ExtremeValueAggregator<>(Double.class, | ||
21 | Double.NEGATIVE_INFINITY, Comparator.reverseOrder()); | ||
14 | 22 | ||
15 | private RealTerms() { | 23 | private RealTerms() { |
16 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); | 24 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); |
17 | } | 25 | } |
18 | 26 | ||
19 | public static ConstantTerm<Double> constant(double value) { | 27 | public static Term<Double> constant(Double value) { |
20 | return new ConstantTerm<>(Double.class, value); | 28 | return new ConstantTerm<>(Double.class, value); |
21 | } | 29 | } |
22 | 30 | ||
23 | public static RealArithmeticUnaryTerm plus(Term<Double> body) { | 31 | public static Term<Double> plus(Term<Double> body) { |
24 | return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); | 32 | return new RealPlusTerm(body); |
25 | } | 33 | } |
26 | 34 | ||
27 | public static RealArithmeticUnaryTerm minus(Term<Double> body) { | 35 | public static Term<Double> minus(Term<Double> body) { |
28 | return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); | 36 | return new RealMinusTerm(body); |
29 | } | 37 | } |
30 | 38 | ||
31 | public static RealArithmeticBinaryTerm add(Term<Double> left, Term<Double> right) { | 39 | public static Term<Double> add(Term<Double> left, Term<Double> right) { |
32 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); | 40 | return new RealAddTerm(left, right); |
33 | } | 41 | } |
34 | 42 | ||
35 | public static RealArithmeticBinaryTerm sub(Term<Double> left, Term<Double> right) { | 43 | public static Term<Double> sub(Term<Double> left, Term<Double> right) { |
36 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); | 44 | return new RealSubTerm(left, right); |
37 | } | 45 | } |
38 | 46 | ||
39 | public static RealArithmeticBinaryTerm mul(Term<Double> left, Term<Double> right) { | 47 | public static Term<Double> mul(Term<Double> left, Term<Double> right) { |
40 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); | 48 | return new RealMulTerm(left, right); |
41 | } | 49 | } |
42 | 50 | ||
43 | public static RealArithmeticBinaryTerm div(Term<Double> left, Term<Double> right) { | 51 | public static Term<Double> div(Term<Double> left, Term<Double> right) { |
44 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); | 52 | return new RealDivTerm(left, right); |
45 | } | 53 | } |
46 | 54 | ||
47 | public static RealArithmeticBinaryTerm pow(Term<Double> left, Term<Double> right) { | 55 | public static Term<Double> pow(Term<Double> left, Term<Double> right) { |
48 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); | 56 | return new RealPowTerm(left, right); |
49 | } | 57 | } |
50 | 58 | ||
51 | public static RealArithmeticBinaryTerm min(Term<Double> left, Term<Double> right) { | 59 | public static Term<Double> min(Term<Double> left, Term<Double> right) { |
52 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); | 60 | return new RealMinTerm(left, right); |
53 | } | 61 | } |
54 | 62 | ||
55 | public static RealArithmeticBinaryTerm max(Term<Double> left, Term<Double> right) { | 63 | public static Term<Double> max(Term<Double> left, Term<Double> right) { |
56 | return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); | 64 | return new RealMaxTerm(left, right); |
57 | } | 65 | } |
58 | 66 | ||
59 | public static RealComparisonTerm eq(Term<Double> left, Term<Double> right) { | 67 | public static Term<Boolean> eq(Term<Double> left, Term<Double> right) { |
60 | return new RealComparisonTerm(ComparisonOperator.EQ, left, right); | 68 | return new EqTerm<>(Double.class, left, right); |
61 | } | 69 | } |
62 | 70 | ||
63 | public static RealComparisonTerm notEq(Term<Double> left, Term<Double> right) { | 71 | public static Term<Boolean> notEq(Term<Double> left, Term<Double> right) { |
64 | return new RealComparisonTerm(ComparisonOperator.NOT_EQ, left, right); | 72 | return new NotEqTerm<>(Double.class, left, right); |
65 | } | 73 | } |
66 | 74 | ||
67 | public static RealComparisonTerm less(Term<Double> left, Term<Double> right) { | 75 | public static Term<Boolean> less(Term<Double> left, Term<Double> right) { |
68 | return new RealComparisonTerm(ComparisonOperator.LESS, left, right); | 76 | return new LessTerm<>(Double.class, left, right); |
69 | } | 77 | } |
70 | 78 | ||
71 | public static RealComparisonTerm lessEq(Term<Double> left, Term<Double> right) { | 79 | public static Term<Boolean> lessEq(Term<Double> left, Term<Double> right) { |
72 | return new RealComparisonTerm(ComparisonOperator.LESS_EQ, left, right); | 80 | return new LessEqTerm<>(Double.class, left, right); |
73 | } | 81 | } |
74 | 82 | ||
75 | public static RealComparisonTerm greater(Term<Double> left, Term<Double> right) { | 83 | public static Term<Boolean> greater(Term<Double> left, Term<Double> right) { |
76 | return new RealComparisonTerm(ComparisonOperator.GREATER, left, right); | 84 | return new GreaterTerm<>(Double.class, left, right); |
77 | } | 85 | } |
78 | 86 | ||
79 | public static RealComparisonTerm greaterEq(Term<Double> left, Term<Double> right) { | 87 | public static Term<Boolean> greaterEq(Term<Double> left, Term<Double> right) { |
80 | return new RealComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); | 88 | return new GreaterEqTerm<>(Double.class, left, right); |
81 | } | 89 | } |
82 | 90 | ||
83 | public static IntToRealTerm asReal(Term<Integer> body) { | 91 | public static Term<Double> asReal(Term<Integer> body) { |
84 | return new IntToRealTerm(body); | 92 | return new IntToRealTerm(body); |
85 | } | 93 | } |
86 | } | 94 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java new file mode 100644 index 00000000..d41c4ed9 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import tools.refinery.store.query.term.Term; | ||
9 | import tools.refinery.store.query.term.UnaryTerm; | ||
10 | |||
11 | public abstract class RealUnaryTerm extends UnaryTerm<Double, Double> { | ||
12 | protected RealUnaryTerm(Term<Double> body) { | ||
13 | super(Double.class, Double.class, body); | ||
14 | } | ||
15 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java new file mode 100644 index 00000000..68905f51 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
11 | |||
12 | public class UpperCardinalityAddTerm extends UpperCardinalityBinaryTerm { | ||
13 | protected UpperCardinalityAddTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
14 | super(left, right); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { | ||
19 | return leftValue.add(rightValue); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) { | ||
24 | return new UpperCardinalityAddTerm(substitutedLeft, substitutedRight); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s + %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java new file mode 100644 index 00000000..0cf8fe44 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.term.BinaryTerm; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
11 | |||
12 | public abstract class UpperCardinalityBinaryTerm extends BinaryTerm<UpperCardinality, UpperCardinality, | ||
13 | UpperCardinality> { | ||
14 | protected UpperCardinalityBinaryTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
15 | super(UpperCardinality.class, UpperCardinality.class, UpperCardinality.class, left, right); | ||
16 | } | ||
17 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java new file mode 100644 index 00000000..ff75f64e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
11 | |||
12 | public class UpperCardinalityMaxTerm extends UpperCardinalityBinaryTerm { | ||
13 | protected UpperCardinalityMaxTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
14 | super(left, right); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { | ||
19 | return leftValue.max(rightValue); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) { | ||
24 | return new UpperCardinalityMaxTerm(substitutedLeft, substitutedRight); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "max(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java new file mode 100644 index 00000000..1e89e9f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
11 | |||
12 | public class UpperCardinalityMinTerm extends UpperCardinalityBinaryTerm { | ||
13 | protected UpperCardinalityMinTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
14 | super(left, right); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { | ||
19 | return leftValue.min(rightValue); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) { | ||
24 | return new UpperCardinalityMinTerm(substitutedLeft, substitutedRight); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "min(%s, %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java new file mode 100644 index 00000000..3b4970f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
9 | import tools.refinery.store.query.term.Term; | ||
10 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
11 | |||
12 | public class UpperCardinalityMulTerm extends UpperCardinalityBinaryTerm { | ||
13 | protected UpperCardinalityMulTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
14 | super(left, right); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { | ||
19 | return leftValue.multiply(rightValue); | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) { | ||
24 | return new UpperCardinalityMulTerm(substitutedLeft, substitutedRight); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String toString() { | ||
29 | return "(%s * %s)".formatted(getLeft(), getRight()); | ||
30 | } | ||
31 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java new file mode 100644 index 00000000..5bbd3081 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.term.StatefulAggregate; | ||
9 | import tools.refinery.store.query.term.StatefulAggregator; | ||
10 | import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; | ||
11 | import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; | ||
12 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
13 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
14 | |||
15 | public class UpperCardinalitySumAggregator implements StatefulAggregator<UpperCardinality, UpperCardinality> { | ||
16 | public static final UpperCardinalitySumAggregator INSTANCE = new UpperCardinalitySumAggregator(); | ||
17 | |||
18 | private UpperCardinalitySumAggregator() { | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public Class<UpperCardinality> getResultType() { | ||
23 | return UpperCardinality.class; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public Class<UpperCardinality> getInputType() { | ||
28 | return UpperCardinality.class; | ||
29 | } | ||
30 | |||
31 | @Override | ||
32 | public StatefulAggregate<UpperCardinality, UpperCardinality> createEmptyAggregate() { | ||
33 | return new Aggregate(); | ||
34 | } | ||
35 | |||
36 | private static class Aggregate implements StatefulAggregate<UpperCardinality, UpperCardinality> { | ||
37 | private int sumFiniteUpperBounds; | ||
38 | private int countUnbounded; | ||
39 | |||
40 | public Aggregate() { | ||
41 | this(0, 0); | ||
42 | } | ||
43 | |||
44 | private Aggregate(int sumFiniteUpperBounds, int countUnbounded) { | ||
45 | this.sumFiniteUpperBounds = sumFiniteUpperBounds; | ||
46 | this.countUnbounded = countUnbounded; | ||
47 | } | ||
48 | |||
49 | @Override | ||
50 | public void add(UpperCardinality value) { | ||
51 | if (value instanceof FiniteUpperCardinality finiteUpperCardinality) { | ||
52 | sumFiniteUpperBounds += finiteUpperCardinality.finiteUpperBound(); | ||
53 | } else if (value instanceof UnboundedUpperCardinality) { | ||
54 | countUnbounded += 1; | ||
55 | } else { | ||
56 | throw new IllegalArgumentException("Unknown UpperCardinality: " + value); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | @Override | ||
61 | public void remove(UpperCardinality value) { | ||
62 | if (value instanceof FiniteUpperCardinality finiteUpperCardinality) { | ||
63 | sumFiniteUpperBounds -= finiteUpperCardinality.finiteUpperBound(); | ||
64 | } else if (value instanceof UnboundedUpperCardinality) { | ||
65 | countUnbounded -= 1; | ||
66 | } else { | ||
67 | throw new IllegalArgumentException("Unknown UpperCardinality: " + value); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | @Override | ||
72 | public UpperCardinality getResult() { | ||
73 | return countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : UpperCardinalities.valueOf(sumFiniteUpperBounds); | ||
74 | } | ||
75 | |||
76 | @Override | ||
77 | public boolean isEmpty() { | ||
78 | return sumFiniteUpperBounds == 0 && countUnbounded == 0; | ||
79 | } | ||
80 | |||
81 | @Override | ||
82 | public StatefulAggregate<UpperCardinality, UpperCardinality> deepCopy() { | ||
83 | return new Aggregate(sumFiniteUpperBounds, countUnbounded); | ||
84 | } | ||
85 | } | ||
86 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java new file mode 100644 index 00000000..13914f2d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import tools.refinery.store.query.term.Aggregator; | ||
9 | import tools.refinery.store.query.term.ConstantTerm; | ||
10 | import tools.refinery.store.query.term.ExtremeValueAggregator; | ||
11 | import tools.refinery.store.query.term.Term; | ||
12 | import tools.refinery.store.query.term.comparable.*; | ||
13 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
14 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
15 | |||
16 | import java.util.Comparator; | ||
17 | |||
18 | public final class UpperCardinalityTerms { | ||
19 | public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_SUM = | ||
20 | UpperCardinalitySumAggregator.INSTANCE; | ||
21 | public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MIN = | ||
22 | new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.UNBOUNDED); | ||
23 | public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MAX = | ||
24 | new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.ZERO, Comparator.reverseOrder()); | ||
25 | |||
26 | private UpperCardinalityTerms() { | ||
27 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
28 | } | ||
29 | |||
30 | public static Term<UpperCardinality> constant(UpperCardinality value) { | ||
31 | return new ConstantTerm<>(UpperCardinality.class, value); | ||
32 | } | ||
33 | |||
34 | public static Term<UpperCardinality> add(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
35 | return new UpperCardinalityAddTerm(left, right); | ||
36 | } | ||
37 | |||
38 | public static Term<UpperCardinality> mul(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
39 | return new UpperCardinalityMulTerm(left, right); | ||
40 | } | ||
41 | |||
42 | public static Term<UpperCardinality> min(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
43 | return new UpperCardinalityMinTerm(left, right); | ||
44 | } | ||
45 | |||
46 | public static Term<UpperCardinality> max(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
47 | return new UpperCardinalityMaxTerm(left, right); | ||
48 | } | ||
49 | |||
50 | public static Term<Boolean> eq(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
51 | return new EqTerm<>(UpperCardinality.class, left, right); | ||
52 | } | ||
53 | |||
54 | public static Term<Boolean> notEq(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
55 | return new NotEqTerm<>(UpperCardinality.class, left, right); | ||
56 | } | ||
57 | |||
58 | public static Term<Boolean> less(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
59 | return new LessTerm<>(UpperCardinality.class, left, right); | ||
60 | } | ||
61 | |||
62 | public static Term<Boolean> lessEq(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
63 | return new LessEqTerm<>(UpperCardinality.class, left, right); | ||
64 | } | ||
65 | |||
66 | public static Term<Boolean> greater(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
67 | return new GreaterTerm<>(UpperCardinality.class, left, right); | ||
68 | } | ||
69 | |||
70 | public static Term<Boolean> greaterEq(Term<UpperCardinality> left, Term<UpperCardinality> right) { | ||
71 | return new GreaterEqTerm<>(UpperCardinality.class, left, right); | ||
72 | } | ||
73 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java new file mode 100644 index 00000000..261ceaa5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.valuation; | ||
7 | |||
8 | import tools.refinery.store.query.term.AnyDataVariable; | ||
9 | import tools.refinery.store.query.term.DataVariable; | ||
10 | |||
11 | import java.util.Map; | ||
12 | |||
13 | record MapBasedValuation(Map<AnyDataVariable, Object> values) implements Valuation { | ||
14 | @Override | ||
15 | public <T> T getValue(DataVariable<T> variable) { | ||
16 | if (!values.containsKey(variable)) { | ||
17 | throw new IllegalArgumentException("No value for variable %s".formatted(variable)); | ||
18 | } | ||
19 | var value = values.get(variable); | ||
20 | return variable.getType().cast(value); | ||
21 | } | ||
22 | } | ||
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java index 88fee35b..1588e957 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java | |||
@@ -10,6 +10,7 @@ import tools.refinery.store.query.substitution.Substitution; | |||
10 | import tools.refinery.store.query.term.AnyDataVariable; | 10 | import tools.refinery.store.query.term.AnyDataVariable; |
11 | import tools.refinery.store.query.term.DataVariable; | 11 | import tools.refinery.store.query.term.DataVariable; |
12 | 12 | ||
13 | import java.util.Map; | ||
13 | import java.util.Set; | 14 | import java.util.Set; |
14 | 15 | ||
15 | public interface Valuation { | 16 | public interface Valuation { |
@@ -25,4 +26,12 @@ public interface Valuation { | |||
25 | default Valuation restrict(Set<? extends AnyDataVariable> allowedVariables) { | 26 | default Valuation restrict(Set<? extends AnyDataVariable> allowedVariables) { |
26 | return new RestrictedValuation(this, Set.copyOf(allowedVariables)); | 27 | return new RestrictedValuation(this, Set.copyOf(allowedVariables)); |
27 | } | 28 | } |
29 | |||
30 | static ValuationBuilder builder() { | ||
31 | return new ValuationBuilder(); | ||
32 | } | ||
33 | |||
34 | static Valuation empty() { | ||
35 | return new MapBasedValuation(Map.of()); | ||
36 | } | ||
28 | } | 37 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java new file mode 100644 index 00000000..7337dbc3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.valuation; | ||
7 | |||
8 | import tools.refinery.store.query.term.AnyDataVariable; | ||
9 | import tools.refinery.store.query.term.DataVariable; | ||
10 | |||
11 | import java.util.Collections; | ||
12 | import java.util.HashMap; | ||
13 | import java.util.Map; | ||
14 | |||
15 | public class ValuationBuilder { | ||
16 | private final Map<AnyDataVariable, Object> values = new HashMap<>(); | ||
17 | |||
18 | ValuationBuilder() { | ||
19 | } | ||
20 | |||
21 | public <T> ValuationBuilder put(DataVariable<T> variable, T value) { | ||
22 | return putChecked(variable, value); | ||
23 | } | ||
24 | |||
25 | public ValuationBuilder putChecked(AnyDataVariable variable, Object value) { | ||
26 | if (value != null && !variable.getType().isInstance(value)) { | ||
27 | throw new IllegalArgumentException("Value %s is not an instance of %s" | ||
28 | .formatted(value, variable.getType().getName())); | ||
29 | } | ||
30 | if (values.containsKey(variable)) { | ||
31 | throw new IllegalArgumentException("Already has value for variable %s".formatted(variable)); | ||
32 | } | ||
33 | values.put(variable, value); | ||
34 | return this; | ||
35 | } | ||
36 | |||
37 | public Valuation build() { | ||
38 | return new MapBasedValuation(Collections.unmodifiableMap(values)); | ||
39 | } | ||
40 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java index 152840f8..01e2ccf6 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java | |||
@@ -6,13 +6,17 @@ | |||
6 | package tools.refinery.store.query; | 6 | package tools.refinery.store.query; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import org.junit.jupiter.params.ParameterizedTest; | ||
10 | import org.junit.jupiter.params.provider.CsvSource; | ||
9 | import tools.refinery.store.query.dnf.Dnf; | 11 | import tools.refinery.store.query.dnf.Dnf; |
10 | import tools.refinery.store.query.literal.BooleanLiteral; | 12 | import tools.refinery.store.query.literal.BooleanLiteral; |
11 | import tools.refinery.store.query.term.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
14 | import tools.refinery.store.query.term.bool.BoolTerms; | ||
12 | import tools.refinery.store.query.view.KeyOnlyView; | 15 | import tools.refinery.store.query.view.KeyOnlyView; |
13 | import tools.refinery.store.representation.Symbol; | 16 | import tools.refinery.store.representation.Symbol; |
14 | 17 | ||
15 | import static org.hamcrest.MatcherAssert.assertThat; | 18 | import static org.hamcrest.MatcherAssert.assertThat; |
19 | import static tools.refinery.store.query.literal.Literals.assume; | ||
16 | import static tools.refinery.store.query.literal.Literals.not; | 20 | import static tools.refinery.store.query.literal.Literals.not; |
17 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | 21 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; |
18 | 22 | ||
@@ -34,6 +38,22 @@ class DnfBuilderTest { | |||
34 | } | 38 | } |
35 | 39 | ||
36 | @Test | 40 | @Test |
41 | void eliminateTrueAssumptionTest() { | ||
42 | var p = Variable.of("p"); | ||
43 | var q = Variable.of("q"); | ||
44 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
45 | var friendView = new KeyOnlyView<>(friend); | ||
46 | |||
47 | var actual = Dnf.builder() | ||
48 | .parameters(p, q) | ||
49 | .clause(assume(BoolTerms.constant(true)), friendView.call(p, q)) | ||
50 | .build(); | ||
51 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
52 | |||
53 | assertThat(actual, structurallyEqualTo(expected)); | ||
54 | } | ||
55 | |||
56 | @Test | ||
37 | void eliminateFalseTest() { | 57 | void eliminateFalseTest() { |
38 | var p = Variable.of("p"); | 58 | var p = Variable.of("p"); |
39 | var q = Variable.of("q"); | 59 | var q = Variable.of("q"); |
@@ -50,6 +70,27 @@ class DnfBuilderTest { | |||
50 | assertThat(actual, structurallyEqualTo(expected)); | 70 | assertThat(actual, structurallyEqualTo(expected)); |
51 | } | 71 | } |
52 | 72 | ||
73 | @ParameterizedTest | ||
74 | @CsvSource(value = { | ||
75 | "false", | ||
76 | "null" | ||
77 | }, nullValues = "null") | ||
78 | void eliminateFalseAssumptionTest(Boolean value) { | ||
79 | var p = Variable.of("p"); | ||
80 | var q = Variable.of("q"); | ||
81 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
82 | var friendView = new KeyOnlyView<>(friend); | ||
83 | |||
84 | var actual = Dnf.builder() | ||
85 | .parameters(p, q) | ||
86 | .clause(friendView.call(p, q)) | ||
87 | .clause(friendView.call(q, p), assume(BoolTerms.constant(value))) | ||
88 | .build(); | ||
89 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
90 | |||
91 | assertThat(actual, structurallyEqualTo(expected)); | ||
92 | } | ||
93 | |||
53 | @Test | 94 | @Test |
54 | void alwaysTrueTest() { | 95 | void alwaysTrueTest() { |
55 | var p = Variable.of("p"); | 96 | var p = Variable.of("p"); |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java new file mode 100644 index 00000000..1cbc101a --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term; | ||
7 | |||
8 | import org.junit.jupiter.api.Assertions; | ||
9 | import org.junit.jupiter.params.ParameterizedTest; | ||
10 | import org.junit.jupiter.params.provider.Arguments; | ||
11 | import org.junit.jupiter.params.provider.MethodSource; | ||
12 | import tools.refinery.store.query.dnf.Dnf; | ||
13 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | ||
14 | import tools.refinery.store.query.substitution.Substitution; | ||
15 | import tools.refinery.store.query.term.bool.BoolTerms; | ||
16 | import tools.refinery.store.query.term.int_.IntTerms; | ||
17 | import tools.refinery.store.query.term.real.RealTerms; | ||
18 | import tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms; | ||
19 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
20 | |||
21 | import java.util.List; | ||
22 | import java.util.stream.Stream; | ||
23 | |||
24 | class TermSubstitutionTest { | ||
25 | private final static DataVariable<Integer> intA = Variable.of("intA", Integer.class); | ||
26 | private final static DataVariable<Integer> intB = Variable.of("intB", Integer.class); | ||
27 | private final static DataVariable<Double> realA = Variable.of("realA", Double.class); | ||
28 | private final static DataVariable<Double> realB = Variable.of("realB", Double.class); | ||
29 | private final static DataVariable<Boolean> boolA = Variable.of("boolA", Boolean.class); | ||
30 | private final static DataVariable<Boolean> boolB = Variable.of("boolB", Boolean.class); | ||
31 | private final static DataVariable<UpperCardinality> upperCardinalityA = Variable.of("upperCardinalityA", | ||
32 | UpperCardinality.class); | ||
33 | private final static DataVariable<UpperCardinality> upperCardinalityB = Variable.of("upperCardinalityB", | ||
34 | UpperCardinality.class); | ||
35 | private final static Substitution substitution = Substitution.builder() | ||
36 | .put(intA, intB) | ||
37 | .put(intB, intA) | ||
38 | .put(realA, realB) | ||
39 | .put(realB, realA) | ||
40 | .put(boolA, boolB) | ||
41 | .put(boolB, boolA) | ||
42 | .put(upperCardinalityA, upperCardinalityB) | ||
43 | .put(upperCardinalityB, upperCardinalityA) | ||
44 | .build(); | ||
45 | |||
46 | @ParameterizedTest | ||
47 | @MethodSource | ||
48 | void substitutionTest(AnyTerm term) { | ||
49 | var substitutedTerm1 = term.substitute(substitution); | ||
50 | Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term"); | ||
51 | var helper = new LiteralEqualityHelper(Dnf::equals, List.of(), List.of()); | ||
52 | Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper"); | ||
53 | // The {@link #substitution} is its own inverse. | ||
54 | var substitutedTerm2 = substitutedTerm1.substitute(substitution); | ||
55 | Assertions.assertEquals(term, substitutedTerm2, "Original term is not equal to back-substituted term"); | ||
56 | } | ||
57 | |||
58 | static Stream<Arguments> substitutionTest() { | ||
59 | return Stream.of( | ||
60 | Arguments.of(IntTerms.plus(intA)), | ||
61 | Arguments.of(IntTerms.minus(intA)), | ||
62 | Arguments.of(IntTerms.add(intA, intB)), | ||
63 | Arguments.of(IntTerms.sub(intA, intB)), | ||
64 | Arguments.of(IntTerms.mul(intA, intB)), | ||
65 | Arguments.of(IntTerms.div(intA, intB)), | ||
66 | Arguments.of(IntTerms.pow(intA, intB)), | ||
67 | Arguments.of(IntTerms.min(intA, intB)), | ||
68 | Arguments.of(IntTerms.max(intA, intB)), | ||
69 | Arguments.of(IntTerms.eq(intA, intB)), | ||
70 | Arguments.of(IntTerms.notEq(intA, intB)), | ||
71 | Arguments.of(IntTerms.less(intA, intB)), | ||
72 | Arguments.of(IntTerms.lessEq(intA, intB)), | ||
73 | Arguments.of(IntTerms.greater(intA, intB)), | ||
74 | Arguments.of(IntTerms.greaterEq(intA, intB)), | ||
75 | Arguments.of(IntTerms.asInt(realA)), | ||
76 | Arguments.of(RealTerms.plus(realA)), | ||
77 | Arguments.of(RealTerms.minus(realA)), | ||
78 | Arguments.of(RealTerms.add(realA, realB)), | ||
79 | Arguments.of(RealTerms.sub(realA, realB)), | ||
80 | Arguments.of(RealTerms.mul(realA, realB)), | ||
81 | Arguments.of(RealTerms.div(realA, realB)), | ||
82 | Arguments.of(RealTerms.pow(realA, realB)), | ||
83 | Arguments.of(RealTerms.min(realA, realB)), | ||
84 | Arguments.of(RealTerms.max(realA, realB)), | ||
85 | Arguments.of(RealTerms.asReal(intA)), | ||
86 | Arguments.of(BoolTerms.not(boolA)), | ||
87 | Arguments.of(BoolTerms.and(boolA, boolB)), | ||
88 | Arguments.of(BoolTerms.or(boolA, boolB)), | ||
89 | Arguments.of(BoolTerms.xor(boolA, boolB)), | ||
90 | Arguments.of(RealTerms.eq(realA, realB)), | ||
91 | Arguments.of(UpperCardinalityTerms.add(upperCardinalityA, upperCardinalityB)), | ||
92 | Arguments.of(UpperCardinalityTerms.mul(upperCardinalityA, upperCardinalityB)), | ||
93 | Arguments.of(UpperCardinalityTerms.min(upperCardinalityA, upperCardinalityB)), | ||
94 | Arguments.of(UpperCardinalityTerms.max(upperCardinalityA, upperCardinalityB)) | ||
95 | ); | ||
96 | } | ||
97 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java new file mode 100644 index 00000000..beff705e --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.bool; | ||
7 | |||
8 | import org.junit.jupiter.params.ParameterizedTest; | ||
9 | import org.junit.jupiter.params.provider.CsvSource; | ||
10 | import tools.refinery.store.query.valuation.Valuation; | ||
11 | |||
12 | import static org.hamcrest.MatcherAssert.assertThat; | ||
13 | import static org.hamcrest.Matchers.is; | ||
14 | |||
15 | class BoolTermsEvaluateTest { | ||
16 | @ParameterizedTest(name = "!{0} == {1}") | ||
17 | @CsvSource(value = { | ||
18 | "false, true", | ||
19 | "true, false", | ||
20 | "null, null" | ||
21 | }, nullValues = "null") | ||
22 | void notTest(Boolean a, Boolean result) { | ||
23 | var term = BoolTerms.not(BoolTerms.constant(a)); | ||
24 | assertThat(term.getType(), is(Boolean.class)); | ||
25 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
26 | } | ||
27 | |||
28 | @ParameterizedTest(name = "{0} && {1} == {2}") | ||
29 | @CsvSource(value = { | ||
30 | "false, false, false", | ||
31 | "false, true, false", | ||
32 | "true, false, false", | ||
33 | "true, true, true", | ||
34 | "false, null, null", | ||
35 | "null, false, null", | ||
36 | "null, null, null" | ||
37 | }, nullValues = "null") | ||
38 | void andTest(Boolean a, Boolean b, Boolean result) { | ||
39 | var term = BoolTerms.and(BoolTerms.constant(a), BoolTerms.constant(b)); | ||
40 | assertThat(term.getType(), is(Boolean.class)); | ||
41 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
42 | } | ||
43 | |||
44 | @ParameterizedTest(name = "{0} || {1} == {2}") | ||
45 | @CsvSource(value = { | ||
46 | "false, false, false", | ||
47 | "false, true, true", | ||
48 | "true, false, true", | ||
49 | "true, true, true", | ||
50 | "true, null, null", | ||
51 | "null, true, null", | ||
52 | "null, null, null" | ||
53 | }, nullValues = "null") | ||
54 | void orTest(Boolean a, Boolean b, Boolean result) { | ||
55 | var term = BoolTerms.or(BoolTerms.constant(a), BoolTerms.constant(b)); | ||
56 | assertThat(term.getType(), is(Boolean.class)); | ||
57 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
58 | } | ||
59 | |||
60 | @ParameterizedTest(name = "{0} ^^ {1} == {2}") | ||
61 | @CsvSource(value = { | ||
62 | "false, false, false", | ||
63 | "false, true, true", | ||
64 | "true, false, true", | ||
65 | "true, true, false", | ||
66 | "false, null, null", | ||
67 | "null, false, null", | ||
68 | "null, null, null" | ||
69 | }, nullValues = "null") | ||
70 | void xorTest(Boolean a, Boolean b, Boolean result) { | ||
71 | var term = BoolTerms.xor(BoolTerms.constant(a), BoolTerms.constant(b)); | ||
72 | assertThat(term.getType(), is(Boolean.class)); | ||
73 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
74 | } | ||
75 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java new file mode 100644 index 00000000..abe50d75 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.int_; | ||
7 | |||
8 | import org.junit.jupiter.params.ParameterizedTest; | ||
9 | import org.junit.jupiter.params.provider.Arguments; | ||
10 | import org.junit.jupiter.params.provider.CsvSource; | ||
11 | import org.junit.jupiter.params.provider.MethodSource; | ||
12 | import tools.refinery.store.query.term.real.RealTerms; | ||
13 | import tools.refinery.store.query.valuation.Valuation; | ||
14 | |||
15 | import java.util.stream.Stream; | ||
16 | |||
17 | import static org.hamcrest.Matchers.is; | ||
18 | import static org.hamcrest.MatcherAssert.assertThat; | ||
19 | |||
20 | class IntTermsEvaluateTest { | ||
21 | @ParameterizedTest(name = "+{0} == {1}") | ||
22 | @CsvSource(value = { | ||
23 | "2, 2", | ||
24 | "null, null" | ||
25 | }, nullValues = "null") | ||
26 | void plusTest(Integer a, Integer result) { | ||
27 | var term = IntTerms.plus(IntTerms.constant(a)); | ||
28 | assertThat(term.getType(), is(Integer.class)); | ||
29 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
30 | } | ||
31 | |||
32 | @ParameterizedTest(name = "-{0} == {1}") | ||
33 | @CsvSource(value = { | ||
34 | "2, -2", | ||
35 | "null, null" | ||
36 | }, nullValues = "null") | ||
37 | void minusTest(Integer a, Integer result) { | ||
38 | var term = IntTerms.minus(IntTerms.constant(a)); | ||
39 | assertThat(term.getType(), is(Integer.class)); | ||
40 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
41 | } | ||
42 | |||
43 | @ParameterizedTest(name = "{0} + {1} == {2}") | ||
44 | @CsvSource(value = { | ||
45 | "1, 2, 3", | ||
46 | "null, 2, null", | ||
47 | "1, null, null", | ||
48 | "null, null, null" | ||
49 | }, nullValues = "null") | ||
50 | void addTest(Integer a, Integer b, Integer result) { | ||
51 | var term = IntTerms.add(IntTerms.constant(a), IntTerms.constant(b)); | ||
52 | assertThat(term.getType(), is(Integer.class)); | ||
53 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
54 | } | ||
55 | |||
56 | @ParameterizedTest(name = "{0} - {1} == {2}") | ||
57 | @CsvSource(value = { | ||
58 | "1, 3, -2", | ||
59 | "null, 3, null", | ||
60 | "1, null, null", | ||
61 | "null, null, null" | ||
62 | }, nullValues = "null") | ||
63 | void subTest(Integer a, Integer b, Integer result) { | ||
64 | var term = IntTerms.sub(IntTerms.constant(a), IntTerms.constant(b)); | ||
65 | assertThat(term.getType(), is(Integer.class)); | ||
66 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
67 | } | ||
68 | |||
69 | @ParameterizedTest(name = "{0} * {1} == {2}") | ||
70 | @CsvSource(value = { | ||
71 | "2, 3, 6", | ||
72 | "null, 3, null", | ||
73 | "2, null, null", | ||
74 | "null, null, null" | ||
75 | }, nullValues = "null") | ||
76 | void mulTest(Integer a, Integer b, Integer result) { | ||
77 | var term = IntTerms.mul(IntTerms.constant(a), IntTerms.constant(b)); | ||
78 | assertThat(term.getType(), is(Integer.class)); | ||
79 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
80 | } | ||
81 | |||
82 | @ParameterizedTest(name = "{0} * {1} == {2}") | ||
83 | @CsvSource(value = { | ||
84 | "6, 3, 2", | ||
85 | "7, 3, 2", | ||
86 | "6, 0, null", | ||
87 | "null, 3, null", | ||
88 | "6, null, null", | ||
89 | "null, null, null" | ||
90 | }, nullValues = "null") | ||
91 | void divTest(Integer a, Integer b, Integer result) { | ||
92 | var term = IntTerms.div(IntTerms.constant(a), IntTerms.constant(b)); | ||
93 | assertThat(term.getType(), is(Integer.class)); | ||
94 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
95 | } | ||
96 | |||
97 | @ParameterizedTest(name = "{0} ** {1} == {2}") | ||
98 | @CsvSource(value = { | ||
99 | "1, 0, 1", | ||
100 | "1, 3, 1", | ||
101 | "1, -3, null", | ||
102 | "2, 0, 1", | ||
103 | "2, 2, 4", | ||
104 | "2, 3, 8", | ||
105 | "2, 4, 16", | ||
106 | "2, 5, 32", | ||
107 | "2, 6, 64", | ||
108 | "2, -3, null", | ||
109 | "null, 3, null", | ||
110 | "2, null, null", | ||
111 | "null, null, null" | ||
112 | }, nullValues = "null") | ||
113 | void powTest(Integer a, Integer b, Integer result) { | ||
114 | var term = IntTerms.pow(IntTerms.constant(a), IntTerms.constant(b)); | ||
115 | assertThat(term.getType(), is(Integer.class)); | ||
116 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
117 | } | ||
118 | |||
119 | @ParameterizedTest(name = "min({0}, {1}) == {2}") | ||
120 | @CsvSource(value = { | ||
121 | "1, 2, 1", | ||
122 | "2, 1, 1", | ||
123 | "null, 2, null", | ||
124 | "1, null, null", | ||
125 | "null, null, null" | ||
126 | }, nullValues = "null") | ||
127 | void minTest(Integer a, Integer b, Integer result) { | ||
128 | var term = IntTerms.min(IntTerms.constant(a), IntTerms.constant(b)); | ||
129 | assertThat(term.getType(), is(Integer.class)); | ||
130 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
131 | } | ||
132 | |||
133 | @ParameterizedTest(name = "max({0}, {1}) == {2}") | ||
134 | @CsvSource(value = { | ||
135 | "1, 2, 2", | ||
136 | "2, 1, 2", | ||
137 | "null, 2, null", | ||
138 | "1, null, null", | ||
139 | "null, null, null" | ||
140 | }, nullValues = "null") | ||
141 | void maxTest(Integer a, Integer b, Integer result) { | ||
142 | var term = IntTerms.max(IntTerms.constant(a), IntTerms.constant(b)); | ||
143 | assertThat(term.getType(), is(Integer.class)); | ||
144 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
145 | } | ||
146 | |||
147 | @ParameterizedTest(name = "({0} == {1}) == {2}") | ||
148 | @CsvSource(value = { | ||
149 | "1, 1, true", | ||
150 | "1, 2, false", | ||
151 | "null, 1, null", | ||
152 | "1, null, null", | ||
153 | "null, null, null" | ||
154 | }, nullValues = "null") | ||
155 | void eqTest(Integer a, Integer b, Boolean result) { | ||
156 | var term = IntTerms.eq(IntTerms.constant(a), IntTerms.constant(b)); | ||
157 | assertThat(term.getType(), is(Boolean.class)); | ||
158 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
159 | } | ||
160 | |||
161 | @ParameterizedTest(name = "({0} != {1}) == {2}") | ||
162 | @CsvSource(value = { | ||
163 | "1, 1, false", | ||
164 | "1, 2, true", | ||
165 | "null, 1, null", | ||
166 | "1, null, null", | ||
167 | "null, null, null" | ||
168 | }, nullValues = "null") | ||
169 | void notEqTest(Integer a, Integer b, Boolean result) { | ||
170 | var term = IntTerms.notEq(IntTerms.constant(a), IntTerms.constant(b)); | ||
171 | assertThat(term.getType(), is(Boolean.class)); | ||
172 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
173 | } | ||
174 | |||
175 | @ParameterizedTest(name = "({0} < {1}) == {2}") | ||
176 | @CsvSource(value = { | ||
177 | "1, -2, false", | ||
178 | "1, 1, false", | ||
179 | "1, 2, true", | ||
180 | "null, 1, null", | ||
181 | "1, null, null", | ||
182 | "null, null, null" | ||
183 | }, nullValues = "null") | ||
184 | void lessTest(Integer a, Integer b, Boolean result) { | ||
185 | var term = IntTerms.less(IntTerms.constant(a), IntTerms.constant(b)); | ||
186 | assertThat(term.getType(), is(Boolean.class)); | ||
187 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
188 | } | ||
189 | |||
190 | @ParameterizedTest(name = "({0} <= {1}) == {2}") | ||
191 | @CsvSource(value = { | ||
192 | "1, -2, false", | ||
193 | "1, 1, true", | ||
194 | "1, 2, true", | ||
195 | "null, 1, null", | ||
196 | "1, null, null", | ||
197 | "null, null, null" | ||
198 | }, nullValues = "null") | ||
199 | void lessEqTest(Integer a, Integer b, Boolean result) { | ||
200 | var term = IntTerms.lessEq(IntTerms.constant(a), IntTerms.constant(b)); | ||
201 | assertThat(term.getType(), is(Boolean.class)); | ||
202 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
203 | } | ||
204 | |||
205 | @ParameterizedTest(name = "({0} > {1}) == {2}") | ||
206 | @CsvSource(value = { | ||
207 | "1, -2, true", | ||
208 | "1, 1, false", | ||
209 | "1, 2, false", | ||
210 | "null, 1, null", | ||
211 | "1, null, null", | ||
212 | "null, null, null" | ||
213 | }, nullValues = "null") | ||
214 | void greaterTest(Integer a, Integer b, Boolean result) { | ||
215 | var term = IntTerms.greater(IntTerms.constant(a), IntTerms.constant(b)); | ||
216 | assertThat(term.getType(), is(Boolean.class)); | ||
217 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
218 | } | ||
219 | |||
220 | @ParameterizedTest(name = "({0} >= {1}) == {2}") | ||
221 | @CsvSource(value = { | ||
222 | "1, -2, true", | ||
223 | "1, 1, true", | ||
224 | "1, 2, false", | ||
225 | "null, 1, null", | ||
226 | "1, null, null", | ||
227 | "null, null, null" | ||
228 | }, nullValues = "null") | ||
229 | void greaterEqTest(Integer a, Integer b, Boolean result) { | ||
230 | var term = IntTerms.greaterEq(IntTerms.constant(a), IntTerms.constant(b)); | ||
231 | assertThat(term.getType(), is(Boolean.class)); | ||
232 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
233 | } | ||
234 | |||
235 | @ParameterizedTest(name = "{0} as int == {1}") | ||
236 | @MethodSource | ||
237 | void asIntTest(Double a, Integer result) { | ||
238 | var term = IntTerms.asInt(RealTerms.constant(a)); | ||
239 | assertThat(term.getType(), is(Integer.class)); | ||
240 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
241 | } | ||
242 | |||
243 | static Stream<Arguments> asIntTest() { | ||
244 | return Stream.of( | ||
245 | Arguments.of(2.0, 2), | ||
246 | Arguments.of(2.1, 2), | ||
247 | Arguments.of(2.9, 2), | ||
248 | Arguments.of(-2.0, -2), | ||
249 | Arguments.of(-2.1, -2), | ||
250 | Arguments.of(-2.9, -2), | ||
251 | Arguments.of(0.0, 0), | ||
252 | Arguments.of(-0.0, 0), | ||
253 | Arguments.of(Double.POSITIVE_INFINITY, Integer.MAX_VALUE), | ||
254 | Arguments.of(Double.NEGATIVE_INFINITY, Integer.MIN_VALUE), | ||
255 | Arguments.of(Double.NaN, null), | ||
256 | Arguments.of(null, null) | ||
257 | ); | ||
258 | } | ||
259 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java new file mode 100644 index 00000000..6a8eebf1 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java | |||
@@ -0,0 +1,238 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.real; | ||
7 | |||
8 | import org.hamcrest.Matcher; | ||
9 | import org.junit.jupiter.params.ParameterizedTest; | ||
10 | import org.junit.jupiter.params.provider.CsvSource; | ||
11 | import tools.refinery.store.query.term.int_.IntTerms; | ||
12 | import tools.refinery.store.query.valuation.Valuation; | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat; | ||
15 | import static org.hamcrest.Matchers.*; | ||
16 | |||
17 | class RealTermEvaluateTest { | ||
18 | public static final double TOLERANCE = 1e-6; | ||
19 | |||
20 | private static Matcher<Double> closeToOrNull(Double expected) { | ||
21 | return expected == null ? nullValue(Double.class) : closeTo(expected, TOLERANCE); | ||
22 | } | ||
23 | |||
24 | @ParameterizedTest(name = "+{0} == {1}") | ||
25 | @CsvSource(value = { | ||
26 | "2.5, 2.5", | ||
27 | "null, null" | ||
28 | }, nullValues = "null") | ||
29 | void plusTest(Double a, Double result) { | ||
30 | var term = RealTerms.plus(RealTerms.constant(a)); | ||
31 | assertThat(term.getType(), is(Double.class)); | ||
32 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
33 | } | ||
34 | |||
35 | @ParameterizedTest(name = "-{0} == {1}") | ||
36 | @CsvSource(value = { | ||
37 | "2.5, -2.5", | ||
38 | "null, null" | ||
39 | }, nullValues = "null") | ||
40 | void minusTest(Double a, Double result) { | ||
41 | var term = RealTerms.minus(RealTerms.constant(a)); | ||
42 | assertThat(term.getType(), is(Double.class)); | ||
43 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
44 | } | ||
45 | |||
46 | @ParameterizedTest(name = "{0} + {1} == {2}") | ||
47 | @CsvSource(value = { | ||
48 | "1.2, 2.3, 3.5", | ||
49 | "null, 2.3, null", | ||
50 | "1.2, null, null", | ||
51 | "null, null, null" | ||
52 | }, nullValues = "null") | ||
53 | void addTest(Double a, Double b, Double result) { | ||
54 | var term = RealTerms.add(RealTerms.constant(a), RealTerms.constant(b)); | ||
55 | assertThat(term.getType(), is(Double.class)); | ||
56 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
57 | } | ||
58 | |||
59 | @ParameterizedTest(name = "{0} - {1} == {2}") | ||
60 | @CsvSource(value = { | ||
61 | "1.2, 3.4, -2.2", | ||
62 | "null, 3.4, null", | ||
63 | "1.2, null, null", | ||
64 | "null, null, null" | ||
65 | }, nullValues = "null") | ||
66 | void subTest(Double a, Double b, Double result) { | ||
67 | var term = RealTerms.sub(RealTerms.constant(a), RealTerms.constant(b)); | ||
68 | assertThat(term.getType(), is(Double.class)); | ||
69 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
70 | } | ||
71 | |||
72 | @ParameterizedTest(name = "{0} * {1} == {2}") | ||
73 | @CsvSource(value = { | ||
74 | "2.3, 3.4, 7.82", | ||
75 | "null, 3.4, null", | ||
76 | "2.3, null, null", | ||
77 | "null, null, null" | ||
78 | }, nullValues = "null") | ||
79 | void mulTest(Double a, Double b, Double result) { | ||
80 | var term = RealTerms.mul(RealTerms.constant(a), RealTerms.constant(b)); | ||
81 | assertThat(term.getType(), is(Double.class)); | ||
82 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
83 | } | ||
84 | |||
85 | @ParameterizedTest(name = "{0} * {1} == {2}") | ||
86 | @CsvSource(value = { | ||
87 | "7.82, 3.4, 2.3", | ||
88 | "null, 3.4, null", | ||
89 | "7.82, null, null", | ||
90 | "null, null, null" | ||
91 | }, nullValues = "null") | ||
92 | void divTest(Double a, Double b, Double result) { | ||
93 | var term = RealTerms.div(RealTerms.constant(a), RealTerms.constant(b)); | ||
94 | assertThat(term.getType(), is(Double.class)); | ||
95 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
96 | } | ||
97 | |||
98 | @ParameterizedTest(name = "{0} ** {1} == {2}") | ||
99 | @CsvSource(value = { | ||
100 | "2.0, 6.0, 64.0", | ||
101 | "null, 6.0, null", | ||
102 | "2.0, null, null", | ||
103 | "null, null, null" | ||
104 | }, nullValues = "null") | ||
105 | void powTest(Double a, Double b, Double result) { | ||
106 | var term = RealTerms.pow(RealTerms.constant(a), RealTerms.constant(b)); | ||
107 | assertThat(term.getType(), is(Double.class)); | ||
108 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
109 | } | ||
110 | |||
111 | @ParameterizedTest(name = "min({0}, {1}) == {2}") | ||
112 | @CsvSource(value = { | ||
113 | "1.5, 2.7, 1.5", | ||
114 | "2.7, 1.5, 1.5", | ||
115 | "null, 2.7, null", | ||
116 | "1.5, null, null", | ||
117 | "null, null, null" | ||
118 | }, nullValues = "null") | ||
119 | void minTest(Double a, Double b, Double result) { | ||
120 | var term = RealTerms.min(RealTerms.constant(a), RealTerms.constant(b)); | ||
121 | assertThat(term.getType(), is(Double.class)); | ||
122 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
123 | } | ||
124 | |||
125 | @ParameterizedTest(name = "max({0}, {1}) == {2}") | ||
126 | @CsvSource(value = { | ||
127 | "1.5, 2.7, 2.7", | ||
128 | "2.7, 1.7, 2.7", | ||
129 | "null, 2.7, null", | ||
130 | "1.5, null, null", | ||
131 | "null, null, null" | ||
132 | }, nullValues = "null") | ||
133 | void maxTest(Double a, Double b, Double result) { | ||
134 | var term = RealTerms.max(RealTerms.constant(a), RealTerms.constant(b)); | ||
135 | assertThat(term.getType(), is(Double.class)); | ||
136 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
137 | } | ||
138 | |||
139 | @ParameterizedTest(name = "({0} == {1}) == {2}") | ||
140 | @CsvSource(value = { | ||
141 | "1.5, 1.5, true", | ||
142 | "1.5, 2.7, false", | ||
143 | "null, 1.5, null", | ||
144 | "1.5, null, null", | ||
145 | "null, null, null" | ||
146 | }, nullValues = "null") | ||
147 | void eqTest(Double a, Double b, Boolean result) { | ||
148 | var term = RealTerms.eq(RealTerms.constant(a), RealTerms.constant(b)); | ||
149 | assertThat(term.getType(), is(Boolean.class)); | ||
150 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
151 | } | ||
152 | |||
153 | @ParameterizedTest(name = "({0} != {1}) == {2}") | ||
154 | @CsvSource(value = { | ||
155 | "1.5, 1.5, false", | ||
156 | "1.5, 2.7, true", | ||
157 | "null, 1.5, null", | ||
158 | "1.5, null, null", | ||
159 | "null, null, null" | ||
160 | }, nullValues = "null") | ||
161 | void notEqTest(Double a, Double b, Boolean result) { | ||
162 | var term = RealTerms.notEq(RealTerms.constant(a), RealTerms.constant(b)); | ||
163 | assertThat(term.getType(), is(Boolean.class)); | ||
164 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
165 | } | ||
166 | |||
167 | @ParameterizedTest(name = "({0} < {1}) == {2}") | ||
168 | @CsvSource(value = { | ||
169 | "1.5, -2.7, false", | ||
170 | "1.5, 1.5, false", | ||
171 | "1.5, 2.7, true", | ||
172 | "null, 1.5, null", | ||
173 | "1.5, null, null", | ||
174 | "null, null, null" | ||
175 | }, nullValues = "null") | ||
176 | void lessTest(Double a, Double b, Boolean result) { | ||
177 | var term = RealTerms.less(RealTerms.constant(a), RealTerms.constant(b)); | ||
178 | assertThat(term.getType(), is(Boolean.class)); | ||
179 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
180 | } | ||
181 | |||
182 | @ParameterizedTest(name = "({0} <= {1}) == {2}") | ||
183 | @CsvSource(value = { | ||
184 | "1.5, -2.7, false", | ||
185 | "1.5, 1.5, true", | ||
186 | "1.5, 2.7, true", | ||
187 | "null, 1.5, null", | ||
188 | "1.5, null, null", | ||
189 | "null, null, null" | ||
190 | }, nullValues = "null") | ||
191 | void lessEqTest(Double a, Double b, Boolean result) { | ||
192 | var term = RealTerms.lessEq(RealTerms.constant(a), RealTerms.constant(b)); | ||
193 | assertThat(term.getType(), is(Boolean.class)); | ||
194 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
195 | } | ||
196 | |||
197 | @ParameterizedTest(name = "({0} > {1}) == {2}") | ||
198 | @CsvSource(value = { | ||
199 | "1.5, -2.7, true", | ||
200 | "1.5, 1.5, false", | ||
201 | "1.5, 2.7, false", | ||
202 | "null, 1.5, null", | ||
203 | "1.5, null, null", | ||
204 | "null, null, null" | ||
205 | }, nullValues = "null") | ||
206 | void greaterTest(Double a, Double b, Boolean result) { | ||
207 | var term = RealTerms.greater(RealTerms.constant(a), RealTerms.constant(b)); | ||
208 | assertThat(term.getType(), is(Boolean.class)); | ||
209 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
210 | } | ||
211 | |||
212 | @ParameterizedTest(name = "({0} >= {1}) == {2}") | ||
213 | @CsvSource(value = { | ||
214 | "1.5, -2.7, true", | ||
215 | "1.5, 1.5, true", | ||
216 | "1.5, 2.7, false", | ||
217 | "null, 1.5, null", | ||
218 | "1.5, null, null", | ||
219 | "null, null, null" | ||
220 | }, nullValues = "null") | ||
221 | void greaterEqTest(Double a, Double b, Boolean result) { | ||
222 | var term = RealTerms.greaterEq(RealTerms.constant(a), RealTerms.constant(b)); | ||
223 | assertThat(term.getType(), is(Boolean.class)); | ||
224 | assertThat(term.evaluate(Valuation.empty()), is(result)); | ||
225 | } | ||
226 | |||
227 | @ParameterizedTest(name = "{0} as real == {1}") | ||
228 | @CsvSource(value = { | ||
229 | "0, 0.0", | ||
230 | "5, 5.0", | ||
231 | "null, null" | ||
232 | }, nullValues = "null") | ||
233 | void asRealTest(Integer a, Double result) { | ||
234 | var term = RealTerms.asReal(IntTerms.constant(a)); | ||
235 | assertThat(term.getType(), is(Double.class)); | ||
236 | assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); | ||
237 | } | ||
238 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java index 53d03cbd..31baf36e 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.store.query.viatra.internal.cardinality; | 6 | package tools.refinery.store.query.term.uppercardinality; |
7 | 7 | ||
8 | import org.junit.jupiter.params.ParameterizedTest; | 8 | import org.junit.jupiter.params.ParameterizedTest; |
9 | import org.junit.jupiter.params.provider.Arguments; | 9 | import org.junit.jupiter.params.provider.Arguments; |
@@ -15,14 +15,14 @@ import java.util.List; | |||
15 | import java.util.stream.Stream; | 15 | import java.util.stream.Stream; |
16 | 16 | ||
17 | import static org.hamcrest.MatcherAssert.assertThat; | 17 | import static org.hamcrest.MatcherAssert.assertThat; |
18 | import static org.hamcrest.Matchers.equalTo; | 18 | import static org.hamcrest.Matchers.is; |
19 | 19 | ||
20 | class UpperCardinalitySumAggregationOperatorStreamTest { | 20 | class UpperCardinalitySumAggregatorStreamTest { |
21 | @ParameterizedTest | 21 | @ParameterizedTest |
22 | @MethodSource | 22 | @MethodSource |
23 | void testStream(List<UpperCardinality> list, UpperCardinality expected) { | 23 | void testStream(List<UpperCardinality> list, UpperCardinality expected) { |
24 | var result = UpperCardinalitySumAggregationOperator.INSTANCE.aggregateStream(list.stream()); | 24 | var result = UpperCardinalitySumAggregator.INSTANCE.aggregateStream(list.stream()); |
25 | assertThat(result, equalTo(expected)); | 25 | assertThat(result, is(expected)); |
26 | } | 26 | } |
27 | 27 | ||
28 | static Stream<Arguments> testStream() { | 28 | static Stream<Arguments> testStream() { |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java new file mode 100644 index 00000000..780cd0ab --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.query.term.StatefulAggregate; | ||
11 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
12 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat; | ||
15 | import static org.hamcrest.Matchers.is; | ||
16 | |||
17 | class UpperCardinalitySumAggregatorTest { | ||
18 | private StatefulAggregate<UpperCardinality, UpperCardinality> accumulator; | ||
19 | |||
20 | @BeforeEach | ||
21 | void beforeEach() { | ||
22 | accumulator = UpperCardinalitySumAggregator.INSTANCE.createEmptyAggregate(); | ||
23 | } | ||
24 | |||
25 | @Test | ||
26 | void emptyAggregationTest() { | ||
27 | assertThat(accumulator.getResult(), is(UpperCardinality.of(0))); | ||
28 | } | ||
29 | |||
30 | @Test | ||
31 | void singleBoundedTest() { | ||
32 | accumulator.add(UpperCardinality.of(3)); | ||
33 | assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); | ||
34 | } | ||
35 | |||
36 | @Test | ||
37 | void multipleBoundedTest() { | ||
38 | accumulator.add(UpperCardinality.of(2)); | ||
39 | accumulator.add(UpperCardinality.of(3)); | ||
40 | assertThat(accumulator.getResult(), is(UpperCardinality.of(5))); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void singleUnboundedTest() { | ||
45 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
46 | assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); | ||
47 | } | ||
48 | |||
49 | @Test | ||
50 | void multipleUnboundedTest() { | ||
51 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
52 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
53 | assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); | ||
54 | } | ||
55 | |||
56 | @Test | ||
57 | void removeBoundedTest() { | ||
58 | accumulator.add(UpperCardinality.of(2)); | ||
59 | accumulator.add(UpperCardinality.of(3)); | ||
60 | accumulator.remove(UpperCardinality.of(2)); | ||
61 | assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); | ||
62 | } | ||
63 | |||
64 | @Test | ||
65 | void removeAllUnboundedTest() { | ||
66 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
67 | accumulator.add(UpperCardinality.of(3)); | ||
68 | accumulator.remove(UpperCardinalities.UNBOUNDED); | ||
69 | assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); | ||
70 | } | ||
71 | |||
72 | @Test | ||
73 | void removeSomeUnboundedTest() { | ||
74 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
75 | accumulator.add(UpperCardinalities.UNBOUNDED); | ||
76 | accumulator.add(UpperCardinality.of(3)); | ||
77 | accumulator.remove(UpperCardinalities.UNBOUNDED); | ||
78 | assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); | ||
79 | } | ||
80 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java new file mode 100644 index 00000000..9d0f3bde --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.term.uppercardinality; | ||
7 | |||
8 | import org.junit.jupiter.params.ParameterizedTest; | ||
9 | import org.junit.jupiter.params.provider.Arguments; | ||
10 | import org.junit.jupiter.params.provider.MethodSource; | ||
11 | import tools.refinery.store.query.valuation.Valuation; | ||
12 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
13 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
14 | |||
15 | import java.util.stream.Stream; | ||
16 | |||
17 | import static org.hamcrest.MatcherAssert.assertThat; | ||
18 | import static org.hamcrest.Matchers.is; | ||
19 | |||
20 | class UpperCardinalityTermsEvaluateTest { | ||
21 | @ParameterizedTest(name = "min({0}, {1}) == {2}") | ||
22 | @MethodSource | ||
23 | void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { | ||
24 | var term = UpperCardinalityTerms.min(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); | ||
25 | assertThat(term.getType(), is(UpperCardinality.class)); | ||
26 | assertThat(term.evaluate(Valuation.empty()), is(expected)); | ||
27 | } | ||
28 | |||
29 | static Stream<Arguments> minTest() { | ||
30 | return Stream.of( | ||
31 | Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)), | ||
32 | Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)), | ||
33 | Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)), | ||
34 | Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)), | ||
35 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)), | ||
36 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
37 | Arguments.of(UpperCardinality.of(1), null, null), | ||
38 | Arguments.of(null, UpperCardinality.of(1), null), | ||
39 | Arguments.of(null, null, null) | ||
40 | ); | ||
41 | } | ||
42 | |||
43 | @ParameterizedTest(name = "max({0}, {1}) == {2}") | ||
44 | @MethodSource | ||
45 | void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { | ||
46 | var term = UpperCardinalityTerms.max(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); | ||
47 | assertThat(term.getType(), is(UpperCardinality.class)); | ||
48 | assertThat(term.evaluate(Valuation.empty()), is(expected)); | ||
49 | } | ||
50 | |||
51 | static Stream<Arguments> maxTest() { | ||
52 | return Stream.of( | ||
53 | Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)), | ||
54 | Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)), | ||
55 | Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)), | ||
56 | Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
57 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED), | ||
58 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
59 | Arguments.of(UpperCardinality.of(1), null, null), | ||
60 | Arguments.of(null, UpperCardinality.of(1), null), | ||
61 | Arguments.of(null, null, null) | ||
62 | ); | ||
63 | } | ||
64 | |||
65 | @ParameterizedTest(name = "{0} + {1} == {2}") | ||
66 | @MethodSource | ||
67 | void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { | ||
68 | var term = UpperCardinalityTerms.add(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); | ||
69 | assertThat(term.getType(), is(UpperCardinality.class)); | ||
70 | assertThat(term.evaluate(Valuation.empty()), is(expected)); | ||
71 | } | ||
72 | |||
73 | static Stream<Arguments> addTest() { | ||
74 | return Stream.of( | ||
75 | Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)), | ||
76 | Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
77 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED), | ||
78 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
79 | Arguments.of(UpperCardinality.of(1), null, null), | ||
80 | Arguments.of(null, UpperCardinality.of(1), null), | ||
81 | Arguments.of(null, null, null) | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | @ParameterizedTest(name = "{0} * {1} == {2}") | ||
86 | @MethodSource | ||
87 | void mulTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { | ||
88 | var term = UpperCardinalityTerms.mul(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); | ||
89 | assertThat(term.getType(), is(UpperCardinality.class)); | ||
90 | assertThat(term.evaluate(Valuation.empty()), is(expected)); | ||
91 | } | ||
92 | |||
93 | static Stream<Arguments> mulTest() { | ||
94 | return Stream.of( | ||
95 | Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)), | ||
96 | Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
97 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED), | ||
98 | Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), | ||
99 | Arguments.of(UpperCardinality.of(1), null, null), | ||
100 | Arguments.of(null, UpperCardinality.of(1), null), | ||
101 | Arguments.of(null, null, null) | ||
102 | ); | ||
103 | } | ||
104 | } | ||
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java index dd7a018d..d6a9e02c 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java | |||
@@ -5,11 +5,11 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.translator; | 6 | package tools.refinery.store.reasoning.translator; |
7 | 7 | ||
8 | import tools.refinery.store.query.substitution.Substitution; | ||
8 | import tools.refinery.store.reasoning.representation.AnyPartialSymbol; | 9 | import tools.refinery.store.reasoning.representation.AnyPartialSymbol; |
9 | import tools.refinery.store.reasoning.representation.PartialRelation; | 10 | import tools.refinery.store.reasoning.representation.PartialRelation; |
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
11 | import tools.refinery.store.query.literal.Literal; | 12 | import tools.refinery.store.query.literal.Literal; |
12 | import tools.refinery.store.query.substitution.Substitutions; | ||
13 | 13 | ||
14 | import java.util.*; | 14 | import java.util.*; |
15 | 15 | ||
@@ -66,14 +66,9 @@ public final class Advice { | |||
66 | public List<Literal> substitute(List<Variable> substituteParameters) { | 66 | public List<Literal> substitute(List<Variable> substituteParameters) { |
67 | checkArity(substituteParameters); | 67 | checkArity(substituteParameters); |
68 | markProcessed(); | 68 | markProcessed(); |
69 | int arity = parameters.size(); | ||
70 | var variableMap = new HashMap<Variable, Variable>(arity); | ||
71 | for (int i = 0; i < arity; i++) { | ||
72 | variableMap.put(parameters.get(i), substituteParameters.get(i)); | ||
73 | } | ||
74 | // Use a renewing substitution to remove any non-parameter variables and avoid clashed between variables | 69 | // Use a renewing substitution to remove any non-parameter variables and avoid clashed between variables |
75 | // coming from different advice in the same clause. | 70 | // coming from different advice in the same clause. |
76 | var substitution = Substitutions.renewing(variableMap); | 71 | var substitution = Substitution.builder().putManyChecked(parameters, substituteParameters).renewing().build(); |
77 | return literals.stream().map(literal -> literal.substitute(substitution)).toList(); | 72 | return literals.stream().map(literal -> literal.substitute(substitution)).toList(); |
78 | } | 73 | } |
79 | 74 | ||