3.3.2. 集合クラス Set

集合は Set というクラスで表現されます.

集合は value キーワードを用いて宣言します. PySIMPLE の集合はすべて順序集合です.また,集合の要素を宣言後に変更することはできません.

以下の例では,自然数 1, 2, 3 を要素とする集合 S を定義しています.:

S = Set(value=[1, 2, 3])

集合の要素が等差数列である場合は range 関数が便利です. 以下の例では,自然数 1, 2, 3 を要素とする集合 S を定義しています.:

S = Set(value=range(1, 4))

添字クラス Element と併用することで,変数クラス Variable制約式クラス Constraint定数クラス Parameter整数変数クラス IntegerVariable0-1 整数変数クラス BinaryVariable式 クラス を集合の要素ごとに設定できます. 以下の例では 3 個の変数 y[1], y[2], y[3], 3 個の定数 b[1], b[2], b[3] を定義しています.:

S = Set(value=[1, 2, 3])
i = Element(set=S)
y = Variable(index=i)
b = Parameter(index=i)

集合の要素には自然数だけでなく,文字列も使用することができます. 以下の例では 2 個の整数変数 z['p'], z['q'],2 個の式 g['p'], g['q'] を定義しています.:

T = Set(value=['p', 'q'])
j = Element(set=T)
z = IntegerVariable(index=j)
g = 2*x[j] + 3*y[j]

要素の文字列は必ずしも一文字である必要はありません.:

T = Set(value=['before', 'after'])

要素の文字列が一文字である場合は直接記述することもできます.:

T = Set(value='pq')  # Set(value=['p', 'q']) と同じ

集合の要素に文字列を使用した場合は,対象を個別に記述する際に, 添字部分にクォート ' またはダブルクォート " を用いる必要があります.:

-1 <= z['p']

一括して記述する場合にはクォートでまたはダブルクォートで囲んではいけません.:

-1 <= z[j]

ある集合に対して定義された添字は,その部分集合に対しても自動的に定義されます.

添字を部分集合のみ(あるいは部分集合以外)で走らせたい場合は,集合と添字の包含関係を表す演算子 <, > を利用します. 以下の例では,定数 a[1], a[2] に -1 を,a[3] に 1 を設定しています.:

S = Set(value=[1, 2, 3])
T = Set(value=[1, 2])
i = Element(set=S)
a = Parameter(index=i)
a[i<T] = -1  # i が T に含まれる場合
a[i>T] = 1   # i が T に含まれない場合

多次元集合(要素の組の集合)を定義することもできます. 以下の例では,二次元の添字をもつ変数 x を定義しています. 各次元のすべての組み合わせについて変数を定義したいわけではない場合などに,多次元集合を使用します.:

IJ = Set(value=[('a', 1), ('b', 2)])
ij = Element(set=IJ)
x = Variable(index=ij)  # x['a',1] と x['b',2] が定義される
x[ij] >= 0              # x['a',1] と x['b',2] に下限を設定する

集合の要素数を取得するには,len 関数を使用します. 以下の例では,n に集合 S の要素数を格納しています.:

n = len(S)

集合に順序がついていることを利用すると漸化式や漸化不等式を取り扱うことが可能です.

次の例では漸化不等式 \(x_{p} \le x_{q}\), \(x_{q} \le x_{r}\), \(x_{r} \le x_{s}\) を記述しています.:

S = Set(value=['p', 'q', 'r', 's'])
i = Element(set=S)
x = Variable(index=i)
i1 = i != S[-1]
x[i1] <= x[S.next(i1)]

最後の条件式 i != S[-1] は i=='s' の場合を除外するためです. 集合[index] で集合の index 番目の要素を取り出します.-1 は最後の要素を表します. 上記の例では next 関数を利用しましたが,以下のように prev 関数を利用することもできます.:

i0 = i != S[0]
x[S.prev(i0)] <= x[i0]

集合の要素が整数の場合は,次のように next や prev を用いない記述も可能です.:

S = Set(value=[1, 2, 3, 4])
i = Element(set=S)
x = Variable(index=i)
i4 = i != 4
x[i4] <= x[i4+1]

同様に次の記述も可能です.:

i1 = i != 1
x[i1-1] <= x[i1]

整数以外の要素からなる集合を利用する場合,条件式において i+1, i-1 等の要素間の演算が使用できない事が, next, prev に頼らざるを得ない主な理由です.

次の例では,定数 a['p'], a['q'], a['r'] にそれぞれ 0, 2, 4(2ずつ増加)を設定します.

S = Set(value=['p', 'q', 'r'])
i = Element(set=S)
a = Parameter(index=i)
a[i] = 2*S.index(i)

以下のように記述しても同じ意味です.:

S = Set(value=['p', 'q', 'r'])
i = Element(set=S)
a = Parameter(index=i)
p = Element(value=range(len(S)))
a[S[p]] = 2*p

集合の要素が整数である場合は,次のように index[] を用いない記述も可能です. 以下の例では,定数 a[1], a[2], a[3] にそれぞれ 2, 4, 6(2ずつ増加)を設定します.:

S = Set(value=[1, 2, 3])
i = Element(set=S)
a = Parameter(index=i)
a[i] = 2*i