Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2012 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. */1314#include "pari.h"15#include "paripriv.h"1617#define DEBUGLEVEL DEBUGLEVEL_factormod1819/***********************************************************************/20/** **/21/** Factorisation over finite field **/22/** **/23/***********************************************************************/2425/*******************************************************************/26/* */27/* ROOTS MODULO a prime p (no multiplicities) */28/* */29/*******************************************************************/30/* Replace F by a monic normalized FpX having the same factors;31* assume p prime and *F a ZX */32static int33ZX_factmod_init(GEN *F, GEN p)34{35if (lgefint(p) == 3)36{37ulong pp = p[2];38if (pp == 2) { *F = ZX_to_F2x(*F); return 0; }39*F = ZX_to_Flx(*F, pp);40if (lg(*F) > 3) *F = Flx_normalize(*F, pp);41return 1;42}43*F = FpX_red(*F, p);44if (lg(*F) > 3) *F = FpX_normalize(*F, p);45return 2;46}47static void48ZX_rootmod_init(GEN *F, GEN p)49{50if (lgefint(p) == 3)51{52ulong pp = p[2];53*F = ZX_to_Flx(*F, pp);54if (lg(*F) > 3) *F = Flx_normalize(*F, pp);55}56else57{58*F = FpX_red(*F, p);59if (lg(*F) > 3) *F = FpX_normalize(*F, p);60}61}6263/* return 1,...,p-1 [not_0 = 1] or 0,...,p [not_0 = 0] */64static GEN65all_roots_mod_p(ulong p, int not_0)66{67GEN r;68ulong i;69if (not_0) {70r = cgetg(p, t_VECSMALL);71for (i = 1; i < p; i++) r[i] = i;72} else {73r = cgetg(p+1, t_VECSMALL);74for (i = 0; i < p; i++) r[i+1] = i;75}76return r;77}7879/* X^n - 1 */80static GEN81Flx_Xnm1(long sv, long n, ulong p)82{83GEN t = cgetg(n+3, t_VECSMALL);84long i;85t[1] = sv;86t[2] = p - 1;87for (i = 3; i <= n+1; i++) t[i] = 0;88t[i] = 1; return t;89}90/* X^n + 1 */91static GEN92Flx_Xn1(long sv, long n, ulong p)93{94GEN t = cgetg(n+3, t_VECSMALL);95long i;96(void) p;97t[1] = sv;98t[2] = 1;99for (i = 3; i <= n+1; i++) t[i] = 0;100t[i] = 1; return t;101}102103static GEN104Flx_root_mod_2(GEN f)105{106int z1, z0 = !(f[2] & 1);107long i,n;108GEN y;109110for (i=2, n=1; i < lg(f); i++) n += f[i];111z1 = n & 1;112y = cgetg(z0+z1+1, t_VECSMALL); i = 1;113if (z0) y[i++] = 0;114if (z1) y[i ] = 1;115return y;116}117static ulong118Flx_oneroot_mod_2(GEN f)119{120long i,n;121if (!(f[2] & 1)) return 0;122for (i=2, n=1; i < lg(f); i++) n += f[i];123if (n & 1) return 1;124return 2;125}126127static GEN FpX_roots_i(GEN f, GEN p);128static GEN Flx_roots_i(GEN f, ulong p);129130static int131cmpGuGu(GEN a, GEN b) { return (ulong)a < (ulong)b? -1: (a == b? 0: 1); }132133/* Generic driver to computes the roots of f modulo pp, using 'Roots' when134* pp is a small prime.135* if (gpwrap), check types thoroughly and return t_INTMODs, otherwise136* assume that f is an FpX, pp a prime and return t_INTs */137static GEN138rootmod_aux(GEN f, GEN pp)139{140GEN y;141switch(lg(f))142{143case 2: pari_err_ROOTS0("rootmod");144case 3: return cgetg(1,t_COL);145}146if (typ(f) == t_VECSMALL)147{148ulong p = pp[2];149if (p == 2)150y = Flx_root_mod_2(f);151else152{153if (!odd(p)) pari_err_PRIME("rootmod",utoi(p));154y = Flx_roots_i(f, p);155}156y = Flc_to_ZC(y);157}158else159y = FpX_roots_i(f, pp);160return y;161}162/* assume that f is a ZX and p a prime */163GEN164FpX_roots(GEN f, GEN p)165{166pari_sp av = avma;167GEN y; ZX_rootmod_init(&f, p); y = rootmod_aux(f, p);168return gerepileupto(av, y);169}170171/* assume x reduced mod p > 2, monic. */172static int173FpX_quad_factortype(GEN x, GEN p)174{175GEN b = gel(x,3), c = gel(x,2);176GEN D = subii(sqri(b), shifti(c,2));177return kronecker(D,p);178}179/* assume x reduced mod p, monic. Return one root, or NULL if irreducible */180static GEN181FpX_quad_root(GEN x, GEN p, int unknown)182{183GEN s, D, b = gel(x,3), c = gel(x,2);184185if (absequaliu(p, 2)) {186if (!signe(b)) return c;187return signe(c)? NULL: gen_1;188}189D = subii(sqri(b), shifti(c,2));190D = remii(D,p);191if (unknown && kronecker(D,p) == -1) return NULL;192193s = Fp_sqrt(D,p);194/* p is not prime, go on and give e.g. maxord a chance to recover */195if (!s) return NULL;196return Fp_halve(Fp_sub(s,b, p), p);197}198static GEN199FpX_otherroot(GEN x, GEN r, GEN p)200{ return Fp_neg(Fp_add(gel(x,3), r, p), p); }201202/* disc(x^2+bx+c) = b^2 - 4c */203static ulong204Fl_disc_bc(ulong b, ulong c, ulong p)205{ return Fl_sub(Fl_sqr(b,p), Fl_double(Fl_double(c,p),p), p); }206/* p > 2 */207static ulong208Flx_quad_root(GEN x, ulong p, int unknown)209{210ulong s, b = x[3], c = x[2];211ulong D = Fl_disc_bc(b, c, p);212if (unknown && krouu(D,p) == -1) return p;213s = Fl_sqrt(D,p);214if (s==~0UL) return p;215return Fl_halve(Fl_sub(s,b, p), p);216}217static ulong218Flx_otherroot(GEN x, ulong r, ulong p)219{ return Fl_neg(Fl_add(x[3], r, p), p); }220221/* 'todo' contains the list of factors to be split.222* 'done' the list of finished factors, no longer touched */223struct split_t { GEN todo, done; };224static void225split_init(struct split_t *S, long max)226{227S->todo = vectrunc_init(max);228S->done = vectrunc_init(max);229}230#if 0231/* move todo[i] to done */232static void233split_convert(struct split_t *S, long i)234{235long n = lg(S->todo)-1;236vectrunc_append(S->done, gel(S->todo,i));237if (n) gel(S->todo,i) = gel(S->todo, n);238setlg(S->todo, n);239}240#endif241/* append t to todo */242static void243split_add(struct split_t *S, GEN t) { vectrunc_append(S->todo, t); }244/* delete todo[i], add t to done */245static void246split_moveto_done(struct split_t *S, long i, GEN t)247{248long n = lg(S->todo)-1;249vectrunc_append(S->done, t);250if (n) gel(S->todo,i) = gel(S->todo, n);251setlg(S->todo, n);252253}254/* append t to done */255static void256split_add_done(struct split_t *S, GEN t)257{ vectrunc_append(S->done, t); }258/* split todo[i] into a and b */259static void260split_todo(struct split_t *S, long i, GEN a, GEN b)261{262gel(S->todo, i) = a;263split_add(S, b);264}265/* split todo[i] into a and b, moved to done */266static void267split_done(struct split_t *S, long i, GEN a, GEN b)268{269split_moveto_done(S, i, a);270split_add_done(S, b);271}272273/* by splitting, assume p > 2 prime, deg(f) > 0, and f monic */274static GEN275FpX_roots_i(GEN f, GEN p)276{277GEN pol, pol0, a, q;278struct split_t S;279280split_init(&S, lg(f)-1);281settyp(S.done, t_COL);282if (ZX_valrem(f, &f)) split_add_done(&S, gen_0);283switch(degpol(f))284{285case 0: return ZC_copy(S.done);286case 1: split_add_done(&S, subii(p, gel(f,2))); return ZC_copy(S.done);287case 2: {288GEN s, r = FpX_quad_root(f, p, 1);289if (r) {290split_add_done(&S, r);291s = FpX_otherroot(f,r, p);292/* f not known to be square free yet */293if (!equalii(r, s)) split_add_done(&S, s);294}295return sort(S.done);296}297}298299a = FpXQ_pow(pol_x(varn(f)), subiu(p,1), f,p);300if (lg(a) < 3) pari_err_PRIME("rootmod",p);301a = FpX_Fp_sub_shallow(a, gen_1, p); /* a = x^(p-1) - 1 mod f */302a = FpX_gcd(f,a, p);303if (!degpol(a)) return ZC_copy(S.done);304split_add(&S, FpX_normalize(a,p));305306q = shifti(p,-1);307pol0 = icopy(gen_1); /* constant term, will vary in place */308pol = deg1pol_shallow(gen_1, pol0, varn(f));309for (pol0[2] = 1;; pol0[2]++)310{311long j, l = lg(S.todo);312if (l == 1) return sort(S.done);313if (pol0[2] == 100 && !BPSW_psp(p)) pari_err_PRIME("polrootsmod",p);314for (j = 1; j < l; j++)315{316GEN b, r, s, c = gel(S.todo,j);317switch(degpol(c))318{ /* convert linear and quadratics to roots, try to split the rest */319case 1:320split_moveto_done(&S, j, subii(p, gel(c,2)));321j--; l--; break;322case 2:323r = FpX_quad_root(c, p, 0);324if (!r) pari_err_PRIME("polrootsmod",p);325s = FpX_otherroot(c,r, p);326split_done(&S, j, r, s);327j--; l--; break;328default:329b = FpXQ_pow(pol,q, c,p);330if (degpol(b) <= 0) continue;331b = FpX_gcd(c,FpX_Fp_sub_shallow(b,gen_1,p), p);332if (!degpol(b)) continue;333b = FpX_normalize(b, p);334c = FpX_div(c,b, p);335split_todo(&S, j, b, c);336}337}338}339}340341/* Assume f is normalized */342static ulong343Flx_cubic_root(GEN ff, ulong p)344{345GEN f = Flx_normalize(ff,p);346ulong pi = get_Fl_red(p);347ulong a = f[4], b=f[3], c=f[2], p3 = p%3==1 ? (2*p+1)/3 :(p+1)/3;348ulong t = Fl_mul_pre(a, p3, p, pi), t2 = Fl_sqr_pre(t, p, pi);349ulong A = Fl_sub(b, Fl_triple(t2, p), p);350ulong B = Fl_addmul_pre(c, t, Fl_sub(Fl_double(t2, p), b, p), p, pi);351ulong A3 = Fl_mul_pre(A, p3, p, pi);352ulong A32 = Fl_sqr_pre(A3, p, pi), A33 = Fl_mul_pre(A3, A32, p, pi);353ulong S = Fl_neg(B,p), P = Fl_neg(A3,p);354ulong D = Fl_add(Fl_sqr_pre(S, p, pi), Fl_double(Fl_double(A33, p), p), p);355if (krouu(D,p) >= 0)356{357ulong s = Fl_sqrt_pre(D, p, pi), vS1, vS2;358ulong S1 = S==s ? S: Fl_halve(Fl_sub(S, s, p), p);359if (p%3==2) /* 1 solutions */360vS1 = Fl_powu_pre(S1, (2*p-1)/3, p, pi);361else362{363vS1 = Fl_sqrtl_pre(S1, 3, p, pi);364if (vS1==~0UL) return p; /*0 solutions*/365/*3 solutions*/366}367vS2 = P? Fl_mul_pre(P, Fl_inv(vS1, p), p, pi): 0;368return Fl_sub(Fl_add(vS1,vS2, p), t, p);369}370else371{372pari_sp av = avma;373GEN S1 = mkvecsmall2(Fl_halve(S, p), Fl_halve(1UL, p));374GEN vS1 = Fl2_sqrtn_pre(S1, utoi(3), D, p, pi, NULL);375ulong Sa;376if (!vS1) return p; /*0 solutions, p%3==2*/377Sa = vS1[1];378if (p%3==1) /*1 solutions*/379{380ulong Fa = Fl2_norm_pre(vS1, D, p, pi);381if (Fa!=P)382Sa = Fl_mul(Sa, Fl_div(Fa, P, p),p);383}384set_avma(av);385return Fl_sub(Fl_double(Sa,p),t,p);386}387}388389/* Assume f is normalized */390static GEN391FpX_cubic_root(GEN ff, GEN p)392{393GEN f = FpX_normalize(ff,p);394GEN a = gel(f,4), b = gel(f,3), c = gel(f,2);395ulong pm3 = umodiu(p,3);396GEN p3 = pm3==1 ? diviuexact(addiu(shifti(p,1),1),3)397: diviuexact(addiu(p,1),3);398GEN t = Fp_mul(a, p3, p), t2 = Fp_sqr(t, p);399GEN A = Fp_sub(b, Fp_mulu(t2, 3, p), p);400GEN B = Fp_addmul(c, t, Fp_sub(shifti(t2, 1), b, p), p);401GEN A3 = Fp_mul(A, p3, p);402GEN A32 = Fp_sqr(A3, p), A33 = Fp_mul(A3, A32, p);403GEN S = Fp_neg(B,p), P = Fp_neg(A3,p);404GEN D = Fp_add(Fp_sqr(S, p), shifti(A33, 2), p);405if (kronecker(D,p) >= 0)406{407GEN s = Fp_sqrt(D, p), vS1, vS2;408GEN S1 = S==s ? S: Fp_halve(Fp_sub(S, s, p), p);409if (pm3 == 2) /* 1 solutions */410vS1 = Fp_pow(S1, diviuexact(addiu(shifti(p, 1), 1), 3), p);411else412{413vS1 = Fp_sqrtn(S1, utoi(3), p, NULL);414if (!vS1) return p; /*0 solutions*/415/*3 solutions*/416}417vS2 = P? Fp_mul(P, Fp_inv(vS1, p), p): 0;418return Fp_sub(Fp_add(vS1,vS2, p), t, p);419}420else421{422pari_sp av = avma;423GEN T = deg2pol_shallow(gen_1, gen_0, negi(D), 0);424GEN S1 = deg1pol_shallow(Fp_halve(gen_1, p), Fp_halve(S, p), 0);425GEN vS1 = FpXQ_sqrtn(S1, utoi(3), T, p, NULL);426GEN Sa;427if (!vS1) return p; /*0 solutions, p%3==2*/428Sa = gel(vS1,2);429if (pm3 == 1) /*1 solutions*/430{431GEN Fa = FpXQ_norm(vS1, T, p);432if (!equalii(Fa,P))433Sa = Fp_mul(Sa, Fp_div(Fa, P, p),p);434}435set_avma(av);436return Fp_sub(shifti(Sa,1),t,p);437}438}439440/* assume p > 2 prime */441static ulong442Flx_oneroot_i(GEN f, ulong p, long fl)443{444GEN pol, a;445ulong q;446long da;447448if (Flx_val(f)) return 0;449switch(degpol(f))450{451case 1: return Fl_neg(f[2], p);452case 2: return Flx_quad_root(f, p, 1);453case 3: if (p>3) return Flx_cubic_root(f, p); /*FALL THROUGH*/454}455456if (!fl)457{458a = Flxq_powu(polx_Flx(f[1]), p - 1, f,p);459if (lg(a) < 3) pari_err_PRIME("rootmod",utoipos(p));460a = Flx_Fl_add(a, p-1, p); /* a = x^(p-1) - 1 mod f */461a = Flx_gcd(f,a, p);462} else a = f;463da = degpol(a);464if (!da) return p;465a = Flx_normalize(a,p);466467q = p >> 1;468pol = polx_Flx(f[1]);469for(pol[2] = 1;; pol[2]++)470{471if (pol[2] == 1000 && !uisprime(p)) pari_err_PRIME("Flx_oneroot",utoipos(p));472switch(da)473{474case 1: return Fl_neg(a[2], p);475case 2: return Flx_quad_root(a, p, 0);476case 3: if (p>3) return Flx_cubic_root(a, p); /*FALL THROUGH*/477default: {478GEN b = Flxq_powu(pol,q, a,p);479long db;480if (degpol(b) <= 0) continue;481b = Flx_gcd(a,Flx_Fl_add(b,p-1,p), p);482db = degpol(b); if (!db) continue;483b = Flx_normalize(b, p);484if (db <= (da >> 1)) {485a = b;486da = db;487} else {488a = Flx_div(a,b, p);489da -= db;490}491}492}493}494}495496/* assume p > 3 prime */497static GEN498FpX_oneroot_i(GEN f, GEN p)499{500GEN pol, pol0, a, q;501long da;502503if (ZX_val(f)) return gen_0;504switch(degpol(f))505{506case 1: return subii(p, gel(f,2));507case 2: return FpX_quad_root(f, p, 1);508case 3: return FpX_cubic_root(f, p);509}510511a = FpXQ_pow(pol_x(varn(f)), subiu(p,1), f,p);512if (lg(a) < 3) pari_err_PRIME("rootmod",p);513a = FpX_Fp_sub_shallow(a, gen_1, p); /* a = x^(p-1) - 1 mod f */514a = FpX_gcd(f,a, p);515da = degpol(a);516if (!da) return NULL;517a = FpX_normalize(a,p);518519q = shifti(p,-1);520pol0 = icopy(gen_1); /* constant term, will vary in place */521pol = deg1pol_shallow(gen_1, pol0, varn(f));522for (pol0[2]=1; ; pol0[2]++)523{524if (pol0[2] == 1000 && !BPSW_psp(p)) pari_err_PRIME("FpX_oneroot",p);525switch(da)526{527case 1: return subii(p, gel(a,2));528case 2: return FpX_quad_root(a, p, 0);529default: {530GEN b = FpXQ_pow(pol,q, a,p);531long db;532if (degpol(b) <= 0) continue;533b = FpX_gcd(a,FpX_Fp_sub_shallow(b,gen_1,p), p);534db = degpol(b); if (!db) continue;535b = FpX_normalize(b, p);536if (db <= (da >> 1)) {537a = b;538da = db;539} else {540a = FpX_div(a,b, p);541da -= db;542}543}544}545}546}547548ulong549Flx_oneroot(GEN f, ulong p)550{551pari_sp av = avma;552ulong r;553switch(lg(f))554{555case 2: return 0;556case 3: return p;557}558if (p == 2) return Flx_oneroot_mod_2(f);559r = Flx_oneroot_i(Flx_normalize(f, p), p, 0);560return gc_ulong(av,r);561}562563ulong564Flx_oneroot_split(GEN f, ulong p)565{566pari_sp av = avma;567ulong r;568switch(lg(f))569{570case 2: return 0;571case 3: return p;572}573if (p == 2) return Flx_oneroot_mod_2(f);574r = Flx_oneroot_i(Flx_normalize(f, p), p, 1);575return gc_ulong(av,r);576}577578/* assume that p is prime */579GEN580FpX_oneroot(GEN f, GEN pp) {581pari_sp av = avma;582ZX_rootmod_init(&f, pp);583switch(lg(f))584{585case 2: set_avma(av); return gen_0;586case 3: return gc_NULL(av);587}588if (typ(f) == t_VECSMALL)589{590ulong r, p = pp[2];591if (p == 2)592r = Flx_oneroot_mod_2(f);593else594r = Flx_oneroot_i(f, p, 0);595set_avma(av);596return (r == p)? NULL: utoi(r);597}598f = FpX_oneroot_i(f, pp);599if (!f) return gc_NULL(av);600return gerepileuptoint(av, f);601}602603/* returns a root of unity in F_p that is suitable for finding a factor */604/* of degree deg_factor of a polynomial of degree deg; the order is */605/* returned in n */606/* A good choice seems to be n close to deg/deg_factor; we choose n */607/* twice as big and decrement until it divides p-1. */608static GEN609good_root_of_unity(GEN p, long deg, long deg_factor, long *pt_n)610{611pari_sp ltop = avma;612GEN pm, factn, power, base, zeta;613long n;614615pm = subis (p, 1ul);616for (n = deg / 2 / deg_factor + 1; !dvdiu (pm, n); n--);617factn = Z_factor(stoi(n));618power = diviuexact (pm, n);619base = gen_1;620do {621base = addis (base, 1l);622zeta = Fp_pow (base, power, p);623}624while (!equaliu (Fp_order (zeta, factn, p), n));625*pt_n = n;626return gerepileuptoint (ltop, zeta);627}628629GEN630FpX_oneroot_split(GEN fact, GEN p)631{632pari_sp av = avma;633long n, deg_f, i, dmin;634GEN prim, expo, minfactor, xplusa, zeta, xpow;635fact = FpX_normalize(fact, p);636deg_f = degpol(fact);637if (deg_f <= 3) return FpX_oneroot(fact, p);638minfactor = fact; /* factor of minimal degree found so far */639dmin = degpol(minfactor);640xplusa = pol_x(varn(fact));641while (dmin > 3)642{643/* split minfactor by computing its gcd with (X+a)^exp-zeta, where */644/* zeta varies over the roots of unity in F_p */645fact = minfactor; deg_f = dmin;646zeta = gen_1;647prim = good_root_of_unity(p, deg_f, 1, &n);648expo = diviuexact(subiu(p, 1), n);649/* update X+a, avoid a=0 */650gel (xplusa, 2) = addis (gel (xplusa, 2), 1);651xpow = FpXQ_pow (xplusa, expo, fact, p);652for (i = 0; i < n; i++)653{654GEN tmp = FpX_gcd(FpX_Fp_sub(xpow, zeta, p), fact, p);655long dtmp = degpol(tmp);656if (dtmp > 0 && dtmp < deg_f)657{658fact = FpX_div(fact, tmp, p); deg_f = degpol(fact);659if (dtmp < dmin)660{661minfactor = FpX_normalize (tmp, p);662dmin = dtmp;663if (dmin == 1 || dmin <= (2 * deg_f) / n - 1)664/* stop early to avoid too many gcds */665break;666}667}668zeta = Fp_mul (zeta, prim, p);669}670}671return gerepileuptoint(av, FpX_oneroot(minfactor, p));672}673674/*******************************************************************/675/* */676/* FACTORISATION MODULO p */677/* */678/*******************************************************************/679680/* F / E a vector of vectors of factors / exponents of virtual length l681* (their real lg may be larger). Set their lg to j, concat and return [F,E] */682static GEN683FE_concat(GEN F, GEN E, long l)684{685setlg(E,l); E = shallowconcat1(E);686setlg(F,l); F = shallowconcat1(F); return mkvec2(F,E);687}688689static GEN690ddf_to_ddf2_i(GEN V, long fl)691{692GEN F, D;693long i, j, l = lg(V);694F = cgetg(l, t_VEC);695D = cgetg(l, t_VECSMALL);696for (i = j = 1; i < l; i++)697{698GEN Vi = gel(V,i);699if ((fl==2 && F2x_degree(Vi) == 0)700||(fl==0 && degpol(Vi) == 0)) continue;701gel(F,j) = Vi;702uel(D,j) = i; j++;703}704setlg(F,j);705setlg(D,j); return mkvec2(F,D);706}707708GEN709ddf_to_ddf2(GEN V)710{ return ddf_to_ddf2_i(V, 0); }711712static GEN713F2x_ddf_to_ddf2(GEN V)714{ return ddf_to_ddf2_i(V, 2); }715716GEN717vddf_to_simplefact(GEN V, long d)718{719GEN E, F;720long i, j, c, l = lg(V);721F = cgetg(d+1, t_VECSMALL);722E = cgetg(d+1, t_VECSMALL);723for (i = c = 1; i < l; i++)724{725GEN Vi = gel(V,i);726long l = lg(Vi);727for (j = 1; j < l; j++)728{729long k, n = degpol(gel(Vi,j)) / j;730for (k = 1; k <= n; k++) { uel(F,c) = j; uel(E,c) = i; c++; }731}732}733setlg(F,c);734setlg(E,c);735return sort_factor(mkvec2(F,E), (void*)&cmpGuGu, cmp_nodata);736}737738/* product of terms of degree 1 in factorization of f */739GEN740FpX_split_part(GEN f, GEN p)741{742long n = degpol(f);743GEN z, X = pol_x(varn(f));744if (n <= 1) return f;745f = FpX_red(f, p);746z = FpX_sub(FpX_Frobenius(f, p), X, p);747return FpX_gcd(z,f,p);748}749750/* Compute the number of roots in Fp without counting multiplicity751* return -1 for 0 polynomial. lc(f) must be prime to p. */752long753FpX_nbroots(GEN f, GEN p)754{755pari_sp av = avma;756GEN z = FpX_split_part(f, p);757return gc_long(av, degpol(z));758}759760/* 1 < deg(f) <= p */761static int762Flx_is_totally_split_i(GEN f, ulong p)763{764GEN F = Flx_Frobenius(f, p);765return degpol(F)==1 && uel(F,2)==0UL && uel(F,3)==1UL;766}767int768Flx_is_totally_split(GEN f, ulong p)769{770pari_sp av = avma;771ulong n = degpol(f);772if (n <= 1) return 1;773if (n > p) return 0; /* includes n < 0 */774return gc_bool(av, Flx_is_totally_split_i(f,p));775}776int777FpX_is_totally_split(GEN f, GEN p)778{779pari_sp av = avma;780ulong n = degpol(f);781int u;782if (n <= 1) return 1;783if (abscmpui(n, p) > 0) return 0; /* includes n < 0 */784if (lgefint(p) != 3)785u = gequalX(FpX_Frobenius(FpX_red(f,p), p));786else787{788ulong pp = (ulong)p[2];789u = Flx_is_totally_split_i(ZX_to_Flx(f,pp), pp);790}791return gc_bool(av, u);792}793794long795Flx_nbroots(GEN f, ulong p)796{797long n = degpol(f);798pari_sp av = avma;799GEN z;800if (n <= 1) return n;801if (n == 2)802{803ulong D;804if (p==2) return (f[2]==0) + (f[2]!=f[3]);805D = Fl_sub(Fl_sqr(f[3], p), Fl_mul(Fl_mul(f[4], f[2], p), 4%p, p), p);806return 1 + krouu(D,p);807}808z = Flx_sub(Flx_Frobenius(f, p), polx_Flx(f[1]), p);809z = Flx_gcd(z, f, p);810return gc_long(av, degpol(z));811}812813long814FpX_ddf_degree(GEN T, GEN XP, GEN p)815{816pari_sp av = avma;817GEN X, b, g, xq;818long i, j, n, v, B, l, m;819pari_timer ti;820hashtable h;821822n = get_FpX_degree(T); v = get_FpX_var(T);823X = pol_x(v);824if (ZX_equal(X,XP)) return 1;825B = n/2;826l = usqrt(B);827m = (B+l-1)/l;828T = FpX_get_red(T, p);829hash_init_GEN(&h, l+2, ZX_equal, 1);830hash_insert_long(&h, X, 0);831hash_insert_long(&h, XP, 1);832if (DEBUGLEVEL>=7) timer_start(&ti);833b = XP;834xq = FpXQ_powers(b, brent_kung_optpow(n, l-1, 1), T, p);835if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: xq baby");836for (i = 3; i <= l+1; i++)837{838b = FpX_FpXQV_eval(b, xq, T, p);839if (gequalX(b)) return gc_long(av,i-1);840hash_insert_long(&h, b, i-1);841}842if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: baby");843g = b;844xq = FpXQ_powers(g, brent_kung_optpow(n, m, 1), T, p);845if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_degree: xq giant");846for(i = 2; i <= m+1; i++)847{848g = FpX_FpXQV_eval(g, xq, T, p);849if (hash_haskey_long(&h, g, &j)) return gc_long(av, l*i-j);850}851return gc_long(av,n);852}853854/* See <http://www.shoup.net/papers/factorimpl.pdf> */855static GEN856FpX_ddf_Shoup(GEN T, GEN XP, GEN p)857{858GEN b, g, h, F, f, Tr, xq;859long i, j, n, v, B, l, m;860pari_timer ti;861862n = get_FpX_degree(T); v = get_FpX_var(T);863if (n == 0) return cgetg(1, t_VEC);864if (n == 1) return mkvec(get_FpX_mod(T));865B = n/2;866l = usqrt(B);867m = (B+l-1)/l;868T = FpX_get_red(T, p);869b = cgetg(l+2, t_VEC);870gel(b, 1) = pol_x(v);871gel(b, 2) = XP;872if (DEBUGLEVEL>=7) timer_start(&ti);873xq = FpXQ_powers(gel(b, 2), brent_kung_optpow(n, l-1, 1), T, p);874if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: xq baby");875for (i = 3; i <= l+1; i++)876gel(b, i) = FpX_FpXQV_eval(gel(b, i-1), xq, T, p);877if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: baby");878xq = FpXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), T, p);879if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: xq giant");880g = cgetg(m+1, t_VEC);881gel(g, 1) = gel(xq, 2);882for(i = 2; i <= m; i++) gel(g, i) = FpX_FpXQV_eval(gel(g, i-1), xq, T, p);883if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: giant");884h = cgetg(m+1, t_VEC);885for (j = 1; j <= m; j++)886{887pari_sp av = avma;888GEN gj = gel(g,j), e = FpX_sub(gj, gel(b,1), p);889for (i = 2; i <= l; i++) e = FpXQ_mul(e, FpX_sub(gj, gel(b,i), p), T, p);890gel(h,j) = gerepileupto(av, e);891}892if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: diff");893Tr = get_FpX_mod(T);894F = cgetg(m+1, t_VEC);895for (j = 1; j <= m; j++)896{897GEN u = FpX_gcd(Tr, gel(h,j), p);898if (degpol(u))899{900u = FpX_normalize(u, p);901Tr = FpX_div(Tr, u, p);902}903gel(F,j) = u;904}905if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: F");906f = const_vec(n, pol_1(v));907for (j = 1; j <= m; j++)908{909GEN e = gel(F, j);910for (i=l-1; i >= 0; i--)911{912GEN u = FpX_gcd(e, FpX_sub(gel(g, j), gel(b, i+1), p), p);913if (degpol(u))914{915u = FpX_normalize(u, p);916gel(f, l*j-i) = u;917e = FpX_div(e, u, p);918}919if (!degpol(e)) break;920}921}922if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_ddf_Shoup: f");923if (degpol(Tr)) gel(f, degpol(Tr)) = Tr;924return f;925}926927static void928FpX_edf_simple(GEN Tp, GEN XP, long d, GEN p, GEN V, long idx)929{930long n = degpol(Tp), r = n/d, ct = 0;931GEN T, f, ff, p2;932if (r==1) { gel(V, idx) = Tp; return; }933p2 = shifti(p,-1);934T = FpX_get_red(Tp, p);935XP = FpX_rem(XP, T, p);936while (1)937{938pari_sp btop = avma;939long i;940GEN g = random_FpX(n, varn(Tp), p);941GEN t = gel(FpXQ_auttrace(mkvec2(XP, g), d, T, p), 2);942if (signe(t) == 0) continue;943for(i=1; i<=10; i++)944{945pari_sp btop2 = avma;946GEN R = FpXQ_pow(FpX_Fp_add(t, randomi(p), p), p2, T, p);947f = FpX_gcd(FpX_Fp_sub(R, gen_1, p), Tp, p);948if (degpol(f) > 0 && degpol(f) < n) break;949set_avma(btop2);950}951if (degpol(f) > 0 && degpol(f) < n) break;952if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf_simple",p);953set_avma(btop);954}955f = FpX_normalize(f, p);956ff = FpX_div(Tp, f ,p);957FpX_edf_simple(f, XP, d, p, V, idx);958FpX_edf_simple(ff, XP, d, p, V, idx+degpol(f)/d);959}960961static void962FpX_edf_rec(GEN T, GEN hp, GEN t, long d, GEN p2, GEN p, GEN V, long idx)963{964pari_sp av;965GEN Tp = get_FpX_mod(T);966long n = degpol(hp), vT = varn(Tp), ct = 0;967GEN u1, u2, f1, f2, R, h;968h = FpX_get_red(hp, p);969t = FpX_rem(t, T, p);970av = avma;971do972{973set_avma(av);974R = FpXQ_pow(deg1pol(gen_1, randomi(p), vT), p2, h, p);975u1 = FpX_gcd(FpX_Fp_sub(R, gen_1, p), hp, p);976if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf_rec",p);977} while (degpol(u1)==0 || degpol(u1)==n);978f1 = FpX_gcd(FpX_FpXQ_eval(u1, t, T, p), Tp, p);979f1 = FpX_normalize(f1, p);980u2 = FpX_div(hp, u1, p);981f2 = FpX_div(Tp, f1, p);982if (degpol(u1)==1)983gel(V, idx) = f1;984else985FpX_edf_rec(FpX_get_red(f1, p), u1, t, d, p2, p, V, idx);986idx += degpol(f1)/d;987if (degpol(u2)==1)988gel(V, idx) = f2;989else990FpX_edf_rec(FpX_get_red(f2, p), u2, t, d, p2, p, V, idx);991}992993/* assume Tp a squarefree product of r > 1 irred. factors of degree d */994static void995FpX_edf(GEN Tp, GEN XP, long d, GEN p, GEN V, long idx)996{997long n = degpol(Tp), r = n/d, vT = varn(Tp), ct = 0;998GEN T, h, t;999pari_timer ti;10001001T = FpX_get_red(Tp, p);1002XP = FpX_rem(XP, T, p);1003if (DEBUGLEVEL>=7) timer_start(&ti);1004do1005{1006GEN g = random_FpX(n, vT, p);1007t = gel(FpXQ_auttrace(mkvec2(XP, g), d, T, p), 2);1008if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_edf: FpXQ_auttrace");1009h = FpXQ_minpoly(t, T, p);1010if (DEBUGLEVEL>=7) timer_printf(&ti,"FpX_edf: FpXQ_minpoly");1011if (++ct == 10 && !BPSW_psp(p)) pari_err_PRIME("FpX_edf",p);1012} while (degpol(h) != r);1013FpX_edf_rec(T, h, t, d, shifti(p, -1), p, V, idx);1014}10151016static GEN1017FpX_factor_Shoup(GEN T, GEN p)1018{1019long i, n, s = 0;1020GEN XP, D, V;1021long e = expi(p);1022pari_timer ti;1023n = get_FpX_degree(T);1024T = FpX_get_red(T, p);1025if (DEBUGLEVEL>=6) timer_start(&ti);1026XP = FpX_Frobenius(T, p);1027if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_Frobenius");1028D = FpX_ddf_Shoup(T, XP, p);1029if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_ddf_Shoup");1030s = ddf_to_nbfact(D);1031V = cgetg(s+1, t_COL);1032for (i = 1, s = 1; i <= n; i++)1033{1034GEN Di = gel(D,i);1035long ni = degpol(Di), ri = ni/i;1036if (ni == 0) continue;1037Di = FpX_normalize(Di, p);1038if (ni == i) { gel(V, s++) = Di; continue; }1039if (ri <= e*expu(e))1040FpX_edf(Di, XP, i, p, V, s);1041else1042FpX_edf_simple(Di, XP, i, p, V, s);1043if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_edf(%ld)",i);1044s += ri;1045}1046return V;1047}10481049long1050ddf_to_nbfact(GEN D)1051{1052long l = lg(D), i, s = 0;1053for(i = 1; i < l; i++) s += degpol(gel(D,i))/i;1054return s;1055}10561057/* Yun algorithm: Assume p > degpol(T) */1058static GEN1059FpX_factor_Yun(GEN T, GEN p)1060{1061long n = degpol(T), i = 1;1062GEN a, b, c, d = FpX_deriv(T, p);1063GEN V = cgetg(n+1,t_VEC);1064a = FpX_gcd(T, d, p);1065if (degpol(a) == 0) return mkvec(T);1066b = FpX_div(T, a, p);1067do1068{1069c = FpX_div(d, a, p);1070d = FpX_sub(c, FpX_deriv(b, p), p);1071a = FpX_normalize(FpX_gcd(b, d, p), p);1072gel(V, i++) = a;1073b = FpX_div(b, a, p);1074} while (degpol(b));1075setlg(V, i); return V;1076}1077GEN1078FpX_factor_squarefree(GEN T, GEN p)1079{1080if (lgefint(p)==3)1081{1082ulong pp = (ulong)p[2];1083GEN u = Flx_factor_squarefree(ZX_to_Flx(T,pp), pp);1084return FlxV_to_ZXV(u);1085}1086return FpX_factor_Yun(T, p);1087}10881089long1090FpX_ispower(GEN f, ulong k, GEN p, GEN *pt_r)1091{1092pari_sp av = avma;1093GEN lc, F;1094long i, l, n = degpol(f), v = varn(f);1095if (n % k) return 0;1096if (lgefint(p)==3)1097{1098ulong pp = p[2];1099GEN fp = ZX_to_Flx(f, pp);1100if (!Flx_ispower(fp, k, pp, pt_r)) return gc_long(av,0);1101if (pt_r) *pt_r = gerepileupto(av, Flx_to_ZX(*pt_r)); else set_avma(av);1102return 1;1103}1104lc = Fp_sqrtn(leading_coeff(f), stoi(k), p, NULL);1105if (!lc) { av = avma; return 0; }1106F = FpX_factor_Yun(f, p); l = lg(F)-1;1107for(i=1; i <= l; i++)1108if (i%k && degpol(gel(F,i))) return gc_long(av,0);1109if (pt_r)1110{1111GEN r = scalarpol(lc, v), s = pol_1(v);1112for (i=l; i>=1; i--)1113{1114if (i%k) continue;1115s = FpX_mul(s, gel(F,i), p);1116r = FpX_mul(r, s, p);1117}1118*pt_r = gerepileupto(av, r);1119} else av = avma;1120return 1;1121}11221123static GEN1124FpX_factor_Cantor(GEN T, GEN p)1125{1126GEN E, F, V = FpX_factor_Yun(T, p);1127long i, j, l = lg(V);1128F = cgetg(l, t_VEC);1129E = cgetg(l, t_VEC);1130for (i=1, j=1; i < l; i++)1131if (degpol(gel(V,i)))1132{1133GEN Fj = FpX_factor_Shoup(gel(V,i), p);1134gel(F, j) = Fj;1135gel(E, j) = const_vecsmall(lg(Fj)-1, i);1136j++;1137}1138return sort_factor_pol(FE_concat(F,E,j), cmpii);1139}11401141static GEN1142FpX_ddf_i(GEN T, GEN p)1143{1144GEN XP;1145T = FpX_get_red(T, p);1146XP = FpX_Frobenius(T, p);1147return ddf_to_ddf2(FpX_ddf_Shoup(T, XP, p));1148}11491150GEN1151FpX_ddf(GEN f, GEN p)1152{1153pari_sp av = avma;1154GEN F;1155switch(ZX_factmod_init(&f, p))1156{1157case 0: F = F2x_ddf(f);1158F2xV_to_ZXV_inplace(gel(F,1)); break;1159case 1: F = Flx_ddf(f,p[2]);1160FlxV_to_ZXV_inplace(gel(F,1)); break;1161default: F = FpX_ddf_i(f,p); break;1162}1163return gerepilecopy(av, F);1164}11651166static GEN Flx_simplefact_Cantor(GEN T, ulong p);1167static GEN1168FpX_simplefact_Cantor(GEN T, GEN p)1169{1170GEN V;1171long i, l;1172if (lgefint(p) == 3)1173{1174ulong pp = p[2];1175return Flx_simplefact_Cantor(ZX_to_Flx(T,pp), pp);1176}1177T = FpX_get_red(T, p);1178V = FpX_factor_Yun(get_FpX_mod(T), p); l = lg(V);1179for (i=1; i < l; i++)1180gel(V,i) = FpX_ddf_Shoup(gel(V,i), FpX_Frobenius(gel(V,i), p), p);1181return vddf_to_simplefact(V, get_FpX_degree(T));1182}11831184static int1185FpX_isirred_Cantor(GEN Tp, GEN p)1186{1187pari_sp av = avma;1188pari_timer ti;1189long n;1190GEN T = get_FpX_mod(Tp);1191GEN dT = FpX_deriv(T, p);1192GEN XP, D;1193if (degpol(FpX_gcd(T, dT, p)) != 0) return gc_bool(av,0);1194n = get_FpX_degree(T);1195T = FpX_get_red(Tp, p);1196if (DEBUGLEVEL>=6) timer_start(&ti);1197XP = FpX_Frobenius(T, p);1198if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_Frobenius");1199D = FpX_ddf_Shoup(T, XP, p);1200if (DEBUGLEVEL>=6) timer_printf(&ti,"FpX_ddf_Shoup");1201return gc_bool(av, degpol(gel(D,n)) == n);1202}12031204static GEN FpX_factor_deg2(GEN f, GEN p, long d, long flag);12051206/*Assume that p is large and odd*/1207static GEN1208FpX_factor_i(GEN f, GEN pp, long flag)1209{1210long d = degpol(f);1211if (d <= 2) return FpX_factor_deg2(f,pp,d,flag);1212switch(flag)1213{1214default: return FpX_factor_Cantor(f, pp);1215case 1: return FpX_simplefact_Cantor(f, pp);1216case 2: return FpX_isirred_Cantor(f, pp)? gen_1: NULL;1217}1218}12191220long1221FpX_nbfact_Frobenius(GEN T, GEN XP, GEN p)1222{1223pari_sp av = avma;1224long s = ddf_to_nbfact(FpX_ddf_Shoup(T, XP, p));1225return gc_long(av,s);1226}12271228long1229FpX_nbfact(GEN T, GEN p)1230{1231pari_sp av = avma;1232GEN XP = FpX_Frobenius(T, p);1233long n = FpX_nbfact_Frobenius(T, XP, p);1234return gc_long(av,n);1235}12361237/* p > 2 */1238static GEN1239FpX_is_irred_2(GEN f, GEN p, long d)1240{1241switch(d)1242{1243case -1:1244case 0: return NULL;1245case 1: return gen_1;1246}1247return FpX_quad_factortype(f, p) == -1? gen_1: NULL;1248}1249/* p > 2 */1250static GEN1251FpX_degfact_2(GEN f, GEN p, long d)1252{1253switch(d)1254{1255case -1:retmkvec2(mkvecsmall(-1),mkvecsmall(1));1256case 0: return trivial_fact();1257case 1: retmkvec2(mkvecsmall(1), mkvecsmall(1));1258}1259switch(FpX_quad_factortype(f, p)) {1260case 1: retmkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1));1261case -1: retmkvec2(mkvecsmall(2), mkvecsmall(1));1262default: retmkvec2(mkvecsmall(1), mkvecsmall(2));1263}1264}12651266GEN1267prime_fact(GEN x) { retmkmat2(mkcolcopy(x), mkcol(gen_1)); }1268GEN1269trivial_fact(void) { retmkmat2(cgetg(1,t_COL), cgetg(1,t_COL)); }12701271/* not gerepile safe */1272static GEN1273FpX_factor_2(GEN f, GEN p, long d)1274{1275GEN r, s, R, S;1276long v;1277int sgn;1278switch(d)1279{1280case -1: retmkvec2(mkcol(pol_0(varn(f))), mkvecsmall(1));1281case 0: retmkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL));1282case 1: retmkvec2(mkcol(f), mkvecsmall(1));1283}1284r = FpX_quad_root(f, p, 1);1285if (!r) return mkvec2(mkcol(f), mkvecsmall(1));1286v = varn(f);1287s = FpX_otherroot(f, r, p);1288if (signe(r)) r = subii(p, r);1289if (signe(s)) s = subii(p, s);1290sgn = cmpii(s, r); if (sgn < 0) swap(s,r);1291R = deg1pol_shallow(gen_1, r, v);1292if (!sgn) return mkvec2(mkcol(R), mkvecsmall(2));1293S = deg1pol_shallow(gen_1, s, v);1294return mkvec2(mkcol2(R,S), mkvecsmall2(1,1));1295}1296static GEN1297FpX_factor_deg2(GEN f, GEN p, long d, long flag)1298{1299switch(flag) {1300case 2: return FpX_is_irred_2(f, p, d);1301case 1: return FpX_degfact_2(f, p, d);1302default: return FpX_factor_2(f, p, d);1303}1304}13051306static int1307F2x_quad_factortype(GEN x)1308{ return x[2] == 7 ? -1: x[2] == 6 ? 1 :0; }13091310static GEN1311F2x_is_irred_2(GEN f, long d)1312{ return d == 1 || (d==2 && F2x_quad_factortype(f) == -1)? gen_1: NULL; }13131314static GEN1315F2x_degfact_2(GEN f, long d)1316{1317if (!d) return trivial_fact();1318if (d == 1) return mkvec2(mkvecsmall(1), mkvecsmall(1));1319switch(F2x_quad_factortype(f)) {1320case 1: return mkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1));1321case -1:return mkvec2(mkvecsmall(2), mkvecsmall(1));1322default: return mkvec2(mkvecsmall(1), mkvecsmall(2));1323}1324}13251326static GEN1327F2x_factor_2(GEN f, long d)1328{1329long v = f[1];1330if (!d) return mkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL));1331if (labs(d) == 1) return mkvec2(mkcol(f), mkvecsmall(1));1332switch(F2x_quad_factortype(f))1333{1334case -1: return mkvec2(mkcol(f), mkvecsmall(1));1335case 0: return mkvec2(mkcol(mkvecsmall2(v,2+F2x_coeff(f,0))), mkvecsmall(2));1336default: return mkvec2(mkcol2(mkvecsmall2(v,2),mkvecsmall2(v,3)), mkvecsmall2(1,1));1337}1338}1339static GEN1340F2x_factor_deg2(GEN f, long d, long flag)1341{1342switch(flag) {1343case 2: return F2x_is_irred_2(f, d);1344case 1: return F2x_degfact_2(f, d);1345default: return F2x_factor_2(f, d);1346}1347}13481349/* xt = NULL or x^(p-1)/2 mod g */1350static void1351split_squares(struct split_t *S, GEN g, ulong p, GEN xt)1352{1353ulong q = p >> 1;1354GEN a = Flx_mod_Xnm1(g, q, p); /* mod x^(p-1)/2 - 1 */1355long d = degpol(a);1356if (d < 0)1357{1358ulong i;1359split_add_done(S, (GEN)1);1360for (i = 2; i <= q; i++) split_add_done(S, (GEN)Fl_sqr(i,p));1361} else {1362if (a != g) { (void)Flx_valrem(a, &a); d = degpol(a); }1363if (d)1364{1365if (xt) xt = Flx_Fl_add(xt, p-1, p); else xt = Flx_Xnm1(g[1], q, p);1366a = Flx_gcd(a, xt, p);1367if (degpol(a)) split_add(S, Flx_normalize(a, p));1368}1369}1370}1371static void1372split_nonsquares(struct split_t *S, GEN g, ulong p, GEN xt)1373{1374ulong q = p >> 1;1375GEN a = Flx_mod_Xn1(g, q, p); /* mod x^(p-1)/2 + 1 */1376long d = degpol(a);1377if (d < 0)1378{1379ulong i, z = nonsquare_Fl(p);1380split_add_done(S, (GEN)z);1381for (i = 2; i <= q; i++) split_add_done(S, (GEN)Fl_mul(z, Fl_sqr(i,p), p));1382} else {1383if (a != g) { (void)Flx_valrem(a, &a); d = degpol(a); }1384if (d)1385{1386if (xt) xt = Flx_Fl_add(xt, 1, p); else xt = Flx_Xn1(g[1], q, p);1387a = Flx_gcd(a, xt, p);1388if (degpol(a)) split_add(S, Flx_normalize(a, p));1389}1390}1391}1392/* p > 2. f monic Flx, f(0) != 0. Add to split_t structs coprime factors1393* of g = \prod_{f(a) = 0} (X - a). Return 0 when f(x) = 0 for all x in Fp* */1394static int1395split_Flx_cut_out_roots(struct split_t *S, GEN f, ulong p)1396{1397GEN a, g = Flx_mod_Xnm1(f, p-1, p); /* f mod x^(p-1) - 1 */1398long d = degpol(g);1399if (d < 0) return 0;1400if (g != f) { (void)Flx_valrem(g, &g); d = degpol(g); } /*kill powers of x*/1401if (!d) return 1;1402if ((p >> 4) <= (ulong)d)1403{ /* small p; split directly using x^((p-1)/2) +/- 1 */1404GEN xt = ((ulong)d < (p>>1))? Flx_rem(monomial_Flx(1, p>>1, g[1]), g, p)1405: NULL;1406split_squares(S, g, p, xt);1407split_nonsquares(S, g, p, xt);1408} else { /* large p; use x^(p-1) - 1 directly */1409a = Flxq_powu(polx_Flx(f[1]), p-1, g,p);1410if (lg(a) < 3) pari_err_PRIME("rootmod",utoipos(p));1411a = Flx_Fl_add(a, p-1, p); /* a = x^(p-1) - 1 mod g */1412g = Flx_gcd(g,a, p);1413if (degpol(g)) split_add(S, Flx_normalize(g,p));1414}1415return 1;1416}14171418/* by splitting, assume p > 2 prime, deg(f) > 0, and f monic */1419static GEN1420Flx_roots_i(GEN f, ulong p)1421{1422GEN pol, g;1423long v = Flx_valrem(f, &g);1424ulong q;1425struct split_t S;14261427/* optimization: test for small degree first */1428switch(degpol(g))1429{1430case 1: {1431ulong r = p - g[2];1432return v? mkvecsmall2(0, r): mkvecsmall(r);1433}1434case 2: {1435ulong r = Flx_quad_root(g, p, 1), s;1436if (r == p) return v? mkvecsmall(0): cgetg(1,t_VECSMALL);1437s = Flx_otherroot(g,r, p);1438if (r < s)1439return v? mkvecsmall3(0, r, s): mkvecsmall2(r, s);1440else if (r > s)1441return v? mkvecsmall3(0, s, r): mkvecsmall2(s, r);1442else1443return v? mkvecsmall2(0, s): mkvecsmall(s);1444}1445}1446q = p >> 1;1447split_init(&S, lg(f)-1);1448settyp(S.done, t_VECSMALL);1449if (v) split_add_done(&S, (GEN)0);1450if (! split_Flx_cut_out_roots(&S, g, p))1451return all_roots_mod_p(p, lg(S.done) == 1);1452pol = polx_Flx(f[1]);1453for (pol[2]=1; ; pol[2]++)1454{1455long j, l = lg(S.todo);1456if (l == 1) { vecsmall_sort(S.done); return S.done; }1457if (pol[2] == 100 && !uisprime(p)) pari_err_PRIME("polrootsmod",utoipos(p));1458for (j = 1; j < l; j++)1459{1460GEN b, c = gel(S.todo,j);1461ulong r, s;1462switch(degpol(c))1463{1464case 1:1465split_moveto_done(&S, j, (GEN)(p - c[2]));1466j--; l--; break;1467case 2:1468r = Flx_quad_root(c, p, 0);1469if (r == p) pari_err_PRIME("polrootsmod",utoipos(p));1470s = Flx_otherroot(c,r, p);1471split_done(&S, j, (GEN)r, (GEN)s);1472j--; l--; break;1473default:1474b = Flxq_powu(pol,q, c,p); /* pol^(p-1)/2 */1475if (degpol(b) <= 0) continue;1476b = Flx_gcd(c,Flx_Fl_add(b,p-1,p), p);1477if (!degpol(b)) continue;1478b = Flx_normalize(b, p);1479c = Flx_div(c,b, p);1480split_todo(&S, j, b, c);1481}1482}1483}1484}14851486GEN1487Flx_roots(GEN f, ulong p)1488{1489pari_sp av = avma;1490switch(lg(f))1491{1492case 2: pari_err_ROOTS0("Flx_roots");1493case 3: set_avma(av); return cgetg(1, t_VECSMALL);1494}1495if (p == 2) return Flx_root_mod_2(f);1496return gerepileuptoleaf(av, Flx_roots_i(Flx_normalize(f, p), p));1497}14981499/* assume x reduced mod p, monic. */1500static int1501Flx_quad_factortype(GEN x, ulong p)1502{1503ulong b = x[3], c = x[2];1504return krouu(Fl_disc_bc(b, c, p), p);1505}1506static GEN1507Flx_is_irred_2(GEN f, ulong p, long d)1508{1509if (!d) return NULL;1510if (d == 1) return gen_1;1511return Flx_quad_factortype(f, p) == -1? gen_1: NULL;1512}1513static GEN1514Flx_degfact_2(GEN f, ulong p, long d)1515{1516if (!d) return trivial_fact();1517if (d == 1) return mkvec2(mkvecsmall(1), mkvecsmall(1));1518switch(Flx_quad_factortype(f, p)) {1519case 1: return mkvec2(mkvecsmall2(1,1), mkvecsmall2(1,1));1520case -1:return mkvec2(mkvecsmall(2), mkvecsmall(1));1521default: return mkvec2(mkvecsmall(1), mkvecsmall(2));1522}1523}1524/* p > 2 */1525static GEN1526Flx_factor_2(GEN f, ulong p, long d)1527{1528ulong r, s;1529GEN R,S;1530long v = f[1];1531if (!d) return mkvec2(cgetg(1,t_COL), cgetg(1,t_VECSMALL));1532if (labs(d) == 1) return mkvec2(mkcol(f), mkvecsmall(1));1533r = Flx_quad_root(f, p, 1);1534if (r==p) return mkvec2(mkcol(f), mkvecsmall(1));1535s = Flx_otherroot(f, r, p);1536r = Fl_neg(r, p);1537s = Fl_neg(s, p);1538if (s < r) lswap(s,r);1539R = mkvecsmall3(v,r,1);1540if (s == r) return mkvec2(mkcol(R), mkvecsmall(2));1541S = mkvecsmall3(v,s,1);1542return mkvec2(mkcol2(R,S), mkvecsmall2(1,1));1543}1544static GEN1545Flx_factor_deg2(GEN f, ulong p, long d, long flag)1546{1547switch(flag) {1548case 2: return Flx_is_irred_2(f, p, d);1549case 1: return Flx_degfact_2(f, p, d);1550default: return Flx_factor_2(f, p, d);1551}1552}15531554static GEN1555F2x_Berlekamp_ker(GEN u)1556{1557pari_sp ltop=avma;1558long j,N = F2x_degree(u);1559GEN Q;1560pari_timer T;1561timer_start(&T);1562Q = F2x_matFrobenius(u);1563for (j=1; j<=N; j++)1564F2m_flip(Q,j,j);1565if(DEBUGLEVEL>=9) timer_printf(&T,"Berlekamp matrix");1566Q = F2m_ker_sp(Q,0);1567if(DEBUGLEVEL>=9) timer_printf(&T,"kernel");1568return gerepileupto(ltop,Q);1569}1570#define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;}1571static long1572F2x_split_Berlekamp(GEN *t)1573{1574GEN u = *t, a, b, vker;1575long lb, d, i, ir, L, la, sv = u[1], du = F2x_degree(u);15761577if (du == 1) return 1;1578if (du == 2)1579{1580if (F2x_quad_factortype(u) == 1) /* 0 is a root: shouldn't occur */1581{1582t[0] = mkvecsmall2(sv, 2);1583t[1] = mkvecsmall2(sv, 3);1584return 2;1585}1586return 1;1587}15881589vker = F2x_Berlekamp_ker(u);1590lb = lgcols(vker);1591d = lg(vker)-1;1592ir = 0;1593/* t[i] irreducible for i < ir, still to be treated for i < L */1594for (L=1; L<d; )1595{1596GEN pol;1597if (d == 2)1598pol = F2v_to_F2x(gel(vker,2), sv);1599else1600{1601GEN v = zero_zv(lb);1602v[1] = du;1603v[2] = random_Fl(2); /*Assume vker[1]=1*/1604for (i=2; i<=d; i++)1605if (random_Fl(2)) F2v_add_inplace(v, gel(vker,i));1606pol = F2v_to_F2x(v, sv);1607}1608for (i=ir; i<L && L<d; i++)1609{1610a = t[i]; la = F2x_degree(a);1611if (la == 1) { set_irred(i); }1612else if (la == 2)1613{1614if (F2x_quad_factortype(a) == 1) /* 0 is a root: shouldn't occur */1615{1616t[i] = mkvecsmall2(sv, 2);1617t[L] = mkvecsmall2(sv, 3); L++;1618}1619set_irred(i);1620}1621else1622{1623pari_sp av = avma;1624long lb;1625b = F2x_rem(pol, a);1626if (F2x_degree(b) <= 0) { set_avma(av); continue; }1627b = F2x_gcd(a,b); lb = F2x_degree(b);1628if (lb && lb < la)1629{1630t[L] = F2x_div(a,b);1631t[i]= b; L++;1632}1633else set_avma(av);1634}1635}1636}1637return d;1638}1639/* assume deg f > 2 */1640static GEN1641F2x_Berlekamp_i(GEN f, long flag)1642{1643long lfact, val, d = F2x_degree(f), j, k, lV;1644GEN y, E, t, V;16451646val = F2x_valrem(f, &f);1647if (flag == 2 && val) return NULL;1648V = F2x_factor_squarefree(f); lV = lg(V);1649if (flag == 2 && lV > 2) return NULL;16501651/* to hold factors and exponents */1652t = cgetg(d+1, flag? t_VECSMALL: t_VEC);1653E = cgetg(d+1,t_VECSMALL);1654lfact = 1;1655if (val) {1656if (flag == 1) t[1] = 1; else gel(t,1) = polx_F2x(f[1]);1657E[1] = val; lfact++;1658}16591660for (k=1; k<lV; k++)1661{1662if (F2x_degree(gel(V, k))==0) continue;1663gel(t,lfact) = gel(V, k);1664d = F2x_split_Berlekamp(&gel(t,lfact));1665if (flag == 2 && d != 1) return NULL;1666if (flag == 1)1667for (j=0; j<d; j++) t[lfact+j] = F2x_degree(gel(t,lfact+j));1668for (j=0; j<d; j++) E[lfact+j] = k;1669lfact += d;1670}1671if (flag == 2) return gen_1; /* irreducible */1672setlg(t, lfact);1673setlg(E, lfact); y = mkvec2(t,E);1674return flag ? sort_factor(y, (void*)&cmpGuGu, cmp_nodata)1675: sort_factor_pol(y, cmpGuGu);1676}16771678/* Adapted from Shoup NTL */1679GEN1680F2x_factor_squarefree(GEN f)1681{1682GEN r, t, v, tv;1683long i, q, n = F2x_degree(f);1684GEN u = const_vec(n+1, pol1_F2x(f[1]));1685for(q = 1;;q *= 2)1686{1687r = F2x_gcd(f, F2x_deriv(f));1688if (F2x_degree(r) == 0)1689{1690gel(u, q) = f;1691break;1692}1693t = F2x_div(f, r);1694if (F2x_degree(t) > 0)1695{1696long j;1697for(j = 1;;j++)1698{1699v = F2x_gcd(r, t);1700tv = F2x_div(t, v);1701if (F2x_degree(tv) > 0)1702gel(u, j*q) = tv;1703if (F2x_degree(v) <= 0) break;1704r = F2x_div(r, v);1705t = v;1706}1707if (F2x_degree(r) == 0) break;1708}1709f = F2x_sqrt(r);1710}1711for (i = n; i; i--)1712if (F2x_degree(gel(u,i))) break;1713setlg(u,i+1); return u;1714}17151716static GEN1717F2x_ddf_simple(GEN T, GEN XP)1718{1719pari_sp av = avma, av2;1720GEN f, z, Tr, X;1721long j, n = F2x_degree(T), v = T[1], B = n/2;1722if (n == 0) return cgetg(1, t_VEC);1723if (n == 1) return mkvec(T);1724z = XP; Tr = T; X = polx_F2x(v);1725f = const_vec(n, pol1_F2x(v));1726av2 = avma;1727for (j = 1; j <= B; j++)1728{1729GEN u = F2x_gcd(Tr, F2x_add(z, X));1730if (F2x_degree(u))1731{1732gel(f, j) = u;1733Tr = F2x_div(Tr, u);1734av2 = avma;1735} else z = gerepileuptoleaf(av2, z);1736if (!F2x_degree(Tr)) break;1737z = F2xq_sqr(z, Tr);1738}1739if (F2x_degree(Tr)) gel(f, F2x_degree(Tr)) = Tr;1740return gerepilecopy(av, f);1741}17421743GEN1744F2x_ddf(GEN T)1745{1746GEN XP;1747T = F2x_get_red(T);1748XP = F2x_Frobenius(T);1749return F2x_ddf_to_ddf2(F2x_ddf_simple(T, XP));1750}17511752static GEN1753F2xq_frobtrace(GEN a, long d, GEN T)1754{1755pari_sp av = avma;1756long i;1757GEN x = a;1758for(i=1; i<d; i++)1759{1760x = F2x_add(a, F2xq_sqr(x,T));1761if (gc_needed(av, 2))1762x = gerepileuptoleaf(av, x);1763}1764return x;1765}17661767static void1768F2x_edf_simple(GEN Tp, GEN XP, long d, GEN V, long idx)1769{1770long n = F2x_degree(Tp), r = n/d;1771GEN T, f, ff;1772if (r==1) { gel(V, idx) = Tp; return; }1773T = Tp;1774XP = F2x_rem(XP, T);1775while (1)1776{1777pari_sp btop = avma;1778long df;1779GEN g = random_F2x(n, Tp[1]);1780GEN t = F2xq_frobtrace(g, d, T);1781if (lgpol(t) == 0) continue;1782f = F2x_gcd(t, Tp); df = F2x_degree(f);1783if (df > 0 && df < n) break;1784set_avma(btop);1785}1786ff = F2x_div(Tp, f);1787F2x_edf_simple(f, XP, d, V, idx);1788F2x_edf_simple(ff, XP, d, V, idx+F2x_degree(f)/d);1789}17901791static GEN1792F2x_factor_Shoup(GEN T)1793{1794long i, n, s = 0;1795GEN XP, D, V;1796pari_timer ti;1797n = F2x_degree(T);1798if (DEBUGLEVEL>=6) timer_start(&ti);1799XP = F2x_Frobenius(T);1800if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius");1801D = F2x_ddf_simple(T, XP);1802if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple");1803for (i = 1; i <= n; i++)1804s += F2x_degree(gel(D,i))/i;1805V = cgetg(s+1, t_COL);1806for (i = 1, s = 1; i <= n; i++)1807{1808GEN Di = gel(D,i);1809long ni = F2x_degree(Di), ri = ni/i;1810if (ni == 0) continue;1811if (ni == i) { gel(V, s++) = Di; continue; }1812F2x_edf_simple(Di, XP, i, V, s);1813if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_edf(%ld)",i);1814s += ri;1815}1816return V;1817}18181819static GEN1820F2x_factor_Cantor(GEN T)1821{1822GEN E, F, V = F2x_factor_squarefree(T);1823long i, j, l = lg(V);1824E = cgetg(l, t_VEC);1825F = cgetg(l, t_VEC);1826for (i=1, j=1; i < l; i++)1827if (F2x_degree(gel(V,i)))1828{1829GEN Fj = F2x_factor_Shoup(gel(V,i));1830gel(F, j) = Fj;1831gel(E, j) = const_vecsmall(lg(Fj)-1, i);1832j++;1833}1834return sort_factor_pol(FE_concat(F,E,j), cmpGuGu);1835}18361837#if 01838static GEN1839F2x_simplefact_Shoup(GEN T)1840{1841long i, n, s = 0, j = 1, k;1842GEN XP, D, V;1843pari_timer ti;1844n = F2x_degree(T);1845if (DEBUGLEVEL>=6) timer_start(&ti);1846XP = F2x_Frobenius(T);1847if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius");1848D = F2x_ddf_simple(T, XP);1849if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple");1850for (i = 1; i <= n; i++)1851s += F2x_degree(gel(D,i))/i;1852V = cgetg(s+1, t_VECSMALL);1853for (i = 1; i <= n; i++)1854{1855long ni = F2x_degree(gel(D,i)), ri = ni/i;1856if (ni == 0) continue;1857for (k = 1; k <= ri; k++)1858V[j++] = i;1859}1860return V;1861}1862static GEN1863F2x_simplefact_Cantor(GEN T)1864{1865GEN E, F, V = F2x_factor_squarefree(T);1866long i, j, l = lg(V);1867F = cgetg(l, t_VEC);1868E = cgetg(l, t_VEC);1869for (i=1, j=1; i < l; i++)1870if (F2x_degree(gel(V,i)))1871{1872GEN Fj = F2x_simplefact_Shoup(gel(V,i));1873gel(F, j) = Fj;1874gel(E, j) = const_vecsmall(lg(Fj)-1, i);1875j++;1876}1877return sort_factor(FE_concat(F,E,j), (void*)&cmpGuGu, cmp_nodata);1878}1879static int1880F2x_isirred_Cantor(GEN T)1881{1882pari_sp av = avma;1883pari_timer ti;1884long n;1885GEN dT = F2x_deriv(T);1886GEN XP, D;1887if (F2x_degree(F2x_gcd(T, dT)) != 0) return gc_bool(av,0);1888n = F2x_degree(T);1889if (DEBUGLEVEL>=6) timer_start(&ti);1890XP = F2x_Frobenius(T);1891if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_Frobenius");1892D = F2x_ddf_simple(T, XP);1893if (DEBUGLEVEL>=6) timer_printf(&ti,"F2x_ddf_simple");1894return gc_bool(av, F2x_degree(gel(D,n)) == n);1895}1896#endif18971898/* driver for Cantor factorization, assume deg f > 2; not competitive for1899* flag != 0, or as deg f increases */1900static GEN1901F2x_Cantor_i(GEN f, long flag)1902{1903switch(flag)1904{1905default: return F2x_factor_Cantor(f);1906#if 01907case 1: return F2x_simplefact_Cantor(f);1908case 2: return F2x_isirred_Cantor(f)? gen_1: NULL;1909#endif1910}1911}1912static GEN1913F2x_factor_i(GEN f, long flag)1914{1915long d = F2x_degree(f);1916if (d <= 2) return F2x_factor_deg2(f,d,flag);1917return (flag == 0 && d <= 20)? F2x_Cantor_i(f, flag)1918: F2x_Berlekamp_i(f, flag);1919}19201921GEN1922F2x_degfact(GEN f)1923{1924pari_sp av = avma;1925GEN z = F2x_factor_i(f, 1);1926return gerepilecopy(av, z);1927}19281929int1930F2x_is_irred(GEN f) { return !!F2x_factor_i(f, 2); }19311932/* Adapted from Shoup NTL */1933GEN1934Flx_factor_squarefree(GEN f, ulong p)1935{1936long i, q, n = degpol(f);1937GEN u = const_vec(n+1, pol1_Flx(f[1]));1938for(q = 1;;q *= p)1939{1940GEN t, v, tv, r = Flx_gcd(f, Flx_deriv(f, p), p);1941if (degpol(r) == 0) { gel(u, q) = f; break; }1942t = Flx_div(f, r, p);1943if (degpol(t) > 0)1944{1945long j;1946for(j = 1;;j++)1947{1948v = Flx_gcd(r, t, p);1949tv = Flx_div(t, v, p);1950if (degpol(tv) > 0)1951gel(u, j*q) = Flx_normalize(tv, p);1952if (degpol(v) <= 0) break;1953r = Flx_div(r, v, p);1954t = v;1955}1956if (degpol(r) == 0) break;1957}1958f = Flx_normalize(Flx_deflate(r, p), p);1959}1960for (i = n; i; i--)1961if (degpol(gel(u,i))) break;1962setlg(u,i+1); return u;1963}19641965long1966Flx_ispower(GEN f, ulong k, ulong p, GEN *pt_r)1967{1968pari_sp av = avma;1969ulong lc;1970GEN F;1971long i, n = degpol(f), v = f[1], l;1972if (n % k) return 0;1973lc = Fl_sqrtn(Flx_lead(f), k, p, NULL);1974if (lc == ULONG_MAX) { av = avma; return 0; }1975F = Flx_factor_squarefree(f, p); l = lg(F)-1;1976for (i = 1; i <= l; i++)1977if (i%k && degpol(gel(F,i))) return gc_long(av,0);1978if (pt_r)1979{1980GEN r = Fl_to_Flx(lc, v), s = pol1_Flx(v);1981for(i = l; i >= 1; i--)1982{1983if (i%k) continue;1984s = Flx_mul(s, gel(F,i), p);1985r = Flx_mul(r, s, p);1986}1987*pt_r = gerepileuptoleaf(av, r);1988} else set_avma(av);1989return 1;1990}19911992/* See <http://www.shoup.net/papers/factorimpl.pdf> */1993static GEN1994Flx_ddf_Shoup(GEN T, GEN XP, ulong p)1995{1996pari_sp av = avma;1997GEN b, g, h, F, f, Tr, xq;1998long i, j, n, v, bo, ro;1999long B, l, m;2000pari_timer ti;2001n = get_Flx_degree(T); v = get_Flx_var(T);2002if (n == 0) return cgetg(1, t_VEC);2003if (n == 1) return mkvec(get_Flx_mod(T));2004B = n/2;2005l = usqrt(B);2006m = (B+l-1)/l;2007T = Flx_get_red(T, p);2008b = cgetg(l+2, t_VEC);2009gel(b, 1) = polx_Flx(v);2010gel(b, 2) = XP;2011bo = brent_kung_optpow(n, l-1, 1);2012ro = l<=1 ? 0:(bo-1)/(l-1) + ((n-1)/bo);2013if (DEBUGLEVEL>=7) timer_start(&ti);2014if (expu(p) <= ro)2015for (i = 3; i <= l+1; i++)2016gel(b, i) = Flxq_powu(gel(b, i-1), p, T, p);2017else2018{2019xq = Flxq_powers(gel(b, 2), bo, T, p);2020if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: xq baby");2021for (i = 3; i <= l+1; i++)2022gel(b, i) = Flx_FlxqV_eval(gel(b, i-1), xq, T, p);2023}2024if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: baby");2025xq = Flxq_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), T, p);2026if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: xq giant");2027g = cgetg(m+1, t_VEC);2028gel(g, 1) = gel(xq, 2);2029for(i = 2; i <= m; i++)2030gel(g, i) = Flx_FlxqV_eval(gel(g, i-1), xq, T, p);2031if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: giant");2032h = cgetg(m+1, t_VEC);2033for (j = 1; j <= m; j++)2034{2035pari_sp av = avma;2036GEN gj = gel(g, j);2037GEN e = Flx_sub(gj, gel(b, 1), p);2038for (i = 2; i <= l; i++)2039e = Flxq_mul(e, Flx_sub(gj, gel(b, i), p), T, p);2040gel(h, j) = gerepileupto(av, e);2041}2042if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: diff");2043Tr = get_Flx_mod(T);2044F = cgetg(m+1, t_VEC);2045for (j = 1; j <= m; j++)2046{2047GEN u = Flx_gcd(Tr, gel(h, j), p);2048if (degpol(u))2049{2050u = Flx_normalize(u, p);2051Tr = Flx_div(Tr, u, p);2052}2053gel(F, j) = u;2054}2055if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: F");2056f = const_vec(n, pol1_Flx(v));2057for (j = 1; j <= m; j++)2058{2059GEN e = gel(F, j);2060for (i=l-1; i >= 0; i--)2061{2062GEN u = Flx_gcd(e, Flx_sub(gel(g, j), gel(b, i+1), p), p);2063if (degpol(u))2064{2065gel(f, l*j-i) = u;2066e = Flx_div(e, u, p);2067}2068if (!degpol(e)) break;2069}2070}2071if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_ddf_Shoup: f");2072if (degpol(Tr)) gel(f, degpol(Tr)) = Tr;2073return gerepilecopy(av, f);2074}20752076static void2077Flx_edf_simple(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx)2078{2079long n = degpol(Tp), r = n/d;2080GEN T, f, ff;2081ulong p2;2082if (r==1) { gel(V, idx) = Tp; return; }2083p2 = p>>1;2084T = Flx_get_red(Tp, p);2085XP = Flx_rem(XP, T, p);2086while (1)2087{2088pari_sp btop = avma;2089long i;2090GEN g = random_Flx(n, Tp[1], p);2091GEN t = gel(Flxq_auttrace(mkvec2(XP, g), d, T, p), 2);2092if (lgpol(t) == 0) continue;2093for(i=1; i<=10; i++)2094{2095pari_sp btop2 = avma;2096GEN R = Flxq_powu(Flx_Fl_add(t, random_Fl(p), p), p2, T, p);2097f = Flx_gcd(Flx_Fl_add(R, p-1, p), Tp, p);2098if (degpol(f) > 0 && degpol(f) < n) break;2099set_avma(btop2);2100}2101if (degpol(f) > 0 && degpol(f) < n) break;2102set_avma(btop);2103}2104f = Flx_normalize(f, p);2105ff = Flx_div(Tp, f ,p);2106Flx_edf_simple(f, XP, d, p, V, idx);2107Flx_edf_simple(ff, XP, d, p, V, idx+degpol(f)/d);2108}2109static void2110Flx_edf(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx);21112112static void2113Flx_edf_rec(GEN T, GEN XP, GEN hp, GEN t, long d, ulong p, GEN V, long idx)2114{2115pari_sp av;2116GEN Tp = get_Flx_mod(T);2117long n = degpol(hp), vT = Tp[1];2118GEN u1, u2, f1, f2;2119ulong p2 = p>>1;2120GEN R, h;2121h = Flx_get_red(hp, p);2122t = Flx_rem(t, T, p);2123av = avma;2124do2125{2126set_avma(av);2127R = Flxq_powu(mkvecsmall3(vT, random_Fl(p), 1), p2, h, p);2128u1 = Flx_gcd(Flx_Fl_add(R, p-1, p), hp, p);2129} while (degpol(u1)==0 || degpol(u1)==n);2130f1 = Flx_gcd(Flx_Flxq_eval(u1, t, T, p), Tp, p);2131f1 = Flx_normalize(f1, p);2132u2 = Flx_div(hp, u1, p);2133f2 = Flx_div(Tp, f1, p);2134if (degpol(u1)==1)2135{2136if (degpol(f1)==d)2137gel(V, idx) = f1;2138else2139Flx_edf(f1, XP, d, p, V, idx);2140}2141else2142Flx_edf_rec(Flx_get_red(f1, p), XP, u1, t, d, p, V, idx);2143idx += degpol(f1)/d;2144if (degpol(u2)==1)2145{2146if (degpol(f2)==d)2147gel(V, idx) = f2;2148else2149Flx_edf(f2, XP, d, p, V, idx);2150}2151else2152Flx_edf_rec(Flx_get_red(f2, p), XP, u2, t, d, p, V, idx);2153}21542155static void2156Flx_edf(GEN Tp, GEN XP, long d, ulong p, GEN V, long idx)2157{2158long n = degpol(Tp), r = n/d, vT = Tp[1];2159GEN T, h, t;2160pari_timer ti;2161if (r==1) { gel(V, idx) = Tp; return; }2162T = Flx_get_red(Tp, p);2163XP = Flx_rem(XP, T, p);2164if (DEBUGLEVEL>=7) timer_start(&ti);2165do2166{2167GEN g = random_Flx(n, vT, p);2168t = gel(Flxq_auttrace(mkvec2(XP, g), d, T, p), 2);2169if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_edf: Flxq_auttrace");2170h = Flxq_minpoly(t, T, p);2171if (DEBUGLEVEL>=7) timer_printf(&ti,"Flx_edf: Flxq_minpoly");2172} while (degpol(h) <= 1);2173Flx_edf_rec(T, XP, h, t, d, p, V, idx);2174}21752176static GEN2177Flx_factor_Shoup(GEN T, ulong p)2178{2179long i, n, s = 0;2180GEN XP, D, V;2181long e = expu(p);2182pari_timer ti;2183n = get_Flx_degree(T);2184T = Flx_get_red(T, p);2185if (DEBUGLEVEL>=6) timer_start(&ti);2186XP = Flx_Frobenius(T, p);2187if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius");2188D = Flx_ddf_Shoup(T, XP, p);2189if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup");2190s = ddf_to_nbfact(D);2191V = cgetg(s+1, t_COL);2192for (i = 1, s = 1; i <= n; i++)2193{2194GEN Di = gel(D,i);2195long ni = degpol(Di), ri = ni/i;2196if (ni == 0) continue;2197Di = Flx_normalize(Di, p);2198if (ni == i) { gel(V, s++) = Di; continue; }2199if (ri <= e*expu(e))2200Flx_edf(Di, XP, i, p, V, s);2201else2202Flx_edf_simple(Di, XP, i, p, V, s);2203if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_edf(%ld)",i);2204s += ri;2205}2206return V;2207}22082209static GEN2210Flx_factor_Cantor(GEN T, ulong p)2211{2212GEN E, F, V = Flx_factor_squarefree(get_Flx_mod(T), p);2213long i, j, l = lg(V);2214F = cgetg(l, t_VEC);2215E = cgetg(l, t_VEC);2216for (i=1, j=1; i < l; i++)2217if (degpol(gel(V,i)))2218{2219GEN Fj = Flx_factor_Shoup(gel(V,i), p);2220gel(F, j) = Fj;2221gel(E, j) = const_vecsmall(lg(Fj)-1, i);2222j++;2223}2224return sort_factor_pol(FE_concat(F,E,j), cmpGuGu);2225}22262227GEN2228Flx_ddf(GEN T, ulong p)2229{2230GEN XP;2231T = Flx_get_red(T, p);2232XP = Flx_Frobenius(T, p);2233return ddf_to_ddf2(Flx_ddf_Shoup(T, XP, p));2234}22352236static GEN2237Flx_simplefact_Cantor(GEN T, ulong p)2238{2239GEN V;2240long i, l;2241T = Flx_get_red(T, p);2242V = Flx_factor_squarefree(get_Flx_mod(T), p); l = lg(V);2243for (i=1; i < l; i++)2244gel(V,i) = Flx_ddf_Shoup(gel(V,i), Flx_Frobenius(gel(V,i), p), p);2245return vddf_to_simplefact(V, get_Flx_degree(T));2246}22472248static int2249Flx_isirred_Cantor(GEN Tp, ulong p)2250{2251pari_sp av = avma;2252pari_timer ti;2253long n;2254GEN T = get_Flx_mod(Tp), dT = Flx_deriv(T, p), XP, D;2255if (degpol(Flx_gcd(T, dT, p)) != 0) return gc_bool(av,0);2256n = get_Flx_degree(T);2257T = Flx_get_red(Tp, p);2258if (DEBUGLEVEL>=6) timer_start(&ti);2259XP = Flx_Frobenius(T, p);2260if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius");2261D = Flx_ddf_Shoup(T, XP, p);2262if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup");2263return gc_bool(av, degpol(gel(D,n)) == n);2264}22652266/* f monic */2267static GEN2268Flx_factor_i(GEN f, ulong pp, long flag)2269{2270long d;2271if (pp==2) { /*We need to handle 2 specially */2272GEN F = F2x_factor_i(Flx_to_F2x(f),flag);2273if (flag==0) F2xV_to_FlxV_inplace(gel(F,1));2274return F;2275}2276d = degpol(f);2277if (d <= 2) return Flx_factor_deg2(f,pp,d,flag);2278switch(flag)2279{2280default: return Flx_factor_Cantor(f, pp);2281case 1: return Flx_simplefact_Cantor(f, pp);2282case 2: return Flx_isirred_Cantor(f, pp)? gen_1: NULL;2283}2284}22852286GEN2287Flx_degfact(GEN f, ulong p)2288{2289pari_sp av = avma;2290GEN z = Flx_factor_i(Flx_normalize(f,p),p,1);2291return gerepilecopy(av, z);2292}22932294/* T must be squarefree mod p*/2295GEN2296Flx_nbfact_by_degree(GEN T, long *nb, ulong p)2297{2298GEN XP, D;2299pari_timer ti;2300long i, s, n = get_Flx_degree(T);2301GEN V = const_vecsmall(n, 0);2302pari_sp av = avma;2303T = Flx_get_red(T, p);2304if (DEBUGLEVEL>=6) timer_start(&ti);2305XP = Flx_Frobenius(T, p);2306if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_Frobenius");2307D = Flx_ddf_Shoup(T, XP, p);2308if (DEBUGLEVEL>=6) timer_printf(&ti,"Flx_ddf_Shoup");2309for (i = 1, s = 0; i <= n; i++)2310{2311V[i] = degpol(gel(D,i))/i;2312s += V[i];2313}2314*nb = s;2315set_avma(av); return V;2316}23172318long2319Flx_nbfact_Frobenius(GEN T, GEN XP, ulong p)2320{2321pari_sp av = avma;2322long s = ddf_to_nbfact(Flx_ddf_Shoup(T, XP, p));2323return gc_long(av,s);2324}23252326/* T must be squarefree mod p*/2327long2328Flx_nbfact(GEN T, ulong p)2329{2330pari_sp av = avma;2331GEN XP = Flx_Frobenius(T, p);2332long n = Flx_nbfact_Frobenius(T, XP, p);2333return gc_long(av,n);2334}23352336int2337Flx_is_irred(GEN f, ulong p)2338{2339pari_sp av = avma;2340f = Flx_normalize(f,p);2341return gc_bool(av, !!Flx_factor_i(f,p,2));2342}23432344/* Use this function when you think f is reducible, and that there are lots of2345* factors. If you believe f has few factors, use FpX_nbfact(f,p)==1 instead */2346int2347FpX_is_irred(GEN f, GEN p)2348{2349pari_sp av = avma;2350int z;2351switch(ZX_factmod_init(&f,p))2352{2353case 0: z = !!F2x_factor_i(f,2); break;2354case 1: z = !!Flx_factor_i(f,p[2],2); break;2355default: z = !!FpX_factor_i(f,p,2); break;2356}2357return gc_bool(av,z);2358}2359GEN2360FpX_degfact(GEN f, GEN p) {2361pari_sp av = avma;2362GEN F;2363switch(ZX_factmod_init(&f,p))2364{2365case 0: F = F2x_factor_i(f,1); break;2366case 1: F = Flx_factor_i(f,p[2],1); break;2367default: F = FpX_factor_i(f,p,1); break;2368}2369return gerepilecopy(av, F);2370}23712372#if 02373/* set x <-- x + c*y mod p */2374/* x is not required to be normalized.*/2375static void2376Flx_addmul_inplace(GEN gx, GEN gy, ulong c, ulong p)2377{2378long i, lx, ly;2379ulong *x=(ulong *)gx;2380ulong *y=(ulong *)gy;2381if (!c) return;2382lx = lg(gx);2383ly = lg(gy);2384if (lx<ly) pari_err_BUG("lx<ly in Flx_addmul_inplace");2385if (SMALL_ULONG(p))2386for (i=2; i<ly; i++) x[i] = (x[i] + c*y[i]) % p;2387else2388for (i=2; i<ly; i++) x[i] = Fl_add(x[i], Fl_mul(c,y[i],p),p);2389}2390#endif23912392GEN2393FpX_factor(GEN f, GEN p)2394{2395pari_sp av = avma;2396GEN F;2397switch(ZX_factmod_init(&f, p))2398{2399case 0: F = F2x_factor_i(f,0);2400F2xV_to_ZXV_inplace(gel(F,1)); break;2401case 1: F = Flx_factor_i(f,p[2],0);2402FlxV_to_ZXV_inplace(gel(F,1)); break;2403default: F = FpX_factor_i(f,p,0); break;2404}2405return gerepilecopy(av, F);2406}24072408GEN2409Flx_factor(GEN f, ulong p)2410{2411pari_sp av = avma;2412return gerepilecopy(av, Flx_factor_i(Flx_normalize(f,p),p,0));2413}2414GEN2415F2x_factor(GEN f)2416{2417pari_sp av = avma;2418return gerepilecopy(av, F2x_factor_i(f,0));2419}242024212422