-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: multi-threaded solving support for Ruin and Recreate moves
- Loading branch information
Showing
5 changed files
with
252 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
...va/ai/timefold/solver/core/impl/heuristic/selector/move/generic/RuinRecreateMoveTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package ai.timefold.solver.core.impl.heuristic.selector.move.generic; | ||
|
||
import static ai.timefold.solver.core.impl.testdata.util.PlannerTestUtils.mockRebasingScoreDirector; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.SoftAssertions.assertSoftly; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import ai.timefold.solver.core.impl.domain.variable.descriptor.GenuineVariableDescriptor; | ||
import ai.timefold.solver.core.impl.solver.scope.SolverScope; | ||
import ai.timefold.solver.core.impl.testdata.domain.TestdataEntity; | ||
import ai.timefold.solver.core.impl.testdata.domain.TestdataSolution; | ||
import ai.timefold.solver.core.impl.testdata.domain.TestdataValue; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
class RuinRecreateMoveTest { | ||
|
||
@SuppressWarnings({ "unchecked", "rawtypes" }) | ||
@Test | ||
void rebase() { | ||
var variableDescriptor = TestdataEntity.buildVariableDescriptorForValue(); | ||
|
||
var v1 = new TestdataValue("v1"); | ||
var v2 = new TestdataValue("v2"); | ||
var e1 = new TestdataEntity("e1", v1); | ||
var e2 = new TestdataEntity("e2", null); | ||
var e3 = new TestdataEntity("e3", v1); | ||
|
||
var destinationV1 = new TestdataValue("v1"); | ||
var destinationV2 = new TestdataValue("v2"); | ||
var destinationE1 = new TestdataEntity("e1", destinationV1); | ||
var destinationE2 = new TestdataEntity("e2", null); | ||
var destinationE3 = new TestdataEntity("e3", destinationV1); | ||
|
||
var destinationScoreDirector = mockRebasingScoreDirector( | ||
variableDescriptor.getEntityDescriptor().getSolutionDescriptor(), new Object[][] { | ||
{ v1, destinationV1 }, | ||
{ v2, destinationV2 }, | ||
{ e1, destinationE1 }, | ||
{ e2, destinationE2 }, | ||
{ e3, destinationE3 }, | ||
}); | ||
|
||
var move = new RuinRecreateMove<TestdataSolution>(mock(GenuineVariableDescriptor.class), | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), Arrays.asList(e1, e2, e3), | ||
Set.of(v1, v2)); | ||
var rebasedMove = move.rebase(destinationScoreDirector); | ||
|
||
assertSoftly(softly -> { | ||
softly.assertThat((Collection) rebasedMove.getPlanningEntities()) | ||
.containsExactly(destinationE1, destinationE2, destinationE3); | ||
softly.assertThat((Collection) rebasedMove.getPlanningValues()) | ||
.containsExactlyInAnyOrder(destinationV1, destinationV2); // The input set is not ordered. | ||
}); | ||
|
||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Test | ||
void equality() { | ||
var v1 = new TestdataValue("v1"); | ||
var v2 = new TestdataValue("v2"); | ||
var e1 = new TestdataEntity("e1", v1); | ||
var e2 = new TestdataEntity("e2", null); | ||
|
||
var descriptor = mock(GenuineVariableDescriptor.class); | ||
var move = new RuinRecreateMove<TestdataSolution>(descriptor, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
var sameMove = new RuinRecreateMove<TestdataSolution>(descriptor, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
assertThat(move).isEqualTo(sameMove); | ||
|
||
var differentMove = new RuinRecreateMove<TestdataSolution>(descriptor, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v2)); | ||
assertThat(move).isNotEqualTo(differentMove); | ||
|
||
var anotherDifferentMove = new RuinRecreateMove<TestdataSolution>(descriptor, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e2), | ||
Set.of(v1)); | ||
assertThat(move).isNotEqualTo(anotherDifferentMove); | ||
|
||
var yetAnotherDifferentMove = new RuinRecreateMove<TestdataSolution>(mock(GenuineVariableDescriptor.class), | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
assertThat(move).isNotEqualTo(yetAnotherDifferentMove); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...efold/solver/core/impl/heuristic/selector/move/generic/list/ListRuinRecreateMoveTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package ai.timefold.solver.core.impl.heuristic.selector.move.generic.list; | ||
|
||
import static ai.timefold.solver.core.impl.testdata.util.PlannerTestUtils.mockRebasingScoreDirector; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.SoftAssertions.assertSoftly; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import ai.timefold.solver.core.impl.domain.variable.ListVariableStateSupply; | ||
import ai.timefold.solver.core.impl.heuristic.selector.move.generic.RuinRecreateConstructionHeuristicPhaseBuilder; | ||
import ai.timefold.solver.core.impl.heuristic.selector.move.generic.list.ruin.ListRuinRecreateMove; | ||
import ai.timefold.solver.core.impl.solver.scope.SolverScope; | ||
import ai.timefold.solver.core.impl.testdata.domain.list.TestdataListEntity; | ||
import ai.timefold.solver.core.impl.testdata.domain.list.TestdataListSolution; | ||
import ai.timefold.solver.core.impl.testdata.domain.list.TestdataListValue; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
class ListRuinRecreateMoveTest { | ||
|
||
@SuppressWarnings({ "unchecked", "rawtypes" }) | ||
@Test | ||
void rebase() { | ||
var variableDescriptor = TestdataListEntity.buildVariableDescriptorForValueList(); | ||
|
||
var v1 = new TestdataListValue("v1"); | ||
var v2 = new TestdataListValue("v2"); | ||
var e1 = new TestdataListEntity("e1", v1); | ||
var e2 = new TestdataListEntity("e2"); | ||
var e3 = new TestdataListEntity("e3", v1); | ||
|
||
var destinationV1 = new TestdataListValue("v1"); | ||
var destinationV2 = new TestdataListValue("v2"); | ||
var destinationE1 = new TestdataListEntity("e1", destinationV1); | ||
var destinationE2 = new TestdataListEntity("e2"); | ||
var destinationE3 = new TestdataListEntity("e3", destinationV1); | ||
|
||
var destinationScoreDirector = mockRebasingScoreDirector( | ||
variableDescriptor.getEntityDescriptor().getSolutionDescriptor(), new Object[][] { | ||
{ v1, destinationV1 }, | ||
{ v2, destinationV2 }, | ||
{ e1, destinationE1 }, | ||
{ e2, destinationE2 }, | ||
{ e3, destinationE3 }, | ||
}); | ||
|
||
var move = new ListRuinRecreateMove<TestdataListSolution>(mock(ListVariableStateSupply.class), | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), Arrays.asList(v1, v2), | ||
Set.of(e1, e2, e3)); | ||
var rebasedMove = move.rebase(destinationScoreDirector); | ||
|
||
assertSoftly(softly -> { | ||
softly.assertThat((Collection) rebasedMove.getPlanningEntities()) | ||
.containsExactlyInAnyOrder(destinationE1, destinationE2, destinationE3); // The input set is not ordered. | ||
softly.assertThat((Collection) rebasedMove.getPlanningValues()) | ||
.containsExactly(destinationV1, destinationV2); | ||
}); | ||
|
||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Test | ||
void equality() { | ||
var v1 = new TestdataListValue("v1"); | ||
var v2 = new TestdataListValue("v2"); | ||
var e1 = new TestdataListEntity("e1", v1); | ||
var e2 = new TestdataListEntity("e2"); | ||
|
||
var supply = mock(ListVariableStateSupply.class); | ||
var move = new ListRuinRecreateMove<TestdataListSolution>(supply, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
var sameMove = new ListRuinRecreateMove<TestdataListSolution>(supply, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
assertThat(move).isEqualTo(sameMove); | ||
|
||
var differentMove = new ListRuinRecreateMove<TestdataListSolution>(supply, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v2)); | ||
assertThat(move).isNotEqualTo(differentMove); | ||
|
||
var anotherDifferentMove = new ListRuinRecreateMove<TestdataListSolution>(supply, | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e2), | ||
Set.of(v1)); | ||
assertThat(move).isNotEqualTo(anotherDifferentMove); | ||
|
||
var yetAnotherDifferentMove = new ListRuinRecreateMove<TestdataListSolution>(mock(ListVariableStateSupply.class), | ||
mock(RuinRecreateConstructionHeuristicPhaseBuilder.class), mock(SolverScope.class), List.of(e1), | ||
Set.of(v1)); | ||
assertThat(move).isNotEqualTo(yetAnotherDifferentMove); | ||
} | ||
|
||
} |