6.11. Custom Solver Phase
Between phases or before the first phase, you might want to run a custom optimization algorithm to initialize the Solution or to take some low hanging fruit to get a better score quickly. Yet you’ll still want to reuse the score calculation. For example, to implement a custom Construction Heuristic without implementing an entire Phase.
Most of the time, a custom solver phase is not worth the hassle. The supported Construction Heuristics are configurable (use the Benchmarker to tweak them), Termination aware and support partially initialized solutions too.
The CustomPhaseCommand interface looks like this:
public interface CustomPhaseCommand {
void applyCustomProperties(Map<String, String> customPropertyMap);
void changeWorkingSolution(ScoreDirector scoreDirector);
}
For example, extend AbstractCustomPhaseCommand and implement the changeWorkingSolution() method:
public class ToOriginalMachineSolutionInitializer extends AbstractCustomPhaseCommand {
public void changeWorkingSolution(ScoreDirector scoreDirector) {
MachineReassignment machineReassignment = (MachineReassignment) scoreDirector.getWorkingSolution();
for (MrProcessAssignment processAssignment : machineReassignment.getProcessAssignmentList()) {
scoreDirector.beforeVariableChanged(processAssignment, "machine");
processAssignment.setMachine(processAssignment.getOriginalMachine());
scoreDirector.afterVariableChanged(processAssignment, "machine");
scoreDirector.triggerVariableListeners();
}
}
}
Any change on the planning entities in a CustomPhaseCommand must be notified to the ScoreDirector.
Do not change any of the problem facts in a CustomPhaseCommand. That will corrupt the Solver because any previous score or solution was for a different problem. To do that, read about repeated planning and do it with a ProblemFactChange instead.
Configure your CustomPhaseCommand like this:
<solver>
...
<customPhase>
<customPhaseCommandClass>org.optaplanner.examples.machinereassignment.solver.solution.initializer.ToOriginalMachineSolutionInitializer</customPhaseCommandClass>
</customPhase>
... <!-- Other phases -->
</solver>
Configure multiple customPhaseCommandClass instances to run them in sequence.
If the changes of a CustomPhaseCommand don’t result in a better score, the best solution won’t be changed (so effectively nothing will have changed for the next Phase or CustomPhaseCommand). To force such changes anyway, use forceUpdateBestSolution:
<customPhase>
<customPhaseCommandClass>...MyUninitializer</customPhaseCommandClass>
<forceUpdateBestSolution>true</forceUpdateBestSolution>
</customPhase>
If the Solver or a Phase wants to terminate while a CustomPhaseCommand is still running, it will wait to terminate until the CustomPhaseCommand is done, however long that takes. The built-in solver phases don’t suffer from this problem.
To configure values of your CustomPhaseCommand dynamically in the solver configuration (so you can tweak those parameters with the Benchmarker), use the customProperties element:
<customPhase>
<customProperties>
<mySelectionSize>5</mySelectionSize>
</customProperties>
</customPhase>
Then override the applyCustomProperties() method to parse and apply them when a Solver is built.
public class MySolutionInitializer extends AbstractCustomPhaseCommand {
private int mySelectionSize;
public void applyCustomProperties(Map<String, String> customPropertyMap) {
String mySelectionSizeString = customPropertyMap.get("mySelectionSize");
if (mySelectionSizeString == null) {
throw new IllegalArgumentException("A customProperty (mySelectionSize) is missing from the solver configuration.");
}
solverFactory = SolverFactory.createFromXmlResource(partitionSolverConfigResource);
if (customPropertyMap.size() != 1) {
throw new IllegalArgumentException("The customPropertyMap's size (" + customPropertyMap.size() + ") is not 1.");
}
mySelectionSize = Integer.parseInt(mySelectionSizeString);
}
...
}
Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.