From 1f8a0c703b7c221e09333cca3208a084e0109269 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 9 Feb 2023 18:18:03 +0100 Subject: refactor: EDSL for DNF literals --- .../refinery/store/query/viatra/QueryTest.java | 117 ++++++++++----------- .../store/query/viatra/QueryTransactionTest.java | 3 +- .../main/java/tools/refinery/store/query/Dnf.java | 18 ++++ .../java/tools/refinery/store/query/Variable.java | 15 +++ .../refinery/store/query/literal/CallPolarity.java | 8 +- .../store/query/literal/DnfCallLiteral.java | 23 +--- .../store/query/literal/EquivalenceLiteral.java | 12 ++- .../refinery/store/query/literal/Literals.java | 11 ++ .../refinery/store/query/literal/PolarLiteral.java | 5 + .../store/query/literal/RelationViewLiteral.java | 24 +---- .../refinery/store/query/view/RelationView.java | 20 ++++ 11 files changed, 149 insertions(+), 107 deletions(-) create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/Literals.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java (limited to 'subprojects') 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 471fdfc9..6a3a62e3 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 @@ -5,10 +5,6 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.DnfCallLiteral; -import tools.refinery.store.query.literal.EquivalenceLiteral; -import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.query.view.FilteredRelationView; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; @@ -21,6 +17,7 @@ import java.util.Set; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; +import static tools.refinery.store.query.literal.Literals.not; class QueryTest { @Test @@ -32,7 +29,7 @@ class QueryTest { var p1 = new Variable("p1"); var predicate = Dnf.builder("TypeConstraint") .parameters(p1) - .clause(new RelationViewLiteral(personView, p1)) + .clause(personView.call(p1)) .build(); var store = ModelStore.builder() @@ -70,9 +67,9 @@ class QueryTest { var predicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -117,10 +114,10 @@ class QueryTest { var predicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2), - new RelationViewLiteral(friendMustView, p2, p1) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2), + friendMustView.call(p2, p1) ) .build(); @@ -172,9 +169,9 @@ class QueryTest { var predicate = Dnf.builder("RelationConstraint") .parameters(p1) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -219,14 +216,14 @@ class QueryTest { var predicate = Dnf.builder("Or") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .clause( - new RelationViewLiteral(animalView, p1), - new RelationViewLiteral(animalView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + animalView.call(p1), + animalView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -269,9 +266,9 @@ class QueryTest { var predicate = Dnf.builder("Equality") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new EquivalenceLiteral(p1, p2) + personView.call(p1), + personView.call(p2), + p1.isEquivalent(p2) ) .build(); @@ -308,11 +305,11 @@ class QueryTest { var predicate = Dnf.builder("Inequality") .parameters(p1, p2, p3) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p3), - new RelationViewLiteral(friendMustView, p2, p3), - new EquivalenceLiteral(false, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p3), + friendMustView.call(p2, p3), + p1.notEquivalent(p2) ) .build(); @@ -352,9 +349,9 @@ class QueryTest { var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -363,9 +360,9 @@ class QueryTest { var predicate = Dnf.builder("PositivePatternCall") .parameters(p3, p4) .clause( - new RelationViewLiteral(personView, p3), - new RelationViewLiteral(personView, p4), - new DnfCallLiteral(friendPredicate, p3, p4) + personView.call(p3), + personView.call(p4), + friendPredicate.call(p3, p4) ) .build(); @@ -405,9 +402,9 @@ class QueryTest { var predicate = Dnf.builder("NegativePatternCall") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(false, friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + not(friendMustView.call(p1, p2)) ) .build(); @@ -447,9 +444,9 @@ class QueryTest { var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -458,9 +455,9 @@ class QueryTest { var predicate = Dnf.builder("NegativePatternCall") .parameters(p3, p4) .clause( - new RelationViewLiteral(personView, p3), - new RelationViewLiteral(personView, p4), - new DnfCallLiteral(false, friendPredicate, p3, p4) + personView.call(p3), + personView.call(p4), + not(friendPredicate.call(p3, p4)) ) .build(); @@ -501,8 +498,8 @@ class QueryTest { var predicate = Dnf.builder("Count") .parameters(p1) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(false, friendMustView, p1, p2) + personView.call(p1), + not(friendMustView.call(p1, p2)) ) .build(); @@ -542,17 +539,17 @@ class QueryTest { var called = Dnf.builder("Called") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); var predicate = Dnf.builder("Count") .parameters(p1) .clause( - new RelationViewLiteral(personView, p1), - new DnfCallLiteral(false, called, p1, p2) + personView.call(p1), + not(called.call(p1, p2)) ) .build(); @@ -591,9 +588,9 @@ class QueryTest { var predicate = Dnf.builder("TransitivePatternCall") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(CallPolarity.TRANSITIVE, friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.callTransitive(p1, p2) ) .build(); @@ -632,9 +629,9 @@ class QueryTest { var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewLiteral(personView, p1), - new RelationViewLiteral(personView, p2), - new RelationViewLiteral(friendMustView, p1, p2) + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) ) .build(); @@ -643,9 +640,9 @@ class QueryTest { var predicate = Dnf.builder("TransitivePatternCall") .parameters(p3, p4) .clause( - new RelationViewLiteral(personView, p3), - new RelationViewLiteral(personView, p4), - new DnfCallLiteral(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) + personView.call(p3), + personView.call(p4), + friendPredicate.callTransitive(p3, p4) ) .build(); diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java index 99b942d2..461685b5 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java @@ -5,7 +5,6 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; @@ -22,7 +21,7 @@ class QueryTransactionTest { var p1 = new Variable("p1"); var predicate = Dnf.builder("TypeConstraint") .parameters(p1) - .clause(new RelationViewLiteral(personView, p1)) + .clause(personView.call(p1)) .build(); var store = ModelStore.builder() diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java b/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java index f7b27b81..1eb9ac76 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java @@ -1,5 +1,7 @@ package tools.refinery.store.query; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.DnfCallLiteral; import tools.refinery.store.query.literal.Literal; import java.util.*; @@ -72,6 +74,22 @@ public final class Dnf implements RelationLike { return clauses; } + public DnfCallLiteral call(CallPolarity polarity, List substitution) { + return new DnfCallLiteral(polarity, this, substitution); + } + + public DnfCallLiteral call(CallPolarity polarity, Variable... substitution) { + return call(polarity, List.of(substitution)); + } + + public DnfCallLiteral call(Variable... substitution) { + return call(CallPolarity.POSITIVE, substitution); + } + + public DnfCallLiteral callTransitive(Variable left, Variable right) { + return call(CallPolarity.TRANSITIVE, List.of(left, right)); + } + public static Builder builder() { return builder(null); } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java b/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java index 6a6831ae..2eb87649 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java @@ -1,5 +1,8 @@ package tools.refinery.store.query; +import tools.refinery.store.query.literal.ConstantLiteral; +import tools.refinery.store.query.literal.EquivalenceLiteral; + import java.util.Objects; public class Variable { @@ -28,6 +31,18 @@ public class Variable { return name != null; } + public ConstantLiteral isConstant(int value) { + return new ConstantLiteral(this, value); + } + + public EquivalenceLiteral isEquivalent(Variable other) { + return new EquivalenceLiteral(true, this, other); + } + + public EquivalenceLiteral notEquivalent(Variable other) { + return new EquivalenceLiteral(false, this, other); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java index ddea0221..84b4b771 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java @@ -22,7 +22,11 @@ public enum CallPolarity { return transitive; } - public static CallPolarity fromBoolean(boolean positive) { - return positive ? POSITIVE : NEGATIVE; + public CallPolarity negate() { + return switch (this) { + case POSITIVE -> NEGATIVE; + case NEGATIVE -> POSITIVE; + case TRANSITIVE -> throw new IllegalArgumentException("Transitive polarity cannot be negated"); + }; } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java index e3410c21..86149b33 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java @@ -5,28 +5,13 @@ import tools.refinery.store.query.Variable; import java.util.List; -public final class DnfCallLiteral extends CallLiteral { +public final class DnfCallLiteral extends CallLiteral implements PolarLiteral { public DnfCallLiteral(CallPolarity polarity, Dnf target, List substitution) { super(polarity, target, substitution); } - public DnfCallLiteral(CallPolarity polarity, Dnf target, Variable... substitution) { - this(polarity, target, List.of(substitution)); - } - - public DnfCallLiteral(boolean positive, Dnf target, List substitution) { - this(CallPolarity.fromBoolean(positive), target, substitution); - } - - public DnfCallLiteral(boolean positive, Dnf target, Variable... substitution) { - this(positive, target, List.of(substitution)); - } - - public DnfCallLiteral(Dnf target, List substitution) { - this(CallPolarity.POSITIVE, target, substitution); - } - - public DnfCallLiteral(Dnf target, Variable... substitution) { - this(target, List.of(substitution)); + @Override + public DnfCallLiteral negate() { + return new DnfCallLiteral(getPolarity().negate(), getTarget(), getSubstitution()); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index a1ec2c41..75afd50b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -4,14 +4,16 @@ import tools.refinery.store.query.Variable; import java.util.Set; -public record EquivalenceLiteral(boolean positive, Variable left, Variable right) implements Literal { - public EquivalenceLiteral(Variable left, Variable right) { - this(true, left, right); - } - +public record EquivalenceLiteral(boolean positive, Variable left, Variable right) + implements PolarLiteral { @Override public void collectAllVariables(Set variables) { variables.add(left); variables.add(right); } + + @Override + public EquivalenceLiteral negate() { + return new EquivalenceLiteral(!positive, left, right); + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literals.java new file mode 100644 index 00000000..2c7e893f --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literals.java @@ -0,0 +1,11 @@ +package tools.refinery.store.query.literal; + +public final class Literals { + private Literals() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static > T not(PolarLiteral literal) { + return literal.negate(); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java new file mode 100644 index 00000000..32523675 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java @@ -0,0 +1,5 @@ +package tools.refinery.store.query.literal; + +public interface PolarLiteral> extends Literal { + T negate(); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java index e2106ba9..7fa99abb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java @@ -5,28 +5,14 @@ import tools.refinery.store.query.view.AnyRelationView; import java.util.List; -public final class RelationViewLiteral extends CallLiteral { +public final class RelationViewLiteral extends CallLiteral + implements PolarLiteral { public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, List substitution) { super(polarity, target, substitution); } - public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, Variable... substitution) { - this(polarity, target, List.of(substitution)); - } - - public RelationViewLiteral(boolean positive, AnyRelationView target, List substitution) { - this(CallPolarity.fromBoolean(positive), target, substitution); - } - - public RelationViewLiteral(boolean positive, AnyRelationView target, Variable... substitution) { - this(positive, target, List.of(substitution)); - } - - public RelationViewLiteral(AnyRelationView target, List substitution) { - this(CallPolarity.POSITIVE, target, substitution); - } - - public RelationViewLiteral(AnyRelationView target, Variable... substitution) { - this(target, List.of(substitution)); + @Override + public RelationViewLiteral negate() { + return new RelationViewLiteral(getPolarity().negate(), getTarget(), getSubstitution()); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java index bbec1e73..0bea962d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java @@ -2,9 +2,13 @@ package tools.refinery.store.query.view; import tools.refinery.store.map.CursorAsIterator; import tools.refinery.store.model.Model; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; +import java.util.List; import java.util.Objects; import java.util.UUID; @@ -47,6 +51,22 @@ public abstract non-sealed class RelationView implements AnyRelationView { return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter)); } + public RelationViewLiteral call(CallPolarity polarity, List substitution) { + return new RelationViewLiteral(polarity, this, substitution); + } + + public RelationViewLiteral call(CallPolarity polarity, Variable... substitution) { + return call(polarity, List.of(substitution)); + } + + public RelationViewLiteral call(Variable... substitution) { + return call(CallPolarity.POSITIVE, substitution); + } + + public RelationViewLiteral callTransitive(Variable left, Variable right) { + return call(CallPolarity.TRANSITIVE, List.of(left, right)); + } + @Override public boolean equals(Object o) { if (this == o) return true; -- cgit v1.2.3-70-g09d2