JBoss.orgCommunity Documentation

Chapter 5. Optimization algorithms

5.1. Introduction
5.2. Algorithms overview
5.3. SolverPhase
5.4. Which optimization algorithms should I use?
5.5. Custom SolverPhase

In number of possible solutions for a planning problem can be mind blowing. For example:

An optimization algorithm that checks every possible solution (even with pruning) can easily run for billions of years on a single real-life planning problem. Most of the time, we are happy with a feasible solution found in a limited amount of time.

The combination of Drools Planner's optimization algorithms and the Drools Expert rule engine turn out to be a very efficient, because:

Drools Planner's implementation combines both. On top of that, it also offers additional support for benchmarking, etc.

todo

A Solver can use multiple optimization algorithms in sequence. Each optimization algorithm is represented by a SolverPhase. There is never more than 1 SolverPhase solving at the same time.

Here's a configuration that runs 3 phases in sequence:

<solver>
  ...
  <customSolverPhase><!-- Phase 1 -->
    ... <!-- custom construction heuristic -->
  </customSolverPhase>
  <localSearch><!-- Phase 2 -->
    ... <!-- simulated annealing -->
  </localSearch>
  <localSearch><!-- Phase 3 -->
    ... <!-- Tabu search -->
  </localSearch>
</solver>

When the first phase terminates, the second phase starts, and so on. When the last phase terminates, the Solver terminates.

Some phases (especially construction heuristics) will terminate automatically. Other phases (especially metaheuristics) will only terminate if the phase is configured to terminate:

<solver>
  ...
  <termination><!-- Solver termination -->
    <maximumSecondsSpend>90</maximumSecondsSpend>
  </termination>
  <localSearch>
    <termination><!-- Phase termination -->
      <maximumSecondsSpend>60</maximumSecondsSpend><!-- Let the next phase run too, before the solver terminates -->
    </termination>
    ...
  </localSearch>
  <localSearch>
    ...
  </localSearch>
</solver>

If the Solver terminates (before the last phase terminates itself), the current phase is terminated and all subsequent phases won't run.

The best optimization algorithms configuration for your use case depends heavily on your use case. Nevertheless, this vanilla recipe will get you into the game with a pretty good configuration, probably much better than what you're used to.

Start with a quick configuration like this as this involves little or no code:

Next, implement planning entity difficulty comparison and turn it into:

Next, implement moves and add tabu search:

At this point the free lunch is over. The result is probably more than good enough, but we can do better. Use the Benchmarker and try a couple of simulated annealing configurations:

And try this too:

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 SolverPhase.

Implement the CustomSolverPhaseCommand interface :

public interface CustomSolverPhaseCommand {

    void changeWorkingSolution(SolutionDirector solutionDirector);

}

For example:

public class ExaminationStartingSolutionInitializer implements CustomSolverPhaseCommand {

    public void changeWorkingSolution(SolutionDirector solutionDirector) {
        Examination examination = (Examination) solutionDirector.getWorkingSolution();
        for (Exam exam : examination.getExamList()) {
            Score unscheduledScore = solutionDirector.calculateScoreFromWorkingMemory();
            ...
            for (Period period : examination.getPeriodList()) {
                exam.setPeriod(period)
                workingMemory.update(examHandle, exam);
                Score score = solutionDirector.calculateScoreFromWorkingMemory();
                ...
            }
            ...
        }
    }

}

And configure it like this:

<solver>
  ...
  <customSolverPhase>
    <customSolverPhaseCommandClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</customSolverPhaseCommandClass>
  </customSolverPhase>
  ... <!-- Other phases -->
</solver>

It's possible to configure multiple customSolverPhaseCommandClass instances, which will be run in sequence.