RCPSP求解プログラムの枠組み

rcpsp30.py
次はプッシュ型とプル型の結果を比べる簡単なプログラムですが、データセットの定義、アクティビティの定義(プッシュ型)、モードの付与(作業期間の指定)、求解からなる構成が見てとれます。


001
002

003
004
005
006
007
008

009
010
011
012
013

#rcpsp30.py
from optseq import *

data=["A01",5,10] #[名前,期間,納期]
prob=Model()
act=prob.addActivity(name=data[0])
#act=prob.addActivity(name=data[0],duedate=data[2]-1,backward=True)
mode=Mode("Mode",duration=data[1])
act.addModes(mode)

prob.Params.Makespan=True
prob.Params.TimeLimit=1
#prob.Params.OutputFlag=True
prob.optimize()
prob.write("rcpsp30.txt")

これを実行すると次を得ます。
【rcpsp30.txt】


001
002
003
004
005
006

  activity    mode   duration 12345
------------------------------------
   A01       Mode       5     =====
------------------------------------
   resource usage/capacity     
------------------------------------

納期日を10日とするプル型の結果を得るときは、


005
006

#act=prob.addActivity(name=data[0])
act=prob.addActivity(name=data[0],duedate=data[2]-1,backward=True) 

とします。納期日の前日まで作業を終わりたいので、duedateは納期日の前日としています。これを実行すると次を得ます。
【rcpsp30.txt】


001
002
003
004
005
00

  activity    mode   duration 123456789
------------------------------------------------
   A01       Mode       5         =====
------------------------------------------------
   resource usage/capacity     
------------------------------------------------

rcpsp31.py
次はRCPSP法のプログラムの基本的な枠組みを示すプログラムで、アクティビティに先行制約が、モードに資源制約が組み込まれています。


001
002
003
004
005
006
007
008
009

#rcpsp31.py
from optseq import *
#====データセット 
#i:[名前,期間,後続,資源]
data={
 1:["A01",5,[2],1],
 2:["A02",1,[0],0]
}
date10=10 #納期日

データセットはPythonの辞書データとしています。keyでアクティビティを識別し、名前、作業期間、後続作業のリスト(後続がないときは0)、必要とするリソースなどからなるリストを対応させています。


010
011
012
013
014
015

#====アクティビティ
prob=Model()
act={}
for i in data:
   #act[i]=prob.addActivity(name=data[i][0])   
    act[i]=prob.addActivity(name=data[i][0],duedate=date10,backward=True)  

データセットで定義された2つのアクティビティ(製作作業と納品作業)を定義しています。プル型のduedateは、2つとも納品作業のものを用いています。次に定義する先行関係があるので、納品作業は必ず製品作業が終わってから行うことになります。


010
011
012
013
014
015
016
017

#====先行制約
for i in data:
    for j in data[i][2]:
        if j>0: prob.addTemporal(act[i],act[j]) 
#----A02固定
i==2
prob.addTemporal("source",act[i],tempType="CC",delay= date10)   
prob.addTemporal(act[i],"source",tempType="CC",delay=-date10)     

プッシュ型計画を行うことも想定して、納期日は固定しています。これは2つの不等式

C("source")+data10\le C("A02")\ \Leftrightarrow\ 10\le C("A02")
C("A02")-data10\le C("source")\ \Leftrightarrow\ C("A02")\le 10

が成り立つ(C(\cdot)は完了日)、すなわちC("A02")=10を要求しているからです。


018
019
020
021
022
023
024

#====資源制約  
res=prob.addResource("worker",capacity={(0,"inf"):1}) 
mode={}  
for i in data:
    mode[i]=Mode("M{0:02d}".format(i),duration=data[i][1])
    mode[i].addResource(res,requirement=data[i][3])
    act[i].addModes(mode[i])   

リソースのキャパシティは1です。各アクティビティについてモードは1個です。各モードは名前で区別します。


025
026
027
028
029
030

#====求解
prob.Params.Makespan=True
prob.Params.TimeLimit=1
#prob.Params.OutputFlag=True
prob.optimize()
prob.write("rcpsp31.txt") 

これを実行すると次の結果を得ます。
【rcpsp31.txt】


001
002
003
004
005
006
007
008
009
010

  activity    mode   duration  1 2 3 4 5 6 7 8 910
------------------------------------------------------------
   A01       M01        5             ==========  
   A02       M02        1                       ==
------------------------------------------------------------
   resource usage/capacity     
------------------------------------------------------------
            worker             0 0 0 0 1 1 1 1 1 0
                               1 1 1 1 1 1 1 1 1 1
------------------------------------------------------------

上のプログラムは、プッシュ型かプル型か、評価関数はメイクススパンか納期遅れ総和かで、4通りの実行ができます。それぞれの目的関数の値を確かめると参考になるかと思います。

rcpsp32.py
例題1をRCPSP法で解くプログラムを次に示します。


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016

#rcpsp32.py
from optseq import *
#====データセット
#i:[名前,期間,後続,資源]
data={
 1:["A01",3,[4,6],3],
 2:["A02",4,[5,7],1],
 3:["A03",6,[8]  ,1],
 4:["A04",4,[5,7],4],
 5:["A05",5,[8]  ,4],
 6:["A06",5,[9]  ,4],
 7:["A07",4,[10] ,5],
 8:["A08",2,[10] ,2],
 9:["A09",2,[10] ,5],
10:["A10",5,[0]  ,3],
}

10個のアクティビティについてデータが定義されています。


017
018
019
020
021

#====アクティビティ
prob=Model()
act={}
for i in data:
    act[i]=prob.addActivity(data[i][0])

プッシュ型の計画が想定されています。


022
023
024
025

#====先行制約
for i in data:
    for j in data[i][2]:
        if j>0: prob.addTemporal(act[i],act[j])  

先行関係は13個あります。


026
027
028
029
030

031
032

#====資源制約  
res=prob.addResource("Resource",capacity={(0,"inf"):10}) 
mode={}  
for i in data:
    mode[i]=Mode("M{0:02d}_{1:02d}".format(i,data[i][3]),
                                    duration=data[i][1])
    mode[i].addResource(res,requirement=data[i][3])
    act[i].addModes(mode[i])

リソースのキャパシティは10です。各アクティビティについてモードは1個です。


033
034
035
036
037
038
039

#====求解
prob.Params.Makespan=True
prob.Params.TimeLimit=1
#prob.Params.OutputFlag=True
prob.optimize()
prob.write("rcpsp32.txt")
prob.writeExcel("rcpsp32.csv")

これを実行すると次の結果を得ます。
【rcpsp32.txt】


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018

  activity    mode   duration  1 2 3 4 5 6 7 8 910111213141516171819
-----------------------------------------------------------------------------
   A01      M01_03      3     ======                                
   A02      M02_01      4     ========                              
   A03      M03_01      6     ============                          
   A04      M04_04      4           ========                        
   A05      M05_04      5                   ==========              
   A06      M06_04      5           ==========                      
   A07      M07_05      4                         ========          
   A08      M08_02      2                             ====          
   A09      M09_05      2                     ====                  
   A10      M10_03      5                                 ==========
-----------------------------------------------------------------------------
   resource usage/capacity     
-----------------------------------------------------------------------------
           Resource            5 5 510 9 9 8 8 9 9 9 9 7 7 3 3 3 3 3
                              10101010101010101010101010101010101010
-----------------------------------------------------------------------------