Skip to content

Commit 2d4e688

Browse files
committed
test: entity and value sort manner
1 parent bb77190 commit 2d4e688

7 files changed

Lines changed: 96 additions & 6 deletions

File tree

core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/placer/entity/QueuedMultiplePlacerFactoryTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ void testPlacersForConstructionHeuristic() {
7878

7979
placer.solvingStarted(solverScope);
8080
var phaseScope = mock(AbstractPhaseScope.class);
81+
when(phaseScope.getSolverScope()).thenReturn(solverScope);
8182
when(phaseScope.getScoreDirector()).thenReturn(scoreDirector);
8283
placer.phaseStarted(phaseScope);
8384

@@ -195,6 +196,7 @@ void testPinnedPlacersForConstructionHeuristic() {
195196

196197
placer.solvingStarted(solverScope);
197198
var phaseScope = mock(AbstractPhaseScope.class);
199+
when(phaseScope.getSolverScope()).thenReturn(solverScope);
198200
when(phaseScope.getScoreDirector()).thenReturn(scoreDirector);
199201
placer.phaseStarted(phaseScope);
200202

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ai.timefold.solver.core.impl.solver;
22

3+
import static ai.timefold.solver.core.config.heuristic.selector.entity.EntitySorterManner.DECREASING_DIFFICULTY;
4+
import static ai.timefold.solver.core.config.heuristic.selector.entity.EntitySorterManner.DECREASING_DIFFICULTY_IF_AVAILABLE;
35
import static org.assertj.core.api.Assertions.assertThat;
46
import static org.assertj.core.api.Assertions.assertThatCode;
57
import static org.assertj.core.api.Assertions.fail;
@@ -39,7 +41,10 @@
3941
import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicType;
4042
import ai.timefold.solver.core.config.constructionheuristic.placer.QueuedEntityPlacerConfig;
4143
import ai.timefold.solver.core.config.constructionheuristic.placer.QueuedValuePlacerConfig;
44+
import ai.timefold.solver.core.config.heuristic.selector.common.SelectionCacheType;
45+
import ai.timefold.solver.core.config.heuristic.selector.common.SelectionOrder;
4246
import ai.timefold.solver.core.config.heuristic.selector.entity.EntitySelectorConfig;
47+
import ai.timefold.solver.core.config.heuristic.selector.entity.EntitySorterManner;
4348
import ai.timefold.solver.core.config.heuristic.selector.entity.pillar.PillarSelectorConfig;
4449
import ai.timefold.solver.core.config.heuristic.selector.list.SubListSelectorConfig;
4550
import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig;
@@ -59,6 +64,7 @@
5964
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListSwapMoveSelectorConfig;
6065
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.kopt.KOptListMoveSelectorConfig;
6166
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig;
67+
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSorterManner;
6268
import ai.timefold.solver.core.config.heuristic.selector.value.chained.SubChainSelectorConfig;
6369
import ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig;
6470
import ai.timefold.solver.core.config.localsearch.LocalSearchType;
@@ -80,6 +86,7 @@
8086
import ai.timefold.solver.core.impl.score.DummySimpleScoreEasyScoreCalculator;
8187
import ai.timefold.solver.core.impl.score.constraint.DefaultConstraintMatchTotal;
8288
import ai.timefold.solver.core.impl.score.constraint.DefaultIndictment;
89+
import ai.timefold.solver.core.impl.util.Pair;
8390
import ai.timefold.solver.core.preview.api.domain.metamodel.PlanningSolutionMetaModel;
8491
import ai.timefold.solver.core.preview.api.domain.metamodel.PlanningVariableMetaModel;
8592
import ai.timefold.solver.core.testdomain.TestdataEntity;
@@ -1647,6 +1654,45 @@ void solveMixedModel() {
16471654
.isEmpty();
16481655
}
16491656

1657+
private static List<Pair<EntitySorterManner, ValueSorterManner>> getSortMannerList() {
1658+
var sortMannerList = new ArrayList<Pair<EntitySorterManner, ValueSorterManner>>();
1659+
for (var valueSortManner : ValueSorterManner.values()) {
1660+
sortMannerList.add(new Pair<>(DECREASING_DIFFICULTY, valueSortManner));
1661+
sortMannerList.add(new Pair<>(DECREASING_DIFFICULTY_IF_AVAILABLE, valueSortManner));
1662+
}
1663+
return sortMannerList;
1664+
}
1665+
1666+
@ParameterizedTest
1667+
@MethodSource("getSortMannerList")
1668+
void solveMixedModelWithSortManner(Pair<EntitySorterManner, ValueSorterManner> sorterManner) {
1669+
var solverConfig = PlannerTestUtils.buildSolverConfig(
1670+
TestdataMixedSolution.class, TestdataMixedEntity.class, TestdataMixedValue.class,
1671+
TestdataMixedOtherValue.class)
1672+
.withPhases(new ConstructionHeuristicPhaseConfig(),
1673+
new LocalSearchPhaseConfig()
1674+
.withMoveSelectorConfig(
1675+
new ChangeMoveSelectorConfig()
1676+
.withEntitySelectorConfig(new EntitySelectorConfig()
1677+
.withCacheType(SelectionCacheType.PHASE)
1678+
.withSelectionOrder(SelectionOrder.SORTED)
1679+
.withSorterManner(sorterManner.key()))
1680+
.withValueSelectorConfig(
1681+
new ValueSelectorConfig()
1682+
.withVariableName("basicValue")
1683+
.withCacheType(SelectionCacheType.PHASE)
1684+
.withSelectionOrder(SelectionOrder.SORTED)
1685+
.withSorterManner(sorterManner.value())))
1686+
.withTerminationConfig(new TerminationConfig().withStepCountLimit(16)))
1687+
.withEasyScoreCalculatorClass(TestdataMixedEasyScoreCalculator.class);
1688+
1689+
var problem = TestdataMixedSolution.generateUninitializedSolution(2, 2, 2);
1690+
var solution = PlannerTestUtils.solve(solverConfig, problem);
1691+
assertThat(solution.getEntityList().stream()
1692+
.filter(e -> e.getBasicValue() == null || e.getSecondBasicValue() == null || e.getValueList().isEmpty()))
1693+
.isEmpty();
1694+
}
1695+
16501696
@Test
16511697
void solvePinnedMixedModel() {
16521698
// We don't enable the LS because we want to ensure the pinned entity remains uninitialized

core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedEntity.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;
1111
import ai.timefold.solver.core.testdomain.TestdataObject;
1212

13-
@PlanningEntity
13+
@PlanningEntity(difficultyComparatorClass = TestdataMixedEntityComparator.class)
1414
public class TestdataMixedEntity extends TestdataObject {
1515

16-
@PlanningVariable(valueRangeProviderRefs = "otherValueRange")
16+
@PlanningVariable(valueRangeProviderRefs = "otherValueRange", strengthComparatorClass = TestdataMixedOtherValueComparator.class)
1717
private TestdataMixedOtherValue basicValue;
1818

1919
@PlanningVariable(valueRangeProviderRefs = "otherValueRange")
@@ -28,12 +28,15 @@ public class TestdataMixedEntity extends TestdataObject {
2828
@PlanningPinToIndex
2929
private int pinnedIndex = 0;
3030

31+
private int difficulty;
32+
3133
public TestdataMixedEntity() {
3234
// Required for cloner
3335
}
3436

35-
public TestdataMixedEntity(String code) {
37+
public TestdataMixedEntity(String code, int difficulty) {
3638
super(code);
39+
this.difficulty = difficulty;
3740
valueList = new ArrayList<>();
3841
}
3942

@@ -76,4 +79,12 @@ public int getPinnedIndex() {
7679
public void setPinnedIndex(int pinnedIndex) {
7780
this.pinnedIndex = pinnedIndex;
7881
}
82+
83+
public int getDifficulty() {
84+
return difficulty;
85+
}
86+
87+
public void setDifficulty(int difficulty) {
88+
this.difficulty = difficulty;
89+
}
7990
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package ai.timefold.solver.core.testdomain.mixed.singleentity;
2+
3+
import java.util.Comparator;
4+
5+
public class TestdataMixedEntityComparator implements Comparator<TestdataMixedEntity> {
6+
@Override
7+
public int compare(TestdataMixedEntity v1, TestdataMixedEntity v2) {
8+
return v1.getDifficulty() - v2.getDifficulty();
9+
}
10+
}

core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedOtherValue.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ public class TestdataMixedOtherValue extends TestdataObject {
1313
@InverseRelationShadowVariable(sourceVariableName = "basicValue")
1414
private List<TestdataMixedEntity> entityList;
1515

16+
private int strength;
17+
1618
public TestdataMixedOtherValue() {
1719
// Required for cloner
1820
}
1921

20-
public TestdataMixedOtherValue(String code) {
22+
public TestdataMixedOtherValue(String code, int strength) {
2123
super(code);
24+
this.strength = strength;
2225
entityList = new ArrayList<>();
2326
}
2427

@@ -29,4 +32,12 @@ public List<TestdataMixedEntity> getEntityList() {
2932
public void setEntityList(List<TestdataMixedEntity> entityList) {
3033
this.entityList = entityList;
3134
}
35+
36+
public int getStrength() {
37+
return strength;
38+
}
39+
40+
public void setStrength(int strength) {
41+
this.strength = strength;
42+
}
3243
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package ai.timefold.solver.core.testdomain.mixed.singleentity;
2+
3+
import java.util.Comparator;
4+
5+
public class TestdataMixedOtherValueComparator implements Comparator<TestdataMixedOtherValue> {
6+
@Override
7+
public int compare(TestdataMixedOtherValue o1, TestdataMixedOtherValue o2) {
8+
return o1.getStrength() - o2.getStrength();
9+
}
10+
}

core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedSolution.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ public static TestdataMixedSolution generateUninitializedSolution(int entityList
2828
valueList.add(new TestdataMixedValue("Generated Value " + i));
2929
}
3030
for (int i = 0; i < otherValueListSize; i++) {
31-
otherValueList.add(new TestdataMixedOtherValue("Generated Other Value " + i));
31+
otherValueList.add(new TestdataMixedOtherValue("Generated Other Value " + i, valueListSize - i));
3232
}
3333
solution.setValueList(valueList);
3434
solution.setOtherValueList(otherValueList);
3535
var entityList = new ArrayList<TestdataMixedEntity>(entityListSize);
3636
for (int i = 0; i < entityListSize; i++) {
37-
var entity = new TestdataMixedEntity("Entity " + i);
37+
var entity = new TestdataMixedEntity("Entity " + i, i);
3838
entityList.add(entity);
3939
}
4040
solution.setEntityList(entityList);

0 commit comments

Comments
 (0)