From dd5c8561b64a6602613d1602e838fe98f0fdbe32 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 8 Jan 2024 14:45:48 +0100 Subject: [PATCH] revived old optimized implementation of transitive closure on binary relations from commit ba86a8 --- .../PersistentHashIndexedBinaryRelation.java | 119 +++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) 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 ad71af11..62d7c647 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer Michael.Steindorfer@cwi.nl CWI *******************************************************************************/ package io.usethesource.vallang.impl.persistent; @@ -16,6 +16,8 @@ import static io.usethesource.vallang.impl.persistent.SetWriter.isTupleOfArityTwo; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Objects; @@ -38,8 +40,11 @@ import io.usethesource.vallang.ISetWriter; import io.usethesource.vallang.ITuple; import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.IWriter; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.util.AbstractTypeBag; +import io.usethesource.vallang.util.RotatingQueue; /** * Implements both ISet and IRelation, by indexing on the first column @@ -539,4 +544,116 @@ public Type getElementType() { public ISet empty() { return ISet.super.empty(); } + + @Override + public ISet closure() { + IWriter resultWriter = writer(); + resultWriter.insertAll(this); + resultWriter.insertAll(computeClosureDelta()); + return resultWriter.done(); + } + + @Override + public ISet closureStar() { + // calculate + java.util.Set closureDelta = computeClosureDelta(); + + IWriter resultWriter = writer(); + resultWriter.insertAll(this); + resultWriter.insertAll(closureDelta); + + for (IValue element : carrier()) { + resultWriter.insertTuple(element, element); + } + + return resultWriter.done(); + } + + private java.util.Set computeClosureDelta() { + IValueFactory vf = ValueFactory.getInstance(); + RotatingQueue iLeftKeys = new RotatingQueue<>(); + RotatingQueue> iLefts = new RotatingQueue<>(); + + Map> interestingLeftSides = new HashMap<>(); + Map> potentialRightSides = new HashMap<>(); + + // Index + for (IValue val : this) { + ITuple tuple = (ITuple) val; + IValue key = tuple.get(0); + IValue value = tuple.get(1); + RotatingQueue leftValues = interestingLeftSides.get(key); + java.util.Set rightValues; + + if (leftValues != null) { + rightValues = potentialRightSides.get(key); + } else { + leftValues = new RotatingQueue<>(); + iLeftKeys.put(key); + iLefts.put(leftValues); + interestingLeftSides.put(key, leftValues); + + rightValues = new HashSet<>(); + potentialRightSides.put(key, rightValues); + } + + leftValues.put(value); + if (rightValues == null) { + rightValues = new HashSet<>(); + } + + rightValues.add(value); + } + + int size = potentialRightSides.size(); + int nextSize = 0; + + // Compute + final java.util.Set newTuples = new HashSet<>(); + do { + Map> rightSides = potentialRightSides; + potentialRightSides = new HashMap<>(); + + for (; size > 0; size--) { + IValue leftKey = iLeftKeys.get(); + RotatingQueue leftValues = iLefts.get(); + RotatingQueue interestingLeftValues = null; + + assert leftKey != null : "@AssumeAssertion(nullness) this only happens at the end of the queue"; + assert leftValues != null : "@AssumeAssertion(nullness) this only happens at the end of the queue"; + + IValue rightKey; + while ((rightKey = leftValues.get()) != null) { + java.util.Set rightValues = rightSides.get(rightKey); + if (rightValues != null) { + Iterator rightValuesIterator = rightValues.iterator(); + while (rightValuesIterator.hasNext()) { + IValue rightValue = rightValuesIterator.next(); + if (newTuples.add(vf.tuple(leftKey, rightValue))) { + if (interestingLeftValues == null) { + nextSize++; + + iLeftKeys.put(leftKey); + interestingLeftValues = new RotatingQueue<>(); + iLefts.put(interestingLeftValues); + } + interestingLeftValues.put(rightValue); + + java.util.Set potentialRightValues = potentialRightSides.get(rightKey); + if (potentialRightValues == null) { + potentialRightValues = new HashSet<>(); + potentialRightSides.put(rightKey, potentialRightValues); + } + potentialRightValues.add(rightValue); + } + } + } + } + } + size = nextSize; + nextSize = 0; + } while (size > 0); + + return newTuples; + } }