3.8.6. 添字の連続した部分の表現

添字の連続した 3 つの部分の変数を記述してみましょう. 添字が等差数列の場合は単純です.:

>>> i = Element(value=range(5), name='i')  # i in (0, 1, 2, 3, 4)
>>> x = Variable(index=i, name='x')
>>> i3 = Element(set=i.set[:-2], name='i3')  # i3 in (0, 1, 2)
>>> x[i3] + x[i3+1] + x[i3+2]
((x[i3]+x[(i3+1)[i3]][i3])[i3]+x[(i3+2)[i3]][i3]):
x[0]+x[1]+x[2]
x[1]+x[2]+x[3]
x[2]+x[3]+x[4]

では,文字列のように添字の順番に規則性がない場合はどうでしょうか. このような場合,連続した 2 つの部分であれば pysimple.Set.next メソッドを利用して表現することができます.:

>>> S = Set(value='ABCDE', name='S')
>>> s = Element(set=S, name='s')  # s in (A, B, C, D, E)
>>> y = Variable(index=s, name='y')
>>> s2 = Element(set=S[:-1], name='s2')  # s2 in (A, B, C, D)
>>> y[s2] + y[S.next(s2)]
(y[s2]+y[S.next(s2)[s2]][s2]):
y['A']+y['B']
y['B']+y['C']
y['C']+y['D']
y['D']+y['E']

しかし,この方法は 3 つの場合には適用できません. これは Set.next(Element) の戻り値は Parameter となるため, Set.next(Set.next(Element)) は Set.next(Parameter) となるためです.:

s3 = Element(set=S[:-2], name='s3')  # s3 in (A, B, C)
>>> S.next(S.next(s3))
TypeError: unhashable type: 'Parameter'

これを回避する方法として,2 つ先の添字を対応させる Parameter を自分で作成してしまう方法が考えられます.:

>>> next2 = Parameter(index=s3, value={_s: S.next(S.next(_s)) for _s, in s3.set}, name='next2')
>>> next2
next2['A']='C'
next2['B']='D'
next2['C']='E'
>>> y[s3] + y[S.next(s3)] + y[next2[s3]]
((y[s3]+y[S.next(s3)[s3]][s3])[s3]+y[next2[s3]][s3]):
y['A']+y['B']+y['C']
y['B']+y['C']+y['D']
y['C']+y['D']+y['E']

この考え方は汎用化することができ,連続した N つの部分の表現も可能となります.:

>>> N = 3
>>> k = Element(value=range(len(S)-N+1), name='k')
>>> sk = Element(set=S[:N], name='sk')
>>> nextk = Parameter(index=(k,sk), value={(kk, ssk): v for kk, in k.set for (ssk,), (v,) in zip(S[:N], S[kk:])}, name='nextk')
>>> nextk
nextk[0,'A']='A'
nextk[0,'B']='B'
nextk[0,'C']='C'
nextk[1,'A']='B'
nextk[1,'B']='C'
nextk[1,'C']='D'
nextk[2,'A']='C'
nextk[2,'B']='D'
nextk[2,'C']='E'
>>> Sum(y[nextk[k,sk]], sk)
Sum(y[nextk[k,sk]][k,sk], sk):
y['A']+y['B']+y['C']
y['B']+y['C']+y['D']
y['C']+y['D']+y['E']