void _acb_hypgeom_coulomb_series(acb_ptr F, acb_ptr G, acb_ptr Hpos, acb_ptr Hneg, const acb_t l, const acb_t eta, acb_srcptr z, slong zlen, slong len, slong prec) { acb_ptr t, v; if (len == 0) return; zlen = FLINT_MIN(zlen, len); if (zlen == 1) { acb_hypgeom_coulomb(F, G, Hpos, Hneg, l, eta, z, prec); if (F != NULL) _acb_vec_zero(F + 1, len - 1); if (G != NULL) _acb_vec_zero(G + 1, len - 1); if (Hpos != NULL) _acb_vec_zero(Hpos + 1, len - 1); if (Hneg != NULL) _acb_vec_zero(Hneg + 1, len - 1); return; } t = _acb_vec_init(len); v = _acb_vec_init(zlen); /* copy nonconstant part first to allow aliasing */ acb_zero(v); _acb_vec_set(v + 1, z + 1, zlen - 1); acb_hypgeom_coulomb_jet(F, G, Hpos, Hneg, l, eta, z, len, prec); if (F != NULL) { _acb_vec_set(t, F, len); _acb_poly_compose_series(F, t, len, v, zlen, len, prec); } if (G != NULL) { _acb_vec_set(t, G, len); _acb_poly_compose_series(G, t, len, v, zlen, len, prec); } if (Hpos != NULL) { _acb_vec_set(t, Hpos, len); _acb_poly_compose_series(Hpos, t, len, v, zlen, len, prec); } if (Hneg != NULL) { _acb_vec_set(t, Hneg, len); _acb_poly_compose_series(Hneg, t, len, v, zlen, len, prec); } _acb_vec_clear(t, len); _acb_vec_clear(v, zlen); }
void _acb_poly_compose_series_brent_kung(acb_ptr res, acb_srcptr poly1, long len1, acb_srcptr poly2, long len2, long n, long prec) { acb_mat_t A, B, C; acb_ptr t, h; long i, m; if (n == 1) { acb_set(res, poly1); return; } m = n_sqrt(n) + 1; acb_mat_init(A, m, n); acb_mat_init(B, m, m); acb_mat_init(C, m, n); h = _acb_vec_init(n); t = _acb_vec_init(n); /* Set rows of B to the segments of poly1 */ for (i = 0; i < len1 / m; i++) _acb_vec_set(B->rows[i], poly1 + i*m, m); _acb_vec_set(B->rows[i], poly1 + i*m, len1 % m); /* Set rows of A to powers of poly2 */ acb_set_ui(A->rows[0] + 0, 1UL); _acb_vec_set(A->rows[1], poly2, len2); for (i = 2; i < m; i++) _acb_poly_mullow(A->rows[i], A->rows[(i + 1) / 2], n, A->rows[i / 2], n, n, prec); acb_mat_mul(C, B, A, prec); /* Evaluate block composition using the Horner scheme */ _acb_vec_set(res, C->rows[m - 1], n); _acb_poly_mullow(h, A->rows[m - 1], n, poly2, len2, n, prec); for (i = m - 2; i >= 0; i--) { _acb_poly_mullow(t, res, n, h, n, n, prec); _acb_poly_add(res, t, n, C->rows[i], n, prec); } _acb_vec_clear(h, n); _acb_vec_clear(t, n); acb_mat_clear(A); acb_mat_clear(B); acb_mat_clear(C); }
void acb_poly_add_si(acb_poly_t res, const acb_poly_t x, long y, long prec) { long len = x->length; if (len == 0) { acb_poly_set_si(res, y); } else { acb_poly_fit_length(res, len); if (y >= 0) acb_add_ui(res->coeffs, x->coeffs, y, prec); else acb_sub_ui(res->coeffs, x->coeffs, -y, prec); if (res != x) _acb_vec_set(res->coeffs + 1, x->coeffs + 1, len - 1); _acb_poly_set_length(res, len); _acb_poly_normalise(res); } }
void _acb_dirichlet_hardy_z_series(acb_ptr res, acb_srcptr s, slong slen, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, slong prec) { slen = FLINT_MIN(slen, len); if (len == 0) return; if (slen == 1) { acb_dirichlet_hardy_z(res, s, G, chi, 1, prec); _acb_vec_zero(res + 1, len - 1); } else { acb_ptr t, u; t = _acb_vec_init(len); u = _acb_vec_init(slen); acb_dirichlet_hardy_z(t, s, G, chi, len, prec); /* compose with nonconstant part */ acb_zero(u); _acb_vec_set(u + 1, s + 1, slen - 1); _acb_poly_compose_series(res, t, len, u, slen, len, prec); _acb_vec_clear(t, len); _acb_vec_clear(u, slen); } }
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_zeta_series(acb_ptr res, acb_srcptr h, slong hlen, const acb_t a, int deflate, slong len, slong prec) { acb_ptr t, u; hlen = FLINT_MIN(hlen, len); t = _acb_vec_init(len); u = _acb_vec_init(len); _acb_poly_zeta_cpx_reflect(t, h, a, deflate, len, prec); /* compose with nonconstant part */ acb_zero(u); _acb_vec_set(u + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, t, len, u, hlen, len, prec); _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
int acb_mat_eig_multiple(acb_ptr E, const acb_mat_t A, acb_srcptr E_approx, const acb_mat_t R_approx, slong prec) { slong n; acb_ptr F; int success; n = arb_mat_nrows(A); F = _acb_vec_init(n); success = acb_mat_eig_simple_vdhoeven_mourrain(F, NULL, NULL, A, E_approx, R_approx, prec); if (!success) success = acb_mat_eig_multiple_rump(F, A, E_approx, R_approx, prec); _acb_vec_set(E, F, n); _acb_vec_clear(F, n); return success; }
void _acb_poly_agm1_series(acb_ptr res, acb_srcptr z, long zlen, long len, long prec) { acb_ptr t, u; zlen = FLINT_MIN(zlen, len); t = _acb_vec_init(len); u = _acb_vec_init(len); acb_agm1_cpx(t, z, len, prec); /* compose with nonconstant part */ acb_zero(u); _acb_vec_set(u + 1, z + 1, zlen - 1); _acb_poly_compose_series(res, t, len, u, zlen, len, prec); _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
void _acb_poly_powsum_one_series_sieved(acb_ptr z, const acb_t s, slong n, slong len, slong prec) { slong * divisors; slong powers_alloc; slong i, j, k, ibound, kprev, power_of_two, horner_point; int critical_line, integer; acb_ptr powers; acb_ptr t, u, x; acb_ptr p1, p2; arb_t logk, v, w; critical_line = arb_is_exact(acb_realref(s)) && (arf_cmp_2exp_si(arb_midref(acb_realref(s)), -1) == 0); integer = arb_is_zero(acb_imagref(s)) && arb_is_int(acb_realref(s)); divisors = flint_calloc(n / 2 + 1, sizeof(slong)); powers_alloc = (n / 6 + 1) * len; powers = _acb_vec_init(powers_alloc); ibound = n_sqrt(n); for (i = 3; i <= ibound; i += 2) if (DIVISOR(i) == 0) for (j = i * i; j <= n; j += 2 * i) DIVISOR(j) = i; t = _acb_vec_init(len); u = _acb_vec_init(len); x = _acb_vec_init(len); arb_init(logk); arb_init(v); arb_init(w); power_of_two = 1; while (power_of_two * 2 <= n) power_of_two *= 2; horner_point = n / power_of_two; _acb_vec_zero(z, len); kprev = 0; COMPUTE_POWER(x, 2, kprev); for (k = 1; k <= n; k += 2) { /* t = k^(-s) */ if (DIVISOR(k) == 0) { COMPUTE_POWER(t, k, kprev); } else { p1 = POWER(DIVISOR(k)); p2 = POWER(k / DIVISOR(k)); if (len == 1) acb_mul(t, p1, p2, prec); else _acb_poly_mullow(t, p1, len, p2, len, len, prec); } if (k * 3 <= n) _acb_vec_set(POWER(k), t, len); _acb_vec_add(u, u, t, len, prec); while (k == horner_point && power_of_two != 1) { _acb_poly_mullow(t, z, len, x, len, len, prec); _acb_vec_add(z, t, u, len, prec); power_of_two /= 2; horner_point = n / power_of_two; horner_point -= (horner_point % 2 == 0); } } _acb_poly_mullow(t, z, len, x, len, len, prec); _acb_vec_add(z, t, u, len, prec); flint_free(divisors); _acb_vec_clear(powers, powers_alloc); _acb_vec_clear(t, len); _acb_vec_clear(u, len); _acb_vec_clear(x, len); arb_clear(logk); arb_clear(v); arb_clear(w); }
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_dirichlet_hurwitz_precomp_init(acb_dirichlet_hurwitz_precomp_t pre, const acb_t s, int deflate, slong A, slong K, slong N, slong prec) { slong i, k; if (A < 1 || K < 1 || N < 1) abort(); pre->deflate = deflate; pre->A = A; pre->K = K; pre->N = N; pre->coeffs = _acb_vec_init(N * K); mag_init(&pre->err); acb_init(&pre->s); acb_set(&pre->s, s); acb_dirichlet_hurwitz_precomp_bound(&pre->err, s, A, K, N); if (mag_is_finite(&pre->err)) { acb_t t, a; acb_init(t); acb_init(a); /* (-1)^k (s)_k / k! */ acb_one(pre->coeffs + 0); for (k = 1; k < K; k++) { acb_add_ui(pre->coeffs + k, s, k - 1, prec); acb_mul(pre->coeffs + k, pre->coeffs + k, pre->coeffs + k - 1, prec); acb_div_ui(pre->coeffs + k, pre->coeffs + k, k, prec); acb_neg(pre->coeffs + k, pre->coeffs + k); } for (i = 1; i < N; i++) _acb_vec_set(pre->coeffs + i * K, pre->coeffs, K); /* zeta(s+k,a) where a = A + (2*i+1)/(2*N) */ for (i = 0; i < N; i++) { acb_set_ui(a, 2 * i + 1); acb_div_ui(a, a, 2 * N, prec); acb_add_ui(a, a, A, prec); for (k = 0; k < K; k++) { acb_add_ui(t, s, k, prec); if (deflate && k == 0) _acb_poly_zeta_cpx_series(t, t, a, 1, 1, prec); else acb_hurwitz_zeta(t, t, a, prec); acb_mul(pre->coeffs + i * K + k, pre->coeffs + i * K + k, t, prec); } } acb_clear(t); acb_clear(a); } }
void _acb_poly_zeta_series(acb_ptr res, acb_srcptr h, long hlen, const acb_t a, int deflate, long len, long prec) { long i; acb_ptr t, u; hlen = FLINT_MIN(hlen, len); t = _acb_vec_init(len); u = _acb_vec_init(len); /* use reflection formula */ if (arf_sgn(arb_midref(acb_realref(h))) < 0 && acb_is_one(a)) { /* zeta(s) = (2*pi)**s * sin(pi*s/2) / pi * gamma(1-s) * zeta(1-s) */ acb_t pi; acb_ptr f, s1, s2, s3, s4; acb_init(pi); f = _acb_vec_init(2); s1 = _acb_vec_init(len); s2 = _acb_vec_init(len); s3 = _acb_vec_init(len); s4 = _acb_vec_init(len); acb_const_pi(pi, prec); /* s1 = (2*pi)**s */ acb_mul_2exp_si(pi, pi, 1); _acb_poly_pow_cpx(s1, pi, h, len, prec); acb_mul_2exp_si(pi, pi, -1); /* s2 = sin(pi*s/2) / pi */ acb_set(f, h); acb_one(f + 1); acb_mul_2exp_si(f, f, -1); acb_mul_2exp_si(f + 1, f + 1, -1); _acb_poly_sin_pi_series(s2, f, 2, len, prec); _acb_vec_scalar_div(s2, s2, len, pi, prec); /* s3 = gamma(1-s) */ acb_sub_ui(f, h, 1, prec); acb_neg(f, f); acb_set_si(f + 1, -1); _acb_poly_gamma_series(s3, f, 2, len, prec); /* s4 = zeta(1-s) */ acb_sub_ui(f, h, 1, prec); acb_neg(f, f); _acb_poly_zeta_cpx_series(s4, f, a, 0, len, prec); for (i = 1; i < len; i += 2) acb_neg(s4 + i, s4 + i); _acb_poly_mullow(u, s1, len, s2, len, len, prec); _acb_poly_mullow(s1, s3, len, s4, len, len, prec); _acb_poly_mullow(t, u, len, s1, len, len, prec); /* add 1/(1-(s+t)) = 1/(1-s) + t/(1-s)^2 + ... */ if (deflate) { acb_sub_ui(u, h, 1, prec); acb_neg(u, u); acb_inv(u, u, prec); for (i = 1; i < len; i++) acb_mul(u + i, u + i - 1, u, prec); _acb_vec_add(t, t, u, len, prec); } acb_clear(pi); _acb_vec_clear(f, 2); _acb_vec_clear(s1, len); _acb_vec_clear(s2, len); _acb_vec_clear(s3, len); _acb_vec_clear(s4, len); } else { _acb_poly_zeta_cpx_series(t, h, a, deflate, len, prec); } /* compose with nonconstant part */ acb_zero(u); _acb_vec_set(u + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, t, len, u, hlen, len, prec); _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
void _acb_poly_lgamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec) { int reflect; slong i, r, n, wp; acb_t zr; acb_ptr t, u; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { acb_lgamma(res, h, prec); if (acb_is_finite(res)) _acb_vec_zero(res + 1, len - 1); else _acb_vec_indeterminate(res + 1, len - 1); return; } if (len == 2) { acb_t v; acb_init(v); acb_set(v, h + 1); acb_digamma(res + 1, h, prec); acb_lgamma(res, h, prec); acb_mul(res + 1, res + 1, v, prec); acb_clear(v); return; } /* use real code for real input and output */ if (_acb_vec_is_real(h, hlen) && arb_is_positive(acb_realref(h))) { arb_ptr tmp = _arb_vec_init(len); for (i = 0; i < hlen; i++) arb_set(tmp + i, acb_realref(h + i)); _arb_poly_lgamma_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); acb_init(zr); /* use Stirling series */ acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 0, wp); if (reflect) { /* log gamma(h+x) = log rf(1-(h+x), r) - log gamma(1-(h+x)+r) - log sin(pi (h+x)) + log(pi) */ if (r != 0) /* otherwise t = 0 */ { acb_sub_ui(u, h, 1, wp); acb_neg(u, u); _log_rising_ui_series(t, u, r, len, wp); for (i = 1; i < len; i += 2) acb_neg(t + i, t + i); } acb_sub_ui(u, h, 1, wp); acb_neg(u, u); acb_add_ui(zr, u, r, wp); _acb_poly_gamma_stirling_eval(u, zr, n, len, wp); for (i = 1; i < len; i += 2) acb_neg(u + i, u + i); _acb_vec_sub(t, t, u, len, wp); /* log(sin) is unstable with large imaginary parts; cot_pi is implemented in a numerically stable way */ acb_set(u, h); acb_one(u + 1); _acb_poly_cot_pi_series(u, u, 2, len - 1, wp); _acb_poly_integral(u, u, len, wp); acb_const_pi(u, wp); _acb_vec_scalar_mul(u + 1, u + 1, len - 1, u, wp); acb_log_sin_pi(u, h, wp); _acb_vec_sub(u, t, u, len, wp); acb_const_pi(t, wp); /* todo: constant for log pi */ acb_log(t, t, wp); acb_add(u, u, t, wp); } else { /* log gamma(x) = log gamma(x+r) - log rf(x,r) */ acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval(u, zr, n, len, wp); if (r != 0) { _log_rising_ui_series(t, h, r, len, wp); _acb_vec_sub(u, u, t, len, wp); } } /* compose with nonconstant part */ acb_zero(t); _acb_vec_set(t + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, u, len, t, hlen, len, prec); acb_clear(zr); _acb_vec_clear(t, len); _acb_vec_clear(u, len); }
void _acb_poly_digamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec) { int reflect; slong i, r, n, rflen, wp; acb_t zr; acb_ptr t, u, v; hlen = FLINT_MIN(hlen, len); if (hlen == 1) { acb_digamma(res, h, prec); if (acb_is_finite(res)) _acb_vec_zero(res + 1, len - 1); else _acb_vec_indeterminate(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_digamma_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 + 1); u = _acb_vec_init(len + 1); v = _acb_vec_init(len + 1); acb_init(zr); /* use Stirling series */ acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 1, wp); /* psi(x) = psi((1-x)+r) - h(1-x,r) - pi*cot(pi*x) */ if (reflect) { if (r != 0) /* otherwise t = 0 */ { acb_sub_ui(v, h, 1, wp); acb_neg(v, v); acb_one(v + 1); rflen = FLINT_MIN(len + 1, r + 1); _acb_poly_rising_ui_series(u, v, 2, r, rflen, wp); _acb_poly_derivative(v, u, rflen, wp); _acb_poly_div_series(t, v, rflen - 1, u, rflen, len, wp); for (i = 1; i < len; i += 2) acb_neg(t + i, t + i); } acb_sub_ui(zr, h, r + 1, wp); acb_neg(zr, zr); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, wp); for (i = 1; i < len; i += 2) acb_neg(u + i, u + i); _acb_vec_sub(u, u, t, len, wp); acb_set(t, h); acb_one(t + 1); _acb_poly_cot_pi_series(t, t, 2, len, wp); acb_const_pi(v, wp); _acb_vec_scalar_mul(t, t, len, v, wp); _acb_vec_sub(u, u, t, len, wp); } else { if (r == 0) { acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, wp); } else { acb_set(v, h); acb_one(v + 1); rflen = FLINT_MIN(len + 1, r + 1); _acb_poly_rising_ui_series(u, v, 2, r, rflen, wp); _acb_poly_derivative(v, u, rflen, wp); _acb_poly_div_series(t, v, rflen - 1, u, rflen, len, wp); acb_add_ui(zr, h, r, wp); _acb_poly_gamma_stirling_eval2(u, zr, n, len + 1, 1, wp); _acb_vec_sub(u, u, t, len, wp); } } /* compose with nonconstant part */ acb_zero(t); _acb_vec_set(t + 1, h + 1, hlen - 1); _acb_poly_compose_series(res, u, len, t, hlen, len, prec); acb_clear(zr); _acb_vec_clear(t, len + 1); _acb_vec_clear(u, len + 1); _acb_vec_clear(v, len + 1); }
slong _acb_poly_find_roots(acb_ptr roots, acb_srcptr poly, acb_srcptr initial, slong len, slong maxiter, slong prec) { slong iter, i, deg; slong rootmag, max_rootmag, correction, max_correction; deg = len - 1; if (deg == 0) { return 0; } else if (acb_contains_zero(poly + len - 1)) { /* if the leading coefficient contains zero, roots can be anywhere */ for (i = 0; i < deg; i++) { arb_zero_pm_inf(acb_realref(roots + i)); arb_zero_pm_inf(acb_imagref(roots + i)); } return 0; } else if (deg == 1) { acb_inv(roots + 0, poly + 1, prec); acb_mul(roots + 0, roots + 0, poly + 0, prec); acb_neg(roots + 0, roots + 0); return 1; } if (initial == NULL) _acb_poly_roots_initial_values(roots, deg, prec); else _acb_vec_set(roots, initial, deg); if (maxiter == 0) maxiter = 2 * deg + n_sqrt(prec); for (iter = 0; iter < maxiter; iter++) { max_rootmag = -ARF_PREC_EXACT; for (i = 0; i < deg; i++) { rootmag = _acb_get_mid_mag(roots + i); max_rootmag = FLINT_MAX(rootmag, max_rootmag); } _acb_poly_refine_roots_durand_kerner(roots, poly, len, prec); max_correction = -ARF_PREC_EXACT; for (i = 0; i < deg; i++) { correction = _acb_get_rad_mag(roots + i); max_correction = FLINT_MAX(correction, max_correction); } /* estimate the correction relative to the whole set of roots */ max_correction -= max_rootmag; /* flint_printf("ITER %wd MAX CORRECTION: %wd\n", iter, max_correction); */ if (max_correction < -prec / 2) maxiter = FLINT_MIN(maxiter, iter + 2); else if (max_correction < -prec / 3) maxiter = FLINT_MIN(maxiter, iter + 3); else if (max_correction < -prec / 4) maxiter = FLINT_MIN(maxiter, iter + 4); } return _acb_poly_validate_roots(roots, poly, len, prec); }
void fmpz_poly_complex_roots_squarefree(const fmpz_poly_t poly, slong initial_prec, slong target_prec, slong print_digits) { slong i, j, prec, deg, deg_deflated, isolated, maxiter, deflation; acb_poly_t cpoly, cpoly_deflated; fmpz_poly_t poly_deflated; acb_ptr roots, roots_deflated; int removed_zero; if (fmpz_poly_degree(poly) < 1) return; fmpz_poly_init(poly_deflated); acb_poly_init(cpoly); acb_poly_init(cpoly_deflated); /* try to write poly as poly_deflated(x^deflation), possibly multiplied by x */ removed_zero = fmpz_is_zero(poly->coeffs); if (removed_zero) fmpz_poly_shift_right(poly_deflated, poly, 1); else fmpz_poly_set(poly_deflated, poly); deflation = fmpz_poly_deflation(poly_deflated); fmpz_poly_deflate(poly_deflated, poly_deflated, deflation); deg = fmpz_poly_degree(poly); deg_deflated = fmpz_poly_degree(poly_deflated); flint_printf("searching for %wd roots, %wd deflated\n", deg, deg_deflated); roots = _acb_vec_init(deg); roots_deflated = _acb_vec_init(deg_deflated); for (prec = initial_prec; ; prec *= 2) { acb_poly_set_fmpz_poly(cpoly_deflated, poly_deflated, prec); maxiter = FLINT_MIN(FLINT_MAX(deg_deflated, 32), prec); TIMEIT_ONCE_START flint_printf("prec=%wd: ", prec); isolated = acb_poly_find_roots(roots_deflated, cpoly_deflated, prec == initial_prec ? NULL : roots_deflated, maxiter, prec); flint_printf("%wd isolated roots | ", isolated); TIMEIT_ONCE_STOP if (isolated == deg_deflated) { if (!check_accuracy(roots_deflated, deg_deflated, target_prec)) continue; if (deflation == 1) { _acb_vec_set(roots, roots_deflated, deg_deflated); } else /* compute all nth roots */ { acb_t w, w2; acb_init(w); acb_init(w2); acb_unit_root(w, deflation, prec); acb_unit_root(w2, 2 * deflation, prec); for (i = 0; i < deg_deflated; i++) { if (arf_sgn(arb_midref(acb_realref(roots_deflated + i))) > 0) { acb_root_ui(roots + i * deflation, roots_deflated + i, deflation, prec); } else { acb_neg(roots + i * deflation, roots_deflated + i); acb_root_ui(roots + i * deflation, roots + i * deflation, deflation, prec); acb_mul(roots + i * deflation, roots + i * deflation, w2, prec); } for (j = 1; j < deflation; j++) { acb_mul(roots + i * deflation + j, roots + i * deflation + j - 1, w, prec); } } acb_clear(w); acb_clear(w2); } /* by assumption that poly is squarefree, must be just one */ if (removed_zero) acb_zero(roots + deg_deflated * deflation); if (!check_accuracy(roots, deg, target_prec)) continue; acb_poly_set_fmpz_poly(cpoly, poly, prec); if (!acb_poly_validate_real_roots(roots, cpoly, prec)) continue; for (i = 0; i < deg; i++) { if (arb_contains_zero(acb_imagref(roots + i))) arb_zero(acb_imagref(roots + i)); } flint_printf("done!\n"); break; } } if (print_digits != 0) { _acb_vec_sort_pretty(roots, deg); for (i = 0; i < deg; i++) { acb_printn(roots + i, print_digits, 0); flint_printf("\n"); } } fmpz_poly_clear(poly_deflated); acb_poly_clear(cpoly); acb_poly_clear(cpoly_deflated); _acb_vec_clear(roots, deg); _acb_vec_clear(roots_deflated, deg_deflated); }