I have a large polynomial in Sympy, and I need to split it into two polynomials. Where in the first are terms(monomials) with a positive sign, and in the second are all terms(monomials) with a negative sign. How to do it with good performance?
An expression can be treated like a sum of terms. Each term has an explicit or implicit coefficient that can be extracted with .as_coeff_Mul()
. Here's how the pieces work:
>>> from sympy import *
>>> from sympy.abc import x, y
>>> (x*y*3).as_coeff_Mul()
>>> (3, x*y)
>>> _[0] # a numerical value will always be first
>>> 3
>>> _.is_positive
True
>>> (x + y).args
(x, y)
>>> Add.make_args(x + y)
(x, y)
>>> (x*y).args
(x, y)
>>> Add.make_args(x*y)
(x*y,)
>>> predicate = lambda x: x>1
>>> istrue,isfalse = sift(range(4), predicate, binary=True)
>>> istrue
[2, 3]
Sifting these terms based on the coefficient sign will give you the two groups you are interested in:
>>> from sympy import sift, Add
>>> ispos = lambda x: x.as_coeff_Mul()[0].is_positive
>>> p = -x*y**2/3 + 4*x*y + 3*x - y
>>> pos, neg = sift(Add.make_args(p), ispos, binary=True)
>>> pos
[3*x, 4*x*y]
To reconstruct the pieces, add them together:
>>> ppos, pneg = map(Add, (pos, neg))
>>> assert ppos == 3*x + 4*x*y