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]_ """ from sympy.utilities.randtest import _randint randint = _randint(seed) ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K) b = dmp_zz_mignotte_bound(f, u, K) p = K(nextprime(b)) if mod is None: if u == 1: mod = 2 else: mod = 1 history, configs, A, r = set([]), [], [K.zero]*u, None try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) _, H = dup_zz_factor_sqf(s, K) r = len(H) if r == 1: return [f] configs = [(s, cs, E, H, A)] except EvaluationFailed: pass eez_num_configs = query('EEZ_NUMBER_OF_CONFIGS') eez_num_tries = query('EEZ_NUMBER_OF_TRIES') eez_mod_step = query('EEZ_MODULUS_STEP') while len(configs) < eez_num_configs: for _ in xrange(eez_num_tries): A = [ K(randint(-mod, mod)) for _ in xrange(u) ] if tuple(A) not in history: history.add(tuple(A)) else: continue try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) except EvaluationFailed: continue _, H = dup_zz_factor_sqf(s, K) rr = len(H) if r is not None: if rr != r: # pragma: no cover if rr < r: configs, r = [], rr else: continue else: r = rr if r == 1: return [f] configs.append((s, cs, E, H, A)) if len(configs) == eez_num_configs: break else: mod += eez_mod_step s_norm, s_arg, i = None, 0, 0 for s, _, _, _, _ in configs: _s_norm = dup_max_norm(s, K) if s_norm is not None: if _s_norm < s_norm: s_norm = _s_norm s_arg = i else: s_norm = _s_norm i += 1 _, cs, E, H, A = configs[s_arg] orig_f = f try: f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K) factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K) 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") negative, result = 0, [] for f in factors: _, f = dmp_ground_primitive(f, u, K) if K.is_negative(dmp_ground_LC(f, u, K)): f = dmp_neg(f, u, K) result.append(f) return result
def test_pickling_polys_errors(): from sympy.polys.polyerrors import ( ExactQuotientFailed, OperationNotSupported, HeuristicGCDFailed, HomomorphismFailed, IsomorphismFailed, ExtraneousFactors, EvaluationFailed, RefinementFailed, CoercionFailed, NotInvertible, NotReversible, NotAlgebraic, DomainError, PolynomialError, UnificationFailed, GeneratorsError, GeneratorsNeeded, ComputationFailed, UnivariatePolynomialError, MultivariatePolynomialError, PolificationFailed, OptionError, FlagError) x = Symbol('x') # TODO: TypeError: __init__() takes at least 3 arguments (1 given) # for c in (ExactQuotientFailed, ExactQuotientFailed(x, 3*x, ZZ)): # check(c) # TODO: TypeError: can't pickle instancemethod objects # for c in (OperationNotSupported, OperationNotSupported(Poly(x), Poly.gcd)): # check(c) for c in (HeuristicGCDFailed, HeuristicGCDFailed()): check(c) for c in (HomomorphismFailed, HomomorphismFailed()): check(c) for c in (IsomorphismFailed, IsomorphismFailed()): check(c) for c in (ExtraneousFactors, ExtraneousFactors()): check(c) for c in (EvaluationFailed, EvaluationFailed()): check(c) for c in (RefinementFailed, RefinementFailed()): check(c) for c in (CoercionFailed, CoercionFailed()): check(c) for c in (NotInvertible, NotInvertible()): check(c) for c in (NotReversible, NotReversible()): check(c) for c in (NotAlgebraic, NotAlgebraic()): check(c) for c in (DomainError, DomainError()): check(c) for c in (PolynomialError, PolynomialError()): check(c) for c in (UnificationFailed, UnificationFailed()): check(c) for c in (GeneratorsError, GeneratorsError()): check(c) for c in (GeneratorsNeeded, GeneratorsNeeded()): check(c) # TODO: PicklingError: Can't pickle <function <lambda> at 0x38578c0>: it's not found as __main__.<lambda> # for c in (ComputationFailed, ComputationFailed(lambda t: t, 3, None)): # check(c) for c in (UnivariatePolynomialError, UnivariatePolynomialError()): check(c) for c in (MultivariatePolynomialError, MultivariatePolynomialError()): check(c) # TODO: TypeError: __init__() takes at least 3 arguments (1 given) # for c in (PolificationFailed, PolificationFailed({}, x, x, False)): # check(c) for c in (OptionError, OptionError()): check(c) for c in (FlagError, FlagError()): check(c)
def dmp_zz_wang(f, u, K, **args): """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. References ========== .. [Wang78] P. S. Wang, An Improved Multivariate Polynomial Factoring Algorithm, Math. of Computation 32, 1978, pp. 1215--1231 .. [Geddes92] K. Geddes, S. R. Czapor, G. Labahn, Algorithms for Computer Algebra, Springer, 1992, pp. 264--272 """ ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K) b = dmp_zz_mignotte_bound(f, u, K) p = K(nextprime(b)) eez_mod = args.get('mod', None) if eez_mod is None: if u == 1: eez_mod = 2 else: eez_mod = 1 history, configs, A, r = set([]), [], [K.zero] * u, None try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) _, H = dup_zz_factor_sqf(s, K) r = len(H) if r == 1: return [f] bad_points = set([tuple(A)]) configs = [(s, cs, E, H, A)] except EvaluationFailed: pass while len(configs) < EEZ_NUM_OK: for _ in xrange(EEZ_NUM_TRY): A = [K(randint(-eez_mod, eez_mod)) for _ in xrange(u)] if tuple(A) not in history: history.add(tuple(A)) else: continue try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) except EvaluationFailed: continue _, H = dup_zz_factor_sqf(s, K) rr = len(H) if r is not None: if rr != r: # pragma: no cover if rr < r: configs, r = [], rr else: continue else: r = rr if r == 1: return [f] configs.append((s, cs, E, H, A)) if len(configs) == EEZ_NUM_OK: break else: eez_mod += EEZ_MOD_STEP s_norm, s_arg, i = None, 0, 0 for s, _, _, _, _ in configs: _s_norm = dup_max_norm(s, K) if s_norm is not None: if _s_norm < s_norm: s_norm = _s_norm s_arg = i else: s_norm = _s_norm i += 1 _, cs, E, H, A = configs[s_arg] try: f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K) factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K) except ExtraneousFactors: # pragma: no cover if args.get('restart', True): return dmp_zz_wang(f, u, K, mod=eez_mod + 1) else: raise ExtraneousFactors( "we need to restart algorithm with better parameters") negative, result = 0, [] for f in factors: _, f = dmp_ground_primitive(f, u, K) if K.is_negative(dmp_ground_LC(f, u, K)): f = dmp_neg(f, u, K) result.append(f) return result