Coverage for /usr/lib/python3/dist-packages/sympy/polys/sqfreetools.py: 13%
177 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"""Square-free decomposition algorithms and related tools. """
4from sympy.polys.densearith import (
5 dup_neg, dmp_neg,
6 dup_sub, dmp_sub,
7 dup_mul,
8 dup_quo, dmp_quo,
9 dup_mul_ground, dmp_mul_ground)
10from sympy.polys.densebasic import (
11 dup_strip,
12 dup_LC, dmp_ground_LC,
13 dmp_zero_p,
14 dmp_ground,
15 dup_degree, dmp_degree,
16 dmp_raise, dmp_inject,
17 dup_convert)
18from sympy.polys.densetools import (
19 dup_diff, dmp_diff, dmp_diff_in,
20 dup_shift, dmp_compose,
21 dup_monic, dmp_ground_monic,
22 dup_primitive, dmp_ground_primitive)
23from sympy.polys.euclidtools import (
24 dup_inner_gcd, dmp_inner_gcd,
25 dup_gcd, dmp_gcd,
26 dmp_resultant)
27from sympy.polys.galoistools import (
28 gf_sqf_list, gf_sqf_part)
29from sympy.polys.polyerrors import (
30 MultivariatePolynomialError,
31 DomainError)
33def dup_sqf_p(f, K):
34 """
35 Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``.
37 Examples
38 ========
40 >>> from sympy.polys import ring, ZZ
41 >>> R, x = ring("x", ZZ)
43 >>> R.dup_sqf_p(x**2 - 2*x + 1)
44 False
45 >>> R.dup_sqf_p(x**2 - 1)
46 True
48 """
49 if not f:
50 return True
51 else:
52 return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K))
55def dmp_sqf_p(f, u, K):
56 """
57 Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``.
59 Examples
60 ========
62 >>> from sympy.polys import ring, ZZ
63 >>> R, x,y = ring("x,y", ZZ)
65 >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2)
66 False
67 >>> R.dmp_sqf_p(x**2 + y**2)
68 True
70 """
71 if dmp_zero_p(f, u):
72 return True
73 else:
74 return not dmp_degree(dmp_gcd(f, dmp_diff(f, 1, u, K), u, K), u)
77def dup_sqf_norm(f, K):
78 """
79 Square-free norm of ``f`` in ``K[x]``, useful over algebraic domains.
81 Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))``
82 is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``.
84 Examples
85 ========
87 >>> from sympy.polys import ring, QQ
88 >>> from sympy import sqrt
90 >>> K = QQ.algebraic_field(sqrt(3))
91 >>> R, x = ring("x", K)
92 >>> _, X = ring("x", QQ)
94 >>> s, f, r = R.dup_sqf_norm(x**2 - 2)
96 >>> s == 1
97 True
98 >>> f == x**2 + K([QQ(-2), QQ(0)])*x + 1
99 True
100 >>> r == X**4 - 10*X**2 + 1
101 True
103 """
104 if not K.is_Algebraic:
105 raise DomainError("ground domain must be algebraic")
107 s, g = 0, dmp_raise(K.mod.rep, 1, 0, K.dom)
109 while True:
110 h, _ = dmp_inject(f, 0, K, front=True)
111 r = dmp_resultant(g, h, 1, K.dom)
113 if dup_sqf_p(r, K.dom):
114 break
115 else:
116 f, s = dup_shift(f, -K.unit, K), s + 1
118 return s, f, r
121def dmp_sqf_norm(f, u, K):
122 """
123 Square-free norm of ``f`` in ``K[X]``, useful over algebraic domains.
125 Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))``
126 is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``.
128 Examples
129 ========
131 >>> from sympy.polys import ring, QQ
132 >>> from sympy import I
134 >>> K = QQ.algebraic_field(I)
135 >>> R, x, y = ring("x,y", K)
136 >>> _, X, Y = ring("x,y", QQ)
138 >>> s, f, r = R.dmp_sqf_norm(x*y + y**2)
140 >>> s == 1
141 True
142 >>> f == x*y + y**2 + K([QQ(-1), QQ(0)])*y
143 True
144 >>> r == X**2*Y**2 + 2*X*Y**3 + Y**4 + Y**2
145 True
147 """
148 if not u:
149 return dup_sqf_norm(f, K)
151 if not K.is_Algebraic:
152 raise DomainError("ground domain must be algebraic")
154 g = dmp_raise(K.mod.rep, u + 1, 0, K.dom)
155 F = dmp_raise([K.one, -K.unit], u, 0, K)
157 s = 0
159 while True:
160 h, _ = dmp_inject(f, u, K, front=True)
161 r = dmp_resultant(g, h, u + 1, K.dom)
163 if dmp_sqf_p(r, u, K.dom):
164 break
165 else:
166 f, s = dmp_compose(f, F, u, K), s + 1
168 return s, f, r
171def dmp_norm(f, u, K):
172 """
173 Norm of ``f`` in ``K[X1, ..., Xn]``, often not square-free.
174 """
175 if not K.is_Algebraic:
176 raise DomainError("ground domain must be algebraic")
178 g = dmp_raise(K.mod.rep, u + 1, 0, K.dom)
179 h, _ = dmp_inject(f, u, K, front=True)
181 return dmp_resultant(g, h, u + 1, K.dom)
184def dup_gf_sqf_part(f, K):
185 """Compute square-free part of ``f`` in ``GF(p)[x]``. """
186 f = dup_convert(f, K, K.dom)
187 g = gf_sqf_part(f, K.mod, K.dom)
188 return dup_convert(g, K.dom, K)
191def dmp_gf_sqf_part(f, u, K):
192 """Compute square-free part of ``f`` in ``GF(p)[X]``. """
193 raise NotImplementedError('multivariate polynomials over finite fields')
196def dup_sqf_part(f, K):
197 """
198 Returns square-free part of a polynomial in ``K[x]``.
200 Examples
201 ========
203 >>> from sympy.polys import ring, ZZ
204 >>> R, x = ring("x", ZZ)
206 >>> R.dup_sqf_part(x**3 - 3*x - 2)
207 x**2 - x - 2
209 """
210 if K.is_FiniteField:
211 return dup_gf_sqf_part(f, K)
213 if not f:
214 return f
216 if K.is_negative(dup_LC(f, K)):
217 f = dup_neg(f, K)
219 gcd = dup_gcd(f, dup_diff(f, 1, K), K)
220 sqf = dup_quo(f, gcd, K)
222 if K.is_Field:
223 return dup_monic(sqf, K)
224 else:
225 return dup_primitive(sqf, K)[1]
228def dmp_sqf_part(f, u, K):
229 """
230 Returns square-free part of a polynomial in ``K[X]``.
232 Examples
233 ========
235 >>> from sympy.polys import ring, ZZ
236 >>> R, x,y = ring("x,y", ZZ)
238 >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2)
239 x**2 + x*y
241 """
242 if not u:
243 return dup_sqf_part(f, K)
245 if K.is_FiniteField:
246 return dmp_gf_sqf_part(f, u, K)
248 if dmp_zero_p(f, u):
249 return f
251 if K.is_negative(dmp_ground_LC(f, u, K)):
252 f = dmp_neg(f, u, K)
254 gcd = f
255 for i in range(u+1):
256 gcd = dmp_gcd(gcd, dmp_diff_in(f, 1, i, u, K), u, K)
257 sqf = dmp_quo(f, gcd, u, K)
259 if K.is_Field:
260 return dmp_ground_monic(sqf, u, K)
261 else:
262 return dmp_ground_primitive(sqf, u, K)[1]
265def dup_gf_sqf_list(f, K, all=False):
266 """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """
267 f = dup_convert(f, K, K.dom)
269 coeff, factors = gf_sqf_list(f, K.mod, K.dom, all=all)
271 for i, (f, k) in enumerate(factors):
272 factors[i] = (dup_convert(f, K.dom, K), k)
274 return K.convert(coeff, K.dom), factors
277def dmp_gf_sqf_list(f, u, K, all=False):
278 """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """
279 raise NotImplementedError('multivariate polynomials over finite fields')
282def dup_sqf_list(f, K, all=False):
283 """
284 Return square-free decomposition of a polynomial in ``K[x]``.
286 Examples
287 ========
289 >>> from sympy.polys import ring, ZZ
290 >>> R, x = ring("x", ZZ)
292 >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
294 >>> R.dup_sqf_list(f)
295 (2, [(x + 1, 2), (x + 2, 3)])
296 >>> R.dup_sqf_list(f, all=True)
297 (2, [(1, 1), (x + 1, 2), (x + 2, 3)])
299 """
300 if K.is_FiniteField:
301 return dup_gf_sqf_list(f, K, all=all)
303 if K.is_Field:
304 coeff = dup_LC(f, K)
305 f = dup_monic(f, K)
306 else:
307 coeff, f = dup_primitive(f, K)
309 if K.is_negative(dup_LC(f, K)):
310 f = dup_neg(f, K)
311 coeff = -coeff
313 if dup_degree(f) <= 0:
314 return coeff, []
316 result, i = [], 1
318 h = dup_diff(f, 1, K)
319 g, p, q = dup_inner_gcd(f, h, K)
321 while True:
322 d = dup_diff(p, 1, K)
323 h = dup_sub(q, d, K)
325 if not h:
326 result.append((p, i))
327 break
329 g, p, q = dup_inner_gcd(p, h, K)
331 if all or dup_degree(g) > 0:
332 result.append((g, i))
334 i += 1
336 return coeff, result
339def dup_sqf_list_include(f, K, all=False):
340 """
341 Return square-free decomposition of a polynomial in ``K[x]``.
343 Examples
344 ========
346 >>> from sympy.polys import ring, ZZ
347 >>> R, x = ring("x", ZZ)
349 >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
351 >>> R.dup_sqf_list_include(f)
352 [(2, 1), (x + 1, 2), (x + 2, 3)]
353 >>> R.dup_sqf_list_include(f, all=True)
354 [(2, 1), (x + 1, 2), (x + 2, 3)]
356 """
357 coeff, factors = dup_sqf_list(f, K, all=all)
359 if factors and factors[0][1] == 1:
360 g = dup_mul_ground(factors[0][0], coeff, K)
361 return [(g, 1)] + factors[1:]
362 else:
363 g = dup_strip([coeff])
364 return [(g, 1)] + factors
367def dmp_sqf_list(f, u, K, all=False):
368 """
369 Return square-free decomposition of a polynomial in ``K[X]``.
371 Examples
372 ========
374 >>> from sympy.polys import ring, ZZ
375 >>> R, x,y = ring("x,y", ZZ)
377 >>> f = x**5 + 2*x**4*y + x**3*y**2
379 >>> R.dmp_sqf_list(f)
380 (1, [(x + y, 2), (x, 3)])
381 >>> R.dmp_sqf_list(f, all=True)
382 (1, [(1, 1), (x + y, 2), (x, 3)])
384 """
385 if not u:
386 return dup_sqf_list(f, K, all=all)
388 if K.is_FiniteField:
389 return dmp_gf_sqf_list(f, u, K, all=all)
391 if K.is_Field:
392 coeff = dmp_ground_LC(f, u, K)
393 f = dmp_ground_monic(f, u, K)
394 else:
395 coeff, f = dmp_ground_primitive(f, u, K)
397 if K.is_negative(dmp_ground_LC(f, u, K)):
398 f = dmp_neg(f, u, K)
399 coeff = -coeff
401 if dmp_degree(f, u) <= 0:
402 return coeff, []
404 result, i = [], 1
406 h = dmp_diff(f, 1, u, K)
407 g, p, q = dmp_inner_gcd(f, h, u, K)
409 while True:
410 d = dmp_diff(p, 1, u, K)
411 h = dmp_sub(q, d, u, K)
413 if dmp_zero_p(h, u):
414 result.append((p, i))
415 break
417 g, p, q = dmp_inner_gcd(p, h, u, K)
419 if all or dmp_degree(g, u) > 0:
420 result.append((g, i))
422 i += 1
424 return coeff, result
427def dmp_sqf_list_include(f, u, K, all=False):
428 """
429 Return square-free decomposition of a polynomial in ``K[x]``.
431 Examples
432 ========
434 >>> from sympy.polys import ring, ZZ
435 >>> R, x,y = ring("x,y", ZZ)
437 >>> f = x**5 + 2*x**4*y + x**3*y**2
439 >>> R.dmp_sqf_list_include(f)
440 [(1, 1), (x + y, 2), (x, 3)]
441 >>> R.dmp_sqf_list_include(f, all=True)
442 [(1, 1), (x + y, 2), (x, 3)]
444 """
445 if not u:
446 return dup_sqf_list_include(f, K, all=all)
448 coeff, factors = dmp_sqf_list(f, u, K, all=all)
450 if factors and factors[0][1] == 1:
451 g = dmp_mul_ground(factors[0][0], coeff, u, K)
452 return [(g, 1)] + factors[1:]
453 else:
454 g = dmp_ground(coeff, u)
455 return [(g, 1)] + factors
458def dup_gff_list(f, K):
459 """
460 Compute greatest factorial factorization of ``f`` in ``K[x]``.
462 Examples
463 ========
465 >>> from sympy.polys import ring, ZZ
466 >>> R, x = ring("x", ZZ)
468 >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2)
469 [(x, 1), (x + 2, 4)]
471 """
472 if not f:
473 raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial")
475 f = dup_monic(f, K)
477 if not dup_degree(f):
478 return []
479 else:
480 g = dup_gcd(f, dup_shift(f, K.one, K), K)
481 H = dup_gff_list(g, K)
483 for i, (h, k) in enumerate(H):
484 g = dup_mul(g, dup_shift(h, -K(k), K), K)
485 H[i] = (h, k + 1)
487 f = dup_quo(f, g, K)
489 if not dup_degree(f):
490 return H
491 else:
492 return [(f, 1)] + H
495def dmp_gff_list(f, u, K):
496 """
497 Compute greatest factorial factorization of ``f`` in ``K[X]``.
499 Examples
500 ========
502 >>> from sympy.polys import ring, ZZ
503 >>> R, x,y = ring("x,y", ZZ)
505 """
506 if not u:
507 return dup_gff_list(f, K)
508 else:
509 raise MultivariatePolynomialError(f)