6.11. Custom Solver Phase

Between phases or before the first phase, you might want to execute a custom action on the Solution to get a better score. Yet you'll still want to reuse the score calculation. For example, to implement a custom construction heuristic without implementing an entire Phase.
Note
Most of the time, a custom solver phase is not worth the hassle. The supported Constructions Heuristics are configurable (use the Benchmarker to tweak them), Termination aware and support partially initialized solutions too.
Implement the CustomPhaseCommand interface:
public interface CustomPhaseCommand {

    void changeWorkingSolution(ScoreDirector scoreDirector);

}
For example:
public class ToOriginalMachineSolutionInitializer implements CustomPhaseCommand {

    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();
        }
    }

}
Warning
Any change on the planning entities in a CustomPhaseCommand must be notified to the ScoreDirector.
Warning
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.
Important
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>
Note
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 build-in solver phases don't suffer from this problem.