'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'>
, andtype(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 |