Top Banner
Python を用いた 最適化ソルバー Gurobi 入門 東京海洋大学 久保 幹雄
65

Gurobi python

Jul 05, 2015

Download

Education

Mikio Kubo
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Gurobi python

Pythonを用いた最適化ソルバー Gurobi入門

東京海洋大学

久保 幹雄

Page 2: Gurobi python

Why Python?• モジュールを読み込めば何でもできる!

• 最適化もできる!import gurobipy (MIP)import SCOP (CP)

• グラフも描ける!import networkXimport matplotlib

• 空を飛ぶことも!?import antigravity ?

http://xkcd.com/353/

Page 3: Gurobi python

Python 1ページ解説複合型

– リスト:任意の要素から成る順序型A=[] これだけで,スタック,キュー,連結リスト,ソート

A.append(5), a=A.pop(), A.remove(“6”), A.sort()

– 辞書: キーと 値の組から構成されるマップ型D= { }Hash 関数と同じ.何でも辞書で高速に保管できる!D[(1,2)] =6, D[“Hello”]=“ ”こんにちは

反復 for i in [1,2,5,6]: for key in D: print i*2 print key,D[key]

=> 2,4,10,12 =>キーと値を出力

Page 4: Gurobi python

混合整数計画とはMixed Integer Programming (MIP)

• 変数( Variables) x : 実数,整数, 0-1整数変数( Binary )

• 制約( Constraints) 線形 or (凸 ) 二次制約

minimize c’x+x’Qx (目的関数 )subject to Ax=b (制約 )

Page 5: Gurobi python

What’s Gurobi?

MIP solver Developed by: Zonghao Gu, Edward Rothberg , Robert Bixby

Current version 4.6.1Free academic license

Page 7: Gurobi python

• 変数オブジェクトの追加x1 = model.addVar(name="x1")x2 = model.addVar(name="x2")x3 = model.addVar(name="x3")

• モデルの更新 (制約を追加する前には必須.怠惰な更新 (lazy update);高速化のための仕様. )model.update()

Gurobi 入門 (2)

Page 8: Gurobi python

Gurobi 入門 (3)

• 目的関数の設定model.setObjective(15*x1 + 18*x2 + 30*x3, GRB.MAXIMIZE)

• 制約の追加model.addConstr(2*x1 + x2 + x3 <= 60)model.addConstr(x1 + 2*x2 + x3 <= 60)model.addConstr(x3 <= 30)

• 最適化model.optimize()

Page 9: Gurobi python

リストを用いたモデル化• 変数オブジェクトをリストに追加

x=[  ] for i in range(1,4): var=model.addVar(name=“x[%s]”%i) x.append(var)

• 制約 “ x1 + x2 + x3 <= 2” の追加model.addConstr( sum(x) <= 2 ) or model.addConstr( quicksum(x) <= 2 )

X[1] X[2] X[3] ・・・

Page 10: Gurobi python

辞書を用いたモデル化 (1)

• 辞書( Dictionary )は,ワインの種類(“ Dry”, “Medium”, “Sweet”) をキーとし,変数オブジェクトを値とした写像型 x={ } x[“Dry”]= model.addVar(name=“Dry”) x[“Medium”]= model.addVar(name=“Medium”) x[“Sweet”]= model.addVar(name=“Sweet”)

キー“Hello”, “Dry Wine”

値“ ”ニーハオ

Variable Object写

Page 11: Gurobi python

辞書を用いたモデル化 (2)

• 制約 “ 2 x1 + x2 + x3 <= 30”の追加model.addConstr( 2*x[“Dry”]+ x[“Medium”] +x[“Sweet”] <=30 )

Blends, Profit = multidictmultidict({"Dry":15, "Medium":18, "Sweet":30})

=> Blends=["Dry", "Medium“, "Sweet“] Profit[“Dry”]=15, Profit[“Medium”]=18, ...

Page 12: Gurobi python

辞書を用いたワイン製造モデル(1)

Blends, Profit = multidictmultidict({"Dry":15, "Medium":18, "Sweet":30})

=> Blends=["Dry", "Medium“, "Sweet“] List of Keys Profit[“Dry”]=15, Profit[“Medium”]=18, ...

Grapes, Inventory = multidict({"Alfrocheiro":60, "Baga":60, "Castelao":30})

Use = { ("Alfrocheiro","Dry"):2, ("Alfrocheiro","Medium"):1, ("Alfrocheiro","Sweet"):1, ("Baga","Dry"):1, .... }

Page 13: Gurobi python

辞書を用いたワイン製造モデル (2)x = {}

for j in Blends:

x[j] = model.addVar(vtype="C", name="x[%s]"%j)

model.update()

model.setObjective(quicksum(Profit[j]*x[j] for j in Blends), GRB.MAXIMIZE)

for i in Grapes:

model.addConstr(quicksum(Use[i,j]*x[j] for j in Blends) <= Inventory[i], name="use[%s]"%i)

model.optimize()

Page 14: Gurobi python

k-median問題• min-sum型の施設配置問題• 顧客数 n=200 ,施設数 k=20

(顧客上から選択)• Euclid距離, x,y座標は一様ランダム

n=200, k=5 の例

Page 16: Gurobi python

Pythonでの実装( 1)from gurobipy import * #gurobipyモジュールの読み込み

# k-medianソルバーの関数

def solve(n,k,cost):

model=Model(“median”) #モデルオブジェクトの生成

y={} #変数を表す辞書の準備

x={}

キー“Hanako”,

(1,2)

写像値

“127cm”変数オブジェクト

Page 17: Gurobi python

I=range(n)J=range(n)for j in J:

y[j] = model.addVar(vtype="B", name="y[%s]"%j)

for i in I:

x[i,j] =model.addVar( vtype="B",name="x[%s,%s]"%(i,j))

model.update()

Pythonでの実装(2)

model.setObjective(quicksum(c[i,j]*x[i,j] for i in I for j in J))

変数オブジェクトの追加“B” は 0-1整数 (binary) 変数 ( GRB.BINARYでも良い)

目的関数の設定

Page 19: Gurobi python

Pythonでの実装(4)…

model.optimize()

print “Opt.value=”,model.ObjVal

edge=[]

for (i,j) in x:

if x[i,j].X= =1:

edge.append((i,j))

return edge

Page 20: Gurobi python

Pythonでの実装(5) import networkx as NX #networkX module

import matplotlib.pyplot as P #prepare drawing

P.ion()

G = NX.Graph() #graph object

G.add_nodes_from(range(n)) #add nodes

for (i,j) in edge: #add edges

G.add_edge(i,j)

NX.draw(G)

Page 21: Gurobi python

Optimize a model with 401 Rows, 40200 Columns and 80400 NonZeros

中略

Explored 1445 nodes (63581 simplex iterations) in 67.08 seconds

Thread count was 2 (of 2 available processors)

Optimal solution found (tolerance 1.00e-04)

Best objective 1.0180195861e+01, best bound 1.0179189780e+01, gap 0.0099%

Opt.value= 10.1801958607

弱い定式化での結果n=200,k=20

Page 22: Gurobi python

上界と下界の変化

0

2

4

6

8

10

12

14

16

18

0 10 20 30 40 50 60 70

CPU

Obj

. Fun

c. V

alue

Page 23: Gurobi python

Optimize a model with 40401 Rows, 40200 Columns and 160400 NonZeros

中略

Explored 0 nodes (1697 simplex iterations) in 3.33 seconds(分枝しないで終了!)

Thread count was 2 (of 2 available processors)

Optimal solution found (tolerance 1.00e-04)

Best objective 1.0180195861e+01, best bound 1.0180195861e+01, gap 0.0%

Opt.value= 10.1801958607

強い定式化での結果

Page 24: Gurobi python

知見

• Big Mを用いない強い定式化が望ましい.

• この程度の式なら,必要な式のみを切除平面として追加するような小細工は必要なし.

(ただし,式の数が増え退化するので,大規模なLPを高速に解けるソルバーが前提)

Page 25: Gurobi python

k-center問題

• min-max型の施設配置問題• 100顧客, 10施設(顧客上から選択)• Euclid距離, x,y座標は一様ランダム

k-center (n=30,k=3) k-median (n=30,k=3)

Page 26: Gurobi python

定式化

Page 27: Gurobi python

上界と下界の変化

0

0.2

0.4

0.6

0.8

1

1.2

0 50 100 150 200 250 300 350 400

CPU Time

Obj

. Fun

. Val

ue

Page 28: Gurobi python

k-被覆問題

=1 顧客 i が被覆されている

距離が θ以内の (被覆されている)顧客数

パラメータ: =1 顧客 iから施設 j

への距離が θ以下

Page 29: Gurobi python

k-被覆 + 二分探索

上界と下界 : UB , LB

while UB – LB >ε: θ= (UB+LB)/2 if k- 被覆問題の目的関数値が 0 then

UB = θ else LB = θ

Page 30: Gurobi python

実験結果

Page 31: Gurobi python

知見• Min-max型の目的関数はMIPソルバーでは解きにくい(双対ギャップが大きい;上界も下界も悪いので,途中で止めても悪い解!).

• 例: Job shopスケジューリングの最大完了時刻(メイクスパン)最小化

• k-被覆問題として制約をなるべく満たすタイプのモデルに直して,最適値を二分探索するとうまくいく.

Page 32: Gurobi python

巡回セールスマン問題(TSP)

• すべての点をちょうど1回通る最短巡回路

• 切除平面法で 85,900点の実際問題(対称TSP)の最適解

Page 33: Gurobi python

Miller-Tucker-Zemlinの定式化

Page 34: Gurobi python

AMPLでの実装(1)param n >=0;

set V := 1..n ; #点集合

set V0 := 2..n; #出発地点 1以外の点集合

set A :=V cross V; #枝集合 =点集合の直積( 2 つ組)

param c { A } >= 0; #枝の距離

var x { A } binary ; #枝を使うとき 1,それ以外のとき 0の 0-1変数

var u { V0 } >=1,<=n-1; #点のポテンシャル

minimize total_cost:

sum {(i,j) in A} c[i,j] * x[i,j];

Page 35: Gurobi python

AMPLでの実装(2)Degree1 {i in V}:

sum {(i,j) in A } x[i,j] =1 ; #出次数制約

Degree2 {i in V}:

sum {(j,i) in A } x[j,i] =1 ; #入次数制約

MTZ{ (i,j) in A: i != j and j!=1 and i!=1}:

u[i]+1 -(n-1)*(1-x[i,j]) + (n-3)*x[j,i]<=u[j]; # 持ち上げ MTZ制約

LiftedLB{ i in V0}:

1+(1-x[1,i]) +(n-3)*x[i,1] <= u[i]; # 持ち上げ下界制約

LiftedUB{ i in V0}:

u[i] <=(n-1)-(1-x[i,1])-(n-3)*x[1,i]; # 持ち上げ上界制約

Page 36: Gurobi python

上界と下界の変化(80点, Euclid TSP)

0

5

10

15

20

25

30

35

40

45

0 50 100 150 200 250 300 350 400

CPU

Obj

. Fun

c. V

alue

強化した式でないと...1日まわして

Out of Memory!

Page 37: Gurobi python

結果Optimize a model with 6480 Rows, 6400 Columns and 37762 NonZeros

中略

Cutting planes:

Gomory: 62

Implied bound: 470

MIR: 299

Zero half: 34

Explored 125799 nodes (2799697 simplex iterations) in 359.01 seconds

Optimal solution found (tolerance 1.00e-04)

Best objective 7.4532855108e+00, best bound 7.4525704995e+00, gap 0.0096%

Opt.value= 7.45328551084

Page 38: Gurobi python

知見

• 式を持ち上げ操作などで強化すると,高速化され,大きな問題例が解けるようになる. (そのためには多面体論の知識が多少必要なので,専門家に相談する)

Page 39: Gurobi python

多品目ロットサイズ決定問題

• 段取り費用と在庫費用のトレードオフを最適化する多期間生産計画

• 多品目で共通の資源を使う容量制約付き問題は,MIPソルバーには難問(と言われてきた)

• T=30 期, P=24 品目: Trigeiro, Thomas, McClain ( 1989 年)の最大のベンチマーク

Page 40: Gurobi python

期t

需要量 (t)

生産量 (t)

在庫量 (t-1)

在庫量( t-1)+生産量 (t)= 需要量 (t)+ 在庫量( t)

在庫量 (t)

ロットサイズ決定問題標準定式化のフローモデル

生産量 (t)≦ 大きな数 “ Large M” × 段取りの有無 (t)

弱い定式化の原因

0-1変数

Page 41: Gurobi python

期s

期t

需要量 (t)

s 期に生産して t 期まで在庫される量 = 需要量 (t)

ロットサイズ決定問題施設配置定式化のフローモデル

∑≤ts

s 期に生産して t 期まで在庫される量

s 期に生産して t 期まで在庫される量 ≦需要量 (t)× 段取りの有無 (s)

Page 42: Gurobi python

アルゴリズムと定式化の関係

(特殊形に対する)多項式時間アルゴリズム

強い定式化 or多項式時間で破っている

妥当不等式の同定

追加制約+つなぎ制約

容量制約なしロットサイズ決定Wagner-Whitin

動的計画アルゴリズム

施設配置定式化最短路定式化(S,l)不等式

1機械重み付き完了時刻和最小化スケジューリングどん欲解法( Simth’s rule)

Super-modular 不等式

Page 43: Gurobi python

弱い定式化弱い定式化

標準定式化 施設配置定式化

)( 2nO

強い定式化

=線形計画緩和が整数多面体と一致

変数の数

定式化のサイズと強さの比較

制約の数

)( 2nO

)(nO変数の数

制約の数)(nO

(S,l)不等式

切除平面

(S,l)不等式

切除平面

追加した制約の数

)2( nO

n: 期数強い定式化

Page 44: Gurobi python

上界と下界の変化(標準定式化)

112000

114000

116000

118000

120000

122000

124000

126000

128000

130000

132000

0 200 400 600 800 1000 1200 1400 1600 1800 2000

CPU

Obj.

Func. Valu

e

1800 秒で最適解;これ以上大きな問題例は無理!

Page 45: Gurobi python

上界と下界の変化(施設配置定式化)

40 秒で最適解; T=100でも大丈夫!

113600

113650

113700

113750

113800

113850

113900

113950

114000

114050

0 5 10 15 20 25 30 35 40 45

CPU

Obj.

Func. Val.

Page 46: Gurobi python

知見

• 従来では難問と言われてきたロットサイズ決定問題でもある程度までは大丈夫

• 緩和固定法( Federgruen, Meissner,Tzur “Progressive Interval Heuristics for Multi-

Item Capacitated Lot-Sizing Problems” 2007)というMIP ベースのメタ解法を作ってみたが,同時間通常の探索を行う「打ち切り分枝限定法」の方が良い!

Page 47: Gurobi python

グラフ彩色問題

• 解の対称性• 点数 n=40 ,彩色数上限 Kmax=10

• ランダムグラフ G(n,p=0.5)

• 彩色数 8 が最適値

Page 48: Gurobi python

定式化

弱い定式化

Page 49: Gurobi python

Pythonでの実装(1)

from gurobipy import *

model=Model("gcp")

x={}

y={}

for i in range(n):

for k in range(K):

x[i,k]=model.addVar(obj=0, vtype="B",name="x"+str(i)+str(k))

for k in range(K):

y[k]=model.addVar(obj=1,vtype=“B”,name="y"+str(k))

model.update()

Page 50: Gurobi python

Pythonでの実装(2)

for i in range(n):

L=LinExpr()

for k in range(K):

L.addTerms(1,x[i,k])

    model.addConstr(lhs=L,sense= " = ",rhs=1,name="const"+str(i))

中略

model.optimize()

print "Opt.value=",model.ObjVal

for v in model.getVars():

if v.X>0.001:

print v.VarName,v.X

Page 51: Gurobi python

上界と下界の変化(原定式化)

点数 n=40 ,彩色数上限 Kmax=10

0

2

4

6

8

10

12

0 200 400 600 800 1000 1200 1400

CPU Time

Obj

. Fun

c. V

alue

Optimize a model with 3820 Rows, 410 Columns and 11740 NonZeros

Explored 17149 nodes (3425130 simplex iterations) in 1321.63 seconds

Page 52: Gurobi python

定式化の改良

対称性の除去(番号の小さい方の色を優先して使う!)

特殊順序集合( SOS: Special Ordered Set ) Type 1 (いずれか1つの変数が正になることの宣言)の追加

model.addSOS(1,変数リスト )

Page 53: Gurobi python

上界と下界の変化(対称性除去)

0

2

4

6

8

10

12

0 50 100 150 200 250 300 350 400 450

CPU

Obj

. Fun

c. V

alue

Optimize a model with 3829 Rows, 410 Columns and 11758 NonZeros

Explored 4399 nodes (1013290 simplex iterations) in 384.53 seconds

MIPFocus=2 (最適性保証優先) で 67 秒,MIPFocus=3 (下界優先) で70 秒

Page 54: Gurobi python

上界と下界の変化( +SOS)

Optimize a model with 3829 Rows, 410 Columns and 11758 NonZerosExplored 109 nodes (58792 simplex iterations) in 22.02 seconds

MIPFocus=2 (最適性保証優先) で 65 秒,MIPFocus=3 (下界優先)で 126 秒

0

2

4

6

8

10

12

0 5 10 15 20 25

CPU

Obj

. Fun

c. V

al.

Page 55: Gurobi python

知見

• 解の対称性のある問題は,下界の改善がしにくいので,分枝限定法では解きにくい(モダンなソルバーは群論などを用いた工夫を入れてはいるが,あまり機能しない問題もある)

• 対称性を除く工夫を入れると多少は改善• SOS( Special Ordered Set)制約の宣言は損はない(ただし,探索手法の変更との相性は悪い.)

Page 56: Gurobi python

Gurobiクラス

• モデルクラス Model モデルオブジェクト =Model(“ ”モデル名)

• 変数クラス Var 変数オブジェクト = モデルオブジェクト .addVar()

• 制約クラス Constr 制約オブジェクト = モデルオブジェク

ト .addConstr()• 線形制約クラス LinExpr線形制約オブジェクト =LinExpr()

• 他にも,特殊順序集合クラス SOS ,定数クラスGRB ,コールバッククラス Callbacks,エラークラ

ス GurobiError ,列クラス Column がある.

Page 57: Gurobi python

Gurobi Objects

Model

Variable

Constraint

LinExpr QuadExpr

Column

Callbacks

GRBError

addVar

addConstr

SOS

addSOS

Page 58: Gurobi python

変数追加メソッド addVarの引数

• lb (下限 ) :規定値 =0• ub (上限 ) :規定値 =GRB.INFINITY(無限大)

• obj (目的関数の係数 ):=0• vtype (変数の種類 ): GRB.CONTINUOUS(連

続変数; “ C”でも可) , GRB.BINARY( 2値変数;“ B”) , GRB.INTEGER(整数変数;“ I”) , GRB.SEMICONT( 0もしくはある範囲内の連続変数;“ S”でも可) , GRB.SEMIINT( 0もしくはある範囲内の整数変数;“ N” でも可)

• name ( 名前 ): =“”• column ( 列 ): =なし( None型)

Page 59: Gurobi python

制約追加メソッド addConstrの引数

• l hs(左辺):線形制約オブジェクトか定数

• sense(制約の向き):GRB.LESS_EQUAL(≦;“ <”でも可) , GRB.EQUAL (=; “ =”でも可) , GRB.GREATER_EQUAL (≧;“ >”でも

可)• rhs(右辺):線形制約オブジェクトか定数

• name(名前)

Page 60: Gurobi python

モデルのその他の主要メソッド

• optimize( コールバック関数):最適化実行• update:モデルの変更を Gurobiに知らせる• getVars:変数オブジェクトを入れたリストを得る

• relax:緩和問題を生成• computeIIS:既約不整合部分系(実行不能になっている原因の制約と変数; Irreducible Inconsistent Subsystem: IIS )を計算

• addSOS( 1 or 2, 変数リスト,重み( option)):特殊順序集合( Special Ordered Set: SOS)を追加

Page 61: Gurobi python

パラメータの設定

書式: setParam(“ ”パラメータ名 ,値) model.Params. パラメータ名 =値例:混合整数計画(MIP)の相対誤差

(終了条件);規定値は 10-4

setParam(“MIPGap”,0.0)

model.Params.MIPGap=0.0

Page 62: Gurobi python

よく使うパラメータ

• TimeLimit:計算時間上限(秒)• MIPGap :相対誤差上限(規定値は 10-4)• MIPFocus:MIP探索戦略( 0=バランス ,1=

暫定解改良 ,2=最適性の保証 ,3= 限界値改良)

• SolutionNumber:探索中に発見された解の番号

• LPMethod:線形計画の解法( 0= 主単体, 1=双対単体, 2=内点)

• OutputFlag:出力制御( 0=Off, 1=On)

Page 63: Gurobi python

属性( attributes)

書式: オブジェクト .setAttr(“ ”属性名 ,値) オブジェクト . 属性名 =値例:変数 varの目的関数の係数を 100に変更

var.setAttr(“Obj”,100)

var.Obj=100

Page 64: Gurobi python

よく使う属性( 1)• モデル

– ObjVal:最適目的関数値(最適化後のみ)– ModelSense:目的関数の方向( 1=最小化, -1=最大化)

– Runtime:計算時間(最後の求解時の)– Status:モデルの状態(1から 13まで;

2=OPTIMAL, 3=INFEASIBLE, 4=UNBOUNDED, 9=TIME_LIMIT, 11=INTERRUPTED, 13=SUBOPTIMAL)

– SolCount:探索で見つかった解の数

Page 65: Gurobi python

よく使う属性(2)• 変数

– LB, UB:下限,上限– Obj:目的関数の係数– Vtype:変数の種類(“ C”=連続,“ B”=2値,“ I”=整数,“ S” =半連続,“ N”= 半整数

– VarName:変数名– X:解の値– Xn:パラメータ SolutionNumberで指定された番号の解の値– RC:被約費用(連続最適化のみ)

• 制約– Sense:制約の向き(“ <”,“ >”,“ =”)– RHS:右辺定数– ConstrName:制約名– Pi:双対変数(連続最適化のみ)– Slack:余裕変数の値