OptaPlanner

Do more business
with less resources

by Geoffrey De Smet

Print

What is business resource optimization?

TSP and VRP demo

What is a planning problem?

  • Complete goals
  • With limited resources
  • Under constraints

Planning problem use cases

  • Employee shift rostering: timetabling nurses, repairmen, ...
  • Agenda scheduling: scheduling meetings, appointments, maintenance jobs, advertisements, ...
  • Educational timetabling: scheduling lessons, courses, exams, conference presentations, ...
  • Vehicle routing: planning vehicles (trucks, trains, boats, airplanes, ...) with freight and/or people
  • Bin packing: filling containers, trucks, ships and storage warehouses, but also cloud computers nodes, ...
  • Job shop scheduling: planning car assembly lines, machine queue planning, workforce task planning, ...
  • Cutting stock: minimizing waste while cutting paper, steel, carpet, ...
  • Sport scheduling: planning leagues (football, baseball, ...)
  • Financial optimization: investment portfolio optimization, risk spreading, ...

Are planning problems
difficult to solve?

Find optimal solution and scale out
for an NP-complete problem?

⇔ Is P = NP?

  • Unresolved since 1971
  • 1 000 000 $ reward since 2000
  • Most believe P ≠ NP
    • Impossible to find optimal solution and scale out
  • 3000+ known NP-complete problems (wikipedia)

Yes,
planning problems are
difficult to solve!

(and humans aren't good at it)

(but they don't realize it)

Reuse optimization algorithms

Find better solutions in time and scale out

  • Open source
    Apache License
  • Regular releases
    Download the zip or from Maven Central
  • Documented
    Reference manual, examples, ...
  • Quality coverage
    Unit, integration and stress tests

CloudBalancing demo

CloudBalancing demo

Domain model

Computer

public class Computer {

  private int cpuPower;
  private int memory;
  private int networkBandwidth;

  private int cost;

  // getters
}

Process is a planning entity

@PlanningEntity
public class Process {

  private int requiredCpuPower;
  private int requiredMemory;
  private int requiredNetworkBandwidth;

  ...

  // getters
}

Process has a planning variable

@PlanningEntity
public class Process {
  ...
  private Computer computer;

  @PlanningVariable(valueRangeProviderRefs = {"computerRange"})
  public Computer getComputer() {
    return computer;
  }
  public void setComputer(Computer computer) {...}
  ...
}

Solution CloudBalance: problem facts

public class CloudBalance
    implements Solution<HardSoftScore> {

  private List<Computer> computerList;

  @ValueRangeProvider(id = "computerRange")
  public List<Computer> getComputerList() {
    return computerList;
  }

  ...
}

Solution CloudBalance: planning entities

public class CloudBalance
    implements Solution<HardSoftScore> {
  ...

  private List<Process> processList;

  @PlanningEntityCollectionProperty
  public List<Process> getProcessList() {
    return processList;
  }

  ...
}

Solution CloudBalance: getProblemFacts()

public class CloudBalance
    implements Solution<HardSoftScore> {
  ...

  // Used in score constraints
  public Collection<Object> getProblemFacts() {
    List<Object> facts = new ArrayList<Object>();
    facts.addAll(computerList);
    return facts;
  }

  ...
}

Solution CloudBalance: score

public class CloudBalance
    implements Solution<HardSoftScore> {
  ...

  private HardSoftScore score;

  public HardSoftScore getScore() {...}
  public void setScore(HardSoftScore score) {...}

  ...
}

Score constraints

Given 2 solutions
which one is better?

Score calculation

  • Easy Java
  • Incremental Java
  • Drools

Easy Java score calculation

  • Easy to implement
  • Bridge an existing system
  • Slow
public class CloudBalancingEasyScoreCalculator
    implements EasyScoreCalculator<CloudBalance> {

  public Score calculateScore(CloudBalance cb) {
    ...
    return DefaultHardSoftScore.valueOf(
        hardScore, softScore);
  }

}

Incremental Java score calculation

  • Fast
    • Solution changes ⇒ recalculate score delta only
  • Hard to implement
    • Much boilerplate code

Drools score calculation

  • Incremental
    • No boilerplate code
  • Constraints in Drools Rule Language (DRL)
    • Declarative (like SQL, regular expression)
  • Integration opportunities
    • Drools Workbench
    • Decision tables

DRL soft constraint: computer cost

rule "computerCost"
  when
    // there is a computer
    $s : Computer($c : cost)
    // there is a processes on that computer
    exists Process(computer == $s)
  then
    // lower soft score by the maintenance cost
    scoreHolder.addSoftConstraintMatch(kcontext,
        - $cost);
end

DRL hard constraint: CPU power

rule "requiredCpuPowerTotal"
  when
    // there is a computer
    $s : Computer($cpu : cpuPower)
    // with too little cpu for its processes
    $total : Number(intValue > $cpu) from accumulate(
      Process(computer == $s,
          $requiredCpu : requiredCpuPower),
      sum($requiredCpu)
    )
  then
    // lower hard score by the excessive CPU usage
    scoreHolder.addHardConstraintMatch(kcontext,
        $cpu - $total.intValue());
end

Solving it

Solver configuration by XML

<solver>
  <solutionClass>...CloudBalance</solutionClass>
  <entityClass>...Process</entityClass>

  <scoreDirectorFactory>
    <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
    <scoreDrl>...ScoreRules.drl</scoreDrl>
  </scoreDirectorFactory>

  <!-- optimization algorithms -->
</solver>

Solving

SolverFactory factory = SolverFactory.createFromXmlResource(
    "...SolverConfig.xml");
Solver solver = factory.buildSolver();

solver.solve(cloudBalance);
cloudBalance = (CloudBalance) solver.getBestSolution();

Optimization algorithms

Brute force config

<solver>
  ...

  <exhaustiveSearch>
    <exhaustiveSearchType>BRUTE_FORCE</exhaustiveSearchType>
  </exhaustiveSearch>
</solver>

Brute force scalability

Plan 1200 processes with brute force?


First Fit config

<solver>
  ...

  <constructionHeuristic>
    <constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
  </constructionHeuristic>
</solver>

First Fit scalability

First Fit results

All hard constraints satisfied: maintenance cost shown

First Fit Decreasing config

<solver>
  ...

  <constructionHeuristic>
    <constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType>
  </constructionHeuristic>
</solver>

DifficultyComparator

public class ProcessDifficultyComparator
    implements Comparator<Process> {
  public int compare(Process a, Process b) {
    // Compare on requiredCpuPower * requiredMemory
    //     * requiredNetworkBandwidth
  }
}

@PlanningEntity(difficultyComparatorClass
    = ProcessDifficultyComparator.class)
public class Process  {
  ...
}

First Fit Decreasing scalability

First Fit Decreasing results

Construction Heuristics + Local Search

<solver>
  ...

  <constructionHeuristic>
    <constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType>
  </constructionHeuristic>
  <localSearch>
    ...
  <localSearch>
</solver>

Hill Climbing config

<localSearch>
  <forager>
    <!-- Untweaked standard value -->
    <acceptedCountLimit>1000</acceptedCountLimit>
  </forager>
</localSearch>

Tabu Search config

<localSearch>
  <acceptor>
    <!-- Untweaked standard value -->
    <entityTabuSize>7</entityTabuSize>
  </acceptor>
  <forager>
    <!-- Untweaked standard value -->
    <acceptedCountLimit>1000</acceptedCountLimit>
  </forager>
</localSearch>

Simulated Annealing config

<localSearch>
  <acceptor>
    <!-- Tweaked value -->
    <simulatedAnnealingStartingTemperature>
        0hard/400soft
    </simulatedAnnealingStartingTemperature>
  </acceptor>
  <forager>
    <!-- Untweaked standard value -->
    <acceptedCountLimit>4</acceptedCountLimit>
  </forager>
</localSearch>

Local Search results

Cost ($) reduction

  • Compared to First Fit
  • First Fit Decreasing
    • 49 480 $ = 4 %
  • Tabu Search
    • 160 860 $ = 14 %
  • Simulated Annealing
    • 128 950 $ = 11 %
  • Few constraints
    • ⇒ low ROI

Repeated planning:
continuous/real-time

Summary

  • OptaPlanner solves planning and scheduling problems
  • Adding constraints: easy and scalable
  • Switching/combining optimization algorithms: easy

Build from source

$ git clone git@github.com:droolsjbpm/optaplanner.git
...
$ cd optaplanner
$ mvn clean install -DskipTests
...
$ mvn exec:exec
...

Q & A


Introduction to
heuristics and metaheuristics
for
business resource optimization

by Geoffrey De Smet

N Queens demo

demo

Simplified problem

N Queens

  • Place n queens on a n sizes chessboard
  • No 2 queens can attach each other

Bad

Good

  • Imperfect example
    • Not NP-complete (shortcuts exist)
    • Score function is too simple (too black and white)

What solution is better?

  • Need for objective scoring
  • Better score ⇔ better solution
  • Highest score ⇔ optimal solution

N Queens

  • Hard constraints:
    • -1 for every pair of conflicting queens
  • Soft constraints:
    • None

Score = -2

Conflicts: A-B, B-D

Score = 0

No conflicts

How do we find the best solution?

  • Need for optimization algorithms
  • Best solution in available time

Brute Force scalability

8 queens = 15.7 seconds
9 queens = 2.5 minutes (times 10)
10 queens = 0.83 hours (times 20)

How many combinations for 100 queens?

  • 1 queen per column
  • 100 queens ⇒ 100 variables
  • 100 rows ⇒ 100 values per variable

Source: NASA (wikipedia)

> humans?
7 000 000 000

How many combinations for 100 queens?

  • 1 queen per column
  • 100 queens ⇒ 100 variables
  • 100 rows ⇒ 100 values per variable

Source: NASA and ESA (wikipedia)

> minimum atoms
in the observable universe?
1080

How many combinations for 100 queens?

  • 1 queen per column
  • 100 queens ⇒ 100 variables
  • 100 rows ⇒ 100 values per variable

100100 = 10200

1 0000000000 0000000000 0000000000 0000000000 0000000000
  0000000000 0000000000 0000000000 0000000000 0000000000
  0000000000 0000000000 0000000000 0000000000 0000000000
  0000000000 0000000000 0000000000 0000000000 0000000000

How many combinations for n queens?

  • 1 queen per column
  • n queens ⇒ n variables
  • n rows ⇒ n values per variable

nn

|valueSet||variableSet|

How long?

Presume 109 scores/ms ⇒ 1020 scores/year

Queens Combinations Calculation time
100 100100 = 10200 10180 years
1000 10001000 = 103000 102980 years
10000 1000010000 = 1040000 1039980 years

Moore's law == a drop in the ocean

Exhaustive Search doesn't scale

  • Branches explode exponentially
  • Not enough CPU
  • Not enough memory

Move types

  • Change move
  • Swap move
  • ...

All change moves

n # moves # solutions
4 16 256
8 64 16777216
64 4096 10116
n n2 nn

Multiple moves

Multiple moves can reach any solution

Performance tricks

Benchmark results

Demo

Reuse existing business code

public class Nurse {

  private Country country;

  public boolean isHoliday(Date date) {
    if (country == Country.BE) {
      // true if date is 1-JAN, easter monday, 21-JUL, ...
    } else if (country == Country.FR) {
      // true if date is 1-JAN, easter monday, 14-JUL, ...
    } else if (...) {
      ...
    }
    ...
  }

}

Q & A