セットの初期化

セットの初期化は、3 つの異なる方法で行うことができます。

外部

セットの初期化の『セット』トピックで説明されているように、セットを初期化する最も単純な方法は、その値を .dat ファイルで明示的にリストすることです。

例えば、次の宣言では、


/* .mod file */
tuple Precedence {
  int before;
  int after;
}
{Precedence} precedences = ...;
/* .dat file */
precedences = {<1,2>, <1,3>, <3,4>};

タプルの集合を初期化します。

内部

また、事前に定義したセットや操作 (和集合、論理積、差、対称差など) を使用するセット式を使用することで、セットを内部的に (.mod ファイルで) 初期化することもできます。2 つのセット AB の対称差は、次のようになります。

(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); 

すべての値 12、...、100000 が明示的に表されたセットが作成されます。一方で、以下の範囲では、


range s = 1..100000; 

境界のみが明示的に表されています。

割り当て s2=s1 を記述する場合は、1 つのエレメントを s1 に追加すると、そのエレメントが s2 にも追加されるので注意してください。これを回避したい場合は、次のように記述します。

s1={i|i in s2}

例えば、次の表のステートメントを比較します。

表 1. モデル・ファイルでのセットの初期化
記述内容 結果

{int} s1={1,2};

{int} s2=s1;

execute

{

s2.add(3);

writeln(s1);

}

{1 2 3}

{int} s1={1,2};

{int} s2={ i | i in s1};

//{int} s2=s1;

execute

{

s2.add(3);

writeln(s1);

}

{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} に初期化します。