Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collecting like term of an expression in Sympy

I am currently dealing with functions of more than one variable and need to collect like terms in an attempt to simplify an expression.

Say the expression is written as follows:

x = sympy.Symbol('x')
y = sympy.Symbol('y')
k = sympy.Symbol('k')
a = sympy.Symbol('a')

z = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zEx = z.expand()
print type(z)
print type(zEx)

EDIT: Formatting to add clarity and changed the expression z to make the problem easier to understand.

Say z contains so many terms, that sifting through them by eye. and selecting the appropriate terms, would take an unsatisfactory amount of time.

I want to collect all of the terms which are ONLY a multiple of a**1. I do not care for quadratic or higher powers of a, and I do not care for terms which do not contain a.

The type of z and zEx return the following:

print type(z)
print type(zEx)
>>>
<class 'sympy.core.add.Add'>
<class 'sympy.core.mul.Mul'>

Does anyone know how I can collect the terms which are a multiple of a , not a^0 or a^2?

tl'dr

Where z(x,y) with constants a and k described by z and zEx and their type(): How can one remove all non-a terms from z AND remove all quadratic or higher terms of a from the expression? Such that what is left is only the terms which contain a unity power of a.

like image 585
hkh Avatar asked Feb 26 '16 05:02

hkh


People also ask

How do you evaluate an expression in SymPy?

evalf() function and subs() function from sympy is used to evaluate algebraic expressions. Example 1: In this example, we import symbols from sympy package. An expression is created and evalf() function is used to evaluate the expression.

How do you write the square root in SymPy?

With the help of sympy. sqrt() method, we can find the square root of any number by using sympy. sqrt() method. Return : Return square root of any number.

How do you write a natural log in SymPy?

With the help of sympy. log() function, we can simplify the principal branch of the natural logarithm. Logarithms are taken with the natural base, e. To get a logarithm of a different base b, use log(x, y), which is essentially short-hand for log(x) / log(y).

How do you write E in SymPy?

Note that by default in SymPy the base of the natural logarithm is E (capital E ). That is, exp(x) is the same as E**x .


3 Answers

In addition to the other answers given, you can also use collect as a dictionary.

print(collect(zEx,a,evaluate=False)[a])

yields the expression

k*x**2 + k*y**2
like image 84
cameronroytaylor Avatar answered Sep 29 '22 14:09

cameronroytaylor


In the end it is just an one-liner. @asmeurer brought me on the right track (check the comments below this post). Here is the code; explanations can be found below:

from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys

x, y, k, a = symbols('x y k a')

# modified string: I added a few terms
z = x*(k*a**9) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*(k*a**1) - k*a**3 + y*a**5

zmod = Add(*[argi for argi in z.args if argi.has(a)])

Then zmod is

a**9*k*x - a**8*k + a**5*y - a**3*k + a*k*x

So let's look at this more carefully:

z.args

is just a collection of all individual terms in your expression (please note, that also the sign is parsed which makes things easier):

(k*x**2, a**5*y, -a**3*k, -a**8*k, a*k*x, a**9*k*x, k**2*x*y, k**3*x**2*y)

In the list comprehension you then select all the terms that contain an a using the function has. All these terms can then be glued back together using Add which gives you the desired output.

EDIT

The above returns all all the expressions that contain an a. If you only want to filter out the expressions that contain a with unity power, you can use collect and Mul:

from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys

x, y, k, a = symbols('x y k a')

z2 = x**2*(k*a**1) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*k*a - k*a**3 + y*a**1

zc = collect(z2, a, evaluate=False)
zmod2 = Mul(zc[a], a)

then zmod2 is

a*(k*x**2 + k*x + y)

and zmod2.expand()

a*k*x**2 + a*k*x + a*y

which is correct.

With the updated z you provide I run:

z3 =  k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zc3 = collect(z3.expand(), a, evaluate=False)
zmod3 = Mul(zc3[a], a)

and then obtain for zmod3.expand():

a*k*x**2 + a*k*y**2

Is this the result you were looking for?

PS: Thanks to @asmeurer for all these helpful comments!

like image 24
Cleb Avatar answered Sep 29 '22 15:09

Cleb


To iterate over the terms of an expression use expr.args.

I'm unclear what a is supposed to be, but the collect function may do what you want.

like image 35
asmeurer Avatar answered Sep 29 '22 13:09

asmeurer