[docs]defdup_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]_ """lc_f,tc_f=dup_LC(f,K),dup_TC(f,K)ifdup_degree(f)<=0:returnNoneiflc_f!=1ortc_fnotin[-1,1]:returnNoneifany(bool(cf)forcfinf[1:-1]):returnNonen=dup_degree(f)F=_dup_cyclotomic_decompose(n,K)ifnotK.is_one(tc_f):returnFelse:H=[]forhin_dup_cyclotomic_decompose(2*n,K):ifhnotinF:H.append(h)returnH

[docs]defdmp_zz_wang_non_divisors(E,cs,ct,K):"""Wang/EEZ: Compute a set of valid divisors. """result=[cs*ct]forqinE:q=abs(q)forrinreversed(result):whiler!=1:r=K.gcd(r,q)q=q//rifK.is_one(q):returnNoneresult.append(q)returnresult[1:]

[docs]defdmp_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]_ """fromsympy.utilities.randtestimport_randintrandint=_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))ifmodisNone:ifu==1:mod=2else:mod=1history,configs,A,r=set([]),[],[K.zero]*u,Nonetry:cs,s,E=dmp_zz_wang_test_points(f,T,ct,A,u,K)_,H=dup_zz_factor_sqf(s,K)r=len(H)ifr==1:return[f]configs=[(s,cs,E,H,A)]exceptEvaluationFailed:passeez_num_configs=query('EEZ_NUMBER_OF_CONFIGS')eez_num_tries=query('EEZ_NUMBER_OF_TRIES')eez_mod_step=query('EEZ_MODULUS_STEP')whilelen(configs)<eez_num_configs:for_inxrange(eez_num_tries):A=[K(randint(-mod,mod))for_inxrange(u)]iftuple(A)notinhistory:history.add(tuple(A))else:continuetry:cs,s,E=dmp_zz_wang_test_points(f,T,ct,A,u,K)exceptEvaluationFailed:continue_,H=dup_zz_factor_sqf(s,K)rr=len(H)ifrisnotNone:ifrr!=r:# pragma: no coverifrr<r:configs,r=[],rrelse:continueelse:r=rrifr==1:return[f]configs.append((s,cs,E,H,A))iflen(configs)==eez_num_configs:breakelse:mod+=eez_mod_steps_norm,s_arg,i=None,0,0fors,_,_,_,_inconfigs:_s_norm=dup_max_norm(s,K)ifs_normisnotNone:if_s_norm<s_norm:s_norm=_s_norms_arg=ielse:s_norm=_s_normi+=1_,cs,E,H,A=configs[s_arg]orig_f=ftry: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)exceptExtraneousFactors:# pragma: no coverifquery('EEZ_RESTART_IF_NEEDED'):returndmp_zz_wang(orig_f,u,K,mod+1)else:raiseExtraneousFactors("we need to restart algorithm with better parameters")negative,result=0,[]forfinfactors:_,f=dmp_ground_primitive(f,u,K)ifK.is_negative(dmp_ground_LC(f,u,K)):f=dmp_neg(f,u,K)result.append(f)returnresult

defdmp_gf_factor(f,u,K):"""Factor multivariate polynomials over finite fields. """raiseDomainError('multivariate polynomials over %s'%K)@cythonized("i,k,u")defdup_factor_list(f,K0):"""Factor polynomials into irreducibles in `K[x]`. """j,f=dup_terms_gcd(f,K0)ifnotK0.has_CharacteristicZero:coeff,factors=dup_gf_factor(f,K0)elifK0.is_Algebraic:coeff,factors=dup_ext_factor(f,K0)else:ifnotK0.is_Exact:K0_inexact,K0=K0,K0.get_exact()f=dup_convert(f,K0_inexact,K0)else:K0_inexact=NoneifK0.has_Field:K=K0.get_ring()denom,f=dup_clear_denoms(f,K0,K)f=dup_convert(f,K0,K)else:K=K0ifK.is_ZZ:coeff,factors=dup_zz_factor(f,K)elifK.is_Poly:f,u=dmp_inject(f,0,K)coeff,factors=dmp_factor_list(f,u,K.dom)fori,(f,k)inenumerate(factors):factors[i]=(dmp_eject(f,u,K),k)coeff=K.convert(coeff,K.dom)else:# pragma: no coverraiseDomainError('factorization not supported over %s'%K0)ifK0.has_Field:fori,(f,k)inenumerate(factors):factors[i]=(dup_convert(f,K,K0),k)coeff=K0.convert(coeff,K)denom=K0.convert(denom,K)coeff=K0.quo(coeff,denom)ifK0_inexactisnotNone:fori,(f,k)inenumerate(factors):factors[i]=(dup_convert(f,K0,K0_inexact),k)coeff=K0_inexact.convert(coeff,K0)ifj:factors.insert(0,([K0.one,K0.zero],j))returncoeff,_sort_factors(factors)defdup_factor_list_include(f,K):"""Factor polynomials into irreducibles in `K[x]`. """coeff,factors=dup_factor_list(f,K)ifnotfactors:return[(dup_strip([coeff]),1)]else:g=dup_mul_ground(factors[0][0],coeff,K)return[(g,factors[0][1])]+factors[1:]@cythonized("u,v,i,k")

[docs]defdmp_factor_list(f,u,K0):"""Factor polynomials into irreducibles in `K[X]`. """ifnotu:returndup_factor_list(f,K0)J,f=dmp_terms_gcd(f,u,K0)ifnotK0.has_CharacteristicZero:# pragma: no covercoeff,factors=dmp_gf_factor(f,u,K0)elifK0.is_Algebraic:coeff,factors=dmp_ext_factor(f,u,K0)else:ifnotK0.is_Exact:K0_inexact,K0=K0,K0.get_exact()f=dmp_convert(f,u,K0_inexact,K0)else:K0_inexact=NoneifK0.has_Field:K=K0.get_ring()denom,f=dmp_clear_denoms(f,u,K0,K)f=dmp_convert(f,u,K0,K)else:K=K0ifK.is_ZZ:levels,f,v=dmp_exclude(f,u,K)coeff,factors=dmp_zz_factor(f,v,K)fori,(f,k)inenumerate(factors):factors[i]=(dmp_include(f,levels,v,K),k)elifK.is_Poly:f,v=dmp_inject(f,u,K)coeff,factors=dmp_factor_list(f,v,K.dom)fori,(f,k)inenumerate(factors):factors[i]=(dmp_eject(f,v,K),k)coeff=K.convert(coeff,K.dom)else:# pragma: no coverraiseDomainError('factorization not supported over %s'%K0)ifK0.has_Field:fori,(f,k)inenumerate(factors):factors[i]=(dmp_convert(f,u,K,K0),k)coeff=K0.convert(coeff,K)denom=K0.convert(denom,K)coeff=K0.quo(coeff,denom)ifK0_inexactisnotNone:fori,(f,k)inenumerate(factors):factors[i]=(dmp_convert(f,u,K0,K0_inexact),k)coeff=K0_inexact.convert(coeff,K0)fori,jinenumerate(reversed(J)):ifnotj:continueterm={(0,)*(u-i)+(1,)+(0,)*i:K0.one}factors.insert(0,(dmp_from_dict(term,u,K0),j))returncoeff,_sort_factors(factors)

defdup_irreducible_p(f,K):"""Returns ``True`` if ``f`` has no factors over its domain. """returndmp_irreducible_p(f,0,K)

[docs]defdmp_irreducible_p(f,u,K):"""Returns ``True`` if ``f`` has no factors over its domain. """_,factors=dmp_factor_list(f,u,K)ifnotfactors:returnTrueeliflen(factors)>1:returnFalseelse:_,k=factors[0]returnk==1