2.2.3. 集合・添字¶
油田運転日数を一般的に記述することを考えてみましょう. まず油田運転日数 \(x\), \(y\) をそれぞれ \(x_0\), \(x_1\) と変更し,定式化を次のように変更します.
対応する PySIMPLE の記述は,次のようになります.:
from pysimple import Problem, Element, Parameter, Variable
problem = Problem(name='油田問題3')
# 油田を表す添字
i = Element(value=[0, 1], name='油田')
# 油田 i の運転コスト/日
costX = Parameter(value=180, name='油田Xの運転コスト')
costY = Parameter(value=160, name='油田Yの運転コスト')
# 油田 i の運転日数(変数)
x = Variable(lb=0, ub=5, index=i, name='油田の運転日数')
# 運転コスト/週(目的関数)
problem += costX*x[0] + costY*x[1], '全運転コスト'
# 製品ノルマ
problem += 6*x[0] + x[1] >= 12, '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= 24, 'ガスノルマ/週'
# 求解
print(problem)
problem.solve()
# 結果出力
print(x.val)
print(problem.objective.val)
定式化と同様,日数制約を一度に書き表しています.
それでは,PySIMPLE の記述の変更・追加点について,上から順に見ていきます.:
# 油田を表す添字
i = Element(value=[0, 1], name='油田')
ここでは添字(油田の添字)を宣言しています.
value=..
には添字がとる要素の列を指定します.
ここでは先の定式化の添字範囲が {0, 1} なので,0, 1 を添字の範囲とします.
name='..'
には添字の名前を指定しますが省略可能です.
C++SIMPLE のように集合を作成した後に,添字を作成することもできます.:
# 油田集合
OilField = Set(value=[0, 1], name='油田集合')
i = Element(set=OilField)
Set を用いる場合には Element と同様にインポートが必要になります.:
x = Variable(lb=0, ub=5, index=i, name='油田の運転日数')
ここでは油田の運転日数を,添字付き変数として宣言しています.index=..
で添字を指定します.
# 運転コスト/週(目的関数)
problem += costX*x[0] + costY*x[1], '全運転コスト'
ここでは運転コストの内容定義をしています.添字付けは,x[添字]
と記述します.:
# 製品ノルマ
problem += 6*x[0] + x[1] >= 12, '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= 24, 'ガスノルマ/週'
ここでは製品ノルマの制約を記述しています. 以前に x, y と書いた変数部分を x[0], x[1] と置き換えただけです.
# 結果出力
print(x.val)
結果出力も上記日数制約と同様に,添字に i と指定することで,
全ての \(i \in OilField\) について x[i] の値が出力されます.
ここでは print(x.val)
としていますが,print(x[i].val)
でも同じ効果があります.
次に実行してみます(実行方法については 数理計画問題を解く を参照してください).
最適化経過が出力されたあと,print(x)
に対応した,以下の出力が得られます.
油田の運転日数[0].val=1.500000000256067
油田の運転日数[1].val=2.9999999999710107
変数名が添字つきで出力されているのが確認できます.
ここまでの記述の変更で,添字 i を導入し,各油田の運転日数を x[i] と簡略化することができました. 次に,油田運転コスト costX, costY も添字 i を用いて簡略化してみます. 運転コストを添字付けし,以下のように表すことにします.
\(costX_0\), \(costX_1\) はそれぞれ以前の \(costX\), \(costY\) に対応する定数です. PySIMPLE でも同様に定数の添字付けを用いて,以下のように修正します.:
# 油田 i の運転コスト/日
costX = Parameter(value=180, name='油田Xの運転コスト')
costY = Parameter(value=160, name='油田Yの運転コスト')
# 運転コスト/週(目的関数)
problem += costX*x[0] + costY*x[1], '全運転コスト'
↓
# 油田 i の運転コスト/日
costX = Parameter(index=i, value={0: 180, 1: 160}, name='油田運転コスト')
# 運転コスト/週(目的関数)
problem += costX[0]*x[0] + costX[1]*x[1], '全運転コスト'
定数の添字付けは,変数の添字付けと同様に index=i
と指定します.
定数の値を要素ごとに指定する場合は Python の辞書で指定します.
では,実行してみましょう(実行方法については 数理計画問題を解く を参照してください). 最適化経過が出力された後,以下のように以前と同様の結果が得られます.:
油田の運転日数[0].val=1.500000000256067
油田の運転日数[1].val=2.9999999999710107
次に,重油とガスの製品についても一般に記述してみましょう. 定式化において製品集合を導入して製品ノルマを以下のように記述します.
PySIMPLE の記述においても同様に定数の添字付けを用いて表現し,ノルマに関する制約式を以下のように変更します.:
# 製品ノルマ
problem += 6*x[0] + x[1] >= 12, '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= 24, 'ガスノルマ/週'
↓
# 製品を表す添字
j = Element(value=['重油', 'ガス'], name='製品')
# 製品 j のノルマ/週
norma = Parameter(index=j, value={'重油': 12, 'ガス': 24}, name='製品ノルマ')
# 製品ノルマ
problem += 6*x[0] + x[1] >= norma['重油'], '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= norma['ガス'], 'ガスノルマ/週'
新たに製品を表す添字 j の宣言を追加し,製品ノルマを添字 j 付きの定数にします.
上記のように文字列を添字に使用する場合は,文字列を '..'
の中に記述する必要があります.
ここまでの変更をまとめて,集合,変数,定数,制約条件,目的関数を分類し整理すると, 定式化と PySIMPLE の記述は次のようになります.
from pysimple import Problem, Element, Parameter, Variable
problem = Problem(name='油田問題3')
# 油田を表す添字
i = Element(value=[0, 1], name='油田')
## 油田集合
#OilField = Set(value=[0, 1], name='油田集合')
#i = Element(set=OilField)
# 製品を表す添字
j = Element(value=['重油', 'ガス'], name='製品')
## 製品集合
#Product = Set(value=['重油', 'ガス'], name='製品集合')
#j = Element(set=Product)
# 油田 i の運転コスト/日
costX = Parameter(index=i, value={0: 180, 1: 160}, name='油田運転コスト')
# 製品 j のノルマ/週
norma = Parameter(index=j, value={'重油': 12, 'ガス': 24}, name='製品ノルマ')
# 油田 i の運転日数(変数)
x = Variable(lb=0, ub=5, index=i, name='油田の運転日数')
print(costX)
print(norma)
# 運転コスト/週(目的関数)
problem += costX[0]*x[0] + costX[1]*x[1], '全運転コスト'
# 製品ノルマ
problem += 6*x[0] + x[1] >= norma['重油'], '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= norma['ガス'], 'ガスノルマ/週'
# 求解
print(problem)
problem.solve()
# 結果出力
print(x.val)
print(problem.objective.val)
このモデルは PySIMPLE のサンプルとして同梱されています. このサンプルを実行するには次のようにします.:
$ python -m pysimple.sample.tutorial oil3