Coverage for sympy/polys/factortools.py : 67%
        
        
    Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
| 
 """Polynomial factorization routines in characteristic zero. """ 
 from __future__ import print_function, division 
 from sympy.polys.galoistools import ( gf_from_int_poly, gf_to_int_poly, gf_lshift, gf_add_mul, gf_mul, gf_div, gf_rem, gf_gcdex, gf_sqf_p, gf_factor_sqf, gf_factor) 
 from sympy.polys.densebasic import ( dup_LC, dmp_LC, dmp_ground_LC, dup_TC, dup_convert, dmp_convert, dup_degree, dmp_degree, dmp_degree_in, dmp_degree_list, dmp_from_dict, dmp_zero_p, dmp_one, dmp_nest, dmp_raise, dup_strip, dmp_ground, dup_inflate, dmp_exclude, dmp_include, dmp_inject, dmp_eject, dup_terms_gcd, dmp_terms_gcd) 
 from sympy.polys.densearith import ( dup_neg, dmp_neg, dup_add, dmp_add, dup_sub, dmp_sub, dup_mul, dmp_mul, dup_sqr, dmp_pow, dup_div, dmp_div, dup_quo, dmp_quo, dmp_expand, dmp_add_mul, dup_sub_mul, dmp_sub_mul, dup_lshift, dup_max_norm, dmp_max_norm, dup_l1_norm, dup_mul_ground, dmp_mul_ground, dup_quo_ground, dmp_quo_ground) 
 from sympy.polys.densetools import ( dup_clear_denoms, dmp_clear_denoms, dup_trunc, dmp_ground_trunc, dup_content, dup_monic, dmp_ground_monic, dup_primitive, dmp_ground_primitive, dmp_eval_tail, dmp_eval_in, dmp_diff_eval_in, dmp_compose, dup_shift, dup_mirror) 
 from sympy.polys.euclidtools import ( dmp_primitive, dup_inner_gcd, dmp_inner_gcd) 
 from sympy.polys.sqfreetools import ( dup_sqf_p, dup_sqf_norm, dmp_sqf_norm, dup_sqf_part, dmp_sqf_part) 
 from sympy.polys.polyutils import _sort_factors from sympy.polys.polyconfig import query 
 from sympy.polys.polyerrors import ( ExtraneousFactors, DomainError, CoercionFailed, EvaluationFailed) 
 from sympy.ntheory import nextprime, isprime, factorint from sympy.utilities import subsets 
 from math import ceil as _ceil, log as _log 
 from sympy.core.compatibility import range 
 
 def dup_trial_division(f, factors, K): """Determine multiplicities of factors using trial division. """ 
 
 
 else: 
 
 
 
 def dmp_trial_division(f, factors, u, K): """Determine multiplicities of factors using trial division. """ 
 
 
 else: 
 
 
 
 def dup_zz_mignotte_bound(f, K): """Mignotte bound for univariate polynomials in `K[x]`. """ a = dup_max_norm(f, K) b = abs(dup_LC(f, K)) n = dup_degree(f) 
 return K.sqrt(K(n + 1))*2**n*a*b 
 
 def dmp_zz_mignotte_bound(f, u, K): """Mignotte bound for multivariate polynomials in `K[X]`. """ 
 
 
 def dup_zz_hensel_step(m, f, g, h, s, t, K): """ One step in Hensel lifting in `Z[x]`. 
 Given positive integer `m` and `Z[x]` polynomials `f`, `g`, `h`, `s` and `t` such that:: 
 f == g*h (mod m) s*g + t*h == 1 (mod m) 
 lc(f) is not a zero divisor (mod m) lc(h) == 1 
 deg(f) == deg(g) + deg(h) deg(s) < deg(h) deg(t) < deg(g) 
 returns polynomials `G`, `H`, `S` and `T`, such that:: 
 f == G*H (mod m**2) S*G + T**H == 1 (mod m**2) 
 References ========== 
 1. [Gathen99]_ 
 """ 
 
 
 
 
 
 
 
 
 
 
 def dup_zz_hensel_lift(p, f, f_list, l, K): """ Multifactor Hensel lifting in `Z[x]`. 
 Given a prime `p`, polynomial `f` over `Z[x]` such that `lc(f)` is a unit modulo `p`, monic pair-wise coprime polynomials `f_i` over `Z[x]` satisfying:: 
 f = lc(f) f_1 ... f_r (mod p) 
 and a positive integer `l`, returns a list of monic polynomials `F_1`, `F_2`, ..., `F_r` satisfying:: 
 f = lc(f) F_1 ... F_r (mod p**l) 
 F_i = f_i (mod p), i = 1..r 
 References ========== 
 1. [Gathen99]_ 
 """ 
 
 
 
 
 
 
 
 
 
 + dup_zz_hensel_lift(p, h, f_list[k:], l, K) 
 def _test_pl(fc, q, pl): return True 
 def dup_zz_zassenhaus(f, K): """Factor primitive square-free polynomials in `Z[x]`. """ 
 
 # choose a prime number `p` such that `f` be square free in Z_p # if there are many factors in Z_p, choose among a few different `p` # the one with fewer factors 
 
 
 
 
 
 
 
 # lift the constant coefficient of the product `G` of the factors # in the subset `S`; if it is does not divide `fc`, `G` does # not divide the input polynomial 
 else: 
 
 
 
 
 
 
 
 
 else: 
 
 
 def dup_zz_irreducible_p(f, K): """Test irreducibility using Eisenstein's criterion. """ lc = dup_LC(f, K) tc = dup_TC(f, K) 
 e_fc = dup_content(f[1:], K) 
 if e_fc: e_ff = factorint(int(e_fc)) 
 for p in e_ff.keys(): if (lc % p) and (tc % p**2): return True 
 
 def dup_cyclotomic_p(f, K, irreducible=False): """ Efficiently test if ``f`` is a cyclotomic polnomial. 
 Examples ======== 
 >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) 
 >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(f) False 
 >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(g) True 
 """ except CoercionFailed: return False elif not K.is_ZZ: return False 
 
 
 
 return False 
 
 
 
 
 
 
 return True 
 
 
 return True 
 
 return True 
 
 
 def dup_zz_cyclotomic_poly(n, K): """Efficiently generate n-th cyclotomic polnomial. """ h = [K.one, -K.one] 
 for p, k in factorint(n).items(): h = dup_quo(dup_inflate(h, p, K), h, K) h = dup_inflate(h, p**(k - 1), K) 
 return h 
 
 def _dup_cyclotomic_decompose(n, K): 
 
 
 
 
 def dup_zz_cyclotomic_factor(f, K): """ Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`. 
 Given a univariate polynomial `f` in `Z[x]` returns a list of factors of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for `n >= 1`. Otherwise returns None. 
 Factorization is performed using using cyclotomic decomposition of `f`, which makes this method much faster that any other direct factorization approach (e.g. Zassenhaus's). 
 References ========== 
 1. [Weisstein09]_ 
 """ 
 return None 
 
 
 
 else: 
 
 
 
 def dup_zz_factor_sqf(f, K): """Factor square-free (non-primitive) polyomials in `Z[x]`. """ 
 
 cont, g = -cont, dup_neg(g, K) 
 return cont, [] 
 if dup_zz_irreducible_p(g, K): return cont, [g] 
 
 
 
 
 
 def dup_zz_factor(f, K): """ Factor (non square-free) polynomials in `Z[x]`. 
 Given a univariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: 
 f = content(f) f_1**k_1 ... f_n**k_n 
 The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Zassenhaus algorithm. Trial division is used to recover the multiplicities of factors. 
 The result is returned as a tuple consisting of:: 
 (content(f), [(f_1, k_1), ..., (f_n, k_n)) 
 Consider polynomial `f = 2*x**4 - 2`:: 
 >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) 
 >>> R.dup_zz_factor(2*x**4 - 2) (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)]) 
 In result we got the following factorization:: 
 f = 2 (x - 1) (x + 1) (x**2 + 1) 
 Note that this is a complete factorization over integers, however over Gaussian integers we can factor the last term. 
 By default, polynomials `x**n - 1` and `x**n + 1` are factored using cyclotomic decomposition to speedup computations. To disable this behaviour set cyclotomic=False. 
 References ========== 
 1. [Gathen99]_ 
 """ 
 
 
 
 if dup_zz_irreducible_p(g, K): return cont, [(g, 1)] 
 
 
 
 
 
 def dmp_zz_wang_non_divisors(E, cs, ct, K): """Wang/EEZ: Compute a set of valid divisors. """ 
 
 
 
 
 
 
 def dmp_zz_wang_test_points(f, T, ct, A, u, K): """Wang/EEZ: Test evaluation points for suitability. """ 
 
 
 
 
 
 
 else: 
 
 def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K): """Wang/EEZ: Compute correct leading coefficients. """ 
 
 
 
 
 
 raise ExtraneousFactors # pragma: no cover 
 
 
 else: g = K.gcd(lc, d) d, cc = d//g, lc//g h, cs = dup_mul_ground(h, d, K), cs//d 
 
 
 
 CCC, HHH = [], [] 
 for c, h in zip(CC, HH): CCC.append(dmp_mul_ground(c, cs, v, K)) HHH.append(dmp_mul_ground(h, cs, 0, K)) 
 f = dmp_mul_ground(f, cs**(len(H) - 1), u, K) 
 return f, HHH, CCC 
 
 def dup_zz_diophantine(F, m, p, K): """Wang/EEZ: Solve univariate Diophantine equations. """ 
 
 
 
 
 
 
 else: 
 
 
 
 
 
 
 
 
 
 def dmp_zz_diophantine(F, c, A, d, p, u, K): """Wang/EEZ: Solve multivariate Diophantine equations. """ 
 
 
 else: n = len(A) e = dmp_expand(F, u, K) 
 a, A = A[-1], A[:-1] B, G = [], [] 
 for f in F: B.append(dmp_quo(e, f, u, K)) G.append(dmp_eval_in(f, a, n, u, K)) 
 C = dmp_eval_in(c, a, n, u, K) 
 v = u - 1 
 S = dmp_zz_diophantine(G, C, A, d, p, v, K) S = [ dmp_raise(s, 1, v, K) for s in S ] 
 for s, b in zip(S, B): c = dmp_sub_mul(c, s, b, u, K) 
 c = dmp_ground_trunc(c, p, u, K) 
 m = dmp_nest([K.one, -a], n, K) M = dmp_one(n, K) 
 for k in K.map(range(0, d)): if dmp_zero_p(c, u): break 
 M = dmp_mul(M, m, u, K) C = dmp_diff_eval_in(c, k + 1, a, n, u, K) 
 if not dmp_zero_p(C, v): C = dmp_quo_ground(C, K.factorial(k + 1), v, K) T = dmp_zz_diophantine(G, C, A, d, p, v, K) 
 for i, t in enumerate(T): T[i] = dmp_mul(dmp_raise(t, 1, v, K), M, u, K) 
 for i, (s, t) in enumerate(zip(S, T)): S[i] = dmp_add(s, t, u, K) 
 for t, b in zip(T, B): c = dmp_sub_mul(c, t, b, u, K) 
 c = dmp_ground_trunc(c, p, u, K) 
 S = [ dmp_ground_trunc(s, p, u, K) for s in S ] 
 
 
 def dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K): """Wang/EEZ: Parallel Hensel lifting algorithm. """ 
 
 s = dmp_eval_in(S[0], a, n - i, u - i, K) S.insert(0, dmp_ground_trunc(s, p, v - i, K)) 
 
 
 
 
 
 
 
 
 
 
 
 
 raise ExtraneousFactors # pragma: no cover else: 
 
 def dmp_zz_wang(f, u, K, mod=None, seed=None): """ Factor primitive square-free polynomials in `Z[X]`. 
 Given a multivariate polynomial `f` in `Z[x_1,...,x_n]`, which is primitive and square-free in `x_1`, computes factorization of `f` into irreducibles over integers. 
 The procedure is based on Wang's Enhanced Extended Zassenhaus algorithm. The algorithm works by viewing `f` as a univariate polynomial in `Z[x_2,...,x_n][x_1]`, for which an evaluation mapping is computed:: 
 x_2 -> a_2, ..., x_n -> a_n 
 where `a_i`, for `i = 2, ..., n`, are carefully chosen integers. The mapping is used to transform `f` into a univariate polynomial in `Z[x_1]`, which can be factored efficiently using Zassenhaus algorithm. The last step is to lift univariate factors to obtain true multivariate factors. For this purpose a parallel Hensel lifting procedure is used. 
 The parameter ``seed`` is passed to _randint and can be used to seed randint (when an integer) or (for testing purposes) can be a sequence of numbers. 
 References ========== 
 1. [Wang78]_ 2. [Geddes92]_ 
 """ 
 
 
 
 else: 
 
 
 
 
 
 
 
 
 else: continue 
 
 
 
 if rr != r: # pragma: no cover if rr < r: configs, r = [], rr else: continue else: 
 
 
 else: 
 
 
 s_norm = _s_norm s_arg = i else: 
 
 
 except ExtraneousFactors: # pragma: no cover if query('EEZ_RESTART_IF_NEEDED'): return dmp_zz_wang(orig_f, u, K, mod + 1) else: raise ExtraneousFactors( "we need to restart algorithm with better parameters") 
 
 
 
 
 
 
 def dmp_zz_factor(f, u, K): """ Factor (non square-free) polynomials in `Z[X]`. 
 Given a multivariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: 
 f = content(f) f_1**k_1 ... f_n**k_n 
 The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Enhanced Extended Zassenhaus (EEZ) algorithm. Trial division is used to recover the multiplicities of factors. 
 The result is returned as a tuple consisting of:: 
 (content(f), [(f_1, k_1), ..., (f_n, k_n)) 
 Consider polynomial `f = 2*(x**2 - y**2)`:: 
 >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) 
 >>> R.dmp_zz_factor(2*x**2 - 2*y**2) (2, [(x - y, 1), (x + y, 1)]) 
 In result we got the following factorization:: 
 f = 2 (x - y) (x + y) 
 References ========== 
 1. [Gathen99]_ 
 """ 
 return K.zero, [] 
 
 
 
 
 
 
 
 
 
 def dup_ext_factor(f, K): """Factor univariate polynomials over algebraic number fields. """ n, lc = dup_degree(f), dup_LC(f, K) 
 f = dup_monic(f, K) 
 if n <= 0: return lc, [] if n == 1: return lc, [(f, 1)] 
 f, F = dup_sqf_part(f, K), f s, g, r = dup_sqf_norm(f, K) 
 factors = dup_factor_list_include(r, K.dom) 
 if len(factors) == 1: return lc, [(f, n//dup_degree(f))] 
 H = s*K.unit 
 for i, (factor, _) in enumerate(factors): h = dup_convert(factor, K.dom, K) h, _, g = dup_inner_gcd(h, g, K) h = dup_shift(h, H, K) factors[i] = h 
 factors = dup_trial_division(F, factors, K) return lc, factors 
 
 def dmp_ext_factor(f, u, K): """Factor multivariate polynomials over algebraic number fields. """ if not u: return dup_ext_factor(f, K) 
 lc = dmp_ground_LC(f, u, K) f = dmp_ground_monic(f, u, K) 
 if all(d <= 0 for d in dmp_degree_list(f, u)): return lc, [] 
 f, F = dmp_sqf_part(f, u, K), f s, g, r = dmp_sqf_norm(f, u, K) 
 factors = dmp_factor_list_include(r, u, K.dom) 
 if len(factors) == 1: coeff, factors = lc, [f] else: H = dmp_raise([K.one, s*K.unit], u, 0, K) 
 for i, (factor, _) in enumerate(factors): h = dmp_convert(factor, u, K.dom, K) h, _, g = dmp_inner_gcd(h, g, u, K) h = dmp_compose(h, H, u, K) factors[i] = h 
 return lc, dmp_trial_division(F, factors, u, K) 
 
 def dup_gf_factor(f, K): """Factor univariate polynomials over finite fields. """ f = dup_convert(f, K, K.dom) 
 coeff, factors = gf_factor(f, K.mod, K.dom) 
 for i, (f, k) in enumerate(factors): factors[i] = (dup_convert(f, K.dom, K), k) 
 return K.convert(coeff, K.dom), factors 
 
 def dmp_gf_factor(f, u, K): """Factor multivariate polynomials over finite fields. """ raise NotImplementedError('multivariate polynomials over finite fields') 
 
 def dup_factor_list(f, K0): """Factor polynomials into irreducibles in `K[x]`. """ 
 coeff, factors = dup_gf_factor(f, K0) coeff, factors = dup_ext_factor(f, K0) else: K0_inexact, K0 = K0, K0.get_exact() f = dup_convert(f, K0_inexact, K0) else: 
 
 else: 
 elif K.is_Poly: f, u = dmp_inject(f, 0, K) 
 coeff, factors = dmp_factor_list(f, u, K.dom) 
 for i, (f, k) in enumerate(factors): factors[i] = (dmp_eject(f, u, K), k) 
 coeff = K.convert(coeff, K.dom) else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) 
 
 
 else: for i, (f, k) in enumerate(factors): f = dup_quo_ground(f, denom, K0) f = dup_convert(f, K0, K0_inexact) factors[i] = (f, k) 
 coeff = K0_inexact.convert(coeff, K0) K0 = K0_inexact 
 
 
 
 def dup_factor_list_include(f, K): """Factor polynomials into irreducibles in `K[x]`. """ coeff, factors = dup_factor_list(f, K) 
 if not factors: return [(dup_strip([coeff]), 1)] else: g = dup_mul_ground(factors[0][0], coeff, K) return [(g, factors[0][1])] + factors[1:] 
 
 def dmp_factor_list(f, u, K0): """Factor polynomials into irreducibles in `K[X]`. """ 
 
 if K0.is_FiniteField: # pragma: no cover coeff, factors = dmp_gf_factor(f, u, K0) coeff, factors = dmp_ext_factor(f, u, K0) else: K0_inexact, K0 = K0, K0.get_exact() f = dmp_convert(f, u, K0_inexact, K0) else: 
 K = K0.get_ring() 
 denom, f = dmp_clear_denoms(f, u, K0, K) f = dmp_convert(f, u, K0, K) else: 
 
 elif K.is_Poly: f, v = dmp_inject(f, u, K) 
 coeff, factors = dmp_factor_list(f, v, K.dom) 
 for i, (f, k) in enumerate(factors): factors[i] = (dmp_eject(f, v, K), k) 
 coeff = K.convert(coeff, K.dom) else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) 
 for i, (f, k) in enumerate(factors): factors[i] = (dmp_convert(f, u, K, K0), k) 
 coeff = K0.convert(coeff, K) 
 if K0_inexact is None: coeff = coeff/denom else: for i, (f, k) in enumerate(factors): f = dmp_quo_ground(f, denom, u, K0) f = dmp_convert(f, u, K0, K0_inexact) factors[i] = (f, k) 
 coeff = K0_inexact.convert(coeff, K0) K0 = K0_inexact 
 
 
 
 
 def dmp_factor_list_include(f, u, K): """Factor polynomials into irreducibles in `K[X]`. """ if not u: return dup_factor_list_include(f, K) 
 coeff, factors = dmp_factor_list(f, u, K) 
 if not factors: return [(dmp_ground(coeff, u), 1)] else: g = dmp_mul_ground(factors[0][0], coeff, u, K) return [(g, factors[0][1])] + factors[1:] 
 
 def dup_irreducible_p(f, K): """Returns ``True`` if ``f`` has no factors over its domain. """ return dmp_irreducible_p(f, 0, K) 
 
 def dmp_irreducible_p(f, u, K): """Returns ``True`` if ``f`` has no factors over its domain. """ 
 return True return False else:  |