Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2016 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_factorff1819/*******************************************************************/20/** **/21/** Isomorphisms between finite fields **/22/** **/23/*******************************************************************/24static void25err_Flxq(const char *s, GEN P, ulong l)26{27if (!uisprime(l)) pari_err_PRIME(s, utoi(l));28pari_err_IRREDPOL(s, Flx_to_ZX(get_Flx_mod(P)));29}30static void31err_FpXQ(const char *s, GEN P, GEN l)32{33if (!BPSW_psp(l)) pari_err_PRIME(s, l);34pari_err_IRREDPOL(s, get_FpX_mod(P));35}3637/* compute the reciprocical isomorphism of S mod T,p, i.e. V such that38V(S)=X mod T,p*/39GEN40Flxq_ffisom_inv(GEN S,GEN T, ulong p)41{42pari_sp ltop = avma;43long n = get_Flx_degree(T);44GEN M = Flxq_matrix_pow(S,n,n,T,p);45GEN V = Flm_Flc_invimage(M, vecsmall_ei(n, 2), p);46if (!V) err_Flxq("Flxq_ffisom_inv", T, p);47return gerepileupto(ltop, Flv_to_Flx(V, get_Flx_var(T)));48}4950GEN51FpXQ_ffisom_inv(GEN S,GEN T, GEN p)52{53pari_sp ltop = avma;54long n = get_FpX_degree(T);55GEN M = FpXQ_matrix_pow(S,n,n,T,p);56GEN V = FpM_FpC_invimage(M, col_ei(n, 2), p);57if (!V) err_FpXQ("Flxq_ffisom_inv", T, p);58return gerepilecopy(ltop, RgV_to_RgX(V, get_FpX_var(T)));59}6061/* Let M the matrix of the Frobenius automorphism of Fp[X]/(T). Compute M^d62* TODO: use left-right binary (tricky!) */63GEN64Flm_Frobenius_pow(GEN M, long d, GEN T, ulong p)65{66pari_sp ltop=avma;67long i,l = get_Flx_degree(T);68GEN R, W = gel(M,2);69for (i = 2; i <= d; ++i) W = Flm_Flc_mul(M,W,p);70R=Flxq_matrix_pow(Flv_to_Flx(W,get_Flx_var(T)),l,l,T,p);71return gerepileupto(ltop,R);72}7374GEN75FpM_Frobenius_pow(GEN M, long d, GEN T, GEN p)76{77pari_sp ltop=avma;78long i,l = get_FpX_degree(T);79GEN R, W = gel(M,2);80for (i = 2; i <= d; ++i) W = FpM_FpC_mul(M,W,p);81R=FpXQ_matrix_pow(RgV_to_RgX(W, get_FpX_var(T)),l,l,T,p);82return gerepilecopy(ltop,R);83}8485/* Essentially we want to compute FqM_ker(MA-pol_x(v),U,l)86* To avoid use of matrix in Fq we compute FpM_ker(U(MA),l) then recover the87* eigenvalue by Galois action */88static GEN89Flx_Flm_Flc_eval(GEN U, GEN MA, GEN a, ulong p)90{91long i, l = lg(U);92GEN b = Flv_Fl_mul(a, uel(U, l-1), p);93for (i=l-2; i>=2; i--)94b = Flv_add(Flm_Flc_mul(MA, b, p), Flv_Fl_mul(a, uel(U, i), p), p);95return b;96}9798static GEN99Flx_intersect_ker(GEN P, GEN MA, GEN U, ulong p)100{101pari_sp ltop = avma;102long i, vp = get_Flx_var(P), vu = get_Flx_var(U), r = get_Flx_degree(U);103GEN V, A, R;104ulong ib0;105pari_timer T;106if (DEBUGLEVEL>=4) timer_start(&T);107V = Flx_div(Flx_Fl_add(monomial_Flx(1, get_Flx_degree(P), vu), p-1, p), U, p);108do109{110A = Flx_Flm_Flc_eval(V, MA, random_Flv(lg(MA)-1, p), p);111} while (zv_equal0(A));112if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");113/*The formula is114* a_{r-1} = -\phi(a_0)/b_0115* a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1116* Where a_0=A[1] and b_i=U[i+2] */117ib0 = Fl_inv(Fl_neg(U[2], p), p);118R = cgetg(r+1,t_MAT);119gel(R,1) = A;120gel(R,r) = Flm_Flc_mul(MA, Flv_Fl_mul(A,ib0, p), p);121for(i=r-1; i>1; i--)122{123gel(R,i) = Flm_Flc_mul(MA,gel(R,i+1),p);124Flv_add_inplace(gel(R,i), Flv_Fl_mul(gel(R,r), U[i+2], p), p);125}126return gerepileupto(ltop, Flm_to_FlxX(Flm_transpose(R),vp,vu));127}128129static GEN130FpX_FpM_FpC_eval(GEN U, GEN MA, GEN a, GEN p)131{132long i, l = lg(U);133GEN b = FpC_Fp_mul(a, gel(U, l-1), p);134for (i=l-2; i>=2; i--)135b = FpC_add(FpM_FpC_mul(MA, b, p), FpC_Fp_mul(a, gel(U, i), p), p);136return b;137}138139static GEN140FpX_intersect_ker(GEN P, GEN MA, GEN U, GEN l)141{142pari_sp ltop = avma;143long i, vp = get_FpX_var(P), vu = get_FpX_var(U), r = get_FpX_degree(U);144GEN V, A, R, ib0;145pari_timer T;146if (DEBUGLEVEL>=4) timer_start(&T);147V = FpX_div(FpX_Fp_sub(pol_xn(get_FpX_degree(P), vu), gen_1, l), U, l);148do149{150A = FpX_FpM_FpC_eval(V, MA, random_FpC(lg(MA)-1, l), l);151} while (ZV_equal0(A));152if (DEBUGLEVEL>=4) timer_printf(&T,"matrix polcyclo");153/*The formula is154* a_{r-1} = -\phi(a_0)/b_0155* a_{i-1} = \phi(a_i)+b_ia_{r-1} i=r-1 to 1156* Where a_0=A[1] and b_i=U[i+2] */157ib0 = Fp_inv(negi(gel(U,2)),l);158R = cgetg(r+1,t_MAT);159gel(R,1) = A;160gel(R,r) = FpM_FpC_mul(MA, FpC_Fp_mul(A,ib0,l), l);161for(i=r-1;i>1;i--)162gel(R,i) = FpC_add(FpM_FpC_mul(MA,gel(R,i+1),l),163FpC_Fp_mul(gel(R,r), gel(U,i+2), l),l);164return gerepilecopy(ltop,RgM_to_RgXX(shallowtrans(R),vp,vu));165}166167/* n must divide both the degree of P and Q. Compute SP and SQ such168* that the subfield of FF_l[X]/(P) generated by SP and the subfield of169* FF_l[X]/(Q) generated by SQ are isomorphic of degree n. P and Q do170* not need to be of the same variable; if MA, resp. MB, is not NULL, must be171* the matrix of the Frobenius map in FF_l[X]/(P), resp. FF_l[X]/(Q).172* Implementation choice: we assume the prime p is large so we handle173* Frobenius as matrices. */174void175Flx_ffintersect(GEN P, GEN Q, long n, ulong l,GEN *SP, GEN *SQ, GEN MA, GEN MB)176{177pari_sp ltop = avma;178long vp = get_Flx_var(P), vq = get_Flx_var(Q);179long np = get_Flx_degree(P), nq = get_Flx_degree(Q), e;180ulong pg;181GEN A, B, Ap, Bp;182if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);183if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);184if (n<=0 || np%n || nq%n)185pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));186e = u_lvalrem(n, l, &pg);187if(!MA) MA = Flx_matFrobenius(P,l);188if(!MB) MB = Flx_matFrobenius(Q,l);189A = Ap = pol0_Flx(vp);190B = Bp = pol0_Flx(vq);191if (pg > 1)192{193pari_timer T;194GEN ipg = utoipos(pg);195if (l%pg == 1)196{ /* more efficient special case */197ulong L, z, An, Bn;198z = Fl_neg(rootsof1_Fl(pg, l), l);199if (DEBUGLEVEL>=4) timer_start(&T);200A = Flm_ker(Flm_Fl_add(MA, z, l),l);201if (lg(A)!=2) err_Flxq("FpX_ffintersect",P,l);202A = Flv_to_Flx(gel(A,1),vp);203204B = Flm_ker(Flm_Fl_add(MB, z, l),l);205if (lg(B)!=2) err_Flxq("FpX_ffintersect",Q,l);206B = Flv_to_Flx(gel(B,1),vq);207208if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");209An = Flxq_powu(A,pg,P,l)[2];210Bn = Flxq_powu(B,pg,Q,l)[2];211if (!Bn) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));212z = Fl_div(An,Bn,l);213L = Fl_sqrtn(z, pg, l, NULL);214if (L==ULONG_MAX) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));215if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");216B = Flx_Fl_mul(B,L,l);217}218else219{220GEN L, An, Bn, z, U;221U = gmael(Flx_factor(ZX_to_Flx(polcyclo(pg, fetch_var()),l),l),1,1);222A = Flx_intersect_ker(P, MA, U, l);223B = Flx_intersect_ker(Q, MB, U, l);224if (DEBUGLEVEL>=4) timer_start(&T);225An = gel(FlxYqq_pow(A,ipg,P,U,l),2);226Bn = gel(FlxYqq_pow(B,ipg,Q,U,l),2);227if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");228z = Flxq_div(An,Bn,U,l);229L = Flxq_sqrtn(z,ipg,U,l,NULL);230if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));231if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");232B = FlxqX_Flxq_mul(B,L,U,l);233A = FlxY_evalx(A,0,l);234B = FlxY_evalx(B,0,l);235(void)delete_var();236}237}238if (e)239{240GEN VP, VQ, Ay, By;241ulong lmun = l-1;242long j;243MA = Flm_Fl_add(MA,lmun,l);244MB = Flm_Fl_add(MB,lmun,l);245Ay = pol1_Flx(vp);246By = pol1_Flx(vq);247VP = vecsmall_ei(np, 1);248VQ = np == nq? VP: vecsmall_ei(nq, 1); /* save memory */249for(j=0;j<e;j++)250{251if (j)252{253Ay = Flxq_mul(Ay,Flxq_powu(Ap,lmun,P,l),P,l);254VP = Flx_to_Flv(Ay,np);255}256Ap = Flm_Flc_invimage(MA,VP,l);257if (!Ap) err_Flxq("FpX_ffintersect",P,l);258Ap = Flv_to_Flx(Ap,vp);259260if (j)261{262By = Flxq_mul(By,Flxq_powu(Bp,lmun,Q,l),Q,l);263VQ = Flx_to_Flv(By,nq);264}265Bp = Flm_Flc_invimage(MB,VQ,l);266if (!Bp) err_Flxq("FpX_ffintersect",Q,l);267Bp = Flv_to_Flx(Bp,vq);268}269}270*SP = Flx_add(A,Ap,l);271*SQ = Flx_add(B,Bp,l);272gerepileall(ltop,2,SP,SQ);273}274275/* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and276* degree(P) divides degree(Q). Output a monomorphism between F_l[X]/(P) and277* F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l. If P and Q have the278* same degree, it is of course an isomorphism. */279GEN280Flx_ffisom(GEN P,GEN Q,ulong l)281{282pari_sp av = avma;283GEN SP, SQ, R;284Flx_ffintersect(P,Q,get_Flx_degree(P),l,&SP,&SQ,NULL,NULL);285R = Flxq_ffisom_inv(SP,P,l);286return gerepileupto(av, Flx_Flxq_eval(R,SQ,Q,l));287}288289void290FpX_ffintersect(GEN P, GEN Q, long n, GEN l, GEN *SP, GEN *SQ, GEN MA, GEN MB)291{292pari_sp ltop = avma;293long vp, vq, np, nq, e;294ulong pg;295GEN A, B, Ap, Bp;296if (lgefint(l)==3)297{298ulong pp = l[2];299GEN Pp = ZX_to_Flx(P,pp), Qp = ZX_to_Flx(Q,pp);300GEN MAp = MA ? ZM_to_Flm(MA, pp): NULL;301GEN MBp = MB ? ZM_to_Flm(MB, pp): NULL;302Flx_ffintersect(Pp, Qp, n, pp, SP, SQ, MAp, MBp);303*SP = Flx_to_ZX(*SP); *SQ = Flx_to_ZX(*SQ);304gerepileall(ltop,2,SP,SQ);305return;306}307vp = get_FpX_var(P); np = get_FpX_degree(P);308vq = get_FpX_var(Q); nq = get_FpX_degree(Q);309if (np<=0) pari_err_IRREDPOL("FpX_ffintersect", P);310if (nq<=0) pari_err_IRREDPOL("FpX_ffintersect", Q);311if (n<=0 || np%n || nq%n)312pari_err_TYPE("FpX_ffintersect [bad degrees]",stoi(n));313e = u_pvalrem(n, l, &pg);314if(!MA) MA = FpX_matFrobenius(P, l);315if(!MB) MB = FpX_matFrobenius(Q, l);316A = Ap = pol_0(vp);317B = Bp = pol_0(vq);318if (pg > 1)319{320GEN ipg = utoipos(pg);321pari_timer T;322if (umodiu(l,pg) == 1)323/* No need to use relative extension, so don't. (Well, now we don't324* in the other case either, but this special case is more efficient) */325{326GEN L, An, Bn, z;327z = negi( rootsof1u_Fp(pg, l) );328if (DEBUGLEVEL>=4) timer_start(&T);329A = FpM_ker(RgM_Rg_add_shallow(MA, z),l);330if (lg(A)!=2) err_FpXQ("FpX_ffintersect",P,l);331A = RgV_to_RgX(gel(A,1),vp);332333B = FpM_ker(RgM_Rg_add_shallow(MB, z),l);334if (lg(B)!=2) err_FpXQ("FpX_ffintersect",Q,l);335B = RgV_to_RgX(gel(B,1),vq);336337if (DEBUGLEVEL>=4) timer_printf(&T, "FpM_ker");338An = gel(FpXQ_pow(A,ipg,P,l),2);339Bn = gel(FpXQ_pow(B,ipg,Q,l),2);340if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));341z = Fp_div(An,Bn,l);342L = Fp_sqrtn(z,ipg,l,NULL);343if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));344if (DEBUGLEVEL>=4) timer_printf(&T, "Fp_sqrtn");345B = FpX_Fp_mul(B,L,l);346}347else348{349GEN L, An, Bn, z, U;350U = gmael(FpX_factor(polcyclo(pg,fetch_var()),l),1,1);351A = FpX_intersect_ker(P, MA, U, l);352B = FpX_intersect_ker(Q, MB, U, l);353if (DEBUGLEVEL>=4) timer_start(&T);354An = gel(FpXYQQ_pow(A,ipg,P,U,l),2);355Bn = gel(FpXYQQ_pow(B,ipg,Q,U,l),2);356if (DEBUGLEVEL>=4) timer_printf(&T,"pows [P,Q]");357if (!signe(Bn)) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));358z = Fq_div(An,Bn,U,l);359L = Fq_sqrtn(z,ipg,U,l,NULL);360if (!L) pari_err_IRREDPOL("FpX_ffintersect", mkvec2(P,Q));361if (DEBUGLEVEL>=4) timer_printf(&T,"FpXQ_sqrtn");362B = FqX_Fq_mul(B,L,U,l);363A = FpXY_evalx(A,gen_0,l);364B = FpXY_evalx(B,gen_0,l);365(void)delete_var();366}367}368if (e)369{370GEN VP, VQ, Ay, By, lmun = subiu(l,1);371long j;372MA = RgM_Rg_add_shallow(MA,gen_m1);373MB = RgM_Rg_add_shallow(MB,gen_m1);374Ay = pol_1(vp);375By = pol_1(vq);376VP = col_ei(np, 1);377VQ = np == nq? VP: col_ei(nq, 1); /* save memory */378for(j=0;j<e;j++)379{380if (j)381{382Ay = FpXQ_mul(Ay,FpXQ_pow(Ap,lmun,P,l),P,l);383VP = RgX_to_RgC(Ay,np);384}385Ap = FpM_FpC_invimage(MA,VP,l);386if (!Ap) err_FpXQ("FpX_ffintersect",P,l);387Ap = RgV_to_RgX(Ap,vp);388389if (j)390{391By = FpXQ_mul(By,FpXQ_pow(Bp,lmun,Q,l),Q,l);392VQ = RgX_to_RgC(By,nq);393}394Bp = FpM_FpC_invimage(MB,VQ,l);395if (!Bp) err_FpXQ("FpX_ffintersect",Q,l);396Bp = RgV_to_RgX(Bp,vq);397}398}399*SP = FpX_add(A,Ap,l);400*SQ = FpX_add(B,Bp,l);401gerepileall(ltop,2,SP,SQ);402}403/* Let l be a prime number, P, Q in Z[X]; both are irreducible modulo l and404* degree(P) divides degree(Q). Output a monomorphism between F_l[X]/(P) and405* F_l[X]/(Q) as a polynomial R such that Q | P(R) mod l. If P and Q have the406* same degree, it is of course an isomorphism. */407GEN408FpX_ffisom(GEN P, GEN Q, GEN p)409{410pari_sp av = avma;411GEN SP, SQ, R;412if (lgefint(p)==3)413{414ulong pp = p[2];415GEN R = Flx_ffisom(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);416return gerepileupto(av, Flx_to_ZX(R));417}418FpX_ffintersect(P,Q,get_FpX_degree(P),p,&SP,&SQ,NULL,NULL);419R = FpXQ_ffisom_inv(SP,P,p);420return gerepileupto(av, FpX_FpXQ_eval(R,SQ,Q,p));421}422423/* Let l be a prime number, P a ZX irreducible modulo l, MP the matrix of the424* Frobenius automorphism of F_l[X]/(P).425* Factor P over the subfield of F_l[X]/(P) of index d. */426static GEN427FpX_factorgalois(GEN P, GEN l, long d, long w, GEN MP)428{429pari_sp ltop = avma;430GEN R, V, Tl, z, M;431long v = get_FpX_var(P), n = get_FpX_degree(P);432long k, m = n/d;433434/* x - y */435if (m == 1) return deg1pol_shallow(gen_1, deg1pol_shallow(subis(l,1), gen_0, w), v);436M = FpM_Frobenius_pow(MP,d,P,l);437438Tl = leafcopy(P); setvarn(Tl,w);439V = cgetg(m+1,t_VEC);440gel(V,1) = pol_x(w);441z = gel(M,2);442gel(V,2) = RgV_to_RgX(z,w);443for(k=3;k<=m;k++)444{445z = FpM_FpC_mul(M,z,l);446gel(V,k) = RgV_to_RgX(z,w);447}448R = FqV_roots_to_pol(V,Tl,l,v);449return gerepileupto(ltop,R);450}451/* same: P is an Flx, MP an Flm */452static GEN453Flx_factorgalois(GEN P, ulong l, long d, long w, GEN MP)454{455pari_sp ltop = avma;456GEN R, V, Tl, z, M;457long k, n = get_Flx_degree(P), m = n/d;458long v = get_Flx_var(P);459460if (m == 1) {461R = polx_Flx(v);462gel(R,2) = z = polx_Flx(w); z[3] = l - 1; /* - y */463gel(R,3) = pol1_Flx(w);464return R; /* x - y */465}466M = Flm_Frobenius_pow(MP,d,P,l);467468Tl = leafcopy(P); Tl[1] = w;469V = cgetg(m+1,t_VEC);470gel(V,1) = polx_Flx(w);471z = gel(M,2);472gel(V,2) = Flv_to_Flx(z,w);473for(k=3;k<=m;k++)474{475z = Flm_Flc_mul(M,z,l);476gel(V,k) = Flv_to_Flx(z,w);477}478R = FlxqV_roots_to_pol(V,Tl,l,v);479return gerepileupto(ltop,R);480}481482GEN483Flx_factorff_irred(GEN P, GEN Q, ulong p)484{485pari_sp ltop = avma, av;486GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR, res;487long np = get_Flx_degree(P), nq = get_Flx_degree(Q), d = ugcd(np,nq);488long i, vp = get_Flx_var(P), vq = get_Flx_var(Q);489if (d==1) retmkcol(Flx_to_FlxX(P, vq));490FQ = Flx_matFrobenius(Q,p);491av = avma;492FP = Flx_matFrobenius(P,p);493Flx_ffintersect(P,Q,d,p,&SP,&SQ, FP, FQ);494E = Flx_factorgalois(P,p,d,vq, FP);495E = FlxX_to_Flm(E,np);496MP= Flxq_matrix_pow(SP,np,d,P,p);497IR= gel(Flm_indexrank(MP,p),1);498E = rowpermute(E, IR);499M = rowpermute(MP,IR);500M = Flm_inv(M,p);501MQ= Flxq_matrix_pow(SQ,nq,d,Q,p);502M = Flm_mul(MQ,M,p);503M = Flm_mul(M,E,p);504M = gerepileupto(av,M);505V = cgetg(d+1,t_VEC);506gel(V,1) = M;507for(i=2;i<=d;i++)508gel(V,i) = Flm_mul(FQ,gel(V,i-1),p);509res = cgetg(d+1,t_COL);510for(i=1;i<=d;i++)511gel(res,i) = Flm_to_FlxX(gel(V,i),vp,vq);512return gerepileupto(ltop,res);513}514515/* P,Q irreducible over F_p. Factor P over FF_p[X] / Q [factors are ordered as516* a Frobenius cycle] */517GEN518FpX_factorff_irred(GEN P, GEN Q, GEN p)519{520pari_sp ltop = avma, av;521GEN res;522long np = get_FpX_degree(P), nq = get_FpX_degree(Q), d = ugcd(np,nq);523if (d==1) return mkcolcopy(P);524525if (lgefint(p)==3)526{527ulong pp = p[2];528GEN F = Flx_factorff_irred(ZX_to_Flx(P,pp), ZX_to_Flx(Q,pp), pp);529long i, lF = lg(F);530res = cgetg(lF, t_COL);531for(i=1; i<lF; i++)532gel(res,i) = FlxX_to_ZXX(gel(F,i));533}534else535{536GEN SP, SQ, MP, MQ, M, FP, FQ, E, V, IR;537long i, vp = get_FpX_var(P), vq = get_FpX_var(Q);538FQ = FpX_matFrobenius(Q,p);539av = avma;540FP = FpX_matFrobenius(P,p);541FpX_ffintersect(P,Q,d,p,&SP,&SQ,FP,FQ);542543E = FpX_factorgalois(P,p,d,vq,FP);544E = RgXX_to_RgM(E,np);545MP= FpXQ_matrix_pow(SP,np,d,P,p);546IR= gel(FpM_indexrank(MP,p),1);547E = rowpermute(E, IR);548M = rowpermute(MP,IR);549M = FpM_inv(M,p);550MQ= FpXQ_matrix_pow(SQ,nq,d,Q,p);551M = FpM_mul(MQ,M,p);552M = FpM_mul(M,E,p);553M = gerepileupto(av,M);554V = cgetg(d+1,t_VEC);555gel(V,1) = M;556for(i=2;i<=d;i++)557gel(V,i) = FpM_mul(FQ,gel(V,i-1),p);558res = cgetg(d+1,t_COL);559for(i=1;i<=d;i++)560gel(res,i) = RgM_to_RgXX(gel(V,i),vp,vq);561}562return gerepilecopy(ltop,res);563}564565/* not memory-clean, as Flx_factorff_i, returning only linear factors */566static GEN567Flx_rootsff_i(GEN P, GEN T, ulong p)568{569GEN V, F = gel(Flx_factor(P,p), 1);570long i, lfact = 1, nmax = lgpol(P), n = lg(F), dT = get_Flx_degree(T);571572V = cgetg(nmax,t_COL);573for(i=1;i<n;i++)574{575GEN R, Fi = gel(F,i);576long di = degpol(Fi), j, r;577if (dT % di) continue;578R = Flx_factorff_irred(gel(F,i),T,p);579r = lg(R);580for (j=1; j<r; j++,lfact++)581gel(V,lfact) = Flx_neg(gmael(R,j, 2), p);582}583setlg(V,lfact);584gen_sort_inplace(V, (void*) &cmp_Flx, &cmp_nodata, NULL);585return V;586}587GEN588Flx_rootsff(GEN P, GEN T, ulong p)589{590pari_sp av = avma;591return gerepilecopy(av, Flx_rootsff_i(P, T, p));592}593594/* dummy implementation */595static GEN596F2x_rootsff_i(GEN P, GEN T)597{598return FlxC_to_F2xC(Flx_rootsff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2UL));599}600601/* not memory-clean, as FpX_factorff_i, returning only linear factors */602static GEN603FpX_rootsff_i(GEN P, GEN T, GEN p)604{605GEN V, F;606long i, lfact, nmax, n, dT;607if (lgefint(p)==3)608{609ulong pp = p[2];610GEN V = Flx_rootsff_i(ZX_to_Flx(P,pp), ZXT_to_FlxT(T,pp), pp);611return FlxC_to_ZXC(V);612}613F = gel(FpX_factor(P,p), 1);614lfact = 1; nmax = lgpol(P); n = lg(F); dT = get_FpX_degree(T);615616V = cgetg(nmax,t_COL);617for(i=1;i<n;i++)618{619GEN R, Fi = gel(F,i);620long di = degpol(Fi), j, r;621if (dT % di) continue;622R = FpX_factorff_irred(gel(F,i),T,p);623r = lg(R);624for (j=1; j<r; j++,lfact++)625gel(V,lfact) = Fq_to_FpXQ(Fq_neg(gmael(R,j, 2), T, p), T, p);626}627setlg(V,lfact);628gen_sort_inplace(V, (void*) &cmp_RgX, &cmp_nodata, NULL);629return V;630}631GEN632FpX_rootsff(GEN P, GEN T, GEN p)633{634pari_sp av = avma;635return gerepilecopy(av, FpX_rootsff_i(P, T, p));636}637638static GEN639Flx_factorff_i(GEN P, GEN T, ulong p)640{641GEN V, E, F = Flx_factor(P, p);642long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);643644V = cgetg(nmax,t_VEC);645E = cgetg(nmax,t_VECSMALL);646for(i=1;i<n;i++)647{648GEN R = Flx_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);649long j, r = lg(R);650for (j=1; j<r; j++,lfact++)651{652gel(V,lfact) = gel(R,j);653gel(E,lfact) = e;654}655}656setlg(V,lfact);657setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_Flx);658}659660static long661simpleff_to_nbfact(GEN F, long dT)662{663long i, l = lg(F), k = 0;664for (i = 1; i < l; i++) k += ugcd(uel(F,i), dT);665return k;666}667668static long669Flx_nbfactff(GEN P, GEN T, ulong p)670{671pari_sp av = avma;672GEN F = gel(Flx_degfact(P, p), 1);673long s = simpleff_to_nbfact(F, get_Flx_degree(T));674return gc_long(av,s);675}676677/* dummy implementation */678static GEN679F2x_factorff_i(GEN P, GEN T)680{681GEN M = Flx_factorff_i(F2x_to_Flx(P), F2x_to_Flx(T), 2);682return mkvec2(FlxXC_to_F2xXC(gel(M,1)), gel(M,2));683}684685/* not memory-clean */686static GEN687FpX_factorff_i(GEN P, GEN T, GEN p)688{689GEN V, E, F = FpX_factor(P,p);690long i, lfact = 1, nmax = lgpol(P), n = lgcols(F);691692V = cgetg(nmax,t_VEC);693E = cgetg(nmax,t_VECSMALL);694for(i=1;i<n;i++)695{696GEN R = FpX_factorff_irred(gmael(F,1,i),T,p), e = gmael(F,2,i);697long j, r = lg(R);698for (j=1; j<r; j++,lfact++)699{700gel(V,lfact) = gel(R,j);701gel(E,lfact) = e;702}703}704setlg(V,lfact);705setlg(E,lfact); return sort_factor_pol(mkvec2(V,E), cmp_RgX);706}707708static long709FpX_nbfactff(GEN P, GEN T, GEN p)710{711pari_sp av = avma;712GEN F = gel(FpX_degfact(P, p), 1);713long s = simpleff_to_nbfact(F, get_FpX_degree(T));714return gc_long(av,s);715}716717GEN718FpX_factorff(GEN P, GEN T, GEN p)719{720pari_sp av = avma;721return gerepilecopy(av, FpX_factorff_i(P, T, p));722}723724/***********************************************************************/725/** **/726/** Factorisation over finite fields **/727/** **/728/***********************************************************************/729730static GEN731FlxqXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, ulong p)732{733GEN ap2 = FlxqXQ_powu(a, p>>1, S, T, p);734GEN V = FlxqXQ_autsum(mkvec3(xp, Xp, ap2), get_Flx_degree(T), S, T, p);735return gel(V,3);736}737738GEN739FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p)740{741long vT = get_Flx_var(T);742GEN xp, Xp;743T = Flx_get_red(T, p);744S = FlxqX_get_red(S, T, p);745xp = Flx_Frobenius(T, p);746Xp = FlxqXQ_powu(polx_FlxX(get_FlxqX_var(S), vT), p, S, T, p);747return FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p);748}749750static GEN751FpXQXQ_halfFrobenius_i(GEN a, GEN xp, GEN Xp, GEN S, GEN T, GEN p)752{753GEN ap2 = FpXQXQ_pow(a, shifti(p,-1), S, T, p);754GEN V = FpXQXQ_autsum(mkvec3(xp, Xp, ap2), get_FpX_degree(T), S, T, p);755return gel(V, 3);756}757758GEN759FpXQXQ_halfFrobenius(GEN a, GEN S, GEN T, GEN p)760{761pari_sp av = avma;762GEN z;763if (lgefint(p)==3)764{765ulong pp = p[2];766long v = get_FpX_var(T);767GEN Tp = ZXT_to_FlxT(T,pp), Sp = ZXXT_to_FlxXT(S, pp, v);768z = FlxX_to_ZXX(FlxqXQ_halfFrobenius(ZXX_to_FlxX(a,pp,v),Sp,Tp,pp));769}770else771{772GEN xp, Xp;773T = FpX_get_red(T, p);774S = FpXQX_get_red(S, T, p);775xp = FpX_Frobenius(T, p);776Xp = FpXQXQ_pow(pol_x(get_FpXQX_var(S)), p, S, T, p);777z = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);778}779return gerepilecopy(av, z);780}781782static GEN783FlxqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, ulong p)784{785ulong dT = get_Flx_degree(T), df = get_FlxqX_degree(f);786GEN q = powuu(p,dT);787if (expi(q) >= expu(dT)*(long)usqrt(df))788return gel(FlxqXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2);789else790return FlxqXQ_pow(pol_x(get_FlxqX_var(f)), q, f, T, p);791}792793GEN794FlxqX_Frobenius(GEN S, GEN T, ulong p)795{796pari_sp av = avma;797GEN X = polx_FlxX(get_FlxqX_var(S), get_Flx_var(T));798GEN xp = Flx_Frobenius(T, p);799GEN Xp = FlxqXQ_powu(X, p, S, T, p);800GEN Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);801return gerepilecopy(av, Xq);802}803804static GEN805FpXQXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T, GEN p)806{807ulong dT = get_FpX_degree(T), df = get_FpXQX_degree(f);808GEN q = powiu(p, dT);809if (expi(q) >= expu(dT)*(long)usqrt(df))810return gel(FpXQXQ_autpow(mkvec2(xp, Xp), dT, f, T, p), 2);811else812return FpXQXQ_pow(pol_x(get_FpXQX_var(f)), q, f, T, p);813}814815GEN816FpXQX_Frobenius(GEN S, GEN T, GEN p)817{818pari_sp av = avma;819GEN X = pol_x(get_FpXQX_var(S));820GEN xp = FpX_Frobenius(T, p);821GEN Xp = FpXQXQ_pow(X, p, S, T, p);822GEN Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);823return gerepilecopy(av, Xq);824}825826static GEN827F2xqXQ_Frobenius(GEN xp, GEN Xp, GEN f, GEN T)828{829ulong dT = get_F2x_degree(T), df = get_F2xqX_degree(f);830if (dT >= expu(dT)*usqrt(df))831return gel(F2xqXQ_autpow(mkvec2(xp, Xp), dT, f, T), 2);832else833{834long v = get_F2xqX_var(f), vT = get_F2x_var(T);835return F2xqXQ_pow(polx_F2xX(v,vT), int2n(dT), f, T);836}837}838839static GEN840FlxqX_split_part(GEN f, GEN T, ulong p)841{842long n = degpol(f);843GEN z, Xq, X = polx_FlxX(varn(f),get_Flx_var(T));844if (n <= 1) return f;845f = FlxqX_red(f, T, p);846Xq = FlxqX_Frobenius(f, T, p);847z = FlxX_sub(Xq, X , p);848return FlxqX_gcd(z, f, T, p);849}850851GEN852FpXQX_split_part(GEN f, GEN T, GEN p)853{854if(lgefint(p)==3)855{856ulong pp=p[2];857GEN Tp = ZXT_to_FlxT(T, pp);858GEN z = FlxqX_split_part(ZXX_to_FlxX(f, pp, get_Flx_var(T)), Tp, pp);859return FlxX_to_ZXX(z);860} else861{862long n = degpol(f);863GEN z, X = pol_x(varn(f));864if (n <= 1) return f;865f = FpXQX_red(f, T, p);866z = FpXQX_Frobenius(f, T, p);867z = FpXX_sub(z, X , p);868return FpXQX_gcd(z, f, T, p);869}870}871872long873FpXQX_nbroots(GEN f, GEN T, GEN p)874{875pari_sp av = avma;876GEN z = FpXQX_split_part(f, T, p);877return gc_long(av, degpol(z));878}879880long881FqX_nbroots(GEN f, GEN T, GEN p)882{ return T ? FpXQX_nbroots(f, T, p): FpX_nbroots(f, p); }883884long885FlxqX_nbroots(GEN f, GEN T, ulong p)886{887pari_sp av = avma;888GEN z = FlxqX_split_part(f, T, p);889return gc_long(av, degpol(z));890}891892static GEN893FlxqX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, ulong p)894{895long j, N = get_FlxqX_degree(S);896GEN Q = FlxqXQ_matrix_pow(Xq,N,N,S,T,p);897for (j=1; j<=N; j++)898gcoeff(Q,j,j) = Flx_Fl_add(gcoeff(Q,j,j), p-1, p);899return FlxqM_ker(Q,T,p);900}901902static GEN903FpXQX_Berlekamp_ker_i(GEN Xq, GEN S, GEN T, GEN p)904{905long j,N = get_FpXQX_degree(S);906GEN Q = FpXQXQ_matrix_pow(Xq,N,N,S,T,p);907for (j=1; j<=N; j++)908gcoeff(Q,j,j) = Fq_sub(gcoeff(Q,j,j), gen_1, T, p);909return FqM_ker(Q,T,p);910}911912static long913isabsolutepol(GEN f)914{915long i, l = lg(f);916for(i=2; i<l; i++)917{918GEN c = gel(f,i);919if (typ(c) == t_POL && degpol(c) > 0) return 0;920}921return 1;922}923924#define set_irred(i) { if ((i)>ir) swap(t[i],t[ir]); ir++;}925926static long927FlxqX_split_Berlekamp(GEN *t, GEN xp, GEN T, ulong p)928{929GEN u = *t, a,b,vker,pol;930long vu = varn(u), vT = get_Flx_var(T), dT = get_Flx_degree(T);931long d, i, ir, L, la, lb;932GEN S, X, Xp, Xq;933if (degpol(u)==1) return 1;934T = Flx_get_red(T, p);935S = FlxqX_get_red(u, T, p);936X = polx_FlxX(get_FlxqX_var(S),get_Flx_var(T));937Xp = FlxqXQ_powu(X, p, S, T, p);938Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);939vker = FlxqX_Berlekamp_ker_i(Xq, S, T, p);940vker = Flm_to_FlxV(vker,u[1]);941d = lg(vker)-1;942ir = 0;943/* t[i] irreducible for i < ir, still to be treated for i < L */944for (L=1; L<d; )945{946pol= scalarpol(random_Flx(dT,vT,p),vu);947for (i=2; i<=d; i++)948pol = FlxX_add(pol, FlxqX_Flxq_mul(gel(vker,i),949random_Flx(dT,vT,p), T, p), p);950pol = FlxqX_red(pol,T,p);951for (i=ir; i<L && L<d; i++)952{953a = t[i]; la = degpol(a);954if (la == 1) { set_irred(i); }955else956{957pari_sp av = avma;958GEN S = FlxqX_get_red(a, T, p);959b = FlxqX_rem(pol, S, T,p);960if (degpol(b)<=0) { set_avma(av); continue; }961b = FlxqXQ_halfFrobenius_i(b, xp, FlxqX_rem(Xp, S, T, p), S, T, p);962if (degpol(b)<=0) { set_avma(av); continue; }963gel(b,2) = Flxq_sub(gel(b,2), gen_1,T,p);964b = FlxqX_gcd(a,b, T,p); lb = degpol(b);965if (lb && lb < la)966{967b = FlxqX_normalize(b, T,p);968t[L] = FlxqX_div(a,b,T,p);969t[i]= b; L++;970}971else set_avma(av);972}973}974}975return d;976}977978static long979FpXQX_split_Berlekamp(GEN *t, GEN T, GEN p)980{981GEN u = *t, a, b, vker, pol;982GEN X, xp, Xp, Xq, S;983long vu = varn(u), vT = get_FpX_var(T), dT = get_FpX_degree(T);984long d, i, ir, L, la, lb;985if (degpol(u)==1) return 1;986T = FpX_get_red(T, p);987xp = FpX_Frobenius(T, p);988S = FpXQX_get_red(u, T, p);989X = pol_x(get_FpXQX_var(S));990Xp = FpXQXQ_pow(X, p, S, T, p);991Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);992vker = FpXQX_Berlekamp_ker_i(Xq, S, T, p);993vker = RgM_to_RgXV(vker,vu);994d = lg(vker)-1;995ir = 0;996/* t[i] irreducible for i < ir, still to be treated for i < L */997for (L=1; L<d; )998{999pol= scalarpol(random_FpX(dT,vT,p),vu);1000for (i=2; i<=d; i++)1001pol = FqX_add(pol, FqX_Fq_mul(gel(vker,i),1002random_FpX(dT,vT,p), T, p), T, p);1003pol = FpXQX_red(pol,T,p);1004for (i=ir; i<L && L<d; i++)1005{1006a = t[i]; la = degpol(a);1007if (la == 1) { set_irred(i); }1008else1009{1010pari_sp av = avma;1011GEN S = FpXQX_get_red(a, T, p);1012b = FqX_rem(pol, S, T,p);1013if (degpol(b)<=0) { set_avma(av); continue; }1014b = FpXQXQ_halfFrobenius_i(b, xp, FpXQX_rem(Xp, S, T, p), S, T, p);1015if (degpol(b)<=0) { set_avma(av); continue; }1016gel(b,2) = Fq_sub(gel(b,2), gen_1,T,p);1017b = FqX_gcd(a,b, T,p); lb = degpol(b);1018if (lb && lb < la)1019{1020b = FpXQX_normalize(b, T,p);1021t[L] = FqX_div(a,b,T,p);1022t[i]= b; L++;1023}1024else set_avma(av);1025}1026}1027}1028return d;1029}10301031static GEN1032F2xqX_quad_roots(GEN P, GEN T)1033{1034GEN b= gel(P,3), c = gel(P,2);1035if (lgpol(b))1036{1037GEN z, d = F2xq_div(c, F2xq_sqr(b,T),T);1038if (F2xq_trace(d,T))1039return cgetg(1, t_COL);1040z = F2xq_mul(b, F2xq_Artin_Schreier(d, T), T);1041return mkcol2(z, F2x_add(b, z));1042}1043else1044return mkcol(F2xq_sqrt(c, T));1045}10461047/* Assume p>2 and x monic */1048static GEN1049FlxqX_quad_roots(GEN x, GEN T, ulong p)1050{1051GEN s, D, nb, b = gel(x,3), c = gel(x,2);1052D = Flx_sub(Flxq_sqr(b,T,p), Flx_mulu(c,4,p), p);1053nb = Flx_neg(b,p);1054if (lgpol(D)==0)1055return mkcol(Flx_halve(nb, p));1056s = Flxq_sqrt(D,T,p);1057if (!s) return cgetg(1, t_COL);1058s = Flx_halve(Flx_add(s,nb,p),p);1059return mkcol2(s, Flx_sub(nb,s,p));1060}10611062static GEN1063FpXQX_quad_roots(GEN x, GEN T, GEN p)1064{1065GEN s, D, nb, b = gel(x,3), c = gel(x,2);1066if (absequaliu(p, 2))1067{1068GEN f2 = ZXX_to_F2xX(x, get_FpX_var(T));1069s = F2xqX_quad_roots(f2, ZX_to_F2x(get_FpX_mod(T)));1070return F2xC_to_ZXC(s);1071}1072D = Fq_sub(Fq_sqr(b,T,p), Fq_Fp_mul(c,utoi(4),T,p), T,p);1073nb = Fq_neg(b,T,p);1074if (signe(D)==0)1075return mkcol(Fq_to_FpXQ(Fq_halve(nb,T, p),T,p));1076s = Fq_sqrt(D,T,p);1077if (!s) return cgetg(1, t_COL);1078s = Fq_halve(Fq_add(s,nb,T,p),T, p);1079return mkcol2(Fq_to_FpXQ(s,T,p), Fq_to_FpXQ(Fq_sub(nb,s,T,p),T,p));1080}10811082static GEN1083F2xqX_Frobenius_deflate(GEN S, GEN T)1084{1085GEN F = RgX_deflate(S, 2);1086long i, l = lg(F);1087for (i=2; i<l; i++)1088gel(F,i) = F2xq_sqrt(gel(F,i), T);1089return F;1090}10911092static GEN1093F2xX_to_F2x(GEN x)1094{1095long l=nbits2lg(lgpol(x));1096GEN z=cgetg(l,t_VECSMALL);1097long i,j,k;1098z[1]=x[1];1099for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)1100{1101if (j==BITS_IN_LONG)1102{1103j=0; k++; z[k]=0;1104}1105if (lgpol(gel(x,i)))1106z[k]|=1UL<<j;1107}1108return F2x_renormalize(z,l);1109}11101111static GEN1112F2xqX_easyroots(GEN f, GEN T)1113{1114if (F2xY_degreex(f) <= 0) return F2x_rootsff_i(F2xX_to_F2x(f), T);1115if (degpol(f)==1) return mkcol(constant_coeff(f));1116if (degpol(f)==2) return F2xqX_quad_roots(f,T);1117return NULL;1118}11191120/* Adapted from Shoup NTL */1121GEN1122F2xqX_factor_squarefree(GEN f, GEN T)1123{1124pari_sp av = avma;1125GEN r, t, v, tv;1126long i, q, n = degpol(f);1127GEN u = const_vec(n+1, pol1_F2xX(varn(f), get_F2x_var(T)));1128for(q = 1;;q *= 2)1129{1130r = F2xqX_gcd(f, F2xX_deriv(f), T);1131if (degpol(r) == 0)1132{1133gel(u, q) = F2xqX_normalize(f, T);1134break;1135}1136t = F2xqX_div(f, r, T);1137if (degpol(t) > 0)1138{1139long j;1140for(j = 1;;j++)1141{1142v = F2xqX_gcd(r, t, T);1143tv = F2xqX_div(t, v, T);1144if (degpol(tv) > 0)1145gel(u, j*q) = F2xqX_normalize(tv, T);1146if (degpol(v) <= 0) break;1147r = F2xqX_div(r, v, T);1148t = v;1149}1150if (degpol(r) == 0) break;1151}1152f = F2xqX_Frobenius_deflate(r, T);1153}1154for (i = n; i; i--)1155if (degpol(gel(u,i))) break;1156setlg(u,i+1); return gerepilecopy(av, u);1157}11581159long1160F2xqX_ispower(GEN f, long k, GEN T, GEN *pt_r)1161{1162pari_sp av = avma;1163GEN lc, F;1164long i, l, n = degpol(f);1165if (n % k) return 0;1166lc = F2xq_sqrtn(leading_coeff(f), stoi(k), T, NULL);1167if (!lc) return gc_long(av,0);1168F = F2xqX_factor_squarefree(f, T); l = lg(F)-1;1169for(i=1; i<=l; i++)1170if (i%k && degpol(gel(F,i))) return gc_long(av,0);1171if (pt_r)1172{1173long v = varn(f);1174GEN r = scalarpol(lc, v), s = pol1_F2xX(v, T[1]);1175for(i=l; i>=1; i--)1176{1177if (i%k) continue;1178s = F2xqX_mul(s, gel(F,i), T);1179r = F2xqX_mul(r, s, T);1180}1181*pt_r = gerepileupto(av, r);1182} else set_avma(av);1183return 1;1184}11851186static void1187F2xqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN V, long idx)1188{1189pari_sp btop;1190long n = degpol(Sp);1191GEN S, f, ff;1192long dT = get_F2x_degree(T);1193GEN R = F2xqX_easyroots(Sp, T);1194if (R)1195{1196long i, l = lg(R)-1;1197for (i=0; i<l; i++)1198gel(V, idx+i) = gel(R,1+i);1199return;1200}1201S = F2xqX_get_red(Sp, T);1202Xp = F2xqX_rem(Xp, S, T);1203btop = avma;1204while (1)1205{1206GEN a = random_F2xqX(degpol(Sp), varn(Sp), T);1207GEN R = gel(F2xqXQ_auttrace(mkvec3(xp, Xp, a), dT, S, T), 3);1208f = F2xqX_gcd(R, Sp, T);1209if (degpol(f) > 0 && degpol(f) < n) break;1210set_avma(btop);1211}1212f = gerepileupto(btop, F2xqX_normalize(f, T));1213ff = F2xqX_div(Sp, f, T);1214F2xqX_roots_edf(f, xp, Xp, T, V, idx);1215F2xqX_roots_edf(ff,xp, Xp, T, V, idx+degpol(f));1216}12171218static GEN1219F2xqX_roots_ddf(GEN f, GEN xp, GEN T)1220{1221GEN X, Xp, Xq, g, V;1222long n;1223GEN R = F2xqX_easyroots(f, T);1224if (R) return R;1225X = pol_x(varn(f));1226Xp = F2xqXQ_sqr(X, f, T);1227Xq = F2xqXQ_Frobenius(xp, Xp, f, T);1228g = F2xqX_gcd(F2xX_add(Xq, X), f, T);1229n = degpol(g);1230if (n==0) return cgetg(1, t_COL);1231g = F2xqX_normalize(g, T);1232V = cgetg(n+1,t_COL);1233F2xqX_roots_edf(g, xp, Xp, T, V, 1);1234return V;1235}1236static GEN1237F2xqX_roots_i(GEN S, GEN T)1238{1239GEN M;1240S = F2xqX_red(S, T);1241if (!signe(S)) pari_err_ROOTS0("F2xqX_roots");1242if (degpol(S)==0) return cgetg(1, t_COL);1243S = F2xqX_normalize(S, T);1244M = F2xqX_easyroots(S, T);1245if (!M)1246{1247GEN xp = F2x_Frobenius(T);1248GEN F, V = F2xqX_factor_squarefree(S, T);1249long i, j, l = lg(V);1250F = cgetg(l, t_VEC);1251for (i=1, j=1; i < l; i++)1252if (degpol(gel(V,i)))1253gel(F, j++) = F2xqX_roots_ddf(gel(V,i), xp, T);1254setlg(F,j); M = shallowconcat1(F);1255}1256gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);1257return M;1258}12591260static GEN1261FlxqX_easyroots(GEN f, GEN T, ulong p)1262{1263if (FlxY_degreex(f) <= 0) return Flx_rootsff_i(FlxX_to_Flx(f), T, p);1264if (degpol(f)==1) return mkcol(Flx_neg(constant_coeff(f), p));1265if (degpol(f)==2) return FlxqX_quad_roots(f,T,p);1266return NULL;1267}12681269static GEN1270FlxqX_invFrobenius(GEN xp, GEN T, ulong p)1271{1272return Flxq_autpow(xp, get_Flx_degree(T)-1, T, p);1273}12741275static GEN1276FlxqX_Frobenius_deflate(GEN S, GEN ixp, GEN T, ulong p)1277{1278GEN F = RgX_deflate(S, p);1279long i, l = lg(F);1280if (typ(ixp)==t_INT)1281for (i=2; i<l; i++)1282gel(F,i) = Flxq_pow(gel(F,i), ixp, T, p);1283else1284{1285long n = brent_kung_optpow(get_Flx_degree(T)-1, l-2, 1);1286GEN V = Flxq_powers(ixp, n, T, p);1287for (i=2; i<l; i++)1288gel(F,i) = Flx_FlxqV_eval(gel(F,i), V, T, p);1289}1290return F;1291}12921293/* Adapted from Shoup NTL */1294static GEN1295FlxqX_factor_squarefree_i(GEN f, GEN xp, GEN T, ulong p)1296{1297pari_sp av = avma;1298GEN r, t, v, tv;1299long i, q, n = degpol(f);1300GEN u = const_vec(n+1, pol1_FlxX(varn(f),get_Flx_var(T)));1301GEN ixp = NULL;1302for(q = 1;;q *= p)1303{1304r = FlxqX_gcd(f, FlxX_deriv(f, p), T, p);1305if (degpol(r) == 0)1306{1307gel(u, q) = FlxqX_normalize(f, T, p);1308break;1309}1310t = FlxqX_div(f, r, T, p);1311if (degpol(t) > 0)1312{1313long j;1314for(j = 1;;j++)1315{1316v = FlxqX_gcd(r, t, T, p);1317tv = FlxqX_div(t, v, T, p);1318if (degpol(tv) > 0)1319gel(u, j*q) = FlxqX_normalize(tv, T, p);1320if (degpol(v) <= 0) break;1321r = FlxqX_div(r, v, T, p);1322t = v;1323}1324if (degpol(r) == 0) break;1325}1326if (!xp) xp = Flx_Frobenius(T, p);1327if (!ixp) ixp = FlxqX_invFrobenius(xp, T, p);1328f = FlxqX_Frobenius_deflate(r, ixp, T, p);1329}1330for (i = n; i; i--)1331if (degpol(gel(u,i))) break;1332setlg(u,i+1); return gerepilecopy(av, u);1333}13341335GEN1336FlxqX_factor_squarefree(GEN f, GEN T, ulong p)1337{1338return FlxqX_factor_squarefree_i(f, NULL, T, p);1339}13401341long1342FlxqX_ispower(GEN f, ulong k, GEN T, ulong p, GEN *pt_r)1343{1344pari_sp av = avma;1345GEN lc, F;1346long i, l, n = degpol(f), v = varn(f);1347if (n % k) return 0;1348lc = Flxq_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);1349if (!lc) return gc_long(av,0);1350F = FlxqX_factor_squarefree_i(f, NULL, T, p); l = lg(F)-1;1351for(i=1; i<=l; i++)1352if (i%k && degpol(gel(F,i))) return gc_long(av,0);1353if (pt_r)1354{1355GEN r = scalarpol(lc, v), s = pol1_FlxX(v, T[1]);1356for(i=l; i>=1; i--)1357{1358if (i%k) continue;1359s = FlxqX_mul(s, gel(F,i), T, p);1360r = FlxqX_mul(r, s, T, p);1361}1362*pt_r = gerepileupto(av, r);1363} else set_avma(av);1364return 1;1365}13661367static GEN1368FlxqX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, ulong p)1369{1370pari_sp btop = avma;1371long n = degpol(Sp);1372GEN f;1373long vT = get_Flx_var(T), dT = get_Flx_degree(T);1374pari_timer ti;1375if (DEBUGLEVEL >= 7) timer_start(&ti);1376while (1)1377{1378GEN a = deg1pol(pol1_Flx(vT), random_Flx(dT, vT, p), varn(Sp));1379GEN R = FlxqXQ_halfFrobenius_i(a, xp, Xp, S, T, p);1380if (DEBUGLEVEL >= 7) timer_printf(&ti, "FlxqXQ_halfFrobenius");1381f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p);1382if (degpol(f) > 0 && degpol(f) < n) break;1383set_avma(btop);1384}1385return gerepileupto(btop, FlxqX_normalize(f, T, p));1386}13871388static void1389FlxqX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, ulong p, GEN V, long idx)1390{1391GEN S, f, ff;1392GEN R = FlxqX_easyroots(Sp, T, p);1393if (R)1394{1395long i, l = lg(R)-1;1396for (i=0; i<l; i++)1397gel(V, idx+i) = gel(R,1+i);1398return;1399}1400S = FlxqX_get_red(Sp, T, p);1401Xp = FlxqX_rem(Xp, S, T, p);1402f = FlxqX_roots_split(Sp, xp, Xp, S, T, p);1403ff = FlxqX_div(Sp, f, T, p);1404FlxqX_roots_edf(f, xp, Xp, T, p, V, idx);1405FlxqX_roots_edf(ff,xp, Xp, T, p, V, idx+degpol(f));1406}14071408static GEN1409FlxqX_roots_ddf(GEN f, GEN xp, GEN T, ulong p)1410{1411GEN X, Xp, Xq, g, V;1412long n;1413GEN R = FlxqX_easyroots(f, T, p);1414if (R) return R;1415X = pol_x(varn(f));1416Xp = FlxqXQ_powu(X, p, f, T, p);1417Xq = FlxqXQ_Frobenius(xp, Xp, f, T, p);1418g = FlxqX_gcd(FlxX_sub(Xq, X, p), f, T, p);1419n = degpol(g);1420if (n==0) return cgetg(1, t_COL);1421g = FlxqX_normalize(g, T, p);1422V = cgetg(n+1,t_COL);1423FlxqX_roots_edf(g, xp, Xp, T, p, V, 1);1424return V;1425}14261427/* do not handle p==2 */1428static GEN1429FlxqX_roots_i(GEN S, GEN T, ulong p)1430{1431GEN M;1432S = FlxqX_red(S, T, p);1433if (!signe(S)) pari_err_ROOTS0("FlxqX_roots");1434if (degpol(S)==0) return cgetg(1, t_COL);1435S = FlxqX_normalize(S, T, p);1436M = FlxqX_easyroots(S, T, p);1437if (!M)1438{1439GEN xp = Flx_Frobenius(T, p);1440GEN F, V = FlxqX_factor_squarefree_i(S, xp, T, p);1441long i, j, l = lg(V);1442F = cgetg(l, t_VEC);1443for (i=1, j=1; i < l; i++)1444if (degpol(gel(V,i)))1445gel(F, j++) = FlxqX_roots_ddf(gel(V,i), xp, T, p);1446setlg(F,j); M = shallowconcat1(F);1447}1448gen_sort_inplace(M, (void*) &cmp_Flx, &cmp_nodata, NULL);1449return M;1450}14511452static GEN1453FpXQX_easyroots(GEN f, GEN T, GEN p)1454{1455if (isabsolutepol(f)) return FpX_rootsff_i(simplify_shallow(f), T, p);1456if (degpol(f)==1) return mkcol(Fq_to_FpXQ(Fq_neg(constant_coeff(f),T,p),T,p));1457if (degpol(f)==2) return FpXQX_quad_roots(f,T,p);1458return NULL;1459}14601461/* Adapted from Shoup NTL */1462static GEN1463FpXQX_factor_Yun(GEN f, GEN T, GEN p)1464{1465pari_sp av = avma;1466GEN r, t, v, tv;1467long j, n = degpol(f);1468GEN u = const_vec(n+1, pol_1(varn(f)));1469r = FpXQX_gcd(f, FpXX_deriv(f, p), T, p);1470t = FpXQX_div(f, r, T, p);1471for (j = 1;;j++)1472{1473v = FpXQX_gcd(r, t, T, p);1474tv = FpXQX_div(t, v, T, p);1475if (degpol(tv) > 0)1476gel(u, j) = FpXQX_normalize(tv, T, p);1477if (degpol(v) <= 0) break;1478r = FpXQX_div(r, v, T, p);1479t = v;1480}1481setlg(u, j+1); return gerepilecopy(av, u);1482}14831484GEN1485FpXQX_factor_squarefree(GEN f, GEN T, GEN p)1486{1487if (lgefint(p)==3)1488{1489pari_sp av = avma;1490ulong pp = p[2];1491GEN M;1492long vT = get_FpX_var(T);1493if (pp==2)1494{1495M = F2xqX_factor_squarefree(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));1496return gerepileupto(av, F2xXC_to_ZXXC(M));1497}1498M = FlxqX_factor_squarefree(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);1499return gerepileupto(av, FlxXC_to_ZXXC(M));1500}1501return FpXQX_factor_Yun(f, T, p);1502}15031504long1505FpXQX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)1506{1507pari_sp av = avma;1508GEN lc, F;1509long i, l, n = degpol(f), v = varn(f);1510if (n % k) return 0;1511if (lgefint(p)==3)1512{1513ulong pp = p[2];1514GEN fp = ZXX_to_FlxX(f, pp, varn(T));1515if (!FlxqX_ispower(fp, k, ZX_to_Flx(T,pp), pp, pt_r)) return gc_long(av,0);1516if (pt_r) *pt_r = gerepileupto(av, FlxX_to_ZXX(*pt_r));1517else set_avma(av);1518return 1;1519}1520lc = FpXQ_sqrtn(leading_coeff(f), stoi(k), T, p, NULL);1521if (!lc) return gc_long(av,0);1522F = FpXQX_factor_Yun(f, T, p); l = lg(F)-1;1523for(i=1; i <= l; i++)1524if (i%k && degpol(gel(F,i))) return gc_long(av,0);1525if (pt_r)1526{1527GEN r = scalarpol(lc, v), s = pol_1(v);1528for(i=l; i>=1; i--)1529{1530if (i%k) continue;1531s = FpXQX_mul(s, gel(F,i), T, p);1532r = FpXQX_mul(r, s, T, p);1533}1534*pt_r = gerepileupto(av, r);1535} else set_avma(av);1536return 1;1537}15381539long1540FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt_r)1541{ return T ? FpXQX_ispower(f, k, T, p, pt_r): FpX_ispower(f, k, p, pt_r); }15421543static GEN1544FpXQX_roots_split(GEN Sp, GEN xp, GEN Xp, GEN S, GEN T, GEN p)1545{1546pari_sp btop = avma;1547long n = degpol(Sp);1548GEN f;1549long vT = get_FpX_var(T), dT = get_FpX_degree(T);1550pari_timer ti;1551if (DEBUGLEVEL >= 7) timer_start(&ti);1552while (1)1553{1554GEN a = deg1pol(pol_1(vT), random_FpX(dT, vT, p), varn(Sp));1555GEN R = FpXQXQ_halfFrobenius_i(a, xp, Xp, S, T, p);1556if (DEBUGLEVEL >= 7) timer_printf(&ti, "FpXQXQ_halfFrobenius");1557f = FpXQX_gcd(FqX_Fq_sub(R, pol_1(vT), T, p), Sp, T, p);1558if (degpol(f) > 0 && degpol(f) < n) break;1559set_avma(btop);1560}1561return gerepileupto(btop, FpXQX_normalize(f, T, p));1562}15631564static void1565FpXQX_roots_edf(GEN Sp, GEN xp, GEN Xp, GEN T, GEN p, GEN V, long idx)1566{1567GEN S, f, ff;1568GEN R = FpXQX_easyroots(Sp, T, p);1569if (R)1570{1571long i, l = lg(R)-1;1572for (i=0; i<l; i++)1573gel(V, idx+i) = gel(R,1+i);1574return;1575}1576S = FpXQX_get_red(Sp, T, p);1577Xp = FpXQX_rem(Xp, S, T, p);1578f = FpXQX_roots_split(Sp, xp, Xp, S, T, p);1579ff = FpXQX_div(Sp, f, T, p);1580FpXQX_roots_edf(f, xp, Xp, T, p, V, idx);1581FpXQX_roots_edf(ff,xp, Xp, T, p, V, idx+degpol(f));1582}15831584static GEN1585FpXQX_roots_ddf(GEN f, GEN xp, GEN T, GEN p)1586{1587GEN X, Xp, Xq, g, V;1588long n;1589GEN R = FpXQX_easyroots(f, T, p);1590if (R) return R;1591X = pol_x(varn(f));1592Xp = FpXQXQ_pow(X, p, f, T, p);1593Xq = FpXQXQ_Frobenius(xp, Xp, f, T, p);1594g = FpXQX_gcd(FpXX_sub(Xq, X, p), f, T, p);1595n = degpol(g);1596if (n==0) return cgetg(1, t_COL);1597g = FpXQX_normalize(g, T, p);1598V = cgetg(n+1,t_COL);1599FpXQX_roots_edf(g, xp, Xp, T, p, V, 1);1600return V;1601}16021603/* do not handle small p */1604static GEN1605FpXQX_roots_i(GEN S, GEN T, GEN p)1606{1607GEN F, M;1608if (lgefint(p)==3)1609{1610ulong pp = p[2];1611if (pp == 2)1612{1613GEN V = F2xqX_roots_i(ZXX_to_F2xX(S,get_FpX_var(T)), ZX_to_F2x(get_FpX_mod(T)));1614return F2xC_to_ZXC(V);1615}1616else1617{1618GEN V = FlxqX_roots_i(ZXX_to_FlxX(S,pp,get_FpX_var(T)), ZXT_to_FlxT(T,pp), pp);1619return FlxC_to_ZXC(V);1620}1621}1622S = FpXQX_red(S, T, p);1623if (!signe(S)) pari_err_ROOTS0("FpXQX_roots");1624if (degpol(S)==0) return cgetg(1, t_COL);1625S = FpXQX_normalize(S, T, p);1626M = FpXQX_easyroots(S, T, p);1627if (!M)1628{1629GEN xp = FpX_Frobenius(T, p);1630GEN V = FpXQX_factor_Yun(S, T, p);1631long i, j, l = lg(V);1632F = cgetg(l, t_VEC);1633for (i=1, j=1; i < l; i++)1634if (degpol(gel(V,i)))1635gel(F, j++) = FpXQX_roots_ddf(gel(V,i), xp, T, p);1636setlg(F,j); M = shallowconcat1(F);1637}1638gen_sort_inplace(M, (void*) &cmp_RgX, &cmp_nodata, NULL);1639return M;1640}16411642GEN1643F2xqX_roots(GEN x, GEN T)1644{1645pari_sp av = avma;1646return gerepilecopy(av, F2xqX_roots_i(x, T));1647}16481649GEN1650FlxqX_roots(GEN x, GEN T, ulong p)1651{1652pari_sp av = avma;1653if (p==2)1654{1655GEN V = F2xqX_roots_i(FlxX_to_F2xX(x), Flx_to_F2x(get_Flx_mod(T)));1656return gerepileupto(av, F2xC_to_FlxC(V));1657}1658return gerepilecopy(av, FlxqX_roots_i(x, T, p));1659}16601661GEN1662FpXQX_roots(GEN x, GEN T, GEN p)1663{1664pari_sp av = avma;1665return gerepilecopy(av, FpXQX_roots_i(x, T, p));1666}16671668static GEN1669FE_concat(GEN F, GEN E, long l)1670{1671setlg(E,l); E = shallowconcat1(E);1672setlg(F,l); F = shallowconcat1(F); return mkvec2(F,E);1673}16741675static GEN1676F2xqX_factor_2(GEN f, GEN T)1677{1678long v = varn(f), vT = get_F2x_var(T);1679GEN r = F2xqX_quad_roots(f, T);1680switch(lg(r)-1)1681{1682case 0:1683return mkvec2(mkcolcopy(f), mkvecsmall(1));1684case 1:1685return mkvec2(mkcol(deg1pol_shallow(pol1_F2x(vT), gel(r,1), v)), mkvecsmall(2));1686default: /* 2 */1687{1688GEN f1 = deg1pol_shallow(pol1_F2x(vT), gel(r,1), v);1689GEN f2 = deg1pol_shallow(pol1_F2x(vT), gel(r,2), v);1690GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);1691sort_factor_pol(mkvec2(t, E), cmp_Flx);1692return mkvec2(t, E);1693}1694}1695}16961697static GEN1698FlxqX_factor_2(GEN f, GEN T, ulong p)1699{1700long v = varn(f), vT = get_Flx_var(T);1701GEN r = FlxqX_quad_roots(f, T, p);1702switch(lg(r)-1)1703{1704case 0:1705return mkvec2(mkcolcopy(f), mkvecsmall(1));1706case 1:1707return mkvec2(mkcol(deg1pol_shallow(pol1_Flx(vT),1708Flx_neg(gel(r,1), p), v)), mkvecsmall(2));1709default: /* 2 */1710{1711GEN f1 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,1), p), v);1712GEN f2 = deg1pol_shallow(pol1_Flx(vT), Flx_neg(gel(r,2), p), v);1713GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);1714sort_factor_pol(mkvec2(t, E), cmp_Flx);1715return mkvec2(t, E);1716}1717}1718}17191720static GEN1721FpXQX_factor_2(GEN f, GEN T, GEN p)1722{1723long v = varn(f);1724GEN r = FpXQX_quad_roots(f, T, p);1725switch(lg(r)-1)1726{1727case 0:1728return mkvec2(mkcolcopy(f), mkvecsmall(1));1729case 1:1730return mkvec2(mkcol(deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v)),1731mkvecsmall(2));1732default: /* 2 */1733{1734GEN f1 = deg1pol_shallow(gen_1, Fq_neg(gel(r,1), T, p), v);1735GEN f2 = deg1pol_shallow(gen_1, Fq_neg(gel(r,2), T, p), v);1736GEN t = mkcol2(f1, f2), E = mkvecsmall2(1, 1);1737sort_factor_pol(mkvec2(t, E), cmp_RgX);1738return mkvec2(t, E);1739}1740}1741}17421743static GEN1744F2xqX_ddf_Shoup(GEN S, GEN Xq, GEN T)1745{1746pari_sp av = avma;1747GEN b, g, h, F, f, Sr, xq;1748long i, j, n, v, vT, dT, bo, ro;1749long B, l, m;1750pari_timer ti;1751n = get_F2xqX_degree(S); v = get_F2xqX_var(S);1752vT = get_F2x_var(T); dT = get_F2x_degree(T);1753if (n == 0) return cgetg(1, t_VEC);1754if (n == 1) return mkvec(get_F2xqX_mod(S));1755B = n/2;1756l = usqrt(B);1757m = (B+l-1)/l;1758S = F2xqX_get_red(S, T);1759b = cgetg(l+2, t_VEC);1760gel(b, 1) = polx_F2xX(v, vT);1761gel(b, 2) = Xq;1762bo = brent_kung_optpow(n, l-1, 1);1763ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);1764if (DEBUGLEVEL>=7) timer_start(&ti);1765if (dT <= ro)1766for (i = 3; i <= l+1; i++)1767gel(b, i) = F2xqXQ_pow(gel(b, i-1), int2n(dT), S, T);1768else1769{1770xq = F2xqXQ_powers(gel(b, 2), bo, S, T);1771if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq baby");1772for (i = 3; i <= l+1; i++)1773gel(b, i) = F2xqX_F2xqXQV_eval(gel(b, i-1), xq, S, T);1774}1775if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: baby");1776xq = F2xqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T);1777if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: xq giant");1778g = cgetg(m+1, t_VEC);1779gel(g, 1) = gel(xq, 2);1780for(i = 2; i <= m; i++)1781gel(g, i) = F2xqX_F2xqXQV_eval(gel(g, i-1), xq, S, T);1782if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: giant");1783h = cgetg(m+1, t_VEC);1784for (j = 1; j <= m; j++)1785{1786pari_sp av = avma;1787GEN gj = gel(g, j);1788GEN e = F2xX_add(gj, gel(b, 1));1789for (i = 2; i <= l; i++)1790e = F2xqXQ_mul(e, F2xX_add(gj, gel(b, i)), S, T);1791gel(h, j) = gerepileupto(av, e);1792}1793if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: diff");1794Sr = get_F2xqX_mod(S);1795F = cgetg(m+1, t_VEC);1796for (j = 1; j <= m; j++)1797{1798GEN u = F2xqX_gcd(Sr, gel(h,j), T);1799if (degpol(u))1800{1801u = F2xqX_normalize(u, T);1802Sr = F2xqX_div(Sr, u, T);1803}1804gel(F,j) = u;1805}1806if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: F");1807f = const_vec(n, pol1_F2xX(v, vT));1808for (j = 1; j <= m; j++)1809{1810GEN e = gel(F, j);1811for (i=l-1; i >= 0; i--)1812{1813GEN u = F2xqX_gcd(e, F2xX_add(gel(g, j), gel(b, i+1)), T);1814if (degpol(u))1815{1816gel(f, l*j-i) = u = F2xqX_normalize(u, T);1817e = F2xqX_div(e, u, T);1818}1819if (!degpol(e)) break;1820}1821}1822if (DEBUGLEVEL>=7) timer_printf(&ti,"F2xqX_ddf_Shoup: f");1823if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;1824return gerepilecopy(av, f);1825}18261827static GEN1828F2xqX_ddf_i(GEN f, GEN T, GEN X, GEN xp)1829{1830GEN Xp, Xq;1831if (!get_F2xqX_degree(f)) return cgetg(1,t_VEC);1832f = F2xqX_get_red(f, T);1833Xp = F2xqXQ_sqr(X, f, T);1834Xq = F2xqXQ_Frobenius(xp, Xp, f, T);1835return F2xqX_ddf_Shoup(f, Xq, T);1836}1837static void1838F2xqX_ddf_init(GEN *S, GEN *T, GEN *xp, GEN *X)1839{1840*T = F2x_get_red(*T);1841*S = F2xqX_normalize(get_F2xqX_mod(*S), *T);1842*xp = F2x_Frobenius(*T);1843*X = polx_F2xX(get_F2xqX_var(*S), get_F2x_var(*T));1844}1845GEN1846F2xqX_degfact(GEN S, GEN T)1847{1848GEN xp, X, V;1849long i, l;1850F2xqX_ddf_init(&S,&T,&xp,&X);1851V = F2xqX_factor_squarefree(S, T); l = lg(V);1852for (i=1; i < l; i++) gel(V,i) = F2xqX_ddf_i(gel(V,i), T, X, xp);1853return vddf_to_simplefact(V, degpol(S));1854}1855GEN1856F2xqX_ddf(GEN S, GEN T)1857{1858GEN xp, X;1859F2xqX_ddf_init(&S,&T,&xp,&X);1860return ddf_to_ddf2( F2xqX_ddf_i(S, T, X, xp) );1861}18621863static void1864F2xqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Sq, long d, GEN T, GEN V, long idx)1865{1866long v = varn(Sp), n = degpol(Sp), r = n/d;1867GEN S, f, ff;1868long dT = get_F2x_degree(T);1869if (r==1) { gel(V, idx) = Sp; return; }1870S = F2xqX_get_red(Sp, T);1871Xp = F2xqX_rem(Xp, S, T);1872Sq = F2xqXQV_red(Sq, S, T);1873while (1)1874{1875pari_sp btop = avma;1876long l;1877GEN w0 = random_F2xqX(n, v, T), g = w0;1878for (l=1; l<d; l++) /* sum_{0<i<d} w^(q^i), result in (F_q)^r */1879g = F2xX_add(w0, F2xqX_F2xqXQV_eval(g, Sq, S, T));1880w0 = g;1881for (l=1; l<dT; l++) /* sum_{0<i<k} w^(2^i), result in (F_2)^r */1882g = F2xX_add(w0, F2xqXQ_sqr(g,S,T));1883f = F2xqX_gcd(g, Sp, T);1884if (degpol(f) > 0 && degpol(f) < n) break;1885set_avma(btop);1886}1887f = F2xqX_normalize(f, T);1888ff = F2xqX_div(Sp, f , T);1889F2xqX_edf_simple(f, xp, Xp, Sq, d, T, V, idx);1890F2xqX_edf_simple(ff, xp, Xp, Sq, d, T, V, idx+degpol(f)/d);1891}18921893static GEN1894F2xqX_factor_Shoup(GEN S, GEN xp, GEN T)1895{1896long i, n, s = 0;1897GEN X, Xp, Xq, Sq, D, V;1898long vT = get_F2x_var(T);1899pari_timer ti;1900n = get_F2xqX_degree(S);1901S = F2xqX_get_red(S, T);1902if (DEBUGLEVEL>=6) timer_start(&ti);1903X = polx_F2xX(get_F2xqX_var(S), vT);1904Xp = F2xqXQ_sqr(X, S, T);1905Xq = F2xqXQ_Frobenius(xp, Xp, S, T);1906Sq = F2xqXQ_powers(Xq, n-1, S, T);1907if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_Frobenius");1908D = F2xqX_ddf_Shoup(S, Xq, T);1909if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_ddf_Shoup");1910s = ddf_to_nbfact(D);1911V = cgetg(s+1, t_COL);1912for (i = 1, s = 1; i <= n; i++)1913{1914GEN Di = gel(D,i);1915long ni = degpol(Di), ri = ni/i;1916if (ni == 0) continue;1917Di = F2xqX_normalize(Di, T);1918if (ni == i) { gel(V, s++) = Di; continue; }1919F2xqX_edf_simple(Di, xp, Xp, Sq, i, T, V, s);1920if (DEBUGLEVEL>=6) timer_printf(&ti,"F2xqX_edf(%ld)",i);1921s += ri;1922}1923return V;1924}19251926static GEN1927F2xqX_factor_Cantor(GEN f, GEN T)1928{1929GEN xp, E, F, V;1930long i, j, l;1931T = F2x_get_red(T);1932f = F2xqX_normalize(f, T);1933switch(degpol(f))1934{1935case -1: retmkmat2(mkcol(f), mkvecsmall(1));1936case 0: return trivial_fact();1937case 1: retmkmat2(mkcol(f), mkvecsmall(1));1938case 2: return F2xqX_factor_2(f, T);1939}1940if (F2xY_degreex(f) <= 0) return F2x_factorff_i(F2xX_to_F2x(f), T);1941xp = F2x_Frobenius(T);1942V = F2xqX_factor_squarefree(f, T);1943l = lg(V);1944F = cgetg(l, t_VEC);1945E = cgetg(l, t_VEC);1946for (i=1, j=1; i < l; i++)1947if (degpol(gel(V,i)))1948{1949GEN Fj = F2xqX_factor_Shoup(gel(V,i), xp, T);1950gel(F, j) = Fj;1951gel(E, j) = const_vecsmall(lg(Fj)-1, i);1952j++;1953}1954return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);1955}19561957static GEN1958FlxqX_Berlekamp_i(GEN f, GEN T, ulong p)1959{1960long lfact, d = degpol(f), j, k, lV;1961GEN E, t, V, xp;1962switch(d)1963{1964case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));1965case 0: return trivial_fact();1966}1967T = Flx_get_red(T, p);1968f = FlxqX_normalize(f, T, p);1969if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);1970if (degpol(f)==2) return FlxqX_factor_2(f, T, p);1971xp = Flx_Frobenius(T, p);1972V = FlxqX_factor_squarefree_i(f, xp, T, p); lV = lg(V);19731974/* to hold factors and exponents */1975t = cgetg(d+1,t_VEC);1976E = cgetg(d+1, t_VECSMALL);1977lfact = 1;1978for (k=1; k<lV ; k++)1979{1980if (degpol(gel(V,k))==0) continue;1981gel(t,lfact) = FlxqX_normalize(gel(V, k), T,p);1982d = FlxqX_split_Berlekamp(&gel(t,lfact), xp, T, p);1983for (j = 0; j < d; j++) E[lfact+j] = k;1984lfact += d;1985}1986setlg(t, lfact);1987setlg(E, lfact);1988return sort_factor_pol(mkvec2(t, E), cmp_Flx);1989}19901991static GEN1992FpXQX_Berlekamp_i(GEN f, GEN T, GEN p)1993{1994long lfact, d = degpol(f), j, k, lV;1995GEN E, t, V;1996switch(d)1997{1998case -1: retmkmat2(mkcolcopy(f), mkvecsmall(1));1999case 0: return trivial_fact();2000}2001T = FpX_get_red(T, p);2002f = FpXQX_normalize(f, T, p);2003if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);2004if (degpol(f)==2) return FpXQX_factor_2(f, T, p);2005V = FpXQX_factor_Yun(f, T, p); lV = lg(V);20062007/* to hold factors and exponents */2008t = cgetg(d+1,t_VEC);2009E = cgetg(d+1, t_VECSMALL);2010lfact = 1;2011for (k=1; k<lV ; k++)2012{2013if (degpol(gel(V,k))==0) continue;2014gel(t,lfact) = FpXQX_normalize(gel(V, k), T,p);2015d = FpXQX_split_Berlekamp(&gel(t,lfact), T, p);2016for (j = 0; j < d; j++) E[lfact+j] = k;2017lfact += d;2018}2019setlg(t, lfact);2020setlg(E, lfact);2021return sort_factor_pol(mkvec2(t, E), cmp_RgX);2022}20232024long2025FlxqX_ddf_degree(GEN S, GEN XP, GEN T, ulong p)2026{2027pari_sp av = avma;2028GEN X, b, g, xq, q;2029long i, j, n, v, B, l, m, bo, ro;2030pari_timer ti;2031hashtable h;20322033n = get_FlxqX_degree(S); v = get_FlxqX_var(S);2034X = polx_FlxX(v,get_Flx_var(T));2035if (gequal(X,XP)) return 1;2036B = n/2;2037l = usqrt(B);2038m = (B+l-1)/l;2039T = Flx_get_red(T, p);2040S = FlxqX_get_red(S, T, p);2041hash_init_GEN(&h, l+2, gequal, 1);2042hash_insert_long(&h, X, 0);2043hash_insert_long(&h, XP, 1);2044bo = brent_kung_optpow(n, l-1, 1);2045ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);2046q = powuu(p, get_Flx_degree(T));2047if (DEBUGLEVEL>=7) timer_start(&ti);2048b = XP;2049if (expi(q) > ro)2050{2051xq = FlxqXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p);2052if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq baby");2053} else xq = NULL;2054for (i = 3; i <= l+1; i++)2055{2056b = xq ? FlxqX_FlxqXQV_eval(b, xq, S, T, p)2057: FlxqXQ_pow(b, q, S, T, p);2058if (gequal(b,X)) return gc_long(av,i-1);2059hash_insert_long(&h, b, i-1);2060}2061if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: baby");2062g = b;2063xq = FlxqXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p);2064if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_degree: xq giant");2065for(i = 2; i <= m+1; i++)2066{2067g = FlxqX_FlxqXQV_eval(g, xq, S, T, p);2068if (hash_haskey_long(&h, g, &j)) return gc_long(av, l*i-j);2069}2070return gc_long(av,n);2071}20722073static GEN2074FlxqX_ddf_Shoup(GEN S, GEN Xq, GEN T, ulong p)2075{2076pari_sp av = avma;2077GEN b, g, h, F, f, Sr, xq, q;2078long i, j, n, v, vT, bo, ro;2079long B, l, m;2080pari_timer ti;2081n = get_FlxqX_degree(S); v = get_FlxqX_var(S);2082vT = get_Flx_var(T);2083if (n == 0) return cgetg(1, t_VEC);2084if (n == 1) return mkvec(get_FlxqX_mod(S));2085B = n/2;2086l = usqrt(B);2087m = (B+l-1)/l;2088S = FlxqX_get_red(S, T, p);2089b = cgetg(l+2, t_VEC);2090gel(b, 1) = polx_FlxX(v, vT);2091gel(b, 2) = Xq;2092bo = brent_kung_optpow(n, l-1, 1);2093ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);2094q = powuu(p, get_Flx_degree(T));2095if (DEBUGLEVEL>=7) timer_start(&ti);2096if (expi(q) <= ro)2097for (i = 3; i <= l+1; i++)2098gel(b, i) = FlxqXQ_pow(gel(b, i-1), q, S, T, p);2099else2100{2101xq = FlxqXQ_powers(gel(b, 2), bo, S, T, p);2102if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq baby");2103for (i = 3; i <= l+1; i++)2104gel(b, i) = FlxqX_FlxqXQV_eval(gel(b, i-1), xq, S, T, p);2105}2106if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: baby");2107xq = FlxqXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p);2108if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: xq giant");2109g = cgetg(m+1, t_VEC);2110gel(g, 1) = gel(xq, 2);2111for(i = 2; i <= m; i++)2112gel(g, i) = FlxqX_FlxqXQV_eval(gel(g, i-1), xq, S, T, p);2113if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: giant");2114h = cgetg(m+1, t_VEC);2115for (j = 1; j <= m; j++)2116{2117pari_sp av = avma;2118GEN gj = gel(g, j);2119GEN e = FlxX_sub(gj, gel(b, 1), p);2120for (i = 2; i <= l; i++)2121e = FlxqXQ_mul(e, FlxX_sub(gj, gel(b, i), p), S, T, p);2122gel(h, j) = gerepileupto(av, e);2123}2124if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: diff");2125Sr = get_FlxqX_mod(S);2126F = cgetg(m+1, t_VEC);2127for (j = 1; j <= m; j++)2128{2129GEN u = FlxqX_gcd(Sr, gel(h, j), T, p);2130if (degpol(u))2131{2132u = FlxqX_normalize(u, T, p);2133Sr = FlxqX_div(Sr, u, T, p);2134}2135gel(F,j) = u;2136}2137if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: F");2138f = const_vec(n, pol1_FlxX(v, vT));2139for (j = 1; j <= m; j++)2140{2141GEN e = gel(F, j);2142for (i=l-1; i >= 0; i--)2143{2144GEN u = FlxqX_gcd(e, FlxX_sub(gel(g, j), gel(b, i+1), p), T, p);2145if (degpol(u))2146{2147gel(f, l*j-i) = u = FlxqX_normalize(u, T, p);2148e = FlxqX_div(e, u, T, p);2149}2150if (!degpol(e)) break;2151}2152}2153if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_ddf_Shoup: f");2154if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;2155return gerepilecopy(av, f);2156}21572158static GEN2159FlxqX_ddf_i(GEN f, GEN T, ulong p)2160{2161GEN Xq;2162if (!get_FlxqX_degree(f)) return cgetg(1, t_VEC);2163f = FlxqX_get_red(f, T, p);2164Xq = FlxqX_Frobenius(f, T, p);2165return FlxqX_ddf_Shoup(f, Xq, T, p);2166}2167GEN2168FlxqX_ddf(GEN S, GEN T, ulong p)2169{2170T = Flx_get_red(T, p);2171S = FlxqX_normalize(get_FlxqX_mod(S), T, p);2172return ddf_to_ddf2( FlxqX_ddf_i(S, T, p) );2173}2174GEN2175FlxqX_degfact(GEN S, GEN T, ulong p)2176{2177GEN V;2178long i, l;2179T = Flx_get_red(T, p);2180S = FlxqX_normalize(get_FlxqX_mod(S), T, p);2181V = FlxqX_factor_squarefree(S, T, p); l = lg(V);2182for (i=1; i < l; i++) gel(V,i) = FlxqX_ddf_i(gel(V,i), T, p);2183return vddf_to_simplefact(V, degpol(S));2184}21852186static void2187FlxqX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, ulong p, GEN V, long idx)2188{2189GEN Sp = get_FlxqX_mod(S);2190GEN u1, u2, f1, f2;2191GEN h;2192h = FlxqX_get_red(hp, T, p);2193t = FlxqX_rem(t, S, T, p);2194Xp = FlxqX_rem(Xp, h, T, p);2195u1 = FlxqX_roots_split(hp, xp, Xp, h, T, p);2196f1 = FlxqX_gcd(FlxqX_FlxqXQ_eval(u1, t, S, T, p), Sp, T, p);2197f1 = FlxqX_normalize(f1, T, p);2198u2 = FlxqX_div(hp, u1, T, p);2199f2 = FlxqX_div(Sp, f1, T, p);2200if (degpol(u1)==1)2201gel(V, idx) = f1;2202else2203FlxqX_edf_rec(FlxqX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx);2204idx += degpol(f1)/d;2205if (degpol(u2)==1)2206gel(V, idx) = f2;2207else2208FlxqX_edf_rec(FlxqX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx);2209}22102211static void2212FlxqX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx)2213{2214long n = degpol(Sp), r = n/d, vS = varn(Sp), vT = get_Flx_var(T);2215GEN S, h, t;2216pari_timer ti;2217if (r==1) { gel(V, idx) = Sp; return; }2218S = FlxqX_get_red(Sp, T, p);2219Xp = FlxqX_rem(Xp, S, T, p);2220Xq = FlxqX_rem(Xq, S, T, p);2221if (DEBUGLEVEL>=7) timer_start(&ti);2222do2223{2224GEN g = random_FlxqX(n, vS, T, p);2225t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);2226if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_auttrace");2227h = FlxqXQ_minpoly(t, S, T, p);2228if (DEBUGLEVEL>=7) timer_printf(&ti,"FlxqX_edf: FlxqXQ_minpoly");2229} while (degpol(h) != r);2230Xp = FlxqXQ_powu(polx_FlxX(vS, vT), p, h, T, p);2231FlxqX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx);2232}22332234static void2235FlxqX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, ulong p, GEN V, long idx)2236{2237long v = varn(Sp), n = degpol(Sp), r = n/d;2238GEN S, f, ff;2239long vT = get_Flx_var(T), dT = get_Flx_degree(T);2240if (r==1) { gel(V, idx) = Sp; return; }2241S = FlxqX_get_red(Sp, T, p);2242Xp = FlxqX_rem(Xp, S, T, p);2243Xq = FlxqX_rem(Xq, S, T, p);2244while (1)2245{2246pari_sp btop = avma;2247long i;2248GEN g = random_FlxqX(n, v, T, p);2249GEN t = gel(FlxqXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);2250if (lgpol(t) == 0) continue;2251for(i=1; i<=10; i++)2252{2253pari_sp btop2 = avma;2254GEN r = random_Flx(dT, vT, p);2255GEN R = FlxqXQ_halfFrobenius_i(FlxX_Flx_add(t, r, p), xp, Xp, S, T, p);2256f = FlxqX_gcd(FlxX_Flx_sub(R, pol1_Flx(vT), p), Sp, T, p);2257if (degpol(f) > 0 && degpol(f) < n) break;2258set_avma(btop2);2259}2260if (degpol(f) > 0 && degpol(f) < n) break;2261set_avma(btop);2262}2263f = FlxqX_normalize(f, T, p);2264ff = FlxqX_div(Sp, f , T, p);2265FlxqX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx);2266FlxqX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d);2267}22682269static GEN2270FlxqX_factor_Shoup(GEN S, GEN xp, GEN T, ulong p)2271{2272long i, n, s = 0;2273GEN X, Xp, Xq, D, V;2274long dT = get_Flx_degree(T), vT = get_Flx_var(T);2275long e = expi(powuu(p, dT));2276pari_timer ti;2277n = get_FlxqX_degree(S);2278S = FlxqX_get_red(S, T, p);2279if (DEBUGLEVEL>=6) timer_start(&ti);2280X = polx_FlxX(get_FlxqX_var(S), vT);2281Xp = FlxqXQ_powu(X, p, S, T, p);2282Xq = FlxqXQ_Frobenius(xp, Xp, S, T, p);2283if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_Frobenius");2284D = FlxqX_ddf_Shoup(S, Xq, T, p);2285if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_ddf_Shoup");2286s = ddf_to_nbfact(D);2287V = cgetg(s+1, t_COL);2288for (i = 1, s = 1; i <= n; i++)2289{2290GEN Di = gel(D,i);2291long ni = degpol(Di), ri = ni/i;2292if (ni == 0) continue;2293Di = FlxqX_normalize(Di, T, p);2294if (ni == i) { gel(V, s++) = Di; continue; }2295if (ri <= e*expu(e))2296FlxqX_edf(Di, xp, Xp, Xq, i, T, p, V, s);2297else2298FlxqX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s);2299if (DEBUGLEVEL>=6) timer_printf(&ti,"FlxqX_edf(%ld)",i);2300s += ri;2301}2302return V;2303}23042305static GEN2306FlxqX_factor_Cantor(GEN f, GEN T, ulong p)2307{2308GEN xp, E, F, V;2309long i, j, l;2310T = Flx_get_red(T, p);2311f = FlxqX_normalize(f, T, p);2312switch(degpol(f))2313{2314case -1: retmkmat2(mkcol(f), mkvecsmall(1));2315case 0: return trivial_fact();2316case 1: retmkmat2(mkcol(f), mkvecsmall(1));2317case 2: return FlxqX_factor_2(f, T, p);2318}2319if (FlxY_degreex(f) <= 0) return Flx_factorff_i(FlxX_to_Flx(f), T, p);2320xp = Flx_Frobenius(T, p);2321V = FlxqX_factor_squarefree_i(f, xp, get_Flx_mod(T), p);2322l = lg(V);2323F = cgetg(l, t_VEC);2324E = cgetg(l, t_VEC);2325for (i=1, j=1; i < l; i++)2326if (degpol(gel(V,i)))2327{2328GEN Fj = FlxqX_factor_Shoup(gel(V,i), xp, T, p);2329gel(F, j) = Fj;2330gel(E, j) = const_vecsmall(lg(Fj)-1, i);2331j++;2332}2333return sort_factor_pol(FE_concat(F,E,j), cmp_Flx);2334}23352336long2337FlxqX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, ulong p)2338{2339pari_sp av = avma;2340GEN u = get_FlxqX_mod(S);2341long s;2342if (FlxY_degreex(u) <= 0)2343s = Flx_nbfactff(FlxX_to_Flx(u), T, p);2344else2345s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, Xq, T, p));2346return gc_long(av,s);2347}23482349long2350FlxqX_nbfact(GEN S, GEN T, ulong p)2351{2352pari_sp av = avma;2353GEN u = get_FlxqX_mod(S);2354long s;2355if (FlxY_degreex(u) <= 0)2356s = Flx_nbfactff(FlxX_to_Flx(u), T, p);2357else2358s = ddf_to_nbfact(FlxqX_ddf_Shoup(S, FlxqX_Frobenius(S, T, p), T, p));2359return gc_long(av,s);2360}23612362GEN2363FlxqX_factor(GEN x, GEN T, ulong p)2364{2365pari_sp av = avma;2366return gerepilecopy(av, FlxqX_factor_Cantor(x, T, p));2367}23682369GEN2370F2xqX_factor(GEN x, GEN T)2371{2372pari_sp av = avma;2373return gerepilecopy(av, F2xqX_factor_Cantor(x, T));2374}23752376long2377FpXQX_ddf_degree(GEN S, GEN XP, GEN T, GEN p)2378{2379pari_sp av = avma;2380GEN X, b, g, xq, q;2381long i, j, n, v, B, l, m, bo, ro;2382pari_timer ti;2383hashtable h;23842385n = get_FpXQX_degree(S); v = get_FpXQX_var(S);2386X = pol_x(v);2387if (gequal(X,XP)) return 1;2388B = n/2;2389l = usqrt(B);2390m = (B+l-1)/l;2391T = FpX_get_red(T, p);2392S = FpXQX_get_red(S, T, p);2393hash_init_GEN(&h, l+2, gequal, 1);2394hash_insert_long(&h, X, 0);2395hash_insert_long(&h, simplify_shallow(XP), 1);2396bo = brent_kung_optpow(n, l-1, 1);2397ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);2398q = powiu(p, get_FpX_degree(T));2399if (DEBUGLEVEL>=7) timer_start(&ti);2400b = XP;2401if (expi(q) > ro)2402{2403xq = FpXQXQ_powers(b, brent_kung_optpow(n, l-1, 1), S, T, p);2404if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq baby");2405} else xq = NULL;2406for (i = 3; i <= l+1; i++)2407{2408b = xq ? FpXQX_FpXQXQV_eval(b, xq, S, T, p)2409: FpXQXQ_pow(b, q, S, T, p);2410if (gequal(b,X)) return gc_long(av,i-1);2411hash_insert_long(&h, simplify_shallow(b), i-1);2412}2413if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: baby");2414g = b;2415xq = FpXQXQ_powers(g, brent_kung_optpow(n, m, 1), S, T, p);2416if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_degree: xq giant");2417for(i = 2; i <= m+1; i++)2418{2419g = FpXQX_FpXQXQV_eval(g, xq, S, T, p);2420if (hash_haskey_long(&h, simplify_shallow(g), &j)) return gc_long(av,l*i-j);2421}2422return gc_long(av,n);2423}24242425static GEN2426FpXQX_ddf_Shoup(GEN S, GEN Xq, GEN T, GEN p)2427{2428pari_sp av = avma;2429GEN b, g, h, F, f, Sr, xq, q;2430long i, j, n, v, bo, ro;2431long B, l, m;2432pari_timer ti;2433n = get_FpXQX_degree(S); v = get_FpXQX_var(S);2434if (n == 0) return cgetg(1, t_VEC);2435if (n == 1) return mkvec(get_FpXQX_mod(S));2436B = n/2;2437l = usqrt(B);2438m = (B+l-1)/l;2439S = FpXQX_get_red(S, T, p);2440b = cgetg(l+2, t_VEC);2441gel(b, 1) = pol_x(v);2442gel(b, 2) = Xq;2443bo = brent_kung_optpow(n, l-1, 1);2444ro = l<=1 ? 0: (bo-1)/(l-1) + ((n-1)/bo);2445q = powiu(p, get_FpX_degree(T));2446if (DEBUGLEVEL>=7) timer_start(&ti);2447if (expi(q) <= ro)2448for (i = 3; i <= l+1; i++)2449gel(b, i) = FpXQXQ_pow(gel(b, i-1), q, S, T, p);2450else2451{2452xq = FpXQXQ_powers(gel(b, 2), bo, S, T, p);2453if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq baby");2454for (i = 3; i <= l+1; i++)2455gel(b, i) = FpXQX_FpXQXQV_eval(gel(b, i-1), xq, S, T, p);2456}2457if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: baby");2458xq = FpXQXQ_powers(gel(b, l+1), brent_kung_optpow(n, m-1, 1), S, T, p);2459if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: xq giant");2460g = cgetg(m+1, t_VEC);2461gel(g, 1) = gel(xq, 2);2462for(i = 2; i <= m; i++)2463gel(g, i) = FpXQX_FpXQXQV_eval(gel(g, i-1), xq, S, T, p);2464if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: giant");2465h = cgetg(m+1, t_VEC);2466for (j = 1; j <= m; j++)2467{2468pari_sp av = avma;2469GEN gj = gel(g, j);2470GEN e = FpXX_sub(gj, gel(b, 1), p);2471for (i = 2; i <= l; i++)2472e = FpXQXQ_mul(e, FpXX_sub(gj, gel(b, i), p), S, T, p);2473gel(h, j) = gerepileupto(av, e);2474}2475if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: diff");2476Sr = get_FpXQX_mod(S);2477F = cgetg(m+1, t_VEC);2478for (j = 1; j <= m; j++)2479{2480GEN u = FpXQX_gcd(Sr, gel(h,j), T, p);2481if (degpol(u))2482{2483u = FpXQX_normalize(u, T, p);2484Sr = FpXQX_div(Sr, u, T, p);2485}2486gel(F,j) = u;2487}2488if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: F");2489f = const_vec(n, pol_1(v));2490for (j = 1; j <= m; j++)2491{2492GEN e = gel(F, j);2493for (i=l-1; i >= 0; i--)2494{2495GEN u = FpXQX_gcd(e, FpXX_sub(gel(g, j), gel(b, i+1), p), T, p);2496if (degpol(u))2497{2498gel(f, l*j-i) = u = FpXQX_normalize(u, T, p);2499e = FpXQX_div(e, u, T, p);2500}2501if (!degpol(e)) break;2502}2503}2504if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_ddf_Shoup: f");2505if (degpol(Sr)) gel(f, degpol(Sr)) = Sr;2506return gerepilecopy(av, f);2507}25082509static GEN2510FpXQX_ddf_i(GEN f, GEN T, GEN p)2511{2512GEN Xq;2513if (!get_FpXQX_degree(f)) return cgetg(1,t_VEC);2514f = FpXQX_get_red(f, T, p);2515Xq = FpXQX_Frobenius(f, T, p);2516return FpXQX_ddf_Shoup(f, Xq, T, p);2517}25182519static GEN2520FpXQX_ddf_raw(GEN f, GEN T, GEN p)2521{2522if (lgefint(p)==3)2523{2524ulong pp = p[2];2525GEN M;2526long vT = get_FpX_var(T);2527if (pp==2)2528{2529M = F2xqX_ddf(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));2530return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));2531}2532M = FlxqX_ddf(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);2533return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));2534}2535T = FpX_get_red(T, p);2536f = FpXQX_normalize(get_FpXQX_mod(f), T, p);2537return ddf_to_ddf2( FpXQX_ddf_i(f, T, p) );2538}25392540GEN2541FpXQX_ddf(GEN x, GEN T, GEN p)2542{ pari_sp av = avma; return gerepilecopy(av, FpXQX_ddf_raw(x,T,p)); }25432544static GEN2545FpXQX_degfact_raw(GEN f, GEN T, GEN p)2546{2547GEN V;2548long i,l;2549if (lgefint(p)==3)2550{2551ulong pp = p[2];2552long vT = get_FpX_var(T);2553if (pp==2)2554return F2xqX_degfact(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));2555else2556return FlxqX_degfact(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);2557}2558T = FpX_get_red(T, p);2559f = FpXQX_normalize(get_FpXQX_mod(f), T, p);2560V = FpXQX_factor_Yun(f, T, p); l = lg(V);2561for (i=1; i < l; i++) gel(V,i) = FpXQX_ddf_i(gel(V,i), T, p);2562return vddf_to_simplefact(V, degpol(f));2563}25642565GEN2566FpXQX_degfact(GEN x, GEN T, GEN p)2567{ pari_sp av = avma; return gerepilecopy(av, FpXQX_degfact_raw(x,T,p)); }25682569static void2570FpXQX_edf_rec(GEN S, GEN xp, GEN Xp, GEN hp, GEN t, long d, GEN T, GEN p, GEN V, long idx)2571{2572GEN Sp = get_FpXQX_mod(S);2573GEN u1, u2, f1, f2;2574GEN h;2575h = FpXQX_get_red(hp, T, p);2576t = FpXQX_rem(t, S, T, p);2577Xp = FpXQX_rem(Xp, h, T, p);2578u1 = FpXQX_roots_split(hp, xp, Xp, h, T, p);2579f1 = FpXQX_gcd(FpXQX_FpXQXQ_eval(u1, t, S, T, p), Sp, T, p);2580f1 = FpXQX_normalize(f1, T, p);2581u2 = FpXQX_div(hp, u1, T, p);2582f2 = FpXQX_div(Sp, f1, T, p);2583if (degpol(u1)==1)2584gel(V, idx) = f1;2585else2586FpXQX_edf_rec(FpXQX_get_red(f1, T, p), xp, Xp, u1, t, d, T, p, V, idx);2587idx += degpol(f1)/d;2588if (degpol(u2)==1)2589gel(V, idx) = f2;2590else2591FpXQX_edf_rec(FpXQX_get_red(f2, T, p), xp, Xp, u2, t, d, T, p, V, idx);2592}25932594static void2595FpXQX_edf(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)2596{2597long n = degpol(Sp), r = n/d, vS = varn(Sp);2598GEN S, h, t;2599pari_timer ti;2600if (r==1) { gel(V, idx) = Sp; return; }2601S = FpXQX_get_red(Sp, T, p);2602Xp = FpXQX_rem(Xp, S, T, p);2603Xq = FpXQX_rem(Xq, S, T, p);2604if (DEBUGLEVEL>=7) timer_start(&ti);2605do2606{2607GEN g = random_FpXQX(n, vS, T, p);2608t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);2609if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_auttrace");2610h = FpXQXQ_minpoly(t, S, T, p);2611if (DEBUGLEVEL>=7) timer_printf(&ti,"FpXQX_edf: FpXQXQ_minpoly");2612} while (degpol(h) != r);2613Xp = FpXQXQ_pow(pol_x(vS), p, h, T, p);2614FpXQX_edf_rec(S, xp, Xp, h, t, d, T, p, V, idx);2615}26162617static void2618FpXQX_edf_simple(GEN Sp, GEN xp, GEN Xp, GEN Xq, long d, GEN T, GEN p, GEN V, long idx)2619{2620long v = varn(Sp), n = degpol(Sp), r = n/d;2621GEN S, f, ff;2622long vT = get_FpX_var(T), dT = get_FpX_degree(T);2623if (r==1) { gel(V, idx) = Sp; return; }2624S = FpXQX_get_red(Sp, T, p);2625Xp = FpXQX_rem(Xp, S, T, p);2626Xq = FpXQX_rem(Xq, S, T, p);2627while (1)2628{2629pari_sp btop = avma;2630long i;2631GEN g = random_FpXQX(n, v, T, p);2632GEN t = gel(FpXQXQ_auttrace(mkvec2(Xq, g), d, S, T, p), 2);2633if (lgpol(t) == 0) continue;2634for(i=1; i<=10; i++)2635{2636pari_sp btop2 = avma;2637GEN r = random_FpX(dT, vT, p);2638GEN R = FpXQXQ_halfFrobenius_i(FqX_Fq_add(t, r, T, p), xp, Xp, S, T, p);2639f = FpXQX_gcd(FqX_Fq_add(R, gen_m1, T, p), Sp, T, p);2640if (degpol(f) > 0 && degpol(f) < n) break;2641set_avma(btop2);2642}2643if (degpol(f) > 0 && degpol(f) < n) break;2644set_avma(btop);2645}2646f = FpXQX_normalize(f, T, p);2647ff = FpXQX_div(Sp, f , T, p);2648FpXQX_edf_simple(f, xp, Xp, Xq, d, T, p, V, idx);2649FpXQX_edf_simple(ff, xp, Xp, Xq, d, T, p, V, idx+degpol(f)/d);2650}26512652static GEN2653FpXQX_factor_Shoup(GEN S, GEN xp, GEN T, GEN p)2654{2655long i, n, s = 0, dT = get_FpX_degree(T), e = expi(powiu(p, dT));2656GEN X, Xp, Xq, D, V;2657pari_timer ti;2658n = get_FpXQX_degree(S);2659S = FpXQX_get_red(S, T, p);2660if (DEBUGLEVEL>=6) timer_start(&ti);2661X = pol_x(get_FpXQX_var(S));2662Xp = FpXQXQ_pow(X, p, S, T, p);2663Xq = FpXQXQ_Frobenius(xp, Xp, S, T, p);2664if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_Frobenius");2665D = FpXQX_ddf_Shoup(S, Xq, T, p);2666if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_ddf_Shoup");2667s = ddf_to_nbfact(D);2668V = cgetg(s+1, t_COL);2669for (i = 1, s = 1; i <= n; i++)2670{2671GEN Di = gel(D,i);2672long ni = degpol(Di), ri = ni/i;2673if (ni == 0) continue;2674Di = FpXQX_normalize(Di, T, p);2675if (ni == i) { gel(V, s++) = Di; continue; }2676if (ri <= e*expu(e))2677FpXQX_edf(Di, xp, Xp, Xq, i, T, p, V, s);2678else2679FpXQX_edf_simple(Di, xp, Xp, Xq, i, T, p, V, s);2680if (DEBUGLEVEL>=6) timer_printf(&ti,"FpXQX_edf(%ld)",i);2681s += ri;2682}2683return V;2684}26852686static GEN2687FpXQX_factor_Cantor(GEN f, GEN T, GEN p)2688{2689GEN xp, E, F, V;2690long i, j, l;2691T = FpX_get_red(T, p);2692f = FpXQX_normalize(f, T, p);2693switch(degpol(f))2694{2695case -1: retmkmat2(mkcol(f), mkvecsmall(1));2696case 0: return trivial_fact();2697case 1: retmkmat2(mkcol(f), mkvecsmall(1));2698case 2: return FpXQX_factor_2(f, T, p);2699}2700if (isabsolutepol(f)) return FpX_factorff_i(simplify_shallow(f), T, p);2701xp = FpX_Frobenius(T, p);2702V = FpXQX_factor_Yun(f, T, p);2703l = lg(V);2704F = cgetg(l, t_VEC);2705E = cgetg(l, t_VEC);2706for (i=1, j=1; i < l; i++)2707if (degpol(gel(V,i)))2708{2709GEN Fj = FpXQX_factor_Shoup(gel(V,i), xp, T, p);2710gel(E,j) = const_vecsmall(lg(Fj)-1, i);2711gel(F,j) = Fj; j++;2712}2713return sort_factor_pol(FE_concat(F,E,j), cmp_RgX);2714}27152716long2717FpXQX_nbfact_Frobenius(GEN S, GEN Xq, GEN T, GEN p)2718{2719pari_sp av = avma;2720GEN u = get_FpXQX_mod(S);2721long s;2722if (lgefint(p)==3)2723{2724ulong pp = p[2];2725long vT = get_FpX_var(T);2726GEN Sp = ZXXT_to_FlxXT(S,pp,vT), Xqp = ZXX_to_FlxX(Xq,pp,vT);2727s = FlxqX_nbfact_Frobenius(Sp, Xqp, ZXT_to_FlxT(T,pp), pp);2728}2729else if (isabsolutepol(u))2730s = FpX_nbfactff(simplify_shallow(u), T, p);2731else2732s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, Xq, T, p));2733return gc_long(av,s);2734}27352736long2737FpXQX_nbfact(GEN S, GEN T, GEN p)2738{2739pari_sp av = avma;2740GEN u = get_FpXQX_mod(S);2741long s;2742if (lgefint(p)==3)2743{2744ulong pp = p[2];2745long vT = get_FpX_var(T);2746s = FlxqX_nbfact(ZXXT_to_FlxXT(S,pp,vT), ZXT_to_FlxT(T,pp), pp);2747}2748else if (isabsolutepol(u))2749s = FpX_nbfactff(simplify_shallow(u), T, p);2750else2751s = ddf_to_nbfact(FpXQX_ddf_Shoup(S, FpXQX_Frobenius(S, T, p), T, p));2752return gc_long(av,s);2753}2754long2755FqX_nbfact(GEN u, GEN T, GEN p)2756{ return T ? FpXQX_nbfact(u, T, p): FpX_nbfact(u, p); }27572758static GEN2759FpXQX_factor_Berlekamp_i(GEN f, GEN T, GEN p)2760{2761if (lgefint(p)==3)2762{2763ulong pp = p[2];2764GEN M;2765long vT = get_FpX_var(T);2766if (pp==2)2767{2768M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));2769return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));2770}2771M = FlxqX_Berlekamp_i(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);2772return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));2773}2774return FpXQX_Berlekamp_i(f, T, p);2775}2776GEN2777FpXQX_factor_Berlekamp(GEN x, GEN T, GEN p)2778{ pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_Berlekamp_i(x,T,p)); }27792780static GEN2781FpXQX_factor_i(GEN f, GEN T, GEN p)2782{2783if (lgefint(p)==3)2784{2785ulong pp = p[2];2786GEN M;2787long vT = get_FpX_var(T);2788if (pp==2)2789{2790M = F2xqX_factor_Cantor(ZXX_to_F2xX(f, vT), ZX_to_F2x(get_FpX_mod(T)));2791return mkvec2(F2xXC_to_ZXXC(gel(M,1)), gel(M,2));2792}2793M = FlxqX_factor_Cantor(ZXX_to_FlxX(f, pp, vT), ZXT_to_FlxT(T, pp), pp);2794return mkvec2(FlxXC_to_ZXXC(gel(M,1)), gel(M,2));2795}2796return FpXQX_factor_Cantor(f, T, p);2797}2798GEN2799FpXQX_factor(GEN x, GEN T, GEN p)2800{ pari_sp av = avma; return gerepilecopy(av, FpXQX_factor_i(x,T,p)); }28012802long2803FlxqX_is_squarefree(GEN P, GEN T, ulong p)2804{2805pari_sp av = avma;2806GEN z = FlxqX_gcd(P, FlxX_deriv(P, p), T, p);2807return gc_long(av, degpol(z)==0);2808}28092810long2811FqX_is_squarefree(GEN P, GEN T, GEN p)2812{2813pari_sp av = avma;2814GEN z = FqX_gcd(P, FqX_deriv(P, T, p), T, p);2815return gc_long(av, degpol(z)==0);2816}28172818/* as RgX_to_FpXQ(FqX_to_FFX), leaving alone t_FFELT */2819static GEN2820RgX_to_FFX(GEN x, GEN ff)2821{2822long i, lx;2823GEN p = FF_p_i(ff), T = FF_mod(ff), y = cgetg_copy(x,&lx);2824y[1] = x[1]; if (degpol(T) == 1) T = NULL;2825for (i = 2; i < lx; i++)2826{2827GEN c = gel(x,i);2828gel(y,i) = typ(c) == t_FFELT? c: Fq_to_FF(Rg_to_Fq(c,T,p), ff);2829}2830return y;2831}28322833#define code(t1,t2) ((t1 << 6) | t2)2834/* Check types and replace F by a monic normalized FpX having the same roots2835* Don't bother to make constant polynomials monic */2836static GEN2837factmod_init(GEN f, GEN *pD, GEN *pT, GEN *pp)2838{2839const char *s = "factormod";2840GEN T, p, D = *pD;2841if (typ(f) != t_POL) pari_err_TYPE(s,f);2842if (!D)2843{2844long pa, t = RgX_type(f, pp, pT, &pa);2845if (t == t_FFELT) return f;2846*pD = gen_0;2847if (t != t_INTMOD && t != code(t_POLMOD,t_INTMOD)) pari_err_TYPE(s,f);2848return RgX_to_FqX(f, *pT, *pp);2849}2850if (typ(D) == t_FFELT) { *pD = NULL; *pT = D; return RgX_to_FFX(f,D); }2851if (!ff_parse_Tp(D, &T, &p, 1)) pari_err_TYPE(s,D);2852if (T && varncmp(varn(T), varn(f)) <= 0)2853pari_err_PRIORITY(s, T, "<=", varn(f));2854*pT = T; *pp = p; return RgX_to_FqX(f, T, p);2855}2856#undef code28572858int2859ff_parse_Tp(GEN Tp, GEN *T, GEN *p, long red)2860{2861long t = typ(Tp);2862*T = *p = NULL;2863if (t == t_INT) { *p = Tp; return cmpiu(*p, 1) > 0; }2864if (t != t_VEC || lg(Tp) != 3) return 0;2865*T = gel(Tp,1);2866*p = gel(Tp,2);2867if (typ(*p) != t_INT)2868{2869if (typ(*T) != t_INT) return 0;2870swap(*T, *p); /* support both [T,p] and [p,T] */2871}2872if (red) *T = RgX_to_FpX(*T, *p);2873return cmpiu(*p, 1) > 0 && typ(*T) == t_POL && RgX_is_ZX(*T);2874}28752876static GEN2877to_Fq(GEN x, GEN T, GEN p)2878{2879long i, lx, tx = typ(x);2880GEN y;28812882if (tx == t_INT)2883y = mkintmod(x,p);2884else2885{2886if (tx != t_POL) pari_err_TYPE("to_Fq",x);2887y = cgetg_copy(x,&lx); y[1] = x[1];2888for (i=2; i<lx; i++) gel(y,i) = mkintmod(gel(x,i), p);2889}2890return mkpolmod(y, T);2891}2892static GEN2893to_Fq_pol(GEN x, GEN T, GEN p)2894{2895long i, lx = lg(x);2896if (lx == 2)2897{2898GEN y = cgetg(3,t_POL); y[1]=x[1];2899gel(y,2) = mkintmod(gen_0,p); return y;2900}2901for (i = 2; i < lx; i++) gel(x,i) = to_Fq(gel(x,i),T,p);2902return x;2903}2904static GEN2905to_Fq_fact(GEN fa, GEN T, GEN p)2906{2907GEN P = gel(fa,1);2908long j, l = lg(P);2909p = icopy(p); T = FpX_to_mod(T, p);2910for (j=1; j<l; j++) gel(P,j) = to_Fq_pol(gel(P,j), T,p);2911return fa;2912}2913static GEN2914to_FqC(GEN P, GEN T, GEN p)2915{2916long j, l = lg(P);2917p = icopy(p); T = FpX_to_mod(T, p);2918for (j=1; j<l; j++) gel(P,j) = to_Fq(gel(P,j), T,p);2919return P;2920}29212922GEN2923factmod(GEN f, GEN D)2924{2925pari_sp av;2926GEN y, F, P, E, T, p;2927f = factmod_init(f, &D, &T,&p);2928if (!D) return FFX_factor(f, T);2929av = avma;2930F = FqX_factor(f, T, p); P = gel(F,1); E = gel(F,2);2931if (!T)2932{2933y = cgetg(3, t_MAT);2934gel(y,1) = FpXC_to_mod(P, p);2935gel(y,2) = Flc_to_ZC(E); return gerepileupto(av, y);2936}2937F = gerepilecopy(av, mkmat2(simplify_shallow(P), Flc_to_ZC(E)));2938return to_Fq_fact(F, T, p);2939}2940GEN2941simplefactmod(GEN f, GEN D)2942{2943pari_sp av = avma;2944GEN T, p;2945f = factmod_init(f, &D, &T,&p);2946if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }2947f = D? FqX_degfact(f, T, p): FFX_degfact(f, T);2948return gerepileupto(av, Flm_to_ZM(f));2949}2950static GEN2951sqf_to_fact(GEN f)2952{2953long i, j, l = lg(f);2954GEN P = cgetg(l, t_COL), E = cgetg(l, t_COL);2955for (i = j = 1; i < l; i++)2956if (degpol(gel(f,i)))2957{2958gel(P,j) = gel(f,i);2959gel(E,j) = utoi(i); j++;2960}2961setlg(P,j);2962setlg(E,j); return mkvec2(P,E);2963}29642965GEN2966factormodSQF(GEN f, GEN D)2967{2968pari_sp av = avma;2969GEN F, T, p;2970f = factmod_init(f, &D, &T,&p);2971if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }2972if (!D)2973F = sqf_to_fact(FFX_factor_squarefree(f, T));2974else2975{2976F = sqf_to_fact(FqX_factor_squarefree(f,T,p));2977gel(F,1) = FqXC_to_mod(gel(F,1), T,p);2978}2979settyp(F,t_MAT); return gerepilecopy(av, F);2980}2981GEN2982factormodDDF(GEN f, GEN D)2983{2984pari_sp av = avma;2985GEN F, T, p;2986f = factmod_init(f, &D, &T,&p);2987if (lg(f) <= 3) { set_avma(av); return trivial_fact(); }2988if (!D) return FFX_ddf(f, T);2989F = FqX_ddf(f,T,p);2990gel(F,1) = FqXC_to_mod(gel(F,1), T,p);2991gel(F,2) = Flc_to_ZC(gel(F,2));2992settyp(F, t_MAT); return gerepilecopy(av, F);2993}29942995GEN2996factormod0(GEN f, GEN p, long flag)2997{2998if (flag == 0) return factmod(f,p);2999if (flag != 1) pari_err_FLAG("factormod");3000return simplefactmod(f,p);3001}3002GEN3003polrootsmod(GEN f, GEN D)3004{3005pari_sp av;3006GEN y, T, p;3007f = factmod_init(f, &D, &T,&p);3008if (!D) return FFX_roots(f, T);3009av = avma; y = FqX_roots(f, T, p);3010if (!T) return gerepileupto(av, FpC_to_mod(y,p));3011y = gerepilecopy(av, simplify_shallow(y));3012return to_FqC(y, T, p);3013}30143015GEN /* OBSOLETE */3016rootmod0(GEN f, GEN p, long flag) { (void)flag; return polrootsmod(f,p); }3017GEN /* OBSOLETE */3018factorff(GEN f, GEN p, GEN T)3019{3020pari_sp av = avma;3021GEN D = (p && T)? mkvec2(T,p): NULL;3022return gerepileupto(av, factmod(f,D));3023}3024GEN /* OBSOLETE */3025polrootsff(GEN f, GEN p, GEN T)3026{3027pari_sp av = avma;3028GEN D = (p && T)? mkvec2(T,p): NULL;3029return gerepileupto(av, polrootsmod(f, D));3030}303130323033