sqfreetools.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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,
  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,
  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_compose,
  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)
  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_sqf_p(f, K):
  31. """
  32. Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``.
  33. Examples
  34. ========
  35. >>> from sympy.polys import ring, ZZ
  36. >>> R, x = ring("x", ZZ)
  37. >>> R.dup_sqf_p(x**2 - 2*x + 1)
  38. False
  39. >>> R.dup_sqf_p(x**2 - 1)
  40. True
  41. """
  42. if not f:
  43. return True
  44. else:
  45. return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K))
  46. def dmp_sqf_p(f, u, K):
  47. """
  48. Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``.
  49. Examples
  50. ========
  51. >>> from sympy.polys import ring, ZZ
  52. >>> R, x,y = ring("x,y", ZZ)
  53. >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2)
  54. False
  55. >>> R.dmp_sqf_p(x**2 + y**2)
  56. True
  57. """
  58. if dmp_zero_p(f, u):
  59. return True
  60. else:
  61. return not dmp_degree(dmp_gcd(f, dmp_diff(f, 1, u, K), u, K), u)
  62. def dup_sqf_norm(f, K):
  63. """
  64. Square-free norm of ``f`` in ``K[x]``, useful over algebraic domains.
  65. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))``
  66. is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``.
  67. Examples
  68. ========
  69. >>> from sympy.polys import ring, QQ
  70. >>> from sympy import sqrt
  71. >>> K = QQ.algebraic_field(sqrt(3))
  72. >>> R, x = ring("x", K)
  73. >>> _, X = ring("x", QQ)
  74. >>> s, f, r = R.dup_sqf_norm(x**2 - 2)
  75. >>> s == 1
  76. True
  77. >>> f == x**2 + K([QQ(-2), QQ(0)])*x + 1
  78. True
  79. >>> r == X**4 - 10*X**2 + 1
  80. True
  81. """
  82. if not K.is_Algebraic:
  83. raise DomainError("ground domain must be algebraic")
  84. s, g = 0, dmp_raise(K.mod.rep, 1, 0, K.dom)
  85. while True:
  86. h, _ = dmp_inject(f, 0, K, front=True)
  87. r = dmp_resultant(g, h, 1, K.dom)
  88. if dup_sqf_p(r, K.dom):
  89. break
  90. else:
  91. f, s = dup_shift(f, -K.unit, K), s + 1
  92. return s, f, r
  93. def dmp_sqf_norm(f, u, K):
  94. """
  95. Square-free norm of ``f`` in ``K[X]``, useful over algebraic domains.
  96. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))``
  97. is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``.
  98. Examples
  99. ========
  100. >>> from sympy.polys import ring, QQ
  101. >>> from sympy import I
  102. >>> K = QQ.algebraic_field(I)
  103. >>> R, x, y = ring("x,y", K)
  104. >>> _, X, Y = ring("x,y", QQ)
  105. >>> s, f, r = R.dmp_sqf_norm(x*y + y**2)
  106. >>> s == 1
  107. True
  108. >>> f == x*y + y**2 + K([QQ(-1), QQ(0)])*y
  109. True
  110. >>> r == X**2*Y**2 + 2*X*Y**3 + Y**4 + Y**2
  111. True
  112. """
  113. if not u:
  114. return dup_sqf_norm(f, K)
  115. if not K.is_Algebraic:
  116. raise DomainError("ground domain must be algebraic")
  117. g = dmp_raise(K.mod.rep, u + 1, 0, K.dom)
  118. F = dmp_raise([K.one, -K.unit], u, 0, K)
  119. s = 0
  120. while True:
  121. h, _ = dmp_inject(f, u, K, front=True)
  122. r = dmp_resultant(g, h, u + 1, K.dom)
  123. if dmp_sqf_p(r, u, K.dom):
  124. break
  125. else:
  126. f, s = dmp_compose(f, F, u, K), s + 1
  127. return s, f, r
  128. def dmp_norm(f, u, K):
  129. """
  130. Norm of ``f`` in ``K[X1, ..., Xn]``, often not square-free.
  131. """
  132. if not K.is_Algebraic:
  133. raise DomainError("ground domain must be algebraic")
  134. g = dmp_raise(K.mod.rep, u + 1, 0, K.dom)
  135. h, _ = dmp_inject(f, u, K, front=True)
  136. return dmp_resultant(g, h, u + 1, K.dom)
  137. def dup_gf_sqf_part(f, K):
  138. """Compute square-free part of ``f`` in ``GF(p)[x]``. """
  139. f = dup_convert(f, K, K.dom)
  140. g = gf_sqf_part(f, K.mod, K.dom)
  141. return dup_convert(g, K.dom, K)
  142. def dmp_gf_sqf_part(f, u, K):
  143. """Compute square-free part of ``f`` in ``GF(p)[X]``. """
  144. raise NotImplementedError('multivariate polynomials over finite fields')
  145. def dup_sqf_part(f, K):
  146. """
  147. Returns square-free part of a polynomial in ``K[x]``.
  148. Examples
  149. ========
  150. >>> from sympy.polys import ring, ZZ
  151. >>> R, x = ring("x", ZZ)
  152. >>> R.dup_sqf_part(x**3 - 3*x - 2)
  153. x**2 - x - 2
  154. """
  155. if K.is_FiniteField:
  156. return dup_gf_sqf_part(f, K)
  157. if not f:
  158. return f
  159. if K.is_negative(dup_LC(f, K)):
  160. f = dup_neg(f, K)
  161. gcd = dup_gcd(f, dup_diff(f, 1, K), K)
  162. sqf = dup_quo(f, gcd, K)
  163. if K.is_Field:
  164. return dup_monic(sqf, K)
  165. else:
  166. return dup_primitive(sqf, K)[1]
  167. def dmp_sqf_part(f, u, K):
  168. """
  169. Returns square-free part of a polynomial in ``K[X]``.
  170. Examples
  171. ========
  172. >>> from sympy.polys import ring, ZZ
  173. >>> R, x,y = ring("x,y", ZZ)
  174. >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2)
  175. x**2 + x*y
  176. """
  177. if not u:
  178. return dup_sqf_part(f, K)
  179. if K.is_FiniteField:
  180. return dmp_gf_sqf_part(f, u, K)
  181. if dmp_zero_p(f, u):
  182. return f
  183. if K.is_negative(dmp_ground_LC(f, u, K)):
  184. f = dmp_neg(f, u, K)
  185. gcd = f
  186. for i in range(u+1):
  187. gcd = dmp_gcd(gcd, dmp_diff_in(f, 1, i, u, K), u, K)
  188. sqf = dmp_quo(f, gcd, u, K)
  189. if K.is_Field:
  190. return dmp_ground_monic(sqf, u, K)
  191. else:
  192. return dmp_ground_primitive(sqf, u, K)[1]
  193. def dup_gf_sqf_list(f, K, all=False):
  194. """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """
  195. f = dup_convert(f, K, K.dom)
  196. coeff, factors = gf_sqf_list(f, K.mod, K.dom, all=all)
  197. for i, (f, k) in enumerate(factors):
  198. factors[i] = (dup_convert(f, K.dom, K), k)
  199. return K.convert(coeff, K.dom), factors
  200. def dmp_gf_sqf_list(f, u, K, all=False):
  201. """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """
  202. raise NotImplementedError('multivariate polynomials over finite fields')
  203. def dup_sqf_list(f, K, all=False):
  204. """
  205. Return square-free decomposition of a polynomial in ``K[x]``.
  206. Examples
  207. ========
  208. >>> from sympy.polys import ring, ZZ
  209. >>> R, x = ring("x", ZZ)
  210. >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
  211. >>> R.dup_sqf_list(f)
  212. (2, [(x + 1, 2), (x + 2, 3)])
  213. >>> R.dup_sqf_list(f, all=True)
  214. (2, [(1, 1), (x + 1, 2), (x + 2, 3)])
  215. """
  216. if K.is_FiniteField:
  217. return dup_gf_sqf_list(f, K, all=all)
  218. if K.is_Field:
  219. coeff = dup_LC(f, K)
  220. f = dup_monic(f, K)
  221. else:
  222. coeff, f = dup_primitive(f, K)
  223. if K.is_negative(dup_LC(f, K)):
  224. f = dup_neg(f, K)
  225. coeff = -coeff
  226. if dup_degree(f) <= 0:
  227. return coeff, []
  228. result, i = [], 1
  229. h = dup_diff(f, 1, K)
  230. g, p, q = dup_inner_gcd(f, h, K)
  231. while True:
  232. d = dup_diff(p, 1, K)
  233. h = dup_sub(q, d, K)
  234. if not h:
  235. result.append((p, i))
  236. break
  237. g, p, q = dup_inner_gcd(p, h, K)
  238. if all or dup_degree(g) > 0:
  239. result.append((g, i))
  240. i += 1
  241. return coeff, result
  242. def dup_sqf_list_include(f, K, all=False):
  243. """
  244. Return square-free decomposition of a polynomial in ``K[x]``.
  245. Examples
  246. ========
  247. >>> from sympy.polys import ring, ZZ
  248. >>> R, x = ring("x", ZZ)
  249. >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16
  250. >>> R.dup_sqf_list_include(f)
  251. [(2, 1), (x + 1, 2), (x + 2, 3)]
  252. >>> R.dup_sqf_list_include(f, all=True)
  253. [(2, 1), (x + 1, 2), (x + 2, 3)]
  254. """
  255. coeff, factors = dup_sqf_list(f, K, all=all)
  256. if factors and factors[0][1] == 1:
  257. g = dup_mul_ground(factors[0][0], coeff, K)
  258. return [(g, 1)] + factors[1:]
  259. else:
  260. g = dup_strip([coeff])
  261. return [(g, 1)] + factors
  262. def dmp_sqf_list(f, u, K, all=False):
  263. """
  264. Return square-free decomposition of a polynomial in ``K[X]``.
  265. Examples
  266. ========
  267. >>> from sympy.polys import ring, ZZ
  268. >>> R, x,y = ring("x,y", ZZ)
  269. >>> f = x**5 + 2*x**4*y + x**3*y**2
  270. >>> R.dmp_sqf_list(f)
  271. (1, [(x + y, 2), (x, 3)])
  272. >>> R.dmp_sqf_list(f, all=True)
  273. (1, [(1, 1), (x + y, 2), (x, 3)])
  274. """
  275. if not u:
  276. return dup_sqf_list(f, K, all=all)
  277. if K.is_FiniteField:
  278. return dmp_gf_sqf_list(f, u, K, all=all)
  279. if K.is_Field:
  280. coeff = dmp_ground_LC(f, u, K)
  281. f = dmp_ground_monic(f, u, K)
  282. else:
  283. coeff, f = dmp_ground_primitive(f, u, K)
  284. if K.is_negative(dmp_ground_LC(f, u, K)):
  285. f = dmp_neg(f, u, K)
  286. coeff = -coeff
  287. if dmp_degree(f, u) <= 0:
  288. return coeff, []
  289. result, i = [], 1
  290. h = dmp_diff(f, 1, u, K)
  291. g, p, q = dmp_inner_gcd(f, h, u, K)
  292. while True:
  293. d = dmp_diff(p, 1, u, K)
  294. h = dmp_sub(q, d, u, K)
  295. if dmp_zero_p(h, u):
  296. result.append((p, i))
  297. break
  298. g, p, q = dmp_inner_gcd(p, h, u, K)
  299. if all or dmp_degree(g, u) > 0:
  300. result.append((g, i))
  301. i += 1
  302. return coeff, result
  303. def dmp_sqf_list_include(f, u, K, all=False):
  304. """
  305. Return square-free decomposition of a polynomial in ``K[x]``.
  306. Examples
  307. ========
  308. >>> from sympy.polys import ring, ZZ
  309. >>> R, x,y = ring("x,y", ZZ)
  310. >>> f = x**5 + 2*x**4*y + x**3*y**2
  311. >>> R.dmp_sqf_list_include(f)
  312. [(1, 1), (x + y, 2), (x, 3)]
  313. >>> R.dmp_sqf_list_include(f, all=True)
  314. [(1, 1), (x + y, 2), (x, 3)]
  315. """
  316. if not u:
  317. return dup_sqf_list_include(f, K, all=all)
  318. coeff, factors = dmp_sqf_list(f, u, K, all=all)
  319. if factors and factors[0][1] == 1:
  320. g = dmp_mul_ground(factors[0][0], coeff, u, K)
  321. return [(g, 1)] + factors[1:]
  322. else:
  323. g = dmp_ground(coeff, u)
  324. return [(g, 1)] + factors
  325. def dup_gff_list(f, K):
  326. """
  327. Compute greatest factorial factorization of ``f`` in ``K[x]``.
  328. Examples
  329. ========
  330. >>> from sympy.polys import ring, ZZ
  331. >>> R, x = ring("x", ZZ)
  332. >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2)
  333. [(x, 1), (x + 2, 4)]
  334. """
  335. if not f:
  336. raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial")
  337. f = dup_monic(f, K)
  338. if not dup_degree(f):
  339. return []
  340. else:
  341. g = dup_gcd(f, dup_shift(f, K.one, K), K)
  342. H = dup_gff_list(g, K)
  343. for i, (h, k) in enumerate(H):
  344. g = dup_mul(g, dup_shift(h, -K(k), K), K)
  345. H[i] = (h, k + 1)
  346. f = dup_quo(f, g, K)
  347. if not dup_degree(f):
  348. return H
  349. else:
  350. return [(f, 1)] + H
  351. def dmp_gff_list(f, u, K):
  352. """
  353. Compute greatest factorial factorization of ``f`` in ``K[X]``.
  354. Examples
  355. ========
  356. >>> from sympy.polys import ring, ZZ
  357. >>> R, x,y = ring("x,y", ZZ)
  358. """
  359. if not u:
  360. return dup_gff_list(f, K)
  361. else:
  362. raise MultivariatePolynomialError(f)