このセクションでは、GurobiのPython API とPython Matrix APIの使い方を一通り紹介していきます。扱う例題は単純なMIPモデルでそれをAPIを使って構築し、最適化、結果の出力までを行います。
Gurobiには“gurobipy”と呼ばれるPythonの拡張機能が付属しており、これを通してモデルの構築やGurobiの各機能へのアクセスを行うことができます。また、お手元のPython環境や仮想環境(https://docs.python.org/3/library/venv.html)に対してgurobipyをインストールすることも可能です。詳細はGurobiをPythonへインストールするには?をご覧ください。
以下の例題では、簡単なMIPモデルを構築し、求解して解を出力します。
例題
以降ではこのような問題を扱います:
maximize | x | + | y | + | 2 z | ||
subject to | x | + | 2 y | + | 3 z | <= | 4 |
x | + | y | >= | 1 | |||
x, y, z binary |
続いて、Gurobi Python APIまたはGurobi Python Matrix APIを使用して上記のモデルを最適化していく流れを1行1行確認していきます。このプログラムのソースコードは以下にあります。
Python API
- オンライン: Example mip1.py
- インストール先: <installdir>/examples/python/mip1.py
Python matrix API
-
- オンライン: Example matrix1.py
- インストール先: <installdir>/examples/python/matrix1.py>
Gurobiの関数とクラスのインポート
Python API
まず、Gurobiの関数やクラスをインポートすることから始めます:
import gurobipy as gp from gurobipy import GRB
1行目Gurobiの関数とクラスをgp.というプレフィックスを通してアクセスできるようにするものです(e.g., gp.Model())。2行目は GRB クラスをプレフィックスなしでアクセスできるようにするコマンドです(e.g., GRB.OPTIMAL)。また、 from gurobipy import * という形で始めることもできます。この場合gp. というプレフィックスをなくすことができますが、プログラム中で複数の Python モジュールを使う場合は、通常、それぞれのプレフィックスを使ってアクセスするのが好ましいとされています。
これらのコマンドがエラーなく終了するためには、PythonアプリケーションはGurobi関数とクラスの場所へアクセス可能である必要があります。これらをインストールするためには GurobiをPythonへインストールするには? をご参照ください。
Python matrix API
Python matrix APIの場合では、まずGurobiの関数とクラス、そしてNumPyとSciPyのパッケージをインポートします:
import gurobipy as gp from gurobipy import GRB import numpy as np import scipy.sparse as sp
最初の2行は Gurobi Python API を使ったアプリケーションと共通です。Python matrix APIを利用する場合には続いて2行の命令文が必要です。
環境の生成
この例では、デフォルトの環境(env)を利用します。デフォルトでないenvを利用する場合には、 How do I manage Gurobi environments in gurobipy? ご覧ください。
モデルの生成
Python API
最初の処理はモデルの生成です。Gurobiのモデルは一つの最適化問題に対応します。モデルは変数集合、制約集合および関連する属性(変数の上下限、目的関数の係数、変数の型、制約の向き、制約の右辺項、等) から構成されます。
まずは空のモデルを作ります:
# Create a new model m = gp.Model("mip1")
gp.Model はモデルの名前を引数として受け取ります。
Python matrix API
Python APIの場合と同様にからのモデルを作るところから始めます:
# Create a new model m = gp.Model("matrix1")
gp.Model はモデルの名前を引数として受け取ります。
モデルへ変数を追加する
Python API
続いてモデルに対して変数を追加していきます。
# Create variables x = m.addVar(vtype=GRB.BINARY, name="x") y = m.addVar(vtype=GRB.BINARY, name="y") z = m.addVar(vtype=GRB.BINARY, name="z")
変数は Model.addVar メソッドを通して1個1個モデルオブジェクトへ追加されます。もしくは Model.addVars を使ってまとめて追加することもできます。変数は常に一つのモデルに紐づいています。
Pythonではメソッドの引数を順序または名前で参照できます。例では引数の名前を使って各値を指定しています。各変数は変数の型(vtype)としてバイナリ型と変数名(name)を与えられています。その他の引数についてはデフォルト値が使用されます。詳細についてはGurobiシェルでの help(gp.Model.addVar) や Model.addVarを参照してください。
Python matrix API
matrix APIでも変数を追加していきます:
# Create variables x = m.addMVar(shape=3, vtype=GRB.BINARY, name="x")
Matrix API用の行列変数は Model.addMVar を通してモデルオブジェクトへ追加されます。例では3つの変数からなる1次元の行列変数が追加されます。行列変数も常に一つのモデルに対して紐づいています。
モデルへ制約を追加する
Python API
次のステップでは線形制約を追加していきます。一つ目の制約はこのように追加できます:
# Add constraint: x + 2 y + 3 z <= 4 m.addConstr(x + 2 * y + 3 * z <= 4, "c0")
変数と同じように、制約も特定のモデルに対して紐づきます。制約オブジェクトは Model.addConstr を通してモデルオブジェクトへ追加されます。
メソッドの中では比較演算子が使われています。このような演算子はモデル構築を容易にするためオーバーロードされています。
Model.addConstr の2つ目の引数は制約名です。これは任意の引数ですが、制約に名前を付けることができます。
この例は、非常に単純な最適化問題を扱っているため、線形制約はそれぞれの変数と係数を式の中に直接記述しています。一般に、より複雑なモデル扱うような場合には、変数のリストやquicksumメソッドなどを使って動的に制約を生成します。
2つ目の制約も同様に記述します。
# Add constraint: x + y >= 1 m.addConstr(x + y >= 1, "c1")
Python matrix API
Matrixの場合は、2つの線形制約を同時に追加していきます。 この操作はスパース行列を利用することで実現できます:
# Build (sparse) constraint matrix val = np.array([1.0, 2.0, 3.0, -1.0, -1.0]) row = np.array([0, 0, 0, 1, 1]) col = np.array([0, 1, 2, 0, 1]) A = sp.csr_matrix((val, (row, col)), shape=(2, 3))
作成した行列は2行(各制約に一つ)×3列(各変数に一つ)の行列です。row 配列と col 配列は、それぞれスパース行列の5つの非ゼロ値の行と列のインデックスに対応します。val 配列はそれぞれの係数値です。>=制約を<=制約に変換するために、2つ目の制約式の両辺に-1を掛けていることに注意してください。
同様に右辺項をNumPy 配列に保存します:
# Build rhs vector rhs = np.array([4.0, -1.0])
次に、オーバーロードされた@演算子と<=演算子を使用して線形行列式を構築します。このときModel.addConstr によって2つの制約(行列の各行ごとに1つ)が同時に追加されます:
# Add constraints m.addConstr(A @ x <= rhs, name="c")
目的関数の設定
Python API
続いて、最適化問題の目的関数を設定していきます:
# Set objective m.setObjective(x + y + 2 * z, GRB.MAXIMIZE)
目的関数はオーバーロードされた演算子を用いて、Model.setObjectiveから設定できます。(これまでにも出てきましたが、Python API はPythonの算術演算子をオーバーロードし、Gurobi変数を含む一次式や二次式を構築できるようにしています。)
第2引数は目的関数の方向で、今回は最大化を意味しています。
今回の例は非常に小規模なため、目的関数を直接記述していますが、より複雑な問題では、通常、動的あるいは逐次的に目的関数を設定することが多いです。今回の例でいえば次のようになりますが、複雑な例になるとfor文など利用します:
obj = gp.LinExpr() obj += x obj += y obj += 2 * z m.setObjective(obj, GRB.MAXIMIZE)
Python matrix API
Python matrix APIで目的関数を設定します:
# Set objective obj = np.array([1.0, 1.0, 2.0]) m.setObjective(obj @ x, GRB.MAXIMIZE)
ここでの目的関数は、定数ベクトルと行列変数のdot積(@演算子)で表現されます。定数ベクトルは変数と同じ長さである必要があります。
第2引数は目的関数の方向で、今回は最大化を意味しています。
モデルの最適化
ここまででモデルが構築できました。続いては最適化の実行です:
# Optimize model m.optimize()
このメソッドを呼び出すことで最適化が実行されます。このとき、モデルの内のいくつかの属性(最適化の状態、解など)が変更されます。
最適化結果の取得
Python API
最適化の完了後、その結果にアクセスすることが可能です。例えば VarName と X を使って変数の名前と解を各変数に対して参照できます:
for v in m.getVars(): print('%s %g' % (v.VarName, v.X))
また ObjVal 属性にアクセスすることで、現在の解の目的関数値を参照できます:
print('Obj: %g' % m.ObjVal)
model, variable, constraint オブジェクトに付随する各属性の詳細は Attributes から確認できます。もしくは help(GRB.Attr) とGurobi シェル上で実行することでも確認できます。
Python matrix API
最適化の完了後、その結果にアクセスすることが可能です。例えば X 属性を使って現在の解を参照できます:
print(x.X)
また ObjVal 属性にアクセスすることで、現在の解の目的関数値を参照できます:
print('Obj: %g' % m.ObjVal)
model, variable, constraint オブジェクトに付随する各属性の詳細は Attributes から確認できます。もしくは help(GRB.Attr) とGurobi シェル上で実行することでも確認できます。
クリーンアップ
他の言語のAPIでは、Gurobi envを使い終わったら、関連するリソースを解放するために明示的に破棄することを推奨しています。Pythonインターフェースでの推奨はもう少し複雑です。
ほとんどの場合、Gurobi Pythonを使ったプログラムはデフォルト env を使用します。このenvはGurobi Modelオブジェクトを最初に構築したときに自動的に作成され、プログラムが終了したときに自動的に破棄されます。disposeDefaultEnv() を呼び出して手動で破棄することもできますが、env を詳細に制御したい場合(例えば、Compute ServerやGurobi Instant Cloudを使用している場合)には、代わりに明示的な env オブジェクトを扱うことをお勧めします。
このような場合については mip1_remote.py を参考としてください。
エラーレポート
Gurobi PythonにおけるエラーはPythonの例外処理機構に従ってハンドルされます。例ではすべてのGurobiプログラムを try ブロックの中に配置され、各エラーは except ブロックでキャッチされます:
try:
# これまでのプログラムをここに記述
except gp.GurobiError as e: print('Error code ' + str(e.errno) + ': ' + str(e)) except AttributeError: print('Encountered an attribute error')
実行例
これまでのプログラムを実行するには、Gurobi Pythonのサンプルディレクトリ(<installdir>/examples/python) に移動し、Gurobiインタラクティブシェルから次のコマンドを打ち込みます:
gurobi.sh mip1.py
注:version 11.0.2から Gurobi Interactive Shell の利用は非推奨となりました
もしお手元のPython環境にgurobipy がインストールされている場合、コマンドプロンプトから次のようにタイプしても実行できます:
python mip1.py
コメント
0件のコメント
記事コメントは受け付けていません。