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
.symbol
import Symbol
6 from sympy
.core
.basic
import Basic
, S
7 from sympy
.core
.numbers
import Integer
8 from sympy
.core
.sympify
import sympify
10 from sympy
.core
.numbers
import igcd
, ilcm
12 from polynomial
import Poly
, SymbolsError
, MultivariatePolyError
14 from monomial
import monomial_cmp
, monomial_lcm
, \
15 monomial_gcd
, monomial_mul
, monomial_div
17 from sympy
.utilities
.iterables
import all
, any
19 def poly_div(f
, g
, *symbols
):
20 """Generalized polynomial division with remainder.
22 Given polynomial f and a set of polynomials g = (g_1, ..., g_n)
23 compute a set of quotients q = (q_1, ..., q_n) and remainder r
24 such that f = q_1*f_1 + ... + q_n*f_n + r, where r = 0 or r is
25 a completely reduced polynomial with respect to g.
27 In particular g can be a tuple, list or a singleton. All g_i
28 and f can be given as Poly class instances or as expressions.
30 For more information on the implemented algorithm refer to:
32 [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
33 Algorithms, Springer, Second Edition, 1997, pp. 62
35 [2] I.A. Ajwa, Z. Liu, P.S. Wang, Groebner Bases Algorithm,
36 http://citeseer.ist.psu.edu/ajwa95grbner.html, 1995
39 if not isinstance(f
, Poly
):
42 raise SymbolsError("Redundant symbols were given")
44 f
, g
= f
.unify_with(g
)
46 symbols
, flags
= f
.symbols
, f
.flags
48 r
= Poly((), *symbols
, **flags
)
50 if isinstance(g
, Basic
):
53 raise ZeroDivisionError
57 return f
.div_term(g
.LC
), r
62 q_coeffs
, q_monoms
= [], []
63 r_coeffs
, r_monoms
= [], []
65 for coeff
, monom
in f
.iter_terms():
66 quotient
= monomial_div(monom
, LM
)
68 if quotient
is not None:
71 q_coeffs
.append(Poly
.cancel(coeff
))
72 q_monoms
.append(quotient
)
74 r_coeffs
.append(coeff
)
75 r_monoms
.append(monom
)
77 return (Poly((q_coeffs
, q_monoms
), *symbols
, **flags
),
78 Poly((r_coeffs
, r_monoms
), *symbols
, **flags
))
85 for i
, h
in enumerate(g
):
86 monom
= monomial_div(f
.LM
, h
.LM
)
89 coeff
= Poly
.cancel(f
.LC
/ h
.LC
)
91 q
[i
] = q
[i
].add_term(coeff
, monom
)
92 f
-= h
.mul_term(coeff
, monom
)
97 f
= f
.kill_lead_term()
104 def poly_pdiv(f
, g
, *symbols
):
105 """Univariate polynomial pseudo-division with remainder.
107 Given univariate polynomials f and g over an integral domain D[x]
108 applying classical division algorithm to LC(g)**(d + 1) * f and g
109 where d = max(-1, deg(f) - deg(g)), compute polynomials q and r
110 such that LC(g)**(d + 1)*f = g*q + r and r = 0 or deg(r) < deg(g).
111 Polynomials q and r are called the pseudo-quotient of f by g and
112 the pseudo-remainder of f modulo g respectively.
114 For more information on the implemented algorithm refer to:
116 [1] M. Bronstein, Symbolic Integration I: Transcendental
117 Functions, Second Edition, Springer-Verlang, 2005
120 if not isinstance(f
, Poly
):
121 f
= Poly(f
, *symbols
)
123 raise SymbolsError("Redundant symbols were given")
125 f
, g
= f
.unify_with(g
)
127 if f
.is_multivariate
:
128 raise MultivariatePolyError(f
)
130 symbols
, flags
= f
.symbols
, f
.flags
132 q
, r
= Poly((), *symbols
, **flags
), f
133 coeff
, N
= g
.LC
, f
.degree
- g
.degree
+ 1
136 M
= r
.degree
- g
.degree
141 T
, N
= (r
.LC
, (M
,)), N
- 1
143 q
= q
.mul_term(coeff
).add_term(*T
)
144 r
= r
.mul_term(coeff
)-g
.mul_term(*T
)
146 return (q
.mul_term(coeff
**N
), r
.mul_term(coeff
**N
))
148 def poly_groebner(f
, *symbols
, **flags
):
149 """Computes reduced Groebner basis for a set of polynomials.
151 Given a set of multivariate polynomials F, find another set G,
152 such that Ideal F = Ideal G and G is a reduced Groebner basis.
154 The resulting basis is unique and has monic generators.
156 Groebner bases can be used to choose specific generators for a
157 polynomial ideal. Because these bases are unique you can check
158 for ideal equality by comparing the Groebner bases. To see if
159 one polynomial lies in an ideal, divide by the elements in the
160 base and see if the remainder vanishes.
162 They can also be used to solve systems of polynomial equations
163 as, by choosing lexicographic ordering, you can eliminate one
164 variable at a time, provided that the ideal is zero-dimensional
165 (finite number of solutions).
167 >>> from sympy import *
168 >>> x,y = symbols('xy')
170 >>> G = poly_groebner([x**2 + y**3, y**2-x], x, y, order='lex')
172 >>> [ g.as_basic() for g in G ]
173 [x - y**2, y**3 + y**4]
175 For more information on the implemented algorithm refer to:
177 [1] N.K. Bose, B. Buchberger, J.P. Guiver, Multidimensional
178 Systems Theory and Applications, Springer, 2003, pp. 98+
180 [2] A. Giovini, T. Mora, "One sugar cube, please" or Selection
181 strategies in Buchberger algorithm, Proc. ISSAC '91, ACM
183 [3] I.A. Ajwa, Z. Liu, P.S. Wang, Groebner Bases Algorithm,
184 http://citeseer.ist.psu.edu/ajwa95grbner.html, 1995
186 [4] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
187 Algorithms, Springer, Second Edition, 1997, pp. 62
190 if isinstance(f
, (tuple, list, set)):
191 f
, g
= f
[0], list(f
[1:])
193 if not isinstance(f
, Poly
):
194 f
= Poly(f
, *symbols
, **flags
)
195 elif symbols
or flags
:
196 raise SymbolsError("Redundant symbols or flags were given")
198 f
, g
= f
.unify_with(g
)
200 symbols
, flags
= f
.symbols
, f
.flags
202 if not isinstance(f
, Poly
):
203 f
= Poly(f
, *symbols
, **flags
)
204 elif symbols
or flags
:
205 raise SymbolsError("Redundant symbols or flags were given")
207 return [f
.as_monic()]
209 compare
= monomial_cmp(flags
.get('order'))
211 f
= [ h
for h
in [f
] + g
if h
]
214 return [Poly((), *symbols
, **flags
)]
216 R
, P
, G
, B
, F
= set(), set(), set(), {}, {}
218 for i
, h
in enumerate(f
):
222 h
= poly_div(g
, [ f
[i
] for i
in H
])[1]
233 def generate(R
, P
, G
, B
):
235 h
= normal(f
[R
.pop()], G | P
)
240 G0
= set(g
for g
in G
if monomial_div(f
[g
].LM
, LM
))
241 P0
= set(p
for p
in P
if monomial_div(f
[p
].LM
, LM
))
243 G
, P
, R
= G
- G0
, P
- P0 |
set([k
]), R | G0 | P0
246 if i
in G0
or j
in G0
:
262 B
[k
] = monomial_lcm(f
[i
].LM
, f
[j
].LM
)
264 G
= set([ normal(f
[g
], G
- set([g
]))[0] for g
in G
])
268 R
, P
, G
, B
= generate(R
, P
, G
, B
)
273 for l
, N
in B
.iteritems():
274 if compare(M
, N
) == 1:
282 p_LM
, q_LM
= p
.LM
, q
.LM
284 if M
== monomial_mul(p_LM
, q_LM
):
293 if not B
.has_key((min(i
, g
), max(i
, g
))):
296 if not B
.has_key((min(j
, g
), max(j
, g
))):
299 if not monomial_div(M
, f
[g
].LM
):
308 p
= p
.mul_term(1/p
.LC
, monomial_div(M
, p_LM
))
309 q
= q
.mul_term(1/q
.LC
, monomial_div(M
, q_LM
))
316 G0
= set(g
for g
in G
if monomial_div(f
[g
].LM
, LM
))
318 R
, P
, G
= G0
, set([k
]), G
- G0
321 if i
in G0
or j
in G0
:
324 R
, P
, G
, B
= generate(R
, P
, G
, B
)
326 G
= [ f
[g
].as_monic() for g
in G
]
328 G
= sorted(G
, compare
, lambda p
: p
.LM
)
330 return list(reversed(G
))
332 def poly_lcm(f
, g
, *symbols
):
333 """Computes least common multiple of two polynomials.
335 Given two univariate polynomials, the LCM is computed via
336 f*g = gcd(f, g)*lcm(f, g) formula. In multivariate case, we
337 compute the unique generator of the intersection of the two
338 ideals, generated by f and g. This is done by computing a
339 Groebner basis, with respect to any lexicographic ordering,
340 of t*f and (1 - t)*g, where t is an unrelated symbol and
341 filtering out solution that does not contain t.
343 For more information on the implemented algorithm refer to:
345 [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
346 Algorithms, Springer, Second Edition, 1997, pp. 187
349 if not isinstance(f
, Poly
):
350 f
= Poly(f
, *symbols
)
352 raise SymbolsError("Redundant symbols were given")
354 f
, g
= f
.unify_with(g
)
356 symbols
, flags
= f
.symbols
, f
.flags
358 if f
.is_monomial
and g
.is_monomial
:
359 monom
= monomial_lcm(f
.LM
, g
.LM
)
363 if fc
.is_Rational
and gc
.is_Rational
:
364 coeff
= Integer(ilcm(fc
.p
, gc
.p
))
368 return Poly((coeff
, monom
), *symbols
, **flags
)
370 fc
, f
= f
.as_primitive()
371 gc
, g
= g
.as_primitive()
373 lcm
= ilcm(int(fc
), int(gc
))
375 if f
.is_multivariate
:
376 t
= Symbol('t', dummy
=True)
377 lex
= { 'order' : 'lex' }
379 f_monoms
= [ (1,) + monom
for monom
in f
.monoms
]
381 F
= Poly((f
.coeffs
, f_monoms
), t
, *symbols
, **lex
)
383 g_monoms
= [ (0,) + monom
for monom
in g
.monoms
] + \
384 [ (1,) + monom
for monom
in g
.monoms
]
386 g_coeffs
= list(g
.coeffs
) + [ -coeff
for coeff
in g
.coeffs
]
387 G
= Poly(dict(zip(g_monoms
, g_coeffs
)), t
, *symbols
, **lex
)
390 return all(not monom
[0] for monom
in h
.monoms
)
392 H
= [ h
for h
in poly_groebner((F
, G
)) if independent(h
) ]
395 h_coeffs
= [ coeff
*lcm
for coeff
in H
[0].coeffs
]
397 h_coeffs
= H
[0].coeffs
399 h_monoms
= [ monom
[1:] for monom
in H
[0].monoms
]
401 return Poly(dict(zip(h_monoms
, h_coeffs
)), *symbols
, **flags
)
403 h
= poly_div(f
* g
, poly_gcd(f
, g
))[0]
406 return h
.mul_term(lcm
/ h
.LC
)
410 def poly_gcd(f
, g
, *symbols
):
411 """Compute greatest common divisor of two polynomials.
413 Given two univariate polynomials, subresultants are used
414 to compute the GCD. In multivariate case Groebner basis
415 approach is used together with f*g = gcd(f, g)*lcm(f, g)
418 For more information on the implemented algorithm refer to:
420 [1] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and
421 Algorithms, Springer, Second Edition, 1997, pp. 187
424 if not isinstance(f
, Poly
):
425 f
= Poly(f
, *symbols
)
427 raise SymbolsError("Redundant symbols were given")
429 f
, g
= f
.unify_with(g
)
431 symbols
, flags
= f
.symbols
, f
.flags
433 if f
.is_zero
and g
.is_zero
:
438 cont
, g
= g
.as_primitive()
439 return g
.mul_term(cont
/ g
.LC
)
445 cont
, f
= f
.as_primitive()
446 return f
.mul_term(cont
/ f
.LC
)
450 if f
.is_monomial
and g
.is_monomial
:
451 monom
= monomial_gcd(f
.LM
, g
.LM
)
455 if fc
.is_Rational
and gc
.is_Rational
:
456 coeff
= Integer(igcd(fc
.p
, gc
.p
))
460 return Poly((coeff
, monom
), *symbols
, **flags
)
462 cf
, f
= f
.as_primitive()
463 cg
, g
= g
.as_primitive()
465 gcd
= igcd(int(cf
), int(cg
))
467 if f
.is_multivariate
:
468 h
= poly_div(f
*g
, poly_lcm(f
, g
))[0]
470 h
= poly_subresultants(f
, g
)[-1]
473 return h
.mul_term(gcd
/ h
.LC
)
477 def poly_gcdex(f
, g
, *symbols
):
478 """Extended Euclidean algorithm.
480 Given univariate polynomials f and g over an Euclidean domain,
481 computes polynomials s, t and h, such that h = gcd(f, g) and
484 For more information on the implemented algorithm refer to:
486 [1] M. Bronstein, Symbolic Integration I: Transcendental
487 Functions, Second Edition, Springer-Verlang, 2005
490 s
, h
= poly_half_gcdex(f
, g
, *symbols
)
491 return s
, poly_div(h
- s
*f
, g
)[0], h
493 def poly_half_gcdex(f
, g
, *symbols
):
494 """Half extended Euclidean algorithm.
496 Efficiently computes gcd(f, g) and one of the coefficients
497 in extended Euclidean algorithm. Formally, given univariate
498 polynomials f and g over an Euclidean domain, computes s
499 and h, such that h = gcd(f, g) and s*f = h (mod g).
501 For more information on the implemented algorithm refer to:
503 [1] M. Bronstein, Symbolic Integration I: Transcendental
504 Functions, Second Edition, Springer-Verlang, 2005
507 if not isinstance(f
, Poly
):
508 f
= Poly(f
, *symbols
)
510 raise SymbolsError("Redundant symbols were given")
512 f
, g
= f
.unify_with(g
)
514 if f
.is_multivariate
:
515 raise MultivariatePolyError(f
)
517 symbols
, flags
= f
.symbols
, f
.flags
519 a
= Poly(S
.One
, *symbols
, **flags
)
520 b
= Poly((), *symbols
, **flags
)
523 q
, r
= poly_div(f
, g
)
531 def poly_resultant(f
, g
, *symbols
):
532 """Computes resultant of two univariate polynomials.
534 Resultants are a classical algebraic tool for determining if
535 a system of n polynomials in n-1 variables have common root
536 without explicitly solving for the roots.
538 They are efficiently represented as determinants of Bezout
539 matrices whose entries are computed using O(n**2) additions
540 and multiplications where n = max(deg(f), deg(g)).
542 >>> from sympy import *
543 >>> x,y = symbols('xy')
545 Polynomials x**2-1 and (x-1)**2 have common root:
547 >>> poly_resultant(x**2-1, (x-1)**2, x)
550 For more information on the implemented algorithm refer to:
552 [1] Eng-Wee Chionh, Fast Computation of the Bezout and Dixon
553 Resultant Matrices, Journal of Symbolic Computation, ACM,
554 Volume 33, Issue 1, January 2002, Pages 13-29
557 if not isinstance(f
, Poly
):
558 f
= Poly(f
, *symbols
)
560 raise SymbolsError("Redundant symbols were given")
562 f
, g
= f
.unify_with(g
)
564 if f
.is_multivariate
:
565 raise MultivariatePolyError(f
)
567 n
, m
= f
.degree
, g
.degree
578 import sympy
.matrices
580 B
= sympy
.matrices
.zeros(N
)
583 for j
in xrange(i
, N
):
584 if p
.has_key(i
) and q
.has_key(j
+1):
585 B
[i
, j
] += p
[i
] * q
[j
+1]
587 if p
.has_key(j
+1) and q
.has_key(i
):
588 B
[i
, j
] -= p
[j
+1] * q
[i
]
590 for i
in xrange(1, N
-1):
591 for j
in xrange(i
, N
-1):
592 B
[i
, j
] += B
[i
-1, j
+1]
595 for j
in xrange(i
+1, N
):
608 sign
= (-1)**(n
*(n
-1)/2)
613 return sign
* Poly
.cancel(det
)
615 def poly_subresultants(f
, g
, *symbols
):
616 """Computes subresultant PRS of two univariate polynomials.
618 Polynomial remainder sequence (PRS) is a fundamental tool in
619 computer algebra as it gives as a sub-product the polynomial
620 greatest common divisor (GCD), provided that the coefficient
621 domain is an unique factorization domain.
623 There are several methods for computing PRS, eg.: Euclidean
624 PRS, where the most famous algorithm is used, primitive PRS
625 and, finally, subresultants which are implemented here.
627 The Euclidean approach is reasonably efficient but suffers
628 severely from coefficient growth. The primitive algorithm
629 avoids this but requires a lot of coefficient computations.
631 Subresultants solve both problems and so it is efficient and
632 have moderate coefficient growth. The current implementation
633 uses pseudo-divisions which is well suited for coefficients
634 in integral domains or number fields.
636 Formally, given univariate polynomials f and g over an UFD,
637 then a sequence (R_0, R_1, ..., R_k, 0, ...) is a polynomial
638 remainder sequence where R_0 = f, R_1 = g, R_k != 0 and R_k
639 is similar to gcd(f, g).
641 For more information on the implemented algorithm refer to:
643 [1] M. Bronstein, Symbolic Integration I: Transcendental
644 Functions, Second Edition, Springer-Verlang, 2005
646 [2] M. Keber, Division-Free computation of subresultants
647 using Bezout matrices, Tech. Report MPI-I-2006-1-006,
651 if not isinstance(f
, Poly
):
652 f
= Poly(f
, *symbols
)
654 raise SymbolsError("Redundant symbols were given")
656 f
, g
= f
.unify_with(g
)
658 if f
.is_multivariate
:
659 raise MultivariatePolyError(f
)
661 symbols
, flags
= f
.symbols
, f
.flags
663 n
, m
= f
.degree
, g
.degree
675 h
= poly_pdiv(f
, g
)[1]
687 c
= (-coeff
)**d
/ c
**(d
-1)
689 b
= -coeff
* c
**(m
-k
)
691 f
, g
, m
, d
= g
, h
, k
, m
-k
693 h
= poly_pdiv(f
, g
)[1]
700 def poly_sqf(f
, *symbols
):
701 """Compute square-free decomposition of an univariate polynomial.
703 Given an univariate polynomial f over an unique factorization domain
704 returns tuple (f_1, f_2, ..., f_n), where all A_i are co-prime and
705 square-free polynomials and f = f_1 * f_2**2 * ... * f_n**n.
707 >>> from sympy import *
708 >>> x,y = symbols('xy')
710 >>> p, q = poly_sqf(x*(x+1)**2, x)
717 For more information on the implemented algorithm refer to:
719 [1] M. Bronstein, Symbolic Integration I: Transcendental
720 Functions, Second Edition, Springer-Verlang, 2005
722 [2] J. von zur Gathen, J. Gerhard, Modern Computer Algebra,
723 Second Edition, Cambridge University Press, 2003
726 if not isinstance(f
, Poly
):
727 f
= Poly(f
, *symbols
)
729 raise SymbolsError("Redundant symbols were given")
731 if f
.is_multivariate
:
732 raise MultivariatePolyError(f
)
734 coeff
, f
= f
.as_primitive()
742 p
= poly_div(f
, g
)[0]
743 q
= poly_div(h
, g
)[0]
755 p
= poly_div(p
, g
)[0]
756 q
= poly_div(h
, g
)[0]
760 head
, tail
= sqf
[0], sqf
[1:]
761 head
= head
.mul_term(coeff
)
765 def poly_decompose(f
, *symbols
):
766 """Computes functional decomposition of an univariate polynomial.
768 Besides factorization and square-free decomposition, functional
769 decomposition is another important, but very different, way of
770 breaking down polynomials into simpler parts.
772 Formally given an univariate polynomial f with coefficients in a
773 field of characteristic zero, returns tuple (f_1, f_2, ..., f_n)
774 where f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) and f_2, ...,
775 f_n are monic and homogeneous polynomials of degree at least 2.
777 Unlike factorization, complete functional decompositions of
778 polynomials are not unique, consider examples:
780 [1] f o g = f(x + b) o (g - b)
781 [2] x**n o x**m = x**m o x**n
782 [3] T_n o T_m = T_m o T_n
784 where T_n and T_m are Chebyshev polynomials.
786 >>> from sympy import *
787 >>> x,y = symbols('xy')
789 >>> p, q = poly_decompose(x**4+2*x**2 + y, x)
796 For more information on the implemented algorithm refer to:
798 [1] D. Kozen, S. Landau, Polynomial decomposition algorithms,
799 Journal of Symbolic Computation 7 (1989), pp. 445-456
802 if not isinstance(f
, Poly
):
803 f
= Poly(f
, *symbols
)
805 raise SymbolsError("Redundant symbols were given")
807 if f
.is_multivariate
:
808 raise MultivariatePolyError(f
)
813 def right_factor(f
, s
):
814 n
, lc
= f
.degree
, f
.LC
821 for k
in xrange(1, s
):
824 for j
in xrange(0, k
):
825 if not f
.has_key(n
+j
-k
):
828 if not q
.has_key(s
-j
):
831 fc
, qc
= f
[n
+j
-k
], q
[s
-j
]
833 coeff
+= (k
- r
*j
)*fc
*qc
835 if coeff
is not S
.Zero
:
836 q
[s
-k
] = coeff
/ (k
*r
*lc
)
838 return Poly(q
, *symbols
, **flags
)
840 def left_factor(f
, h
):
844 q
, r
= poly_div(f
, h
)
846 if not r
.is_constant
:
849 if r
.LC
is not S
.Zero
:
854 return Poly(g
, *symbols
, **flags
)
859 for s
in xrange(2, deg
):
863 h
= right_factor(f
, s
)
866 g
= left_factor(f
, h
)
876 result
= decompose(f
)
878 if result
is not None: