Red Hat Decision Manager 計画最適化の性能検証

著者: 株式会社 日立ソリューションズ 柳村 明宏
監修: 株式会社 日立製作所




# はじめに  
計画最適化とは、限られたリソースの中で、守るべき制約や効率を考慮しながら、最も良い計画(組合せ計画)を立案することです。

ここで、対象となる計画の規模(例：人員のシフト計画の場合、対象となる人員数や割り当てるシフト枠数)が増加すると、その組合せ数も増加し、良い計画を立案できるまでの時間も増加します。
そのため、計画最適化を行う場合は、以下の内容を検討する必要があります。

- どれくらいの規模の最適化を行うのか
- どれくらいの計算時間をかけられるのか
- どれくらいのマシンスペックが必要か

本稿では、人員の日次シフト計画のモデルケースについてRed Hat Decision Managerを利⽤して計画を最適化する性能検証を紹介します。
本稿が以下のような点でお役に立てれば幸いです。

- 計画最適化が、規模の大きいケースでも現実的な計算時間で対応できることを確認する
- 計算時間やマシンスペックの概算見積時の参考値として利用する
- 設計開発時に調整する最適化アルゴリズムやパラメタのベース値として参照する

なお、Red Hat Decision Managerを利⽤した計画最適化の概要や活用イメージについては、以下の記事を参考にしてください。
[結果の理由が分かるAIで計画最適化](https://qiita.com/t-takahisa/items/6cb1287f97a5139bffbc)
[結果の理由が分かるAIで計画最適化「活用イメージ」](https://qiita.com/t-takahisa/items/5ced5669c9b0564fdc01)




# モデルケース

## 計画の概要  
１つの勤務エリアで複数の業務が存在する人員の日次のシフト計画を立案します。具体的には、各シフト枠に対して業務を遂行する人員を、制約や効率を考慮しながら割り当てます。

シフトデータ(⼈員割当後のシフト枠)の作成イメージを以下に示します。
![システム概要_イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/62a570f9-bfe0-7bbd-ba99-4674fe71ac02.png)
今回のモデルケースでは以下の3パターンの人員数とシフト枠数があるものとします。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%">#</th>
  <th width="47%">人員数</th>
  <th width="47%">シフト枠数</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>1000</td>
  <td>4212</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>500</td>
  <td>2106</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>250</td>
  <td>1053</td>
 </tr>
</table>




## 制約ルール  
本モデルケースでは以下の制約ルールを設定しています。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%">#</th>
  <th width="45%">制約ルール</th>
  <th width="15%">制約種別</th>
  <th width="25%">制約種別説明</th>
  <th width="10%">レベル</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td align="left">シフト枠に必ず人員を割り当てる。</td>
  <td rowspan="2">絶対制約</td>
  <td align="left" rowspan="2">必ず遵守する制約ルール。</td>
  <td rowspan="2">Hard</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td align="left">同じ人員を、同じ勤務時間帯の複数のシフト枠に割り当てない。</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td align="left">各人員の勤務時間帯を遵守する(早出、残業をさせない)。</td>
  <td rowspan="5">考慮制約</td>
  <td align="left" rowspan="5">可能な限り遵守する制約ルール。<br>ただし、他の制約ルール、評価指標との兼ね合いで遵守しないケースもある。</td>
  <td rowspan="7">Soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td align="left">業務に必要なスキルを持つ人員を割り当てる。</td>
 </tr>
 <tr align="center">
  <td>5</td>
  <td align="left">スキルレベルが低い人員をスキルレベルの高いシフトに割り当てない。</td>
 </tr>
 <tr align="center">
  <td>6</td>
  <td align="left">OJTグループが同じ人員(指導係と新人)は、同じ勤務時間帯＋同じ勤務場所とする。</td>
 </tr>
 <tr align="center">
  <td>7</td>
  <td align="left">同一シフト枠除外グループが同じ人員(相性が合わない人など)は、同じ勤務時間帯＋同じ勤務場所にしない。</td>
 </tr>
 <tr align="center">
  <td>8</td>
  <td align="left">勤務エリアの移動回数を少なくする。</td>
  <td rowspan="2">評価指標</td>
  <td align="left" rowspan="2">より良い組合せを算出するための制約ルール。</td>
 </tr>
 <tr align="center">
  <td>9</td>
  <td align="left">人員の作業時間を平準化する。</td>
 </tr>
</table>





## モデルケースの規模(探索空間のサイズ)と目標スコア  
スコアは最適化計算を評価する指標値です。
本モデルケースでは、すべての制約ルールでスコアにペナルティ値(負の値)を付与するため、0(0hard/0soft)が最良のスコアとなります。しかし、限られたリソース(人員数、シフト枠数)や、計画にかけられる時間などの制限がある中で、どこまで最適化できれば良しとするかを目標スコアとして設定します。

本モデルケースで設定する規模(探索空間のサイズ)に対する目標スコアは以下の通りです。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">#</th>
  <th colspan="2">規模(探索空間のサイズ)</th>
  <th width="32%" rowspan="2">目標スコア</th>
 </tr>
 <tr align="center">
  <th width="32%">人員数</th>
  <th width="32%">シフト枠数</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>1000</td>
  <td>4212</td>
  <td>0hard/-69000soft</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>500</td>
  <td>2106</td>
  <td>0hard/-34500soft</td>
</tr>
 <tr align="center">
  <td>3</td>
  <td>250</td>
  <td>1053</td>
  <td>0hard/-17250soft</td>
 </tr>
</table>


目標スコアの考え方は以下の通りです。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="15%">制約種別</th>
  <th>目標スコア</th>
  <th>目標スコアの計算式</th>
 </tr>
 <tr align="center">
  <td>絶対制約</td>
  <td>0</td>
  <td>―</td>
 </tr>
 <tr align="center">
  <td>考慮制約</td>
  <td>0</td>
  <td>―</td>
 </tr>
 <tr align="center">
  <td>評価指標</td>
  <td align="left">
      <font size ="2">本モデルケースでは、以下の目標で最小化します。
      <ol>
          <li>勤務エリア移動回数:1人2回以内とする。</li>
          <li>作業平準化:平均シフト従業率の±7%以内とする。</li>
      </ol>
     </font>
  </td>
  <td align="left">
   <font size="2">
   <ol>
    <li>2[回/人] × 人員数 × ペナルティ(重み)値(-10)</li>
    <li>7<sup>2</sup>[%] × 人員数 × ペナルティ(重み)値(-1)</li>
   </ol>
   </font>
  </td>
 </tr>
 <tr align="right">
  <td colspan="3"><font size="2">合計　0hard/-(69 × 人員数)soft</font></td>
 </tr>
</table>


### 探索空間のサイズ
探索空間のサイズは、計画に対して考えられる組合せ数であり、探索空間のサイズが大きいほど計算時間がかかります。
本モデルケースにおける探索空間のサイズは、「人員数」の「シフト枠数」乗となります。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%">#</th>
  <th width="30%">人員数</th>
  <th width="30%">シフト枠数</th>
  <th width="35%">探索空間のサイズ</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>250</td>
  <td>1053</td>
  <td>250<sup>1053</sup> ≧ 10<sup>2525</sup></td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>500</td>
  <td>2106</td>
  <td>500<sup>2106</sup> ≧ 10<sup>5684</sup></td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>1000</td>
  <td>4212</td>
  <td>1000<sup>4212</sup> ≧ 10<sup>12636</sup></td>
 </tr>
</table>

Red Hat Decision Managerの探索空間のサイズの仕様は、[OptaPlanner User Guide の Search space size](https://docs.optaplanner.org/7.30.0.Final/optaplanner-docs/html_single/#searchSpaceSize) に記載されていますので、参考にしてください。
本稿の検証結果を参考値として利用する場合は、この探索空間のサイズを十分に考慮してください。



# 検証環境
本検証では以下のような検証環境を利用して検証を実施しました。

**マシン環境**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="20%">項目</th>
  <th width="80%">値</th>
 </tr>
 <tr align="left">
  <td>OS名</td>
  <td>Microsoft Windows10 Pro</td>
 </tr>
 <tr align="left">
  <td>プロセッサ</td>
  <td>Intel® Core™ i7-6700 CPU @ 3.40GHz、3408 Mhz、4個のコア、8個のロジカルプロセッサ</td>
 </tr>
 <tr align="left">
  <td>物理メモリ</td>
  <td>16GB</td>
 </tr>
</table>
**ソフトウェア情報**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="50%">ソフトウェア名称</th>
  <th width="50%">バージョン</th>
 </tr>
 <tr align="left">
  <td>Red Hat Decision Manager</td>
  <td>7.6.0</td>
 </tr>
 <tr align="left">
  <td>OpenJDK</td>
  <td>1.8.0</td>
 </tr>
</table>


**設定情報**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="50%">項目</th>
  <th width="50%">値</th>
 </tr>
 <tr align="left">
  <td>Javaの初期ヒープ・サイズ</td>
  <td>4096 MB</td>
 </tr>
 <tr align="left">
  <td>Javaの最大ヒープ・サイズ</td>
  <td>4096 MB</td>
 </tr>
 <tr align="left">
  <td>利用スレッド数</td>
  <td>6</td>
 </tr>
</table>
Red Hat Decision Managerの最適化計算では、複数のCPUスレッドを利用して、計算速度を向上できる機能として、Multithreaded incremental solvingという機能があります。moveThreadCountパラメタを追加し、そこに利用したいスレッド数を指定することで利用できます。
本機能を利用した場合、複数のスレッドで分割して最適化計算を行うことができますが、nスレッド使っても単純にn倍の計算速度になるわけではないことに注意してください。

Multithreaded incremental solvingの詳細な仕様は、[OptaPlanner User Guide の Multithreaded incremental solving](https://docs.optaplanner.org/7.30.0.Final/optaplanner-docs/html_single/#multithreadedIncrementalSolving)を参照してください。




# 検証方法
## 最適化アルゴリズムとチューニングパラメタ
Red Hat Decision Managerは、様々な最適化アルゴリズムをサポートしています。
目標スコアに到達するまでに必要な計算時間は、選択した最適化アルゴリズムとそのアルゴリズムのチューニングパラメタの指定値によって変わります。

本検証では、よく利用される以下の3つの最適化アルゴルズムを利用して検証を行います。

- Tabu Search
- Late Acceptance
- Simulated Annealing

アルゴリズムの詳細な仕様や、Red Hat Decision Managerで利用できる他のアリゴリズムに関して知りたい方は、[OptaPlanner User Guide](https://docs.optaplanner.org/7.30.0.Final/optaplanner-docs/html_single/)を参照してください。

また、Red Hat Decision Managerには、アルゴリズム、パラメタの最適化計算結果をレポートで出力する機能として、ベンチマーク機能があります。ベンチマーク機能を利用し、各アルゴリズム、パラメタの構成を比較することで、パラメタチューニングを効率よく推進することができます。
ベンチマーク機能の詳細な仕様は、[OptaPlanner User Guide の Benchmarking and Tweaking](https://docs.optaplanner.org/7.30.0.Final/optaplanner-docs/html_single/#benchmarker)を参照してください。



## 最適化計算の終了条件
本検証では、最適化計算の終了条件として、以下の2つのどちらかを満たした場合に終了する設定としています。

- 規定時間到達
- ベストスコアが5分間未更新 

「目標スコアに到達」という終了条件も設定できますが、どの程度までスコアが上昇するかも確認したかったため、上記の終了条件としています。実際のシステムでも、目標スコアに到達したらすぐ計算終了させることよりも、許容される時間内でより良い結果を得られるように、上記のような終了条件を設定することも多いと思います。



## 評価ポイント
本検証では以下の結果をまとめています。

1. 目標スコアに到達した時間
2. 30分経過後のベストスコア
3. 60分経過後のベストスコア(250名規模は30分までしか検証しなかったため、500名規模、1000名規模のみ記載。)

250名規模のような小規模の最適化計算では、可能な限り速く目標スコアに到達することを一番の評価ポイントと考え、1 で評価(順位付け)します。
500名、1000名規模のような大規模の最適化計算では、目標スコアに到達する時間も重要な評価ポイントですが、限られた時間で最適な解を導くことを最も重要な評価ポイントと考え、2 で評価(順位付け)します。




# 検証結果
検証したパターンが非常に多いため、上位の検証結果を抜粋して紹介します。
「30分/60分経過後のベストスコア」列の下段の括弧内の数値は、終了条件「ベストスコアが5分間未更新」を満たし、最適化計算が終了した際の時間(秒)を表します。「目標スコアに到達した時間[秒]」列の太字になっている箇所は、各検証パターンで最速で目標スコアに到達した時間です。

## 1000名(目標スコア : 0hard/-69000soft) 
**Tabu Search**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th width="25%" rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th width="5%" rowspan="2">30分経過後の<br>ベストスコア</th>
  <th width="5%" rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th width="20%">entityTabuSize</th>
  <th width="10%">acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>9</td>
  <td>4000</td>
  <td>602</td>
  <td>0hard/-55780soft</td>
  <td>0hard/-53928soft<br>(3559[秒])</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>9</td>
  <td>2000</td>
  <td>687</td>
  <td>0hard/-57125soft</td>
  <td>0hard/-56419soft<br>(2545[秒])</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>5</td>
  <td>4000</td>
  <td>668</td>
  <td>0hard/-57476soft</td>
  <td>0hard/-55623soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>7</td>
  <td>2000</td>
  <td>1154</td>
  <td>0hard/-57586soft</td>
  <td>0hard/-57208soft<br>(2317[秒])</td>
 </tr>
</table>

**Late Acceptance**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th width="40%" colspan="2">パラメタ</th>
  <th width="25%" rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th width="15%" rowspan="2">30分経過後の<br>ベストスコア</th>
  <th width="15%" rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>lateAcceptanceSize</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>3</td>
  <td>1</td>
  <td>731</td>
  <td>0hard/-51909soft</td>
  <td>0hard/-50175soft</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>1</td>
  <td>1</td>
  <td><strong>306</strong></td>
  <td>0hard/-53840soft</td>
  <td>0hard/-52862soft</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>5</td>
  <td>1</td>
  <td>1239</td>
  <td>0hard/-54752soft</td>
  <td>0hard/-51532soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>1</td>
  <td>4</td>
  <td>1270</td>
  <td>0hard/-55282soft</td>
  <td>0hard/-53976soft</td>
 </tr>
</table>

**Simulated Annealing**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th width="30%" colspan="2">パラメタ</th>
  <th width="25%" rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th width="20%" rowspan="2">30分経過後の<br>ベストスコア</th>
  <th width="20%" rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>simulatedAnnealing<br>StartingTemperature</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>0hard/10soft</td>
  <td>4</td>
  <td>348</td>
  <td>0hard/-53457soft</td>
  <td>0hard/-52426soft</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>0hard/5soft</td>
  <td>4</td>
  <td>1113</td>
  <td>0hard/-55198soft</td>
  <td>0hard/-53803soft</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>0hard/50soft</td>
  <td>4</td>
  <td>477</td>
  <td>0hard/-55700soft</td>
  <td>0hard/-52170soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>0hard/100soft</td>
  <td>4</td>
  <td>1210</td>
  <td>0hard/-58192soft</td>
  <td>0hard/-51499soft</td>
 </tr>
</table>

1000名規模のデータでは、最速306秒で目標スコアに到達しました。
また、目標スコア到達後も最適化計算を行うことで、ベストスコアが更新されました。

以下は、前述の表でのアルゴリズムごとのNo1のSoftスコア遷移です。
![1000人_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/cee72d92-21b1-6ffa-7012-8f6b03ca9cf9.png)
各アルゴリズムの始点はHardスコアが0hardとなった地点です。
①の吹き出しのとおり、Simulated Annealingが最も速く0hardに収束しました。

以下に②を拡大した図を記載します。
![1000人_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/95158e5d-8b0a-8b9c-e953-9b068fc78dc8.png)
目標スコアへの到達が最も速いアルゴリズムは、Simulated Annealingでした。
1000秒程度までは、Simulated Annealingが最も良いスコアですが、以降はLate Acceptanceが最も良いスコアとなりました。
①の3000秒から最適化計算終了までのスコア上昇に関しては、各アルゴリズムで数100程度となっており、これ以上最適化計算を行っても大幅なスコア改善は見込まれないと想定します。



## 500名(目標スコア : 0hard/-34500soft)
**Tabu Search**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>entityTabuSize</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>7</td>
  <td>2000</td>
  <td>436</td>
  <td>0hard/-27506soft</td>
  <td>0hard/-27506soft<br>(2027[秒])</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>5</td>
  <td>4000</td>
  <td>263</td>
  <td>0hard/-28082soft</td>
  <td>0hard/-27701soft<br>(2584[秒])</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>7</td>
  <td>4000</td>
  <td>464</td>
  <td>0hard/-28222soft</td>
  <td>0hard/-27649soft<br>(3237[秒])</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>9</td>
  <td>2000</td>
  <td>170</td>
  <td>0hard/-28585soft<br>(1129[秒])</td>
  <td>―</td>
 </tr>
</table>

**Late Acceptance**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>lateAcceptanceSize</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>5</td>
  <td>1</td>
  <td>188</td>
  <td>0hard/-24991soft</td>
  <td>0hard/-24621soft</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>3</td>
  <td>1</td>
  <td>153</td>
  <td>0hard/-25755soft</td>
  <td>0hard/-25625soft<br>(2712[秒])</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>100</td>
  <td>4</td>
  <td>517</td>
  <td>0hard/-25983soft</td>
  <td>0hard/-25213soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>50</td>
  <td>4</td>
  <td>284</td>
  <td>0hard/-26562soft</td>
  <td>0hard/-26196soft</td>
 </tr>
</table>

**Simulated Annealing**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>simulatedAnnealing<br>StartingTemperature</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>0hard/5soft</td>
  <td>4</td>
  <td>244</td>
  <td>0hard/-26071soft</td>
  <td>0hard/-25384soft</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>0hard/10soft</td>
  <td>4</td>
  <td>685</td>
  <td>0hard/-26438soft</td>
  <td>0hard/-25791soft</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>0hard/5soft</td>
  <td>1</td>
  <td>468</td>
  <td>0hard/-27423soft</td>
  <td>0hard/-26365soft</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>0hard/50soft</td>
  <td>4</td>
  <td><strong>151</strong></td>
  <td>0hard/-27932soft</td>
  <td>0hard/-26146soft</td>
 </tr>
</table>
500名規模のデータでは、最速151秒で目標スコアに到達しました。
また、目標スコア到達後も最適化計算を行うことで、ベストスコアが更新されました。

以下は、前述の表でのアルゴリズムごとのNo1のSoftスコア遷移です。
![500人_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/3f203bfb-5f8b-c703-9280-8091b199ebd1.png)
各アルゴリズムの始点はHardスコアが0hardとなった地点です。
①の吹き出しのとおり、Simulated Annealingが最も速く0hardに収束しました。

以下に②を拡大した図を記載します。
![500人_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/72c3c4b6-3776-4d94-e3ff-81428f914b92.png)
目標スコアへの到達が最も速いアルゴリズムは、Late Acceptanceでした。
250秒から700秒程度までは、Simulated Annealingが最も良いスコアですが、以降はLate Acceptanceが最も良いスコアとなりました。
①の1800秒から最適化計算終了までのスコア上昇に関しては、各アルゴリズムで数100程度となっており、これ以上最適化計算を行っても大幅なスコア改善は見込まれないと想定します。また、Tabu Searchに関しては、2000秒程度でスコアの改善が見られず最適化計算が終了しています。



## 250名(目標スコア : 0hard/-17250soft)
**Tabu Search**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>entityTabuSize</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>11</td>
  <td>2000</td>
  <td>167</td>
  <td>0hard/-15400soft<br>(1378[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>9</td>
  <td>2000</td>
  <td>224</td>
  <td>0hard/-15265soft<br>(1722[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>5</td>
  <td>1000</td>
  <td>244</td>
  <td>0hard/-16190soft<br>(686[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>7</td>
  <td>4000</td>
  <td>262</td>
  <td>0hard/-15850soft</td>
  <td>―</td>
 </tr>
</table>

**Late Acceptance**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>lateAcceptanceSize</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>5</td>
  <td>1</td>
  <td><strong>98</strong></td>
  <td>0hard/-14755soft<br>(1775[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>20</td>
  <td>1</td>
  <td>182</td>
  <td>0hard/-14681soft</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>10</td>
  <td>1</td>
  <td>216</td>
  <td>0hard/-14534soft<br>(1739[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>10</td>
  <td>4</td>
  <td>248</td>
  <td>0hard/-15118soft<br>(1499[秒])</td>
  <td>ー</td>
 </tr>
</table>
**Simulated Annealing**

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th width="5%" rowspan="2">順位</th>
  <th colspan="2">パラメタ</th>
  <th rowspan="2">目標スコアに<br>到達した時間[秒]</th>
  <th rowspan="2">30分経過後の<br>ベストスコア</th>
  <th rowspan="2">60分経過後の<br>ベストスコア</th>
 </tr>
 <tr align="center">
  <th>simulatedAnnealing<br>StartingTemperature</th>
  <th>acceptedCountLimit</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td>0hard/5soft</td>
  <td>4</td>
  <td>193</td>
  <td>0hard/-15151soft<br>(1159[秒])</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>0hard/100soft</td>
  <td>4</td>
  <td>325</td>
  <td>0hard/-14977soft</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td>0hard/50soft</td>
  <td>1</td>
  <td>1215</td>
  <td>0hard/-14584soft</td>
  <td>ー</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>0hard/500soft</td>
  <td>4</td>
  <td>1355</td>
  <td>0hard/-15122soft</td>
  <td>ー</td>
 </tr>
</table>

250名規模のデータでは、最速98秒で目標スコアに到達しました。
また、目標スコア到達後も最適化計算を行うことで、ベストスコアが更新されました。

以下は、前述の表でのアルゴリズムごとのNo1のSoftスコア遷移です。
![250人_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/b50568d3-3865-572a-bfe8-248c7224be3d.png)
各アルゴリズムの始点はHardスコアが0hardとなった地点です。
①の吹き出しのとおり、Simulated Annealingが最も速く0hardに収束しました。

以下に②を拡大した図を記載します。
![250人_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702183/51312fa8-caf9-cb6c-ec5c-97490f86f8ae.png)
目標スコアへの到達が最も速いアルゴリズムは、Late Acceptanceでした。
開始から終了までLate Acceptanceが最も良いスコアとなりました。
①の300秒から最適化計算終了までのスコア上昇に関しては、各アルゴリズムで数100程度となっており、これ以上最適化計算を行っても大幅なスコア改善は見込まれないと想定します。




# 考察
今回の検証では、Red Hat Decision Managerで1000名規模の計画最適化を現実的な時間の範囲内で実現できることが確認できました。ここでは、検証から見えてきた内容を考察します。

## 各アルゴリズムの計算時間とスコアの特性
本検証のモデルケース、規模(探索空間のサイズ)および制約ルールの重み値では、各アルゴリズムの計算時間のスコアの特性(傾向)は見られませんでした。



## 各アルゴリズムのチューニングのしやすさ

<table style=" font-size: 10.5pt;">
 <tr align="center">
  <th width="5%">#</th>
  <th width="15%">最適化アルゴリズム</th>
  <th width="40%">検証から見られる特性</th>
  <th width="40%">検証結果からの考察</th>
 </tr>
 <tr>
  <td>1</td>
  <td>Tabu Search</td>
  <td>チューニングパラメタの値の範囲が広い。</td>
  <td>多くのパラメタを検証してチューニングすれば、最高スコアを出せる可能性は高いと想定します。<br>ただし、入力データは毎回同じではないため、汎用的な調整は難しいと想定します。</td>
 </tr>
 <tr>
  <td>2</td>
  <td>Late Acceptance</td>
  <td>チューニングパラメタの値の範囲が比較的狭い。</td>
  <td>パラメタの変更に伴うスコアの改善・悪化の傾向が見えやすく、本検証で利用した3つのアルゴリズムの中では、最も調整しやすいと想定します。</td>
 </tr>
 <tr>
  <td>3</td>
  <td>Simulated Annealing</td>
  <td>本検証の検証結果では、チューニングパラメタの値の範囲が比較的狭い。<br>ただし、チューニングパラメタ「simulatedAnnealingStartingTemperature」で「受け入れを許可するスコア値の初期値」を指定するため、制約ルールの重み値に依存する。</td>
  <td>規模(探索空間のサイズ)だけでなく、制約ルールの重み値も考慮して調整する必要があり、Late Acceptanceより調整が難しいと想定します。</td>
 </tr>
</table>



## チューニングパラメタの調整方法
<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th>#</th>
  <th>最適化<br>アルゴリズム</th>
  <th>チューニングパラメタ</th>
  <th>指定範囲</th>
 </tr>
 <tr align="center">
  <td>1</td>
  <td rowspan="2">Tabu Search</td>
  <td>entityTabuSize</td>
  <td>5～12</td>
 </tr>
 <tr align="center">
  <td>2</td>
  <td>acceptedCountLimit</td>
  <td>1000～4000</td>
 </tr>
 <tr align="center">
  <td>3</td>
  <td rowspan="2">Late Acceptance</td>
  <td>lateAcceptanceSize</td>
  <td>1～600</td>
 </tr>
 <tr align="center">
  <td>4</td>
  <td>acceptedCountLimit</td>
  <td>1 または 4</td>
 </tr>
 <tr align="center">
  <td>5</td>
  <td rowspan="2">Simulated Annealing</td>
  <td>simulatedAnnealingStartingTemperature</td>
  <td>(制約ルールの重み値に依存。)</td>
 </tr>
 <tr align="center">
  <td>6</td>
  <td>acceptedCountLimit</td>
  <td>1 または 4</td>
 </tr>
</table>
**#3,#5 :**
規模(探索空間のサイズ)によって調整するパラメタです。規模(探索空間のサイズ)が大きいほど値を小さくすると良いと想定します。<br>指定値が大きい場合は、評価対象の組合せ数が多くなり、問題を解く時間が長くなりますが、最高スコアが高くなります。<br>指定値が小さい場合は、評価対象の組合せ数が少なくなり、問題を解く時間が短くなりますが、最高スコアが低くなります。
**#1 :**
傾向は明確ではありませんが、7,9が比較的よく、規模(探索空間のサイズ)が小さい場合は、値を大きくすると良いと想定します。
**#2,#4,#6 :**
傾向が不明なパラメタのため、実測することを推奨します。

Tabu Size の entityTabuSize の指定範囲は5～11の範囲で検証しましたが、以下のサイトに「5～12の値が良い」と記載がありました。
https://ja.wikipedia.org/wiki/%E3%82%BF%E3%83%96%E3%83%BC%E3%82%B5%E3%83%BC%E3%83%81

どのアルゴリズムでもチューニングパラメタを変更することで結果が大きく変わりますが、調整次第で良い結果を得られることがわかりました。
各アルゴリズムのチューニングパラメタの調整方法を紹介しましたが、Late Acceptance が他のアルゴリズムと比較して調整しやすいと感じました。そのため、実測する時間が十分に確保できない場合は、Late Acceptance から調整してみるのも良いと想定します。



## 規模(探索空間のサイズ)ごとに基礎値として利用できそうなパラメタ
本検証では、各規模で約60パターンの検証を行いました。
同様のモデルケース、規模(探索空間のサイズ)および制約ルールの重み値で最適化計算を行う場合は、以下の最適化アルゴリズム・パラメタの組合せの範囲から、パラメタのチューニングを行うことで、効率よくチューニングを行うことできると想定します。

<table style="width=100%; font-size: 10.5pt;">
 <tr align="center">
  <th colspan="2">規模<br>(探索空間のサイズ)</th>
  <th rowspan="2">最適化アルゴリズム</th>
  <th rowspan="2">パラメタ</th>
 </tr>
 <tr align="center">
  <th>人員数</th>
  <th>シフト<br>枠数</th>
 </tr>
 <tr align="center">
  <td rowspan="3">1000</td>
  <td rowspan="3">4212</td>
  <td>Tabu Search</td>
  <td align="left">entityTabuSize : 7～9<br>acceptedCountLimit : 1000～4000</td>
 </tr>
  <tr align="center">
  <td>Late Acceptance</td>
  <td align="left">lateAcceptanceSize : 1～10<br>acceptedCountLimit : 1</td>
 </tr>
 </tr>
  <tr align="center">
  <td>Simulated Annealing</td>
  <td align="left">simulatedAnnealingStartingTemperature : 0hard/5soft～0hard/100soft<br>acceptedCountLimit : 4</td>
 </tr>
 <tr align="center">
  <td rowspan="4">500</td>
  <td rowspan="4">2106</td>
  <td>Tabu Search</td>
  <td align="left">entityTabuSize : 5～9<br>acceptedCountLimit : 1000～4000</td>
 </tr>
  <tr align="center">
  <td rowspan="2">Late Acceptance</td>
  <td align="left">lateAcceptanceSize : 3～10<br>acceptedCountLimit : 1</td>
 </tr>
 </tr>
  <tr align="center">
  <td align="left">lateAcceptanceSize : 30～100<br>acceptedCountLimit : 4</td>
 </tr>
 </tr>
  <tr align="center">
  <td>Simulated Annealing</td>
  <td align="left">simulatedAnnealingStartingTemperature : 0hard/5soft～0hard/100soft<br>acceptedCountLimit : 4</td>
 </tr>
 <tr align="center">
  <td rowspan="3">250</td>
  <td rowspan="3">1053</td>
  <td>Tabu Search</td>
  <td align="left">entityTabuSize : 11<br>acceptedCountLimit : 1000～4000</td>
 </tr>
  <tr align="center">
  <td>Late Acceptance</td>
  <td align="left">lateAcceptanceSize : 5～20<br>acceptedCountLimit : 1</td>
 </tr>
 </tr>
  <tr align="center">
  <td>Simulated Annealing</td>
  <td align="left">simulatedAnnealingStartingTemperature : 0hard/5soft<br>acceptedCountLimit : 4</td>
 </tr>
</table>



# おわりに
本稿では、250名、500名、1000名規模の計画最適化における性能検証結果を紹介しました。
紹介したチューニングパラメタの調整方法や、基礎値として利用できそうなパラメタを参考にすることで、Red Hat Decision Managerがより使いやすくなると思いますので、是非お試しください。