Andrey Komendantyan
Andrey Komendantyan

Reputation: 43

How to correctly substitude indexed variable in sympy?

I try to use IndexBase for summation, but dont understand, how to do substitution of sequences:

A = sympy.IndexedBase('A')
i = sympy.Symbol('i', integer=True)
N = sympy.Symbol('N', integer=True)

S = sympy.Sum(A[i], (i, 0, N))
Trace = sympy.Sum(A[i, i], (i, 0, N))

S.subs([(A, range(3)), (N, 2)]).doit()  # python3 range
# result: 3

S.subs([(A, [8, 16, 32]), (N, 2)]).doit()
# result: A[0] + A[1] + A[2]

S.subs([(A, numpy.arange(3)), (N, 2)]).doit()
# result: A[0] + A[1] + A[2]

Trace.subs([(A, numpy.diag([2, 4, 8])), (N, 2)]).doit()
# result: A[0, 0] + A[1, 1] + A[2, 2]

The only case which works is substitution of range. Could you explain, how to substitude it in general case?

Upvotes: 4

Views: 1678

Answers (1)

user6655984
user6655984

Reputation:

Usually one substitutes for Indexed objects A[i] rather than for IndexedBase A. This works if the sum is written out explicitly by doit prior to substitution.

S.subs(N, 2).doit().subs([(A[i], i**2) for i in range(3)])   # 5

or

values = [8, 16, 32]
S.subs(N, 2).doit().subs([(A[i], values[i]) for i in range(3)])  # 56

Similarly, Trace.subs(N, 2).doit().subs([(A[i, i], values[i]) for i in range(3)]) returns 56.


The substitution by Python range works because it's sympified by subs into SymPy's Range object, which is something that can be a part of a SymPy expression.

>>> S.subs([(A, range(3)), (N, 2)])
Sum(Range(0, 3, 1)[i], (i, 0, 2)) 

It looks like one should be able to similarly substitute with SymPy's SeqFormula objects:

>>> n = sympy.symbols('n')
>>> S.subs([(A, sympy.sequence(n**2, (n, 0, 3))), (N, 3)]) 
Sum(SeqFormula(n**2, (n, 0, 3))[i], (i, 0, 3))

But subsequent doit fails here with SympifyError: None which looks like a bug.

Upvotes: 3

Related Questions