void acb_poly_inv_series(acb_poly_t Qinv, const acb_poly_t Q, slong n, slong prec) { if (n == 0) { acb_poly_zero(Qinv); return; } if (Q->length == 0) { acb_poly_fit_length(Qinv, n); _acb_vec_indeterminate(Qinv->coeffs, n); _acb_poly_set_length(Qinv, n); return; } if (Qinv == Q) { acb_poly_t t; acb_poly_init(t); acb_poly_inv_series(t, Q, n, prec); acb_poly_swap(Qinv, t); acb_poly_clear(t); return; } acb_poly_fit_length(Qinv, n); _acb_poly_inv_series(Qinv->coeffs, Q->coeffs, Q->length, n, prec); _acb_poly_set_length(Qinv, n); _acb_poly_normalise(Qinv); }
void _acb_poly_revert_series_lagrange_fast(acb_ptr Qinv, acb_srcptr Q, slong Qlen, slong n, slong prec) { slong i, j, k, m; acb_ptr R, S, T, tmp; acb_t t; if (n <= 2) { if (n >= 1) acb_zero(Qinv); if (n == 2) acb_inv(Qinv + 1, Q + 1, prec); return; } m = n_sqrt(n); acb_init(t); R = _acb_vec_init((n - 1) * m); S = _acb_vec_init(n - 1); T = _acb_vec_init(n - 1); acb_zero(Qinv); acb_inv(Qinv + 1, Q + 1, prec); _acb_poly_inv_series(Ri(1), Q + 1, FLINT_MIN(Qlen, n) - 1, n - 1, prec); for (i = 2; i <= m; i++) _acb_poly_mullow(Ri(i), Ri((i + 1) / 2), n - 1, Ri(i / 2), n - 1, n - 1, prec); for (i = 2; i < m; i++) acb_div_ui(Qinv + i, Ri(i) + i - 1, i, prec); _acb_vec_set(S, Ri(m), n - 1); for (i = m; i < n; i += m) { acb_div_ui(Qinv + i, S + i - 1, i, prec); for (j = 1; j < m && i + j < n; j++) { acb_mul(t, S + 0, Ri(j) + i + j - 1, prec); for (k = 1; k <= i + j - 1; k++) acb_addmul(t, S + k, Ri(j) + i + j - 1 - k, prec); acb_div_ui(Qinv + i + j, t, i + j, prec); } if (i + 1 < n) { _acb_poly_mullow(T, S, n - 1, Ri(m), n - 1, n - 1, prec); tmp = S; S = T; T = tmp; } } acb_clear(t); _acb_vec_clear(R, (n - 1) * m); _acb_vec_clear(S, n - 1); _acb_vec_clear(T, n - 1); }
void _acb_poly_rgamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec) { int reflect; slong i, rflen, r, n, wp; acb_ptr t, u, v; acb_struct f[2]; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { acb_rgamma(res, h, prec); _acb_vec_zero(res + 1, len - 1); return; } /* use real code for real input */ if (_acb_vec_is_real(h, hlen)) { arb_ptr tmp = _arb_vec_init(len); for (i = 0; i < hlen; i++) arb_set(tmp + i, acb_realref(h + i)); _arb_poly_rgamma_series(tmp, tmp, hlen, len, prec); for (i = 0; i < len; i++) acb_set_arb(res + i, tmp + i); _arb_vec_clear(tmp, len); return; } wp = prec + FLINT_BIT_COUNT(prec); t = _acb_vec_init(len); u = _acb_vec_init(len); v = _acb_vec_init(len); acb_init(f); acb_init(f + 1); /* otherwise use Stirling series */ acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 0, wp); /* rgamma(h) = (gamma(1-h+r) sin(pi h)) / (rf(1-h, r) * pi), h = h0 + t*/ if (reflect) { /* u = gamma(r+1-h) */ acb_sub_ui(f, h, r + 1, wp); acb_neg(f, f); _acb_poly_gamma_stirling_eval(t, f, n, len, wp); _acb_poly_exp_series(u, t, len, len, wp); for (i = 1; i < len; i += 2) acb_neg(u + i, u + i); /* v = sin(pi x) */ acb_set(f, h); acb_one(f + 1); _acb_poly_sin_pi_series(v, f, 2, len, wp); _acb_poly_mullow(t, u, len, v, len, len, wp); /* rf(1-h,r) * pi */ if (r == 0) { acb_const_pi(u, wp); _acb_vec_scalar_div(v, t, len, u, wp); } else { acb_sub_ui(f, h, 1, wp); acb_neg(f, f); acb_set_si(f + 1, -1); rflen = FLINT_MIN(len, r + 1); _acb_poly_rising_ui_series(v, f, FLINT_MIN(2, len), r, rflen, wp); acb_const_pi(u, wp); _acb_vec_scalar_mul(v, v, rflen, u, wp); /* divide by rising factorial */ /* TODO: might better to use div_series, when it has a good basecase */ _acb_poly_inv_series(u, v, rflen, len, wp); _acb_poly_mullow(v, t, len, u, len, len, wp); } } else { /* rgamma(h) = rgamma(h+r) rf(h,r) */ if (r == 0) { acb_add_ui(f, h, r, wp); _acb_poly_gamma_stirling_eval(t, f, n, len, wp); _acb_vec_neg(t, t, len); _acb_poly_exp_series(v, t, len, len, wp); } else { acb_set(f, h); acb_one(f + 1); rflen = FLINT_MIN(len, r + 1); _acb_poly_rising_ui_series(t, f, FLINT_MIN(2, len), r, rflen, wp); acb_add_ui(f, h, r, wp); _acb_poly_gamma_stirling_eval(v, f, n, len, wp); _acb_vec_neg(v, v, len); _acb_poly_exp_series(u, v, len, len, wp); _acb_poly_mullow(v, u, len, t, rflen, len, wp); } } /* compose with nonconstant part */ acb_zero(t); _acb_vec_set(t + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, v, len, t, hlen, len, prec); acb_clear(f); acb_clear(f + 1); _acb_vec_clear(t, len); _acb_vec_clear(u, len); _acb_vec_clear(v, len); }
void _acb_poly_sin_cos_series_tangent(acb_ptr s, acb_ptr c, const acb_srcptr h, slong hlen, slong len, slong prec, int times_pi) { acb_ptr t, u, v; acb_t s0, c0; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { if (times_pi) acb_sin_cos_pi(s, c, h, prec); else acb_sin_cos(s, c, h, prec); _acb_vec_zero(s + 1, len - 1); _acb_vec_zero(c + 1, len - 1); return; } /* sin(x) = 2*tan(x/2)/(1+tan(x/2)^2) cos(x) = (1-tan(x/2)^2)/(1+tan(x/2)^2) */ acb_init(s0); acb_init(c0); t = _acb_vec_init(3 * len); u = t + len; v = u + len; /* sin, cos of h0 */ if (times_pi) acb_sin_cos_pi(s0, c0, h, prec); else acb_sin_cos(s0, c0, h, prec); /* t = tan((h-h0)/2) */ acb_zero(u); _acb_vec_scalar_mul_2exp_si(u + 1, h + 1, hlen - 1, -1); if (times_pi) { acb_const_pi(t, prec); _acb_vec_scalar_mul(u + 1, u + 1, hlen - 1, t, prec); } _acb_poly_tan_series(t, u, hlen, len, prec); /* v = 1 + t^2 */ _acb_poly_mullow(v, t, len, t, len, len, prec); acb_add_ui(v, v, 1, prec); /* u = 1/(1+t^2) */ _acb_poly_inv_series(u, v, len, len, prec); /* sine */ _acb_poly_mullow(s, t, len, u, len, len, prec); _acb_vec_scalar_mul_2exp_si(s, s, len, 1); /* cosine */ acb_sub_ui(v, v, 2, prec); _acb_vec_neg(v, v, len); _acb_poly_mullow(c, v, len, u, len, len, prec); /* sin(h0 + h1) = cos(h0) sin(h1) + sin(h0) cos(h1) cos(h0 + h1) = cos(h0) cos(h1) - sin(h0) sin(h1) */ if (!acb_is_zero(s0)) { _acb_vec_scalar_mul(t, s, len, c0, prec); _acb_vec_scalar_mul(u, c, len, s0, prec); _acb_vec_scalar_mul(v, s, len, s0, prec); _acb_vec_add(s, t, u, len, prec); _acb_vec_scalar_mul(t, c, len, c0, prec); _acb_vec_sub(c, t, v, len, prec); } _acb_vec_clear(t, 3 * len); acb_clear(s0); acb_clear(c0); }