GEN bnflogdegree(GEN nf, GEN A, GEN ell) { pari_sp av = avma; GEN AZ, A0Z, NA0; long vAZ; if (typ(ell) != t_INT) pari_err_TYPE("bnflogdegree", ell); nf = checknf(nf); A = idealhnf(nf, A); AZ = gcoeff(A,1,1); vAZ = Z_pvalrem(AZ, ell, &A0Z); if (is_pm1(A0Z)) NA0 = gen_1; else (void)Z_pvalrem(idealnorm(nf,A), ell, &NA0); if (vAZ) { GEN Aell = ZM_hnfmodid(A, powiu(ell,vAZ)); GEN S = idealprimedec(nf, ell), T; long l, i, s = 0; T = padicfact(nf, S, 100); l = lg(S); for (i = 1; i < l; i++) { GEN P = gel(S,i); long v = idealval(nf, Aell, P); if (v) s += v * ftilde(nf, P, gel(T,i)); } if (s) NA0 = gmul(NA0, gpowgs(ell1(ell), s)); } return gerepileupto(av, NA0); }
static GEN _F2xqE_mul(void *E, GEN P, GEN n) { pari_sp av = avma; struct _F2xqE *e=(struct _F2xqE *) E; long s = signe(n); if (!s || ell_is_inf(P)) return ellinf(); if (s<0) P = F2xqE_neg(P, e->a2, e->T); if (is_pm1(n)) return s>0? gcopy(P): P; return gerepileupto(av, gen_pow(P, n, e, &_F2xqE_dbl, &_F2xqE_add)); }
GEN gcdii(GEN a, GEN b) { long v, w; pari_sp av; GEN t; switch (absi_cmp(a,b)) { case 0: return absi(a); case -1: swap(a,b); } if (!signe(b)) return absi(a); /* here |a|>|b|>0. Try single precision first */ if (lgefint(a)==3) return igcduu((ulong)a[2], (ulong)b[2]); if (lgefint(b)==3) { ulong u = resiu(a,(ulong)b[2]); if (!u) return absi(b); return igcduu((ulong)b[2], u); } /* larger than gcd: "avma=av" gerepile (erasing t) is valid */ av = avma; (void)new_chunk(lgefint(b)+1); /* HACK */ t = remii(a,b); if (!signe(t)) { avma=av; return absi(b); } a = b; b = t; v = vali(a); a = shifti(a,-v); setabssign(a); w = vali(b); b = shifti(b,-w); setabssign(b); if (w < v) v = w; switch(absi_cmp(a,b)) { case 0: avma=av; a=shifti(a,v); return a; case -1: swap(a,b); } if (is_pm1(b)) { avma=av; return int2n(v); } { /* general case */ /*This serve two purposes: 1) mpn_gcd destroy its input and need an extra * limb 2) this allows us to use icopy instead of gerepile later. NOTE: we * must put u before d else the final icopy could fail. */ GEN res= cgeti(lgefint(a)+1); GEN ca = icopy_ef(a,lgefint(a)+1); GEN cb = icopy_ef(b,lgefint(b)+1); long l = mpn_gcd(LIMBS(res), LIMBS(ca), NLIMBS(ca), LIMBS(cb), NLIMBS(cb)); res[1] = evalsigne(1)|evallgefint(l+2); avma=av; return shifti(res,v); } }
static GEN nf_chk_factors(nfcmbf_t *T, GEN P, GEN M_L, GEN famod, GEN pk) { GEN nf = T->nf, bound = T->bound; GEN nfT = gel(nf,1); long i, r; GEN pol = P, list, piv, y; GEN C2ltpol, C = T->L->topowden, Tpk = T->L->Tpk; GEN lc = absi(leading_term(pol)), lt = is_pm1(lc)? NULL: lc; GEN Clt = mul_content(C, lt); GEN C2lt = mul_content(C,Clt); piv = special_pivot(M_L); if (!piv) return NULL; if (DEBUGLEVEL>3) fprintferr("special_pivot output:\n%Z\n",piv); r = lg(piv)-1; list = cgetg(r+1, t_COL); C2ltpol = C2lt? gmul(C2lt,pol): pol; for (i = 1;;) { pari_sp av = avma; if (DEBUGLEVEL) fprintferr("nf_LLL_cmbf: checking factor %ld (avma - bot = %lu)\n", i, avma - bot); y = chk_factors_get(lt, famod, gel(piv,i), Tpk, pk); if (DEBUGLEVEL>2) fprintferr("... mod p^k (avma - bot = %lu)\n", avma-bot); if (! (y = nf_pol_lift(y, bound, T)) ) return NULL; if (DEBUGLEVEL>2) fprintferr("... lifted (avma - bot = %lu)\n", avma-bot); y = gerepilecopy(av, y); /* y is the candidate factor */ pol = RgXQX_divrem(C2ltpol, y, nfT, ONLY_DIVIDES); if (!pol) return NULL; y = Q_primpart(y); gel(list,i) = QXQX_normalize(y, nfT); if (++i >= r) break; if (C2lt) pol = Q_primpart(pol); if (lt) lt = absi(leading_term(pol)); Clt = mul_content(C, lt); C2lt = mul_content(C,Clt); C2ltpol = C2lt? gmul(C2lt,pol): pol; } y = Q_primpart(pol); gel(list,i) = QXQX_normalize(y, nfT); return list; }
/* Naive recombination of modular factors: combine up to maxK modular * factors, degree <= klim and divisible by hint * * target = polynomial we want to factor * famod = array of modular factors. Product should be congruent to * target/lc(target) modulo p^a * For true factors: S1,S2 <= p^b, with b <= a and p^(b-a) < 2^31 */ static GEN nfcmbf(nfcmbf_t *T, GEN p, long a, long maxK, long klim) { GEN pol = T->pol, nf = T->nf, famod = T->fact, dn = T->dn; GEN bound = T->bound; GEN nfpol = gel(nf,1); long K = 1, cnt = 1, i,j,k, curdeg, lfamod = lg(famod)-1, dnf = degpol(nfpol); GEN res = cgetg(3, t_VEC); pari_sp av0 = avma; GEN pk = gpowgs(p,a), pks2 = shifti(pk,-1); GEN ind = cgetg(lfamod+1, t_VECSMALL); GEN degpol = cgetg(lfamod+1, t_VECSMALL); GEN degsofar = cgetg(lfamod+1, t_VECSMALL); GEN listmod = cgetg(lfamod+1, t_COL); GEN fa = cgetg(lfamod+1, t_COL); GEN lc = absi(leading_term(pol)), lt = is_pm1(lc)? NULL: lc; GEN C2ltpol, C = T->L->topowden, Tpk = T->L->Tpk; GEN Clt = mul_content(C, lt); GEN C2lt = mul_content(C,Clt); const double Bhigh = get_Bhigh(lfamod, dnf); trace_data _T1, _T2, *T1, *T2; pari_timer ti; TIMERstart(&ti); if (maxK < 0) maxK = lfamod-1; C2ltpol = C2lt? gmul(C2lt,pol): pol; { GEN q = ceil_safe(sqrtr(T->BS_2)); GEN t1,t2, ltdn, lt2dn; GEN trace1 = cgetg(lfamod+1, t_MAT); GEN trace2 = cgetg(lfamod+1, t_MAT); ltdn = mul_content(lt, dn); lt2dn= mul_content(ltdn, lt); for (i=1; i <= lfamod; i++) { pari_sp av = avma; GEN P = gel(famod,i); long d = degpol(P); degpol[i] = d; P += 2; t1 = gel(P,d-1);/* = - S_1 */ t2 = gsqr(t1); if (d > 1) t2 = gsub(t2, gmul2n(gel(P,d-2), 1)); /* t2 = S_2 Newton sum */ t2 = typ(t2)!=t_INT? FpX_rem(t2, Tpk, pk): modii(t2, pk); if (lt) { if (typ(t2)!=t_INT) { t1 = FpX_red(gmul(ltdn, t1), pk); t2 = FpX_red(gmul(lt2dn,t2), pk); } else { t1 = remii(mulii(ltdn, t1), pk); t2 = remii(mulii(lt2dn,t2), pk); } } gel(trace1,i) = gclone( nf_bestlift(t1, NULL, T->L) ); gel(trace2,i) = gclone( nf_bestlift(t2, NULL, T->L) ); avma = av; } T1 = init_trace(&_T1, trace1, T->L, q); T2 = init_trace(&_T2, trace2, T->L, q); for (i=1; i <= lfamod; i++) { gunclone(gel(trace1,i)); gunclone(gel(trace2,i)); } } degsofar[0] = 0; /* sentinel */ /* ind runs through strictly increasing sequences of length K, * 1 <= ind[i] <= lfamod */ nextK: if (K > maxK || 2*K > lfamod) goto END; if (DEBUGLEVEL > 3) fprintferr("\n### K = %d, %Z combinations\n", K,binomial(utoipos(lfamod), K)); setlg(ind, K+1); ind[1] = 1; i = 1; curdeg = degpol[ind[1]]; for(;;) { /* try all combinations of K factors */ for (j = i; j < K; j++) { degsofar[j] = curdeg; ind[j+1] = ind[j]+1; curdeg += degpol[ind[j+1]]; } if (curdeg <= klim && curdeg % T->hint == 0) /* trial divide */ { GEN t, y, q, list; pari_sp av; av = avma; /* d - 1 test */ if (T1) { t = get_trace(ind, T1); if (rtodbl(QuickNormL2(t,DEFAULTPREC)) > Bhigh) { if (DEBUGLEVEL>6) fprintferr("."); avma = av; goto NEXT; } } /* d - 2 test */ if (T2) { t = get_trace(ind, T2); if (rtodbl(QuickNormL2(t,DEFAULTPREC)) > Bhigh) { if (DEBUGLEVEL>3) fprintferr("|"); avma = av; goto NEXT; } } avma = av; y = lt; /* full computation */ for (i=1; i<=K; i++) { GEN q = gel(famod, ind[i]); if (y) q = gmul(y, q); y = FqX_centermod(q, Tpk, pk, pks2); } y = nf_pol_lift(y, bound, T); if (!y) { if (DEBUGLEVEL>3) fprintferr("@"); avma = av; goto NEXT; } /* try out the new combination: y is the candidate factor */ q = RgXQX_divrem(C2ltpol, y, nfpol, ONLY_DIVIDES); if (!q) { if (DEBUGLEVEL>3) fprintferr("*"); avma = av; goto NEXT; } /* found a factor */ list = cgetg(K+1, t_VEC); gel(listmod,cnt) = list; for (i=1; i<=K; i++) list[i] = famod[ind[i]]; y = Q_primpart(y); gel(fa,cnt++) = QXQX_normalize(y, nfpol); /* fix up pol */ pol = q; for (i=j=k=1; i <= lfamod; i++) { /* remove used factors */ if (j <= K && i == ind[j]) j++; else { famod[k] = famod[i]; update_trace(T1, k, i); update_trace(T2, k, i); degpol[k] = degpol[i]; k++; } } lfamod -= K; if (lfamod < 2*K) goto END; i = 1; curdeg = degpol[ind[1]]; if (C2lt) pol = Q_primpart(pol); if (lt) lt = absi(leading_term(pol)); Clt = mul_content(C, lt); C2lt = mul_content(C,Clt); C2ltpol = C2lt? gmul(C2lt,pol): pol; if (DEBUGLEVEL > 2) { fprintferr("\n"); msgTIMER(&ti, "to find factor %Z",y); fprintferr("remaining modular factor(s): %ld\n", lfamod); } continue; } NEXT: for (i = K+1;;) { if (--i == 0) { K++; goto nextK; } if (++ind[i] <= lfamod - K + i) { curdeg = degsofar[i-1] + degpol[ind[i]]; if (curdeg <= klim) break; } } } END: if (degpol(pol) > 0) { /* leftover factor */ if (signe(leading_term(pol)) < 0) pol = gneg_i(pol); if (C2lt && lfamod < 2*K) pol = QXQX_normalize(Q_primpart(pol), nfpol); setlg(famod, lfamod+1); gel(listmod,cnt) = shallowcopy(famod); gel(fa,cnt++) = pol; } if (DEBUGLEVEL>6) fprintferr("\n"); if (cnt == 2) { avma = av0; gel(res,1) = mkvec(T->pol); gel(res,2) = mkvec(T->fact); } else { setlg(listmod, cnt); setlg(fa, cnt); gel(res,1) = fa; gel(res,2) = listmod; res = gerepilecopy(av0, res); } return res; }
static GEN nf_LLL_cmbf(nfcmbf_t *T, GEN p, long k, long rec) { nflift_t *L = T->L; GEN pk = L->pk, PRK = L->prk, PRKinv = L->iprk, GSmin = L->GSmin; GEN Tpk = L->Tpk; GEN famod = T->fact, nf = T->nf, ZC = T->ZC, Br = T->Br; GEN Pbase = T->polbase, P = T->pol, dn = T->dn; GEN nfT = gel(nf,1); GEN Btra; long dnf = degpol(nfT), dP = degpol(P); double BitPerFactor = 0.5; /* nb bits / modular factor */ long i, C, tmax, n0; GEN lP, Bnorm, Tra, T2, TT, CM_L, m, list, ZERO; double Bhigh; pari_sp av, av2, lim; long ti_LLL = 0, ti_CF = 0; pari_timer ti2, TI; lP = absi(leading_term(P)); if (is_pm1(lP)) lP = NULL; n0 = lg(famod) - 1; /* Lattice: (S PRK), small vector (vS vP). To find k bound for the image, * write S = S1 q + S0, P = P1 q + P0 * |S1 vS + P1 vP|^2 <= Bhigh for all (vS,vP) assoc. to true factors */ Btra = mulrr(ZC, mulsr(dP*dP, normlp(Br, 2, dnf))); Bhigh = get_Bhigh(n0, dnf); C = (long)ceil(sqrt(Bhigh/n0)) + 1; /* C^2 n0 ~ Bhigh */ Bnorm = dbltor( n0 * C * C + Bhigh ); ZERO = zeromat(n0, dnf); av = avma; lim = stack_lim(av, 1); TT = cgetg(n0+1, t_VEC); Tra = cgetg(n0+1, t_MAT); for (i=1; i<=n0; i++) TT[i] = 0; CM_L = gscalsmat(C, n0); /* tmax = current number of traces used (and computed so far) */ for(tmax = 0;; tmax++) { long a, b, bmin, bgood, delta, tnew = tmax + 1, r = lg(CM_L)-1; GEN oldCM_L, M_L, q, S1, P1, VV; int first = 1; /* bound for f . S_k(genuine factor) = ZC * bound for T_2(S_tnew) */ Btra = mulrr(ZC, mulsr(dP*dP, normlp(Br, 2*tnew, dnf))); bmin = logint(ceil_safe(sqrtr(Btra)), gen_2, NULL); if (DEBUGLEVEL>2) fprintferr("\nLLL_cmbf: %ld potential factors (tmax = %ld, bmin = %ld)\n", r, tmax, bmin); /* compute Newton sums (possibly relifting first) */ if (gcmp(GSmin, Btra) < 0) { nflift_t L1; GEN polred; bestlift_init(k<<1, nf, T->pr, Btra, &L1); polred = ZqX_normalize(Pbase, lP, &L1); k = L1.k; pk = L1.pk; PRK = L1.prk; PRKinv = L1.iprk; GSmin = L1.GSmin; Tpk = L1.Tpk; famod = hensel_lift_fact(polred, famod, Tpk, p, pk, k); for (i=1; i<=n0; i++) TT[i] = 0; } for (i=1; i<=n0; i++) { GEN h, lPpow = lP? gpowgs(lP, tnew): NULL; GEN z = polsym_gen(gel(famod,i), gel(TT,i), tnew, Tpk, pk); gel(TT,i) = z; h = gel(z,tnew+1); /* make Newton sums integral */ lPpow = mul_content(lPpow, dn); if (lPpow) h = FpX_red(gmul(h,lPpow), pk); gel(Tra,i) = nf_bestlift(h, NULL, L); /* S_tnew(famod) */ } /* compute truncation parameter */ if (DEBUGLEVEL>2) { TIMERstart(&ti2); TIMERstart(&TI); } oldCM_L = CM_L; av2 = avma; b = delta = 0; /* -Wall */ AGAIN: M_L = Q_div_to_int(CM_L, utoipos(C)); VV = get_V(Tra, M_L, PRK, PRKinv, pk, &a); if (first) { /* initialize lattice, using few p-adic digits for traces */ bgood = (long)(a - max(32, BitPerFactor * r)); b = max(bmin, bgood); delta = a - b; } else { /* add more p-adic digits and continue reduction */ if (a < b) b = a; b = max(b-delta, bmin); if (b - delta/2 < bmin) b = bmin; /* near there. Go all the way */ } /* restart with truncated entries */ q = int2n(b); P1 = gdivround(PRK, q); S1 = gdivround(Tra, q); T2 = gsub(gmul(S1, M_L), gmul(P1, VV)); m = vconcat( CM_L, T2 ); if (first) { first = 0; m = shallowconcat( m, vconcat(ZERO, P1) ); /* [ C M_L 0 ] * m = [ ] square matrix * [ T2' PRK ] T2' = Tra * M_L truncated */ } CM_L = LLL_check_progress(Bnorm, n0, m, b == bmin, /*dbg:*/ &ti_LLL); if (DEBUGLEVEL>2) fprintferr("LLL_cmbf: (a,b) =%4ld,%4ld; r =%3ld -->%3ld, time = %ld\n", a,b, lg(m)-1, CM_L? lg(CM_L)-1: 1, TIMER(&TI)); if (!CM_L) { list = mkcol(QXQX_normalize(P,nfT)); break; } if (b > bmin) { CM_L = gerepilecopy(av2, CM_L); goto AGAIN; } if (DEBUGLEVEL>2) msgTIMER(&ti2, "for this trace"); i = lg(CM_L) - 1; if (i == r && gequal(CM_L, oldCM_L)) { CM_L = oldCM_L; avma = av2; continue; } if (i <= r && i*rec < n0) { pari_timer ti; if (DEBUGLEVEL>2) TIMERstart(&ti); list = nf_chk_factors(T, P, Q_div_to_int(CM_L,utoipos(C)), famod, pk); if (DEBUGLEVEL>2) ti_CF += TIMER(&ti); if (list) break; CM_L = gerepilecopy(av2, CM_L); } if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) pari_warn(warnmem,"nf_LLL_cmbf"); gerepileall(av, Tpk? 9: 8, &CM_L,&TT,&Tra,&famod,&pk,&GSmin,&PRK,&PRKinv,&Tpk); } } if (DEBUGLEVEL>2) fprintferr("* Time LLL: %ld\n* Time Check Factor: %ld\n",ti_LLL,ti_CF); return list; }