再計画

これを得るプログラムを、本資料では次のように分割して示しています。

 プログラムIII ************************ 再計画 ************************
・プログラムIII-1 リソース(場所)の定義
・プログラムIII-2 リソース(作業員)の定義
・プログラムIII-3 再計画アクティビティ(仕掛作業、未着手作業)の定義
         未着手作業の先行制約の設定
・プログラムIII-4 モードの設定
         仕掛作業のモード継承
         未着手作業の資源制約(配員)
         未着手作業の資源制約(作業場所)
・プログラムIII-5 RCPSP求解

プログラム:Part III

#プログラムIII-1.0
from optseq import *
import math
#=======================================================================
print("")
print(' ************************ リスケ on rdate **********************')
import dill
dill.load_session('usukiR040510b.pkl')  
#=======================================================================
usuki3=Model()
CS=["CS","CC","SS","SC"]

プログラムIII-1

#プログラムIII-1
#=======================================================================
#リソースの定義(場所) 
#=======================================================================
#-----メッシュの使用可否
resPL={}
for id in R:
  resPL[id]=0
  if not id in [4,5,6,13]:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):        
        resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):1}) 
  if id==4:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,11) and j in range(0,12):
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):1})
  if id==5:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,7) and j in range(0,10):
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):1})
  if id==6:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [0,22,23,24,25,26,27,28,29,30,31,32,33,34,35] and j in range(0,13):
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):0})
        elif i in range(1,17) and j in range(0,1):
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):0})            
        else:     
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):1})
  if id==13:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [31,32,33,34,35,36,37,63,64,65,66,67,68,69,70,71] and j in range(0,24):
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):0})         
        else:     
          resPL[id,i,j] =usuki3.addResource(R[id][0]+"[{0:02d}_{1:02d}]".format(i,j), capacity={(0,"inf"):1})

プログラムIII-2

#プログラムIII-2
#=======================================================================
#リソースの定義(作業員)
#=======================================================================
eps1=1.25
resWH={}    #取付28人
r=math.floor(28*4*eps1);
resWH=usuki3.addResource("R[WH]", capacity={(0,"inf"):r})
#-----
resWW={}    #溶接43人
r=math.floor(43*4*eps1);
resWW=usuki3.addResource("R[WW]", capacity={(0,"inf"):r})
#-----
eps2=1.25
resWF1={}   #鉄艤5人
r=math.floor(5*4*eps2);
resWF1=usuki3.addResource("R[WF1]", capacity={(0,"inf"):r})
#-----
resWF2={}   #甲配7人
r=math.floor(7*4*eps2);
resWF2=usuki3.addResource("R[WF2]", capacity={(0,"inf"):r})
#-----
resWF3={}   #機配5人⇒10人
r=math.floor(10*4*eps2);
resWF3=usuki3.addResource("R[WF3]", capacity={(0,"inf"):r})
#-----
resWP={}    #塗装内4人⇒8人
r=math.floor(8*4*eps2);
resWP=usuki3.addResource("R[WP]", capacity={(0,"inf"):r})
#-----
resWP2={}   #塗装外8人
r=math.floor(8*4*eps2);
resWP2=usuki3.addResource("R[WP2]", capacity={(0,"inf"):r})

プログラムIII-3

#プログラムIII-3.1
#=======================================================================
#再計画 アクティビティ idata3
#=======================================================================
rdate=179
w1=[]; w2=[]; w3=[];
idata12=idata1.union(idata2)
for i in idata12:
  if data[i][3]+data[i][2] < rdate: w1.append(i)
  if data[i][3] <= rdate  and  rdate <= data[i][3]+data[i][2]: w2.append(i)
  if rdate < data[i][3]: w3.append(i)
idata3a=w2;   #仕掛かり中のアクティビティ
idata3b=w3;   #仕掛かっていないアクティビティ 
idata3=w2+w3; #リスケすべきアクティビティ 
print(idata3) 
#プログラムIII-3.2
#=======================================================================
#再計画 作業の定義
#=======================================================================
act3={}
for i in idata3:    
  j=i  
  while data[j][1]!=0:
    j=data[j][4][0]
  act3[i]=usuki3.addActivity(data[i][0], duedate=data[j][3]+data[j][2], \
                                                         backward=True)
#プログラムIII-3.3
#=======================================================================
#再計画 先行制約
#======================================================================= 
for i in idata3b:
  if data[i][1] in ACT_gisou+ACT_kumitate:
    for iw in[0,1,2,3,4]:  
      if data[i][4][iw] in idata3:
        usuki3.addTemporal(act3[i],act3[data[i][4][iw]],\
        tempType=CS[data[i][5][iw][0]], delay= int(data[i][5][iw][1]*2))  
        if data[i][1] in ["A02010","A02610","A03010","A03210","A04310",\
                                     "A09210"] and data[i][5][iw][0]==0:
          usuki3.addTemporal(act3[data[i][4][iw]],act3[i],\
                        tempType=CS[3], delay=-int(data[i][5][iw][1]*2))        
#-----
for i in  idata3b:
  if data[i][1] in PL_gisou+PL_kumitate:
    for iw in [0]:
      if data[i][4][iw] in idata3b:
        ii=data[i][4][iw]      
        usuki3.addTemporal(act3[i],act3[ii],tempType="CS")
        usuki3.addTemporal(act3[ii],act3[i],tempType="SC")       
        for jj in idata3b:   
          for iw in [0]:
            if data[i][4][iw] in idata3b:            
              if data[jj][4][iw]==i:              
                usuki3.addTemporal(act3[jj],act3[i],tempType="CS")
                usuki3.addTemporal(act3[i],act3[jj],tempType="SC")               
#-----開始日の制約
for i in idata3a:   
  usuki3.addTemporal("source",act3[i],tempType="SS",delay= int(data[i][3]))
  usuki3.addTemporal(act3[i],"source",tempType="SS",delay=-int(data[i][3]))     
#-----     
for i in idata3b:
  usuki3.addTemporal("source",act3[i],tempType="SS",delay= rdate)    

プログラムIII-4

#プログラムIII-4.1
#=======================================================================
#仕掛作業 資源制約(配員、場所) 
#=======================================================================
mode3={}
for i in idata3a:  
  if data[i][1] in ACT_gisou:
    mode3[i]=mode1[i] 
    mode3[i].name='mode3['+i+']'
    act3[i].addModes(mode3[i]) 
#-----
  if data[i][1] in [11,1,2,3,4,5,6,12,13,14,15,36,37,38]: #ACT_kumitate.remove(16):  
    mode3[i]=mode2[i] 
    mode3[i].name='mode3['+i+']'    
    act3[i].addModes(mode3[i])
#-----
  if data[i][1] in PL_gisou: 
    mode3[i]=mode1[i] 
    s=mode1[i].name
    mode3[i].name=s[:4]+"3"+s[6:]       
    act3[i].addModes(mode3[i])    
#-----  
  if data[i][1] in PL_kumitate: 
    mode3[i]=mode2[i] 
    s=mode2[i].name
    mode3[i].name=s[:4]+"3"+s[6:]      
    act3[i].addModes(mode3[i])         
#プログラムIII-4.2  
#=======================================================================
#再計画 資源制約(配員)  
#=======================================================================    
for i in idata3b:
  if data[i][1] in ACT_gisou+ACT_kumitate:
#-----
    #1F #2W #3C #4CC #20ブラスト #31鉄艤 #32甲配 #33機配 #34PA #39_甲配 #40_機配   
    if data[i][1] in [1,2,3,4,20,31,32,33,34,39,40]:
      n=math.ceil(data[i][9][0][0]/5)  #1人で何日かかるか
      if data[i][1] in [1,3]:       #取付
        mode3[i]=Mode("mode3["+i+"]",duration=n) 
        mode3[i].addBreak(0,0)
        mode3[i].addResource(resWH,{(0,n):5})
        mode3[i].addParallel(1,n,28)   
      if data[i][1] in [2,4]:       #溶接
        mode3[i]=Mode("mode3["+i+"]",duration=n)    
        mode3[i].addBreak(0,0)
        mode3[i].addResource(resWW,{(0,n):5})
        mode3[i].addParallel(1,n,43)             
      if data[i][1] in [31]:        #鉄艤装
        mode3[i]=Mode("mode3["+i+"]",duration=n)     
        mode3[i].addBreak(0,0)
        mode3[i].addResource(resWF1,{(0,n):5})
        mode3[i].addParallel(1,n,5)          
      if data[i][1] in [32,39]:     #甲板配管
        mode3[i]=Mode("mode3["+i+"]",duration=n)      
        mode3[i].addBreak(0,0)    
        mode3[i].addResource(resWF2,{(0,n):5})
        mode3[i].addParallel(1,n,7)    
      if data[i][1] in [33,40]:     #機関配管
        mode3[i]=Mode("mode3["+i+"]",duration=n)
        mode3[i].addBreak(0,0)    
        mode3[i].addResource(resWF3,{(0,n):5})
        mode3[i].addParallel(1,n,10)     
      if data[i][1]==20:            #塗装内
        mode3[i]=Mode("mode3["+i+"]",duration=n)      
        mode3[i].addBreak(0,0)    
        mode3[i].addResource(resWP, {(0,n):5})   
        mode3[i].addParallel(1,n,8)    
      if data[i][1]==34:            #塗装外
        mode3[i]=Mode("mode3["+i+"]",duration=n)   
        mode3[i].addBreak(0,0)    
        mode3[i].addResource(resWP2,{(0,n):5}) 
        mode3[i].addParallel(1,n,8)    
      act3[i].addModes(mode3[i])
#-----
    #10:入荷 #7:社0 #8:検0 #9:W0 #16:運 #17:運0 #18:運2 #19:合体 #21:運ブ #25:運ブ2	 #35:AT #0:搭載 
    elif data[i][1] in [10,7,8,9,16,17,18,19,21,25,35,0]: 
      mode3[i]=Mode("mode3["+i+"]",duration=data[i][2])   
      act3[i].addModes(mode3[i])
#-----
    #11:開始 #5:社 #6:検 #12:正 #13:反 #14:積み #15:一体 #36:磨き #37:O/P #38:_鉄艤 #16:運 
    elif data[i][1] in [11,5,6,12,13,14,15,36,37,38,16]:      
      mode3[i]=Mode("mode3["+i+"]",duration=data[i][2])  
      act3[i].addModes(mode3[i])       
#プログラムIII-4.3     
#=======================================================================
#再計画 資源制約(作業場所)
#=======================================================================    
for i in idata3b:      
  if data[i][1] in PL_gisou+PL_kumitate:       
#-----
   if data[i][1] in [22,23,24,70,71,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87]: #PL_gisou.remove(72): #72:D5_AH	 
      if data[i][1] in [22,23,24]: data[i][6]=AB
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode3[i]=Mode("mode3["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode3[i].addBreak(0,0)
                mode3[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act3[i].addModes(mode3[i])            
#-----
    elif data[i][1] in [51,53,54,55,56,57,58,59,60,61,62,63,64]: #PL_kumitate.remove(65): #65:K4_1AS1
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode3[i]=Mode("mode3["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode3[i].addBreak(0,0)
                mode3[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act3[i].addModes(mode1[i])     
#-----
    elif i in {"A01431","A11701","A11711","A11721"}:  #場所と期間が固定されている場合
      if data[i][6]!=0:
        for no in range(len(data[i][6])):
          no1=data[i][6][no][0];
          L=R[no1][1]; B=R[no1][2];
          L1=data[i][6][no][1]; L2=data[i][6][no][2];
          B1=data[i][6][no][3]; B2=data[i][6][no][4];      
          skipL=math.floor(L/4); skipL=2; 
          skipB=math.floor(B/2); # skipB=1;        
          l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);
          for j in range(L1,L2-l+1,skipL):
            for k in range(B1,B2-b+1,skipB):         
              mode3[i]=Mode("mode3["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b),duration=int(data[i][2]))
              for s in range(0,l):
                for t in range(0,b):
                  mode3[i].addResource(resPL[no1,j+s,k+t],1)        
              act3[i].addModes(mode1[i,no1,j,k])                        

プログラムIII-5

#プログラムIII-5
#=======================================================================
#再計画 問題の規模
#======================================================================= 
N=len(usuki3.act)
print("アクティビティ総数(含待機数):",N)  
M=[]
for a in usuki3.act: M.append(len(a.modes)) 
print("モード数:",M)  
print("平均モード数:",round(sum(M)/N))
P=math.ceil(math.log10(round(sum(M)/N)**N))
print("問題の規模: 10**",P)                       
#=======================================================================
#組立工程計画 問題求解
#=======================================================================
#usuki3.Params.Makespan=True
usuki3.Params.Initial=False
usuki3.Params.TimeLimit=600
usuki3.Params.Neighborhood=20
usuki3.Params.OutputFlag=False
usuki3.optimize()       

プログラムIII-6

#プログラムIII-6
#=======================================================================
#データセットの更新
#=======================================================================
print("")  
for a in usuki3.act:
  for i in idata3b: 
    if a.name==data[i][0]:
      if len(a.modes)==1: nam=a.selected.name
      else: nam=a.selected
      #print("_"+a.name,len(a.modes),nam,a.start,a.completion)
      data[i][3]=a.start
      data[i][2]=a.completion-a.start
      if len(nam)>15:
        r=int(nam[16:19]) 
        x=int(nam[21:24]) 
        y=int(nam[25:28]) 
        l=int(nam[30:33]) 
        b=int(nam[34:37])       
        place=[[ r, x, x+l, y, y+b]]
        data[i][6]=place
        print(data[i][0:8])  
#========================================================================
filename="usu_S1777_resche_R040510c.csv"
print("writing "+filename) 
usuki3.writeExcel(filename)    
import dill
dill.dump_session('usukiR040510c.pkl')  
#------
#eof

組立計画

組立計画

これを得るプログラムを、本資料では次のように分割して示しています。

 プログラムII ************************ 組立工程計画 ************************
・プログラムII-1 リソース(場所・メッシュ)の定義
・プログラムII-2 リソース(作業員)の定義
・プログラムII-3 組立工程計画アクティビティの定義(一部艤装工程追加)
         先行制約の設定
・プログラムII-4 モードの設定
         組立工程計画 資源制約(配員)
         組立工程計画 資源制約(作業場所)
・プログラムII-5 RCPSP求解
・プログラムII-6 データセットの更新

#プログラムII-1.0
#========================================================================
print("")
print(' ************************ 組立工程計画 *************************')
print("")
#========================================================================
# import dill
# dill.load_session('usukiR040510a.pkl')  
#=====
usuki2=Model()

プログラムII-1

#プログラムII-1.1
#=======================================================================
#リソースの定義(場所) 
#=======================================================================
#-----メッシュの使用可否
for id in R:
  if not id in [4,5,6,13]:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):        
        resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                       format(i,j), capacity=resPL[id,i,j].residual)  
  if id==4:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,11) and j in range(0,12):
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity=resPL[id,i,j].residual)  
  if id==5:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,7) and j in range(0,10):
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity=resPL[id,i,j].residual)  
  if id==6:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [0,22,23,24,25,26,27,28,29,30,31,32,33,34,35] and \
                                                 j in range(0,13):
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity={(0,"inf"):0})
        elif i in range(1,17) and j in range(0,1):
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity={(0,"inf"):0})            
        else:     
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity=resPL[id,i,j].residual)  
  if id==13:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [31,32,33,34,35,36,37,63,64,65,66,67,68,69,70,71] and \
                                                     j in range(0,24):
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity={(0,"inf"):0})         
        else:     
          resPL[id,i,j] =usuki2.addResource(R[id][0]+"[{0:02d}_{1:02d}]".\
                         format(i,j), capacity=resPL[id,i,j].residual)  

プログラムII-2

#プログラムII-2                 
#=======================================================================
#リソースの定義(作業員)
#=======================================================================
resWH =usuki2.addResource("R[WH]",  capacity=resWH.residual)
resWW =usuki2.addResource("R[WW]",  capacity=resWW.residua)
resWF1=usuki2.addResource("R[WF1]", capacity=resWF1.residual)
resWF2=usuki2.addResource("R[WF2]", capacity=resWF2.residual)
resWF3=usuki2.addResource("R[WF3]", capacity=resWF3.residual)
resWP =usuki2.addResource("R[WP]",  capacity=resWP.residual)
resWP2=usuki2.addResource("R[WP2]", capacity=resWP2.residual)

プログラムII-3

#プログラムII-3
#=======================================================================
#組立工程計画アクティビティ idata2
#=======================================================================
w=[]                             
for i in data:
 if data[i][1] in ACT_kumitate+PL_kumitate and data[i][11] in BLK_all and data[i][12] in [0]:
   w.append(i)
idata2=w&data.keys()    
if 3 in BLK_all:
  idata2.add("A09320") #組立中ブラスト(運ブ)
  idata2.add("A09321") #組立中ブラスト(ブラスト棟)
  idata2.add("A09322") #組立中ブラスト(ブラスト作業)
  idata2.add("A09330") #組立中ブラスト(運ブ2)
if 7 in BLK_all:
  idata2=idata2-{
  'A11700','A11701','A11702','A11703','A11704','A11705','A11706',\
  'A11710','A11711','A11712','A11713','A11714','A11715','A11716',\
  'A11720','A11721','A11722','A11723','A11724','A11725','A11726','A11727','A11728','A11729'} #総組は場所だけ残して作業は除く
print(idata2)

プログラムII-4.1

#プログラムII-4.1a
#=======================================================================
#組立工程計画 作業の定義
#=======================================================================
act2={}
for i in idata2:    
  j=i  
  while data[j][1]!=16:
    j=data[j][4][0]
  act2[i]=usuki2.addActivity(data[i][0], duedate=data[j][3]+data[j][2], backward=True)      
#プログラムII-4.1b  
#=======================================================================
#組立工程計画 先行制約
#=======================================================================
for i in idata2:
  if data[i][1] in ACT_kumitate:
    for iw in[0,1,2,3,4]:
      if data[i][4][iw] in idata2:
        usuki2.addTemporal(act2[i],act2[data[i][4][iw]],tempType=CS[data[i][5][iw][0]], delay= int(data[i][5][iw][1]*2))  
        if data[i][1] in ["A02010","A02610","A03010","A03210","A04310","A09210",] and data[i][5][iw][0]==0: #外板
          usuki2.addTemporal(act2[data[i][4][iw]],act2[i],tempType=CS[3], delay=-int(data[i][5][iw][1]*2))   
#-----
for i in idata2:
  if data[i][1] in PL_kumitate:
    for iw in[0]:
      if data[i][4][iw] in idata2:
        ii=data[i][4][iw]      
        usuki2.addTemporal(act2[i],act2[ii],tempType="CS")
        usuki2.addTemporal(act2[ii],act2[i],tempType="SC")       
        for jj in idata2:   
          for iw in[0]:
            if data[i][4][iw] in idata2:            
              if data[jj][4][iw]==i:              
                usuki2.addTemporal(act2[jj],act2[i],tempType="CS")
                usuki2.addTemporal(act2[i],act2[jj],tempType="SC")   
#-----開始日の制約
for i in idata2:
  if data[i][1] in [11]:
    usuki2.addTemporal("source",act2[i],tempType="SS",delay= 80)    
#-----運搬日の制約
for i in idata2:
  if data[i][1] in [16]:
    usuki2.addTemporal("source",act2[i],tempType="SS",delay= int(data[i][3]-10))      

プログラムII-4.2

#プログラムII-4.2a  
#=======================================================================
#組立工程計画  資源制約(配員)  
#=======================================================================
mode2={}
for i in idata2:
  if data[i][1] in ACT_kumitate+ACT_gisou:
#-----
    #1F #2W #3C #4CC #20ブラスト #31鉄艤 #32甲配 #33機配 #34PA #39_甲配 #40_機配   
    if data[i][1] in [1,2,3,4,20,31,32,33,34,39,40]:
      n=math.ceil(data[i][9][0][0]/5)  #1人で何日かかるか
      if data[i][1] in [1,3]:       #取付
        mode2[i]=Mode("mode2["+i+"]",duration=n) 
        mode2[i].addBreak(0,0)
        mode2[i].addResource(resWH,{(0,n):5})
        mode2[i].addParallel(1,n,28)   
      if data[i][1] in [2,4]:       #溶接
        mode2[i]=Mode("mode2["+i+"]",duration=n)    
        mode2[i].addBreak(0,0)
        mode2[i].addResource(resWW,{(0,n):5})
        mode2[i].addParallel(1,n,43)             
      if data[i][1] in [31]:        #鉄組立
        mode2[i]=Mode("mode0["+i+"]",duration=n)     
        mode2[i].addBreak(0,0)
        mode2[i].addResource(resWF1,{(0,n):5})
        mode2[i].addParallel(1,n,5)          
      if data[i][1] in [32,39]:     #甲板配管
        mode2[i]=Mode("mode0["+i+"]",duration=n)      
        mode2[i].addBreak(0,0)    
        mode2[i].addResource(resWF2,{(0,n):5})
        mode2[i].addParallel(1,n,7)    
      if data[i][1] in [33,40]:     #機関配管
        mode2[i]=Mode("mode0["+i+"]",duration=n)
        mode2[i].addBreak(0,0)    
        mode2[i].addResource(resWF3,{(0,n):5})
        mode2[i].addParallel(1,n,10)     
      if data[i][1]==20:            #塗装内
        mode2[i]=Mode("mode0["+i+"]",duration=n)      
        mode2[i].addBreak(0,0)    
        mode2[i].addResource(resWP, {(0,n):5})   
        mode2[i].addParallel(1,n,8)    
      if data[i][1]==34:            #塗装外
        mode2[i]=Mode("mode0["+i+"]",duration=n)   
        mode2[i].addBreak(0,0)    
        mode2[i].addResource(resWP2,{(0,n):5}) 
        mode2[i].addParallel(1,n,8)    
      act2[i].addModes(mode2[i])
#-----
    #10:入荷 #7:社0 #8:検0 #9:W0 #16:運 #17:運0 #18:運2 #19:合体 #21:運ブ #25:運ブ2 #35:AT #0:搭載 
    elif data[i][1] in [10,7,8,9,16,17,18,19,21,25,35,0]: 
      mode2[i]=Mode("mode2["+i+"]",duration=data[i][2]) #組立工程運搬作業時数未定のため期間だけ確保 
      act2[i].addModes(mode2[i])
#-----
    #11:開始 #5:社 #6:検 #12:正 #13:反 #14:積み #15:一体 #36:磨き #37:O/P #38:_鉄艤 #16:運 
    elif data[i][1] in [11,5,6,12,13,14,15,36,37,38,16]:      
      mode2[i]=Mode("mode2["+i+"]",duration=data[i][2]) #組立工程運搬作業時数未定のため期間だけ確保   
      act2[i].addModes(mode2[i])                
#プログラムII-4.2b                                
#=======================================================================
#組立工程計画 資源制約(作業場所)      
#=======================================================================
for i in idata2:      
  if data[i][1] in PL_kumitate+PL_gisou:   
#-----    
    if data[i][1] in [22,23,24,70,71,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87]: #PL_gisou.remove(72): #72:D5_AH	 
      if data[i][1] in [22,23,24]: data[i][6]=AB
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode2[i]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode2[i].addBreak(0,0)
                mode2[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act2[i].addModes(mode2[i])            
#-----
    elif data[i][1] in [51,53,54,55,56,57,58,59,60,61,62,63,64]: #PL_kumitate.remove(65): #65:K4_1AS1
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode2[i,no1,j,k]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode2[i].addBreak(0,0)
                mode2[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act2[i].addModes(mode2[i])     
#-----
    elif i in {"A01431","A11701","A11711","A11721"}:  #場所と期間が固定されている場合
      if data[i][6]!=0:
        for no in range(len(data[i][6])):
          no1=data[i][6][no][0];
          L=R[no1][1]; B=R[no1][2];
          L1=data[i][6][no][1]; L2=data[i][6][no][2];
          B1=data[i][6][no][3]; B2=data[i][6][no][4];      
          skipL=math.floor(L/4); skipL=2; 
          skipB=math.floor(B/2); # skipB=1;        
          l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);
          for j in range(L1,L2-l+1,skipL):
            for k in range(B1,B2-b+1,skipB):         
              mode2[i]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b),duration=int(data[i][2]))
              for s in range(0,l):
                for t in range(0,b):
                  mode2[i].addResource(resPL[no1,j+s,k+t],1)        
              act2[i].addModes(mode2[i])                

プログラムII-5

#プログラムII-5
#=======================================================================
#組立工程計画 問題の規模
#=======================================================================
N=len(usuki2.act)
print("アクティビティ総数(含待機数):",N)  
M=[]
for a in usuki2.act: M.append(len(a.modes)) 
print("モード数:",M)  
print("平均モード数:",round(sum(M)/N))
P=math.ceil(math.log10(round(sum(M)/N)**N))
print("問題の規模: 10**",P)                       
#=======================================================================
#組立工程計画 問題求解
#=======================================================================
#usuki2.Params.Makespan=True
usuki2.Params.Initial=False
usuki2.Params.TimeLimit=3600
usuki2.Params.Neighborhood=20
usuki2.Params.OutputFlag=False
usuki2.optimize()      

●プログラムII-6

#プログラムII-6             
#=======================================================================
#データセットの更新
#=======================================================================
print("")  
for a in usuki2.act:
  for i in idata2: 
    if a.name==data[i][0]:
      if len(a.modes)==1: nam=a.selected.name
      else: nam=a.selected
     #print("_"+a.name,len(a.modes),nam,a.start,a.completion)
      data[i][3]=a.start
      data[i][2]=a.completion-a.start
      if len(nam)>15:
        r=int(nam[16:19]) 
        x=int(nam[21:24]) 
        y=int(nam[25:28]) 
        l=int(nam[30:33]) 
        b=int(nam[34:37])       
        place=[[ r, x, x+l, y, y+b]]
        data[i][6]=place
        print(data[i][0:8])  
#========================================================================
filename="usu_S1777_kumitate_R040510b.csv"
print("writing "+filename) 
usuki2.writeExcel(filename)  
import dill
dill.dump_session('usukiR040510b.pkl')  
#------
#eof

艤装計画

艤装計画

プログラム:Part I-4

●プログラムI-4.1

#プログラムI-4.1
#=======================================================================
#艤装工程計画  資源制約(配員)  
#=======================================================================
mode1={}
for i in idata1:  
  if data[i][1] in ACT_gisou:
#-----
    #1F #2W #3C #4CC #20ブラスト #31鉄艤 #32甲配 #33機配 #34PA #39_甲配 #40_機配   
    if data[i][1] in [1,2,3,4,20,31,32,33,34,39,40]:
      n=math.ceil(data[i][9][0][0]/5)  #1人で何日かかるか
      if data[i][1] in [1,3]:       #取付
        mode1[i]=Mode("mode0["+i+"]",duration=n) 
        mode1[i].addBreak(0,0)
        mode1[i].addResource(resWH,{(0,n):5})
        mode1[i].addParallel(1,n,28)   
      if data[i][1] in [2,4]:       #溶接
        mode1[i]=Mode("mode0["+i+"]",duration=n)    
        mode1[i].addBreak(0,0)
        mode1[i].addResource(resWW,{(0,n):5})
        mode1[i].addParallel(1,n,43)             
      if data[i][1] in [31]:        #鉄艤装
        mode1[i]=Mode("mode2["+i+"]",duration=n)     
        mode1[i].addBreak(0,0)
        mode1[i].addResource(resWF1,{(0,n):5})
        mode1[i].addParallel(1,n,5)          
      if data[i][1] in [32,39]:     #甲板配管
        mode1[i]=Mode("mode2["+i+"]",duration=n)      
        mode1[i].addBreak(0,0)    
        mode1[i].addResource(resWF2,{(0,n):5})
        mode1[i].addParallel(1,n,7)    
      if data[i][1] in [33,40]:     #機関配管
        mode1[i]=Mode("mode2["+i+"]",duration=n)
        mode1[i].addBreak(0,0)    
        mode1[i].addResource(resWF3,{(0,n):5})
        mode1[i].addParallel(1,n,10)     
      if data[i][1]==20:            #塗装内
        mode1[i]=Mode("mode2["+i+"]",duration=n)      
        mode1[i].addBreak(0,0)    
        mode1[i].addResource(resWP, {(0,n):5})   
        mode1[i].addParallel(1,n,8)    
      if data[i][1]==34:            #塗装外
        mode1[i]=Mode("mode2["+i+"]",duration=n)   
        mode1[i].addBreak(0,0)    
        mode1[i].addResource(resWP2,{(0,n):5}) 
        mode1[i].addParallel(1,n,8)    
      act1[i].addModes(mode1[i])
#-----
    #10:入荷 #7:社0 #8:検0 #9:W0 #16:運 #17:運0 #18:運2 #19:合体 #21:運ブ #25:運ブ2 #35:AT #0:搭載 
    elif data[i][1] in [10,7,8,9,16,17,18,19,21,25,35,0]: 
      mode1[i]=Mode("mode2["+i+"]",duration=data[i][2]) #艤装工程運搬作業時数未定のため期間だけ確保 
      act1[i].addModes(mode1[i])
#-----
    #11:開始 #5:社 #6:検 #12:正 #13:反 #14:積み #15:一体 #36:磨き #37:O/P #38:_鉄艤 #16:運 
    elif data[i][1] in [11,5,6,12,13,14,15,36,37,38,16]:      
      mode1[i]=Mode("mode0["+i+"]",duration=data[i][2]) #組立工程運搬作業時数未定のため期間だけ確保   
      act1[i].addModes(mode1[i])       

●プログラムI-4.2

#プログラムI-4.2
#=======================================================================
#艤装工程計画 資源制約(作業場所)      
#=======================================================================
for i in idata1:      
  if data[i][1] in PL_gisou:      
#----- 
    if data[i][1] in [22,23,24,70,71,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87]: #PL_gisou.remove(72): #72:D5_AH	 
      if data[i][1] in [22,23,24]: data[i][6]=AB
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode1[i]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode1[i].addBreak(0,0)
                mode1[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act1[i].addModes(mode1[i])            
#-----
    elif data[i][1] in [51,53,54,55,56,57,58,59,60,61,62,63,64]: #PL_kumitate.remove(65): #65:K4_1AS1
      for no in range(len(data[i][6])):
        no1=data[i][6][no][0];
        L=R[no1][1]; B=R[no1][2];
        L1=data[i][6][no][1]; L2=data[i][6][no][2];
        B1=data[i][6][no][3]; B2=data[i][6][no][4];       
        skipL=math.floor(L/8); skipL=1
        skipB=math.floor(B/2); 
        l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);  
        if data[i][1] in [22,23,24]:  l=19; b=16;
        for j in range(L1,L2-l+1,skipL): 
          for k in range(B1,B2-b+1,skipB):
            mode1[i]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b))
            for s in range(0,l):
              for t in range(0,b):
                mode1[i].addBreak(0,0)
                mode1[i].addResource(resPL[no1,j+s,k+t],1,"break")
            act1[i].addModes(mode1[i])     
#-----
    elif i in {"A01431","A11701","A11711","A11721"}:  #場所と期間が固定されている場合(1AS1,D5_AH)
      if data[i][6]!=0:
        for no in range(len(data[i][6])):
          no1=data[i][6][no][0];
          L=R[no1][1]; B=R[no1][2];
          L1=data[i][6][no][1]; L2=data[i][6][no][2];
          B1=data[i][6][no][3]; B2=data[i][6][no][4];      
          skipL=math.floor(L/4); skipL=2; 
          skipB=math.floor(B/2); # skipB=1;        
          l=math.floor(data[i][8][0]); b=math.floor(data[i][8][1]);
          for j in range(L1,L2-l+1,skipL):
            for k in range(B1,B2-b+1,skipB):         
              mode1[i]=Mode("mode2["+i+"]_R[{0:03d}][{1:03d}_{2:03d}][{3:03d}_{4:03d}]".format(no1,j,k,l,b),duration=int(data[i][2]))
              for s in range(0,l):
                for t in range(0,b):
                  mode1[i].addResource(resPL[no1,j+s,k+t],1)        
              act1[i].addModes(mode1[i])       

●プログラムI-5

#プログラムI-5  
#=======================================================================
#艤装工程計画 問題の規模
#=======================================================================
N=len(usuki1.act)
print("アクティビティ総数(含待機数):",N)  
M=[]
for a in usuki1.act: M.append(len(a.modes))
print("モード数:",M)  
print("平均モード数:",round(sum(M)/N))
P=math.ceil(math.log10(round(sum(M)/N)**N))
print("問題の規模: 10**",P)                       
#=======================================================================
#艤装工程計画 問題求解
#=======================================================================
usuki1.Params.Makespan=True
usuki1.Params.Initial=False
usuki1.Params.TimeLimit=3600
usuki1.Params.Neighborhood=20
# usuki1.Params.RandomSeed=10
usuki1.Params.OutputFlag=False
usuki1.optimize()

●プログラムI-6

#プログラムI-6             
#=======================================================================
#データセットの更新
#=======================================================================
print("")  
for a in usuki1.act:
  for i in idata1: 
    if a.name==data[i][0]:
      if len(a.modes)==1: nam=a.selected.name
      else: nam=a.selected
     #print("_"+a.name,len(a.modes),nam,a.start,a.completion)
      data[i][3]=a.start
      data[i][2]=a.completion-a.start
      if len(nam)>15:
        r=int(nam[16:19]) 
        x=int(nam[21:24]) 
        y=int(nam[25:28]) 
        l=int(nam[30:33]) 
        b=int(nam[34:37])       
        place=[[ r, x, x+l, y, y+b]]
        data[i][6]=place
        print(data[i][0:8])  
#========================================================================
filename="usu_S1777_gisou_R040510a.csv"
print("writing "+filename)  
usuki1.writeExcel(filename)   
# import dill
# dill.dump_session('usukiR040510a.pkl')  
# sys.exit()     
#-----
#eof

工程計画

現行計画

現行計画(総合日程表)における各ブロックのブロック搭載日、ブラスト開始日、組立開始日また外注の場合の入荷日をグラフにしたものを次に示します。

「工程’s」にはリソースの山積機能がありますので、これを利用して作業時数と場所の専有面積を山積した結果を次に示します。

時数山積み

面積山積み

実際の配員計画と定盤計画では様々なやりくり(残業・休日出勤、段積み・先行搭載など)がなされていて、実際の造船工程が回っていると言えます。

RCPSP計画
当該造船所の工程計画問題をRCPSPとして定式化した場合、大規模な組合せ最適化問題となり、ソルバーOptSeqを用いても、問題全体を一括して解くことは困難です。そのため、造船工程をブロック組立工程と艤装・待機工程に分割して、適切につなぎ合わせる工夫が必要となります。一般にブロック搭載工程は固定してよいので、下流の艤装・待機工程はプル型すなわち搭載日程に後詰めします。これに、上流の組立工程をジャストインすることになりますが、その際前詰め(方針I)するか後詰め(方針II)するかの2通りが考えられます。各ブロック組立の開始順番などは経験的に確立されているとしてよいので、総合日程表におけるブロック開始日を固定してこれに前詰めするのが方針Iです。ただ、これはジャストインの達成は難しいので、接続を行う特別の場所の確保が必要となります。これらの方針を次図に示します。

一方、組立工程を艤装・待機工程にジャストインする方針を次図に示します。

どちらともリソース(作業員と作業場所)が分離されていることが前提となりますが、実際には一部例外的な処理が必要です。

また共通した重要な課題として、日程計画・配員計画・定盤計画(場所の割付)をどう連動させるかがあります。本研究では、OptSeqのもつ小作業並列化機能を用いて作業時数と配員制約から作業期間を決めます。同時にその未知の期間に場所の割付ができるかを、OptSeqのもつ仮想アクティビティの手法を用いてチェックします。すなわち、OptSeqと用いて日程計画・配員計画・定盤計画の3つを連動させることを試みます。

●種々検討の結果、上の現行計画に対応して、方針IIに基づいて次図を得ることができました。

艤装工程計画を得るプログラムを、本資料では次のように分割して示しています。

 プログラム I ************************ 艤装工程計画 ************************
・プログラム I-1 リソース(場所・メッシュ、作業員)の定義
・プログラム I-2 データセットの定義
・プログラム I-3 艤装工程計画アクティビティの定義(一部組立工程追加)
         先行制約の設定
・プログラム I-4 モードの設定
         艤装工程計画 資源制約(配員)
         艤装工程計画 資源制約(作業場所) 
・プログラム I-5 RCPSP求解
・プログラム I-6 データセットの更新

プログラム:Part I-3

#プログラムI-3.0
#=======================================================================
#識別番号 
#=======================================================================
#作業項目・作業場所の識別番号 data[i][1]
#----- 
#11:開始 #1:F #2:W #3:C #4:CC #5:社 #6:検 #12:正 #13:反 #14:積み #15:一体 #36:磨き #37:O/P #38:_鉄艤 #16:運 
ACT_kumitate=[11,1,2,3,4,5,6,12,13,14,15,36,37,38,16]
#----- 
#10:入荷 #7:社0 #8:検0 #9:W0 #16:運 #17:運0 #18:運2 #19:合体 #20:ブラスト #21:運ブ #25:運ブ2	
#31:鉄艤 #32:甲配 #33:機配 #39:_甲配 #40:_機配 #34:PA #35:AT #0:搭載 
ACT_gisou=[10,7,8,9,16,17,18,19,20,21,25,31,32,33,39,40,34,35,0] 
#----- 
#51:K1K2 #53:K3	 #54:K4 #55:K5U	 #55:K5R #56:K6	 
#57:K1_1FS1 #58:K1_1S6P #59:K1_1S6S #60:K2_8S6P #61:K2_8S6S #62:K4S4 #63:県岸 #64:K1K2_K5U #65:K4_1AS1
PL_kumitate=[51,53,54,55,56,57,58,59,60,61,62,63,64,65]		
#----- 
#22:AB #23:BB #24:CB #70:RD #71:RD2 #72:D5_AH		
#73:D7_3AS1 #74:D7_3AS12 #75:D7_1AS1P #76:D7_1AS1P2 #77:D7_1AS1S #78:D7_1AS1S2 #79:D7_1AS5	
#80:D7_1AS5P2 #81:D7_1AS5S #82:D7_1AS5S2 #83:D7_2S6P #84:D7_2S6S #85:D7_AH1P #86:D7_AH1S #87:D7_AH
PL_gisou=[22,23,24,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87]
#----- 
#99:その他
ACT_misc=[99]
#----- 
#ブロックカテゴリの識別番号 data[i][11] 
#1:S1 #2:AS #3:FS #4:S6 #5:L1 #6:D1 #7:AH 
BLK_all=[1,2,3,4,5,6,7]
#----- 
#外注の識別番号 data[i][12] 
#1:外注 #2:内製
ORD_all=[1,0]

●プログラムI-3.1

#プログラムI-3.1a
#=======================================================================
#艤装工程計画アクティビティのidata1
#=======================================================================
w=[]                             
for i in data:
  if (data[i][1] in ACT_gisou+PL_gisou) and (data[i][11] in BLK_all) and (data[i][12] in ORD_all):
    w.append(i)
idata1=w&data.keys()
#-----
if 7 in BLK_all:
  idata1=idata1-{\
  'A11700','A11701','A11702','A11703','A11704','A11705','A11706',\
  'A11710','A11711','A11712','A11713','A11714','A11715','A11716',\
  'A11720','A11721','A11722','A11723','A11724','A11725','A11726','A11727','A11728','A11729'} #総組は場所さけ残して作業は除く
print(idata1)
#====
act1={}
for i in idata1:   
    j=i  
    while not (data[j][1] in [0]):
      j=data[j][4][0]
    act1[i]=usuki1.addActivity(data[i][0], duedate=data[j][3]+data[j][2], backward=True)           
●プログラムI-3.1b
#=======================================================================
#艤装工程計画 先行制約
#=======================================================================
for i in  idata1:
  if data[i][1] in ACT_gisou:
    for iw in[0,1,2,3,4]:
      if data[i][4][iw] in idata1:
        usuki1.addTemporal(act1[i],act1[data[i][4][iw]],tempType=CS[data[i][5][iw][0]], delay= int(data[i][5][iw][1]*2))  
        if data[i][1] in ["A02010","A02610","A03010","A03210","A04310","A09210",] and data[i][5][iw][0]==0: #外板
          usuki1.addTemporal(act1[data[i][4][iw]],act1[i],tempType=CS[3], delay=-int(data[i][5][iw][1]*2))   
#-----
for i in  idata1:
  if data[i][1] in PL_gisou:
    for iw in [0]:
      if data[i][4][iw] in idata1:
        ii=data[i][4][iw]      
        usuki1.addTemporal(act1[i],act1[ii],tempType="CS")
        usuki1.addTemporal(act1[ii],act1[i],tempType="SC")       
        for jj in idata1:   
          for iw in [0]:
            if data[i][4][iw] in idata1:            
              if data[jj][4][iw]==i:              
                usuki1.addTemporal(act1[jj],act1[i],tempType="CS")
                usuki1.addTemporal(act1[i],act1[jj],tempType="SC")              
#-----搭載日の固定
for i in idata1:
  if data[i][1] in [0,11]:
    usuki1.addTemporal("source",act1[i],tempType="SS",delay= int(data[i][3]))
    if data[i][1]==0:
      usuki1.addTemporal(act1[i],"source",tempType="SS",delay=-int(data[i][3]))     

データセット

S1777ブロック一覧

番船S1777では次の119個のブロックを扱います。

# 外注 ブロック名 L[m] B[m] H[m] S[m2] W[t]
1 3AS1 8 7 3.7 56 14.8
2 5S1S 14 13 1.9 182 75.8
3 5S1P 11 13 1.9 143 53.7
4 6S1S 14 13 1.9 182 75.8
5 6S1P 11 13 1.9 143 54.0
6 4S1S 14 12 1.9 168 73.4
7 4S1P 11 12 1.9 132 52.1
8 3S1S 14 13 1.9 182 77.2
9 3S1P 11 13 1.9 143 55.5
10 7S1S 14 13 1.9 182 76.1
11 7S1P 12 13 1.9 156 54.5
12 8S1S 13 12 1.9 156 56.5
13 8S1P 11 12 1.9 132 37.0
14 1AS1P 9 8 4.1 72 37.5
15 1AS1S 10 8 4.1 80 41.7
16 2S1S 13 13 1.9 169 73.5
17 2S1P 11 13 1.9 143 51.5
18 1S1S 14 12 1.9 168 66.8
19 1S1P 14 9 1.9 126 41.1
20 2AS1_SH 13 6 0.5 78 5.8
21 2AS1 13 12 4.0 156 69.3
22 1FS1 15 12 2.7 180 35.8
23 1FS3 14 7 4.9 98 51.4
24 1AS4P 12 11 3.1 132 35.5
25 1AS4S 12 11 3.1 132 36.9
26 2FS3_SH 10 10 0.5 100 6.0
27 2FS3 8 10 4.9 80 25.6
28 1L1 13 12 3.2 156 39.5
29 9L1 13 11 3.2 143 36.7
30 1FS5_SH 10 10 0.5 100 7.0
31 1FS5 13 9 5.1 117 57.2
32 2AS4_SH 10 10 1.0 100 9.0
33 2AS4 17 9 3.0 153 24.1
34 2L1 13 13 3.2 169 40.7
35 T157P 12 6 0.9 72 12.6
36 T157S 12 6 0.9 72 12.6
37 T45P 12 5 0.9 60 10.2
38 T45S 12 5 0.9 60 10.2
39 8L1 13 13 3.2 169 40.8
40 3L1 13 13 3.0 169 29.5
41 T141P 12 6 0.9 72 12.9
42 T141S 12 6 0.9 72 12.9
43 2FS5_SH 6 5 0.5 30 3.5
44 2FS5 7 8 5.1 56 12.8
45 7L1 13 12 3.2 156 39.4
46 4L1 13 11 3.2 143 35.8
47 T61P 12 7 0.9 84 13.5
48 T61S 12 7 0.9 84 13.5
49 T121P 12 7 0.9 84 13.5
50 T121S 13 7 0.9 91 13.5
51 T81P 12 7 0.9 84 13.5
52 T81S 12 7 0.9 84 13.5
53 1FS6 17 10 2.8 170 39.6
54 1AS5P 12 11 3.5 132 40.2
55 1AS5S 12 11 3.5 132 42.0
56 5L1 13 9 3.2 117 31.6
57 T105P 13 7 0.9 91 13.5
58 T105S 13 7 0.9 91 13.5
59 2AS5P 11 10 3.7 110 20.5
60 2AS5S 11 10 3.7 110 21.1
61 6L1 14 12 3.2 168 41.5
62 1S6P 10 13 8.6 130 52.4
63 1S6S 10 13 8.6 130 52.4
64 3AS5 17 10 4.2 170 59.9
65 T97P 12 7 0.9 84 13.1
66 T97S 12 7 0.9 84 13.1
67 1AS6P 12 11 4.4 132 40.9
68 1AS6S 12 11 4.4 132 42.7
69 2S4P 13 6 3.0 153 20.6
70 2S4S 13 6 78 20.6
71 8S6P 10 13 8.3 130 58.0
72 8S6S 10 13 8.3 130 58.0
73 2AS6P 12 10 3.5 120 21.3
74 2AS6S 12 10 3.5 120 24.3
75 2S6P 9 12 4.8 108 40.1
76 2S6S 9 12 4.9 108 40.1
77 3AS6 20 10 3.2 200 44.5
78 7S6P 14 12 4.7 168 67.0
79 7S6S 14 12 4.7 168 66.9
80 3S6P 14 13 4.0 182 68.6
81 3S6S 14 13 4.0 182 68.6
82 1AS7P 13 12 4.2 156 34.1
83 1AS7S 13 12 5.2 156 35.3
84 6S6P 14 12 3.8 168 66.9
85 6S6S 14 12 3.8 168 67.4
86 2AS7P 13 12 2.9 156 23.9
87 2AS7S 13 12 2.9 156 21.2
88 2D1AP 20 11 1.4 220 21.7
89 2D1AS 20 11 1.4 220 17.4
90 4S6S 14 12 3.8 168 64.2
91 4S6P 14 12 3.8 168 64.2
92 2FD1_SH 7 7 1.0 49 7.0
93 2FD1 10 12 6.3 120 12.0
94 2FS7 18 13 7.7 234 38.8
95 10D1AP 20 11 1.5 220 28.8
96 10D1AS 20 11 1.5 220 25.5
97 3AS7 21 8 2.9 168 28.5
98 5S6P 14 12 3.8 168 71.3
99 5S6S 14 12 3.8 168 79.9
100 1FS7 21 13 5.4 273 68.8
101 4D1AP 20 11 1.5 220 25.8
102 4D1AS 20 11 1.5 220 22.0
103 8D1AP 20 12 2.1 240 27.6
104 8D1AS 20 12 2.1 240 26.6
105 6D1AP 20 12 1.5 240 28.9
106 6D1AS 20 12 1.5 240 25.5
107 1AD1 6 5 0.4 30 3.6
108 1AD3 10 6 2.6 60 7.6
109 AH1P 12 18 2.8 216 28.1
110 AH1S 12 18 2.8 216 27.3
111 AH2P 7 3 2.2 21 2.7
112 AH2S 7 3 2.2 21 2.7
113 AH12 16 8 2.7 128 12.0
114 AH11 24 12 2.7 288 34.3
115 AH21 24 12 5.3 288 39.9
116 AH31 15 9 2.8 135 14.3
117 総組
118 DHP 6 3 2.9 18 4.6
119 DHS 7 4 2.8 28 6.4

総合日程表の「工程’s」による表現
●RCPSP計画に必要なデータセットの作成のために、まず総合日程表を「工程’s」で表します。そこでは資源マスターとして次表を定義しています。

資源ID 資源名称
WH 取付(280h)
WW 溶接(430h)
WF1 鉄艤(120h)
WF2 甲板配管(120h)
WF3 機関配管(120h)
WP 塗装(120h)
WP2 塗装2(80h)
WI 検査
WM その他
K1K2 K1K2(1274m2)
K3 K3(705m2)
K4S4 K4(1122m2)
K5 K5(951m2)
K6S2 K6(1475m2)
RD RD(4722m2)
KK 県岸
AB AB(304m2)
BB BB(304m2)
CB CB(304m2)
I 入荷
E 搭載
CL150 運搬
CL60 60Tクレーン
CA 台車
TB タグボート

データセット
●RCPSP計画に必要なデータセットは、総合日程表を「工程’s」で表したあと、「エクスポート」機能を用いてTSVファイルを得て、これを編集して生成します。

データセットは1847 個のレコードから構成され、1レコードの各フィールドを次に示します。

#id:[ “A00602”:[
0:番船_ブロック_id_サイズ_作業, “S1777_4S1S_A00602_14Lx12B_F”,
1:job, 1,
2:期間, 8,
3:開始, 83,
[4:後続#1,4:後続#2,4:後続#3,4:後続#4,4:後続#5], [“A00603″,”A00702″,”0″,”0″,”0”],
[[5:型#1,5:型#2],[5:型#1,5:型#2],[5:型#1,5:型#2],[5:型#1,5:型#2],[5:型#1,5:型#2]], [[0,0],[ 2,0],[ 0,0],[ 0,0],[ 0,0]],
6:組立場所, 0,
7:待機場所, 0,
[8:L,8:B,8:W], [ 14 , 12 , 73 ],
[[9:時数],[9:時数],[9:時数]], [[152 ],[0 ],[0 ]],
[[10:CL],[10:CA],[10:TB]], [[0 ],[0 ],[0 ]],
11:ID1, 1,
12:ID2, 0,
13:ID3 ,
],\ ],\

右列は、次の一例を対応させたものです。

“A00602”:[“S1777_4S1S_A00602_14Lx12B_F”,1,8,83 ,[“A00603″,”A00702″,”0″,”0″,”0”],[[0,0],[ 2,0],[ 0,0],[ 0,0],[ 0,0]], 0, 0,[ 14 , 12 , 73 ],[[152 ],[0 ],[0 ]],[[0 ],[0 ],[0 ]],1, 0, ],\

上記フィールドで作業番号jobは次表で定義されます。

組立作業 job# 艤装作業 job# 運搬作業 job#
F 1 鉄艤 31 入荷 10
W 2 甲配 32 開始 11
C 3 機配 33 12
CC 4 PA 34 13
5 AT 35 積み 14
6 磨き 36 一体 15
社0 7 O/P 37 16
検0 8 _鉄艤 38 運0 17
W0 9 _甲配 39 運2 18
_機配 40 合体 19
搭載 0
ブラスト作業 job#
ブラスト 20
運ブ 21
AB 22
BB 23
CB 24
運ブ2 25
組立場所 job# 待機場所 job# その他 job#
K1K2 51 RD 70 一体期間 99
K3 53 RD2 71 定盤 99
K4 54 D5_AH 72 開始2 99
K5U 55 D7_3AS1 73 資材 99
K5R 55 D7_3AS12 74 出棟 99
K6 56 D7_1AS1P 75 船装 99
K1_1FS1 57 D7_1AS1P2 76 塗装 99
K1_1S6P 58 D7_1AS1S 77 窓付 99
K1_1S6S 59 D7_1AS1S2 78 解体 99
K2_8S6P 60 D7_1AS5P 79 予備 99
K2_8S6S 61 D7_1AS5P2 80
K4S4 62 D7_1AS5S 81
県岸 63 D7_1AS5S2 82
K1K2_K5U 64 D7_2S6P 83
D7_2S6S 84
D7_AH1P 85
D7_AH1S 86
D7_AH2 87

●作業時数については「工数管理システム」においてログが取られています。これに基づいて標準作業時間が決められています。

プログラム:Part I-2

●プログラムI-2.1

#プログラムI-2.1a
#=====データセット
#id":["0:番船_ブロック_id_サイズ_作業",1:job,2:期間,3:開始,
#["4:後続#1"," 4:後続#2"," 4:後続#3"," 4:後続#4"],
#[[5:型#1,5:型#2],[ 5:型#1,5:型#2],[ 5:型#1,5:型#2],[ 5:型#1,5:型#2]], 
#6:組立場所, 7:待機場所,
#[ 8:L, 8:B, 8:W],[[9:取付],[9:溶接],[9:艤装]],[[10:CL],[10:CA],[10:TB]],
#11:ID1, 12:ID2, 13:due],\          
data={
"A00100":["S1777_3AS1_A00100_8Lx7B_入荷",10,1,188 ,\
["A00101","A00102","A00103","0","0"],[[0,0],[ 0,0],[ 0,0],[ 0,0],[ 0,0]], \
0, 0,\
[ 8 , 7 , 15 ],[[1 ],[0 ],[0 ]],[[0 ],[0 ],[0 ]],\
2, 1, ],\
"A00101":["S1777_3AS1_A00101_8Lx7B_D7_3AS1",73,18,189 ,\
["A00110","0","0","0","0"],[[0,0],[ 0,0],[ 0,0],[ 0,0],[ 0,0]],\
 D7_3AS1, 0,\
[ 8 , 7 , 15 ],[[56 ],[0 ],[0 ]],[[0 ],[0 ],[0 ]],\
2, 1, ],\
 :
}
#プログラムI-2.1b
#=====データ修正
data["A02201"][8][0]=14
data["A06950"][2]=1
data["A07050"][2]=1
data["A07540"][2]=1 
data["A08050"][2]=1
data["A08520"][2]=1 
data["A09030"][2]=1
data["A02610"][5][1][1]=data["A02610"][5][0][1]
data["A03010"][5][1][1]=data["A03010"][5][0][1]
data["A03210"][5][1][1]=data["A03210"][5][0][1]
data["A04310"][5][1][1]=data["A04310"][5][0][1]
data["A09210"][5][0][1]=-3.5
data["A09210"][5][1][1]=data["A09210"][5][0][1]
data["A09322"][4][0],data["A09322"][4][1]=\
data["A09322"][4][1],data["A09322"][4][0]
data0=data
#sys.exit() 

臼杵造船所

●研究対象とする造船所の全景と物流を次に示します。敷地の制約から、艤装と待機は台船上で行われます。したがって、上構部を除いて、総組は行われていません。

●組立場所のレイアウトを次に示します。

●艤装・待機場所のレイアウトを次に示します。

カレンダーとしては、いわゆる工場カレンダーのほかに、ブラスト専用のカレンダーが使われています。当研究では、工場カレンダーに基づいて計画単位を半日としています。

工場カレンダー ブラストカレンダー

●主に日程計画をまとめた総合日程表が作成されており、これを基にして定盤計画と配員計画が実施されています。

●また配員可能数については次を参考にしています。

プログラム:Part I-1

#プログラムI-1.0
from optseq import *
import math
#=====
print("")
print(' ************************ 艤装工程計画 *************************')
#=====
usuki1=Model()
CS=["CS","CC","SS","SC"]

●プログラムI-1.1

#プログラムI-1.1a
#=======================================================================
#リソースの定義(場所) 
#=======================================================================
#作業場所の名前と矩形サイズ [name,L=L2-L1+1,B=B2-B1+1]
R={
 1:["R[K1]",   42,  13  ],\
 2:["R[K2]",   56,  13  ],\
 3:["R[K3]",   47,  15  ],\
 4:["R[K4S4]", 33,  37+2],\
 5:["R[K5]",   45,  23+2],\
 6:["R[K6S2]", 61,  26],\
 7:["R[AB]",   19,  16  ],\
 8:["R[BB]",   19,  16  ],\
 9:["R[CB]",   19,  16  ],\
10:["R[WB]",   14,  13  ],\
11:["R[D35]",  33+2,18+2],\
12:["R[D5]",   54+2,16+2],\
13:["R[D7]",   72,  22+2],\
14:["R[RD1]",  40+2,14+2],\
15:["R[RD3]",  35+2,17+2],\
16:["R[RD4]",  40+2,15+2],\
17:["R[RD5]",  30+2,12+2],\
18:["R[RD6]",  30+2,12+2],\
19:["R[RD7]",  35+2,15+2],\
20:["R[RD8]",  40+2,15+2],\
}
#プログラムI-1.1b
#-----各場所の長さ方向線分[L1,L2]・幅方向線分[B1,B2]
K1=  [ 1,0, R[1][1],0, R[1][2]]
K2=  [ 2,0, R[2][1],0, R[2][2]]
K3=  [ 3,0, R[3][1],0, R[3][2]]
K4S4=[ 4,0, R[4][1],0, R[4][2]]
K5=  [ 5,0, R[5][1],0, R[5][2]]
K6S2=[ 6,0, R[6][1],0, R[6][2]]
AB = [ 7,0, R[7][1],0, R[7][2]]
BB = [ 8,0, R[8][1],0, R[8][2]]
CB = [ 9,0, R[9][1],0, R[9][2]]
WB = [10,0,R[10][1],0,R[10][2]]
D35= [11,0,R[11][1],0,R[11][2]]
D5=  [12,0,R[12][1],0,R[12][2]]
D7=  [13,0,R[13][1],0,R[13][2]]
RD1= [14,0,R[14][1],0,R[14][2]]
RD3= [15,0,R[15][1],0,R[15][2]]
RD4= [16,0,R[16][1],0,R[16][2]]
RD5= [17,0,R[17][1],0,R[17][2]]
RD6= [18,0,R[18][1],0,R[18][2]]
RD7= [19,0,R[19][1],0,R[19][2]]
RD8= [20,0,R[20][1],0,R[20][2]]
#プログラムI-1.1c
#-----各区画の長さ方向線分[L1,L2]・幅方向線分[B1,B2]
K12= [ 1, 14, 28,         0, R[1][2] ]
K13= [ 1, 28, 42,         0, R[1][2] ]
K14= [ 1, 42, R[1][1],    0, R[1][2] ]
K21= [ 2,  0, 14,         0, R[2][2] ]
K22= [ 2, 14, 28,         0, R[2][2] ]
K23= [ 2, 28, 42,         0, R[2][2] ]
K24= [ 2, 42, R[2][1],    0, R[2][2] ]
K312=[ 3,  0, 24,         0, R[3][2] ]
K33 =[ 3, 24, 47,         0, R[3][2] ]
S4  =[ 4, 11, R[4][1],    0, 12      ]
K411=[ 4,  0, 16,        12, 26      ]
K412=[ 4, 16, R[4][1],   12, 26      ]
K421=[ 4,  0, 16,        26, R[4][2] ]
K422=[ 4, 16, R[4][1],   26, R[4][2] ]
K5U= [ 5,  7, R[5][1],    0, 12      ] 
K5R= [ 5,  0, R[5][1],   10+2, R[5][2] ] 
S2W= [ 6,  1, 22,         1, 13+2    ]
S2E= [ 6, 36, R[6][1],    0, 13+2    ]
K6=  [ 6,  0, R[6][1],   13, R[6][2] ]
D7N =[13,  0, 31,         0, 24      ]
D7S =[13, 38, 63,         0, 24      ]
D7EN=[13,  0, 31,         0, 12      ]
D7ES=[13, 38, 63,         0, 12      ]
D7WN=[13,  0, 31,        13, 24      ]
D7WS=[13, 38, 63,        13, 24      ] 
#プログラムI-1.1d
#-----データセットにおける割付場所
K1K2    =[K12,K13,K14,K21,K22,K23,K24]; 
K1K2_K5U=[K12,K13,K14,K21,K22,K23,K24,K5U]
K3=[K312,K33]; 
K4=[K411,K412,K421,K422,S4,WB];
K5U=[K5U];
K5R=[K5R];
K6=[K6,S2W,S2E]
#AB=[AB]; BB=[BB]; CB=[CB];
ABC=[AB,BB,CB]; 
AB=ABC; BB=ABC; CB=ABC;
RD =[RD1,RD3,RD4,RD5,RD6,RD7,RD8,D35,D5,D7N,D7S,S4] 
RD2=[RD1,RD3,RD4,RD5,RD6,RD7,RD8,D35,D5,D7N,D7S,S4] 
#プログラムI-1.1e
#-----ブロック特有の割付場所の起点・終点 [i,x1,y1,x2,y2]
K1_1FS1=[[ 1,R[1][1]-14, R[1][1],   0, R[1][2]]]
K1_1S6P=[[ 1,R[1][1]-11, R[1][1],   0, R[1][2]]]
K1_1S6S=[[ 1,R[1][1]-22, R[1][1]-11,0, R[1][2]]]
K2_8S6P=[[ 2,R[2][1]-22, R[2][1]-11,0, R[2][2]]]
K2_8S6S=[[ 2,R[2][1]-11, R[2][1],   0, R[2][2]]]
K4_1AS1=[S4]
D5_AH=  [[12,1,25,0,12]]
D7_3AS1=[D7ES]
D7_1AS1P=[D7ES]
D7_1AS1S=[D7ES]
D7_1AS5P=[D7WN]
D7_1AS5S=[D7WN]
D7_2S6P=[D7ES]
D7_2S6S=[D7ES]
D7_AH1P=[D7N]
D7_AH1S=[D7N]
D7_AH2=[D7N]
D7_3AS12=[D7ES]
D7_1AS1P2=[D7ES]
D7_1AS1S2=[D7ES]
D7_1AS5P2=[D7WN]
D7_1AS5S2=[D7WN]
県岸=0
#プログラムI-1.1f
resPL={}
for id in R:
  resPL[id]=0
  if not id in [4,5,6,13]:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):        
        resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                         .format(i,j), capacity={(0,"inf"):1}) 
  if id==4:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,11) and j in range(0,12):
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):1})
  if id==5:
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in  range(0,7) and j in range(0,10):
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):0})
        else:     
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):1})
  if id==6:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [0,22,23,24,25,26,27,28,29,30,31,32,33,34,35] and j in range(0,13):
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):0})
        elif i in range(1,17) and j in range(0,1):
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):0})            
        else:     
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):1})
  if id==13:       
    for i in range(0,R[id][1]):
      for j in range(0,R[id][2]):  
        if i in [31,32,33,34,35,36,37,63,64,65,66,67,68,69,70,71] and j in range(0,24):
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):0})         
        else:     
          resPL[id,i,j] =usuki1.addResource(R[id][0]+"[{0:02d}_{1:02d}]"\
                                           .format(i,j), capacity={(0,"inf"):1})

●プログラムI-1.2

#プログラムI-1.2    
#=======================================================================
#リソースの定義(作業員)
#=======================================================================
eps1=1.25
resWH={}    #取付28人
r=math.floor(28*4*eps1);
resWH=usuki1.addResource("R[WH]", capacity={(0,"inf"):r})
#-----
resWW={}    #溶接43人
r=math.floor(43*4*eps1);
resWW=usuki1.addResource("R[WW]", capacity={(0,"inf"):r})
#-----
eps2=1.25
resWF1={}   #鉄艤5人
r=math.floor(5*4*eps2);
resWF1=usuki1.addResource("R[WF1]", capacity={(0,"inf"):r})
#-----
resWF2={}   #甲配7人
r=math.floor(7*4*eps2);
resWF2=usuki1.addResource("R[WF2]", capacity={(0,"inf"):r})
#-----
resWF3={}   #機配5人⇒10人
r=math.floor(10*4*eps2);
resWF3=usuki1.addResource("R[WF3]", capacity={(0,"inf"):r})
#-----
resWP={}    #塗装内4人⇒8人
r=math.floor(8*4*eps2);
resWP=usuki1.addResource("R[WP]", capacity={(0,"inf"):r})
#-----
resWP2={}   #塗装外8人
r=math.floor(8*4*eps2);
resWP2=usuki1.addResource("R[WP2]", capacity={(0,"inf"):r})

例題研究(2)

例題(ex11,12,13,14,15,16,17,22,23,24)


●例題ex11:実務的な機械スケジューリング問題

#ex11



●例題ex12:状態変数

#ex12



●例題ex13:順序依存の段取り時間

#ex13



●例題ex14:貯蔵資源の表現方法

#ex14



●例題ex15:ジョブショップスケジューリング問題のベンチマーク問題例

#ex15



●例題ex16:後ろ詰めの表現方法

#ex16



●例題ex17:リリース時刻

#ex17



●例題ex22:Excel出力用の例題

#ex22



●例題23:モードに依存した段取り時間

#ex23



●例題ex24:納期遅れに対する2次のペナルティ

#ex24


例題研究(1)

以下では、スケジューリングソルバーOptSeqのマニュアルに出てくる例題の分析を行います。

例題(ex1,ex2,ex18,ex8)


●例題ex1:PERT

例題ex1は、作業情報が次表のように与えられるとき、最終作業(出発)の完了時刻(メイクスパン)を求めようとしています。

# 作業名 作業期間(分) 後続作業
1 乗客降し 13 3
2 荷物降し 25 5 4
3 機内清掃  15 4
4 乗客搭乗 27 6
5 荷物積込 22 6
6 出発 1 0

#optseq_ex1.py
from optseq import *
#-----データセット
ex1=Model()
data={\
1:[13,[3]],\
2:[25,[5,4]],\
3:[15,[4]],\
4:[27,[6]],\
5:[22,[6]],\
6:[ 1,[0]],\
}
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex1.addActivity("Act[{0}]".format(i))
  mode[i]=Mode("Mode[{0}]".format(i),data[i][0])
  act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if data[i][1][0]!=0:
    for j in data[i][1]:
      ex1.addTemporal(act[i],act[j])
#-----最適化
ex1.Params.TimeLimit=1
ex1.Params.Makespan=True
#ex1.Params.OutputFlag=True
ex1.optimize()
#ex1.writeExcel("ex1_result.csv")
ex1.write("ex1_result.txt")
#-----ex1_result.txt
#  activity    mode   duration  1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
#----------------------------------------------------------------------------------------------------------------------------------------------
#  Act[1]   Mode[1]      13    ==========================                                                                                      
#  Act[2]   Mode[2]      25    ==================================================                                                              
#  Act[3]   Mode[3]      15                              ==============================                                                        
#  Act[4]   Mode[4]      27                            #                                ======================================================  
#  Act[5]   Mode[5]      22                                                      ============================================                  
#  Act[6]   Mode[6]      1                                                                                                                   ==
#----------------------------------------------------------------------------------------------------------------------------------------------
#   resource usage/capacity     
#----------------------------------------------------------------------------------------------------------------------------------------------


このプログラムを実行して、メイクスパンは56分であることが分かります。ex1_result.csvにおいて、でクリティカルパス(CP)を示すと次のようになりま。


●例題ex2:資源制約付きPERT

例題ex2は例題ex1において、各作業の監督者をアサインする場合を検討しています。

リソース 許容量
1 監督者 1

#optseq_ex2.py
from optseq import *
#-----データセット
ex2=Model()
data={\
1:[13,[3]],\
2:[25,[5,4]],\
3:[15,[4]],\
4:[27,[6]],\
5:[22,[6]],\
6:[ 1,[0]],\
}
res=ex2.addResource("worker",capacity={(0,"inf"):1})
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex2.addActivity("Act[{0}]".format(i))
  mode[i]=Mode("Mode[{0}]".format(i),data[i][0])
  mode[i].addResource(res,requirement=1)
  act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if data[i][1][0]!=0:
    for j in data[i][1]:
      ex2.addTemporal(act[i],act[j])
#-----最適化
ex2.Params.TimeLimit=1
ex2.Params.Makespan=True
#ex2.Params.OutputFlag=True
ex2.optimize()
#ex2.writeExcel("ex2_result.csv")
#ex2.write("ex2_result.txt")
#-----ex2_result.txt
#  activity    mode   duration   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#  Act[1]   Mode[1]      13    =======================================                                                                                                                                                                                                                                                                              
#  Act[2]   Mode[2]      25                                                                                        ===========================================================================                                                                                                                                                      
#  Act[3]   Mode[3]      15                                           =============================================                                                                                                                                                                                                                                 
#  Act[4]   Mode[4]      27                                                                                                                                                                                                                                     =================================================================================   
#  Act[5]   Mode[5]      22                                                                                                                                                                   ==================================================================                                                                                    
#  Act[6]   Mode[6]      1                                                                                                                                                                                                                                                                                                                       ===
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#   resource usage/capacity     
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#            worker              1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
#                                1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
#---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


このプログラムを実行して、監督者が1人しかいないと、メイクスパンは103分にまで伸びることが分かります。

●例題ex18:作業情報の抽出(原題:平準化)

例題ex18は、例題ex2において先行制約を外し、作業員を何人まで増やせば納期52日を満たすかを調べています。

#optseq_ex18.py
from optseq import *
#-----データセット
data={\
  1:[13],\
  2:[25],\
  3:[15],\
  4:[27],\
  5:[22],\
  6:[ 1],\
}
duedate52=52
#=====
for ub in range(1,10):
  ex18=Model()
  res=ex18.addResource("wor##ker",capacity={(0,"inf"):ub})
#-----作業とモード
  act={}
  mode={}
  for i in data:
    act[i]=ex18.addActivity("Act[{0}]".format(i), duedate=duedate52)
    mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
    mode[i].addResource(res,requirement=1)
    act[i].addModes(mode[i])
#-----最適化
  ex18.Params.TimeLimit=1
  ex18.Params.Makespan=True
 #ex18.Params.OutputFlag=True
  ex18.optimize()
  ex18.writeExcel("ex18_result.csv")
  ex18.write("ex18_result.txt")
#-----納期は満たされたか?
  completion=0
  for a in act:
    completion=max(completion, act[a].completion)
  if completion<=duedate52: break
#eof
#-----ex18_result.txt
#  activity    mode   duration  1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
#--------------------------------------------------------------------------------------------------------------------------------------
#  Act[1]   Mode[1]      13                                  ==========================                                                
#  Act[2]   Mode[2]      25                                                          ==================================================
#  Act[3]   Mode[3]      15    ==============================                                                                          
#  Act[4]   Mode[4]      27    ======================================================                                                  
#  Act[5]   Mode[5]      22                                                            ============================================    
#  Act[6]   Mode[6]      1                                                                                                         ==  
#--------------------------------------------------------------------------------------------------------------------------------------
#   resource usage/capacity     
#--------------------------------------------------------------------------------------------------------------------------------------
#            worker             2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1
#                               2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
-----------------------------------------------------------------------------------------

このプログラムを実行して、監督者を1人増やすと、メイクスパンは52分に収まることが分かります。

コマンドdir(作業インスタンス)を用いて、適用可能なメソッドのリストを得るとができます。
 :
‘addModes’,
‘autoselect’,
‘backward’,⇒前詰めか後詰めか
‘completion’,⇒完了時刻
‘duedate’,⇒納期
‘execute’,
‘modes’,
‘name’,⇒作業名
‘selected’,⇒選択されたモード
‘start’,⇒開始時刻
‘weight’


●例題ex8:時間制約

例題ex8は、2つの作業の開始のタイミングを揃えたり、ある作業の開始のタイミングを固定する方法を示しています。

#optseq_ex8.py
from optseq import *
#-----データセット
ex8=Model()
data={\
1:[13,[3],  0],\
2:[25,[5,4],0],\
3:[15,[4],  5],\
4:[27,[6],  0],\
5:[22,[6],  0],\
6:[1, [0],  0],\
}
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex8.addActivity("Act[{0}]".format(i))
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if data[i][1][0]!=0:
    for j in data[i][1]:
      ex8.addTemporal(act[i],act[j])
#-----同時開始
for i in data:
  if data[i][2]>0:
    ex8.addTemporal(act[i],act[data[i][2]],'SS',0)
    ex8.addTemporal(act[data[i][2]],act[i],'SS',0)
#-----最適化
ex8.Params.TimeLimit=1
ex8.Params.Makespan=True
#ex8.Params.OutputFlag=True
ex8.optimize()
#ex8.writeExcel("ex8_result.csv")
ex8.write("ex8_result.txt")
#-----ex8_result.txt
#  activity    mode   duration  1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
#----------------------------------------------------------------------------------------------------------------------------------------------------------------------
#  Act[1]   Mode[1]      13    ==========================                                                                                                              
#  Act[2]   Mode[2]      25    ==================================================                                                                                      
#  Act[3]   Mode[3]      15                                                      ==============================                                                        
#  Act[4]   Mode[4]      27                                                                                    ======================================================  
#  Act[5]   Mode[5]      22                                                      ============================================                                          
#  Act[6]   Mode[6]      1                                                                                                                                           ==
#----------------------------------------------------------------------------------------------------------------------------------------------------------------------
#   resource usage/capacity     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------


このプログラムを実行して、作業3と5の開始のタイミングが揃っていることが分かります。ex8_result.csvでは次のように確認できます。

例題(ex3,ex4,ex10)


●例題ex3:並列ショップスケジューリング

例題ex3は、作業間の先行関係が次表のように与えられるとき、最終作業(出発)の完了時刻(メイクスパン)を求めようとしています。

# 作業名 作業期間 後続作業
1 給油準備 3 9
2 飲料水取替 2 11
3 ガラス拭き 2 11
4 ジャッキアップ 2 5 6 7 8
5 タイヤ交換(前輪左側) 4 10
6 タイヤ交換(前輪右側) 4 10
7 タイヤ交換(後輪左側) 4 10
8 タイヤ交換(後輪右側) 4 10
9 給油 11 11
10 ジャッキダウン 2 11
11 出発 1 0

ただし、配員可能な作業員数は次の通りとします。

リソース 許容量
1 作業員 3

#optseq_ex3.py
from optseq import *	
#-----データセット	
ex3=Model()	
data={\	
1:[3,[9]],\	
2:[2,[11]],\	
3:[2,[11]],\	
4:[2,[5,6,7,8]],\	
5:[4,[10]],\	
6:[4,[10]],\	
7:[4,[10]],\	
8:[4,[10]],\	
9:[11,[11]],\	
10:[2,[11]],\	
11:[1,[0]],\	
}	
res=ex3.addResource("worker",capacity={(0,"inf"):3})	
#-----作業とモード	
act={}	
mode={}	
for i in data:	
  act[i]=ex3.addActivity("Act[{0}]".format(i))	
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])	
  mode[i].addResource(res,requirement=1)
  act[i].addModes(mode[i])	
#-----先行制約	
for i in data:	
  if i<11:	
    for j in data[i][1]:	
      ex3.addTemporal(act[i],act[j])	
#-----最適化	
ex3.Params.TimeLimit=1	
ex3.Params.Makespan=True	
#ex3.Params.OutputFlag=True	
ex3.optimize()	
#ex3.writeExcel("ex3_result.csv")	
ex3.write("ex3_result.txt")		
#-----ex3_result.txt
#   activity    mode   duration  1 2 3 4 5 6 7 8 9101112131415
# -------------------------------------------------------------
#   Act[1]   Mode[1]      3     ======                        
#   Act[2]   Mode[2]      2     ====                          
#   Act[3]   Mode[3]      2     ====                          
#   Act[4]   Mode[4]      2         ====                      
#   Act[5]   Mode[5]      4             ========              
#   Act[6]   Mode[6]      4                     ========      
#   Act[7]   Mode[7]      4             ========              
#   Act[8]   Mode[8]      4                     ========      
#   Act[9]   Mode[9]      11          ======================  
#  Act[10]   Mode[10]     2                             ====  
#  Act[11]   Mode[11]     1                                 ==
# -------------------------------------------------------------
#    resource usage/capacity     
# -------------------------------------------------------------
#             worker             3 3 2 2 3 3 3 3 3 3 3 3 2 2 1
#                                3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
# -------------------------------------------------------------


このプログラムを実行して、最大配員数の範囲内で作業を並列化する(同時進行させる)ことができています。ex3_result.csvでは次のようになります。


●例題ex4:作業の並列実行(モードの利用)

例題ex4は、作業1についての配員数を変えたモードを複数個設定することで、メイクスパンを短縮するモードを自動選択させています。

#optseq_ex4.py
from optseq import *
#-----データセット
ex4=Model()
data={\
1:[3,[9]],\
2:[2,[11]],\
3:[2,[11]],\
4:[2,[5,6,7,8]],\
5:[4,[10]],\
6:[4,[10]],\
7:[4,[10]],\
8:[4,[10]],\
9:[11,[11]],\
10:[2,[11]],\
11:[1,[0]],\
}
res=ex4.addResource("worker",capacity={(0,"inf"):3})
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex4.addActivity("Act[{0}]".format(i))
  if i==1:
    mode[1,1]=Mode("Mode[1_1]",duration=3)
    mode[1,1].addResource(res,requirement=1)
    mode[1,2]=Mode("Mode[1_2]",duration=2)
    mode[1,2].addResource(res,requirement=2)
    mode[1,3]=Mode("Mode[1_3]",duration=1)
    mode[1,3].addResource(res,requirement=3)
    act[i].addModes(mode[1,1],mode[1,2],mode[1,3])
  else:
    mode[i]=Mode("Mode[{0}]".format(i),data[i][0])
    mode[i].addResource(res,requirement=1)
    act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if i<11:
    for j in data[i][1]:
      ex4.addTemporal(act[i],act[j])
#-----最適化
ex4.Params.TimeLimit=1
ex4.Params.Makespan=True
#ex4.Params.OutputFlag=True
ex4.optimize()
#ex4.writeExcel("ex4_result.csv")
ex4.write("ex4.txt")
#-----ex4_result.txt
#   activity    mode   duration  1 2 3 4 5 6 7 8 91011121314
# -----------------------------------------------------------
#   Act[1]  Mode[1_3]     1     ==                          
#   Act[2]   Mode[2]      2       ====                      
#   Act[3]   Mode[3]      2                           ====  
#   Act[4]   Mode[4]      2       ====                      
#   Act[5]   Mode[5]      4           ========              
#   Act[6]   Mode[6]      4                   ========      
#   Act[7]   Mode[7]      4                   ========      
#   Act[8]   Mode[8]      4           ========              
#   Act[9]   Mode[9]      11      ======================   
#  Act[10]   Mode[10]     2                           ====  
#  Act[11]   Mode[11]     1                               ==
# -----------------------------------------------------------
#    resource usage/capacity     
# -----------------------------------------------------------
#             worker             3 3 3 3 3 3 3 3 3 3 3 3 2 1
#                                3 3 3 3 3 3 3 3 3 3 3 3 3 3
# -----------------------------------------------------------


このプログラムを実行して、作業1について3人を配員するモードmode[1,3]が選ばれています。メイクスパンはex3より1日短くなっています。ex4_result.csvでは次のようになります。


●例題ex10:作業の並列実行(小作業の並列化)

例題ex10は、作業1を1人で行うものとして登録し、これを配員可能な複数人で行って、並列化することを狙っています。この手法は小作業並列化手法と呼ばれ、作業期間が自動調整されることから、高度な平準化手法の基礎となる可能性があります(詳しくは改めて説明します)。

#optseq_ex10.py
from optseq import *
#-----データセット
ex10=Model()
data={\
1:[3,[9]],\
2:[2,[11]],\
3:[2,[11]],\
4:[2,[5,6,7,8]],\
5:[4,[10]],\
6:[4,[10]],\
7:[4,[10]],\
8:[4,[10]],\
9:[11,[11]],\
10:[2,[11]],\
11:[1,[0]],\
}
res=ex10.addResource("worker",capacity={(0,"inf"):3})
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex10.addActivity("Act[{0}]".format(i))
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  mode[i].addResource(res,requirement=1)
  if i==1:
    mode[i].addParallel(start=1,finish=1,maxparallel=3)
  act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if i<11:
    for j in data[i][1]:
      ex10.addTemporal(act[i],act[j])
#-----最適化
ex10.Params.TimeLimit=1
ex10.Params.Makespan=True
#ex10.Params.OutputFlag=True
ex10.optimize()
#ex10.writeExcel("ex10_result.csv")
ex10.write("ex10_result.txt")
#-----ex10_result.txt
#   activity    mode   duration  1 2 3 4 5 6 7 8 910111213
# ---------------------------------------------------------
#   Act[1]   Mode[1]      3     *3                        
#   Act[2]   Mode[2]      2                           ====
#   Act[3]   Mode[3]      2                           ====
#   Act[4]   Mode[4]      2       ====                    
#   Act[5]   Mode[5]      4           ========            
#   Act[6]   Mode[6]      4       ========                
#   Act[7]   Mode[7]      4               ========        
#   Act[8]   Mode[8]      4                   ========    
#   Act[9]   Mode[9]      11        ======================
#  Act[10]   Mode[10]     2                       ====    
#  Act[11]   Mode[11]     1       ==                      
# ---------------------------------------------------------
#    resource usage/capacity     
# ---------------------------------------------------------
#             worker             3 3 3 3 3 3 3 3 3 3 3 3 3
#                                3 3 3 3 3 3 3 3 3 3 3 3 3
# ---------------------------------------------------------


このプログラムを実行して、作業1は作業員3人で行ない作業期間は1日となっており(■*3)、ex4と同じメイスパンとなっています。ex10_result.csvでは次のようになります。

例題(ex5,ex6,ex20,ex9)


●例題ex5:一般化資源制約付きスケジューリング

例題ex5は、リソースの許容量を期間ごとに決めています。これは休日をもつカレンダーを導入するために役立ちます。

#optseq_ex5.py
from optseq import *
#-----データセット
ex5=Model()
data={\
1:[1,2,[2,4]],\
2:[1,2,[3]],\
3:[2,1,[5]],\
4:[2,1,[7]],\
5:[1,1,[6]],\
6:[1,2,[7]],\
7:[1,1,[0]],\
}
res=ex5.addResource("worker")
res.addCapacity(start=0,finish=2,amount=2)
res.addCapacity(start=2,finish=3,amount=1)
res.addCapacity(start=3,finish="inf",amount=2)
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex5.addActivity("Act[{0}]".format(i))
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  mode[i].addResource(res,requirement=data[i][1])
  act[i].addModes(mode[i])
#-----先行制約
for i in data:
  if i<7:
    for j in data[i][2]:
      ex5.addTemporal(act[i],act[j])
#-----最適化
ex5.Params.TimeLimit=1
ex5.Params.Makespan=True
#ex5.Params.OutputFlag=True
ex5.optimize()
#ex5.writeExcel("ex5_result.csv")
ex5.write("ex5.txt")
#-----ex5_result.txt
#   activity    mode   duration 1234567
# --------------------------------------
#   Act[1]   Mode[1]      1     =      
#   Act[2]   Mode[2]      1      =     
#   Act[3]   Mode[3]      2       ==   
#   Act[4]   Mode[4]      2        ==  
#   Act[5]   Mode[5]      1         =  
#   Act[6]   Mode[6]      1          = 
#   Act[7]   Mode[7]      1           =
# --------------------------------------
#    resource usage/capacity     
# --------------------------------------
#             worker            2212221
#                               2212222
# --------------------------------------


このプログラムを実行して、3日目の配員が1名に抑えられていることが分かります。


●例題ex6:納期遅れ最小化スケジューリング

例題ex6は、納期のある複数個の作業を、納期遅れ総和を最小にするためには、どの順番で実施すればよいかを検討しています。

#optseq_ex6.py
from optseq import *
#-----データセット
data={\
ex6=Model()
1:[1,5],\
2:[2,9],\
3:[3,6],\
4:[4,4],\
}
res=ex6.addResource("writer")
res.addCapacity(0,"inf",1)
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex6.addActivity("Act[{0}]".format(i),duedate=data[i][1])
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  mode[i].addResource(res,requirement=1)
  act[i].addModes(mode[i])
#-----最適化
ex6.Params.TimeLimit=1
ex6.Params.Makespan=False
#ex6.Params.OutputFlag=True
ex6.optimize()
#ex6.writeExcel("ex6_result.csv")
ex6.write("ex6_result..txt")
#-----ex6_result.txt
#   activity    mode   duration  1 2 3 4 5 6 7 8 910
# ---------------------------------------------------
#   Act[1]   Mode[1]      1             ==          
#   Act[2]   Mode[2]      2                     ====
#   Act[3]   Mode[3]      3               ======    
#   Act[4]   Mode[4]      4     ========            
# ---------------------------------------------------
#    resource usage/capacity     
# ---------------------------------------------------
#             writer             1 1 1 1 1 1 1 1 1 1
#                                1 1 1 1 1 1 1 1 1 1
# ---------------------------------------------------


このプログラムを実行して、作業4,1,3,2の順に行うと納期遅れが最小になることが分かります。それでも、ex6_result.csvにで示すような納期遅れが生じています。


●例題ex20:納期遅れをしない範囲でなるべく多くの仕事をこなす方法

例題ex20では、この目的を達成するために、作業期間0のモードをうまく利用しています。

##optseq_ex20.py
from optseq import *
#-----データセット
ex20= Model()
data={
1:[5,1],\
2:[9,2],\
3:[6,3],\
4:[4,4],\
}
res=ex20.addResource("writer")
res.addCapacity(0,"inf",1)
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex20.addActivity(f"Act[{i}]",duedate=data[i][0],weight=100)
  mode[i]=Mode(f"Mode[{i}]",duration=data[i][1])
  mode[i,0]=Mode(f"Mode[{i}0]",duration=0)
  mode[i].addResource(res,1)
  act[i].addModes(mode[i],mode[i,0])
#-----モード制約
con1=ex20.addResource("constraint_1",rhs=0,direction="<=",weight=1)
con1.addTerms(coeffs=[1,1,1,1], vars=[act[1],act[2],act[3],act[4]],\
              values=[mode[1,0],mode[2,0],mode[3,0],mode[4,0]])
#-----最適化
ex20.Params.TimeLimit=1
ex20.Params.Makespan=False
#ex20.Params.OutputFlag=True
ex20.optimize()
#ex20.writeExcel("ex20_result.csv")
ex20.write("ex20_result.txt")
#-----ex20_result.txt
#   activity    mode   duration 1234567
# --------------------------------------
#   Act[1]   Mode[1]      1         =  
#   Act[2]   Mode[2]      2          ==
#   Act[3]   Mode[30]     0            
#   Act[4]   Mode[4]      4     ====   
# --------------------------------------
#    resource usage/capacity     
# --------------------------------------
#             writer            1111111
#                               1111111
# --------------------------------------


このプログラムを実行して、作業3を行わなければ、他の作業は納期に間に合うことが分かります。

●例題ex9:作業の途中中断 

例題ex9は、例題ex6に休業日を考慮する手法を示しています。

#optseq_ex9.py
from optseq import *
#-----データセット
ex9=Model()
data={\
1:[1,5],\
2:[2,9],\
3:[3,6],\
4:[4,4],\
}
res=ex9.addResource("writer")
res.addCapacity(0,3,1)
res.addCapacity(4,6,1)
res.addCapacity(7,10,1)
res.addCapacity(11,"inf",1)
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex9.addActivity("Act[{0}]".format(i),duedate=data[i][1])
  mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  mode[i].addResource(res,requirement=1)
  mode[i].addBreak(start=0,finish='inf',maxtime=1)
  mode[i].addResource(res,{(0,"inf"):1},"break")  #break中も資源を使う場合
  act[i].addModes(mode[i])
#-----最適化
ex9.Params.TimeLimit=1
#ex9.Params.OutputFlag=True
ex9.Params.Makespan=False
ex9.optimize()
#ex9.writeExcel("ex9_result.csv")
ex9.write("ex9_result.txt")
#-----ex9_result.txt
#   activity    mode   duration  1 2 3 4 5 6 7 8 9101112131415
# -------------------------------------------------------------
#   Act[1]   Mode[1]      1             ==                    
#   Act[2]   Mode[2]      2                   ====            
#   Act[3]   Mode[3]      3     ======                        
#   Act[4]   Mode[4]      4                           ========
# -------------------------------------------------------------
#    resource usage/capacity     
# -------------------------------------------------------------
#             writer             1 1 1 0 1 0 0 1 1 0 0 1 1 1 1
#                                1 1 1 0 1 1 0 1 1 1 0 1 1 1 1


このプログラムを実行して、次の結果①を得ます。結果②、③,④は中断中のリソースの使用を不可にしたり、中断期間を無制限にしたりして、計画がどのように変わるかを調べています。

例題(ex7,ex19,ex21)


●例題ex7:クリティカルパス法

例題ex7は、例題ex1の作業時間を、次表のように短縮する可能性を探ろうとしています。ただし、短縮する場合は1万円必要とするとします。

# 作業名 作業期間 後続作業 短縮時間
1 乗客降し 13 3 10
2 荷物降し 25 5 4 20
3 機内清掃 15 4 10
4 乗客搭乗 27 6 25
5 荷物積込 22 6 20
6 出発 1 0 1

そのために各作業に通常の作業時間をもつモード1と短縮された作業時間をもつモード2を割り当て、モード2を使う場合は資金rhs万円(再生不能資源)の中から1万円使用するようにします。これは制約式

    \[c_1\times x_{1,2}+c_2\times x_{2,2}+\cdots+c_5\times x_{5,2}\le rhs(man\ yen)\]

ただし

    \[c_1=c_2=c_3=c_4=c_5=1(man\ yen)\]

    \[x_{1,2},\ x_{2,2},\ x_{3,2},\ x_{4,2},\ x_{5,2}=1\ or\ 0\]

を課すように問題定式化が行われます。

#optseq_ex7.py
from optseq import *
#-----データセット
ex7=Model()
data={\
1:[13,[3],  10],\
2:[25,[5,4],20],\
3:[15,[4],  10],\
4:[27,[6],  25],\
5:[22,[6],  30],\
6:[ 1,[0],   1],\
}
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex7.addActivity("Act[{0}]".format(i))
  mode[i,1]=Mode("Mode[{0}][1]".format(i),duration=data[i][0])
  mode[i,2]=Mode("Mode[{0}][2]".format(i),duration=data[i][2])
  act[i].addModes(mode[i,1],mode[i,2])
#-----モード制約
res=ex7.addResource("money",rhs=5,direction="<=")
for i in data:
  if data[i][1][0]!=0:
    res.addTerms(1,act[i],mode[i,2])
#-----先行制約
for i in data:
  if data[i][1][0]!=0:
    for j in data[i][1]:
      ex7.addTemporal(act[i],act[j])
#-----最適化
ex7.Params.TimeLimit=1
ex7.Params.Makespan=True
#ex7.Params.OutputFlag=True
ex7.optimize()
#ex7.writeExcel("ex7_result.csv")
#ex7.write("ex7.txt")


このプログラムを実行して、次の結果を得ます。ただし、資金1,2,3はそれぞれ4万円、1万円、0万円(rhs=4,1,0)に対応しています。


●例題ex19:モード間の関係

#optseq_ex19.py
from optseq import *
#-----データセット
model=Model()
duration ={ 
("A",0) :10,\
("A",1) :13,\
("A",2) :12,\
("B",0) :15,\
("B",1) :11,\
("B",2) :12,\
("B",3) :14,\
}
#-----作業とモード
act={}
mode={}
act["A"] = model.addActivity("Act[A]")
act["B"] = model.addActivity("Act[B]")
for i,j in duration:
  mode[i,j] = Mode(f"Mode[{i},{j}]", duration[i,j])
act["A"].addModes(mode["A",0], mode["A",1], mode["A",2])
act["B"].addModes(mode["B",0], mode["B",1], mode["B",2], mode["B",3] )
#-----モード制約
con1=model.addResource("constraint_1",rhs=0,direction = "=")
con1.addTerms(coeffs=[1,-1], vars= [act["A"], act["B"]],\
 values =[mode["A",0],mode["B",0]])
con2=model.addResource("constraint_2",rhs=1,direction = "<=")
con2.addTerms(coeffs=[1,1], vars= [act["A"], act["B"]],\
 values =[mode["A",1],mode["B",1]])
con3=model.addResource("constraint_3",rhs=0,direction = "<=")
con3.addTerms(coeffs=[1,-1,-1], vars= [act["A"], act["B"], act["B"]],\
 values =[mode["A",2], mode["B",2], mode["B",3]])
#-----最適化
model.Params.TimeLimit=1
model.Params.Makespan=True
model.optimize()
#-----
#eof


任意の作業aがモードmをとるとき値1を、m以外のモードをとるとき値0をとる変数をx_{a,m}とします。このとき
1^\circ 作業Aと作業Bに対して同じモードmを選択させる制約式は

    \[x_{A,m}=x_{B,m}\ \Rightarrow\ x_{A,m}+(-1)x_{B,m}=0\]

2^\circ 作業Aと作業Bのどちらかにモードmを選択させる制約式は

    \[x_{A,m}+x_{B,m}\le 1\]

3^\circ 作業Aがモードmを選択するとき、作業Bにはモードmまたはモードm'を選択させる制約式は

    \[x_{A,m}\le x_{B,m}+x_{B,m'}\ \Rightarrow\ x_{A,m}+(-1)x_{B,m}+(-1)x_{B,m'}\le0\]


●例題ex21:資源の優先利用の設定法

#optseq_ex21.py
from optseq import *
#-----データセット
ex21=Model()
data={
1:[3,[]],\
2:[2,[]],\
3:[2,[]],\
4:[2,[]],\
5:[4,[]],\
6:[4,[]],\
7:[4,[]],\
8:[4,[]],\
9:[11,[]],\
10:[2,[]],\
}
res={}
for r in range(1,4):
  res[r]=ex21.addResource("worker"+str(r), capacity=1)
#-----作業とモード
act={}
mode={}
for i in data:
  act[i]=ex21.addActivity("Act[{0}]".format(i))
  for r in range(1,4):
    mode[i,r]=Mode("Mode[{0}{1}]".format(i,r),duration=data[i][0])
    mode[i,r].addResource(res[r],1)
    act[i].addModes(mode[i,r])
#-----モード制約  
con={}
weight={1:1, 2:2, 3:3}
for r in range(1,4):
  con[r]=ex21.addResource(name="Constraint{0}".format(r),\
                          rhs=0,direction="<=",weight=weight[r])
  for i in data:
    con[r].addTerms(1,act[i],mode[i,r])
#-----先行制約
ex21.addTemporal(act[1],act[9])
for i in range(5,9):
  ex21.addTemporal(act[4],act[i])
  ex21.addTemporal(act[i],act[10])
#-----最適化
ex21.Params.TimeLimit=1
ex21.Params.Makespan=True
#ex21.Params.OutputFlag=True
ex21.optimize()
ex21.writeExcel("ex21_result.csv")
#ex21.write("ex21.txt")
#-----
#eof

工程計画ベンチマーク問題

●一般の工程計画問題は、日程計画・配員計画・定盤計画・運搬計画がお互いに連動すると考えられます。ここで、定盤計画とは作業場所の割付を意味しています。これを解くために参考になると思われるベンチマーク問題を作成してみました。各計画において考慮すべきファクターとして、次のものがあります。

1^\circ 日程計画: 作業間先行制約
2^\circ 配員計画: 作業員(平準化)、工場カレンダー
3^\circ 定盤計画: 作業場所、待機場所
4^\circ 運搬計画: 作業機械(台車、クレーン)

これらの計画を行うためには、まず各作業の総時数と各作業員数を考慮して、各作業期間を決定し、納期までの先行関係を明らかにし、配員計画と日程計画を同時に立てます。次に日程計画に沿って、作業場所の確保(定盤計画)を行います。場所が空いていなければ、待機が必要となりますが、その期間を計画前に予め把握することはできないことに注意します。また、各運搬日には運搬機械を使う時間帯を決める運搬計画を立てます。さらに、悪天候や機械の故障、作業員の欠勤などによる工程中断後、工程の再計画(リスケジューリング)を行う必要があります。

●次の初期計画を考えます。

これから作業と先行制約に関して次表を得ます。

また、リソースについては次表のようにまとめられます。

(1) 作業場所・待機場所

(2) 作業機械

(3) 作業員

●次のプログラムを考えます、

#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

●日程計画

●定盤計画

●その他

場所の割付

ここでは、作業場所の割付、配置計画について検討します。

上図のように、作業場所はサイズ5Lx5Bの定盤で、ここにサイズ2Lx2Bの製作物を3日間だけ据置きたいとします。ただし黒色のメッシュは柱があって使えないとします。このとき割付可能な候補は12通りあり、このうちのどれか1つを選びたいとします。

#prob21.py
from optseq import *
#=====リソース
prob21=Model()
res={}
for i in range(0,5):
  for j in range(0,5):  
    if i==1 and j==3 :
      res[i,j] =prob21.addResource("place[{0:02d}_{1:02d}]".format(i,j),capacity={(0,"inf"):0})            
    else:     
      res[i,j] =prob21.addResource("place[{0:02d}_{1:02d}]".format(i,j),capacity={(0,"inf"):1})           
#====データセット
#i:[期間,納期,[l,b]]
data={1:[3,5,[2,2]]}    
#=====アクティビティ
act={}
for i in data.keys():
  act[i]=prob21.addActivity("act[{0}]".format(i))
#====資源制約  
L=5; B=5; L1=0; L2=4; B1=0; B2=4; skipL=1; skipB=1; 
mode={}  
for i in data.keys():
  #mode[i]=Mode("Mode[{0}]".format(i),duration=data[i][0])
  l=data[i][2][0]; b=data[i][2][1];
  for j in range(L1,L2-l+1,skipL):
    for k in range(B1,B2-b+1,skipB):         
      mode[i,j,k]=Mode("mode[{0:02d}]_[{1:02d}_{2:02d}][{3:02d}_{4:02d}]".\
                  format(i,j,k,l,b),duration=data[i][0])
      for s in range(0,l):
        for t in range(0,b):
          mode[i,j,k].addResource(res[j+s,k+t],1)         
      act[i].addModes(mode[i,j,k])       
#=====最適化
prob21.Params.Makespan=True
prob21.Params.TimeLimit=1
#prob3.Params.OutputFlag=True
prob21.optimize()
prob21.write("prob21.txt")
prob21.writeExcel("prob21.csv")
#=====prob21.txt
#  activity    mode   duration 123
#----------------------------------
#  act[1]  mode[01]_[01_00][02_02]    3     ===
#----------------------------------
#   resource usage/capacity     
#----------------------------------
#         place[00_00]         000      #         place[03_00]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[00_01]         000      #         place[03_01]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[00_02]         000      #         place[03_02]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[00_03]         000      #         place[03_03]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[00_04]         000      #         place[03_04]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[01_00]         111      #         place[04_00]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[01_01]         111      #         place[04_01]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[01_02]         000      #         place[04_02]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[01_03]         000      #         place[04_03]         000
#                              000      #                              111
#----------------------------------     #----------------------------------
#         place[01_04]         000      #         place[04_04]         000
#                              111      #                              111
#----------------------------------     #----------------------------------
#         place[02_00]         111
#                              111
#----------------------------------
#         place[02_01]         111
#                              111
#----------------------------------
#         place[02_02]         000
#                              111
#----------------------------------
#         place[02_03]         000
#                              111
#----------------------------------
#         place[02_04]         000
#                              111
#----------------------------------  

このプログラムを実行して、次の結果を得ます。