static trace_data * init_trace(trace_data *T, GEN S, nflift_t *L, GEN q) { long e = gexpo(S), i,j, l,h; GEN qgood, S1, invd; if (e < 0) return NULL; /* S = 0 */ qgood = int2n(e - 32); /* single precision check */ if (cmpii(qgood, q) > 0) q = qgood; S1 = gdivround(S, q); if (gcmp0(S1)) return NULL; invd = ginv(itor(L->den, DEFAULTPREC)); T->dPinvS = gmul(L->iprk, S); l = lg(S); h = lg(T->dPinvS[1]); T->PinvSdbl = (double**)cgetg(l, t_MAT); init_dalloc(); for (j = 1; j < l; j++) { double *t = dalloc(h * sizeof(double)); GEN c = gel(T->dPinvS,j); pari_sp av = avma; T->PinvSdbl[j] = t; for (i=1; i < h; i++) t[i] = rtodbl(mpmul(invd, gel(c,i))); avma = av; } T->d = L->den; T->P1 = gdivround(L->prk, q); T->S1 = S1; return T; }
/* We want to be able to reconstruct x, |x|^2 < C, from x mod pr^k */ static double bestlift_bound(GEN C, long d, double alpha, GEN Npr) { const double y = 1 / (alpha - 0.25); /* = 2 if alpha = 3/4 */ double t; if (typ(C) != t_REAL) C = gmul(C, real_1(DEFAULTPREC)); setlg(C, DEFAULTPREC); t = rtodbl(mplog(gmul2n(divrs(C,d), 4))) * 0.5 + (d-1) * log(1.5 * sqrt(y)); return ceil((t * d) / log(gtodouble(Npr))); }
/* 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 double todbl(GEN x) { return rtodbl(gtofp(x, LOWDEFAULTPREC)); }
engine_RawRingElementArrayOrNull rawRoots(const RingElement *p, long prec, int unique) { const Ring *R = p->get_ring(); const PolynomialRing *P = R->cast_to_PolynomialRing(); if (P == 0) { ERROR("expected a polynomial ring"); return NULL; } const int n = P->n_vars(); if (n != 1) { ERROR("expected a univariate polynomial ring"); return NULL; } const Ring *K = P->getCoefficients(); int degree = 0; for (Nterm *t = p->get_value(); t != NULL; t = t->next) { degree = max(degree, abs(*(t->monom))); } if (prec == -1) { prec = (K->get_precision() == 0 ? 53 : K->get_precision()); } engine_RawRingElementArrayOrNull result = nullptr; /* Start PARI computations. */ pari_CATCH(e_STACK) { #ifdef NDEBUG /* * Every time the stack is changed PARI writes a message to the file pari_errfile * which by default is /dev/stderr. To avoid showing this message to the user we * redirect to /dev/null before the PARI's stack is modified. */ FILE *tmp, *dev_null = fopen("/dev/null", "w"); if (dev_null != NULL) { tmp = pari_errfile; pari_errfile = dev_null; } #endif allocatemem(0); // passing 0 will double the current stack size. #ifdef NDEBUG /* * We set pari_errfile back to the default value just in case PARI crashes. */ if (dev_null != NULL) { pari_errfile = tmp; fclose(dev_null); } #endif } pari_RETRY { const pari_sp av = avma; GEN q = cgetg(2 + degree + 1, t_POL); setsigne(q, 1); setvarn(q, 0); for (int i = 0; i < degree + 1; ++i) { gel(q, 2 + i) = gen_0; } switch (K->ringID()) { case M2::ring_ZZ: ZZ_GMP: for (Nterm *t = p->get_value(); t != NULL; t = t->next) { gel(q, 2 + abs(*(t->monom))) = mpz_get_GEN(reinterpret_cast<const mpz_ptr>(t->coeff.poly_val)); } break; case M2::ring_QQ: for (Nterm *t = p->get_value(); t != NULL; t = t->next) { gel(q, 2 + abs(*(t->monom))) = mpq_get_GEN(reinterpret_cast<const mpq_ptr>(t->coeff.poly_val)); } break; case M2::ring_RR: pari_CATCH(e_OVERFLOW) { ERROR("coefficient is NaN or Infinity"); avma = av; return NULL; } pari_TRY { for (Nterm *t = p->get_value(); t != NULL; t = t->next) { gel(q, 2 + abs(*(t->monom))) = dbltor(*reinterpret_cast<double *>(t->coeff.poly_val)); } } pari_ENDCATCH break; case M2::ring_CC: pari_CATCH(e_OVERFLOW) { ERROR("coefficient is NaN or Infinity"); avma = av; return NULL; } pari_TRY { for (Nterm *t = p->get_value(); t != NULL; t = t->next) { GEN z = cgetg(3, t_COMPLEX); gel(z, 1) = dbltor(reinterpret_cast<complex *>(t->coeff.poly_val)->re); gel(z, 2) = dbltor(reinterpret_cast<complex *>(t->coeff.poly_val)->im); gel(q, 2 + abs(*(t->monom))) = z; } } pari_ENDCATCH break; case M2::ring_RRR: for (Nterm *t = p->get_value(); t != NULL; t = t->next) { gel(q, 2 + abs(*(t->monom))) = mpfr_get_GEN(reinterpret_cast<const mpfr_ptr>(t->coeff.poly_val)); } break; case M2::ring_CCC: for (Nterm *t = p->get_value(); t != NULL; t = t->next) { gel(q, 2 + abs(*(t->monom))) = mpc_get_GEN(reinterpret_cast<const mpc_ptr>(t->coeff.poly_val)); } break; case M2::ring_old: if (K->is_ZZ()) { goto ZZ_GMP; } default: ERROR("expected coefficient ring of the form ZZ, QQ, RR or CC"); return NULL; } if (unique) { q = RgX_div(q, RgX_gcd_simple(q, RgX_deriv(q))); } GEN roots = cleanroots(q, nbits2prec(prec)); const size_t num_roots = lg(roots) - 1; result = getmemarraytype(engine_RawRingElementArray, num_roots); result->len = static_cast<int>(num_roots); ring_elem m2_root; if (prec <= 53) { const RingCC *CC = dynamic_cast<const RingCC *>(IM2_Ring_CCC(prec)); for (int i = 0; i < num_roots; ++i) { const pari_sp av2 = avma; GEN pari_root = gel(roots, 1 + i); const complex root = {rtodbl(greal(pari_root)), rtodbl(gimag(pari_root))}; CC->ring().to_ring_elem(m2_root, root); result->array[i] = RingElement::make_raw(CC, m2_root); avma = av2; } } else { const RingCCC *CCC = dynamic_cast<const RingCCC *>(IM2_Ring_CCC(prec)); for (int i = 0; i < num_roots; ++i) { const pari_sp av2 = avma; mpc_t root; auto root1 = reinterpret_cast<mpfc_t*>(&root); pari_mpc_init_set_GEN(root, gel(roots, 1 + i), GMP_RNDN); // CCC->ring().to_ring_elem(m2_root, **reinterpret_cast<mpfc_t*>(&root)); CCC->ring().to_ring_elem(m2_root, **root1); result->array[i] = RingElement::make_raw(CCC, m2_root); avma = av2; } } /* End PARI computations. */ avma = av; } pari_ENDCATCH return result; }