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_interpolation_weights(acb_ptr w, acb_ptr * tree, slong len, slong prec) { acb_ptr tmp; slong i, n, height; if (len == 0) return; if (len == 1) { acb_one(w); return; } tmp = _acb_vec_init(len + 1); height = FLINT_CLOG2(len); n = WORD(1) << (height - 1); _acb_poly_mul_monic(tmp, tree[height-1], n + 1, tree[height-1] + (n + 1), (len - n + 1), prec); _acb_poly_derivative(tmp, tmp, len + 1, prec); _acb_poly_evaluate_vec_fast_precomp(w, tmp, len, tree, len, prec); for (i = 0; i < len; i++) acb_inv(w + i, w + i, prec); _acb_vec_clear(tmp, len + 1); }
void acb_hypgeom_pfq_sum_bs_invz(acb_t s, acb_t t, acb_srcptr a, slong p, acb_srcptr b, slong q, const acb_t z, slong n, slong prec) { acb_t u, v, w; if (n < 4) { acb_init(u); acb_inv(u, z, prec); acb_hypgeom_pfq_sum_forward(s, t, a, p, b, q, u, n, prec); acb_clear(u); return; } acb_init(u); acb_init(v); acb_init(w); bsplit(u, v, w, a, p, b, q, z, 0, n, prec, 1); acb_div(t, u, w, prec); acb_div(s, v, w, prec); acb_clear(u); acb_clear(v); acb_clear(w); }
void acb_lambertw_initial_asymp(acb_t w, const acb_t z, const fmpz_t k, slong prec) { acb_t L1, L2, t; acb_init(L1); acb_init(L2); acb_init(t); acb_const_pi(L2, prec); acb_mul_2exp_si(L2, L2, 1); acb_mul_fmpz(L2, L2, k, prec); acb_mul_onei(L2, L2); acb_log(L1, z, prec); acb_add(L1, L1, L2, prec); acb_log(L2, L1, prec); /* L1 - L2 + L2/L1 + L2(L2-2)/(2 L1^2) */ acb_inv(t, L1, prec); acb_mul_2exp_si(w, L2, 1); acb_submul(w, L2, L2, prec); acb_neg(w, w); acb_mul(w, w, t, prec); acb_mul_2exp_si(w, w, -1); acb_add(w, w, L2, prec); acb_mul(w, w, t, prec); acb_sub(w, w, L2, prec); acb_add(w, w, L1, prec); acb_clear(L1); acb_clear(L2); acb_clear(t); }
int main() { slong iter; flint_rand_t state; flint_printf("rsqrt...."); fflush(stdout); flint_randinit(state); /* check (a^(-1/2))^(-2) = a */ for (iter = 0; iter < 10000; iter++) { acb_t a, b, c; slong prec; acb_init(a); acb_init(b); acb_init(c); acb_randtest(a, state, 1 + n_randint(state, 2000), 10); acb_randtest(b, state, 1 + n_randint(state, 2000), 10); prec = 2 + n_randint(state, 2000); acb_rsqrt(b, a, prec); acb_inv(c, b, prec); acb_mul(c, c, c, prec); if (!acb_contains(c, a)) { flint_printf("FAIL: containment\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_printf("c = "); acb_print(c); flint_printf("\n\n"); abort(); } acb_rsqrt(a, a, prec); if (!acb_equal(a, b)) { flint_printf("FAIL: aliasing\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); abort(); } acb_clear(a); acb_clear(b); acb_clear(c); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
/* f(z) = 1/(1+z^2) */ int f_atanderiv(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ acb_mul(res, z, z, prec); acb_add_ui(res, res, 1, prec); acb_inv(res, res, prec); return 0; }
/* note: the tmp variable t should have zero radius */ static void acb_approx_div(acb_t z, const acb_t x, const acb_t y, acb_t t, slong prec) { arf_set(arb_midref(acb_realref(t)), arb_midref(acb_realref(y))); arf_set(arb_midref(acb_imagref(t)), arb_midref(acb_imagref(y))); acb_inv(t, t, prec); mag_zero(arb_radref(acb_realref(t))); mag_zero(arb_radref(acb_imagref(t))); acb_approx_mul(z, x, t, prec); }
void integrals_edge_factors_gc(acb_ptr res, const acb_t cab, const acb_t ba2, sec_t c, slong prec) { slong i; acb_t cj, ci; acb_init(cj); acb_init(ci); /* polynomial shift */ acb_vec_polynomial_shift(res, cab, c.g, prec); /* constants cj, j = 1 */ /* c_1 = (1-zeta^-1) ba2^(-d/2) (-I)^i * = 2 / ba2^(d/2) */ acb_pow_ui(cj, ba2, c.d / 2, prec); if (c.d % 2) { acb_t t; acb_init(t); acb_sqrt(t, ba2, prec); acb_mul(cj, cj, t, prec); acb_clear(t); } acb_inv(cj, cj, prec); acb_mul_2exp_si(cj, cj, 1); _acb_vec_scalar_mul(res, res, c.g, cj, prec); /* constant ci = -I * ba2*/ acb_one(ci); for (i = 1; i < c.g; i++) { acb_mul(ci, ci, ba2, prec); acb_div_onei(ci, ci); acb_mul(res + i, res + i, ci, prec); } acb_clear(ci); acb_clear(cj); }
int f_lambertw(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { acb_t t; if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ acb_init(t); prec = FLINT_MIN(prec, acb_rel_accuracy_bits(z) + 10); if (order != 0) { /* check for branch cut */ arb_const_e(acb_realref(t), prec); acb_inv(t, t, prec); acb_add(t, t, z, prec); if (arb_contains_zero(acb_imagref(t)) && arb_contains_nonpositive(acb_realref(t))) { acb_indeterminate(t); } } if (acb_is_finite(t)) { fmpz_t k; fmpz_init(k); acb_lambertw(res, z, k, 0, prec); fmpz_clear(k); } else { acb_indeterminate(res); } acb_clear(t); return 0; }
/* f(z) = sin(1/z), assume on real interval */ int f_essing(acb_ptr res, const acb_t z, void * param, slong order, slong prec) { if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ if ((order == 0) && acb_is_real(z) && arb_contains_zero(acb_realref(z))) { /* todo: arb_zero_pm_one, arb_unit_interval? */ acb_zero(res); mag_one(arb_radref(acb_realref(res))); } else { acb_inv(res, z, prec); acb_sin(res, res, prec); } return 0; }
void acb_hypgeom_ci_asymp(acb_t res, const acb_t z, slong prec) { acb_t t, u, w, v, one; acb_init(t); acb_init(u); acb_init(w); acb_init(v); acb_init(one); acb_one(one); acb_mul_onei(w, z); /* u = U(1,1,iz) */ acb_hypgeom_u_asymp(u, one, one, w, -1, prec); /* v = e^(-iz) */ acb_neg(v, w); acb_exp(v, v, prec); acb_mul(t, u, v, prec); if (acb_is_real(z)) { arb_div(acb_realref(t), acb_imagref(t), acb_realref(z), prec); arb_zero(acb_imagref(t)); acb_neg(t, t); } else { /* u = U(1,1,-iz) */ acb_neg(w, w); acb_hypgeom_u_asymp(u, one, one, w, -1, prec); acb_inv(v, v, prec); acb_submul(t, u, v, prec); acb_div(t, t, w, prec); acb_mul_2exp_si(t, t, -1); } if (arb_is_zero(acb_realref(z))) { if (arb_is_positive(acb_imagref(z))) { arb_const_pi(acb_imagref(t), prec); arb_mul_2exp_si(acb_imagref(t), acb_imagref(t), -1); } else if (arb_is_negative(acb_imagref(z))) { arb_const_pi(acb_imagref(t), prec); arb_mul_2exp_si(acb_imagref(t), acb_imagref(t), -1); arb_neg(acb_imagref(t), acb_imagref(t)); } else { acb_const_pi(u, prec); acb_mul_2exp_si(u, u, -1); arb_zero(acb_imagref(t)); arb_add_error(acb_imagref(t), acb_realref(u)); } } else { /* 0 if positive or positive imaginary pi if upper left quadrant (including negative real axis) -pi if lower left quadrant (including negative imaginary axis) */ if (arb_is_positive(acb_realref(z))) { /* do nothing */ } else if (arb_is_negative(acb_realref(z)) && arb_is_nonnegative(acb_imagref(z))) { acb_const_pi(u, prec); arb_add(acb_imagref(t), acb_imagref(t), acb_realref(u), prec); } else if (arb_is_nonpositive(acb_realref(z)) && arb_is_negative(acb_imagref(z))) { acb_const_pi(u, prec); arb_sub(acb_imagref(t), acb_imagref(t), acb_realref(u), prec); } else { /* add [-pi,pi] */ acb_const_pi(u, prec); arb_add_error(acb_imagref(t), acb_realref(u)); } } acb_swap(res, t); acb_clear(t); acb_clear(u); acb_clear(w); acb_clear(v); acb_clear(one); }
void gc_integrals_precomp(acb_ptr res, acb_srcptr u, slong d1, slong d, slong g, const gc_int_t gc, int flag, slong prec) { slong l; arb_t w, x; acb_t y, yxi; void (*sqrt_pol) (acb_t y, acb_srcptr u, slong d1, slong d, const arb_t x, slong prec); arb_init(w); arb_init(x); acb_init(y); acb_init(yxi); #if DEBUG flint_printf("\ngc integral : d1 = %ld, d = %ld, g = %ld, n = %ld, prec = %ld", d1, d, g, gc->n, prec); #endif sqrt_pol = &sqrt_pol_turn; if (flag & AJ_ROOT_DEF) sqrt_pol = &sqrt_pol_def; else if (flag & AJ_ROOT_TURN) sqrt_pol = &sqrt_pol_turn; /* compute integral */ _acb_vec_zero(res, g); for (l = 0; l < gc->len; l++) { /* compute 1/y(x) */ sqrt_pol(y, u, d1, d, gc->x + l, prec); acb_inv(y, y, prec); /* differentials */ acb_vec_add_geom_arb(res, g, y, gc->x + l, prec); /* now on -x */ arb_neg(x, gc->x + l); sqrt_pol(y, u, d1, d, x, prec); acb_inv(y, y, prec); acb_vec_add_geom_arb(res, g, y, x, prec); } if (gc->n % 2) { arb_zero(x); /* FIXME: pb with turn */ sqrt_pol_def(y, u, d1, d, x, prec); #if DEBUG > 1 flint_printf("\nend integration sum"); _acb_vec_printd(res, g, 30, "\n"); flint_printf("\nroots (d1=%ld, d=%ld)\n",d1,d); _acb_vec_printd(u, d, 30, "\n"); flint_printf("\n -> y = "); acb_printd(y, 30); #endif acb_inv(y, y, prec); acb_add(res + 0, res + 0, y, prec); } /* multiply by weight = Pi / n */ arb_const_pi(w, prec); arb_div_ui(w, w, gc->n, prec); _acb_vec_scalar_mul_arb(res, res, g, w, prec); #if DEBUG > 1 flint_printf("\nend integration "); _acb_vec_printd(res, g, 30, "\n"); #endif arb_clear(x); arb_clear(w); acb_clear(y); acb_clear(yxi); }
void acb_pow_fmpz_binexp(acb_t y, const acb_t b, const fmpz_t e, long prec) { long i, wp, bits; if (-2L <= *e && *e <= 4L) { if (*e == 0L) { acb_one(y); } else if (*e == 1L) { acb_set_round(y, b, prec); } else if (*e == -1L) { acb_inv(y, b, prec); } else if (*e == 2L) { acb_mul(y, b, b, prec); } else if (*e == 3L) { acb_cube(y, b, prec); } else if (*e == 4L) { acb_mul(y, b, b, prec); acb_mul(y, y, y, prec); } else { acb_inv(y, b, prec); acb_mul(y, y, y, prec); } return; } if (fmpz_sgn(e) < 0) { fmpz_t f; fmpz_init(f); fmpz_neg(f, e); acb_pow_fmpz_binexp(y, b, f, prec + 2); acb_inv(y, y, prec); fmpz_clear(f); return; } if (!COEFF_IS_MPZ(*e) && ((*e) % 3 == 0)) { fmpz e3 = (*e) / 3; acb_pow_fmpz_binexp(y, b, &e3, prec); acb_cube(y, y, prec); return; } if (y == b) { acb_t t; acb_init(t); acb_set(t, b); acb_pow_fmpz_binexp(y, t, e, prec); acb_clear(t); return; } acb_set(y, b); bits = fmpz_bits(e); wp = ARF_PREC_ADD(prec, bits); for (i = bits - 2; i >= 0; i--) { acb_mul(y, y, y, wp); if (fmpz_tstbit(e, i)) acb_mul(y, y, b, wp); } }
void _acb_poly_zeta_cpx_reflect(acb_ptr t, const acb_t h, const acb_t a, int deflate, slong len, slong prec) { /* 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, hcopy; acb_ptr f, s1, s2, s3, s4, u; slong i; acb_init(pi); acb_init(hcopy); 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); u = _acb_vec_init(len); acb_set(hcopy, h); 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, hcopy, 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, hcopy, 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, hcopy, 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_clear(hcopy); _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); _acb_vec_clear(u, len); } else { _acb_poly_zeta_cpx_series(t, h, a, deflate, len, prec); } }
int main() { long iter; flint_rand_t state; printf("det...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000; iter++) { fmpq_mat_t Q; fmpq_t Qdet; acb_mat_t A; acb_t Adet, imagunit; long n, qbits, prec; int imaginary; n = n_randint(state, 8); qbits = 1 + n_randint(state, 100); prec = 2 + n_randint(state, 200); imaginary = n_randint(state, 2); fmpq_mat_init(Q, n, n); fmpq_init(Qdet); acb_mat_init(A, n, n); acb_init(Adet); acb_init(imagunit); fmpq_mat_randtest(Q, state, qbits); fmpq_mat_det(Qdet, Q); acb_mat_set_fmpq_mat(A, Q, prec); if (imaginary) { acb_onei(imagunit); acb_mat_scalar_mul_acb(A, A, imagunit, prec); } acb_mat_det(Adet, A, prec); if (imaginary) { acb_onei(imagunit); acb_inv(imagunit, imagunit, prec); acb_pow_ui(imagunit, imagunit, n, prec); acb_mul(Adet, Adet, imagunit, prec); } if (!acb_contains_fmpq(Adet, Qdet)) { printf("FAIL (containment, iter = %ld)\n", iter); printf("n = %ld, prec = %ld\n", n, prec); printf("\n"); printf("Q = \n"); fmpq_mat_print(Q); printf("\n\n"); printf("Qdet = \n"); fmpq_print(Qdet); printf("\n\n"); printf("A = \n"); acb_mat_printd(A, 15); printf("\n\n"); printf("Adet = \n"); acb_printd(Adet, 15); printf("\n\n"); printf("Adet = \n"); acb_print(Adet); printf("\n\n"); abort(); } fmpq_mat_clear(Q); fmpq_clear(Qdet); acb_mat_clear(A); acb_clear(Adet); acb_clear(imagunit); } flint_randclear(state); flint_cleanup(); printf("PASS\n"); return EXIT_SUCCESS; }
void acb_modular_eisenstein(acb_ptr r, const acb_t tau, slong len, slong prec) { psl2z_t g; arf_t one_minus_eps; acb_t tau_prime, t1, t2, t3, t4, q; slong m, n; if (len < 1) return; psl2z_init(g); arf_init(one_minus_eps); acb_init(tau_prime); acb_init(t1); acb_init(t2); acb_init(t3); acb_init(t4); acb_init(q); arf_set_ui_2exp_si(one_minus_eps, 63, -6); acb_modular_fundamental_domain_approx(tau_prime, g, tau, one_minus_eps, prec); acb_exp_pi_i(q, tau_prime, prec); acb_modular_theta_const_sum(t2, t3, t4, q, prec); /* fourth powers of the theta functions (a, b, c) */ acb_mul(t2, t2, t2, prec); acb_mul(t2, t2, t2, prec); acb_mul(t2, t2, q, prec); acb_mul(t3, t3, t3, prec); acb_mul(t3, t3, t3, prec); acb_mul(t4, t4, t4, prec); acb_mul(t4, t4, t4, prec); /* c2 = pi^4 * (a^8 + b^8 + c^8) / 30 */ /* c3 = pi^6 * (b^12 + c^12 - 3a^8 * (b^4+c^4)) / 180 */ /* r = a^8 */ acb_mul(r, t2, t2, prec); if (len > 1) { /* r[1] = -3 a^8 * (b^4 + c^4) */ acb_add(r + 1, t3, t4, prec); acb_mul(r + 1, r + 1, r, prec); acb_mul_si(r + 1, r + 1, -3, prec); } /* b^8 */ acb_mul(t1, t3, t3, prec); acb_add(r, r, t1, prec); /* b^12 */ if (len > 1) acb_addmul(r + 1, t1, t3, prec); /* c^8 */ acb_mul(t1, t4, t4, prec); acb_add(r, r, t1, prec); /* c^12 */ if (len > 1) acb_addmul(r + 1, t1, t4, prec); acb_const_pi(t1, prec); acb_mul(t1, t1, t1, prec); acb_mul(t2, t1, t1, prec); acb_mul(r, r, t2, prec); acb_div_ui(r, r, 30, prec); if (len > 1) { acb_mul(t2, t2, t1, prec); acb_mul(r + 1, r + 1, t2, prec); acb_div_ui(r + 1, r + 1, 189, prec); } /* apply modular transformation */ if (!fmpz_is_zero(&g->c)) { acb_mul_fmpz(t1, tau, &g->c, prec); acb_add_fmpz(t1, t1, &g->d, prec); acb_inv(t1, t1, prec); acb_mul(t1, t1, t1, prec); acb_mul(t2, t1, t1, prec); acb_mul(r, r, t2, prec); if (len > 1) { acb_mul(t2, t1, t2, prec); acb_mul(r + 1, r + 1, t2, prec); } } /* compute more coefficients using recurrence */ for (n = 4; n < len + 2; n++) { acb_zero(r + n - 2); m = 2; for (m = 2; m * 2 < n; m++) acb_addmul(r + n - 2, r + m - 2, r + n - m - 2, prec); acb_mul_2exp_si(r + n - 2, r + n - 2, 1); if (n % 2 == 0) acb_addmul(r + n - 2, r + n / 2 - 2, r + n / 2 - 2, prec); acb_mul_ui(r + n - 2, r + n - 2, 3, prec); acb_div_ui(r + n - 2, r + n - 2, (2 * n + 1) * (n - 3), prec); } /* convert c's to G's */ for (n = 0; n < len; n++) acb_div_ui(r + n, r + n, 2 * n + 3, prec); psl2z_clear(g); arf_clear(one_minus_eps); acb_clear(tau_prime); acb_clear(t1); acb_clear(t2); acb_clear(t3); acb_clear(t4); acb_clear(q); }
void acb_hypgeom_chi_asymp(acb_t res, const acb_t z, slong prec) { acb_t t, u, v, one; acb_init(t); acb_init(u); acb_init(v); acb_init(one); acb_one(one); /* u = U(1,1,z) */ acb_hypgeom_u_asymp(u, one, one, z, -1, prec); /* v = e^(-z) */ acb_neg(v, z); acb_exp(v, v, prec); acb_mul(t, u, v, prec); if (arb_is_zero(acb_realref(z))) { arb_div(acb_realref(t), acb_imagref(t), acb_imagref(z), prec); arb_zero(acb_imagref(t)); acb_neg(t, t); } else { /* u = U(1,1,-z) */ acb_neg(u, z); acb_hypgeom_u_asymp(u, one, one, u, -1, prec); acb_inv(v, v, prec); acb_submul(t, u, v, prec); acb_div(t, t, z, prec); acb_mul_2exp_si(t, t, -1); acb_neg(t, t); } if (acb_is_real(z)) { if (arb_is_positive(acb_realref(z))) { arb_zero(acb_imagref(t)); } else if (arb_is_negative(acb_realref(z))) { arb_const_pi(acb_imagref(t), prec); } else { /* add [-pi,pi]/2 i */ acb_const_pi(u, prec); arb_zero(acb_imagref(t)); arb_add_error(acb_imagref(t), acb_realref(u)); } } else { /* -pi/2 if positive real or in lower half plane pi/2 if negative real or in upper half plane */ if (arb_is_negative(acb_imagref(z))) { acb_const_pi(u, prec); acb_mul_2exp_si(u, u, -1); arb_sub(acb_imagref(t), acb_imagref(t), acb_realref(u), prec); } else if (arb_is_positive(acb_imagref(z))) { acb_const_pi(u, prec); acb_mul_2exp_si(u, u, -1); arb_add(acb_imagref(t), acb_imagref(t), acb_realref(u), prec); } else { /* add [-pi,pi]/2 i */ acb_const_pi(u, prec); acb_mul_2exp_si(u, u, -1); arb_add_error(acb_imagref(t), acb_realref(u)); } } acb_swap(res, t); acb_clear(t); acb_clear(u); acb_clear(v); acb_clear(one); }
void acb_gamma_stirling_eval(acb_t s, const acb_t z, long nterms, int digamma, long prec) { acb_t t, logz, zinv, zinv2; arb_t b; mag_t err; long k, term_prec; double z_mag, term_mag; acb_init(t); acb_init(logz); acb_init(zinv); acb_init(zinv2); arb_init(b); acb_log(logz, z, prec); acb_inv(zinv, z, prec); nterms = FLINT_MAX(nterms, 1); acb_zero(s); if (nterms > 1) { acb_mul(zinv2, zinv, zinv, prec); z_mag = arf_get_d(arb_midref(acb_realref(logz)), ARF_RND_UP) * 1.44269504088896; for (k = nterms - 1; k >= 1; k--) { term_mag = bernoulli_bound_2exp_si(2 * k); term_mag -= (2 * k - 1) * z_mag; term_prec = prec + term_mag; term_prec = FLINT_MIN(term_prec, prec); term_prec = FLINT_MAX(term_prec, 10); arb_gamma_stirling_coeff(b, k, digamma, term_prec); if (prec > 2000) { acb_set_round(t, zinv2, term_prec); acb_mul(s, s, t, term_prec); } else acb_mul(s, s, zinv2, term_prec); arb_add(acb_realref(s), acb_realref(s), b, term_prec); } if (digamma) acb_mul(s, s, zinv2, prec); else acb_mul(s, s, zinv, prec); } /* remainder bound */ mag_init(err); acb_gamma_stirling_bound(err, z, digamma ? 1 : 0, 1, nterms); mag_add(arb_radref(acb_realref(s)), arb_radref(acb_realref(s)), err); mag_add(arb_radref(acb_imagref(s)), arb_radref(acb_imagref(s)), err); mag_clear(err); if (digamma) { acb_neg(s, s); acb_mul_2exp_si(zinv, zinv, -1); acb_sub(s, s, zinv, prec); acb_add(s, s, logz, prec); } else { /* (z-0.5)*log(z) - z + log(2*pi)/2 */ arb_one(b); arb_mul_2exp_si(b, b, -1); arb_set(acb_imagref(t), acb_imagref(z)); arb_sub(acb_realref(t), acb_realref(z), b, prec); acb_mul(t, logz, t, prec); acb_add(s, s, t, prec); acb_sub(s, s, z, prec); arb_const_log_sqrt2pi(b, prec); arb_add(acb_realref(s), acb_realref(s), b, prec); } acb_clear(t); acb_clear(logz); acb_clear(zinv); acb_clear(zinv2); arb_clear(b); }
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 acb_hypgeom_u_asymp(acb_t res, const acb_t a, const acb_t b, const acb_t z, slong n, slong prec) { acb_struct aa[3]; acb_t s, t, w, winv; int R, p, q, is_real, is_terminating; slong n_terminating; if (!acb_is_finite(a) || !acb_is_finite(b) || !acb_is_finite(z)) { acb_indeterminate(res); return; } acb_init(aa); acb_init(aa + 1); acb_init(aa + 2); acb_init(s); acb_init(t); acb_init(w); acb_init(winv); is_terminating = 0; n_terminating = WORD_MAX; /* special case, for incomplete gamma [todo: also when they happen to be exact and with difference 1...] */ if (a == b) { acb_set(aa, a); p = 1; q = 0; } else { acb_set(aa, a); acb_sub(aa + 1, a, b, prec); acb_add_ui(aa + 1, aa + 1, 1, prec); acb_one(aa + 2); p = 2; q = 1; } if (acb_is_nonpositive_int(aa)) { is_terminating = 1; if (arf_cmpabs_ui(arb_midref(acb_realref(aa)), prec) < 0) n_terminating = 1 - arf_get_si(arb_midref(acb_realref(aa)), ARF_RND_DOWN); } if (p == 2 && acb_is_nonpositive_int(aa + 1)) { is_terminating = 1; if (arf_cmpabs_ui(arb_midref(acb_realref(aa + 1)), n_terminating) < 0) n_terminating = 1 - arf_get_si(arb_midref(acb_realref(aa + 1)), ARF_RND_DOWN); } acb_neg(w, z); acb_inv(w, w, prec); acb_neg(winv, z); /* low degree polynomial -- no need to try to terminate sooner */ if (is_terminating && n_terminating < 8) { acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n_terminating, prec); acb_set(res, s); } else { mag_t C1, Cn, alpha, nu, sigma, rho, zinv, tmp, err; mag_init(C1); mag_init(Cn); mag_init(alpha); mag_init(nu); mag_init(sigma); mag_init(rho); mag_init(zinv); mag_init(tmp); mag_init(err); acb_hypgeom_u_asymp_bound_factors(&R, alpha, nu, sigma, rho, zinv, a, b, z); is_real = acb_is_real(a) && acb_is_real(b) && acb_is_real(z) && (is_terminating || arb_is_positive(acb_realref(z))); if (R == 0) { /* if R == 0, the error bound is infinite unless terminating */ if (is_terminating && n_terminating < prec) { acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n_terminating, prec); acb_set(res, s); } else { acb_indeterminate(res); } } else { /* C1 */ acb_hypgeom_mag_Cn(C1, R, nu, sigma, 1); /* err = 2 * alpha * exp(...) */ mag_mul(tmp, C1, rho); mag_mul(tmp, tmp, alpha); mag_mul(tmp, tmp, zinv); mag_mul_2exp_si(tmp, tmp, 1); mag_exp(err, tmp); mag_mul(err, err, alpha); mag_mul_2exp_si(err, err, 1); /* choose n automatically */ if (n < 0) { slong moreprec; /* take err into account when finding truncation point */ /* we should take Cn into account as well, but this depends on n which is to be determined; it's easier to look only at exp(...) which should be larger anyway */ if (mag_cmp_2exp_si(err, 10 * prec) > 0) moreprec = 10 * prec; else if (mag_cmp_2exp_si(err, 0) < 0) moreprec = 0; else moreprec = MAG_EXP(err); n = acb_hypgeom_pfq_choose_n_max(aa, p, aa + p, q, w, prec + moreprec, FLINT_MIN(WORD_MAX / 2, 50 + 10.0 * prec)); } acb_hypgeom_pfq_sum_invz(s, t, aa, p, aa + p, q, w, winv, n, prec); /* add error bound, if not terminating */ if (!(is_terminating && n == n_terminating)) { acb_hypgeom_mag_Cn(Cn, R, nu, sigma, n); mag_mul(err, err, Cn); /* nth term * factor */ acb_get_mag(tmp, t); mag_mul(err, err, tmp); if (is_real) arb_add_error_mag(acb_realref(s), err); else acb_add_error_mag(s, err); } acb_set(res, s); } mag_clear(C1); mag_clear(Cn); mag_clear(alpha); mag_clear(nu); mag_clear(sigma); mag_clear(rho); mag_clear(zinv); mag_clear(tmp); mag_clear(err); } acb_clear(aa); acb_clear(aa + 1); acb_clear(aa + 2); acb_clear(s); acb_clear(t); acb_clear(w); acb_clear(winv); }
int main() { slong iter; flint_rand_t state; flint_printf("airy...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) { acb_t z, t, w; acb_t ai1, aip1, bi1, bip1; acb_t ai2, aip2, bi2, bip2; slong n1, n2, prec1, prec2; unsigned int mask; acb_init(z); acb_init(t); acb_init(w); acb_init(ai1); acb_init(aip1); acb_init(bi1); acb_init(bip1); acb_init(ai2); acb_init(aip2); acb_init(bi2); acb_init(bip2); prec1 = 2 + n_randint(state, 1000); prec2 = 2 + n_randint(state, 1000); n1 = n_randint(state, 300); n2 = n_randint(state, 300); acb_randtest_param(z, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_randtest_param(t, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_add(z, z, t, 1000); acb_sub(z, z, t, 1000); switch (n_randint(state, 3)) { case 0: acb_hypgeom_airy_direct(ai1, aip1, bi1, bip1, z, n1, prec1); break; case 1: acb_hypgeom_airy_asymp(ai1, aip1, bi1, bip1, z, n1, prec1); break; default: acb_hypgeom_airy(ai1, aip1, bi1, bip1, z, prec1); break; } switch (n_randint(state, 3)) { case 0: acb_hypgeom_airy_direct(ai2, aip2, bi2, bip2, z, n2, prec2); break; case 1: acb_hypgeom_airy_asymp(ai2, aip2, bi2, bip2, z, n2, prec2); break; default: acb_hypgeom_airy(ai2, aip2, bi2, bip2, z, prec2); break; } if (!acb_overlaps(ai1, ai2)) { flint_printf("FAIL: consistency (Ai)\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("ai1 = "); acb_printd(ai1, 30); flint_printf("\n\n"); flint_printf("ai2 = "); acb_printd(ai2, 30); flint_printf("\n\n"); abort(); } if (!acb_overlaps(aip1, aip2)) { flint_printf("FAIL: consistency (Ai')\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("aip1 = "); acb_printd(aip1, 30); flint_printf("\n\n"); flint_printf("aip2 = "); acb_printd(aip2, 30); flint_printf("\n\n"); abort(); } if (!acb_overlaps(bi1, bi2)) { flint_printf("FAIL: consistency (Bi)\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("bi1 = "); acb_printd(bi1, 30); flint_printf("\n\n"); flint_printf("bi2 = "); acb_printd(bi2, 30); flint_printf("\n\n"); abort(); } if (!acb_overlaps(bip1, bip2)) { flint_printf("FAIL: consistency (Bi')\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("bip1 = "); acb_printd(bip1, 30); flint_printf("\n\n"); flint_printf("bip2 = "); acb_printd(bip2, 30); flint_printf("\n\n"); abort(); } acb_mul(w, ai1, bip1, prec1); acb_submul(w, bi1, aip1, prec1); acb_const_pi(t, prec1); acb_inv(t, t, prec1); if (!acb_overlaps(w, t)) { flint_printf("FAIL: wronskian\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("ai1 = "); acb_printd(ai1, 30); flint_printf("\n\n"); flint_printf("aip1 = "); acb_printd(aip1, 30); flint_printf("\n\n"); flint_printf("bi1 = "); acb_printd(bi1, 30); flint_printf("\n\n"); flint_printf("bip1 = "); acb_printd(bip1, 30); flint_printf("\n\n"); flint_printf("w = "); acb_printd(w, 30); flint_printf("\n\n"); abort(); } mask = n_randlimb(state); acb_hypgeom_airy((mask & 1) ? ai2 : NULL, (mask & 2) ? aip2 : NULL, (mask & 4) ? bi2 : NULL, (mask & 8) ? bip2 : NULL, z, prec2); if (!acb_overlaps(ai1, ai2) || !acb_overlaps(aip1, aip2) || !acb_overlaps(bi1, bi2) || !acb_overlaps(bip1, bip2)) { flint_printf("FAIL: consistency (mask)\n\n"); flint_printf("mask = %u\n\n", mask); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("ai1 = "); acb_printd(ai1, 30); flint_printf("\n\n"); flint_printf("ai2 = "); acb_printd(ai2, 30); flint_printf("\n\n"); flint_printf("aip1 = "); acb_printd(aip1, 30); flint_printf("\n\n"); flint_printf("aip2 = "); acb_printd(aip2, 30); flint_printf("\n\n"); flint_printf("bi1 = "); acb_printd(bi1, 30); flint_printf("\n\n"); flint_printf("bi2 = "); acb_printd(bi2, 30); flint_printf("\n\n"); flint_printf("bip1 = "); acb_printd(bip1, 30); flint_printf("\n\n"); flint_printf("bip2 = "); acb_printd(bip2, 30); flint_printf("\n\n"); abort(); } acb_clear(z); acb_clear(t); acb_clear(w); acb_clear(ai1); acb_clear(aip1); acb_clear(bi1); acb_clear(bip1); acb_clear(ai2); acb_clear(aip2); acb_clear(bi2); acb_clear(bip2); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void acb_hypgeom_2f1_transform_nolimit(acb_t res, const acb_t a, const acb_t b, const acb_t c, const acb_t z, int regularized, int which, slong prec) { acb_t ba, ca, cb, cab, ac1, bc1, ab1, ba1, w, t, u, v, s; if (acb_contains_zero(z) || !acb_is_finite(z)) { acb_indeterminate(res); return; } if (arb_contains_si(acb_realref(z), 1) && arb_contains_zero(acb_imagref(z))) { acb_indeterminate(res); return; } if (!regularized) { acb_init(t); acb_gamma(t, c, prec); acb_hypgeom_2f1_transform_nolimit(res, a, b, c, z, 1, which, prec); acb_mul(res, res, t, prec); acb_clear(t); return; } acb_init(ba); acb_init(ca); acb_init(cb); acb_init(cab); acb_init(ac1); acb_init(bc1); acb_init(ab1); acb_init(ba1); acb_init(w); acb_init(t); acb_init(u); acb_init(v); acb_init(s); acb_add_si(s, z, -1, prec); /* s = 1 - z */ acb_neg(s, s); acb_sub(ba, b, a, prec); /* ba = b - a */ acb_sub(ca, c, a, prec); /* ca = c - a */ acb_sub(cb, c, b, prec); /* cb = c - b */ acb_sub(cab, ca, b, prec); /* cab = c - a - b */ acb_add_si(ac1, ca, -1, prec); acb_neg(ac1, ac1); /* ac1 = a - c + 1 */ acb_add_si(bc1, cb, -1, prec); acb_neg(bc1, bc1); /* bc1 = b - c + 1 */ acb_add_si(ab1, ba, -1, prec); acb_neg(ab1, ab1); /* ab1 = a - b + 1 */ acb_add_si(ba1, ba, 1, prec); /* ba1 = b - a + 1 */ /* t = left term, u = right term (DLMF 15.8.1 - 15.8.5) */ if (which == 2) { acb_inv(w, z, prec); /* w = 1/z */ acb_hypgeom_2f1_direct(t, a, ac1, ab1, w, 1, prec); acb_hypgeom_2f1_direct(u, b, bc1, ba1, w, 1, prec); } else if (which == 3) { acb_inv(w, s, prec); /* w = 1/(1-z) */ acb_hypgeom_2f1_direct(t, a, cb, ab1, w, 1, prec); acb_hypgeom_2f1_direct(u, b, ca, ba1, w, 1, prec); } else if (which == 4) { acb_set(w, s); /* w = 1-z */ acb_add(v, ac1, b, prec); /* v = a+b-c+1 */ acb_hypgeom_2f1_direct(t, a, b, v, w, 1, prec); acb_add_si(v, cab, 1, prec); /* v = c-a-b+1 */ acb_hypgeom_2f1_direct(u, ca, cb, v, w, 1, prec); } else if (which == 5) { acb_inv(w, z, prec); /* w = 1-1/z */ acb_neg(w, w); acb_add_si(w, w, 1, prec); acb_add(v, ac1, b, prec); /* v = a+b-c+1 */ acb_hypgeom_2f1_direct(t, a, ac1, v, w, 1, prec); acb_add_si(v, cab, 1, prec); /* v = c-a-b+1 */ acb_add_si(u, a, -1, prec); /* u = 1-a */ acb_neg(u, u); acb_hypgeom_2f1_direct(u, ca, u, v, w, 1, prec); } else { flint_printf("invalid transformation!\n"); flint_abort(); } /* gamma factors */ acb_rgamma(v, a, prec); acb_mul(u, u, v, prec); acb_rgamma(v, ca, prec); acb_mul(t, t, v, prec); acb_rgamma(v, b, prec); if (which == 2 || which == 3) acb_mul(t, t, v, prec); else acb_mul(u, u, v, prec); acb_rgamma(v, cb, prec); if (which == 2 || which == 3) acb_mul(u, u, v, prec); else acb_mul(t, t, v, prec); if (which == 2 || which == 3) { if (which == 2) acb_neg(s, z); /* -z, otherwise 1-z since before */ acb_neg(v, a); acb_pow(v, s, v, prec); acb_mul(t, t, v, prec); acb_neg(v, b); acb_pow(v, s, v, prec); acb_mul(u, u, v, prec); } else { acb_pow(v, s, cab, prec); acb_mul(u, u, v, prec); if (which == 5) { acb_neg(v, a); acb_pow(v, z, v, prec); acb_mul(t, t, v, prec); acb_neg(v, ca); acb_pow(v, z, v, prec); acb_mul(u, u, v, prec); } } acb_sub(t, t, u, prec); if (which == 2 || which == 3) acb_sin_pi(v, ba, prec); else acb_sin_pi(v, cab, prec); acb_div(t, t, v, prec); acb_const_pi(v, prec); acb_mul(t, t, v, prec); acb_set(res, t); acb_clear(ba); acb_clear(ca); acb_clear(cb); acb_clear(cab); acb_clear(ac1); acb_clear(bc1); acb_clear(ab1); acb_clear(ba1); acb_clear(w); acb_clear(t); acb_clear(u); acb_clear(v); acb_clear(s); }
int main() { slong iter; flint_rand_t state; flint_printf("airy_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * arb_test_multiplier(); iter++) { acb_poly_t ai, aip, bi, bip, ai2, aip2, bi2, bip2, z, w, t; acb_t c; slong n1, n2, prec1, prec2; unsigned int mask; acb_poly_init(ai); acb_poly_init(aip); acb_poly_init(bi); acb_poly_init(bip); acb_poly_init(ai2); acb_poly_init(aip2); acb_poly_init(bi2); acb_poly_init(bip2); acb_poly_init(z); acb_poly_init(w); acb_poly_init(t); acb_init(c); prec1 = 2 + n_randint(state, 300); prec2 = 2 + n_randint(state, 300); n1 = n_randint(state, 6); n2 = n_randint(state, 6); acb_poly_randtest(ai, state, 10, prec1, 10); acb_poly_randtest(aip, state, 10, prec1, 10); acb_poly_randtest(bi, state, 10, prec1, 10); acb_poly_randtest(bip, state, 10, prec1, 10); acb_poly_randtest(z, state, 1 + n_randint(state, 10), prec1, 10); acb_hypgeom_airy_series(ai, aip, bi, bip, z, n1, prec1); acb_poly_mullow(w, ai, bip, n1, prec1); acb_poly_mullow(t, bi, aip, n1, prec1); acb_poly_sub(w, w, t, prec1); acb_const_pi(c, prec1); acb_inv(c, c, prec1); acb_poly_set_acb(t, c); acb_poly_truncate(t, n1); if (!acb_poly_overlaps(w, t)) { flint_printf("FAIL: wronskian\n\n"); flint_printf("z = "); acb_poly_printd(z, 30); flint_printf("\n\n"); flint_printf("ai = "); acb_poly_printd(ai, 30); flint_printf("\n\n"); flint_printf("aip = "); acb_poly_printd(aip, 30); flint_printf("\n\n"); flint_printf("bi = "); acb_poly_printd(bi, 30); flint_printf("\n\n"); flint_printf("bip = "); acb_poly_printd(bip, 30); flint_printf("\n\n"); flint_printf("w = "); acb_poly_printd(w, 30); flint_printf("\n\n"); abort(); } mask = n_randlimb(state); acb_hypgeom_airy_series((mask & 1) ? ai2 : NULL, (mask & 2) ? aip2 : NULL, (mask & 4) ? bi2 : NULL, (mask & 8) ? bip2 : NULL, z, n2, prec2); acb_poly_truncate(ai, FLINT_MIN(n1, n2)); acb_poly_truncate(aip, FLINT_MIN(n1, n2)); acb_poly_truncate(bi, FLINT_MIN(n1, n2)); acb_poly_truncate(bip, FLINT_MIN(n1, n2)); acb_poly_truncate(ai2, FLINT_MIN(n1, n2)); acb_poly_truncate(aip2, FLINT_MIN(n1, n2)); acb_poly_truncate(bi2, FLINT_MIN(n1, n2)); acb_poly_truncate(bip2, FLINT_MIN(n1, n2)); if (((mask & 1) && (!acb_poly_overlaps(ai, ai2))) || ((mask & 2) && (!acb_poly_overlaps(aip, aip2))) || ((mask & 4) && (!acb_poly_overlaps(bi, bi2))) || ((mask & 8) && (!acb_poly_overlaps(bip, bip2)))) { flint_printf("FAIL: consistency (mask)\n\n"); flint_printf("mask = %u\n\n", mask); flint_printf("len1 = %wd, len2 = %wd\n\n", n1, n2); flint_printf("z = "); acb_poly_printd(z, 30); flint_printf("\n\n"); flint_printf("ai = "); acb_poly_printd(ai, 30); flint_printf("\n\n"); flint_printf("ai2 = "); acb_poly_printd(ai2, 30); flint_printf("\n\n"); flint_printf("aip = "); acb_poly_printd(aip, 30); flint_printf("\n\n"); flint_printf("aip2 = "); acb_poly_printd(aip2, 30); flint_printf("\n\n"); flint_printf("bi = "); acb_poly_printd(bi, 30); flint_printf("\n\n"); flint_printf("bi2 = "); acb_poly_printd(bi2, 30); flint_printf("\n\n"); flint_printf("bip = "); acb_poly_printd(bip, 30); flint_printf("\n\n"); flint_printf("bip2 = "); acb_poly_printd(bip2, 30); flint_printf("\n\n"); abort(); } acb_poly_clear(ai); acb_poly_clear(aip); acb_poly_clear(bi); acb_poly_clear(bip); acb_poly_clear(ai2); acb_poly_clear(aip2); acb_poly_clear(bi2); acb_poly_clear(bip2); acb_poly_clear(z); acb_poly_clear(w); acb_poly_clear(t); acb_clear(c); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void _acb_poly_zeta_em_sum(acb_ptr z, const acb_t s, const acb_t a, int deflate, ulong N, ulong M, slong d, slong prec) { acb_ptr t, u, v, term, sum; acb_t Na, one; slong i; t = _acb_vec_init(d + 1); u = _acb_vec_init(d); v = _acb_vec_init(d); term = _acb_vec_init(d); sum = _acb_vec_init(d); acb_init(Na); acb_init(one); prec += 2 * (FLINT_BIT_COUNT(N) + FLINT_BIT_COUNT(d)); acb_one(one); /* sum 1/(k+a)^(s+x) */ if (acb_is_one(a) && d <= 3) _acb_poly_powsum_one_series_sieved(sum, s, N, d, prec); else if (N > 50 && flint_get_num_threads() > 1) _acb_poly_powsum_series_naive_threaded(sum, s, a, one, N, d, prec); else _acb_poly_powsum_series_naive(sum, s, a, one, N, d, prec); /* t = 1/(N+a)^(s+x); we might need one extra term for deflation */ acb_add_ui(Na, a, N, prec); _acb_poly_acb_invpow_cpx(t, Na, s, d + 1, prec); /* sum += (N+a) * 1/((s+x)-1) * t */ if (!deflate) { /* u = (N+a)^(1-(s+x)) */ acb_sub_ui(v, s, 1, prec); _acb_poly_acb_invpow_cpx(u, Na, v, d, prec); /* divide by 1/((s-1) + x) */ acb_sub_ui(v, s, 1, prec); acb_div(u, u, v, prec); for (i = 1; i < d; i++) { acb_sub(u + i, u + i, u + i - 1, prec); acb_div(u + i, u + i, v, prec); } _acb_vec_add(sum, sum, u, d, prec); } /* sum += ((N+a)^(1-(s+x)) - 1) / ((s+x) - 1) */ else { /* at s = 1, this becomes (N*t - 1)/x, i.e. just remove one coeff */ if (acb_is_one(s)) { for (i = 0; i < d; i++) acb_mul(u + i, t + i + 1, Na, prec); _acb_vec_add(sum, sum, u, d, prec); } else { /* TODO: this is numerically unstable for large derivatives, and divides by zero if s contains 1. We want a good way to evaluate the power series ((N+a)^y - 1) / y where y has nonzero constant term, without doing a division. How is this best done? */ _acb_vec_scalar_mul(t, t, d, Na, prec); acb_sub_ui(t + 0, t + 0, 1, prec); acb_sub_ui(u + 0, s, 1, prec); acb_inv(u + 0, u + 0, prec); for (i = 1; i < d; i++) acb_mul(u + i, u + i - 1, u + 0, prec); for (i = 1; i < d; i += 2) acb_neg(u + i, u + i); _acb_poly_mullow(v, u, d, t, d, d, prec); _acb_vec_add(sum, sum, v, d, prec); _acb_poly_acb_invpow_cpx(t, Na, s, d, prec); } } /* sum += u = 1/2 * t */ _acb_vec_scalar_mul_2exp_si(u, t, d, -WORD(1)); _acb_vec_add(sum, sum, u, d, prec); /* Euler-Maclaurin formula tail */ if (d < 5 || d < M / 10) _acb_poly_zeta_em_tail_naive(u, s, Na, t, M, d, prec); else _acb_poly_zeta_em_tail_bsplit(u, s, Na, t, M, d, prec); _acb_vec_add(z, sum, u, d, prec); _acb_vec_clear(t, d + 1); _acb_vec_clear(u, d); _acb_vec_clear(v, d); _acb_vec_clear(term, d); _acb_vec_clear(sum, d); acb_clear(Na); acb_clear(one); }
int main() { slong iter; flint_rand_t state; flint_printf("digamma...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 3000 * arb_test_multiplier(); iter++) { acb_t a, b, c; slong prec1, prec2; prec1 = 2 + n_randint(state, 1000); prec2 = prec1 + 30; acb_init(a); acb_init(b); acb_init(c); arb_randtest_precise(acb_realref(a), state, 1 + n_randint(state, 1000), 3); arb_randtest_precise(acb_imagref(a), state, 1 + n_randint(state, 1000), 3); acb_digamma(b, a, prec1); acb_digamma(c, a, prec2); if (!acb_overlaps(b, c)) { flint_printf("FAIL: overlap\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_printf("c = "); acb_print(c); flint_printf("\n\n"); abort(); } acb_set(c, a); acb_digamma(c, c, prec2); if (!acb_overlaps(b, c)) { flint_printf("FAIL: aliasing\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_printf("c = "); acb_print(c); flint_printf("\n\n"); abort(); } /* check digamma(z+1) = digamma(z) + 1/z */ acb_inv(c, a, prec1); acb_add(b, b, c, prec1); acb_add_ui(c, a, 1, prec1); acb_digamma(c, c, prec1); if (!acb_overlaps(b, c)) { flint_printf("FAIL: functional equation\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_printf("c = "); acb_print(c); flint_printf("\n\n"); abort(); } acb_clear(a); acb_clear(b); acb_clear(c); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void acb_modular_elliptic_k_cpx(acb_ptr w, const acb_t m, slong len, slong prec) { acb_t t, u, msub1m, m2sub1; slong k, n; if (len < 1) return; if (len == 1) { acb_modular_elliptic_k(w, m, prec); return; } if (acb_is_zero(m)) { acb_const_pi(w, prec); acb_mul_2exp_si(w, w, -1); for (k = 1; k < len; k++) { acb_mul_ui(w + k, w + k - 1, (2 * k - 1) * (2 * k - 1), prec); acb_div_ui(w + k, w + k, 4 * k * k, prec); } return; } acb_init(t); acb_init(u); acb_init(msub1m); acb_init(m2sub1); acb_sub_ui(msub1m, m, 1, prec); acb_neg(t, msub1m); acb_sqrt(t, t, prec); acb_mul(msub1m, msub1m, m, prec); acb_mul_2exp_si(m2sub1, m, 1); acb_sub_ui(m2sub1, m2sub1, 1, prec); acb_agm1_cpx(w, t, 2, prec); /* pi M'(t) / (4 t M(t)^2) */ acb_mul(u, w, w, prec); acb_mul(t, t, u, prec); acb_div(w + 1, w + 1, t, prec); acb_const_pi(u, prec); acb_mul(w + 1, w + 1, u, prec); acb_mul_2exp_si(w + 1, w + 1, -2); /* pi / (2 M(t)) */ acb_const_pi(u, prec); acb_div(w, u, w, prec); acb_mul_2exp_si(w, w, -1); acb_inv(t, msub1m, prec); for (k = 2; k < len; k++) { n = k - 2; acb_mul_ui(w + k, w + n, (2 * n + 1) * (2 * n + 1), prec); acb_mul(u, w + n + 1, m2sub1, prec); acb_addmul_ui(w + k, u, (n + 1) * (n + 1) * 4, prec); acb_mul(w + k, w + k, t, prec); acb_div_ui(w + k, w + k, 4 * (n + 1) * (n + 2), prec); acb_neg(w + k, w + k); } acb_clear(t); acb_clear(u); acb_clear(msub1m); acb_clear(m2sub1); }
void _acb_poly_zeta_em_tail_naive(acb_ptr sum, const acb_t s, const acb_t Na, acb_srcptr Nasx, slong M, slong d, slong prec) { acb_ptr u, term; acb_t Na2, splus, rec; arb_t x; fmpz_t c; int aint; slong r; BERNOULLI_ENSURE_CACHED(2 * M); u = _acb_vec_init(d); term = _acb_vec_init(d); acb_init(splus); acb_init(rec); acb_init(Na2); arb_init(x); fmpz_init(c); _acb_vec_zero(sum, d); /* u = 1/2 * Nasx */ _acb_vec_scalar_mul_2exp_si(u, Nasx, d, -WORD(1)); /* term = u * (s+x) / (N+a) */ _acb_poly_mullow_cpx(u, u, d, s, d, prec); _acb_vec_scalar_div(term, u, d, Na, prec); /* (N+a)^2 or 1/(N+a)^2 */ acb_mul(Na2, Na, Na, prec); aint = acb_is_int(Na2); if (!aint) acb_inv(Na2, Na2, prec); for (r = 1; r <= M; r++) { /* flint_printf("sum 2: %wd %wd\n", r, M); */ /* sum += bernoulli number * term */ arb_set_round_fmpz(x, fmpq_numref(bernoulli_cache + 2 * r), prec); arb_div_fmpz(x, x, fmpq_denref(bernoulli_cache + 2 * r), prec); _acb_vec_scalar_mul_arb(u, term, d, x, prec); _acb_vec_add(sum, sum, u, d, prec); /* multiply term by ((s+x)+2r-1)((s+x)+2r) / ((N+a)^2 * (2*r+1)*(2*r+2)) */ acb_set(splus, s); arb_add_ui(acb_realref(splus), acb_realref(splus), 2*r-1, prec); _acb_poly_mullow_cpx(term, term, d, splus, d, prec); arb_add_ui(acb_realref(splus), acb_realref(splus), 1, prec); _acb_poly_mullow_cpx(term, term, d, splus, d, prec); /* TODO: combine with previous multiplication? */ if (aint) { arb_mul_ui(x, acb_realref(Na2), 2*r+1, prec); arb_mul_ui(x, x, 2*r+2, prec); _acb_vec_scalar_div_arb(term, term, d, x, prec); } else { fmpz_set_ui(c, 2*r+1); fmpz_mul_ui(c, c, 2*r+2); acb_div_fmpz(rec, Na2, c, prec); _acb_vec_scalar_mul(term, term, d, rec, prec); } } _acb_vec_clear(u, d); _acb_vec_clear(term, d); acb_clear(splus); acb_clear(rec); acb_clear(Na2); arb_clear(x); fmpz_clear(c); }
void acb_modular_transform(acb_t w, const psl2z_t g, const acb_t z, slong prec) { #define a (&g->a) #define b (&g->b) #define c (&g->c) #define d (&g->d) #define x acb_realref(z) #define y acb_imagref(z) if (fmpz_is_zero(c)) { /* (az+b)/d, where we must have a = d = 1 */ acb_add_fmpz(w, z, b, prec); } else if (fmpz_is_zero(a)) { /* b/(cz+d), where -bc = 1, c = 1 => -1/(z+d) */ acb_add_fmpz(w, z, d, prec); acb_inv(w, w, prec); acb_neg(w, w); } else if (0) { acb_t t, u; acb_init(t); acb_init(u); acb_set_fmpz(t, b); acb_addmul_fmpz(t, z, a, prec); acb_set_fmpz(u, d); acb_addmul_fmpz(u, z, c, prec); acb_div(w, t, u, prec); acb_clear(t); acb_clear(u); } else { /* (az+b)/(cz+d) = (re+im*i)/den where re = bd + (bc+ad)x + ac(x^2+y^2) im = (ad-bc)y den = c^2(x^2+y^2) + 2cdx + d^2 */ fmpz_t t; arb_t re, im, den; arb_init(re); arb_init(im); arb_init(den); fmpz_init(t); arb_mul(im, x, x, prec); arb_addmul(im, y, y, prec); fmpz_mul(t, b, d); arb_set_fmpz(re, t); fmpz_mul(t, b, c); fmpz_addmul(t, a, d); arb_addmul_fmpz(re, x, t, prec); fmpz_mul(t, a, c); arb_addmul_fmpz(re, im, t, prec); fmpz_mul(t, d, d); arb_set_fmpz(den, t); fmpz_mul(t, c, d); fmpz_mul_2exp(t, t, 1); arb_addmul_fmpz(den, x, t, prec); fmpz_mul(t, c, c); arb_addmul_fmpz(den, im, t, prec); fmpz_mul(t, a, d); fmpz_submul(t, b, c); arb_mul_fmpz(im, y, t, prec); arb_div(acb_realref(w), re, den, prec); arb_div(acb_imagref(w), im, den, prec); arb_clear(re); arb_clear(im); arb_clear(den); fmpz_clear(t); } #undef a #undef b #undef c #undef d #undef x #undef y }
void _acb_poly_inv_series(acb_ptr Qinv, acb_srcptr Q, slong Qlen, slong len, slong prec) { Qlen = FLINT_MIN(Qlen, len); acb_inv(Qinv, Q, prec); if (Qlen == 1) { _acb_vec_zero(Qinv + 1, len - 1); } else if (len == 2) { acb_mul(Qinv + 1, Qinv, Qinv, prec); acb_mul(Qinv + 1, Qinv + 1, Q + 1, prec); acb_neg(Qinv + 1, Qinv + 1); } else { slong i, blen; /* The basecase algorithm is faster for much larger Qlen or len than this, but unfortunately also much less numerically stable. */ if (Qlen == 2 || len <= 8) blen = len; else blen = FLINT_MIN(len, 4); for (i = 1; i < blen; i++) { acb_dot(Qinv + i, NULL, 1, Q + 1, 1, Qinv + i - 1, -1, FLINT_MIN(i, Qlen - 1), prec); if (!acb_is_one(Qinv)) acb_mul(Qinv + i, Qinv + i, Qinv, prec); } if (len > blen) { slong Qnlen, Wlen, W2len; acb_ptr W; W = _acb_vec_init(len); NEWTON_INIT(blen, len) NEWTON_LOOP(m, n) Qnlen = FLINT_MIN(Qlen, n); Wlen = FLINT_MIN(Qnlen + m - 1, n); W2len = Wlen - m; MULLOW(W, Q, Qnlen, Qinv, m, Wlen, prec); MULLOW(Qinv + m, Qinv, m, W + m, W2len, n - m, prec); _acb_vec_neg(Qinv + m, Qinv + m, n - m); NEWTON_END_LOOP NEWTON_END _acb_vec_clear(W, len); } } }