2.2.4. 集約・複数の添字

コスト定義式:

# 運転コスト/週(目的関数)
problem += costX[0]*x[0] + costX[1]*x[1], '全運転コスト'

は,すべての油田について運転コストの和をとるという意味なので, これを一般的に記述すると,以下のようになります.

\[\sum_i{costX_i \cdot x_i}\]

対応する PySIMPLE の記述は,以下のようになります.:

Sum(costX[i]*x[i], i)

Sum()\(\displaystyle \sum\) に対応する関数で,:

Sum(和をとる式, 添字)

の書式を持ちます.

次にノルマ制約についても,Sum() を適用したいと考えますが,旧記述では,:

# 製品ノルマ
problem += 6*x[0] +   x[1] >= norma['重油'], '重油ノルマ/週'
problem += 4*x[0] + 6*x[1] >= norma['ガス'], 'ガスノルマ/週'

と各油田の生産量が直接数値で記述されているので,一般化できません. そこで,定式化において定数 \(prodX_{i,j}\) を導入し,制約式を次のように記述します.


\[\begin{split}\begin{array}{ll} \bf{制約条件} \\ \hline \sum_{i \in OilField}{prodX_{i,j} \cdot x_i} \ge norma_j, \quad \forall j \in Product & 製品jのノルマ/週の制約式 \\ \hline \\ \bf{定数} \\ \hline prodX_{i,j}, \quad i \in OilField, j \in Product & 油田iの製品j生産量/日 \\ \hline norma_j, \quad j \in Product & 製品jのノルマ/週 \\ \hline \end{array}\end{split}\]

対応する PySIMPLE の記述は,以下のようになります.:

# 油田 i の製品 j 生産量/日
prodXvalue = {(0,'重油'): 6, (0,'ガス'): 4,
              (1,'重油'): 1, (1,'ガス'): 6}
prodX = Parameter(index=(i,j), value=prodXvalue, name='油田の生産量')

# 製品ノルマ
problem += Sum(prodX[i,j]*x[i], i) >= norma[j], '製品ノルマ'

複数の添字に依存する定数を宣言する際には,index=(i,j,..) と指定します. 複数の添字に対する値は辞書のキーをタプルにします.

Sum() は指定した添字 i のみの和をとります. i, j について和をとる場合は,Sum(任意の式, (i,j)) と記述します.

実行結果は以前と同様になります.

ここまでの変更をまとめて,添字,変数,定数,制約条件,目的関数を分類し整理すると, 定式化と PySIMPLE の記述は次のようになります.


\[\begin{split}\begin{array}{ll} \bf{添字} \\ \hline i \in OilField = \{ 0, 1 \} & 油田を表す添字 \\ \hline j \in Product = \{ 重油, ガス \} & 製品を表す添字 \\ \hline \\ \bf{定数} \\ \hline costX_i, \quad i \in OilField & 油田iの運転コスト/日 \\ \hline norma_j, \quad j \in Product & 製品jのノルマ/週 \\ \hline prodX_{i,j}, \quad i \in OilField, j \in Product & 油田iの製品j生産量/日 \\ \hline \\ \bf{変数} \\ \hline x_i, \quad i \in OilField & 油田iの運転日数/週 \\ \hline \\ \bf{目的関数(最小化)} \\ \hline \sum_{i \in OilField}{costX_i \cdot x_i} & 運転コスト/週 \\ \hline \\ \bf{制約条件} \\ \hline \sum_{i \in OilField}{prodX_{i,j} \cdot x_i} \ge norma_j & 製品jのノルマ/週の制約式 \\ \hline 0 \le x_i \le 5, \forall i \in OilField & 油田iの週あたりの運転日数制約 \\ \hline \end{array}\end{split}\]

from pysimple import Problem, Element, Parameter, Variable, Sum

problem = Problem(name='油田問題4')

# 油田を表す添字
i = Element(value=[0, 1], name='油田')

# 製品を表す添字
j = Element(value=['重油', 'ガス'], name='製品')

# 油田 i の運転コスト/日
costX = Parameter(index=i, value={0: 180, 1: 160}, name='油田運転コスト')

# 製品 j のノルマ/週
norma = Parameter(index=j, value={'重油': 12, 'ガス': 24}, name='製品ノルマ')

# 油田 i の製品 j 生産量/日
prodXvalue = {(0,'重油'): 6, (0,'ガス'): 4,
              (1,'重油'): 1, (1,'ガス'): 6}
prodX = Parameter(index=(i,j), value=prodXvalue, name='油田の生産量')

# 油田 i の運転日数(変数)
x = Variable(lb=0, ub=5, index=i, name='油田の運転日数')

print(costX)
print(norma)
print(prodX)

# 運転コスト/週(目的関数)
problem += Sum(costX[i]*x[i], i), '全運転コスト'

# 製品ノルマ
problem += Sum(prodX[i,j]*x[i], i) >= norma[j], '製品ノルマ'

# 求解
print(problem)
problem.solve()

# 結果出力
print(x.val)
print(problem.objective.val)

このモデルは PySIMPLE のサンプルとして同梱されています. このサンプルを実行するには次のようにします.:

$ python -m pysimple.sample.tutorial oil4