Interface ProblemChange<Solution_>
- Type Parameters:
Solution_- the solution type, the class with thePlanningSolutionannotation
- Functional Interface:
- This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
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:
- clones the last
best solutionand sets the clone as the newworking solution - applies every problem change keeping the order in which problem changes have been submitted;
after every problem change,
variable listenersare triggered - calculates the score and makes the
updated working solutionthe newbest solution; note that thissolutionis not published via theBestSolutionChangedEvent, as it hasn't been initialized yet - restarts solving to fill potential uninitialized
planning entities
From the above, it follows that the solver will require some time
to restart solving and produce the next best solution.
For that reason, it is recommended to submit problem changes in batches, rather than one by one.
If there is not enough time between problem changes,
the solver may not have enough time to produce a new best solution
and the barrage of problem changes will have effectively caused the optimization process to stop.
It is impossible to say with certainty how much time is needed between problem changes,
as it depends on the problem size, complexity, and the speed of the Score calculation.
But in general, problem changes should be separated by at least a few seconds, if not minutes.
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);
}
}
-
Method Summary
Modifier and TypeMethodDescriptionvoiddoChange(Solution_ workingSolution, ProblemChangeDirector problemChangeDirector) Do the change on thePlanningSolution.
-
Method Details
-
doChange
Do the change on thePlanningSolution. Every modification to thePlanningSolutionmust be done via theProblemChangeDirector, otherwise theScorecalculation will be corrupted.- Parameters:
workingSolution- theworking solutionwhich contains the problem facts (andplanning entities) to changeproblemChangeDirector-ProblemChangeDirectorto perform the change through
-