Coverage for /usr/lib/python3/dist-packages/sympy/polys/euclidtools.py: 9%
668 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """
4from sympy.polys.densearith import (
5 dup_sub_mul,
6 dup_neg, dmp_neg,
7 dmp_add,
8 dmp_sub,
9 dup_mul, dmp_mul,
10 dmp_pow,
11 dup_div, dmp_div,
12 dup_rem,
13 dup_quo, dmp_quo,
14 dup_prem, dmp_prem,
15 dup_mul_ground, dmp_mul_ground,
16 dmp_mul_term,
17 dup_quo_ground, dmp_quo_ground,
18 dup_max_norm, dmp_max_norm)
19from sympy.polys.densebasic import (
20 dup_strip, dmp_raise,
21 dmp_zero, dmp_one, dmp_ground,
22 dmp_one_p, dmp_zero_p,
23 dmp_zeros,
24 dup_degree, dmp_degree, dmp_degree_in,
25 dup_LC, dmp_LC, dmp_ground_LC,
26 dmp_multi_deflate, dmp_inflate,
27 dup_convert, dmp_convert,
28 dmp_apply_pairs)
29from sympy.polys.densetools import (
30 dup_clear_denoms, dmp_clear_denoms,
31 dup_diff, dmp_diff,
32 dup_eval, dmp_eval, dmp_eval_in,
33 dup_trunc, dmp_ground_trunc,
34 dup_monic, dmp_ground_monic,
35 dup_primitive, dmp_ground_primitive,
36 dup_extract, dmp_ground_extract)
37from sympy.polys.galoistools import (
38 gf_int, gf_crt)
39from sympy.polys.polyconfig import query
40from sympy.polys.polyerrors import (
41 MultivariatePolynomialError,
42 HeuristicGCDFailed,
43 HomomorphismFailed,
44 NotInvertible,
45 DomainError)
50def dup_half_gcdex(f, g, K):
51 """
52 Half extended Euclidean algorithm in `F[x]`.
54 Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``.
56 Examples
57 ========
59 >>> from sympy.polys import ring, QQ
60 >>> R, x = ring("x", QQ)
62 >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15
63 >>> g = x**3 + x**2 - 4*x - 4
65 >>> R.dup_half_gcdex(f, g)
66 (-1/5*x + 3/5, x + 1)
68 """
69 if not K.is_Field:
70 raise DomainError("Cannot compute half extended GCD over %s" % K)
72 a, b = [K.one], []
74 while g:
75 q, r = dup_div(f, g, K)
76 f, g = g, r
77 a, b = b, dup_sub_mul(a, q, b, K)
79 a = dup_quo_ground(a, dup_LC(f, K), K)
80 f = dup_monic(f, K)
82 return a, f
85def dmp_half_gcdex(f, g, u, K):
86 """
87 Half extended Euclidean algorithm in `F[X]`.
89 Examples
90 ========
92 >>> from sympy.polys import ring, ZZ
93 >>> R, x,y = ring("x,y", ZZ)
95 """
96 if not u:
97 return dup_half_gcdex(f, g, K)
98 else:
99 raise MultivariatePolynomialError(f, g)
102def dup_gcdex(f, g, K):
103 """
104 Extended Euclidean algorithm in `F[x]`.
106 Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``.
108 Examples
109 ========
111 >>> from sympy.polys import ring, QQ
112 >>> R, x = ring("x", QQ)
114 >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15
115 >>> g = x**3 + x**2 - 4*x - 4
117 >>> R.dup_gcdex(f, g)
118 (-1/5*x + 3/5, 1/5*x**2 - 6/5*x + 2, x + 1)
120 """
121 s, h = dup_half_gcdex(f, g, K)
123 F = dup_sub_mul(h, s, f, K)
124 t = dup_quo(F, g, K)
126 return s, t, h
129def dmp_gcdex(f, g, u, K):
130 """
131 Extended Euclidean algorithm in `F[X]`.
133 Examples
134 ========
136 >>> from sympy.polys import ring, ZZ
137 >>> R, x,y = ring("x,y", ZZ)
139 """
140 if not u:
141 return dup_gcdex(f, g, K)
142 else:
143 raise MultivariatePolynomialError(f, g)
146def dup_invert(f, g, K):
147 """
148 Compute multiplicative inverse of `f` modulo `g` in `F[x]`.
150 Examples
151 ========
153 >>> from sympy.polys import ring, QQ
154 >>> R, x = ring("x", QQ)
156 >>> f = x**2 - 1
157 >>> g = 2*x - 1
158 >>> h = x - 1
160 >>> R.dup_invert(f, g)
161 -4/3
163 >>> R.dup_invert(f, h)
164 Traceback (most recent call last):
165 ...
166 NotInvertible: zero divisor
168 """
169 s, h = dup_half_gcdex(f, g, K)
171 if h == [K.one]:
172 return dup_rem(s, g, K)
173 else:
174 raise NotInvertible("zero divisor")
177def dmp_invert(f, g, u, K):
178 """
179 Compute multiplicative inverse of `f` modulo `g` in `F[X]`.
181 Examples
182 ========
184 >>> from sympy.polys import ring, QQ
185 >>> R, x = ring("x", QQ)
187 """
188 if not u:
189 return dup_invert(f, g, K)
190 else:
191 raise MultivariatePolynomialError(f, g)
194def dup_euclidean_prs(f, g, K):
195 """
196 Euclidean polynomial remainder sequence (PRS) in `K[x]`.
198 Examples
199 ========
201 >>> from sympy.polys import ring, QQ
202 >>> R, x = ring("x", QQ)
204 >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5
205 >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21
207 >>> prs = R.dup_euclidean_prs(f, g)
209 >>> prs[0]
210 x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5
211 >>> prs[1]
212 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21
213 >>> prs[2]
214 -5/9*x**4 + 1/9*x**2 - 1/3
215 >>> prs[3]
216 -117/25*x**2 - 9*x + 441/25
217 >>> prs[4]
218 233150/19773*x - 102500/6591
219 >>> prs[5]
220 -1288744821/543589225
222 """
223 prs = [f, g]
224 h = dup_rem(f, g, K)
226 while h:
227 prs.append(h)
228 f, g = g, h
229 h = dup_rem(f, g, K)
231 return prs
234def dmp_euclidean_prs(f, g, u, K):
235 """
236 Euclidean polynomial remainder sequence (PRS) in `K[X]`.
238 Examples
239 ========
241 >>> from sympy.polys import ring, ZZ
242 >>> R, x,y = ring("x,y", ZZ)
244 """
245 if not u:
246 return dup_euclidean_prs(f, g, K)
247 else:
248 raise MultivariatePolynomialError(f, g)
251def dup_primitive_prs(f, g, K):
252 """
253 Primitive polynomial remainder sequence (PRS) in `K[x]`.
255 Examples
256 ========
258 >>> from sympy.polys import ring, ZZ
259 >>> R, x = ring("x", ZZ)
261 >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5
262 >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21
264 >>> prs = R.dup_primitive_prs(f, g)
266 >>> prs[0]
267 x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5
268 >>> prs[1]
269 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21
270 >>> prs[2]
271 -5*x**4 + x**2 - 3
272 >>> prs[3]
273 13*x**2 + 25*x - 49
274 >>> prs[4]
275 4663*x - 6150
276 >>> prs[5]
277 1
279 """
280 prs = [f, g]
281 _, h = dup_primitive(dup_prem(f, g, K), K)
283 while h:
284 prs.append(h)
285 f, g = g, h
286 _, h = dup_primitive(dup_prem(f, g, K), K)
288 return prs
291def dmp_primitive_prs(f, g, u, K):
292 """
293 Primitive polynomial remainder sequence (PRS) in `K[X]`.
295 Examples
296 ========
298 >>> from sympy.polys import ring, ZZ
299 >>> R, x,y = ring("x,y", ZZ)
301 """
302 if not u:
303 return dup_primitive_prs(f, g, K)
304 else:
305 raise MultivariatePolynomialError(f, g)
308def dup_inner_subresultants(f, g, K):
309 """
310 Subresultant PRS algorithm in `K[x]`.
312 Computes the subresultant polynomial remainder sequence (PRS)
313 and the non-zero scalar subresultants of `f` and `g`.
314 By [1] Thm. 3, these are the constants '-c' (- to optimize
315 computation of sign).
316 The first subdeterminant is set to 1 by convention to match
317 the polynomial and the scalar subdeterminants.
318 If 'deg(f) < deg(g)', the subresultants of '(g,f)' are computed.
320 Examples
321 ========
323 >>> from sympy.polys import ring, ZZ
324 >>> R, x = ring("x", ZZ)
326 >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1)
327 ([x**2 + 1, x**2 - 1, -2], [1, 1, 4])
329 References
330 ==========
332 .. [1] W.S. Brown, The Subresultant PRS Algorithm.
333 ACM Transaction of Mathematical Software 4 (1978) 237-249
335 """
336 n = dup_degree(f)
337 m = dup_degree(g)
339 if n < m:
340 f, g = g, f
341 n, m = m, n
343 if not f:
344 return [], []
346 if not g:
347 return [f], [K.one]
349 R = [f, g]
350 d = n - m
352 b = (-K.one)**(d + 1)
354 h = dup_prem(f, g, K)
355 h = dup_mul_ground(h, b, K)
357 lc = dup_LC(g, K)
358 c = lc**d
360 # Conventional first scalar subdeterminant is 1
361 S = [K.one, c]
362 c = -c
364 while h:
365 k = dup_degree(h)
366 R.append(h)
368 f, g, m, d = g, h, k, m - k
370 b = -lc * c**d
372 h = dup_prem(f, g, K)
373 h = dup_quo_ground(h, b, K)
375 lc = dup_LC(g, K)
377 if d > 1: # abnormal case
378 q = c**(d - 1)
379 c = K.quo((-lc)**d, q)
380 else:
381 c = -lc
383 S.append(-c)
385 return R, S
388def dup_subresultants(f, g, K):
389 """
390 Computes subresultant PRS of two polynomials in `K[x]`.
392 Examples
393 ========
395 >>> from sympy.polys import ring, ZZ
396 >>> R, x = ring("x", ZZ)
398 >>> R.dup_subresultants(x**2 + 1, x**2 - 1)
399 [x**2 + 1, x**2 - 1, -2]
401 """
402 return dup_inner_subresultants(f, g, K)[0]
405def dup_prs_resultant(f, g, K):
406 """
407 Resultant algorithm in `K[x]` using subresultant PRS.
409 Examples
410 ========
412 >>> from sympy.polys import ring, ZZ
413 >>> R, x = ring("x", ZZ)
415 >>> R.dup_prs_resultant(x**2 + 1, x**2 - 1)
416 (4, [x**2 + 1, x**2 - 1, -2])
418 """
419 if not f or not g:
420 return (K.zero, [])
422 R, S = dup_inner_subresultants(f, g, K)
424 if dup_degree(R[-1]) > 0:
425 return (K.zero, R)
427 return S[-1], R
430def dup_resultant(f, g, K, includePRS=False):
431 """
432 Computes resultant of two polynomials in `K[x]`.
434 Examples
435 ========
437 >>> from sympy.polys import ring, ZZ
438 >>> R, x = ring("x", ZZ)
440 >>> R.dup_resultant(x**2 + 1, x**2 - 1)
441 4
443 """
444 if includePRS:
445 return dup_prs_resultant(f, g, K)
446 return dup_prs_resultant(f, g, K)[0]
449def dmp_inner_subresultants(f, g, u, K):
450 """
451 Subresultant PRS algorithm in `K[X]`.
453 Examples
454 ========
456 >>> from sympy.polys import ring, ZZ
457 >>> R, x,y = ring("x,y", ZZ)
459 >>> f = 3*x**2*y - y**3 - 4
460 >>> g = x**2 + x*y**3 - 9
462 >>> a = 3*x*y**4 + y**3 - 27*y + 4
463 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16
465 >>> prs = [f, g, a, b]
466 >>> sres = [[1], [1], [3, 0, 0, 0, 0], [-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]]
468 >>> R.dmp_inner_subresultants(f, g) == (prs, sres)
469 True
471 """
472 if not u:
473 return dup_inner_subresultants(f, g, K)
475 n = dmp_degree(f, u)
476 m = dmp_degree(g, u)
478 if n < m:
479 f, g = g, f
480 n, m = m, n
482 if dmp_zero_p(f, u):
483 return [], []
485 v = u - 1
486 if dmp_zero_p(g, u):
487 return [f], [dmp_ground(K.one, v)]
489 R = [f, g]
490 d = n - m
492 b = dmp_pow(dmp_ground(-K.one, v), d + 1, v, K)
494 h = dmp_prem(f, g, u, K)
495 h = dmp_mul_term(h, b, 0, u, K)
497 lc = dmp_LC(g, K)
498 c = dmp_pow(lc, d, v, K)
500 S = [dmp_ground(K.one, v), c]
501 c = dmp_neg(c, v, K)
503 while not dmp_zero_p(h, u):
504 k = dmp_degree(h, u)
505 R.append(h)
507 f, g, m, d = g, h, k, m - k
509 b = dmp_mul(dmp_neg(lc, v, K),
510 dmp_pow(c, d, v, K), v, K)
512 h = dmp_prem(f, g, u, K)
513 h = [ dmp_quo(ch, b, v, K) for ch in h ]
515 lc = dmp_LC(g, K)
517 if d > 1:
518 p = dmp_pow(dmp_neg(lc, v, K), d, v, K)
519 q = dmp_pow(c, d - 1, v, K)
520 c = dmp_quo(p, q, v, K)
521 else:
522 c = dmp_neg(lc, v, K)
524 S.append(dmp_neg(c, v, K))
526 return R, S
529def dmp_subresultants(f, g, u, K):
530 """
531 Computes subresultant PRS of two polynomials in `K[X]`.
533 Examples
534 ========
536 >>> from sympy.polys import ring, ZZ
537 >>> R, x,y = ring("x,y", ZZ)
539 >>> f = 3*x**2*y - y**3 - 4
540 >>> g = x**2 + x*y**3 - 9
542 >>> a = 3*x*y**4 + y**3 - 27*y + 4
543 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16
545 >>> R.dmp_subresultants(f, g) == [f, g, a, b]
546 True
548 """
549 return dmp_inner_subresultants(f, g, u, K)[0]
552def dmp_prs_resultant(f, g, u, K):
553 """
554 Resultant algorithm in `K[X]` using subresultant PRS.
556 Examples
557 ========
559 >>> from sympy.polys import ring, ZZ
560 >>> R, x,y = ring("x,y", ZZ)
562 >>> f = 3*x**2*y - y**3 - 4
563 >>> g = x**2 + x*y**3 - 9
565 >>> a = 3*x*y**4 + y**3 - 27*y + 4
566 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16
568 >>> res, prs = R.dmp_prs_resultant(f, g)
570 >>> res == b # resultant has n-1 variables
571 False
572 >>> res == b.drop(x)
573 True
574 >>> prs == [f, g, a, b]
575 True
577 """
578 if not u:
579 return dup_prs_resultant(f, g, K)
581 if dmp_zero_p(f, u) or dmp_zero_p(g, u):
582 return (dmp_zero(u - 1), [])
584 R, S = dmp_inner_subresultants(f, g, u, K)
586 if dmp_degree(R[-1], u) > 0:
587 return (dmp_zero(u - 1), R)
589 return S[-1], R
592def dmp_zz_modular_resultant(f, g, p, u, K):
593 """
594 Compute resultant of `f` and `g` modulo a prime `p`.
596 Examples
597 ========
599 >>> from sympy.polys import ring, ZZ
600 >>> R, x,y = ring("x,y", ZZ)
602 >>> f = x + y + 2
603 >>> g = 2*x*y + x + 3
605 >>> R.dmp_zz_modular_resultant(f, g, 5)
606 -2*y**2 + 1
608 """
609 if not u:
610 return gf_int(dup_prs_resultant(f, g, K)[0] % p, p)
612 v = u - 1
614 n = dmp_degree(f, u)
615 m = dmp_degree(g, u)
617 N = dmp_degree_in(f, 1, u)
618 M = dmp_degree_in(g, 1, u)
620 B = n*M + m*N
622 D, a = [K.one], -K.one
623 r = dmp_zero(v)
625 while dup_degree(D) <= B:
626 while True:
627 a += K.one
629 if a == p:
630 raise HomomorphismFailed('no luck')
632 F = dmp_eval_in(f, gf_int(a, p), 1, u, K)
634 if dmp_degree(F, v) == n:
635 G = dmp_eval_in(g, gf_int(a, p), 1, u, K)
637 if dmp_degree(G, v) == m:
638 break
640 R = dmp_zz_modular_resultant(F, G, p, v, K)
641 e = dmp_eval(r, a, v, K)
643 if not v:
644 R = dup_strip([R])
645 e = dup_strip([e])
646 else:
647 R = [R]
648 e = [e]
650 d = K.invert(dup_eval(D, a, K), p)
651 d = dup_mul_ground(D, d, K)
652 d = dmp_raise(d, v, 0, K)
654 c = dmp_mul(d, dmp_sub(R, e, v, K), v, K)
655 r = dmp_add(r, c, v, K)
657 r = dmp_ground_trunc(r, p, v, K)
659 D = dup_mul(D, [K.one, -a], K)
660 D = dup_trunc(D, p, K)
662 return r
665def _collins_crt(r, R, P, p, K):
666 """Wrapper of CRT for Collins's resultant algorithm. """
667 return gf_int(gf_crt([r, R], [P, p], K), P*p)
670def dmp_zz_collins_resultant(f, g, u, K):
671 """
672 Collins's modular resultant algorithm in `Z[X]`.
674 Examples
675 ========
677 >>> from sympy.polys import ring, ZZ
678 >>> R, x,y = ring("x,y", ZZ)
680 >>> f = x + y + 2
681 >>> g = 2*x*y + x + 3
683 >>> R.dmp_zz_collins_resultant(f, g)
684 -2*y**2 - 5*y + 1
686 """
688 n = dmp_degree(f, u)
689 m = dmp_degree(g, u)
691 if n < 0 or m < 0:
692 return dmp_zero(u - 1)
694 A = dmp_max_norm(f, u, K)
695 B = dmp_max_norm(g, u, K)
697 a = dmp_ground_LC(f, u, K)
698 b = dmp_ground_LC(g, u, K)
700 v = u - 1
702 B = K(2)*K.factorial(K(n + m))*A**m*B**n
703 r, p, P = dmp_zero(v), K.one, K.one
705 from sympy.ntheory import nextprime
707 while P <= B:
708 p = K(nextprime(p))
710 while not (a % p) or not (b % p):
711 p = K(nextprime(p))
713 F = dmp_ground_trunc(f, p, u, K)
714 G = dmp_ground_trunc(g, p, u, K)
716 try:
717 R = dmp_zz_modular_resultant(F, G, p, u, K)
718 except HomomorphismFailed:
719 continue
721 if K.is_one(P):
722 r = R
723 else:
724 r = dmp_apply_pairs(r, R, _collins_crt, (P, p, K), v, K)
726 P *= p
728 return r
731def dmp_qq_collins_resultant(f, g, u, K0):
732 """
733 Collins's modular resultant algorithm in `Q[X]`.
735 Examples
736 ========
738 >>> from sympy.polys import ring, QQ
739 >>> R, x,y = ring("x,y", QQ)
741 >>> f = QQ(1,2)*x + y + QQ(2,3)
742 >>> g = 2*x*y + x + 3
744 >>> R.dmp_qq_collins_resultant(f, g)
745 -2*y**2 - 7/3*y + 5/6
747 """
748 n = dmp_degree(f, u)
749 m = dmp_degree(g, u)
751 if n < 0 or m < 0:
752 return dmp_zero(u - 1)
754 K1 = K0.get_ring()
756 cf, f = dmp_clear_denoms(f, u, K0, K1)
757 cg, g = dmp_clear_denoms(g, u, K0, K1)
759 f = dmp_convert(f, u, K0, K1)
760 g = dmp_convert(g, u, K0, K1)
762 r = dmp_zz_collins_resultant(f, g, u, K1)
763 r = dmp_convert(r, u - 1, K1, K0)
765 c = K0.convert(cf**m * cg**n, K1)
767 return dmp_quo_ground(r, c, u - 1, K0)
770def dmp_resultant(f, g, u, K, includePRS=False):
771 """
772 Computes resultant of two polynomials in `K[X]`.
774 Examples
775 ========
777 >>> from sympy.polys import ring, ZZ
778 >>> R, x,y = ring("x,y", ZZ)
780 >>> f = 3*x**2*y - y**3 - 4
781 >>> g = x**2 + x*y**3 - 9
783 >>> R.dmp_resultant(f, g)
784 -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16
786 """
787 if not u:
788 return dup_resultant(f, g, K, includePRS=includePRS)
790 if includePRS:
791 return dmp_prs_resultant(f, g, u, K)
793 if K.is_Field:
794 if K.is_QQ and query('USE_COLLINS_RESULTANT'):
795 return dmp_qq_collins_resultant(f, g, u, K)
796 else:
797 if K.is_ZZ and query('USE_COLLINS_RESULTANT'):
798 return dmp_zz_collins_resultant(f, g, u, K)
800 return dmp_prs_resultant(f, g, u, K)[0]
803def dup_discriminant(f, K):
804 """
805 Computes discriminant of a polynomial in `K[x]`.
807 Examples
808 ========
810 >>> from sympy.polys import ring, ZZ
811 >>> R, x = ring("x", ZZ)
813 >>> R.dup_discriminant(x**2 + 2*x + 3)
814 -8
816 """
817 d = dup_degree(f)
819 if d <= 0:
820 return K.zero
821 else:
822 s = (-1)**((d*(d - 1)) // 2)
823 c = dup_LC(f, K)
825 r = dup_resultant(f, dup_diff(f, 1, K), K)
827 return K.quo(r, c*K(s))
830def dmp_discriminant(f, u, K):
831 """
832 Computes discriminant of a polynomial in `K[X]`.
834 Examples
835 ========
837 >>> from sympy.polys import ring, ZZ
838 >>> R, x,y,z,t = ring("x,y,z,t", ZZ)
840 >>> R.dmp_discriminant(x**2*y + x*z + t)
841 -4*y*t + z**2
843 """
844 if not u:
845 return dup_discriminant(f, K)
847 d, v = dmp_degree(f, u), u - 1
849 if d <= 0:
850 return dmp_zero(v)
851 else:
852 s = (-1)**((d*(d - 1)) // 2)
853 c = dmp_LC(f, K)
855 r = dmp_resultant(f, dmp_diff(f, 1, u, K), u, K)
856 c = dmp_mul_ground(c, K(s), v, K)
858 return dmp_quo(r, c, v, K)
861def _dup_rr_trivial_gcd(f, g, K):
862 """Handle trivial cases in GCD algorithm over a ring. """
863 if not (f or g):
864 return [], [], []
865 elif not f:
866 if K.is_nonnegative(dup_LC(g, K)):
867 return g, [], [K.one]
868 else:
869 return dup_neg(g, K), [], [-K.one]
870 elif not g:
871 if K.is_nonnegative(dup_LC(f, K)):
872 return f, [K.one], []
873 else:
874 return dup_neg(f, K), [-K.one], []
876 return None
879def _dup_ff_trivial_gcd(f, g, K):
880 """Handle trivial cases in GCD algorithm over a field. """
881 if not (f or g):
882 return [], [], []
883 elif not f:
884 return dup_monic(g, K), [], [dup_LC(g, K)]
885 elif not g:
886 return dup_monic(f, K), [dup_LC(f, K)], []
887 else:
888 return None
891def _dmp_rr_trivial_gcd(f, g, u, K):
892 """Handle trivial cases in GCD algorithm over a ring. """
893 zero_f = dmp_zero_p(f, u)
894 zero_g = dmp_zero_p(g, u)
895 if_contain_one = dmp_one_p(f, u, K) or dmp_one_p(g, u, K)
897 if zero_f and zero_g:
898 return tuple(dmp_zeros(3, u, K))
899 elif zero_f:
900 if K.is_nonnegative(dmp_ground_LC(g, u, K)):
901 return g, dmp_zero(u), dmp_one(u, K)
902 else:
903 return dmp_neg(g, u, K), dmp_zero(u), dmp_ground(-K.one, u)
904 elif zero_g:
905 if K.is_nonnegative(dmp_ground_LC(f, u, K)):
906 return f, dmp_one(u, K), dmp_zero(u)
907 else:
908 return dmp_neg(f, u, K), dmp_ground(-K.one, u), dmp_zero(u)
909 elif if_contain_one:
910 return dmp_one(u, K), f, g
911 elif query('USE_SIMPLIFY_GCD'):
912 return _dmp_simplify_gcd(f, g, u, K)
913 else:
914 return None
917def _dmp_ff_trivial_gcd(f, g, u, K):
918 """Handle trivial cases in GCD algorithm over a field. """
919 zero_f = dmp_zero_p(f, u)
920 zero_g = dmp_zero_p(g, u)
922 if zero_f and zero_g:
923 return tuple(dmp_zeros(3, u, K))
924 elif zero_f:
925 return (dmp_ground_monic(g, u, K),
926 dmp_zero(u),
927 dmp_ground(dmp_ground_LC(g, u, K), u))
928 elif zero_g:
929 return (dmp_ground_monic(f, u, K),
930 dmp_ground(dmp_ground_LC(f, u, K), u),
931 dmp_zero(u))
932 elif query('USE_SIMPLIFY_GCD'):
933 return _dmp_simplify_gcd(f, g, u, K)
934 else:
935 return None
938def _dmp_simplify_gcd(f, g, u, K):
939 """Try to eliminate `x_0` from GCD computation in `K[X]`. """
940 df = dmp_degree(f, u)
941 dg = dmp_degree(g, u)
943 if df > 0 and dg > 0:
944 return None
946 if not (df or dg):
947 F = dmp_LC(f, K)
948 G = dmp_LC(g, K)
949 else:
950 if not df:
951 F = dmp_LC(f, K)
952 G = dmp_content(g, u, K)
953 else:
954 F = dmp_content(f, u, K)
955 G = dmp_LC(g, K)
957 v = u - 1
958 h = dmp_gcd(F, G, v, K)
960 cff = [ dmp_quo(cf, h, v, K) for cf in f ]
961 cfg = [ dmp_quo(cg, h, v, K) for cg in g ]
963 return [h], cff, cfg
966def dup_rr_prs_gcd(f, g, K):
967 """
968 Computes polynomial GCD using subresultants over a ring.
970 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``,
971 and ``cfg = quo(g, h)``.
973 Examples
974 ========
976 >>> from sympy.polys import ring, ZZ
977 >>> R, x = ring("x", ZZ)
979 >>> R.dup_rr_prs_gcd(x**2 - 1, x**2 - 3*x + 2)
980 (x - 1, x + 1, x - 2)
982 """
983 result = _dup_rr_trivial_gcd(f, g, K)
985 if result is not None:
986 return result
988 fc, F = dup_primitive(f, K)
989 gc, G = dup_primitive(g, K)
991 c = K.gcd(fc, gc)
993 h = dup_subresultants(F, G, K)[-1]
994 _, h = dup_primitive(h, K)
996 c *= K.canonical_unit(dup_LC(h, K))
998 h = dup_mul_ground(h, c, K)
1000 cff = dup_quo(f, h, K)
1001 cfg = dup_quo(g, h, K)
1003 return h, cff, cfg
1006def dup_ff_prs_gcd(f, g, K):
1007 """
1008 Computes polynomial GCD using subresultants over a field.
1010 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``,
1011 and ``cfg = quo(g, h)``.
1013 Examples
1014 ========
1016 >>> from sympy.polys import ring, QQ
1017 >>> R, x = ring("x", QQ)
1019 >>> R.dup_ff_prs_gcd(x**2 - 1, x**2 - 3*x + 2)
1020 (x - 1, x + 1, x - 2)
1022 """
1023 result = _dup_ff_trivial_gcd(f, g, K)
1025 if result is not None:
1026 return result
1028 h = dup_subresultants(f, g, K)[-1]
1029 h = dup_monic(h, K)
1031 cff = dup_quo(f, h, K)
1032 cfg = dup_quo(g, h, K)
1034 return h, cff, cfg
1037def dmp_rr_prs_gcd(f, g, u, K):
1038 """
1039 Computes polynomial GCD using subresultants over a ring.
1041 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``,
1042 and ``cfg = quo(g, h)``.
1044 Examples
1045 ========
1047 >>> from sympy.polys import ring, ZZ
1048 >>> R, x,y, = ring("x,y", ZZ)
1050 >>> f = x**2 + 2*x*y + y**2
1051 >>> g = x**2 + x*y
1053 >>> R.dmp_rr_prs_gcd(f, g)
1054 (x + y, x + y, x)
1056 """
1057 if not u:
1058 return dup_rr_prs_gcd(f, g, K)
1060 result = _dmp_rr_trivial_gcd(f, g, u, K)
1062 if result is not None:
1063 return result
1065 fc, F = dmp_primitive(f, u, K)
1066 gc, G = dmp_primitive(g, u, K)
1068 h = dmp_subresultants(F, G, u, K)[-1]
1069 c, _, _ = dmp_rr_prs_gcd(fc, gc, u - 1, K)
1071 if K.is_negative(dmp_ground_LC(h, u, K)):
1072 h = dmp_neg(h, u, K)
1074 _, h = dmp_primitive(h, u, K)
1075 h = dmp_mul_term(h, c, 0, u, K)
1077 cff = dmp_quo(f, h, u, K)
1078 cfg = dmp_quo(g, h, u, K)
1080 return h, cff, cfg
1083def dmp_ff_prs_gcd(f, g, u, K):
1084 """
1085 Computes polynomial GCD using subresultants over a field.
1087 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``,
1088 and ``cfg = quo(g, h)``.
1090 Examples
1091 ========
1093 >>> from sympy.polys import ring, QQ
1094 >>> R, x,y, = ring("x,y", QQ)
1096 >>> f = QQ(1,2)*x**2 + x*y + QQ(1,2)*y**2
1097 >>> g = x**2 + x*y
1099 >>> R.dmp_ff_prs_gcd(f, g)
1100 (x + y, 1/2*x + 1/2*y, x)
1102 """
1103 if not u:
1104 return dup_ff_prs_gcd(f, g, K)
1106 result = _dmp_ff_trivial_gcd(f, g, u, K)
1108 if result is not None:
1109 return result
1111 fc, F = dmp_primitive(f, u, K)
1112 gc, G = dmp_primitive(g, u, K)
1114 h = dmp_subresultants(F, G, u, K)[-1]
1115 c, _, _ = dmp_ff_prs_gcd(fc, gc, u - 1, K)
1117 _, h = dmp_primitive(h, u, K)
1118 h = dmp_mul_term(h, c, 0, u, K)
1119 h = dmp_ground_monic(h, u, K)
1121 cff = dmp_quo(f, h, u, K)
1122 cfg = dmp_quo(g, h, u, K)
1124 return h, cff, cfg
1126HEU_GCD_MAX = 6
1129def _dup_zz_gcd_interpolate(h, x, K):
1130 """Interpolate polynomial GCD from integer GCD. """
1131 f = []
1133 while h:
1134 g = h % x
1136 if g > x // 2:
1137 g -= x
1139 f.insert(0, g)
1140 h = (h - g) // x
1142 return f
1145def dup_zz_heu_gcd(f, g, K):
1146 """
1147 Heuristic polynomial GCD in `Z[x]`.
1149 Given univariate polynomials `f` and `g` in `Z[x]`, returns
1150 their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg``
1151 such that::
1153 h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h)
1155 The algorithm is purely heuristic which means it may fail to compute
1156 the GCD. This will be signaled by raising an exception. In this case
1157 you will need to switch to another GCD method.
1159 The algorithm computes the polynomial GCD by evaluating polynomials
1160 f and g at certain points and computing (fast) integer GCD of those
1161 evaluations. The polynomial GCD is recovered from the integer image
1162 by interpolation. The final step is to verify if the result is the
1163 correct GCD. This gives cofactors as a side effect.
1165 Examples
1166 ========
1168 >>> from sympy.polys import ring, ZZ
1169 >>> R, x = ring("x", ZZ)
1171 >>> R.dup_zz_heu_gcd(x**2 - 1, x**2 - 3*x + 2)
1172 (x - 1, x + 1, x - 2)
1174 References
1175 ==========
1177 .. [1] [Liao95]_
1179 """
1180 result = _dup_rr_trivial_gcd(f, g, K)
1182 if result is not None:
1183 return result
1185 df = dup_degree(f)
1186 dg = dup_degree(g)
1188 gcd, f, g = dup_extract(f, g, K)
1190 if df == 0 or dg == 0:
1191 return [gcd], f, g
1193 f_norm = dup_max_norm(f, K)
1194 g_norm = dup_max_norm(g, K)
1196 B = K(2*min(f_norm, g_norm) + 29)
1198 x = max(min(B, 99*K.sqrt(B)),
1199 2*min(f_norm // abs(dup_LC(f, K)),
1200 g_norm // abs(dup_LC(g, K))) + 2)
1202 for i in range(0, HEU_GCD_MAX):
1203 ff = dup_eval(f, x, K)
1204 gg = dup_eval(g, x, K)
1206 if ff and gg:
1207 h = K.gcd(ff, gg)
1209 cff = ff // h
1210 cfg = gg // h
1212 h = _dup_zz_gcd_interpolate(h, x, K)
1213 h = dup_primitive(h, K)[1]
1215 cff_, r = dup_div(f, h, K)
1217 if not r:
1218 cfg_, r = dup_div(g, h, K)
1220 if not r:
1221 h = dup_mul_ground(h, gcd, K)
1222 return h, cff_, cfg_
1224 cff = _dup_zz_gcd_interpolate(cff, x, K)
1226 h, r = dup_div(f, cff, K)
1228 if not r:
1229 cfg_, r = dup_div(g, h, K)
1231 if not r:
1232 h = dup_mul_ground(h, gcd, K)
1233 return h, cff, cfg_
1235 cfg = _dup_zz_gcd_interpolate(cfg, x, K)
1237 h, r = dup_div(g, cfg, K)
1239 if not r:
1240 cff_, r = dup_div(f, h, K)
1242 if not r:
1243 h = dup_mul_ground(h, gcd, K)
1244 return h, cff_, cfg
1246 x = 73794*x * K.sqrt(K.sqrt(x)) // 27011
1248 raise HeuristicGCDFailed('no luck')
1251def _dmp_zz_gcd_interpolate(h, x, v, K):
1252 """Interpolate polynomial GCD from integer GCD. """
1253 f = []
1255 while not dmp_zero_p(h, v):
1256 g = dmp_ground_trunc(h, x, v, K)
1257 f.insert(0, g)
1259 h = dmp_sub(h, g, v, K)
1260 h = dmp_quo_ground(h, x, v, K)
1262 if K.is_negative(dmp_ground_LC(f, v + 1, K)):
1263 return dmp_neg(f, v + 1, K)
1264 else:
1265 return f
1268def dmp_zz_heu_gcd(f, g, u, K):
1269 """
1270 Heuristic polynomial GCD in `Z[X]`.
1272 Given univariate polynomials `f` and `g` in `Z[X]`, returns
1273 their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg``
1274 such that::
1276 h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h)
1278 The algorithm is purely heuristic which means it may fail to compute
1279 the GCD. This will be signaled by raising an exception. In this case
1280 you will need to switch to another GCD method.
1282 The algorithm computes the polynomial GCD by evaluating polynomials
1283 f and g at certain points and computing (fast) integer GCD of those
1284 evaluations. The polynomial GCD is recovered from the integer image
1285 by interpolation. The evaluation process reduces f and g variable by
1286 variable into a large integer. The final step is to verify if the
1287 interpolated polynomial is the correct GCD. This gives cofactors of
1288 the input polynomials as a side effect.
1290 Examples
1291 ========
1293 >>> from sympy.polys import ring, ZZ
1294 >>> R, x,y, = ring("x,y", ZZ)
1296 >>> f = x**2 + 2*x*y + y**2
1297 >>> g = x**2 + x*y
1299 >>> R.dmp_zz_heu_gcd(f, g)
1300 (x + y, x + y, x)
1302 References
1303 ==========
1305 .. [1] [Liao95]_
1307 """
1308 if not u:
1309 return dup_zz_heu_gcd(f, g, K)
1311 result = _dmp_rr_trivial_gcd(f, g, u, K)
1313 if result is not None:
1314 return result
1316 gcd, f, g = dmp_ground_extract(f, g, u, K)
1318 f_norm = dmp_max_norm(f, u, K)
1319 g_norm = dmp_max_norm(g, u, K)
1321 B = K(2*min(f_norm, g_norm) + 29)
1323 x = max(min(B, 99*K.sqrt(B)),
1324 2*min(f_norm // abs(dmp_ground_LC(f, u, K)),
1325 g_norm // abs(dmp_ground_LC(g, u, K))) + 2)
1327 for i in range(0, HEU_GCD_MAX):
1328 ff = dmp_eval(f, x, u, K)
1329 gg = dmp_eval(g, x, u, K)
1331 v = u - 1
1333 if not (dmp_zero_p(ff, v) or dmp_zero_p(gg, v)):
1334 h, cff, cfg = dmp_zz_heu_gcd(ff, gg, v, K)
1336 h = _dmp_zz_gcd_interpolate(h, x, v, K)
1337 h = dmp_ground_primitive(h, u, K)[1]
1339 cff_, r = dmp_div(f, h, u, K)
1341 if dmp_zero_p(r, u):
1342 cfg_, r = dmp_div(g, h, u, K)
1344 if dmp_zero_p(r, u):
1345 h = dmp_mul_ground(h, gcd, u, K)
1346 return h, cff_, cfg_
1348 cff = _dmp_zz_gcd_interpolate(cff, x, v, K)
1350 h, r = dmp_div(f, cff, u, K)
1352 if dmp_zero_p(r, u):
1353 cfg_, r = dmp_div(g, h, u, K)
1355 if dmp_zero_p(r, u):
1356 h = dmp_mul_ground(h, gcd, u, K)
1357 return h, cff, cfg_
1359 cfg = _dmp_zz_gcd_interpolate(cfg, x, v, K)
1361 h, r = dmp_div(g, cfg, u, K)
1363 if dmp_zero_p(r, u):
1364 cff_, r = dmp_div(f, h, u, K)
1366 if dmp_zero_p(r, u):
1367 h = dmp_mul_ground(h, gcd, u, K)
1368 return h, cff_, cfg
1370 x = 73794*x * K.sqrt(K.sqrt(x)) // 27011
1372 raise HeuristicGCDFailed('no luck')
1375def dup_qq_heu_gcd(f, g, K0):
1376 """
1377 Heuristic polynomial GCD in `Q[x]`.
1379 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``,
1380 ``cff = quo(f, h)``, and ``cfg = quo(g, h)``.
1382 Examples
1383 ========
1385 >>> from sympy.polys import ring, QQ
1386 >>> R, x = ring("x", QQ)
1388 >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2)
1389 >>> g = QQ(1,2)*x**2 + x
1391 >>> R.dup_qq_heu_gcd(f, g)
1392 (x + 2, 1/2*x + 3/4, 1/2*x)
1394 """
1395 result = _dup_ff_trivial_gcd(f, g, K0)
1397 if result is not None:
1398 return result
1400 K1 = K0.get_ring()
1402 cf, f = dup_clear_denoms(f, K0, K1)
1403 cg, g = dup_clear_denoms(g, K0, K1)
1405 f = dup_convert(f, K0, K1)
1406 g = dup_convert(g, K0, K1)
1408 h, cff, cfg = dup_zz_heu_gcd(f, g, K1)
1410 h = dup_convert(h, K1, K0)
1412 c = dup_LC(h, K0)
1413 h = dup_monic(h, K0)
1415 cff = dup_convert(cff, K1, K0)
1416 cfg = dup_convert(cfg, K1, K0)
1418 cff = dup_mul_ground(cff, K0.quo(c, cf), K0)
1419 cfg = dup_mul_ground(cfg, K0.quo(c, cg), K0)
1421 return h, cff, cfg
1424def dmp_qq_heu_gcd(f, g, u, K0):
1425 """
1426 Heuristic polynomial GCD in `Q[X]`.
1428 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``,
1429 ``cff = quo(f, h)``, and ``cfg = quo(g, h)``.
1431 Examples
1432 ========
1434 >>> from sympy.polys import ring, QQ
1435 >>> R, x,y, = ring("x,y", QQ)
1437 >>> f = QQ(1,4)*x**2 + x*y + y**2
1438 >>> g = QQ(1,2)*x**2 + x*y
1440 >>> R.dmp_qq_heu_gcd(f, g)
1441 (x + 2*y, 1/4*x + 1/2*y, 1/2*x)
1443 """
1444 result = _dmp_ff_trivial_gcd(f, g, u, K0)
1446 if result is not None:
1447 return result
1449 K1 = K0.get_ring()
1451 cf, f = dmp_clear_denoms(f, u, K0, K1)
1452 cg, g = dmp_clear_denoms(g, u, K0, K1)
1454 f = dmp_convert(f, u, K0, K1)
1455 g = dmp_convert(g, u, K0, K1)
1457 h, cff, cfg = dmp_zz_heu_gcd(f, g, u, K1)
1459 h = dmp_convert(h, u, K1, K0)
1461 c = dmp_ground_LC(h, u, K0)
1462 h = dmp_ground_monic(h, u, K0)
1464 cff = dmp_convert(cff, u, K1, K0)
1465 cfg = dmp_convert(cfg, u, K1, K0)
1467 cff = dmp_mul_ground(cff, K0.quo(c, cf), u, K0)
1468 cfg = dmp_mul_ground(cfg, K0.quo(c, cg), u, K0)
1470 return h, cff, cfg
1473def dup_inner_gcd(f, g, K):
1474 """
1475 Computes polynomial GCD and cofactors of `f` and `g` in `K[x]`.
1477 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``,
1478 ``cff = quo(f, h)``, and ``cfg = quo(g, h)``.
1480 Examples
1481 ========
1483 >>> from sympy.polys import ring, ZZ
1484 >>> R, x = ring("x", ZZ)
1486 >>> R.dup_inner_gcd(x**2 - 1, x**2 - 3*x + 2)
1487 (x - 1, x + 1, x - 2)
1489 """
1490 if not K.is_Exact:
1491 try:
1492 exact = K.get_exact()
1493 except DomainError:
1494 return [K.one], f, g
1496 f = dup_convert(f, K, exact)
1497 g = dup_convert(g, K, exact)
1499 h, cff, cfg = dup_inner_gcd(f, g, exact)
1501 h = dup_convert(h, exact, K)
1502 cff = dup_convert(cff, exact, K)
1503 cfg = dup_convert(cfg, exact, K)
1505 return h, cff, cfg
1506 elif K.is_Field:
1507 if K.is_QQ and query('USE_HEU_GCD'):
1508 try:
1509 return dup_qq_heu_gcd(f, g, K)
1510 except HeuristicGCDFailed:
1511 pass
1513 return dup_ff_prs_gcd(f, g, K)
1514 else:
1515 if K.is_ZZ and query('USE_HEU_GCD'):
1516 try:
1517 return dup_zz_heu_gcd(f, g, K)
1518 except HeuristicGCDFailed:
1519 pass
1521 return dup_rr_prs_gcd(f, g, K)
1524def _dmp_inner_gcd(f, g, u, K):
1525 """Helper function for `dmp_inner_gcd()`. """
1526 if not K.is_Exact:
1527 try:
1528 exact = K.get_exact()
1529 except DomainError:
1530 return dmp_one(u, K), f, g
1532 f = dmp_convert(f, u, K, exact)
1533 g = dmp_convert(g, u, K, exact)
1535 h, cff, cfg = _dmp_inner_gcd(f, g, u, exact)
1537 h = dmp_convert(h, u, exact, K)
1538 cff = dmp_convert(cff, u, exact, K)
1539 cfg = dmp_convert(cfg, u, exact, K)
1541 return h, cff, cfg
1542 elif K.is_Field:
1543 if K.is_QQ and query('USE_HEU_GCD'):
1544 try:
1545 return dmp_qq_heu_gcd(f, g, u, K)
1546 except HeuristicGCDFailed:
1547 pass
1549 return dmp_ff_prs_gcd(f, g, u, K)
1550 else:
1551 if K.is_ZZ and query('USE_HEU_GCD'):
1552 try:
1553 return dmp_zz_heu_gcd(f, g, u, K)
1554 except HeuristicGCDFailed:
1555 pass
1557 return dmp_rr_prs_gcd(f, g, u, K)
1560def dmp_inner_gcd(f, g, u, K):
1561 """
1562 Computes polynomial GCD and cofactors of `f` and `g` in `K[X]`.
1564 Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``,
1565 ``cff = quo(f, h)``, and ``cfg = quo(g, h)``.
1567 Examples
1568 ========
1570 >>> from sympy.polys import ring, ZZ
1571 >>> R, x,y, = ring("x,y", ZZ)
1573 >>> f = x**2 + 2*x*y + y**2
1574 >>> g = x**2 + x*y
1576 >>> R.dmp_inner_gcd(f, g)
1577 (x + y, x + y, x)
1579 """
1580 if not u:
1581 return dup_inner_gcd(f, g, K)
1583 J, (f, g) = dmp_multi_deflate((f, g), u, K)
1584 h, cff, cfg = _dmp_inner_gcd(f, g, u, K)
1586 return (dmp_inflate(h, J, u, K),
1587 dmp_inflate(cff, J, u, K),
1588 dmp_inflate(cfg, J, u, K))
1591def dup_gcd(f, g, K):
1592 """
1593 Computes polynomial GCD of `f` and `g` in `K[x]`.
1595 Examples
1596 ========
1598 >>> from sympy.polys import ring, ZZ
1599 >>> R, x = ring("x", ZZ)
1601 >>> R.dup_gcd(x**2 - 1, x**2 - 3*x + 2)
1602 x - 1
1604 """
1605 return dup_inner_gcd(f, g, K)[0]
1608def dmp_gcd(f, g, u, K):
1609 """
1610 Computes polynomial GCD of `f` and `g` in `K[X]`.
1612 Examples
1613 ========
1615 >>> from sympy.polys import ring, ZZ
1616 >>> R, x,y, = ring("x,y", ZZ)
1618 >>> f = x**2 + 2*x*y + y**2
1619 >>> g = x**2 + x*y
1621 >>> R.dmp_gcd(f, g)
1622 x + y
1624 """
1625 return dmp_inner_gcd(f, g, u, K)[0]
1628def dup_rr_lcm(f, g, K):
1629 """
1630 Computes polynomial LCM over a ring in `K[x]`.
1632 Examples
1633 ========
1635 >>> from sympy.polys import ring, ZZ
1636 >>> R, x = ring("x", ZZ)
1638 >>> R.dup_rr_lcm(x**2 - 1, x**2 - 3*x + 2)
1639 x**3 - 2*x**2 - x + 2
1641 """
1642 fc, f = dup_primitive(f, K)
1643 gc, g = dup_primitive(g, K)
1645 c = K.lcm(fc, gc)
1647 h = dup_quo(dup_mul(f, g, K),
1648 dup_gcd(f, g, K), K)
1650 return dup_mul_ground(h, c, K)
1653def dup_ff_lcm(f, g, K):
1654 """
1655 Computes polynomial LCM over a field in `K[x]`.
1657 Examples
1658 ========
1660 >>> from sympy.polys import ring, QQ
1661 >>> R, x = ring("x", QQ)
1663 >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2)
1664 >>> g = QQ(1,2)*x**2 + x
1666 >>> R.dup_ff_lcm(f, g)
1667 x**3 + 7/2*x**2 + 3*x
1669 """
1670 h = dup_quo(dup_mul(f, g, K),
1671 dup_gcd(f, g, K), K)
1673 return dup_monic(h, K)
1676def dup_lcm(f, g, K):
1677 """
1678 Computes polynomial LCM of `f` and `g` in `K[x]`.
1680 Examples
1681 ========
1683 >>> from sympy.polys import ring, ZZ
1684 >>> R, x = ring("x", ZZ)
1686 >>> R.dup_lcm(x**2 - 1, x**2 - 3*x + 2)
1687 x**3 - 2*x**2 - x + 2
1689 """
1690 if K.is_Field:
1691 return dup_ff_lcm(f, g, K)
1692 else:
1693 return dup_rr_lcm(f, g, K)
1696def dmp_rr_lcm(f, g, u, K):
1697 """
1698 Computes polynomial LCM over a ring in `K[X]`.
1700 Examples
1701 ========
1703 >>> from sympy.polys import ring, ZZ
1704 >>> R, x,y, = ring("x,y", ZZ)
1706 >>> f = x**2 + 2*x*y + y**2
1707 >>> g = x**2 + x*y
1709 >>> R.dmp_rr_lcm(f, g)
1710 x**3 + 2*x**2*y + x*y**2
1712 """
1713 fc, f = dmp_ground_primitive(f, u, K)
1714 gc, g = dmp_ground_primitive(g, u, K)
1716 c = K.lcm(fc, gc)
1718 h = dmp_quo(dmp_mul(f, g, u, K),
1719 dmp_gcd(f, g, u, K), u, K)
1721 return dmp_mul_ground(h, c, u, K)
1724def dmp_ff_lcm(f, g, u, K):
1725 """
1726 Computes polynomial LCM over a field in `K[X]`.
1728 Examples
1729 ========
1731 >>> from sympy.polys import ring, QQ
1732 >>> R, x,y, = ring("x,y", QQ)
1734 >>> f = QQ(1,4)*x**2 + x*y + y**2
1735 >>> g = QQ(1,2)*x**2 + x*y
1737 >>> R.dmp_ff_lcm(f, g)
1738 x**3 + 4*x**2*y + 4*x*y**2
1740 """
1741 h = dmp_quo(dmp_mul(f, g, u, K),
1742 dmp_gcd(f, g, u, K), u, K)
1744 return dmp_ground_monic(h, u, K)
1747def dmp_lcm(f, g, u, K):
1748 """
1749 Computes polynomial LCM of `f` and `g` in `K[X]`.
1751 Examples
1752 ========
1754 >>> from sympy.polys import ring, ZZ
1755 >>> R, x,y, = ring("x,y", ZZ)
1757 >>> f = x**2 + 2*x*y + y**2
1758 >>> g = x**2 + x*y
1760 >>> R.dmp_lcm(f, g)
1761 x**3 + 2*x**2*y + x*y**2
1763 """
1764 if not u:
1765 return dup_lcm(f, g, K)
1767 if K.is_Field:
1768 return dmp_ff_lcm(f, g, u, K)
1769 else:
1770 return dmp_rr_lcm(f, g, u, K)
1773def dmp_content(f, u, K):
1774 """
1775 Returns GCD of multivariate coefficients.
1777 Examples
1778 ========
1780 >>> from sympy.polys import ring, ZZ
1781 >>> R, x,y, = ring("x,y", ZZ)
1783 >>> R.dmp_content(2*x*y + 6*x + 4*y + 12)
1784 2*y + 6
1786 """
1787 cont, v = dmp_LC(f, K), u - 1
1789 if dmp_zero_p(f, u):
1790 return cont
1792 for c in f[1:]:
1793 cont = dmp_gcd(cont, c, v, K)
1795 if dmp_one_p(cont, v, K):
1796 break
1798 if K.is_negative(dmp_ground_LC(cont, v, K)):
1799 return dmp_neg(cont, v, K)
1800 else:
1801 return cont
1804def dmp_primitive(f, u, K):
1805 """
1806 Returns multivariate content and a primitive polynomial.
1808 Examples
1809 ========
1811 >>> from sympy.polys import ring, ZZ
1812 >>> R, x,y, = ring("x,y", ZZ)
1814 >>> R.dmp_primitive(2*x*y + 6*x + 4*y + 12)
1815 (2*y + 6, x + 2)
1817 """
1818 cont, v = dmp_content(f, u, K), u - 1
1820 if dmp_zero_p(f, u) or dmp_one_p(cont, v, K):
1821 return cont, f
1822 else:
1823 return cont, [ dmp_quo(c, cont, v, K) for c in f ]
1826def dup_cancel(f, g, K, include=True):
1827 """
1828 Cancel common factors in a rational function `f/g`.
1830 Examples
1831 ========
1833 >>> from sympy.polys import ring, ZZ
1834 >>> R, x = ring("x", ZZ)
1836 >>> R.dup_cancel(2*x**2 - 2, x**2 - 2*x + 1)
1837 (2*x + 2, x - 1)
1839 """
1840 return dmp_cancel(f, g, 0, K, include=include)
1843def dmp_cancel(f, g, u, K, include=True):
1844 """
1845 Cancel common factors in a rational function `f/g`.
1847 Examples
1848 ========
1850 >>> from sympy.polys import ring, ZZ
1851 >>> R, x,y = ring("x,y", ZZ)
1853 >>> R.dmp_cancel(2*x**2 - 2, x**2 - 2*x + 1)
1854 (2*x + 2, x - 1)
1856 """
1857 K0 = None
1859 if K.is_Field and K.has_assoc_Ring:
1860 K0, K = K, K.get_ring()
1862 cq, f = dmp_clear_denoms(f, u, K0, K, convert=True)
1863 cp, g = dmp_clear_denoms(g, u, K0, K, convert=True)
1864 else:
1865 cp, cq = K.one, K.one
1867 _, p, q = dmp_inner_gcd(f, g, u, K)
1869 if K0 is not None:
1870 _, cp, cq = K.cofactors(cp, cq)
1872 p = dmp_convert(p, u, K, K0)
1873 q = dmp_convert(q, u, K, K0)
1875 K = K0
1877 p_neg = K.is_negative(dmp_ground_LC(p, u, K))
1878 q_neg = K.is_negative(dmp_ground_LC(q, u, K))
1880 if p_neg and q_neg:
1881 p, q = dmp_neg(p, u, K), dmp_neg(q, u, K)
1882 elif p_neg:
1883 cp, p = -cp, dmp_neg(p, u, K)
1884 elif q_neg:
1885 cp, q = -cp, dmp_neg(q, u, K)
1887 if not include:
1888 return cp, cq, p, q
1890 p = dmp_mul_ground(p, cp, u, K)
1891 q = dmp_mul_ground(q, cq, u, K)
1893 return p, q