From 3c1e93b7cb50d20abe08f1b95b8dc8d62ed4c38c Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sun, 27 Nov 2022 21:11:39 +0100 Subject: feat: add cardinality interval abstraction --- .../UpperCardinalitySumAggregationOperator.java | 97 ++++ .../refinery/store/query/viatra/QueryTest.java | 510 +++++++++++++++++++++ .../store/query/viatra/QueryTransactionTest.java | 54 +++ ...ardinalitySumAggregationOperatorStreamTest.java | 50 ++ ...UpperCardinalitySumAggregationOperatorTest.java | 87 ++++ .../store/query/viatra/tests/QueryTest.java | 510 --------------------- .../query/viatra/tests/QueryTransactionTest.java | 54 --- 7 files changed, 798 insertions(+), 564 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTransactionTest.java (limited to 'subprojects/store-query-viatra') 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 new file mode 100644 index 00000000..ffd5f6de --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java @@ -0,0 +1,97 @@ +package tools.refinery.store.query.viatra.internal.cardinality; + +import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; +import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; +import tools.refinery.store.model.representation.cardinality.FiniteUpperCardinality; +import tools.refinery.store.model.representation.cardinality.UnboundedUpperCardinality; +import tools.refinery.store.model.representation.cardinality.UpperCardinalities; +import tools.refinery.store.model.representation.cardinality.UpperCardinality; + +import java.util.stream.Stream; + +public class UpperCardinalitySumAggregationOperator implements IMultisetAggregationOperator { + public static final UpperCardinalitySumAggregationOperator INSTANCE = new UpperCardinalitySumAggregationOperator(); + + public static final BoundAggregator BOUND_AGGREGATOR = new BoundAggregator(INSTANCE, UpperCardinality.class, + UpperCardinality.class); + + private UpperCardinalitySumAggregationOperator() { + // Singleton constructor. + } + + @Override + public String getName() { + return "sum"; + } + + @Override + public String getShortDescription() { + return "%s computes the sum of finite or unbounded upper cardinalities".formatted(getName()); + } + + @Override + public Accumulator createNeutral() { + return new Accumulator(); + } + + @Override + public boolean isNeutral(Accumulator result) { + return result.sumFiniteUpperBounds == 0 && result.countUnbounded == 0; + } + + @Override + public Accumulator update(Accumulator oldResult, UpperCardinality updateValue, boolean isInsertion) { + if (updateValue instanceof FiniteUpperCardinality finiteUpperCardinality) { + int finiteUpperBound = finiteUpperCardinality.finiteUpperBound(); + if (isInsertion) { + oldResult.sumFiniteUpperBounds += finiteUpperBound; + } else { + oldResult.sumFiniteUpperBounds -= finiteUpperBound; + } + } else if (updateValue instanceof UnboundedUpperCardinality) { + if (isInsertion) { + oldResult.countUnbounded += 1; + } else { + oldResult.countUnbounded -= 1; + } + } else { + throw new IllegalArgumentException("Unknown UpperCardinality: " + updateValue); + } + return oldResult; + } + + @Override + public UpperCardinality getAggregate(Accumulator result) { + return result.countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : + UpperCardinalities.valueOf(result.sumFiniteUpperBounds); + } + + @Override + public UpperCardinality aggregateStream(Stream stream) { + var result = stream.collect(this::createNeutral, (accumulator, value) -> update(accumulator, value, true), + (left, right) -> new Accumulator(left.sumFiniteUpperBounds + right.sumFiniteUpperBounds, + left.countUnbounded + right.countUnbounded)); + return getAggregate(result); + } + + @Override + public Accumulator clone(Accumulator original) { + return new Accumulator(original.sumFiniteUpperBounds, original.countUnbounded); + } + + public static class Accumulator { + private int sumFiniteUpperBounds; + + private int countUnbounded; + + private Accumulator(int sumFiniteUpperBounds, int countUnbounded) { + this.sumFiniteUpperBounds = sumFiniteUpperBounds; + this.countUnbounded = countUnbounded; + } + + private Accumulator() { + this(0, 0); + } + } +} 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 new file mode 100644 index 00000000..d18187e5 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java @@ -0,0 +1,510 @@ +package tools.refinery.store.query.viatra; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.representation.Relation; +import tools.refinery.store.model.representation.TruthValue; +import tools.refinery.store.query.*; +import tools.refinery.store.query.atom.*; +import tools.refinery.store.query.viatra.ViatraQueryableModelStore; +import tools.refinery.store.query.view.FilteredRelationView; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.TupleLike; + +import java.util.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class QueryTest { + @Test + void typeConstraintTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation asset = new Relation<>("Asset", 1, Boolean.class, false); + RelationView personView = new KeyOnlyRelationView(person); + + var p1 = new Variable("p1"); + DNF predicate = DNF.builder("TypeConstraint") + .parameters(p1) + .clause(new RelationViewAtom(personView, p1)) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), + Set.of(predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(asset, Tuple.of(1), true); + model.put(asset, Tuple.of(2), true); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); + } + + @Test + void relationConstraintTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF predicate = DNF.builder("RelationConstraint") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + assertEquals(0, model.countResults(predicate)); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + assertEquals(0, model.countResults(predicate)); + + model.flushChanges(); + assertEquals(3, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); + } + + @Test + void andTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF predicate = DNF.builder("RelationConstraint") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2), + new RelationViewAtom(friendMustView, p2, p1) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + assertEquals(0, model.countResults(predicate)); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(0, model.countResults(predicate)); + + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); + + model.put(friend, Tuple.of(2, 0), TruthValue.TRUE); + model.flushChanges(); + assertEquals(4, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), + Tuple.of(2, 0))); + } + + @Test + void existTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF predicate = DNF.builder("RelationConstraint") + .parameters(p1) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + assertEquals(0, model.countResults(predicate)); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + assertEquals(0, model.countResults(predicate)); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); + } + + @Test + void orTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation animal = new Relation<>("Animal", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView animalView = new KeyOnlyRelationView(animal); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF predicate = DNF.builder("Or") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .clause( + new RelationViewAtom(animalView, p1), + new RelationViewAtom(animalView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, animal, friend), + Set.of(personView, animalView, friendMustView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(animal, Tuple.of(2), true); + model.put(animal, Tuple.of(3), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + model.put(friend, Tuple.of(2, 3), TruthValue.TRUE); + model.put(friend, Tuple.of(3, 0), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); + } + + @Test + void equalityTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + RelationView personView = new KeyOnlyRelationView(person); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF predicate = DNF.builder("Equality") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new EquivalenceAtom(p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person), Set.of(personView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + + model.flushChanges(); + assertEquals(3, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); + } + + @Test + void inequalityTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + Variable p3 = new Variable("p3"); + DNF predicate = DNF.builder("Inequality") + .parameters(p1, p2, p3) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p3), + new RelationViewAtom(friendMustView, p2, p3), + new EquivalenceAtom(false, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); + } + + @Test + void patternCallTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF friendPredicate = DNF.builder("RelationConstraint") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + DNF predicate = DNF.builder("PositivePatternCall") + .parameters(p3, p4) + .clause( + new RelationViewAtom(personView, p3), + new RelationViewAtom(personView, p4), + new CallAtom<>(friendPredicate, p3, p4) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + model.flushChanges(); + + assertEquals(3, model.countResults(friendPredicate)); + } + + @Test + void negativePatternCallTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF friendPredicate = DNF.builder("RelationConstraint") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + DNF predicate = DNF.builder("NegativePatternCall") + .parameters(p3, p4) + .clause( + new RelationViewAtom(personView, p3), + new RelationViewAtom(personView, p4), + new CallAtom<>(false, friendPredicate, p3, p4) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(6, model.countResults(predicate)); + } + + @Test + void negativeWithQuantificationTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + + DNF called = DNF.builder("Called") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + DNF predicate = DNF.builder("Count") + .parameters(p1) + .clause( + new RelationViewAtom(personView, p1), + new CallAtom<>(false, called, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(called, predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + } + + @Test + void transitivePatternCallTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + DNF friendPredicate = DNF.builder("RelationConstraint") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + Variable p3 = new Variable("p3"); + Variable p4 = new Variable("p4"); + DNF predicate = DNF.builder("TransitivePatternCall") + .parameters(p3, p4) + .clause( + new RelationViewAtom(personView, p3), + new RelationViewAtom(personView, p4), + new CallAtom<>(SimplePolarity.TRANSITIVE, friendPredicate, p3, p4) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(3, model.countResults(predicate)); + } + + @Test + void countMatchTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); + RelationView personView = new KeyOnlyRelationView(person); + RelationView friendMustView = new FilteredRelationView<>(friend, "must", + TruthValue::must); + + Variable p1 = new Variable("p1"); + Variable p2 = new Variable("p2"); + + DNF called = DNF.builder("Called") + .parameters(p1, p2) + .clause( + new RelationViewAtom(personView, p1), + new RelationViewAtom(personView, p2), + new RelationViewAtom(friendMustView, p1, p2) + ) + .build(); + + DNF predicate = DNF.builder("Count") + .parameters(p1) + .clause( + new RelationViewAtom(personView, p1), + new CallAtom<>(new CountingPolarity(ComparisonOperator.EQUALS, 2), called, p1, p2) + ) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), + Set.of(personView, friendMustView), Set.of(called, predicate)); + QueryableModel model = store.createModel(); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(person, Tuple.of(2), true); + model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); + model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); + + model.flushChanges(); + assertEquals(1, model.countResults(predicate)); + } + + static void compareMatchSets(Stream matchSet, Set expected) { + Set translatedMatchSet = new HashSet<>(); + var iterator = matchSet.iterator(); + while (iterator.hasNext()) { + var element = iterator.next(); + translatedMatchSet.add(element.toTuple()); + } + assertEquals(expected, translatedMatchSet); + } +} 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 new file mode 100644 index 00000000..e8fa6ed1 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java @@ -0,0 +1,54 @@ +package tools.refinery.store.query.viatra; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.representation.Relation; +import tools.refinery.store.query.DNF; +import tools.refinery.store.query.QueryableModel; +import tools.refinery.store.query.QueryableModelStore; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.atom.RelationViewAtom; +import tools.refinery.store.query.viatra.ViatraQueryableModelStore; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.tuple.Tuple; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class QueryTransactionTest { + @Test + void flushTest() { + Relation person = new Relation<>("Person", 1, Boolean.class, false); + Relation asset = new Relation<>("Asset", 1, Boolean.class, false); + RelationView personView = new KeyOnlyRelationView(person); + + var p1 = new Variable("p1"); + DNF predicate = DNF.builder("TypeConstraint") + .parameters(p1) + .clause(new RelationViewAtom(personView, p1)) + .build(); + + QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), + Set.of(predicate)); + QueryableModel model = store.createModel(); + + assertEquals(0, model.countResults(predicate)); + + model.put(person, Tuple.of(0), true); + model.put(person, Tuple.of(1), true); + model.put(asset, Tuple.of(1), true); + model.put(asset, Tuple.of(2), true); + + assertEquals(0, model.countResults(predicate)); + + model.flushChanges(); + assertEquals(2, model.countResults(predicate)); + + model.put(person, Tuple.of(4), true); + assertEquals(2, model.countResults(predicate)); + + model.flushChanges(); + assertEquals(3, model.countResults(predicate)); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java new file mode 100644 index 00000000..07869050 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java @@ -0,0 +1,50 @@ +package tools.refinery.store.query.viatra.internal.cardinality; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.model.representation.cardinality.UpperCardinalities; +import tools.refinery.store.model.representation.cardinality.UpperCardinality; + +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +class UpperCardinalitySumAggregationOperatorStreamTest { + @ParameterizedTest + @MethodSource + void testStream(Stream stream, UpperCardinality expected) { + var result = UpperCardinalitySumAggregationOperator.INSTANCE.aggregateStream(stream); + assertThat(result, equalTo(expected)); + } + + static Stream testStream() { + return Stream.of( + Arguments.of(Stream.of(), UpperCardinalities.ZERO), + Arguments.of(Stream.of(UpperCardinality.of(3)), UpperCardinality.of(3)), + Arguments.of( + Stream.of( + UpperCardinality.of(2), + UpperCardinality.of(3) + ), + UpperCardinality.of(5) + ), + Arguments.of(Stream.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED), + Arguments.of( + Stream.of( + UpperCardinalities.UNBOUNDED, + UpperCardinalities.UNBOUNDED + ), + UpperCardinalities.UNBOUNDED + ), + Arguments.of( + Stream.of( + UpperCardinalities.UNBOUNDED, + UpperCardinality.of(3) + ), + UpperCardinalities.UNBOUNDED + ) + ); + } +} 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 new file mode 100644 index 00000000..afc4a2f3 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java @@ -0,0 +1,87 @@ +package tools.refinery.store.query.viatra.internal.cardinality; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.representation.cardinality.UpperCardinalities; +import tools.refinery.store.model.representation.cardinality.UpperCardinality; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +class UpperCardinalitySumAggregationOperatorTest { + private UpperCardinalitySumAggregationOperator.Accumulator accumulator; + + @BeforeEach + void beforeEach() { + accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.createNeutral(); + } + + @Test + void emptyAggregationTest() { + assertResult(UpperCardinality.of(0)); + } + + @Test + void singleBoundedTest() { + insert(UpperCardinality.of(3)); + assertResult(UpperCardinality.of(3)); + } + + @Test + void multipleBoundedTest() { + insert(UpperCardinality.of(2)); + insert(UpperCardinality.of(3)); + assertResult(UpperCardinality.of(5)); + } + + @Test + void singleUnboundedTest() { + insert(UpperCardinalities.UNBOUNDED); + assertResult(UpperCardinalities.UNBOUNDED); + } + + @Test + void multipleUnboundedTest() { + insert(UpperCardinalities.UNBOUNDED); + insert(UpperCardinalities.UNBOUNDED); + assertResult(UpperCardinalities.UNBOUNDED); + } + + @Test + void removeBoundedTest() { + insert(UpperCardinality.of(2)); + insert(UpperCardinality.of(3)); + remove(UpperCardinality.of(2)); + assertResult(UpperCardinality.of(3)); + } + + @Test + void removeAllUnboundedTest() { + insert(UpperCardinalities.UNBOUNDED); + insert(UpperCardinality.of(3)); + remove(UpperCardinalities.UNBOUNDED); + assertResult(UpperCardinality.of(3)); + } + + @Test + void removeSomeUnboundedTest() { + insert(UpperCardinalities.UNBOUNDED); + insert(UpperCardinalities.UNBOUNDED); + insert(UpperCardinality.of(3)); + remove(UpperCardinalities.UNBOUNDED); + assertResult(UpperCardinalities.UNBOUNDED); + } + + private void insert(UpperCardinality value) { + accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, true); + } + + private void remove(UpperCardinality value) { + accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, false); + } + + private void assertResult(UpperCardinality expected) { + var result = UpperCardinalitySumAggregationOperator.INSTANCE.getAggregate(accumulator); + assertThat(result, equalTo(expected)); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTest.java deleted file mode 100644 index a7e09023..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTest.java +++ /dev/null @@ -1,510 +0,0 @@ -package tools.refinery.store.query.viatra.tests; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.representation.Relation; -import tools.refinery.store.model.representation.TruthValue; -import tools.refinery.store.query.*; -import tools.refinery.store.query.atom.*; -import tools.refinery.store.query.viatra.ViatraQueryableModelStore; -import tools.refinery.store.query.view.FilteredRelationView; -import tools.refinery.store.query.view.KeyOnlyRelationView; -import tools.refinery.store.query.view.RelationView; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.TupleLike; - -import java.util.*; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class QueryTest { - @Test - void typeConstraintTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation asset = new Relation<>("Asset", 1, Boolean.class, false); - RelationView personView = new KeyOnlyRelationView(person); - - var p1 = new Variable("p1"); - DNF predicate = DNF.builder("TypeConstraint") - .parameters(p1) - .clause(new RelationViewAtom(personView, p1)) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), - Set.of(predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(asset, Tuple.of(1), true); - model.put(asset, Tuple.of(2), true); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); - } - - @Test - void relationConstraintTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF predicate = DNF.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - assertEquals(0, model.countResults(predicate)); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - assertEquals(0, model.countResults(predicate)); - - model.flushChanges(); - assertEquals(3, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); - } - - @Test - void andTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF predicate = DNF.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2), - new RelationViewAtom(friendMustView, p2, p1) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - assertEquals(0, model.countResults(predicate)); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(0, model.countResults(predicate)); - - model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); - - model.put(friend, Tuple.of(2, 0), TruthValue.TRUE); - model.flushChanges(); - assertEquals(4, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), - Tuple.of(2, 0))); - } - - @Test - void existTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF predicate = DNF.builder("RelationConstraint") - .parameters(p1) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - assertEquals(0, model.countResults(predicate)); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - assertEquals(0, model.countResults(predicate)); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0), Tuple.of(1))); - } - - @Test - void orTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation animal = new Relation<>("Animal", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView animalView = new KeyOnlyRelationView(animal); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF predicate = DNF.builder("Or") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .clause( - new RelationViewAtom(animalView, p1), - new RelationViewAtom(animalView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, animal, friend), - Set.of(personView, animalView, friendMustView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(animal, Tuple.of(2), true); - model.put(animal, Tuple.of(3), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); - model.put(friend, Tuple.of(2, 3), TruthValue.TRUE); - model.put(friend, Tuple.of(3, 0), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); - } - - @Test - void equalityTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - RelationView personView = new KeyOnlyRelationView(person); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF predicate = DNF.builder("Equality") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new EquivalenceAtom(p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person), Set.of(personView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - - model.flushChanges(); - assertEquals(3, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); - } - - @Test - void inequalityTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - Variable p3 = new Variable("p3"); - DNF predicate = DNF.builder("Inequality") - .parameters(p1, p2, p3) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p3), - new RelationViewAtom(friendMustView, p2, p3), - new EquivalenceAtom(false, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - compareMatchSets(model.allResults(predicate), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); - } - - @Test - void patternCallTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF friendPredicate = DNF.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - Variable p3 = new Variable("p3"); - Variable p4 = new Variable("p4"); - DNF predicate = DNF.builder("PositivePatternCall") - .parameters(p3, p4) - .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new CallAtom<>(friendPredicate, p3, p4) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - model.flushChanges(); - - assertEquals(3, model.countResults(friendPredicate)); - } - - @Test - void negativePatternCallTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF friendPredicate = DNF.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - Variable p3 = new Variable("p3"); - Variable p4 = new Variable("p4"); - DNF predicate = DNF.builder("NegativePatternCall") - .parameters(p3, p4) - .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new CallAtom<>(false, friendPredicate, p3, p4) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 0), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(6, model.countResults(predicate)); - } - - @Test - void negativeWithQuantificationTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - - DNF called = DNF.builder("Called") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - DNF predicate = DNF.builder("Count") - .parameters(p1) - .clause( - new RelationViewAtom(personView, p1), - new CallAtom<>(false, called, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(called, predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - } - - @Test - void transitivePatternCallTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - DNF friendPredicate = DNF.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - Variable p3 = new Variable("p3"); - Variable p4 = new Variable("p4"); - DNF predicate = DNF.builder("TransitivePatternCall") - .parameters(p3, p4) - .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new CallAtom<>(SimplePolarity.TRANSITIVE, friendPredicate, p3, p4) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(friendPredicate, predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(1, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(3, model.countResults(predicate)); - } - - @Test - void countMatchTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation friend = new Relation<>("friend", 2, TruthValue.class, TruthValue.FALSE); - RelationView personView = new KeyOnlyRelationView(person); - RelationView friendMustView = new FilteredRelationView<>(friend, "must", - TruthValue::must); - - Variable p1 = new Variable("p1"); - Variable p2 = new Variable("p2"); - - DNF called = DNF.builder("Called") - .parameters(p1, p2) - .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) - ) - .build(); - - DNF predicate = DNF.builder("Count") - .parameters(p1) - .clause( - new RelationViewAtom(personView, p1), - new CallAtom<>(new CountingPolarity(ComparisonOperator.EQUALS, 2), called, p1, p2) - ) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, friend), - Set.of(personView, friendMustView), Set.of(called, predicate)); - QueryableModel model = store.createModel(); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(person, Tuple.of(2), true); - model.put(friend, Tuple.of(0, 1), TruthValue.TRUE); - model.put(friend, Tuple.of(0, 2), TruthValue.TRUE); - - model.flushChanges(); - assertEquals(1, model.countResults(predicate)); - } - - static void compareMatchSets(Stream matchSet, Set expected) { - Set translatedMatchSet = new HashSet<>(); - var iterator = matchSet.iterator(); - while (iterator.hasNext()) { - var element = iterator.next(); - translatedMatchSet.add(element.toTuple()); - } - assertEquals(expected, translatedMatchSet); - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTransactionTest.java deleted file mode 100644 index 117edd3e..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryTransactionTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package tools.refinery.store.query.viatra.tests; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.representation.Relation; -import tools.refinery.store.query.DNF; -import tools.refinery.store.query.QueryableModel; -import tools.refinery.store.query.QueryableModelStore; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.atom.RelationViewAtom; -import tools.refinery.store.query.viatra.ViatraQueryableModelStore; -import tools.refinery.store.query.view.KeyOnlyRelationView; -import tools.refinery.store.query.view.RelationView; -import tools.refinery.store.tuple.Tuple; - -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class QueryTransactionTest { - @Test - void flushTest() { - Relation person = new Relation<>("Person", 1, Boolean.class, false); - Relation asset = new Relation<>("Asset", 1, Boolean.class, false); - RelationView personView = new KeyOnlyRelationView(person); - - var p1 = new Variable("p1"); - DNF predicate = DNF.builder("TypeConstraint") - .parameters(p1) - .clause(new RelationViewAtom(personView, p1)) - .build(); - - QueryableModelStore store = new ViatraQueryableModelStore(Set.of(person, asset), Set.of(personView), - Set.of(predicate)); - QueryableModel model = store.createModel(); - - assertEquals(0, model.countResults(predicate)); - - model.put(person, Tuple.of(0), true); - model.put(person, Tuple.of(1), true); - model.put(asset, Tuple.of(1), true); - model.put(asset, Tuple.of(2), true); - - assertEquals(0, model.countResults(predicate)); - - model.flushChanges(); - assertEquals(2, model.countResults(predicate)); - - model.put(person, Tuple.of(4), true); - assertEquals(2, model.countResults(predicate)); - - model.flushChanges(); - assertEquals(3, model.countResults(predicate)); - } -} -- cgit v1.2.3-54-g00ecf