diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java index c885b5d1..07d14976 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java @@ -734,12 +734,13 @@ else if (values instanceof Set) { throw new IllegalArgumentException("Unexpected map entry"); } // we mark ourselves as done before we did it, - // so we don't do the that causes an extra round + // so we don't do the that causes an useless round done.add(lhs); IValue rhs; while ((rhs = todo.poll()) != null) { + boolean rhsFull = done.contains(rhs); for (IValue composed : result.get(rhs)) { - if (result.__insert(lhs, composed) && !done.contains(composed)) { + if (result.__insert(lhs, composed) && !rhsFull) { todo.push(composed); } } diff --git a/src/test/java/io/usethesource/vallang/specification/IRelationTests.java b/src/test/java/io/usethesource/vallang/specification/IRelationTests.java index 4a14f8b2..e192b7ba 100644 --- a/src/test/java/io/usethesource/vallang/specification/IRelationTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IRelationTests.java @@ -12,6 +12,7 @@ import io.usethesource.vallang.ExpectedType; import io.usethesource.vallang.GivenValue; import io.usethesource.vallang.IList; +import io.usethesource.vallang.IRelation; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.ITuple; @@ -55,7 +56,30 @@ public void transClosureLocs(@ExpectedType("rel[loc,loc]") ISet src) { assertEquals(src.asRelation().closure().intersect(src), src); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void deepClosure(IValueFactory vf) { + IValue prev = vf.integer(0); + var rBuilder = vf.setWriter(); + for (int i=1; i < 100; i++) { + IValue next = vf.integer(i); + rBuilder.appendTuple(prev, next); + prev = next; + } + var r = rBuilder.done().asRelation(); + + assertEquals(slowClosure(vf, r),r.closure(),() -> "Failed with input: " + r.toString()); + } + + private ISet slowClosure(IValueFactory vf, IRelation r) { + var prev = vf.set(); + ISet result = r.asContainer(); + while (!prev.equals(result)) { + prev = result; + result = result.union( r.compose(result.asRelation())); + } + return result; + } + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void carrierForTriples(@ExpectedType("rel[int,int,int]") ISet src) { ISet carrier = src.asRelation().carrier();