Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,18 @@
import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory;
import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleStorePositionTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple;

public final class IndexedIfExistsBiNode<A, B, C> extends AbstractIndexedIfExistsNode<BiTuple<A, B>, C> {

private final TriPredicate<A, B, C> filtering;

public IndexedIfExistsBiNode(boolean shouldExist, IndexerFactory<C> indexerFactory,
int inputStoreIndexLeftKeys, int inputStoreIndexLeftCounterEntry,
int inputStoreIndexRightKeys, int inputStoreIndexRightEntry,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle) {
this(shouldExist, indexerFactory,
inputStoreIndexLeftKeys, inputStoreIndexLeftCounterEntry, -1,
inputStoreIndexRightKeys, inputStoreIndexRightEntry, -1,
nextNodesTupleLifecycle, null);
}

public IndexedIfExistsBiNode(boolean shouldExist, IndexerFactory<C> indexerFactory,
int inputStoreIndexLeftKeys, int inputStoreIndexLeftCounterEntry, int inputStoreIndexLeftTrackerList,
int inputStoreIndexRightKeys, int inputStoreIndexRightEntry, int inputStoreIndexRightTrackerList,
TupleStorePositionTracker leftTupleStorePositionTracker, TupleStorePositionTracker rightTupleStorePositionTracker,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle, TriPredicate<A, B, C> filtering) {
super(shouldExist, indexerFactory.buildBiLeftKeysExtractor(), indexerFactory,
inputStoreIndexLeftKeys, inputStoreIndexLeftCounterEntry, inputStoreIndexLeftTrackerList,
inputStoreIndexRightKeys, inputStoreIndexRightEntry, inputStoreIndexRightTrackerList,
nextNodesTupleLifecycle, filtering != null);
super(shouldExist, indexerFactory.buildBiLeftKeysExtractor(), indexerFactory, leftTupleStorePositionTracker,
rightTupleStorePositionTracker, nextNodesTupleLifecycle, filtering != null);
this.filtering = filtering;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,26 @@
import ai.timefold.solver.core.impl.bavet.common.AbstractIndexedJoinNode;
import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory;
import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple;
import ai.timefold.solver.core.impl.bavet.common.tuple.OutputStoreSizeTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleStorePositionTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple;

public final class IndexedJoinBiNode<A, B> extends AbstractIndexedJoinNode<UniTuple<A>, B, BiTuple<A, B>> {

private final BiPredicate<A, B> filtering;
private final int outputStoreSize;

public IndexedJoinBiNode(IndexerFactory<B> indexerFactory,
int inputStoreIndexA, int inputStoreIndexEntryA, int inputStoreIndexOutTupleListA,
int inputStoreIndexB, int inputStoreIndexEntryB, int inputStoreIndexOutTupleListB,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle, BiPredicate<A, B> filtering,
int outputStoreSize, int outputStoreIndexOutEntryA, int outputStoreIndexOutEntryB) {
super(indexerFactory.buildUniLeftKeysExtractor(), indexerFactory,
inputStoreIndexA, inputStoreIndexEntryA, inputStoreIndexOutTupleListA,
inputStoreIndexB, inputStoreIndexEntryB, inputStoreIndexOutTupleListB,
nextNodesTupleLifecycle, filtering != null,
outputStoreIndexOutEntryA, outputStoreIndexOutEntryB);

public IndexedJoinBiNode(IndexerFactory<B> indexerFactory, TupleStorePositionTracker leftTupleStorePositionTracker,
TupleStorePositionTracker rightTupleStorePositionTracker, OutputStoreSizeTracker outputStoreSizeTracker,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle, BiPredicate<A, B> filtering) {
super(indexerFactory.buildUniLeftKeysExtractor(), indexerFactory, leftTupleStorePositionTracker,
rightTupleStorePositionTracker, outputStoreSizeTracker, nextNodesTupleLifecycle, filtering != null);
this.filtering = filtering;
this.outputStoreSize = outputStoreSize;
}

@Override
protected BiTuple<A, B> createOutTuple(UniTuple<A> leftTuple, UniTuple<B> rightTuple) {
return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSize);
return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSizeTracker.computeOutputStoreSize());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,19 @@
import ai.timefold.solver.core.impl.bavet.common.AbstractUnindexedIfExistsNode;
import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleStorePositionTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple;

public final class UnindexedIfExistsBiNode<A, B, C> extends AbstractUnindexedIfExistsNode<BiTuple<A, B>, C> {

private final TriPredicate<A, B, C> filtering;

public UnindexedIfExistsBiNode(boolean shouldExist,
int inputStoreIndexLeftCounterEntry, int inputStoreIndexRightEntry,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle) {
this(shouldExist,
inputStoreIndexLeftCounterEntry, -1, inputStoreIndexRightEntry, -1,
nextNodesTupleLifecycle, null);
}

public UnindexedIfExistsBiNode(boolean shouldExist,
int inputStoreIndexLeftCounterEntry, int inputStoreIndexLeftTrackerList, int inputStoreIndexRightEntry,
int inputStoreIndexRightTrackerList,
TupleStorePositionTracker leftTupleStorePositionTracker, TupleStorePositionTracker rightTupleStorePositionTracker,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle,
TriPredicate<A, B, C> filtering) {
super(shouldExist,
inputStoreIndexLeftCounterEntry, inputStoreIndexLeftTrackerList, inputStoreIndexRightEntry,
inputStoreIndexRightTrackerList,
nextNodesTupleLifecycle, filtering != null);
super(shouldExist, leftTupleStorePositionTracker, rightTupleStorePositionTracker, nextNodesTupleLifecycle,
filtering != null);
this.filtering = filtering;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,27 @@

import ai.timefold.solver.core.impl.bavet.common.AbstractUnindexedJoinNode;
import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple;
import ai.timefold.solver.core.impl.bavet.common.tuple.OutputStoreSizeTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleStorePositionTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple;

public final class UnindexedJoinBiNode<A, B>
extends AbstractUnindexedJoinNode<UniTuple<A>, B, BiTuple<A, B>> {

private final BiPredicate<A, B> filtering;
private final int outputStoreSize;

public UnindexedJoinBiNode(
int inputStoreIndexLeftEntry, int inputStoreIndexLeftOutTupleList,
int inputStoreIndexRightEntry, int inputStoreIndexRightOutTupleList,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle, BiPredicate<A, B> filtering,
int outputStoreSize,
int outputStoreIndexLeftOutEntry, int outputStoreIndexRightOutEntry) {
super(inputStoreIndexLeftEntry, inputStoreIndexLeftOutTupleList,
inputStoreIndexRightEntry, inputStoreIndexRightOutTupleList,
nextNodesTupleLifecycle, filtering != null,
outputStoreIndexLeftOutEntry, outputStoreIndexRightOutEntry);

public UnindexedJoinBiNode(TupleStorePositionTracker leftTupleStorePositionTracker,
TupleStorePositionTracker rightTupleStorePositionTracker, OutputStoreSizeTracker outputStoreSizeTracker,
TupleLifecycle<BiTuple<A, B>> nextNodesTupleLifecycle, BiPredicate<A, B> filtering) {
super(leftTupleStorePositionTracker, rightTupleStorePositionTracker, outputStoreSizeTracker, nextNodesTupleLifecycle,
filtering != null);
this.filtering = filtering;
this.outputStoreSize = outputStoreSize;
}

@Override
protected BiTuple<A, B> createOutTuple(UniTuple<A> leftTuple, UniTuple<B> rightTuple) {
return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSize);
return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSizeTracker.computeOutputStoreSize());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package ai.timefold.solver.core.impl.bavet.common;

import ai.timefold.solver.core.impl.bavet.common.index.IndexedSet;
import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState;
import ai.timefold.solver.core.impl.bavet.common.tuple.TupleStorePositionTracker;
import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple;
import ai.timefold.solver.core.impl.util.ElementAwareList;
import ai.timefold.solver.core.impl.util.ElementAwareListEntry;

/**
* This class has two direct children: {@link AbstractIndexedIfExistsNode} and {@link AbstractUnindexedIfExistsNode}.
Expand All @@ -20,20 +20,17 @@ public abstract class AbstractIfExistsNode<LeftTuple_ extends AbstractTuple, Rig
extends AbstractTwoInputNode<LeftTuple_, UniTuple<Right_>> {

protected final boolean shouldExist;

protected final int inputStoreIndexLeftTrackerList; // -1 if !isFiltering
protected final int inputStoreIndexRightTrackerList; // -1 if !isFiltering

protected final int inputStoreIndexLeftTrackerSet; // -1 if !isFiltering
protected final int inputStoreIndexRightTrackerSet; // -1 if !isFiltering
protected final boolean isFiltering;
private final DynamicPropagationQueue<LeftTuple_, ExistsCounter<LeftTuple_>> propagationQueue;

protected AbstractIfExistsNode(boolean shouldExist,
int inputStoreIndexLeftTrackerList, int inputStoreIndexRightTrackerList,
TupleLifecycle<LeftTuple_> nextNodesTupleLifecycle,
protected AbstractIfExistsNode(boolean shouldExist, TupleStorePositionTracker leftTupleStorePositionTracker,
TupleStorePositionTracker rightTupleStorePositionTracker, TupleLifecycle<LeftTuple_> nextNodesTupleLifecycle,
boolean isFiltering) {
this.shouldExist = shouldExist;
this.inputStoreIndexLeftTrackerList = inputStoreIndexLeftTrackerList;
this.inputStoreIndexRightTrackerList = inputStoreIndexRightTrackerList;
this.inputStoreIndexLeftTrackerSet = isFiltering ? leftTupleStorePositionTracker.reserveNextAvailablePosition() : -1;
this.inputStoreIndexRightTrackerSet = isFiltering ? rightTupleStorePositionTracker.reserveNextAvailablePosition() : -1;
this.isFiltering = isFiltering;
this.propagationQueue = new DynamicPropagationQueue<>(nextNodesTupleLifecycle);
}
Expand Down Expand Up @@ -66,8 +63,9 @@ protected void updateCounterLeft(ExistsCounter<LeftTuple_> counter) {
}
case OK, DYING -> propagationQueue.update(counter);
case DEAD, ABORTING -> propagationQueue.insert(counter);
default -> throw new IllegalStateException("Impossible state: the counter (" + counter
+ ") has an impossible insert state (" + state + ").");
default ->
throw new IllegalStateException("Impossible state: the counter (%s) has an impossible insert state (%s)."
.formatted(counter, state));
}
} else {
// Retract or remain dead
Expand All @@ -80,8 +78,9 @@ protected void updateCounterLeft(ExistsCounter<LeftTuple_> counter) {
propagationQueue.retract(counter, TupleState.ABORTING);
case OK, UPDATING -> // Kill the original propagation.
propagationQueue.retract(counter, TupleState.DYING);
default -> throw new IllegalStateException("Impossible state: The counter (" + counter
+ ") has an impossible retract state (" + state + ").");
default ->
throw new IllegalStateException("Impossible state: The counter (%s) has an impossible retract state (%s)."
.formatted(counter, state));

}
}
Expand Down Expand Up @@ -115,27 +114,26 @@ protected void decrementCounterRight(ExistsCounter<LeftTuple_> counter) {
} // Else do not even propagate an update
}

protected ElementAwareList<FilteringTracker<LeftTuple_>> updateRightTrackerList(UniTuple<Right_> rightTuple) {
ElementAwareList<FilteringTracker<LeftTuple_>> rightTrackerList = rightTuple.getStore(inputStoreIndexRightTrackerList);
for (FilteringTracker<LeftTuple_> tuple : rightTrackerList) {
IndexedSet<ExistsCounterHandle<LeftTuple_>> updateRightTrackerSet(UniTuple<Right_> rightTuple) {
IndexedSet<ExistsCounterHandle<LeftTuple_>> rightTrackerSet = rightTuple.getStore(inputStoreIndexRightTrackerSet);
rightTrackerSet.forEach(tuple -> {
decrementCounterRight(tuple.counter);
tuple.remove();
}
return rightTrackerList;
});
return rightTrackerSet;
}

protected void updateCounterFromLeft(LeftTuple_ leftTuple, UniTuple<Right_> rightTuple, ExistsCounter<LeftTuple_> counter,
ElementAwareList<FilteringTracker<LeftTuple_>> leftTrackerList) {
void updateCounterFromLeft(LeftTuple_ leftTuple, UniTuple<Right_> rightTuple, ExistsCounter<LeftTuple_> counter,
IndexedSet<ExistsCounterHandle<LeftTuple_>> leftTrackerSet) {
if (testFiltering(leftTuple, rightTuple)) {
counter.countRight++;
ElementAwareList<FilteringTracker<LeftTuple_>> rightTrackerList =
rightTuple.getStore(inputStoreIndexRightTrackerList);
new FilteringTracker<>(counter, leftTrackerList, rightTrackerList);
IndexedSet<ExistsCounterHandle<LeftTuple_>> rightTrackerSet = rightTuple.getStore(inputStoreIndexRightTrackerSet);
new ExistsCounterHandle<>(counter, leftTrackerSet, rightTrackerSet);
}
}

protected void updateCounterFromRight(UniTuple<Right_> rightTuple, ExistsCounter<LeftTuple_> counter,
ElementAwareList<FilteringTracker<LeftTuple_>> rightTrackerList) {
void updateCounterFromRight(UniTuple<Right_> rightTuple, ExistsCounter<LeftTuple_> counter,
IndexedSet<ExistsCounterHandle<LeftTuple_>> rightTrackerSet) {
var leftTuple = counter.leftTuple;
if (!leftTuple.state.isActive()) {
// Assume the following scenario:
Expand All @@ -156,18 +154,18 @@ protected void updateCounterFromRight(UniTuple<Right_> rightTuple, ExistsCounter
}
if (testFiltering(counter.leftTuple, rightTuple)) {
incrementCounterRight(counter);
ElementAwareList<FilteringTracker<LeftTuple_>> leftTrackerList =
counter.leftTuple.getStore(inputStoreIndexLeftTrackerList);
new FilteringTracker<>(counter, leftTrackerList, rightTrackerList);
IndexedSet<ExistsCounterHandle<LeftTuple_>> leftTrackerSet =
counter.leftTuple.getStore(inputStoreIndexLeftTrackerSet);
new ExistsCounterHandle<>(counter, leftTrackerSet, rightTrackerSet);
}
}

private void doInsertCounter(ExistsCounter<LeftTuple_> counter) {
switch (counter.state) {
case DYING -> propagationQueue.update(counter);
case DEAD, ABORTING -> propagationQueue.insert(counter);
default -> throw new IllegalStateException("Impossible state: the counter (" + counter
+ ") has an impossible insert state (" + counter.state + ").");
default -> throw new IllegalStateException("Impossible state: the counter (%s) has an impossible insert state (%s)."
.formatted(counter, counter.state));
}
}

Expand All @@ -177,8 +175,9 @@ private void doRetractCounter(ExistsCounter<LeftTuple_> counter) {
propagationQueue.retract(counter, TupleState.ABORTING);
case OK, UPDATING -> // Kill the original propagation.
propagationQueue.retract(counter, TupleState.DYING);
default -> throw new IllegalStateException("Impossible state: The counter (" + counter
+ ") has an impossible retract state (" + counter.state + ").");
default ->
throw new IllegalStateException("Impossible state: The counter (%s) has an impossible retract state (%s)."
.formatted(counter, counter.state));
}
}

Expand All @@ -187,23 +186,4 @@ public Propagator getPropagator() {
return propagationQueue;
}

protected static final class FilteringTracker<LeftTuple_ extends AbstractTuple> {
final ExistsCounter<LeftTuple_> counter;
private final ElementAwareListEntry<FilteringTracker<LeftTuple_>> leftTrackerEntry;
private final ElementAwareListEntry<FilteringTracker<LeftTuple_>> rightTrackerEntry;

FilteringTracker(ExistsCounter<LeftTuple_> counter, ElementAwareList<FilteringTracker<LeftTuple_>> leftTrackerList,
ElementAwareList<FilteringTracker<LeftTuple_>> rightTrackerList) {
this.counter = counter;
leftTrackerEntry = leftTrackerList.add(this);
rightTrackerEntry = rightTrackerList.add(this);
}

public void remove() {
leftTrackerEntry.remove();
rightTrackerEntry.remove();
}

}

}
Loading
Loading