Pyomoは、Gurobiをサポートするモデリングフレームワークの一つです。この記事では、Pyomoを通じてGurobiを使用する方法について説明します。より詳しい情報やPyomoに関連する問題の解決には、Pyomo公式ウェブサイトをご覧ください。
Gurobiへのインターフェース
PyomoはGurobiへの複数のインターフェースを提供しています。これらのインターフェースは、Pyomoで定義されたモデルをGurobiモデルに変換する役割を担います。それぞれのインターフェースはわずかに異なる機能を提供し、デフォルトの動作も異なります。したがって、はじめに適切なインターフェースを選ぶことが重要です。主なインターフェースは以下の通りで、詳細は後述します。
-
直接インターフェース:一時ファイルを生成せずにモデルを直接
gurobipyに変換します。求解後にモデルをメモリに保持しません。通常、汎用的に良い選択肢です。 -
ファイルベースインターフェース:Pyomoはモデルを記述するMPSまたはLPファイルを生成し、その後
gurobipyを使ってそのモデルを読み込みます。 -
永続インターフェース:
gurobipyと連携しますが、求解後もモデルをメモリに保持します。再求解の際に、モデルの変更を明示的にマークし、基礎となるgurobipyモデルオブジェクトをPyomoが効率的に更新します。 - 自動永続インターフェース(APPSI):永続インターフェースと似ていますが、Pyomoモデル定義の変更を手動でマークせずに自動的に検出します。
以下のセクションでは、これらの各インターフェースの詳細を説明します。すべてのコードスニペットは、すでにPyomoモデルが構築されていること(例えば下記のようなmodelオブジェクト)を前提としています。
import pyomo.environ as pyo
model = pyo.ConcreteModel()
model.x = pyo.Var(bounds=(0, None))
model.y = pyo.Var(bounds=(0, None))
model.c = pyo.Constraint(expr = model.x + model.y >= 1)
model.obj = pyo.Objective(expr = 2*model.x + 3*model.y, sense=pyo.minimize)直接インターフェース
インターフェースの使用方法
直接インターフェースでモデルを解くには、以下のいずれかのオプションを使用します:
# 解く前にこれらのいずれかを使用
opt = pyo.SolverFactory("gurobi_direct")
opt = pyo.SolverFactory("gurobi", solver_io="direct")
opt.solve(model)Gurobi environmentの管理
デフォルトでは、Pyomoはグローバル(デフォルト)Gurobi environmentオブジェクトに依存しています。欠点は、この環境が最初の使用時に自動的に作成されるものの、Pythonスクリプト全体が終了するまで破棄されないことです。これにより、他のプロセスが同じライセンスに依存している場合に問題が生じることがあります。
これを解決するために、Pyomoにデフォルト環境を明示的に破棄し、すべてのPyomo関連リソースを解放するよう指示できます。デフォルト環境はすべてのPyomoモデルで共有されていることに注意してください。
opt = pyo.SolverFactory("gurobi_direct")
opt.solve(model)
opt.close_global() # Gurobi environmentを解放あるいは、PyomoにGurobiインターフェース専用の環境を作成させ、環境が不要になったときに明示的に解放することもできます:
opt = pyo.SolverFactory("gurobi_direct", manage_env=True)
opt.solve(model)
opt.close() # Gurobi environmentを解放環境パラメータの設定
manage_env=Trueのシナリオでのみ環境パラメータを設定できます。他のシナリオではデフォルト環境がすでに構築されており、パラメータを設定する余地がありません。インターフェース構築時にoptions引数を通じて環境パラメータを提供できます:
opt = pyo.SolverFactory("gurobi_direct", manage_env=True, options={'ComputeServer':'localhost'})モデルパラメータの設定
モデルパラメータ(ソルバーの動作に影響)をsolve()関数のoptionsパラメータを通じて設定できます:
opt.solve(model, options={'TimeLimit':60})または、solve()関数を呼び出す前に個別のパラメータを下記のように設定することも可能です:
opt.options['TimeLimit'] = 60モデルのエクスポート
PyomoはGurobiに依存せずにMPSおよびLPファイルを生成できます。つまり、Gurobiをインストールする前からファイルを生成できます。ただし、ファイルは必ずしもGurobiが適用する規約に従わない場合があります。デフォルトでは、変数や制約の名前は匿名化され、連番が付与されます。モデルの実際の変数名や制約名を使いたい場合は、symbolic_solver_labelsオプションを使用してください:
# LPファイルを生成;変数/制約はx1, x2...のように番号付けされる
model.write("model.lp")
# MPSファイルを生成;変数は元の名前を保持
model.write("model.mps", io_options={"symbolic_solver_labels": True})あるいは、Gurobiにモデルのエクスポートを任せたい場合は、GURO_PAR_DUMPまたはResultFileパラメータを使用してください。
ログ出力
デフォルトでは、PyomoはGurobiの出力をキャプチャし、コンソールやログファイルには何も表示しません。
- 画面にログ出力を表示するには、
opt.solve(model, tee=True)を使用します - ログファイルを生成するには、
opt.solve(model, logfile="test.log", keepfiles=True, tee=True)を使用します - または、
opt.solve(model, options={"LogFile": "test.log"}, tee=True)を呼び出します
サポートされるモデルタイプ
- LP、MIP、QP、QCP、MIQP、MIQCPがサポートされています
- 区分的線形制約はサポートされていますが、Gurobiに渡す前にPyomoによってSOS2制約に変換されます
- 論理制約(インジケータ制約を含む)は、
gdp.bigm変換を使わない限りサポートされません(この記事の範囲外です) - 非線形関数(exp, sin, cos, logなど)はサポートされません
基礎となるGurobiモデルオブジェクトへのアクセス
以下のように基礎となるモデルオブジェクトにアクセスできます。以下の例ではIISを計算しています。
opt.solve(model)
opt._solver_model.computeIIS()同様の方法で、多目的やマルチシナリオモデルの機能にもアクセスできます。ただし、そのような機能を呼び出した結果を要求するには、個々のgurobipyの変数や制約オブジェクトにアクセスする必要があります。これらの情報はPyomoの変数や制約オブジェクトには戻されません。インターフェースはPyomoとGurobiの要素をマッピングするための2つの辞書構造を提供しています:
-
_pyomo_var_to_solver_var_map:変数用。キーとして冒頭のスニペットにおけるmodel.xのようなPyomoの変数オブジェクトを渡します -
_pyomo_con_to_solver_con_map:制約用。キーとして冒頭のスニペットにおけるmodel.cのようなPyomoの制約オブジェクトを渡します
ファイルベースインターフェース
インターフェースの使用方法
ファイルベースインターフェースを使用する際は以下の例のようにします。デフォルトではLPファイルを生成する動作となりますが、MPSファイルもサポートされています。マシンにgurobipyがインストールされている場合、生成されたファイルの読み込みと求解に使用されます。そうでない場合、Pyomoはgurobi_clを実行しようとします。これはGurobi Optimizerの完全なパッケージをインストールしている場合にのみ利用可能です。
# LPファイルベースインターフェースを使用
opt = pyo.SolverFactory("gurobi")
# MPSファイルベースインターフェースを使用
opt = pyo.SolverFactory("gurobi", solver_io="mps")Gurobi environmentの管理
このインターフェースは常にデフォルトのGurobi environmentを使用します。環境のパラメータはカスタマイズできませんので、代わりにGurobiライセンスファイルを使用してください。
その他の注意点
直接インターフェースに関する多くの注意点について、ファイルベースインターフェースにも同じことが言えます:
- モデルパラメータを変更するには、
solve()関数に渡します。 -
model.write()でモデルをエクスポートできます。 - ログ出力はコンソールおよびファイルの両方で制御できます。
- サポートされるモデルタイプも同様です。
ただし、基礎となるGurobiモデルオブジェクトにはアクセスできません。
永続インターフェース
インターフェースの使用方法
永続インターフェースは以下のように使用できます:
opt = pyo.SolverFactory("gurobi_persistent")
opt.set_instance(model)
opt.solve(tee=True)モデルの更新
初回の求解後にモデルを変更した場合、各変更を明示的にマークしてソルバーインターフェースに通知する必要があります。これにより、再求解前に基礎となるGurobiモデルが正しく更新されます。可能な変更は以下の通りです。詳細はPyomoのドキュメントを参照してください。
- 変数
model.xを追加した場合、後でpt.add_var(model.x)を呼び出します - 変数の境界を変更したり、特定の変数
model.xを固定・解除した場合、opt.update_var(model.x)を呼び出します - 変数
model.xを削除する場合、opt.remove_var(model.x)を呼び出してからdel model.xを実行します - 新しい制約
model.cを追加した場合、opt.add_constraint(model.c)を呼び出します - 制約
model.cをmodel.c.set_value()で更新した場合、後でopt.update_constraint(model.c)を呼び出します - 制約
model.cを削除する場合、opt.remove_constraint(model.c)を呼び出してからdel model.cを実行します - 目的関数を置き換えるには、まず
model.obj.deactivate()を呼び出します。その後、新しい目的関数を構築し、opt.set_objective(model.obj)を呼び出します
その他の注意点
以下の機能は直接インターフェースと同様に動作します:
- Pyomoに環境管理を任せ、初期化オプションを提供できます
-
solve()関数のoptions引数を使ってモデルパラメータを提供できます - モデルをMPSおよびLP形式でエクスポートできます
- ログ出力やサポートされるモデルタイプに関する注意点も同様です
-
opt._solver_modelを使って基礎となるGurobiモデルオブジェクトにアクセスできます
自動永続インターフェース
インターフェースの使用方法
自動永続インターフェースは以下のように使用できます:
from pyomo.contrib.appsi.solvers import Gurobi
solver = Gurobi()
solver.solve(model)
solver.release_license()Gurobi environmentの管理
このインターフェースは常にデフォルトのGurobi environmentを使用します。環境を初期化する際にパラメータを提供できませんので、ライセンスファイルを使用してください。ライセンスを解放するために必ずrelease_license()を呼び出してください。これを怠ると、環境は生き続け(ライセンスをブロックし)、Pythonプロセス終了まで解放されません。
モデルパラメータの設定
モデル求解のためのパラメータは、solver.gurobi_options辞書を通じて提供できます:
from pyomo.contrib.appsi.solvers import Gurobi
solver = Gurobi()
solver.gurobi_options = { "TimeLimit": 60 }
solver.solve(model)
solver.release_license()モデルのエクスポート
上述の方法は自動永続インターフェースでも機能します。加えて、solver.write(filename)関数を使うこともできます。これは(Pyomoではなく)Gurobiを利用してファイルを生成します。Gurobi側のモデルがどのようなものか理解するためのデバッグに役立ちます。
ログ出力
デフォルトでは、PyomoはGurobiの出力をキャプチャし、コンソールやログファイルには何も表示しません。
- 画面にログ出力を表示するには、
solver.config.stream_solver = Trueを設定します - ログファイルを生成するには、
solver.gurobi_options = { "LogFile": "test.log" }を使用します
サポートされるモデルタイプ
このインターフェースでサポートされるモデルタイプのセットは、上記と同じです。
基礎となるGurobiモデルオブジェクトへのアクセス
基礎となるGurobiモデルは、solver._solver_modelを通じて上記と同様にアクセス可能です。インターフェースはPyomoとGurobiの要素をマッピングするための2つの辞書構造を提供しています:
-
_pyomo_var_to_solver_var_map:変数用。キーとしてid(model.x)を渡します。ここではid()関数が使用されていますが、他のインターフェースでは使用されません。 -
_pyomo_con_to_solver_con_map:制約用。キーとしてmodel.cを渡します