>(recordingStaticConstraintStream);
+ var outputStoreSize = buildHelper.extractTupleStoreSize(aftStream);
+
+ buildHelper.addNode(new StaticDataUniNode<>(staticDataBuildHelper.getNodeNetwork(),
+ staticDataBuildHelper.getRecordingTupleLifecycle(),
+ outputStoreSize,
+ buildHelper.getAggregatedTupleLifecycle(aftStream.getChildStreamList()),
+ staticDataBuildHelper.getSourceClasses()),
+ this);
+ }
+
+ @Override
+ public void collectActiveConstraintStreams(Set> constraintStreamSet) {
+ constraintStreamSet.add(this);
+ }
+}
diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/RetrievalSemantics.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/RetrievalSemantics.java
index fa19cc252c..8001c3f686 100644
--- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/RetrievalSemantics.java
+++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/RetrievalSemantics.java
@@ -2,12 +2,13 @@
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;
import ai.timefold.solver.core.api.score.stream.ConstraintFactory;
+import ai.timefold.solver.core.api.score.stream.StaticDataFactory;
/**
* Determines the behavior of joins and conditional propagation
* based on whether they are coming off of a constraint stream started by
- * either {@link ConstraintFactory#from(Class)}
- * or {@link ConstraintFactory#forEach(Class)}
+ * either {@link ConstraintFactory#from(Class)}, {@link ConstraintFactory#forEach(Class)},
+ * or {@link StaticDataFactory#forEachUnfiltered(Class)}
* family of methods.
*
*
@@ -29,6 +30,15 @@ public enum RetrievalSemantics {
* Applies when the stream comes off of a {@link ConstraintFactory#forEach(Class)} family of methods.
*/
STANDARD,
+
+ /**
+ * Joins and conditional propagation always include entities with null planning variables,
+ * regardless of whether their planning variables allow unassigned values.
+ *
+ * Applies when the stream comes off of a {@link StaticDataFactory#forEachUnfiltered(Class)} family of methods.
+ */
+ STATIC,
+
/**
* Joins include entities with null planning variables if these variables allow unassigned values.
* Conditional propagation always includes entities with null planning variables,
diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/bi/InnerBiConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/bi/InnerBiConstraintStream.java
index e3125ff6d3..34c8c71ab1 100644
--- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/bi/InnerBiConstraintStream.java
+++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/bi/InnerBiConstraintStream.java
@@ -1,7 +1,5 @@
package ai.timefold.solver.core.impl.score.stream.common.bi;
-import static ai.timefold.solver.core.impl.score.stream.common.RetrievalSemantics.STANDARD;
-
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
@@ -45,53 +43,55 @@ static BiFunction> createDefaultIndictedObjectsMappin
@Override
default @NonNull TriConstraintStream join(@NonNull Class otherClass, TriJoiner... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return join(getConstraintFactory().forEach(otherClass), joiners);
- } else {
- return join(getConstraintFactory().from(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> join(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> join(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ case LEGACY -> join(getConstraintFactory().from(otherClass), joiners);
+ };
}
@Override
default @NonNull BiConstraintStream ifExists(@NonNull Class otherClass,
TriJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull BiConstraintStream ifExistsIncludingUnassigned(@NonNull Class otherClass,
@NonNull TriJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
- } else {
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ // Calls fromUnfiltered() for backward compatibility only
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull BiConstraintStream ifNotExists(@NonNull Class otherClass,
@NonNull TriJoiner... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifNotExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull BiConstraintStream ifNotExistsIncludingUnassigned(@NonNull Class otherClass,
@NonNull TriJoiner... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifNotExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
- } else {
- return ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifNotExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
+ case STATIC -> ifNotExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ // Calls fromUnfiltered() for backward compatibility only
+ case LEGACY -> ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/quad/InnerQuadConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/quad/InnerQuadConstraintStream.java
index 51911c1737..816d6e2662 100644
--- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/quad/InnerQuadConstraintStream.java
+++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/quad/InnerQuadConstraintStream.java
@@ -44,43 +44,45 @@ static QuadFunction> createDefaultIndicte
@Override
default @NonNull QuadConstraintStream ifExists(@NonNull Class otherClass,
@NonNull PentaJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == RetrievalSemantics.STANDARD) {
- return ifExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull QuadConstraintStream ifExistsIncludingUnassigned(@NonNull Class otherClass,
@NonNull PentaJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == RetrievalSemantics.STANDARD) {
- return ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
- } else {
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ // Calls fromUnfiltered() for backward compatibility only
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull QuadConstraintStream ifNotExists(@NonNull Class otherClass,
@NonNull PentaJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == RetrievalSemantics.STANDARD) {
- return ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifNotExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull QuadConstraintStream ifNotExistsIncludingUnassigned(@NonNull Class otherClass,
@NonNull PentaJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == RetrievalSemantics.STANDARD) {
- return ifNotExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
- } else {
- return ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifNotExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
+ case STATIC -> ifNotExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ // Calls fromUnfiltered() for backward compatibility only
+ case LEGACY -> ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/tri/InnerTriConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/tri/InnerTriConstraintStream.java
index 6d975c6cf5..c531cdf8c7 100644
--- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/tri/InnerTriConstraintStream.java
+++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/tri/InnerTriConstraintStream.java
@@ -1,7 +1,5 @@
package ai.timefold.solver.core.impl.score.stream.common.tri;
-import static ai.timefold.solver.core.impl.score.stream.common.RetrievalSemantics.STANDARD;
-
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
@@ -46,53 +44,55 @@ static TriFunction> createDefaultIndictedObject
@Override
default @NonNull QuadConstraintStream join(@NonNull Class otherClass,
@NonNull QuadJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return join(getConstraintFactory().forEach(otherClass), joiners);
- } else {
- return join(getConstraintFactory().from(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> join(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> join(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ case LEGACY -> join(getConstraintFactory().from(otherClass), joiners);
+ };
}
@Override
default @NonNull TriConstraintStream ifExists(@NonNull Class otherClass,
@NonNull QuadJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull TriConstraintStream ifExistsIncludingUnassigned(@NonNull Class otherClass,
@NonNull QuadJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
- } else {
- return ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifExists(getConstraintFactory().forEachIncludingUnassigned(otherClass), joiners);
+ case STATIC -> ifExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
+ // Calls fromUnfiltered() for backward compatibility only
+ case LEGACY -> ifExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull TriConstraintStream ifNotExists(@NonNull Class otherClass,
@NonNull QuadJoiner @NonNull... joiners) {
- if (getRetrievalSemantics() == STANDARD) {
- return ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
- } else {
+ return switch (getRetrievalSemantics()) {
+ case STANDARD -> ifNotExists(getConstraintFactory().forEach(otherClass), joiners);
+ case STATIC -> ifNotExists(getConstraintFactory().forEachUnfiltered(otherClass), joiners);
// Calls fromUnfiltered() for backward compatibility only
- return ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
- }
+ case LEGACY -> ifNotExists(getConstraintFactory().fromUnfiltered(otherClass), joiners);
+ };
}
@Override
default @NonNull