Additional Constraints

release_time, deadline

各Taskには開始可能時刻(Release Time)と終了締め切り時刻(Deadline)を与えることができます。

下記例ではJob Aの0番目のプロセスの開始時間は10以上、終了時間は20以下であることを指定します。

from amplify_sched import *

token = "xxxxxxxxxxxxxxxxxxxxxxxxx"

model = Model()
model.jobs.add("Job A")
model.machines.add("Machine X")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine X"] = 10
model.jobs["Job A"][0].release_time = 10
model.jobs["Job A"][0].deadline = 20
gantt = model.solve(token=token, timeout=1)
gantt.timeline()

transportation_time

ある Machine からある Machine への輸送時間(transportation_time)を Task ごとに設定できます。輸送時間が設定されている場合、その時間より短い間隔では次の Task を開始できません。

下記例ではMachine A からMachine BJob Aの0番目のプロセスの輸送時間を10に設定しています。

model = Model()
model.jobs.add("Job A")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 7
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine B"] = 5
model.jobs["Job A"][0].transportation_times.append((10, "Machine A", "Machine B"))
gantt = model.solve(token=token, timeout=1)
gantt.timeline()

setup_time

ある Machine において、ある Task からある Task への切り替えにかかる準備時間(setup_time)を設定できます。準備時間が設定されている場合、その時間より短い間隔では次の Task を開始できません

下記例ではMachine A において、Task[Job A, 0]<->Task[Job B,1]の切り替えにかかる準備時間を10に設定しています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 7
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 7
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine A"] = 5
model.machines["Machine A"].setup_times.append((10, model.jobs["Job A", 0], model.jobs["Job B", 1]))
model.machines["Machine A"].setup_times.append((10, model.jobs["Job B", 1], model.jobs["Job A", 0]))
gantt = model.solve(token=token, timeout=1)
gantt.timeline(machine_view=True)

maintenance_time

ある Machine が稼働できない時間区間を設定できます。設定した時間区間ではその Machine では Task を行うことはできません。

下記例ではMachine Aは10~15をmaintenance_timeにしています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.jobs.add("Job C")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 7
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 7
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine A"] = 5
model.jobs["Job C"].append(Task())
model.jobs["Job C"][0].processing_times["Machine A"] = 10
model.machines["Machine A"].maintenance_times.append(TimeRange(10, 15))
gantt = model.solve(token=token, timeout=1)
gantt.timeline(machine_view=True)

buffer

ある Machine で終了した Task を、次の Machine での処理が始まるまで保管する倉庫を考えます。このとき、各 Machine の倉庫の容量と各 Task が占有するサイズを設定することができます。これらが設定されている場合、各時刻において倉庫の容量を超えるようなスケジュールは許されません。

下記例ではMachine Aのバッファを1に、Task["Job A",0],Task["Job B",0],Task["Job C",1]の要求バッファサイズを1に設定しています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.jobs.add("Job C")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 1
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine B"] = 3
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine A"] = 1
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine B"] = 2
model.jobs["Job C"].append(Task())
model.jobs["Job C"][0].processing_times["Machine A"] = 1
model.jobs["Job C"].append(Task())
model.jobs["Job C"][1].processing_times["Machine B"] = 7
model.jobs["Job A"][1].deadline = 4
model.jobs["Job B"][1].deadline = 6
model.machines["Machine A"].buffer_size = 1
model.machines["Machine A"].maintenance_times.append(TimeRange(3, 6))
model.jobs["Job A"][0].required_buffer_size = 1
model.jobs["Job B"][0].required_buffer_size = 1
model.jobs["Job C"][0].required_buffer_size = 1
gantt = model.solve(token=token, timeout=1)
gantt.timeline(machine_view=True)

resource

各 Task を行うために必要なリソースを定義できます。各リソースには同時使用上限数が定められ、その数を超える複数の Task で同時にリソースを使用できません。

下記例はTask[Job A,0],Task[Job B,0]Resource Aを使用します。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.resources.add("Resource A")
model.resources["Resource A"].capacity = 1
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 10
model.jobs["Job A"][0].required_resources.append("Resource A")
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 10
model.jobs["Job B"][0].required_resources.append("Resource A")

gantt = model.solve(token=token, timeout=1)
gantt.timeline(machine_view=True)

より詳細な設定として、各 Task が実行される Machine ごとに異なるリソースを使用するように設定することもできます。 例えばあるTask がMachine Aで実行される際にはResource Aを、Machine Bで実行される際にはResource Bを使用するように設定できます。

下記例ではTask[Job A,0]Machine AResource Aを使用し、Machine BResource Bを使用するように、Task[Job B,0]Machine BResource Aを使用するように設定しています。 リソースを考えなければTask[Job A,0]Machine ATask[Job B,0]Machine Bで同時に実行できますが、それぞれcapacity=1Resource Aを使用するため同時に実行することはできません。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.resources.add("Resource A")
model.resources["Resource A"].capacity = 1
model.resources.add("Resource B")
model.resources["Resource B"].capacity = 1
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 6
model.jobs["Job A"][0].processing_times["Machine B"] = 5
model.jobs["Job A"][0].required_resources.append(("Resource A", "Machine A"))
model.jobs["Job A"][0].required_resources.append(("Resource B", "Machine B"))
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 10
model.jobs["Job B"][0].required_resources.append(("Resource A", "Machine B"))

gantt = model.solve(token=token, timeout=1)
gantt.timeline(machine_view=True)

no_wait

各 Job に no-wait フラグを設定できます。no-wait が設定された Job は一度 Task を始めたら、全 Task が終了するまで連続で Task を行う必要があります。

下記例はJob Bno_wait=Trueを設定しています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.machines.add("Machine C")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine B"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine A"] = 15
model.jobs["Job B"].append(Task())
model.jobs["Job B"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].no_wait = True
gantt = model.solve(token=token, timeout=1)
gantt.timeline()

dependent_jobs

各 Job ごとに依存する Job を複数定義できます。依存する Job が定義されている場合、それらがすべて完了しないとその Job は開始できません。

下記例はJob BJob Aに依存すると設定しています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.machines.add("Machine C")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine B"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine A"] = 15
model.jobs["Job B"].append(Task())
model.jobs["Job B"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].dependent_jobs.append("Job A")
gantt = model.solve(token=token, timeout=1)
gantt.timeline()

また、指定した依存先 Job の完了と依存元 Job の開始の間のインターバル時間を制約として課すことができます。例えば、インターバル時間として整数を指定した場合、依存先ー依存元間のインターバル時間は指定の時間と等しくなるように制約が課されます。また、インターバル時間として、(5, 10) のような上限値・下限値から構成されるタプルで指定すれば、依存先ー依存元間のインターバル時間が時指定した上限値・下限値に収まるような制約が課されます。上限値・下限値の片方のみ課したい場合は、もう片方に None を指定します。また、上限値 = 下限値となるようなタプルを与えた場合は、インターバル時間として整数を指定した場合と同じ挙動になります。

下記例はJob BJob Aに依存し、その間のインターバル時間は 5 以上である、と設定しています。

model = Model()
model.jobs.add("Job A")
model.jobs.add("Job B")
model.machines.add("Machine A")
model.machines.add("Machine B")
model.machines.add("Machine C")
model.jobs["Job A"].append(Task())
model.jobs["Job A"][0].processing_times["Machine A"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][1].processing_times["Machine B"] = 10
model.jobs["Job A"].append(Task())
model.jobs["Job A"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][0].processing_times["Machine B"] = 10
model.jobs["Job B"].append(Task())
model.jobs["Job B"][1].processing_times["Machine A"] = 15
model.jobs["Job B"].append(Task())
model.jobs["Job B"][2].processing_times["Machine C"] = 10
model.jobs["Job B"].dependent_jobs.append(("Job A", (5, None)))
gantt = model.solve(token=token, timeout=1)
gantt.timeline()

複数の制約がある場合

transportation_time + setup_time

transportation_time と setup_time が両方設定されている場合、それぞれ独立に制約を課します。すなわちある Machine における切り替え準備は前後の Task の輸送時間中にも行うことができます。

transportation_time + no_wait

no-wait フラグと transportation_time が両方設定されている場合、no-wait フラグが設定されている Job の連続する 2 つの Task(j, p), Task(j,p+1)について、Task(j,p+1) の処理開始時刻 = Task(j,p) の処理終了時刻 + transportation_time[Task(j,p), Machine A, Machine B] となります。

transportation_time + dependent_jobs

dependent_jobs によって Job A -> Job C という順序関係が定義されている場合、Job A の最後の工程に対して transportation_time を設定することができ、Job C の最初の工程は Job A の最後の工程から transportaion_time 以上経過しないと開始できません。

transportation_time + buffer

buffer と transportation_time が両方設定されている場合、Task は輸送時間中には倉庫を使用しないとし、輸送直後に次のタスクが開始されると考えます。