数理最適化セミナーのご案内

2.4 集約・複数の添字

 コスト定義式

cost = costX[0] * x[0] + costX[1] * x[1];

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

\[cost = \sum_{i} costX_i \cdot x_i\]

 対応するC++SIMPLEの記述は,以下のようになります.

cost = sum(costX[i] * x[i], i);

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

sum(和をとる式, 添字)

の書式を持ちます.

 

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

6 * x[0] + x[1] >= norma["重油"];
4 * x[0] + 6 * x[1] >= norma["ガス"];

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

制約条件
$\displaystyle \sum_{i \in OilField} prodX_{i,j} \cdot x_i \geq norma_j$, $\forall j \in Product$ 製品jのノルマ/週の制約式
 
定数
$prodX_{i,j}$, $i \in OilField$, $j \in Product$ 油田iの製品j生産量/日
$norma_j$, $j \in Product$ 製品jのノルマ/週

 対応するC++SIMPLEの記述は,以下のようになります.

Parameter prodX(name = "油田の生産量", index=(i, j));
sum(prodX[i, j] * x[i], i) >= norma[j];

 複数の添字に依存する定数を宣言する際には,index = (i, j, ..)と指定します.上記sum()は指定した添字iのみの和をとります.i, jについて和をとる場合は,sum(任意の式, (i, j)),と記述します.

 

 次に油田の生産量の値を追加した以下のデータファイルを作成します.

"油田運転コスト" = [0] 180 [1] 160;
"製品ノルマ" = ["重油"] 12 ["ガス"] 24;
"油田の生産量" =
[0, "重油"] 6  [1, "重油"] 1
[0, "ガス"] 4  [1, "ガス"] 6
;

 データファイル中の””に囲まれていない,スペース,タブ,改行は無視されます.従って,上記の“油田の生産量”のように,値を複数の行にわたって記述することができます.以上で,変更可能性のある全ての数値データをデータファイルから入力することができました.実行結果は以前と同様になります.

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

集合
$OilField = \{0,1\}$ 油田集合
$Product = \{重油,ガス\}$ 製品集合
 
定数
${\rm costX}_i$, $i \in OilField$ 油田iの運転コスト/日
$norma_j$, $j \in Product$ 製品jのノルマ/週
$prodX_{i,j}$, $i \in OilField$, $j \in Product$ 油田iの製品j生産量/日
 
変数
$x_i$, $i \in OilField$ 油田iの運転日数/週
 
目的関数(最小化)
$\displaystyle \sum_{i \in OilField} {\rm costX}_i \cdot x_i$ 運転コスト/週
 
制約条件
$\displaystyle \sum_{i \in OilField} prodX_{i,j} \cdot x_i \geq norma_j$, $\forall j \in Product$ 製品jのノルマ/週の制約式
$0 \leq x_i \leq 5$, $\forall i \in OilField$ 油田iの週あたりの運転日数制約
// 油田集合
Set OilField(name = "油田集合");
Element i(set = OilField);

// 製品集合
Set Product(name = "製品集合");
Element j(set = Product);

// 油田 i の運転コスト/日
Parameter costX(name = "油田運転コスト", index = i);

// 製品 j のノルマ/週
Parameter norma(name = "製品ノルマ", index = j);

// 油田 i の製品 j 生産量/日
Parameter prodX(name = "油田の生産量", index = (i, j));

// 油田 i の運転日数/週(変数)
Variable x(name="油田の運転日数", index = i);

// 運転コスト/週(目的関数)
Objective cost(name = "全運転コスト", type = minimize);
cost = sum(costX[i] * x[i], i);

// 製品 j のノルマ/週の制約式
sum(prodX[i, j] * x[i], i) >= norma[j];

// 油田 i の週当りの運転日数制約
0 <= x[i] <= 5;

// 求解
solve();

// 結果出力
x[i].val.print();
cost.val.print();

 

 

上に戻る