From ae71162c6f08723a5419e8479db5cdc20ea7433c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Sat, 20 Dec 2025 08:39:05 +0100 Subject: [PATCH 01/10] perf: monomorphic tuple # Conflicts: # core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNode.java # core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java # Conflicts: # core/src/main/java/ai/timefold/solver/core/impl/bavet/common/RecordAndReplayPropagator.java --- .../impl/bavet/bi/AbstractGroupBiNode.java | 6 +- .../core/impl/bavet/bi/ConcatBiBiNode.java | 12 +- .../core/impl/bavet/bi/ConcatBiUniNode.java | 12 +- .../core/impl/bavet/bi/ConcatUniBiNode.java | 12 +- .../core/impl/bavet/bi/FlattenLastBiNode.java | 4 +- .../bi/Group0Mapping1CollectorBiNode.java | 4 +- .../bi/Group0Mapping2CollectorBiNode.java | 6 +- .../bi/Group0Mapping3CollectorBiNode.java | 8 +- .../bi/Group0Mapping4CollectorBiNode.java | 10 +- .../bi/Group1Mapping0CollectorBiNode.java | 4 +- .../bi/Group1Mapping1CollectorBiNode.java | 4 +- .../bi/Group1Mapping2CollectorBiNode.java | 6 +- .../bi/Group1Mapping3CollectorBiNode.java | 8 +- .../bi/Group2Mapping0CollectorBiNode.java | 10 +- .../bi/Group2Mapping1CollectorBiNode.java | 4 +- .../bi/Group2Mapping2CollectorBiNode.java | 6 +- .../bi/Group3Mapping0CollectorBiNode.java | 12 +- .../bi/Group3Mapping1CollectorBiNode.java | 4 +- .../bi/Group4Mapping0CollectorBiNode.java | 13 +-- .../impl/bavet/bi/IndexedIfExistsBiNode.java | 2 +- .../core/impl/bavet/bi/IndexedJoinBiNode.java | 8 +- .../core/impl/bavet/bi/MapBiToBiNode.java | 19 ++- .../core/impl/bavet/bi/MapBiToQuadNode.java | 28 ++--- .../core/impl/bavet/bi/MapBiToTriNode.java | 24 ++-- .../core/impl/bavet/bi/MapBiToUniNode.java | 15 +-- .../core/impl/bavet/bi/PrecomputeBiNode.java | 2 +- .../bavet/bi/UnindexedIfExistsBiNode.java | 2 +- .../impl/bavet/bi/UnindexedJoinBiNode.java | 8 +- .../impl/bavet/common/AbstractConcatNode.java | 16 +-- .../bavet/common/AbstractFlattenLastNode.java | 6 +- .../impl/bavet/common/AbstractGroupNode.java | 18 +-- .../common/AbstractGroupNodeConstructor.java | 4 +- .../bavet/common/AbstractIfExistsNode.java | 8 +- .../common/AbstractIndexedIfExistsNode.java | 4 +- .../bavet/common/AbstractIndexedJoinNode.java | 8 +- .../impl/bavet/common/AbstractJoinNode.java | 20 ++-- .../impl/bavet/common/AbstractMapNode.java | 10 +- .../bavet/common/AbstractNodeBuildHelper.java | 20 ++-- .../bavet/common/AbstractPrecomputeNode.java | 4 +- .../AbstractPropagationMetadataCarrier.java | 4 +- .../impl/bavet/common/AbstractScorer.java | 4 +- .../bavet/common/AbstractTwoInputNode.java | 4 +- .../common/AbstractUnindexedIfExistsNode.java | 4 +- .../common/AbstractUnindexedJoinNode.java | 6 +- .../bavet/common/DynamicPropagationQueue.java | 4 +- .../core/impl/bavet/common/ExistsCounter.java | 4 +- .../solver/core/impl/bavet/common/Group.java | 14 +-- .../bavet/common/GroupNodeConstructor.java | 64 +++++----- .../GroupNodeConstructorWithAccumulate.java | 4 +- ...GroupNodeConstructorWithoutAccumulate.java | 4 +- .../common/RecordAndReplayPropagator.java | 8 +- .../bavet/common/StaticPropagationQueue.java | 26 ++--- .../core/impl/bavet/common/TupleRecorder.java | 4 +- .../bavet/common/index/IndexerFactory.java | 66 +++++------ .../bavet/common/tuple/AbstractTuple.java | 45 -------- .../tuple/AggregatedTupleLifecycle.java | 2 +- .../core/impl/bavet/common/tuple/BiTuple.java | 37 ++++-- .../tuple/ConditionalTupleLifecycle.java | 4 +- .../common/tuple/LeftTupleLifecycle.java | 2 +- .../common/tuple/LeftTupleLifecycleImpl.java | 2 +- .../impl/bavet/common/tuple/QuadTuple.java | 67 ++++++++--- .../common/tuple/RecordingTupleLifecycle.java | 2 +- .../common/tuple/RightTupleLifecycle.java | 2 +- .../common/tuple/RightTupleLifecycleImpl.java | 2 +- .../impl/bavet/common/tuple/TriTuple.java | 54 ++++++--- .../core/impl/bavet/common/tuple/Tuple.java | 36 ++++++ .../bavet/common/tuple/TupleLifecycle.java | 19 +-- .../impl/bavet/common/tuple/UniTuple.java | 24 ++-- .../bavet/common/tuple/UniversalTuple.java | 109 ++++++++++++++++++ .../bavet/quad/AbstractGroupQuadNode.java | 6 +- .../impl/bavet/quad/ConcatBiQuadNode.java | 21 ++-- .../impl/bavet/quad/ConcatQuadBiNode.java | 21 ++-- .../impl/bavet/quad/ConcatQuadQuadNode.java | 20 ++-- .../impl/bavet/quad/ConcatQuadTriNode.java | 24 ++-- .../impl/bavet/quad/ConcatQuadUniNode.java | 17 ++- .../impl/bavet/quad/ConcatTriQuadNode.java | 26 ++--- .../impl/bavet/quad/ConcatUniQuadNode.java | 17 ++- .../impl/bavet/quad/FlattenLastQuadNode.java | 5 +- .../quad/Group0Mapping1CollectorQuadNode.java | 4 +- .../quad/Group0Mapping2CollectorQuadNode.java | 6 +- .../quad/Group0Mapping3CollectorQuadNode.java | 8 +- .../quad/Group0Mapping4CollectorQuadNode.java | 10 +- .../quad/Group1Mapping0CollectorQuadNode.java | 4 +- .../quad/Group1Mapping1CollectorQuadNode.java | 4 +- .../quad/Group1Mapping2CollectorQuadNode.java | 6 +- .../quad/Group1Mapping3CollectorQuadNode.java | 8 +- .../quad/Group2Mapping0CollectorQuadNode.java | 14 +-- .../quad/Group2Mapping1CollectorQuadNode.java | 4 +- .../quad/Group2Mapping2CollectorQuadNode.java | 6 +- .../quad/Group3Mapping0CollectorQuadNode.java | 16 ++- .../quad/Group3Mapping1CollectorQuadNode.java | 4 +- .../quad/Group4Mapping0CollectorQuadNode.java | 17 ++- .../bavet/quad/IndexedIfExistsQuadNode.java | 3 +- .../impl/bavet/quad/IndexedJoinQuadNode.java | 12 +- .../core/impl/bavet/quad/MapQuadToBiNode.java | 28 ++--- .../impl/bavet/quad/MapQuadToQuadNode.java | 37 +++--- .../impl/bavet/quad/MapQuadToTriNode.java | 31 +++-- .../impl/bavet/quad/MapQuadToUniNode.java | 24 ++-- .../impl/bavet/quad/PrecomputeQuadNode.java | 3 +- .../bavet/quad/UnindexedIfExistsQuadNode.java | 3 +- .../bavet/quad/UnindexedJoinQuadNode.java | 12 +- .../impl/bavet/tri/AbstractGroupTriNode.java | 6 +- .../core/impl/bavet/tri/ConcatBiTriNode.java | 18 +-- .../core/impl/bavet/tri/ConcatTriBiNode.java | 18 +-- .../core/impl/bavet/tri/ConcatTriTriNode.java | 16 +-- .../core/impl/bavet/tri/ConcatTriUniNode.java | 16 ++- .../core/impl/bavet/tri/ConcatUniTriNode.java | 16 ++- .../impl/bavet/tri/FlattenLastTriNode.java | 4 +- .../tri/Group0Mapping1CollectorTriNode.java | 4 +- .../tri/Group0Mapping2CollectorTriNode.java | 6 +- .../tri/Group0Mapping3CollectorTriNode.java | 8 +- .../tri/Group0Mapping4CollectorTriNode.java | 10 +- .../tri/Group1Mapping0CollectorTriNode.java | 4 +- .../tri/Group1Mapping1CollectorTriNode.java | 4 +- .../tri/Group1Mapping2CollectorTriNode.java | 6 +- .../tri/Group1Mapping3CollectorTriNode.java | 8 +- .../tri/Group2Mapping0CollectorTriNode.java | 12 +- .../tri/Group2Mapping1CollectorTriNode.java | 4 +- .../tri/Group2Mapping2CollectorTriNode.java | 6 +- .../tri/Group3Mapping0CollectorTriNode.java | 14 +-- .../tri/Group3Mapping1CollectorTriNode.java | 4 +- .../tri/Group4Mapping0CollectorTriNode.java | 15 +-- .../bavet/tri/IndexedIfExistsTriNode.java | 2 +- .../impl/bavet/tri/IndexedJoinTriNode.java | 10 +- .../core/impl/bavet/tri/MapTriToBiNode.java | 22 ++-- .../core/impl/bavet/tri/MapTriToQuadNode.java | 32 ++--- .../core/impl/bavet/tri/MapTriToTriNode.java | 28 ++--- .../core/impl/bavet/tri/MapTriToUniNode.java | 20 ++-- .../impl/bavet/tri/PrecomputeTriNode.java | 2 +- .../bavet/tri/UnindexedIfExistsTriNode.java | 2 +- .../impl/bavet/tri/UnindexedJoinTriNode.java | 10 +- .../bavet/uni/AbstractForEachUniNode.java | 6 +- .../impl/bavet/uni/AbstractGroupUniNode.java | 6 +- .../core/impl/bavet/uni/ConcatUniUniNode.java | 8 +- .../impl/bavet/uni/FlattenLastUniNode.java | 4 +- .../uni/Group0Mapping1CollectorUniNode.java | 4 +- .../uni/Group0Mapping2CollectorUniNode.java | 6 +- .../uni/Group0Mapping3CollectorUniNode.java | 8 +- .../uni/Group0Mapping4CollectorUniNode.java | 10 +- .../uni/Group1Mapping0CollectorUniNode.java | 4 +- .../uni/Group1Mapping1CollectorUniNode.java | 4 +- .../uni/Group1Mapping2CollectorUniNode.java | 6 +- .../uni/Group1Mapping3CollectorUniNode.java | 8 +- .../uni/Group2Mapping0CollectorUniNode.java | 8 +- .../uni/Group2Mapping1CollectorUniNode.java | 4 +- .../uni/Group2Mapping2CollectorUniNode.java | 6 +- .../uni/Group3Mapping0CollectorUniNode.java | 9 +- .../uni/Group3Mapping1CollectorUniNode.java | 4 +- .../uni/Group4Mapping0CollectorUniNode.java | 11 +- .../bavet/uni/IndexedIfExistsUniNode.java | 2 +- .../core/impl/bavet/uni/MapUniToBiNode.java | 15 +-- .../core/impl/bavet/uni/MapUniToQuadNode.java | 24 ++-- .../core/impl/bavet/uni/MapUniToTriNode.java | 21 ++-- .../core/impl/bavet/uni/MapUniToUniNode.java | 12 +- .../impl/bavet/uni/PrecomputeUniNode.java | 2 +- .../bavet/uni/UnindexedIfExistsUniNode.java | 2 +- .../stream/BiOriginalMoveIterator.java | 6 +- .../stream/BiRandomMoveIterator.java | 8 +- .../stream/FilteringIterator.java | 6 +- .../common/AbstractDatasetInstance.java | 4 +- .../common/AbstractLeftDatasetInstance.java | 4 +- .../common/DataNodeBuildHelper.java | 4 +- .../impl/score/stream/bavet/bi/BiScorer.java | 2 +- .../common/BavetPrecomputeBuildHelper.java | 4 +- .../score/stream/bavet/quad/QuadScorer.java | 2 +- .../score/stream/bavet/tri/TriScorer.java | 2 +- .../score/stream/bavet/uni/UniScorer.java | 2 +- .../index/EqualsAndComparisonIndexerTest.java | 2 +- .../bavet/common/index/EqualsIndexerTest.java | 2 +- .../index/RandomAccessIndexerBackendTest.java | 2 +- .../bavet/uni/FlattenLastUniNodeTest.java | 39 ++++--- .../enumerating/UniEnumeratingStreamTest.java | 41 +++---- 172 files changed, 1063 insertions(+), 1007 deletions(-) delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AbstractTuple.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/Tuple.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniversalTuple.java diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/AbstractGroupBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/AbstractGroupBiNode.java index 425fba808c..659eded5b3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/AbstractGroupBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/AbstractGroupBiNode.java @@ -6,11 +6,11 @@ import ai.timefold.solver.core.api.score.stream.bi.BiConstraintCollector; import ai.timefold.solver.core.config.solver.EnvironmentMode; import ai.timefold.solver.core.impl.bavet.common.AbstractGroupNode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -abstract class AbstractGroupBiNode +abstract class AbstractGroupBiNode extends AbstractGroupNode, OutTuple_, GroupKey_, ResultContainer_, Result_> { private final TriFunction accumulator; @@ -37,7 +37,7 @@ protected AbstractGroupBiNode(int groupStoreIndex, @Override protected final Runnable accumulate(ResultContainer_ resultContainer, BiTuple tuple) { - return accumulator.apply(resultContainer, tuple.factA, tuple.factB); + return accumulator.apply(resultContainer, tuple.getA(), tuple.getB()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiBiNode.java index 27dcbaf79a..0dda60d09c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiBiNode.java @@ -15,24 +15,24 @@ public ConcatBiBiNode(TupleLifecycle> nextNodesTupleLifecycle, @Override protected BiTuple getOutTupleFromLeft(BiTuple leftTuple) { - return new BiTuple<>(leftTuple.factA, leftTuple.factB, outputStoreSize); + return BiTuple.of(leftTuple.getA(), leftTuple.getB(), outputStoreSize); } @Override protected BiTuple getOutTupleFromRight(BiTuple rightTuple) { - return new BiTuple<>(rightTuple.factA, rightTuple.factB, outputStoreSize); + return BiTuple.of(rightTuple.getA(), rightTuple.getB(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(BiTuple leftTuple, BiTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void updateOutTupleFromRight(BiTuple rightTuple, BiTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiUniNode.java index 02e37019c0..5c8f07e725 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatBiUniNode.java @@ -21,24 +21,24 @@ public ConcatBiUniNode(Function paddingFunction, TupleLifecycle getOutTupleFromLeft(BiTuple leftTuple) { - return new BiTuple<>(leftTuple.factA, leftTuple.factB, outputStoreSize); + return BiTuple.of(leftTuple.getA(), leftTuple.getB(), outputStoreSize); } @Override protected BiTuple getOutTupleFromRight(UniTuple rightTuple) { - var factA = rightTuple.factA; - return new BiTuple<>(factA, paddingFunction.apply(factA), outputStoreSize); + var factA = rightTuple.getA(); + return BiTuple.of(factA, paddingFunction.apply(factA), outputStoreSize); } @Override protected void updateOutTupleFromLeft(BiTuple leftTuple, BiTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void updateOutTupleFromRight(UniTuple rightTuple, BiTuple outTuple) { - outTuple.factA = rightTuple.factA; + outTuple.setA(rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatUniBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatUniBiNode.java index 700ad1c2cc..c1caf99ca0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatUniBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/ConcatUniBiNode.java @@ -22,24 +22,24 @@ public ConcatUniBiNode(Function paddingFunction, TupleLifecycle getOutTupleFromLeft(UniTuple leftTuple) { - var factA = leftTuple.factA; - return new BiTuple<>(factA, paddingFunction.apply(factA), outputStoreSize); + var factA = leftTuple.getA(); + return BiTuple.of(factA, paddingFunction.apply(factA), outputStoreSize); } @Override protected BiTuple getOutTupleFromRight(BiTuple rightTuple) { - return new BiTuple<>(rightTuple.factA, rightTuple.factB, outputStoreSize); + return BiTuple.of(rightTuple.getA(), rightTuple.getB(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(UniTuple leftTuple, BiTuple outTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void updateOutTupleFromRight(BiTuple rightTuple, BiTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/FlattenLastBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/FlattenLastBiNode.java index bcb5ecdef1..160b96027b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/FlattenLastBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/FlattenLastBiNode.java @@ -18,12 +18,12 @@ public FlattenLastBiNode(int flattenLastStoreIndex, Function> @Override protected BiTuple createTuple(BiTuple originalTuple, NewB newB) { - return new BiTuple<>(originalTuple.factA, newB, outputStoreSize); + return BiTuple.of(originalTuple.getA(), newB, outputStoreSize); } @Override protected B getEffectiveFactIn(BiTuple tuple) { - return tuple.factB; + return tuple.getB(); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping1CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping1CollectorBiNode.java index 2fff40a8e1..d0d7a44081 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping1CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping1CollectorBiNode.java @@ -20,12 +20,12 @@ public Group0Mapping1CollectorBiNode(int groupStoreIndex, int undoStoreIndex, @Override protected UniTuple createOutTuple(Void groupKey) { - return new UniTuple<>(null, outputStoreSize); + return UniTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(UniTuple outTuple, A a) { - outTuple.factA = a; + outTuple.setA(a); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping2CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping2CollectorBiNode.java index 28493700fa..074c13da74 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping2CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping2CollectorBiNode.java @@ -31,13 +31,13 @@ BiConstraintCollector> mergeCollectors( @Override protected BiTuple createOutTuple(Void groupKey) { - return new BiTuple<>(null, null, outputStoreSize); + return BiTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, Pair result) { - outTuple.factA = result.key(); - outTuple.factB = result.value(); + outTuple.setA(result.key()); + outTuple.setB(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping3CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping3CollectorBiNode.java index 4c2e3d86fd..64f3f1e0c6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping3CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping3CollectorBiNode.java @@ -34,14 +34,14 @@ BiConstraintCollector> mergeCollectors( @Override protected TriTuple createOutTuple(Void groupKey) { - return new TriTuple<>(null, null, null, outputStoreSize); + return TriTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Triple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping4CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping4CollectorBiNode.java index 8d369e2f6c..9c36a5d7e6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping4CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group0Mapping4CollectorBiNode.java @@ -38,15 +38,15 @@ BiConstraintCollector> mergeCollectors @Override protected QuadTuple createOutTuple(Void groupKey) { - return new QuadTuple<>(null, null, null, null, outputStoreSize); + return QuadTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Quadruple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); - outTuple.factD = result.d(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); + outTuple.setD(result.d()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping0CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping0CollectorBiNode.java index 8da5045ac1..0e1b1862d7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping0CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping0CollectorBiNode.java @@ -21,12 +21,12 @@ public Group1Mapping0CollectorBiNode(BiFunction groupKeyMapping, } static A createGroupKey(BiFunction groupKeyMapping, BiTuple tuple) { - return groupKeyMapping.apply(tuple.factA, tuple.factB); + return groupKeyMapping.apply(tuple.getA(), tuple.getB()); } @Override protected UniTuple createOutTuple(A a) { - return new UniTuple<>(a, outputStoreSize); + return UniTuple.of(a, outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping1CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping1CollectorBiNode.java index 17f13c6e3c..a818f6c492 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping1CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping1CollectorBiNode.java @@ -26,12 +26,12 @@ public Group1Mapping1CollectorBiNode(BiFunction groupKeyMapping, @Override protected BiTuple createOutTuple(A a) { - return new BiTuple<>(a, null, outputStoreSize); + return BiTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, B b) { - outTuple.factB = b; + outTuple.setB(b); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping2CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping2CollectorBiNode.java index 8a95f69eb2..9c522aaf8e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping2CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping2CollectorBiNode.java @@ -29,13 +29,13 @@ public Group1Mapping2CollectorBiNode(BiFunction groupKeyMapping, @Override protected TriTuple createOutTuple(A a) { - return new TriTuple<>(a, null, null, outputStoreSize); + return TriTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Pair result) { - outTuple.factB = result.key(); - outTuple.factC = result.value(); + outTuple.setB(result.key()); + outTuple.setC(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping3CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping3CollectorBiNode.java index 62f5ae9b64..1363ac13aa 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping3CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group1Mapping3CollectorBiNode.java @@ -31,14 +31,14 @@ public Group1Mapping3CollectorBiNode(BiFunction groupKeyMapping, @Override protected QuadTuple createOutTuple(A a) { - return new QuadTuple<>(a, null, null, null, outputStoreSize); + return QuadTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Triple result) { - outTuple.factB = result.a(); - outTuple.factC = result.b(); - outTuple.factD = result.c(); + outTuple.setB(result.a()); + outTuple.setC(result.b()); + outTuple.setD(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping0CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping0CollectorBiNode.java index f567f84639..c431ca6606 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping0CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping0CollectorBiNode.java @@ -23,16 +23,14 @@ public Group2Mapping0CollectorBiNode(BiFunction groupKeyMappingA, static Pair createGroupKey(BiFunction groupKeyMappingA, BiFunction groupKeyMappingB, BiTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - A a = groupKeyMappingA.apply(oldA, oldB); - B b = groupKeyMappingB.apply(oldA, oldB); - return new Pair<>(a, b); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + return new Pair<>(groupKeyMappingA.apply(oldA, oldB), groupKeyMappingB.apply(oldA, oldB)); } @Override protected BiTuple createOutTuple(Pair groupKey) { - return new BiTuple<>(groupKey.key(), groupKey.value(), outputStoreSize); + return BiTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping1CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping1CollectorBiNode.java index d18b55c937..616a564f9a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping1CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping1CollectorBiNode.java @@ -25,12 +25,12 @@ public Group2Mapping1CollectorBiNode(BiFunction groupKeyMappingA, @Override protected TriTuple createOutTuple(Pair groupKey) { - return new TriTuple<>(groupKey.key(), groupKey.value(), null, outputStoreSize); + return TriTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, C c) { - outTuple.factC = c; + outTuple.setC(c); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping2CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping2CollectorBiNode.java index 0d07488ce4..96fd85e560 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping2CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group2Mapping2CollectorBiNode.java @@ -29,13 +29,13 @@ public Group2Mapping2CollectorBiNode(BiFunction groupKeyMappingA, @Override protected QuadTuple createOutTuple(Pair groupKey) { - return new QuadTuple<>(groupKey.key(), groupKey.value(), null, null, outputStoreSize); + return QuadTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Pair result) { - outTuple.factC = result.key(); - outTuple.factD = result.value(); + outTuple.setC(result.key()); + outTuple.setD(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping0CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping0CollectorBiNode.java index ea313a7dd0..9d24783786 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping0CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping0CollectorBiNode.java @@ -25,17 +25,15 @@ public Group3Mapping0CollectorBiNode(BiFunction groupKeyMappingA, static Triple createGroupKey(BiFunction groupKeyMappingA, BiFunction groupKeyMappingB, BiFunction groupKeyMappingC, BiTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - A a = groupKeyMappingA.apply(oldA, oldB); - B b = groupKeyMappingB.apply(oldA, oldB); - C c = groupKeyMappingC.apply(oldA, oldB); - return new Triple<>(a, b, c); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + return new Triple<>(groupKeyMappingA.apply(oldA, oldB), groupKeyMappingB.apply(oldA, oldB), + groupKeyMappingC.apply(oldA, oldB)); } @Override protected TriTuple createOutTuple(Triple groupKey) { - return new TriTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); + return TriTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping1CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping1CollectorBiNode.java index 3d768ee557..b39c5cea2e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping1CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group3Mapping1CollectorBiNode.java @@ -30,12 +30,12 @@ public Group3Mapping1CollectorBiNode(BiFunction groupKeyMappingA, @Override protected QuadTuple createOutTuple(Triple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), null, outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, D d) { - outTuple.factD = d; + outTuple.setD(d); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group4Mapping0CollectorBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group4Mapping0CollectorBiNode.java index 7220bdacd9..33bb4a67f1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group4Mapping0CollectorBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/Group4Mapping0CollectorBiNode.java @@ -29,18 +29,15 @@ private static Quadruple createGroupKey( BiFunction groupKeyMappingA, BiFunction groupKeyMappingB, BiFunction groupKeyMappingC, BiFunction groupKeyMappingD, BiTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - A a = groupKeyMappingA.apply(oldA, oldB); - B b = groupKeyMappingB.apply(oldA, oldB); - C c = groupKeyMappingC.apply(oldA, oldB); - D d = groupKeyMappingD.apply(oldA, oldB); - return new Quadruple<>(a, b, c, d); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + return new Quadruple<>(groupKeyMappingA.apply(oldA, oldB), groupKeyMappingB.apply(oldA, oldB), + groupKeyMappingC.apply(oldA, oldB), groupKeyMappingD.apply(oldA, oldB)); } @Override protected QuadTuple createOutTuple(Quadruple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedIfExistsBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedIfExistsBiNode.java index 2863df5e34..08cefb384a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedIfExistsBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedIfExistsBiNode.java @@ -27,7 +27,7 @@ public IndexedIfExistsBiNode(boolean shouldExist, IndexerFactory indexerFacto @Override protected boolean testFiltering(BiTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedJoinBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedJoinBiNode.java index 92070ffcca..a9ffef4fd9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedJoinBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/IndexedJoinBiNode.java @@ -22,22 +22,22 @@ public IndexedJoinBiNode(IndexerFactory indexerFactory, TupleLifecycle createOutTuple(UniTuple leftTuple, UniTuple rightTuple) { - return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSizeTracker.computeStoreSize()); + return BiTuple.of(leftTuple.getA(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(BiTuple outTuple, UniTuple leftTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void setOutTupleRightFact(BiTuple outTuple, UniTuple rightTuple) { - outTuple.factB = rightTuple.factA; + outTuple.setB(rightTuple.getA()); } @Override protected boolean testFiltering(UniTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, rightTuple.factA); + return filtering.test(leftTuple.getA(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToBiNode.java index 63bf37bfc6..b8884696fd 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToBiNode.java @@ -21,22 +21,17 @@ public MapBiToBiNode(int mapStoreIndex, BiFunction mappingFunctionA, @Override protected BiTuple map(BiTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - return new BiTuple<>( - mappingFunctionA.apply(factA, factB), - mappingFunctionB.apply(factA, factB), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + return BiTuple.of(mappingFunctionA.apply(factA, factB), mappingFunctionB.apply(factA, factB), outputStoreSize); } @Override protected void remap(BiTuple inTuple, BiTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - NewA newA = mappingFunctionA.apply(factA, factB); - NewB newB = mappingFunctionB.apply(factA, factB); - outTuple.factA = newA; - outTuple.factB = newB; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + outTuple.setA(mappingFunctionA.apply(factA, factB)); + outTuple.setB(mappingFunctionB.apply(factA, factB)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToQuadNode.java index 42e314f411..58abc1300a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToQuadNode.java @@ -28,28 +28,20 @@ public MapBiToQuadNode(int mapStoreIndex, BiFunction mappingFunction @Override protected QuadTuple map(BiTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - return new QuadTuple<>( - mappingFunctionA.apply(factA, factB), - mappingFunctionB.apply(factA, factB), - mappingFunctionC.apply(factA, factB), - mappingFunctionD.apply(factA, factB), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + return QuadTuple.of(mappingFunctionA.apply(factA, factB), mappingFunctionB.apply(factA, factB), + mappingFunctionC.apply(factA, factB), mappingFunctionD.apply(factA, factB), outputStoreSize); } @Override protected void remap(BiTuple inTuple, QuadTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - NewA newA = mappingFunctionA.apply(factA, factB); - NewB newB = mappingFunctionB.apply(factA, factB); - NewC newC = mappingFunctionC.apply(factA, factB); - NewD newD = mappingFunctionD.apply(factA, factB); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; - outTuple.factD = newD; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + outTuple.setA(mappingFunctionA.apply(factA, factB)); + outTuple.setB(mappingFunctionB.apply(factA, factB)); + outTuple.setC(mappingFunctionC.apply(factA, factB)); + outTuple.setD(mappingFunctionD.apply(factA, factB)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToTriNode.java index e745fd8338..ea8de70cdb 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToTriNode.java @@ -25,25 +25,19 @@ public MapBiToTriNode(int mapStoreIndex, BiFunction mappingFunctionA @Override protected TriTuple map(BiTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - return new TriTuple<>( - mappingFunctionA.apply(factA, factB), - mappingFunctionB.apply(factA, factB), - mappingFunctionC.apply(factA, factB), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + return TriTuple.of(mappingFunctionA.apply(factA, factB), mappingFunctionB.apply(factA, factB), + mappingFunctionC.apply(factA, factB), outputStoreSize); } @Override protected void remap(BiTuple inTuple, TriTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - NewA newA = mappingFunctionA.apply(factA, factB); - NewB newB = mappingFunctionB.apply(factA, factB); - NewC newC = mappingFunctionC.apply(factA, factB); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + outTuple.setA(mappingFunctionA.apply(factA, factB)); + outTuple.setB(mappingFunctionB.apply(factA, factB)); + outTuple.setC(mappingFunctionC.apply(factA, factB)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToUniNode.java index 1462b7ce36..73a5f1c140 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/MapBiToUniNode.java @@ -20,19 +20,16 @@ public MapBiToUniNode(int mapStoreIndex, BiFunction mappingFunction, @Override protected UniTuple map(BiTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - return new UniTuple<>( - mappingFunction.apply(factA, factB), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + return UniTuple.of(mappingFunction.apply(factA, factB), outputStoreSize); } @Override protected void remap(BiTuple inTuple, UniTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - NewA newA = mappingFunction.apply(factA, factB); - outTuple.factA = newA; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + outTuple.setA(mappingFunction.apply(factA, factB)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/PrecomputeBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/PrecomputeBiNode.java index ed7879379d..ee4f3575c3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/PrecomputeBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/PrecomputeBiNode.java @@ -23,6 +23,6 @@ public PrecomputeBiNode(Supplier>> prec @Override protected BiTuple remapTuple(BiTuple tuple) { - return new BiTuple<>(tuple.factA, tuple.factB, outputStoreSize); + return BiTuple.of(tuple.getA(), tuple.getB(), outputStoreSize); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedIfExistsBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedIfExistsBiNode.java index c2bfa2a77e..f34c89e5a9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedIfExistsBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedIfExistsBiNode.java @@ -24,7 +24,7 @@ public UnindexedIfExistsBiNode(boolean shouldExist, TupleLifecycle @Override protected boolean testFiltering(BiTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedJoinBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedJoinBiNode.java index a374595b48..b0758e6fe3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedJoinBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/UnindexedJoinBiNode.java @@ -21,22 +21,22 @@ public UnindexedJoinBiNode(TupleLifecycle> nextNodesTupleLifecycle @Override protected BiTuple createOutTuple(UniTuple leftTuple, UniTuple rightTuple) { - return new BiTuple<>(leftTuple.factA, rightTuple.factA, outputStoreSizeTracker.computeStoreSize()); + return BiTuple.of(leftTuple.getA(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(BiTuple outTuple, UniTuple leftTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void setOutTupleRightFact(BiTuple outTuple, UniTuple rightTuple) { - outTuple.factB = rightTuple.factA; + outTuple.setB(rightTuple.getA()); } @Override protected boolean testFiltering(UniTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, rightTuple.factA); + return filtering.test(leftTuple.getA(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractConcatNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractConcatNode.java index 87b4b21dd8..42b40f5223 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractConcatNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractConcatNode.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; @@ -24,7 +24,7 @@ * the tuple's store. If the same tuple is inserted twice (i.e. when the left and right parent * have the same {@link TupleSource}), it creates another clone. */ -public abstract class AbstractConcatNode +public abstract class AbstractConcatNode extends AbstractTwoInputNode { private final int leftSourceTupleCloneStoreIndex; @@ -52,7 +52,7 @@ protected AbstractConcatNode(TupleLifecycle nextNodesTupleLifecycle, @Override public final void insertLeft(LeftTuple_ tuple) { - OutTuple_ outTuple = getOutTupleFromLeft(tuple); + var outTuple = getOutTupleFromLeft(tuple); tuple.setStore(leftSourceTupleCloneStoreIndex, outTuple); propagationQueue.insert(outTuple); } @@ -69,7 +69,7 @@ public final void updateLeft(LeftTuple_ tuple) { updateOutTupleFromLeft(tuple, outTuple); // Even if the facts of tuple do not change, an update MUST be done so // downstream nodes get notified of updates in planning variables. - TupleState previousState = outTuple.state; + var previousState = outTuple.getState(); if (previousState == TupleState.CREATING || previousState == TupleState.UPDATING) { return; } @@ -83,7 +83,7 @@ public final void retractLeft(LeftTuple_ tuple) { // No fail fast if null because we don't track which tuples made it through the filter predicate(s) return; } - TupleState state = outTuple.state; + var state = outTuple.getState(); if (!state.isActive()) { // No fail fast for inactive tuples, since the same tuple can be // passed twice if they are from the same source; @@ -95,7 +95,7 @@ public final void retractLeft(LeftTuple_ tuple) { @Override public final void insertRight(RightTuple_ tuple) { - OutTuple_ outTuple = getOutTupleFromRight(tuple); + var outTuple = getOutTupleFromRight(tuple); tuple.setStore(rightSourceTupleCloneStoreIndex, outTuple); propagationQueue.insert(outTuple); } @@ -112,7 +112,7 @@ public final void updateRight(RightTuple_ tuple) { updateOutTupleFromRight(tuple, outTuple); // Even if the facts of tuple do not change, an update MUST be done so // downstream nodes get notified of updates in planning variables. - TupleState previousState = outTuple.state; + var previousState = outTuple.getState(); if (previousState == TupleState.CREATING || previousState == TupleState.UPDATING) { return; } @@ -126,7 +126,7 @@ public final void retractRight(RightTuple_ tuple) { // No fail fast if null because we don't track which tuples made it through the filter predicate(s) return; } - TupleState state = outTuple.state; + var state = outTuple.getState(); if (!state.isActive()) { // No fail fast for inactive tuples, since the same tuple can be // passed twice if they are from the same source; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractFlattenLastNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractFlattenLastNode.java index 0877555ec9..2c440f44e7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractFlattenLastNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractFlattenLastNode.java @@ -10,12 +10,12 @@ import java.util.function.Function; import java.util.function.Supplier; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; 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.util.CollectionUtils; -public abstract class AbstractFlattenLastNode +public abstract class AbstractFlattenLastNode extends AbstractNode implements TupleLifecycle { @@ -103,7 +103,7 @@ public final void retract(InTuple_ tuple) { } private void removeTuple(OutTuple_ outTuple) { - var state = outTuple.state; + var state = outTuple.getState(); if (!state.isActive()) { throw new IllegalStateException("Impossible state: The tuple (%s) is in an unexpected state (%s)." .formatted(outTuple, state)); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNode.java index 7df2c693f5..034d20e524 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNode.java @@ -7,11 +7,11 @@ import java.util.function.Supplier; import ai.timefold.solver.core.config.solver.EnvironmentMode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; -public abstract class AbstractGroupNode +public abstract class AbstractGroupNode extends AbstractNode implements TupleLifecycle { @@ -76,7 +76,7 @@ protected AbstractGroupNode(int groupStoreIndex, int undoStoreIndex, this.propagationQueue = hasCollector ? new DynamicPropagationQueue<>(nextNodesTupleLifecycle, group -> { var outTuple = group.getTuple(); - var state = outTuple.state; + var state = outTuple.getState(); if (state == TupleState.CREATING || state == TupleState.UPDATING) { updateOutTupleToFinisher(outTuple, group.getResultContainer()); } @@ -105,14 +105,14 @@ public final void insert(InTuple_ tuple) { private void createTuple(InTuple_ tuple, GroupKey_ userSuppliedKey) { var newGroup = getOrCreateGroup(userSuppliedKey); var outTuple = accumulate(tuple, newGroup); - switch (outTuple.state) { + switch (outTuple.getState()) { case CREATING, UPDATING -> { // Already in the correct state. } case OK, DYING -> propagationQueue.update(newGroup); case ABORTING -> propagationQueue.insert(newGroup); default -> throw new IllegalStateException("Impossible state: The group (" + newGroup + ") in node (" + this - + ") is in an unexpected state (" + outTuple.state + ")."); + + ") is in an unexpected state (" + outTuple.getState() + ")."); } } @@ -200,14 +200,14 @@ public final void update(InTuple_ tuple) { private void updateGroup(InTuple_ tuple, Group oldGroup) { // No need to change parentCount because it is the same group var outTuple = accumulate(tuple, oldGroup); - switch (outTuple.state) { + switch (outTuple.getState()) { case CREATING, UPDATING -> { // Already in the correct state. } case OK -> propagationQueue.update(oldGroup); default -> throw new IllegalStateException("Impossible state: The group (%s) in node (%s) is in an unexpected state (%s)." - .formatted(oldGroup, this, outTuple.state)); + .formatted(oldGroup, this, outTuple.getState())); } } @@ -224,7 +224,7 @@ private void killTuple(Group group) { } } var outTuple = group.getTuple(); - switch (outTuple.state) { + switch (outTuple.getState()) { case CREATING -> { if (killGroup) { propagationQueue.retract(group, TupleState.ABORTING); @@ -243,7 +243,7 @@ private void killTuple(Group group) { } } default -> throw new IllegalStateException("Impossible state: The group (" + group + ") in node (" + this - + ") is in an unexpected state (" + outTuple.state + ")."); + + ") is in an unexpected state (" + outTuple.getState() + ")."); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNodeConstructor.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNodeConstructor.java index 0eba3c44aa..ebcc333a77 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNodeConstructor.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractGroupNodeConstructor.java @@ -2,9 +2,9 @@ import java.util.Objects; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; -abstract sealed class AbstractGroupNodeConstructor +abstract sealed class AbstractGroupNodeConstructor implements GroupNodeConstructor permits GroupNodeConstructorWithAccumulate, GroupNodeConstructorWithoutAccumulate { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIfExistsNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIfExistsNode.java index e47938bf02..ece32fcc29 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIfExistsNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIfExistsNode.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InTupleStorePositionTracker; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; 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.UniTuple; @@ -18,7 +18,7 @@ * @param * @param */ -public abstract class AbstractIfExistsNode +public abstract class AbstractIfExistsNode extends AbstractTwoInputNode> { protected final boolean shouldExist; @@ -138,7 +138,7 @@ protected void updateCounterFromLeft(ExistsCounter counter, UniTuple protected void updateCounterFromRight(ExistsCounter counter, UniTuple rightTuple, ElementAwareLinkedList> rightTrackerList) { var leftTuple = counter.leftTuple; - if (!leftTuple.state.isActive()) { + if (!leftTuple.getState().isActive()) { // Assume the following scenario: // - The operation is of two entities of the same type, both filtering out unassigned. // - One entity became unassigned, so the outTuple is getting retracted. @@ -188,7 +188,7 @@ public Propagator getPropagator() { } @NullMarked - protected static final class FilteringTracker { + protected static final class FilteringTracker { final ExistsCounter counter; private final ElementAwareLinkedList.Entry> leftTrackerEntry; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedIfExistsNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedIfExistsNode.java index ab2017b144..188b1fe683 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedIfExistsNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedIfExistsNode.java @@ -4,10 +4,10 @@ import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory; import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory.KeysExtractor; import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory.UniKeysExtractor; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.util.ElementAwareLinkedList; @@ -20,7 +20,7 @@ * @param * @param */ -public abstract class AbstractIndexedIfExistsNode +public abstract class AbstractIndexedIfExistsNode extends AbstractIfExistsNode implements LeftTupleLifecycle, RightTupleLifecycle> { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedJoinNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedJoinNode.java index 5ac58b458b..c7a937e596 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedJoinNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedJoinNode.java @@ -4,10 +4,10 @@ import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory; import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory.KeysExtractor; import ai.timefold.solver.core.impl.bavet.common.index.IndexerFactory.UniKeysExtractor; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InOutTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.util.ElementAwareLinkedList; @@ -19,7 +19,7 @@ * @param * @param */ -public abstract class AbstractIndexedJoinNode +public abstract class AbstractIndexedJoinNode extends AbstractJoinNode implements LeftTupleLifecycle, RightTupleLifecycle> { @@ -30,7 +30,7 @@ public abstract class AbstractIndexedJoinNode indexerLeft; private final Indexer> indexerRight; @@ -87,7 +87,7 @@ public final void updateLeft(LeftTuple_ leftTuple) { private void indexAndPropagateLeft(LeftTuple_ leftTuple, Object compositeKey) { leftTuple.setStore(inputStoreIndexLeftCompositeKey, compositeKey); leftTuple.setStore(inputStoreIndexLeftEntry, indexerLeft.put(compositeKey, leftTuple)); - if (!leftTuple.state.isActive()) { + if (!leftTuple.getState().isActive()) { // Assume the following scenario: // - The join is of two entities of the same type, both filtering out unassigned. // - One entity became unassigned, so the outTuple is getting retracted. diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractJoinNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractJoinNode.java index 452e039a92..a795d73d6e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractJoinNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractJoinNode.java @@ -2,9 +2,9 @@ import java.util.function.Consumer; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InOutTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.OutTupleStorePositionTracker; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; 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.UniTuple; @@ -19,7 +19,7 @@ * @param * @param */ -public abstract class AbstractJoinNode +public abstract class AbstractJoinNode extends AbstractTwoInputNode> { protected final int inputStoreIndexLeftOutTupleList; @@ -59,7 +59,7 @@ protected final void insertOutTuple(LeftTuple_ leftTuple, UniTuple right } protected final void insertOutTupleFilteredFromLeft(LeftTuple_ leftTuple, UniTuple rightTuple) { - if (!leftTuple.state.isActive()) { + if (!leftTuple.getState().isActive()) { // Assume the following scenario: // - The join is of two entities of the same type, both filtering out unassigned. // - One entity became unassigned, so the outTuple is getting retracted. @@ -93,7 +93,7 @@ protected final void innerUpdateLeft(LeftTuple_ leftTuple, Consumer rightTuple, Consumer rightTuple, ElementAwareLinkedList outList, ElementAwareLinkedList outTupleList, int outputStoreIndexOutEntry) { - if (!leftTuple.state.isActive()) { + if (!leftTuple.getState().isActive()) { // Assume the following scenario: // - The join is of two entities of the same type, both filtering out unassigned. // - One entity became unassigned, so the outTuple is getting retracted. @@ -186,7 +186,7 @@ private void processOutTupleUpdate(LeftTuple_ leftTuple, UniTuple rightT } } - private static Tuple_ findOutTuple(ElementAwareLinkedList sourceList, + private static Tuple_ findOutTuple(ElementAwareLinkedList sourceList, ElementAwareLinkedList referenceList, int outputStoreIndexOutEntry) { // Hack: the outTuple has no left/right input tuple reference, use the left/right outList reference instead. var item = sourceList.first(); @@ -223,10 +223,10 @@ private void removeEntry(OutTuple_ outTuple, int outputStoreIndex) { } private void propagateRetract(OutTuple_ outTuple) { - var state = outTuple.state; + var state = outTuple.getState(); if (!state.isActive()) { // Impossible because they shouldn't linger in the indexes. throw new IllegalStateException("Impossible state: The tuple (%s) in node (%s) is in an unexpected state (%s)." - .formatted(outTuple, this, outTuple.state)); + .formatted(outTuple, this, state)); } propagationQueue.retract(outTuple, state == TupleState.CREATING ? TupleState.ABORTING : TupleState.DYING); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractMapNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractMapNode.java index 16e0cbfde7..7047ef7a55 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractMapNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractMapNode.java @@ -1,10 +1,10 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; -public abstract class AbstractMapNode +public abstract class AbstractMapNode extends AbstractNode implements TupleLifecycle { @@ -24,7 +24,7 @@ public final void insert(InTuple_ tuple) { throw new IllegalStateException("Impossible state: the input for the tuple (" + tuple + ") was already added in the tupleStore."); } - OutTuple_ outTuple = map(tuple); + var outTuple = map(tuple); tuple.setStore(inputStoreIndex, outTuple); propagationQueue.insert(outTuple); } @@ -42,7 +42,7 @@ public final void update(InTuple_ tuple) { remap(tuple, outTuple); // Update must be propagated even if outTuple did not change, since if it is a planning // entity, the entity's planning variable might have changed. - TupleState previousState = outTuple.state; + var previousState = outTuple.getState(); if (previousState == TupleState.CREATING || previousState == TupleState.UPDATING) { // Already in the queue in the correct state. return; @@ -63,7 +63,7 @@ public final void retract(InTuple_ tuple) { // No fail fast if null because we don't track which tuples made it through the filter predicate(s) return; } - propagationQueue.retract(outTuple, outTuple.state == TupleState.CREATING ? TupleState.ABORTING : TupleState.DYING); + propagationQueue.retract(outTuple, outTuple.getState() == TupleState.CREATING ? TupleState.ABORTING : TupleState.DYING); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractNodeBuildHelper.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractNodeBuildHelper.java index 2f6c608b6f..5428f7c4c0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractNodeBuildHelper.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractNodeBuildHelper.java @@ -12,17 +12,17 @@ import java.util.function.UnaryOperator; import ai.timefold.solver.core.impl.bavet.NodeNetwork; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InOutTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; public abstract class AbstractNodeBuildHelper { private final Set activeStreamSet; private final Map nodeCreatorMap; - private final Map> tupleLifecycleMap; + private final Map> tupleLifecycleMap; private final Map storeIndexMap; private List reversedNodeList; @@ -52,30 +52,30 @@ public void addNode(AbstractNode node, Stream_ creator, Stream_ parent) { throw new IllegalStateException("Impossible state: The node (%s) has no parent (%s)." .formatted(node, parent)); } - putInsertUpdateRetract(parent, (TupleLifecycle) node); + putInsertUpdateRetract(parent, (TupleLifecycle) node); } } public void addNode(AbstractNode node, Stream_ creator, Stream_ leftParent, Stream_ rightParent) { reversedNodeList.add(node); nodeCreatorMap.put(node, creator); - putInsertUpdateRetract(leftParent, TupleLifecycle.ofLeft((LeftTupleLifecycle) node)); - putInsertUpdateRetract(rightParent, TupleLifecycle.ofRight((RightTupleLifecycle) node)); + putInsertUpdateRetract(leftParent, TupleLifecycle.ofLeft((LeftTupleLifecycle) node)); + putInsertUpdateRetract(rightParent, TupleLifecycle.ofRight((RightTupleLifecycle) node)); } - public void putInsertUpdateRetract(Stream_ stream, + public void putInsertUpdateRetract(Stream_ stream, TupleLifecycle tupleLifecycle) { tupleLifecycleMap.put(stream, tupleLifecycle); } - public void putInsertUpdateRetract(Stream_ stream, List childStreamList, + public void putInsertUpdateRetract(Stream_ stream, List childStreamList, UnaryOperator> tupleLifecycleFunction) { TupleLifecycle tupleLifecycle = getAggregatedTupleLifecycle(childStreamList); putInsertUpdateRetract(stream, tupleLifecycleFunction.apply(tupleLifecycle)); } @SuppressWarnings("unchecked") - public TupleLifecycle + public TupleLifecycle getAggregatedTupleLifecycle(List streamList) { var tupleLifecycles = streamList.stream() .filter(this::isStreamActive) @@ -91,8 +91,8 @@ public void putInsertUpdateRetract(Stream_ stream } @SuppressWarnings("unchecked") - private static TupleLifecycle getTupleLifecycle(Stream_ stream, - Map> tupleLifecycleMap) { + private static TupleLifecycle getTupleLifecycle(Stream_ stream, + Map> tupleLifecycleMap) { var tupleLifecycle = (TupleLifecycle) tupleLifecycleMap.get(stream); if (tupleLifecycle == null) { throw new IllegalStateException("Impossible state: the stream (%s) hasn't built a node yet." diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPrecomputeNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPrecomputeNode.java index 3d41e372ed..9fdfb356a9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPrecomputeNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPrecomputeNode.java @@ -2,7 +2,7 @@ import java.util.function.Supplier; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.score.stream.bavet.common.BavetPrecomputeBuildHelper; @@ -10,7 +10,7 @@ import org.jspecify.annotations.Nullable; @NullMarked -public abstract class AbstractPrecomputeNode extends AbstractNode +public abstract class AbstractPrecomputeNode extends AbstractNode implements BavetRootNode { private final RecordAndReplayPropagator recordAndReplayPropagator; private final Class[] sourceClasses; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPropagationMetadataCarrier.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPropagationMetadataCarrier.java index 32b0116738..35f1ec944c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPropagationMetadataCarrier.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractPropagationMetadataCarrier.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; /** @@ -8,7 +8,7 @@ * in order to be able to store metadata on them. * This metadata is necessary for efficient operation of the queue. */ -sealed abstract class AbstractPropagationMetadataCarrier +sealed abstract class AbstractPropagationMetadataCarrier permits Group, ExistsCounter { public int positionInDirtyList = -1; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java index ff9d2945ce..c5e4c35e54 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java @@ -1,11 +1,11 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; -public abstract class AbstractScorer implements TupleLifecycle { +public abstract class AbstractScorer implements TupleLifecycle { protected final WeightedScoreImpacter weightedScoreImpacter; private final int inputStoreIndex; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractTwoInputNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractTwoInputNode.java index 1b835cf285..5e3af55699 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractTwoInputNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractTwoInputNode.java @@ -1,10 +1,10 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; -public abstract class AbstractTwoInputNode +public abstract class AbstractTwoInputNode extends AbstractNode implements LeftTupleLifecycle, RightTupleLifecycle { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedIfExistsNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedIfExistsNode.java index fddbff1289..9564e30b4c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedIfExistsNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedIfExistsNode.java @@ -1,9 +1,9 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.util.ElementAwareLinkedList; @@ -15,7 +15,7 @@ * @param * @param */ -public abstract class AbstractUnindexedIfExistsNode +public abstract class AbstractUnindexedIfExistsNode extends AbstractIfExistsNode implements LeftTupleLifecycle, RightTupleLifecycle> { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedJoinNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedJoinNode.java index 235c29e5f5..e95860232b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedJoinNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractUnindexedJoinNode.java @@ -1,9 +1,9 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.InOutTupleStorePositionTracker; import ai.timefold.solver.core.impl.bavet.common.tuple.LeftTupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.RightTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.util.ElementAwareLinkedList; @@ -15,7 +15,7 @@ * @param * @param */ -public abstract class AbstractUnindexedJoinNode +public abstract class AbstractUnindexedJoinNode extends AbstractJoinNode implements LeftTupleLifecycle, RightTupleLifecycle> { @@ -40,7 +40,7 @@ public final void insertLeft(LeftTuple_ leftTuple) { } leftTuple.setStore(inputStoreIndexLeftEntry, leftTupleList.add(leftTuple)); leftTuple.setStore(inputStoreIndexLeftOutTupleList, new ElementAwareLinkedList()); - if (!leftTuple.state.isActive()) { + if (!leftTuple.getState().isActive()) { // Assume the following scenario: // - The join is of two entities of the same type, both filtering out unassigned. // - One entity became unassigned, so the outTuple is getting retracted. diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/DynamicPropagationQueue.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/DynamicPropagationQueue.java index ae48a7620a..3fd9d479e1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/DynamicPropagationQueue.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/DynamicPropagationQueue.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.function.Consumer; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; @@ -16,7 +16,7 @@ * @param * @param */ -final class DynamicPropagationQueue> +final class DynamicPropagationQueue> implements PropagationQueue { private static final int INITIAL_CAPACITY = 1000; // Selected arbitrarily. diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/ExistsCounter.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/ExistsCounter.java index a47bdd2910..0b69b862fb 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/ExistsCounter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/ExistsCounter.java @@ -1,9 +1,9 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; -public final class ExistsCounter +public final class ExistsCounter extends AbstractPropagationMetadataCarrier { final Tuple_ leftTuple; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/Group.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/Group.java index 7c2f02dafd..60fdc67b63 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/Group.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/Group.java @@ -1,22 +1,22 @@ package ai.timefold.solver.core.impl.bavet.common; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; -final class Group +final class Group extends AbstractPropagationMetadataCarrier { - public static Group + public static Group createWithoutAccumulate(Object groupKey, OutTuple_ outTuple) { return new Group<>(groupKey, null, outTuple); } - public static Group + public static Group createWithoutGroupKey(ResultContainer_ resultContainer, OutTuple_ outTuple) { return new Group<>(null, resultContainer, outTuple); } - public static Group create(Object groupKey, + public static Group create(Object groupKey, ResultContainer_ resultContainer, OutTuple_ outTuple) { return new Group<>(groupKey, resultContainer, outTuple); } @@ -47,12 +47,12 @@ public OutTuple_ getTuple() { @Override public TupleState getState() { - return outTuple.state; + return outTuple.getState(); } @Override public void setState(TupleState state) { - outTuple.state = state; + outTuple.setState(state); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructor.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructor.java index 0e4d148249..f7245a6140 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructor.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructor.java @@ -3,13 +3,13 @@ import java.util.List; import ai.timefold.solver.core.config.solver.EnvironmentMode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.util.Pair; import ai.timefold.solver.core.impl.util.Quadruple; import ai.timefold.solver.core.impl.util.Triple; -public sealed interface GroupNodeConstructor +public sealed interface GroupNodeConstructor permits AbstractGroupNodeConstructor { // Although Tuple_ is unused in GroupNodeConstructor, // it is used in its two implementations: GroupNodeConstructorWithAccumulate @@ -35,7 +35,7 @@ public sealed interface GroupNodeConstructor // GroupXMappingYCollector...Node signature, allowing a method reference to be used. // To reduce the number of interfaces, we use Collector..._ and Key..._ generics // (instead of the classes UniConstraintCollector/Function, BiConstraintCollector/BiFunction, ...). - static GroupNodeConstructor + static GroupNodeConstructor zeroKeysGroupBy(CollectorA_ collector, GroupBy0Mapping1CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>(collector, (groupStoreIndex, undoStoreIndex, nextNodesTupleLifecycle, outputStoreSize, environmentMode) -> builder.build( @@ -43,7 +43,7 @@ public sealed interface GroupNodeConstructor environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor zeroKeysGroupBy(CollectorA_ collectorA, CollectorB_ collectorB, GroupBy0Mapping2CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>(new Pair<>(collectorA, collectorB), @@ -52,7 +52,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor zeroKeysGroupBy(CollectorA_ collectorA, CollectorB_ collectorB, CollectorC_ collectorC, GroupBy0Mapping3CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -62,7 +62,7 @@ public sealed interface GroupNodeConstructor nextNodesTupleLifecycle, outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor zeroKeysGroupBy(CollectorA_ collectorA, CollectorB_ collectorB, CollectorC_ collectorC, CollectorD_ collectorD, GroupBy0Mapping4CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -73,14 +73,14 @@ public sealed interface GroupNodeConstructor nextNodesTupleLifecycle, outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor oneKeyGroupBy(KeyA_ keyMapping, GroupBy1Mapping0CollectorNodeBuilder builder) { return new GroupNodeConstructorWithoutAccumulate<>(keyMapping, (groupStoreIndex, nextNodesTupleLifecycle, outputStoreSize, environmentMode) -> builder.build(keyMapping, groupStoreIndex, nextNodesTupleLifecycle, outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor oneKeyGroupBy(KeyA_ keyMappingA, CollectorB_ collectorB, GroupBy1Mapping1CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>(new Pair<>(keyMappingA, collectorB), @@ -89,7 +89,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor oneKeyGroupBy(KeyA_ keyMappingA, CollectorB_ collectorB, CollectorC_ collectorC, GroupBy1Mapping2CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -100,7 +100,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor oneKeyGroupBy(KeyA_ keyMappingA, CollectorB_ collectorB, CollectorC_ collectorC, CollectorD_ collectorD, GroupBy1Mapping3CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -111,7 +111,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor twoKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, GroupBy2Mapping0CollectorNodeBuilder builder) { return new GroupNodeConstructorWithoutAccumulate<>(new Pair<>(keyMappingA, keyMappingB), @@ -120,7 +120,7 @@ public sealed interface GroupNodeConstructor environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor twoKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, CollectorC_ collectorC, GroupBy2Mapping1CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -131,7 +131,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor twoKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, CollectorC_ collectorC, CollectorD_ collectorD, GroupBy2Mapping2CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -142,7 +142,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor threeKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, GroupBy3Mapping0CollectorNodeBuilder builder) { return new GroupNodeConstructorWithoutAccumulate<>( @@ -152,7 +152,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor threeKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, CollectorD_ collectorD, GroupBy3Mapping1CollectorNodeBuilder builder) { return new GroupNodeConstructorWithAccumulate<>( @@ -163,7 +163,7 @@ public sealed interface GroupNodeConstructor outputStoreSize, environmentMode)); } - static GroupNodeConstructor + static GroupNodeConstructor fourKeysGroupBy(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, KeyD_ keyMappingD, GroupBy4Mapping0CollectorNodeBuilder builder) { return new GroupNodeConstructorWithoutAccumulate<>( @@ -174,7 +174,7 @@ public sealed interface GroupNodeConstructor } @FunctionalInterface - interface NodeConstructorWithAccumulate { + interface NodeConstructorWithAccumulate { AbstractNode apply(int groupStoreIndex, int undoStoreIndex, TupleLifecycle nextNodesTupleLifecycle, int outputStoreSize, EnvironmentMode environmentMode); @@ -182,7 +182,7 @@ AbstractNode apply(int groupStoreIndex, int undoStoreIndex, TupleLifecycle { + interface NodeConstructorWithoutAccumulate { AbstractNode apply(int groupStoreIndex, TupleLifecycle nextNodesTupleLifecycle, int outputStoreSize, EnvironmentMode environmentMode); @@ -190,14 +190,14 @@ AbstractNode apply(int groupStoreIndex, TupleLifecycle nextNodesTupleLif } @FunctionalInterface - interface GroupBy0Mapping1CollectorNodeBuilder { + interface GroupBy0Mapping1CollectorNodeBuilder { AbstractNode build(int groupStoreIndex, int undoStoreIndex, CollectorA_ collector, TupleLifecycle nextNodesTupleLifecycle, int outputStoreSize, EnvironmentMode environmentMode); } @FunctionalInterface - interface GroupBy0Mapping2CollectorNodeBuilder { + interface GroupBy0Mapping2CollectorNodeBuilder { AbstractNode build(int groupStoreIndex, int undoStoreIndex, CollectorA_ collectorA, CollectorB_ collectorB, @@ -205,7 +205,7 @@ AbstractNode build(int groupStoreIndex, int undoStoreIndex, } @FunctionalInterface - interface GroupBy0Mapping3CollectorNodeBuilder { + interface GroupBy0Mapping3CollectorNodeBuilder { AbstractNode build(int groupStoreIndex, int undoStoreIndex, CollectorA_ collectorA, CollectorB_ collectorB, @@ -214,7 +214,7 @@ AbstractNode build(int groupStoreIndex, int undoStoreIndex, } @FunctionalInterface - interface GroupBy0Mapping4CollectorNodeBuilder { + interface GroupBy0Mapping4CollectorNodeBuilder { AbstractNode build(int groupStoreIndex, int undoStoreIndex, CollectorA_ collectorA, CollectorB_ collectorB, @@ -224,21 +224,21 @@ AbstractNode build(int groupStoreIndex, int undoStoreIndex, } @FunctionalInterface - interface GroupBy1Mapping0CollectorNodeBuilder { + interface GroupBy1Mapping0CollectorNodeBuilder { AbstractNode build(KeyA_ keyMapping, int groupStoreIndex, TupleLifecycle nextNodesTupleLifecycle, int outputStoreSize, EnvironmentMode environmentMode); } @FunctionalInterface - interface GroupBy2Mapping0CollectorNodeBuilder { + interface GroupBy2Mapping0CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, int groupStoreIndex, TupleLifecycle nextNodesTupleLifecycle, int outputStoreSize, EnvironmentMode environmentMode); } @FunctionalInterface - interface GroupBy3Mapping0CollectorNodeBuilder { + interface GroupBy3Mapping0CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, @@ -247,7 +247,7 @@ AbstractNode build(KeyA_ keyMappingA, } @FunctionalInterface - interface GroupBy4Mapping0CollectorNodeBuilder { + interface GroupBy4Mapping0CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, @@ -257,7 +257,7 @@ AbstractNode build(KeyA_ keyMappingA, } @FunctionalInterface - interface GroupBy1Mapping1CollectorNodeBuilder { + interface GroupBy1Mapping1CollectorNodeBuilder { AbstractNode build(KeyA_ keyMapping, int groupStoreIndex, int undoStoreIndex, CollectorB_ collector, @@ -265,7 +265,7 @@ AbstractNode build(KeyA_ keyMapping, } @FunctionalInterface - interface GroupBy1Mapping2CollectorNodeBuilder { + interface GroupBy1Mapping2CollectorNodeBuilder { AbstractNode build(KeyA_ keyMapping, int groupStoreIndex, int undoStoreIndex, CollectorB_ collectorA, @@ -274,7 +274,7 @@ AbstractNode build(KeyA_ keyMapping, } @FunctionalInterface - interface GroupBy1Mapping3CollectorNodeBuilder { + interface GroupBy1Mapping3CollectorNodeBuilder { AbstractNode build(KeyA_ keyMapping, int groupStoreIndex, int undoStoreIndex, CollectorB_ collectorA, @@ -284,7 +284,7 @@ AbstractNode build(KeyA_ keyMapping, } @FunctionalInterface - interface GroupBy2Mapping1CollectorNodeBuilder { + interface GroupBy2Mapping1CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, int groupStoreIndex, int undoStoreIndex, CollectorC_ collectorC, @@ -292,7 +292,7 @@ AbstractNode build(KeyA_ keyMappingA, } @FunctionalInterface - interface GroupBy2Mapping2CollectorNodeBuilder { + interface GroupBy2Mapping2CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, int groupStoreIndex, int undoStoreIndex, @@ -302,7 +302,7 @@ AbstractNode build(KeyA_ keyMappingA, } @FunctionalInterface - interface GroupBy3Mapping1CollectorNodeBuilder { + interface GroupBy3Mapping1CollectorNodeBuilder { AbstractNode build(KeyA_ keyMappingA, KeyB_ keyMappingB, KeyC_ keyMappingC, diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithAccumulate.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithAccumulate.java index 68c5fdfd47..1924b26154 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithAccumulate.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithAccumulate.java @@ -3,10 +3,10 @@ import java.util.List; import ai.timefold.solver.core.config.solver.EnvironmentMode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -final class GroupNodeConstructorWithAccumulate extends AbstractGroupNodeConstructor { +final class GroupNodeConstructorWithAccumulate extends AbstractGroupNodeConstructor { private final NodeConstructorWithAccumulate nodeConstructorFunction; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithoutAccumulate.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithoutAccumulate.java index 672c629e0a..9eac2b753c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithoutAccumulate.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/GroupNodeConstructorWithoutAccumulate.java @@ -3,10 +3,10 @@ import java.util.List; import ai.timefold.solver.core.config.solver.EnvironmentMode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -final class GroupNodeConstructorWithoutAccumulate extends AbstractGroupNodeConstructor { +final class GroupNodeConstructorWithoutAccumulate extends AbstractGroupNodeConstructor { private final NodeConstructorWithoutAccumulate nodeConstructorFunction; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/RecordAndReplayPropagator.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/RecordAndReplayPropagator.java index c62334447d..7b38d8b9f5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/RecordAndReplayPropagator.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/RecordAndReplayPropagator.java @@ -11,8 +11,8 @@ import java.util.function.UnaryOperator; import ai.timefold.solver.core.impl.bavet.NodeNetwork; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.RecordingTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; 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.score.stream.bavet.common.BavetPrecomputeBuildHelper; @@ -28,7 +28,7 @@ * @param */ @NullMarked -public final class RecordAndReplayPropagator implements Propagator { +public final class RecordAndReplayPropagator implements Propagator { private final Set retractQueue; private final Set insertQueue; @@ -168,14 +168,14 @@ public void propagateInserts() { } private void insertIfAbsent(Tuple_ tuple) { - var state = tuple.state; + var state = tuple.getState(); if (state != TupleState.CREATING) { propagationQueue.insert(tuple); } } private void retractIfPresent(Tuple_ tuple) { - var state = tuple.state; + var state = tuple.getState(); if (state.isDirty()) { if (state == TupleState.DYING || state == TupleState.ABORTING) { // We already retracted this tuple from another list, so we diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java index f66bea6dd2..ace5d38cb2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java @@ -4,7 +4,7 @@ import java.util.Deque; import java.util.function.Consumer; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleState; @@ -16,7 +16,7 @@ * * @param */ -public final class StaticPropagationQueue +public final class StaticPropagationQueue implements PropagationQueue { private final Deque retractQueue; @@ -38,26 +38,26 @@ public StaticPropagationQueue(TupleLifecycle nextNodesTupleLifecycle) { @Override public void insert(Tuple_ carrier) { - if (carrier.state == TupleState.CREATING) { + if (carrier.getState() == TupleState.CREATING) { throw new IllegalStateException("Impossible state: The tuple (%s) is already in the insert queue." .formatted(carrier)); } - carrier.state = TupleState.CREATING; + carrier.setState(TupleState.CREATING); insertQueue.add(carrier); } @Override public void update(Tuple_ carrier) { - if (carrier.state == TupleState.UPDATING) { // Skip double updates. + if (carrier.getState() == TupleState.UPDATING) { // Skip double updates. return; } - carrier.state = TupleState.UPDATING; + carrier.setState(TupleState.UPDATING); updateQueue.add(carrier); } @Override public void retract(Tuple_ carrier, TupleState state) { - var carrierState = carrier.state; + var carrierState = carrier.getState(); if (carrierState == state) { // Skip double retracts. return; } @@ -68,7 +68,7 @@ public void retract(Tuple_ carrier, TupleState state) { throw new IllegalStateException("Impossible state: The tuple (%s) is already in the retract queue." .formatted(carrier)); } - carrier.state = state; + carrier.setState(state); retractQueue.add(carrier); } @@ -76,13 +76,13 @@ public void retract(Tuple_ carrier, TupleState state) { public void propagateRetracts() { while (!retractQueue.isEmpty()) { var tuple = retractQueue.poll(); - switch (tuple.state) { + switch (tuple.getState()) { case DYING -> { // Change state before propagation, so that the next node can't make decisions on the original state. - tuple.state = TupleState.DEAD; + tuple.setState(TupleState.DEAD); nextNodesTupleLifecycle.retract(tuple); } - case ABORTING -> tuple.state = TupleState.DEAD; + case ABORTING -> tuple.setState(TupleState.DEAD); } } } @@ -96,7 +96,7 @@ private static void processAndClear(Deque Consumer tupleLifecycle) { while (!dirtyQueue.isEmpty()) { var tuple = dirtyQueue.poll(); - if (tuple.state == TupleState.DEAD) { + if (tuple.getState() == TupleState.DEAD) { // DEAD signifies the tuple was both in insert/update and retract queues. // This happens when a tuple was inserted/updated and subsequently retracted, all before propagation. // We can safely ignore the later insert/update, @@ -105,7 +105,7 @@ private static void processAndClear(Deque continue; } // Change state before propagation, so that the next node can't make decisions on the original state. - tuple.state = TupleState.OK; + tuple.setState(TupleState.OK); tupleLifecycle.accept(tuple); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/TupleRecorder.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/TupleRecorder.java index be7c5694fe..c2fab90d52 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/TupleRecorder.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/TupleRecorder.java @@ -4,12 +4,12 @@ import java.util.List; import java.util.function.UnaryOperator; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import org.jspecify.annotations.NullMarked; @NullMarked -public record TupleRecorder(List recordedTupleList, +public record TupleRecorder(List recordedTupleList, UnaryOperator mapper, IdentityHashMap inputTupleToOutputTuple) { public void recordTuple(Tuple_ tuple) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/IndexerFactory.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/IndexerFactory.java index b30cc7960a..662fce25c5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/IndexerFactory.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/IndexerFactory.java @@ -14,10 +14,10 @@ import ai.timefold.solver.core.impl.bavet.bi.joiner.DefaultBiJoiner; import ai.timefold.solver.core.impl.bavet.common.joiner.AbstractJoiner; import ai.timefold.solver.core.impl.bavet.common.joiner.JoinerType; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.bavet.penta.joiner.DefaultPentaJoiner; import ai.timefold.solver.core.impl.bavet.quad.joiner.DefaultQuadJoiner; @@ -39,7 +39,7 @@ *

* Indexers have an id, which is the position of the indexer in the chain. * Top-most indexer has id 0, and the id increases as we go down the hierarchy. - * Each {@link AbstractTuple tuple} is assigned an + * Each {@link Tuple tuple} is assigned an * {@link CompositeKey} instance, * which determines its location in the index. * {@link CompositeKey} instances are built from @@ -186,7 +186,7 @@ private static Function toCompositeKeyFunction(Function UniKeysExtractor toKeysExtractor(Function keyFunction) { return tuple -> { - var a = tuple.factA; + var a = tuple.getA(); return CompositeKey.of(keyFunction.apply(a)); }; } @@ -199,12 +199,12 @@ private static UniKeysExtractor toKeysExtractor(List> var keyFunction1 = keyFunctionList.get(0); var keyFunction2 = keyFunctionList.get(1); yield tuple -> { - var a = tuple.factA; + var a = tuple.getA(); return CompositeKey.of(keyFunction1.apply(a), keyFunction2.apply(a)); }; } default -> tuple -> { - var a = tuple.factA; + var a = tuple.getA(); var arr = new Object[keyFunctionCount]; for (var i = 0; i < keyFunctionCount; i++) { arr[i] = keyFunctionList.get(i).apply(a); @@ -276,14 +276,14 @@ public BiKeysExtractor buildBiLeftKeysExtractor() { var keyFunction1 = keyFunctionList.get(0); var keyFunction2 = keyFunctionList.get(1); yield tuple -> { - var a = tuple.factA; - var b = tuple.factB; + var a = tuple.getA(); + var b = tuple.getB(); return CompositeKey.of(keyFunction1.apply(a, b), keyFunction2.apply(a, b)); }; } default -> tuple -> { - var a = tuple.factA; - var b = tuple.factB; + var a = tuple.getA(); + var b = tuple.getB(); var arr = new Object[keyFunctionCount]; for (var i = 0; i < keyFunctionCount; i++) { arr[i] = keyFunctionList.get(i).apply(a, b); @@ -295,8 +295,8 @@ public BiKeysExtractor buildBiLeftKeysExtractor() { private static BiKeysExtractor toKeysExtractor(BiFunction keyFunction) { return tuple -> { - var a = tuple.factA; - var b = tuple.factB; + var a = tuple.getA(); + var b = tuple.getB(); return CompositeKey.of(keyFunction.apply(a, b)); }; } @@ -364,16 +364,16 @@ public TriKeysExtractor buildTriLeftKeysExtractor() { var keyFunction1 = keyFunctionList.get(0); var keyFunction2 = keyFunctionList.get(1); yield tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); return CompositeKey.of(keyFunction1.apply(a, b, c), keyFunction2.apply(a, b, c)); }; } default -> tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); var arr = new Object[keyFunctionCount]; for (var i = 0; i < keyFunctionCount; i++) { arr[i] = keyFunctionList.get(i).apply(a, b, c); @@ -385,9 +385,9 @@ public TriKeysExtractor buildTriLeftKeysExtractor() { private static TriKeysExtractor toKeysExtractor(TriFunction keyFunction) { return tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); return CompositeKey.of(keyFunction.apply(a, b, c)); }; } @@ -455,18 +455,18 @@ public QuadKeysExtractor buildQuadLeftKeysExtractor() { var keyFunction1 = keyFunctionList.get(0); var keyFunction2 = keyFunctionList.get(1); yield tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; - var d = tuple.factD; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); return CompositeKey.of(keyFunction1.apply(a, b, c, d), keyFunction2.apply(a, b, c, d)); }; } default -> tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; - var d = tuple.factD; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); var arr = new Object[keyFunctionCount]; for (var i = 0; i < keyFunctionCount; i++) { arr[i] = keyFunctionList.get(i).apply(a, b, c, d); @@ -478,10 +478,10 @@ public QuadKeysExtractor buildQuadLeftKeysExtractor() { private static QuadKeysExtractor toKeysExtractor(QuadFunction keyFunction) { return tuple -> { - var a = tuple.factA; - var b = tuple.factB; - var c = tuple.factC; - var d = tuple.factD; + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); return CompositeKey.of(keyFunction.apply(a, b, c, d)); }; } @@ -545,7 +545,7 @@ public Indexer buildIndexer(boolean isLeftBridge) { * @param */ @FunctionalInterface - public interface KeysExtractor extends Function { + public interface KeysExtractor extends Function { } @FunctionalInterface diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AbstractTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AbstractTuple.java deleted file mode 100644 index 2342725fb5..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AbstractTuple.java +++ /dev/null @@ -1,45 +0,0 @@ -package ai.timefold.solver.core.impl.bavet.common.tuple; - -import java.util.function.Function; - -import ai.timefold.solver.core.api.score.stream.uni.UniConstraintStream; - -/** - * A tuple is an out tuple in exactly one node and an in tuple in one or more nodes. - * - *

- * A tuple must not implement equals()/hashCode() to fact equality, - * because some stream operations ({@link UniConstraintStream#map(Function)}, ...) - * might create 2 different tuple instances to contain the same facts - * and because a tuple's origin may replace a tuple's fact. - * - *

- * A tuple is modifiable. - * However, only the origin node of a tuple (the node where the tuple is the out tuple) may modify it. - */ -public abstract sealed class AbstractTuple permits UniTuple, BiTuple, TriTuple, QuadTuple { - - private static final Object[] EMPTY_STORE = new Object[0]; - - private final Object[] store; - public TupleState state = TupleState.DEAD; // It's the node's job to mark a new tuple as CREATING. - - protected AbstractTuple(int storeSize) { - this.store = storeSize == 0 ? EMPTY_STORE : new Object[storeSize]; - } - - public final Value_ getStore(int index) { - return (Value_) store[index]; - } - - public final void setStore(int index, Object value) { - store[index] = value; - } - - public final Value_ removeStore(int index) { - Value_ value = getStore(index); - setStore(index, null); - return value; - } - -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AggregatedTupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AggregatedTupleLifecycle.java index 061aedf908..80d24853a6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AggregatedTupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/AggregatedTupleLifecycle.java @@ -3,7 +3,7 @@ import java.util.Arrays; import java.util.Objects; -record AggregatedTupleLifecycle(TupleLifecycle... lifecycles) +record AggregatedTupleLifecycle(TupleLifecycle... lifecycles) implements TupleLifecycle { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/BiTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/BiTuple.java index 80fe6fd712..93bfff25bc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/BiTuple.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/BiTuple.java @@ -1,20 +1,35 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public final class BiTuple extends AbstractTuple { +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; - // Only a tuple's origin node may modify a fact. - public A factA; - public B factB; +@NullMarked +public sealed interface BiTuple extends Tuple permits UniversalTuple { - public BiTuple(A factA, B factB, int storeSize) { - super(storeSize); - this.factA = factA; - this.factB = factB; + static BiTuple of(int storeSize) { + return new UniversalTuple(storeSize, 2); } - @Override - public String toString() { - return "{" + factA + ", " + factB + "}"; + static BiTuple of(@Nullable A a, int storeSize) { + var tuple = BiTuple. of(storeSize); + tuple.setA(a); + return tuple; } + static BiTuple of(@Nullable A a, @Nullable B b, int storeSize) { + var tuple = BiTuple. of(a, storeSize); + tuple.setB(b); + return tuple; + } + + @Nullable + A getA(); + + void setA(@Nullable A a); + + @Nullable + B getB(); + + void setB(@Nullable B b); + } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/ConditionalTupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/ConditionalTupleLifecycle.java index a4dab56b71..87c79f6f14 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/ConditionalTupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/ConditionalTupleLifecycle.java @@ -3,7 +3,7 @@ import java.util.Objects; import java.util.function.Predicate; -public record ConditionalTupleLifecycle(TupleLifecycle downstreamLifecycle, +public record ConditionalTupleLifecycle(TupleLifecycle downstreamLifecycle, TuplePredicate predicate) implements TupleLifecycle { @@ -40,7 +40,7 @@ public String toString() { } @FunctionalInterface - interface TuplePredicate extends Predicate { + interface TuplePredicate extends Predicate { } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycle.java index c6b6d9c9d0..33ca38918b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycle.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public interface LeftTupleLifecycle { +public interface LeftTupleLifecycle { void insertLeft(Tuple_ tuple); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycleImpl.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycleImpl.java index c8f98444df..efe6db29fe 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycleImpl.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/LeftTupleLifecycleImpl.java @@ -2,7 +2,7 @@ import java.util.Objects; -record LeftTupleLifecycleImpl(LeftTupleLifecycle leftTupleLifecycle) +record LeftTupleLifecycleImpl(LeftTupleLifecycle leftTupleLifecycle) implements TupleLifecycle { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/QuadTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/QuadTuple.java index 7176d628b2..e44d2065a9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/QuadTuple.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/QuadTuple.java @@ -1,24 +1,57 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public final class QuadTuple extends AbstractTuple { - - // Only a tuple's origin node may modify a fact. - public A factA; - public B factB; - public C factC; - public D factD; - - public QuadTuple(A factA, B factB, C factC, D factD, int storeSize) { - super(storeSize); - this.factA = factA; - this.factB = factB; - this.factC = factC; - this.factD = factD; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public sealed interface QuadTuple extends Tuple permits UniversalTuple { + + static QuadTuple of(int storeSize) { + return new UniversalTuple<>(storeSize, 4); + } + + static QuadTuple of(@Nullable A a, int storeSize) { + var tuple = QuadTuple. of(storeSize); + tuple.setA(a); + return tuple; + } + + static QuadTuple of(@Nullable A a, @Nullable B b, int storeSize) { + var tuple = QuadTuple. of(a, storeSize); + tuple.setB(b); + return tuple; + } + + static QuadTuple of(@Nullable A a, @Nullable B b, @Nullable C c, int storeSize) { + var tuple = QuadTuple. of(a, b, storeSize); + tuple.setC(c); + return tuple; } - @Override - public String toString() { - return "{" + factA + ", " + factB + ", " + factC + ", " + factD + "}"; + static QuadTuple of(@Nullable A a, @Nullable B b, @Nullable C c, @Nullable D d, int storeSize) { + var tuple = QuadTuple. of(a, b, c, storeSize); + tuple.setD(d); + return tuple; } + @Nullable + A getA(); + + void setA(@Nullable A a); + + @Nullable + B getB(); + + void setB(@Nullable B b); + + @Nullable + C getC(); + + void setC(@Nullable C c); + + @Nullable + D getD(); + + void setD(@Nullable D d); + } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RecordingTupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RecordingTupleLifecycle.java index 6f19dcb3aa..23c9b34e65 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RecordingTupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RecordingTupleLifecycle.java @@ -6,7 +6,7 @@ import org.jspecify.annotations.Nullable; @NullMarked -public class RecordingTupleLifecycle implements TupleLifecycle, AutoCloseable { +public class RecordingTupleLifecycle implements TupleLifecycle, AutoCloseable { @Nullable TupleRecorder tupleRecorder; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycle.java index 3b4020918f..3467a9ace7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycle.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public interface RightTupleLifecycle { +public interface RightTupleLifecycle { void insertRight(Tuple_ tuple); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycleImpl.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycleImpl.java index 9aea31e6b9..b207db9218 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycleImpl.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/RightTupleLifecycleImpl.java @@ -2,7 +2,7 @@ import java.util.Objects; -record RightTupleLifecycleImpl(RightTupleLifecycle rightTupleLifecycle) +record RightTupleLifecycleImpl(RightTupleLifecycle rightTupleLifecycle) implements TupleLifecycle { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TriTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TriTuple.java index b279d59c1b..ffe4118717 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TriTuple.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TriTuple.java @@ -1,22 +1,46 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public final class TriTuple extends AbstractTuple { - - // Only a tuple's origin node may modify a fact. - public A factA; - public B factB; - public C factC; - - public TriTuple(A factA, B factB, C factC, int storeSize) { - super(storeSize); - this.factA = factA; - this.factB = factB; - this.factC = factC; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public sealed interface TriTuple extends Tuple permits UniversalTuple { + + static TriTuple of(int storeSize) { + return new UniversalTuple(storeSize, 3); + } + + static TriTuple of(@Nullable A a, int storeSize) { + var tuple = TriTuple. of(storeSize); + tuple.setA(a); + return tuple; + } + + static TriTuple of(@Nullable A a, @Nullable B b, int storeSize) { + var tuple = TriTuple. of(a, storeSize); + tuple.setB(b); + return tuple; } - @Override - public String toString() { - return "{" + factA + ", " + factB + ", " + factC + "}"; + static TriTuple of(@Nullable A a, @Nullable B b, @Nullable C c, int storeSize) { + var tuple = TriTuple. of(a, b, storeSize); + tuple.setC(c); + return tuple; } + @Nullable + A getA(); + + void setA(@Nullable A a); + + @Nullable + B getB(); + + void setB(@Nullable B b); + + @Nullable + C getC(); + + void setC(@Nullable C c); + } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/Tuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/Tuple.java new file mode 100644 index 0000000000..c4b03d67f3 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/Tuple.java @@ -0,0 +1,36 @@ +package ai.timefold.solver.core.impl.bavet.common.tuple; + +import java.util.function.Function; + +import ai.timefold.solver.core.api.score.stream.uni.UniConstraintStream; + +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * A tuple is an out tuple in exactly one node and an in tuple in one or more nodes. + * + *

+ * A tuple must not implement equals()/hashCode() to fact equality, + * because some stream operations ({@link UniConstraintStream#map(Function)}, ...) + * might create 2 different tuple instances to contain the same facts + * and because a tuple's origin may replace a tuple's fact. + * + *

+ * A tuple is modifiable. + * However, only the origin node of a tuple (the node where the tuple is the out tuple) may modify it. + */ +@NullMarked +public sealed interface Tuple permits BiTuple, QuadTuple, TriTuple, UniTuple { + + TupleState getState(); + + void setState(TupleState state); + + @Nullable Value_ getStore(int index); + + void setStore(int index, @Nullable Object value); + + @Nullable Value_ removeStore(int index); + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TupleLifecycle.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TupleLifecycle.java index 675e6f7164..6d01cd2f09 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TupleLifecycle.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/TupleLifecycle.java @@ -8,19 +8,19 @@ import ai.timefold.solver.core.api.function.QuadPredicate; import ai.timefold.solver.core.api.function.TriPredicate; -public interface TupleLifecycle { +public interface TupleLifecycle { - static TupleLifecycle ofLeft(LeftTupleLifecycle leftTupleLifecycle) { + static TupleLifecycle ofLeft(LeftTupleLifecycle leftTupleLifecycle) { return new LeftTupleLifecycleImpl<>(leftTupleLifecycle); } - static TupleLifecycle ofRight(RightTupleLifecycle rightTupleLifecycle) { + static TupleLifecycle ofRight(RightTupleLifecycle rightTupleLifecycle) { return new RightTupleLifecycleImpl<>(rightTupleLifecycle); } @SuppressWarnings({ "rawtypes", "unchecked" }) @SafeVarargs - static TupleLifecycle aggregate(TupleLifecycle... tupleLifecycles) { + static TupleLifecycle aggregate(TupleLifecycle... tupleLifecycles) { var distinctTupleLifecycles = Arrays.stream(Objects.requireNonNull(tupleLifecycles)) .distinct() .toArray(TupleLifecycle[]::new); @@ -32,26 +32,27 @@ static TupleLifecycle aggregate(TupleLife } static TupleLifecycle> conditionally(TupleLifecycle> tupleLifecycle, Predicate predicate) { - return new ConditionalTupleLifecycle<>(tupleLifecycle, tuple -> predicate.test(tuple.factA)); + return new ConditionalTupleLifecycle<>(tupleLifecycle, tuple -> predicate.test(tuple.getA())); } static TupleLifecycle> conditionally(TupleLifecycle> tupleLifecycle, BiPredicate predicate) { - return new ConditionalTupleLifecycle<>(tupleLifecycle, tuple -> predicate.test(tuple.factA, tuple.factB)); + return new ConditionalTupleLifecycle<>(tupleLifecycle, tuple -> predicate.test(tuple.getA(), tuple.getB())); } static TupleLifecycle> conditionally(TupleLifecycle> tupleLifecycle, TriPredicate predicate) { - return new ConditionalTupleLifecycle<>(tupleLifecycle, tuple -> predicate.test(tuple.factA, tuple.factB, tuple.factC)); + return new ConditionalTupleLifecycle<>(tupleLifecycle, + tuple -> predicate.test(tuple.getA(), tuple.getB(), tuple.getC())); } static TupleLifecycle> conditionally(TupleLifecycle> tupleLifecycle, QuadPredicate predicate) { return new ConditionalTupleLifecycle<>(tupleLifecycle, - tuple -> predicate.test(tuple.factA, tuple.factB, tuple.factC, tuple.factD)); + tuple -> predicate.test(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD())); } - static TupleLifecycle recording() { + static TupleLifecycle recording() { return new RecordingTupleLifecycle<>(); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniTuple.java index 7cd1e40bc5..20f23f8b70 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniTuple.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniTuple.java @@ -1,18 +1,24 @@ package ai.timefold.solver.core.impl.bavet.common.tuple; -public final class UniTuple extends AbstractTuple { +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; - // Only a tuple's origin node may modify a fact. - public A factA; +@NullMarked +public sealed interface UniTuple extends Tuple permits UniversalTuple { - public UniTuple(A factA, int storeSize) { - super(storeSize); - this.factA = factA; + static UniTuple of(int storeSize) { + return new UniversalTuple(storeSize, 1); } - @Override - public String toString() { - return "{" + factA + "}"; + static UniTuple of(@Nullable A a, int storeSize) { + var tuple = UniTuple. of(storeSize); + tuple.setA(a); + return tuple; } + @Nullable + A getA(); + + void setA(@Nullable A a); + } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniversalTuple.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniversalTuple.java new file mode 100644 index 0000000000..5efa7381d2 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/tuple/UniversalTuple.java @@ -0,0 +1,109 @@ +package ai.timefold.solver.core.impl.bavet.common.tuple; + +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * This is a monomorphic implementation for all tuple cardinalities, helping with performance. + * Accessed through interfaces (such as {@link UniTuple}) to hide getters/setters from higher cardinalities. + */ +@NullMarked +final class UniversalTuple + implements UniTuple, BiTuple, TriTuple, QuadTuple { + + private static final Object[] EMPTY_STORE = new Object[0]; + + private final int cardinality; + private final @Nullable Object[] store; + + private @Nullable A a; + private @Nullable B b; + private @Nullable C c; + private @Nullable D d; + private TupleState state = TupleState.DEAD; // It's the node's job to mark a new tuple as CREATING. + + UniversalTuple(int storeSize, int cardinality) { + this.cardinality = cardinality; + this.store = storeSize > 0 ? new Object[storeSize] : EMPTY_STORE; + } + + @Override + public void setA(@Nullable A a) { + this.a = a; + } + + @Override + public @Nullable A getA() { + return a; + } + + @Override + public void setB(@Nullable B b) { + this.b = b; + } + + @Override + public @Nullable B getB() { + return b; + } + + @Override + public void setC(@Nullable C c) { + this.c = c; + } + + @Override + public @Nullable C getC() { + return c; + } + + @Override + public void setD(@Nullable D d) { + this.d = d; + } + + @Override + public @Nullable D getD() { + return d; + } + + @Override + public TupleState getState() { + return state; + } + + @Override + public void setState(TupleState state) { + this.state = state; + } + + @SuppressWarnings("unchecked") + @Override + public @Nullable Value_ getStore(int index) { + return (Value_) store[index]; + } + + @Override + public void setStore(int index, @Nullable Object value) { + store[index] = value; + } + + @Override + public @Nullable Value_ removeStore(int index) { + Value_ value = getStore(index); + setStore(index, null); + return value; + } + + @Override + public String toString() { + return switch (cardinality) { + case 1 -> "{%s}".formatted(getA()); + case 2 -> "{%s, %s}".formatted(getA(), getB()); + case 3 -> "{%s, %s, %s}".formatted(getA(), getB(), getC()); + case 4 -> "{%s, %s, %s, %s}".formatted(getA(), getB(), getC(), getD()); + default -> throw new IllegalStateException("Impossible cardinality: %d.".formatted(cardinality)); + }; + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/AbstractGroupQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/AbstractGroupQuadNode.java index 2f800928a3..0ab3fb5c0c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/AbstractGroupQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/AbstractGroupQuadNode.java @@ -6,11 +6,11 @@ import ai.timefold.solver.core.api.score.stream.quad.QuadConstraintCollector; import ai.timefold.solver.core.config.solver.EnvironmentMode; import ai.timefold.solver.core.impl.bavet.common.AbstractGroupNode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -abstract class AbstractGroupQuadNode +abstract class AbstractGroupQuadNode extends AbstractGroupNode, OutTuple_, GroupKey_, ResultContainer_, Result_> { private final PentaFunction accumulator; @@ -37,7 +37,7 @@ protected AbstractGroupQuadNode(int groupStoreIndex, @Override protected final Runnable accumulate(ResultContainer_ resultContainer, QuadTuple tuple) { - return accumulator.apply(resultContainer, tuple.factA, tuple.factB, tuple.factC, tuple.factD); + return accumulator.apply(resultContainer, tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatBiQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatBiQuadNode.java index 7b859b7145..c68e0eab1d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatBiQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatBiQuadNode.java @@ -24,30 +24,29 @@ public ConcatBiQuadNode(BiFunction paddingFunctionC, BiFunction getOutTupleFromLeft(BiTuple leftTuple) { - var factA = leftTuple.factA; - var factB = leftTuple.factB; - return new QuadTuple<>(factA, factB, - paddingFunctionC.apply(factA, factB), paddingFunctionD.apply(factA, factB), + var factA = leftTuple.getA(); + var factB = leftTuple.getB(); + return QuadTuple.of(factA, factB, paddingFunctionC.apply(factA, factB), paddingFunctionD.apply(factA, factB), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(QuadTuple rightTuple) { - return new QuadTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, rightTuple.factD, outputStoreSize); + return QuadTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), rightTuple.getD(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(BiTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void updateOutTupleFromRight(QuadTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; - outTuple.factD = rightTuple.factD; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); + outTuple.setD(rightTuple.getD()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadBiNode.java index f9d1dd40b2..474212e065 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadBiNode.java @@ -24,30 +24,29 @@ public ConcatQuadBiNode(BiFunction paddingFunctionC, BiFunction getOutTupleFromLeft(QuadTuple leftTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, outputStoreSize); + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(BiTuple rightTuple) { - var factA = rightTuple.factA; - var factB = rightTuple.factB; - return new QuadTuple<>(factA, factB, - paddingFunctionC.apply(factA, factB), paddingFunctionD.apply(factA, factB), + var factA = rightTuple.getA(); + var factB = rightTuple.getB(); + return QuadTuple.of(factA, factB, paddingFunctionC.apply(factA, factB), paddingFunctionD.apply(factA, factB), outputStoreSize); } @Override protected void updateOutTupleFromLeft(QuadTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; - outTuple.factD = leftTuple.factD; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); + outTuple.setD(leftTuple.getD()); } @Override protected void updateOutTupleFromRight(BiTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadQuadNode.java index e12add2e73..93db72244e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadQuadNode.java @@ -15,28 +15,28 @@ public ConcatQuadQuadNode(TupleLifecycle> nextNodesTupleLi @Override protected QuadTuple getOutTupleFromLeft(QuadTuple leftTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, outputStoreSize); + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(QuadTuple rightTuple) { - return new QuadTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, rightTuple.factD, outputStoreSize); + return QuadTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), rightTuple.getD(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(QuadTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; - outTuple.factD = leftTuple.factD; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); + outTuple.setD(leftTuple.getD()); } @Override protected void updateOutTupleFromRight(QuadTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; - outTuple.factD = rightTuple.factD; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); + outTuple.setD(rightTuple.getD()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadTriNode.java index 31a3f87e58..ce800cb376 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadTriNode.java @@ -21,32 +21,28 @@ public ConcatQuadTriNode(TriFunction paddingFunction, @Override protected QuadTuple getOutTupleFromLeft(QuadTuple leftTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, outputStoreSize); + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(TriTuple rightTuple) { - var factA = rightTuple.factA; - var factB = rightTuple.factB; - var factC = rightTuple.factC; - return new QuadTuple<>(factA, factB, factC, - paddingFunction.apply(factA, factB, factC), - outputStoreSize); + return QuadTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), + paddingFunction.apply(rightTuple.getA(), rightTuple.getB(), rightTuple.getC()), outputStoreSize); } @Override protected void updateOutTupleFromLeft(QuadTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; - outTuple.factD = leftTuple.factD; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); + outTuple.setD(leftTuple.getD()); } @Override protected void updateOutTupleFromRight(TriTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadUniNode.java index 3007886129..a796967c70 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatQuadUniNode.java @@ -26,28 +26,27 @@ public ConcatQuadUniNode(Function paddingFunctionB, Function padding @Override protected QuadTuple getOutTupleFromLeft(QuadTuple leftTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, outputStoreSize); + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(UniTuple rightTuple) { - var factA = rightTuple.factA; - return new QuadTuple<>(factA, - paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), paddingFunctionD.apply(factA), + var factA = rightTuple.getA(); + return QuadTuple.of(factA, paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), paddingFunctionD.apply(factA), outputStoreSize); } @Override protected void updateOutTupleFromLeft(QuadTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; - outTuple.factD = leftTuple.factD; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); + outTuple.setD(leftTuple.getD()); } @Override protected void updateOutTupleFromRight(UniTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; + outTuple.setA(rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatTriQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatTriQuadNode.java index d9d237994b..d48a1afdab 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatTriQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatTriQuadNode.java @@ -21,32 +21,30 @@ public ConcatTriQuadNode(TriFunction paddingFunction, @Override protected QuadTuple getOutTupleFromLeft(TriTuple leftTuple) { - var factA = leftTuple.factA; - var factB = leftTuple.factB; - var factC = leftTuple.factC; - return new QuadTuple<>(factA, factB, factC, - paddingFunction.apply(factA, factB, factC), - outputStoreSize); + var factA = leftTuple.getA(); + var factB = leftTuple.getB(); + var factC = leftTuple.getC(); + return QuadTuple.of(factA, factB, factC, paddingFunction.apply(factA, factB, factC), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(QuadTuple rightTuple) { - return new QuadTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, rightTuple.factD, outputStoreSize); + return QuadTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), rightTuple.getD(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(TriTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void updateOutTupleFromRight(QuadTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; - outTuple.factD = rightTuple.factD; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); + outTuple.setD(rightTuple.getD()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatUniQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatUniQuadNode.java index 7ecf3c9123..384957babf 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatUniQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/ConcatUniQuadNode.java @@ -27,28 +27,27 @@ public ConcatUniQuadNode(Function paddingFunctionB, Function padding @Override protected QuadTuple getOutTupleFromLeft(UniTuple leftTuple) { - var factA = leftTuple.factA; - return new QuadTuple<>(factA, - paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), paddingFunctionD.apply(factA), + var factA = leftTuple.getA(); + return QuadTuple.of(factA, paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), paddingFunctionD.apply(factA), outputStoreSize); } @Override protected QuadTuple getOutTupleFromRight(QuadTuple rightTuple) { - return new QuadTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, rightTuple.factD, outputStoreSize); + return QuadTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), rightTuple.getD(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(UniTuple leftTuple, QuadTuple outTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void updateOutTupleFromRight(QuadTuple rightTuple, QuadTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; - outTuple.factD = rightTuple.factD; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); + outTuple.setD(rightTuple.getD()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/FlattenLastQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/FlattenLastQuadNode.java index 6e5e263b0b..5bfa22f381 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/FlattenLastQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/FlattenLastQuadNode.java @@ -19,13 +19,12 @@ public FlattenLastQuadNode(int flattenLastStoreIndex, Function @Override protected QuadTuple createTuple(QuadTuple originalTuple, NewD newD) { - return new QuadTuple<>(originalTuple.factA, originalTuple.factB, originalTuple.factC, newD, - outputStoreSize); + return QuadTuple.of(originalTuple.getA(), originalTuple.getB(), originalTuple.getC(), newD, outputStoreSize); } @Override protected D getEffectiveFactIn(QuadTuple tuple) { - return tuple.factD; + return tuple.getD(); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping1CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping1CollectorQuadNode.java index c728e2a749..8a7b252bcb 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping1CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping1CollectorQuadNode.java @@ -20,12 +20,12 @@ public Group0Mapping1CollectorQuadNode(int groupStoreIndex, int undoStoreIndex, @Override protected UniTuple createOutTuple(Void groupKey) { - return new UniTuple<>(null, outputStoreSize); + return UniTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(UniTuple outTuple, A a) { - outTuple.factA = a; + outTuple.setA(a); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping2CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping2CollectorQuadNode.java index 4464a52d6d..95d55262b3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping2CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping2CollectorQuadNode.java @@ -32,13 +32,13 @@ QuadConstraintCollector> mergeCollect @Override protected BiTuple createOutTuple(Void groupKey) { - return new BiTuple<>(null, null, outputStoreSize); + return BiTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, Pair result) { - outTuple.factA = result.key(); - outTuple.factB = result.value(); + outTuple.setA(result.key()); + outTuple.setB(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping3CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping3CollectorQuadNode.java index 1cb82ab0d0..8186660db4 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping3CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping3CollectorQuadNode.java @@ -35,14 +35,14 @@ QuadConstraintCollector> mergeCo @Override protected TriTuple createOutTuple(Void groupKey) { - return new TriTuple<>(null, null, null, outputStoreSize); + return TriTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Triple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping4CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping4CollectorQuadNode.java index 07d8d54356..aedd1ef4e5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping4CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group0Mapping4CollectorQuadNode.java @@ -38,15 +38,15 @@ QuadConstraintCollector> m @Override protected QuadTuple createOutTuple(Void groupKey) { - return new QuadTuple<>(null, null, null, null, outputStoreSize); + return QuadTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Quadruple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); - outTuple.factD = result.d(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); + outTuple.setD(result.d()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping0CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping0CollectorQuadNode.java index 35a99189b8..4e3bfeb74b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping0CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping0CollectorQuadNode.java @@ -21,12 +21,12 @@ public Group1Mapping0CollectorQuadNode(QuadFunction g static A createGroupKey(QuadFunction groupKeyMapping, QuadTuple tuple) { - return groupKeyMapping.apply(tuple.factA, tuple.factB, tuple.factC, tuple.factD); + return groupKeyMapping.apply(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()); } @Override protected UniTuple createOutTuple(A a) { - return new UniTuple<>(a, outputStoreSize); + return UniTuple.of(a, outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping1CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping1CollectorQuadNode.java index f4e71ec459..7e071373a7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping1CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping1CollectorQuadNode.java @@ -23,12 +23,12 @@ public Group1Mapping1CollectorQuadNode(QuadFunction g @Override protected BiTuple createOutTuple(A a) { - return new BiTuple<>(a, null, outputStoreSize); + return BiTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, B b) { - outTuple.factB = b; + outTuple.setB(b); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping2CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping2CollectorQuadNode.java index 135d6396a4..7d43c3bd07 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping2CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping2CollectorQuadNode.java @@ -26,13 +26,13 @@ public Group1Mapping2CollectorQuadNode(QuadFunction g @Override protected TriTuple createOutTuple(A a) { - return new TriTuple<>(a, null, null, outputStoreSize); + return TriTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Pair result) { - outTuple.factB = result.key(); - outTuple.factC = result.value(); + outTuple.setB(result.key()); + outTuple.setC(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping3CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping3CollectorQuadNode.java index 741b478b17..e9772186a1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping3CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group1Mapping3CollectorQuadNode.java @@ -28,14 +28,14 @@ public Group1Mapping3CollectorQuadNode(QuadFunction g @Override protected QuadTuple createOutTuple(A a) { - return new QuadTuple<>(a, null, null, null, outputStoreSize); + return QuadTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Triple result) { - outTuple.factB = result.a(); - outTuple.factC = result.b(); - outTuple.factD = result.c(); + outTuple.setB(result.a()); + outTuple.setC(result.b()); + outTuple.setD(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping0CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping0CollectorQuadNode.java index fd668a5543..d0d717abd1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping0CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping0CollectorQuadNode.java @@ -24,18 +24,16 @@ public Group2Mapping0CollectorQuadNode(QuadFunction g static Pair createGroupKey(QuadFunction groupKeyMappingA, QuadFunction groupKeyMappingB, QuadTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - OldD oldD = tuple.factD; - A a = groupKeyMappingA.apply(oldA, oldB, oldC, oldD); - B b = groupKeyMappingB.apply(oldA, oldB, oldC, oldD); - return new Pair<>(a, b); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + var oldD = tuple.getD(); + return new Pair<>(groupKeyMappingA.apply(oldA, oldB, oldC, oldD), groupKeyMappingB.apply(oldA, oldB, oldC, oldD)); } @Override protected BiTuple createOutTuple(Pair groupKey) { - return new BiTuple<>(groupKey.key(), groupKey.value(), outputStoreSize); + return BiTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping1CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping1CollectorQuadNode.java index 87979bc88a..c93c0d54d0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping1CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping1CollectorQuadNode.java @@ -26,12 +26,12 @@ public Group2Mapping1CollectorQuadNode(QuadFunction g @Override protected TriTuple createOutTuple(Pair groupKey) { - return new TriTuple<>(groupKey.key(), groupKey.value(), null, outputStoreSize); + return TriTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, C c) { - outTuple.factC = c; + outTuple.setC(c); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping2CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping2CollectorQuadNode.java index 9b6e7714ae..d51271d91a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping2CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group2Mapping2CollectorQuadNode.java @@ -29,13 +29,13 @@ public Group2Mapping2CollectorQuadNode(QuadFunction g @Override protected QuadTuple createOutTuple(Pair groupKey) { - return new QuadTuple<>(groupKey.key(), groupKey.value(), null, null, outputStoreSize); + return QuadTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Pair result) { - outTuple.factC = result.key(); - outTuple.factD = result.value(); + outTuple.setC(result.key()); + outTuple.setD(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping0CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping0CollectorQuadNode.java index a9da29f98a..6531d5a775 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping0CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping0CollectorQuadNode.java @@ -28,19 +28,17 @@ static Triple createGroupKey( QuadFunction groupKeyMappingB, QuadFunction groupKeyMappingC, QuadTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - OldD oldD = tuple.factD; - A a = groupKeyMappingA.apply(oldA, oldB, oldC, oldD); - B b = groupKeyMappingB.apply(oldA, oldB, oldC, oldD); - C c = groupKeyMappingC.apply(oldA, oldB, oldC, oldD); - return new Triple<>(a, b, c); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + var oldD = tuple.getD(); + return new Triple<>(groupKeyMappingA.apply(oldA, oldB, oldC, oldD), groupKeyMappingB.apply(oldA, oldB, oldC, oldD), + groupKeyMappingC.apply(oldA, oldB, oldC, oldD)); } @Override protected TriTuple createOutTuple(Triple groupKey) { - return new TriTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); + return TriTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping1CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping1CollectorQuadNode.java index c3b6dd1bb1..33734b71a4 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping1CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group3Mapping1CollectorQuadNode.java @@ -29,12 +29,12 @@ public Group3Mapping1CollectorQuadNode(QuadFunction g @Override protected QuadTuple createOutTuple(Triple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), null, outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, D d) { - outTuple.factD = d; + outTuple.setD(d); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group4Mapping0CollectorQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group4Mapping0CollectorQuadNode.java index c008fb934f..ba80fc045b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group4Mapping0CollectorQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/Group4Mapping0CollectorQuadNode.java @@ -30,20 +30,17 @@ private static Quadruple create QuadFunction groupKeyMappingC, QuadFunction groupKeyMappingD, QuadTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - OldD oldD = tuple.factD; - A a = groupKeyMappingA.apply(oldA, oldB, oldC, oldD); - B b = groupKeyMappingB.apply(oldA, oldB, oldC, oldD); - C c = groupKeyMappingC.apply(oldA, oldB, oldC, oldD); - D d = groupKeyMappingD.apply(oldA, oldB, oldC, oldD); - return new Quadruple<>(a, b, c, d); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + var oldD = tuple.getD(); + return new Quadruple<>(groupKeyMappingA.apply(oldA, oldB, oldC, oldD), groupKeyMappingB.apply(oldA, oldB, oldC, oldD), + groupKeyMappingC.apply(oldA, oldB, oldC, oldD), groupKeyMappingD.apply(oldA, oldB, oldC, oldD)); } @Override protected QuadTuple createOutTuple(Quadruple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedIfExistsQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedIfExistsQuadNode.java index dd71dcefbe..e195ef2b76 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedIfExistsQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedIfExistsQuadNode.java @@ -28,8 +28,7 @@ public IndexedIfExistsQuadNode(boolean shouldExist, IndexerFactory indexerFac @Override protected boolean testFiltering(QuadTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, - rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedJoinQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedJoinQuadNode.java index f6759b33f2..b7d88a1d76 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedJoinQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/IndexedJoinQuadNode.java @@ -23,25 +23,25 @@ public IndexedJoinQuadNode(IndexerFactory indexerFactory, TupleLifecycle createOutTuple(TriTuple leftTuple, UniTuple rightTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA, + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(QuadTuple outTuple, TriTuple leftTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void setOutTupleRightFact(QuadTuple outTuple, UniTuple rightTuple) { - outTuple.factD = rightTuple.factA; + outTuple.setD(rightTuple.getA()); } @Override protected boolean testFiltering(TriTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToBiNode.java index 4bcb76619c..a1de1dfdac 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToBiNode.java @@ -23,26 +23,22 @@ public MapQuadToBiNode(int mapStoreIndex, QuadFunction mapping @Override protected BiTuple map(QuadTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - D factD = tuple.factD; - return new BiTuple<>( - mappingFunctionA.apply(factA, factB, factC, factD), - mappingFunctionB.apply(factA, factB, factC, factD), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + var factD = tuple.getD(); + return BiTuple.of(mappingFunctionA.apply(factA, factB, factC, factD), + mappingFunctionB.apply(factA, factB, factC, factD), outputStoreSize); } @Override protected void remap(QuadTuple inTuple, BiTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - D factD = inTuple.factD; - NewA newA = mappingFunctionA.apply(factA, factB, factC, factD); - NewB newB = mappingFunctionB.apply(factA, factB, factC, factD); - outTuple.factA = newA; - outTuple.factB = newB; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + var factD = inTuple.getD(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC, factD)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC, factD)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToQuadNode.java index 093edc1300..749cb52972 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToQuadNode.java @@ -28,32 +28,25 @@ public MapQuadToQuadNode(int mapStoreIndex, QuadFunction mappi @Override protected QuadTuple map(QuadTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - D factD = tuple.factD; - return new QuadTuple<>( - mappingFunctionA.apply(factA, factB, factC, factD), - mappingFunctionB.apply(factA, factB, factC, factD), - mappingFunctionC.apply(factA, factB, factC, factD), - mappingFunctionD.apply(factA, factB, factC, factD), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + var factD = tuple.getD(); + return QuadTuple.of(mappingFunctionA.apply(factA, factB, factC, factD), + mappingFunctionB.apply(factA, factB, factC, factD), mappingFunctionC.apply(factA, factB, factC, factD), + mappingFunctionD.apply(factA, factB, factC, factD), outputStoreSize); } @Override protected void remap(QuadTuple inTuple, QuadTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - D factD = inTuple.factD; - NewA newA = mappingFunctionA.apply(factA, factB, factC, factD); - NewB newB = mappingFunctionB.apply(factA, factB, factC, factD); - NewC newC = mappingFunctionC.apply(factA, factB, factC, factD); - NewD newD = mappingFunctionD.apply(factA, factB, factC, factD); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; - outTuple.factD = newD; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + var factD = inTuple.getD(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC, factD)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC, factD)); + outTuple.setC(mappingFunctionC.apply(factA, factB, factC, factD)); + outTuple.setD(mappingFunctionD.apply(factA, factB, factC, factD)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToTriNode.java index 840ac00dfd..849237e25d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToTriNode.java @@ -26,29 +26,24 @@ public MapQuadToTriNode(int mapStoreIndex, QuadFunction mappin @Override protected TriTuple map(QuadTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - D factD = tuple.factD; - return new TriTuple<>( - mappingFunctionA.apply(factA, factB, factC, factD), - mappingFunctionB.apply(factA, factB, factC, factD), - mappingFunctionC.apply(factA, factB, factC, factD), + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + var factD = tuple.getD(); + return TriTuple.of(mappingFunctionA.apply(factA, factB, factC, factD), + mappingFunctionB.apply(factA, factB, factC, factD), mappingFunctionC.apply(factA, factB, factC, factD), outputStoreSize); } @Override protected void remap(QuadTuple inTuple, TriTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - D factD = inTuple.factD; - NewA newA = mappingFunctionA.apply(factA, factB, factC, factD); - NewB newB = mappingFunctionB.apply(factA, factB, factC, factD); - NewC newC = mappingFunctionC.apply(factA, factB, factC, factD); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + var factD = inTuple.getD(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC, factD)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC, factD)); + outTuple.setC(mappingFunctionC.apply(factA, factB, factC, factD)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToUniNode.java index 1cfa564cc3..515429024a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/MapQuadToUniNode.java @@ -20,23 +20,21 @@ public MapQuadToUniNode(int mapStoreIndex, QuadFunction mappin @Override protected UniTuple map(QuadTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - D factD = tuple.factD; - return new UniTuple<>( - mappingFunction.apply(factA, factB, factC, factD), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + var factD = tuple.getD(); + return UniTuple.of(mappingFunction.apply(factA, factB, factC, factD), outputStoreSize); } @Override protected void remap(QuadTuple inTuple, UniTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - D factD = inTuple.factD; - NewA newA = mappingFunction.apply(factA, factB, factC, factD); - outTuple.factA = newA; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + var factD = inTuple.getD(); + var newA = mappingFunction.apply(factA, factB, factC, factD); + outTuple.setA(newA); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/PrecomputeQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/PrecomputeQuadNode.java index 5a7e6d2f97..8c65119bd9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/PrecomputeQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/PrecomputeQuadNode.java @@ -23,7 +23,6 @@ public PrecomputeQuadNode(Supplier remapTuple(QuadTuple tuple) { - return new QuadTuple<>(tuple.factA, tuple.factB, tuple.factC, tuple.factD, - outputStoreSize); + return QuadTuple.of(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD(), outputStoreSize); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedIfExistsQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedIfExistsQuadNode.java index 61d4ccf8ba..927e5007e1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedIfExistsQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedIfExistsQuadNode.java @@ -24,8 +24,7 @@ public UnindexedIfExistsQuadNode(boolean shouldExist, TupleLifecycle leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, leftTuple.factD, - rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), leftTuple.getD(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedJoinQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedJoinQuadNode.java index 2d06d5c318..352ae06c98 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedJoinQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/UnindexedJoinQuadNode.java @@ -21,25 +21,25 @@ public UnindexedJoinQuadNode(TupleLifecycle> nextNodesTupl @Override protected QuadTuple createOutTuple(TriTuple leftTuple, UniTuple rightTuple) { - return new QuadTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA, + return QuadTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(QuadTuple outTuple, TriTuple leftTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void setOutTupleRightFact(QuadTuple outTuple, UniTuple rightTuple) { - outTuple.factD = rightTuple.factA; + outTuple.setD(rightTuple.getA()); } @Override protected boolean testFiltering(TriTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/AbstractGroupTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/AbstractGroupTriNode.java index c5b9842fd4..ecf4f272dd 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/AbstractGroupTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/AbstractGroupTriNode.java @@ -6,11 +6,11 @@ import ai.timefold.solver.core.api.score.stream.tri.TriConstraintCollector; import ai.timefold.solver.core.config.solver.EnvironmentMode; import ai.timefold.solver.core.impl.bavet.common.AbstractGroupNode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -abstract class AbstractGroupTriNode +abstract class AbstractGroupTriNode extends AbstractGroupNode, OutTuple_, GroupKey_, ResultContainer_, Result_> { private final QuadFunction accumulator; @@ -36,7 +36,7 @@ protected AbstractGroupTriNode(int groupStoreIndex, @Override protected final Runnable accumulate(ResultContainer_ resultContainer, TriTuple tuple) { - return accumulator.apply(resultContainer, tuple.factA, tuple.factB, tuple.factC); + return accumulator.apply(resultContainer, tuple.getA(), tuple.getB(), tuple.getC()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatBiTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatBiTriNode.java index cd74e7f1b1..3b2a5f6778 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatBiTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatBiTriNode.java @@ -22,27 +22,27 @@ public ConcatBiTriNode(BiFunction paddingFunction, @Override protected TriTuple getOutTupleFromLeft(BiTuple leftTuple) { - var factA = leftTuple.factA; - var factB = leftTuple.factB; - return new TriTuple<>(factA, factB, paddingFunction.apply(factA, factB), outputStoreSize); + var factA = leftTuple.getA(); + var factB = leftTuple.getB(); + return TriTuple.of(factA, factB, paddingFunction.apply(factA, factB), outputStoreSize); } @Override protected TriTuple getOutTupleFromRight(TriTuple rightTuple) { - return new TriTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, outputStoreSize); + return TriTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(BiTuple leftTuple, TriTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void updateOutTupleFromRight(TriTuple rightTuple, TriTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriBiNode.java index d0e5ec270c..0dc2c8b3b3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriBiNode.java @@ -22,27 +22,27 @@ public ConcatTriBiNode(BiFunction paddingFunction, @Override protected TriTuple getOutTupleFromLeft(TriTuple leftTuple) { - return new TriTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, outputStoreSize); + return TriTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), outputStoreSize); } @Override protected TriTuple getOutTupleFromRight(BiTuple rightTuple) { - var factA = rightTuple.factA; - var factB = rightTuple.factB; - return new TriTuple<>(factA, factB, paddingFunction.apply(factA, factB), outputStoreSize); + var factA = rightTuple.getA(); + var factB = rightTuple.getB(); + return TriTuple.of(factA, factB, paddingFunction.apply(factA, factB), outputStoreSize); } @Override protected void updateOutTupleFromLeft(TriTuple leftTuple, TriTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void updateOutTupleFromRight(BiTuple rightTuple, TriTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriTriNode.java index 5a7d9f2c3d..c8ac6077e7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriTriNode.java @@ -15,26 +15,26 @@ public ConcatTriTriNode(TupleLifecycle> nextNodesTupleLifecycl @Override protected TriTuple getOutTupleFromLeft(TriTuple leftTuple) { - return new TriTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, outputStoreSize); + return TriTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), outputStoreSize); } @Override protected TriTuple getOutTupleFromRight(TriTuple rightTuple) { - return new TriTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, outputStoreSize); + return TriTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(TriTuple leftTuple, TriTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void updateOutTupleFromRight(TriTuple rightTuple, TriTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriUniNode.java index 3fcfd5135c..34b9d0113f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatTriUniNode.java @@ -24,27 +24,25 @@ public ConcatTriUniNode(Function paddingFunctionB, Function paddingF @Override protected TriTuple getOutTupleFromLeft(TriTuple leftTuple) { - return new TriTuple<>(leftTuple.factA, leftTuple.factB, leftTuple.factC, outputStoreSize); + return TriTuple.of(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), outputStoreSize); } @Override protected TriTuple getOutTupleFromRight(UniTuple rightTuple) { - var factA = rightTuple.factA; - return new TriTuple<>(factA, - paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), - outputStoreSize); + var factA = rightTuple.getA(); + return TriTuple.of(factA, paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), outputStoreSize); } @Override protected void updateOutTupleFromLeft(TriTuple leftTuple, TriTuple outTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; - outTuple.factC = leftTuple.factC; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); + outTuple.setC(leftTuple.getC()); } @Override protected void updateOutTupleFromRight(UniTuple rightTuple, TriTuple outTuple) { - outTuple.factA = rightTuple.factA; + outTuple.setA(rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatUniTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatUniTriNode.java index 3a701e7a2f..ff186b7385 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatUniTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/ConcatUniTriNode.java @@ -25,27 +25,25 @@ public ConcatUniTriNode(Function paddingFunctionB, Function paddingF @Override protected TriTuple getOutTupleFromLeft(UniTuple leftTuple) { - var factA = leftTuple.factA; - return new TriTuple<>(factA, - paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), - outputStoreSize); + var factA = leftTuple.getA(); + return TriTuple.of(factA, paddingFunctionB.apply(factA), paddingFunctionC.apply(factA), outputStoreSize); } @Override protected TriTuple getOutTupleFromRight(TriTuple rightTuple) { - return new TriTuple<>(rightTuple.factA, rightTuple.factB, rightTuple.factC, outputStoreSize); + return TriTuple.of(rightTuple.getA(), rightTuple.getB(), rightTuple.getC(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(UniTuple leftTuple, TriTuple outTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void updateOutTupleFromRight(TriTuple rightTuple, TriTuple outTuple) { - outTuple.factA = rightTuple.factA; - outTuple.factB = rightTuple.factB; - outTuple.factC = rightTuple.factC; + outTuple.setA(rightTuple.getA()); + outTuple.setB(rightTuple.getB()); + outTuple.setC(rightTuple.getC()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/FlattenLastTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/FlattenLastTriNode.java index 9e09f2b99f..48b71a3f51 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/FlattenLastTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/FlattenLastTriNode.java @@ -19,12 +19,12 @@ public FlattenLastTriNode(int flattenLastStoreIndex, Function> @Override protected TriTuple createTuple(TriTuple originalTuple, NewC newC) { - return new TriTuple<>(originalTuple.factA, originalTuple.factB, newC, outputStoreSize); + return TriTuple.of(originalTuple.getA(), originalTuple.getB(), newC, outputStoreSize); } @Override protected C getEffectiveFactIn(TriTuple tuple) { - return tuple.factC; + return tuple.getC(); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping1CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping1CollectorTriNode.java index 66ee29ad50..9d96f39618 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping1CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping1CollectorTriNode.java @@ -20,12 +20,12 @@ public Group0Mapping1CollectorTriNode(int groupStoreIndex, int undoStoreIndex, @Override protected UniTuple createOutTuple(Void groupKey) { - return new UniTuple<>(null, outputStoreSize); + return UniTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(UniTuple outTuple, A a) { - outTuple.factA = a; + outTuple.setA(a); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping2CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping2CollectorTriNode.java index 6f1bf300c8..bc6cdd22d8 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping2CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping2CollectorTriNode.java @@ -33,13 +33,13 @@ TriConstraintCollector> mergeCollectors( @Override protected BiTuple createOutTuple(Void groupKey) { - return new BiTuple<>(null, null, outputStoreSize); + return BiTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, Pair result) { - outTuple.factA = result.key(); - outTuple.factB = result.value(); + outTuple.setA(result.key()); + outTuple.setB(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping3CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping3CollectorTriNode.java index 35f79968c3..a7145388a9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping3CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping3CollectorTriNode.java @@ -35,14 +35,14 @@ TriConstraintCollector> mergeCollector @Override protected TriTuple createOutTuple(Void groupKey) { - return new TriTuple<>(null, null, null, outputStoreSize); + return TriTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Triple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping4CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping4CollectorTriNode.java index 5a1e4f9f1f..819476ed26 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping4CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group0Mapping4CollectorTriNode.java @@ -38,15 +38,15 @@ TriConstraintCollector> mergeCol @Override protected QuadTuple createOutTuple(Void groupKey) { - return new QuadTuple<>(null, null, null, null, outputStoreSize); + return QuadTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Quadruple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); - outTuple.factD = result.d(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); + outTuple.setD(result.d()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping0CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping0CollectorTriNode.java index 4cbb7d15d5..cc92e0b3f7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping0CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping0CollectorTriNode.java @@ -21,12 +21,12 @@ public Group1Mapping0CollectorTriNode(TriFunction groupKeyM static A createGroupKey(TriFunction groupKeyMapping, TriTuple tuple) { - return groupKeyMapping.apply(tuple.factA, tuple.factB, tuple.factC); + return groupKeyMapping.apply(tuple.getA(), tuple.getB(), tuple.getC()); } @Override protected UniTuple createOutTuple(A a) { - return new UniTuple<>(a, outputStoreSize); + return UniTuple.of(a, outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping1CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping1CollectorTriNode.java index 378e942430..ee608b229f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping1CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping1CollectorTriNode.java @@ -23,12 +23,12 @@ public Group1Mapping1CollectorTriNode(TriFunction groupKeyM @Override protected BiTuple createOutTuple(A a) { - return new BiTuple<>(a, null, outputStoreSize); + return BiTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, B b) { - outTuple.factB = b; + outTuple.setB(b); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping2CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping2CollectorTriNode.java index de9a567c60..cc923c2155 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping2CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping2CollectorTriNode.java @@ -26,13 +26,13 @@ public Group1Mapping2CollectorTriNode(TriFunction groupKeyM @Override protected TriTuple createOutTuple(A a) { - return new TriTuple<>(a, null, null, outputStoreSize); + return TriTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Pair result) { - outTuple.factB = result.key(); - outTuple.factC = result.value(); + outTuple.setB(result.key()); + outTuple.setC(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping3CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping3CollectorTriNode.java index 017e952e8b..cae45e327b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping3CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group1Mapping3CollectorTriNode.java @@ -29,14 +29,14 @@ public Group1Mapping3CollectorTriNode(TriFunction groupKeyM @Override protected QuadTuple createOutTuple(A a) { - return new QuadTuple<>(a, null, null, null, outputStoreSize); + return QuadTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Triple result) { - outTuple.factB = result.a(); - outTuple.factC = result.b(); - outTuple.factD = result.c(); + outTuple.setB(result.a()); + outTuple.setC(result.b()); + outTuple.setD(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping0CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping0CollectorTriNode.java index 914cd9713c..568958f681 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping0CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping0CollectorTriNode.java @@ -22,17 +22,15 @@ public Group2Mapping0CollectorTriNode(TriFunction groupKeyM static Pair createGroupKey(TriFunction groupKeyMappingA, TriFunction groupKeyMappingB, TriTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - A a = groupKeyMappingA.apply(oldA, oldB, oldC); - B b = groupKeyMappingB.apply(oldA, oldB, oldC); - return new Pair<>(a, b); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + return new Pair<>(groupKeyMappingA.apply(oldA, oldB, oldC), groupKeyMappingB.apply(oldA, oldB, oldC)); } @Override protected BiTuple createOutTuple(Pair groupKey) { - return new BiTuple<>(groupKey.key(), groupKey.value(), outputStoreSize); + return BiTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping1CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping1CollectorTriNode.java index ca11f32cd2..d65d0a0f1c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping1CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping1CollectorTriNode.java @@ -26,12 +26,12 @@ public Group2Mapping1CollectorTriNode(TriFunction groupKeyM @Override protected TriTuple createOutTuple(Pair groupKey) { - return new TriTuple<>(groupKey.key(), groupKey.value(), null, outputStoreSize); + return TriTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, C c) { - outTuple.factC = c; + outTuple.setC(c); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping2CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping2CollectorTriNode.java index a1cf2fe149..f1502d8c87 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping2CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group2Mapping2CollectorTriNode.java @@ -29,13 +29,13 @@ public Group2Mapping2CollectorTriNode(TriFunction groupKeyM @Override protected QuadTuple createOutTuple(Pair groupKey) { - return new QuadTuple<>(groupKey.key(), groupKey.value(), null, null, outputStoreSize); + return QuadTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Pair result) { - outTuple.factC = result.key(); - outTuple.factD = result.value(); + outTuple.setC(result.key()); + outTuple.setD(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping0CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping0CollectorTriNode.java index 6197fc87e0..698e909888 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping0CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping0CollectorTriNode.java @@ -24,18 +24,16 @@ public Group3Mapping0CollectorTriNode(TriFunction groupKeyM static Triple createGroupKey(TriFunction groupKeyMappingA, TriFunction groupKeyMappingB, TriFunction groupKeyMappingC, TriTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - A a = groupKeyMappingA.apply(oldA, oldB, oldC); - B b = groupKeyMappingB.apply(oldA, oldB, oldC); - C c = groupKeyMappingC.apply(oldA, oldB, oldC); - return new Triple<>(a, b, c); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + return new Triple<>(groupKeyMappingA.apply(oldA, oldB, oldC), groupKeyMappingB.apply(oldA, oldB, oldC), + groupKeyMappingC.apply(oldA, oldB, oldC)); } @Override protected TriTuple createOutTuple(Triple groupKey) { - return new TriTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); + return TriTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping1CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping1CollectorTriNode.java index 00a2cb7657..3ad015a559 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping1CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group3Mapping1CollectorTriNode.java @@ -29,12 +29,12 @@ public Group3Mapping1CollectorTriNode(TriFunction groupKeyM @Override protected QuadTuple createOutTuple(Triple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), null, outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, D d) { - outTuple.factD = d; + outTuple.setD(d); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group4Mapping0CollectorTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group4Mapping0CollectorTriNode.java index c1d926fdfb..01ed78c343 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group4Mapping0CollectorTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/Group4Mapping0CollectorTriNode.java @@ -31,19 +31,16 @@ private static Quadruple createGroupK TriFunction groupKeyMappingC, TriFunction groupKeyMappingD, TriTuple tuple) { - OldA oldA = tuple.factA; - OldB oldB = tuple.factB; - OldC oldC = tuple.factC; - A a = groupKeyMappingA.apply(oldA, oldB, oldC); - B b = groupKeyMappingB.apply(oldA, oldB, oldC); - C c = groupKeyMappingC.apply(oldA, oldB, oldC); - D d = groupKeyMappingD.apply(oldA, oldB, oldC); - return new Quadruple<>(a, b, c, d); + var oldA = tuple.getA(); + var oldB = tuple.getB(); + var oldC = tuple.getC(); + return new Quadruple<>(groupKeyMappingA.apply(oldA, oldB, oldC), groupKeyMappingB.apply(oldA, oldB, oldC), + groupKeyMappingC.apply(oldA, oldB, oldC), groupKeyMappingD.apply(oldA, oldB, oldC)); } @Override protected QuadTuple createOutTuple(Quadruple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedIfExistsTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedIfExistsTriNode.java index ebdbb637da..3aa25d9cd5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedIfExistsTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedIfExistsTriNode.java @@ -27,7 +27,7 @@ public IndexedIfExistsTriNode(boolean shouldExist, IndexerFactory indexerFact @Override protected boolean testFiltering(TriTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedJoinTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedJoinTriNode.java index 0da582d565..b59890d721 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedJoinTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/IndexedJoinTriNode.java @@ -23,23 +23,23 @@ public IndexedJoinTriNode(IndexerFactory indexerFactory, TupleLifecycle createOutTuple(BiTuple leftTuple, UniTuple rightTuple) { - return new TriTuple<>(leftTuple.factA, leftTuple.factB, rightTuple.factA, outputStoreSizeTracker.computeStoreSize()); + return TriTuple.of(leftTuple.getA(), leftTuple.getB(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(TriTuple outTuple, BiTuple leftTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void setOutTupleRightFact(TriTuple outTuple, UniTuple rightTuple) { - outTuple.factC = rightTuple.factA; + outTuple.setC(rightTuple.getA()); } @Override protected boolean testFiltering(BiTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToBiNode.java index 4c97783376..addcf5679d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToBiNode.java @@ -23,24 +23,20 @@ public MapTriToBiNode(int mapStoreIndex, TriFunction mappingFunct @Override protected BiTuple map(TriTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - return new BiTuple<>( - mappingFunctionA.apply(factA, factB, factC), - mappingFunctionB.apply(factA, factB, factC), + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + return BiTuple.of(mappingFunctionA.apply(factA, factB, factC), mappingFunctionB.apply(factA, factB, factC), outputStoreSize); } @Override protected void remap(TriTuple inTuple, BiTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - NewA newA = mappingFunctionA.apply(factA, factB, factC); - NewB newB = mappingFunctionB.apply(factA, factB, factC); - outTuple.factA = newA; - outTuple.factB = newB; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToQuadNode.java index d2cb5857a0..6a5626aa69 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToQuadNode.java @@ -29,30 +29,22 @@ public MapTriToQuadNode(int mapStoreIndex, TriFunction mappingFun @Override protected QuadTuple map(TriTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - return new QuadTuple<>( - mappingFunctionA.apply(factA, factB, factC), - mappingFunctionB.apply(factA, factB, factC), - mappingFunctionC.apply(factA, factB, factC), - mappingFunctionD.apply(factA, factB, factC), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + return QuadTuple.of(mappingFunctionA.apply(factA, factB, factC), mappingFunctionB.apply(factA, factB, factC), + mappingFunctionC.apply(factA, factB, factC), mappingFunctionD.apply(factA, factB, factC), outputStoreSize); } @Override protected void remap(TriTuple inTuple, QuadTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - NewA newA = mappingFunctionA.apply(factA, factB, factC); - NewB newB = mappingFunctionB.apply(factA, factB, factC); - NewC newC = mappingFunctionC.apply(factA, factB, factC); - NewD newD = mappingFunctionD.apply(factA, factB, factC); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; - outTuple.factD = newD; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC)); + outTuple.setC(mappingFunctionC.apply(factA, factB, factC)); + outTuple.setD(mappingFunctionD.apply(factA, factB, factC)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToTriNode.java index 2479cd603c..ccc1790d54 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToTriNode.java @@ -26,27 +26,21 @@ public MapTriToTriNode(int mapStoreIndex, TriFunction mappingFunc @Override protected TriTuple map(TriTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - return new TriTuple<>( - mappingFunctionA.apply(factA, factB, factC), - mappingFunctionB.apply(factA, factB, factC), - mappingFunctionC.apply(factA, factB, factC), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + return TriTuple.of(mappingFunctionA.apply(factA, factB, factC), mappingFunctionB.apply(factA, factB, factC), + mappingFunctionC.apply(factA, factB, factC), outputStoreSize); } @Override protected void remap(TriTuple inTuple, TriTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - NewA newA = mappingFunctionA.apply(factA, factB, factC); - NewB newB = mappingFunctionB.apply(factA, factB, factC); - NewC newC = mappingFunctionC.apply(factA, factB, factC); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + outTuple.setA(mappingFunctionA.apply(factA, factB, factC)); + outTuple.setB(mappingFunctionB.apply(factA, factB, factC)); + outTuple.setC(mappingFunctionC.apply(factA, factB, factC)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToUniNode.java index bcbce11a16..da952ca39d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/MapTriToUniNode.java @@ -20,21 +20,19 @@ public MapTriToUniNode(int mapStoreIndex, TriFunction mappingFunc @Override protected UniTuple map(TriTuple tuple) { - A factA = tuple.factA; - B factB = tuple.factB; - C factC = tuple.factC; - return new UniTuple<>( - mappingFunction.apply(factA, factB, factC), - outputStoreSize); + var factA = tuple.getA(); + var factB = tuple.getB(); + var factC = tuple.getC(); + return UniTuple.of(mappingFunction.apply(factA, factB, factC), outputStoreSize); } @Override protected void remap(TriTuple inTuple, UniTuple outTuple) { - A factA = inTuple.factA; - B factB = inTuple.factB; - C factC = inTuple.factC; - NewA newA = mappingFunction.apply(factA, factB, factC); - outTuple.factA = newA; + var factA = inTuple.getA(); + var factB = inTuple.getB(); + var factC = inTuple.getC(); + var newA = mappingFunction.apply(factA, factB, factC); + outTuple.setA(newA); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/PrecomputeTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/PrecomputeTriNode.java index 23952d1afb..936563f13c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/PrecomputeTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/PrecomputeTriNode.java @@ -23,6 +23,6 @@ public PrecomputeTriNode(Supplier>> @Override protected TriTuple remapTuple(TriTuple tuple) { - return new TriTuple<>(tuple.factA, tuple.factB, tuple.factC, outputStoreSize); + return TriTuple.of(tuple.getA(), tuple.getB(), tuple.getC(), outputStoreSize); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedIfExistsTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedIfExistsTriNode.java index b52dacebaf..97e06ed6c6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedIfExistsTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedIfExistsTriNode.java @@ -24,7 +24,7 @@ public UnindexedIfExistsTriNode(boolean shouldExist, TupleLifecycle leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, leftTuple.factC, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), leftTuple.getC(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedJoinTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedJoinTriNode.java index 2bb59d9758..964c58524f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedJoinTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/UnindexedJoinTriNode.java @@ -21,23 +21,23 @@ public UnindexedJoinTriNode(TupleLifecycle> nextNodesTupleLife @Override protected TriTuple createOutTuple(BiTuple leftTuple, UniTuple rightTuple) { - return new TriTuple<>(leftTuple.factA, leftTuple.factB, rightTuple.factA, outputStoreSizeTracker.computeStoreSize()); + return TriTuple.of(leftTuple.getA(), leftTuple.getB(), rightTuple.getA(), outputStoreSizeTracker.computeStoreSize()); } @Override protected void setOutTupleLeftFacts(TriTuple outTuple, BiTuple leftTuple) { - outTuple.factA = leftTuple.factA; - outTuple.factB = leftTuple.factB; + outTuple.setA(leftTuple.getA()); + outTuple.setB(leftTuple.getB()); } @Override protected void setOutTupleRightFact(TriTuple outTuple, UniTuple rightTuple) { - outTuple.factC = rightTuple.factA; + outTuple.setC(rightTuple.getA()); } @Override protected boolean testFiltering(BiTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, leftTuple.factB, rightTuple.factA); + return filtering.test(leftTuple.getA(), leftTuple.getB(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractForEachUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractForEachUniNode.java index ed857aa335..d7777a4ba7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractForEachUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractForEachUniNode.java @@ -52,7 +52,7 @@ public Class[] getSourceClasses() { @Override public void insert(@Nullable A a) { - var tuple = new UniTuple<>(a, outputStoreSize); + var tuple = UniTuple.of(a, outputStoreSize); var old = tupleMap.put(a, tuple); if (old != null) { throw new IllegalStateException("The fact (%s) was already inserted, so it cannot insert again." @@ -62,7 +62,7 @@ public void insert(@Nullable A a) { } protected final void updateExisting(@Nullable A a, UniTuple tuple) { - var state = tuple.state; + var state = tuple.getState(); if (state.isDirty()) { if (state == TupleState.DYING || state == TupleState.ABORTING) { throw new IllegalStateException("The fact (%s) was retracted, so it cannot update." @@ -85,7 +85,7 @@ public void retract(@Nullable A a) { } protected void retractExisting(@Nullable A a, UniTuple tuple) { - var state = tuple.state; + var state = tuple.getState(); if (state.isDirty()) { if (state == TupleState.DYING || state == TupleState.ABORTING) { throw new IllegalStateException("The fact (%s) was already retracted, so it cannot retract." diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractGroupUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractGroupUniNode.java index 6c1693cfda..4b0e33da8f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractGroupUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/AbstractGroupUniNode.java @@ -6,11 +6,11 @@ import ai.timefold.solver.core.api.score.stream.uni.UniConstraintCollector; import ai.timefold.solver.core.config.solver.EnvironmentMode; import ai.timefold.solver.core.impl.bavet.common.AbstractGroupNode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; -abstract class AbstractGroupUniNode +abstract class AbstractGroupUniNode extends AbstractGroupNode, OutTuple_, GroupKey_, ResultContainer_, Result_> { private final BiFunction accumulator; @@ -37,6 +37,6 @@ protected AbstractGroupUniNode(int groupStoreIndex, @Override protected final Runnable accumulate(ResultContainer_ resultContainer, UniTuple tuple) { - return accumulator.apply(resultContainer, tuple.factA); + return accumulator.apply(resultContainer, tuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/ConcatUniUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/ConcatUniUniNode.java index db214f40cf..d3c8159064 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/ConcatUniUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/ConcatUniUniNode.java @@ -16,22 +16,22 @@ public ConcatUniUniNode(TupleLifecycle> nextNodesTupleLifecycle, @Override protected UniTuple getOutTupleFromLeft(UniTuple leftTuple) { - return new UniTuple<>(leftTuple.factA, outputStoreSize); + return UniTuple.of(leftTuple.getA(), outputStoreSize); } @Override protected UniTuple getOutTupleFromRight(UniTuple rightTuple) { - return new UniTuple<>(rightTuple.factA, outputStoreSize); + return UniTuple.of(rightTuple.getA(), outputStoreSize); } @Override protected void updateOutTupleFromLeft(UniTuple leftTuple, UniTuple outTuple) { - outTuple.factA = leftTuple.factA; + outTuple.setA(leftTuple.getA()); } @Override protected void updateOutTupleFromRight(UniTuple rightTuple, UniTuple outTuple) { - outTuple.factA = rightTuple.factA; + outTuple.setA(rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNode.java index 09a037461c..378db61d4e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNode.java @@ -18,12 +18,12 @@ public FlattenLastUniNode(int flattenLastStoreIndex, Function> @Override protected UniTuple createTuple(UniTuple originalTuple, NewA item) { - return new UniTuple<>(item, outputStoreSize); + return UniTuple.of(item, outputStoreSize); } @Override protected A getEffectiveFactIn(UniTuple tuple) { - return tuple.factA; + return tuple.getA(); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping1CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping1CollectorUniNode.java index 9149f57a77..b9825e7305 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping1CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping1CollectorUniNode.java @@ -20,12 +20,12 @@ public Group0Mapping1CollectorUniNode(int groupStoreIndex, int undoStoreIndex, @Override protected UniTuple createOutTuple(Void groupKey) { - return new UniTuple<>(null, outputStoreSize); + return UniTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(UniTuple outTuple, A a) { - outTuple.factA = a; + outTuple.setA(a); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping2CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping2CollectorUniNode.java index 9ad112a67c..240572684a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping2CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping2CollectorUniNode.java @@ -31,13 +31,13 @@ UniConstraintCollector> mergeCollectors( @Override protected BiTuple createOutTuple(Void groupKey) { - return new BiTuple<>(null, null, outputStoreSize); + return BiTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, Pair result) { - outTuple.factA = result.key(); - outTuple.factB = result.value(); + outTuple.setA(result.key()); + outTuple.setB(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping3CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping3CollectorUniNode.java index bf3685e259..72836aff7a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping3CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping3CollectorUniNode.java @@ -34,14 +34,14 @@ UniConstraintCollector> mergeCollectors( @Override protected TriTuple createOutTuple(Void groupKey) { - return new TriTuple<>(null, null, null, outputStoreSize); + return TriTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Triple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping4CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping4CollectorUniNode.java index 91efb0900e..5409631243 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping4CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group0Mapping4CollectorUniNode.java @@ -38,15 +38,15 @@ UniConstraintCollector> mergeCollectors( @Override protected QuadTuple createOutTuple(Void groupKey) { - return new QuadTuple<>(null, null, null, null, outputStoreSize); + return QuadTuple.of(outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Quadruple result) { - outTuple.factA = result.a(); - outTuple.factB = result.b(); - outTuple.factC = result.c(); - outTuple.factD = result.d(); + outTuple.setA(result.a()); + outTuple.setB(result.b()); + outTuple.setC(result.c()); + outTuple.setD(result.d()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping0CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping0CollectorUniNode.java index e81264c52c..349adcce29 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping0CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping0CollectorUniNode.java @@ -20,12 +20,12 @@ public Group1Mapping0CollectorUniNode(Function groupKeyMapping, } static A createGroupKey(Function groupKeyMapping, UniTuple tuple) { - return groupKeyMapping.apply(tuple.factA); + return groupKeyMapping.apply(tuple.getA()); } @Override protected UniTuple createOutTuple(A a) { - return new UniTuple<>(a, outputStoreSize); + return UniTuple.of(a, outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping1CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping1CollectorUniNode.java index 8293279019..745bb5a44f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping1CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping1CollectorUniNode.java @@ -26,12 +26,12 @@ public Group1Mapping1CollectorUniNode(Function groupKeyMapping, @Override protected BiTuple createOutTuple(A a) { - return new BiTuple<>(a, null, outputStoreSize); + return BiTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(BiTuple outTuple, B b) { - outTuple.factB = b; + outTuple.setB(b); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping2CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping2CollectorUniNode.java index 596efdbd81..5aca9b97af 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping2CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping2CollectorUniNode.java @@ -27,13 +27,13 @@ public Group1Mapping2CollectorUniNode(Function groupKeyMapping, @Override protected TriTuple createOutTuple(A a) { - return new TriTuple<>(a, null, null, outputStoreSize); + return TriTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, Pair result) { - outTuple.factB = result.key(); - outTuple.factC = result.value(); + outTuple.setB(result.key()); + outTuple.setC(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping3CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping3CollectorUniNode.java index c4a2e5762a..3ec5a82ff8 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping3CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group1Mapping3CollectorUniNode.java @@ -31,14 +31,14 @@ public Group1Mapping3CollectorUniNode(Function groupKeyMapping, @Override protected QuadTuple createOutTuple(A a) { - return new QuadTuple<>(a, null, null, null, outputStoreSize); + return QuadTuple.of(a, outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Triple result) { - outTuple.factB = result.a(); - outTuple.factC = result.b(); - outTuple.factD = result.c(); + outTuple.setB(result.a()); + outTuple.setC(result.b()); + outTuple.setD(result.c()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping0CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping0CollectorUniNode.java index 4e8e4149ab..25c6361636 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping0CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping0CollectorUniNode.java @@ -23,15 +23,13 @@ public Group2Mapping0CollectorUniNode(Function groupKeyMappingA, Functi static Pair createGroupKey(Function groupKeyMappingA, Function groupKeyMappingB, UniTuple tuple) { - OldA oldA = tuple.factA; - A a = groupKeyMappingA.apply(oldA); - B b = groupKeyMappingB.apply(oldA); - return new Pair<>(a, b); + var oldA = tuple.getA(); + return new Pair<>(groupKeyMappingA.apply(oldA), groupKeyMappingB.apply(oldA)); } @Override protected BiTuple createOutTuple(Pair groupKey) { - return new BiTuple<>(groupKey.key(), groupKey.value(), outputStoreSize); + return BiTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping1CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping1CollectorUniNode.java index 4b582c5777..01b9d8e157 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping1CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping1CollectorUniNode.java @@ -27,12 +27,12 @@ public Group2Mapping1CollectorUniNode(Function groupKeyMappingA, Functi @Override protected TriTuple createOutTuple(Pair groupKey) { - return new TriTuple<>(groupKey.key(), groupKey.value(), null, outputStoreSize); + return TriTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(TriTuple outTuple, C c) { - outTuple.factC = c; + outTuple.setC(c); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping2CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping2CollectorUniNode.java index 3fd3813c80..4fee25e342 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping2CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group2Mapping2CollectorUniNode.java @@ -30,13 +30,13 @@ public Group2Mapping2CollectorUniNode(Function groupKeyMappingA, Functi @Override protected QuadTuple createOutTuple(Pair groupKey) { - return new QuadTuple<>(groupKey.key(), groupKey.value(), null, null, outputStoreSize); + return QuadTuple.of(groupKey.key(), groupKey.value(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, Pair result) { - outTuple.factC = result.key(); - outTuple.factD = result.value(); + outTuple.setC(result.key()); + outTuple.setD(result.value()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping0CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping0CollectorUniNode.java index 646d939bfa..83e72a3203 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping0CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping0CollectorUniNode.java @@ -24,16 +24,13 @@ public Group3Mapping0CollectorUniNode(Function groupKeyMappingA, Functi static Triple createGroupKey(Function groupKeyMappingA, Function groupKeyMappingB, Function groupKeyMappingC, UniTuple tuple) { - OldA oldA = tuple.factA; - A a = groupKeyMappingA.apply(oldA); - B b = groupKeyMappingB.apply(oldA); - C c = groupKeyMappingC.apply(oldA); - return new Triple<>(a, b, c); + var oldA = tuple.getA(); + return new Triple<>(groupKeyMappingA.apply(oldA), groupKeyMappingB.apply(oldA), groupKeyMappingC.apply(oldA)); } @Override protected TriTuple createOutTuple(Triple groupKey) { - return new TriTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); + return TriTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping1CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping1CollectorUniNode.java index d41e651bc1..04ed73ea90 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping1CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group3Mapping1CollectorUniNode.java @@ -30,12 +30,12 @@ public Group3Mapping1CollectorUniNode(Function groupKeyMappingA, Functi @Override protected QuadTuple createOutTuple(Triple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), null, outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), outputStoreSize); } @Override protected void updateOutTupleToResult(QuadTuple outTuple, D d) { - outTuple.factD = d; + outTuple.setD(d); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group4Mapping0CollectorUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group4Mapping0CollectorUniNode.java index c645500663..d77039a70f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group4Mapping0CollectorUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/Group4Mapping0CollectorUniNode.java @@ -28,17 +28,14 @@ public Group4Mapping0CollectorUniNode(Function groupKeyMappingA, Functi private static Quadruple createGroupKey(Function groupKeyMappingA, Function groupKeyMappingB, Function groupKeyMappingC, Function groupKeyMappingD, UniTuple tuple) { - OldA oldA = tuple.factA; - A a = groupKeyMappingA.apply(oldA); - B b = groupKeyMappingB.apply(oldA); - C c = groupKeyMappingC.apply(oldA); - D d = groupKeyMappingD.apply(oldA); - return new Quadruple<>(a, b, c, d); + var oldA = tuple.getA(); + return new Quadruple<>(groupKeyMappingA.apply(oldA), groupKeyMappingB.apply(oldA), groupKeyMappingC.apply(oldA), + groupKeyMappingD.apply(oldA)); } @Override protected QuadTuple createOutTuple(Quadruple groupKey) { - return new QuadTuple<>(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); + return QuadTuple.of(groupKey.a(), groupKey.b(), groupKey.c(), groupKey.d(), outputStoreSize); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/IndexedIfExistsUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/IndexedIfExistsUniNode.java index a7c543ad86..c2b5e64c2d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/IndexedIfExistsUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/IndexedIfExistsUniNode.java @@ -28,7 +28,7 @@ public IndexedIfExistsUniNode(boolean shouldExist, IndexerFactory indexerFact @Override protected boolean testFiltering(UniTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, rightTuple.factA); + return filtering.test(leftTuple.getA(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToBiNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToBiNode.java index 2c29456b8a..a97b88fe61 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToBiNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToBiNode.java @@ -22,20 +22,15 @@ public MapUniToBiNode(int mapStoreIndex, Function mappingFunctionA, Fun @Override protected BiTuple map(UniTuple tuple) { - A factA = tuple.factA; - return new BiTuple<>( - mappingFunctionA.apply(factA), - mappingFunctionB.apply(factA), - outputStoreSize); + var factA = tuple.getA(); + return BiTuple.of(mappingFunctionA.apply(factA), mappingFunctionB.apply(factA), outputStoreSize); } @Override protected void remap(UniTuple inTuple, BiTuple outTuple) { - A factA = inTuple.factA; - NewA newA = mappingFunctionA.apply(factA); - NewB newB = mappingFunctionB.apply(factA); - outTuple.factA = newA; - outTuple.factB = newB; + var factA = inTuple.getA(); + outTuple.setA(mappingFunctionA.apply(factA)); + outTuple.setB(mappingFunctionB.apply(factA)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToQuadNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToQuadNode.java index 344d9a600a..514bf3d07f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToQuadNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToQuadNode.java @@ -28,26 +28,18 @@ public MapUniToQuadNode(int mapStoreIndex, Function mappingFunctionA, F @Override protected QuadTuple map(UniTuple tuple) { - A factA = tuple.factA; - return new QuadTuple<>( - mappingFunctionA.apply(factA), - mappingFunctionB.apply(factA), - mappingFunctionC.apply(factA), - mappingFunctionD.apply(factA), - outputStoreSize); + var factA = tuple.getA(); + return QuadTuple.of(mappingFunctionA.apply(factA), mappingFunctionB.apply(factA), mappingFunctionC.apply(factA), + mappingFunctionD.apply(factA), outputStoreSize); } @Override protected void remap(UniTuple inTuple, QuadTuple outTuple) { - A factA = inTuple.factA; - NewA newA = mappingFunctionA.apply(factA); - NewB newB = mappingFunctionB.apply(factA); - NewC newC = mappingFunctionC.apply(factA); - NewD newD = mappingFunctionD.apply(factA); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; - outTuple.factD = newD; + var factA = inTuple.getA(); + outTuple.setA(mappingFunctionA.apply(factA)); + outTuple.setB(mappingFunctionB.apply(factA)); + outTuple.setC(mappingFunctionC.apply(factA)); + outTuple.setD(mappingFunctionD.apply(factA)); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToTriNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToTriNode.java index b00e22fd4c..e392202c20 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToTriNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToTriNode.java @@ -25,23 +25,20 @@ public MapUniToTriNode(int mapStoreIndex, Function mappingFunctionA, Fu @Override protected TriTuple map(UniTuple tuple) { - A factA = tuple.factA; - return new TriTuple<>( - mappingFunctionA.apply(factA), - mappingFunctionB.apply(factA), - mappingFunctionC.apply(factA), + var factA = tuple.getA(); + return TriTuple.of(mappingFunctionA.apply(factA), mappingFunctionB.apply(factA), mappingFunctionC.apply(factA), outputStoreSize); } @Override protected void remap(UniTuple inTuple, TriTuple outTuple) { - A factA = inTuple.factA; - NewA newA = mappingFunctionA.apply(factA); - NewB newB = mappingFunctionB.apply(factA); - NewC newC = mappingFunctionC.apply(factA); - outTuple.factA = newA; - outTuple.factB = newB; - outTuple.factC = newC; + var factA = inTuple.getA(); + var newA = mappingFunctionA.apply(factA); + var newB = mappingFunctionB.apply(factA); + var newC = mappingFunctionC.apply(factA); + outTuple.setA(newA); + outTuple.setB(newB); + outTuple.setC(newC); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToUniNode.java index 0aece3279d..ddfb746543 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/MapUniToUniNode.java @@ -19,17 +19,15 @@ public MapUniToUniNode(int mapStoreIndex, Function mappingFunction, @Override protected UniTuple map(UniTuple tuple) { - A factA = tuple.factA; - return new UniTuple<>( - mappingFunction.apply(factA), - outputStoreSize); + var factA = tuple.getA(); + return UniTuple.of(mappingFunction.apply(factA), outputStoreSize); } @Override protected void remap(UniTuple inTuple, UniTuple outTuple) { - A factA = inTuple.factA; - NewA newA = mappingFunction.apply(factA); - outTuple.factA = newA; + var factA = inTuple.getA(); + var newA = mappingFunction.apply(factA); + outTuple.setA(newA); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/PrecomputeUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/PrecomputeUniNode.java index c849e6ec4d..1d0fc4cfc6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/PrecomputeUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/PrecomputeUniNode.java @@ -23,6 +23,6 @@ public PrecomputeUniNode(Supplier>> preco @Override protected UniTuple remapTuple(UniTuple tuple) { - return new UniTuple<>(tuple.factA, outputStoreSize); + return UniTuple.of(tuple.getA(), outputStoreSize); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/UnindexedIfExistsUniNode.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/UnindexedIfExistsUniNode.java index 6d340c975a..fef6996eba 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/UnindexedIfExistsUniNode.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/uni/UnindexedIfExistsUniNode.java @@ -24,7 +24,7 @@ public UnindexedIfExistsUniNode(boolean shouldExist, TupleLifecycle> @Override protected boolean testFiltering(UniTuple leftTuple, UniTuple rightTuple) { - return filtering.test(leftTuple.factA, rightTuple.factA); + return filtering.test(leftTuple.getA(), rightTuple.getA()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiOriginalMoveIterator.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiOriginalMoveIterator.java index a1fe8b9906..1fbfda4647 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiOriginalMoveIterator.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiOriginalMoveIterator.java @@ -24,7 +24,7 @@ final class BiOriginalMoveIterator implements Iterator> { @SuppressWarnings("rawtypes") - private static final UniTuple EMPTY_TUPLE = new UniTuple<>(null, 0); + private static final UniTuple EMPTY_TUPLE = UniTuple.of(0); private final BiMoveStreamContext context; private final UniLeftDatasetInstance leftDatasetInstance; @@ -75,8 +75,8 @@ public boolean hasNext() { return false; } } else { // Both iterators have elements. - var leftFact = leftTuple.factA; - var rightFact = rightTupleIterator.next().factA; + var leftFact = leftTuple.getA(); + var rightFact = rightTupleIterator.next().getA(); nextMove = context.buildMove(leftFact, rightFact); if (nextMove instanceof ai.timefold.solver.core.impl.heuristic.move.Move legacyMove) { throw new UnsupportedOperationException(""" diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java index b03d8c3e60..1b43c6ca12 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java @@ -91,10 +91,10 @@ private UniqueRandomSequence> computeRightSequence(UniTuple leftT if (filter == null) { // Shortcut: no filter means we can take the entire right dataset as-is. return rightDatasetInstance.buildRandomSequence(compositeKey); } - var leftFact = leftTuple.factA; + var leftFact = leftTuple.getA(); var solutionView = context.neighborhoodSession().getSolutionView(); return rightDatasetInstance.buildRandomSequence(compositeKey, - rightTuple -> filter.test(solutionView, leftFact, rightTuple.factA)); + rightTuple -> filter.test(solutionView, leftFact, rightTuple.getA())); } @Override @@ -128,8 +128,8 @@ private void pickNextMove(UniqueRandomSequence.SequenceElement> left } else { try { var bTuple = rightTupleSequence.remove(workingRandom); - var leftFact = leftTuple.factA; - var rightFact = bTuple.factA; + var leftFact = leftTuple.getA(); + var rightFact = bTuple.getA(); nextMove = context.buildMove(leftFact, rightFact); } catch (NoSuchElementException e) { // We cannot guarantee that the right sequence is empty, because we do not check filtering eagerly. diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/FilteringIterator.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/FilteringIterator.java index c9a7e43fac..7fdd22ac68 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/FilteringIterator.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/FilteringIterator.java @@ -14,7 +14,7 @@ final class FilteringIterator implements Iterator> { @SuppressWarnings("rawtypes") - private static final UniTuple EMPTY_TUPLE = new UniTuple<>(null, 0); + private static final UniTuple EMPTY_TUPLE = UniTuple.of(0); private final SolutionView solutionView; private final BiEnumeratingPredicate filter; @@ -42,10 +42,10 @@ public boolean hasNext() { return true; } - var leftFact = leftTuple.factA; + var leftFact = leftTuple.getA(); while (rightTupleIterator.hasNext()) { var rightTuple = rightTupleIterator.next(); - var rightFact = rightTuple.factA; + var rightFact = rightTuple.getA(); if (filter.test(solutionView, leftFact, rightFact)) { hasNext = true; next = rightTuple; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractDatasetInstance.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractDatasetInstance.java index 1707ee9cd2..15ec0bcba4 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractDatasetInstance.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractDatasetInstance.java @@ -2,13 +2,13 @@ import java.util.Objects; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import org.jspecify.annotations.NullMarked; @NullMarked -public abstract class AbstractDatasetInstance +public abstract class AbstractDatasetInstance implements TupleLifecycle { private final AbstractDataset parent; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java index ff9a91aad6..6398855b96 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java @@ -2,14 +2,14 @@ import java.util.Iterator; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.util.ElementAwareArrayList; import ai.timefold.solver.core.impl.util.ListEntry; import org.jspecify.annotations.NullMarked; @NullMarked -public abstract class AbstractLeftDatasetInstance +public abstract class AbstractLeftDatasetInstance extends AbstractDatasetInstance implements Iterable { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/DataNodeBuildHelper.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/DataNodeBuildHelper.java index 9e2c02f9fb..59098ae3b1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/DataNodeBuildHelper.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/DataNodeBuildHelper.java @@ -7,7 +7,7 @@ import java.util.Set; import ai.timefold.solver.core.impl.bavet.common.AbstractNodeBuildHelper; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; import ai.timefold.solver.core.impl.score.director.SessionContext; @@ -27,7 +27,7 @@ public DataNodeBuildHelper(SessionContext sessionContext, @SuppressWarnings({ "rawtypes", "unchecked" }) @Override - public void putInsertUpdateRetract(AbstractEnumeratingStream stream, + public void putInsertUpdateRetract(AbstractEnumeratingStream stream, TupleLifecycle tupleLifecycle) { super.putInsertUpdateRetract(stream, tupleLifecycle); if (tupleLifecycle instanceof AbstractDatasetInstance datasetInstance) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java index 249b9780a4..4cabd9ca05 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java @@ -19,7 +19,7 @@ public BiScorer(WeightedScoreImpacter weightedScoreImpacter, @Override protected UndoScoreImpacter impact(BiTuple tuple) { try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.factA, tuple.factB); + return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB()); } catch (Exception e) { throw createExceptionOnImpact(tuple, e); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetPrecomputeBuildHelper.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetPrecomputeBuildHelper.java index c61a018cf7..d71956d9b5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetPrecomputeBuildHelper.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetPrecomputeBuildHelper.java @@ -15,15 +15,15 @@ import ai.timefold.solver.core.impl.bavet.common.AbstractNodeBuildHelper; import ai.timefold.solver.core.impl.bavet.common.BavetAbstractConstraintStream; import ai.timefold.solver.core.impl.bavet.common.BavetRootNode; -import ai.timefold.solver.core.impl.bavet.common.tuple.AbstractTuple; import ai.timefold.solver.core.impl.bavet.common.tuple.RecordingTupleLifecycle; +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.domain.variable.declarative.ConsistencyTracker; import ai.timefold.solver.core.impl.score.buildin.SimpleScoreDefinition; import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchPolicy; import ai.timefold.solver.core.impl.score.stream.common.RetrievalSemantics; import ai.timefold.solver.core.impl.score.stream.common.inliner.AbstractScoreInliner; -public final class BavetPrecomputeBuildHelper { +public final class BavetPrecomputeBuildHelper { private final NodeNetwork nodeNetwork; private final RecordingTupleLifecycle recordingTupleLifecycle; private final Class[] sourceClasses; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java index 4a7c2193e5..dd49c5174b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java @@ -19,7 +19,7 @@ public QuadScorer(WeightedScoreImpacter weightedScoreImpacter, @Override protected UndoScoreImpacter impact(QuadTuple tuple) { try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.factA, tuple.factB, tuple.factC, tuple.factD); + return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()); } catch (Exception e) { throw createExceptionOnImpact(tuple, e); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java index e3c843b241..708217e762 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java @@ -19,7 +19,7 @@ public TriScorer(WeightedScoreImpacter weightedScoreImpacter, @Override protected UndoScoreImpacter impact(TriTuple tuple) { try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.factA, tuple.factB, tuple.factC); + return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB(), tuple.getC()); } catch (Exception e) { throw createExceptionOnImpact(tuple, e); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java index aa0f6df71c..55b4486146 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java @@ -20,7 +20,7 @@ public UniScorer(WeightedScoreImpacter weightedScoreImpacter, @Override protected UndoScoreImpacter impact(UniTuple tuple) { try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.factA); + return scoreImpacter.apply(weightedScoreImpacter, tuple.getA()); } catch (Exception e) { throw createExceptionOnImpact(tuple, e); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsAndComparisonIndexerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsAndComparisonIndexerTest.java index 1c2b25f314..561cc691a5 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsAndComparisonIndexerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsAndComparisonIndexerTest.java @@ -61,7 +61,7 @@ void visit() { } private static UniTuple newTuple(String factA) { - return new UniTuple<>(factA, 0); + return UniTuple.of(factA, 0); } } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsIndexerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsIndexerTest.java index f418b7bbb2..6d3dc27bbd 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsIndexerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/EqualsIndexerTest.java @@ -61,7 +61,7 @@ void visit() { } private static UniTuple newTuple(String factA) { - return new UniTuple<>(factA, 0); + return UniTuple.of(factA, 0); } } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessIndexerBackendTest.java b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessIndexerBackendTest.java index 23a50aecf4..c1660ddde7 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessIndexerBackendTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessIndexerBackendTest.java @@ -64,7 +64,7 @@ void visit() { } private static UniTuple newTuple(String factA) { - return new UniTuple<>(factA, 0); + return UniTuple.of(factA, 0); } } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNodeTest.java b/core/src/test/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNodeTest.java index 5ee31af0f8..7d6c26a529 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNodeTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/bavet/uni/FlattenLastUniNodeTest.java @@ -46,11 +46,12 @@ private static List split(String factString) { } private static UniTuple createTuple(String... facts) { - return new UniTuple<>(merge(facts), 1); + String a = merge(facts); + return UniTuple.of(a, 1); } private static UniTuple modifyTuple(UniTuple tuple, String... facts) { - ((UniTuple) tuple).factA = merge(facts); + tuple.setA(merge(facts)); return tuple; } @@ -66,8 +67,8 @@ void insertAndRetract() { Propagator propagator = node.getPropagator(); propagator.propagateEverything(); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "A"))); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "B"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "A"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "B"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -77,8 +78,8 @@ void insertAndRetract() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "B"))); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "C"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "B"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "C"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -87,8 +88,8 @@ void insertAndRetract() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "A"))); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "B"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "A"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "B"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -97,8 +98,8 @@ void insertAndRetract() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "B"))); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "C"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "B"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "C"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -131,10 +132,10 @@ void modify() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "A"))); - verify(downstream).update(argThat(t -> Objects.equals(t.factA, "B"))); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "X"))); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "B"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "A"))); + verify(downstream).update(argThat(t -> Objects.equals(t.getA(), "B"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "X"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "B"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -144,9 +145,9 @@ void modify() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream).retract(argThat(t -> Objects.equals(t.factA, "B"))); - verify(downstream).update(argThat(t -> Objects.equals(t.factA, "C"))); - verify(downstream).insert(argThat(t -> Objects.equals(t.factA, "X"))); + verify(downstream).retract(argThat(t -> Objects.equals(t.getA(), "B"))); + verify(downstream).update(argThat(t -> Objects.equals(t.getA(), "C"))); + verify(downstream).insert(argThat(t -> Objects.equals(t.getA(), "X"))); verifyNoMoreInteractions(downstream); reset(downstream); @@ -156,8 +157,8 @@ void modify() { verifyNoInteractions(downstream); propagator.propagateEverything(); - verify(downstream, times(2)).retract(argThat(t -> Objects.equals(t.factA, "B"))); - verify(downstream).update(argThat(t -> Objects.equals(t.factA, "X"))); + verify(downstream, times(2)).retract(argThat(t -> Objects.equals(t.getA(), "B"))); + verify(downstream).update(argThat(t -> Objects.equals(t.getA(), "X"))); verifyNoMoreInteractions(downstream); } diff --git a/core/src/test/java/ai/timefold/solver/core/preview/api/neighborhood/stream/enumerating/UniEnumeratingStreamTest.java b/core/src/test/java/ai/timefold/solver/core/preview/api/neighborhood/stream/enumerating/UniEnumeratingStreamTest.java index c876b073b9..9c31e73dee 100644 --- a/core/src/test/java/ai/timefold/solver/core/preview/api/neighborhood/stream/enumerating/UniEnumeratingStreamTest.java +++ b/core/src/test/java/ai/timefold/solver/core/preview/api/neighborhood/stream/enumerating/UniEnumeratingStreamTest.java @@ -6,6 +6,7 @@ import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore; import ai.timefold.solver.core.config.solver.EnvironmentMode; +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.neighborhood.stream.enumerating.DatasetSession; import ai.timefold.solver.core.impl.neighborhood.stream.enumerating.DatasetSessionFactory; import ai.timefold.solver.core.impl.neighborhood.stream.enumerating.EnumeratingStreamFactory; @@ -43,7 +44,7 @@ void forEachBasicVariable() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(entity1, entity2); // Make incremental changes. @@ -54,7 +55,7 @@ void forEachBasicVariable() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(entity1, entity3); } @@ -80,7 +81,7 @@ void forEachBasicVariableIncludingNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, entity1, entity2); // Make incremental changes. @@ -91,7 +92,7 @@ void forEachBasicVariableIncludingNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, entity1, entity3); } @@ -112,7 +113,7 @@ void forEachListVariable() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(entity1, entity2); // Make incremental changes. @@ -123,7 +124,7 @@ void forEachListVariable() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(entity1, entity3); } @@ -144,7 +145,7 @@ void forEachListVariableIncludingNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, entity1, entity2); // Make incremental changes. @@ -155,7 +156,7 @@ void forEachListVariableIncludingNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, entity1, entity3); } @@ -205,7 +206,7 @@ void forEachListVariableIncludingPinned() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(fullyPinnedEntity, partiallyPinnedEntity, unpinnedEntity); // Make incremental changes. @@ -217,7 +218,7 @@ void forEachListVariableIncludingPinned() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(fullyPinnedEntity, unpinnedEntity, entity4); } @@ -249,7 +250,7 @@ void forEachListVariableIncludingPinnedAndNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, fullyPinnedEntity, partiallyPinnedEntity, unpinnedEntity); // Make incremental changes. @@ -261,7 +262,7 @@ void forEachListVariableIncludingPinnedAndNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, fullyPinnedEntity, unpinnedEntity, entity4); } @@ -294,7 +295,7 @@ void forEachListVariableExcludingPinned() { // Entities with planningPin true wi assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(partiallyPinnedEntity, unpinnedEntity); // Make incremental changes. @@ -306,7 +307,7 @@ void forEachListVariableExcludingPinned() { // Entities with planningPin true wi assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(unpinnedEntity); } @@ -339,7 +340,7 @@ void forEachListVariableExcludingPinnedIncludingNull() { // Entities with planni assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, partiallyPinnedEntity, unpinnedEntity); // Make incremental changes. @@ -351,7 +352,7 @@ void forEachListVariableExcludingPinnedIncludingNull() { // Entities with planni assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, unpinnedEntity); } @@ -393,7 +394,7 @@ void forEachListVariableIncludingPinnedValues() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(value1, value2, value3, value4, unassignedValue); } @@ -435,7 +436,7 @@ void forEachListVariableIncludingPinnedValuesAndNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, value1, value2, value3, value4, unassignedValue); } @@ -479,7 +480,7 @@ void forEachListVariableExcludingPinnedValues() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(value2, value3, value4); } @@ -523,7 +524,7 @@ void forEachListVariableExcludingPinnedValuesIncludingNull() { assertThat(uniDatasetInstance.iterator()) .toIterable() - .map(t -> t.factA) + .map(UniTuple::getA) .containsExactly(null, value2, value3, value4); } From 6eda9f8e2c1746092a6963321c9ac1f9f712be16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Sat, 20 Dec 2025 20:12:02 +0100 Subject: [PATCH 02/10] perf: refactor scoring to use tuples on the outside --- .../impl/bavet/common/AbstractScorer.java | 69 --------- .../bi/BavetScoringBiConstraintStream.java | 139 ++---------------- .../bavet/bi/BiBigDecimalImpactHandler.java | 37 +++++ .../stream/bavet/bi/BiImpactHandler.java | 17 +++ .../stream/bavet/bi/BiIntImpactHandler.java | 36 +++++ .../stream/bavet/bi/BiLongImpactHandler.java | 36 +++++ .../stream/bavet/bi/BiScoreImpacter.java | 16 ++ .../impl/score/stream/bavet/bi/BiScorer.java | 27 ---- .../common/BavetScoringConstraintStream.java | 23 --- .../stream/bavet/common/ImpactHandler.java | 39 +++++ .../stream/bavet/common/ScoreImpacter.java | 16 ++ .../score/stream/bavet/common/Scorer.java | 74 ++++++++++ .../BavetScoringQuadConstraintStream.java | 139 ++---------------- .../quad/QuadBigDecimalImpactHandler.java | 42 ++++++ .../stream/bavet/quad/QuadImpactHandler.java | 17 +++ .../bavet/quad/QuadIntImpactHandler.java | 40 +++++ .../bavet/quad/QuadLongImpactHandler.java | 40 +++++ .../stream/bavet/quad/QuadScoreImpacter.java | 16 ++ .../score/stream/bavet/quad/QuadScorer.java | 27 ---- .../tri/BavetScoringTriConstraintStream.java | 139 ++---------------- .../bavet/tri/TriBigDecimalImpactHandler.java | 40 +++++ .../stream/bavet/tri/TriImpactHandler.java | 17 +++ .../stream/bavet/tri/TriIntImpactHandler.java | 38 +++++ .../bavet/tri/TriLongImpactHandler.java | 38 +++++ .../stream/bavet/tri/TriScoreImpacter.java | 16 ++ .../score/stream/bavet/tri/TriScorer.java | 27 ---- .../uni/BavetScoringUniConstraintStream.java | 139 ++---------------- .../bavet/uni/UniBigDecimalImpactHandler.java | 34 +++++ .../stream/bavet/uni/UniImpactHandler.java | 17 +++ .../stream/bavet/uni/UniIntImpactHandler.java | 33 +++++ .../bavet/uni/UniLongImpactHandler.java | 33 +++++ .../stream/bavet/uni/UniScoreImpacter.java | 16 ++ .../score/stream/bavet/uni/UniScorer.java | 28 ---- 33 files changed, 756 insertions(+), 709 deletions(-) delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScoreImpacter.java delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScoreImpacter.java delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScoreImpacter.java delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScoreImpacter.java delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java deleted file mode 100644 index c5e4c35e54..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractScorer.java +++ /dev/null @@ -1,69 +0,0 @@ -package ai.timefold.solver.core.impl.bavet.common; - -import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; -import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; - -public abstract class AbstractScorer implements TupleLifecycle { - - protected final WeightedScoreImpacter weightedScoreImpacter; - private final int inputStoreIndex; - - protected AbstractScorer(WeightedScoreImpacter weightedScoreImpacter, int inputStoreIndex) { - this.weightedScoreImpacter = weightedScoreImpacter; - this.inputStoreIndex = inputStoreIndex; - } - - @Override - public final void insert(Tuple_ tuple) { - if (tuple.getStore(inputStoreIndex) != null) { - throw new IllegalStateException("Impossible state: the input for the tuple (" + tuple - + ") was already added in the tupleStore."); - } - tuple.setStore(inputStoreIndex, impact(tuple)); - } - - @Override - public final void update(Tuple_ tuple) { - UndoScoreImpacter undoScoreImpacter = tuple.getStore(inputStoreIndex); - // No fail fast if null because we don't track which tuples made it through the filter predicate(s) - if (undoScoreImpacter != null) { - undoScoreImpacter.run(); - } - tuple.setStore(inputStoreIndex, impact(tuple)); - } - - protected abstract UndoScoreImpacter impact(Tuple_ tuple); - - /** - * Helps with debugging exceptions thrown by user code during impact calls. - * - * @param tuple never null - * @param cause never null - * @return never null, exception to be thrown. - */ - protected RuntimeException createExceptionOnImpact(Tuple_ tuple, Exception cause) { - return new IllegalStateException( - "Consequence of a constraint (" + weightedScoreImpacter.getContext().getConstraint().getConstraintRef() - + ") threw an exception processing a tuple (" + tuple + ").", - cause); - } - - @Override - public final void retract(Tuple_ tuple) { - UndoScoreImpacter undoScoreImpacter = tuple.getStore(inputStoreIndex); - // No fail fast if null because we don't track which tuples made it through the filter predicate(s) - if (undoScoreImpacter != null) { - undoScoreImpacter.run(); - tuple.setStore(inputStoreIndex, null); - } - } - - @Override - public final String toString() { - return getClass().getSimpleName() + "(" + weightedScoreImpacter.getContext().getConstraint().getConstraintRef() - + ") with constraintWeight (" + weightedScoreImpacter.getContext().getConstraintWeight() + ")"; - } - -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BavetScoringBiConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BavetScoringBiConstraintStream.java index e508269cac..89bc1bb775 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BavetScoringBiConstraintStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BavetScoringBiConstraintStream.java @@ -1,63 +1,41 @@ package ai.timefold.solver.core.impl.score.stream.bavet.bi; -import static ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream.impactWithConstraintMatchNoJustifications; - import java.math.BigDecimal; import java.util.function.BiFunction; import java.util.function.ToIntBiFunction; import java.util.function.ToLongBiFunction; -import ai.timefold.solver.core.api.function.TriFunction; import ai.timefold.solver.core.api.score.Score; import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchPolicy; import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraint; import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraintFactory; import ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream; import ai.timefold.solver.core.impl.score.stream.bavet.common.ConstraintNodeBuildHelper; -import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.bavet.common.Scorer; final class BavetScoringBiConstraintStream extends BavetAbstractBiConstraintStream implements BavetScoringConstraintStream { - private final ToIntBiFunction intMatchWeigher; - private final ToLongBiFunction longMatchWeigher; - private final BiFunction bigDecimalMatchWeigher; + private final BiImpactHandler scoreImpact; private BavetConstraint constraint; public BavetScoringBiConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractBiConstraintStream parent, ToIntBiFunction intMatchWeigher) { - this(constraintFactory, parent, intMatchWeigher, null, null); - if (intMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new BiIntImpactHandler<>(intMatchWeigher); } public BavetScoringBiConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractBiConstraintStream parent, ToLongBiFunction longMatchWeigher) { - this(constraintFactory, parent, null, longMatchWeigher, null); - if (longMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new BiLongImpactHandler<>(longMatchWeigher); } public BavetScoringBiConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractBiConstraintStream parent, BiFunction bigDecimalMatchWeigher) { - this(constraintFactory, parent, null, null, bigDecimalMatchWeigher); - if (bigDecimalMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } - } - - private BavetScoringBiConstraintStream(BavetConstraintFactory constraintFactory, - BavetAbstractBiConstraintStream parent, ToIntBiFunction intMatchWeigher, - ToLongBiFunction longMatchWeigher, BiFunction bigDecimalMatchWeigher) { super(constraintFactory, parent); - this.intMatchWeigher = intMatchWeigher; - this.longMatchWeigher = longMatchWeigher; - this.bigDecimalMatchWeigher = bigDecimalMatchWeigher; + this.scoreImpact = new BiBigDecimalImpactHandler<>(bigDecimalMatchWeigher); } @Override @@ -74,108 +52,19 @@ public > void buildNode(ConstraintNodeBuildHelper(weightedScoreImpacter, scoreImpacter, + var scorer = new Scorer<>(scoreImpacter, weightedScoreImpacter, buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); buildHelper.putInsertUpdateRetract(this, scorer); } - private TriFunction, A, B, UndoScoreImpacter> - buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { + private BiScoreImpacter buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { return switch (constraintMatchPolicy) { - case DISABLED -> buildScoreImpacter(); - case ENABLED -> buildScoreImpacterWithConstraintMatch(); - case ENABLED_WITHOUT_JUSTIFICATIONS -> buildScoreImpacterWithConstraintMatchNoJustifications(); + case DISABLED -> scoreImpact::impactNaked; + case ENABLED -> scoreImpact::impactFull; + case ENABLED_WITHOUT_JUSTIFICATIONS -> scoreImpact::impactWithoutJustification; }; } - private TriFunction, A, B, UndoScoreImpacter> buildScoreImpacter() { - if (intMatchWeigher != null) { - return (impacter, a, b) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b); - return impacter.impactScore(matchWeight, null); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b); - return impacter.impactScore(matchWeight, null); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b); - return impacter.impactScore(matchWeight, null); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private TriFunction, A, B, UndoScoreImpacter> buildScoreImpacterWithConstraintMatch() { - if (intMatchWeigher != null) { - return (impacter, a, b) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b); - return impactWithConstraintMatch(impacter, matchWeight, a, b); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b); - return impactWithConstraintMatch(impacter, matchWeight, a, b); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b); - return impactWithConstraintMatch(impacter, matchWeight, a, b); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, int matchWeight, A a, B b) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, long matchWeight, A a, B b) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, BigDecimal matchWeight, A a, B b) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private TriFunction, A, B, UndoScoreImpacter> - buildScoreImpacterWithConstraintMatchNoJustifications() { - if (intMatchWeigher != null) { - return (impacter, a, b) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - // ************************************************************************ // Equality for node sharing // ************************************************************************ @@ -187,8 +76,4 @@ public String toString() { return "Scoring(" + constraint.getConstraintRef() + ")"; } - // ************************************************************************ - // Getters/setters - // ************************************************************************ - } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java new file mode 100644 index 0000000000..6613bfaa66 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java @@ -0,0 +1,37 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.bi; + +import java.math.BigDecimal; +import java.util.function.BiFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record BiBigDecimalImpactHandler(BiFunction matchWeigher) + implements + BiImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.apply(a, b), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiImpactHandler.java new file mode 100644 index 0000000000..d54c0a1d01 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiImpactHandler.java @@ -0,0 +1,17 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.bi; + +import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ImpactHandler; + +import org.jspecify.annotations.NullMarked; + +/** + * A {@link BiTuple}-specific version of {@link ImpactHandler}. + * The methods (inherited from {@link ImpactHandler}) match the signature of {@link BiScoreImpacter}. + */ +@NullMarked +sealed interface BiImpactHandler + extends ImpactHandler> + permits BiBigDecimalImpactHandler, BiIntImpactHandler, BiLongImpactHandler { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java new file mode 100644 index 0000000000..b1ba18d2f0 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java @@ -0,0 +1,36 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.bi; + +import java.util.function.ToIntBiFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record BiIntImpactHandler(ToIntBiFunction matchWeigher) + implements + BiImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB()), null); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsInt(a, b), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b)); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java new file mode 100644 index 0000000000..d1b9586bd4 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java @@ -0,0 +1,36 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.bi; + +import java.util.function.ToLongBiFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record BiLongImpactHandler(ToLongBiFunction matchWeigher) + implements + BiImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB()), null); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsLong(a, b), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b)); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScoreImpacter.java new file mode 100644 index 0000000000..c01fb3f7e0 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScoreImpacter.java @@ -0,0 +1,16 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.bi; + +import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +/** + * Instances are provided by {@link BiImpactHandler}. + */ +@NullMarked +@FunctionalInterface +public interface BiScoreImpacter + extends ScoreImpacter> { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java deleted file mode 100644 index 4cabd9ca05..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiScorer.java +++ /dev/null @@ -1,27 +0,0 @@ -package ai.timefold.solver.core.impl.score.stream.bavet.bi; - -import ai.timefold.solver.core.api.function.TriFunction; -import ai.timefold.solver.core.impl.bavet.common.AbstractScorer; -import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; - -final class BiScorer extends AbstractScorer> { - - private final TriFunction, A, B, UndoScoreImpacter> scoreImpacter; - - public BiScorer(WeightedScoreImpacter weightedScoreImpacter, - TriFunction, A, B, UndoScoreImpacter> scoreImpacter, int inputStoreIndex) { - super(weightedScoreImpacter, inputStoreIndex); - this.scoreImpacter = scoreImpacter; - } - - @Override - protected UndoScoreImpacter impact(BiTuple tuple) { - try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB()); - } catch (Exception e) { - throw createExceptionOnImpact(tuple, e); - } - } -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetScoringConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetScoringConstraintStream.java index 7518927884..d26c5d1455 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetScoringConstraintStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/BavetScoringConstraintStream.java @@ -1,14 +1,9 @@ package ai.timefold.solver.core.impl.score.stream.bavet.common; -import java.math.BigDecimal; import java.util.Set; -import ai.timefold.solver.core.api.score.Score; import ai.timefold.solver.core.impl.bavet.common.BavetAbstractConstraintStream; import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraint; -import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; public interface BavetScoringConstraintStream { @@ -16,22 +11,4 @@ public interface BavetScoringConstraintStream { void collectActiveConstraintStreams(Set> constraintStreamSet); - static > UndoScoreImpacter - impactWithConstraintMatchNoJustifications(WeightedScoreImpacter impacter, int matchWeight) { - var constraintMatchSupplier = ConstraintMatchSupplier. empty(); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - static > UndoScoreImpacter - impactWithConstraintMatchNoJustifications(WeightedScoreImpacter impacter, long matchWeight) { - var constraintMatchSupplier = ConstraintMatchSupplier. empty(); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - static > UndoScoreImpacter - impactWithConstraintMatchNoJustifications(WeightedScoreImpacter impacter, BigDecimal matchWeight) { - var constraintMatchSupplier = ConstraintMatchSupplier. empty(); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java new file mode 100644 index 0000000000..bb4841e4a8 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java @@ -0,0 +1,39 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.common; + +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +public interface ImpactHandler { + + /** + * Impacts the score, providing neither constraint match information, neither justification for it. + * + * @param impacter knows which level(s) of the score to impact, and using which type of number + * @param tuple the tuple that triggered the impact + * @return run to undo the impact + */ + UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, Tuple_ tuple); + + /** + * Impacts the score, providing constraint match information but justification for it. + * + * @param impacter knows which level(s) of the score to impact, and using which type of number + * @param tuple the tuple that triggered the impact + * @return run to undo the impact + */ + UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, Tuple_ tuple); + + /** + * Impacts the score, providing all available metadata. + * + * @param impacter knows which level(s) of the score to impact, and using which type of number + * @param tuple the tuple that triggered the impact + * @return run to undo the impact + */ + UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, Tuple_ tuple); + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java new file mode 100644 index 0000000000..6573fd54da --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java @@ -0,0 +1,16 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.common; + +import java.util.function.BiFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +@FunctionalInterface +public interface ScoreImpacter + extends BiFunction, Tuple_, UndoScoreImpacter> { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java new file mode 100644 index 0000000000..2425921d55 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java @@ -0,0 +1,74 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.common; + +import java.util.Objects; + +import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; +import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +public final class Scorer implements TupleLifecycle { + + private final ScoreImpacter scoreImpacter; + private final WeightedScoreImpacter weightedScoreImpacter; + private final int inputStoreIndex; + + public Scorer(ScoreImpacter scoreImpacter, WeightedScoreImpacter weightedScoreImpacter, int inputStoreIndex) { + this.scoreImpacter = Objects.requireNonNull(scoreImpacter); + this.weightedScoreImpacter = Objects.requireNonNull(weightedScoreImpacter); + this.inputStoreIndex = inputStoreIndex; + } + + @Override + public void insert(Tuple_ tuple) { + if (tuple.getStore(inputStoreIndex) != null) { + throw new IllegalStateException( + "Impossible state: the input for the tuple (%s) was already added in the tupleStore." + .formatted(tuple)); + } + tuple.setStore(inputStoreIndex, impact(tuple)); + } + + @Override + public void update(Tuple_ tuple) { + UndoScoreImpacter undoScoreImpacter = tuple.getStore(inputStoreIndex); + // No fail fast if null because we don't track which tuples made it through the filter predicate(s) + if (undoScoreImpacter != null) { + undoScoreImpacter.run(); + } + tuple.setStore(inputStoreIndex, impact(tuple)); + } + + public UndoScoreImpacter impact(Tuple_ tuple) { + try { + return scoreImpacter.apply(weightedScoreImpacter, tuple); + } catch (Exception e) { + // Helps with debugging exceptions thrown by user code during impact calls. + throw new IllegalStateException( + "Consequence of a constraint (%s) threw an exception processing a tuple (%s)." + .formatted(weightedScoreImpacter.getContext().getConstraint().getConstraintRef(), tuple), + e); + } + } + + @Override + public void retract(Tuple_ tuple) { + UndoScoreImpacter undoScoreImpacter = tuple.removeStore(inputStoreIndex); + // No fail fast if null because we don't track which tuples made it through the filter predicate(s) + if (undoScoreImpacter != null) { + undoScoreImpacter.run(); + } + } + + @Override + public String toString() { + var context = weightedScoreImpacter.getContext(); + return "%s(%s) with constraintWeight (%s)" + .formatted(getClass().getSimpleName(), context.getConstraint().getConstraintRef(), + context.getConstraintWeight()); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/BavetScoringQuadConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/BavetScoringQuadConstraintStream.java index 2acade862b..51b401cbd2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/BavetScoringQuadConstraintStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/BavetScoringQuadConstraintStream.java @@ -1,10 +1,7 @@ package ai.timefold.solver.core.impl.score.stream.bavet.quad; -import static ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream.impactWithConstraintMatchNoJustifications; - import java.math.BigDecimal; -import ai.timefold.solver.core.api.function.PentaFunction; import ai.timefold.solver.core.api.function.QuadFunction; import ai.timefold.solver.core.api.function.ToIntQuadFunction; import ai.timefold.solver.core.api.function.ToLongQuadFunction; @@ -14,51 +11,32 @@ import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraintFactory; import ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream; import ai.timefold.solver.core.impl.score.stream.bavet.common.ConstraintNodeBuildHelper; -import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.bavet.common.Scorer; final class BavetScoringQuadConstraintStream extends BavetAbstractQuadConstraintStream implements BavetScoringConstraintStream { - private final ToIntQuadFunction intMatchWeigher; - private final ToLongQuadFunction longMatchWeigher; - private final QuadFunction bigDecimalMatchWeigher; + private final QuadImpactHandler scoreImpact; private BavetConstraint constraint; public BavetScoringQuadConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractQuadConstraintStream parent, ToIntQuadFunction intMatchWeigher) { - this(constraintFactory, parent, intMatchWeigher, null, null); - if (intMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new QuadIntImpactHandler<>(intMatchWeigher); } public BavetScoringQuadConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractQuadConstraintStream parent, ToLongQuadFunction longMatchWeigher) { - this(constraintFactory, parent, null, longMatchWeigher, null); - if (longMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new QuadLongImpactHandler<>(longMatchWeigher); } public BavetScoringQuadConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractQuadConstraintStream parent, QuadFunction bigDecimalMatchWeigher) { - this(constraintFactory, parent, null, null, bigDecimalMatchWeigher); - if (bigDecimalMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } - } - - private BavetScoringQuadConstraintStream(BavetConstraintFactory constraintFactory, - BavetAbstractQuadConstraintStream parent, ToIntQuadFunction intMatchWeigher, - ToLongQuadFunction longMatchWeigher, QuadFunction bigDecimalMatchWeigher) { super(constraintFactory, parent); - this.intMatchWeigher = intMatchWeigher; - this.longMatchWeigher = longMatchWeigher; - this.bigDecimalMatchWeigher = bigDecimalMatchWeigher; + this.scoreImpact = new QuadBigDecimalImpactHandler<>(bigDecimalMatchWeigher); } @Override @@ -75,108 +53,19 @@ public > void buildNode(ConstraintNodeBuildHelper(weightedScoreImpacter, scoreImpacter, + var scorer = new Scorer<>(scoreImpacter, weightedScoreImpacter, buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); buildHelper.putInsertUpdateRetract(this, scorer); } - private PentaFunction, A, B, C, D, UndoScoreImpacter> - buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { + private QuadScoreImpacter buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { return switch (constraintMatchPolicy) { - case DISABLED -> buildScoreImpacter(); - case ENABLED -> buildScoreImpacterWithConstraintMatch(); - case ENABLED_WITHOUT_JUSTIFICATIONS -> buildScoreImpacterWithConstraintMatchNoJustifications(); + case DISABLED -> scoreImpact::impactNaked; + case ENABLED -> scoreImpact::impactFull; + case ENABLED_WITHOUT_JUSTIFICATIONS -> scoreImpact::impactWithoutJustification; }; } - private PentaFunction, A, B, C, D, UndoScoreImpacter> buildScoreImpacter() { - if (intMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c, d); - return impacter.impactScore(matchWeight, null); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c, d); - return impacter.impactScore(matchWeight, null); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c, d); - return impacter.impactScore(matchWeight, null); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private PentaFunction, A, B, C, D, UndoScoreImpacter> buildScoreImpacterWithConstraintMatch() { - if (intMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c, d); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c, d); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c, d); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c, d); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c, d); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c, d); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, int matchWeight, A a, B b, C c, D d) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c, d); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, long matchWeight, A a, B b, C c, D d) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c, d); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, BigDecimal matchWeight, A a, B b, C c, D d) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c, d); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private PentaFunction, A, B, C, D, UndoScoreImpacter> - buildScoreImpacterWithConstraintMatchNoJustifications() { - if (intMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c, d); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c, d); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c, d) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c, d); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - // ************************************************************************ // Equality for node sharing // ************************************************************************ @@ -188,8 +77,4 @@ public String toString() { return "Scoring(" + constraint.getConstraintRef() + ")"; } - // ************************************************************************ - // Getters/setters - // ************************************************************************ - } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java new file mode 100644 index 0000000000..4552ef4429 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java @@ -0,0 +1,42 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.quad; + +import java.math.BigDecimal; + +import ai.timefold.solver.core.api.function.QuadFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record QuadBigDecimalImpactHandler(QuadFunction matchWeigher) + implements + QuadImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + QuadTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), + ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.apply(a, b, c, d), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c, d)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadImpactHandler.java new file mode 100644 index 0000000000..90d50b5d12 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadImpactHandler.java @@ -0,0 +1,17 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.quad; + +import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ImpactHandler; + +import org.jspecify.annotations.NullMarked; + +/** + * A {@link QuadTuple}-specific version of {@link ImpactHandler}. + * The methods (inherited from {@link ImpactHandler}) match the signature of {@link QuadScoreImpacter}. + */ +@NullMarked +sealed interface QuadImpactHandler + extends ImpactHandler> + permits QuadBigDecimalImpactHandler, QuadIntImpactHandler, QuadLongImpactHandler { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java new file mode 100644 index 0000000000..966c3b2a40 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java @@ -0,0 +1,40 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.quad; + +import ai.timefold.solver.core.api.function.ToIntQuadFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record QuadIntImpactHandler(ToIntQuadFunction matchWeigher) + implements + QuadImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + QuadTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), + ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsInt(a, b, c, d), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c, d)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java new file mode 100644 index 0000000000..74a475890e --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java @@ -0,0 +1,40 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.quad; + +import ai.timefold.solver.core.api.function.ToLongQuadFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record QuadLongImpactHandler(ToLongQuadFunction matchWeigher) + implements + QuadImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + QuadTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), + ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var d = tuple.getD(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsLong(a, b, c, d), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c, d)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScoreImpacter.java new file mode 100644 index 0000000000..27693a66cb --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScoreImpacter.java @@ -0,0 +1,16 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.quad; + +import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +/** + * Instances are provided by {@link QuadImpactHandler}. + */ +@NullMarked +@FunctionalInterface +public interface QuadScoreImpacter + extends ScoreImpacter> { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java deleted file mode 100644 index dd49c5174b..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadScorer.java +++ /dev/null @@ -1,27 +0,0 @@ -package ai.timefold.solver.core.impl.score.stream.bavet.quad; - -import ai.timefold.solver.core.api.function.PentaFunction; -import ai.timefold.solver.core.impl.bavet.common.AbstractScorer; -import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; - -final class QuadScorer extends AbstractScorer> { - - private final PentaFunction, A, B, C, D, UndoScoreImpacter> scoreImpacter; - - public QuadScorer(WeightedScoreImpacter weightedScoreImpacter, - PentaFunction, A, B, C, D, UndoScoreImpacter> scoreImpacter, int inputStoreIndex) { - super(weightedScoreImpacter, inputStoreIndex); - this.scoreImpacter = scoreImpacter; - } - - @Override - protected UndoScoreImpacter impact(QuadTuple tuple) { - try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()); - } catch (Exception e) { - throw createExceptionOnImpact(tuple, e); - } - } -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/BavetScoringTriConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/BavetScoringTriConstraintStream.java index c8e2c28201..86b54c0430 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/BavetScoringTriConstraintStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/BavetScoringTriConstraintStream.java @@ -1,10 +1,7 @@ package ai.timefold.solver.core.impl.score.stream.bavet.tri; -import static ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream.impactWithConstraintMatchNoJustifications; - import java.math.BigDecimal; -import ai.timefold.solver.core.api.function.QuadFunction; import ai.timefold.solver.core.api.function.ToIntTriFunction; import ai.timefold.solver.core.api.function.ToLongTriFunction; import ai.timefold.solver.core.api.function.TriFunction; @@ -14,51 +11,32 @@ import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraintFactory; import ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream; import ai.timefold.solver.core.impl.score.stream.bavet.common.ConstraintNodeBuildHelper; -import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.bavet.common.Scorer; final class BavetScoringTriConstraintStream extends BavetAbstractTriConstraintStream implements BavetScoringConstraintStream { - private final ToIntTriFunction intMatchWeigher; - private final ToLongTriFunction longMatchWeigher; - private final TriFunction bigDecimalMatchWeigher; + private final TriImpactHandler scoreImpact; private BavetConstraint constraint; public BavetScoringTriConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractTriConstraintStream parent, ToIntTriFunction intMatchWeigher) { - this(constraintFactory, parent, intMatchWeigher, null, null); - if (intMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new TriIntImpactHandler<>(intMatchWeigher); } public BavetScoringTriConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractTriConstraintStream parent, ToLongTriFunction longMatchWeigher) { - this(constraintFactory, parent, null, longMatchWeigher, null); - if (longMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new TriLongImpactHandler<>(longMatchWeigher); } public BavetScoringTriConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractTriConstraintStream parent, TriFunction bigDecimalMatchWeigher) { - this(constraintFactory, parent, null, null, bigDecimalMatchWeigher); - if (bigDecimalMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } - } - - private BavetScoringTriConstraintStream(BavetConstraintFactory constraintFactory, - BavetAbstractTriConstraintStream parent, ToIntTriFunction intMatchWeigher, - ToLongTriFunction longMatchWeigher, TriFunction bigDecimalMatchWeigher) { super(constraintFactory, parent); - this.intMatchWeigher = intMatchWeigher; - this.longMatchWeigher = longMatchWeigher; - this.bigDecimalMatchWeigher = bigDecimalMatchWeigher; + this.scoreImpact = new TriBigDecimalImpactHandler<>(bigDecimalMatchWeigher); } @Override @@ -75,108 +53,19 @@ public > void buildNode(ConstraintNodeBuildHelper(weightedScoreImpacter, scoreImpacter, + var scorer = new Scorer<>(scoreImpacter, weightedScoreImpacter, buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); buildHelper.putInsertUpdateRetract(this, scorer); } - private QuadFunction, A, B, C, UndoScoreImpacter> - buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { + private TriScoreImpacter buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { return switch (constraintMatchPolicy) { - case DISABLED -> buildScoreImpacter(); - case ENABLED -> buildScoreImpacterWithConstraintMatch(); - case ENABLED_WITHOUT_JUSTIFICATIONS -> buildScoreImpacterWithConstraintMatchNoJustifications(); + case DISABLED -> scoreImpact::impactNaked; + case ENABLED -> scoreImpact::impactFull; + case ENABLED_WITHOUT_JUSTIFICATIONS -> scoreImpact::impactWithoutJustification; }; } - private QuadFunction, A, B, C, UndoScoreImpacter> buildScoreImpacter() { - if (intMatchWeigher != null) { - return (impacter, a, b, c) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c); - return impacter.impactScore(matchWeight, null); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c); - return impacter.impactScore(matchWeight, null); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c); - return impacter.impactScore(matchWeight, null); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private QuadFunction, A, B, C, UndoScoreImpacter> buildScoreImpacterWithConstraintMatch() { - if (intMatchWeigher != null) { - return (impacter, a, b, c) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c); - return impactWithConstraintMatch(impacter, matchWeight, a, b, c); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, int matchWeight, A a, B b, C c) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, long matchWeight, A a, B b, C c) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, BigDecimal matchWeight, A a, B b, C c) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a, b, c); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private QuadFunction, A, B, C, UndoScoreImpacter> - buildScoreImpacterWithConstraintMatchNoJustifications() { - if (intMatchWeigher != null) { - return (impacter, a, b, c) -> { - int matchWeight = intMatchWeigher.applyAsInt(a, b, c); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (longMatchWeigher != null) { - return (impacter, a, b, c) -> { - long matchWeight = longMatchWeigher.applyAsLong(a, b, c); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a, b, c) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a, b, c); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - // ************************************************************************ // Equality for node sharing // ************************************************************************ @@ -188,8 +77,4 @@ public String toString() { return "Scoring(" + constraint.getConstraintRef() + ")"; } - // ************************************************************************ - // Getters/setters - // ************************************************************************ - } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java new file mode 100644 index 0000000000..1cd9bad5ff --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java @@ -0,0 +1,40 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.tri; + +import java.math.BigDecimal; + +import ai.timefold.solver.core.api.function.TriFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record TriBigDecimalImpactHandler(TriFunction matchWeigher) + implements + TriImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC()), null); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.apply(a, b, c), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c)); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC()), + ConstraintMatchSupplier.empty()); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriImpactHandler.java new file mode 100644 index 0000000000..a1ddabd498 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriImpactHandler.java @@ -0,0 +1,17 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.tri; + +import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ImpactHandler; + +import org.jspecify.annotations.NullMarked; + +/** + * A {@link TriTuple}-specific version of {@link ImpactHandler}. + * The methods (inherited from {@link ImpactHandler}) match the signature of {@link TriScoreImpacter}. + */ +@NullMarked +sealed interface TriImpactHandler + extends ImpactHandler> + permits TriBigDecimalImpactHandler, TriIntImpactHandler, TriLongImpactHandler { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java new file mode 100644 index 0000000000..ba2c92251f --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java @@ -0,0 +1,38 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.tri; + +import ai.timefold.solver.core.api.function.ToIntTriFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record TriIntImpactHandler(ToIntTriFunction matchWeigher) + implements + TriImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC()), + ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + var a = tuple.getA(); + var b = tuple.getB(); + var c = tuple.getC(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsInt(a, b, c), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java new file mode 100644 index 0000000000..86b3c5be3e --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java @@ -0,0 +1,38 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.tri; + +import ai.timefold.solver.core.api.function.ToLongTriFunction; +import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record TriLongImpactHandler(ToLongTriFunction matchWeigher) + implements + TriImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC()), + ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + var a = tuple.getA(); + B b = tuple.getB(); + C c = tuple.getC(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsLong(a, b, c), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a, b, + c)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScoreImpacter.java new file mode 100644 index 0000000000..1770d81c96 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScoreImpacter.java @@ -0,0 +1,16 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.tri; + +import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +/** + * Instances are provided by {@link TriImpactHandler}. + */ +@NullMarked +@FunctionalInterface +public interface TriScoreImpacter + extends ScoreImpacter> { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java deleted file mode 100644 index 708217e762..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriScorer.java +++ /dev/null @@ -1,27 +0,0 @@ -package ai.timefold.solver.core.impl.score.stream.bavet.tri; - -import ai.timefold.solver.core.api.function.QuadFunction; -import ai.timefold.solver.core.impl.bavet.common.AbstractScorer; -import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; - -final class TriScorer extends AbstractScorer> { - - private final QuadFunction, A, B, C, UndoScoreImpacter> scoreImpacter; - - public TriScorer(WeightedScoreImpacter weightedScoreImpacter, - QuadFunction, A, B, C, UndoScoreImpacter> scoreImpacter, int inputStoreIndex) { - super(weightedScoreImpacter, inputStoreIndex); - this.scoreImpacter = scoreImpacter; - } - - @Override - protected UndoScoreImpacter impact(TriTuple tuple) { - try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.getA(), tuple.getB(), tuple.getC()); - } catch (Exception e) { - throw createExceptionOnImpact(tuple, e); - } - } -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/BavetScoringUniConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/BavetScoringUniConstraintStream.java index 0dd7ca1ba0..6df32b620e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/BavetScoringUniConstraintStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/BavetScoringUniConstraintStream.java @@ -1,9 +1,6 @@ package ai.timefold.solver.core.impl.score.stream.bavet.uni; -import static ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream.impactWithConstraintMatchNoJustifications; - import java.math.BigDecimal; -import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; @@ -14,50 +11,31 @@ import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraintFactory; import ai.timefold.solver.core.impl.score.stream.bavet.common.BavetScoringConstraintStream; import ai.timefold.solver.core.impl.score.stream.bavet.common.ConstraintNodeBuildHelper; -import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.bavet.common.Scorer; final class BavetScoringUniConstraintStream extends BavetAbstractUniConstraintStream implements BavetScoringConstraintStream { - private final ToIntFunction intMatchWeigher; - private final ToLongFunction longMatchWeigher; - private final Function bigDecimalMatchWeigher; + private final UniImpactHandler scoreImpact; private BavetConstraint constraint; public BavetScoringUniConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractUniConstraintStream parent, ToIntFunction intMatchWeigher) { - this(constraintFactory, parent, intMatchWeigher, null, null); - if (intMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new UniIntImpactHandler<>(intMatchWeigher); } public BavetScoringUniConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractUniConstraintStream parent, ToLongFunction longMatchWeigher) { - this(constraintFactory, parent, null, longMatchWeigher, null); - if (longMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } + super(constraintFactory, parent); + this.scoreImpact = new UniLongImpactHandler<>(longMatchWeigher); } public BavetScoringUniConstraintStream(BavetConstraintFactory constraintFactory, BavetAbstractUniConstraintStream parent, Function bigDecimalMatchWeigher) { - this(constraintFactory, parent, null, null, bigDecimalMatchWeigher); - if (bigDecimalMatchWeigher == null) { - throw new IllegalArgumentException("The matchWeigher (null) cannot be null."); - } - } - - private BavetScoringUniConstraintStream(BavetConstraintFactory constraintFactory, - BavetAbstractUniConstraintStream parent, ToIntFunction intMatchWeigher, - ToLongFunction longMatchWeigher, Function bigDecimalMatchWeigher) { super(constraintFactory, parent); - this.intMatchWeigher = intMatchWeigher; - this.longMatchWeigher = longMatchWeigher; - this.bigDecimalMatchWeigher = bigDecimalMatchWeigher; + this.scoreImpact = new UniBigDecimalImpactHandler<>(bigDecimalMatchWeigher); } @Override @@ -74,108 +52,19 @@ public > void buildNode(ConstraintNodeBuildHelper(weightedScoreImpacter, scoreImpacter, + var scorer = new Scorer<>(scoreImpacter, weightedScoreImpacter, buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); buildHelper.putInsertUpdateRetract(this, scorer); } - private BiFunction, A, UndoScoreImpacter> - buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { + private UniScoreImpacter buildScoreImpacter(ConstraintMatchPolicy constraintMatchPolicy) { return switch (constraintMatchPolicy) { - case DISABLED -> buildScoreImpacter(); - case ENABLED -> buildScoreImpacterWithConstraintMatch(); - case ENABLED_WITHOUT_JUSTIFICATIONS -> buildScoreImpacterWithConstraintMatchNoJustifications(); + case DISABLED -> scoreImpact::impactNaked; + case ENABLED -> scoreImpact::impactFull; + case ENABLED_WITHOUT_JUSTIFICATIONS -> scoreImpact::impactWithoutJustification; }; } - private BiFunction, A, UndoScoreImpacter> buildScoreImpacter() { - if (intMatchWeigher != null) { - return (impacter, a) -> { - int matchWeight = intMatchWeigher.applyAsInt(a); - return impacter.impactScore(matchWeight, null); - }; - } else if (longMatchWeigher != null) { - return (impacter, a) -> { - long matchWeight = longMatchWeigher.applyAsLong(a); - return impacter.impactScore(matchWeight, null); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a); - return impacter.impactScore(matchWeight, null); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private BiFunction, A, UndoScoreImpacter> buildScoreImpacterWithConstraintMatch() { - if (intMatchWeigher != null) { - return (impacter, a) -> { - int matchWeight = intMatchWeigher.applyAsInt(a); - return impactWithConstraintMatch(impacter, matchWeight, a); - }; - } else if (longMatchWeigher != null) { - return (impacter, a) -> { - long matchWeight = longMatchWeigher.applyAsLong(a); - return impactWithConstraintMatch(impacter, matchWeight, a); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a); - return impactWithConstraintMatch(impacter, matchWeight, a); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, int matchWeight, A a) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, long matchWeight, A a) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private static > UndoScoreImpacter - impactWithConstraintMatch(WeightedScoreImpacter impacter, BigDecimal matchWeight, A a) { - var constraint = impacter.getContext().getConstraint(); - var constraintMatchSupplier = ConstraintMatchSupplier. of(constraint.getJustificationMapping(), - constraint.getIndictedObjectsMapping(), a); - return impacter.impactScore(matchWeight, constraintMatchSupplier); - } - - private BiFunction, A, UndoScoreImpacter> - buildScoreImpacterWithConstraintMatchNoJustifications() { - if (intMatchWeigher != null) { - return (impacter, a) -> { - int matchWeight = intMatchWeigher.applyAsInt(a); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (longMatchWeigher != null) { - return (impacter, a) -> { - long matchWeight = longMatchWeigher.applyAsLong(a); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else if (bigDecimalMatchWeigher != null) { - return (impacter, a) -> { - BigDecimal matchWeight = bigDecimalMatchWeigher.apply(a); - return impactWithConstraintMatchNoJustifications(impacter, matchWeight); - }; - } else { - throw new IllegalStateException("Impossible state: neither of the supported match weighers provided."); - } - } - // ************************************************************************ // Equality for node sharing // ************************************************************************ @@ -187,8 +76,4 @@ public String toString() { return "Scoring(" + constraint.getConstraintRef() + ")"; } - // ************************************************************************ - // Getters/setters - // ************************************************************************ - } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java new file mode 100644 index 0000000000..20aa43a759 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java @@ -0,0 +1,34 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.uni; + +import java.math.BigDecimal; +import java.util.function.Function; + +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record UniBigDecimalImpactHandler(Function matchWeigher) implements UniImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.apply(tuple.getA()), ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + var a = tuple.getA(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.apply(a), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniImpactHandler.java new file mode 100644 index 0000000000..ac2980932b --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniImpactHandler.java @@ -0,0 +1,17 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.uni; + +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ImpactHandler; + +import org.jspecify.annotations.NullMarked; + +/** + * A {@link UniTuple}-specific version of {@link ImpactHandler}. + * The methods (inherited from {@link ImpactHandler}) match the signature of {@link UniScoreImpacter}. + */ +@NullMarked +sealed interface UniImpactHandler + extends ImpactHandler> + permits UniBigDecimalImpactHandler, UniIntImpactHandler, UniLongImpactHandler { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java new file mode 100644 index 0000000000..5fb3c0e99d --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java @@ -0,0 +1,33 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.uni; + +import java.util.function.ToIntFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record UniIntImpactHandler(ToIntFunction matchWeigher) implements UniImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA()), null); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA()), ConstraintMatchSupplier.empty()); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + var a = tuple.getA(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsInt(a), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a)); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java new file mode 100644 index 0000000000..7671aaefa1 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java @@ -0,0 +1,33 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.uni; + +import java.util.function.ToLongFunction; + +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; +import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +@NullMarked +record UniLongImpactHandler(ToLongFunction matchWeigher) implements UniImpactHandler { + + @Override + public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA()), null); + } + + @Override + public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + var a = tuple.getA(); + var constraint = impacter.getContext().getConstraint(); + return impacter.impactScore(matchWeigher.applyAsLong(a), + ConstraintMatchSupplier.of(constraint.getJustificationMapping(), constraint.getIndictedObjectsMapping(), a)); + } + + @Override + public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA()), ConstraintMatchSupplier.empty()); + } + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScoreImpacter.java new file mode 100644 index 0000000000..896bc40e64 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScoreImpacter.java @@ -0,0 +1,16 @@ +package ai.timefold.solver.core.impl.score.stream.bavet.uni; + +import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; +import ai.timefold.solver.core.impl.score.stream.bavet.common.ScoreImpacter; + +import org.jspecify.annotations.NullMarked; + +/** + * Instances are provided by {@link UniImpactHandler}. + */ +@NullMarked +@FunctionalInterface +public interface UniScoreImpacter + extends ScoreImpacter> { + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java deleted file mode 100644 index 55b4486146..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniScorer.java +++ /dev/null @@ -1,28 +0,0 @@ -package ai.timefold.solver.core.impl.score.stream.bavet.uni; - -import java.util.function.BiFunction; - -import ai.timefold.solver.core.impl.bavet.common.AbstractScorer; -import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; -import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; - -final class UniScorer extends AbstractScorer> { - - private final BiFunction, A, UndoScoreImpacter> scoreImpacter; - - public UniScorer(WeightedScoreImpacter weightedScoreImpacter, - BiFunction, A, UndoScoreImpacter> scoreImpacter, int inputStoreIndex) { - super(weightedScoreImpacter, inputStoreIndex); - this.scoreImpacter = scoreImpacter; - } - - @Override - protected UndoScoreImpacter impact(UniTuple tuple) { - try { - return scoreImpacter.apply(weightedScoreImpacter, tuple.getA()); - } catch (Exception e) { - throw createExceptionOnImpact(tuple, e); - } - } -} From 1bba8b0c39354316913124272b86c235f21d5f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Sun, 21 Dec 2025 09:06:50 +0100 Subject: [PATCH 03/10] perf: avoid capturing lambdas during scoring --- .../bavet/bi/BiBigDecimalImpactHandler.java | 8 +- .../stream/bavet/bi/BiIntImpactHandler.java | 8 +- .../stream/bavet/bi/BiLongImpactHandler.java | 8 +- .../stream/bavet/common/ImpactHandler.java | 8 +- .../stream/bavet/common/ScoreImpacter.java | 4 +- .../score/stream/bavet/common/Scorer.java | 12 +- .../quad/QuadBigDecimalImpactHandler.java | 8 +- .../bavet/quad/QuadIntImpactHandler.java | 8 +- .../bavet/quad/QuadLongImpactHandler.java | 8 +- .../bavet/tri/TriBigDecimalImpactHandler.java | 8 +- .../stream/bavet/tri/TriIntImpactHandler.java | 8 +- .../bavet/tri/TriLongImpactHandler.java | 8 +- .../bavet/uni/UniBigDecimalImpactHandler.java | 8 +- .../stream/bavet/uni/UniIntImpactHandler.java | 8 +- .../bavet/uni/UniLongImpactHandler.java | 8 +- .../common/inliner/AbstractScoreInliner.java | 43 ++++-- .../BendableBigDecimalScoreContext.java | 128 ++++++++++++---- .../inliner/BendableLongScoreContext.java | 127 +++++++++++---- .../common/inliner/BendableScoreContext.java | 126 +++++++++++---- .../BigDecimalWeightedScoreImpacter.java | 6 +- .../HardMediumSoftBigDecimalScoreContext.java | 145 ++++++++++++++---- .../HardMediumSoftLongScoreContext.java | 70 ++++----- .../HardMediumSoftLongScoreInliner.java | 32 +--- .../inliner/HardMediumSoftScoreContext.java | 68 ++++---- .../inliner/HardMediumSoftScoreInliner.java | 17 +- .../HardSoftBigDecimalScoreContext.java | 106 ++++++++++--- .../inliner/HardSoftLongScoreContext.java | 55 ++++--- .../inliner/HardSoftLongScoreInliner.java | 24 +-- .../common/inliner/HardSoftScoreContext.java | 53 +++---- .../common/inliner/HardSoftScoreInliner.java | 12 +- .../inliner/IntWeightedScoreImpacter.java | 6 +- .../inliner/LongWeightedScoreImpacter.java | 6 +- .../stream/common/inliner/ScoreContext.java | 4 +- .../stream/common/inliner/ScoreImpact.java | 13 ++ .../inliner/SimpleBigDecimalScoreContext.java | 34 +++- .../inliner/SimpleLongScoreContext.java | 35 ++++- .../inliner/SimpleLongScoreInliner.java | 4 +- .../common/inliner/SimpleScoreContext.java | 35 ++++- .../common/inliner/SimpleScoreInliner.java | 4 +- .../common/inliner/UndoScoreImpacter.java | 6 - .../common/inliner/WeightedScoreImpacter.java | 12 +- .../BendableBigDecimalScoreInlinerTest.java | 32 ++-- .../inliner/BendableLongScoreInlinerTest.java | 32 ++-- .../inliner/BendableScoreInlinerTest.java | 32 ++-- ...dMediumSoftBigDecimalScoreInlinerTest.java | 32 ++-- .../HardMediumSoftLongScoreInlinerTest.java | 32 ++-- .../HardMediumSoftScoreInlinerTest.java | 32 ++-- .../HardSoftBigDecimalScoreInlinerTest.java | 24 +-- .../inliner/HardSoftLongScoreInlinerTest.java | 24 +-- .../inliner/HardSoftScoreInlinerTest.java | 24 +-- .../SimpleBigDecimalScoreInlinerTest.java | 8 +- .../inliner/SimpleLongScoreInlinerTest.java | 8 +- .../inliner/SimpleScoreInlinerTest.java | 8 +- 53 files changed, 974 insertions(+), 605 deletions(-) create mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java delete mode 100644 core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/UndoScoreImpacter.java diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java index 6613bfaa66..b47eb217d9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiBigDecimalImpactHandler.java @@ -5,7 +5,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -16,17 +16,17 @@ record BiBigDecimalImpactHandler(BiFunction matchWeigher BiImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var constraint = impacter.getContext().getConstraint(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java index b1ba18d2f0..ab084b8e11 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiIntImpactHandler.java @@ -4,7 +4,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -15,12 +15,12 @@ record BiIntImpactHandler(ToIntBiFunction matchWeigher) BiImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB()), null); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var constraint = impacter.getContext().getConstraint(); @@ -29,7 +29,7 @@ public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTupl } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java index d1b9586bd4..6b652c9945 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/bi/BiLongImpactHandler.java @@ -4,7 +4,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.BiTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -15,12 +15,12 @@ record BiLongImpactHandler(ToLongBiFunction matchWeigher) BiImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB()), null); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, BiTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var constraint = impacter.getContext().getConstraint(); @@ -29,7 +29,7 @@ public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, BiTupl } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, BiTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB()), ConstraintMatchSupplier.empty()); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java index bb4841e4a8..af14855fe3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ImpactHandler.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.impl.score.stream.bavet.common; import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -16,7 +16,7 @@ public interface ImpactHandler { * @param tuple the tuple that triggered the impact * @return run to undo the impact */ - UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, Tuple_ tuple); + ScoreImpact impactNaked(WeightedScoreImpacter impacter, Tuple_ tuple); /** * Impacts the score, providing constraint match information but justification for it. @@ -25,7 +25,7 @@ public interface ImpactHandler { * @param tuple the tuple that triggered the impact * @return run to undo the impact */ - UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, Tuple_ tuple); + ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, Tuple_ tuple); /** * Impacts the score, providing all available metadata. @@ -34,6 +34,6 @@ public interface ImpactHandler { * @param tuple the tuple that triggered the impact * @return run to undo the impact */ - UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, Tuple_ tuple); + ScoreImpact impactFull(WeightedScoreImpacter impacter, Tuple_ tuple); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java index 6573fd54da..9909d36b05 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/ScoreImpacter.java @@ -3,7 +3,7 @@ import java.util.function.BiFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -11,6 +11,6 @@ @NullMarked @FunctionalInterface public interface ScoreImpacter - extends BiFunction, Tuple_, UndoScoreImpacter> { + extends BiFunction, Tuple_, ScoreImpact> { } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java index 2425921d55..dbb89d9392 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/common/Scorer.java @@ -4,7 +4,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.Tuple; import ai.timefold.solver.core.impl.bavet.common.tuple.TupleLifecycle; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -34,15 +34,15 @@ public void insert(Tuple_ tuple) { @Override public void update(Tuple_ tuple) { - UndoScoreImpacter undoScoreImpacter = tuple.getStore(inputStoreIndex); + ScoreImpact undoScoreImpacter = tuple.getStore(inputStoreIndex); // No fail fast if null because we don't track which tuples made it through the filter predicate(s) if (undoScoreImpacter != null) { - undoScoreImpacter.run(); + undoScoreImpacter.undo(); } tuple.setStore(inputStoreIndex, impact(tuple)); } - public UndoScoreImpacter impact(Tuple_ tuple) { + public ScoreImpact impact(Tuple_ tuple) { try { return scoreImpacter.apply(weightedScoreImpacter, tuple); } catch (Exception e) { @@ -56,10 +56,10 @@ public UndoScoreImpacter impact(Tuple_ tuple) { @Override public void retract(Tuple_ tuple) { - UndoScoreImpacter undoScoreImpacter = tuple.removeStore(inputStoreIndex); + ScoreImpact undoScoreImpacter = tuple.removeStore(inputStoreIndex); // No fail fast if null because we don't track which tuples made it through the filter predicate(s) if (undoScoreImpacter != null) { - undoScoreImpacter.run(); + undoScoreImpacter.undo(); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java index 4552ef4429..7571c47555 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadBigDecimalImpactHandler.java @@ -5,7 +5,7 @@ import ai.timefold.solver.core.api.function.QuadFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -16,19 +16,19 @@ record QuadBigDecimalImpactHandler(QuadFunction { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var c = tuple.getC(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java index 966c3b2a40..a174912805 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadIntImpactHandler.java @@ -3,7 +3,7 @@ import ai.timefold.solver.core.api.function.ToIntQuadFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -14,19 +14,19 @@ record QuadIntImpactHandler(ToIntQuadFunction matchWeigh QuadImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var c = tuple.getC(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java index 74a475890e..2eedac1a3b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/quad/QuadLongImpactHandler.java @@ -3,7 +3,7 @@ import ai.timefold.solver.core.api.function.ToLongQuadFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.QuadTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -14,19 +14,19 @@ record QuadLongImpactHandler(ToLongQuadFunction matchWei QuadImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, QuadTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC(), tuple.getD()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, QuadTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var c = tuple.getC(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java index 1cd9bad5ff..de918349a2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriBigDecimalImpactHandler.java @@ -5,7 +5,7 @@ import ai.timefold.solver.core.api.function.TriFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -16,12 +16,12 @@ record TriBigDecimalImpactHandler(TriFunction matc TriImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC()), null); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var c = tuple.getC(); @@ -32,7 +32,7 @@ public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTup } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA(), tuple.getB(), tuple.getC()), ConstraintMatchSupplier.empty()); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java index ba2c92251f..04a0e12d67 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriIntImpactHandler.java @@ -3,7 +3,7 @@ import ai.timefold.solver.core.api.function.ToIntTriFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -14,18 +14,18 @@ record TriIntImpactHandler(ToIntTriFunction matchWeigher) TriImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA(), tuple.getB(), tuple.getC()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { var a = tuple.getA(); var b = tuple.getB(); var c = tuple.getC(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java index 86b3c5be3e..a0021d7b03 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/tri/TriLongImpactHandler.java @@ -3,7 +3,7 @@ import ai.timefold.solver.core.api.function.ToLongTriFunction; import ai.timefold.solver.core.impl.bavet.common.tuple.TriTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -14,18 +14,18 @@ record TriLongImpactHandler(ToLongTriFunction matchWeigher) TriImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, TriTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA(), tuple.getB(), tuple.getC()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, TriTuple tuple) { var a = tuple.getA(); B b = tuple.getB(); C c = tuple.getC(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java index 20aa43a759..2074066028 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniBigDecimalImpactHandler.java @@ -5,7 +5,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -14,17 +14,17 @@ record UniBigDecimalImpactHandler(Function matchWeigher) implements UniImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.apply(tuple.getA()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { var a = tuple.getA(); var constraint = impacter.getContext().getConstraint(); return impacter.impactScore(matchWeigher.apply(a), diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java index 5fb3c0e99d..0dd3c7ae99 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniIntImpactHandler.java @@ -4,7 +4,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -13,17 +13,17 @@ record UniIntImpactHandler(ToIntFunction matchWeigher) implements UniImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA()), null); } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.applyAsInt(tuple.getA()), ConstraintMatchSupplier.empty()); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { var a = tuple.getA(); var constraint = impacter.getContext().getConstraint(); return impacter.impactScore(matchWeigher.applyAsInt(a), diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java index 7671aaefa1..e86cb12511 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/bavet/uni/UniLongImpactHandler.java @@ -4,7 +4,7 @@ import ai.timefold.solver.core.impl.bavet.common.tuple.UniTuple; import ai.timefold.solver.core.impl.score.stream.common.inliner.ConstraintMatchSupplier; -import ai.timefold.solver.core.impl.score.stream.common.inliner.UndoScoreImpacter; +import ai.timefold.solver.core.impl.score.stream.common.inliner.ScoreImpact; import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter; import org.jspecify.annotations.NullMarked; @@ -13,12 +13,12 @@ record UniLongImpactHandler(ToLongFunction matchWeigher) implements UniImpactHandler { @Override - public UndoScoreImpacter impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactNaked(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA()), null); } @Override - public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactFull(WeightedScoreImpacter impacter, UniTuple tuple) { var a = tuple.getA(); var constraint = impacter.getContext().getConstraint(); return impacter.impactScore(matchWeigher.applyAsLong(a), @@ -26,7 +26,7 @@ public UndoScoreImpacter impactFull(WeightedScoreImpacter impacter, UniTup } @Override - public UndoScoreImpacter impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { + public ScoreImpact impactWithoutJustification(WeightedScoreImpacter impacter, UniTuple tuple) { return impacter.impactScore(matchWeigher.applyAsLong(tuple.getA()), ConstraintMatchSupplier.empty()); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java index 0afdbaca12..e80a0286cd 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java @@ -144,21 +144,40 @@ private void validateConstraintWeight(Constraint constraint, Score_ constraintWe */ public abstract WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint); - protected final UndoScoreImpacter addConstraintMatch(Constraint constraint, Score_ score, - ConstraintMatchSupplier constraintMatchSupplier, UndoScoreImpacter undoScoreImpact) { + protected final ScoreImpact addConstraintMatch(Constraint constraint, + ConstraintMatchSupplier constraintMatchSupplier, ScoreImpact scoreImpact) { var constraintMatchList = getConstraintMatchList(constraint); /* * Creating a constraint match is a heavy operation which may yet be undone. * Defer creation of the constraint match until a later point. */ - var entry = - constraintMatchList.add(new ConstraintMatchCarrier<>(constraintMatchSupplier, constraint, score)); + var entry = constraintMatchList.add(new ConstraintMatchCarrier<>(constraintMatchSupplier, constraint, scoreImpact)); clearMaps(); - return () -> { - undoScoreImpact.run(); + return new WrappingScoreImpact<>(scoreImpact, entry); + } + + private record WrappingScoreImpact>(ScoreImpact delegate, + ElementAwareLinkedList.Entry> entry) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return delegate.scoreInliner(); + } + + @Override + public void undo() { + delegate.undo(); entry.remove(); - clearMaps(); - }; + delegate.scoreInliner().clearMaps(); + } + + @Override + public Score_ toScore() { + return delegate.toScore(); + } + } private ElementAwareLinkedList> getConstraintMatchList(Constraint constraint) { @@ -260,21 +279,21 @@ private static final class ConstraintMatchCarrier> private final Constraint constraint; private final ConstraintMatchSupplier constraintMatchSupplier; - private final Score_ score; + private final ScoreImpact scoreImpact; private ConstraintMatch constraintMatch; private ConstraintMatchCarrier(ConstraintMatchSupplier constraintMatchSupplier, Constraint constraint, - Score_ score) { + ScoreImpact scoreImpact) { this.constraint = constraint; this.constraintMatchSupplier = constraintMatchSupplier; - this.score = score; + this.scoreImpact = scoreImpact; } @Override public ConstraintMatch get() { if (constraintMatch == null) { // Repeated requests for score explanation should not create the same constraint match over and over. - constraintMatch = constraintMatchSupplier.apply(constraint, score); + constraintMatch = constraintMatchSupplier.apply(constraint, scoreImpact.toScore()); } return constraintMatch; } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java index fee99387a5..3f176ec22f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java @@ -5,6 +5,8 @@ import ai.timefold.solver.core.api.score.buildin.bendablebigdecimal.BendableBigDecimalScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class BendableBigDecimalScoreContext extends ScoreContext { private final int hardScoreLevelCount; @@ -27,61 +29,121 @@ public BendableBigDecimalScoreContext(BendableBigDecimalScoreInliner parent, Abs this(parent, constraint, constraintWeight, hardScoreLevelCount, softScoreLevelCount, -1, BigDecimal.ZERO); } - public UndoScoreImpacter changeSoftScoreBy(BigDecimal matchWeight, + public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal softImpact = scoreLevelWeight.multiply(matchWeight); + var softImpact = scoreLevelWeight.multiply(matchWeight); parent.softScores[scoreLevel] = parent.softScores[scoreLevel].add(softImpact); - UndoScoreImpacter undoScoreImpact = - () -> parent.softScores[scoreLevel] = parent.softScores[scoreLevel].subtract(softImpact); + var scoreImpact = + new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableBigDecimalScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(BigDecimal matchWeight, + public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal hardImpact = scoreLevelWeight.multiply(matchWeight); + var hardImpact = scoreLevelWeight.multiply(matchWeight); parent.hardScores[scoreLevel] = parent.hardScores[scoreLevel].add(hardImpact); - UndoScoreImpacter undoScoreImpact = - () -> parent.hardScores[scoreLevel] = parent.hardScores[scoreLevel].subtract(hardImpact); + var scoreImpact = + new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableBigDecimalScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeScoreBy(BigDecimal matchWeight, + public ScoreImpact changeScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal[] hardImpacts = new BigDecimal[hardScoreLevelCount]; - BigDecimal[] softImpacts = new BigDecimal[softScoreLevelCount]; - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - BigDecimal hardImpact = constraintWeight.hardScore(hardScoreLevel).multiply(matchWeight); + var hardImpacts = new BigDecimal[hardScoreLevelCount]; + var softImpacts = new BigDecimal[softScoreLevelCount]; + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var hardImpact = constraintWeight.hardScore(hardScoreLevel).multiply(matchWeight); hardImpacts[hardScoreLevel] = hardImpact; parent.hardScores[hardScoreLevel] = parent.hardScores[hardScoreLevel].add(hardImpact); } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - BigDecimal softImpact = constraintWeight.softScore(softScoreLevel).multiply(matchWeight); + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + var softImpact = constraintWeight.softScore(softScoreLevel).multiply(matchWeight); softImpacts[softScoreLevel] = softImpact; parent.softScores[softScoreLevel] = parent.softScores[softScoreLevel].add(softImpact); } - UndoScoreImpacter undoScoreImpact = () -> { - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - parent.hardScores[hardScoreLevel] = parent.hardScores[hardScoreLevel].subtract(hardImpacts[hardScoreLevel]); + var scoreImpact = + new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SingleSoftLevelScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, + int softScoreLevelCount, int scoreLevel, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScores[scoreLevel] = inliner.softScores[scoreLevel].subtract(impact); + } + + @Override + public BendableBigDecimalScore toScore() { + return BendableBigDecimalScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record SingleHardLevelScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, + int softScoreLevelCount, int scoreLevel, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScores[scoreLevel] = inliner.hardScores[scoreLevel].subtract(impact); + } + + @Override + public BendableBigDecimalScore toScore() { + return BendableBigDecimalScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record ComplexScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, + BigDecimal[] hardImpacts, BigDecimal[] softImpacts) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + inliner.hardScores[hardScoreLevel] = inliner.hardScores[hardScoreLevel].subtract(hardImpacts[hardScoreLevel]); } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - parent.softScores[softScoreLevel] = parent.softScores[softScoreLevel].subtract(softImpacts[softScoreLevel]); + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + inliner.softScores[softScoreLevel] = inliner.softScores[softScoreLevel].subtract(softImpacts[softScoreLevel]); } - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, BendableBigDecimalScore.of(hardImpacts, softImpacts), - constraintMatchSupplier); + + @Override + public BendableBigDecimalScore toScore() { + return BendableBigDecimalScore.of(hardImpacts, softImpacts); + } } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java index 3b10961213..7c3aa52e73 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.bendablelong.BendableLongScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class BendableLongScoreContext extends ScoreContext { private final int hardScoreLevelCount; @@ -25,60 +27,121 @@ public BendableLongScoreContext(BendableLongScoreInliner parent, AbstractConstra this(parent, constraint, constraintWeight, hardScoreLevelCount, softScoreLevelCount, -1, -1); } - public UndoScoreImpacter changeSoftScoreBy(long matchWeight, + public ScoreImpact changeSoftScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long softImpact = scoreLevelWeight * matchWeight; + var softImpact = scoreLevelWeight * matchWeight; parent.softScores[scoreLevel] += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScores[scoreLevel] -= softImpact; - ; + var scoreImpact = + new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableLongScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(long matchWeight, + public ScoreImpact changeHardScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long hardImpact = scoreLevelWeight * matchWeight; + var hardImpact = scoreLevelWeight * matchWeight; parent.hardScores[scoreLevel] += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScores[scoreLevel] -= hardImpact; + var scoreImpact = + new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableLongScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeScoreBy(long matchWeight, + public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long[] hardImpacts = new long[hardScoreLevelCount]; - long[] softImpacts = new long[softScoreLevelCount]; - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - long hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; + var hardImpacts = new long[hardScoreLevelCount]; + var softImpacts = new long[softScoreLevelCount]; + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; hardImpacts[hardScoreLevel] = hardImpact; parent.hardScores[hardScoreLevel] += hardImpact; } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - long softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + var softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; softImpacts[softScoreLevel] = softImpact; parent.softScores[softScoreLevel] += softImpact; } - UndoScoreImpacter undoScoreImpact = () -> { - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - parent.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; + var scoreImpact = + new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SingleSoftLevelScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, + int softScoreLevelCount, int scoreLevel, long impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScores[scoreLevel] -= impact; + } + + @Override + public BendableLongScore toScore() { + return BendableLongScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record SingleHardLevelScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, + int softScoreLevelCount, int scoreLevel, long impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScores[scoreLevel] -= impact; + } + + @Override + public BendableLongScore toScore() { + return BendableLongScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record ComplexScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, + long[] hardImpacts, long[] softImpacts) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + inliner.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - parent.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + inliner.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; } - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, BendableLongScore.of(hardImpacts, softImpacts), - constraintMatchSupplier); + + @Override + public BendableLongScore toScore() { + return BendableLongScore.of(hardImpacts, softImpacts); + } } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java index 8aef9b9d9d..ee099578df 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.bendable.BendableScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class BendableScoreContext extends ScoreContext { private final int hardScoreLevelCount; @@ -25,57 +27,121 @@ public BendableScoreContext(BendableScoreInliner parent, AbstractConstraint changeSoftScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int softImpact = scoreLevelWeight * matchWeight; + var softImpact = scoreLevelWeight * matchWeight; parent.softScores[scoreLevel] += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScores[scoreLevel] -= softImpact; + var scoreImpact = + new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(int matchWeight, + public ScoreImpact changeHardScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int hardImpact = scoreLevelWeight * matchWeight; + var hardImpact = scoreLevelWeight * matchWeight; parent.hardScores[scoreLevel] += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScores[scoreLevel] -= hardImpact; + var scoreImpact = + new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, - BendableScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int[] hardImpacts = new int[hardScoreLevelCount]; - int[] softImpacts = new int[softScoreLevelCount]; - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - int hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; + public ScoreImpact changeScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var hardImpacts = new int[hardScoreLevelCount]; + var softImpacts = new int[softScoreLevelCount]; + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; hardImpacts[hardScoreLevel] = hardImpact; parent.hardScores[hardScoreLevel] += hardImpact; } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - int softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + var softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; softImpacts[softScoreLevel] = softImpact; parent.softScores[softScoreLevel] += softImpact; } - UndoScoreImpacter undoScoreImpact = () -> { - for (int hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { - parent.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; + var scoreImpact = + new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SingleSoftLevelScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, + int scoreLevel, int impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScores[scoreLevel] -= impact; + } + + @Override + public BendableScore toScore() { + return BendableScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record SingleHardLevelScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, + int scoreLevel, int impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScores[scoreLevel] -= impact; + } + + @Override + public BendableScore toScore() { + return BendableScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + } + } + + @NullMarked + private record ComplexScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, + int[] hardImpacts, int[] softImpacts) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + inliner.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; } - for (int softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { - parent.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; + for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + inliner.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; } - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, BendableScore.of(hardImpacts, softImpacts), constraintMatchSupplier); + + @Override + public BendableScore toScore() { + return BendableScore.of(hardImpacts, softImpacts); + } } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java index cb53e8110c..447ff17ac0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java @@ -18,19 +18,19 @@ public BigDecimalWeightedScoreImpacter(BigDecimalImpactFunction constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, BigDecimal.valueOf(matchWeight), constraintMatchSupplier); } @Override - public UndoScoreImpacter impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, BigDecimal.valueOf(matchWeight), constraintMatchSupplier); } @Override - public UndoScoreImpacter impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java index f4038aa9cd..f8a28a2de3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java @@ -5,6 +5,8 @@ import ai.timefold.solver.core.api.score.buildin.hardmediumsoftbigdecimal.HardMediumSoftBigDecimalScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardMediumSoftBigDecimalScoreContext extends ScoreContext { @@ -13,60 +15,143 @@ public HardMediumSoftBigDecimalScoreContext(HardMediumSoftBigDecimalScoreInliner super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeSoftScoreBy(BigDecimal matchWeight, + public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal softImpact = constraintWeight.softScore().multiply(matchWeight); + var softImpact = constraintWeight.softScore().multiply(matchWeight); parent.softScore = parent.softScore.add(softImpact); - UndoScoreImpacter undoScoreImpact = () -> parent.softScore = parent.softScore.subtract(softImpact); + var scoreImpact = new SoftBigDecimalImpact(parent, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftBigDecimalScore.ofSoft(softImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeMediumScoreBy(BigDecimal matchWeight, + public ScoreImpact changeMediumScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); + var mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); parent.mediumScore = parent.mediumScore.add(mediumImpact); - UndoScoreImpacter undoScoreImpact = () -> parent.mediumScore = parent.mediumScore.subtract(mediumImpact); + var scoreImpact = new MediumBigDecimalImpact(parent, mediumImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftBigDecimalScore.ofMedium(mediumImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(BigDecimal matchWeight, + public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal hardImpact = constraintWeight.hardScore().multiply(matchWeight); + var hardImpact = constraintWeight.hardScore().multiply(matchWeight); parent.hardScore = parent.hardScore.add(hardImpact); - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore = parent.hardScore.subtract(hardImpact); + var scoreImpact = new HardBigDecimalImpact(parent, hardImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftBigDecimalScore.ofHard(hardImpact), - constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeScoreBy(BigDecimal matchWeight, + public ScoreImpact changeScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal hardImpact = constraintWeight.hardScore().multiply(matchWeight); - BigDecimal mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); - BigDecimal softImpact = constraintWeight.softScore().multiply(matchWeight); + var hardImpact = constraintWeight.hardScore().multiply(matchWeight); + var mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); + var softImpact = constraintWeight.softScore().multiply(matchWeight); parent.hardScore = parent.hardScore.add(hardImpact); parent.mediumScore = parent.mediumScore.add(mediumImpact); parent.softScore = parent.softScore.add(softImpact); - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore = parent.hardScore.subtract(hardImpact); - parent.mediumScore = parent.mediumScore.subtract(mediumImpact); - parent.softScore = parent.softScore.subtract(softImpact); - }; + var scoreImpact = new HardMediumSoftBigDecimalImpact(parent, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SoftBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, - HardMediumSoftBigDecimalScore.of(hardImpact, mediumImpact, softImpact), constraintMatchSupplier); + + @Override + public void undo() { + inliner.softScore = inliner.softScore.subtract(impact); + } + + @Override + public HardMediumSoftBigDecimalScore toScore() { + return HardMediumSoftBigDecimalScore.ofSoft(impact); + } + + } + + @NullMarked + private record MediumBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.mediumScore = inliner.mediumScore.subtract(impact); + } + + @Override + public HardMediumSoftBigDecimalScore toScore() { + return HardMediumSoftBigDecimalScore.ofMedium(impact); + } + + } + + @NullMarked + private record HardBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore = inliner.hardScore.subtract(impact); + } + + @Override + public HardMediumSoftBigDecimalScore toScore() { + return HardMediumSoftBigDecimalScore.ofHard(impact); + } + + } + + @NullMarked + private record HardMediumSoftBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, + BigDecimal mediumImpact, BigDecimal softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore = inliner.hardScore.subtract(hardImpact); + inliner.mediumScore = inliner.mediumScore.subtract(mediumImpact); + inliner.softScore = inliner.softScore.subtract(softImpact); + } + + @Override + public HardMediumSoftBigDecimalScore toScore() { + return HardMediumSoftBigDecimalScore.of(hardImpact, mediumImpact, softImpact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java index cf4a3a64d6..32c5a1b0ef 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardMediumSoftLongScoreContext extends ScoreContext { public HardMediumSoftLongScoreContext(HardMediumSoftLongScoreInliner parent, AbstractConstraint constraint, @@ -10,58 +12,44 @@ public HardMediumSoftLongScoreContext(HardMediumSoftLongScoreInliner parent, Abs super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeSoftScoreBy(long matchWeight, + public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long softImpact = constraintWeight.softScore() * matchWeight; + var hardImpact = constraintWeight.hardScore() * matchWeight; + var mediumImpact = constraintWeight.mediumScore() * matchWeight; + var softImpact = constraintWeight.softScore() * matchWeight; + parent.hardScore += hardImpact; + parent.mediumScore += mediumImpact; parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScore -= softImpact; + var scoreImpact = new HardMediumSoftLongImpact(parent, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftLongScore.ofSoft(softImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeMediumScoreBy(long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - long mediumImpact = constraintWeight.mediumScore() * matchWeight; - parent.mediumScore += mediumImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.mediumScore -= mediumImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @NullMarked + private record HardMediumSoftLongImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact, long mediumImpact, + long softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftLongScore.ofMedium(mediumImpact), - constraintMatchSupplier); - } - public UndoScoreImpacter changeHardScoreBy(long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - long hardImpact = constraintWeight.hardScore() * matchWeight; - parent.hardScore += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore -= hardImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public void undo() { + inliner.hardScore -= hardImpact; + inliner.mediumScore -= mediumImpact; + inliner.softScore -= softImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftLongScore.ofHard(hardImpact), constraintMatchSupplier); - } - public UndoScoreImpacter changeScoreBy(long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - long hardImpact = constraintWeight.hardScore() * matchWeight; - long mediumImpact = constraintWeight.mediumScore() * matchWeight; - long softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.mediumScore += mediumImpact; - parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore -= hardImpact; - parent.mediumScore -= mediumImpact; - parent.softScore -= softImpact; - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public HardMediumSoftLongScore toScore() { + return HardMediumSoftLongScore.of(hardImpact, mediumImpact, softImpact); } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftLongScore.of(hardImpact, mediumImpact, softImpact), - constraintMatchSupplier); + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java index 15da682fe1..0244a95499 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java @@ -21,32 +21,12 @@ final class HardMediumSoftLongScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - HardMediumSoftLongScore constraintWeight = constraintWeightMap.get(constraint); - long hardConstraintWeight = constraintWeight.hardScore(); - long mediumConstraintWeight = constraintWeight.mediumScore(); - long softConstraintWeight = constraintWeight.softScore(); - HardMediumSoftLongScoreContext context = new HardMediumSoftLongScoreContext(this, constraint, constraintWeight); - if (mediumConstraintWeight == 0L && softConstraintWeight == 0L) { - return WeightedScoreImpacter.of(context, - (HardMediumSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeHardScoreBy(matchWeight, constraintMatchSupplier)); - } else if (hardConstraintWeight == 0L && softConstraintWeight == 0L) { - return WeightedScoreImpacter.of(context, - (HardMediumSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeMediumScoreBy(matchWeight, constraintMatchSupplier)); - } else if (hardConstraintWeight == 0L && mediumConstraintWeight == 0L) { - return WeightedScoreImpacter.of(context, - (HardMediumSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeSoftScoreBy(matchWeight, constraintMatchSupplier)); - } else { - return WeightedScoreImpacter.of(context, - (HardMediumSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeScoreBy(matchWeight, constraintMatchSupplier)); - } + var constraintWeight = constraintWeightMap.get(constraint); + var context = new HardMediumSoftLongScoreContext(this, constraint, constraintWeight); + return WeightedScoreImpacter.of(context, + (HardMediumSoftLongScoreContext ctx, long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) -> ctx + .changeScoreBy(matchWeight, constraintMatchSupplier)); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java index 653a6c7f97..7273c63e2f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardMediumSoftScoreContext extends ScoreContext { public HardMediumSoftScoreContext(HardMediumSoftScoreInliner parent, AbstractConstraint constraint, @@ -10,57 +12,43 @@ public HardMediumSoftScoreContext(HardMediumSoftScoreInliner parent, AbstractCon super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeSoftScoreBy(int matchWeight, + public ScoreImpact changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int softImpact = constraintWeight.softScore() * matchWeight; + var hardImpact = constraintWeight.hardScore() * matchWeight; + var mediumImpact = constraintWeight.mediumScore() * matchWeight; + var softImpact = constraintWeight.softScore() * matchWeight; + parent.hardScore += hardImpact; + parent.mediumScore += mediumImpact; parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScore -= softImpact; + var scoreImpact = new HardMediumSoftImpact(parent, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftScore.ofSoft(softImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeMediumScoreBy(int matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - int mediumImpact = constraintWeight.mediumScore() * matchWeight; - parent.mediumScore += mediumImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.mediumScore -= mediumImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @NullMarked + private record HardMediumSoftImpact(HardMediumSoftScoreInliner inliner, int hardImpact, int mediumImpact, int softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftScore.ofMedium(mediumImpact), constraintMatchSupplier); - } - public UndoScoreImpacter changeHardScoreBy(int matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - int hardImpact = constraintWeight.hardScore() * matchWeight; - parent.hardScore += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore -= hardImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public void undo() { + inliner.hardScore -= hardImpact; + inliner.mediumScore -= mediumImpact; + inliner.softScore -= softImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftScore.ofHard(hardImpact), constraintMatchSupplier); - } - public UndoScoreImpacter changeScoreBy(int matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - int hardImpact = constraintWeight.hardScore() * matchWeight; - int mediumImpact = constraintWeight.mediumScore() * matchWeight; - int softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.mediumScore += mediumImpact; - parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore -= hardImpact; - parent.mediumScore -= mediumImpact; - parent.softScore -= softImpact; - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public HardMediumSoftScore toScore() { + return HardMediumSoftScore.of(hardImpact, mediumImpact, softImpact); } - return impactWithConstraintMatch(undoScoreImpact, HardMediumSoftScore.of(hardImpact, mediumImpact, softImpact), - constraintMatchSupplier); + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java index cf49748c52..fe33065d5c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java @@ -21,20 +21,9 @@ final class HardMediumSoftScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - HardMediumSoftScore constraintWeight = constraintWeightMap.get(constraint); - int hardConstraintWeight = constraintWeight.hardScore(); - int mediumConstraintWeight = constraintWeight.mediumScore(); - int softConstraintWeight = constraintWeight.softScore(); - HardMediumSoftScoreContext context = new HardMediumSoftScoreContext(this, constraint, constraintWeight); - if (mediumConstraintWeight == 0 && softConstraintWeight == 0) { - return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeHardScoreBy); - } else if (hardConstraintWeight == 0 && softConstraintWeight == 0) { - return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeMediumScoreBy); - } else if (hardConstraintWeight == 0 && mediumConstraintWeight == 0) { - return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeSoftScoreBy); - } else { - return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeScoreBy); - } + var constraintWeight = constraintWeightMap.get(constraint); + var context = new HardMediumSoftScoreContext(this, constraint, constraintWeight); + return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeScoreBy); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java index 6e01aa8213..09fde84dd0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java @@ -5,6 +5,8 @@ import ai.timefold.solver.core.api.score.buildin.hardsoftbigdecimal.HardSoftBigDecimalScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardSoftBigDecimalScoreContext extends ScoreContext { public HardSoftBigDecimalScoreContext(HardSoftBigDecimalScoreInliner parent, AbstractConstraint constraint, @@ -12,43 +14,107 @@ public HardSoftBigDecimalScoreContext(HardSoftBigDecimalScoreInliner parent, Abs super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeSoftScoreBy(BigDecimal matchWeight, + public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal softImpact = constraintWeight.softScore().multiply(matchWeight); + var softImpact = constraintWeight.softScore().multiply(matchWeight); parent.softScore = parent.softScore.add(softImpact); - UndoScoreImpacter undoScoreImpact = () -> parent.softScore = parent.softScore.subtract(softImpact); + var scoreImpact = new SoftBigDecimalImpact(parent, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftBigDecimalScore.ofSoft(softImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(BigDecimal matchWeight, + public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal hardImpact = constraintWeight.hardScore().multiply(matchWeight); + var hardImpact = constraintWeight.hardScore().multiply(matchWeight); parent.hardScore = parent.hardScore.add(hardImpact); - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore = parent.hardScore.subtract(hardImpact); + var scoreImpact = new HardBigDecimalImpact(parent, hardImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftBigDecimalScore.ofHard(hardImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeScoreBy(BigDecimal matchWeight, + public ScoreImpact changeScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal hardImpact = constraintWeight.hardScore().multiply(matchWeight); - BigDecimal softImpact = constraintWeight.softScore().multiply(matchWeight); + var hardImpact = constraintWeight.hardScore().multiply(matchWeight); + var softImpact = constraintWeight.softScore().multiply(matchWeight); parent.hardScore = parent.hardScore.add(hardImpact); parent.softScore = parent.softScore.add(softImpact); - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore = parent.hardScore.subtract(hardImpact); - parent.softScore = parent.softScore.subtract(softImpact); - }; + var scoreImpact = new HardSoftBigDecimalImpact(parent, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SoftBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScore = inliner.softScore.subtract(impact); + } + + @Override + public HardSoftBigDecimalScore toScore() { + return HardSoftBigDecimalScore.ofSoft(impact); + } + + } + + @NullMarked + private record HardBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftBigDecimalScore.of(hardImpact, softImpact), - constraintMatchSupplier); + + @Override + public void undo() { + inliner.hardScore = inliner.hardScore.subtract(impact); + } + + @Override + public HardSoftBigDecimalScore toScore() { + return HardSoftBigDecimalScore.ofHard(impact); + } + + } + + @NullMarked + private record HardSoftBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, + BigDecimal softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore = inliner.hardScore.subtract(hardImpact); + inliner.softScore = inliner.softScore.subtract(softImpact); + } + + @Override + public HardSoftBigDecimalScore toScore() { + return HardSoftBigDecimalScore.of(hardImpact, softImpact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java index 9e5f831d8f..5f4d8023c9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.hardsoftlong.HardSoftLongScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardSoftLongScoreContext extends ScoreContext { public HardSoftLongScoreContext(HardSoftLongScoreInliner parent, AbstractConstraint constraint, @@ -10,43 +12,40 @@ public HardSoftLongScoreContext(HardSoftLongScoreInliner parent, AbstractConstra super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeSoftScoreBy(long matchWeight, + public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long softImpact = constraintWeight.softScore() * matchWeight; + var hardImpact = constraintWeight.hardScore() * matchWeight; + var softImpact = constraintWeight.softScore() * matchWeight; + parent.hardScore += hardImpact; parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScore -= softImpact; + var scoreImpact = new HardSoftLongImpact(parent, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftLongScore.ofSoft(softImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - long hardImpact = constraintWeight.hardScore() * matchWeight; - parent.hardScore += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore -= hardImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @NullMarked + private record HardSoftLongImpact(HardSoftLongScoreInliner inliner, long hardImpact, long softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftLongScore.ofHard(hardImpact), constraintMatchSupplier); - } - public UndoScoreImpacter changeScoreBy(long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - long hardImpact = constraintWeight.hardScore() * matchWeight; - long softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore -= hardImpact; - parent.softScore -= softImpact; - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public void undo() { + inliner.hardScore -= hardImpact; + inliner.softScore -= softImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftLongScore.of(hardImpact, softImpact), - constraintMatchSupplier); + + @Override + public HardSoftLongScore toScore() { + return HardSoftLongScore.of(hardImpact, softImpact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java index 0ebd6ddf67..be071cf052 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java @@ -19,24 +19,12 @@ final class HardSoftLongScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - HardSoftLongScore constraintWeight = constraintWeightMap.get(constraint); - HardSoftLongScoreContext context = new HardSoftLongScoreContext(this, constraint, constraintWeight); - if (constraintWeight.softScore() == 0L) { - return WeightedScoreImpacter.of(context, - (HardSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeHardScoreBy(matchWeight, constraintMatchSupplier)); - } else if (constraintWeight.hardScore() == 0L) { - return WeightedScoreImpacter.of(context, - (HardSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeSoftScoreBy(matchWeight, constraintMatchSupplier)); - } else { - return WeightedScoreImpacter.of(context, - (HardSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeScoreBy(matchWeight, constraintMatchSupplier)); - } + var constraintWeight = constraintWeightMap.get(constraint); + var context = new HardSoftLongScoreContext(this, constraint, constraintWeight); + return WeightedScoreImpacter.of(context, + (HardSoftLongScoreContext ctx, long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) -> ctx + .changeScoreBy(matchWeight, constraintMatchSupplier)); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java index c0038ecf9c..0108649aeb 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class HardSoftScoreContext extends ScoreContext { public HardSoftScoreContext(HardSoftScoreInliner parent, AbstractConstraint constraint, @@ -10,41 +12,40 @@ public HardSoftScoreContext(HardSoftScoreInliner parent, AbstractConstraint changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int softImpact = constraintWeight.softScore() * matchWeight; + var hardImpact = constraintWeight.hardScore() * matchWeight; + var softImpact = constraintWeight.softScore() * matchWeight; + parent.hardScore += hardImpact; parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.softScore -= softImpact; + var scoreImpact = new HardSoftImpact(parent, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftScore.ofSoft(softImpact), constraintMatchSupplier); + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } - public UndoScoreImpacter changeHardScoreBy(int matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) { - int hardImpact = constraintWeight.hardScore() * matchWeight; - parent.hardScore += hardImpact; - UndoScoreImpacter undoScoreImpact = () -> parent.hardScore -= hardImpact; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @NullMarked + private record HardSoftImpact(HardSoftScoreInliner inliner, int hardImpact, int softImpact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftScore.ofHard(hardImpact), constraintMatchSupplier); - } - public UndoScoreImpacter changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int hardImpact = constraintWeight.hardScore() * matchWeight; - int softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.softScore += softImpact; - UndoScoreImpacter undoScoreImpact = () -> { - parent.hardScore -= hardImpact; - parent.softScore -= softImpact; - }; - if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + @Override + public void undo() { + inliner.hardScore -= hardImpact; + inliner.softScore -= softImpact; } - return impactWithConstraintMatch(undoScoreImpact, HardSoftScore.of(hardImpact, softImpact), constraintMatchSupplier); + + @Override + public HardSoftScore toScore() { + return HardSoftScore.of(hardImpact, softImpact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java index 2c470d7244..f929b0577b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java @@ -19,15 +19,9 @@ final class HardSoftScoreInliner extends AbstractScoreInliner { @Override public WeightedScoreImpacter buildWeightedScoreImpacter( AbstractConstraint constraint) { - HardSoftScore constraintWeight = constraintWeightMap.get(constraint); - HardSoftScoreContext context = new HardSoftScoreContext(this, constraint, constraintWeight); - if (constraintWeight.softScore() == 0) { - return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeHardScoreBy); - } else if (constraintWeight.hardScore() == 0) { - return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeSoftScoreBy); - } else { - return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeScoreBy); - } + var constraintWeight = constraintWeightMap.get(constraint); + var context = new HardSoftScoreContext(this, constraint, constraintWeight); + return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeScoreBy); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java index 6efce9d9ff..4debbaafc4 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java @@ -17,18 +17,18 @@ public IntWeightedScoreImpacter(IntImpactFunction impactFuncti } @Override - public UndoScoreImpacter impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } @Override - public UndoScoreImpacter impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing long into an int impacter."); } @Override - public UndoScoreImpacter impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing BigDecimal into an int impacter."); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java index adb05df636..0a3310127d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java @@ -17,19 +17,19 @@ public LongWeightedScoreImpacter(LongImpactFunction impactFunc } @Override - public UndoScoreImpacter impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); // int can be cast to long } @Override - public UndoScoreImpacter impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } @Override - public UndoScoreImpacter impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing BigDecimal into a long impacter."); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java index afc85abc1e..9b9e8164d0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java @@ -26,9 +26,9 @@ public Score_ getConstraintWeight() { return constraintWeight; } - protected UndoScoreImpacter impactWithConstraintMatch(UndoScoreImpacter undoScoreImpact, Score_ score, + protected ScoreImpact impactWithConstraintMatch(ScoreImpact scoreImpact, ConstraintMatchSupplier constraintMatchSupplier) { - return parent.addConstraintMatch(constraint, score, constraintMatchSupplier, undoScoreImpact); + return parent.addConstraintMatch(constraint, constraintMatchSupplier, scoreImpact); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java new file mode 100644 index 0000000000..dfb1ed14b7 --- /dev/null +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java @@ -0,0 +1,13 @@ +package ai.timefold.solver.core.impl.score.stream.common.inliner; + +import ai.timefold.solver.core.api.score.Score; + +public interface ScoreImpact> { + + AbstractScoreInliner scoreInliner(); + + void undo(); + + Score_ toScore(); + +} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java index 580d59fa78..592b838596 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java @@ -5,6 +5,8 @@ import ai.timefold.solver.core.api.score.buildin.simplebigdecimal.SimpleBigDecimalScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class SimpleBigDecimalScoreContext extends ScoreContext { public SimpleBigDecimalScoreContext(SimpleBigDecimalScoreInliner parent, AbstractConstraint constraint, @@ -12,15 +14,37 @@ public SimpleBigDecimalScoreContext(SimpleBigDecimalScoreInliner parent, Abstrac super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeScoreBy(BigDecimal matchWeight, + public ScoreImpact changeScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - BigDecimal impact = constraintWeight.score().multiply(matchWeight); + var impact = constraintWeight.score().multiply(matchWeight); parent.score = parent.score.add(impact); - UndoScoreImpacter undoScoreImpact = () -> parent.score = parent.score.subtract(impact); + var scoreImpact = new SimpleBigDecimalImpact(parent, impact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SimpleBigDecimalImpact(SimpleBigDecimalScoreInliner inliner, BigDecimal impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, SimpleBigDecimalScore.of(impact), constraintMatchSupplier); + + @Override + public void undo() { + inliner.score = inliner.score.subtract(impact); + } + + @Override + public SimpleBigDecimalScore toScore() { + return SimpleBigDecimalScore.of(impact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java index ab57995777..79777a0437 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java @@ -3,6 +3,8 @@ import ai.timefold.solver.core.api.score.buildin.simplelong.SimpleLongScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class SimpleLongScoreContext extends ScoreContext { public SimpleLongScoreContext(SimpleLongScoreInliner parent, AbstractConstraint constraint, @@ -10,14 +12,37 @@ public SimpleLongScoreContext(SimpleLongScoreInliner parent, AbstractConstraint< super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - long impact = constraintWeight.score() * matchWeight; + public ScoreImpact changeScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var impact = constraintWeight.score() * matchWeight; parent.score += impact; - UndoScoreImpacter undoScoreImpact = () -> parent.score -= impact; + var scoreImpact = new SimpleLongImpact(parent, impact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SimpleLongImpact(SimpleLongScoreInliner inliner, long impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, SimpleLongScore.of(impact), constraintMatchSupplier); + + @Override + public void undo() { + inliner.score -= impact; + } + + @Override + public SimpleLongScore toScore() { + return SimpleLongScore.of(impact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java index 3e9ff0149e..a4bd04562e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java @@ -18,8 +18,8 @@ final class SimpleLongScoreInliner extends AbstractScoreInliner @Override public WeightedScoreImpacter buildWeightedScoreImpacter( AbstractConstraint constraint) { - SimpleLongScore constraintWeight = constraintWeightMap.get(constraint); - SimpleLongScoreContext context = new SimpleLongScoreContext(this, constraint, constraintWeight); + var constraintWeight = constraintWeightMap.get(constraint); + var context = new SimpleLongScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, (SimpleLongScoreContext ctx, long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) -> ctx diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java index adb93ae6d6..af9a978739 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java @@ -3,20 +3,45 @@ import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import org.jspecify.annotations.NullMarked; + final class SimpleScoreContext extends ScoreContext { public SimpleScoreContext(SimpleScoreInliner parent, AbstractConstraint constraint, SimpleScore constraintWeight) { super(parent, constraint, constraintWeight); } - public UndoScoreImpacter changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { - int impact = constraintWeight.score() * matchWeight; + public ScoreImpact changeScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var impact = constraintWeight.score() * matchWeight; parent.score += impact; - UndoScoreImpacter undoScoreImpact = () -> parent.score -= impact; + var scoreImpact = new SimpleLongImpact(parent, impact); if (!constraintMatchPolicy.isEnabled()) { - return undoScoreImpact; + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + @NullMarked + private record SimpleLongImpact(SimpleScoreInliner inliner, int impact) + implements + ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; } - return impactWithConstraintMatch(undoScoreImpact, SimpleScore.of(impact), constraintMatchSupplier); + + @Override + public void undo() { + inliner.score -= impact; + } + + @Override + public SimpleScore toScore() { + return SimpleScore.of(impact); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java index 5c1f88804e..a207a1599d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java @@ -18,8 +18,8 @@ final class SimpleScoreInliner extends AbstractScoreInliner { @Override public WeightedScoreImpacter buildWeightedScoreImpacter( AbstractConstraint constraint) { - SimpleScore constraintWeight = constraintWeightMap.get(constraint); - SimpleScoreContext context = new SimpleScoreContext(this, constraint, constraintWeight); + var constraintWeight = constraintWeightMap.get(constraint); + var context = new SimpleScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, SimpleScoreContext::changeScoreBy); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/UndoScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/UndoScoreImpacter.java deleted file mode 100644 index 6a7729abd4..0000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/UndoScoreImpacter.java +++ /dev/null @@ -1,6 +0,0 @@ -package ai.timefold.solver.core.impl.score.stream.common.inliner; - -@FunctionalInterface -public interface UndoScoreImpacter extends Runnable { - -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java index 0742edb2b9..4ac931e025 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java @@ -43,42 +43,42 @@ public interface WeightedScoreImpacter, Context_ ex * @param constraintMatchSupplier ignored unless constraint match enableds * @return never null */ - UndoScoreImpacter impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); /** * @param matchWeight never null * @param constraintMatchSupplier ignored unless constraint match enabled * @return never null */ - UndoScoreImpacter impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); /** * @param matchWeight never null * @param constraintMatchSupplier ignored unless constraint match enabled * @return never null */ - UndoScoreImpacter impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier); Context_ getContext(); @FunctionalInterface interface IntImpactFunction, Context_ extends ScoreContext> { - UndoScoreImpacter impact(Context_ context, int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impact(Context_ context, int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); } @FunctionalInterface interface LongImpactFunction, Context_ extends ScoreContext> { - UndoScoreImpacter impact(Context_ context, long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impact(Context_ context, long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); } @FunctionalInterface interface BigDecimalImpactFunction, Context_ extends ScoreContext> { - UndoScoreImpacter impact(Context_ context, BigDecimal matchWeight, + ScoreImpact impact(Context_ context, BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java index 9d1aa4fdc0..55ebac3199 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java @@ -28,19 +28,19 @@ void impactHard() { var impacter = buildScoreImpacter(buildScore(90, 0, 0)); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(270, 0, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -50,19 +50,19 @@ void impactSoft1() { var impacter = buildScoreImpacter(buildScore(0, 90, 0)); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -72,19 +72,19 @@ void impactSoft2() { var impacter = buildScoreImpacter(buildScore(0, 0, 90)); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -94,19 +94,19 @@ void impactAll() { var impacter = buildScoreImpacter(buildScore(10, 100, 1_000)); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(300, 3_000, 30_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java index f62a50df83..e4abcd2786 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java @@ -27,19 +27,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(270, 0, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -50,19 +50,19 @@ void impactSoft1() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -73,19 +73,19 @@ void impactSoft2() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -96,19 +96,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(300, 3_000, 30_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java index aa903de086..b6ccd825d7 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java @@ -27,19 +27,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(270, 0, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(90, 0, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -50,19 +50,19 @@ void impactSoft1() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -73,19 +73,19 @@ void impactSoft2() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } @@ -96,19 +96,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(300, 3_000, 30_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(100, 1_000, 10_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(buildScore(0, 0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java index 2ff4d05fa9..66f44c4a68 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java @@ -29,19 +29,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(90), BigDecimal.ZERO, BigDecimal.ZERO)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(270), BigDecimal.ZERO, BigDecimal.ZERO)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(90), BigDecimal.ZERO, BigDecimal.ZERO)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(0), BigDecimal.ZERO, BigDecimal.ZERO)); } @@ -52,19 +52,19 @@ void impactMedium() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(90), BigDecimal.ZERO)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(270), BigDecimal.ZERO)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(90), BigDecimal.ZERO)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); } @@ -75,19 +75,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.valueOf(90))); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.valueOf(270))); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.valueOf(90))); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); } @@ -99,22 +99,22 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(100), BigDecimal.valueOf(1_000), BigDecimal.valueOf(10_000))); - var undo2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(300), BigDecimal.valueOf(3_000), BigDecimal.valueOf(30_000))); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(100), BigDecimal.valueOf(1_000), BigDecimal.valueOf(10_000))); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java index 85bd5476ed..19692c0a62 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java @@ -28,19 +28,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(90, 0, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(270, 0, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(90, 0, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 0)); } @@ -51,19 +51,19 @@ void impactMedium() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 0)); } @@ -74,19 +74,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 0)); } @@ -97,19 +97,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(100, 1_000, 10_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(300, 3_000, 30_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(100, 1_000, 10_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftLongScore.of(0, 0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java index 699438606b..3cb66b12b0 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java @@ -28,19 +28,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(90, 0, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(270, 0, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(90, 0, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 0)); } @@ -51,19 +51,19 @@ void impactMedium() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 0)); } @@ -74,19 +74,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 0)); } @@ -97,19 +97,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(100, 1_000, 10_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(300, 3_000, 30_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(100, 1_000, 10_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardMediumSoftScore.of(0, 0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java index 3517bbe7c4..b9dbfcb38e 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java @@ -29,19 +29,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(90), BigDecimal.ZERO)); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(270), BigDecimal.ZERO)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(90), BigDecimal.ZERO)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(0), BigDecimal.ZERO)); } @@ -52,19 +52,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(90))); - var undo2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(2), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(270))); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.valueOf(90))); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO)); } @@ -75,19 +75,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(100), BigDecimal.valueOf(1000))); - var undo2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(300), BigDecimal.valueOf(3000))); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.valueOf(100), BigDecimal.valueOf(1000))); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftBigDecimalScore.of(BigDecimal.ZERO, BigDecimal.ZERO)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java index 8dbcaa0ba9..7ff9f402db 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java @@ -27,19 +27,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 0)); } @@ -50,19 +50,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 0)); } @@ -73,19 +73,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(100, 1_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(300, 3_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(100, 1_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftLongScore.of(0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java index a4948cddd1..a33d489fc5 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java @@ -27,19 +27,19 @@ void impactHard() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(90, 0)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(270, 0)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(90, 0)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 0)); } @@ -50,19 +50,19 @@ void impactSoft() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 90)); - var undo2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(2, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 270)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 90)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 0)); } @@ -73,19 +73,19 @@ void impactAll() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(100, 1_000)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(300, 3_000)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(100, 1_000)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(HardSoftScore.of(0, 0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java index 2408901de3..f2b365125e 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java @@ -29,19 +29,19 @@ void impact() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleBigDecimalScore.of(BigDecimal.valueOf(100))); - var undo2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(BigDecimal.valueOf(20), ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleBigDecimalScore.of(BigDecimal.valueOf(300))); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleBigDecimalScore.of(BigDecimal.valueOf(100))); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleBigDecimalScore.of(BigDecimal.ZERO)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java index e6c473e970..44e8804bfc 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java @@ -27,19 +27,19 @@ void impact() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleLongScore.of(100)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleLongScore.of(300)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleLongScore.of(100)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleLongScore.of(0)); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java index 613d4c0335..34605e4820 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java @@ -27,19 +27,19 @@ void impact() { var impacter = buildScoreImpacter(constraintWeight); var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; - var undo1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); + var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleScore.of(100)); - var undo2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); + var impact2 = impacter.impactScore(20, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleScore.of(300)); - undo2.run(); + impact2.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleScore.of(100)); - undo1.run(); + impact1.undo(); assertThat(scoreInliner.extractScore()) .isEqualTo(SimpleScore.of(0)); } From 57a9ecb7dc38f4b2bbf702cb27d74f8d289d4bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Mon, 5 Jan 2026 16:00:22 +0100 Subject: [PATCH 04/10] Allocate less in bendable --- .../BendableBigDecimalScoreContext.java | 58 +++++++++---------- .../inliner/BendableLongScoreContext.java | 54 ++++++++--------- .../common/inliner/BendableScoreContext.java | 52 +++++++---------- .../HardMediumSoftBigDecimalScoreContext.java | 42 ++++++-------- .../HardMediumSoftLongScoreContext.java | 14 ++--- .../inliner/HardMediumSoftScoreContext.java | 13 ++--- .../HardSoftBigDecimalScoreContext.java | 30 +++++----- .../inliner/HardSoftLongScoreContext.java | 11 ++-- .../common/inliner/HardSoftScoreContext.java | 11 ++-- .../stream/common/inliner/ScoreContext.java | 10 ++-- .../inliner/SimpleBigDecimalScoreContext.java | 9 ++- .../inliner/SimpleLongScoreContext.java | 8 +-- .../common/inliner/SimpleScoreContext.java | 8 +-- .../BendableBigDecimalScoreInlinerTest.java | 8 +-- .../inliner/BendableLongScoreInlinerTest.java | 8 +-- .../inliner/BendableScoreInlinerTest.java | 8 +-- ...dMediumSoftBigDecimalScoreInlinerTest.java | 8 +-- .../HardMediumSoftLongScoreInlinerTest.java | 8 +-- .../HardMediumSoftScoreInlinerTest.java | 8 +-- .../HardSoftBigDecimalScoreInlinerTest.java | 6 +- .../inliner/HardSoftLongScoreInlinerTest.java | 6 +- .../inliner/HardSoftScoreInlinerTest.java | 6 +- .../SimpleBigDecimalScoreInlinerTest.java | 2 +- .../inliner/SimpleLongScoreInlinerTest.java | 2 +- .../inliner/SimpleScoreInlinerTest.java | 2 +- 25 files changed, 176 insertions(+), 216 deletions(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java index 3f176ec22f..558c2aa8a2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java @@ -32,9 +32,8 @@ public BendableBigDecimalScoreContext(BendableBigDecimalScoreInliner parent, Abs public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var softImpact = scoreLevelWeight.multiply(matchWeight); - parent.softScores[scoreLevel] = parent.softScores[scoreLevel].add(softImpact); - var scoreImpact = - new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); + inliner.softScores[scoreLevel] = inliner.softScores[scoreLevel].add(softImpact); + var scoreImpact = new SingleSoftImpact(this, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -44,9 +43,8 @@ public ScoreImpact changeSoftScoreBy(BigDecimal matchWe public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = scoreLevelWeight.multiply(matchWeight); - parent.hardScores[scoreLevel] = parent.hardScores[scoreLevel].add(hardImpact); - var scoreImpact = - new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); + inliner.hardScores[scoreLevel] = inliner.hardScores[scoreLevel].add(hardImpact); + var scoreImpact = new SingleHardImpact(this, hardImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -60,15 +58,14 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { var hardImpact = constraintWeight.hardScore(hardScoreLevel).multiply(matchWeight); hardImpacts[hardScoreLevel] = hardImpact; - parent.hardScores[hardScoreLevel] = parent.hardScores[hardScoreLevel].add(hardImpact); + inliner.hardScores[hardScoreLevel] = inliner.hardScores[hardScoreLevel].add(hardImpact); } for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { var softImpact = constraintWeight.softScore(softScoreLevel).multiply(matchWeight); softImpacts[softScoreLevel] = softImpact; - parent.softScores[softScoreLevel] = parent.softScores[softScoreLevel].add(softImpact); + inliner.softScores[softScoreLevel] = inliner.softScores[softScoreLevel].add(softImpact); } - var scoreImpact = - new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -76,66 +73,65 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight } @NullMarked - private record SingleSoftLevelScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, - int softScoreLevelCount, int scoreLevel, BigDecimal impact) - implements - ScoreImpact { + private record SingleSoftImpact(BendableBigDecimalScoreContext ctx, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.softScores[scoreLevel] = inliner.softScores[scoreLevel].subtract(impact); + var inliner = ctx.inliner; + var level = ctx.scoreLevel; + inliner.softScores[level] = inliner.softScores[level].subtract(impact); } @Override public BendableBigDecimalScore toScore() { - return BendableBigDecimalScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableBigDecimalScore.ofSoft(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record SingleHardLevelScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, - int softScoreLevelCount, int scoreLevel, BigDecimal impact) - implements - ScoreImpact { + private record SingleHardImpact(BendableBigDecimalScoreContext ctx, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.hardScores[scoreLevel] = inliner.hardScores[scoreLevel].subtract(impact); + var inliner = ctx.inliner; + var level = ctx.scoreLevel; + inliner.hardScores[level] = inliner.hardScores[level].subtract(impact); } @Override public BendableBigDecimalScore toScore() { - return BendableBigDecimalScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableBigDecimalScore.ofHard(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record ComplexScoreImpact(BendableBigDecimalScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, - BigDecimal[] hardImpacts, BigDecimal[] softImpacts) - implements - ScoreImpact { + private record ComplexImpact(BendableBigDecimalScoreContext ctx, BigDecimal[] hardImpacts, + BigDecimal[] softImpacts) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var inliner = ctx.inliner; + for (var hardScoreLevel = 0; hardScoreLevel < ctx.hardScoreLevelCount; hardScoreLevel++) { inliner.hardScores[hardScoreLevel] = inliner.hardScores[hardScoreLevel].subtract(hardImpacts[hardScoreLevel]); } - for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + for (var softScoreLevel = 0; softScoreLevel < ctx.softScoreLevelCount; softScoreLevel++) { inliner.softScores[softScoreLevel] = inliner.softScores[softScoreLevel].subtract(softImpacts[softScoreLevel]); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java index 7c3aa52e73..93028a8ad3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java @@ -30,9 +30,8 @@ public BendableLongScoreContext(BendableLongScoreInliner parent, AbstractConstra public ScoreImpact changeSoftScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var softImpact = scoreLevelWeight * matchWeight; - parent.softScores[scoreLevel] += softImpact; - var scoreImpact = - new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); + inliner.softScores[scoreLevel] += softImpact; + var scoreImpact = new SingleSoftImpact(this, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -42,9 +41,8 @@ public ScoreImpact changeSoftScoreBy(long matchWeight, public ScoreImpact changeHardScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = scoreLevelWeight * matchWeight; - parent.hardScores[scoreLevel] += hardImpact; - var scoreImpact = - new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); + inliner.hardScores[scoreLevel] += hardImpact; + var scoreImpact = new SingleHardImpact(this, hardImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -58,15 +56,14 @@ public ScoreImpact changeScoreBy(long matchWeight, for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { var hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; hardImpacts[hardScoreLevel] = hardImpact; - parent.hardScores[hardScoreLevel] += hardImpact; + inliner.hardScores[hardScoreLevel] += hardImpact; } for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { var softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; softImpacts[softScoreLevel] = softImpact; - parent.softScores[softScoreLevel] += softImpact; + inliner.softScores[softScoreLevel] += softImpact; } - var scoreImpact = - new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -74,66 +71,61 @@ public ScoreImpact changeScoreBy(long matchWeight, } @NullMarked - private record SingleSoftLevelScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, - int softScoreLevelCount, int scoreLevel, long impact) - implements - ScoreImpact { + private record SingleSoftImpact(BendableLongScoreContext ctx, + long impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.softScores[scoreLevel] -= impact; + ctx.inliner.softScores[ctx.scoreLevel] -= impact; } @Override public BendableLongScore toScore() { - return BendableLongScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableLongScore.ofSoft(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record SingleHardLevelScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, - int softScoreLevelCount, int scoreLevel, long impact) - implements - ScoreImpact { + private record SingleHardImpact(BendableLongScoreContext ctx, + long impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.hardScores[scoreLevel] -= impact; + ctx.inliner.hardScores[ctx.scoreLevel] -= impact; } @Override public BendableLongScore toScore() { - return BendableLongScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableLongScore.ofHard(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record ComplexScoreImpact(BendableLongScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, - long[] hardImpacts, long[] softImpacts) - implements - ScoreImpact { + private record ComplexImpact(BendableLongScoreContext ctx, long[] hardImpacts, + long[] softImpacts) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var inliner = ctx.inliner; + for (var hardScoreLevel = 0; hardScoreLevel < ctx.hardScoreLevelCount; hardScoreLevel++) { inliner.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; } - for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + for (var softScoreLevel = 0; softScoreLevel < ctx.softScoreLevelCount; softScoreLevel++) { inliner.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java index ee099578df..3e0216cc0c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java @@ -30,9 +30,8 @@ public BendableScoreContext(BendableScoreInliner parent, AbstractConstraint changeSoftScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var softImpact = scoreLevelWeight * matchWeight; - parent.softScores[scoreLevel] += softImpact; - var scoreImpact = - new SingleSoftLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, softImpact); + inliner.softScores[scoreLevel] += softImpact; + var scoreImpact = new SingleSoftImpact(this, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -42,9 +41,8 @@ public ScoreImpact changeSoftScoreBy(int matchWeight, public ScoreImpact changeHardScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = scoreLevelWeight * matchWeight; - parent.hardScores[scoreLevel] += hardImpact; - var scoreImpact = - new SingleHardLevelScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, scoreLevel, hardImpact); + inliner.hardScores[scoreLevel] += hardImpact; + var scoreImpact = new SingleHardImpact(this, hardImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -58,15 +56,14 @@ public ScoreImpact changeScoreBy(int matchWeight, for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { var hardImpact = constraintWeight.hardScore(hardScoreLevel) * matchWeight; hardImpacts[hardScoreLevel] = hardImpact; - parent.hardScores[hardScoreLevel] += hardImpact; + inliner.hardScores[hardScoreLevel] += hardImpact; } for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { var softImpact = constraintWeight.softScore(softScoreLevel) * matchWeight; softImpacts[softScoreLevel] = softImpact; - parent.softScores[softScoreLevel] += softImpact; + inliner.softScores[softScoreLevel] += softImpact; } - var scoreImpact = - new ComplexScoreImpact(parent, hardScoreLevelCount, softScoreLevelCount, hardImpacts, softImpacts); + var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -74,66 +71,59 @@ public ScoreImpact changeScoreBy(int matchWeight, } @NullMarked - private record SingleSoftLevelScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, - int scoreLevel, int impact) - implements - ScoreImpact { + private record SingleSoftImpact(BendableScoreContext ctx, int impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.softScores[scoreLevel] -= impact; + ctx.inliner.softScores[ctx.scoreLevel] -= impact; } @Override public BendableScore toScore() { - return BendableScore.ofSoft(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableScore.ofSoft(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record SingleHardLevelScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, - int scoreLevel, int impact) - implements - ScoreImpact { + private record SingleHardImpact(BendableScoreContext ctx, int impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - inliner.hardScores[scoreLevel] -= impact; + ctx.inliner.hardScores[ctx.scoreLevel] -= impact; } @Override public BendableScore toScore() { - return BendableScore.ofHard(hardScoreLevelCount, softScoreLevelCount, scoreLevel, impact); + return BendableScore.ofHard(ctx.hardScoreLevelCount, ctx.softScoreLevelCount, ctx.scoreLevel, impact); } } @NullMarked - private record ComplexScoreImpact(BendableScoreInliner inliner, int hardScoreLevelCount, int softScoreLevelCount, - int[] hardImpacts, int[] softImpacts) - implements - ScoreImpact { + private record ComplexImpact(BendableScoreContext ctx, int[] hardImpacts, + int[] softImpacts) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { - return inliner; + return ctx.inliner; } @Override public void undo() { - for (var hardScoreLevel = 0; hardScoreLevel < hardScoreLevelCount; hardScoreLevel++) { + var inliner = ctx.inliner; + for (var hardScoreLevel = 0; hardScoreLevel < ctx.hardScoreLevelCount; hardScoreLevel++) { inliner.hardScores[hardScoreLevel] -= hardImpacts[hardScoreLevel]; } - for (var softScoreLevel = 0; softScoreLevel < softScoreLevelCount; softScoreLevel++) { + for (var softScoreLevel = 0; softScoreLevel < ctx.softScoreLevelCount; softScoreLevel++) { inliner.softScores[softScoreLevel] -= softImpacts[softScoreLevel]; } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java index f8a28a2de3..810c8643bc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java @@ -18,8 +18,8 @@ public HardMediumSoftBigDecimalScoreContext(HardMediumSoftBigDecimalScoreInliner public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var softImpact = constraintWeight.softScore().multiply(matchWeight); - parent.softScore = parent.softScore.add(softImpact); - var scoreImpact = new SoftBigDecimalImpact(parent, softImpact); + inliner.softScore = inliner.softScore.add(softImpact); + var scoreImpact = new SoftImpact(inliner, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -29,8 +29,8 @@ public ScoreImpact changeSoftScoreBy(BigDecimal m public ScoreImpact changeMediumScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); - parent.mediumScore = parent.mediumScore.add(mediumImpact); - var scoreImpact = new MediumBigDecimalImpact(parent, mediumImpact); + inliner.mediumScore = inliner.mediumScore.add(mediumImpact); + var scoreImpact = new MediumImpact(inliner, mediumImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -40,8 +40,8 @@ public ScoreImpact changeMediumScoreBy(BigDecimal public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore().multiply(matchWeight); - parent.hardScore = parent.hardScore.add(hardImpact); - var scoreImpact = new HardBigDecimalImpact(parent, hardImpact); + inliner.hardScore = inliner.hardScore.add(hardImpact); + var scoreImpact = new HardImpact(inliner, hardImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -53,10 +53,10 @@ public ScoreImpact changeScoreBy(BigDecimal match var hardImpact = constraintWeight.hardScore().multiply(matchWeight); var mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); var softImpact = constraintWeight.softScore().multiply(matchWeight); - parent.hardScore = parent.hardScore.add(hardImpact); - parent.mediumScore = parent.mediumScore.add(mediumImpact); - parent.softScore = parent.softScore.add(softImpact); - var scoreImpact = new HardMediumSoftBigDecimalImpact(parent, hardImpact, mediumImpact, softImpact); + inliner.hardScore = inliner.hardScore.add(hardImpact); + inliner.mediumScore = inliner.mediumScore.add(mediumImpact); + inliner.softScore = inliner.softScore.add(softImpact); + var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -64,9 +64,8 @@ public ScoreImpact changeScoreBy(BigDecimal match } @NullMarked - private record SoftBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record SoftImpact(HardMediumSoftBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { @@ -86,9 +85,8 @@ public HardMediumSoftBigDecimalScore toScore() { } @NullMarked - private record MediumBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record MediumImpact(HardMediumSoftBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { @@ -108,9 +106,8 @@ public HardMediumSoftBigDecimalScore toScore() { } @NullMarked - private record HardBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record HardImpact(HardMediumSoftBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { @@ -130,10 +127,9 @@ public HardMediumSoftBigDecimalScore toScore() { } @NullMarked - private record HardMediumSoftBigDecimalImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, - BigDecimal mediumImpact, BigDecimal softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, + BigDecimal mediumImpact, + BigDecimal softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java index 32c5a1b0ef..9ec8fce1a9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java @@ -17,10 +17,10 @@ public ScoreImpact changeScoreBy(long matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; var mediumImpact = constraintWeight.mediumScore() * matchWeight; var softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.mediumScore += mediumImpact; - parent.softScore += softImpact; - var scoreImpact = new HardMediumSoftLongImpact(parent, hardImpact, mediumImpact, softImpact); + inliner.hardScore += hardImpact; + inliner.mediumScore += mediumImpact; + inliner.softScore += softImpact; + var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -28,10 +28,8 @@ public ScoreImpact changeScoreBy(long matchWeight, } @NullMarked - private record HardMediumSoftLongImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact, long mediumImpact, - long softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact, long mediumImpact, + long softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java index 7273c63e2f..41eb08791a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java @@ -17,10 +17,10 @@ public ScoreImpact changeScoreBy(int matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; var mediumImpact = constraintWeight.mediumScore() * matchWeight; var softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.mediumScore += mediumImpact; - parent.softScore += softImpact; - var scoreImpact = new HardMediumSoftImpact(parent, hardImpact, mediumImpact, softImpact); + inliner.hardScore += hardImpact; + inliner.mediumScore += mediumImpact; + inliner.softScore += softImpact; + var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -28,9 +28,8 @@ public ScoreImpact changeScoreBy(int matchWeight, } @NullMarked - private record HardMediumSoftImpact(HardMediumSoftScoreInliner inliner, int hardImpact, int mediumImpact, int softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardMediumSoftScoreInliner inliner, int hardImpact, int mediumImpact, + int softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java index 09fde84dd0..66174eb130 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java @@ -17,8 +17,8 @@ public HardSoftBigDecimalScoreContext(HardSoftBigDecimalScoreInliner parent, Abs public ScoreImpact changeSoftScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var softImpact = constraintWeight.softScore().multiply(matchWeight); - parent.softScore = parent.softScore.add(softImpact); - var scoreImpact = new SoftBigDecimalImpact(parent, softImpact); + inliner.softScore = inliner.softScore.add(softImpact); + var scoreImpact = new SoftImpact(inliner, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -28,8 +28,8 @@ public ScoreImpact changeSoftScoreBy(BigDecimal matchWe public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore().multiply(matchWeight); - parent.hardScore = parent.hardScore.add(hardImpact); - var scoreImpact = new HardBigDecimalImpact(parent, hardImpact); + inliner.hardScore = inliner.hardScore.add(hardImpact); + var scoreImpact = new HardImpact(inliner, hardImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -40,9 +40,9 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore().multiply(matchWeight); var softImpact = constraintWeight.softScore().multiply(matchWeight); - parent.hardScore = parent.hardScore.add(hardImpact); - parent.softScore = parent.softScore.add(softImpact); - var scoreImpact = new HardSoftBigDecimalImpact(parent, hardImpact, softImpact); + inliner.hardScore = inliner.hardScore.add(hardImpact); + inliner.softScore = inliner.softScore.add(softImpact); + var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -50,9 +50,8 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight } @NullMarked - private record SoftBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record SoftImpact(HardSoftBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { @@ -72,9 +71,8 @@ public HardSoftBigDecimalScore toScore() { } @NullMarked - private record HardBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record HardImpact(HardSoftBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { @@ -94,10 +92,8 @@ public HardSoftBigDecimalScore toScore() { } @NullMarked - private record HardSoftBigDecimalImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, - BigDecimal softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, + BigDecimal softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java index 5f4d8023c9..6b55c59ca1 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java @@ -16,9 +16,9 @@ public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; var softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.softScore += softImpact; - var scoreImpact = new HardSoftLongImpact(parent, hardImpact, softImpact); + inliner.hardScore += hardImpact; + inliner.softScore += softImpact; + var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -26,9 +26,8 @@ public ScoreImpact changeScoreBy(long matchWeight, } @NullMarked - private record HardSoftLongImpact(HardSoftLongScoreInliner inliner, long hardImpact, long softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardSoftLongScoreInliner inliner, long hardImpact, + long softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java index 0108649aeb..d2f37b6359 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java @@ -16,9 +16,9 @@ public ScoreImpact changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; var softImpact = constraintWeight.softScore() * matchWeight; - parent.hardScore += hardImpact; - parent.softScore += softImpact; - var scoreImpact = new HardSoftImpact(parent, hardImpact, softImpact); + inliner.hardScore += hardImpact; + inliner.softScore += softImpact; + var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -26,9 +26,8 @@ public ScoreImpact changeScoreBy(int matchWeight, } @NullMarked - private record HardSoftImpact(HardSoftScoreInliner inliner, int hardImpact, int softImpact) - implements - ScoreImpact { + private record ComplexImpact(HardSoftScoreInliner inliner, int hardImpact, + int softImpact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java index 9b9e8164d0..248cb3a0da 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java @@ -6,16 +6,16 @@ public abstract class ScoreContext, ScoreInliner_ extends AbstractScoreInliner> { - protected final ScoreInliner_ parent; + protected final ScoreInliner_ inliner; protected final AbstractConstraint constraint; protected final Score_ constraintWeight; protected final ConstraintMatchPolicy constraintMatchPolicy; - protected ScoreContext(ScoreInliner_ parent, AbstractConstraint constraint, Score_ constraintWeight) { - this.parent = parent; + protected ScoreContext(ScoreInliner_ inliner, AbstractConstraint constraint, Score_ constraintWeight) { + this.inliner = inliner; this.constraint = constraint; this.constraintWeight = constraintWeight; - this.constraintMatchPolicy = parent.constraintMatchPolicy; + this.constraintMatchPolicy = inliner.constraintMatchPolicy; } public AbstractConstraint getConstraint() { @@ -28,7 +28,7 @@ public Score_ getConstraintWeight() { protected ScoreImpact impactWithConstraintMatch(ScoreImpact scoreImpact, ConstraintMatchSupplier constraintMatchSupplier) { - return parent.addConstraintMatch(constraint, constraintMatchSupplier, scoreImpact); + return inliner.addConstraintMatch(constraint, constraintMatchSupplier, scoreImpact); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java index 592b838596..c5508844e6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java @@ -17,8 +17,8 @@ public SimpleBigDecimalScoreContext(SimpleBigDecimalScoreInliner parent, Abstrac public ScoreImpact changeScoreBy(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var impact = constraintWeight.score().multiply(matchWeight); - parent.score = parent.score.add(impact); - var scoreImpact = new SimpleBigDecimalImpact(parent, impact); + inliner.score = inliner.score.add(impact); + var scoreImpact = new Impact(inliner, impact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -26,9 +26,8 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight, } @NullMarked - private record SimpleBigDecimalImpact(SimpleBigDecimalScoreInliner inliner, BigDecimal impact) - implements - ScoreImpact { + private record Impact(SimpleBigDecimalScoreInliner inliner, + BigDecimal impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java index 79777a0437..6143064812 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java @@ -15,8 +15,8 @@ public SimpleLongScoreContext(SimpleLongScoreInliner parent, AbstractConstraint< public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var impact = constraintWeight.score() * matchWeight; - parent.score += impact; - var scoreImpact = new SimpleLongImpact(parent, impact); + inliner.score += impact; + var scoreImpact = new Impact(inliner, impact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -24,9 +24,7 @@ public ScoreImpact changeScoreBy(long matchWeight, } @NullMarked - private record SimpleLongImpact(SimpleLongScoreInliner inliner, long impact) - implements - ScoreImpact { + private record Impact(SimpleLongScoreInliner inliner, long impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java index af9a978739..b1edff4221 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java @@ -14,8 +14,8 @@ public SimpleScoreContext(SimpleScoreInliner parent, AbstractConstraint public ScoreImpact changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var impact = constraintWeight.score() * matchWeight; - parent.score += impact; - var scoreImpact = new SimpleLongImpact(parent, impact); + inliner.score += impact; + var scoreImpact = new Impact(inliner, impact); if (!constraintMatchPolicy.isEnabled()) { return scoreImpact; } @@ -23,9 +23,7 @@ public ScoreImpact changeScoreBy(int matchWeight, } @NullMarked - private record SimpleLongImpact(SimpleScoreInliner inliner, int impact) - implements - ScoreImpact { + private record Impact(SimpleScoreInliner inliner, int impact) implements ScoreImpact { @Override public AbstractScoreInliner scoreInliner() { diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java index 55ebac3199..140afa431c 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInlinerTest.java @@ -26,7 +26,7 @@ void defaultScore() { @Test void impactHard() { var impacter = buildScoreImpacter(buildScore(90, 0, 0)); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -48,7 +48,7 @@ void impactHard() { @Test void impactSoft1() { var impacter = buildScoreImpacter(buildScore(0, 90, 0)); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -70,7 +70,7 @@ void impactSoft1() { @Test void impactSoft2() { var impacter = buildScoreImpacter(buildScore(0, 0, 90)); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -92,7 +92,7 @@ void impactSoft2() { @Test void impactAll() { var impacter = buildScoreImpacter(buildScore(10, 100, 1_000)); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java index e4abcd2786..36f10ffeaf 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impactHard() { var constraintWeight = buildScore(90, 0, 0); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -48,7 +48,7 @@ void impactHard() { void impactSoft1() { var constraintWeight = buildScore(0, 90, 0); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -71,7 +71,7 @@ void impactSoft1() { void impactSoft2() { var constraintWeight = buildScore(0, 0, 90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -94,7 +94,7 @@ void impactSoft2() { void impactAll() { var constraintWeight = buildScore(10, 100, 1_000); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java index b6ccd825d7..4c27c4c943 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impactHard() { var constraintWeight = buildScore(90, 0, 0); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -48,7 +48,7 @@ void impactHard() { void impactSoft1() { var constraintWeight = buildScore(0, 90, 0); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -71,7 +71,7 @@ void impactSoft1() { void impactSoft2() { var constraintWeight = buildScore(0, 0, 90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -94,7 +94,7 @@ void impactSoft2() { void impactAll() { var constraintWeight = buildScore(10, 100, 1_000); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java index 66f44c4a68..3776263b25 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInlinerTest.java @@ -27,7 +27,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardMediumSoftBigDecimalScore.ofHard(BigDecimal.valueOf(90)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -50,7 +50,7 @@ void impactHard() { void impactMedium() { var constraintWeight = HardMediumSoftBigDecimalScore.ofMedium(BigDecimal.valueOf(90)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -73,7 +73,7 @@ void impactMedium() { void impactSoft() { var constraintWeight = HardMediumSoftBigDecimalScore.ofSoft(BigDecimal.valueOf(90)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -97,7 +97,7 @@ void impactAll() { var constraintWeight = HardMediumSoftBigDecimalScore.of(BigDecimal.valueOf(10), BigDecimal.valueOf(100), BigDecimal.valueOf(1_000)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java index 19692c0a62..f9243c059b 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInlinerTest.java @@ -26,7 +26,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardMediumSoftLongScore.ofHard(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -49,7 +49,7 @@ void impactHard() { void impactMedium() { var constraintWeight = HardMediumSoftLongScore.ofMedium(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -72,7 +72,7 @@ void impactMedium() { void impactSoft() { var constraintWeight = HardMediumSoftLongScore.ofSoft(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -95,7 +95,7 @@ void impactSoft() { void impactAll() { var constraintWeight = HardMediumSoftLongScore.of(10, 100, 1_000); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java index 3cb66b12b0..5b3560c5d1 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInlinerTest.java @@ -26,7 +26,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardMediumSoftScore.ofHard(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -49,7 +49,7 @@ void impactHard() { void impactMedium() { var constraintWeight = HardMediumSoftScore.ofMedium(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -72,7 +72,7 @@ void impactMedium() { void impactSoft() { var constraintWeight = HardMediumSoftScore.ofSoft(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -95,7 +95,7 @@ void impactSoft() { void impactAll() { var constraintWeight = HardMediumSoftScore.of(10, 100, 1_000); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java index b9dbfcb38e..f48239e313 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInlinerTest.java @@ -27,7 +27,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardSoftBigDecimalScore.ofHard(BigDecimal.valueOf(90)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -50,7 +50,7 @@ void impactHard() { void impactSoft() { var constraintWeight = HardSoftBigDecimalScore.ofSoft(BigDecimal.valueOf(90)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.ONE, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -73,7 +73,7 @@ void impactSoft() { void impactAll() { var constraintWeight = HardSoftBigDecimalScore.of(BigDecimal.valueOf(10), BigDecimal.valueOf(100)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java index 7ff9f402db..3c7ba2568f 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardSoftLongScore.ofHard(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -48,7 +48,7 @@ void impactHard() { void impactSoft() { var constraintWeight = HardSoftLongScore.ofSoft(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -71,7 +71,7 @@ void impactSoft() { void impactAll() { var constraintWeight = HardSoftLongScore.of(10, 100); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java index a33d489fc5..14b6cbe1af 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impactHard() { var constraintWeight = HardSoftScore.ofHard(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -48,7 +48,7 @@ void impactHard() { void impactSoft() { var constraintWeight = HardSoftScore.ofSoft(90); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(1, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) @@ -71,7 +71,7 @@ void impactSoft() { void impactAll() { var constraintWeight = HardSoftScore.of(10, 100); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java index f2b365125e..d56550d9df 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInlinerTest.java @@ -27,7 +27,7 @@ void defaultScore() { void impact() { var constraintWeight = SimpleBigDecimalScore.of(BigDecimal.valueOf(10)); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(BigDecimal.TEN, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java index 44e8804bfc..2434259932 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impact() { var constraintWeight = SimpleLongScore.of(10); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java index 34605e4820..9d43f9dc05 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInlinerTest.java @@ -25,7 +25,7 @@ void defaultScore() { void impact() { var constraintWeight = SimpleScore.of(10); var impacter = buildScoreImpacter(constraintWeight); - var scoreInliner = (AbstractScoreInliner) impacter.getContext().parent; + var scoreInliner = (AbstractScoreInliner) impacter.getContext().inliner; var impact1 = impacter.impactScore(10, ConstraintMatchSupplier.empty()); assertThat(scoreInliner.extractScore()) From e858fc7803e4631d2478542a89605d69928f0145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Mon, 5 Jan 2026 16:28:07 +0100 Subject: [PATCH 05/10] Limit the impacts --- .../inliner/BendableLongScoreInliner.java | 27 +++--- .../common/inliner/BendableScoreInliner.java | 14 ++- .../BigDecimalWeightedScoreImpacter.java | 3 +- .../HardMediumSoftLongScoreContext.java | 96 +++++++++++++++++++ .../HardMediumSoftLongScoreInliner.java | 21 +++- .../inliner/HardMediumSoftScoreContext.java | 96 +++++++++++++++++++ .../inliner/HardMediumSoftScoreInliner.java | 13 ++- .../inliner/HardSoftLongScoreContext.java | 64 +++++++++++++ .../inliner/HardSoftLongScoreInliner.java | 17 +++- .../common/inliner/HardSoftScoreContext.java | 62 ++++++++++++ .../common/inliner/HardSoftScoreInliner.java | 13 ++- .../inliner/SimpleBigDecimalScoreInliner.java | 3 +- .../inliner/SimpleLongScoreInliner.java | 7 +- .../common/inliner/SimpleScoreInliner.java | 3 +- 14 files changed, 396 insertions(+), 43 deletions(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInliner.java index 7319b9716b..4bee7050f9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreInliner.java @@ -14,8 +14,7 @@ public final class BendableLongScoreInliner extends AbstractScoreInliner constraintWeightMap, - ConstraintMatchPolicy constraintMatchPolicy, - int hardLevelsSize, int softLevelsSize) { + ConstraintMatchPolicy constraintMatchPolicy, int hardLevelsSize, int softLevelsSize) { super(constraintWeightMap, constraintMatchPolicy); hardScores = new long[hardLevelsSize]; softScores = new long[softLevelsSize]; @@ -40,27 +39,29 @@ public final class BendableLongScoreInliner extends AbstractScoreInliner constraintMatchSupplier) -> ctx.changeHardScoreBy(impact, - constraintMatchSupplier)); + return WeightedScoreImpacter.of(context, + (BendableLongScoreContext ctx, long impact, + ConstraintMatchSupplier constraintMatchSupplier) -> ctx + .changeHardScoreBy(impact, constraintMatchSupplier)); } else { - return WeightedScoreImpacter.of(context, (BendableLongScoreContext ctx, long impact, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx.changeSoftScoreBy(impact, - constraintMatchSupplier)); + return WeightedScoreImpacter.of(context, + (BendableLongScoreContext ctx, long impact, + ConstraintMatchSupplier constraintMatchSupplier) -> ctx + .changeSoftScoreBy(impact, constraintMatchSupplier)); } } else { BendableLongScoreContext context = new BendableLongScoreContext(this, constraint, constraintWeight, hardScores.length, softScores.length); - return WeightedScoreImpacter.of(context, (BendableLongScoreContext ctx, long impact, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx.changeScoreBy(impact, - constraintMatchSupplier)); + return WeightedScoreImpacter.of(context, + (BendableLongScoreContext ctx, long impact, + ConstraintMatchSupplier constraintMatchSupplier) -> ctx.changeScoreBy(impact, + constraintMatchSupplier)); } } @Override public BendableLongScore extractScore() { - return BendableLongScore.of(Arrays.copyOf(hardScores, hardScores.length), - Arrays.copyOf(softScores, softScores.length)); + return BendableLongScore.of(Arrays.copyOf(hardScores, hardScores.length), Arrays.copyOf(softScores, softScores.length)); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInliner.java index def141d858..b845265d47 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreInliner.java @@ -14,8 +14,7 @@ final class BendableScoreInliner extends AbstractScoreInliner { final int[] softScores; BendableScoreInliner(Map constraintWeightMap, ConstraintMatchPolicy constraintMatchPolicy, - int hardLevelsSize, - int softLevelsSize) { + int hardLevelsSize, int softLevelsSize) { super(constraintWeightMap, constraintMatchPolicy); hardScores = new int[hardLevelsSize]; softScores = new int[softLevelsSize]; @@ -37,24 +36,23 @@ final class BendableScoreInliner extends AbstractScoreInliner { if (singleLevel != null) { boolean isHardScore = singleLevel < constraintWeight.hardLevelsSize(); int level = isHardScore ? singleLevel : singleLevel - constraintWeight.hardLevelsSize(); - BendableScoreContext context = new BendableScoreContext(this, constraint, constraintWeight, - hardScores.length, softScores.length, level, constraintWeight.hardOrSoftScore(singleLevel)); + BendableScoreContext context = new BendableScoreContext(this, constraint, constraintWeight, hardScores.length, + softScores.length, level, constraintWeight.hardOrSoftScore(singleLevel)); if (isHardScore) { return WeightedScoreImpacter.of(context, BendableScoreContext::changeHardScoreBy); } else { return WeightedScoreImpacter.of(context, BendableScoreContext::changeSoftScoreBy); } } else { - BendableScoreContext context = new BendableScoreContext(this, constraint, constraintWeight, - hardScores.length, softScores.length); + BendableScoreContext context = + new BendableScoreContext(this, constraint, constraintWeight, hardScores.length, softScores.length); return WeightedScoreImpacter.of(context, BendableScoreContext::changeScoreBy); } } @Override public BendableScore extractScore() { - return BendableScore.of(Arrays.copyOf(hardScores, hardScores.length), - Arrays.copyOf(softScores, softScores.length)); + return BendableScore.of(Arrays.copyOf(hardScores, hardScores.length), Arrays.copyOf(softScores, softScores.length)); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java index 447ff17ac0..8e6286c223 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java @@ -11,8 +11,7 @@ final class BigDecimalWeightedScoreImpacter, Contex private final BigDecimalImpactFunction impactFunction; private final Context_ context; - public BigDecimalWeightedScoreImpacter(BigDecimalImpactFunction impactFunction, - Context_ context) { + public BigDecimalWeightedScoreImpacter(BigDecimalImpactFunction impactFunction, Context_ context) { this.impactFunction = Objects.requireNonNull(impactFunction); this.context = context; } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java index 9ec8fce1a9..c7dbc114fa 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java @@ -12,6 +12,39 @@ public HardMediumSoftLongScoreContext(HardMediumSoftLongScoreInliner parent, Abs super(parent, constraint, constraintWeight); } + public ScoreImpact changeSoftScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var softImpact = constraintWeight.softScore() * matchWeight; + inliner.softScore += softImpact; + var scoreImpact = new SoftImpact(inliner, softImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeMediumScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var mediumImpact = constraintWeight.mediumScore() * matchWeight; + inliner.mediumScore += mediumImpact; + var scoreImpact = new MediumImpact(inliner, mediumImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeHardScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var hardImpact = constraintWeight.hardScore() * matchWeight; + inliner.hardScore += hardImpact; + var scoreImpact = new HardImpact(inliner, hardImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; @@ -27,6 +60,69 @@ public ScoreImpact changeScoreBy(long matchWeight, return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } + @NullMarked + private record SoftImpact(HardMediumSoftLongScoreInliner inliner, + long softImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScore -= softImpact; + } + + @Override + public HardMediumSoftLongScore toScore() { + return HardMediumSoftLongScore.ofSoft(softImpact); + } + + } + + @NullMarked + private record MediumImpact(HardMediumSoftLongScoreInliner inliner, + long mediumImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.mediumScore -= mediumImpact; + } + + @Override + public HardMediumSoftLongScore toScore() { + return HardMediumSoftLongScore.ofMedium(mediumImpact); + } + + } + + @NullMarked + private record HardImpact(HardMediumSoftLongScoreInliner inliner, + long hardImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore -= hardImpact; + } + + @Override + public HardMediumSoftLongScore toScore() { + return HardMediumSoftLongScore.ofHard(hardImpact); + } + + } + @NullMarked private record ComplexImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact, long mediumImpact, long softImpact) implements ScoreImpact { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java index 0244a95499..d167f459b2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreInliner.java @@ -6,6 +6,7 @@ import ai.timefold.solver.core.api.score.stream.Constraint; import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchPolicy; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter.LongImpactFunction; final class HardMediumSoftLongScoreInliner extends AbstractScoreInliner { @@ -22,11 +23,23 @@ final class HardMediumSoftLongScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); + var softConstraintWeight = constraintWeight.softScore(); + var mediumConstraintWeight = constraintWeight.mediumScore(); + var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardMediumSoftLongScoreContext(this, constraint, constraintWeight); - return WeightedScoreImpacter.of(context, - (HardMediumSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeScoreBy(matchWeight, constraintMatchSupplier)); + if (mediumConstraintWeight == 0 && softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardMediumSoftLongScoreContext::changeHardScoreBy); + } else if (hardConstraintWeight == 0 && softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardMediumSoftLongScoreContext::changeMediumScoreBy); + } else if (hardConstraintWeight == 0 && mediumConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardMediumSoftLongScoreContext::changeSoftScoreBy); + } else { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardMediumSoftLongScoreContext::changeScoreBy); + } } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java index 41eb08791a..b88de99409 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java @@ -12,6 +12,39 @@ public HardMediumSoftScoreContext(HardMediumSoftScoreInliner parent, AbstractCon super(parent, constraint, constraintWeight); } + public ScoreImpact changeSoftScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var softImpact = constraintWeight.softScore() * matchWeight; + inliner.softScore += softImpact; + var scoreImpact = new SoftImpact(inliner, softImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeMediumScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var mediumImpact = constraintWeight.mediumScore() * matchWeight; + inliner.mediumScore += mediumImpact; + var scoreImpact = new MediumImpact(inliner, mediumImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeHardScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var hardImpact = constraintWeight.hardScore() * matchWeight; + inliner.hardScore += hardImpact; + var scoreImpact = new HardImpact(inliner, hardImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + public ScoreImpact changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; @@ -27,6 +60,69 @@ public ScoreImpact changeScoreBy(int matchWeight, return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } + @NullMarked + private record SoftImpact(HardMediumSoftScoreInliner inliner, + int softImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScore -= softImpact; + } + + @Override + public HardMediumSoftScore toScore() { + return HardMediumSoftScore.ofSoft(softImpact); + } + + } + + @NullMarked + private record MediumImpact(HardMediumSoftScoreInliner inliner, + int mediumImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.mediumScore -= mediumImpact; + } + + @Override + public HardMediumSoftScore toScore() { + return HardMediumSoftScore.ofMedium(mediumImpact); + } + + } + + @NullMarked + private record HardImpact(HardMediumSoftScoreInliner inliner, + int hardImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore -= hardImpact; + } + + @Override + public HardMediumSoftScore toScore() { + return HardMediumSoftScore.ofHard(hardImpact); + } + + } + @NullMarked private record ComplexImpact(HardMediumSoftScoreInliner inliner, int hardImpact, int mediumImpact, int softImpact) implements ScoreImpact { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java index fe33065d5c..e9802ca7aa 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreInliner.java @@ -22,8 +22,19 @@ final class HardMediumSoftScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); + var softConstraintWeight = constraintWeight.softScore(); + var mediumConstraintWeight = constraintWeight.mediumScore(); + var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardMediumSoftScoreContext(this, constraint, constraintWeight); - return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeScoreBy); + if (mediumConstraintWeight == 0 && softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeHardScoreBy); + } else if (hardConstraintWeight == 0 && softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeMediumScoreBy); + } else if (hardConstraintWeight == 0 && mediumConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeSoftScoreBy); + } else { + return WeightedScoreImpacter.of(context, HardMediumSoftScoreContext::changeScoreBy); + } } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java index 6b55c59ca1..651e4e4e53 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java @@ -12,6 +12,28 @@ public HardSoftLongScoreContext(HardSoftLongScoreInliner parent, AbstractConstra super(parent, constraint, constraintWeight); } + public ScoreImpact changeSoftScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var softImpact = constraintWeight.softScore() * matchWeight; + inliner.softScore += softImpact; + var scoreImpact = new SoftImpact(inliner, softImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeHardScoreBy(long matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var hardImpact = constraintWeight.hardScore() * matchWeight; + inliner.hardScore += hardImpact; + var scoreImpact = new HardImpact(inliner, hardImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + public ScoreImpact changeScoreBy(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; @@ -25,6 +47,48 @@ public ScoreImpact changeScoreBy(long matchWeight, return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } + @NullMarked + private record SoftImpact(HardSoftLongScoreInliner inliner, + long softImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScore -= softImpact; + } + + @Override + public HardSoftLongScore toScore() { + return HardSoftLongScore.ofSoft(softImpact); + } + + } + + @NullMarked + private record HardImpact(HardSoftLongScoreInliner inliner, + long hardImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore -= hardImpact; + } + + @Override + public HardSoftLongScore toScore() { + return HardSoftLongScore.ofHard(hardImpact); + } + + } + @NullMarked private record ComplexImpact(HardSoftLongScoreInliner inliner, long hardImpact, long softImpact) implements ScoreImpact { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java index be071cf052..5abafdca75 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java @@ -6,6 +6,7 @@ import ai.timefold.solver.core.api.score.stream.Constraint; import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchPolicy; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; +import ai.timefold.solver.core.impl.score.stream.common.inliner.WeightedScoreImpacter.LongImpactFunction; final class HardSoftLongScoreInliner extends AbstractScoreInliner { @@ -20,11 +21,19 @@ final class HardSoftLongScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); + var softConstraintWeight = constraintWeight.softScore(); + var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardSoftLongScoreContext(this, constraint, constraintWeight); - return WeightedScoreImpacter.of(context, - (HardSoftLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeScoreBy(matchWeight, constraintMatchSupplier)); + if (softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardSoftLongScoreContext::changeHardScoreBy); + } else if (hardConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardSoftLongScoreContext::changeSoftScoreBy); + } else { + return WeightedScoreImpacter.of(context, + (LongImpactFunction) HardSoftLongScoreContext::changeScoreBy); + } } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java index d2f37b6359..68119f0209 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java @@ -12,6 +12,28 @@ public HardSoftScoreContext(HardSoftScoreInliner parent, AbstractConstraint changeSoftScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var softImpact = constraintWeight.softScore() * matchWeight; + inliner.softScore += softImpact; + var scoreImpact = new SoftImpact(inliner, softImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + + public ScoreImpact changeHardScoreBy(int matchWeight, + ConstraintMatchSupplier constraintMatchSupplier) { + var hardImpact = constraintWeight.hardScore() * matchWeight; + inliner.hardScore += hardImpact; + var scoreImpact = new HardImpact(inliner, hardImpact); + if (!constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } + return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + } + public ScoreImpact changeScoreBy(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { var hardImpact = constraintWeight.hardScore() * matchWeight; @@ -25,6 +47,46 @@ public ScoreImpact changeScoreBy(int matchWeight, return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); } + @NullMarked + private record SoftImpact(HardSoftScoreInliner inliner, int softImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.softScore -= softImpact; + } + + @Override + public HardSoftScore toScore() { + return HardSoftScore.ofSoft(softImpact); + } + + } + + @NullMarked + private record HardImpact(HardSoftScoreInliner inliner, int hardImpact) implements ScoreImpact { + + @Override + public AbstractScoreInliner scoreInliner() { + return inliner; + } + + @Override + public void undo() { + inliner.hardScore -= hardImpact; + } + + @Override + public HardSoftScore toScore() { + return HardSoftScore.ofHard(hardImpact); + } + + } + @NullMarked private record ComplexImpact(HardSoftScoreInliner inliner, int hardImpact, int softImpact) implements ScoreImpact { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java index f929b0577b..111c3c11b5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java @@ -17,11 +17,18 @@ final class HardSoftScoreInliner extends AbstractScoreInliner { } @Override - public WeightedScoreImpacter buildWeightedScoreImpacter( - AbstractConstraint constraint) { + public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); + var softConstraintWeight = constraintWeight.softScore(); + var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardSoftScoreContext(this, constraint, constraintWeight); - return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeScoreBy); + if (softConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeHardScoreBy); + } else if (hardConstraintWeight == 0) { + return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeSoftScoreBy); + } else { + return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeScoreBy); + } } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java index ba35f0c278..4d0a325cef 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java @@ -18,8 +18,7 @@ final class SimpleBigDecimalScoreInliner extends AbstractScoreInliner - buildWeightedScoreImpacter(AbstractConstraint constraint) { + public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { SimpleBigDecimalScore constraintWeight = constraintWeightMap.get(constraint); SimpleBigDecimalScoreContext context = new SimpleBigDecimalScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, SimpleBigDecimalScoreContext::changeScoreBy); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java index a4bd04562e..3741b7781a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreInliner.java @@ -16,14 +16,13 @@ final class SimpleLongScoreInliner extends AbstractScoreInliner } @Override - public WeightedScoreImpacter buildWeightedScoreImpacter( - AbstractConstraint constraint) { + public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); var context = new SimpleLongScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, (SimpleLongScoreContext ctx, long matchWeight, - ConstraintMatchSupplier constraintMatchSupplier) -> ctx - .changeScoreBy(matchWeight, constraintMatchSupplier)); + ConstraintMatchSupplier constraintMatchSupplier) -> ctx.changeScoreBy(matchWeight, + constraintMatchSupplier)); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java index a207a1599d..d702a507ba 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreInliner.java @@ -16,8 +16,7 @@ final class SimpleScoreInliner extends AbstractScoreInliner { } @Override - public WeightedScoreImpacter buildWeightedScoreImpacter( - AbstractConstraint constraint) { + public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); var context = new SimpleScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, SimpleScoreContext::changeScoreBy); From 19d650b9fcd6ab22d4aa3dea7c13f6ae65f33755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Mon, 5 Jan 2026 16:30:56 +0100 Subject: [PATCH 06/10] var --- .../inliner/BendableBigDecimalScoreInliner.java | 12 ++++++------ .../common/inliner/BendableLongScoreInliner.java | 12 ++++++------ .../stream/common/inliner/BendableScoreInliner.java | 12 ++++++------ .../HardMediumSoftBigDecimalScoreInliner.java | 10 +++++----- .../inliner/HardSoftBigDecimalScoreInliner.java | 4 ++-- .../common/inliner/SimpleBigDecimalScoreInliner.java | 4 ++-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInliner.java index d8d045d902..2d962b9481 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreInliner.java @@ -27,8 +27,8 @@ final class BendableBigDecimalScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { Integer singleLevel = null; - BendableBigDecimalScore constraintWeight = constraintWeightMap.get(constraint); - for (int i = 0; i < constraintWeight.levelsSize(); i++) { + var constraintWeight = constraintWeightMap.get(constraint); + for (var i = 0; i < constraintWeight.levelsSize(); i++) { if (!constraintWeight.hardOrSoftScore(i).equals(BigDecimal.ZERO)) { if (singleLevel != null) { singleLevel = null; @@ -38,9 +38,9 @@ final class BendableBigDecimalScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { Integer singleLevel = null; - BendableLongScore constraintWeight = constraintWeightMap.get(constraint); - for (int i = 0; i < constraintWeight.levelsSize(); i++) { + var constraintWeight = constraintWeightMap.get(constraint); + for (var i = 0; i < constraintWeight.levelsSize(); i++) { if (constraintWeight.hardOrSoftScore(i) != 0L) { if (singleLevel != null) { singleLevel = null; @@ -34,9 +34,9 @@ public final class BendableLongScoreInliner extends AbstractScoreInliner { @Override public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { Integer singleLevel = null; - BendableScore constraintWeight = constraintWeightMap.get(constraint); - for (int i = 0; i < constraintWeight.levelsSize(); i++) { + var constraintWeight = constraintWeightMap.get(constraint); + for (var i = 0; i < constraintWeight.levelsSize(); i++) { if (constraintWeight.hardOrSoftScore(i) != 0L) { if (singleLevel != null) { singleLevel = null; @@ -34,9 +34,9 @@ final class BendableScoreInliner extends AbstractScoreInliner { } } if (singleLevel != null) { - boolean isHardScore = singleLevel < constraintWeight.hardLevelsSize(); - int level = isHardScore ? singleLevel : singleLevel - constraintWeight.hardLevelsSize(); - BendableScoreContext context = new BendableScoreContext(this, constraint, constraintWeight, hardScores.length, + var isHardScore = singleLevel < constraintWeight.hardLevelsSize(); + var level = isHardScore ? singleLevel : singleLevel - constraintWeight.hardLevelsSize(); + var context = new BendableScoreContext(this, constraint, constraintWeight, hardScores.length, softScores.length, level, constraintWeight.hardOrSoftScore(singleLevel)); if (isHardScore) { return WeightedScoreImpacter.of(context, BendableScoreContext::changeHardScoreBy); @@ -44,7 +44,7 @@ final class BendableScoreInliner extends AbstractScoreInliner { return WeightedScoreImpacter.of(context, BendableScoreContext::changeSoftScoreBy); } } else { - BendableScoreContext context = + var context = new BendableScoreContext(this, constraint, constraintWeight, hardScores.length, softScores.length); return WeightedScoreImpacter.of(context, BendableScoreContext::changeScoreBy); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInliner.java index 6c9709b07a..b6fc880d00 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreInliner.java @@ -22,11 +22,11 @@ final class HardMediumSoftBigDecimalScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - HardMediumSoftBigDecimalScore constraintWeight = constraintWeightMap.get(constraint); - BigDecimal hardConstraintWeight = constraintWeight.hardScore(); - BigDecimal mediumConstraintWeight = constraintWeight.mediumScore(); - BigDecimal softConstraintWeight = constraintWeight.softScore(); - HardMediumSoftBigDecimalScoreContext context = + var constraintWeight = constraintWeightMap.get(constraint); + var hardConstraintWeight = constraintWeight.hardScore(); + var mediumConstraintWeight = constraintWeight.mediumScore(); + var softConstraintWeight = constraintWeight.softScore(); + var context = new HardMediumSoftBigDecimalScoreContext(this, constraint, constraintWeight); if (mediumConstraintWeight.equals(BigDecimal.ZERO) && softConstraintWeight.equals(BigDecimal.ZERO)) { return WeightedScoreImpacter.of(context, HardMediumSoftBigDecimalScoreContext::changeHardScoreBy); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInliner.java index 5d0ece87eb..b3e64da08d 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreInliner.java @@ -21,8 +21,8 @@ final class HardSoftBigDecimalScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - HardSoftBigDecimalScore constraintWeight = constraintWeightMap.get(constraint); - HardSoftBigDecimalScoreContext context = new HardSoftBigDecimalScoreContext(this, constraint, constraintWeight); + var constraintWeight = constraintWeightMap.get(constraint); + var context = new HardSoftBigDecimalScoreContext(this, constraint, constraintWeight); if (constraintWeight.softScore().equals(BigDecimal.ZERO)) { return WeightedScoreImpacter.of(context, HardSoftBigDecimalScoreContext::changeHardScoreBy); } else if (constraintWeight.hardScore().equals(BigDecimal.ZERO)) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java index 4d0a325cef..723120dd5e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreInliner.java @@ -19,8 +19,8 @@ final class SimpleBigDecimalScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { - SimpleBigDecimalScore constraintWeight = constraintWeightMap.get(constraint); - SimpleBigDecimalScoreContext context = new SimpleBigDecimalScoreContext(this, constraint, constraintWeight); + var constraintWeight = constraintWeightMap.get(constraint); + var context = new SimpleBigDecimalScoreContext(this, constraint, constraintWeight); return WeightedScoreImpacter.of(context, SimpleBigDecimalScoreContext::changeScoreBy); } From 2c8ed1fb90fe06468c207c09cff8b0009832471e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Mon, 5 Jan 2026 16:42:50 +0100 Subject: [PATCH 07/10] Reuse code --- .../common/inliner/AbstractScoreInliner.java | 12 ++---- .../BendableBigDecimalScoreContext.java | 30 ++------------ .../inliner/BendableLongScoreContext.java | 30 ++------------ .../common/inliner/BendableScoreContext.java | 30 ++------------ .../HardMediumSoftBigDecimalScoreContext.java | 40 ++----------------- .../HardMediumSoftLongScoreContext.java | 40 ++----------------- .../inliner/HardMediumSoftScoreContext.java | 40 ++----------------- .../HardSoftBigDecimalScoreContext.java | 30 ++------------ .../inliner/HardSoftLongScoreContext.java | 30 ++------------ .../inliner/HardSoftLongScoreInliner.java | 6 +-- .../common/inliner/HardSoftScoreContext.java | 30 ++------------ .../common/inliner/HardSoftScoreInliner.java | 6 +-- .../stream/common/inliner/ScoreContext.java | 18 ++++----- .../stream/common/inliner/ScoreImpact.java | 2 - .../inliner/SimpleBigDecimalScoreContext.java | 10 +---- .../inliner/SimpleLongScoreContext.java | 10 +---- .../common/inliner/SimpleScoreContext.java | 10 +---- 17 files changed, 50 insertions(+), 324 deletions(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java index e80a0286cd..60a3a61a3c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/AbstractScoreInliner.java @@ -153,24 +153,20 @@ protected final ScoreImpact addConstraintMatch(Constraint constraint, */ var entry = constraintMatchList.add(new ConstraintMatchCarrier<>(constraintMatchSupplier, constraint, scoreImpact)); clearMaps(); - return new WrappingScoreImpact<>(scoreImpact, entry); + return new WrappingScoreImpact<>(this, scoreImpact, entry); } - private record WrappingScoreImpact>(ScoreImpact delegate, + private record WrappingScoreImpact>(AbstractScoreInliner inliner, + ScoreImpact delegate, ElementAwareLinkedList.Entry> entry) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return delegate.scoreInliner(); - } - @Override public void undo() { delegate.undo(); entry.remove(); - delegate.scoreInliner().clearMaps(); + inliner.clearMaps(); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java index 558c2aa8a2..1daabd6186 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java @@ -34,10 +34,7 @@ public ScoreImpact changeSoftScoreBy(BigDecimal matchWe var softImpact = scoreLevelWeight.multiply(matchWeight); inliner.softScores[scoreLevel] = inliner.softScores[scoreLevel].add(softImpact); var scoreImpact = new SingleSoftImpact(this, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, @@ -45,10 +42,7 @@ public ScoreImpact changeHardScoreBy(BigDecimal matchWe var hardImpact = scoreLevelWeight.multiply(matchWeight); inliner.hardScores[scoreLevel] = inliner.hardScores[scoreLevel].add(hardImpact); var scoreImpact = new SingleHardImpact(this, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(BigDecimal matchWeight, @@ -66,21 +60,13 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight inliner.softScores[softScoreLevel] = inliner.softScores[softScoreLevel].add(softImpact); } var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SingleSoftImpact(BendableBigDecimalScoreContext ctx, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { var inliner = ctx.inliner; @@ -98,11 +84,6 @@ public BendableBigDecimalScore toScore() { private record SingleHardImpact(BendableBigDecimalScoreContext ctx, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { var inliner = ctx.inliner; @@ -120,11 +101,6 @@ public BendableBigDecimalScore toScore() { private record ComplexImpact(BendableBigDecimalScoreContext ctx, BigDecimal[] hardImpacts, BigDecimal[] softImpacts) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { var inliner = ctx.inliner; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java index 93028a8ad3..1a1eaa0ebf 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java @@ -32,10 +32,7 @@ public ScoreImpact changeSoftScoreBy(long matchWeight, var softImpact = scoreLevelWeight * matchWeight; inliner.softScores[scoreLevel] += softImpact; var scoreImpact = new SingleSoftImpact(this, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(long matchWeight, @@ -43,10 +40,7 @@ public ScoreImpact changeHardScoreBy(long matchWeight, var hardImpact = scoreLevelWeight * matchWeight; inliner.hardScores[scoreLevel] += hardImpact; var scoreImpact = new SingleHardImpact(this, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(long matchWeight, @@ -64,21 +58,13 @@ public ScoreImpact changeScoreBy(long matchWeight, inliner.softScores[softScoreLevel] += softImpact; } var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SingleSoftImpact(BendableLongScoreContext ctx, long impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { ctx.inliner.softScores[ctx.scoreLevel] -= impact; @@ -94,11 +80,6 @@ public BendableLongScore toScore() { private record SingleHardImpact(BendableLongScoreContext ctx, long impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { ctx.inliner.hardScores[ctx.scoreLevel] -= impact; @@ -114,11 +95,6 @@ public BendableLongScore toScore() { private record ComplexImpact(BendableLongScoreContext ctx, long[] hardImpacts, long[] softImpacts) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { var inliner = ctx.inliner; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java index 3e0216cc0c..76ff1fddcc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java @@ -32,10 +32,7 @@ public ScoreImpact changeSoftScoreBy(int matchWeight, var softImpact = scoreLevelWeight * matchWeight; inliner.softScores[scoreLevel] += softImpact; var scoreImpact = new SingleSoftImpact(this, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(int matchWeight, @@ -43,10 +40,7 @@ public ScoreImpact changeHardScoreBy(int matchWeight, var hardImpact = scoreLevelWeight * matchWeight; inliner.hardScores[scoreLevel] += hardImpact; var scoreImpact = new SingleHardImpact(this, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(int matchWeight, @@ -64,20 +58,12 @@ public ScoreImpact changeScoreBy(int matchWeight, inliner.softScores[softScoreLevel] += softImpact; } var scoreImpact = new ComplexImpact(this, hardImpacts, softImpacts); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SingleSoftImpact(BendableScoreContext ctx, int impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { ctx.inliner.softScores[ctx.scoreLevel] -= impact; @@ -92,11 +78,6 @@ public BendableScore toScore() { @NullMarked private record SingleHardImpact(BendableScoreContext ctx, int impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { ctx.inliner.hardScores[ctx.scoreLevel] -= impact; @@ -112,11 +93,6 @@ public BendableScore toScore() { private record ComplexImpact(BendableScoreContext ctx, int[] hardImpacts, int[] softImpacts) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return ctx.inliner; - } - @Override public void undo() { var inliner = ctx.inliner; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java index 810c8643bc..7ddbf4e386 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftBigDecimalScoreContext.java @@ -20,10 +20,7 @@ public ScoreImpact changeSoftScoreBy(BigDecimal m var softImpact = constraintWeight.softScore().multiply(matchWeight); inliner.softScore = inliner.softScore.add(softImpact); var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeMediumScoreBy(BigDecimal matchWeight, @@ -31,10 +28,7 @@ public ScoreImpact changeMediumScoreBy(BigDecimal var mediumImpact = constraintWeight.mediumScore().multiply(matchWeight); inliner.mediumScore = inliner.mediumScore.add(mediumImpact); var scoreImpact = new MediumImpact(inliner, mediumImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, @@ -42,10 +36,7 @@ public ScoreImpact changeHardScoreBy(BigDecimal m var hardImpact = constraintWeight.hardScore().multiply(matchWeight); inliner.hardScore = inliner.hardScore.add(hardImpact); var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(BigDecimal matchWeight, @@ -57,21 +48,13 @@ public ScoreImpact changeScoreBy(BigDecimal match inliner.mediumScore = inliner.mediumScore.add(mediumImpact); inliner.softScore = inliner.softScore.add(softImpact); var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore = inliner.softScore.subtract(impact); @@ -88,11 +71,6 @@ public HardMediumSoftBigDecimalScore toScore() { private record MediumImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.mediumScore = inliner.mediumScore.subtract(impact); @@ -109,11 +87,6 @@ public HardMediumSoftBigDecimalScore toScore() { private record HardImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore = inliner.hardScore.subtract(impact); @@ -131,11 +104,6 @@ private record ComplexImpact(HardMediumSoftBigDecimalScoreInliner inliner, BigDe BigDecimal mediumImpact, BigDecimal softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore = inliner.hardScore.subtract(hardImpact); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java index c7dbc114fa..278bce0410 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftLongScoreContext.java @@ -17,10 +17,7 @@ public ScoreImpact changeSoftScoreBy(long matchWeight, var softImpact = constraintWeight.softScore() * matchWeight; inliner.softScore += softImpact; var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeMediumScoreBy(long matchWeight, @@ -28,10 +25,7 @@ public ScoreImpact changeMediumScoreBy(long matchWeight var mediumImpact = constraintWeight.mediumScore() * matchWeight; inliner.mediumScore += mediumImpact; var scoreImpact = new MediumImpact(inliner, mediumImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(long matchWeight, @@ -39,10 +33,7 @@ public ScoreImpact changeHardScoreBy(long matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; inliner.hardScore += hardImpact; var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(long matchWeight, @@ -54,21 +45,13 @@ public ScoreImpact changeScoreBy(long matchWeight, inliner.mediumScore += mediumImpact; inliner.softScore += softImpact; var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardMediumSoftLongScoreInliner inliner, long softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore -= softImpact; @@ -85,11 +68,6 @@ public HardMediumSoftLongScore toScore() { private record MediumImpact(HardMediumSoftLongScoreInliner inliner, long mediumImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.mediumScore -= mediumImpact; @@ -106,11 +84,6 @@ public HardMediumSoftLongScore toScore() { private record HardImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; @@ -127,11 +100,6 @@ public HardMediumSoftLongScore toScore() { private record ComplexImpact(HardMediumSoftLongScoreInliner inliner, long hardImpact, long mediumImpact, long softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java index b88de99409..7af7b7bf27 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardMediumSoftScoreContext.java @@ -17,10 +17,7 @@ public ScoreImpact changeSoftScoreBy(int matchWeight, var softImpact = constraintWeight.softScore() * matchWeight; inliner.softScore += softImpact; var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeMediumScoreBy(int matchWeight, @@ -28,10 +25,7 @@ public ScoreImpact changeMediumScoreBy(int matchWeight, var mediumImpact = constraintWeight.mediumScore() * matchWeight; inliner.mediumScore += mediumImpact; var scoreImpact = new MediumImpact(inliner, mediumImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(int matchWeight, @@ -39,10 +33,7 @@ public ScoreImpact changeHardScoreBy(int matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; inliner.hardScore += hardImpact; var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(int matchWeight, @@ -54,21 +45,13 @@ public ScoreImpact changeScoreBy(int matchWeight, inliner.mediumScore += mediumImpact; inliner.softScore += softImpact; var scoreImpact = new ComplexImpact(inliner, hardImpact, mediumImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardMediumSoftScoreInliner inliner, int softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore -= softImpact; @@ -85,11 +68,6 @@ public HardMediumSoftScore toScore() { private record MediumImpact(HardMediumSoftScoreInliner inliner, int mediumImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.mediumScore -= mediumImpact; @@ -106,11 +84,6 @@ public HardMediumSoftScore toScore() { private record HardImpact(HardMediumSoftScoreInliner inliner, int hardImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; @@ -127,11 +100,6 @@ public HardMediumSoftScore toScore() { private record ComplexImpact(HardMediumSoftScoreInliner inliner, int hardImpact, int mediumImpact, int softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java index 66174eb130..a7e1db8ca5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftBigDecimalScoreContext.java @@ -19,10 +19,7 @@ public ScoreImpact changeSoftScoreBy(BigDecimal matchWe var softImpact = constraintWeight.softScore().multiply(matchWeight); inliner.softScore = inliner.softScore.add(softImpact); var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(BigDecimal matchWeight, @@ -30,10 +27,7 @@ public ScoreImpact changeHardScoreBy(BigDecimal matchWe var hardImpact = constraintWeight.hardScore().multiply(matchWeight); inliner.hardScore = inliner.hardScore.add(hardImpact); var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(BigDecimal matchWeight, @@ -43,21 +37,13 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight inliner.hardScore = inliner.hardScore.add(hardImpact); inliner.softScore = inliner.softScore.add(softImpact); var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore = inliner.softScore.subtract(impact); @@ -74,11 +60,6 @@ public HardSoftBigDecimalScore toScore() { private record HardImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore = inliner.hardScore.subtract(impact); @@ -95,11 +76,6 @@ public HardSoftBigDecimalScore toScore() { private record ComplexImpact(HardSoftBigDecimalScoreInliner inliner, BigDecimal hardImpact, BigDecimal softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore = inliner.hardScore.subtract(hardImpact); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java index 651e4e4e53..269db98f21 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreContext.java @@ -17,10 +17,7 @@ public ScoreImpact changeSoftScoreBy(long matchWeight, var softImpact = constraintWeight.softScore() * matchWeight; inliner.softScore += softImpact; var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(long matchWeight, @@ -28,10 +25,7 @@ public ScoreImpact changeHardScoreBy(long matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; inliner.hardScore += hardImpact; var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(long matchWeight, @@ -41,21 +35,13 @@ public ScoreImpact changeScoreBy(long matchWeight, inliner.hardScore += hardImpact; inliner.softScore += softImpact; var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardSoftLongScoreInliner inliner, long softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore -= softImpact; @@ -72,11 +58,6 @@ public HardSoftLongScore toScore() { private record HardImpact(HardSoftLongScoreInliner inliner, long hardImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; @@ -93,11 +74,6 @@ public HardSoftLongScore toScore() { private record ComplexImpact(HardSoftLongScoreInliner inliner, long hardImpact, long softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java index 5abafdca75..65c3ea2c22 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftLongScoreInliner.java @@ -21,13 +21,11 @@ final class HardSoftLongScoreInliner extends AbstractScoreInliner buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); - var softConstraintWeight = constraintWeight.softScore(); - var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardSoftLongScoreContext(this, constraint, constraintWeight); - if (softConstraintWeight == 0) { + if (constraintWeight.softScore() == 0) { return WeightedScoreImpacter.of(context, (LongImpactFunction) HardSoftLongScoreContext::changeHardScoreBy); - } else if (hardConstraintWeight == 0) { + } else if (constraintWeight.hardScore() == 0) { return WeightedScoreImpacter.of(context, (LongImpactFunction) HardSoftLongScoreContext::changeSoftScoreBy); } else { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java index 68119f0209..14ab965899 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreContext.java @@ -17,10 +17,7 @@ public ScoreImpact changeSoftScoreBy(int matchWeight, var softImpact = constraintWeight.softScore() * matchWeight; inliner.softScore += softImpact; var scoreImpact = new SoftImpact(inliner, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeHardScoreBy(int matchWeight, @@ -28,10 +25,7 @@ public ScoreImpact changeHardScoreBy(int matchWeight, var hardImpact = constraintWeight.hardScore() * matchWeight; inliner.hardScore += hardImpact; var scoreImpact = new HardImpact(inliner, hardImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } public ScoreImpact changeScoreBy(int matchWeight, @@ -41,20 +35,12 @@ public ScoreImpact changeScoreBy(int matchWeight, inliner.hardScore += hardImpact; inliner.softScore += softImpact; var scoreImpact = new ComplexImpact(inliner, hardImpact, softImpact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record SoftImpact(HardSoftScoreInliner inliner, int softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.softScore -= softImpact; @@ -70,11 +56,6 @@ public HardSoftScore toScore() { @NullMarked private record HardImpact(HardSoftScoreInliner inliner, int hardImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; @@ -91,11 +72,6 @@ public HardSoftScore toScore() { private record ComplexImpact(HardSoftScoreInliner inliner, int hardImpact, int softImpact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.hardScore -= hardImpact; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java index 111c3c11b5..bb0bdae07e 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/HardSoftScoreInliner.java @@ -19,12 +19,10 @@ final class HardSoftScoreInliner extends AbstractScoreInliner { @Override public WeightedScoreImpacter buildWeightedScoreImpacter(AbstractConstraint constraint) { var constraintWeight = constraintWeightMap.get(constraint); - var softConstraintWeight = constraintWeight.softScore(); - var hardConstraintWeight = constraintWeight.hardScore(); var context = new HardSoftScoreContext(this, constraint, constraintWeight); - if (softConstraintWeight == 0) { + if (constraintWeight.softScore() == 0) { return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeHardScoreBy); - } else if (hardConstraintWeight == 0) { + } else if (constraintWeight.hardScore() == 0) { return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeSoftScoreBy); } else { return WeightedScoreImpacter.of(context, HardSoftScoreContext::changeScoreBy); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java index 248cb3a0da..04354f1359 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreContext.java @@ -1,33 +1,33 @@ package ai.timefold.solver.core.impl.score.stream.common.inliner; import ai.timefold.solver.core.api.score.Score; -import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchPolicy; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; public abstract class ScoreContext, ScoreInliner_ extends AbstractScoreInliner> { - protected final ScoreInliner_ inliner; - protected final AbstractConstraint constraint; + private final AbstractConstraint constraint; protected final Score_ constraintWeight; - protected final ConstraintMatchPolicy constraintMatchPolicy; + protected final ScoreInliner_ inliner; protected ScoreContext(ScoreInliner_ inliner, AbstractConstraint constraint, Score_ constraintWeight) { - this.inliner = inliner; this.constraint = constraint; this.constraintWeight = constraintWeight; - this.constraintMatchPolicy = inliner.constraintMatchPolicy; + this.inliner = inliner; } - public AbstractConstraint getConstraint() { + public final AbstractConstraint getConstraint() { return constraint; } - public Score_ getConstraintWeight() { + public final Score_ getConstraintWeight() { return constraintWeight; } - protected ScoreImpact impactWithConstraintMatch(ScoreImpact scoreImpact, + protected final ScoreImpact possiblyAddConstraintMatch(ScoreImpact scoreImpact, ConstraintMatchSupplier constraintMatchSupplier) { + if (!inliner.constraintMatchPolicy.isEnabled()) { + return scoreImpact; + } return inliner.addConstraintMatch(constraint, constraintMatchSupplier, scoreImpact); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java index dfb1ed14b7..6052528e9a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/ScoreImpact.java @@ -4,8 +4,6 @@ public interface ScoreImpact> { - AbstractScoreInliner scoreInliner(); - void undo(); Score_ toScore(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java index c5508844e6..2b21b27010 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleBigDecimalScoreContext.java @@ -19,21 +19,13 @@ public ScoreImpact changeScoreBy(BigDecimal matchWeight, var impact = constraintWeight.score().multiply(matchWeight); inliner.score = inliner.score.add(impact); var scoreImpact = new Impact(inliner, impact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record Impact(SimpleBigDecimalScoreInliner inliner, BigDecimal impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.score = inliner.score.subtract(impact); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java index 6143064812..7e5dbd8757 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleLongScoreContext.java @@ -17,20 +17,12 @@ public ScoreImpact changeScoreBy(long matchWeight, var impact = constraintWeight.score() * matchWeight; inliner.score += impact; var scoreImpact = new Impact(inliner, impact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record Impact(SimpleLongScoreInliner inliner, long impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.score -= impact; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java index b1edff4221..052082a3d7 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/SimpleScoreContext.java @@ -16,20 +16,12 @@ public ScoreImpact changeScoreBy(int matchWeight, var impact = constraintWeight.score() * matchWeight; inliner.score += impact; var scoreImpact = new Impact(inliner, impact); - if (!constraintMatchPolicy.isEnabled()) { - return scoreImpact; - } - return impactWithConstraintMatch(scoreImpact, constraintMatchSupplier); + return possiblyAddConstraintMatch(scoreImpact, constraintMatchSupplier); } @NullMarked private record Impact(SimpleScoreInliner inliner, int impact) implements ScoreImpact { - @Override - public AbstractScoreInliner scoreInliner() { - return inliner; - } - @Override public void undo() { inliner.score -= impact; From a6d37f2cb3e32ae506c7fd9bcea511eab3ca4894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Tue, 6 Jan 2026 07:53:45 +0100 Subject: [PATCH 08/10] Fix a rebase --- .../solver/core/impl/bavet/common/StaticPropagationQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java index ace5d38cb2..bf7ad74a63 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/bavet/common/StaticPropagationQueue.java @@ -92,7 +92,7 @@ public void propagateUpdates() { processAndClear(updateQueue, nextNodesTupleLifecycle::update); } - private static void processAndClear(Deque dirtyQueue, + private static void processAndClear(Deque dirtyQueue, Consumer tupleLifecycle) { while (!dirtyQueue.isEmpty()) { var tuple = dirtyQueue.poll(); From 514dddb046864f26f4fcd13892d09dd6bb332a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Tue, 6 Jan 2026 08:04:51 +0100 Subject: [PATCH 09/10] Sonar --- .../BendableBigDecimalScoreContext.java | 31 ++++++++++++++++++ .../inliner/BendableLongScoreContext.java | 32 +++++++++++++++++++ .../common/inliner/BendableScoreContext.java | 32 +++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java index 1daabd6186..1c403a2f2b 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableBigDecimalScoreContext.java @@ -1,6 +1,8 @@ package ai.timefold.solver.core.impl.score.stream.common.inliner; import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Objects; import ai.timefold.solver.core.api.score.buildin.bendablebigdecimal.BendableBigDecimalScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; @@ -116,6 +118,35 @@ public void undo() { public BendableBigDecimalScore toScore() { return BendableBigDecimalScore.of(hardImpacts, softImpacts); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ComplexImpact that)) { + return false; + } + return Objects.equals(ctx, that.ctx) && + Objects.deepEquals(hardImpacts, that.hardImpacts) && + Objects.deepEquals(softImpacts, that.softImpacts); + } + + @Override + public int hashCode() { + var hash = 1; + hash = 31 * hash + ctx.hashCode(); + hash = 31 * hash + Arrays.hashCode(hardImpacts); + hash = 31 * hash + Arrays.hashCode(softImpacts); + return hash; + } + + @Override + public String toString() { + return "Impact(hard: %s, soft: %s)" + .formatted(Arrays.toString(hardImpacts), Arrays.toString(softImpacts)); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java index 1a1eaa0ebf..61c7a9cb2a 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableLongScoreContext.java @@ -1,5 +1,8 @@ package ai.timefold.solver.core.impl.score.stream.common.inliner; +import java.util.Arrays; +import java.util.Objects; + import ai.timefold.solver.core.api.score.buildin.bendablelong.BendableLongScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; @@ -110,6 +113,35 @@ public void undo() { public BendableLongScore toScore() { return BendableLongScore.of(hardImpacts, softImpacts); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ComplexImpact that)) { + return false; + } + return Objects.equals(ctx, that.ctx) && + Objects.deepEquals(hardImpacts, that.hardImpacts) && + Objects.deepEquals(softImpacts, that.softImpacts); + } + + @Override + public int hashCode() { + var hash = 1; + hash = 31 * hash + ctx.hashCode(); + hash = 31 * hash + Arrays.hashCode(hardImpacts); + hash = 31 * hash + Arrays.hashCode(softImpacts); + return hash; + } + + @Override + public String toString() { + return "Impact(hard: %s, soft: %s)" + .formatted(Arrays.toString(hardImpacts), Arrays.toString(softImpacts)); + } + } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java index 76ff1fddcc..9605111907 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BendableScoreContext.java @@ -1,5 +1,8 @@ package ai.timefold.solver.core.impl.score.stream.common.inliner; +import java.util.Arrays; +import java.util.Objects; + import ai.timefold.solver.core.api.score.buildin.bendable.BendableScore; import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraint; @@ -108,6 +111,35 @@ public void undo() { public BendableScore toScore() { return BendableScore.of(hardImpacts, softImpacts); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ComplexImpact that)) { + return false; + } + return Objects.equals(ctx, that.ctx) && + Objects.deepEquals(hardImpacts, that.hardImpacts) && + Objects.deepEquals(softImpacts, that.softImpacts); + } + + @Override + public int hashCode() { + var hash = 1; + hash = 31 * hash + ctx.hashCode(); + hash = 31 * hash + Arrays.hashCode(hardImpacts); + hash = 31 * hash + Arrays.hashCode(softImpacts); + return hash; + } + + @Override + public String toString() { + return "Impact(hard: %s, soft: %s)" + .formatted(Arrays.toString(hardImpacts), Arrays.toString(softImpacts)); + } + } } From cf91fa53d9a1c87f0581efbcb040820073a162db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Petrovick=C3=BD?= Date: Tue, 6 Jan 2026 17:47:14 +0100 Subject: [PATCH 10/10] Review --- .../BigDecimalWeightedScoreImpacter.java | 12 +++++++--- .../inliner/IntWeightedScoreImpacter.java | 12 +++++++--- .../inliner/LongWeightedScoreImpacter.java | 12 +++++++--- .../common/inliner/WeightedScoreImpacter.java | 23 +++++++++++++------ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java index 8e6286c223..1ed4673e40 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/BigDecimalWeightedScoreImpacter.java @@ -5,6 +5,10 @@ import ai.timefold.solver.core.api.score.Score; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked final class BigDecimalWeightedScoreImpacter, Context_ extends ScoreContext> implements WeightedScoreImpacter { @@ -17,19 +21,21 @@ public BigDecimalWeightedScoreImpacter(BigDecimalImpactFunction impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, BigDecimal.valueOf(matchWeight), constraintMatchSupplier); } @Override - public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, BigDecimal.valueOf(matchWeight), constraintMatchSupplier); } @Override - public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java index 4debbaafc4..854bc83f97 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/IntWeightedScoreImpacter.java @@ -5,6 +5,10 @@ import ai.timefold.solver.core.api.score.Score; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked final class IntWeightedScoreImpacter, Context_ extends ScoreContext> implements WeightedScoreImpacter { @@ -17,18 +21,20 @@ public IntWeightedScoreImpacter(IntImpactFunction impactFuncti } @Override - public ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } @Override - public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing long into an int impacter."); } @Override - public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing BigDecimal into an int impacter."); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java index 0a3310127d..0d2e0e4c49 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/LongWeightedScoreImpacter.java @@ -5,6 +5,10 @@ import ai.timefold.solver.core.api.score.Score; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked final class LongWeightedScoreImpacter, Context_ extends ScoreContext> implements WeightedScoreImpacter { @@ -17,19 +21,21 @@ public LongWeightedScoreImpacter(LongImpactFunction impactFunc } @Override - public ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(int matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); // int can be cast to long } @Override - public ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(long matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { context.getConstraint().assertCorrectImpact(matchWeight); return impactFunction.impact(context, matchWeight, constraintMatchSupplier); } @Override - public ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier) { + public ScoreImpact impactScore(BigDecimal matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier) { throw new UnsupportedOperationException("Impossible state: passing BigDecimal into a long impacter."); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java index 4ac931e025..b40a9f7549 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/inliner/WeightedScoreImpacter.java @@ -4,6 +4,9 @@ import ai.timefold.solver.core.api.score.Score; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + /** * There are several valid ways how an impacter could be called from a constraint stream: * @@ -21,6 +24,7 @@ * for the method types it doesn't support. The CS API guarantees no types are mixed. For example, * a {@link BigDecimal} parameter method won't be called on an instance built with an {@link IntImpactFunction}. */ +@NullMarked public interface WeightedScoreImpacter, Context_ extends ScoreContext> { static , Context_ extends ScoreContext> WeightedScoreImpacter @@ -40,46 +44,51 @@ public interface WeightedScoreImpacter, Context_ ex /** * @param matchWeight never null - * @param constraintMatchSupplier ignored unless constraint match enableds + * @param constraintMatchSupplier ignored unless constraint match enabled * @return never null */ - ScoreImpact impactScore(int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(int matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier); /** * @param matchWeight never null * @param constraintMatchSupplier ignored unless constraint match enabled * @return never null */ - ScoreImpact impactScore(long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(long matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier); /** * @param matchWeight never null * @param constraintMatchSupplier ignored unless constraint match enabled * @return never null */ - ScoreImpact impactScore(BigDecimal matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impactScore(BigDecimal matchWeight, @Nullable ConstraintMatchSupplier constraintMatchSupplier); Context_ getContext(); + @NullMarked @FunctionalInterface interface IntImpactFunction, Context_ extends ScoreContext> { - ScoreImpact impact(Context_ context, int matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impact(Context_ context, int matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier); } + @NullMarked @FunctionalInterface interface LongImpactFunction, Context_ extends ScoreContext> { - ScoreImpact impact(Context_ context, long matchWeight, ConstraintMatchSupplier constraintMatchSupplier); + ScoreImpact impact(Context_ context, long matchWeight, + @Nullable ConstraintMatchSupplier constraintMatchSupplier); } + @NullMarked @FunctionalInterface interface BigDecimalImpactFunction, Context_ extends ScoreContext> { ScoreImpact impact(Context_ context, BigDecimal matchWeight, - ConstraintMatchSupplier constraintMatchSupplier); + @Nullable ConstraintMatchSupplier constraintMatchSupplier); }