How do I properly replace index variables in sympy?… here is a solution to the problem.
How do I properly replace index variables in sympy?
I tried summing with IndexBase but don’t understand how to do sequence substitution:
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 feasible case is to replace the range
. Can you explain, how to replace it in general?
Solution
It is common to replace Indexed objects A[i]
instead of IndexedBase A
. This method works if the sum is explicitly written out by doit
before replacing.
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.
Python-scoped substitution is valid because it is simplified by subs
to a Range
object for SymPy, which can be part of a SymPy expression.
>>> S.subs([(A, range(3)), (N, 2)])
Sum(Range(0, 3, 1)[i], (i, 0, 2))
It looks like it should be possible to make a similar replacement with SymPy's SeqFormula
object:
>>> 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 then doit
fails here, with SympifyError: None
, which looks like an error.