As @unutbu points out, from this question you can see that factor_list
gives the factors of a polynomial in a easier to use fashon.
Unfortunately, SymPy doesn't actually deal with Laurent polynomials (see https://github.com/sympy/sympy/issues/5131). You might actually not get what you are expecting for higher order terms. What SymPy does is it sees that p
is a rational function, so it factors the numerator and denominator separately.
If you also want to do this, you can use something like
n, d = fraction(cancel(p))
factor_list(n)
factor_list(d)
and manipulate the factors separately.
The cancel
will ensure that there are no duplicates, which would otherwise happen automatically with factor(p)
, and it also puts the expression in rational form so that fraction
will work. You could also use p.as_numer_denom()
to skip this step (if it ends up being slow).
Alternately, you may want to consider x
and 1/x
as separate generators of the polynomial. Here's a (corrected) function from the above issue
def aspoly1t(p, t, z=Symbol('z')):
"""
Rewrite p, a polynomial in t and 1/t, as a polynomial in t and z=1/t
"""
pa, pd = cancel(p).as_numer_denom()
pa, pd = Poly(pa, t), Poly(pd, t)
assert pd.is_monomial
d = pd.degree(t)
one_t_part = pa.slice(0, d + 1)
t_part = pa - one_t_part
t_part = t_part.to_field().quo(pd)
one_t_part = Poly.from_list(reversed(one_t_part.rep.rep), *one_t_part.gens, domain=one_t_part.domain)
one_t_part = one_t_part.replace(t, z) # z will be 1/t
ans = t_part.as_poly(t, z) + one_t_part.as_poly(t, z)
return ans
(some day Poly will support this natively as Poly(p, x, 1/x)
) You can then use factor_list
on this:
>>> aspoly1t(p, x)
Poly(2*y*x**2 + 4*y*z, x, z, domain='ZZ[y]')
>>> factor_list(aspoly1t(p, x))
(2, [(Poly(y, x, y, z, domain='ZZ'), 1), (Poly(x**2 + 2*z, x, y, z, domain='ZZ'), 1)])
Note that the factors here are not the same, so it really does matter how you want to interpret and factor your Laurent polynomials.