820 likes | 884 Views
スケジューリング最適化システム OptSeq II Python モジュールの使い方 補助資料: OptSeq II によるスケジューリング入門 トライアルバージョン http://www.logopt.com/OptSeq/OptSeq.htm. スケジューリングモデルとは. 作業( activity ;活動) :遂行すべき仕事のこと.別名,オペレーション( operation ),ジョブ,仕事 (job) ,タスク (task) .作業時間や納期の情報が付加される.
E N D
スケジューリング最適化システムOptSeq IIPythonモジュールの使い方補助資料: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) モードメソッド(1) • addBreak メソッド addBreak(start=0, finish=0, maxtime=‘inf’) • start,finish: 休憩開始時間,休憩終了時間 • maxtime: 最大休憩可能時間 • addParallel メソッド addParallel(start=1, finish=1, maxparallel=‘inf’) • start,finish: 並列開始小作業番号,並列終了小作業番号 • maxparallel: 最大並列数
作業の途中中断 • Pythonインターフェイスによる記述 モード名.addBreak(中断開始時刻,中断終了時刻,最大中断時間) 作業Aが,0から3の区間でそれぞれ最大1中断可能: モード名.addBreak(0,3,1) 開始から2時刻で中断した例
作業の並列処理 • Pythonインターフェイスによる記述 モード名.addParallel(開始小作業番号,終了小作業番号,最大並列数) 作業1(作業時間は3秒)を最大3単位並列可能: モード名.addParallel(1,1,3) 作業1 小作業1,小作業1
並列処理の結果 • 1番目の小作業を3単位並列可能: 1 2 3
モードクラス ー Mode(3) モードメソッド(2) • 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単位使用
資源クラス ー 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 : 先行作業と後続作業の時間ずれ; 負の数も可
時間制約 時間制約オブジェクトの生成法 Temporal (先行作業 , 後続作業 , “制約タイプ” , 時間ずれ) Completion Start A B 後続作業 先行作業 作業Aの完了後に作業Bの開始 Temporal(pred=A, succ=B, tempType=“CS”, delay=0)
制約タイプ(type) Start Start type SS A B Start Completion type SC A B Completion Completion type CC A B
時間ずれ(delay) Completion Start A B delay 10 作業Bの開始可能時間帯 10 Completion Start A B delay -10 作業Bの開始可能時間帯 10
時間制約の応用 1(同時開始) • Pythonインターフェイスによる記述 モデル名.addTemporal(先行作業,後続作業,“制約タイプ”,時間ずれ) モデル名.addTemporal(A,B,"SS",0) モデル名.addTemporal(B,A,"SS",0) AとBの同時開始 Aの開始+0 ≦ Bの開始 Aの開始=Bの開始 Bの開始+0 ≦ Aの開始
時間制約の応用 2(開始時間固定) モデル名.addTemporal(source,A,"SS",50) モデル名.addTemporal(A, source,"SS",-50) Aの開始を50に 固定 ダミーの始点(source)の開始+50 ≦ Aの開始 Aの開始-50 ≦ダミーの始点(source)の開始 sourceの開始時刻は0 Aの開始=50
時間制約の応用 3(最大・最小段取り時間) Aの完了後最小 10分最大30分で Bを開始 モデル名.addTemporal(A,B,"CS",10) モデル名.addTemporal(B,A,"SC",-30) Aの終了+10 ≦ Bの開始 Bの開始≦ Aの終了+30 Bの開始-30 ≦Aの終了 Bの開始はAの終了+[10,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の古典) 航空機を早く離陸させよう! 作業1 15分 13分 27分 作業2 25分 22分 作業4 作業3 完了時刻最小化 ダミー作業 先行制約 作業5 作業1:乗客降ろし(13分) 作業2:荷物降ろし(25分) 作業3:機内清掃(15分) 作業4:乗客搭乗(27分) 作業5:荷物積み込み(22分) 点が作業(活動)のグラフ->点上活動図式
航空機を早く離陸させよう! 作業4 作業3 作業1 15分 13分 27分 ダミー作業 先行制約 作業2 作業5 ダミー作業 25分 22分 完了時刻最小化 開始時刻 終了時刻 作業1:乗客降ろし(13分) 作業2:荷物降ろし(25分) 作業3:機内清掃(15分) 作業4:乗客搭乗(27分) 作業5:荷物積み込み(22分)
duration ={1:13, 2:25, 3:15, 4:27, 5:22 } キー 値 Pythonインターフェイスによる記述(1) • OptSeqⅡのモジュールを読み込む • モデルオブジェクトm1 を作成 • 作業時間を作業をキー,作業時間を値とする辞書duration に保管 from optseq2 import * m1=Model()
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 反復回数
航空機を早く離陸させよう! 作業4 作業3 作業1 15分 13分 27分 ダミー作業 先行制約 作業2 作業5 ダミー作業 25分 22分 完了時刻最小化 開始時刻 終了時刻 作業1:乗客降ろし(13分) 作業2:荷物降ろし(25分) 作業3:機内清掃(15分) 作業4:乗客搭乗(27分) 作業5:荷物積み込み(22分) 作業員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コードまとめ 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() 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])
Pythonインターフェイスによる記述(3) • 実行結果(一部) source ---: 0 0 sink ---: 102 102 activity[1] ---: 47 47--60 60 activity[2] ---: 0 0--25 25 activity[3] ---: 60 60--75 75 activity[4] ---: 75 75--102 102 activity[5] ---: 25 25--47 47 objective value = 102 cpu time = 0.00/3.00(s) iteration = 0/64983
並列ショップスケジューリングピットイン時間を短縮せよ!並列ショップスケジューリングピットイン時間を短縮せよ! 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=1 m1.Params.OutputFlag=True m1.Params.Makespan=True m1.optimize()
Pythonインターフェイスによる記述(3) • 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",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インターフェイスによる記述(4) • 実行結果(一部) source ---: 0 0 sink ---: 14 14 prepare ---: 0 0--3 3 water ---: 0 0--2 2 front ---: 0 0--2 2 jackup ---: 2 2--4 4 tire1 ---: 8 8--12 12 tire2 ---: 4 4--8 8 tire3 ---: 8 8--12 12 tire4 ---: 4 4--8 8 oil ---: 3 3--14 14 jackdown ---: 12 12--14 14 objective value = 14 cpu time = 0.00/3.00(s) iteration = 0/37644
並列ショップスケジューリング- 複数モード - gas 3 秒 作業1 W A T E R 作業9 11 2 秒 秒 作業2 作業5 4 秒 2 秒 作業6 4 作業3 秒 2 秒 作業7 4 作業10 秒 作業8 2 4 秒 秒 作業4 1人 3秒 2人 2秒 3人 1秒 3人のピットクルー (資源制約) 資源(機械)制約 があると難しい!
並列ショップスケジューリング 2 - モードの概念と使用法 - モード:作業を行うための処理方法 例: 作業 「ジュースを買う」 コンビニモード:作業時間 20 分,お金資源 120 円,人資源 1人 自販機モード:作業時間 5 分,お金資源 120 円,人資源 1人 スーパーモード:作業時間 40 分,お金資源 100 円,人資源 1人,車資源 1 台
Pythonインターフェイスによる記述(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インターフェイスによる記述(2) • Pythonコードまとめ(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]) 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={}
Pythonインターフェイスによる記述(3) • 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=1 m1.Params.OutputFlag=True m1.Params.Makespan=True m1.optimize()
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 計算結果とガントチャート
資源制約付きスケジュールングお家を早く造ろう!資源制約付きスケジュールングお家を早く造ろう! 作業時間=2日1日目1人,2日目2人の資源が必要! 1階 屋根 土台 1人の作業員休暇 完成! 資源量(人) 2人 内装 0 3 時間(日)
最適解 資源制約付きスケジューリングは一般的なモデル (ジョブショップ,並列ショップスケジューリングを特殊形として含む.)
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単位使用可能