スケジューリングモデルとは
DESCRIPTION
スケジューリング最適化システム OptSeq II Python モジュールの使い方 補助資料: OptSeq II によるスケジューリング入門 トライアルバージョン http://www.logopt.com/OptSeq/OptSeq.htm. スケジューリングモデルとは. 作業( activity ;活動) :遂行すべき仕事のこと.別名,オペレーション( operation ),ジョブ,仕事 (job) ,タスク (task) .作業時間や納期の情報が付加される. - PowerPoint PPT PresentationTRANSCRIPT
スケジューリング最適化システムOptSeq II
Python モジュールの使い方
補助資料: OptSeq II によるスケジューリング入門 トライアルバージョン
http://www.logopt.com/OptSeq/OptSeq.htm
スケジューリングモデルとは
• 作業( activity ;活動):遂行すべき仕事のこと.別名,オペレーション( operation ),ジョブ,仕事(job) ,タスク (task) .作業時間や納期の情報が付加される.
• 先行(時間)制約( precedence (time) constraint ):ある作業(ジョブ,活動)がある作業(ジョブ,活動)の前に処理されなければならないことを表す制約.
• 資源( resource ):作業を行うときに必要とされるもので,その量に限りがあるもの.機械 (machine )はジョブによって占有される資源.その他,人員,材料,お金なども全部資源.
optseq2.py モジュールとは
• スケジューリングソルバー OptSeq を,超高級言語 Python から直接呼び出して,求解するためのモジュール
• すべて Python で書かれたクラスで構成
• ソースコード(すべて Python で記述)も公開されているので,ユーザが書き換え可能
Python モジュールのクラス
• 作業クラス ー Activity
• モードクラス ー Mode
• 資源クラス ー Resource
• 先行制約クラス ー Temporal
• モデルクラス ー Model
• パラメータクラス ー Parameters
作業クラス ー Activity
• activity の引数と引数のデフォルト値activity(name=‘’, dudate=‘inf’, weight=1)– name : 作業の名前,文字列で入力– dudate : 作業の納期,非負の整数または‘ inf’ で入力– weight : 作業が納期遅れした時のペナルティ, positive 整
数
• activity の addModes メソッドactivity.addModes(modes) – modes : モードクラスで作成– 作業にモード(一つまたは複数のモード)を追加する時に使
用– 例: activity.addModes(mode1,mode2)
作業の定義を行う
モードクラス ー Mode (1)
• mode の引数と引数のデフォルト値mode(name=‘ ’, duration=0) – name : モードの名前,文字列で入力– duration : このモードを選択した場合の作業時間
• mode のメソッド (次のページで詳しく)– addBreak(start=0, finish=0, maxtime=‘inf’)
休憩に関する情報をモードに追加 – addParallel(start=1, finish=1, maxparallel=‘inf’)
並列処理に関する情報をモードに追加 – addResource(resource, requirement={}, rtype=None)
資源に関する情報をモードに追加
モードの定義を行う
モードクラス ー Mode (2)
• addBreak メソッドaddBreak(start=0, finish=0, maxtime=‘inf’)– start , finish : 休憩開始時間,休憩終了時間– maxtime : 最大休憩可能時間
• addParallel メソッドaddParallel(start=1, finish=1, maxparallel=‘inf’)– start , finish : 並列開始小作業番号,並列終了小作業
番号– maxparallel : 最大並列数
モードメソッド(1)
モード名 .addBreak(0,3,1)
モード名 .addBreak( 中断開始時刻 , 中断終了時刻 , 最大中断時間 )
作業の途中中断• Python インターフェイスによる記述
作業 A が, 0 から 3 の区間でそれぞれ最大 1 中断可能:
開始から 2 時刻で中断した例
モード名 .addParallel(1,1,3)
モード名 .addParallel( 開始小作業番号 , 終了小作業番号 , 最大並列数 )
作業の並列処理
小作業 1, 小作業 1
作業1(作業時間は3秒)を最大3単位並列可能:
• Python インターフェイスによる記述
作業1
並列処理の結果
• 1 番目の小作業を 3 単位並列可能:
2 3
1
モードクラス ー Mode (3)
• addResource メソッドaddResource(resource, requirement={}, rtype=None)– resource : 資源オブジェクト– requirement : 資源必要量
資源を必要とする開始時刻と終了時刻を辞書で表す.必要量を正数値として入力すると,開始 0 ,終了 “ inf” になる.
例: mode.addResource(worker,{(0,10):1}) 時刻 0 から時刻 10 まで worker という資源を1単位必要
– rtype : リソースのタイプ ----- break と max がある例: mode.addResource(machine,{(0,"inf"):1},"break") break は休憩中も資源を1単位使用例: mode.addResource(machine,{(0,"inf"):1},"max") max は並列処理を行う時も資源は1単位使用
モードメソッド(2)
資源クラス ー Resource (1)
• resource の引数と引数のデフォルト値resource (name=' ', capacity= {} , rhs=0, direction='<=') – name : 資源の名前,文字列で入力– capacity : 再生可能資源の最大容量 ; 区間と容量の辞書で入力
正数値を入力すると,開始時刻 0 ,終了時刻 “ inf” に変換
– rhs : 再生不能資源の制約– direction : 再生不能資源制約の向き "<=" or ">="
• resource のメソッド (次のページで詳しく)– addCapacity(start=0, finish=0, amount=1)
資源に容量を追加– addTerms(coeffs=[], vars=[], values=[])
再生不能資源に関する制約の左辺追加– printConstraint( )
再生不能資源に関する制約を展開 – setRhs(rhs=0)– 再生不能資源に関する制約の右辺追加
資源の定義を行う
資源メソッド
資源クラス ー Resource (2)
resource のメソッド– addCapacity(start=0, finish=0, amount=1)
start, finish : 資源使用開始と終了時刻amount : 資源の使用量例: manpower.addCapacity(0,5,2) 時刻 0 から時刻 5 の間に資源 (manpower) を 2 単位使
用– addTerms(coeffs=[], vars=[], values=[])
coeffs : 追加する項; リストで入力可vars : 作業オブジェクト; リストで入力可values : モードオブジェクト; リストで入力可例: budget.addTerms(1,act,express) act と言う作業が express と言うモードで行う時
再生不能資源を 1 単位追加
時間制約クラス ー Temporal
• Temporal の引数と引数のデフォルト値Temporal(pred, succ, tempType, delay) – pred : 先行作業のオブジェクト– succ : 後続作業のオブジェクト– tempType : 時間制約のタイプ; 規定値 = "CS"
• "CS"=Completion-Start, "SS"=Start-Start, "SC"= Start-Completion, "CC"=Completion-Completion
• 先行作業の終了 ( 開始 ) 時刻 +delay <= 後続作業の開始 ( 終了 ) 時刻
– delay : 先行作業と後続作業の時間ずれ; 負の数も可
時間制約の定義を行う
時間制約
A B
Temporal ( 先行作業 , 後続作業 , “ 制約タイプ” , 時間ずれ )
時間制約オブジェクトの生成法
先行作業 後続作業
Temporal(pred=A, succ=B, tempType=“CS”, delay=0)
作業 A の完了後に作業 B の開始
Completion Start
制約タイプ( type )
A B type SS
Start Start
A B type SC
Start Completion
A B type CC
Completion Completion
時間ずれ( delay )
A B
Completion Start
delay 10
10 作業 B の開始可能時間帯
A B
Completion Start
delay -10
10作業 B の開始可能時間帯
時間制約の応用 1 (同時開始)
A と B の同時開始
A の開始 +0 ≦ B の開始
B の開始 +0 ≦ A の開始A の開始 = Bの開始
モデル名 .addTemporal(A,B,"SS",0)モデル名 .addTemporal(B,A,"SS",0)
モデル名 .addTemporal( 先行作業 , 後続作業 ,“ 制約タイプ” , 時間ずれ )
• Python インターフェイスによる記述
時間制約の応用 2 (開始時間固定)
A の開始を 50 に固定
ダミーの始点( source )の開始 +50 ≦ A の開始
A の開始 =50
A の開始 -50 ≦ ダミーの始点( source )の開始
source の開始時刻は 0
モデル名 .addTemporal(source,A,"SS",50)モデル名 .addTemporal(A, source,"SS",-50)
時間制約の応用 3(最大・最小段取り時間)
A の完了後最小10 分最大 30 分でB を開始
A の終了 +10 ≦ B の開始
B の開始は A の終了 +[10,30]
B の開始 -30 ≦A の終了 B の開始≦ A の終了 +30
モデル名 .addTemporal(A,B,"CS",10)モデル名 .addTemporal(B,A,"SC",-30)
モデルクラス ー Model
• モデルクラスのメソッド – addActivity(name=‘’, duedate=‘inf’, weight=1)
モデルに作業を追加 (括弧内の引数説明は activity クラス参照)
– addResource(name=‘’, capacity={}, rhs=0, direction=‘<=’)モデルに資源を追加 (括弧内の引数説明は resource クラス参照)
– addTemporal(pred, succ, tempType=‘CS’, delay=0)モデルに先行制約を追加 (括弧内の引数説明は temporal クラス参照)
– optimize()モデルの最適化を行う
– write(filename=‘optseq.txt’)テキスト形式のガントチャートを書く
モデルを作成
パラメータクラス ー Parameters
• TimeLimit :求解する時の制限時間;単位は秒;既定値 =600 秒
• OutputFlag :モデルを出力する場合 True ,出力しない場合 False ; 既定値 =False
• Makespan :最大完了時刻最小化の時は True ,それ以外の時は False ; 既定値 =False
• RandomSeed – random seed を設定;整数;既定値 =1
よく使うパラメータ
• PERT: Program Evaluation and Review Technique,第二次世界大戦のポラリス潜水艦の建造で利用.( ORの古典)
航空機を早く離陸させよう!
22 分25 分
13 分 15 分 27 分
作業 1
作業 2
作業 3 作業 4
作業 5
ダミー作業
先行制約
作業1:乗客降ろし(13分)作業2:荷物降ろし(25分)作業3:機内清掃(15分)作業4:乗客搭乗(27分)作業5:荷物積み込み(22分)
完了時刻最小化
点が作業(活動)のグラフ -> 点上活動図式
航空機を早く離陸させよう!
作業1:乗客降ろし(13分)作業2:荷物降ろし(25分)作業3:機内清掃(15分)作業4:乗客搭乗(27分)作業5:荷物積み込み(22分)
完了時刻最小化
22 分25 分
13 分 15 分 27 分
作業 1
作業 2
作業 3 作業 4
作業 5
ダミー作業
ダミー作業
先行制約開始時刻
終了時刻
Python インターフェイスによる記述(1)
• OptSeqⅡのモジュールを読み込む
• モデルオブジェクト m1 を作成
• 作業時間を作業をキー,作業時間を値とする辞書 duration に保管
from optseq2 import *
m1=Model()
duration ={1:13, 2:25, 3:15, 4:27, 5:22 }
キー 値
Python インターフェイスによる記述(2)
• 作業を保管するための空の辞書 act を作成
• モードを保管するための空の辞書 mode を作成
act={}
mode={}
Python インターフェイスによる記述(3)
• モデルオブジェクト m1 の addActivity(“ 作業名” ) メソッドを用いてモデルに作業を追加
• モードクラス Mode(“ モード名” , 作業時間 ) を用いてモードに必要な作業時間を入力
• addModes メソッドを用いて作業にモードを追加for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
act[i].addModes(mode[i])
Python インターフェイスによる記述(4)
• モデルに addTemporal ( 先行作業 , 後続作業 ) メソッドを用いて時間制約を追加
m1.addTemporal(act[1],act[3])
m1.addTemporal(act[2],act[4])
m1.addTemporal(act[2],act[5])
m1.addTemporal(act[3],act[4])
Python インターフェイスによる記述(5)
• m1.optimize() を入力して求解
m1.Params.TimeLimit=1 求解時の制限時間
m1.Params.OutputFlag=True モデルを出力する場合 True
m1.Params.Makespan=True 最大完了時刻最小化の時はTrue
m1.optimize()
Python インターフェイスによる記述(6)
• Python コードまとめ
from optseq2 import *
m1=Model()
duration ={1:13, 2:25, 3:15, 4:27, 5:22 }
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
act[i].addModes(mode[i])
m1.addTemporal(act[1],act[3])
m1.addTemporal(act[2],act[4])
m1.addTemporal(act[2],act[5])
m1.addTemporal(act[3],act[4])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
Python インターフェイスによる記述(7)
• 実行結果(一部)source ---: 0 0 ダミーの始点の開始時刻が0
sink ---: 55 55 ダミーの終点の開始時刻が55(完了時刻)
activity[1] ---: 0 0--13 13 作業1は0に開始されて13に終了
activity[2] ---: 0 0--25 25 作業2は0に開始されて25に終了
activity[3] ---: 13 13--28 28 作業3は13に開始されて28に終了
activity[4] ---: 28 28--55 55 作業4は28に開始されて55に終了
activity[5] ---: 25 25--47 47 作業5は25に開始されて47に終了
objective value = 55 目的関数
cpu time = 0.00/1.00(s) 計算時間
iteration = 1/15962 反復回数
航空機を早く離陸させよう!最適解
13分
1作 業15分
3作 業27分
4作 業
25分
2作 業22分
5作 業
時 間0 55
航空機を早く離陸させよう!
作業1:乗客降ろし(13分)作業2:荷物降ろし(25分)作業3:機内清掃(15分)作業4:乗客搭乗(27分)作業5:荷物積み込み(22分)
完了時刻最小化
22 分25 分
13 分 15 分 27 分
作業 1
作業 2
作業 3 作業 4
作業 5
ダミー作業
ダミー作業
先行制約開始時刻
終了時刻
作業員1人
Python インターフェイスによる記述(1)•資源(この例題の場合は作業員)制約の記述:
モデル名 .addResource ( “資源名” , {( 時刻 1, 時刻 2):供給量 } )
•モードに資源使用量追加:
モード名 .addResource ( 資源 ,{( 資源使用可能区間 ): 使用量 } )
r e s=m1. addResource ( "worker " , {(0 , " i n f " ) : 1} )
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
Python インターフェイスによる記述(2)
• Python コードまとめfrom optseq2 import *
m1=Model()
duration ={1:13, 2:25, 3:15, 4:27, 5:22 }
res=m1.addResource("worker",capacity={(0,"inf"):1})
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
m1.addTemporal(act[1],act[3])
m1.addTemporal(act[2],act[4])
m1.addTemporal(act[2],act[5])
m1.addTemporal(act[3],act[4])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
Python インターフェイスによる記述(3)
source ---: 0 0sink ---: 102 102activity[1] ---: 47 47--60 60activity[2] ---: 0 0--25 25activity[3] ---: 60 60--75 75activity[4] ---: 75 75--102 102activity[5] ---: 25 25--47 47
objective value = 102cpu time = 0.00/3.00(s)iteration = 0/64983
• 実行結果(一部)
並列ショップスケジューリングピットイン時間を短縮せよ!
gas
4
4
4
4
2
3
2
2
2
11作業1
作業2
作業3
作業4
作業5
作業6
作業7
作業8
作業9
作業10
秒
秒
秒
秒
秒
秒
秒
秒
秒
秒
3人のピットクルー(資源制約)
資源(機械)制約があると難しい!
Python インターフェイスによる記述(1)3人の作業員記述:資源制約モデル名 .addResource ( " 資源名
",( 時刻 1, 時刻 2):供給量 ) の供給量を 3 に設定
from optseq2 import *m1=Model() duration ={1:3, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:11, 10:2 }res=m1.addResource("worker",capacity={(0,"inf"):3})act={}mode={} for i in duration: act[i]=m1.addActivity("Act[%s]"%i) mode[i]=Mode("Mode[%s]"%i,duration[i]) mode[i].addResource(res,{(0,"inf"):1}) act[i].addModes(mode[i])
Python インターフェイスによる記述(2)
時間制約
求解実行
m1.addTemporal(act[1],act[9])for i in range(5,9): m1.addTemporal(act[4],act[i]) m1.addTemporal(act[i],act[10])
m1.Params.TimeLimit=1m1.Params.OutputFlag=Truem1.Params.Makespan=Truem1.optimize()
Python インターフェイスによる記述(3)• Python コードまとめ
from optseq2 import *
m1=Model()
duration ={1:3, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:11, 10:2 }
res=m1.addResource("worker",capacity={(0,"inf"):3})
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
m1.addTemporal(act[1],act[9])
for i in range(5,9):
m1.addTemporal(act[4],act[i])
m1.addTemporal(act[i],act[10])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
source ---: 0 0sink ---: 14 14prepare ---: 0 0--3 3water ---: 0 0--2 2front ---: 0 0--2 2jackup ---: 2 2--4 4tire1 ---: 8 8--12 12tire2 ---: 4 4--8 8tire3 ---: 8 8--12 12tire4 ---: 4 4--8 8oil ---: 3 3--14 14jackdown ---: 12 12--14 14
objective value = 14cpu time = 0.00/3.00(s)iteration = 0/37644
Python インターフェイスによる記述(4)
• 実行結果(一部)
並列ショップスケジューリング- 複数モード -
3人のピットクルー(資源制約)
資源(機械)制約があると難しい!
gas
WATER
4
4
4
4
2
3
2
2
2
11
作業1
作業2
作業3
作業4
作業5
作業6
作業7
作業8
作業9
作業10
秒
秒
秒
秒
秒
秒
秒
秒
秒
秒
1人 3秒2人 2秒3人 1秒
並列ショップスケジューリング 2 - モードの概念と使用法 -
コンビニモード:作業時間 20 分,お金資源 120 円,人資源 1 人
自販機モード:作業時間 5 分,お金資源 120 円,人資源 1 人
スーパーモード:作業時間 40 分,お金資源 100 円,人資源 1 人,車資源 1 台
モード:作業を行うための処理方法
例: 作業 「ジュースを買う」
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
if i==1:
mode[1,1]=Mode("Mode[1_1]",3)
mode[1,1].addResource(res,{(0,"inf"):1})
mode[1,2]=Mode("Mode[1_2]",2)
mode[1,2].addResource(res,{(0,"inf"):2})
mode[1,3]=Mode("Mode[1_3]",1)
mode[1,3].addResource(res,{(0,"inf"):3})
act[i].addModes(mode[1,1],mode[1,2],mode[1,3])
else:
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
作業1のモード1
作業1のモード1に資源を追加
作業1にモード1,モード2,モード3
を追加
• 多モードの記述
Python インターフェイスによる記述(1)
Python インターフェイスによる記述(2)
• Python コードまとめ(1)
from optseq2 import *
m1=Model()
duration ={1:3, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:11, 10:2 }
res=m1.addResource("worker",capacity={(0,"inf"):3})
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
if i==1:
mode[1,1]=Mode("Mode[1_1]",3)
mode[1,1].addResource(res,{(0,"inf"):1})
mode[1,2]=Mode("Mode[1_2]",2)
mode[1,2].addResource(res,{(0,"inf"):2})
mode[1,3]=Mode("Mode[1_3]",1)
mode[1,3].addResource(res,{(0,"inf"):3})
act[i].addModes(mode[1,1],mode[1,2],mode[1,3])
else:
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
m1.addTemporal(act[1],act[9])
for i in range(5,9):
m1.addTemporal(act[4],act[i])
m1.addTemporal(act[i],act[10])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
Python インターフェイスによる記述(3)
• Python コードまとめ(2)
Python インターフェイスによる記述(4)
計算結果とガントチャート
objective value = 13
cpu time = 0.00/1.00(s)
iteration = 7/7343
source --- 0 0
sink --- 13 13
Act[1] Mode[1_3] 0 1
Act[2] --- 1 3
Act[3] --- 11 13
Act[4] --- 1 3
Act[5] --- 7 11
Act[6] --- 3 7
Act[7] --- 7 11
Act[8] --- 3 7
Act[9] --- 1 12
Act[10] --- 11 13
planning horizon= 13
資源制約付きスケジュールングお家を早く造ろう!
土台
1階
内装
屋根
完成!
時間(日)
資源量(人)
30
2人
1人の作業員休暇
作業時間=2日1日目1人,2日目2人の資源が必要!
最適解
時 間 ( 日 )
資 源 量 ( 人 )
資源制約付きスケジューリングは一般的なモデル(ジョブショップ,並列ショップスケジューリングを特殊形として含む.)
Python インターフェイスによる記述(1)
• 資源の必要量入力m1=Model()
duration ={1:1,2:3,3:2,4:2}
req={}
req[1]={(0,1):2 }
req[2]={(0,1):2 ,(1,3):1}
req[3]={(0,2):1 }
req[4]={(0,1):1,(1,2):2 }
res=m1.addResource("worker")
res.addCapacity(0,2,2)
res.addCapacity(2,3,1)
res.addCapacity(3,"inf",2)
{(0,1):2 }
{( 開始時刻,終了時刻 ): 資源必要量 }
土台造り ( req[1] )は1日目に資源(人)が2単位必要
(0,2,2)
(開始時刻,終了時刻,資源容量) 最初の2日間は資源(人)が
2単位使用可能
• 資源の容量制約入力
Python インターフェイスによる記述(2)• Python コードまとめ
from optseq2 import *
m1=Model()
duration ={1:1,2:3,3:2,4:2}
req={}
req[1]={(0,1):2 }
req[2]={(0,1):2 ,(1,3):1}
req[3]={(0,2):1 }
req[4]={(0,1):1,(1,2):2 }
res=m1.addResource("worker")
res.addCapacity(0,2,2)
res.addCapacity(2,3,1)
res.addCapacity(3,"inf",2)
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,req[i])
act[i].addModes(mode[i])
m1.addTemporal(act[1],act[2])
m1.addTemporal(act[1],act[3])
m1.addTemporal(act[2],act[4])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
Python インターフェイスによる記述(3)
objective value = 6cpu time = 0.00/1.00(s)iteration = 1/6936
source --- 0 0sink --- 6 6Act[1] --- 0 1Act[2] --- 1 4Act[3] --- 3 5Act[4] --- 4 6planning horizon= 6
• 実行結果(一部)
1機械スケジュールング納期遅れを最小にしよう!
• 完了時刻最小化(メイクスパン)以外の目的関数の例– 納期遅れ最小化– 納期ずれ最小化– 納期遅れした作業(ジョブ)数最小化– 納期遅れの最大値の最小化– 上の指標の重み付きの尺度最小化 ....会社名 A社 B社 C社 D社
作業時間 1日 2日 3日 4日
納期 5日後 9日後 6日後 4日後
Python インターフェイスによる記述(1)
納期を辞書に保管 due={1:5,2:9,3:6,4:4}
.......
for i in req: act[i]=m1.addActivity("Act[%s]"%i,duedate=due[i])
mode[i]=Mode("Mode[%s]"%i,req[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
• 納期に関する入力
納期を作業に追加
Python インターフェイスによる記述(2)
• Python コードまとめ
from optseq2 import *
m1=Model()
due={1:5,2:9,3:6,4:4}
req={1:1, 2:2, 3:3, 4:4 }
res=m1.addResource("writer")
res.addCapacity(0,"inf",1)
act={}
mode={}
for i in req: act[i]=m1.addActivity("Act[%s]"%i,duedate=due[i])
mode[i]=Mode("Mode[%s]"%i,req[i])
mode[i].addResource(res,{(0,"inf"):1})
act[i].addModes(mode[i])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=False
m1.optimize()
--- best solution ---source,---, 0 0sink,---, 10 10Act[1],---, 4 4--5 5Act[2],---, 8 8--10 10Act[3],---, 5 5--8 8Act[4],---, 0 0--4 4
--- tardy activity ---Act[2]: 1Act[3]: 2
時 間 ( 日 )
010
1(A作 業 社 ) 2 B作 業 ( 社 ) 3 C作 業 ( 社 ) 4 D作 業 ( 社 )
A社 納 期C社 納 期D社 納 期 B社 納 期
納 期 遅 れ 納 期 遅 れ
会社名 A社 B社 C社 D社
作業時間
1日 2日 3日 4日
納期 5日後 9日後 6日後 4日後
Python インターフェイスによる記述(3)
• 実行結果(一部)
航空機をもっと早く離陸させよう !
作業 1 :乗客降ろし 13 分. 10 分に短縮可能で, 1 万円必要.作業 2 :荷物降ろし 25 分. 20 分に短縮可能で, 1万円必要.作業 3 :機内清掃 15 分. 10 分に短縮可能で, 1万円必要.作業 4 :新しい乗客の搭乗 27 分. 25 分に短縮可能で, 1万円必要.作業 5 : 新しい荷物積み込み 22 分. 20 分に短縮可能で, 1万円必要.
クリティカルパス法 ( critical path method ,略して CPM )
作業時間を費用をかけることによって短縮できる
再生不能資源(使用可能なお金) 4 万万円以下
再生可能資源と再生不能資源
• 再生可能資源作業完了後に再び使用可能になる資源機械や作業員など
• 再生不能資源一度使うとなくなってしまう資源(計画期間内での合計に制約を設ける)お金や原材料など
クリティカルパス法の予算を再生不能資源として扱う!
Python インターフェイスによる記述(1)
通常時の作業時間
再生不能資源使用時の作業時間
m1=Model()
durationA = {1:13, 2:25, 3:15, 4:27, 5:22 }
durationB = {1:10, 2:20, 3:10, 4:25, 5:20 }
act={}
mode={}
res=m1.addResource("money",rhs=4,direction="<=")
• 再生不能資源に関する入力(1)
再生不能資源使用可能量制約
Python インターフェイスによる記述(2)
• Python コードまとめm1.addTemporal(act[1],act[3])
m1.addTemporal(act[2],act[4])
m1.addTemporal(act[2],act[5])
m1.addTemporal(act[3],act[4])
print m1
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
from optseq2 import *
m1=Model()
durationA = {1:13, 2:25, 3:15, 4:27, 5:22 }
durationB = {1:10, 2:20, 3:10, 4:25, 5:20 }
act={}
mode={}
res=m1.addResource("money",rhs=4,direction="<=")
for i in durationA:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i,1]=Mode("Mode[%s][1]"%i,durationA[i])
mode[i,2]=Mode("Mode[%s][2]"%i,durationB[i])
act[i].addModes(mode[i,1],mode[i,2])
res.addTerms(1,act[i],mode[i,2])
結果
10分
1作業
13分
1作業
10分
3作業
10分
3作業
25分
4作業
27分
4作業
20分
2作業
25分
2作業
22分
5作業
22分
5作業
時間
時間
0
0
45
13分
1作業15分
3作業27分
4作業
25分
2作業22分
5作業
時間0 55
52
4万円
1万円
0万円
並列ショップスケジューリング
3人のピットクルー(資源制約)
資源(機械)制約があると難しい!
gas
WATER
4
4
4
4
2
3
2
2
2
11
作業1
作業2
作業3
作業4
作業5
作業6
作業7
作業8
作業9
作業10
秒
秒
秒
秒
秒
秒
秒
秒
秒
秒
1人 3秒2人 2秒3人 1秒
複数モード 複数資源による作業の並列処理
Python インターフェイスによる記述(1)
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
if i==1:
mode[i].addParallel(1,1,3)
act[i].addModes(mode[i])
• 並列処理入力
1 番目の小作業を 3 単位並列可能
Python インターフェイスによる記述(2)• Python コードまとめ
m1.addTemporal(act[1],act[9])
for i in range(5,9):
m1.addTemporal(act[4],act[i])
m1.addTemporal(act[i],act[10])
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
from optseq2 import *
m1=Model()
duration ={1:3, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:11, 10:2 }
res=m1.addResource("worker")
res.addCapacity(0,"inf",3)
act={}
mode={}
for i in duration:
act[i]=m1.addActivity("Act[%s]"%i)
mode[i]=Mode("Mode[%s]"%i,duration[i])
mode[i].addResource(res,{(0,"inf"):1})
if i==1:
mode[i].addParallel(1,1,3)
act[i].addModes(mode[i])
ジョブショップスケジューリンングジョブ(作業)ごとに機械(工程)順が異なっても良い!
5
1 0
1 3
9
4
11
9
1 2
9
7
3
6
機械 作業機械3
機械1
機械2
機械1
機械1
機械1
機械2
機械2
機械2
機械3
機械3
機械3
作業 1
作業 2
作業 3
作業 4
小作業 1 小作業 2 小作業 3
ジョブショップスケジューリンング
• 各作業は,最初の2日間は作業員の作業が必要• 各作業は小作業 1,2,3 の順に処理される• 各作業は1日目の作業後休むことが可能• 作業員は平日(週5日間)のみ作業可能• 作業員は1日最大2人作業可能• 機械1の最初の2日間分の作業は並列処理可能• 機械2は express モードで処理可能;処理時間は4日
間に短縮可能• express モードは最大1回しか使用できない• 機械1での作業2は,作業1が完了した直後に行う
(他の作業が間に入らない)
manpower=m1.addResource("manpower")
for t in range(9):
manpower.addCapacity(t*7,t*7+5,2) # 作業員は平日のみ作業可能;平日の作業可能な作業員上限2人
machine={}
for j in range(1,4):
machine[j]=m1.addResource("machine[%s]"%j,capacity={(0,"inf"):1}) # 3種類の機械;各機械は1つの作業しか処理できない
Python インターフェイスによる記述(1)
• 作業員に関する制約
• 機械に関する制約
JobInfo={ (1,1):(1,7), (1,2):(2,10), (1,3):(3,4),
(2,1):(3,9), (2,2):(1,5), (2,3):(2,11),
(3,1):(1,3), (3,2):(3,9), (3,3):(2,12),
(4,1):(2,6), (4,2):(3,13), (4,3):(1,9) }
Python インターフェイスによる記述(2)
(1,1): (1,7) は作業1の子作業1の機械1での作業時間が7日であること
• 作業と機械
1047
作業1小作業1 小作業2 小作業3
budget=m1.addResource(“budget_constraint”,rhs=1) # express モードが1回しか使え
ないことを資源( budget )の使用可能量 (rhs) =1 で表現
express=Mode("Express",duration=4) # express の作業時間は4日
express.addResource(machine[2],{(0,"inf"):1},"max") # express は機械2を1単位使用
express.addResource(manpower,{(0,2):1}) # 最初の2期の間は作業員が1人必要
express.addBreak(1,1) # 各作業は1日目作業後休憩可能
Python インターフェイスによる記述(3)
• 機械2は express モードで処理可能
express.addResource(machine[2],{(0,"inf"):1},"max")資源タイプ“ max” :並列作業時も機械は1単位しか使用しない
資源タイプ
for (i,j) in JobInfo:
act[i,j]=m1.addActivity(“Act[%s][%s]”%(i,j)) # (作業名)
mode[i,j]=Mode(“Mode[%s][%s]”%(i,j),duration=JobInfo[i,j][1])#モード名 , 作業時間追加 mode[i,j].addResource(machine[JobInfo[i,j][0]],{(0,“inf”):1},“max”)
mode[i,j].addResource(manpowe):1}) # 最初の2期の間は作業員が1人必要
mode[i,j].addBreak(1,1) # 各作業は1日目作業後休憩可能
if JobInfo[i,j][0]==1:
mode[i,j].addParallel(1,1,2) # 機械1での各小作業は並列処理可能
if JobInfo[i,j][0]==2:
act[i,j].addModes(mode[i,j],express) # 機械2に express モードを追加
budget.addTerms(1,act[i,j],express) # express モードは最大1回しか使用できない
else:
act[i,j].addModes(mode[i,j])
Python インターフェイスによる記述(4)
• 作業にモード追加
Python インターフェイスによる記述(5)
for i in range(1,5):
for j in range(1,3):
m1.addTemporal(act[i,j],act[i,j+1])
• 各作業は子作業 1,2,3 の作業順で処理される
5
1 0
1 3
9
4
11
9
1 2
9
7
3
6
作業1
小作業1 小作業2 小作業3
小作業1 小作業2 小作業3
小作業1 小作業2 小作業3
小作業1 小作業2 小作業3
作業2
作業3
作業4
Python インターフェイスによる記述(6)
d_act=m1.addActivity(“dummy_activity”) # ダミーの作業を追加
d_mode=Mode(“dummy_mode”) # ダミーのモードを追加
d_mode.addBreak(0,0) # 作業開始時刻から無限に休憩可能
d_mode.addResource(machine[1],{(0,0):1},“break”) # 休憩中にも資源を使用
d_act.addModes(d_mode) # 作業にモードを追加
機械1での作業2は,作業1が完了した直後に行う(他の作業が間に入らない)
1. ダミーの作業を生成
資源使用量
期
作業時間 0 のダミーの作業
作業開始時刻から無限に休憩可能
休憩中にも資源を使用
Python インターフェイスによる記述(6)
m1.addTemporal(act[1,1],d_act,tempType=“CS”) #(1)
m1.addTemporal(d_act,act[1,1],tempType="SC") #(2)
m1.addTemporal(d_act,act[2,2],tempType="CS") #(3)
m1.addTemporal(act[2,2],d_act,tempType="SC") #(4)
2. 時間制約追加
期
ダミー作業は休憩中にも資源を使用act[1,1] act[2,2]
(1) 作業 1 の小作業 1(act[1,1]) が終了しないとダミー作業 (d_act) が開始できない
(2) ダミー作業 (d_act) が開始しないと作業 1 の小作業 1 (act[1,1]) が終了できない
(3) , (4) も (1) , (2) と同様
ダミー作業
資源使用量
結論: 作業 1 の小作業 1 はダミー作業の直後に開始
ダミー作業は作業 1 の小作業 1 の直後に開始
Python インターフェイスによる記述(7)
• Python コードまとめ(1)from optseq2 import *
m1=Model()
machine={}
for j in range(1,4):
machine[j]=m1.addResource("machine[%s]"%j,capacity={(0,"inf"):1})
manpower=m1.addResource("manpower")
for t in range(9):
manpower.addCapacity(t*7,t*7+5,2)
budget=m1.addResource("budget_constraint",rhs=1)
JobInfo={ (1,1):(1,7), (1,2):(2,10), (1,3):(3,4),
(2,1):(3,9), (2,2):(1,5), (2,3):(2,11),
(3,1):(1,3), (3,2):(3,9), (3,3):(2,12),
(4,1):(2,6), (4,2):(3,13), (4,3):(1,9) }
act={}
Python インターフェイスによる記述(8)
• Python コードまとめ(2)
express=Mode("Express",duration=4)
express.addResource(machine[2],{(0,"inf"):1},"max")
express.addResource(manpower,{(0,2):1})
express.addBreak(1,1)
mode={}
for (i,j) in JobInfo:
act[i,j]=m1.addActivity("Act[%s][%s]"%(i,j))
mode[i,j]=Mode("Mode[%s][%s]"%(i,j),
duration=JobInfo[i,j][1])
mode[i,j].addResource (
machine[JobInfo[i,j][0]],{(0,"inf"):1},"max")
mode[i,j].addResource(manpower,{(0,2):1})
mode[i,j].addBreak(1,1)
if JobInfo[i,j][0]==1:
mode[i,j].addParallel(1,1,2)
if JobInfo[i,j][0]==2:
act[i,j].addModes(mode[i,j],express)
budget.addTerms(1,act[i,j],express)
else:
act[i,j].addModes(mode[i,j])
Python インターフェイスによる記述(9)
• Python コードまとめ(3)for i in range(1,5):
for j in range(1,3):
m1.addTemporal(act[i,j],act[i,j+1])
d_act=m1.addActivity("dummy_activity")
d_mode=Mode("dummy_mode")
d_mode.addBreak(0,0)
d_mode.addResource(machine[1],{(0,0):1},"break")
d_act.addModes(d_mode)
m1.addTemporal(act[1,1],d_act,tempType="CS")
m1.addTemporal(d_act,act[1,1],tempType="SC")
m1.addTemporal(d_act,act[2,2],tempType="CS")
m1.addTemporal(act[2,2],d_act,tempType="SC")
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()
時刻によって変化可能
• 段取り替えを表現
• 特定の時刻になると仕事を開始する– 例:毎週月曜日にしか開始できない仕事を表現
状態1
A1 A2 B1
段取り替え 段取り替え生産ライン
1 時間 5 時間
日1 8 15 22
• モデルに状態メソッドを追加– 引数は状態の名称を表す文字列,返値は状態オブジェ
クト– addState(name= ' ' )
• モードに状態メソッドを追加– モード実行時における状態の値と状態の実行直後(実
行開始が時刻 t のときには,時刻 t+1 )の状態の値を定義する
– addState(state, fromValue=0, toValue=0)• state :モードに付随する状態オブジェクト,省略不可• fromValue :モード実行時における状態の値,省略可,規定値
は 0
• toValue :状態の実行直後の値,省略可,規定値は 0
状態2
autoselect
状態オブジェクトに addValue (初期状態)
状態(例題)
A タイプ
A タイプ
B タイプ
段取り替え 段取り替え機械
1 時間 5 時間
処理時間3 時間
処理時間3 時間
目的: 最大完了時刻最小化
機械( 1台)
A1 A2 B1A3 B2 B3作業( 6 つ)
A タイプ B タイプ
Python インターフェイスによる記述(1)
from optseq2 import *
m1=Model()
duration={(1,1):3,(1,2):3,(1,3):3,(2,1):3,(2,2):3,(2,3):3} # 作業時間
setup={(1,1):1,(1,2):5,(2,1):5,(2,2):1} # 段取り時間
act={} # 作業
act_setup={} # 段取り作業
mode={} # 作業モード
mode_setup={} # 段取りモード
rs=m1.addResource(“machine”,1) # 機械資源
s1=m1.addState(“Setup_State”) # モデルに状態を追加
s1.addValue(time=0,value=1) # 時刻 0 の状態は 1 (状態 1 は作業 A の状態)
Python インターフェイスによる記述(2)for (i,j) in setup:
mode_setup[i,j]=Mode(" Mode_setup " +str(i)+str(j),setup[i,j]) # 段取りモード作成
mode_setup[i,j].addState(s1,i,j) # 段取りモードに状態を追加(状態 2 は作業 Bの状態)
mode_setup[i,j].addResource(rs,{(0, " inf "):1}) # 段取りのとき機械資源1を使用
for (i,j) in duration:
act_setup[i,j]=m1.addActivity("Setup" +str(i)+str(j),autoselect=True) # 段取り作業作成
act_setup[i,j].addModes(mode_setup[1,i],mode_setup[2,i]) # 段取り作業にモード追加
act[i,j]=m1.addActivity(" Act " +str(i)+str(j)) # 作業作成
mode[i,j]=Mode(" Mode "+str(i)+str(j),duration[i,j]) # 作業にモード追加
mode[i,j].addResource(rs,{(0,"inf"):1}) # 作業にードに資源追加
mode[i,j].addBreak(0,0) # 作業は中断可能
mode[i,j].addResource(rs,{(0,"inf"):1},"break") # 作業の中断中も資源使用
act[i,j].addModes(mode[i,j]) # 作業にモード追加
Python インターフェイスによる記述(3)
for (i,j) in duration: # 先行制約追加
m1.addTemporal(act_setup[i,j],act[i,j],"CS")
m1.addTemporal(act[i,j],act_setup[i,j],"SC")
m1.Params.TimeLimit=1
m1.Params.OutputFlag=True
m1.Params.Makespan=True
m1.optimize()