OptaPlanner examples その5

Tennis club scheduling

OptaPlanner training (http://d.hatena.ne.jp/tokobayashi/20141027) をやってないひとはここを読む前に、先に training をやりましょう!


ここまでが「Basic examples」です。今回は日時、人、リソースを要素としたプランニングの基礎パターンと言えそうです。

各チームに公平にテニスコートを使ってもらい、またできるだけ対戦相手が偏らないようにする、という制約です。「公平さ」をどうルールで表現するかの例題でもあります。

  • TennisSolution : @PlanningSolution
    • List getTeamList() : @ValueRangeProvider(id = "teamRange")
    • List getTeamAssignmentList() : @PlanningEntityCollectionProperty
  • TeamAssignment : @PlanningEntity
    • Team getTeam() : @PlanningVariable(valueRangeProviderRefs = {"teamRange"})
    • Day day
    • int indexInDay

Team と Day が N-N の関係になるので、間に TeamAssignment を用意して @PlanningEntity にする、という基本パターン。一日に何チームがコートを使えるか、というのは indexInDay で表現している。複雑なケースだとここもクラス化されるはず。

「各チームが公平にテニスコートを使う」は「対戦相手が偏らないようにする」より重要な制約なので、ここでは HardMediumSoftScore という制約3段構えが来ました。Hard は絶対破ってはダメ。Medium は破ってもいいけど、Medium の点数は Soft の点数より絶対的に重視される。つまりいくら Soft が良くても、Medium の点数が下がれば採用されない。

「公平さ」を表現する「Fairness score」はここを読もう。 http://docs.jboss.org/optaplanner/release/latest/optaplanner-docs/html_single/index.html#fairnessScoreConstraints

まあ簡単に言えば、「自乗してマイナス」。

rule "fairAssignmentCountPerTeam"
    when
        $t : Team()
        $total : Number() from accumulate(
            $a : TeamAssignment(team == $t),
            count($a)
        )
    then
        scoreHolder.addMediumConstraintMatch(kcontext, - ($total.intValue() * $total.intValue()));
end