3.8.4. 複雑な制約式の記述

添字が動く範囲に制限がある制約式を記述するには多次元の添字が利用できます. いくつか例を見てみましょう.

\(\sum_{i, i\lt j} x_i \ge a_j, \quad \forall j\):

>>> i = Element(value=[1, 2, 3, 4], name='i')
>>> j = Element(set=i.set, name='j')
>>> x = Variable(index=i, name='x')
>>> a = Parameter(index=j, name='a'); a[j] = j
>>> ij = i<j
>>> Sum(x[ij(0)], ij(0)) >= a[ij(1)]
(Sum(x[(i<j)(0)], (i<j)(0))[(i<j)(1)]>=a[(i<j)(1)]):
x[1]>=2
x[1]+x[2]>=3
x[1]+x[2]+x[3]>=4

添字の範囲を集合で指定する場合にも同様の考え方が利用できます.

\(\sum_{i, (i,j)\lt IJ} x_i \ge 1, \quad \forall j\):

>>> i = Element(value=[1, 2], name='i')
>>> j = Element(value=[3, 4], name='j')
>>> ij = Element(value=[(1,3), (1,4), (2,3)], name='ij')
>>> x = Variable(index=i, name='x')
>>> Sum(x[ij(0)], ij(0)) >= 1
(Sum(x[ij(0)], ij(0))[ij(1)]>=1):
x[1]+x[2]>=1
x[1]>=1

複数の条件が絡む場合は,条件を満たす多次元の添字をあらかじめ用意することで記述できます.

\(x_{i,t} \ge x_{i,t+1}, \quad \forall (i,t)\in IT, (i,t+1)\in IT\):

>>> IT = Set(value=[('A',1), ('B',2), ('C',3), ('D',1), ('D',2), ('E',1), ('E',3), ('F',2), ('F',3), ('G',1), ('G',2), ('G',3)], name='IT')
>>> it = Element(set=IT, name='it')
>>> it2 = Element(set=IT, name='it2')
>>> x = Variable(index=it, name='x')
>>> itt = Condition((it,it2(1)), (it(0)==it2(0), it(1)+1==it2(1)))
>>> itt.name = 'itt'
>>> itt
itt[it,it2(1)] in [('D', 1, 2), ('F', 2, 3), ('G', 1, 2), ('G', 2, 3)]
>>> x[itt(0,1)] >= x[itt(0,2)]
(x[itt(0,1)]>=x[itt(0,2)]):
x['D',1]-x['D',2]>=0
x['F',2]-x['F',3]>=0
x['G',1]-x['G',2]>=0
x['G',2]-x['G',3]>=0

ただし,このような場合,無理をして 3 次元の添字を用意するよりも,Python の for 文を利用して 条件を満たす集合を直接作成した方が低コストです.:

>>> it1 = Element(value=[(i,t) for i, t in IT if (i,t+1) in IT], name='it1')
>>> it1.set
Set(name='it1.set', dim=2, value=[('D', 1), ('F', 2), ('G', 1), ('G', 2)])
>>> x[it1] >= x[it1(0),it1(1)+1]
(x[it1]>=x[it1(0),(it1(1)+1)[it1(1)]][it1(0),it1(1)]):
x['D',1]-x['D',2]>=0
x['F',2]-x['F',3]>=0
x['G',1]-x['G',2]>=0
x['G',2]-x['G',3]>=0

別の例を見てみましょう.こちらも条件を満たす集合を直接作成するという考え方は同じです.

\(\sum_{i, (i,j)\in IJ, (i,k) \in IK}x_{i,j} + y_{i,k} \ge 1, \quad \forall j,k\):

>>> i = Element(value=[1, 2], name='i')
>>> j = Element(value=[3, 4], name='j')
>>> k = Element(value=[5, 6], name='k')
>>> IJ = Set(value=[(1,3), (1,4), (2,3)], name='IJ')
>>> IK = Set(value=[(1,5), (1,6), (2,5)], name='IK')
>>> x = Variable(index=IJ, name='x')
>>> y = Variable(index=IK, name='y')
>>> ijk = Element(value=[(_i,_j,_k) for _i, in i.set for _j, in j.set for _k, in k.set if (_i,_j) in IJ and (_i,_k) in IK], name='ijk')
>>> Sum(x[ijk(0,1)] + y[ijk(0,2)], ijk(0)) >= 1
(Sum((x[ijk(0,1)]+y[ijk(0,2)])[ijk(0,1),ijk(2)], ijk(0))[ijk(1,2)]>=1):
x[1,3]+x[2,3]+y[1,5]+y[2,5]>=1
x[1,3]+y[1,6]>=1
x[1,4]+y[1,5]>=1
x[1,4]+y[1,6]>=1

\(\sum_{i, (i,j)\in IJ, (i,k) \in IK}x_{i,j} + y_{i,k} \ge 1, \quad \forall (j,k) \in JK\):

>>> JK = Set(value=[(3,5), (3,6), (4,5)], name='JK')
>>> ijk = Element(value=[(_i,_j,_k) for _i, in i.set for _j, in j.set for _k, in k.set if (_i,_j) in IJ and (_i,_k) in IK and (_j,_k) in JK], name='ijk')
>>> Sum(x[ijk(0,1)] + y[ijk(0,2)], ijk(0)) >= 1
(Sum((x[ijk(0,1)]+y[ijk(0,2)])[ijk(0,1),ijk(2)], ijk(0))[ijk(1,2)]>=1):
x[1,3]+x[2,3]+y[1,5]+y[2,5]>=1
x[1,3]+y[1,6]>=1
x[1,4]+y[1,5]>=1

制約式としてよく出現する境界条件やフロー保存則などは 初期条件やフロー保存則の記述テクニック なども参照してください.