'Extract coefficients and corresponding monomials from a given polynomial in SymPy

Given a symbolic multivariate polynomial P, I need to extract both its coefficients and corresponding monomials as lists:

def poly_decomp(P):
    ....
    return coeffs, monoms

such that P is the dot product of coefficients and monomials, e.g., if P(x,y) = ax**2 + bxy + cy**2 then we should get coeffs = [a, b, c] and monoms = [x**2, x*y, y**2].

Getting the coefficients is easy since the function is built in coeffs = P.coeffs(). However, I'm having trouble getting the monomials. Here the build in function returns a list of exponents, e.g., in the example above we would get P.monoms() = [(2,0),(1,1),(0,2)].

Obviously the idea would be, provided a list of the variables var=[x,y], to do something like

powers = P.monoms() 
monoms = [sympy.prod(x**k for x,k in zip(var, mon)) for mon in powers ]

However the polynomial class doesn't seem to offer a function that returns a list of variables. All I could find were the methods free_symbols and free_symbols_in_domain which return the sets {a, b, c, x, y} and {a, b, c}. So by taking their difference one could get the set {x, y}.

However then we are faced with the issue that the sets are unordered, hence converting it into a list might mess up the order in different ways depending on the number of variables.

I am kind of at a loss here. Any tips?



Solution 1:[1]

The property gens (short for generators) holds a tuple of symbols or other suitable objects that the polynomial is defined over.

from sympy import symbols, Poly

x, y = symbols('x y')
p = Poly(x**3 + 2*x**2 + 3*x*y + 4*y**2 + 5*y**3, x, y)
q = Poly(x**3 + 2*x**2 + 3*x*y + 4*y**2 + 5*y**3, y, x)
print(p.gens)  # (x, y)
print(q.gens)  # (y, x)

So,

[prod(x**k for x, k in zip(p.gens, mon)) for mon in p.monoms()]

returns [x**3, x**2, x*y, y**3, y**2].

Note also that the generators can be types other than symbols, for example:

import sympy

x = sympy.symbols('x')
poly = sympy.poly(sympy.sqrt(2) * x**2)
print('generators: {g}'.format(g=poly.gens))
print('monomials: {m}'.format(m=poly.monoms()))
print('coefficients: {c}'.format(c=poly.coeffs()))

which prints:

generators: (x, sqrt(2))
monomials: [(2, 1)]
coefficients: [1]

where:

  • type(poly.gens[0]) is <class 'sympy.core.symbol.Symbol'>, and
  • type(poly.gens[1]) is <class 'sympy.core.power.Pow'>.

A relevant method is sympy.polys.polytools.Poly.as_dict, which returns a dict with keys that are monomials, and values that are the corresponding coefficients.

Solution 2:[2]

Maybe late to answer, but just to supplement the great answer above:

In Sympy 1.8, a Poly object x has the attribute .args, i.e.:

import sympy as sp  

x = sp.Poly(x**3 + 2*x**2 + 3*x*y + 4*y**2 + 5*y**3)
x.args[1:] #returns (x,y)

and x.args[1:] will be sorted based on how you defined your symbols. For instance, if your polynomial has n variables in terms of the symbols:

a = sp.symbols('a:n')

then x.args[1:] would be in the order (a0, ..., an). Knowing this and x.monoms(), I'm sure it could be put in the format that you wanted.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 0 _
Solution 2 fishboi