{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# マシニングセンタスケジューリング\n",
"\n",
"マシニングセンタは材料(ワーク)の加工を行う機械で、自動工具交換装置(Automatic Tool Changer)を搭載しており、ワーク加工中の工具の入れ替えを自動で行うことができます。\n",
"\n",
"1 つのマシニングセンタに 1 人の作業員が配置され、ワークの着脱、工具の入れ替えを行うことを考えます。\n",
"\n",
"一つのワークの完成のフローは下記です。\n",
"\n",
"1. 工具の装着\n",
"2. ワークの装着\n",
"3. マシニングセンタによる加工\n",
"4. ワークの取り外し\n",
"5. 工具の取り外し\n",
"\n",
"ここで、複数のワークを順番に加工する場合、ワーク加工で使用する工具で共通する工具が多いと、工具の着脱工程を短縮することができます。\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 問題設定\n",
"\n",
"複数のワークを、加工時間が異なる複数のマシニングセンタとそれぞれの作業者に割り当てる、スケジューリング問題を考えます。\n",
"目的関数はメイクスパンとします。\n",
"\n",
"ここではワークの数を 15、マシニングセンタの数と作業者の人数を 3 とします。\n",
"ワークは(w1,w2,...,w15)とマシニングセンタは(m1,m2,m3)と表します。\n",
"\n",
"### ワーク\n",
"\n",
"各ワークには、マシニングセンタごとの加工時間が割り当てられています。ここで加工時間は、ワークの装着からワークの取り外しまでの時間とします。\n",
"\n",
"| ワーク | 加工時間(m1) | 加工時間(m2) | 加工時間(m3) |\n",
"| :----: | :----------: | :----------: | :----------: |\n",
"| w1 | 10 | 20 | 30 |\n",
"| w2 | 20 | 30 | 10 |\n",
"| w3 | 30 | 40 | 20 |\n",
"| w4 | 40 | 10 | 30 |\n",
"| w5 | 10 | 30 | 40 |\n",
"| w6 | 20 | 40 | 10 |\n",
"| w7 | 30 | 10 | 20 |\n",
"| w8 | 40 | 20 | 30 |\n",
"| w9 | 10 | 20 | 40 |\n",
"| w10 | 20 | 30 | 10 |\n",
"| w11 | 30 | 40 | 20 |\n",
"| w12 | 40 | 10 | 30 |\n",
"| w13 | 10 | 30 | 40 |\n",
"| w14 | 20 | 40 | 10 |\n",
"| w15 | 30 | 10 | 20 |\n",
"\n",
"### 使用工具\n",
"\n",
"各ワークには使用工具が割り当てられており、使用工具の数は 20 で(k1,k2,...,k20)とします。\n",
"\n",
"| ワーク | 使用工具 |\n",
"| :----: | :---------------------: |\n",
"| w1 | k1, k2, k3, k4, k5 |\n",
"| w2 | k6, k7, k8, k9, k10 |\n",
"| w3 | k11, k12, k13, k14, k15 |\n",
"| w4 | k16, k17, k18, k19, k20 |\n",
"| w5 | k1, k2, k11, k16 |\n",
"| w6 | k3, k4, k12, k17 |\n",
"| w7 | k5, k6, k13, k18 |\n",
"| w8 | k7, k8, k14, k19 |\n",
"| w9 | k9, k10, k15, k20 |\n",
"| w10 | k1, k6, k11, k16 |\n",
"| w11 | k1, k2, k3, k4, k5 |\n",
"| w12 | k6, k7, k8, k9, k10 |\n",
"| w13 | k11, k12, k13, k14, k15 |\n",
"| w14 | k16, k17, k18, k19, k20 |\n",
"| w15 | k1, k2, k3, k4, k5 |\n",
"\n",
"ここで、同一マシニングセンタにおいて、ワークの切り替えにかかる時間を下記のように定めます。\n",
"\n",
"$$\n",
"\\begin{align}\n",
"\\text{ワークの切り替え時間} = \\text{工具の取り外し数} \\times \\text{取り外しコスト} + \\text{工具の取付数} \\times \\text{取りつけコスト}\n",
"\\end{align}\n",
"$$\n",
"\n",
"今回は$\\text{取り外しコスト} = \\text{取りつけコスト} = 10$とします。\n",
"\n",
"例えば、ワーク w1 からワーク w2 に切り替えるための時間は、工具 k1, k2, k3, k4, k5 を取り外し、工具 k6, k7, k8, k9, k10 を取り付けるため、$5 \\times 10 + 5 \\times 10 = 100$となります。 \n",
"一方、ワーク w1 からワーク w5 に切り替えるための時間は、工具 k3, k4, k5 を取り外し、工具 k11, k16 を取り付けるため、$3 \\times 10 + 2 \\times 10 = 50$となります。\n",
"\n",
"また使用工具の同時使用可能数は下記とします。\n",
"\n",
"| 使用工具 | 同時使用可能数 |\n",
"| :------: | :------------: |\n",
"| k1 | 2 |\n",
"| k2 | 2 |\n",
"| k3 | 3 |\n",
"| k4 | 3 |\n",
"| k5 | 3 |\n",
"| k6 | 2 |\n",
"| k7 | 2 |\n",
"| k8 | 2 |\n",
"| k9 | 2 |\n",
"| k10 | 2 |\n",
"| k11 | 2 |\n",
"| k12 | 2 |\n",
"| k13 | 2 |\n",
"| k14 | 2 |\n",
"| k15 | 2 |\n",
"| k16 | 2 |\n",
"| k17 | 3 |\n",
"| k18 | 2 |\n",
"| k19 | 2 |\n",
"| k20 | 2 |\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Amplify Sched を用いた解法\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from amplify_sched import *\n",
"import itertools\n",
"import pandas as pd\n",
"\n",
"machine_list = [\"m1\", \"m2\", \"m3\"]\n",
"remove_work_time = 10\n",
"set_work_time = 10\n",
"df_w = pd.DataFrame()\n",
"df_w[\"ワーク\"] = [\"w{}\".format(i) for i in range(1, 16)]\n",
"df_w[\"m1\"] = [10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30]\n",
"df_w[\"m2\"] = [20, 30, 40, 10, 30, 40, 10, 20, 20, 30, 40, 10, 30, 40, 10]\n",
"df_w[\"m3\"] = [30, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30, 40, 10, 20]\n",
"df_w[\"使用工具\"] = [\n",
" [\"k1\", \"k2\", \"k3\", \"k4\", \"k5\"],\n",
" [\"k6\", \"k7\", \"k8\", \"k9\", \"k10\"],\n",
" [\"k11\", \"k12\", \"k13\", \"k14\", \"k15\"],\n",
" [\"k16\", \"k17\", \"k18\", \"k19\", \"k20\"],\n",
" [\"k1\", \"k2\", \"k11\", \"k16\"],\n",
" [\"k3\", \"k4\", \"k12\", \"k17\"],\n",
" [\"k5\", \"k6\", \"k13\", \"k18\"],\n",
" [\"k7\", \"k8\", \"k14\", \"k19\"],\n",
" [\"k9\", \"k10\", \"k15\", \"k20\"],\n",
" [\"k1\", \"k6\", \"k11\", \"k16\"],\n",
" [\"k1\", \"k2\", \"k3\", \"k4\", \"k5\"],\n",
" [\"k6\", \"k7\", \"k8\", \"k9\", \"k10\"],\n",
" [\"k11\", \"k12\", \"k13\", \"k14\", \"k15\"],\n",
" [\"k16\", \"k17\", \"k18\", \"k19\", \"k20\"],\n",
" [\"k1\", \"k2\", \"k3\", \"k4\", \"k5\"],\n",
"]\n",
"df_w.set_index(\"ワーク\", inplace=True)\n",
"\n",
"df_k = pd.DataFrame()\n",
"df_k[\"工具\"] = [\"k{}\".format(i) for i in range(1, 21)]\n",
"df_k[\"同時使用可能数\"] = [2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2]\n",
"df_k.set_index(\"工具\", inplace=True)\n",
"\n",
"\n",
"model = Model()\n",
"for j in df_w.index:\n",
" model.jobs.add(j)\n",
" model.jobs[j].append(Task())\n",
"for m in machine_list:\n",
" model.machines.add(m)\n",
"for k in df_k.index:\n",
" model.resources.add(k)\n",
" model.resources[k].capacity = int(df_k.loc[k, \"同時使用可能数\"])\n",
"\n",
"\n",
"for j in df_w.index:\n",
" for m in machine_list:\n",
" model.jobs[j][0].processing_times[m] = int(df_w.loc[j, m])\n",
" for k in df_w.loc[j, \"使用工具\"]:\n",
" model.jobs[j][0].required_resources.append(k)\n",
"\n",
"setup_times = {}\n",
"for j1, j2 in itertools.combinations(df_w.index, 2):\n",
" remove_num = len(set(df_w.loc[j1, \"使用工具\"]) - set(df_w.loc[j2, \"使用工具\"]))\n",
" add_num = len(set(df_w.loc[j2, \"使用工具\"]) - set(df_w.loc[j1, \"使用工具\"]))\n",
" setup_times[(j1, j2)] = remove_num * remove_work_time + add_num * set_work_time\n",
" setup_times[(j2, j1)] = add_num * remove_work_time + remove_num * set_work_time\n",
"\n",
" for m in machine_list:\n",
" model.machines[m].setup_times.append((setup_times[(j1, j2)], j1, j2))\n",
" model.machines[m].setup_times.append((setup_times[(j2, j1)], j2, j1))"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
" \n",
" "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.plotly.v1+json": {
"config": {
"plotlyServerURL": "https://plot.ly"
},
"data": [
{
"alignmentgroup": "True",
"base": [
70
],
"customdata": [
[
"w1",
0
]
],
"hovertemplate": "Job=%{customdata[0]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}
Start=%{base}
Finish=%{x}
Machine=%{y}
Process=%{customdata[1]}