Skip to content

Commit 0f74239

Browse files
chore: save split random on step start so we can restore it
This allows move iterators to generate additional moves without affecting the random (and thus reach the same result when those moves are not generated provided the same number of steps).
1 parent 90cc103 commit 0f74239

3 files changed

Lines changed: 10 additions & 3 deletions

File tree

core/src/main/java/ai/timefold/solver/core/impl/solver/AbstractSolver.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Iterator;
44
import java.util.List;
5+
import java.util.random.RandomGenerator;
56

67
import ai.timefold.solver.core.api.domain.solution.PlanningSolution;
78
import ai.timefold.solver.core.api.solver.Solver;
@@ -12,6 +13,7 @@
1213
import ai.timefold.solver.core.impl.phase.scope.AbstractPhaseScope;
1314
import ai.timefold.solver.core.impl.phase.scope.AbstractStepScope;
1415
import ai.timefold.solver.core.impl.solver.event.SolverEventSupport;
16+
import ai.timefold.solver.core.impl.solver.random.DelegatingSplittableRandomGenerator;
1517
import ai.timefold.solver.core.impl.solver.recaller.BestSolutionRecaller;
1618
import ai.timefold.solver.core.impl.solver.scope.SolverScope;
1719
import ai.timefold.solver.core.impl.solver.termination.UniversalTermination;
@@ -44,6 +46,8 @@ public abstract class AbstractSolver<Solution_> implements Solver<Solution_> {
4446
protected final UniversalTermination<Solution_> globalTermination;
4547
protected final List<Phase<Solution_>> phaseList;
4648

49+
private RandomGenerator.SplittableGenerator savedRandom;
50+
4751
// ************************************************************************
4852
// Constructors and simple getters/setters
4953
// ************************************************************************
@@ -123,10 +127,12 @@ public void stepStarted(AbstractStepScope<Solution_> stepScope) {
123127
bestSolutionRecaller.stepStarted(stepScope);
124128
phaseLifecycleSupport.fireStepStarted(stepScope);
125129
globalTermination.stepStarted(stepScope);
130+
savedRandom = ((DelegatingSplittableRandomGenerator) stepScope.getWorkingRandom()).split();
126131
// Do not propagate to phases; the active phase does that for itself and they should not propagate further.
127132
}
128133

129134
public void stepEnded(AbstractStepScope<Solution_> stepScope) {
135+
((DelegatingSplittableRandomGenerator) stepScope.getWorkingRandom()).setDelegate(savedRandom);
130136
bestSolutionRecaller.stepEnded(stepScope);
131137
phaseLifecycleSupport.fireStepEnded(stepScope);
132138
globalTermination.stepEnded(stepScope);

core/src/main/java/ai/timefold/solver/core/impl/solver/random/DefaultRandomFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public DefaultRandomFactory(RandomType randomType, Long randomSeed) {
3232
public RandomGenerator createRandom() {
3333
switch (randomType) {
3434
case JDK:
35-
return randomSeed == null ? new DelegatingSplittableRandomGenerator(new Random().nextLong()) : new DelegatingSplittableRandomGenerator(randomSeed);
35+
return randomSeed == null ? new DelegatingSplittableRandomGenerator(new Random().nextLong())
36+
: new DelegatingSplittableRandomGenerator(randomSeed);
3637
case MERSENNE_TWISTER:
3738
return new RandomAdaptor(randomSeed == null ? new MersenneTwister() : new MersenneTwister(randomSeed));
3839
case WELL512A:

core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,8 +1397,8 @@ void solveStaleBuiltinShadows() {
13971397

13981398
var solution = PlannerTestUtils.solve(solverConfig, problem);
13991399

1400-
assertThat(solution.getEntityList().getFirst().getValue().getCode()).isEqualTo("v1");
1401-
assertThat(solution.getEntityList().get(1).getValue().getCode()).isEqualTo("v2");
1400+
assertThat(solution.getEntityList().getFirst().getValue().getCode()).isEqualTo("v2");
1401+
assertThat(solution.getEntityList().get(1).getValue().getCode()).isEqualTo("v1");
14021402

14031403
assertThat(solution.getScore()).isEqualTo(SimpleScore.of(-2));
14041404
}

0 commit comments

Comments
 (0)