diff options
10 files changed, 146 insertions, 22 deletions
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java index 297cdf04..25bcb0dc 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java | |||
@@ -572,6 +572,78 @@ class QueryTest { | |||
572 | ), predicateResultSet); | 572 | ), predicateResultSet); |
573 | } | 573 | } |
574 | 574 | ||
575 | @Test | ||
576 | void filteredIntegerViewTest() { | ||
577 | var distance = Symbol.of("distance", 2, Integer.class); | ||
578 | var nearView = new FilteredView<>(distance, value -> value < 2); | ||
579 | var farView = new FilteredView<>(distance, value -> value >= 5); | ||
580 | var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( | ||
581 | a1.notEquivalent(a2), | ||
582 | nearView.call(a1, a3), | ||
583 | nearView.call(a2, a3), | ||
584 | not(farView.call(a1, a2)) | ||
585 | ))); | ||
586 | var store = ModelStore.builder() | ||
587 | .symbols(distance) | ||
588 | .with(ViatraModelQueryAdapter.builder() | ||
589 | .queries(dangerQuery)) | ||
590 | .build(); | ||
591 | |||
592 | var model = store.createEmptyModel(); | ||
593 | var distanceInterpretation = model.getInterpretation(distance); | ||
594 | distanceInterpretation.put(Tuple.of(0, 1), 1); | ||
595 | distanceInterpretation.put(Tuple.of(1, 0), 1); | ||
596 | distanceInterpretation.put(Tuple.of(0, 2), 1); | ||
597 | distanceInterpretation.put(Tuple.of(2, 0), 1); | ||
598 | distanceInterpretation.put(Tuple.of(1, 2), 3); | ||
599 | distanceInterpretation.put(Tuple.of(2, 1), 3); | ||
600 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
601 | var dangerResultSet = queryEngine.getResultSet(dangerQuery); | ||
602 | queryEngine.flushChanges(); | ||
603 | assertResults(Map.of( | ||
604 | Tuple.of(0, 1), false, | ||
605 | Tuple.of(0, 2), false, | ||
606 | Tuple.of(1, 2), true, | ||
607 | Tuple.of(2, 1), true | ||
608 | ), dangerResultSet); | ||
609 | } | ||
610 | |||
611 | @Test | ||
612 | void filteredDoubleViewTest() { | ||
613 | var distance = Symbol.of("distance", 2, Double.class); | ||
614 | var nearView = new FilteredView<>(distance, value -> value < 2); | ||
615 | var farView = new FilteredView<>(distance, value -> value >= 5); | ||
616 | var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( | ||
617 | a1.notEquivalent(a2), | ||
618 | nearView.call(a1, a3), | ||
619 | nearView.call(a2, a3), | ||
620 | not(farView.call(a1, a2)) | ||
621 | ))); | ||
622 | var store = ModelStore.builder() | ||
623 | .symbols(distance) | ||
624 | .with(ViatraModelQueryAdapter.builder() | ||
625 | .queries(dangerQuery)) | ||
626 | .build(); | ||
627 | |||
628 | var model = store.createEmptyModel(); | ||
629 | var distanceInterpretation = model.getInterpretation(distance); | ||
630 | distanceInterpretation.put(Tuple.of(0, 1), 1.0); | ||
631 | distanceInterpretation.put(Tuple.of(1, 0), 1.0); | ||
632 | distanceInterpretation.put(Tuple.of(0, 2), 1.0); | ||
633 | distanceInterpretation.put(Tuple.of(2, 0), 1.0); | ||
634 | distanceInterpretation.put(Tuple.of(1, 2), 3.0); | ||
635 | distanceInterpretation.put(Tuple.of(2, 1), 3.0); | ||
636 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
637 | var dangerResultSet = queryEngine.getResultSet(dangerQuery); | ||
638 | queryEngine.flushChanges(); | ||
639 | assertResults(Map.of( | ||
640 | Tuple.of(0, 1), false, | ||
641 | Tuple.of(0, 2), false, | ||
642 | Tuple.of(1, 2), true, | ||
643 | Tuple.of(2, 1), true | ||
644 | ), dangerResultSet); | ||
645 | } | ||
646 | |||
575 | @QueryEngineTest | 647 | @QueryEngineTest |
576 | void assumeTest(QueryEvaluationHint hint) { | 648 | void assumeTest(QueryEvaluationHint hint) { |
577 | var age = Symbol.of("age", 1, Integer.class); | 649 | var age = Symbol.of("age", 1, Integer.class); |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java index c1f9d688..fd37604e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java | |||
@@ -20,12 +20,10 @@ import java.util.stream.Collectors; | |||
20 | import java.util.stream.IntStream; | 20 | import java.util.stream.IntStream; |
21 | 21 | ||
22 | public abstract class AbstractFunctionView<T> extends SymbolView<T> { | 22 | public abstract class AbstractFunctionView<T> extends SymbolView<T> { |
23 | private final T defaultValue; | ||
24 | private final List<Parameter> parameters; | 23 | private final List<Parameter> parameters; |
25 | 24 | ||
26 | protected AbstractFunctionView(Symbol<T> symbol, String name, Parameter outParameter) { | 25 | protected AbstractFunctionView(Symbol<T> symbol, String name, Parameter outParameter) { |
27 | super(symbol, name); | 26 | super(symbol, name); |
28 | defaultValue = symbol.defaultValue(); | ||
29 | parameters = createParameters(symbol.arity(), outParameter); | 27 | parameters = createParameters(symbol.arity(), outParameter); |
30 | } | 28 | } |
31 | 29 | ||
@@ -46,16 +44,16 @@ public abstract class AbstractFunctionView<T> extends SymbolView<T> { | |||
46 | } | 44 | } |
47 | 45 | ||
48 | @Override | 46 | @Override |
49 | public final boolean filter(Tuple key, T value) { | 47 | protected boolean doFilter(Tuple key, T value) { |
50 | return !Objects.equals(defaultValue, value); | 48 | return true; |
51 | } | 49 | } |
52 | 50 | ||
53 | protected Object forwardMapValue(Tuple key, T value) { | 51 | protected Object forwardMapValue(T value) { |
54 | return value; | 52 | return value; |
55 | } | 53 | } |
56 | 54 | ||
57 | protected boolean valueEquals(Tuple key, T value, Object otherForwardMappedValue) { | 55 | protected boolean valueEquals(T value, Object otherForwardMappedValue) { |
58 | return Objects.equals(otherForwardMappedValue, forwardMapValue(key, value)); | 56 | return Objects.equals(otherForwardMappedValue, forwardMapValue(value)); |
59 | } | 57 | } |
60 | 58 | ||
61 | @Override | 59 | @Override |
@@ -65,7 +63,7 @@ public abstract class AbstractFunctionView<T> extends SymbolView<T> { | |||
65 | for (int i = 0; i < size; i++) { | 63 | for (int i = 0; i < size; i++) { |
66 | result[i] = Tuple.of(key.get(i)); | 64 | result[i] = Tuple.of(key.get(i)); |
67 | } | 65 | } |
68 | result[key.getSize()] = forwardMapValue(key, value); | 66 | result[key.getSize()] = forwardMapValue(value); |
69 | return result; | 67 | return result; |
70 | } | 68 | } |
71 | 69 | ||
@@ -81,7 +79,7 @@ public abstract class AbstractFunctionView<T> extends SymbolView<T> { | |||
81 | Tuple key = Tuple.of(content); | 79 | Tuple key = Tuple.of(content); |
82 | var valueInTuple = tuple[tuple.length - 1]; | 80 | var valueInTuple = tuple[tuple.length - 1]; |
83 | T valueInMap = model.getInterpretation(getSymbol()).get(key); | 81 | T valueInMap = model.getInterpretation(getSymbol()).get(key); |
84 | return valueEquals(key, valueInMap, valueInTuple); | 82 | return valueEquals(valueInMap, valueInTuple); |
85 | } | 83 | } |
86 | 84 | ||
87 | @Override | 85 | @Override |
@@ -95,12 +93,12 @@ public abstract class AbstractFunctionView<T> extends SymbolView<T> { | |||
95 | if (o == null || getClass() != o.getClass()) return false; | 93 | if (o == null || getClass() != o.getClass()) return false; |
96 | if (!super.equals(o)) return false; | 94 | if (!super.equals(o)) return false; |
97 | AbstractFunctionView<?> that = (AbstractFunctionView<?>) o; | 95 | AbstractFunctionView<?> that = (AbstractFunctionView<?>) o; |
98 | return Objects.equals(defaultValue, that.defaultValue) && Objects.equals(parameters, that.parameters); | 96 | return Objects.equals(parameters, that.parameters); |
99 | } | 97 | } |
100 | 98 | ||
101 | @Override | 99 | @Override |
102 | public int hashCode() { | 100 | public int hashCode() { |
103 | return Objects.hash(super.hashCode(), defaultValue, parameters); | 101 | return Objects.hash(super.hashCode(), parameters); |
104 | } | 102 | } |
105 | 103 | ||
106 | private static List<Parameter> createParameters(int symbolArity, Parameter outParameter) { | 104 | private static List<Parameter> createParameters(int symbolArity, Parameter outParameter) { |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java index 922c7355..abae6e5c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java | |||
@@ -27,14 +27,16 @@ public class FilteredView<T> extends TuplePreservingView<T> { | |||
27 | 27 | ||
28 | public FilteredView(Symbol<T> symbol, String name, Predicate<T> predicate) { | 28 | public FilteredView(Symbol<T> symbol, String name, Predicate<T> predicate) { |
29 | this(symbol, name, (k, v) -> predicate.test(v)); | 29 | this(symbol, name, (k, v) -> predicate.test(v)); |
30 | validateDefaultValue(predicate); | ||
30 | } | 31 | } |
31 | 32 | ||
32 | public FilteredView(Symbol<T> symbol, Predicate<T> predicate) { | 33 | public FilteredView(Symbol<T> symbol, Predicate<T> predicate) { |
33 | this(symbol, (k, v) -> predicate.test(v)); | 34 | this(symbol, (k, v) -> predicate.test(v)); |
35 | validateDefaultValue(predicate); | ||
34 | } | 36 | } |
35 | 37 | ||
36 | @Override | 38 | @Override |
37 | public boolean filter(Tuple key, T value) { | 39 | protected boolean doFilter(Tuple key, T value) { |
38 | return this.predicate.test(key, value); | 40 | return this.predicate.test(key, value); |
39 | } | 41 | } |
40 | 42 | ||
@@ -51,4 +53,21 @@ public class FilteredView<T> extends TuplePreservingView<T> { | |||
51 | public int hashCode() { | 53 | public int hashCode() { |
52 | return Objects.hash(super.hashCode(), predicate); | 54 | return Objects.hash(super.hashCode(), predicate); |
53 | } | 55 | } |
56 | |||
57 | private void validateDefaultValue(Predicate<T> predicate) { | ||
58 | var defaultValue = getSymbol().defaultValue(); | ||
59 | boolean matchesDefaultValue = false; | ||
60 | try { | ||
61 | matchesDefaultValue = predicate.test(defaultValue); | ||
62 | } catch (NullPointerException e) { | ||
63 | if (defaultValue != null) { | ||
64 | throw e; | ||
65 | } | ||
66 | // The predicate doesn't need to handle the default value if it is null. | ||
67 | } | ||
68 | if (matchesDefaultValue) { | ||
69 | throw new IllegalArgumentException("Tuples with default value %s cannot be enumerated in %s" | ||
70 | .formatted(defaultValue, getSymbol())); | ||
71 | } | ||
72 | } | ||
54 | } | 73 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java index 26b717ee..c312330e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java | |||
@@ -15,7 +15,7 @@ public class ForbiddenView extends TuplePreservingView<TruthValue> { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | @Override | 17 | @Override |
18 | public boolean filter(Tuple key, TruthValue value) { | 18 | protected boolean doFilter(Tuple key, TruthValue value) { |
19 | return !value.may(); | 19 | return !value.may(); |
20 | } | 20 | } |
21 | } | 21 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java index 7e86f6e4..f0e4a61e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java | |||
@@ -21,8 +21,8 @@ public final class KeyOnlyView<T> extends TuplePreservingView<T> { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | @Override | 23 | @Override |
24 | public boolean filter(Tuple key, T value) { | 24 | protected boolean doFilter(Tuple key, T value) { |
25 | return !Objects.equals(value, defaultValue); | 25 | return true; |
26 | } | 26 | } |
27 | 27 | ||
28 | @Override | 28 | @Override |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java index e75a8171..c322e220 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java | |||
@@ -15,7 +15,7 @@ public class MayView extends TuplePreservingView<TruthValue> { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | @Override | 17 | @Override |
18 | public boolean filter(Tuple key, TruthValue value) { | 18 | protected boolean doFilter(Tuple key, TruthValue value) { |
19 | return value.may(); | 19 | return value.may(); |
20 | } | 20 | } |
21 | } | 21 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java index a48f8045..65bb4e4c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java | |||
@@ -15,7 +15,7 @@ public class MustView extends TuplePreservingView<TruthValue> { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | @Override | 17 | @Override |
18 | public boolean filter(Tuple key, TruthValue value) { | 18 | protected boolean doFilter(Tuple key, TruthValue value) { |
19 | return value.must(); | 19 | return value.must(); |
20 | } | 20 | } |
21 | } | 21 | } |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java index 267a99d3..cd8bd56b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java | |||
@@ -21,7 +21,6 @@ import java.util.UUID; | |||
21 | */ | 21 | */ |
22 | public abstract non-sealed class SymbolView<T> implements AnySymbolView { | 22 | public abstract non-sealed class SymbolView<T> implements AnySymbolView { |
23 | private final Symbol<T> symbol; | 23 | private final Symbol<T> symbol; |
24 | |||
25 | private final String viewName; | 24 | private final String viewName; |
26 | 25 | ||
27 | protected SymbolView(Symbol<T> symbol, String viewName) { | 26 | protected SymbolView(Symbol<T> symbol, String viewName) { |
@@ -48,7 +47,11 @@ public abstract non-sealed class SymbolView<T> implements AnySymbolView { | |||
48 | return symbol.name() + "#" + viewName; | 47 | return symbol.name() + "#" + viewName; |
49 | } | 48 | } |
50 | 49 | ||
51 | public abstract boolean filter(Tuple key, T value); | 50 | public final boolean filter(Tuple key, T value) { |
51 | return !Objects.equals(symbol.defaultValue(), value) && doFilter(key, value); | ||
52 | } | ||
53 | |||
54 | protected abstract boolean doFilter(Tuple key, T value); | ||
52 | 55 | ||
53 | public abstract Object[] forwardMap(Tuple key, T value); | 56 | public abstract Object[] forwardMap(Tuple key, T value); |
54 | 57 | ||
@@ -77,6 +80,6 @@ public abstract non-sealed class SymbolView<T> implements AnySymbolView { | |||
77 | 80 | ||
78 | @Override | 81 | @Override |
79 | public int hashCode() { | 82 | public int hashCode() { |
80 | return Objects.hash(symbol, viewName); | 83 | return Objects.hash(getClass(), symbol, viewName); |
81 | } | 84 | } |
82 | } | 85 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java index ce2d6ff3..40de4644 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java | |||
@@ -9,6 +9,8 @@ import tools.refinery.store.reasoning.representation.PartialRelation; | |||
9 | import tools.refinery.store.query.view.TuplePreservingView; | 9 | import tools.refinery.store.query.view.TuplePreservingView; |
10 | import tools.refinery.store.tuple.Tuple; | 10 | import tools.refinery.store.tuple.Tuple; |
11 | 11 | ||
12 | import java.util.Objects; | ||
13 | |||
12 | class InferredMayTypeView extends TuplePreservingView<InferredType> { | 14 | class InferredMayTypeView extends TuplePreservingView<InferredType> { |
13 | private final PartialRelation type; | 15 | private final PartialRelation type; |
14 | 16 | ||
@@ -18,7 +20,21 @@ class InferredMayTypeView extends TuplePreservingView<InferredType> { | |||
18 | } | 20 | } |
19 | 21 | ||
20 | @Override | 22 | @Override |
21 | public boolean filter(Tuple key, InferredType value) { | 23 | protected boolean doFilter(Tuple key, InferredType value) { |
22 | return value.mayConcreteTypes().contains(type); | 24 | return value.mayConcreteTypes().contains(type); |
23 | } | 25 | } |
26 | |||
27 | @Override | ||
28 | public boolean equals(Object o) { | ||
29 | if (this == o) return true; | ||
30 | if (o == null || getClass() != o.getClass()) return false; | ||
31 | if (!super.equals(o)) return false; | ||
32 | InferredMayTypeView that = (InferredMayTypeView) o; | ||
33 | return Objects.equals(type, that.type); | ||
34 | } | ||
35 | |||
36 | @Override | ||
37 | public int hashCode() { | ||
38 | return Objects.hash(super.hashCode(), type); | ||
39 | } | ||
24 | } | 40 | } |
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java index beda1796..1a121547 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java | |||
@@ -9,6 +9,8 @@ import tools.refinery.store.reasoning.representation.PartialRelation; | |||
9 | import tools.refinery.store.query.view.TuplePreservingView; | 9 | import tools.refinery.store.query.view.TuplePreservingView; |
10 | import tools.refinery.store.tuple.Tuple; | 10 | import tools.refinery.store.tuple.Tuple; |
11 | 11 | ||
12 | import java.util.Objects; | ||
13 | |||
12 | class InferredMustTypeView extends TuplePreservingView<InferredType> { | 14 | class InferredMustTypeView extends TuplePreservingView<InferredType> { |
13 | private final PartialRelation type; | 15 | private final PartialRelation type; |
14 | 16 | ||
@@ -18,7 +20,21 @@ class InferredMustTypeView extends TuplePreservingView<InferredType> { | |||
18 | } | 20 | } |
19 | 21 | ||
20 | @Override | 22 | @Override |
21 | public boolean filter(Tuple key, InferredType value) { | 23 | protected boolean doFilter(Tuple key, InferredType value) { |
22 | return value.mustTypes().contains(type); | 24 | return value.mustTypes().contains(type); |
23 | } | 25 | } |
26 | |||
27 | @Override | ||
28 | public boolean equals(Object o) { | ||
29 | if (this == o) return true; | ||
30 | if (o == null || getClass() != o.getClass()) return false; | ||
31 | if (!super.equals(o)) return false; | ||
32 | InferredMustTypeView that = (InferredMustTypeView) o; | ||
33 | return Objects.equals(type, that.type); | ||
34 | } | ||
35 | |||
36 | @Override | ||
37 | public int hashCode() { | ||
38 | return Objects.hash(super.hashCode(), type); | ||
39 | } | ||
24 | } | 40 | } |