マシニングセンタスケジューリング

マシニングセンタは材料(ワーク)の加工を行う機械で、自動工具交換装置(Automatic Tool Changer)を搭載しており、ワーク加工中の工具の入れ替えを自動で行うことができます。

1 つのマシニングセンタに 1 人の作業員が配置され、ワークの着脱、工具の入れ替えを行うことを考えます。

一つのワークの完成のフローは下記です。

  1. 工具の装着

  2. ワークの装着

  3. マシニングセンタによる加工

  4. ワークの取り外し

  5. 工具の取り外し

ここで、複数のワークを順番に加工する場合、ワーク加工で使用する工具で共通する工具が多いと、工具の着脱工程を短縮することができます。

問題設定

複数のワークを、加工時間が異なる複数のマシニングセンタとそれぞれの作業者に割り当てる、スケジューリング問題を考えます。 目的関数はメイクスパンとします。

ここではワークの数を 15、マシニングセンタの数と作業者の人数を 3 とします。 ワークは(w1,w2,…,w15)とマシニングセンタは(m1,m2,m3)と表します。

ワーク

各ワークには、マシニングセンタごとの加工時間が割り当てられています。ここで加工時間は、ワークの装着からワークの取り外しまでの時間とします。

ワーク

加工時間(m1)

加工時間(m2)

加工時間(m3)

w1

10

20

30

w2

20

30

10

w3

30

40

20

w4

40

10

30

w5

10

30

40

w6

20

40

10

w7

30

10

20

w8

40

20

30

w9

10

20

40

w10

20

30

10

w11

30

40

20

w12

40

10

30

w13

10

30

40

w14

20

40

10

w15

30

10

20

使用工具

各ワークには使用工具が割り当てられており、使用工具の数は 20 で(k1,k2,…,k20)とします。

ワーク

使用工具

w1

k1, k2, k3, k4, k5

w2

k6, k7, k8, k9, k10

w3

k11, k12, k13, k14, k15

w4

k16, k17, k18, k19, k20

w5

k1, k2, k11, k16

w6

k3, k4, k12, k17

w7

k5, k6, k13, k18

w8

k7, k8, k14, k19

w9

k9, k10, k15, k20

w10

k1, k6, k11, k16

w11

k1, k2, k3, k4, k5

w12

k6, k7, k8, k9, k10

w13

k11, k12, k13, k14, k15

w14

k16, k17, k18, k19, k20

w15

k1, k2, k3, k4, k5

ここで、同一マシニングセンタにおいて、ワークの切り替えにかかる時間を下記のように定めます。

\[ \begin{align} \text{ワークの切り替え時間} = \text{工具の取り外し数} \times \text{取り外しコスト} + \text{工具の取付数} \times \text{取りつけコスト} \end{align} \]

今回は\(\text{取り外しコスト} = \text{取りつけコスト} = 10\)とします。

例えば、ワーク w1 からワーク w2 に切り替えるための時間は、工具 k1, k2, k3, k4, k5 を取り外し、工具 k6, k7, k8, k9, k10 を取り付けるため、\(5 \times 10 + 5 \times 10 = 100\)となります。
一方、ワーク w1 からワーク w5 に切り替えるための時間は、工具 k3, k4, k5 を取り外し、工具 k11, k16 を取り付けるため、\(3 \times 10 + 2 \times 10 = 50\)となります。

また使用工具の同時使用可能数は下記とします。

使用工具

同時使用可能数

k1

2

k2

2

k3

3

k4

3

k5

3

k6

2

k7

2

k8

2

k9

2

k10

2

k11

2

k12

2

k13

2

k14

2

k15

2

k16

2

k17

3

k18

2

k19

2

k20

2

Amplify Sched を用いた解法

from amplify_sched import *
import itertools
import pandas as pd

machine_list = ["m1", "m2", "m3"]
remove_work_time = 10
set_work_time = 10
df_w = pd.DataFrame()
df_w["ワーク"] = ["w{}".format(i) for i in range(1, 16)]
df_w["m1"] = [10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30]
df_w["m2"] = [20, 30, 40, 10, 30, 40, 10, 20, 20, 30, 40, 10, 30, 40, 10]
df_w["m3"] = [30, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20]
df_w["使用工具"] = [
    ["k1", "k2", "k3", "k4", "k5"],
    ["k6", "k7", "k8", "k9", "k10"],
    ["k11", "k12", "k13", "k14", "k15"],
    ["k16", "k17", "k18", "k19", "k20"],
    ["k1", "k2", "k11", "k16"],
    ["k3", "k4", "k12", "k17"],
    ["k5", "k6", "k13", "k18"],
    ["k7", "k8", "k14", "k19"],
    ["k9", "k10", "k15", "k20"],
    ["k1", "k6", "k11", "k16"],
    ["k1", "k2", "k3", "k4", "k5"],
    ["k6", "k7", "k8", "k9", "k10"],
    ["k11", "k12", "k13", "k14", "k15"],
    ["k16", "k17", "k18", "k19", "k20"],
    ["k1", "k2", "k3", "k4", "k5"],
]
df_w.set_index("ワーク", inplace=True)

df_k = pd.DataFrame()
df_k["工具"] = ["k{}".format(i) for i in range(1, 21)]
df_k["同時使用可能数"] = [2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2]
df_k.set_index("工具", inplace=True)


model = Model()
for j in df_w.index:
    model.jobs.add(j)
    model.jobs[j].append(Task())
for m in machine_list:
    model.machines.add(m)
for k in df_k.index:
    model.resources.add(k)
    model.resources[k].capacity = int(df_k.loc[k, "同時使用可能数"])


for j in df_w.index:
    for m in machine_list:
        model.jobs[j][0].processing_times[m] = int(df_w.loc[j, m])
    for k in df_w.loc[j, "使用工具"]:
        model.jobs[j][0].required_resources.append(k)

setup_times = {}
for j1, j2 in itertools.combinations(df_w.index, 2):
    remove_num = len(set(df_w.loc[j1, "使用工具"]) - set(df_w.loc[j2, "使用工具"]))
    add_num = len(set(df_w.loc[j2, "使用工具"]) - set(df_w.loc[j1, "使用工具"]))
    setup_times[(j1, j2)] = remove_num * remove_work_time + add_num * set_work_time
    setup_times[(j2, j1)] = add_num * remove_work_time + remove_num * set_work_time

    for m in machine_list:
        model.machines[m].setup_times.append((setup_times[(j1, j2)], j1, j2))
        model.machines[m].setup_times.append((setup_times[(j2, j1)], j2, j1))
token = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
gantt = model.solve(token=token, timeout=10)
gantt.timeline(machine_view=True)