factortools.py 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648
  1. """Polynomial factorization routines in characteristic zero. """
  2. from sympy.external.gmpy import GROUND_TYPES
  3. from sympy.core.random import _randint
  4. from sympy.polys.galoistools import (
  5. gf_from_int_poly, gf_to_int_poly,
  6. gf_lshift, gf_add_mul, gf_mul,
  7. gf_div, gf_rem,
  8. gf_gcdex,
  9. gf_sqf_p,
  10. gf_factor_sqf, gf_factor)
  11. from sympy.polys.densebasic import (
  12. dup_LC, dmp_LC, dmp_ground_LC,
  13. dup_TC,
  14. dup_convert, dmp_convert,
  15. dup_degree, dmp_degree,
  16. dmp_degree_in, dmp_degree_list,
  17. dmp_from_dict,
  18. dmp_zero_p,
  19. dmp_one,
  20. dmp_nest, dmp_raise,
  21. dup_strip,
  22. dmp_ground,
  23. dup_inflate,
  24. dmp_exclude, dmp_include,
  25. dmp_inject, dmp_eject,
  26. dup_terms_gcd, dmp_terms_gcd)
  27. from sympy.polys.densearith import (
  28. dup_neg, dmp_neg,
  29. dup_add, dmp_add,
  30. dup_sub, dmp_sub,
  31. dup_mul, dmp_mul,
  32. dup_sqr,
  33. dmp_pow,
  34. dup_div, dmp_div,
  35. dup_quo, dmp_quo,
  36. dmp_expand,
  37. dmp_add_mul,
  38. dup_sub_mul, dmp_sub_mul,
  39. dup_lshift,
  40. dup_max_norm, dmp_max_norm,
  41. dup_l1_norm,
  42. dup_mul_ground, dmp_mul_ground,
  43. dup_quo_ground, dmp_quo_ground)
  44. from sympy.polys.densetools import (
  45. dup_clear_denoms, dmp_clear_denoms,
  46. dup_trunc, dmp_ground_trunc,
  47. dup_content,
  48. dup_monic, dmp_ground_monic,
  49. dup_primitive, dmp_ground_primitive,
  50. dmp_eval_tail,
  51. dmp_eval_in, dmp_diff_eval_in,
  52. dup_shift, dmp_shift, dup_mirror)
  53. from sympy.polys.euclidtools import (
  54. dmp_primitive,
  55. dup_inner_gcd, dmp_inner_gcd)
  56. from sympy.polys.sqfreetools import (
  57. dup_sqf_p,
  58. dup_sqf_norm, dmp_sqf_norm,
  59. dup_sqf_part, dmp_sqf_part,
  60. _dup_check_degrees, _dmp_check_degrees,
  61. )
  62. from sympy.polys.polyutils import _sort_factors
  63. from sympy.polys.polyconfig import query
  64. from sympy.polys.polyerrors import (
  65. ExtraneousFactors, DomainError, CoercionFailed, EvaluationFailed)
  66. from sympy.utilities import subsets
  67. from math import ceil as _ceil, log as _log, log2 as _log2
  68. if GROUND_TYPES == 'flint':
  69. from flint import fmpz_poly
  70. else:
  71. fmpz_poly = None
  72. def dup_trial_division(f, factors, K):
  73. """
  74. Determine multiplicities of factors for a univariate polynomial
  75. using trial division.
  76. An error will be raised if any factor does not divide ``f``.
  77. """
  78. result = []
  79. for factor in factors:
  80. k = 0
  81. while True:
  82. q, r = dup_div(f, factor, K)
  83. if not r:
  84. f, k = q, k + 1
  85. else:
  86. break
  87. if k == 0:
  88. raise RuntimeError("trial division failed")
  89. result.append((factor, k))
  90. return _sort_factors(result)
  91. def dmp_trial_division(f, factors, u, K):
  92. """
  93. Determine multiplicities of factors for a multivariate polynomial
  94. using trial division.
  95. An error will be raised if any factor does not divide ``f``.
  96. """
  97. result = []
  98. for factor in factors:
  99. k = 0
  100. while True:
  101. q, r = dmp_div(f, factor, u, K)
  102. if dmp_zero_p(r, u):
  103. f, k = q, k + 1
  104. else:
  105. break
  106. if k == 0:
  107. raise RuntimeError("trial division failed")
  108. result.append((factor, k))
  109. return _sort_factors(result)
  110. def dup_zz_mignotte_bound(f, K):
  111. """
  112. The Knuth-Cohen variant of Mignotte bound for
  113. univariate polynomials in ``K[x]``.
  114. Examples
  115. ========
  116. >>> from sympy.polys import ring, ZZ
  117. >>> R, x = ring("x", ZZ)
  118. >>> f = x**3 + 14*x**2 + 56*x + 64
  119. >>> R.dup_zz_mignotte_bound(f)
  120. 152
  121. By checking ``factor(f)`` we can see that max coeff is 8
  122. Also consider a case that ``f`` is irreducible for example
  123. ``f = 2*x**2 + 3*x + 4``. To avoid a bug for these cases, we return the
  124. bound plus the max coefficient of ``f``
  125. >>> f = 2*x**2 + 3*x + 4
  126. >>> R.dup_zz_mignotte_bound(f)
  127. 6
  128. Lastly, to see the difference between the new and the old Mignotte bound
  129. consider the irreducible polynomial:
  130. >>> f = 87*x**7 + 4*x**6 + 80*x**5 + 17*x**4 + 9*x**3 + 12*x**2 + 49*x + 26
  131. >>> R.dup_zz_mignotte_bound(f)
  132. 744
  133. The new Mignotte bound is 744 whereas the old one (SymPy 1.5.1) is 1937664.
  134. References
  135. ==========
  136. ..[1] [Abbott13]_
  137. """
  138. from sympy.functions.combinatorial.factorials import binomial
  139. d = dup_degree(f)
  140. delta = _ceil(d / 2)
  141. delta2 = _ceil(delta / 2)
  142. # euclidean-norm
  143. eucl_norm = K.sqrt( sum( cf**2 for cf in f ) )
  144. # biggest values of binomial coefficients (p. 538 of reference)
  145. t1 = binomial(delta - 1, delta2)
  146. t2 = binomial(delta - 1, delta2 - 1)
  147. lc = K.abs(dup_LC(f, K)) # leading coefficient
  148. bound = t1 * eucl_norm + t2 * lc # (p. 538 of reference)
  149. bound += dup_max_norm(f, K) # add max coeff for irreducible polys
  150. bound = _ceil(bound / 2) * 2 # round up to even integer
  151. return bound
  152. def dmp_zz_mignotte_bound(f, u, K):
  153. """Mignotte bound for multivariate polynomials in `K[X]`. """
  154. a = dmp_max_norm(f, u, K)
  155. b = abs(dmp_ground_LC(f, u, K))
  156. n = sum(dmp_degree_list(f, u))
  157. return K.sqrt(K(n + 1))*2**n*a*b
  158. def dup_zz_hensel_step(m, f, g, h, s, t, K):
  159. """
  160. One step in Hensel lifting in `Z[x]`.
  161. Given positive integer `m` and `Z[x]` polynomials `f`, `g`, `h`, `s`
  162. and `t` such that::
  163. f = g*h (mod m)
  164. s*g + t*h = 1 (mod m)
  165. lc(f) is not a zero divisor (mod m)
  166. lc(h) = 1
  167. deg(f) = deg(g) + deg(h)
  168. deg(s) < deg(h)
  169. deg(t) < deg(g)
  170. returns polynomials `G`, `H`, `S` and `T`, such that::
  171. f = G*H (mod m**2)
  172. S*G + T*H = 1 (mod m**2)
  173. References
  174. ==========
  175. .. [1] [Gathen99]_
  176. """
  177. M = m**2
  178. e = dup_sub_mul(f, g, h, K)
  179. e = dup_trunc(e, M, K)
  180. q, r = dup_div(dup_mul(s, e, K), h, K)
  181. q = dup_trunc(q, M, K)
  182. r = dup_trunc(r, M, K)
  183. u = dup_add(dup_mul(t, e, K), dup_mul(q, g, K), K)
  184. G = dup_trunc(dup_add(g, u, K), M, K)
  185. H = dup_trunc(dup_add(h, r, K), M, K)
  186. u = dup_add(dup_mul(s, G, K), dup_mul(t, H, K), K)
  187. b = dup_trunc(dup_sub(u, [K.one], K), M, K)
  188. c, d = dup_div(dup_mul(s, b, K), H, K)
  189. c = dup_trunc(c, M, K)
  190. d = dup_trunc(d, M, K)
  191. u = dup_add(dup_mul(t, b, K), dup_mul(c, G, K), K)
  192. S = dup_trunc(dup_sub(s, d, K), M, K)
  193. T = dup_trunc(dup_sub(t, u, K), M, K)
  194. return G, H, S, T
  195. def dup_zz_hensel_lift(p, f, f_list, l, K):
  196. r"""
  197. Multifactor Hensel lifting in `Z[x]`.
  198. Given a prime `p`, polynomial `f` over `Z[x]` such that `lc(f)`
  199. is a unit modulo `p`, monic pair-wise coprime polynomials `f_i`
  200. over `Z[x]` satisfying::
  201. f = lc(f) f_1 ... f_r (mod p)
  202. and a positive integer `l`, returns a list of monic polynomials
  203. `F_1,\ F_2,\ \dots,\ F_r` satisfying::
  204. f = lc(f) F_1 ... F_r (mod p**l)
  205. F_i = f_i (mod p), i = 1..r
  206. References
  207. ==========
  208. .. [1] [Gathen99]_
  209. """
  210. r = len(f_list)
  211. lc = dup_LC(f, K)
  212. if r == 1:
  213. F = dup_mul_ground(f, K.gcdex(lc, p**l)[0], K)
  214. return [ dup_trunc(F, p**l, K) ]
  215. m = p
  216. k = r // 2
  217. d = int(_ceil(_log2(l)))
  218. g = gf_from_int_poly([lc], p)
  219. for f_i in f_list[:k]:
  220. g = gf_mul(g, gf_from_int_poly(f_i, p), p, K)
  221. h = gf_from_int_poly(f_list[k], p)
  222. for f_i in f_list[k + 1:]:
  223. h = gf_mul(h, gf_from_int_poly(f_i, p), p, K)
  224. s, t, _ = gf_gcdex(g, h, p, K)
  225. g = gf_to_int_poly(g, p)
  226. h = gf_to_int_poly(h, p)
  227. s = gf_to_int_poly(s, p)
  228. t = gf_to_int_poly(t, p)
  229. for _ in range(1, d + 1):
  230. (g, h, s, t), m = dup_zz_hensel_step(m, f, g, h, s, t, K), m**2
  231. return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \
  232. + dup_zz_hensel_lift(p, h, f_list[k:], l, K)
  233. def _test_pl(fc, q, pl):
  234. if q > pl // 2:
  235. q = q - pl
  236. if not q:
  237. return True
  238. return fc % q == 0
  239. def dup_zz_zassenhaus(f, K):
  240. """Factor primitive square-free polynomials in `Z[x]`. """
  241. n = dup_degree(f)
  242. if n == 1:
  243. return [f]
  244. from sympy.ntheory import isprime
  245. fc = f[-1]
  246. A = dup_max_norm(f, K)
  247. b = dup_LC(f, K)
  248. B = int(abs(K.sqrt(K(n + 1))*2**n*A*b))
  249. C = int((n + 1)**(2*n)*A**(2*n - 1))
  250. gamma = int(_ceil(2*_log2(C)))
  251. bound = int(2*gamma*_log(gamma))
  252. a = []
  253. # choose a prime number `p` such that `f` be square free in Z_p
  254. # if there are many factors in Z_p, choose among a few different `p`
  255. # the one with fewer factors
  256. for px in range(3, bound + 1):
  257. if not isprime(px) or b % px == 0:
  258. continue
  259. px = K.convert(px)
  260. F = gf_from_int_poly(f, px)
  261. if not gf_sqf_p(F, px, K):
  262. continue
  263. fsqfx = gf_factor_sqf(F, px, K)[1]
  264. a.append((px, fsqfx))
  265. if len(fsqfx) < 15 or len(a) > 4:
  266. break
  267. p, fsqf = min(a, key=lambda x: len(x[1]))
  268. l = int(_ceil(_log(2*B + 1, p)))
  269. modular = [gf_to_int_poly(ff, p) for ff in fsqf]
  270. g = dup_zz_hensel_lift(p, f, modular, l, K)
  271. sorted_T = range(len(g))
  272. T = set(sorted_T)
  273. factors, s = [], 1
  274. pl = p**l
  275. while 2*s <= len(T):
  276. for S in subsets(sorted_T, s):
  277. # lift the constant coefficient of the product `G` of the factors
  278. # in the subset `S`; if it is does not divide `fc`, `G` does
  279. # not divide the input polynomial
  280. if b == 1:
  281. q = 1
  282. for i in S:
  283. q = q*g[i][-1]
  284. q = q % pl
  285. if not _test_pl(fc, q, pl):
  286. continue
  287. else:
  288. G = [b]
  289. for i in S:
  290. G = dup_mul(G, g[i], K)
  291. G = dup_trunc(G, pl, K)
  292. G = dup_primitive(G, K)[1]
  293. q = G[-1]
  294. if q and fc % q != 0:
  295. continue
  296. H = [b]
  297. S = set(S)
  298. T_S = T - S
  299. if b == 1:
  300. G = [b]
  301. for i in S:
  302. G = dup_mul(G, g[i], K)
  303. G = dup_trunc(G, pl, K)
  304. for i in T_S:
  305. H = dup_mul(H, g[i], K)
  306. H = dup_trunc(H, pl, K)
  307. G_norm = dup_l1_norm(G, K)
  308. H_norm = dup_l1_norm(H, K)
  309. if G_norm*H_norm <= B:
  310. T = T_S
  311. sorted_T = [i for i in sorted_T if i not in S]
  312. G = dup_primitive(G, K)[1]
  313. f = dup_primitive(H, K)[1]
  314. factors.append(G)
  315. b = dup_LC(f, K)
  316. break
  317. else:
  318. s += 1
  319. return factors + [f]
  320. def dup_zz_irreducible_p(f, K):
  321. """Test irreducibility using Eisenstein's criterion. """
  322. lc = dup_LC(f, K)
  323. tc = dup_TC(f, K)
  324. e_fc = dup_content(f[1:], K)
  325. if e_fc:
  326. from sympy.ntheory import factorint
  327. e_ff = factorint(int(e_fc))
  328. for p in e_ff.keys():
  329. if (lc % p) and (tc % p**2):
  330. return True
  331. def dup_cyclotomic_p(f, K, irreducible=False):
  332. """
  333. Efficiently test if ``f`` is a cyclotomic polynomial.
  334. Examples
  335. ========
  336. >>> from sympy.polys import ring, ZZ
  337. >>> R, x = ring("x", ZZ)
  338. >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1
  339. >>> R.dup_cyclotomic_p(f)
  340. False
  341. >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1
  342. >>> R.dup_cyclotomic_p(g)
  343. True
  344. References
  345. ==========
  346. Bradford, Russell J., and James H. Davenport. "Effective tests for
  347. cyclotomic polynomials." In International Symposium on Symbolic and
  348. Algebraic Computation, pp. 244-251. Springer, Berlin, Heidelberg, 1988.
  349. """
  350. if K.is_QQ:
  351. try:
  352. K0, K = K, K.get_ring()
  353. f = dup_convert(f, K0, K)
  354. except CoercionFailed:
  355. return False
  356. elif not K.is_ZZ:
  357. return False
  358. lc = dup_LC(f, K)
  359. tc = dup_TC(f, K)
  360. if lc != 1 or (tc != -1 and tc != 1):
  361. return False
  362. if not irreducible:
  363. coeff, factors = dup_factor_list(f, K)
  364. if coeff != K.one or factors != [(f, 1)]:
  365. return False
  366. n = dup_degree(f)
  367. g, h = [], []
  368. for i in range(n, -1, -2):
  369. g.insert(0, f[i])
  370. for i in range(n - 1, -1, -2):
  371. h.insert(0, f[i])
  372. g = dup_sqr(dup_strip(g), K)
  373. h = dup_sqr(dup_strip(h), K)
  374. F = dup_sub(g, dup_lshift(h, 1, K), K)
  375. if K.is_negative(dup_LC(F, K)):
  376. F = dup_neg(F, K)
  377. if F == f:
  378. return True
  379. g = dup_mirror(f, K)
  380. if K.is_negative(dup_LC(g, K)):
  381. g = dup_neg(g, K)
  382. if F == g and dup_cyclotomic_p(g, K):
  383. return True
  384. G = dup_sqf_part(F, K)
  385. if dup_sqr(G, K) == F and dup_cyclotomic_p(G, K):
  386. return True
  387. return False
  388. def dup_zz_cyclotomic_poly(n, K):
  389. """Efficiently generate n-th cyclotomic polynomial. """
  390. from sympy.ntheory import factorint
  391. h = [K.one, -K.one]
  392. for p, k in factorint(n).items():
  393. h = dup_quo(dup_inflate(h, p, K), h, K)
  394. h = dup_inflate(h, p**(k - 1), K)
  395. return h
  396. def _dup_cyclotomic_decompose(n, K):
  397. from sympy.ntheory import factorint
  398. H = [[K.one, -K.one]]
  399. for p, k in factorint(n).items():
  400. Q = [ dup_quo(dup_inflate(h, p, K), h, K) for h in H ]
  401. H.extend(Q)
  402. for i in range(1, k):
  403. Q = [ dup_inflate(q, p, K) for q in Q ]
  404. H.extend(Q)
  405. return H
  406. def dup_zz_cyclotomic_factor(f, K):
  407. """
  408. Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`.
  409. Given a univariate polynomial `f` in `Z[x]` returns a list of factors
  410. of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for
  411. `n >= 1`. Otherwise returns None.
  412. Factorization is performed using cyclotomic decomposition of `f`,
  413. which makes this method much faster that any other direct factorization
  414. approach (e.g. Zassenhaus's).
  415. References
  416. ==========
  417. .. [1] [Weisstein09]_
  418. """
  419. lc_f, tc_f = dup_LC(f, K), dup_TC(f, K)
  420. if dup_degree(f) <= 0:
  421. return None
  422. if lc_f != 1 or tc_f not in [-1, 1]:
  423. return None
  424. if any(bool(cf) for cf in f[1:-1]):
  425. return None
  426. n = dup_degree(f)
  427. F = _dup_cyclotomic_decompose(n, K)
  428. if not K.is_one(tc_f):
  429. return F
  430. else:
  431. H = []
  432. for h in _dup_cyclotomic_decompose(2*n, K):
  433. if h not in F:
  434. H.append(h)
  435. return H
  436. def dup_zz_factor_sqf(f, K):
  437. """Factor square-free (non-primitive) polynomials in `Z[x]`. """
  438. cont, g = dup_primitive(f, K)
  439. n = dup_degree(g)
  440. if dup_LC(g, K) < 0:
  441. cont, g = -cont, dup_neg(g, K)
  442. if n <= 0:
  443. return cont, []
  444. elif n == 1:
  445. return cont, [g]
  446. if query('USE_IRREDUCIBLE_IN_FACTOR'):
  447. if dup_zz_irreducible_p(g, K):
  448. return cont, [g]
  449. factors = None
  450. if query('USE_CYCLOTOMIC_FACTOR'):
  451. factors = dup_zz_cyclotomic_factor(g, K)
  452. if factors is None:
  453. factors = dup_zz_zassenhaus(g, K)
  454. return cont, _sort_factors(factors, multiple=False)
  455. def dup_zz_factor(f, K):
  456. """
  457. Factor (non square-free) polynomials in `Z[x]`.
  458. Given a univariate polynomial `f` in `Z[x]` computes its complete
  459. factorization `f_1, ..., f_n` into irreducibles over integers::
  460. f = content(f) f_1**k_1 ... f_n**k_n
  461. The factorization is computed by reducing the input polynomial
  462. into a primitive square-free polynomial and factoring it using
  463. Zassenhaus algorithm. Trial division is used to recover the
  464. multiplicities of factors.
  465. The result is returned as a tuple consisting of::
  466. (content(f), [(f_1, k_1), ..., (f_n, k_n))
  467. Examples
  468. ========
  469. Consider the polynomial `f = 2*x**4 - 2`::
  470. >>> from sympy.polys import ring, ZZ
  471. >>> R, x = ring("x", ZZ)
  472. >>> R.dup_zz_factor(2*x**4 - 2)
  473. (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)])
  474. In result we got the following factorization::
  475. f = 2 (x - 1) (x + 1) (x**2 + 1)
  476. Note that this is a complete factorization over integers,
  477. however over Gaussian integers we can factor the last term.
  478. By default, polynomials `x**n - 1` and `x**n + 1` are factored
  479. using cyclotomic decomposition to speedup computations. To
  480. disable this behaviour set cyclotomic=False.
  481. References
  482. ==========
  483. .. [1] [Gathen99]_
  484. """
  485. if GROUND_TYPES == 'flint':
  486. f_flint = fmpz_poly(f[::-1])
  487. cont, factors = f_flint.factor()
  488. factors = [(fac.coeffs()[::-1], exp) for fac, exp in factors]
  489. return cont, _sort_factors(factors)
  490. cont, g = dup_primitive(f, K)
  491. n = dup_degree(g)
  492. if dup_LC(g, K) < 0:
  493. cont, g = -cont, dup_neg(g, K)
  494. if n <= 0:
  495. return cont, []
  496. elif n == 1:
  497. return cont, [(g, 1)]
  498. if query('USE_IRREDUCIBLE_IN_FACTOR'):
  499. if dup_zz_irreducible_p(g, K):
  500. return cont, [(g, 1)]
  501. g = dup_sqf_part(g, K)
  502. H = None
  503. if query('USE_CYCLOTOMIC_FACTOR'):
  504. H = dup_zz_cyclotomic_factor(g, K)
  505. if H is None:
  506. H = dup_zz_zassenhaus(g, K)
  507. factors = dup_trial_division(f, H, K)
  508. _dup_check_degrees(f, factors)
  509. return cont, factors
  510. def dmp_zz_wang_non_divisors(E, cs, ct, K):
  511. """Wang/EEZ: Compute a set of valid divisors. """
  512. result = [ cs*ct ]
  513. for q in E:
  514. q = abs(q)
  515. for r in reversed(result):
  516. while r != 1:
  517. r = K.gcd(r, q)
  518. q = q // r
  519. if K.is_one(q):
  520. return None
  521. result.append(q)
  522. return result[1:]
  523. def dmp_zz_wang_test_points(f, T, ct, A, u, K):
  524. """Wang/EEZ: Test evaluation points for suitability. """
  525. if not dmp_eval_tail(dmp_LC(f, K), A, u - 1, K):
  526. raise EvaluationFailed('no luck')
  527. g = dmp_eval_tail(f, A, u, K)
  528. if not dup_sqf_p(g, K):
  529. raise EvaluationFailed('no luck')
  530. c, h = dup_primitive(g, K)
  531. if K.is_negative(dup_LC(h, K)):
  532. c, h = -c, dup_neg(h, K)
  533. v = u - 1
  534. E = [ dmp_eval_tail(t, A, v, K) for t, _ in T ]
  535. D = dmp_zz_wang_non_divisors(E, c, ct, K)
  536. if D is not None:
  537. return c, h, E
  538. else:
  539. raise EvaluationFailed('no luck')
  540. def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K):
  541. """Wang/EEZ: Compute correct leading coefficients. """
  542. C, J, v = [], [0]*len(E), u - 1
  543. for h in H:
  544. c = dmp_one(v, K)
  545. d = dup_LC(h, K)*cs
  546. for i in reversed(range(len(E))):
  547. k, e, (t, _) = 0, E[i], T[i]
  548. while not (d % e):
  549. d, k = d//e, k + 1
  550. if k != 0:
  551. c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1
  552. C.append(c)
  553. if not all(J):
  554. raise ExtraneousFactors # pragma: no cover
  555. CC, HH = [], []
  556. for c, h in zip(C, H):
  557. d = dmp_eval_tail(c, A, v, K)
  558. lc = dup_LC(h, K)
  559. if K.is_one(cs):
  560. cc = lc//d
  561. else:
  562. g = K.gcd(lc, d)
  563. d, cc = d//g, lc//g
  564. h, cs = dup_mul_ground(h, d, K), cs//d
  565. c = dmp_mul_ground(c, cc, v, K)
  566. CC.append(c)
  567. HH.append(h)
  568. if K.is_one(cs):
  569. return f, HH, CC
  570. CCC, HHH = [], []
  571. for c, h in zip(CC, HH):
  572. CCC.append(dmp_mul_ground(c, cs, v, K))
  573. HHH.append(dmp_mul_ground(h, cs, 0, K))
  574. f = dmp_mul_ground(f, cs**(len(H) - 1), u, K)
  575. return f, HHH, CCC
  576. def dup_zz_diophantine(F, m, p, K):
  577. """Wang/EEZ: Solve univariate Diophantine equations. """
  578. if len(F) == 2:
  579. a, b = F
  580. f = gf_from_int_poly(a, p)
  581. g = gf_from_int_poly(b, p)
  582. s, t, G = gf_gcdex(g, f, p, K)
  583. s = gf_lshift(s, m, K)
  584. t = gf_lshift(t, m, K)
  585. q, s = gf_div(s, f, p, K)
  586. t = gf_add_mul(t, q, g, p, K)
  587. s = gf_to_int_poly(s, p)
  588. t = gf_to_int_poly(t, p)
  589. result = [s, t]
  590. else:
  591. G = [F[-1]]
  592. for f in reversed(F[1:-1]):
  593. G.insert(0, dup_mul(f, G[0], K))
  594. S, T = [], [[1]]
  595. for f, g in zip(F, G):
  596. t, s = dmp_zz_diophantine([g, f], T[-1], [], 0, p, 1, K)
  597. T.append(t)
  598. S.append(s)
  599. result, S = [], S + [T[-1]]
  600. for s, f in zip(S, F):
  601. s = gf_from_int_poly(s, p)
  602. f = gf_from_int_poly(f, p)
  603. r = gf_rem(gf_lshift(s, m, K), f, p, K)
  604. s = gf_to_int_poly(r, p)
  605. result.append(s)
  606. return result
  607. def dmp_zz_diophantine(F, c, A, d, p, u, K):
  608. """Wang/EEZ: Solve multivariate Diophantine equations. """
  609. if not A:
  610. S = [ [] for _ in F ]
  611. n = dup_degree(c)
  612. for i, coeff in enumerate(c):
  613. if not coeff:
  614. continue
  615. T = dup_zz_diophantine(F, n - i, p, K)
  616. for j, (s, t) in enumerate(zip(S, T)):
  617. t = dup_mul_ground(t, coeff, K)
  618. S[j] = dup_trunc(dup_add(s, t, K), p, K)
  619. else:
  620. n = len(A)
  621. e = dmp_expand(F, u, K)
  622. a, A = A[-1], A[:-1]
  623. B, G = [], []
  624. for f in F:
  625. B.append(dmp_quo(e, f, u, K))
  626. G.append(dmp_eval_in(f, a, n, u, K))
  627. C = dmp_eval_in(c, a, n, u, K)
  628. v = u - 1
  629. S = dmp_zz_diophantine(G, C, A, d, p, v, K)
  630. S = [ dmp_raise(s, 1, v, K) for s in S ]
  631. for s, b in zip(S, B):
  632. c = dmp_sub_mul(c, s, b, u, K)
  633. c = dmp_ground_trunc(c, p, u, K)
  634. m = dmp_nest([K.one, -a], n, K)
  635. M = dmp_one(n, K)
  636. for k in range(0, d):
  637. if dmp_zero_p(c, u):
  638. break
  639. M = dmp_mul(M, m, u, K)
  640. C = dmp_diff_eval_in(c, k + 1, a, n, u, K)
  641. if not dmp_zero_p(C, v):
  642. C = dmp_quo_ground(C, K.factorial(K(k) + 1), v, K)
  643. T = dmp_zz_diophantine(G, C, A, d, p, v, K)
  644. for i, t in enumerate(T):
  645. T[i] = dmp_mul(dmp_raise(t, 1, v, K), M, u, K)
  646. for i, (s, t) in enumerate(zip(S, T)):
  647. S[i] = dmp_add(s, t, u, K)
  648. for t, b in zip(T, B):
  649. c = dmp_sub_mul(c, t, b, u, K)
  650. c = dmp_ground_trunc(c, p, u, K)
  651. S = [ dmp_ground_trunc(s, p, u, K) for s in S ]
  652. return S
  653. def dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K):
  654. """Wang/EEZ: Parallel Hensel lifting algorithm. """
  655. S, n, v = [f], len(A), u - 1
  656. H = list(H)
  657. for i, a in enumerate(reversed(A[1:])):
  658. s = dmp_eval_in(S[0], a, n - i, u - i, K)
  659. S.insert(0, dmp_ground_trunc(s, p, v - i, K))
  660. d = max(dmp_degree_list(f, u)[1:])
  661. for j, s, a in zip(range(2, n + 2), S, A):
  662. G, w = list(H), j - 1
  663. I, J = A[:j - 2], A[j - 1:]
  664. for i, (h, lc) in enumerate(zip(H, LC)):
  665. lc = dmp_ground_trunc(dmp_eval_tail(lc, J, v, K), p, w - 1, K)
  666. H[i] = [lc] + dmp_raise(h[1:], 1, w - 1, K)
  667. m = dmp_nest([K.one, -a], w, K)
  668. M = dmp_one(w, K)
  669. c = dmp_sub(s, dmp_expand(H, w, K), w, K)
  670. dj = dmp_degree_in(s, w, w)
  671. for k in range(0, dj):
  672. if dmp_zero_p(c, w):
  673. break
  674. M = dmp_mul(M, m, w, K)
  675. C = dmp_diff_eval_in(c, k + 1, a, w, w, K)
  676. if not dmp_zero_p(C, w - 1):
  677. C = dmp_quo_ground(C, K.factorial(K(k) + 1), w - 1, K)
  678. T = dmp_zz_diophantine(G, C, I, d, p, w - 1, K)
  679. for i, (h, t) in enumerate(zip(H, T)):
  680. h = dmp_add_mul(h, dmp_raise(t, 1, w - 1, K), M, w, K)
  681. H[i] = dmp_ground_trunc(h, p, w, K)
  682. h = dmp_sub(s, dmp_expand(H, w, K), w, K)
  683. c = dmp_ground_trunc(h, p, w, K)
  684. if dmp_expand(H, u, K) != f:
  685. raise ExtraneousFactors # pragma: no cover
  686. else:
  687. return H
  688. def dmp_zz_wang(f, u, K, mod=None, seed=None):
  689. r"""
  690. Factor primitive square-free polynomials in `Z[X]`.
  691. Given a multivariate polynomial `f` in `Z[x_1,...,x_n]`, which is
  692. primitive and square-free in `x_1`, computes factorization of `f` into
  693. irreducibles over integers.
  694. The procedure is based on Wang's Enhanced Extended Zassenhaus
  695. algorithm. The algorithm works by viewing `f` as a univariate polynomial
  696. in `Z[x_2,...,x_n][x_1]`, for which an evaluation mapping is computed::
  697. x_2 -> a_2, ..., x_n -> a_n
  698. where `a_i`, for `i = 2, \dots, n`, are carefully chosen integers. The
  699. mapping is used to transform `f` into a univariate polynomial in `Z[x_1]`,
  700. which can be factored efficiently using Zassenhaus algorithm. The last
  701. step is to lift univariate factors to obtain true multivariate
  702. factors. For this purpose a parallel Hensel lifting procedure is used.
  703. The parameter ``seed`` is passed to _randint and can be used to seed randint
  704. (when an integer) or (for testing purposes) can be a sequence of numbers.
  705. References
  706. ==========
  707. .. [1] [Wang78]_
  708. .. [2] [Geddes92]_
  709. """
  710. from sympy.ntheory import nextprime
  711. randint = _randint(seed)
  712. ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K)
  713. b = dmp_zz_mignotte_bound(f, u, K)
  714. p = K(nextprime(b))
  715. if mod is None:
  716. if u == 1:
  717. mod = 2
  718. else:
  719. mod = 1
  720. history, configs, A, r = set(), [], [K.zero]*u, None
  721. try:
  722. cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K)
  723. _, H = dup_zz_factor_sqf(s, K)
  724. r = len(H)
  725. if r == 1:
  726. return [f]
  727. configs = [(s, cs, E, H, A)]
  728. except EvaluationFailed:
  729. pass
  730. eez_num_configs = query('EEZ_NUMBER_OF_CONFIGS')
  731. eez_num_tries = query('EEZ_NUMBER_OF_TRIES')
  732. eez_mod_step = query('EEZ_MODULUS_STEP')
  733. while len(configs) < eez_num_configs:
  734. for _ in range(eez_num_tries):
  735. A = [ K(randint(-mod, mod)) for _ in range(u) ]
  736. if tuple(A) not in history:
  737. history.add(tuple(A))
  738. else:
  739. continue
  740. try:
  741. cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K)
  742. except EvaluationFailed:
  743. continue
  744. _, H = dup_zz_factor_sqf(s, K)
  745. rr = len(H)
  746. if r is not None:
  747. if rr != r: # pragma: no cover
  748. if rr < r:
  749. configs, r = [], rr
  750. else:
  751. continue
  752. else:
  753. r = rr
  754. if r == 1:
  755. return [f]
  756. configs.append((s, cs, E, H, A))
  757. if len(configs) == eez_num_configs:
  758. break
  759. else:
  760. mod += eez_mod_step
  761. s_norm, s_arg, i = None, 0, 0
  762. for s, _, _, _, _ in configs:
  763. _s_norm = dup_max_norm(s, K)
  764. if s_norm is not None:
  765. if _s_norm < s_norm:
  766. s_norm = _s_norm
  767. s_arg = i
  768. else:
  769. s_norm = _s_norm
  770. i += 1
  771. _, cs, E, H, A = configs[s_arg]
  772. orig_f = f
  773. try:
  774. f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K)
  775. factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K)
  776. except ExtraneousFactors: # pragma: no cover
  777. if query('EEZ_RESTART_IF_NEEDED'):
  778. return dmp_zz_wang(orig_f, u, K, mod + 1)
  779. else:
  780. raise ExtraneousFactors(
  781. "we need to restart algorithm with better parameters")
  782. result = []
  783. for f in factors:
  784. _, f = dmp_ground_primitive(f, u, K)
  785. if K.is_negative(dmp_ground_LC(f, u, K)):
  786. f = dmp_neg(f, u, K)
  787. result.append(f)
  788. return result
  789. def dmp_zz_factor(f, u, K):
  790. r"""
  791. Factor (non square-free) polynomials in `Z[X]`.
  792. Given a multivariate polynomial `f` in `Z[x]` computes its complete
  793. factorization `f_1, \dots, f_n` into irreducibles over integers::
  794. f = content(f) f_1**k_1 ... f_n**k_n
  795. The factorization is computed by reducing the input polynomial
  796. into a primitive square-free polynomial and factoring it using
  797. Enhanced Extended Zassenhaus (EEZ) algorithm. Trial division
  798. is used to recover the multiplicities of factors.
  799. The result is returned as a tuple consisting of::
  800. (content(f), [(f_1, k_1), ..., (f_n, k_n))
  801. Consider polynomial `f = 2*(x**2 - y**2)`::
  802. >>> from sympy.polys import ring, ZZ
  803. >>> R, x,y = ring("x,y", ZZ)
  804. >>> R.dmp_zz_factor(2*x**2 - 2*y**2)
  805. (2, [(x - y, 1), (x + y, 1)])
  806. In result we got the following factorization::
  807. f = 2 (x - y) (x + y)
  808. References
  809. ==========
  810. .. [1] [Gathen99]_
  811. """
  812. if not u:
  813. return dup_zz_factor(f, K)
  814. if dmp_zero_p(f, u):
  815. return K.zero, []
  816. cont, g = dmp_ground_primitive(f, u, K)
  817. if dmp_ground_LC(g, u, K) < 0:
  818. cont, g = -cont, dmp_neg(g, u, K)
  819. if all(d <= 0 for d in dmp_degree_list(g, u)):
  820. return cont, []
  821. G, g = dmp_primitive(g, u, K)
  822. factors = []
  823. if dmp_degree(g, u) > 0:
  824. g = dmp_sqf_part(g, u, K)
  825. H = dmp_zz_wang(g, u, K)
  826. factors = dmp_trial_division(f, H, u, K)
  827. for g, k in dmp_zz_factor(G, u - 1, K)[1]:
  828. factors.insert(0, ([g], k))
  829. _dmp_check_degrees(f, u, factors)
  830. return cont, _sort_factors(factors)
  831. def dup_qq_i_factor(f, K0):
  832. """Factor univariate polynomials into irreducibles in `QQ_I[x]`. """
  833. # Factor in QQ<I>
  834. K1 = K0.as_AlgebraicField()
  835. f = dup_convert(f, K0, K1)
  836. coeff, factors = dup_factor_list(f, K1)
  837. factors = [(dup_convert(fac, K1, K0), i) for fac, i in factors]
  838. coeff = K0.convert(coeff, K1)
  839. return coeff, factors
  840. def dup_zz_i_factor(f, K0):
  841. """Factor univariate polynomials into irreducibles in `ZZ_I[x]`. """
  842. # First factor in QQ_I
  843. K1 = K0.get_field()
  844. f = dup_convert(f, K0, K1)
  845. coeff, factors = dup_qq_i_factor(f, K1)
  846. new_factors = []
  847. for fac, i in factors:
  848. # Extract content
  849. fac_denom, fac_num = dup_clear_denoms(fac, K1)
  850. fac_num_ZZ_I = dup_convert(fac_num, K1, K0)
  851. content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, 0, K0)
  852. coeff = (coeff * content ** i) // fac_denom ** i
  853. new_factors.append((fac_prim, i))
  854. factors = new_factors
  855. coeff = K0.convert(coeff, K1)
  856. return coeff, factors
  857. def dmp_qq_i_factor(f, u, K0):
  858. """Factor multivariate polynomials into irreducibles in `QQ_I[X]`. """
  859. # Factor in QQ<I>
  860. K1 = K0.as_AlgebraicField()
  861. f = dmp_convert(f, u, K0, K1)
  862. coeff, factors = dmp_factor_list(f, u, K1)
  863. factors = [(dmp_convert(fac, u, K1, K0), i) for fac, i in factors]
  864. coeff = K0.convert(coeff, K1)
  865. return coeff, factors
  866. def dmp_zz_i_factor(f, u, K0):
  867. """Factor multivariate polynomials into irreducibles in `ZZ_I[X]`. """
  868. # First factor in QQ_I
  869. K1 = K0.get_field()
  870. f = dmp_convert(f, u, K0, K1)
  871. coeff, factors = dmp_qq_i_factor(f, u, K1)
  872. new_factors = []
  873. for fac, i in factors:
  874. # Extract content
  875. fac_denom, fac_num = dmp_clear_denoms(fac, u, K1)
  876. fac_num_ZZ_I = dmp_convert(fac_num, u, K1, K0)
  877. content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, u, K0)
  878. coeff = (coeff * content ** i) // fac_denom ** i
  879. new_factors.append((fac_prim, i))
  880. factors = new_factors
  881. coeff = K0.convert(coeff, K1)
  882. return coeff, factors
  883. def dup_ext_factor(f, K):
  884. r"""Factor univariate polynomials over algebraic number fields.
  885. The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).
  886. Examples
  887. ========
  888. First define the algebraic number field `K = \mathbb{Q}(\sqrt{2})`:
  889. >>> from sympy import QQ, sqrt
  890. >>> from sympy.polys.factortools import dup_ext_factor
  891. >>> K = QQ.algebraic_field(sqrt(2))
  892. We can now factorise the polynomial `x^2 - 2` over `K`:
  893. >>> p = [K(1), K(0), K(-2)] # x^2 - 2
  894. >>> p1 = [K(1), -K.unit] # x - sqrt(2)
  895. >>> p2 = [K(1), +K.unit] # x + sqrt(2)
  896. >>> dup_ext_factor(p, K) == (K.one, [(p1, 1), (p2, 1)])
  897. True
  898. Usually this would be done at a higher level:
  899. >>> from sympy import factor
  900. >>> from sympy.abc import x
  901. >>> factor(x**2 - 2, extension=sqrt(2))
  902. (x - sqrt(2))*(x + sqrt(2))
  903. Explanation
  904. ===========
  905. Uses Trager's algorithm. In particular this function is algorithm
  906. ``alg_factor`` from [Trager76]_.
  907. If `f` is a polynomial in `k(a)[x]` then its norm `g(x)` is a polynomial in
  908. `k[x]`. If `g(x)` is square-free and has irreducible factors `g_1(x)`,
  909. `g_2(x)`, `\cdots` then the irreducible factors of `f` in `k(a)[x]` are
  910. given by `f_i(x) = \gcd(f(x), g_i(x))` where the GCD is computed in
  911. `k(a)[x]`.
  912. The first step in Trager's algorithm is to find an integer shift `s` so
  913. that `f(x-sa)` has square-free norm. Then the norm is factorized in `k[x]`
  914. and the GCD of (shifted) `f` with each factor gives the shifted factors of
  915. `f`. At the end the shift is undone to recover the unshifted factors of `f`
  916. in `k(a)[x]`.
  917. The algorithm reduces the problem of factorization in `k(a)[x]` to
  918. factorization in `k[x]` with the main additional steps being to compute the
  919. norm (a resultant calculation in `k[x,y]`) and some polynomial GCDs in
  920. `k(a)[x]`.
  921. In practice in SymPy the base field `k` will be the rationals :ref:`QQ` and
  922. this function factorizes a polynomial with coefficients in an algebraic
  923. number field like `\mathbb{Q}(\sqrt{2})`.
  924. See Also
  925. ========
  926. dmp_ext_factor:
  927. Analogous function for multivariate polynomials over ``k(a)``.
  928. dup_sqf_norm:
  929. Subroutine ``sqfr_norm`` also from [Trager76]_.
  930. sympy.polys.polytools.factor:
  931. The high-level function that ultimately uses this function as needed.
  932. """
  933. n, lc = dup_degree(f), dup_LC(f, K)
  934. f = dup_monic(f, K)
  935. if n <= 0:
  936. return lc, []
  937. if n == 1:
  938. return lc, [(f, 1)]
  939. f, F = dup_sqf_part(f, K), f
  940. s, g, r = dup_sqf_norm(f, K)
  941. factors = dup_factor_list_include(r, K.dom)
  942. if len(factors) == 1:
  943. return lc, [(f, n//dup_degree(f))]
  944. H = s*K.unit
  945. for i, (factor, _) in enumerate(factors):
  946. h = dup_convert(factor, K.dom, K)
  947. h, _, g = dup_inner_gcd(h, g, K)
  948. h = dup_shift(h, H, K)
  949. factors[i] = h
  950. factors = dup_trial_division(F, factors, K)
  951. _dup_check_degrees(F, factors)
  952. return lc, factors
  953. def dmp_ext_factor(f, u, K):
  954. r"""Factor multivariate polynomials over algebraic number fields.
  955. The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).
  956. Examples
  957. ========
  958. First define the algebraic number field `K = \mathbb{Q}(\sqrt{2})`:
  959. >>> from sympy import QQ, sqrt
  960. >>> from sympy.polys.factortools import dmp_ext_factor
  961. >>> K = QQ.algebraic_field(sqrt(2))
  962. We can now factorise the polynomial `x^2 y^2 - 2` over `K`:
  963. >>> p = [[K(1),K(0),K(0)], [], [K(-2)]] # x**2*y**2 - 2
  964. >>> p1 = [[K(1),K(0)], [-K.unit]] # x*y - sqrt(2)
  965. >>> p2 = [[K(1),K(0)], [+K.unit]] # x*y + sqrt(2)
  966. >>> dmp_ext_factor(p, 1, K) == (K.one, [(p1, 1), (p2, 1)])
  967. True
  968. Usually this would be done at a higher level:
  969. >>> from sympy import factor
  970. >>> from sympy.abc import x, y
  971. >>> factor(x**2*y**2 - 2, extension=sqrt(2))
  972. (x*y - sqrt(2))*(x*y + sqrt(2))
  973. Explanation
  974. ===========
  975. This is Trager's algorithm for multivariate polynomials. In particular this
  976. function is algorithm ``alg_factor`` from [Trager76]_.
  977. See :func:`dup_ext_factor` for explanation.
  978. See Also
  979. ========
  980. dup_ext_factor:
  981. Analogous function for univariate polynomials over ``k(a)``.
  982. dmp_sqf_norm:
  983. Multivariate version of subroutine ``sqfr_norm`` also from [Trager76]_.
  984. sympy.polys.polytools.factor:
  985. The high-level function that ultimately uses this function as needed.
  986. """
  987. if not u:
  988. return dup_ext_factor(f, K)
  989. lc = dmp_ground_LC(f, u, K)
  990. f = dmp_ground_monic(f, u, K)
  991. if all(d <= 0 for d in dmp_degree_list(f, u)):
  992. return lc, []
  993. f, F = dmp_sqf_part(f, u, K), f
  994. s, g, r = dmp_sqf_norm(f, u, K)
  995. factors = dmp_factor_list_include(r, u, K.dom)
  996. if len(factors) == 1:
  997. factors = [f]
  998. else:
  999. for i, (factor, _) in enumerate(factors):
  1000. h = dmp_convert(factor, u, K.dom, K)
  1001. h, _, g = dmp_inner_gcd(h, g, u, K)
  1002. a = [si*K.unit for si in s]
  1003. h = dmp_shift(h, a, u, K)
  1004. factors[i] = h
  1005. result = dmp_trial_division(F, factors, u, K)
  1006. _dmp_check_degrees(F, u, result)
  1007. return lc, result
  1008. def dup_gf_factor(f, K):
  1009. """Factor univariate polynomials over finite fields. """
  1010. f = dup_convert(f, K, K.dom)
  1011. coeff, factors = gf_factor(f, K.mod, K.dom)
  1012. for i, (f, k) in enumerate(factors):
  1013. factors[i] = (dup_convert(f, K.dom, K), k)
  1014. return K.convert(coeff, K.dom), factors
  1015. def dmp_gf_factor(f, u, K):
  1016. """Factor multivariate polynomials over finite fields. """
  1017. raise NotImplementedError('multivariate polynomials over finite fields')
  1018. def dup_factor_list(f, K0):
  1019. """Factor univariate polynomials into irreducibles in `K[x]`. """
  1020. j, f = dup_terms_gcd(f, K0)
  1021. cont, f = dup_primitive(f, K0)
  1022. if K0.is_FiniteField:
  1023. coeff, factors = dup_gf_factor(f, K0)
  1024. elif K0.is_Algebraic:
  1025. coeff, factors = dup_ext_factor(f, K0)
  1026. elif K0.is_GaussianRing:
  1027. coeff, factors = dup_zz_i_factor(f, K0)
  1028. elif K0.is_GaussianField:
  1029. coeff, factors = dup_qq_i_factor(f, K0)
  1030. else:
  1031. if not K0.is_Exact:
  1032. K0_inexact, K0 = K0, K0.get_exact()
  1033. f = dup_convert(f, K0_inexact, K0)
  1034. else:
  1035. K0_inexact = None
  1036. if K0.is_Field:
  1037. K = K0.get_ring()
  1038. denom, f = dup_clear_denoms(f, K0, K)
  1039. f = dup_convert(f, K0, K)
  1040. else:
  1041. K = K0
  1042. if K.is_ZZ:
  1043. coeff, factors = dup_zz_factor(f, K)
  1044. elif K.is_Poly:
  1045. f, u = dmp_inject(f, 0, K)
  1046. coeff, factors = dmp_factor_list(f, u, K.dom)
  1047. for i, (f, k) in enumerate(factors):
  1048. factors[i] = (dmp_eject(f, u, K), k)
  1049. coeff = K.convert(coeff, K.dom)
  1050. else: # pragma: no cover
  1051. raise DomainError('factorization not supported over %s' % K0)
  1052. if K0.is_Field:
  1053. for i, (f, k) in enumerate(factors):
  1054. factors[i] = (dup_convert(f, K, K0), k)
  1055. coeff = K0.convert(coeff, K)
  1056. coeff = K0.quo(coeff, denom)
  1057. if K0_inexact:
  1058. for i, (f, k) in enumerate(factors):
  1059. max_norm = dup_max_norm(f, K0)
  1060. f = dup_quo_ground(f, max_norm, K0)
  1061. f = dup_convert(f, K0, K0_inexact)
  1062. factors[i] = (f, k)
  1063. coeff = K0.mul(coeff, K0.pow(max_norm, k))
  1064. coeff = K0_inexact.convert(coeff, K0)
  1065. K0 = K0_inexact
  1066. if j:
  1067. factors.insert(0, ([K0.one, K0.zero], j))
  1068. return coeff*cont, _sort_factors(factors)
  1069. def dup_factor_list_include(f, K):
  1070. """Factor univariate polynomials into irreducibles in `K[x]`. """
  1071. coeff, factors = dup_factor_list(f, K)
  1072. if not factors:
  1073. return [(dup_strip([coeff]), 1)]
  1074. else:
  1075. g = dup_mul_ground(factors[0][0], coeff, K)
  1076. return [(g, factors[0][1])] + factors[1:]
  1077. def dmp_factor_list(f, u, K0):
  1078. """Factor multivariate polynomials into irreducibles in `K[X]`. """
  1079. if not u:
  1080. return dup_factor_list(f, K0)
  1081. J, f = dmp_terms_gcd(f, u, K0)
  1082. cont, f = dmp_ground_primitive(f, u, K0)
  1083. if K0.is_FiniteField: # pragma: no cover
  1084. coeff, factors = dmp_gf_factor(f, u, K0)
  1085. elif K0.is_Algebraic:
  1086. coeff, factors = dmp_ext_factor(f, u, K0)
  1087. elif K0.is_GaussianRing:
  1088. coeff, factors = dmp_zz_i_factor(f, u, K0)
  1089. elif K0.is_GaussianField:
  1090. coeff, factors = dmp_qq_i_factor(f, u, K0)
  1091. else:
  1092. if not K0.is_Exact:
  1093. K0_inexact, K0 = K0, K0.get_exact()
  1094. f = dmp_convert(f, u, K0_inexact, K0)
  1095. else:
  1096. K0_inexact = None
  1097. if K0.is_Field:
  1098. K = K0.get_ring()
  1099. denom, f = dmp_clear_denoms(f, u, K0, K)
  1100. f = dmp_convert(f, u, K0, K)
  1101. else:
  1102. K = K0
  1103. if K.is_ZZ:
  1104. levels, f, v = dmp_exclude(f, u, K)
  1105. coeff, factors = dmp_zz_factor(f, v, K)
  1106. for i, (f, k) in enumerate(factors):
  1107. factors[i] = (dmp_include(f, levels, v, K), k)
  1108. elif K.is_Poly:
  1109. f, v = dmp_inject(f, u, K)
  1110. coeff, factors = dmp_factor_list(f, v, K.dom)
  1111. for i, (f, k) in enumerate(factors):
  1112. factors[i] = (dmp_eject(f, v, K), k)
  1113. coeff = K.convert(coeff, K.dom)
  1114. else: # pragma: no cover
  1115. raise DomainError('factorization not supported over %s' % K0)
  1116. if K0.is_Field:
  1117. for i, (f, k) in enumerate(factors):
  1118. factors[i] = (dmp_convert(f, u, K, K0), k)
  1119. coeff = K0.convert(coeff, K)
  1120. coeff = K0.quo(coeff, denom)
  1121. if K0_inexact:
  1122. for i, (f, k) in enumerate(factors):
  1123. max_norm = dmp_max_norm(f, u, K0)
  1124. f = dmp_quo_ground(f, max_norm, u, K0)
  1125. f = dmp_convert(f, u, K0, K0_inexact)
  1126. factors[i] = (f, k)
  1127. coeff = K0.mul(coeff, K0.pow(max_norm, k))
  1128. coeff = K0_inexact.convert(coeff, K0)
  1129. K0 = K0_inexact
  1130. for i, j in enumerate(reversed(J)):
  1131. if not j:
  1132. continue
  1133. term = {(0,)*(u - i) + (1,) + (0,)*i: K0.one}
  1134. factors.insert(0, (dmp_from_dict(term, u, K0), j))
  1135. return coeff*cont, _sort_factors(factors)
  1136. def dmp_factor_list_include(f, u, K):
  1137. """Factor multivariate polynomials into irreducibles in `K[X]`. """
  1138. if not u:
  1139. return dup_factor_list_include(f, K)
  1140. coeff, factors = dmp_factor_list(f, u, K)
  1141. if not factors:
  1142. return [(dmp_ground(coeff, u), 1)]
  1143. else:
  1144. g = dmp_mul_ground(factors[0][0], coeff, u, K)
  1145. return [(g, factors[0][1])] + factors[1:]
  1146. def dup_irreducible_p(f, K):
  1147. """
  1148. Returns ``True`` if a univariate polynomial ``f`` has no factors
  1149. over its domain.
  1150. """
  1151. return dmp_irreducible_p(f, 0, K)
  1152. def dmp_irreducible_p(f, u, K):
  1153. """
  1154. Returns ``True`` if a multivariate polynomial ``f`` has no factors
  1155. over its domain.
  1156. """
  1157. _, factors = dmp_factor_list(f, u, K)
  1158. if not factors:
  1159. return True
  1160. elif len(factors) > 1:
  1161. return False
  1162. else:
  1163. _, k = factors[0]
  1164. return k == 1