sqfreetools.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. """Square-free decomposition algorithms and related tools. """
  2. from sympy.polys.densearith import (
  3. dup_neg, dmp_neg,
  4. dup_sub, dmp_sub,
  5. dup_mul, dmp_mul,
  6. dup_quo, dmp_quo,
  7. dup_mul_ground, dmp_mul_ground)
  8. from sympy.polys.densebasic import (
  9. dup_strip,
  10. dup_LC, dmp_ground_LC,
  11. dmp_zero_p,
  12. dmp_ground,
  13. dup_degree, dmp_degree, dmp_degree_in, dmp_degree_list,
  14. dmp_raise, dmp_inject,
  15. dup_convert)
  16. from sympy.polys.densetools import (
  17. dup_diff, dmp_diff, dmp_diff_in,
  18. dup_shift, dmp_shift,
  19. dup_monic, dmp_ground_monic,
  20. dup_primitive, dmp_ground_primitive)
  21. from sympy.polys.euclidtools import (
  22. dup_inner_gcd, dmp_inner_gcd,
  23. dup_gcd, dmp_gcd,
  24. dmp_resultant, dmp_primitive)
  25. from sympy.polys.galoistools import (
  26. gf_sqf_list, gf_sqf_part)
  27. from sympy.polys.polyerrors import (
  28. MultivariatePolynomialError,
  29. DomainError)
  30. def _dup_check_degrees(f, result):
  31. """Sanity check the degrees of a computed factorization in K[x]."""
  32. deg = sum(k * dup_degree(fac) for (fac, k) in result)
  33. assert deg == dup_degree(f)
  34. def _dmp_check_degrees(f, u, result):
  35. """Sanity check the degrees of a computed factorization in K[X]."""
  36. degs = [0] * (u + 1)
  37. for fac, k in result:
  38. degs_fac = dmp_degree_list(fac, u)
  39. degs = [d1 + k * d2 for d1, d2 in zip(degs, degs_fac)]
  40. assert tuple(degs) == dmp_degree_list(f, u)
  41. def dup_sqf_p(f, K):
  42. """
  43. Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``.
  44. Examples
  45. ========
  46. >>> from sympy.polys import ring, ZZ
  47. >>> R, x = ring("x", ZZ)
  48. >>> R.dup_sqf_p(x**2 - 2*x + 1)
  49. False
  50. >>> R.dup_sqf_p(x**2 - 1)
  51. True
  52. """
  53. if not f:
  54. return True
  55. else:
  56. return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K))
  57. def dmp_sqf_p(f, u, K):
  58. """
  59. Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``.
  60. Examples
  61. ========
  62. >>> from sympy.polys import ring, ZZ
  63. >>> R, x,y = ring("x,y", ZZ)
  64. >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2)
  65. False
  66. >>> R.dmp_sqf_p(x**2 + y**2)
  67. True
  68. """
  69. if dmp_zero_p(f, u):
  70. return True
  71. for i in range(u+1):
  72. fp = dmp_diff_in(f, 1, i, u, K)
  73. if dmp_zero_p(fp, u):
  74. continue
  75. gcd = dmp_gcd(f, fp, u, K)
  76. if dmp_degree_in(gcd, i, u) != 0:
  77. return False
  78. return True
  79. def dup_sqf_norm(f, K):
  80. r"""
  81. Find a shift of `f` in `K[x]` that has square-free norm.
  82. The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).
  83. Returns `(s,g,r)`, such that `g(x)=f(x-sa)`, `r(x)=\text{Norm}(g(x))` and
  84. `r` is a square-free polynomial over `k`.
  85. Examples
  86. ========
  87. We first create the algebraic number field `K=k(a)=\mathbb{Q}(\sqrt{3})`
  88. and rings `K[x]` and `k[x]`:
  89. >>> from sympy.polys import ring, QQ
  90. >>> from sympy import sqrt
  91. >>> K = QQ.algebraic_field(sqrt(3))
  92. >>> R, x = ring("x", K)
  93. >>> _, X = ring("x", QQ)
  94. We can now find a square free norm for a shift of `f`:
  95. >>> f = x**2 - 1
  96. >>> s, g, r = R.dup_sqf_norm(f)
  97. The choice of shift `s` is arbitrary and the particular values returned for
  98. `g` and `r` are determined by `s`.
  99. >>> s == 1
  100. True
  101. >>> g == x**2 - 2*sqrt(3)*x + 2
  102. True
  103. >>> r == X**4 - 8*X**2 + 4
  104. True
  105. The invariants are:
  106. >>> g == f.shift(-s*K.unit)
  107. True
  108. >>> g.norm() == r
  109. True
  110. >>> r.is_squarefree
  111. True
  112. Explanation
  113. ===========
  114. This is part of Trager's algorithm for factorizing polynomials over
  115. algebraic number fields. In particular this function is algorithm
  116. ``sqfr_norm`` from [Trager76]_.
  117. See Also
  118. ========
  119. dmp_sqf_norm:
  120. Analogous function for multivariate polynomials over ``k(a)``.
  121. dmp_norm:
  122. Computes the norm of `f` directly without any shift.
  123. dup_ext_factor:
  124. Function implementing Trager's algorithm that uses this.
  125. sympy.polys.polytools.sqf_norm:
  126. High-level interface for using this function.
  127. """
  128. if not K.is_Algebraic:
  129. raise DomainError("ground domain must be algebraic")
  130. s, g = 0, dmp_raise(K.mod.to_list(), 1, 0, K.dom)
  131. while True:
  132. h, _ = dmp_inject(f, 0, K, front=True)
  133. r = dmp_resultant(g, h, 1, K.dom)
  134. if dup_sqf_p(r, K.dom):
  135. break
  136. else:
  137. f, s = dup_shift(f, -K.unit, K), s + 1
  138. return s, f, r
  139. def _dmp_sqf_norm_shifts(f, u, K):
  140. """Generate a sequence of candidate shifts for dmp_sqf_norm."""
  141. #
  142. # We want to find a minimal shift if possible because shifting high degree
  143. # variables can be expensive e.g. x**10 -> (x + 1)**10. We try a few easy
  144. # cases first before the final infinite loop that is guaranteed to give
  145. # only finitely many bad shifts (see Trager76 for proof of this in the
  146. # univariate case).
  147. #
  148. # First the trivial shift [0, 0, ...]
  149. n = u + 1
  150. s0 = [0] * n
  151. yield s0, f
  152. # Shift in multiples of the generator of the extension field K
  153. a = K.unit
  154. # Variables of degree > 0 ordered by increasing degree
  155. d = dmp_degree_list(f, u)
  156. var_indices = [i for di, i in sorted(zip(d, range(u+1))) if di > 0]
  157. # Now try [1, 0, 0, ...], [0, 1, 0, ...]
  158. for i in var_indices:
  159. s1 = s0.copy()
  160. s1[i] = 1
  161. a1 = [-a*s1i for s1i in s1]
  162. f1 = dmp_shift(f, a1, u, K)
  163. yield s1, f1
  164. # Now try [1, 1, 1, ...], [2, 2, 2, ...]
  165. j = 0
  166. while True:
  167. j += 1
  168. sj = [j] * n
  169. aj = [-a*j] * n
  170. fj = dmp_shift(f, aj, u, K)
  171. yield sj, fj
  172. def dmp_sqf_norm(f, u, K):
  173. r"""
  174. Find a shift of ``f`` in ``K[X]`` that has square-free norm.
  175. The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).
  176. Returns `(s,g,r)`, such that `g(x_1,x_2,\cdots)=f(x_1-s_1 a, x_2 - s_2 a,
  177. \cdots)`, `r(x)=\text{Norm}(g(x))` and `r` is a square-free polynomial over
  178. `k`.
  179. Examples
  180. ========
  181. We first create the algebraic number field `K=k(a)=\mathbb{Q}(i)` and rings
  182. `K[x,y]` and `k[x,y]`:
  183. >>> from sympy.polys import ring, QQ
  184. >>> from sympy import I
  185. >>> K = QQ.algebraic_field(I)
  186. >>> R, x, y = ring("x,y", K)
  187. >>> _, X, Y = ring("x,y", QQ)
  188. We can now find a square free norm for a shift of `f`:
  189. >>> f = x*y + y**2
  190. >>> s, g, r = R.dmp_sqf_norm(f)
  191. The choice of shifts ``s`` is arbitrary and the particular values returned
  192. for ``g`` and ``r`` are determined by ``s``.
  193. >>> s
  194. [0, 1]
  195. >>> g == x*y - I*x + y**2 - 2*I*y - 1
  196. True
  197. >>> r == X**2*Y**2 + X**2 + 2*X*Y**3 + 2*X*Y + Y**4 + 2*Y**2 + 1
  198. True
  199. The required invariants are:
  200. >>> g == f.shift_list([-si*K.unit for si in s])
  201. True
  202. >>> g.norm() == r
  203. True
  204. >>> r.is_squarefree
  205. True
  206. Explanation
  207. ===========
  208. This is part of Trager's algorithm for factorizing polynomials over
  209. algebraic number fields. In particular this function is a multivariate
  210. generalization of algorithm ``sqfr_norm`` from [Trager76]_.
  211. See Also
  212. ========
  213. dup_sqf_norm:
  214. Analogous function for univariate polynomials over ``k(a)``.
  215. dmp_norm:
  216. Computes the norm of `f` directly without any shift.
  217. dmp_ext_factor:
  218. Function implementing Trager's algorithm that uses this.
  219. sympy.polys.polytools.sqf_norm:
  220. High-level interface for using this function.
  221. """
  222. if not u:
  223. s, g, r = dup_sqf_norm(f, K)
  224. return [s], g, r
  225. if not K.is_Algebraic:
  226. raise DomainError("ground domain must be algebraic")
  227. g = dmp_raise(K.mod.to_list(), u + 1, 0, K.dom)
  228. for s, f in _dmp_sqf_norm_shifts(f, u, K):
  229. h, _ = dmp_inject(f, u, K, front=True)
  230. r = dmp_resultant(g, h, u + 1, K.dom)
  231. if dmp_sqf_p(r, u, K.dom):
  232. break
  233. return s, f, r
  234. def dmp_norm(f, u, K):
  235. r"""
  236. Norm of ``f`` in ``K[X]``, often not square-free.
  237. The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).
  238. Examples
  239. ========
  240. We first define the algebraic number field `K = k(a) = \mathbb{Q}(\sqrt{2})`:
  241. >>> from sympy import QQ, sqrt
  242. >>> from sympy.polys.sqfreetools import dmp_norm
  243. >>> k = QQ
  244. >>> K = k.algebraic_field(sqrt(2))
  245. We can now compute the norm of a polynomial `p` in `K[x,y]`:
  246. >>> p = [[K(1)], [K(1),K.unit]] # x + y + sqrt(2)
  247. >>> N = [[k(1)], [k(2),k(0)], [k(1),k(0),k(-2)]] # x**2 + 2*x*y + y**2 - 2
  248. >>> dmp_norm(p, 1, K) == N
  249. True
  250. In higher level functions that is:
  251. >>> from sympy import expand, roots, minpoly
  252. >>> from sympy.abc import x, y
  253. >>> from math import prod
  254. >>> a = sqrt(2)
  255. >>> e = (x + y + a)
  256. >>> e.as_poly([x, y], extension=a).norm()
  257. Poly(x**2 + 2*x*y + y**2 - 2, x, y, domain='QQ')
  258. This is equal to the product of the expressions `x + y + a_i` where the
  259. `a_i` are the conjugates of `a`:
  260. >>> pa = minpoly(a)
  261. >>> pa
  262. _x**2 - 2
  263. >>> rs = roots(pa, multiple=True)
  264. >>> rs
  265. [sqrt(2), -sqrt(2)]
  266. >>> n = prod(e.subs(a, r) for r in rs)
  267. >>> n
  268. (x + y - sqrt(2))*(x + y + sqrt(2))
  269. >>> expand(n)
  270. x**2 + 2*x*y + y**2 - 2
  271. Explanation
  272. ===========
  273. Given an algebraic number field `K = k(a)` any element `b` of `K` can be
  274. represented as polynomial function `b=g(a)` where `g` is in `k[x]`. If the
  275. minimal polynomial of `a` over `k` is `p_a` then the roots `a_1`, `a_2`,
  276. `\cdots` of `p_a(x)` are the conjugates of `a`. The norm of `b` is the
  277. product `g(a1) \times g(a2) \times \cdots` and is an element of `k`.
  278. As in [Trager76]_ we extend this norm to multivariate polynomials over `K`.
  279. If `b(x)` is a polynomial in `k(a)[X]` then we can think of `b` as being
  280. alternately a function `g_X(a)` where `g_X` is an element of `k[X][y]` i.e.
  281. a polynomial function with coefficients that are elements of `k[X]`. Then
  282. the norm of `b` is the product `g_X(a1) \times g_X(a2) \times \cdots` and
  283. will be an element of `k[X]`.
  284. See Also
  285. ========
  286. dmp_sqf_norm:
  287. Compute a shift of `f` so that the `\text{Norm}(f)` is square-free.
  288. sympy.polys.polytools.Poly.norm:
  289. Higher-level function that calls this.
  290. """
  291. if not K.is_Algebraic:
  292. raise DomainError("ground domain must be algebraic")
  293. g = dmp_raise(K.mod.to_list(), u + 1, 0, K.dom)
  294. h, _ = dmp_inject(f, u, K, front=True)
  295. return dmp_resultant(g, h, u + 1, K.dom)
  296. def dup_gf_sqf_part(f, K):
  297. """Compute square-free part of ``f`` in ``GF(p)[x]``. """
  298. f = dup_convert(f, K, K.dom)
  299. g = gf_sqf_part(f, K.mod, K.dom)
  300. return dup_convert(g, K.dom, K)
  301. def dmp_gf_sqf_part(f, u, K):
  302. """Compute square-free part of ``f`` in ``GF(p)[X]``. """
  303. raise NotImplementedError('multivariate polynomials over finite fields')
  304. def dup_sqf_part(f, K):
  305. """
  306. Returns square-free part of a polynomial in ``K[x]``.
  307. Examples
  308. ========
  309. >>> from sympy.polys import ring, ZZ
  310. >>> R, x = ring("x", ZZ)
  311. >>> R.dup_sqf_part(x**3 - 3*x - 2)
  312. x**2 - x - 2
  313. See Also
  314. ========
  315. sympy.polys.polytools.Poly.sqf_part
  316. """
  317. if K.is_FiniteField:
  318. return dup_gf_sqf_part(f, K)
  319. if not f:
  320. return f
  321. if K.is_negative(dup_LC(f, K)):
  322. f = dup_neg(f, K)
  323. gcd = dup_gcd(f, dup_diff(f, 1, K), K)
  324. sqf = dup_quo(f, gcd, K)
  325. if K.is_Field:
  326. return dup_monic(sqf, K)
  327. else:
  328. return dup_primitive(sqf, K)[1]
  329. def dmp_sqf_part(f, u, K):
  330. """
  331. Returns square-free part of a polynomial in ``K[X]``.
  332. Examples
  333. ========
  334. >>> from sympy.polys import ring, ZZ
  335. >>> R, x,y = ring("x,y", ZZ)
  336. >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2)
  337. x**2 + x*y
  338. """
  339. if not u:
  340. return dup_sqf_part(f, K)
  341. if K.is_FiniteField:
  342. return dmp_gf_sqf_part(f, u, K)
  343. if dmp_zero_p(f, u):
  344. return f
  345. if K.is_negative(dmp_ground_LC(f, u, K)):
  346. f = dmp_neg(f, u, K)
  347. gcd = f
  348. for i in range(u+1):
  349. gcd = dmp_gcd(gcd, dmp_diff_in(f, 1, i, u, K), u, K)
  350. sqf = dmp_quo(f, gcd, u, K)
  351. if K.is_Field:
  352. return dmp_ground_monic(sqf, u, K)
  353. else:
  354. return dmp_ground_primitive(sqf, u, K)[1]
  355. def dup_gf_sqf_list(f, K, all=False):
  356. """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """
  357. f_orig = f
  358. f = dup_convert(f, K, K.dom)
  359. coeff, factors = gf_sqf_list(f, K.mod, K.dom, all=all)
  360. for i, (f, k) in enumerate(factors):
  361. factors[i] = (dup_convert(f, K.dom, K), k)
  362. _dup_check_degrees(f_orig, factors)
  363. return K.convert(coeff, K.dom), factors
  364. def dmp_gf_sqf_list(f, u, K, all=False):
  365. """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """
  366. raise NotImplementedError('multivariate polynomials over finite fields')
  367. def dup_sqf_list(f, K, all=False):
  368. """
  369. Return square-free decomposition of a polynomial in ``K[x]``.
  370. Uses Yun's algorithm from [Yun76]_.
  371. Examples
  372. ========
  373. >>> from sympy.polys import ring, ZZ
  374. >>> R, x = ring("x", ZZ)
  375. >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
  376. >>> R.dup_sqf_list(f)
  377. (2, [(x + 1, 2), (x + 2, 3)])
  378. >>> R.dup_sqf_list(f, all=True)
  379. (2, [(1, 1), (x + 1, 2), (x + 2, 3)])
  380. See Also
  381. ========
  382. dmp_sqf_list:
  383. Corresponding function for multivariate polynomials.
  384. sympy.polys.polytools.sqf_list:
  385. High-level function for square-free factorization of expressions.
  386. sympy.polys.polytools.Poly.sqf_list:
  387. Analogous method on :class:`~.Poly`.
  388. References
  389. ==========
  390. [Yun76]_
  391. """
  392. if K.is_FiniteField:
  393. return dup_gf_sqf_list(f, K, all=all)
  394. f_orig = f
  395. if K.is_Field:
  396. coeff = dup_LC(f, K)
  397. f = dup_monic(f, K)
  398. else:
  399. coeff, f = dup_primitive(f, K)
  400. if K.is_negative(dup_LC(f, K)):
  401. f = dup_neg(f, K)
  402. coeff = -coeff
  403. if dup_degree(f) <= 0:
  404. return coeff, []
  405. result, i = [], 1
  406. h = dup_diff(f, 1, K)
  407. g, p, q = dup_inner_gcd(f, h, K)
  408. while True:
  409. d = dup_diff(p, 1, K)
  410. h = dup_sub(q, d, K)
  411. if not h:
  412. result.append((p, i))
  413. break
  414. g, p, q = dup_inner_gcd(p, h, K)
  415. if all or dup_degree(g) > 0:
  416. result.append((g, i))
  417. i += 1
  418. _dup_check_degrees(f_orig, result)
  419. return coeff, result
  420. def dup_sqf_list_include(f, K, all=False):
  421. """
  422. Return square-free decomposition of a polynomial in ``K[x]``.
  423. Examples
  424. ========
  425. >>> from sympy.polys import ring, ZZ
  426. >>> R, x = ring("x", ZZ)
  427. >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
  428. >>> R.dup_sqf_list_include(f)
  429. [(2, 1), (x + 1, 2), (x + 2, 3)]
  430. >>> R.dup_sqf_list_include(f, all=True)
  431. [(2, 1), (x + 1, 2), (x + 2, 3)]
  432. """
  433. coeff, factors = dup_sqf_list(f, K, all=all)
  434. if factors and factors[0][1] == 1:
  435. g = dup_mul_ground(factors[0][0], coeff, K)
  436. return [(g, 1)] + factors[1:]
  437. else:
  438. g = dup_strip([coeff])
  439. return [(g, 1)] + factors
  440. def dmp_sqf_list(f, u, K, all=False):
  441. """
  442. Return square-free decomposition of a polynomial in `K[X]`.
  443. Examples
  444. ========
  445. >>> from sympy.polys import ring, ZZ
  446. >>> R, x,y = ring("x,y", ZZ)
  447. >>> f = x**5 + 2*x**4*y + x**3*y**2
  448. >>> R.dmp_sqf_list(f)
  449. (1, [(x + y, 2), (x, 3)])
  450. >>> R.dmp_sqf_list(f, all=True)
  451. (1, [(1, 1), (x + y, 2), (x, 3)])
  452. Explanation
  453. ===========
  454. Uses Yun's algorithm for univariate polynomials from [Yun76]_ recursively.
  455. The multivariate polynomial is treated as a univariate polynomial in its
  456. leading variable. Then Yun's algorithm computes the square-free
  457. factorization of the primitive and the content is factored recursively.
  458. It would be better to use a dedicated algorithm for multivariate
  459. polynomials instead.
  460. See Also
  461. ========
  462. dup_sqf_list:
  463. Corresponding function for univariate polynomials.
  464. sympy.polys.polytools.sqf_list:
  465. High-level function for square-free factorization of expressions.
  466. sympy.polys.polytools.Poly.sqf_list:
  467. Analogous method on :class:`~.Poly`.
  468. """
  469. if not u:
  470. return dup_sqf_list(f, K, all=all)
  471. if K.is_FiniteField:
  472. return dmp_gf_sqf_list(f, u, K, all=all)
  473. f_orig = f
  474. if K.is_Field:
  475. coeff = dmp_ground_LC(f, u, K)
  476. f = dmp_ground_monic(f, u, K)
  477. else:
  478. coeff, f = dmp_ground_primitive(f, u, K)
  479. if K.is_negative(dmp_ground_LC(f, u, K)):
  480. f = dmp_neg(f, u, K)
  481. coeff = -coeff
  482. deg = dmp_degree(f, u)
  483. if deg < 0:
  484. return coeff, []
  485. # Yun's algorithm requires the polynomial to be primitive as a univariate
  486. # polynomial in its main variable.
  487. content, f = dmp_primitive(f, u, K)
  488. result = {}
  489. if deg != 0:
  490. h = dmp_diff(f, 1, u, K)
  491. g, p, q = dmp_inner_gcd(f, h, u, K)
  492. i = 1
  493. while True:
  494. d = dmp_diff(p, 1, u, K)
  495. h = dmp_sub(q, d, u, K)
  496. if dmp_zero_p(h, u):
  497. result[i] = p
  498. break
  499. g, p, q = dmp_inner_gcd(p, h, u, K)
  500. if all or dmp_degree(g, u) > 0:
  501. result[i] = g
  502. i += 1
  503. coeff_content, result_content = dmp_sqf_list(content, u-1, K, all=all)
  504. coeff *= coeff_content
  505. # Combine factors of the content and primitive part that have the same
  506. # multiplicity to produce a list in ascending order of multiplicity.
  507. for fac, i in result_content:
  508. fac = [fac]
  509. if i in result:
  510. result[i] = dmp_mul(result[i], fac, u, K)
  511. else:
  512. result[i] = fac
  513. result = [(result[i], i) for i in sorted(result)]
  514. _dmp_check_degrees(f_orig, u, result)
  515. return coeff, result
  516. def dmp_sqf_list_include(f, u, K, all=False):
  517. """
  518. Return square-free decomposition of a polynomial in ``K[x]``.
  519. Examples
  520. ========
  521. >>> from sympy.polys import ring, ZZ
  522. >>> R, x,y = ring("x,y", ZZ)
  523. >>> f = x**5 + 2*x**4*y + x**3*y**2
  524. >>> R.dmp_sqf_list_include(f)
  525. [(1, 1), (x + y, 2), (x, 3)]
  526. >>> R.dmp_sqf_list_include(f, all=True)
  527. [(1, 1), (x + y, 2), (x, 3)]
  528. """
  529. if not u:
  530. return dup_sqf_list_include(f, K, all=all)
  531. coeff, factors = dmp_sqf_list(f, u, K, all=all)
  532. if factors and factors[0][1] == 1:
  533. g = dmp_mul_ground(factors[0][0], coeff, u, K)
  534. return [(g, 1)] + factors[1:]
  535. else:
  536. g = dmp_ground(coeff, u)
  537. return [(g, 1)] + factors
  538. def dup_gff_list(f, K):
  539. """
  540. Compute greatest factorial factorization of ``f`` in ``K[x]``.
  541. Examples
  542. ========
  543. >>> from sympy.polys import ring, ZZ
  544. >>> R, x = ring("x", ZZ)
  545. >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2)
  546. [(x, 1), (x + 2, 4)]
  547. """
  548. if not f:
  549. raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial")
  550. f = dup_monic(f, K)
  551. if not dup_degree(f):
  552. return []
  553. else:
  554. g = dup_gcd(f, dup_shift(f, K.one, K), K)
  555. H = dup_gff_list(g, K)
  556. for i, (h, k) in enumerate(H):
  557. g = dup_mul(g, dup_shift(h, -K(k), K), K)
  558. H[i] = (h, k + 1)
  559. f = dup_quo(f, g, K)
  560. if not dup_degree(f):
  561. return H
  562. else:
  563. return [(f, 1)] + H
  564. def dmp_gff_list(f, u, K):
  565. """
  566. Compute greatest factorial factorization of ``f`` in ``K[X]``.
  567. Examples
  568. ========
  569. >>> from sympy.polys import ring, ZZ
  570. >>> R, x,y = ring("x,y", ZZ)
  571. """
  572. if not u:
  573. return dup_gff_list(f, K)
  574. else:
  575. raise MultivariatePolynomialError(f)