2 from sympy
.core
.add
import Add
3 from sympy
.core
.mul
import Mul
4 from sympy
.core
.power
import Pow
5 from sympy
.core
.sympify
import sympify
6 from sympy
.core
.basic
import Basic
, S
, C
7 from sympy
.core
.symbol
import Symbol
, Wild
8 from sympy
.core
.numbers
import Integer
, igcd
, ilcm
10 from sympy
.utilities
import all
, any
12 from sympy
.polys
.monomial
import monomial_cmp
, monomial_mul
, \
13 monomial_div
, monomial_max
, monomial_min
, monomial_as_basic
19 class SymbolsError(Exception):
22 class PolynomialError(Exception):
25 class CoefficientError(PolynomialError
):
28 class UnivariatePolyError(PolynomialError
):
30 def __init__(self
, poly
):
31 self
.message
= "%s is an univariate polynomial" % poly
36 class MultivariatePolyError(PolynomialError
):
38 def __init__(self
, poly
):
39 self
.message
= "%s is a multivariate polynomial" % poly
47 ## [!] Copy + Write tests for everything.
48 ## [2] Analyze dense MV multiplication.
49 ## [~] Create MV poly with int coeffs.
50 ## [4] Think on GF polys (for factoring).
51 ## [5] Improve coefficients analysis.
52 ## [6] Implement FactoredPoly.
53 ## [7] Concept of Monomial.
57 """Represents polynomials with symbolic coefficients.
59 Polynomials are internally represented as two lists containing
60 coefficients and monomials (tuples of exponents) respectively.
61 Stored are only terms with non-zero coefficients, so generally
62 all polynomials are considered sparse. However algorithms will
63 detect dense polynomials and use the appropriate method to
64 solve the given problem in the most efficient way.
66 The most common way to initialize a polynomial instance is to
67 provide a valid expression together witch a set of ordered
68 symbols and, additionally, monomial ordering:
70 Poly(expression, x_1, x_2, ..., x_n, order='grlex')
72 If the given expression is not a polynomial with respect to
73 the given variables, an exception is raised. Alternatively
74 you can use Basic.as_poly to avoid exception handling.
76 By default ordering of monomials can be omitted. In this case
77 graded lexicographic order will be used. Anyway remember that
78 'order' is a keyword argument.
80 Currently there are supported four standard orderings:
82 [1] lex -> lexicographic order
83 [2] grlex -> graded lex order
84 [3] grevlex -> reversed grlex order
85 [4] 1-el -> first elimination order
87 Polynomial can be also constructed explicitly by specifying
88 a collection of coefficients and monomials. This can be done
89 in at least three different ways:
91 [1] [(c_1, M_1), (c_2, M_2), ..., (c_1, M_1)]
93 [2] (c_1, c2, ..., c_n), (M_1, M_2, ..., M_n)
95 [3] { M_1 : c_1, M_2 : c_2, ..., M_n : c_n }
97 Although all three representation look similar, they are
98 designed for different tasks and have specific properties:
100 [1] All coefficients and monomials are validated before
101 polynomial instance is created. Monomials are sorted
102 with respect to the given order.
104 [2] No validity checking, no sorting, just a raw copy.
106 [3] Also no validity checking however monomials are
107 sorted with respect to the given order.
109 For interactive usage choose [1] as it's safe and relatively
110 fast. Use [2] or [3] internally for time critical algorithms,
111 when you know that coefficients and monomials will be valid.
115 U --> handles uniformly int | long and Basic coefficients
116 (other methods need to be overridden in IntegerPoly)
118 P --> a property (with appropriate decorator)
122 [1] Representation conversion:
124 [1.1] [--] as_basic --> converts to a valid sympy expression
125 [1.2] [U-] as_dict --> returns { M_1 : c_1, ..., M_1 : c_1 }
126 [1.3] [U-] as_uv_dict --> returns dict with integer keys
128 [2] Polynomial internals:
130 [2.1] [UP] coeffs --> list of coefficients
131 [2.2] [UP] monoms --> list of monomials
132 [2.3] [UP] symbols --> an ordered list of symbols
133 [2.4] [UP] order --> the ordering of monomials
134 [2.5] [UP] stamp --> frozen set of polynomial's variables
135 [2.6] [UP] domain --> coefficient domain, see [8] for details
136 [2.7] [UP] args --> required for printing and hashing
137 [2.8] [UP] flags --> dict of keyword arguments to Poly
139 [3] General characteristics:
141 [3.1] [UP] norm --> computes oo-norm of coefficients
142 [3.2] [UP] length --> counts the total number of terms
143 [3.3] [UP] degree --> returns degree of the leading monomial
144 [3.4] [UP] total_degree --> returns true total degree of a polynomial
146 [4] Items generators:
148 [4.1] [U-] iter_coeffs --> iterate over coefficients
149 [4.2] [U-] iter_monoms --> iterate over monomials
150 [4.3] [U-] iter_terms --> iterate over terms
152 [4.4] [U-] iter_all_coeffs --> iterate over all coefficients
153 [4.5] [U-] iter_all_monoms --> iterate over all monomials
154 [4.6] [U-] iter_all_terms --> iterate over all terms
156 [5] Leading and trailing items:
158 [5.1] [UP] lead_coeff or LC --> returns the leading coefficient
159 [5.2] [UP] lead_monom or LM --> returns the leading monomial
160 [5.3] [UP] lead_term or LT --> returns the leading term
162 [5.4] [UP] tail_coeff or TC --> returns the trailing coefficient
163 [5.5] [UP] tail_monom or TM --> returns the trailing monomial
164 [5.6] [UP] tail_term or TT --> returns the trailing term
166 [6] Arithmetic operators:
168 [6.1] [U-] __abs__ --> for all i, abs(c_i)
169 [6.2] [U-] __neg__ --> polynomial negation
170 [6.3] [U-] __add__ --> polynomial addition
171 [6.4] [U-] __sub__ --> polynomial subtraction
172 [6.5] [--] __mul__ --> polynomial multiplication
173 [6.6] [U-] __pow__ --> polynomial exponentiation
174 [6.7] [U-] __div__ --> polynomial quotient
175 [6.8] [U-] __mod__ --> polynomial remainder
176 [6.9] [U-] __divmod__ --> both 'div' and 'mod'
177 [6.10] [U-] __truediv__ --> the same as 'div'
179 [7] Polynomial properties:
181 [7.1] [UP] is_zero --> only one term c_0 == 0
182 [7.2] [UP] is_one --> only one term c_0 == 1
183 [7.3] [-P] is_number --> only numeric constant term
184 [7.4] [UP] is_constant --> only arbitrary constant term
185 [7.5] [UP] is_monomial --> number of terms == 1
186 [7.6] [UP] is_univariate --> number of variables == 1
187 [7.7] [UP] is_multivariate --> number of variables > 1
188 [7.8] [UP] is_homogeneous --> has constant term
189 [7.9] [UP] is_inhomogeneous --> no constant term
190 [7.10] [UP] is_sparse --> filled with less than 90% of terms
191 [7.11] [UP] is_dense --> filled with more than 90% of terms
192 [7.12] [UP] is_monic --> returns True if leading coeff is one
193 [7.13] [UP] is_primitive --> returns True if content is one
194 [7.14] [UP] is_squarefree --> no factors of multiplicity >= 2
195 [7.15] [UP] is_linear --> all monomials of degree <= 1
197 [8] Coefficients properties:
199 [8.1] [UP] has_integer_coeffs --> for all i, c_i in Z
200 [8.2] [UP] has_rational_coeffs --> for all i, c_i in Q
201 [8.3] [UP] has_radical_coeffs --> for all i, c_i in R
202 [8.4] [UP] has_complex_coeffs --> for all i, c_i in C
203 [8.5] [UP] has_symbolic_coeffs --> otherwise
205 [9] Special functionality:
207 [9.1] [--] as_monic --> divides all coefficients by LC
208 [9.2] [--] as_integer --> returns polynomial with integer coeffs
210 [9.3] [-P] content --> returns GCD of polynomial coefficients
211 [9.4] [--] as_primitive --> returns content and primitive part
213 [9.5] [U-] as_squarefree --> returns square-free part of a polynomial
215 [9.6] [U-] as_reduced --> extract GCD of polynomial monomials
217 [9.7] [--] map_coeffs --> applies a function to all coefficients
218 [9.8] [U-] coeff --> returns coefficient of the given monomial
220 [9.9] [U-] unify_with --> returns polys with a common set of symbols
222 [9.10] [U-] diff --> efficient polynomial differentiation
223 [9.11] [U-] integrate --> efficient polynomial integration
225 [10] Operations on terms:
227 [10.1] [U-] add_term --> add a term to a polynomial
228 [10.2] [U-] sub_term --> subtract a term from a polynomial
230 [10.3] [--] mul_term --> multiply a polynomial with a term
231 [10.4] [--] div_term --> divide a polynomial by a term
233 [10.5] [U-] remove_lead_term --> remove leading term (up to order)
234 [10.6] [U-] remove_last_term --> remove last term (up to order)
236 [11] Substitution and evaluation:
238 [11.1] [U-] __call__ --> evaluates poly a the given point
239 [11.2] [U-] evaluate --> evaluates poly for specific vars
240 [11.3] [--] _eval_subs --> efficiently substitute variables
242 [12] Comparison functions:
244 [12.1] [U-] __eq__ --> P1 == P, up to order of monomials
245 [12.2] [U-] __ne__ --> P1 != P, up to order of monomials
246 [12.3] [U-] __nonzero__ --> check if zero polynomial
248 [13] String representation functions:
250 [13.1] [U-] repr --> returns represantation of 'self'
251 [13.3] [U-] str --> returns pretty representation
253 [14] Other (derived from Basic) functionality:
255 [14.1] [U-] _eval_is_polynomial --> checks if poly is a poly
257 For general information on polynomials and algorithms, refer to:
259 [1] D. E. Knuth, The Art of Computer Programming: Seminumerical
260 Algorithms, v.2, Addison-Wesley Professional, 1997
262 [2] J. von zur Gathen, J. Gerhard, Modern Computer Algebra,
263 Second Edition, Cambridge University Press, 2003
265 [3] K. Geddes, S. R. Czapor, G. Labahn, Algorithms for
266 Computer Algebra, Springer, 1992
268 [4] D. Bini, V. Y.Pan, Polynomial and Matrix Computations:
269 Volume 1: Fundamental Algorithms, Birkhauser Boston, 1994
271 [5] R. T. Moenck, Practical Fast Polynomial Multiplication,
272 Proceedings of the third ACM symposium on Symbolic and
273 algebraic computation, ACM Press, Yorktown Heights,
274 New York, USA, 1976, pp. 136-148
276 [6] M. Bronstein, Symbolic Integration I: Transcendental
277 Functions, Second Edition, Springer-Verlang, 2005
279 See also documentation of particular methods.
283 def __new__(cls
, poly
, *symbols
, **flags
):
284 N
, terms
= len(symbols
), {}
285 coeffs
, monoms
= (), ()
287 order
= flags
.pop('order', 'grlex')
290 if isinstance(poly
, Poly
):
291 if order
!= poly
.order
:
292 symbols
= poly
.symbols
293 N
= len(poly
.symbols
)
294 poly
= poly
.as_dict()
298 raise SymbolsError("No symbols were given")
300 stamp
= frozenset(symbols
)
303 raise SymbolsError("Duplicate symbols: %s" % (symbols
,))
305 symbols
= tuple(map(sympify
, symbols
))
307 if any(not s
.is_Symbol
for s
in symbols
):
308 raise SymbolsError("Invalid symbols: %s" % (symbols
,))
310 if any(not s
.is_commutative
for s
in symbols
):
311 raise SymbolsError("Non-commutative symbols: %s" % (symbols
,))
313 # { M1: c1, M2: c2, ... }
314 if type(poly
) is dict:
321 # ((c1, c2, ...), (M1, M2, ...))
322 elif type(poly
) is tuple:
328 coeffs
, monoms
= poly
[0], poly
[1]
330 if isinstance(coeffs
, (tuple, list)):
331 if not (coeffs
or monoms
):
338 raise PolynomialError("Invalid arguments," \
339 " should get '(coeffs, monoms)' tuple")
341 # [ (c1,M1), (c2,M2), ... ]
342 elif type(poly
) is list:
347 for coeff
, monom
in poly
:
348 coeff
= sympify(coeff
)
350 if coeff
.has_any_symbols(*symbols
):
351 raise CoefficientError("%s coefficient is dependent" \
352 " of polynomial's symbols %s" % (coeff
, symbols
))
354 if type(monom
) is int:
358 raise PolynomialError("Dimension of %s monomial does" \
359 " not match the number of symbols (%d)" % (monom
, N
))
364 if terms
.has_key(monom
):
365 coeff
+= terms
[monom
]
376 elif isinstance(poly
, Poly
):
377 if stamp
<= poly
.stamp
:
378 if symbols
== poly
.symbols
:
379 if N
> 1 and order
!= poly
.order
:
380 terms
= poly
.as_dict()
384 terms
= Poly
._permute
(poly
, *symbols
)
386 if any(coeff
.has_any_symbols(*symbols
) for coeff
in poly
.coeffs
):
387 terms
= Poly
._decompose
(poly
.as_basic(), *symbols
)
389 K
= len(poly
.symbols
)
391 if symbols
[:K
] == poly
.symbols
:
392 coeffs
, T
= poly
.coeffs
, (0,) * (N
- K
)
393 monoms
= tuple(M
+ T
for M
in poly
.monoms
)
395 if order
!= poly
.order
:
396 terms
= dict(zip(monoms
, coeffs
))
398 terms
= Poly
._permute
(poly
, *symbols
)
400 terms
= Poly
._decompose
(poly
, *symbols
)
403 if N
== 1 and type(terms
.keys()[0]) is not tuple:
404 keys
= tuple(reversed(sorted(terms
.keys())))
406 coeffs
= [ terms
[i
] for i
in keys
]
407 monoms
= [ (i
,) for i
in keys
]
409 f
= monomial_cmp(order
)
411 monoms
= terms
.keys()
412 monoms
.sort(f
, reverse
=True)
414 coeffs
= [ terms
[monom
] for monom
in monoms
]
416 args
= (tuple(coeffs
), tuple(monoms
),
417 symbols
, order
, stamp
, None)
419 return Basic
.__new
__(cls
, *args
, **flags
)
422 def _permute(poly
, *symbols
):
423 terms
, N
= {}, len(symbols
)
425 if symbols
== poly
.symbols
[:N
]:
426 symbols
= poly
.symbols
[N
:]
428 for coeff
, monom
in poly
.iter_terms():
429 coeff
*= monomial_as_basic(monom
[N
:], *symbols
)
433 if terms
.has_key(monom
):
434 coeff
+= terms
[monom
]
442 new_symbols
, indices
= list(poly
.symbols
), []
444 for s
in new_symbols
[:]:
445 for i
, t
in enumerate(symbols
):
447 new_symbols
.remove(s
)
453 for coeff
, monom
in poly
.iter_terms():
454 exponents
, j
= [0] * N
, 0
456 for exp
, i
in zip(monom
, indices
):
458 coeff
*= new_symbols
[j
]**exp
463 monom
= tuple(exponents
)
465 if terms
.has_key(monom
):
466 coeff
+= terms
[monom
]
477 def _decompose(poly
, *symbols
):
478 """Converts basic expression to dictionary representation.
480 This procedure will expand given expression and scan it,
481 extracting coefficients and monomials according to a set
482 of symbols, if possible. At this point there is no need
483 for specifying ordering information. If conversion is
484 not possible an exception is raised.
486 This method should be left for internal use. To convert
487 expression to a polynomial use Polynomial constructor
488 explicitly or Basic.as_poly method.
490 >>> from sympy import *
491 >>> x, y = symbols('xy')
493 >>> Poly._decompose(y*x**2 + 3, x)
496 >>> Poly._decompose(y*x**2 + 3, x, y)
497 {(0, 0): 3, (2, 1): 1}
500 result
, indices
, N
= {}, {}, len(symbols
)
502 for i
, sym
in enumerate(symbols
):
505 poly
= sympify(poly
).expand()
511 return { (0,) * N
: poly
}
516 if not term
.has_any_symbols(*symbols
):
517 coeff
, monom
= term
, (0,) * N
524 coeff
, monom
= S
.One
, [0] * N
526 for factor
in factors
:
527 if factor
.has_any_symbols(*symbols
):
529 if factor
.exp
.is_Integer
:
530 b
, e
= factor
.base
, factor
.exp
.p
532 if b
.is_Symbol
and e
> 0:
533 monom
[indices
[b
]] += e
535 elif factor
.is_Symbol
:
536 monom
[indices
[factor
]] += 1
539 raise PolynomialError("Can't decompose %s" % factor
)
545 if result
.has_key(monom
):
546 coeff
+= result
[monom
]
552 result
[monom
] = coeff
555 return { (0,) * N
: S
.One
}
560 def cancel(f
, *symbols
):
561 """Cancel common factors in a fractional expression.
563 Given a quotient of polynomials, cancel common factors from
564 the numerator and the denominator. The result is formed in
565 an expanded form, even if there was no cancellation.
567 To improve the speed of calculations a list of symbols can
568 be specified. This can be particularly useful in univariate
569 case with additional parameters, to avoid Groebner basis
572 The input fraction can be given as a single expression or
573 as a tuple consisting of the numerator and denominator.
575 >>> from sympy import *
576 >>> x,y = symbols('xy')
578 >>> Poly.cancel((x**2-y**2)/(x-y), x, y)
581 >>> Poly.cancel((x**2-y**2, x-y), x, y)
592 symbols
= f
.atoms(Symbol
)
597 symbols
= sorted(symbols
)
599 numer
, denom
= f
.as_numer_denom()
601 numer
= numer
.expand()
606 denom
= denom
.expand()
613 a
, b
, c
= map(Wild
, 'abc')
615 r
= denom
.match(a
+ b
*c
**S
.Half
)
621 a
, b
, c
= r
[a
], r
[b
], r
[c
]
623 numer
*= a
-b
*c
**S
.Half
624 numer
= numer
.expand()
626 denom
= a
**2 - c
*b
**2
631 p
= Poly(numer
, *symbols
)
632 q
= Poly(denom
, *symbols
)
633 except PolynomialError
:
636 g
= sympy
.polys
.algorithms
.poly_gcd(p
, q
)
638 p
= sympy
.polys
.algorithms
.poly_div(p
, g
)[0]
639 q
= sympy
.polys
.algorithms
.poly_div(q
, g
)[0]
641 return p
.as_basic() / q
.as_basic()
644 """Converts polynomial to a valid sympy expression.
646 Takes list representation of a polynomial and constructs
647 expression using symbols used during creation of a given
648 polynomial. If you wish to have different symbols in the
649 resulting expressions, use subs() first.
651 Note that the result is always returned in expanded form.
653 >>> from sympy import *
654 >>> x,y = symbols('xy')
656 >>> p = Poly(x**2+3, x)
661 multinomial
= dict(zip(self
.monoms
, self
.coeffs
))
662 return multinomial_as_basic(multinomial
, *self
.symbols
)
665 """Convert list representation to dictionary representation.
667 Due to hashing of immutable expressions in Python, we can
668 not store a dictionary directly in a polynomial instance.
669 Also it would be inconvenient in case of ordering of
670 monomials (unnecessary sorting).
672 This method creates dictionary efficiently, so it can be
673 used in several algorithms which perform best when dicts
674 are being used, eg. addition, multiplication etc.
676 >>> from sympy import *
677 >>> x,y = symbols('xy')
679 >>> p = Poly(x**2+3, x)
684 return dict(zip(self
.monoms
, self
.coeffs
))
686 def as_uv_dict(self
):
687 """Return dictionary representation with integer keys.
689 In case of univariate polynomials it is inefficient to
690 to handle exponents as singleton tuples, as an example
691 see multiplication algorithm. This method will return
692 dictionary representation with all tuples converted to
695 >>> from sympy import *
696 >>> x,y = symbols('xy')
698 >>> p = Poly(x**2+3, x)
703 if self
.is_univariate
:
704 return dict(zip([ M
[0] for M
in self
.monoms
], self
.coeffs
))
706 raise MultivariatePolyError(self
)
734 return self
._args
[0:4]
738 return { 'order' : self
.order
}
742 return len(self
.monoms
)
746 """Returns degree of the leading term. """
747 return sum(self
.monoms
[0])
750 def total_degree(self
):
751 """Returns true total degree of a polynomial. """
752 return max([ sum(monom
) for monom
in self
.monoms
])
756 """Computes oo-norm of polynomial's coefficients. """
757 return max([ abs(coeff
) for coeff
in self
.coeffs
])
759 def iter_basic_args(self
):
760 for coeff
in self
.coeffs
:
763 for i
, symbol
in enumerate(self
.symbols
):
764 if any(monom
[i
] != 0 for monom
in self
.monoms
):
767 def iter_coeffs(self
):
768 for coeff
in self
.coeffs
:
771 def iter_monoms(self
):
772 for monom
in self
.monoms
:
775 def iter_terms(self
):
776 for coeff
, monom
in zip(self
.coeffs
, self
.monoms
):
779 def iter_all_coeffs(self
):
780 if self
.is_univariate
:
781 terms
= self
.as_uv_dict()
783 for i
in xrange(self
.degree
, -1, -1):
789 raise MultivariatePolyError(self
)
791 def iter_all_monoms(self
):
792 if self
.is_univariate
:
793 for i
in xrange(self
.degree
, -1, -1):
796 raise MultivariatePolyError(self
)
798 def iter_all_terms(self
):
799 if self
.is_univariate
:
800 terms
= self
.as_uv_dict()
802 for i
in xrange(self
.degree
, -1, -1):
808 raise MultivariatePolyError(self
)
811 def lead_coeff(self
):
812 return self
.coeffs
[0]
815 def lead_monom(self
):
816 return self
.monoms
[0]
820 return (self
.coeffs
[0], self
.monoms
[0])
827 def tail_coeff(self
):
828 return self
.coeffs
[-1]
831 def tail_monom(self
):
832 return self
.monoms
[-1]
836 return (self
.coeffs
[-1], self
.monoms
[-1])
843 return self
.__class
__(([ abs(coeff
) for coeff
in self
.coeffs
],
844 self
.monoms
), *self
.symbols
, **self
.flags
)
847 return self
.__class
__(([ -coeff
for coeff
in self
.coeffs
],
848 self
.monoms
), *self
.symbols
, **self
.flags
)
850 def __add__(self
, other
):
852 self
, poly
= self
.unify_with(other
)
853 except PolynomialError
:
854 return self
.as_basic() + other
.as_basic()
863 return self
.add_term(*poly
.LT
)
866 return poly
.add_term(*self
.LT
)
868 terms
= self
.as_dict()
870 for coeff
, monom
in poly
.iter_terms():
871 if terms
.has_key(monom
):
872 coeff
+= terms
[monom
]
874 coeff
= Poly
.cancel(coeff
)
882 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
884 def __sub__(self
, other
):
886 self
, poly
= self
.unify_with(other
)
887 except PolynomialError
:
888 return self
.as_basic() - other
.as_basic()
897 return self
.sub_term(*poly
.LT
)
900 return (-poly
).add_term(*self
.LT
)
902 terms
= self
.as_dict()
904 for coeff
, monom
in poly
.iter_terms():
905 if terms
.has_key(monom
):
906 coeff
-= terms
[monom
]
908 coeff
= Poly
.cancel(coeff
)
914 terms
[monom
] = -coeff
916 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
918 def __mul__(self
, other
):
919 """Efficiently multiply sparse and dense polynomials.
921 Given polynomials P and Q, if both of them are dense, then
922 in univariate case perform dense multiplication, otherwise
923 apply Kronecker 'trick', mapping multivariate polynomials
924 to univariate ones in last variable and then multiply.
926 If any of the polynomials is sparse then in both univariate
927 and multivariate cases use naive multiplication algorithm.
929 For more information on implemented algorithms refer to:
931 [1] R. T. Moenck, Practical Fast Polynomial Multiplication,
932 Proceedings of the third ACM symposium on Symbolic and
933 algebraic computation, ACM Press, Yorktown Heights,
934 New York, USA, 1976, pp. 136-148
937 self
, poly
= self
.unify_with(other
)
938 except PolynomialError
:
939 return self
.as_basic() * other
.as_basic()
947 return poly
.mul_term(self
.LC
)
955 return self
.mul_term(poly
.LC
)
958 return poly
.mul_term(*self
.LT
)
961 return self
.mul_term(*poly
.LT
)
963 if self
.is_dense
and poly
.is_dense
:
964 if self
.is_multivariate
:
965 a
= monomial_max(*self
.monoms
)
966 b
= monomial_max(*poly
.monoms
)
968 degs
, p
, q
= [1], {}, {}
970 for x
, y
in reversed(zip(a
, b
)[1:]):
971 degs
.insert(0, degs
[0]*(x
+y
+1))
973 N
= sum([ x
*y
for x
, y
in zip(self
.LM
, degs
) ])
974 M
= sum([ x
*y
for x
, y
in zip(poly
.LM
, degs
) ])
976 for coeff
, monom
in self
.iter_terms():
977 p
[sum([ x
*y
for x
, y
in zip(monom
, degs
) ])] = coeff
979 for coeff
, monom
in poly
.iter_terms():
980 q
[sum([ x
*y
for x
, y
in zip(monom
, degs
) ])] = coeff
982 p
, N
= self
.as_uv_dict(), self
.degree
983 q
, M
= poly
.as_uv_dict(), poly
.degree
985 coeffs
, monoms
= [], []
987 for k
in xrange(N
+M
, -1, -1):
990 for i
in xrange(k
+1):
991 if p
.has_key(i
) and q
.has_key(k
-i
):
992 coeff
+= Poly
.cancel(p
[i
] * q
[k
-i
])
998 if self
.is_multivariate
:
999 terms
, degs
= {}, degs
[:-1]
1001 for i
, d
in enumerate(monoms
):
1008 terms
[tuple(monom
)+(d
,)] = coeffs
[i
]
1010 terms
= coeffs
, monoms
1014 for coeff_p
, M
in self
.iter_terms():
1015 for coeff_q
, N
in poly
.iter_terms():
1016 monom
= monomial_mul(M
, N
)
1018 coeff
= coeff_p
* coeff_q
1019 coeff
= Poly
.cancel(coeff
)
1021 if terms
.has_key(monom
):
1022 coeff
+= terms
[monom
]
1028 terms
[monom
] = coeff
1030 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
1032 def __pow__(self
, other
):
1033 """Polynomial exponentiation using binary method.
1035 Given a polynomial P and integer exponent N, raise P to power
1036 N in floor(lg(N)) + 1(N) multiplications, where lg(N) stands
1037 for binary logarithm and 1(N) is the number of ones in binary
1038 representation of N.
1040 For more information on the implemented algorithm refer to:
1042 [1] D. E. Knuth, The Art of Computer Programming: Seminumerical
1043 Algorithms, v.2, Addison-Wesley Professional, 1997, pp. 461
1046 other
= sympify(other
)
1048 if isinstance(other
, Poly
):
1049 if other
.is_constant
:
1050 other
= sympify(other
.lead_coeff
)
1052 return self
.as_basic()**other
.as_basic()
1054 if other
.is_Integer
:
1058 P
= self
.__class
__(S
.One
, *self
.symbols
, **self
.flags
)
1063 N
, Q
= abs(int(other
)), self
1076 if other
.is_positive
:
1079 return Pow(P
, S
.NegativeOne
)
1081 return self
.as_basic()**other
1083 def __div__(self
, other
):
1085 return sympy
.polys
.algorithms
.poly_div(self
, other
)[0]
1086 except PolynomialError
:
1087 return self
.as_basic() / other
.as_basic()
1089 def __mod__(self
, other
):
1091 return sympy
.polys
.algorithms
.poly_div(self
, other
)[1]
1092 except PolynomialError
:
1095 def __divmod__(self
, other
):
1097 return sympy
.polys
.algorithms
.poly_div(self
, other
)
1098 except PolynomialError
:
1099 return (self
.as_basic() / other
.as_basic(), S
.Zero
)
1101 __truediv__
= __div__
1105 return self
.coeffs
in ((S
.Zero
,), (0,))
1109 return self
.coeffs
in ((S
.One
,), (1,)) and \
1110 all(e
== 0 for e
in self
.monoms
[0])
1113 def is_number(self
):
1114 return self
.is_constant
and self
.coeffs
[0].is_number
1117 def is_constant(self
):
1118 return len(self
.monoms
) == 1 and \
1119 all(e
== 0 for e
in self
.monoms
[0])
1122 def is_monomial(self
):
1123 return len(self
.monoms
) == 1
1126 def is_univariate(self
):
1127 return len(self
.symbols
) == 1
1130 def is_multivariate(self
):
1131 return len(self
.symbols
) != 1
1134 def is_homogeneous(self
):
1135 return any(e
!= 0 for e
in self
.monoms
[-1])
1138 def is_inhomogeneous(self
):
1139 return all(e
== 0 for e
in self
.monoms
[-1])
1142 def is_sparse(self
):
1143 return not self
.is_dense
1147 """Returns True if 'self' is dense.
1149 Let 'self' be a polynomial in M variables of a total degree N
1150 and having L terms (with non-zero coefficients). Let K be the
1151 number of monomials in M variables of degree at most N. Then
1152 'self' is considered dense if it's at least 90% filled.
1154 The total number of monomials is given by (M + N)! / (M! N!),
1155 where the factorials are estimated using improved Stirling's
1158 n! = sqrt((2 n + 1/3) pi) n**n exp(-n)
1160 For more information on this subject refer to:
1162 http://mathworld.wolfram.com/StirlingsApproximation.html
1168 S
= 2.4*math
.sqrt(U
/V
)
1169 A
= math
.pow(U
/M
, M
)
1170 B
= math
.pow(U
/N
, N
)
1173 V
, N
= len(self
.symbols
), self
.total_degree
1175 return (self
.length
/ enum(V
, N
)) > 0.9
1178 def is_primitive(self
):
1179 return self
.content
in (S
.One
, 1)
1183 return self
.lead_coeff
in (S
.One
, 1)
1186 def is_squarefree(self
):
1187 """Returns True if 'self' has no factors of multiplicity >= 2.
1189 >>> from sympy import *
1190 >>> x,y = symbols('xy')
1192 >>> Poly(x-1, x).is_squarefree
1195 >>> Poly((x-1)**2, x).is_squarefree
1199 return self
.as_squarefree() is self
1202 def is_linear(self
):
1203 return all(sum(monom
) <= 1 for monom
in self
.iter_monoms())
1206 def has_integer_coeffs(self
):
1207 return self
.domain
== 'Z'
1210 def has_rational_coeffs(self
):
1211 return self
.domain
== 'Q'
1214 def has_radical_coeffs(self
):
1215 return self
.domain
== 'R'
1218 def has_complex_coeffs(self
):
1219 return self
.domain
== 'C'
1222 def has_symbolic_coeffs(self
):
1223 return self
.domain
== 'S'
1226 """Returns a monic polynomial.
1228 >>> from sympy import *
1229 >>> x,y = symbols('xy')
1231 >>> Poly(x**2 + 4, x).as_monic()
1234 >>> Poly(2*x**2 + 4, x).as_monic()
1237 >>> Poly(y*x**2 + y**2 + y, x).as_monic()
1238 Poly(x**2 + 1 + y, x)
1241 LC
= self
.lead_coeff
1243 if not self
or LC
is S
.One
:
1246 coeffs
= [ coeff
/ LC
for coeff
in self
.coeffs
]
1248 for i
, coeff
in enumerate(coeffs
):
1249 coeffs
[i
] = Poly
.cancel(coeff
)
1251 return self
.__class
__((coeffs
, self
.monoms
),
1252 *self
.symbols
, **self
.flags
)
1254 def as_integer(self
):
1255 """Makes all coefficients integers if possible.
1257 Given a polynomial with rational coefficients, returns a tuple
1258 consisting of a common denominator of those coefficients and an
1259 integer polynomial. Otherwise an exception is being raised.
1261 >>> from sympy import *
1262 >>> x,y = symbols("xy")
1264 >>> Poly(3*x**2 + x, x).as_integer()
1265 (1, Poly(3*x**2 + x, x))
1267 >>> Poly(3*x**2 + x/2, x).as_integer()
1268 (2, Poly(6*x**2 + x, x))
1273 for coeff
in self
.iter_coeffs():
1274 if coeff
.is_Rational
:
1275 if not coeff
.is_Integer
:
1276 denom
= ilcm(denom
, coeff
.q
)
1278 raise CoefficientError("%s is not a rational number" % coeff
)
1280 denom
= sympify(denom
)
1285 coeffs
= [ coeff
* denom
for coeff
in self
.iter_coeffs() ]
1287 return denom
, self
.__class
__((coeffs
, self
.monoms
),
1288 *self
.symbols
, **self
.flags
)
1292 """Returns integer GCD of all the coefficients.
1294 >>> from sympy import *
1295 >>> x,y,z = symbols('xyz')
1297 >>> p = Poly(2*x + 5*x*y, x, y)
1301 >>> p = Poly(2*x + 4*x*y, x, y)
1305 >>> p = Poly(2*x + z*x*y, x, y)
1315 for coeff
in self
.coeffs
:
1316 if coeff
.is_Rational
:
1317 content
= igcd(content
, coeff
.p
)
1321 return Integer(content
)
1323 def as_primitive(self
):
1324 """Returns content and primitive part of a polynomial.
1326 >>> from sympy import *
1327 >>> x,y = symbols('xy')
1329 >>> p = Poly(4*x**2 + 2*x, x)
1330 >>> p.as_primitive()
1331 (2, Poly(2*x**2 + x, x))
1334 content
= self
.content
1336 if content
is S
.Zero
or content
is S
.One
:
1337 return content
, self
1339 coeffs
= [ coeff
/ content
for coeff
in self
.coeffs
]
1341 return content
, self
.__class
__((coeffs
,
1342 self
.monoms
), *self
.symbols
, **self
.flags
)
1344 def as_squarefree(self
):
1345 """Returns square-free part of a polynomial.
1347 >>> from sympy import *
1348 >>> x,y = symbols('xy')
1350 >>> Poly((x-1)**2, x).as_squarefree()
1354 f
, A
= self
, sympy
.polys
.algorithms
1357 F
= f
.as_primitive()[1]
1361 g
= A
.poly_gcd(F
, h
)
1362 r
= A
.poly_div(f
, g
)
1366 raise MultivariatePolyError(f
)
1368 def as_reduced(self
):
1369 """Remove GCD of monomials from 'self'.
1371 >>> from sympy import *
1372 >>> x,y = symbols('xy')
1374 >>> Poly(x**3 + x, x).as_reduced()
1375 ((1,), Poly(x**2 + 1, x))
1377 >>> Poly(x**3*y+x**2*y**2, x, y).as_reduced()
1378 ((2, 1), Poly(x + y, x, y))
1381 if self
.is_inhomogeneous
:
1382 return (0,)*len(self
.symbols
), self
1384 if self
.is_univariate
:
1385 gcd
= self
.monoms
[-1]
1387 terms
= self
.coeffs
, [ (monom
- gcd
[0],)
1388 for (monom
,) in self
.monoms
]
1390 gcd
= monomial_min(*self
.monoms
)
1392 if all(not n
for n
in gcd
):
1397 for coeff
, monom
in self
.iter_terms():
1398 terms
[monomial_div(monom
, gcd
)] = coeff
1400 return gcd
, Poly(terms
, *self
.symbols
, **self
.flags
)
1402 def map_coeffs(self
, f
, *args
, **kwargs
):
1403 """Apply a function to all the coefficients.
1405 >>> from sympy import *
1406 >>> x,y,u,v = symbols('xyuv')
1408 >>> p = Poly(x**2 + 2*x*y, x, y)
1409 >>> q = p.map_coeffs(lambda c: 2*c)
1414 >>> p = Poly(u*x**2 + v*x*y, x, y)
1415 >>> q = p.map_coeffs(expand, complex=True)
1418 x**2*(I*im(u) + re(u)) + x*y*(I*im(v) + re(v))
1423 for coeff
, monom
in self
.iter_terms():
1424 coeff
= f(coeff
, *args
, **kwargs
)
1426 if coeff
.has_any_symbols(*self
.symbols
):
1427 raise CoefficientError("%s coefficient is dependent" \
1428 " of polynomial's symbols %s" % (coeff
, self
.symbols
))
1429 elif coeff
is not S
.Zero
:
1430 terms
.append((coeff
, monom
))
1432 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
1434 def coeff(self
, *monom
):
1435 """Returns coefficient of a particular monomial.
1437 >>> from sympy import *
1438 >>> x,y = symbols('xy')
1440 >>> p = Poly(3*x**2*y + 4*x*y**2 + 1, x, y)
1449 If len(monom) == 0 then returns coeff of the constant term:
1458 if all(e
== 0 for e
in self
.monoms
[-1]):
1459 return self
.coeffs
[-1]
1461 for i
in xrange(len(self
.monoms
)):
1462 if self
.monoms
[i
] == monom
:
1463 return self
.coeffs
[i
]
1467 def unify_with(self
, other
):
1468 """Unify 'self' with a polynomial or a set of polynomials.
1470 This method will return polynomials of the same type, dominated
1471 by 'self', with a common set of symbols (which is a union of all
1472 symbols from all polynomials) and with common monomial ordering.
1474 You can pass a polynomial or an expression to this method, or
1475 a list or a tuple of polynomials or expressions. If any of the
1476 inputs would be an expression then it will be converted to a
1480 symbols
, stamp
= self
.symbols
, self
.stamp
1481 flags
, cls
= self
.flags
, self
.__class
__
1483 if isinstance(other
, (tuple, list, set)):
1485 if isinstance(poly
, Poly
):
1488 # stamp |= poly.atoms(Symbol)
1490 if not (stamp
<= self
.stamp
):
1491 symbols
= tuple(sorted(stamp
))
1492 self
= cls(self
, *symbols
, **flags
)
1494 other
= other
.__class
__( cls(poly
,
1495 *symbols
, **flags
) for poly
in other
)
1497 other
= sympify(other
)
1499 if isinstance(other
, Poly
):
1500 stamp |
= other
.stamp
1502 # stamp |= other.atoms(Symbol)
1504 if not (stamp
<= self
.stamp
):
1505 symbols
= tuple(sorted(stamp
))
1506 self
= cls(self
, *symbols
, **flags
)
1508 other
= cls(other
, *symbols
, **flags
)
1512 def diff(self
, *symbols
):
1513 """Efficiently differentiate polynomials.
1515 Differentiate a polynomial with respect to a set of symbols. If
1516 a symbol is polynomial's variable, then monomial differentiation
1517 is performed and coefficients updated with integer factors. In
1518 other case each of the coefficients is differentiated.
1520 Additionally, for each of the symbols you can specify a single
1521 positive integer which will indicate the number of times to
1522 perform differentiation using this symbol.
1524 >>> from sympy import *
1525 >>> x,y,z = symbols('xyz')
1527 >>> p = Poly(x**2*y + z**2, x, y)
1551 new_symbols
.append((s
, 1))
1553 sym
, _
= new_symbols
.pop()
1554 new_symbols
.append((sym
, int(s
)))
1559 if self
.is_univariate
:
1560 new_symbols
= [(self
.symbols
[0], 1)]
1564 indices
, symbols
= {}, self
.stamp
1566 for i
, s
in enumerate(self
.symbols
):
1569 poly
= self
.as_dict()
1571 for s
, k
in new_symbols
:
1577 for M
, coeff
in poly
.iteritems():
1581 monom
= M
[:i
]+(n
,)+M
[i
+1:]
1583 for j
in xrange(n
, M
[i
]):
1586 if new_poly
.has_key(monom
):
1587 coeff
+= new_poly
[monom
]
1593 new_poly
[monom
] = coeff
1594 elif not isinstance(self
, IntegerPoly
):
1595 for monom
, coeff
in poly
.iteritems():
1596 if coeff
.has_any_symbols(s
):
1597 coeff
= coeff
.diff(*([s
]*k
))
1600 new_poly
[monom
] = coeff
1607 return self
.__class
__(poly
, *self
.symbols
, **self
.flags
)
1609 def integrate(self
, *symbols
):
1610 """Efficiently integrate polynomials.
1612 Integrate a polynomial with respect a set of symbols. If a
1613 symbol is polynomial's variable, then monomial integration
1614 is performed and coefficients updated with integer factors.
1615 In other case each of the coefficients is integrated.
1617 Additionally, for each of the symbols you can specify a
1618 single positive integer which will indicate the number
1619 of times to perform integration using this symbol.
1621 >>> from sympy import *
1622 >>> x,y,z = symbols('xyz')
1624 >>> p = Poly(x**2*y + z**2, x, y)
1627 Poly(1/3*x**3*y + z**2*x, x, y)
1629 >>> p.integrate(x, 2)
1630 Poly(1/12*x**4*y + 1/2*z**2*x**2, x, y)
1632 >>> p.integrate(x, 2, y)
1633 Poly(1/24*x**4*y**2 + 1/2*z**2*x**2*y, x, y)
1636 Poly(z*x**2*y + 1/3*z**3, x, y)
1648 new_symbols
.append((s
, 1))
1650 sym
, _
= new_symbols
.pop()
1651 new_symbols
.append((sym
, int(s
)))
1655 indices
, symbols
= {}, self
.stamp
1657 for i
, s
in enumerate(self
.symbols
):
1660 poly
= self
.as_dict()
1662 for s
, k
in new_symbols
:
1668 for M
, coeff
in poly
.iteritems():
1671 monom
= M
[:i
]+(n
,)+M
[i
+1:]
1673 for j
in xrange(M
[i
], n
):
1676 if new_poly
.has_key(monom
):
1677 coeff
+= new_poly
[monom
]
1683 new_poly
[monom
] = coeff
1685 for M
, coeff
in poly
.iteritems():
1686 new_poly
[M
] = C
.Integral(coeff
, *([s
]*k
)).doit()
1693 return self
.__class
__(poly
, *self
.symbols
, **self
.flags
)
1695 def add_term(self
, coeff
, monom
):
1696 """Efficiently add a single term to 'self'.
1698 The list of monomials is sorted at initialization time, this
1699 motivates usage of binary search algorithm to find an index
1700 of an existing monomial or a suitable place for a new one.
1701 This gives O(lg(n)) complexity, where 'n' is the initial
1702 number of terms, superior to naive approach.
1704 For more information on the implemented algorithm refer to:
1706 [1] D. E. Knuth, The Art of Computer Programming: Sorting
1707 and Searching, v.1, Addison-Wesley Professional, 1998
1714 coeffs
= list(self
.coeffs
)
1715 monoms
= list(self
.monoms
)
1717 compare
= monomial_cmp(self
.order
)
1719 if compare(monom
, monoms
[0]) > 0:
1720 coeffs
.insert(0, coeff
)
1721 monoms
.insert(0, monom
)
1722 elif compare(monom
, monoms
[-1]) < 0:
1723 coeffs
.append(coeff
)
1724 monoms
.append(monom
)
1726 lo
, hi
= 0, len(monoms
)-1
1731 k
= compare(monom
, monoms
[i
])
1749 coeffs
.insert(i
, coeff
)
1750 monoms
.insert(i
, monom
)
1752 return self
.__class
__((coeffs
, monoms
),
1753 *self
.symbols
, **self
.flags
)
1755 def sub_term(self
, coeff
, monom
):
1756 """Efficiently subtract a single term from 'self'.
1758 The list of monomials is sorted at initialization time, this
1759 motivates usage of binary search algorithm to find an index
1760 of an existing monomial or a suitable place for a new one.
1761 This gives O(lg(n)) complexity, where 'n' is the initial
1762 number of terms, superior to naive approach.
1764 For more information on the implemented algorithm refer to:
1766 [1] D. E. Knuth, The Art of Computer Programming: Sorting
1767 and Searching, v.2, Addison-Wesley Professional, 1998
1774 coeffs
= list(self
.coeffs
)
1775 monoms
= list(self
.monoms
)
1777 compare
= monomial_cmp(self
.order
)
1779 if compare(monom
, monoms
[0]) > 0:
1780 coeffs
.insert(0, -coeff
)
1781 monoms
.insert(0, monom
)
1782 elif compare(monom
, monoms
[-1]) < 0:
1783 coeffs
.append(-coeff
)
1784 monoms
.append(monom
)
1786 lo
, hi
= 0, len(monoms
)-1
1791 k
= compare(monom
, monoms
[i
])
1809 coeffs
.insert(i
, -coeff
)
1810 monoms
.insert(i
, monom
)
1812 return self
.__class
__((coeffs
, monoms
),
1813 *self
.symbols
, **self
.flags
)
1815 def mul_term(self
, coeff
, monom
=None):
1816 """Efficiently multiply 'self' with a single term. """
1817 coeff
= sympify(coeff
)
1826 coeffs
= self
.coeffs
1828 coeffs
= [ p_coeff
* coeff
for p_coeff
in self
.coeffs
]
1830 for i
, coeff
in enumerate(coeffs
):
1831 coeffs
[i
] = Poly
.cancel(coeff
)
1834 monoms
= self
.monoms
1836 monoms
= [ monomial_mul(p_monom
, monom
)
1837 for p_monom
in self
.monoms
]
1839 terms
= coeffs
, monoms
1841 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
1843 def div_term(self
, coeff
, monom
=None):
1844 """Efficiently divide 'self' by a single term. """
1845 coeff
= sympify(coeff
)
1848 raise ZeroDivisionError
1854 coeffs
= self
.coeffs
1856 coeffs
= [ p_coeff
/ coeff
for p_coeff
in self
.coeffs
]
1858 for i
, coeff
in enumerate(coeffs
):
1859 coeffs
[i
] = Poly
.cancel(coeff
)
1862 monoms
= self
.monoms
1864 monoms
= [ monomial_div(p_monom
, monom
)
1865 for p_monom
in self
.monoms
]
1867 if any(monom
is None for monom
in monoms
):
1868 raise PolynomialError("%s monomial must divide" \
1869 " exactly the given polynomial" % (monom
,))
1871 return self
.__class
__((coeffs
, monoms
),
1872 *self
.symbols
, **self
.flags
)
1874 def kill_lead_term(self
):
1875 """Removes leading term from 'self'. """
1876 terms
= self
.coeffs
[1:], self
.monoms
[1:]
1877 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
1879 def kill_last_term(self
):
1880 """Removes last term from 'self'. """
1881 terms
= self
.coeffs
[:-1], self
.monoms
[:-1]
1882 return self
.__class
__(terms
, *self
.symbols
, **self
.flags
)
1884 def __call__(self
, *point
):
1885 """Efficiently evaluate polynomial at a given point.
1887 Evaluation is always done using Horner scheme. In multivariate
1888 case a greedy algorithm is used to obtain a sequence of partial
1889 evaluations which minimizes the total number of multiplications
1890 required to perform this evaluation. This strategy is efficient
1891 for most of multivariate polynomials.
1893 Note that evaluation is done for all variables, which means the
1894 dimension of the given point must match the number of symbols.
1896 If you wish to efficiently evaluate polynomial for a subset of
1897 symbols use 'evaluate' method instead. Alternatively one can
1898 use Basic.subs() for this purpose.
1900 >>> from sympy import *
1901 >>> x,y = symbols('xy')
1903 >>> p = Poly(x**2 + 2*x + 1, x)
1910 For more information on the implemented algorithm refer to:
1912 [1] M. Ceberio, V. Kreinovich, Greedy Algorithms for Optimizing
1913 Multivariate Horner Schemes, ACM SIGSAM Bulletin, Volume 38,
1914 Issue 1, 2004, pp. 8-15
1917 N
= len(self
.symbols
)
1920 raise ValueError("Dimension of %s does not match" \
1921 " the number of symbols (%d)" % (point
, N
))
1923 if self
.is_univariate
:
1924 terms
= self
.as_uv_dict()
1926 point
, result
= point
[0], 0
1928 for k
in xrange(self
.degree
, -1, -1):
1931 if terms
.has_key(k
):
1936 def evaluate(terms
):
1939 for monom
in terms
.iterkeys():
1940 for i
, M
in enumerate(monom
):
1949 for monom
, coeff
in terms
.iteritems():
1950 for base
, exp
in zip(point
, monom
):
1961 k
, indeps
, depend
= count
.index(K
), {}, {}
1963 n
= min([ M
[k
] for M
in terms
.iterkeys() if M
[k
] ])
1965 for M
, coeff
in terms
.iteritems():
1967 depend
[M
[:k
]+(M
[k
]-n
,)+M
[k
+1:]] = coeff
1971 result
= point
[k
]**n
* evaluate(depend
)
1974 return result
+ evaluate(indeps
)
1978 return evaluate(self
.as_dict())
1980 def evaluate(self
, pattern
):
1981 """Evaluates polynomial for a given set of symbols. """
1982 symbols
= list(self
.symbols
)
1984 if type(pattern
) is dict:
1985 pattern
= pattern
.items()
1986 elif type(pattern
) is tuple:
1989 poly
= self
.as_dict()
1991 for s
, value
in pattern
:
1992 if s
not in self
.stamp
:
1993 raise PolynomialError("%s symbol does" \
1994 " not belong to %s" % (s
, self
.symbols
))
1996 i
= symbols
.index(s
)
1998 # 'value' might be int | long
1999 if isinstance(value
, Symbol
):
2000 if value
in self
.stamp
:
2001 raise PolynomialError("%s symbol must" \
2002 " not belong to %s" % (s
, self
.symbols
))
2006 for M
, coeff
in poly
.iteritems():
2007 monom
= M
[:i
] + M
[i
+1:]
2008 coeff
*= value
** M
[i
]
2010 coeff
= Poly
.cancel(coeff
)
2012 if terms
.has_key(monom
):
2013 coeff
+= terms
[monom
]
2021 terms
[monom
] = coeff
2030 return poly
.popitem()[1]
2032 return self
.__class
__(poly
, *symbols
, **self
.flags
)
2034 def _eval_subs(self
, old
, new
):
2035 symbols
= list(self
.symbols
)
2037 if old
in self
.stamp
:
2038 terms
, i
= {}, symbols
.index(old
)
2041 if new
in self
.stamp
:
2042 j
= symbols
.index(new
)
2044 for coeff
, M
in self
.iter_terms():
2048 monom
= M
[:i
]+M
[i
+1:j
]+(m
+n
,)+M
[j
+1:]
2050 monom
= M
[:j
]+(m
+n
,)+M
[j
+1:i
]+M
[i
+1:]
2052 if terms
.has_key(monom
):
2053 coeff
+= terms
[monom
]
2059 terms
[monom
] = coeff
2063 return self
.__class
__(terms
, *symbols
, **self
.flags
)
2065 for coeff
in self
.coeffs
:
2066 if coeff
.has_any_symbols(new
):
2069 symbols
[i
], terms
= new
, (self
.coeffs
, self
.monoms
)
2070 return self
.__class
__(terms
, *symbols
, **self
.flags
)
2072 if len(symbols
) == 1:
2075 return self
.evaluate((old
, new
))
2076 elif not new
.has_any_symbols(*symbols
):
2077 coeffs
= [ sympify(coeff
).subs(old
, new
) for coeff
in self
.coeffs
]
2078 return self
.__class
__((coeffs
, self
.monoms
), *symbols
, **self
.flags
)
2080 result
= self
.as_basic().subs(old
, new
)
2083 return self
.__class
__(result
, *symbols
, **self
.flags
)
2084 except PolynomialError
:
2087 def __eq__(self
, other
):
2088 """Compare polynomials up to order of symbols and monomials. """
2090 poly
= self
.__class
__(other
, *self
.symbols
, **self
.flags
)
2091 except PolynomialError
:
2094 if self
.length
!= poly
.length
:
2097 if hash(self
.monoms
) != hash(poly
.monoms
):
2100 if hash(self
.coeffs
) != hash(poly
.coeffs
):
2101 for a
, b
in zip(self
.coeffs
, poly
.coeffs
):
2107 def __ne__(self
, other
):
2108 """Compare polynomials up to order of symbols and monomials. """
2110 poly
= self
.__class
__(other
, *self
.symbols
, **self
.flags
)
2111 except PolynomialError
:
2114 if self
.length
!= poly
.length
:
2117 if hash(self
.monoms
) != hash(poly
.monoms
):
2120 if hash(self
.coeffs
) != hash(poly
.coeffs
):
2121 for a
, b
in zip(self
.coeffs
, poly
.coeffs
):
2127 def __nonzero__(self
):
2128 return self
.coeffs
not in ((S
.Zero
,), (0,))
2130 def _eval_is_polynomial(self
, symbols
):
2132 self
.__class
__(self
, *symbols
, **self
.flags
)
2133 except PolynomialError
:
2138 class IntegerPoly(Poly
):
2141 def multinomial_as_basic(multinomial
, *symbols
):
2143 Converts the multinomial to Add/Mul/Pow instances.
2145 multinomial is a dict of {powers: coefficient} pairs, powers is a tuple of
2146 python integers, coefficient is a python integer.
2149 for powers
, k
in multinomial
.iteritems():
2151 for i
,e
in enumerate(powers
):
2152 term
.append(Pow(symbols
[i
], powers
[i
]))
2153 l
.append(Mul(*term
))