JavaScriptを有効にしてください

Pyomoモデルの変数・制約の情報を一括で取得する

 ·   ·   4 min read

はじめに

Pythonの最適化モデリングツールであるPyomoで、最適化モデルに定義された変数や制約の情報を一括して取得する方法をまとめました。Pyomoの変数や制約がベクトル化された状態でも対応できます。

検証環境は以下の通りです。GLPKという線形ソルバを使用します。

バージョン
Python 3.9.7
Pyomo 6.4.1
GLPK 4.65

PyomoとGLPKのインストール方法は以下の記事を参照ください。
Pyomoで線形計画問題を解く – Helve Tech Blog

対象とするPyomoモデル

以下のPyomoモデルを考えます。整数線形計画問題です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pyomo.environ as pyo

def pyomo_const(pyo_model, i):
    return pyo_model.x1[i] + 3*pyo_model.x1[i+1] <= 8

model = pyo.ConcreteModel()

model.x0 = pyo.Var(domain=pyo.Integers, bounds=(0, 10))
model.x1 = pyo.Var(range(3), domain=pyo.Integers, bounds=(0, 5))

model.const0 = pyo.Constraint(expr = 2*model.x0 + model.x1[0] <= 7)
model.const1 = pyo.Constraint(range(2), rule=pyomo_const)

model.obj = pyo.Objective(expr=2*model.x0 + sum(model.x1[i] for i in range(3)), sense=pyo.maximize)

opt = pyo.SolverFactory('glpk')
res = opt.solve(model, tee=False)

変数x0はスカラー、x1はベクトルです。また、制約const0はスカラー、const1はベクトルです。

変数の一覧を取得する

変数を一括で取得するには、ConcreteModelオブジェクトのcomponent_data_objectsメソッドを使います。

1
2
component_data_objects(ctype=None, active=None, sort=False,
    descend_into=True, descent_order=None,)

引数ctypeは、絞り込みたい型(変数の場合はVar, 制約の場合はConstraint)を与えられることで、フィルタの役割を果たします。component_data_objectsメソッドの戻り値はジェネレータとなります。そのため、for文などを使って個々の要素(変数)を取得します。

変数の一覧を取得する例を以下に示します。

1
2
for v in model.component_data_objects(ctype=pyo.Var):
    print(f"{v.name=}, {v.lb=}, {v.value=}, {v.ub=}")

実行結果

1
2
3
4
v.name='x0', v.lb=0, v.value=3.0, v.ub=10
v.name='x1[0]', v.lb=0, v.value=1.0, v.ub=5
v.name='x1[1]', v.lb=0, v.value=2.0, v.ub=5
v.name='x1[2]', v.lb=0, v.value=2.0, v.ub=5

取得結果vの属性の意味は以下の通りです。

  • name: 変数名
  • lb: 下限
  • value: 最適化結果(最適化実行前の場合、初期値またはNone
  • ub: 上限

さらに、取得結果vの型を確認してみます。以下の結果から、スカラー変数はScalarVar, ベクトル変数は_GeneralVarDataというクラスであることが分かります。

1
2
for v in model.component_data_objects(ctype=pyo.Var):
    print(type(v))

実行結果

1
2
3
4
<class 'pyomo.core.base.var.ScalarVar'>
<class 'pyomo.core.base.var._GeneralVarData'>
<class 'pyomo.core.base.var._GeneralVarData'>
<class 'pyomo.core.base.var._GeneralVarData'>

また、変数の一覧をPandasのDataFrameに格納する例を以下に示します。

1
2
3
4
5
6
7
8
import pandas as pd

df = pd.DataFrame(columns=["lb", "value", "ub"])

for v in model.component_data_objects(ctype=pyo.Var):
    df.loc[v.name] = [v.lb, v.value, v.ub]

print(df)

実行結果

1
2
3
4
5
        lb  value    ub
x0     0.0    3.0  10.0
x1[0]  0.0    1.0   5.0
x1[1]  0.0    2.0   5.0
x1[2]  0.0    2.0   5.0

制約の一覧を取得する

制約を一括で取得するには、ConcreteModelオブジェクトのcomponent_objectsメソッドを使います。

1
2
component_objects(ctype=None, active=None, sort=False,
    descend_into=True, descent_order=None,)

引数ctypeは、絞り込みたい型(変数の場合はVar, 制約の場合はConstraint)を与えられることで、フィルタの役割を果たします。component_objectsメソッドの戻り値はジェネレータとなります。そのため、for文などを使って個々の要素(制約)を取得します。

制約の一覧を取得する例を以下に示します(2022/7/17 制約の値を取得する方法を追記しました)。

1
2
3
4
5
from pyomo.core.expr.numvalue import value

for c in model.component_objects(ctype=pyo.Constraint):
    for v in c._data.values():
        print(f"{v.name=}, {v.lb=}, {value(v.body)=}, {v.ub=}")

実行結果

1
2
3
v.name='const0', v.lb=None, value(v.body)=7.0, v.ub=7
v.name='const1[0]', v.lb=None, value(v.body)=7.0, v.ub=8
v.name='const1[1]', v.lb=None, value(v.body)=8.0, v.ub=8

取得結果vの属性の意味は以下の通りです。

  • name: 制約名
  • lb: 下限
  • body: 制約の値(bodyだけでは制約式が返されるため、value関数で実際の値を計算します)
  • ub: 上限

さらに、取得結果cの型を確認してみます。以下の結果から、スカラーの制約はScalarConstraint, ベクトルの制約はIndexedConstraintというクラスであることが分かります。

1
2
for c in model.component_objects(ctype=pyo.Constraint):
    print(type(c))

実行結果

1
2
<class 'pyomo.core.base.constraint.ScalarConstraint'>
<class 'pyomo.core.base.constraint.IndexedConstraint'>

また、制約の結果をコンソールに表示するだけであれば、displayメソッドも使えます。

1
2
for c in model.component_objects(ctype=pyo.Constraint):
    c.display()

実行結果

1
2
3
4
5
6
7
const0 : Size=1
    Key  : Lower : Body : Upper
    None :  None :  7.0 :   7.0
const1 : Size=2
    Key : Lower : Body : Upper
      0 :  None :  7.0 :   8.0
      1 :  None :  8.0 :   8.0

参考

Pyomoの公式リファレンス
Working with Pyomo Models — Pyomo 6.4.1 documentation.htm

シェアする

Helve
WRITTEN BY
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

サイト内検索