This tutorial tries to give an overview of the functionality concerning polynomials within SymPy. All code examples assume:
>>> from sympy import *
>>> x, y, z = symbols('xyz')
These functions provide different algorithms dealing with polynomials in the form of SymPy expression, like symbols, sums etc.
The function div() provides division of polynomials with remainder. That is, for polynomials f and g, it computes q and r, such that f == g*q + r and degree(r) < q. For polynomials in one variables with coefficients in a field, say, the rational numbers, q and r are uniquely defined this way.
>>> from sympy import pprint
>>> import sys
>>> sys.displayhook = pprint
>>> f = 5*x**2 + 10*x + 3
>>> g = 2*x + 2
>>> q, r = div(f, g, x, y)
>>> q
5*x
5/2 + 
2
>>> r
2
>>> (q*g + r).expand()
2
3 + 10*x + 5*x
As you can see, q has a noninteger coefficient. If you want to do division only in the ring of polynomials with integer coefficients you can specify an additional parameter.
>>> q, r = div(f, g, coeff='int')
>>> q
0
>>> r
13 + 5*x**2 + 15*x
But be warned, that this ring is no longer euclidean and that the degree of the remainder doesn’t need to be smaller than that of f. Since 2 doesn’t divide 5, 2*x doesn’t divide 5*x**2, even if the degree is smaller. But:
>>> g = 5*x + 1
>>> q, r = div(f, g, x, coeff='int')
>>> q
x
>>> r
13 + 14*x
>>> (q*g + r).expand()
13 + 5*x**2 + 15*x
This also works for polynomials with multiple variables.
>>> f = x*y + y*z
>>> g = 3*x + 3*z
>>> q, r = div(f, g, x, y)
>>> q
y

3
>>> r
0
In the last examples, all of the three variables x, y and z are assumed to be variables of the polynomials. But if you have some unrelated constant as coefficient, you can specify the variables explicitly:
>>> a, b, c = symbols('abc')
>>> f = a*x**2 + b*x + c
>>> g = 3*x + 2
>>> q, r = div(f, g, x)
>>> q
2*a b a*x
  +  + 
9 3 3
>>> r
2*b 4*a
c   + 
3 9
Another option is division by multiple polynomials at the same time. In general, the output is not unique and depends on the order of the divisors and the given monomial order (if specified).
>>> f = x*y + y*z + z*x
>>> g1 = x + 1
>>> g2 = 2*y + 1
>>> q, r = div(f, [g1, g2], x, y, z)
>>> q
z
[y + z, 1/2 + ]
2
>>> r
3*z
1/2  
2
>>> (q[0]*g1 + q[1]*g2 + r).expand()
x*y + x*z + y*z
>>> q, r = div(f, [g2, g1], x, y, z)
>>> q
x z
[ + , 1/2 + z]
2 2
>>> r
3*z
1/2  
2
>>> (q[0]*g2 + q[1]*g1 + r).expand()
x*y + x*z + y*z
With division, there is also the computation of the greatest common divisor and the least common multiple.
When the polynomials have integer coefficients, the contents’ gcd is also considered.
>>> f = 12*(x + 1)*x
>>> g = 16*x**2
>>> gcd(f, g, x)
4*x
It also works with multiple variables. In this case, the variables are ordered alphabetically, be default, which has influence on the leading coefficient.
>>> f = x*y/2 + y**2
>>> g = 3*x + 6*y
>>> gcd(f, g, x, y)
x + 2*y
>>> gcd(f, g, y, x)
x
y + 
2
The lcm is connected with the gcd and one can be computed using the other.
>>> f = x*y**2 + x**2*y
>>> g = x**2*y**2
>>> gcd(f, g, x, y)
x*y
>>> lcm(f, g, x, y)
3 2 2 3
x *y + x *y
>>> (f*g).expand()
4 3 3 4
x *y + x *y
>>> (gcd(f, g, x, y)*lcm(f, g, x, y)).expand()
4 3 3 4
x *y + x *y
The squarefree factorization of a univariate polynomial is the product of all factors (not irreducible) of degree 1, 2 ...
>>> sqf((x + 2)*(x*(x + 1))**2, x)
2
[2 + x, x + x ]
This function provides factorization of univariate and multivariate polynomials with rational coefficients.
>>> factor(Rational(1,2)*x**4 + Rational(5,12)*x**3  Rational(1,3)*x**2)
2
x *(1  2*x)*(4 + 3*x)

12
>>> factor(x**2 + 4*x*y + 4*y**2)
2
(x + 2*y)
Buchberger’s algorithm is implemented, supporting various monomial orders.
>>> groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex')
2 4
[1 + x , 1 + y ]
>>> groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex')
4 3 2
[1 + y , z , 1 + x ]
We have (incomplete) methods to find the complex or even symbolic roots of polynomials and to solve some systems of polynomial equations.
>>> from sympy import roots, solve_poly_system
>>> solve(x**3 + 2*x + 3, x)
____ ____
I*\/ 11 I*\/ 11
[1/2  , 1, 1/2 + ]
2 2
>>> p = Symbol('p')
>>> q = Symbol('q')
>>> sorted(solve(x**2 + p*x + q, x))
___________ ___________
/ 2 / 2
p \/ 4*q + p p \/ 4*q + p
[  + ,    ]
2 2 2 2
>>> solve_poly_system([y  x, x  5], x, y)
[(5, 5)]
>>> solve_poly_system([y**2  x**3 + 1, y*x], x, y)
___ ___
I*\/ 3 I*\/ 3
[(0, I), (1, 0), (1/2  , 0), (1/2 + , 0), (0, I)]
2 2
Represents polynomials with symbolic coefficients.
Polynomials are internally represented as two lists containing coefficients and monomials (tuples of exponents), respectively. Stored are only terms with nonzero coefficients, so generally all polynomials are considered sparse. However, algorithms will detect dense polynomials and use the appropriate method to solve them in the most efficient way.
The most common way to initialize a polynomial instance is to provide a valid expression together with a set of ordered symbols and, additionally, monomial ordering:
Poly(expression, x_1, x_2, ..., x_n, order=’grlex’)
If the given expression is not a polynomial with respect to the given variables, an exception is raised. Alternatively you can use Basic.as_poly to avoid exception handling.
By default ordering of monomials can be omitted. In this case graded lexicographic order will be used. Anyway, remember that ‘order’ is a keyword argument.
Currently, four standard orderings are supported:
[1] lex > lexicographic order [2] grlex > graded lex order [3] grevlex > reversed grlex order [4] 1el > first elimination order
Polynomials can also be constructed explicitly by passing a collection of coefficients and monomials in as an expression. Interpretation of the collection depends on the collection’s type according to the following semantics:
 [1] expression is a LIST
 [(c_1, M_1), (c_2, M_2), ..., (c_n, M_n)]
 [(c_1, m_1), (c_2, m_2), ..., (c_n, m_n)]
 [ c_1, c_2, ..., c_n ]
>>> from sympy import Poly, S >>> from sympy.abc import a, x, y >>> # a) M is a tuple (m_1, m_2, ..., m_3) >>> Poly([(4, (2,2)), (3, (1,2))], x, y) Poly(4*x**2*y**2 + 3*x*y**2, x, y) >>> # b) m_i are integers >>> Poly([(1, 2), (a, 0)], x) Poly(x**2 + a, x) >>> # c) only coefficients >>> Poly([1, 0, a], x) Poly(x**2 + a, x) [2] expression is a TUPLE:
((c_1, c2, ..., c_n), (M_1, M_2, ..., M_n))
>>> Poly( ((S(1), S(2)), ((3,), (4,))), x) Poly(x**3 + 2*x**4, x) [3] expression is a DICTIONARY:
{ M_1 : c_1, M_2 : c_2, ..., M_n : c_n }
>>> Poly( {(1, 2): S(3), (4, 5): S(6)} ,x ,y) Poly(6*x**4*y**5 + 3*x*y**2, x, y)
These initialization methods are not just conveniences for creating polynomials. They are designed for different tasks and the resulting polynomials have specific properties:
 [1] All coefficients and monomials are validated before
 polynomial instance is created. Monomials are sorted with respect to the given order.
[2] No validity checking, no sorting, just a raw copy.
 [3] No validity checking, but monomials are sorted with
 respect to the given order.
For interactive usage choose [1] as it’s safe and relatively fast.
CAUTION: Use [2] or [3] internally for time critical algorithms, when you know that coefficients and monomials will be valid sympy expressions. Use them with caution! If the coefficients are integers instead of sympy integers (e.g. 1 instead of S(1)) the polynomial will be created but you may run into problems if you try to print the polynomial. If the monomials are not given as tuples of integers you will have problems.
Implemented methods:
 U –> handles uniformly int  long and Basic coefficients
 (other methods need to be overridden in IntegerPoly)
P –> a property (with appropriate decorator)
 –> otherwise
[1] Representation conversion:
[1.1] [–] as_basic –> converts to a valid sympy expression [1.2] [U] as_dict –> returns { M_1 : c_1, ..., M_1 : c_1 } [1.3] [U] as_uv_dict –> returns dict with integer keys
[2] Polynomial internals:
[2.1] [UP] coeffs –> list of coefficients [2.2] [UP] monoms –> list of monomials [2.3] [UP] symbols –> an ordered list of symbols [2.4] [UP] order –> the ordering of monomials [2.5] [UP] stamp –> frozen set of polynomial’s variables [2.6] [UP] domain –> coefficient domain, see [8] for details [2.7] [UP] args –> required for printing and hashing [2.8] [UP] flags –> dict of keyword arguments to Poly
[3] General characteristics:
[3.1] [UP] norm –> computes oonorm of coefficients [3.2] [UP] length –> counts the total number of terms [3.3] [UP] degree –> returns degree of the leading monomial [3.4] [UP] total_degree –> returns true total degree of a polynomial
[4] Items generators:
[4.1] [U] iter_coeffs –> iterate over coefficients [4.2] [U] iter_monoms –> iterate over monomials [4.3] [U] iter_terms –> iterate over terms
[4.4] [U] iter_all_coeffs –> iterate over all coefficients [4.5] [U] iter_all_monoms –> iterate over all monomials [4.6] [U] iter_all_terms –> iterate over all terms
[5] Leading and trailing items:
[5.1] [UP] lead_coeff or LC –> returns the leading coefficient [5.2] [UP] lead_monom or LM –> returns the leading monomial [5.3] [UP] lead_term or LT –> returns the leading term
[5.4] [UP] tail_coeff or TC –> returns the trailing coefficient [5.5] [UP] tail_monom or TM –> returns the trailing monomial [5.6] [UP] tail_term or TT –> returns the trailing term
[6] Arithmetic operators:
[6.1] [U] __abs__ –> for all i, abs(c_i) [6.2] [U] __neg__ –> polynomial negation [6.3] [U] __add__ –> polynomial addition [6.4] [U] __sub__ –> polynomial subtraction [6.5] [–] __mul__ –> polynomial multiplication [6.6] [U] __pow__ –> polynomial exponentiation [6.7] [U] __div__ –> polynomial quotient [6.8] [U] __mod__ –> polynomial remainder [6.9] [U] __divmod__ –> both ‘div’ and ‘mod’ [6.10] [U] __truediv__ –> the same as ‘div’
[7] Polynomial properties:
[7.1] [UP] is_zero –> only one term c_0 == 0 [7.2] [UP] is_one –> only one term c_0 == 1 [7.3] [P] is_number –> only numeric constant term [7.4] [UP] is_constant –> only arbitrary constant term [7.5] [UP] is_monomial –> number of terms == 1 [7.6] [UP] is_univariate –> number of variables == 1 [7.7] [UP] is_multivariate –> number of variables > 1 [7.8] [UP] is_homogeneous –> has constant term [7.9] [UP] is_inhomogeneous –> no constant term [7.10] [UP] is_sparse –> filled with less than 90% of terms [7.11] [UP] is_dense –> filled with more than 90% of terms [7.12] [UP] is_monic –> returns True if leading coeff is one [7.13] [UP] is_primitive –> returns True if content is one [7.14] [UP] is_squarefree –> no factors of multiplicity >= 2 [7.15] [UP] is_linear –> all monomials of degree <= 1
[8] Coefficients properties:
[8.1] [UP] has_integer_coeffs –> for all i, c_i in Z [8.2] [UP] has_rational_coeffs –> for all i, c_i in Q [8.3] [UP] has_radical_coeffs –> for all i, c_i in R [8.4] [UP] has_complex_coeffs –> for all i, c_i in C [8.5] [UP] has_symbolic_coeffs –> otherwise
[9] Special functionality:
[9.1] [–] as_monic –> divides all coefficients by LC [9.2] [–] as_integer –> returns polynomial with integer coeffs
[9.3] [P] content –> returns GCD of polynomial coefficients [9.4] [–] as_primitive –> returns content and primitive part
[9.5] [U] as_squarefree –> returns squarefree part of a polynomial
[9.6] [U] as_reduced –> extract GCD of polynomial monomials
[9.7] [–] map_coeffs –> applies a function to all coefficients [9.8] [U] coeff –> returns coefficient of the given monomial
[9.9] [U] unify_with –> returns polys with a common set of symbols
[9.10] [U] diff –> efficient polynomial differentiation [9.11] [U] integrate –> efficient polynomial integration
[9.12] [U] invert –> computes multiplicative inverse in K[t]
[10] Operations on terms:
[10.1] [U] add_term –> add a term to a polynomial [10.2] [U] sub_term –> subtract a term from a polynomial
[10.3] [–] mul_term –> multiply a polynomial with a term [10.4] [–] div_term –> divide a polynomial by a term
[10.5] [U] remove_lead_term –> remove leading term (up to order) [10.6] [U] remove_last_term –> remove last term (up to order)
[11] Substitution and evaluation:
[11.1] [U] __call__ –> evaluates poly at the given point [11.2] [U] evaluate –> evaluates poly for specific vars [11.3] [–] _eval_subs –> efficiently substitute variables
[12] Comparison functions:
[12.1] [U] __eq__ –> P1 == P, up to order of monomials [12.2] [U] __ne__ –> P1 != P, up to order of monomials [12.3] [U] __nonzero__ –> check if zero polynomial
[13] String representation functions:
[13.1] [U] repr –> returns representation of ‘self’ [13.3] [U] str –> returns pretty representation
[14] Other (derived from Basic) functionality:
[14.1] [U] _eval_is_polynomial –> checks if poly is a poly
For general information on polynomials and algorithms, refer to:
See also documentation of particular methods.
Efficiently add a single term to ‘self’.
The list of monomials is sorted at initialization time, this motivates usage of binary search algorithm to find an index of an existing monomial or a suitable place for a new one. This gives O(lg(n)) complexity, where ‘n’ is the initial number of terms, superior to naive approach.
For more information on the implemented algorithm refer to:
Converts polynomial to a valid sympy expression.
Takes list representation of a polynomial and constructs expression using symbols used during creation of a given polynomial. If you wish to have different symbols in the resulting expressions, use subs() first.
Note that the result is always returned in expanded form.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> p = Poly(x**2+3, x)
>>> p.as_basic()
3 + x**2
Convert list representation to dictionary representation.
Due to hashing of immutable expressions in Python, we can not store a dictionary directly in a polynomial instance. Also it would be inconvenient in case of ordering of monomials (unnecessary sorting).
This method creates dictionary efficiently, so it can be used in several algorithms which perform best when dicts are being used, e.g. addition, multiplication etc.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> p = Poly(x**2+3, x)
>>> p.as_dict()
{(0,): 3, (2,): 1}
Makes all coefficients integers if possible.
Given a polynomial with rational coefficients, returns a tuple consisting of a common denominator of those coefficients and an integer polynomial. Otherwise an exception is being raised.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly(3*x**2 + x, x).as_integer()
(1, Poly(3*x**2 + x, x))
>>> Poly(3*x**2 + x/2, x).as_integer()
(2, Poly(6*x**2 + x, x))
Returns a monic polynomial.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly(x**2 + 4, x).as_monic()
Poly(x**2 + 4, x)
>>> Poly(2*x**2 + 4, x).as_monic()
Poly(x**2 + 2, x)
>>> Poly(y*x**2 + y**2 + y, x).as_monic()
Poly(x**2 + 1 + y, x)
Returns content and primitive part of a polynomial.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> p = Poly(4*x**2 + 2*x, x)
>>> p.as_primitive()
(2, Poly(2*x**2 + x, x))
Remove GCD of monomials from ‘self’.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly(x**3 + x, x).as_reduced()
((1,), Poly(x**2 + 1, x))
>>> Poly(x**3*y+x**2*y**2, x, y).as_reduced()
((2, 1), Poly(x + y, x, y))
Returns squarefree part of a polynomial.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly((x1)**2, x).as_squarefree()
Poly(x  1, x)
Return dictionary representation with integer keys.
In case of univariate polynomials it is inefficient to to handle exponents as singleton tuples, as an example see multiplication algorithm. This method will return dictionary representation with all tuples converted to explicit integers.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> p = Poly(x**2+3, x)
>>> p.as_uv_dict()
{0: 3, 2: 1}
Cancel common factors in a fractional expression.
Given a quotient of polynomials, cancel common factors from the numerator and the denominator. The result is formed in an expanded form, even if there was no cancellation.
To improve the speed of calculations a list of symbols can be specified. This can be particularly useful in univariate case with additional parameters, to avoid Groebner basis computations.
The input fraction can be given as a single expression or as a tuple consisting of the numerator and denominator.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly.cancel((x**2y**2)/(xy), x, y)
x + y
>>> Poly.cancel((x**2y**2, xy), x, y)
x + y
Returns coefficient of a particular monomial.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> p = Poly(3*x**2*y + 4*x*y**2 + 1, x, y)
>>> p.coeff(2, 1)
3
>>> p.coeff(1, 2)
4
>>> p.coeff(1, 1)
0
If len(monom) == 0 then returns coeff of the constant term:
>>> p.coeff(0, 0)
1
>>> p.coeff()
1
Returns integer GCD of all the coefficients.
>>> from sympy import Poly
>>> from sympy.abc import x, y, z
>>> p = Poly(2*x + 5*x*y, x, y)
>>> p.content
1
>>> p = Poly(2*x + 4*x*y, x, y)
>>> p.content
2
>>> p = Poly(2*x + z*x*y, x, y)
>>> p.content
1
Efficiently differentiate polynomials.
Differentiate a polynomial with respect to a set of symbols. If a symbol is polynomial’s variable, then monomial differentiation is performed and coefficients updated with integer factors. In other case each of the coefficients is differentiated.
Additionally, for each of the symbols you can specify a single positive integer which will indicate the number of times to perform differentiation using this symbol.
>>> from sympy import Poly
>>> from sympy.abc import x, y, z
>>> p = Poly(x**2*y + z**2, x, y)
>>> p.diff(x)
Poly(2*x*y, x, y)
>>> p.diff(x, 2)
Poly(2*y, x, y)
>>> p.diff(x, 2, y)
Poly(2, x, y)
>>> p.diff(z)
Poly(2*z, x, y)
Efficiently integrate polynomials.
Integrate a polynomial with respect a set of symbols. If a symbol is polynomial’s variable, then monomial integration is performed and coefficients updated with integer factors. In other case each of the coefficients is integrated.
Additionally, for each of the symbols you can specify a single positive integer which will indicate the number of times to perform integration using this symbol.
>>> from sympy import Poly
>>> from sympy.abc import x, y, z
>>> p = Poly(x**2*y + z**2, x, y)
>>> p.integrate(x)
Poly(1/3*x**3*y + z**2*x, x, y)
>>> p.integrate(x, 2)
Poly(1/12*x**4*y + z**2/2*x**2, x, y)
>>> p.integrate(x, 2, y)
Poly(1/24*x**4*y**2 + z**2/2*x**2*y, x, y)
>>> p.integrate(z)
Poly(z*x**2*y + z**3/3, x, y)
Returns True if ‘self’ is dense.
Let ‘self’ be a polynomial in M variables of a total degree N and having L terms (with nonzero coefficients). Let K be the number of monomials in M variables of degree at most N. Then ‘self’ is considered dense if it’s at least 90% filled.
The total number of monomials is given by (M + N)! / (M! N!), where the factorials are estimated using improved Stirling’s approximation:
n! = sqrt((2 n + 1/3) pi) n**n exp(n)
For more information on this subject refer to:
http://mathworld.wolfram.com/StirlingsApproximation.html
Returns True if ‘self’ has no factors of multiplicity >= 2.
>>> from sympy import Poly
>>> from sympy.abc import x, y
>>> Poly(x1, x).is_squarefree
True
>>> Poly((x1)**2, x).is_squarefree
False
Apply a function to all the coefficients.
>>> from sympy import Poly, expand
>>> from sympy.abc import x, y, u, v
>>> p = Poly(x**2 + 2*x*y, x, y)
>>> q = p.map_coeffs(lambda c: 2*c)
>>> q.as_basic()
4*x*y + 2*x**2
>>> p = Poly(u*x**2 + v*x*y, x, y)
>>> q = p.map_coeffs(expand, complex=True)
>>> q.as_basic()
x**2*(I*im(u) + re(u)) + x*y*(I*im(v) + re(v))
Efficiently subtract a single term from ‘self’.
The list of monomials is sorted at initialization time, this motivates usage of binary search algorithm to find an index of an existing monomial or a suitable place for a new one. This gives O(lg(n)) complexity, where ‘n’ is the initial number of terms, superior to naive approach.
For more information on the implemented algorithm refer to:
Unify ‘self’ with a polynomial or a set of polynomials.
This method will return polynomials of the same type, dominated by ‘self’, with a common set of symbols (which is a union of all symbols from all polynomials) and with common monomial ordering.
You can pass a polynomial or an expression to this method, or a list or a tuple of polynomials or expressions. If any of the inputs would be an expression then it will be converted to a polynomial.