void __nmod_poly_exp_series_prealloc(mp_ptr f, mp_ptr g, mp_srcptr h, mp_srcptr hprime, mp_ptr T, mp_ptr U, long n, nmod_t mod, int extend) { long m, m2, l; if (n < NMOD_NEWTON_EXP_CUTOFF) { _nmod_poly_exp_series_basecase(f, h, n, n, mod); _nmod_poly_inv_series_basecase(g, f, extend ? n : (n + 1) / 2, mod); return; } m = (n + 1) / 2; m2 = (m + 1) / 2; l = m - 1; /* shifted for derivative */ /* f := exp(h) + O(x^m), g := exp(-h) + O(x^m2) */ __nmod_poly_exp_series_prealloc(f, g, h, hprime, T, U, m, mod, 0); /* g := exp(-h) + O(x^m) */ _nmod_poly_mullow(T, f, m, g, m2, m, mod); _nmod_poly_mullow(g + m2, g, m2, T + m2, m - m2, m - m2, mod); _nmod_vec_neg(g + m2, g + m2, m - m2, mod); /* U := h' + g (f' - f h') + O(x^(n-1)) Note: should replace h' by h' mod x^(m-1) */ _nmod_vec_zero(f + m, n - m); _nmod_poly_mullow(T, f, n, hprime, n, n, mod); /* should be mulmid */ _nmod_poly_derivative(U, f, n, mod); /* should skip low terms */ _nmod_vec_sub(U + l, U + l, T + l, n - l, mod); _nmod_poly_mullow(T + l, g, n - m, U + l, n - m, n - m, mod); _nmod_vec_add(U + l, hprime + l, T + l, n - m, mod); /* f := f + f * (h - int U) + O(x^n) = exp(h) + O(x^n) */ _nmod_poly_integral(U, U, n, mod); /* should skip low terms */ _nmod_vec_sub(U + m, h + m, U + m, n - m, mod); _nmod_poly_mullow(f + m, f, n - m, U + m, n - m, n - m, mod); /* g := exp(-h) + O(x^n) */ if (extend) { _nmod_poly_mullow(T, f, n, g, m, n, mod); _nmod_poly_mullow(g + m, g, m, T + m, n - m, n - m, mod); _nmod_vec_neg(g + m, g + m, n - m, mod); } }
void _nmod_poly_atanh_series(mp_ptr g, mp_srcptr h, long n, nmod_t mod) { mp_ptr t, u; t = _nmod_vec_init(n); u = _nmod_vec_init(n); /* atanh(h(x)) = integral(h'(x)/(1-h(x)^2)) */ _nmod_poly_mullow(u, h, n, h, n, n, mod); _nmod_vec_neg(u, u, n, mod); u[0] = 1UL; _nmod_poly_derivative(t, h, n, mod); t[n-1] = 0UL; _nmod_poly_div_series(g, t, u, n, mod); _nmod_poly_integral(g, g, n, mod); _nmod_vec_free(t); _nmod_vec_free(u); }
void _nmod_poly_asin_series(mp_ptr g, mp_srcptr h, slong n, nmod_t mod) { mp_ptr t, u; t = _nmod_vec_init(n); u = _nmod_vec_init(n); /* asin(h(x)) = integral(h'(x)/sqrt(1-h(x)^2)) */ _nmod_poly_mullow(u, h, n, h, n, n, mod); _nmod_vec_neg(u, u, n, mod); u[0] = UWORD(1); _nmod_poly_invsqrt_series(t, u, n, mod); _nmod_poly_derivative(u, h, n, mod); u[n-1] = UWORD(0); _nmod_poly_mullow(g, t, n, u, n, n, mod); _nmod_poly_integral(g, g, n, mod); _nmod_vec_clear(t); _nmod_vec_clear(u); }
slong _nmod_poly_xgcd_hgcd(mp_ptr G, mp_ptr S, mp_ptr T, mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod) { const slong cutoff = FLINT_BIT_COUNT(mod.n) <= 8 ? NMOD_POLY_SMALL_GCD_CUTOFF : NMOD_POLY_GCD_CUTOFF; slong lenG, lenS, lenT; if (lenB == 1) { G[0] = B[0]; T[0] = 1; lenG = 1; lenS = 0; lenT = 1; } else { mp_ptr q = _nmod_vec_init(lenA + lenB); mp_ptr r = q + lenA; slong lenq, lenr; __divrem(q, lenq, r, lenr, A, lenA, B, lenB); if (lenr == 0) { __set(G, lenG, B, lenB); T[0] = 1; lenS = 0; lenT = 1; } else { mp_ptr h, j, v, w, R[4], X; slong lenh, lenj, lenv, lenw, lenR[4]; int sgnR; lenh = lenj = lenB; lenv = lenw = lenA + lenB - 2; lenR[0] = lenR[1] = lenR[2] = lenR[3] = (lenB + 1) / 2; X = _nmod_vec_init(2 * lenh + 2 * lenv + 4 * lenR[0]); h = X; j = h + lenh; v = j + lenj; w = v + lenv; R[0] = w + lenw; R[1] = R[0] + lenR[0]; R[2] = R[1] + lenR[1]; R[3] = R[2] + lenR[2]; sgnR = _nmod_poly_hgcd(R, lenR, h, &lenh, j, &lenj, B, lenB, r, lenr, mod); if (sgnR > 0) { _nmod_vec_neg(S, R[1], lenR[1], mod); _nmod_vec_set(T, R[0], lenR[0]); } else { _nmod_vec_set(S, R[1], lenR[1]); _nmod_vec_neg(T, R[0], lenR[0], mod); } lenS = lenR[1]; lenT = lenR[0]; while (lenj != 0) { __divrem(q, lenq, r, lenr, h, lenh, j, lenj); __mul(v, lenv, q, lenq, T, lenT); { slong l; _nmod_vec_swap(S, T, FLINT_MAX(lenS, lenT)); l = lenS; lenS = lenT; lenT = l; } __sub(T, lenT, T, lenT, v, lenv); if (lenr == 0) { __set(G, lenG, j, lenj); goto cofactor; } if (lenj < cutoff) { mp_ptr u0 = R[0], u1 = R[1]; slong lenu0 = lenr - 1, lenu1 = lenj - 1; lenG = _nmod_poly_xgcd_euclidean(G, u0, u1, j, lenj, r, lenr, mod); MPN_NORM(u0, lenu0); MPN_NORM(u1, lenu1); __mul(v, lenv, S, lenS, u0, lenu0); __mul(w, lenw, T, lenT, u1, lenu1); __add(S, lenS, v, lenv, w, lenw); goto cofactor; } sgnR = _nmod_poly_hgcd(R, lenR, h, &lenh, j, &lenj, j,lenj, r, lenr, mod); __mul(v, lenv, R[1], lenR[1], T, lenT); __mul(w, lenw, R[2], lenR[2], S, lenS); __mul(q, lenq, S, lenS, R[3], lenR[3]); if (sgnR > 0) __sub(S, lenS, q, lenq, v, lenv); else __sub(S, lenS, v, lenv, q, lenq); __mul(q, lenq, T, lenT, R[0], lenR[0]); if (sgnR > WORD(0)) __sub(T, lenT, q, lenq, w, lenw); else __sub(T, lenT, w, lenw, q, lenq); } __set(G, lenG, h, lenh); cofactor: __mul(v, lenv, S, lenS, A, lenA); __sub(w, lenw, G, lenG, v, lenv); __div(T, lenT, w, lenw, B, lenB); _nmod_vec_clear(X); } _nmod_vec_clear(q); } flint_mpn_zero(S + lenS, lenB - 1 - lenS); flint_mpn_zero(T + lenT, lenA - 1 - lenT); return lenG; }
void _nmod_poly_divrem_divconquer_recursive(mp_ptr Q, mp_ptr BQ, mp_ptr W, mp_ptr V, mp_srcptr A, mp_srcptr B, slong lenB, nmod_t mod) { if (lenB <= NMOD_DIVREM_DIVCONQUER_CUTOFF) { mp_ptr t = V; mp_ptr w = t + 2*lenB - 1; flint_mpn_copyi(t + lenB - 1, A + lenB - 1, lenB); flint_mpn_zero(t, lenB - 1); _nmod_poly_divrem_basecase(Q, BQ, w, t, 2 * lenB - 1, B, lenB, mod); /* BQ = A - R */ _nmod_vec_neg(BQ, BQ, lenB - 1, mod); } else { const slong n2 = lenB / 2; const slong n1 = lenB - n2; mp_ptr W1 = W; mp_ptr W2 = W + n2; mp_srcptr p1 = A + 2 * n2; mp_srcptr p2; mp_srcptr d1 = B + n2; mp_srcptr d2 = B; mp_srcptr d3 = B + n1; mp_srcptr d4 = B; mp_ptr q1 = Q + n2; mp_ptr q2 = Q; mp_ptr dq1 = BQ + n2; mp_ptr d1q1 = BQ + n2 - (n1 - 1); mp_ptr d2q1, d3q2, d4q2, t; /* Set q1 to p1 div d1, a 2 n1 - 1 by n1 division so q1 ends up being of length n1; low(d1q1) = d1 q1 is of length n1 - 1 */ _nmod_poly_divrem_divconquer_recursive(q1, d1q1, W1, V, p1, d1, n1, mod); /* Compute bottom n1 + n2 - 1 coeffs of d2q1 = d2 q1 */ d2q1 = W1; _nmod_poly_mullow(d2q1, q1, n1, d2, n2, n1 + n2 - 1, mod); /* Compute dq1 = d1 q1 x^n2 + d2 q1, of length n1 + n2 - 1 Split it into a segment of length n1 - 1 at dq1 and a piece of length n2 at BQ. */ flint_mpn_copyi(dq1, d2q1, n1 - 1); if (n2 > n1 - 1) BQ[0] = d2q1[n1 - 1]; _nmod_vec_add(d1q1, d1q1, d2q1 + n2, n1 - 1, mod); /* Compute t = A/x^n2 - dq1, which has length 2 n1 + n2 - 1, but we are not interested in the top n1 coeffs as they will be zero, so this has effective length n1 + n2 - 1 For the following division, we want to set {p2, 2 n2 - 1} to the top 2 n2 - 1 coeffs of this Since the bottom n2 - 1 coeffs of p2 are irrelevant for the division, we in fact set {t, n2} to the relevant coeffs */ t = W1; _nmod_vec_sub(t, A + n2 + (n1 - 1), BQ, n2, mod); p2 = t - (n2 - 1); /* Compute q2 = t div d3, a 2 n2 - 1 by n2 division, so q2 will have length n2; let low(d3q2) = d3 q2, of length n2 - 1 */ d3q2 = BQ; _nmod_poly_divrem_divconquer_recursive(q2, d3q2, W2, V, p2, d3, n2, mod); /* Compute d4q2 = d4 q2, of length n1 + n2 - 1 */ d4q2 = W1; _nmod_poly_mullow(d4q2, d4, n1, q2, n2, n1 + n2 - 1, mod); /* Compute dq2 = d3q2 x^n1 + d4q2, of length n1 + n2 - 1 */ _nmod_vec_add(BQ + n1, BQ + n1, d3q2, n2 - 1, mod); flint_mpn_copyi(BQ, d4q2, n2); _nmod_vec_add(BQ + n2, BQ + n2, d4q2 + n2, n1 - 1, mod); /* Note Q = q1 x^n2 + q2, and BQ = dq1 x^n2 + dq2 */ } }