'Set a ListMoveChange filter when using OptaPlanner Spring Boot starter
We are using the OptaPlanner Spring Boot starter to create a vehicle routing problem solver based on the example in the OptaPlanner quickstarts:
https://github.com/kiegroup/optaplanner-quickstarts/tree/stable/use-cases/vehicle-routing
So we do not have an solveConfig.xml file. We would like to define a filter for ListChangeMoves but it's not clear how we would register this without using an XML file. We have tried using a solverConfig.xml e.g.
<localSearch>
<unionMoveSelector>
<listChangeMoveSelector>
<filterClass>my.filter.Class</filterClass>
</listChangeMoveSelector>
</unionMoveSelector>
</localSearch>
But this is not working. Is there an example of setting up a filter for list moves?
Solution 1:[1]
This is a XML solver config using a a swap move selector and a change move selector with move filtering:
<constructionHeuristic/>
<localSearch>
<unionMoveSelector>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
<swapMoveSelector/>
</unionMoveSelector>
</localSearch>
If you don't want to use swap moves, then you don't need the union move selector and the configuration can be simplified to:
<constructionHeuristic/>
<localSearch>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
</localSearch>
A few comments:
- I'm including the CH phase because it is necessary in a typical case. See OptaPlanner terminates immediately if I add constructionHeuristic config for an explanation.
- The
ChangeMoveSelectoris automatically configured to produceListChangeMoves if the planning entity has a@PlanningListVariable. There is no<listChangeMoveSelector>config element. - More information including how to implement the move selection filter can be found in the documentation.
UPDATE: No XML configuration
It's possible to inject SolverConfig, modify it and then use it to create other objects, for example Solver, SolverManager, and ScoreManager.
The code would look something like this:
@Component
class MyService {
// Don't inject these.
private final SolverManager<VrpSolution, Long> solverManager;
private final ScoreManager<VrpSolution, HardSoftScore> scoreManager;
// But inject the SolverConfig.
public MyService(SolverConfig solverConfig) {
// And instantiate SolverManager and ScoreManager manually.
this.solverManager = SolverManager.<VrpSolution, Long>create(
solverConfig.withPhaseList(Arrays.asList(
new ConstructionHeuristicPhaseConfig(),
new LocalSearchPhaseConfig().withMoveSelectorConfig(
new ChangeMoveSelectorConfig()
.withFilterClass(MyFilter.class)))));
this.scoreManager = ScoreManager.create(SolverFactory.create(solverConfig));
}
}
Pros:
SolverConfigwill be initialized byOptaPlannerAutoConfiguration(fromoptaplanner-spring-boot-starter) before it's injected into your component. That means:- The solution and entity classes will be auto-discovered and you don't have to specify them (which you have to in
solverConfig.xml). - You can use
application.propertiesto do minor solver config tweaks, for example set time-spent termination.
Cons:
- You have to create
Solver,SolverManager, andScoreManagerinstances manually. Specifically, you can't have a@Beanmethod producing an instance of one of the types above because that would deactivateOptaPlannerAutoConfiguration, which creates theSolverConfigbean.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
