Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */13#include "pari.h"14#include "paripriv.h"1516#define DEBUGLEVEL DEBUGLEVEL_factor1718/* x,y two ZX, y non constant. Return q = x/y if y divides x in Z[X] and NULL19* otherwise. If not NULL, B is a t_INT upper bound for ||q||_oo. */20static GEN21ZX_divides_i(GEN x, GEN y, GEN B)22{23long dx, dy, dz, i, j;24pari_sp av;25GEN z,p1,y_lead;2627dy=degpol(y);28dx=degpol(x);29dz=dx-dy; if (dz<0) return NULL;30z=cgetg(dz+3,t_POL); z[1] = x[1];31x += 2; y += 2; z += 2;32y_lead = gel(y,dy);33if (equali1(y_lead)) y_lead = NULL;3435p1 = gel(x,dx);36if (y_lead) {37GEN r;38p1 = dvmdii(p1,y_lead, &r);39if (r != gen_0) return NULL;40}41else p1 = icopy(p1);42gel(z,dz) = p1;43for (i=dx-1; i>=dy; i--)44{45av = avma; p1 = gel(x,i);46for (j=i-dy+1; j<=i && j<=dz; j++)47p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));48if (y_lead) {49GEN r;50p1 = dvmdii(p1,y_lead, &r);51if (r != gen_0) return NULL;52}53if (B && abscmpii(p1, B) > 0) return NULL;54p1 = gerepileuptoint(av, p1);55gel(z,i-dy) = p1;56}57av = avma;58for (; i >= 0; i--)59{60p1 = gel(x,i);61/* we always enter this loop at least once */62for (j=0; j<=i && j<=dz; j++)63p1 = subii(p1, mulii(gel(z,j),gel(y,i-j)));64if (signe(p1)) return NULL;65set_avma(av);66}67return z - 2;68}69static GEN70ZX_divides(GEN x, GEN y) { return ZX_divides_i(x,y,NULL); }7172#if 073/* cf Beauzamy et al: upper bound for74* lc(x) * [2^(5/8) / pi^(3/8)] e^(1/4n) 2^(n/2) sqrt([x]_2)/ n^(3/8)75* where [x]_2 = sqrt(\sum_i=0^n x[i]^2 / binomial(n,i)). One factor has76* all coeffs less than then bound */77static GEN78two_factor_bound(GEN x)79{80long i, j, n = lg(x) - 3;81pari_sp av = avma;82GEN *invbin, c, r = cgetr(3), z;8384x += 2; invbin = (GEN*)new_chunk(n+1);85z = real_1(LOWDEFAULTPREC); /* invbin[i] = 1 / binomial(n, i) */86for (i=0,j=n; j >= i; i++,j--)87{88invbin[i] = invbin[j] = z;89z = divru(mulru(z, i+1), n-i);90}91z = invbin[0]; /* = 1 */92for (i=0; i<=n; i++)93{94c = gel(x,i); if (!signe(c)) continue;95affir(c, r);96z = addrr(z, mulrr(sqrr(r), invbin[i]));97}98z = shiftr(sqrtr(z), n);99z = divrr(z, dbltor(pow((double)n, 0.75)));100z = roundr_safe(sqrtr(z));101z = mulii(z, absi_shallow(gel(x,n)));102return gerepileuptoint(av, shifti(z, 1));103}104#endif105106/* A | S ==> |a_i| <= binom(d-1, i-1) || S ||_2 + binom(d-1, i) lc(S) */107static GEN108Mignotte_bound(GEN S)109{110long i, d = degpol(S);111GEN C, N2, t, binlS, lS = leading_coeff(S), bin = vecbinomial(d-1);112113N2 = sqrtr(RgX_fpnorml2(S,DEFAULTPREC));114binlS = is_pm1(lS)? bin: ZC_Z_mul(bin, lS);115116/* i = 0 */117C = gel(binlS,1);118/* i = d */119t = N2; if (gcmp(C, t) < 0) C = t;120for (i = 1; i < d; i++)121{122t = addri(mulir(gel(bin,i), N2), gel(binlS,i+1));123if (mpcmp(C, t) < 0) C = t;124}125return C;126}127/* A | S ==> |a_i|^2 <= 3^{3/2 + d} / (4 \pi d) [P]_2^2,128* where [P]_2 is Bombieri's 2-norm */129static GEN130Beauzamy_bound(GEN S)131{132const long prec = DEFAULTPREC;133long i, d = degpol(S);134GEN bin, lS, s, C;135bin = vecbinomial(d);136137s = real_0(prec);138for (i=0; i<=d; i++)139{140GEN c = gel(S,i+2);141if (gequal0(c)) continue;142/* s += P_i^2 / binomial(d,i) */143s = addrr(s, divri(itor(sqri(c), prec), gel(bin,i+1)));144}145/* s = [S]_2^2 */146C = powruhalf(utor(3,prec), 3 + 2*d); /* 3^{3/2 + d} */147C = divrr(mulrr(C, s), mulur(4*d, mppi(prec)));148lS = absi_shallow(leading_coeff(S));149return mulir(lS, sqrtr(C));150}151152static GEN153factor_bound(GEN S)154{155pari_sp av = avma;156GEN a = Mignotte_bound(S);157GEN b = Beauzamy_bound(S);158if (DEBUGLEVEL>2)159{160err_printf("Mignotte bound: %Ps\n",a);161err_printf("Beauzamy bound: %Ps\n",b);162}163return gerepileupto(av, ceil_safe(gmin_shallow(a, b)));164}165166/* Naive recombination of modular factors: combine up to maxK modular167* factors, degree <= klim168*169* target = polynomial we want to factor170* famod = array of modular factors. Product should be congruent to171* target/lc(target) modulo p^a172* For true factors: S1,S2 <= p^b, with b <= a and p^(b-a) < 2^31 */173static GEN174cmbf(GEN pol, GEN famod, GEN bound, GEN p, long a, long b,175long klim, long *pmaxK, int *done)176{177long K = 1, cnt = 1, i,j,k, curdeg, lfamod = lg(famod)-1;178ulong spa_b, spa_bs2, Sbound;179GEN lc, lcpol, pa = powiu(p,a), pas2 = shifti(pa,-1);180GEN trace1 = cgetg(lfamod+1, t_VECSMALL);181GEN trace2 = cgetg(lfamod+1, t_VECSMALL);182GEN ind = cgetg(lfamod+1, t_VECSMALL);183GEN deg = cgetg(lfamod+1, t_VECSMALL);184GEN degsofar = cgetg(lfamod+1, t_VECSMALL);185GEN listmod = cgetg(lfamod+1, t_VEC);186GEN fa = cgetg(lfamod+1, t_VEC);187188*pmaxK = cmbf_maxK(lfamod);189lc = absi_shallow(leading_coeff(pol));190if (equali1(lc)) lc = NULL;191lcpol = lc? ZX_Z_mul(pol, lc): pol;192193{194GEN pa_b,pa_bs2,pb, lc2 = lc? sqri(lc): NULL;195196pa_b = powiu(p, a-b); /* < 2^31 */197pa_bs2 = shifti(pa_b,-1);198pb= powiu(p, b);199for (i=1; i <= lfamod; i++)200{201GEN T1,T2, P = gel(famod,i);202long d = degpol(P);203204deg[i] = d; P += 2;205T1 = gel(P,d-1);/* = - S_1 */206T2 = sqri(T1);207if (d > 1) T2 = subii(T2, shifti(gel(P,d-2),1));208T2 = modii(T2, pa); /* = S_2 Newton sum */209if (lc)210{211T1 = Fp_mul(lc, T1, pa);212T2 = Fp_mul(lc2,T2, pa);213}214uel(trace1,i) = itou(diviiround(T1, pb));215uel(trace2,i) = itou(diviiround(T2, pb));216}217spa_b = uel(pa_b,2); /* < 2^31 */218spa_bs2 = uel(pa_bs2,2); /* < 2^31 */219}220degsofar[0] = 0; /* sentinel */221222/* ind runs through strictly increasing sequences of length K,223* 1 <= ind[i] <= lfamod */224nextK:225if (K > *pmaxK || 2*K > lfamod) goto END;226if (DEBUGLEVEL > 3)227err_printf("\n### K = %d, %Ps combinations\n", K,binomial(utoipos(lfamod), K));228setlg(ind, K+1); ind[1] = 1;229Sbound = (ulong) ((K+1)>>1);230i = 1; curdeg = deg[ind[1]];231for(;;)232{ /* try all combinations of K factors */233for (j = i; j < K; j++)234{235degsofar[j] = curdeg;236ind[j+1] = ind[j]+1; curdeg += deg[ind[j+1]];237}238if (curdeg <= klim) /* trial divide */239{240GEN y, q, list;241pari_sp av;242ulong t;243244/* d - 1 test */245for (t=uel(trace1,ind[1]),i=2; i<=K; i++)246t = Fl_add(t, uel(trace1,ind[i]), spa_b);247if (t > spa_bs2) t = spa_b - t;248if (t > Sbound)249{250if (DEBUGLEVEL>6) err_printf(".");251goto NEXT;252}253/* d - 2 test */254for (t=uel(trace2,ind[1]),i=2; i<=K; i++)255t = Fl_add(t, uel(trace2,ind[i]), spa_b);256if (t > spa_bs2) t = spa_b - t;257if (t > Sbound)258{259if (DEBUGLEVEL>6) err_printf("|");260goto NEXT;261}262263av = avma;264/* check trailing coeff */265y = lc;266for (i=1; i<=K; i++)267{268GEN q = constant_coeff(gel(famod,ind[i]));269if (y) q = mulii(y, q);270y = centermodii(q, pa, pas2);271}272if (!signe(y) || !dvdii(constant_coeff(lcpol), y))273{274if (DEBUGLEVEL>3) err_printf("T");275set_avma(av); goto NEXT;276}277y = lc; /* full computation */278for (i=1; i<=K; i++)279{280GEN q = gel(famod,ind[i]);281if (y) q = gmul(y, q);282y = centermod_i(q, pa, pas2);283}284285/* y is the candidate factor */286if (! (q = ZX_divides_i(lcpol,y,bound)) )287{288if (DEBUGLEVEL>3) err_printf("*");289set_avma(av); goto NEXT;290}291/* found a factor */292list = cgetg(K+1, t_VEC);293gel(listmod,cnt) = list;294for (i=1; i<=K; i++) list[i] = famod[ind[i]];295296y = Q_primpart(y);297gel(fa,cnt++) = y;298/* fix up pol */299pol = q;300if (lc) pol = Q_div_to_int(pol, leading_coeff(y));301for (i=j=k=1; i <= lfamod; i++)302{ /* remove used factors */303if (j <= K && i == ind[j]) j++;304else305{306gel(famod,k) = gel(famod,i);307uel(trace1,k) = uel(trace1,i);308uel(trace2,k) = uel(trace2,i);309deg[k] = deg[i]; k++;310}311}312lfamod -= K;313*pmaxK = cmbf_maxK(lfamod);314if (lfamod < 2*K) goto END;315i = 1; curdeg = deg[ind[1]];316bound = factor_bound(pol);317if (lc) lc = absi_shallow(leading_coeff(pol));318lcpol = lc? ZX_Z_mul(pol, lc): pol;319if (DEBUGLEVEL>3)320err_printf("\nfound factor %Ps\nremaining modular factor(s): %ld\n",321y, lfamod);322continue;323}324325NEXT:326for (i = K+1;;)327{328if (--i == 0) { K++; goto nextK; }329if (++ind[i] <= lfamod - K + i)330{331curdeg = degsofar[i-1] + deg[ind[i]];332if (curdeg <= klim) break;333}334}335}336END:337*done = 1;338if (degpol(pol) > 0)339{ /* leftover factor */340if (signe(leading_coeff(pol)) < 0) pol = ZX_neg(pol);341if (lfamod >= 2*K) *done = 0;342343setlg(famod, lfamod+1);344gel(listmod,cnt) = leafcopy(famod);345gel(fa,cnt++) = pol;346}347if (DEBUGLEVEL>6) err_printf("\n");348setlg(listmod, cnt);349setlg(fa, cnt); return mkvec2(fa, listmod);350}351352/* recombination of modular factors: van Hoeij's algorithm */353354/* Q in Z[X], return Q(2^n) */355static GEN356shifteval(GEN Q, long n)357{358pari_sp av = avma;359long i, l = lg(Q);360GEN s;361362if (!signe(Q)) return gen_0;363s = gel(Q,l-1);364for (i = l-2; i > 1; i--)365{366s = addii(gel(Q,i), shifti(s, n));367if (gc_needed(av,1)) s = gerepileuptoint(av, s);368}369return s;370}371372/* return integer y such that all |a| <= y if P(a) = 0 */373static GEN374root_bound(GEN P0)375{376GEN Q = leafcopy(P0), lP = absi_shallow(leading_coeff(Q)), x,y,z;377long k, d = degpol(Q);378379/* P0 = lP x^d + Q, deg Q < d */380Q = normalizepol_lg(Q, d+2);381for (k=lg(Q)-1; k>1; k--) gel(Q,k) = absi_shallow(gel(Q,k));382k = (long)(fujiwara_bound(P0));383for ( ; k >= 0; k--)384{385pari_sp av = avma;386/* y = 2^k; Q(y) >= lP y^d ? */387if (cmpii(shifteval(Q,k), shifti(lP, d*k)) >= 0) break;388set_avma(av);389}390if (k < 0) k = 0;391y = int2n(k+1);392if (d > 2000) return y; /* likely to be expensive, don't bother */393x = int2n(k);394for(k=0; ; k++)395{396z = shifti(addii(x,y), -1);397if (equalii(x,z) || k > 5) break;398if (cmpii(ZX_Z_eval(Q,z), mulii(lP, powiu(z, d))) < 0)399y = z;400else401x = z;402}403return y;404}405406GEN407chk_factors_get(GEN lt, GEN famod, GEN c, GEN T, GEN N)408{409long i = 1, j, l = lg(famod);410GEN V = cgetg(l, t_VEC);411for (j = 1; j < l; j++)412if (signe(gel(c,j))) gel(V,i++) = gel(famod,j);413if (lt && i > 1) gel(V,1) = RgX_Rg_mul(gel(V,1), lt);414setlg(V, i);415return T? FpXQXV_prod(V, T, N): FpXV_prod(V,N);416}417418static GEN419chk_factors(GEN P, GEN M_L, GEN bound, GEN famod, GEN pa)420{421long i, r;422GEN pol = P, list, piv, y, ltpol, lt, paov2;423424piv = ZM_hnf_knapsack(M_L);425if (!piv) return NULL;426if (DEBUGLEVEL>7) err_printf("ZM_hnf_knapsack output:\n%Ps\n",piv);427428r = lg(piv)-1;429list = cgetg(r+1, t_VEC);430lt = absi_shallow(leading_coeff(pol));431if (equali1(lt)) lt = NULL;432ltpol = lt? ZX_Z_mul(pol, lt): pol;433paov2 = shifti(pa,-1);434for (i = 1;;)435{436if (DEBUGLEVEL) err_printf("LLL_cmbf: checking factor %ld\n",i);437y = chk_factors_get(lt, famod, gel(piv,i), NULL, pa);438y = FpX_center_i(y, pa, paov2);439if (! (pol = ZX_divides_i(ltpol,y,bound)) ) return NULL;440if (lt) y = Q_primpart(y);441gel(list,i) = y;442if (++i >= r) break;443444if (lt)445{446pol = ZX_Z_divexact(pol, leading_coeff(y));447lt = absi_shallow(leading_coeff(pol));448ltpol = ZX_Z_mul(pol, lt);449}450else451ltpol = pol;452}453y = Q_primpart(pol);454gel(list,i) = y; return list;455}456457GEN458LLL_check_progress(GEN Bnorm, long n0, GEN m, int final, long *ti_LLL)459{460GEN norm, u;461long i, R;462pari_timer T;463464if (DEBUGLEVEL>2) timer_start(&T);465u = ZM_lll_norms(m, final? 0.999: 0.75, LLL_INPLACE, &norm);466if (DEBUGLEVEL>2) *ti_LLL += timer_delay(&T);467for (R=lg(m)-1; R > 0; R--)468if (cmprr(gel(norm,R), Bnorm) < 0) break;469for (i=1; i<=R; i++) setlg(u[i], n0+1);470if (R <= 1)471{472if (!R) pari_err_BUG("LLL_cmbf [no factor]");473return NULL; /* irreducible */474}475setlg(u, R+1); return u;476}477478static ulong479next2pow(ulong a)480{481ulong b = 1;482while (b < a) b <<= 1;483return b;484}485486/* Recombination phase of Berlekamp-Zassenhaus algorithm using a variant of487* van Hoeij's knapsack488*489* P = squarefree in Z[X].490* famod = array of (lifted) modular factors mod p^a491* bound = Mignotte bound for the size of divisors of P (for the sup norm)492* previously recombined all set of factors with less than rec elts */493static GEN494LLL_cmbf(GEN P, GEN famod, GEN p, GEN pa, GEN bound, long a, long rec)495{496const long N0 = 1; /* # of traces added at each step */497double BitPerFactor = 0.4; /* nb bits in p^(a-b) / modular factor */498long i,j,tmax,n0,C, dP = degpol(P);499double logp = log((double)itos(p)), LOGp2 = M_LN2/logp;500double b0 = log((double)dP*2) / logp, logBr;501GEN lP, Br, Bnorm, Tra, T2, TT, CM_L, m, list, ZERO;502pari_sp av, av2;503long ti_LLL = 0, ti_CF = 0;504505lP = absi_shallow(leading_coeff(P));506if (equali1(lP)) lP = NULL;507Br = root_bound(P);508if (lP) Br = mulii(lP, Br);509logBr = gtodouble(glog(Br, DEFAULTPREC)) / logp;510511n0 = lg(famod) - 1;512C = (long)ceil( sqrt(N0 * n0 / 4.) ); /* > 1 */513Bnorm = dbltor(n0 * (C*C + N0*n0/4.) * 1.00001);514ZERO = zeromat(n0, N0);515516av = avma;517TT = cgetg(n0+1, t_VEC);518Tra = cgetg(n0+1, t_MAT);519for (i=1; i<=n0; i++)520{521TT[i] = 0;522gel(Tra,i) = cgetg(N0+1, t_COL);523}524CM_L = scalarmat_s(C, n0);525/* tmax = current number of traces used (and computed so far) */526for (tmax = 0;; tmax += N0)527{528long b, bmin, bgood, delta, tnew = tmax + N0, r = lg(CM_L)-1;529GEN M_L, q, CM_Lp, oldCM_L;530int first = 1;531pari_timer ti2, TI;532533bmin = (long)ceil(b0 + tnew*logBr);534if (DEBUGLEVEL>2)535err_printf("\nLLL_cmbf: %ld potential factors (tmax = %ld, bmin = %ld)\n",536r, tmax, bmin);537538/* compute Newton sums (possibly relifting first) */539if (a <= bmin)540{541a = (long)ceil(bmin + 3*N0*logBr) + 1; /* enough for 3 more rounds */542a = (long)next2pow((ulong)a);543544pa = powiu(p,a);545famod = ZpX_liftfact(P, famod, pa, p, a);546for (i=1; i<=n0; i++) TT[i] = 0;547}548for (i=1; i<=n0; i++)549{550GEN p1 = gel(Tra,i);551GEN p2 = polsym_gen(gel(famod,i), gel(TT,i), tnew, NULL, pa);552gel(TT,i) = p2;553p2 += 1+tmax; /* ignore traces number 0...tmax */554for (j=1; j<=N0; j++) gel(p1,j) = gel(p2,j);555if (lP)556{ /* make Newton sums integral */557GEN lPpow = powiu(lP, tmax);558for (j=1; j<=N0; j++)559{560lPpow = mulii(lPpow,lP);561gel(p1,j) = mulii(gel(p1,j), lPpow);562}563}564}565566/* compute truncation parameter */567if (DEBUGLEVEL>2) { timer_start(&ti2); timer_start(&TI); }568oldCM_L = CM_L;569av2 = avma;570delta = b = 0; /* -Wall */571AGAIN:572M_L = Q_div_to_int(CM_L, utoipos(C));573T2 = centermod( ZM_mul(Tra, M_L), pa );574if (first)575{ /* initialize lattice, using few p-adic digits for traces */576double t = gexpo(T2) - maxdd(32.0, BitPerFactor*r);577bgood = (long) (t * LOGp2);578b = maxss(bmin, bgood);579delta = a - b;580}581else582{ /* add more p-adic digits and continue reduction */583long b0 = (long)(gexpo(T2) * LOGp2);584if (b0 < b) b = b0;585b = maxss(b-delta, bmin);586if (b - delta/2 < bmin) b = bmin; /* near there. Go all the way */587}588589q = powiu(p, b);590m = vconcat( CM_L, gdivround(T2, q) );591if (first)592{593GEN P1 = scalarmat(powiu(p, a-b), N0);594first = 0;595m = shallowconcat( m, vconcat(ZERO, P1) );596/* [ C M_L 0 ]597* m = [ ] square matrix598* [ T2' p^(a-b) I_N0 ] T2' = Tra * M_L truncated599*/600}601602CM_L = LLL_check_progress(Bnorm, n0, m, b == bmin, /*dbg:*/ &ti_LLL);603if (DEBUGLEVEL>2)604err_printf("LLL_cmbf: (a,b) =%4ld,%4ld; r =%3ld -->%3ld, time = %ld\n",605a,b, lg(m)-1, CM_L? lg(CM_L)-1: 1, timer_delay(&TI));606if (!CM_L) { list = mkvec(P); break; }607if (b > bmin)608{609CM_L = gerepilecopy(av2, CM_L);610goto AGAIN;611}612if (DEBUGLEVEL>2) timer_printf(&ti2, "for this block of traces");613614i = lg(CM_L) - 1;615if (i == r && ZM_equal(CM_L, oldCM_L))616{617CM_L = oldCM_L;618set_avma(av2); continue;619}620621CM_Lp = FpM_image(CM_L, utoipos(27449)); /* inexpensive test */622if (lg(CM_Lp) != lg(CM_L))623{624if (DEBUGLEVEL>2) err_printf("LLL_cmbf: rank decrease\n");625CM_L = ZM_hnf(CM_L);626}627628if (i <= r && i*rec < n0)629{630pari_timer ti;631if (DEBUGLEVEL>2) timer_start(&ti);632list = chk_factors(P, Q_div_to_int(CM_L,utoipos(C)), bound, famod, pa);633if (DEBUGLEVEL>2) ti_CF += timer_delay(&ti);634if (list) break;635if (DEBUGLEVEL>2) err_printf("LLL_cmbf: chk_factors failed");636}637CM_L = gerepilecopy(av2, CM_L);638if (gc_needed(av,1))639{640if(DEBUGMEM>1) pari_warn(warnmem,"LLL_cmbf");641gerepileall(av, 5, &CM_L, &TT, &Tra, &famod, &pa);642}643}644if (DEBUGLEVEL>2)645err_printf("* Time LLL: %ld\n* Time Check Factor: %ld\n",ti_LLL,ti_CF);646return list;647}648649/* Find a,b minimal such that A < q^a, B < q^b, 1 << q^(a-b) < 2^31 */650static int651cmbf_precs(GEN q, GEN A, GEN B, long *pta, long *ptb, GEN *qa, GEN *qb)652{653long a,b,amin,d = (long)(31 * M_LN2/gtodouble(glog(q,DEFAULTPREC)) - 1e-5);654int fl = 0;655656b = logintall(B, q, qb) + 1;657*qb = mulii(*qb, q);658amin = b + d;659if (gcmp(powiu(q, amin), A) <= 0)660{661a = logintall(A, q, qa) + 1;662*qa = mulii(*qa, q);663b = a - d; *qb = powiu(q, b);664}665else666{ /* not enough room */667a = amin; *qa = powiu(q, a);668fl = 1;669}670if (DEBUGLEVEL > 3) {671err_printf("S_2 bound: %Ps^%ld\n", q,b);672err_printf("coeff bound: %Ps^%ld\n", q,a);673}674*pta = a;675*ptb = b; return fl;676}677678/* use van Hoeij's knapsack algorithm */679static GEN680combine_factors(GEN target, GEN famod, GEN p, long klim)681{682GEN la, B, A, res, L, pa, pb, listmod;683long a,b, l, maxK, n = degpol(target);684int done;685pari_timer T;686687A = factor_bound(target);688689la = absi_shallow(leading_coeff(target));690B = mului(n, sqri(mulii(la, root_bound(target)))); /* = bound for S_2 */691692(void)cmbf_precs(p, A, B, &a, &b, &pa, &pb);693694if (DEBUGLEVEL>2) timer_start(&T);695famod = ZpX_liftfact(target, famod, pa, p, a);696if (DEBUGLEVEL>2) timer_printf(&T, "Hensel lift (mod %Ps^%ld)", p,a);697L = cmbf(target, famod, A, p, a, b, klim, &maxK, &done);698if (DEBUGLEVEL>2) timer_printf(&T, "Naive recombination");699700res = gel(L,1);701listmod = gel(L,2); l = lg(listmod)-1;702famod = gel(listmod,l);703if (maxK > 0 && lg(famod)-1 > 2*maxK)704{705if (l!=1) A = factor_bound(gel(res,l));706if (DEBUGLEVEL > 4) err_printf("last factor still to be checked\n");707L = LLL_cmbf(gel(res,l), famod, p, pa, A, a, maxK);708if (DEBUGLEVEL>2) timer_printf(&T,"Knapsack");709/* remove last elt, possibly unfactored. Add all new ones. */710setlg(res, l); res = shallowconcat(res, L);711}712return res;713}714715/* Assume 'a' a squarefree ZX; return 0 if no root (fl=1) / irreducible (fl=0).716* Otherwise return prime p such that a mod p has fewest roots / factors */717static ulong718pick_prime(GEN a, long fl, pari_timer *T)719{720pari_sp av = avma, av1;721const long MAXNP = 7, da = degpol(a);722long nmax = da+1, np;723ulong chosenp = 0;724GEN lead = gel(a,da+2);725forprime_t S;726if (equali1(lead)) lead = NULL;727u_forprime_init(&S, 2, ULONG_MAX);728av1 = avma;729for (np = 0; np < MAXNP; set_avma(av1))730{731ulong p = u_forprime_next(&S);732long nfacp;733GEN z;734735if (!p) pari_err_OVERFLOW("DDF [out of small primes]");736if (lead && !umodiu(lead,p)) continue;737z = ZX_to_Flx(a, p);738if (!Flx_is_squarefree(z, p)) continue;739740if (fl)741{742nfacp = Flx_nbroots(z, p);743if (!nfacp) { chosenp = 0; break; } /* no root */744}745else746{747nfacp = Flx_nbfact(z, p);748if (nfacp == 1) { chosenp = 0; break; } /* irreducible */749}750if (DEBUGLEVEL>4)751err_printf("...tried prime %3lu (%-3ld %s). Time = %ld\n",752p, nfacp, fl? "roots": "factors", timer_delay(T));753if (nfacp < nmax)754{755nmax = nfacp; chosenp = p;756if (da > 100 && nmax < 5) break; /* large degree, few factors. Enough */757}758np++;759}760return gc_ulong(av, chosenp);761}762763/* Assume A a squarefree ZX; return the vector of its rational roots */764static GEN765DDF_roots(GEN A)766{767GEN p, lc, lcpol, z, pe, pes2, bound;768long i, m, e, lz;769ulong pp;770pari_sp av;771pari_timer T;772773if (DEBUGLEVEL>2) timer_start(&T);774pp = pick_prime(A, 1, &T);775if (!pp) return cgetg(1,t_VEC); /* no root */776p = utoipos(pp);777lc = leading_coeff(A);778if (is_pm1(lc))779{ lc = NULL; lcpol = A; }780else781{ lc = absi_shallow(lc); lcpol = ZX_Z_mul(A, lc); }782bound = root_bound(A); if (lc) bound = mulii(lc, bound);783e = logintall(addiu(shifti(bound, 1), 1), p, &pe) + 1;784pe = mulii(pe, p);785pes2 = shifti(pe, -1);786if (DEBUGLEVEL>2) timer_printf(&T, "Root bound");787av = avma;788z = ZpX_roots(A, p, e); lz = lg(z);789z = deg1_from_roots(z, varn(A));790if (DEBUGLEVEL>2) timer_printf(&T, "Hensel lift (mod %lu^%ld)", pp,e);791for (m=1, i=1; i < lz; i++)792{793GEN q, r, y = gel(z,i);794if (lc) y = ZX_Z_mul(y, lc);795y = centermod_i(y, pe, pes2);796if (! (q = ZX_divides(lcpol, y)) ) continue;797798lcpol = q;799r = negi( constant_coeff(y) );800if (lc) {801r = gdiv(r,lc);802lcpol = Q_primpart(lcpol);803lc = absi_shallow( leading_coeff(lcpol) );804if (is_pm1(lc)) lc = NULL; else lcpol = ZX_Z_mul(lcpol, lc);805}806gel(z,m++) = r;807if (gc_needed(av,2))808{809if (DEBUGMEM>1) pari_warn(warnmem,"DDF_roots, m = %ld", m);810gerepileall(av, lc? 3:2, &z, &lcpol, &lc);811}812}813if (DEBUGLEVEL>2) timer_printf(&T, "Recombination");814z[0] = evaltyp(t_VEC) | evallg(m); return z;815}816817/* Assume a squarefree ZX, deg(a) > 0, return rational factors.818* In fact, a(0) != 0 but we don't use this */819static GEN820DDF(GEN a)821{822GEN ap, prime, famod, z;823long ti = 0;824ulong p = 0;825pari_sp av = avma;826pari_timer T, T2;827828if (DEBUGLEVEL>2) { timer_start(&T); timer_start(&T2); }829p = pick_prime(a, 0, &T2);830if (!p) return mkvec(a);831prime = utoipos(p);832ap = Flx_normalize(ZX_to_Flx(a, p), p);833famod = gel(Flx_factor(ap, p), 1);834if (DEBUGLEVEL>2)835{836if (DEBUGLEVEL>4) timer_printf(&T2, "splitting mod p = %lu", p);837ti = timer_delay(&T);838err_printf("Time setup: %ld\n", ti);839}840z = combine_factors(a, FlxV_to_ZXV(famod), prime, degpol(a)-1);841if (DEBUGLEVEL>2)842err_printf("Total Time: %ld\n===========\n", ti + timer_delay(&T));843return gerepilecopy(av, z);844}845846/* Distinct Degree Factorization (deflating first)847* Assume x squarefree, degree(x) > 0, x(0) != 0 */848GEN849ZX_DDF(GEN x)850{851GEN L;852long m;853x = ZX_deflate_max(x, &m);854L = DDF(x);855if (m > 1)856{857GEN e, v, fa = factoru(m);858long i,j,k, l;859860e = gel(fa,2); k = 0;861fa= gel(fa,1); l = lg(fa);862for (i=1; i<l; i++) k += e[i];863v = cgetg(k+1, t_VECSMALL); k = 1;864for (i=1; i<l; i++)865for (j=1; j<=e[i]; j++) v[k++] = fa[i];866for (k--; k; k--)867{868GEN L2 = cgetg(1,t_VEC);869for (i=1; i < lg(L); i++)870L2 = shallowconcat(L2, DDF(RgX_inflate(gel(L,i), v[k])));871L = L2;872}873}874return L;875}876877/* SquareFree Factorization. f = prod P^e, all e distinct, in Z[X] (char 0878* would be enough, if ZX_gcd --> ggcd). Return (P), set *ex = (e) */879GEN880ZX_squff(GEN f, GEN *ex)881{882GEN T, V, P, e;883long i, k, val = ZX_valrem(f, &f), n = 2 + degpol(f);884885if (signe(leading_coeff(f)) < 0) f = ZX_neg(f);886e = cgetg(n,t_VECSMALL);887P = cgetg(n,t_COL);888T = ZX_gcd_all(f, ZX_deriv(f), &V);889for (k = i = 1;; k++)890{891GEN W = ZX_gcd_all(T,V, &T); /* V and W are squarefree */892long dW = degpol(W), dV = degpol(V);893/* f = prod_i T_i^{e_i}894* W = prod_{i: e_i > k} T_i,895* V = prod_{i: e_i >= k} T_i,896* T = prod_{i: e_i > k} T_i^{e_i - k} */897if (!dW)898{899if (dV) { gel(P,i) = Q_primpart(V); e[i] = k; i++; }900break;901}902if (dW == dV)903{904GEN U;905while ( (U = ZX_divides(T, V)) ) { k++; T = U; }906}907else908{909gel(P,i) = Q_primpart(RgX_div(V,W));910e[i] = k; i++; V = W;911}912}913if (val) { gel(P,i) = pol_x(varn(f)); e[i] = val; i++;}914setlg(P,i);915setlg(e,i); *ex = e; return P;916}917918static GEN919fact_from_DDF(GEN fa, GEN e, long n)920{921GEN v,w, y = cgetg(3, t_MAT);922long i,j,k, l = lg(fa);923924v = cgetg(n+1,t_COL); gel(y,1) = v;925w = cgetg(n+1,t_COL); gel(y,2) = w;926for (k=i=1; i<l; i++)927{928GEN L = gel(fa,i), ex = utoipos(e[i]);929long J = lg(L);930for (j=1; j<J; j++,k++)931{932gel(v,k) = gcopy(gel(L,j));933gel(w,k) = ex;934}935}936return y;937}938939/* Factor x in Z[t] */940static GEN941ZX_factor_i(GEN x)942{943GEN fa,ex,y;944long n,i,l;945946if (!signe(x)) return prime_fact(x);947fa = ZX_squff(x, &ex);948l = lg(fa); n = 0;949for (i=1; i<l; i++)950{951gel(fa,i) = ZX_DDF(gel(fa,i));952n += lg(gel(fa,i))-1;953}954y = fact_from_DDF(fa,ex,n);955return sort_factor_pol(y, cmpii);956}957GEN958ZX_factor(GEN x)959{960pari_sp av = avma;961return gerepileupto(av, ZX_factor_i(x));962}963GEN964QX_factor(GEN x)965{966pari_sp av = avma;967return gerepileupto(av, ZX_factor_i(Q_primpart(x)));968}969970long971ZX_is_irred(GEN x)972{973pari_sp av = avma;974long l = lg(x);975GEN y;976if (l <= 3) return 0; /* degree < 1 */977if (l == 4) return 1; /* degree 1 */978if (ZX_val(x)) return 0;979if (!ZX_is_squarefree(x)) return 0;980y = ZX_DDF(x); set_avma(av);981return (lg(y) == 2);982}983984GEN985nfrootsQ(GEN x)986{987pari_sp av = avma;988GEN z;989long val;990991if (typ(x)!=t_POL) pari_err_TYPE("nfrootsQ",x);992if (!signe(x)) pari_err_ROOTS0("nfrootsQ");993x = Q_primpart(x);994RgX_check_ZX(x,"nfrootsQ");995val = ZX_valrem(x, &x);996z = DDF_roots( ZX_radical(x) );997if (val) z = vec_append(z, gen_0);998return gerepileupto(av, sort(z));999}10001001/************************************************************************1002* GCD OVER Z[X] / Q[X] *1003************************************************************************/1004int1005ZX_is_squarefree(GEN x)1006{1007pari_sp av = avma;1008GEN d;1009long m;1010if (lg(x) == 2) return 0;1011m = ZX_deflate_order(x);1012if (m > 1)1013{1014if (!signe(gel(x,2))) return 0;1015x = RgX_deflate(x, m);1016}1017d = ZX_gcd(x,ZX_deriv(x));1018return gc_bool(av, lg(d) == 3);1019}10201021static int1022ZX_gcd_filter(GEN *pt_A, GEN *pt_P)1023{1024GEN A = *pt_A, P = *pt_P;1025long i, j, l = lg(A), n = 1, d = degpol(gel(A,1));1026GEN B, Q;1027for (i=2; i<l; i++)1028{1029long di = degpol(gel(A,i));1030if (di==d) n++;1031else if (d > di)1032{ n=1; d = di; }1033}1034if (n == l-1)1035return 0;1036B = cgetg(n+1, t_VEC);1037Q = cgetg(n+1, typ(P));1038for (i=1, j=1; i<l; i++)1039{1040if (degpol(gel(A,i))==d)1041{1042gel(B,j) = gel(A,i);1043Q[j] = P[i];1044j++;1045}1046}1047*pt_A = B; *pt_P = Q; return 1;1048}10491050static GEN1051ZX_gcd_Flx(GEN a, GEN b, ulong g, ulong p)1052{1053GEN H = Flx_gcd(a, b, p);1054if (!g)1055return Flx_normalize(H, p);1056else1057{1058ulong t = Fl_mul(g, Fl_inv(Flx_lead(H), p), p);1059return Flx_Fl_mul(H, t, p);1060}1061}10621063static GEN1064ZX_gcd_slice(GEN A, GEN B, GEN g, GEN P, GEN *mod)1065{1066pari_sp av = avma;1067long i, n = lg(P)-1;1068GEN H, T;1069if (n == 1)1070{1071ulong p = uel(P,1), gp = g ? umodiu(g, p): 0;1072GEN a = ZX_to_Flx(A, p), b = ZX_to_Flx(B, p);1073GEN Hp = ZX_gcd_Flx(a, b, gp, p);1074H = gerepileupto(av, Flx_to_ZX(Hp));1075*mod = utoi(p);1076return H;1077}1078T = ZV_producttree(P);1079A = ZX_nv_mod_tree(A, P, T);1080B = ZX_nv_mod_tree(B, P, T);1081g = g ? Z_ZV_mod_tree(g, P, T): NULL;1082H = cgetg(n+1, t_VEC);1083for(i=1; i <= n; i++)1084{1085ulong p = P[i];1086GEN a = gel(A,i), b = gel(B,i);1087gel(H,i) = ZX_gcd_Flx(a, b, g? g[i]: 0, p);1088}1089if (ZX_gcd_filter(&H, &P))1090T = ZV_producttree(P);1091H = nxV_chinese_center_tree(H, P, T, ZV_chinesetree(P, T));1092*mod = gmael(T, lg(T)-1, 1);1093gerepileall(av, 2, &H, mod);1094return H;1095}10961097GEN1098ZX_gcd_worker(GEN P, GEN A, GEN B, GEN g)1099{1100GEN V = cgetg(3, t_VEC);1101gel(V,1) = ZX_gcd_slice(A, B, equali1(g)? NULL: g , P, &gel(V,2));1102return V;1103}11041105static GEN1106ZX_gcd_chinese(GEN A, GEN P, GEN *mod)1107{1108ZX_gcd_filter(&A, &P);1109return nxV_chinese_center(A, P, mod);1110}11111112GEN1113ZX_gcd_all(GEN A, GEN B, GEN *Anew)1114{1115pari_sp av = avma;1116long k, valH, valA, valB, vA = varn(A), dA = degpol(A), dB = degpol(B);1117GEN worker, c, cA, cB, g, Ag, Bg, H = NULL, mod = gen_1, R;1118GEN Ap, Bp, Hp;1119forprime_t S;1120ulong pp;1121if (dA < 0) { if (Anew) *Anew = pol_0(vA); return ZX_copy(B); }1122if (dB < 0) { if (Anew) *Anew = pol_1(vA); return ZX_copy(A); }1123A = Q_primitive_part(A, &cA);1124B = Q_primitive_part(B, &cB);1125valA = ZX_valrem(A, &A); dA -= valA;1126valB = ZX_valrem(B, &B); dB -= valB;1127valH = minss(valA, valB);1128valA -= valH; /* valuation(Anew) */1129c = (cA && cB)? gcdii(cA, cB): NULL; /* content(gcd) */1130if (!dA || !dB)1131{1132if (Anew) *Anew = RgX_shift_shallow(A, valA);1133return monomial(c? c: gen_1, valH, vA);1134}1135g = gcdii(leading_coeff(A), leading_coeff(B)); /* multiple of lead(gcd) */1136if (is_pm1(g)) {1137g = NULL;1138Ag = A;1139Bg = B;1140} else {1141Ag = ZX_Z_mul(A,g);1142Bg = ZX_Z_mul(B,g);1143}1144init_modular_big(&S);1145do {1146pp = u_forprime_next(&S);1147Ap = ZX_to_Flx(Ag, pp);1148Bp = ZX_to_Flx(Bg, pp);1149} while (degpol(Ap) != dA || degpol(Bp) != dB);1150if (degpol(Flx_gcd(Ap, Bp, pp)) == 0)1151{1152if (Anew) *Anew = RgX_shift_shallow(A, valA);1153return monomial(c? c: gen_1, valH, vA);1154}1155worker = snm_closure(is_entry("_ZX_gcd_worker"), mkvec3(A, B, g? g: gen_1));1156av = avma;1157for (k = 1; ;k *= 2)1158{1159gen_inccrt_i("ZX_gcd", worker, g, (k+1)>>1, 0, &S, &H, &mod, ZX_gcd_chinese, NULL);1160gerepileall(av, 2, &H, &mod);1161Hp = ZX_to_Flx(H, pp);1162if (lgpol(Flx_rem(Ap, Hp, pp)) || lgpol(Flx_rem(Bp, Hp, pp))) continue;1163if (!ZX_divides(Bg, H)) continue;1164R = ZX_divides(Ag, H);1165if (R) break;1166}1167/* lead(H) = g */1168if (g) H = Q_primpart(H);1169if (c) H = ZX_Z_mul(H,c);1170if (DEBUGLEVEL>5) err_printf("done\n");1171if (Anew) *Anew = RgX_shift_shallow(R, valA);1172return valH? RgX_shift_shallow(H, valH): H;1173}11741175#if 01176/* ceil( || p ||_oo / lc(p) ) */1177static GEN1178maxnorm(GEN p)1179{1180long i, n = degpol(p), av = avma;1181GEN x, m = gen_0;11821183p += 2;1184for (i=0; i<n; i++)1185{1186x = gel(p,i);1187if (abscmpii(x,m) > 0) m = x;1188}1189m = divii(m, gel(p,n));1190return gerepileuptoint(av, addiu(absi_shallow(m),1));1191}1192#endif11931194GEN1195ZX_gcd(GEN A, GEN B)1196{1197pari_sp av = avma;1198return gerepilecopy(av, ZX_gcd_all(A,B,NULL));1199}12001201GEN1202ZX_radical(GEN A) { GEN B; (void)ZX_gcd_all(A,ZX_deriv(A),&B); return B; }12031204static GEN1205_gcd(GEN a, GEN b)1206{1207if (!a) a = gen_1;1208if (!b) b = gen_1;1209return Q_gcd(a,b);1210}1211/* A0 and B0 in Q[X] */1212GEN1213QX_gcd(GEN A0, GEN B0)1214{1215GEN a, b, D;1216pari_sp av = avma, av2;12171218D = ZX_gcd(Q_primitive_part(A0, &a), Q_primitive_part(B0, &b));1219av2 = avma; a = _gcd(a,b);1220if (isint1(a)) set_avma(av2); else D = ZX_Q_mul(D, a);1221return gerepileupto(av, D);1222}12231224/*****************************************************************************1225* Variants of the Bradford-Davenport algorithm: look for cyclotomic *1226* factors, and decide whether a ZX is cyclotomic or a product of cyclotomic *1227*****************************************************************************/1228/* f of degree 1, return a cyclotomic factor (Phi_1 or Phi_2) or NULL */1229static GEN1230BD_deg1(GEN f)1231{1232GEN a = gel(f,3), b = gel(f,2); /* f = ax + b */1233if (!absequalii(a,b)) return NULL;1234return polcyclo((signe(a) == signe(b))? 2: 1, varn(f));1235}12361237/* f a squarefree ZX; not divisible by any Phi_n, n even */1238static GEN1239BD_odd(GEN f)1240{1241while(degpol(f) > 1)1242{1243GEN f1 = ZX_graeffe(f); /* contain all cyclotomic divisors of f */1244if (ZX_equal(f1, f)) return f; /* product of cyclotomics */1245f = ZX_gcd(f, f1);1246}1247if (degpol(f) == 1) return BD_deg1(f);1248return NULL; /* no cyclotomic divisor */1249}12501251static GEN1252myconcat(GEN v, GEN x)1253{1254if (typ(x) != t_VEC) x = mkvec(x);1255if (!v) return x;1256return shallowconcat(v, x);1257}12581259/* Bradford-Davenport algorithm.1260* f a squarefree ZX of degree > 0, return NULL or a vector of coprime1261* cyclotomic factors of f [ possibly reducible ] */1262static GEN1263BD(GEN f)1264{1265GEN G = NULL, Gs = NULL, Gp = NULL, Gi = NULL;1266GEN fs2, fp, f2, f1, fe, fo, fe1, fo1;1267RgX_even_odd(f, &fe, &fo);1268fe1 = ZX_eval1(fe);1269fo1 = ZX_eval1(fo);1270if (absequalii(fe1, fo1)) /* f(1) = 0 or f(-1) = 0 */1271{1272long i, v = varn(f);1273if (!signe(fe1))1274G = mkvec2(polcyclo(1, v), polcyclo(2, v)); /* both 0 */1275else if (signe(fe1) == signe(fo1))1276G = mkvec(polcyclo(2, v)); /*f(-1) = 0*/1277else1278G = mkvec(polcyclo(1, v)); /*f(1) = 0*/1279for (i = lg(G)-1; i; i--) f = RgX_div(f, gel(G,i));1280}1281/* f no longer divisible by Phi_1 or Phi_2 */1282if (degpol(f) <= 1) return G;1283f1 = ZX_graeffe(f); /* has at most square factors */1284if (ZX_equal(f1, f)) return myconcat(G,f); /* f = product of Phi_n, n odd */12851286fs2 = ZX_gcd_all(f1, ZX_deriv(f1), &f2); /* fs2 squarefree */1287if (degpol(fs2))1288{ /* fs contains all Phi_n | f, 4 | n; and only those */1289/* In that case, Graeffe(Phi_n) = Phi_{n/2}^2, and Phi_n = Phi_{n/2}(x^2) */1290GEN fs = RgX_inflate(fs2, 2);1291(void)ZX_gcd_all(f, fs, &f); /* remove those Phi_n | f, 4 | n */1292Gs = BD(fs2);1293if (Gs)1294{1295long i;1296for (i = lg(Gs)-1; i; i--) gel(Gs,i) = RgX_inflate(gel(Gs,i), 2);1297/* prod Gs[i] is the product of all Phi_n | f, 4 | n */1298G = myconcat(G, Gs);1299}1300/* f2 = f1 / fs2 */1301f1 = RgX_div(f2, fs2); /* f1 / fs2^2 */1302}1303fp = ZX_gcd(f, f1); /* contains all Phi_n | f, n > 1 odd; and only those */1304if (degpol(fp))1305{1306Gp = BD_odd(fp);1307/* Gp is the product of all Phi_n | f, n odd */1308if (Gp) G = myconcat(G, Gp);1309f = RgX_div(f, fp);1310}1311if (degpol(f))1312{ /* contains all Phi_n originally dividing f, n = 2 mod 4, n > 2;1313* and only those1314* In that case, Graeffe(Phi_n) = Phi_{n/2}, and Phi_n = Phi_{n/2}(-x) */1315Gi = BD_odd(ZX_z_unscale(f, -1));1316if (Gi)1317{ /* N.B. Phi_2 does not divide f */1318Gi = ZX_z_unscale(Gi, -1);1319/* Gi is the product of all Phi_n | f, n = 2 mod 4 */1320G = myconcat(G, Gi);1321}1322}1323return G;1324}13251326/* Let f be a nonzero QX, return the (squarefree) product of cyclotomic1327* divisors of f */1328GEN1329polcyclofactors(GEN f)1330{1331pari_sp av = avma;1332if (typ(f) != t_POL || !signe(f)) pari_err_TYPE("polcyclofactors",f);1333(void)RgX_valrem(f, &f);1334f = Q_primpart(f);1335RgX_check_ZX(f,"polcyclofactors");1336if (degpol(f))1337{1338f = BD(ZX_radical(f));1339if (f) return gerepilecopy(av, f);1340}1341set_avma(av); return cgetg(1,t_VEC);1342}13431344/* return t*x mod T(x), T a monic ZX. Assume deg(t) < deg(T) */1345static GEN1346ZXQ_mul_by_X(GEN t, GEN T)1347{1348GEN lt;1349t = RgX_shift_shallow(t, 1);1350if (degpol(t) < degpol(T)) return t;1351lt = leading_coeff(t);1352if (is_pm1(lt)) return signe(lt) > 0 ? ZX_sub(t, T): ZX_add(t, T);1353return ZX_sub(t, ZX_Z_mul(T, leading_coeff(t)));1354}1355/* f a product of Phi_n, all n odd; deg f > 1. Is it irreducible ? */1356static long1357BD_odd_iscyclo(GEN f)1358{1359pari_sp av;1360long d, e, n, bound;1361GEN t;1362f = ZX_deflate_max(f, &e);1363av = avma;1364/* The original f is cyclotomic (= Phi_{ne}) iff the present one is Phi_n,1365* where all prime dividing e also divide n. If current f is Phi_n,1366* then n is odd and squarefree */1367d = degpol(f); /* = phi(n) */1368/* Let e > 0, g multiplicative such that1369g(p) = p / (p-1)^(1+e) < 1 iff p < (p-1)^(1+e)1370For all squarefree odd n, we have g(n) < C, hence n < C phi(n)^(1+e), where1371C = \prod_{p odd | p > (p-1)^(1+e)} g(p)1372For e = 1/10, we obtain p = 3, 5 and C < 1.5231373For e = 1/100, we obtain p = 3, 5, ..., 29 and C < 2.5731374In fact, for n <= 10^7 odd & squarefree, we have n < 2.92 * phi(n)1375By the above, n<10^7 covers all d <= (10^7/2.573)^(1/(1+1/100)) < 3344391.1376*/1377if (d <= 3344391)1378bound = (long)(2.92 * d);1379else1380bound = (long)(2.573 * pow(d,1.01));1381/* IF f = Phi_n, n squarefree odd, then n <= bound */1382t = pol_xn(d-1, varn(f));1383for (n = d; n <= bound; n++)1384{1385t = ZXQ_mul_by_X(t, f);1386/* t = (X mod f(X))^d */1387if (degpol(t) == 0) break;1388if (gc_needed(av,1))1389{1390if(DEBUGMEM>1) pari_warn(warnmem,"BD_odd_iscyclo");1391t = gerepilecopy(av, t);1392}1393}1394if (n > bound || eulerphiu(n) != (ulong)d) return 0;13951396if (e > 1) return (u_ppo(e, n) == 1)? e * n : 0;1397return n;1398}13991400/* Checks if f, monic squarefree ZX with |constant coeff| = 1, is a cyclotomic1401* polynomial. Returns n if f = Phi_n, and 0 otherwise */1402static long1403BD_iscyclo(GEN f)1404{1405pari_sp av = avma;1406GEN f2, fn, f1;14071408if (degpol(f) == 1) return isint1(gel(f,2))? 2: 1;1409f1 = ZX_graeffe(f);1410/* f = product of Phi_n, n odd */1411if (ZX_equal(f, f1)) return gc_long(av, BD_odd_iscyclo(f));14121413fn = ZX_z_unscale(f, -1); /* f(-x) */1414/* f = product of Phi_n, n = 2 mod 4 */1415if (ZX_equal(f1, fn)) return gc_long(av, 2*BD_odd_iscyclo(fn));14161417if (issquareall(f1, &f2))1418{1419GEN lt = leading_coeff(f2);1420long c;1421if (signe(lt) < 0) f2 = ZX_neg(f2);1422c = BD_iscyclo(f2);1423return odd(c)? 0: 2*c;1424}1425return gc_long(av, 0);1426}1427long1428poliscyclo(GEN f)1429{1430long d;1431if (typ(f) != t_POL) pari_err_TYPE("poliscyclo", f);1432d = degpol(f);1433if (d <= 0 || !RgX_is_ZX(f)) return 0;1434if (!equali1(gel(f,d+2)) || !is_pm1(gel(f,2))) return 0;1435if (d == 1) return signe(gel(f,2)) > 0? 2: 1;1436return ZX_is_squarefree(f)? BD_iscyclo(f): 0;1437}14381439long1440poliscycloprod(GEN f)1441{1442pari_sp av = avma;1443long i, d = degpol(f);1444if (typ(f) != t_POL) pari_err_TYPE("poliscycloprod",f);1445if (!RgX_is_ZX(f)) return 0;1446if (!ZX_is_monic(f) || !is_pm1(constant_coeff(f))) return 0;1447if (d < 2) return (d == 1);1448if ( degpol(ZX_gcd_all(f, ZX_deriv(f), &f)) )1449{1450d = degpol(f);1451if (d == 1) return 1;1452}1453f = BD(f); if (!f) return 0;1454for (i = lg(f)-1; i; i--) d -= degpol(gel(f,i));1455return gc_long(av, d == 0);1456}145714581459