●一般の工程計画問題は、日程計画・配員計画・定盤計画・運搬計画がお互いに連動すると考えられます。ここで、定盤計画とは作業場所の割付を意味しています。これを解くために参考になると思われるベンチマーク問題を作成してみました。各計画において考慮すべきファクターとして、次のものがあります。
日程計画: 作業間先行制約
配員計画: 作業員(平準化)、工場カレンダー
定盤計画: 作業場所、待機場所
運搬計画: 作業機械(台車、クレーン)
これらの計画を行うためには、まず各作業の総時数と各作業員数を考慮して、各作業期間を決定し、納期までの先行関係を明らかにし、配員計画と日程計画を同時に立てます。次に日程計画に沿って、作業場所の確保(定盤計画)を行います。場所が空いていなければ、待機が必要となりますが、その期間を計画前に予め把握することはできないことに注意します。また、各運搬日には運搬機械を使う時間帯を決める運搬計画を立てます。さらに、悪天候や機械の故障、作業員の欠勤などによる工程中断後、工程の再計画(リスケジューリング)を行う必要があります。
●次の初期計画を考えます。
これから作業と先行制約に関して次表を得ます。
また、リソースについては次表のようにまとめられます。
作業場所・待機場所
作業機械
作業員
●次のプログラムを考えます、
#prob31.py
from optseq import *
import math
#=====リソース
bp=Model()
resJ={}
for j in range(0,4):
for k in range(0,5):
resJ[j,k] =bp.addResource("J{0}{1}".format(j,k), capacity={(0,"inf"):1})
resH={}
for k in range(0,5):
resH[k] =bp.addResource("H{0}".format(k), capacity={(0,"inf"):3})
resP=bp.addResource("P", capacity={(0,"inf"):1})
#resD=bp.addResource("D", capacity={(0,"inf"):3})
resT=bp.addResource("T", capacity={(0,"inf"):20})
resC={}
for i in range(0,2):
for j in range(0,3):
resC[i,j] =bp.addResource("C{0}{1}".format(i,j), capacity={(0,"inf"):1})
resW1=bp.addResource("W1", capacity={(0,"inf"):1})
resW2=bp.addResource("W2", capacity={(0,"inf"):4})
#=====データセット
#0:"アクティビティ", #1:[作業ID],
#2:[作業日数], #3:"納期(順時間)",
#4:["後続アクティビティNo(順時間)"], #5:["CS時差(順時間)"],
#6:"作業場所選択肢", #7:["作業場所使用量"],
#8:"待機場所選択肢", #9:["待機場所使用量"],
#10:"作業設備選択肢", #11:{"作業設備使用量"},
#12:["職種選択肢"], #13:["作業員使用期間"],#14:["作業員使用量"]
J=1; P=2; D=3; T=1; H=1; C=2; W1=1; W2=2;
data={\
1:["100_B1_取付",[1],[2], 13, [2],[0], J, [3, 2], 0, [0], H, {1:[3]},[W1],[2],[1]],\
2:["100_B1_溶接",[2],[4], 18, [-3,9],[0,0], J, [3, 2], 0, [0], H, {1:[2]},[W2],[4],[2]],\
3:["100_B1_塗装",[3],[1], 21, [-4],[0], P, [1], T, [3, 2], 0, {0},[0],[0],[0]],\
4:["100_B1_搭載",[4],[1], 25, [0],[0], D, [0], T, [3, 2], C, {1:[1, 2]},[0],[0],[0]],\
5:["100_B2_取付",[1],[3], 14, [6],[-1], J, [2, 3], 0, [0], H, {1:[2]},[W1],[3],[1]],\
6:["100_B2_溶接",[2],[5], 18, [-7,9],[0,0], J, [2, 3], 0, [0], H, {1:[2]},[W2],[5],[2]],\
7:["100_B2_塗装",[3],[1], 21, [-8],[0], P, [1], T, [2, 3], 0, {0},[0],[0],[0]],\
8:["100_B2_搭載",[4],[1], 25, [0],[0], D, [0], T, [2, 3], C, {1:[1, 2]},[0],[0],[0]],\
9:["100_B3_取付",[1],[1], 20, [10],[0], J, [3, 3], 0, [0], H, {1:[1]},[W1],[1],[1]],\
10:["100_B3_溶接",[2],[2], 22, [-11],[0], J, [3, 3], 0, [0], H, {1:[1]},[W2],[2],[2]],\
11:["100_B3_搭載",[4],[1], 26, [0],[0], D, [0], T, [3, 3], C, {1:[1, 2]},[0],[0],[0]],\
}
#=====アクティビティ
act={}
for i in data: #納期設定
act[i]=bp.addActivity(data[i][0],duedate=data[i][3])
#=====先行制約
for i in data:
if not data[i][4]==[0]: #次作業が搭載(終端)でなければ先行関係を定義
for j in range(0,len(data[i][4])):
bp.addTemporal(act[i],act[abs(data[i][4][j])],tempType="CS",delay=0)# data[i][5][j])
if data[i][1]==[1]:
bp.addTemporal(act[abs(data[i][4][j])],act[i],tempType="SC",delay=0) #-data[i][5][j])
#-----納期日
for i in data:
if data[i][1]==[4]: #現作業が搭載ならば納期を実日程に固定
bp.addTemporal("source",act[i],"SS",delay= data[i][3])
bp.addTemporal(act[i],"source","SS",delay=-data[i][3])
bp.addTemporal(act[2],act[6],"CC",delay=0)
bp.addTemporal(act[6],act[2],"CC",delay=0)
#-----開始日
start=12
bp.addTemporal("source",act[1],"SS",delay= start)
bp.addTemporal(act[1],"source","SS",delay=-start)
bp.addTemporal("source",act[5],"SS",delay= start)
bp.addTemporal(act[5],"source","SS",delay=-start)
#=====資源制約
mode={}
for i in data:
#-----作業場所(組立定盤) resJ
if data[i][6]==J:
l=data[i][7][0]
b=data[i][7][1]
for j in range(0,4-b+1): #幅方向の定盤選択
for k in range(0,5-l+1): #長さ方向の定盤選択
mode[i,j,k]=Mode("mode[{0:03d}][{1}_{2}][{3}_{4}]".format(i,j,k,b,l),duration=sum(data[i][2]))
mode[i,j,k].addBreak(0,'inf')
for s in range(0,b): #ブロック幅の定盤確保
for t in range(0,l):#ブロック長の定盤確保
mode[i,j,k].addResource(resJ[j+s,k+t],1)
mode[i,j,k].addResource(resJ[j+s,k+t],1,"break")
mode[i,j,k].addResource(resH[k+t],data[i][11][1][0])
mode[i,j,k].addResource(resH[k+t],data[i][11][1][0],"break")
#-----高さ制約
if i==2 or i==6 or i==10:
for q in range(k+l,5):
mode[i,j,k].addResource(resH[q],data[i][11][1][0],"break")
#-----員数制約
if data[i][12][0]==W1:
mode[i,j,k].addResource(resW1,data[i][14][0])
if data[i][12][0]==W2:
mode[i,j,k].addResource(resW2,data[i][14][0])
act[i].addModes(mode[i,j,k])
#-----作業場所(塗装工場) resP
if data[i][6]==P:
mode[i]=Mode("mode[{0:03d}1]".format(i),duration=data[i][2][0])
mode[i].addResource(resP,1)
act[i].addModes(mode[i])
#-----作業場所(ドック) resD, resC
if data[i][6]==D:
for time in data[i][11]:
for j in range(0,3-time): #開始時間
mode[i,j]=Mode("mode[{0:03d}1][{1}]".format(i,j),duration=1)
#mode[i,j].addResource(resD,{(0,1):1})
for k in data[i][11][time]:
for s in range(0,time): #稼働時間
mode[i,j].addResource(resC[k-1,j+s],1)
act[i].addModes(mode[i,j])
#=====待機場所(塗装前、搭載前) resT
d_act={}
for i in data:
if data[i][1]==[3] or data[i][1]==[4]:
d_act[i]=bp.addActivity("act[{0:03d}]待機".format(i))
bp.addTemporal(act[i-1],d_act[i],tempType="CS")
bp.addTemporal(d_act[i],act[i-1],tempType="SC")
bp.addTemporal(d_act[i],act[i],tempType="CS")
bp.addTemporal(act[i],d_act[i],tempType="SC")
d_mode={}
for i in data:
if data[i][1]==[3] or data[i][1]==[4]:
d_mode[i]=Mode("mode[{0:03d}]".format(i))
d_mode[i].addBreak(0,0)
d_mode[i].addResource(resT,{(0,"inf"):data[i][9][0]*data[i][9][1]},"break")
d_act[i].addModes(d_mode[i])
#=====モード制約
n_res={}
for i in data:
if data[i][6]==J and data[i+1][6]==J:
l=data[i][7][0]
b=data[i][7][1]
for j in range(0,4-b+1):
for k in range(0,5-l+1):
n_res[i,j,k]=bp.addResource("constraint[{0}_{1}_{2}]".format(i,j,k),rhs=0,direction="=")
n_res[i,j,k].addTerms(1,act[i],mode[i,j,k])
n_res[i,j,k].addTerms(-1,act[i+1],mode[i+1,j,k])
#=====最適化
bp.Params.Makespan=False
bp.Params.Initial=False
bp.Params.TimeLimit=1
bp.Params.Neighborhood=20
bp.optimize()
bp.writeExcel("bp_result.csv")
bp.write("bp_result.txt")
#-----
#eof
●日程計画
●定盤計画
●その他