Using sympy to sum over a range of symbols - python

Consider two sets i,j which both have m elements. Say we have an expression which describes a sum of terms. Each term can be described as a product of an element of i and j. Now, I would like to sum over each element of j, where each element has the range [i1,i2,...,im].
In the context of python & sympy, this is difficult since sympy's Sum describes the summation variable with (symbol,start,stop), which assume integer steps.
To demonstrate what I mean, consider the following code:
>>> from sympy import *
>>> i = symbols('i1,i2,i3,i4') # for the case m = 4
>>> j = symbols('j1,j2,j3,j4')
Here I use permutations to setup the expression:
>>> from itertools import permutations as perm
>>> c = list(perm(range(4),2))
>>> a,b = c[0]
>>> expr = i[a]*j[b]
>>> for a,b in c[1:]:
>>> expr += i[a]*j[b]
>>> print(expr)
i1*j2 + i1*j3 + i1*j4 + i2*j1 + i2*j3 + i2*j4 + i3*j1 + i3*j2 + i3*j4 + i4*j1 + i4*j2 + i4*j3
Now, using Sum over each j with range of i. It would be ideal if I could write one of the following:
>>> s = Sum(expr,(j,i))
>>> s = Sum(expr,(j1,i),(j2,i),...,(jm,i))
But that's not canonical with the sympy documentation. Are there any other methods which can be used to solve this problem?
Edit:
In this post, I tried to isolate the problem by only using elements i,j in expr. The full context problem is where expr is a sum of Kronecker Delta functions of i,j and using a sum over index set j, where each element of j has range i. For example:
>>> from sympy import KroneckerDelta as KD
>>> expr = KD(i[0],j[1]) # Only doing j[1] to reduce clutter
>>> print(expr)
KroneckerDelta(i1,j2)
>>> s = Sum(expr,(j[1],i)).doit()
>>> print(s)
# Desired output to look like:
1 + KroneckerDelta(i1,i2) + KroneckerDelta(i1,i3) + KroneckerDelta(i1,i4)
This is the reason for which I phrased my question as: summing over each element of j with range i.

IndexedBase can act as a symbolic, integer-indexed array:
>>> from sympy import *
>>> from sympy.abc import k,l
>>> i,j = map(IndexedBase,'ij')
>>> Sum(i[k]*j[l],(k,1,2),(l,1,2)).doit().expand()
i[1]*j[1] + i[1]*j[2] + i[2]*j[1] + i[2]*j[2]
>>> Sum(Piecewise((i[k]*j[l],Ne(k,l)),(0,True)),(k,1,2),(l,1,2)).doit()
i[1]*j[2] + i[2]*j[1]
It's not clear whether you want the cross terms when the indicices are the same, so both versions are shown.

Related

Symbolic simplification of algebraic expressions composed of complex numbers

I have a question concerning the symbolic simplification of algebraic expressions composed of complex numbers. I have executed the following Python script:
from sympy import *
expr1 = 3*(2 - 11*I)**Rational(1, 3)*(2 + 11*I)**Rational(2, 3)
expr2 = 3*((2 - 11*I)*(2 + 11*I))**Rational(1, 3)*(2 + 11*I)**Rational(1, 3)
print("expr1 = {0}".format(expr1))
print("expr2 = {0}\n".format(expr2))
print("simplify(expr1) = {0}".format(simplify(expr1)))
print("simplify(expr2) = {0}\n".format(simplify(expr2)))
print("expand(expr1) = {0}".format(expand(expr1)))
print("expand(expr2) = {0}\n".format(expand(expr2)))
print("expr1.equals(expr2) = {0}".format(expr1.equals(expr2)))
The output is:
expr1 = 3*(2 - 11*I)**(1/3)*(2 + 11*I)**(2/3)
expr2 = 3*((2 - 11*I)*(2 + 11*I))**(1/3)*(2 + 11*I)**(1/3)
simplify(expr1) = 3*(2 - 11*I)**(1/3)*(2 + 11*I)**(2/3)
simplify(expr2) = 15*(2 + 11*I)**(1/3)
expand(expr1) = 3*(2 - 11*I)**(1/3)*(2 + 11*I)**(2/3)
expand(expr2) = 15*(2 + 11*I)**(1/3)
expr1.equals(expr2) = True
My questions is why the simplifications does not work for expr1 but
works for expr2 thoug the expressions are algebraically equal.
What has to be done to get the same result from simplify for expr1 as for expr2?
Thanks in advance for your replys.
Kind regards
Klaus
You can use the minimal polynomial to place algebraic numbers into a canonical representation:
In [30]: x = symbols('x')
In [31]: p1 = minpoly(expr1, x, polys=True)
In [32]: p2 = minpoly(expr2, x, polys=True)
In [33]: p1
Out[33]: Poly(x**2 - 60*x + 1125, x, domain='QQ')
In [34]: p2
Out[34]: Poly(x**2 - 60*x + 1125, x, domain='QQ')
In [35]: [r for r in p1.all_roots() if p1.same_root(r, expr1)]
Out[35]: [30 + 15⋅ⅈ]
In [36]: [r for r in p2.all_roots() if p2.same_root(r, expr2)]
Out[36]: [30 + 15⋅ⅈ]
This method should work for any two expressions representing algebraic numbers through algebraic operations: either they give the precise same result or they are distinct numbers.
It works (but nominally) for expr1 because when the product in the radical is expanded you get the cube root of 125 which is reported as 5. But SymPy tries to be careful about putting radicals together under a common exponent, an operation that is not generally valid (e.g. root(-1, 3)*root(-1,3) != root(1, 3) because the principle values are used for the roots. But if you want the bases to combine under a common exponent, you can force it to happen with powsimp:
>>> from sympy.abc import x, y
>>> from sympy import powsimp, root, solve, numer, together
>>> powsimp(root(x,3)*root(y,3), force=True)
(x*y)**(1/3)
But that only works if the exponents are the same:
>>> powsimp(root(x,3)*root(y,3)**2, force=True)
x**(1/3)*y**(2/3)
As you saw, equals was able to show that the two expressions were the same. One way this could be done is to solve for root(2 + 11*I, 3) and see if any of the resulting expression are the same:
>>> solve(expr1 - expr2, root(2 + 11*I,3))
[0, 5/(2 - 11*I)**(1/3)]
We can check the non-zero candidate:
>>> numer(together(_[1]-root(2+11*I,3)))
-(2 - 11*I)**(1/3)*(2 + 11*I)**(1/3) + 5
>>> powsimp(_, force=True)
5 - ((2 - 11*I)*(2 + 11*I))**(1/3)
>>> expand(_)
0
So we have shown (with force) that the expression was the same as that for which we solved. (And, as Oscar showed while I was writing this, minpoly is a nice candidate when it works: e.g. minpoly(expr1-expr2) -> x which means expr1 == expr2.)

How can I automatically generate an expression in Sympy using the coefficients of a 5th-order expression?

How can I automatically write a 5th order expression using a for loop using sympy in Python?
For example, let the expression be: y = 2x^5 + 3x^4 + 17x^3 + x^2 - 8x +101
I have the coefficients in the 5th order expression as a list. You can think of it like [101,-8,1,17,3,2].
I want to create a 5th order expression using the elements of this list using sympy.
I would be very grateful if you could help with this.
from sympy import *
x = symbols("x")
coeff = [101,-8,1,17,3,2]
# create a list of exponents going from 0 to 5 (included)
expon = list(range(len(coeff)))
# create a list of polynomial terms using list-comprehension syntax
# and sum up the elements
expr = sum(c * x**e for c, e in zip(coeff, expon))
Edit to satisfy comment:
from sympy import *
x = symbols("x")
coeff = [101,-8,1,17,3,2]
# create a list of exponents going from 0 to 5 (included)
expon = list(range(len(coeff)))
terms = []
for c, e in zip(coeff, expon):
terms.append(c * x**e)
expr = sum(terms)
Poly can accept a list of coefficients and the generator directly. It expects them in order from high to low. If you want an Expr, not a Poly, you can append the as_expr() call:
>>> little_endian = [101,-8,1,17,3,2]
>>> Poly(reversed(little_endian), x).as_expr()
2*x**5 + 3*x**4 + 17*x**3 + x**2 - 8*x + 101

SymPy: Expression for Summation of Symbols in a List

I'm writing a program that evaluates the power series sum_{m=0}{oo} a[m]x^m, where a[m] is recursively defined: a[m]=f(a[m-1]). I am generating symbols as follows:
a = list(sympy.symbols(' '.join([('a%d' % i) for i in range(10)])))
for i in range(1, LIMIT):
a[i] = f_recur(a[i-1], i-1)
This lets me refer to the symbols a0,a1,...,a9 using a[0],a[1],...,a[9], and a[m] is a function of a[m-1] given by f_recur.
Now, I hope code up the summation as follows:
m, x, y = sympy.symbols('m x y')
y = sympy.Sum(a[m]*x**m, (m, 0, 10))
But, m is not an integer so a[m] throws an Exception.
In this situation, where symbols are stored in a list, how would you code the summation? Thanks for any help!
SymPy's Sum is designed as a sum with a symbolic index. You want a sum with a concrete index running through 0, ... 9. This could be Python's sum
y = sum([a[m]*x**m for m in range(10)])
or, which is preferable from the performance point of view (relevant issue)
y = sympy.Add(*[a[m]*x**m for m in range(10)])
In either case, m is not a symbol but an integer.
I have a work-around that does not use sympy.Sum:
x = sympy.symbols('x')
y = a[0]*x**0
for i in range(1, LIMIT):
y += a[i]*x**i
This does the job, but sympy.Sum is not used.
Use IndexedBase instead of Symbol:
>>> a = IndexedBase('a')
>>> Sum(x**m*a[m],(m,1,3))
Sum(a[m]*x**m, (m, 1, 3))
>>> _.doit()
a[1]*x + a[2]*x**2 + a[3]*x**3

How do you substitute the values of sympy.core.add.add objects when they are in a list?

I have a list of sympy objects that I would like to evaluate at a certain point (x0 = 1 , x1=1), I have tried using evalf and subs in a for loop but have had no luck. Here is my code:
from sympy import *
b = [3*x0**2 + 4*x1, 4*x0]
for i in b:
i = i.subs({x0:1, x1:1})
print(b)
It returns the same list as before.
In your loop you're not operating on b at all.
You could do this.
>>> from sympy import *
>>> var('x0 x1')
(x0, x1)
>>> b = [3*x0**2 + 4*x1, 4*x0]
>>> [_.subs({x0:1, x1:1}) for _ in b]
[7, 4]
Notice that this code operates on each expression within b individually because b as a whole is not a sympy expression.

Sympy parser doesn't pass the right constant

>>>from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, function_exponentiation)
>>> transformations = standard_transformations + (function_exponentiation,)
>>>parse= parse_expr('2x', transformations=transformations)
parse = parse_expr("2x", transformations=transformations)
>>> parse.coeff("x",0)
2
>>> parse.coeff("x")
2
>>> parse = parse_expr("2x+5", transformations=transformations)
>>> parse.coeff("x")
2
>>> parse.coeff("x",0)
5
I am quite new to python and sympy.
The problem here is that any time I want to get the constant 0 it returns the coefficient of x. But this doesn't happen when the constant is not zero(shown in the second equation). I am trying to use this to solve linear equations in which I don't know the user input. But it keeps giving me a wrong answer when there is no constant attached after x.
There is some discussion on Github: https://github.com/sympy/sympy/issues/5657
One way to do it is to convert to a polynomial:
>>> (2*x + 3).as_poly()
Poly(2*x + 3, x, domain='ZZ')
>>> (2*x + 3).as_poly().nth(0)
3
>>> (2*x + 3).as_poly().nth(1)
2
>>> (2*x).as_poly().nth(0)
0
>>> (2*x).as_poly().nth(1)
2
Unfortunately converting to a Poly first is slower.

Categories

Resources