Interface ProblemChange<Solution_>

  • Type Parameters:
    Solution_ - the solution type, the class with the PlanningSolution annotation
    Functional Interface:
    This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

    @FunctionalInterface
    public interface ProblemChange<Solution_>
    A ProblemChange represents a change in one or more planning entities or problem facts of a PlanningSolution.

    The Solver checks the presence of waiting problem changes after every Move evaluation. If there are waiting problem changes, the Solver:

    1. clones the last best solution and sets the clone as the new working solution
    2. applies every problem change keeping the order in which problem changes have been submitted; after every problem change, variable listeners are triggered
    3. calculates the score and makes the updated working solution the new best solution; note that this solution is not published via the BestSolutionChangedEvent, as it hasn't been initialized yet
    4. restarts solving to fill potential uninitialized planning entities

    Note that the Solver clones a PlanningSolution at will. Any change must be done on the problem facts and planning entities referenced by the PlanningSolution.

    An example implementation, based on the Cloud balancing problem, looks as follows:

     
     public class DeleteComputerProblemChange implements ProblemChange<CloudBalance> {
    
         private final CloudComputer computer;
    
         public DeleteComputerProblemChange(CloudComputer computer) {
             this.computer = computer;
         }
    
         {@literal @Override}
         public void doChange(CloudBalance cloudBalance, ProblemChangeDirector problemChangeDirector) {
             CloudComputer workingComputer = problemChangeDirector.lookUpWorkingObjectOrFail(computer);
             // First remove the problem fact from all planning entities that use it
             for (CloudProcess process : cloudBalance.getProcessList()) {
                 if (process.getComputer() == workingComputer) {
                     problemChangeDirector.changeVariable(process, "computer",
                             workingProcess -> workingProcess.setComputer(null));
                 }
             }
             // A SolutionCloner does not clone problem fact lists (such as computerList), only entity lists.
             // Shallow clone the computerList so only the working solution is affected.
             ArrayList<CloudComputer> computerList = new ArrayList<>(cloudBalance.getComputerList());
             cloudBalance.setComputerList(computerList);
             // Remove the problem fact itself
             problemChangeDirector.removeProblemFact(workingComputer, computerList::remove);
         }
     }