void FastTraceVec(vec_zz_p& S, const zz_pX& f) { long n = deg(f); if (n <= 0) Error("FastTraceVec: bad args"); if (n == 0) { S.SetLength(0); return; } if (n == 1) { S.SetLength(1); set(S[0]); return; } long i; zz_pX f1; f1.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) f1.rep[i] = f.rep[n-i]; f1.normalize(); zz_pX f2; f2.rep.SetLength(n-1); for (i = 0; i <= n-2; i++) mul(f2.rep[i], f.rep[n-1-i], i+1); f2.normalize(); zz_pX f3; InvTrunc(f3, f1, n-1); MulTrunc(f3, f3, f2, n-1); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(f3, i-1)); }
static void compute_a_vals(Vec<ZZ>& a, long p, long e) // computes a[m] = a(m)/m! for m = p..(e-1)(p-1)+1, // as defined by Chen and Han. // a.length() is set to (e-1)(p-1)+2 { ZZ p_to_e = power_ZZ(p, e); ZZ p_to_2e = power_ZZ(p, 2*e); long len = (e-1)*(p-1)+2; ZZ_pPush push(p_to_2e); ZZ_pX x_plus_1_to_p = power(ZZ_pX(INIT_MONO, 1) + 1, p); ZZ_pX denom = InvTrunc(x_plus_1_to_p - ZZ_pX(INIT_MONO, p), len); ZZ_pX poly = MulTrunc(x_plus_1_to_p, denom, len); poly *= p; a.SetLength(len); ZZ m_fac(1); for (long m = 2; m < p; m++) { m_fac = MulMod(m_fac, m, p_to_2e); } for (long m = p; m < len; m++) { m_fac = MulMod(m_fac, m, p_to_2e); ZZ c = rep(coeff(poly, m)); ZZ d = GCD(m_fac, p_to_2e); if (d == 0 || d > p_to_e || c % d != 0) Error("cannot divide"); ZZ m_fac_deflated = (m_fac / d) % p_to_e; ZZ c_deflated = (c / d) % p_to_e; a[m] = MulMod(c_deflated, InvMod(m_fac_deflated, p_to_e), p_to_e); } }
static CYTHON_INLINE struct ZZX* ZZX_multiply_and_truncate(struct ZZX* x, struct ZZX* y, long m) { ZZX* t = new ZZX(); MulTrunc(*t, *x, *y, m); return t; }