Search code examples
pythonsympy

Sympy - split polynomial into two parts, positive and negative


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?


Solution

  • 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