|
1 | 1 | package ai.timefold.solver.core.impl.solver; |
2 | 2 |
|
| 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; |
3 | 5 | import static org.assertj.core.api.Assertions.assertThat; |
4 | 6 | import static org.assertj.core.api.Assertions.assertThatCode; |
5 | 7 | import static org.assertj.core.api.Assertions.fail; |
|
39 | 41 | import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicType; |
40 | 42 | import ai.timefold.solver.core.config.constructionheuristic.placer.QueuedEntityPlacerConfig; |
41 | 43 | 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; |
42 | 46 | import ai.timefold.solver.core.config.heuristic.selector.entity.EntitySelectorConfig; |
| 47 | +import ai.timefold.solver.core.config.heuristic.selector.entity.EntitySorterManner; |
43 | 48 | import ai.timefold.solver.core.config.heuristic.selector.entity.pillar.PillarSelectorConfig; |
44 | 49 | import ai.timefold.solver.core.config.heuristic.selector.list.SubListSelectorConfig; |
45 | 50 | import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig; |
|
59 | 64 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListSwapMoveSelectorConfig; |
60 | 65 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.kopt.KOptListMoveSelectorConfig; |
61 | 66 | import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig; |
| 67 | +import ai.timefold.solver.core.config.heuristic.selector.value.ValueSorterManner; |
62 | 68 | import ai.timefold.solver.core.config.heuristic.selector.value.chained.SubChainSelectorConfig; |
63 | 69 | import ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig; |
64 | 70 | import ai.timefold.solver.core.config.localsearch.LocalSearchType; |
|
80 | 86 | import ai.timefold.solver.core.impl.score.DummySimpleScoreEasyScoreCalculator; |
81 | 87 | import ai.timefold.solver.core.impl.score.constraint.DefaultConstraintMatchTotal; |
82 | 88 | import ai.timefold.solver.core.impl.score.constraint.DefaultIndictment; |
| 89 | +import ai.timefold.solver.core.impl.util.Pair; |
83 | 90 | import ai.timefold.solver.core.preview.api.domain.metamodel.PlanningSolutionMetaModel; |
84 | 91 | import ai.timefold.solver.core.preview.api.domain.metamodel.PlanningVariableMetaModel; |
85 | 92 | import ai.timefold.solver.core.testdomain.TestdataEntity; |
@@ -1647,6 +1654,45 @@ void solveMixedModel() { |
1647 | 1654 | .isEmpty(); |
1648 | 1655 | } |
1649 | 1656 |
|
| 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 | + |
1650 | 1696 | @Test |
1651 | 1697 | void solvePinnedMixedModel() { |
1652 | 1698 | // We don't enable the LS because we want to ensure the pinned entity remains uninitialized |
|
0 commit comments