より柔軟な生産計画立案¶
本チュートリアルでは、Fixstars Amplify Scheduling Engine (Amplify SE) を用い、各タスクを処理可能なマシン候補が複数ある場合の生産計画問題について考えます。このような問題を Flexible Job Shop Scheduling と呼ぶ場合があります。
本チュートリアルで扱う問題¶
『Amplify SE とは』で述べたクッキー工場を例にとり、次のような条件において、メイクスパンを最小化する生産計画を立案しましょう。
クッキー工場¶
この工場では、
- プレーンクッキ
- チョコチップクッキー
- ジンジャークッキー
を製造しており、それぞれのクッキーの製造に必要な全工程がジョブになります。つまり、この工場では、3種類のクッキーを製造するという3つのジョブを実行する必要があります。通常、それぞれのジョブは複数の『工程』 (Process) から構成されており、ここでは、
- 生地を作る
- クッキーの型を取る
- 焼く
- 梱包する
という工程があるとします。
問題設定¶
以下の設定で、最もメイクスパンを最小とするようなジョブの処理順序計画を立案します。以下で用いられている用語や Amplify SE については、『Amplify SE とは』をご覧ください。
-
4 台のマシン (
Machine W
、Machine X
、Machine Y
、Machine Z
) で 3 つのジョブ (Job A
、Job B
、Job C
) を処理。-
Job A
$\rightarrow$ プレーンクッキー -
Job B
$\rightarrow$ チョコチップクッキー -
Job C
$\rightarrow$ ジンジャークッキー
-
-
各ジョブでは、4 つの工程 (
0
$\rightarrow$1
$\rightarrow$2
$\rightarrow$3
)を順に処理し、これらの処理順序は全てのジョブで同一。-
工程
0
$\rightarrow$ 生地 -
工程
1
$\rightarrow$ 型取り -
工程
2
$\rightarrow$ 焼き -
工程
3
$\rightarrow$ 梱包
-
-
各マシンは次の複数のタスクを処理(あるタスクを処理できる複数のマシン候補がある)
ジョブ
j
の工程p
に属するタスクを(j, p)
と表記すると、-
Machine W
$\rightarrow$ タスク(A, 0)
、(A, 2)
、(B, 1)
、(B, 2)
、(C, 1)
、(C, 3)
-
Machine X
$\rightarrow$ タスク(A, 1)
、(A, 3)
、(B, 0)
、(B, 3)
、(C, 0)
、(C, 2)
-
Machine Y
$\rightarrow$ タスク(A, 0)
、(A, 2)
、(B, 1)
、(B, 2)
、(C, 1)
、(C, 3)
-
Machine Z
$\rightarrow$ タスク(A, 1)
、(A, 3)
、(B, 0)
、(B, 3)
、(C, 0)
、(C, 2)
-
まとめると、次のようなジョブ、工程、マシン設定を考慮する必要があり、また、各タスクに対しての処理時間の情報が次のように与えられているとします。処理時間の単位は任意ですが、時間は全て整数値で与える必要があります。ここでは分とします。
ジョブ名 | 工程 | タスクの処理ができるマシン名 | 処理時間(分) |
---|---|---|---|
Job A | 0 | Machine W Machine Y |
10 15 |
Job A | 1 | Machine Z Machine X |
15 10 |
Job A | 2 | Machine Y Machine W |
20 25 |
Job A | 3 | Machine X Machine Z |
5 5 |
Job B | 0 | Machine X Machine Z |
15 20 |
Job B | 1 | Machine Y Machine W |
20 15 |
Job B | 2 | Machine W Machine Y |
10 15 |
Job B | 3 | Machine Z Machine X |
5 5 |
Job C | 0 | Machine Z Machine X |
10 15 |
Job C | 1 | Machine W Machine Y |
20 15 |
Job C | 2 | Machine X Machine Z |
15 20 |
Job C | 3 | Machine Y Machine W |
5 5 |
問題実装と求解¶
上記で与えられた問題に対し、各ジョブや工程、条件を追加していくのみで、メイクスパン最小の生産計画を立案、可視化できるプログラムが完成します。以下のプログラムを実際に実行してみましょう。実行方法として次の 3 通りがあります。
-
Binderhub 上で実行(最も手軽)
-
Google Colab 上で実行(要 Google アカウント)
-
コードをダウンロード後、ローカルで実行(要ローカルでの環境構築)
得られた解 solution
の .timeline
メソッドにより、すぐに取得された計画のガントチャートを表示することができます。このインタラクティブなガントチャートは、マウス操作により様々な情報を表示することができます。以下では、マシン別、ジョブ別、タスク別のガントチャートの表示例を示しています。実際にセルを実行し、ガントチャートを表示させ、各ジョブに対して、タスクが工程順に実施されていること、上記問題設定を満たしていることを確認してください。また、立案された生産計画を、『最もシンプルな生産計画立案』や『少し柔軟な生産計画立案』と比較してみましょう。より柔軟な計画立案」では、メイクスパンが最も短くなっていることが分かります。
本チュートリアルにて 『Amplify SE 入門チュートリアル』は終了です。これまで学んだ知識で基本的な計画立案ができるようになりました。より複雑な計画のためのサンプルプログラムや解説はこちらに紹介されていますのでご覧ください。
# ! pip install amplify_sched # Google Colab 場合、こちらのコメントアウトを外し、amplify_sched をインストールしてください。
from amplify_sched import *
token = "" # ローカル環境等で使用する場合は、Amplify SE のアクセストークンを入力してください。
# モデルを作成
model = Model()
# モデルに 3 つのジョブを加える (jobs.add)
model.jobs.add("Job A") # プレーンクッキー
model.jobs.add("Job B") # チョコチップクッキー
model.jobs.add("Job C") # ジンジャークッキー
# モデルに 4 つのマシンを加える (machines.add)
model.machines.add("Machine W")
model.machines.add("Machine X")
model.machines.add("Machine Y")
model.machines.add("Machine Z")
# 各ジョブに対して、*工程順*にタスクを追加 (append)。
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times[
"Machine W"
] = 10 # 各タスクを担当し得るそれぞれのマシンに対して、処理時間 (processing_times) を指定。
model.jobs["Job A"][0].processing_times[
"Machine Y"
] = 15 # 各タスクを担当し得るそれぞれのマシンに対して、処理時間 (processing_times) を指定。
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine Z"] = 15
model.jobs["Job A"][1].processing_times["Machine X"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][2].processing_times["Machine Y"] = 20
model.jobs["Job A"][2].processing_times["Machine W"] = 25
model.jobs["Job A"].append(Task())
model.jobs["Job A"][3].processing_times["Machine X"] = 5
model.jobs["Job A"][3].processing_times["Machine Z"] = 5
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine X"] = 15
model.jobs["Job B"][0].processing_times["Machine Z"] = 20
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine Y"] = 20
model.jobs["Job B"][1].processing_times["Machine W"] = 15
model.jobs["Job B"].append(Task())
model.jobs["Job B"][2].processing_times["Machine W"] = 10
model.jobs["Job B"][2].processing_times["Machine Y"] = 15
model.jobs["Job B"].append(Task())
model.jobs["Job B"][3].processing_times["Machine Z"] = 5
model.jobs["Job B"][3].processing_times["Machine X"] = 5
model.jobs["Job C"].append(Task())
model.jobs["Job C"][0].processing_times["Machine Z"] = 15
model.jobs["Job C"][0].processing_times["Machine X"] = 10
model.jobs["Job C"].append(Task())
model.jobs["Job C"][1].processing_times["Machine W"] = 20
model.jobs["Job C"][1].processing_times["Machine Y"] = 15
model.jobs["Job C"].append(Task())
model.jobs["Job C"][2].processing_times["Machine X"] = 15
model.jobs["Job C"][2].processing_times["Machine Z"] = 20
model.jobs["Job C"].append(Task())
model.jobs["Job C"][3].processing_times["Machine Y"] = 5
model.jobs["Job C"][3].processing_times["Machine W"] = 5
# model.solve でスケジュールを求解
solution = model.solve(token=token, timeout=1)
# メソッド .timeline でマシン別のガントチャートを取得し、表示
fig = solution.timeline(machine_view=True)
fig.show()
# メソッド .timeline でジョブ別のガントチャートを取得し、表示
fig = solution.timeline()
fig.show()
# メソッド .timeline でタスク別のガントチャートを取得し、表示
fig = solution.timeline(separated_by_task=True)
fig.show()