セットの初期化
セットの初期化は、3 つの異なる方法で行うことができます。
外部
セットの初期化の『セット』トピックで説明されているように、セットを初期化する最も単純な方法は、その値を .dat ファイルで明示的にリストすることです。
例えば、次の宣言では、
/* .mod file */
tuple Precedence {
int before;
int after;
}
{Precedence} precedences = ...;
/* .dat file */
precedences = {<1,2>, <1,3>, <3,4>};
タプルの集合を初期化します。
内部
また、事前に定義したセットや操作 (和集合、論理積、差、対称差など) を使用するセット式を使用することで、セットを内部的に (.mod ファイルで) 初期化することもできます。2 つのセット A と B の対称差は、次のようになります。
(A
B) ¥ (A
B)
(式を参照)
例えば、次の宣言では、
{int} s1 = {1,2,3};
{int} s2 = {1,4,5};
{int} i = s1 inter s2;
{int} j = {1,4,8,10} inter s2;
{int} u = s1 union {5,7,9};
{int} d = s1 diff s2;
{int} sd = s1 symdiff {1,4,5};
i を {1} に、u を {1,2,3,5,7,9} に、d を {2,3} に、
sd を {2,3,4,5} に初期化します。
範囲式からセットを初期化することもできます。例えば、次の宣言では、
{int} s = asSet(1..10)
s を {1,2,..,10} に初期化します。
この時点で、範囲によって初期化されたセットが明示的に (範囲とは異なり) 表されていることを確認することが重要です。結果として、以下の形式の宣言では、
{int} s = asSet(1..100000);
すべての値 1、2、...、100000 が明示的に表されたセットが作成されます。一方で、以下の範囲では、
range s = 1..100000;
境界のみが明示的に表されています。
割り当て s2=s1 を記述する場合は、1 つのエレメントを s1 に追加すると、そのエレメントが s2 にも追加されるので注意してください。これを回避したい場合は、次のように記述します。
s1={i|i in s2}
例えば、次の表のステートメントを比較します。
| 記述内容 | 結果 |
|---|---|
|
} |
{1 2 3} |
|
} |
{1 2}
|
ジェネリック集合
OPL は、リレーショナル・データベース照会に似た表現力を持つジェネリック集合 をサポートします。例えば、次の宣言では、
{int} s = {i | i in 1..10: i mod 3 == 1};
s をセット {1,4,7,10} で初期化します。ジェネリック集合は、以下の式の論理積です。
p in S : condition
ここで、p はパラメーター (またはパラメーターのタプル)、S は範囲または有限集合、condition はブール式です。
これらの式は、forall ステートメントおよび集約演算子でも使用されます。詳しくは、仮パラメーターを参照してください。
以下の宣言は、
{string} Resources ...;
{string} Tasks ...;
Tasks res[Resources] = ...;
tuple Disjunction {
{string} first;
{string} second;
}
{Disjunction} disj = {<i,j> |
r in Resources, ordered i,j in res[r]
};
より興味深い例です。これは、式の論理積を示しています。詳しくは、仮パラメーターを参照してください。ジェネリック集合は、多くの場合、データ構造 (例えば、ファイルに保管されているデータ) を、モデルを効果的に記述するのに適したデータ構造に変換する場合に有用です。例えば、以下のような宣言について考えてみます。
{string} Nodes ...;
int edges[Nodes][Nodes] = ...;
これは、ブール隣接行列の観点から、グラフのエッジを記述しています。エッジのスパース表現をモデルで使用することが重要な場合があります (例えば、エッジは配列の添字付けに使用されるため)。以下の宣言では、
tuple Edge {
Nodes o;
Nodes d;
}
{Edge} setEdges = {<o,d> | o,d in Nodes : edges[o][d]==1};
このスパース表現を単純なジェネリック集合を使用して計算します。もちろん、セットの汎用配列を定義することも可能です。例えば、次の宣言では、
{int} a[i in 3..4] = {e | e in 1..10: e mod i == 0};
a[3] を {3,6,9} に、a[4] を {4,8} に初期化します。