|
5 | 5 |
|
6 | 6 | import ai.timefold.solver.core.config.heuristic.selector.common.SelectionCacheType; |
7 | 7 | import ai.timefold.solver.core.config.heuristic.selector.common.SelectionOrder; |
| 8 | +import ai.timefold.solver.core.config.heuristic.selector.entity.pillar.PillarSelectorConfig; |
| 9 | +import ai.timefold.solver.core.config.heuristic.selector.list.SubListSelectorConfig; |
8 | 10 | import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig; |
9 | 11 | import ai.timefold.solver.core.config.heuristic.selector.move.NearbyAutoConfigurationEnabled; |
10 | 12 | import ai.timefold.solver.core.config.heuristic.selector.move.composite.UnionMoveSelectorConfig; |
11 | 13 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.ChangeMoveSelectorConfig; |
| 14 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarChangeMoveSelectorConfig; |
| 15 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarSwapMoveSelectorConfig; |
| 16 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.RuinRecreateMoveSelectorConfig; |
12 | 17 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.SwapMoveSelectorConfig; |
| 18 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.SubChainChangeMoveSelectorConfig; |
| 19 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.SubChainSwapMoveSelectorConfig; |
13 | 20 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.TailChainSwapMoveSelectorConfig; |
14 | 21 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig; |
| 22 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListRuinRecreateMoveSelectorConfig; |
15 | 23 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListSwapMoveSelectorConfig; |
| 24 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListChangeMoveSelectorConfig; |
| 25 | +import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListSwapMoveSelectorConfig; |
16 | 26 | import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.kopt.KOptListMoveSelectorConfig; |
| 27 | +import ai.timefold.solver.core.config.heuristic.selector.value.chained.SubChainSelectorConfig; |
17 | 28 | import ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig; |
18 | 29 | import ai.timefold.solver.core.config.localsearch.LocalSearchType; |
19 | 30 | import ai.timefold.solver.core.config.localsearch.decider.acceptor.AcceptorType; |
@@ -60,8 +71,9 @@ phaseTermination, buildDecider(phaseConfigPolicy, phaseTermination)) |
60 | 71 | private LocalSearchDecider<Solution_> buildDecider(HeuristicConfigPolicy<Solution_> configPolicy, |
61 | 72 | PhaseTermination<Solution_> termination) { |
62 | 73 | var moveSelector = buildMoveSelector(configPolicy); |
| 74 | + var perturbationMoveSelector = buildPerturbationMoveSelector(configPolicy); |
63 | 75 | var acceptor = buildAcceptor(configPolicy); |
64 | | - RestartStrategy<Solution_> restartStrategy = new AcceptorRestartStrategy<>(acceptor); |
| 76 | + RestartStrategy<Solution_> restartStrategy = new AcceptorRestartStrategy<>(perturbationMoveSelector, acceptor); |
65 | 77 | var forager = buildForager(configPolicy); |
66 | 78 | if (moveSelector.isNeverEnding() && !forager.supportsNeverEndingMoveSelector()) { |
67 | 79 | throw new IllegalStateException("The moveSelector (" + moveSelector |
@@ -188,6 +200,15 @@ protected MoveSelector<Solution_> buildMoveSelector(HeuristicConfigPolicy<Soluti |
188 | 200 | return moveSelector; |
189 | 201 | } |
190 | 202 |
|
| 203 | + @SuppressWarnings("rawtypes") |
| 204 | + protected MoveSelector<Solution_> buildPerturbationMoveSelector(HeuristicConfigPolicy<Solution_> configPolicy) { |
| 205 | + var defaultCacheType = SelectionCacheType.JUST_IN_TIME; |
| 206 | + SelectionOrder defaultSelectionOrder; |
| 207 | + defaultSelectionOrder = SelectionOrder.RANDOM; |
| 208 | + return new UnionMoveSelectorFactory<Solution_>(determinePerturbationMoveSelectorConfig(configPolicy)) |
| 209 | + .buildMoveSelector(configPolicy, defaultCacheType, defaultSelectionOrder, true); |
| 210 | + } |
| 211 | + |
191 | 212 | private UnionMoveSelectorConfig determineDefaultMoveSelectorConfig(HeuristicConfigPolicy<Solution_> configPolicy) { |
192 | 213 | var solutionDescriptor = configPolicy.getSolutionDescriptor(); |
193 | 214 | var basicVariableDescriptorList = solutionDescriptor.getEntityDescriptors().stream() |
@@ -234,4 +255,48 @@ private UnionMoveSelectorConfig determineDefaultMoveSelectorConfig(HeuristicConf |
234 | 255 | .withMoveSelectors(new ChangeMoveSelectorConfig(), new SwapMoveSelectorConfig()); |
235 | 256 | } |
236 | 257 | } |
| 258 | + |
| 259 | + private UnionMoveSelectorConfig determinePerturbationMoveSelectorConfig(HeuristicConfigPolicy<Solution_> configPolicy) { |
| 260 | + var solutionDescriptor = configPolicy.getSolutionDescriptor(); |
| 261 | + var basicVariableDescriptorList = solutionDescriptor.getEntityDescriptors().stream() |
| 262 | + .flatMap(entityDescriptor -> entityDescriptor.getGenuineVariableDescriptorList().stream()) |
| 263 | + .filter(variableDescriptor -> !variableDescriptor.isListVariable()) |
| 264 | + .distinct() |
| 265 | + .toList(); |
| 266 | + var hasChainedVariable = basicVariableDescriptorList.stream() |
| 267 | + .filter(v -> v instanceof BasicVariableDescriptor<Solution_>) |
| 268 | + .anyMatch(v -> ((BasicVariableDescriptor<?>) v).isChained()); |
| 269 | + var listVariableDescriptor = solutionDescriptor.getListVariableDescriptor(); |
| 270 | + if (basicVariableDescriptorList.isEmpty()) { // We only have the one list variable. |
| 271 | + return new UnionMoveSelectorConfig() |
| 272 | + .withMoveSelectors(new ListChangeMoveSelectorConfig(), new ListSwapMoveSelectorConfig(), |
| 273 | + new KOptListMoveSelectorConfig().withMinimumK(2).withMaximumK(2), |
| 274 | + new SubListChangeMoveSelectorConfig().withSubListSelectorConfig( |
| 275 | + new SubListSelectorConfig().withMinimumSubListSize(2).withMaximumSubListSize(5)), |
| 276 | + new SubListSwapMoveSelectorConfig().withSubListSelectorConfig( |
| 277 | + new SubListSelectorConfig().withMinimumSubListSize(2).withMaximumSubListSize(5)), |
| 278 | + new ListRuinRecreateMoveSelectorConfig().withMinimumRuinedCount(1).withMaximumRuinedCount(5)); |
| 279 | + } else if (listVariableDescriptor == null) { // We only have basic variables. |
| 280 | + if (hasChainedVariable && basicVariableDescriptorList.size() == 1) { |
| 281 | + return new UnionMoveSelectorConfig() |
| 282 | + .withMoveSelectors(new ChangeMoveSelectorConfig(), new SwapMoveSelectorConfig(), |
| 283 | + new SubChainChangeMoveSelectorConfig().withSubChainSelectorConfig( |
| 284 | + new SubChainSelectorConfig().withMinimumSubChainSize(2).withMaximumSubChainSize(5)), |
| 285 | + new SubChainSwapMoveSelectorConfig().withSubChainSelectorConfig( |
| 286 | + new SubChainSelectorConfig().withMinimumSubChainSize(2).withMaximumSubChainSize(5)), |
| 287 | + new TailChainSwapMoveSelectorConfig()); |
| 288 | + } else { |
| 289 | + return new UnionMoveSelectorConfig() |
| 290 | + .withMoveSelectors(new ChangeMoveSelectorConfig(), new SwapMoveSelectorConfig(), |
| 291 | + new PillarChangeMoveSelectorConfig().withPillarSelectorConfig( |
| 292 | + new PillarSelectorConfig().withMinimumSubPillarSize(2).withMaximumSubPillarSize(5)), |
| 293 | + new PillarSwapMoveSelectorConfig().withPillarSelectorConfig( |
| 294 | + new PillarSelectorConfig().withMinimumSubPillarSize(2).withMaximumSubPillarSize(5)), |
| 295 | + new RuinRecreateMoveSelectorConfig().withMinimumRuinedCount(1).withMaximumRuinedCount(5)); |
| 296 | + } |
| 297 | + } else { |
| 298 | + return new UnionMoveSelectorConfig() |
| 299 | + .withMoveSelectors(new ChangeMoveSelectorConfig(), new SwapMoveSelectorConfig()); |
| 300 | + } |
| 301 | + } |
237 | 302 | } |
0 commit comments