void acb_hypgeom_u(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) { acb_t t; acb_init(t); acb_sub(t, a, b, prec); acb_add_ui(t, t, 1, prec); if ((acb_is_int(a) && arf_sgn(arb_midref(acb_realref(a))) <= 0) || (acb_is_int(t) && arf_sgn(arb_midref(acb_realref(t))) <= 0) || acb_hypgeom_u_use_asymp(z, prec)) { acb_neg(t, a); acb_pow(t, z, t, prec); acb_hypgeom_u_asymp(res, a, b, z, -1, prec); acb_mul(res, res, t, prec); } else { acb_hypgeom_u_1f1(res, a, b, z, prec); } acb_clear(t); }
void acb_hypgeom_bessel_j_0f1(acb_t res, const acb_t nu, const acb_t z, long prec) { acb_struct b[2]; acb_t w, c, t; if (acb_is_int(nu) && arb_is_negative(acb_realref(nu))) { acb_init(t); acb_neg(t, nu); acb_hypgeom_bessel_j_0f1(res, t, z, prec); acb_mul_2exp_si(t, t, -1); if (!acb_is_int(t)) acb_neg(res, res); acb_clear(t); return; } acb_init(b + 0); acb_init(b + 1); acb_init(w); acb_init(c); acb_init(t); acb_add_ui(b + 0, nu, 1, prec); acb_one(b + 1); /* (z/2)^nu / gamma(nu+1) */ acb_mul_2exp_si(c, z, -1); acb_pow(c, c, nu, prec); acb_rgamma(t, b + 0, prec); acb_mul(c, t, c, prec); /* -z^2/4 */ acb_mul(w, z, z, prec); acb_mul_2exp_si(w, w, -2); acb_neg(w, w); acb_hypgeom_pfq_direct(t, NULL, 0, b, 2, w, -1, prec); acb_mul(res, t, c, prec); acb_clear(b + 0); acb_clear(b + 1); acb_clear(w); acb_clear(c); acb_clear(t); }
void acb_polygamma(acb_t res, const acb_t s, const acb_t z, long prec) { if (acb_is_zero(s)) { acb_digamma(res, z, prec); } else if (acb_is_int(s) && arb_is_positive(acb_realref(s))) { acb_t t, u; acb_init(t); acb_init(u); acb_add_ui(t, s, 1, prec); acb_gamma(u, t, prec); acb_hurwitz_zeta(t, t, z, prec); if (arf_is_int_2exp_si(arb_midref(acb_realref(s)), 1)) acb_neg(t, t); acb_mul(res, t, u, prec); acb_clear(t); acb_clear(u); } else { acb_t t, u; acb_struct v[2]; acb_init(t); acb_init(u); acb_init(v); acb_init(v + 1); /* u = psi(-s) + gamma */ acb_neg(t, s); acb_digamma(u, t, prec); arb_const_euler(acb_realref(v), prec); arb_add(acb_realref(u), acb_realref(u), acb_realref(v), prec); acb_add_ui(t, s, 1, prec); _acb_poly_zeta_cpx_series(v, t, z, 0, 2, prec); acb_addmul(v + 1, v, u, prec); acb_neg(t, s); acb_rgamma(u, t, prec); acb_mul(res, v + 1, u, prec); acb_clear(v); acb_clear(v + 1); acb_clear(t); acb_clear(u); } }
void acb_hypgeom_bessel_jy(acb_t res1, acb_t res2, const acb_t nu, const acb_t z, slong prec) { acb_t jnu, t, u, v; acb_init(jnu); acb_init(t); acb_init(u); acb_init(v); acb_hypgeom_bessel_j(jnu, nu, z, prec); if (acb_is_int(nu)) { int is_real = acb_is_real(nu) && acb_is_real(z) && arb_is_positive(acb_realref(z)); acb_mul_onei(t, z); acb_hypgeom_bessel_k(t, nu, t, prec); acb_onei(u); acb_pow(u, u, nu, prec); acb_mul(t, t, u, prec); acb_const_pi(u, prec); acb_div(t, t, u, prec); acb_mul_2exp_si(t, t, 1); acb_neg(t, t); phase(v, acb_realref(z), acb_imagref(z)); acb_mul(u, jnu, v, prec); acb_mul_onei(u, u); acb_sub(res2, t, u, prec); if (is_real) arb_zero(acb_imagref(res2)); } else { acb_sin_cos_pi(t, u, nu, prec); acb_mul(v, jnu, u, prec); acb_neg(u, nu); acb_hypgeom_bessel_j(u, u, z, prec); acb_sub(v, v, u, prec); acb_div(res2, v, t, prec); } if (res1 != NULL) acb_set(res1, jnu); acb_clear(jnu); acb_clear(t); acb_clear(u); acb_clear(v); }
void acb_hurwitz_zeta(acb_t z, const acb_t s, const acb_t a, slong prec) { if (acb_is_one(a) && acb_is_int(s) && arf_cmpabs_2exp_si(arb_midref(acb_realref(s)), FLINT_BITS - 1) < 0) { acb_zeta_si(z, arf_get_si(arb_midref(acb_realref(s)), ARF_RND_DOWN), prec); return; } _acb_poly_zeta_cpx_series(z, s, a, 0, 1, prec); }
void acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, slong prec) { if (arf_sgn(arb_midref(acb_realref(z))) >= 0 || (acb_is_int(a) && arb_is_nonpositive(acb_realref(a)))) { _acb_hypgeom_m_1f1(res, a, b, z, regularized, prec, prec, 0); } else { _acb_hypgeom_m_1f1(res, a, b, z, regularized, prec, prec, 1); } }
/* this can be improved */ static int use_recurrence(const acb_t n, const acb_t m, slong prec) { if (!acb_is_int(n) || !arb_is_nonnegative(acb_realref(n))) return 0; if (arf_cmpabs_ui(arb_midref(acb_realref(n)), prec) > 0) return 0; if (arf_cmpabs(arb_midref(acb_realref(n)), arb_midref(acb_realref(m))) >= 0) return 0; return 1; }
/* this can be improved */ static int use_recurrence(const acb_t n, const acb_t a, const acb_t b, slong prec) { if (!acb_is_int(n) || !arb_is_nonnegative(acb_realref(n))) return 0; if (arf_cmpabs_ui(arb_midref(acb_realref(n)), prec) > 0) return 0; if (arb_is_nonnegative(acb_realref(a)) || arf_get_d(arb_midref(acb_realref(a)), ARF_RND_DOWN) > -0.9) return 0; return 1; }
static void _acb_hypgeom_li_offset(acb_t res, const acb_t z, long prec) { if (acb_is_int(z) && arf_cmp_2exp_si(arb_midref(acb_realref(z)), 1) == 0) { acb_zero(res); } else { arb_t t; arb_init(t); _acb_hypgeom_const_li2(t, prec); _acb_hypgeom_li(res, z, prec); arb_sub(acb_realref(res), acb_realref(res), t, prec); arb_clear(t); } }
void acb_rising(acb_t y, const acb_t x, const acb_t n, long prec) { if (acb_is_int(n) && arf_sgn(arb_midref(acb_realref(n))) >= 0 && arf_cmpabs_ui(arb_midref(acb_realref(n)), FLINT_MAX(prec, 100)) < 0) { acb_rising_ui_rec(y, x, arf_get_si(arb_midref(acb_realref(n)), ARF_RND_DOWN), prec); } else { acb_t t; acb_init(t); acb_add(t, x, n, prec); acb_gamma(t, t, prec); acb_rgamma(y, x, prec); acb_mul(y, y, t, prec); acb_clear(t); } }
void acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) { acb_t t; if (regularized) { acb_init(t); acb_rgamma(t, b, prec); } if (arf_sgn(arb_midref(acb_realref(z))) >= 0 || (acb_is_int(a) && arb_is_nonpositive(acb_realref(a)))) { _acb_hypgeom_m_1f1(res, a, b, z, prec); } else { /* Kummer's transformation */ acb_t u, v; acb_init(u); acb_init(v); acb_sub(u, b, a, prec); acb_neg(v, z); _acb_hypgeom_m_1f1(u, u, b, v, prec); acb_exp(v, z, prec); acb_mul(res, u, v, prec); acb_clear(u); acb_clear(v); } if (regularized) { acb_mul(res, res, t, prec); acb_clear(t); } }
void acb_hypgeom_m_choose(int * asymp, int * kummer, slong * wp, const acb_t a, const acb_t b, const acb_t z, int regularized, slong prec) { double x, y, t, cancellation; double input_accuracy, direct_accuracy, asymp_accuracy; slong m = WORD_MAX; slong n = WORD_MAX; if (acb_is_int(a) && arf_cmpabs_2exp_si(arb_midref(acb_realref(a)), 30) < 0) { m = arf_get_si(arb_midref(acb_realref(a)), ARF_RND_DOWN); } if (acb_is_int(b) && arf_cmpabs_2exp_si(arb_midref(acb_realref(b)), 30) < 0) { n = arf_get_si(arb_midref(acb_realref(b)), ARF_RND_DOWN); } *asymp = 0; *kummer = 0; *wp = prec; /* The 1F1 series terminates. */ /* TODO: for large m, estimate extra precision here. */ if (m <= 0 && m < n && m > -10 * prec && (n > 0 || !regularized)) { *asymp = 0; return; } /* The 1F1 series terminates with the Kummer transform. */ /* TODO: for large m, estimate extra precision here. */ if (m >= 1 && n >= 1 && m < 0.1 * prec && n < 0.1 * prec && n <= m) { *asymp = 0; *kummer = 1; return; } input_accuracy = acb_rel_accuracy_bits(z); t = acb_rel_accuracy_bits(a); input_accuracy = FLINT_MIN(input_accuracy, t); t = acb_rel_accuracy_bits(b); input_accuracy = FLINT_MIN(input_accuracy, t); input_accuracy = FLINT_MAX(input_accuracy, 0.0); /* From here we ignore the values of a, b. Taking them into account is a possible future improvement... */ /* Tiny |z|. */ if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 2) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 2) < 0)) { *asymp = 0; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } /* Huge |z|. */ if ((arf_cmpabs_2exp_si(arb_midref(acb_realref(z)), 64) > 0 || arf_cmpabs_2exp_si(arb_midref(acb_imagref(z)), 64) > 0)) { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } x = arf_get_d(arb_midref(acb_realref(z)), ARF_RND_DOWN); y = arf_get_d(arb_midref(acb_imagref(z)), ARF_RND_DOWN); asymp_accuracy = sqrt(x * x + y * y) * 1.44269504088896 - 5.0; /* The Kummer transformation gives less cancellation with the 1F1 series. */ if (x < 0.0) { *kummer = 1; x = -x; } if (asymp_accuracy >= prec) { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); return; } cancellation = hypotmx(x, y) * 1.44269504088896; direct_accuracy = input_accuracy - cancellation; if (direct_accuracy > asymp_accuracy) { *asymp = 0; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec + cancellation)); } else { *asymp = 1; *wp = FLINT_MAX(2, FLINT_MIN(input_accuracy + 20, prec)); } }
void acb_hypgeom_u_1f1_series(acb_poly_t res, const acb_poly_t a, const acb_poly_t b, const acb_poly_t z, long len, long prec) { acb_poly_t s, u, A, B; acb_poly_struct aa[3]; arb_t c; long wlen; int singular; acb_poly_init(s); acb_poly_init(u); acb_poly_init(A); acb_poly_init(B); acb_poly_init(aa + 0); acb_poly_init(aa + 1); acb_poly_init(aa + 2); arb_init(c); singular = (b->length == 0) || acb_is_int(b->coeffs); wlen = len + (singular != 0); /* A = rgamma(a-b+1) * 1F~1(a,b,z) */ acb_poly_sub(u, a, b, prec); acb_poly_add_si(u, u, 1, prec); acb_poly_rgamma_series(A, u, wlen, prec); /* todo: handle a = 1 efficiently */ acb_poly_set(aa, a); acb_poly_set(aa + 1, b); acb_poly_one(aa + 2); acb_hypgeom_pfq_series_direct(s, aa, 1, aa + 1, 2, z, 1, -1, wlen, prec); acb_poly_mullow(A, A, s, wlen, prec); /* B = rgamma(a) * 1F~1(a-b+1,2-b,z) * z^(1-b) */ acb_poly_set(aa, u); acb_poly_add_si(aa + 1, b, -2, prec); acb_poly_neg(aa + 1, aa + 1); acb_hypgeom_pfq_series_direct(s, aa, 1, aa + 1, 2, z, 1, -1, wlen, prec); acb_poly_rgamma_series(B, a, wlen, prec); acb_poly_mullow(B, B, s, wlen, prec); acb_poly_add_si(u, b, -1, prec); acb_poly_neg(u, u); acb_poly_pow_series(s, z, u, wlen, prec); acb_poly_mullow(B, B, s, wlen, prec); acb_poly_sub(A, A, B, prec); /* multiply by pi csc(pi b) */ acb_poly_sin_pi_series(B, b, wlen, prec); if (singular) { acb_poly_shift_right(A, A, 1); acb_poly_shift_right(B, B, 1); } acb_poly_div_series(res, A, B, len, prec); arb_const_pi(c, prec); _acb_vec_scalar_mul_arb(res->coeffs, res->coeffs, res->length, c, prec); acb_poly_clear(s); acb_poly_clear(u); acb_poly_clear(A); acb_poly_clear(B); acb_poly_clear(aa + 0); acb_poly_clear(aa + 1); acb_poly_clear(aa + 2); arb_clear(c); }
void acb_hypgeom_bessel_i_asymp(acb_t res, const acb_t nu, const acb_t z, long prec) { acb_t A1, A2, C, U1, U2, s, t, u; int is_real, is_imag; acb_init(A1); acb_init(A2); acb_init(C); acb_init(U1); acb_init(U2); acb_init(s); acb_init(t); acb_init(u); is_imag = 0; is_real = acb_is_real(nu) && acb_is_real(z) && (acb_is_int(nu) || arb_is_positive(acb_realref(z))); if (!is_real && arb_is_zero(acb_realref(z)) && acb_is_int(nu)) { acb_mul_2exp_si(t, nu, -1); if (acb_is_int(t)) is_real = 1; else is_imag = 1; } acb_hypgeom_bessel_i_asymp_prefactors(A1, A2, C, nu, z, prec); /* todo: if Ap ~ 2^a and Am = 2^b and U1 ~ U2 ~ 1, change precision? */ if (!acb_is_finite(A1) || !acb_is_finite(A2) || !acb_is_finite(C)) { acb_indeterminate(res); } else { /* s = 1/2 + nu */ acb_one(s); acb_mul_2exp_si(s, s, -1); acb_add(s, s, nu, prec); /* t = 1 + 2 nu */ acb_mul_2exp_si(t, nu, 1); acb_add_ui(t, t, 1, prec); acb_mul_2exp_si(u, z, 1); acb_hypgeom_u_asymp(U1, s, t, u, -1, prec); acb_neg(u, u); acb_hypgeom_u_asymp(U2, s, t, u, -1, prec); acb_mul(res, A1, U1, prec); acb_addmul(res, A2, U2, prec); acb_mul(res, res, C, prec); if (is_real) arb_zero(acb_imagref(res)); if (is_imag) arb_zero(acb_realref(res)); } acb_clear(A1); acb_clear(A2); acb_clear(C); acb_clear(U1); acb_clear(U2); acb_clear(s); acb_clear(t); acb_clear(u); }
void acb_hypgeom_m(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, long prec) { long m = LONG_MAX; long n = LONG_MAX; if (acb_is_int(a) && arf_cmpabs_2exp_si(arb_midref(acb_realref(a)), 30) < 0) { m = arf_get_si(arb_midref(acb_realref(a)), ARF_RND_DOWN); } if (acb_is_int(b) && arf_cmpabs_2exp_si(arb_midref(acb_realref(b)), 30) < 0) { n = arf_get_si(arb_midref(acb_realref(b)), ARF_RND_DOWN); } /* terminating */ if (m <= 0 && m < n && m > -10 * prec && (n > 0 || !regularized)) { acb_hypgeom_m_1f1(res, a, b, z, regularized, prec); return; } /* large */ if (acb_hypgeom_u_use_asymp(z, prec)) { acb_hypgeom_m_asymp(res, a, b, z, regularized, prec); return; } /* remove singularity */ if (n <= 0 && n > -10 * prec && regularized) { acb_t c, d, t, u; acb_init(c); acb_init(d); acb_init(t); acb_init(u); acb_sub(c, a, b, prec); acb_add_ui(c, c, 1, prec); acb_neg(d, b); acb_add_ui(d, d, 2, prec); acb_hypgeom_m_1f1(t, c, d, z, 0, prec); acb_pow_ui(u, z, 1 - n, prec); acb_mul(t, t, u, prec); acb_rising_ui(u, a, 1 - n, prec); acb_mul(t, t, u, prec); arb_fac_ui(acb_realref(u), 1 - n, prec); acb_div_arb(res, t, acb_realref(u), prec); acb_clear(c); acb_clear(d); acb_clear(t); acb_clear(u); } else { acb_hypgeom_m_1f1(res, a, b, z, regularized, prec); } }
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); }
int main() { slong iter; flint_rand_t state; flint_printf("gamma_lower...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 2000 * arb_test_multiplier(); iter++) { acb_t a0, a1, b, z, w0, w1, t, u, enz; slong prec0, prec1; int regularized; acb_init(a0); acb_init(a1); acb_init(b); acb_init(z); acb_init(w0); acb_init(w1); acb_init(t); acb_init(u); acb_init(enz); regularized = n_randint(state, 3); prec0 = 2 + n_randint(state, 1000); prec1 = 2 + n_randint(state, 1000); acb_randtest_param(a0, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_randtest(z, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_randtest(w0, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_randtest(w1, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); acb_add_ui(a1, a0, 1, prec0); acb_hypgeom_gamma_lower(w0, a0, z, regularized, prec0); acb_hypgeom_gamma_lower(w1, a1, z, regularized, prec1); acb_neg(enz, z); acb_exp(enz, enz, prec0); /* recurrence relations */ if (regularized == 2) { /* gamma^{*}(a,z) - exp(-z)/Gamma(a+1) - z gamma^{*}(a+1,z) = 0 */ /* http://dlmf.nist.gov/8.8.E4 */ acb_set(t, w0); acb_rgamma(u, a1, prec0); acb_submul(t, enz, u, prec0); acb_submul(t, z, w1, prec0); } else if (regularized == 1) { /* P(a,z) - exp(-z) z^a / Gamma(a+1) - P(a+1,z) = 0 */ /* http://dlmf.nist.gov/8.8.E5 */ acb_pow(u, z, a0, prec0); acb_rgamma(b, a1, prec0); acb_mul(u, u, b, prec0); acb_sub(t, w0, w1, prec0); acb_submul(t, enz, u, prec0); } else { /* a gamma(a,z) - exp(-z) z^a - gamma(a+1,z) = 0 */ /* http://dlmf.nist.gov/8.8.E1 */ acb_pow(u, z, a0, prec0); acb_mul(t, a0, w0, prec0); acb_submul(t, enz, u, prec0); acb_sub(t, t, w1, prec0); } if (!acb_contains_zero(t)) { flint_printf("FAIL: recurrence relation\n\n"); flint_printf("regularized = %d\n\n", regularized); flint_printf("a0 = "); acb_printd(a0, 30); flint_printf("\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("w0 = "); acb_printd(w0, 30); flint_printf("\n\n"); flint_printf("w1 = "); acb_printd(w1, 30); flint_printf("\n\n"); flint_printf("t = "); acb_printd(t, 30); flint_printf("\n\n"); abort(); } /* identities relating lower and upper incomplete gamma functions */ if (regularized == 0 || regularized == 1) { acb_t u0; acb_init(u0); acb_hypgeom_gamma_upper(u0, a0, z, regularized, prec0); acb_zero(t); if (regularized == 1) { /* P(s,z) + Q(s,z) - 1 = 0 */ /* http://dlmf.nist.gov/8.2.E5 */ acb_add(t, w0, u0, prec0); acb_sub_ui(t, t, 1, prec0); } else { /* gamma(s,z) + Gamma(s,z) - Gamma(s) = 0 */ /* excludes non-positive integer values of s */ /* http://dlmf.nist.gov/8.2.E3 */ if (!acb_is_int(a0) || arb_is_positive(acb_realref(a0))) { acb_gamma(b, a0, prec0); acb_add(t, w0, u0, prec0); acb_sub(t, t, b, prec0); } } if (!acb_contains_zero(t)) { flint_printf("FAIL: lower plus upper\n\n"); flint_printf("regularized = %d\n\n", regularized); flint_printf("a0 = "); acb_printd(a0, 30); flint_printf("\n\n"); flint_printf("z = "); acb_printd(z, 30); flint_printf("\n\n"); flint_printf("w0 = "); acb_printd(w0, 30); flint_printf("\n\n"); flint_printf("w1 = "); acb_printd(w1, 30); flint_printf("\n\n"); flint_printf("t = "); acb_printd(t, 30); flint_printf("\n\n"); abort(); } acb_clear(u0); } acb_clear(a0); acb_clear(a1); acb_clear(b); acb_clear(z); acb_clear(w0); acb_clear(w1); acb_clear(t); acb_clear(u); acb_clear(enz); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }
void acb_hypgeom_bessel_k_0f1_series(acb_poly_t res, const acb_poly_t nu, const acb_poly_t z, slong len, slong prec) { acb_poly_t s, u, A, B; acb_poly_struct b[2]; arb_t c; slong wlen; int singular; acb_poly_init(s); acb_poly_init(u); acb_poly_init(A); acb_poly_init(B); acb_poly_init(b + 0); acb_poly_init(b + 1); arb_init(c); singular = (nu->length == 0) || acb_is_int(nu->coeffs); wlen = len + (singular != 0); /* A = (z/2)^nu, B = 1/A */ acb_poly_scalar_mul_2exp_si(A, z, -1); acb_poly_pow_series(A, A, nu, wlen, prec); acb_poly_inv_series(B, A, wlen, prec); acb_poly_mullow(u, z, z, wlen, prec); acb_poly_scalar_mul_2exp_si(u, u, -2); acb_poly_one(b + 1); acb_poly_add_si(b + 0, nu, 1, prec); acb_hypgeom_pfq_series_direct(s, NULL, 0, b, 2, u, 1, -1, wlen, prec); acb_poly_mullow(A, A, s, wlen, prec); acb_poly_add_si(b + 0, nu, -1, prec); acb_poly_neg(b + 0, b + 0); acb_hypgeom_pfq_series_direct(s, NULL, 0, b, 2, u, 1, -1, wlen, prec); acb_poly_mullow(B, B, s, wlen, prec); acb_poly_sub(A, B, A, prec); acb_poly_scalar_mul_2exp_si(A, A, -1); /* multiply by pi csc(pi nu) */ acb_poly_sin_pi_series(B, nu, wlen, prec); if (singular) { acb_poly_shift_right(A, A, 1); acb_poly_shift_right(B, B, 1); } acb_poly_div_series(res, A, B, len, prec); arb_const_pi(c, prec); _acb_vec_scalar_mul_arb(res->coeffs, res->coeffs, res->length, c, prec); acb_poly_clear(s); acb_poly_clear(u); acb_poly_clear(A); acb_poly_clear(B); acb_poly_clear(b + 0); acb_poly_clear(b + 1); arb_clear(c); }
void acb_hypgeom_chebyshev_t(acb_t res, const acb_t n, const acb_t z, slong prec) { acb_t t; if (acb_is_int(n) && arf_cmpabs_2exp_si(arb_midref(acb_realref(n)), FLINT_BITS - 1) < 0) { slong k = arf_get_si(arb_midref(acb_realref(n)), ARF_RND_DOWN); acb_chebyshev_t_ui(res, FLINT_ABS(k), z, prec); return; } if (acb_is_zero(z)) { acb_mul_2exp_si(res, n, -1); acb_cos_pi(res, res, prec); return; } if (acb_is_one(z)) { acb_one(res); return; } acb_init(t); acb_set_si(t, -1); if (acb_equal(t, z)) { acb_cos_pi(res, n, prec); } else { acb_sub_ui(t, z, 1, prec); if (arf_cmpabs_2exp_si(arb_midref(acb_realref(t)), -2 - prec / 10) < 0 && arf_cmpabs_2exp_si(arb_midref(acb_imagref(t)), -2 - prec / 10) < 0) { acb_t a, c; acb_init(a); acb_init(c); acb_neg(a, n); acb_one(c); acb_mul_2exp_si(c, c, -1); acb_neg(t, t); acb_mul_2exp_si(t, t, -1); acb_hypgeom_2f1(res, a, n, c, t, 0, prec); acb_clear(a); acb_clear(c); } else if (arb_is_nonnegative(acb_realref(t))) { acb_acosh(t, z, prec); acb_mul(t, t, n, prec); acb_cosh(res, t, prec); } else { acb_acos(t, z, prec); acb_mul(t, t, n, prec); acb_cos(res, t, prec); } } acb_clear(t); }
void acb_hypgeom_u_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, long prec) { if (acb_is_int(b)) { acb_poly_t aa, bb, zz; acb_poly_init(aa); acb_poly_init(bb); acb_poly_init(zz); acb_poly_set_acb(aa, a); acb_poly_set_coeff_acb(bb, 0, b); acb_poly_set_coeff_si(bb, 1, 1); acb_poly_set_acb(zz, z); acb_hypgeom_u_1f1_series(zz, aa, bb, zz, 1, prec); acb_poly_get_coeff_acb(res, zz, 0); acb_poly_clear(aa); acb_poly_clear(bb); acb_poly_clear(zz); } else { acb_t t, u, v; acb_struct aa[3]; acb_init(t); acb_init(u); acb_init(v); acb_init(aa + 0); acb_init(aa + 1); acb_init(aa + 2); acb_set(aa, a); acb_set(aa + 1, b); acb_one(aa + 2); acb_hypgeom_pfq_direct(u, aa, 1, aa + 1, 2, z, -1, prec); acb_sub(aa, a, b, prec); acb_add_ui(aa, aa, 1, prec); acb_sub_ui(aa + 1, b, 2, prec); acb_neg(aa + 1, aa + 1); acb_hypgeom_pfq_direct(v, aa, 1, aa + 1, 2, z, -1, prec); acb_sub_ui(aa + 1, b, 1, prec); /* rgamma(a-b+1) * gamma(1-b) * u */ acb_rgamma(t, aa, prec); acb_mul(u, u, t, prec); acb_neg(t, aa + 1); acb_gamma(t, t, prec); acb_mul(u, u, t, prec); /* rgamma(a) * gamma(b-1) * z^(1-b) * v */ acb_rgamma(t, a, prec); acb_mul(v, v, t, prec); acb_gamma(t, aa + 1, prec); acb_mul(v, v, t, prec); acb_neg(t, aa + 1); acb_pow(t, z, t, prec); acb_mul(v, v, t, prec); acb_add(res, u, v, prec); acb_clear(t); acb_clear(u); acb_clear(v); acb_clear(aa + 0); acb_clear(aa + 1); acb_clear(aa + 2); } }
void acb_hypgeom_2f1(acb_t res, const acb_t a, const acb_t b, const acb_t c, const acb_t z, int flags, slong prec) { int algorithm, regularized; regularized = flags & ACB_HYPGEOM_2F1_REGULARIZED; if (!acb_is_finite(a) || !acb_is_finite(b) || !acb_is_finite(c) || !acb_is_finite(z)) { acb_indeterminate(res); return; } if (acb_is_zero(z)) { if (regularized) acb_rgamma(res, c, prec); else acb_one(res); return; } if (regularized && acb_is_int(c) && arb_is_nonpositive(acb_realref(c))) { if ((acb_is_int(a) && arb_is_nonpositive(acb_realref(a)) && arf_cmp(arb_midref(acb_realref(a)), arb_midref(acb_realref(c))) >= 0) || (acb_is_int(b) && arb_is_nonpositive(acb_realref(b)) && arf_cmp(arb_midref(acb_realref(b)), arb_midref(acb_realref(c))) >= 0)) { acb_zero(res); return; } } if (regularized && acb_eq(a, c)) { _acb_hypgeom_2f1r_reduced(res, b, c, z, prec); return; } if (regularized && acb_eq(b, c)) { _acb_hypgeom_2f1r_reduced(res, a, c, z, prec); return; } /* polynomial */ if (acb_is_int(a) && arf_sgn(arb_midref(acb_realref(a))) <= 0 && arf_cmpabs_ui(arb_midref(acb_realref(a)), prec) < 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); return; } /* polynomial */ if (acb_is_int(b) && arf_sgn(arb_midref(acb_realref(b))) <= 0 && arf_cmpabs_ui(arb_midref(acb_realref(b)), prec) < 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); return; } /* Try to reduce to a polynomial case using the Pfaff transformation */ /* TODO: look at flags for integer c-b, c-a here, even when c is nonexact */ if (acb_is_exact(c)) { acb_t t; acb_init(t); acb_sub(t, c, b, prec); if (acb_is_int(t) && arb_is_nonpositive(acb_realref(t))) { acb_hypgeom_2f1_transform(res, a, b, c, z, flags, 1, prec); acb_clear(t); return; } acb_sub(t, c, a, prec); if (acb_is_int(t) && arb_is_nonpositive(acb_realref(t))) { int f1, f2; /* When swapping a, b, also swap the flags. */ f1 = flags & ACB_HYPGEOM_2F1_AC; f2 = flags & ACB_HYPGEOM_2F1_BC; flags &= ~ACB_HYPGEOM_2F1_AC; flags &= ~ACB_HYPGEOM_2F1_BC; if (f1) flags |= ACB_HYPGEOM_2F1_BC; if (f2) flags |= ACB_HYPGEOM_2F1_AC; acb_hypgeom_2f1_transform(res, b, a, c, z, flags, 1, prec); acb_clear(t); return; } acb_clear(t); } /* special value at z = 1 */ if (acb_is_one(z)) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); acb_sub(t, c, a, prec); acb_sub(u, c, b, prec); acb_sub(v, t, b, prec); if (arb_is_positive(acb_realref(v))) { acb_rgamma(t, t, prec); acb_rgamma(u, u, prec); acb_mul(t, t, u, prec); acb_gamma(v, v, prec); acb_mul(t, t, v, prec); if (!regularized) { acb_gamma(v, c, prec); acb_mul(t, t, v, prec); } acb_set(res, t); } else { acb_indeterminate(res); } acb_clear(t); acb_clear(u); acb_clear(v); return; } algorithm = acb_hypgeom_2f1_choose(z); if (algorithm == 0) { acb_hypgeom_2f1_direct(res, a, b, c, z, regularized, prec); } else if (algorithm >= 1 && algorithm <= 5) { acb_hypgeom_2f1_transform(res, a, b, c, z, flags, algorithm, prec); } else { acb_hypgeom_2f1_corner(res, a, b, c, z, regularized, prec); } }
void _acb_hypgeom_legendre_q_double(acb_t res, const acb_t n, const acb_t m, const acb_t z, slong prec) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); if (acb_is_int(m)) { acb_sub_ui(t, z, 1, prec); acb_mul_2exp_si(u, m, -1); acb_pow(v, t, u, prec); acb_neg(t, t); acb_neg(u, u); acb_pow(t, t, u, prec); acb_mul(t, t, v, prec); acb_hypgeom_legendre_q(u, n, m, z, 0, prec); acb_mul(t, t, u, prec); acb_mul_2exp_si(u, m, -1); if (!acb_is_int(u)) acb_neg(t, t); acb_sub_ui(u, z, 1, prec); acb_sqrt(u, u, prec); acb_sub_ui(v, z, 1, prec); acb_neg(v, v); acb_rsqrt(v, v, prec); acb_mul(u, u, v, prec); acb_hypgeom_legendre_p(v, n, m, z, 1, prec); acb_mul(u, u, v, prec); acb_const_pi(v, prec); acb_mul(u, u, v, prec); acb_mul_2exp_si(u, u, -1); acb_sub(res, t, u, prec); } else { acb_sub(t, n, m, prec); acb_add_ui(t, t, 1, prec); acb_mul_2exp_si(u, m, 1); acb_rising(t, t, u, prec); acb_neg(u, m); acb_hypgeom_legendre_p(u, n, u, z, 1, prec); acb_mul(t, t, u, prec); acb_hypgeom_legendre_p(u, n, m, z, 1, prec); acb_sub(t, u, t, prec); acb_exp_pi_i(u, m, prec); acb_mul(t, t, u, prec); acb_sin_pi(u, m, prec); acb_div(t, t, u, prec); acb_const_pi(u, prec); acb_mul(t, t, u, prec); acb_mul_2exp_si(t, t, -1); acb_set(res, t); } acb_clear(t); acb_clear(u); acb_clear(v); }
static int acb_is_nonpositive_int(const acb_t x) { return acb_is_int(x) && arf_sgn(arb_midref(acb_realref(x))) <= 0; }
void acb_hypgeom_2f1_transform(acb_t res, const acb_t a, const acb_t b, const acb_t c, const acb_t z, int flags, int which, slong prec) { int regularized; regularized = flags & ACB_HYPGEOM_2F1_REGULARIZED; if (which == 1) { acb_t t, u, v; acb_init(t); acb_init(u); acb_init(v); acb_sub_ui(t, z, 1, prec); /* t = z-1 */ acb_div(u, z, t, prec); /* u = z/(z-1) */ acb_neg(t, t); acb_neg(v, a); acb_pow(t, t, v, prec); /* t = (1-z)^-a */ acb_sub(v, c, b, prec); /* v = c-b */ /* We cannot use regularized=1 directly, since if c is a nonnegative integer, the transformation formula reads (lhs) * 0 = (rhs) * 0. */ acb_hypgeom_2f1_direct(u, a, v, c, u, 1, prec); if (!regularized) { acb_gamma(v, c, prec); acb_mul(u, u, v, prec); } acb_mul(res, u, t, prec); acb_clear(t); acb_clear(u); acb_clear(v); } else { acb_t d; int limit; acb_init(d); if (which == 2 || which == 3) { if (flags & ACB_HYPGEOM_2F1_AB) { limit = 1; } else { acb_sub(d, b, a, prec); limit = acb_is_int(d); } } else { if (flags & ACB_HYPGEOM_2F1_ABC) { limit = 1; } else { acb_sub(d, c, a, prec); acb_sub(d, d, b, prec); limit = acb_is_int(d); } } if (limit) acb_hypgeom_2f1_transform_limit(res, a, b, c, z, regularized, which, prec); else acb_hypgeom_2f1_transform_nolimit(res, a, b, c, z, regularized, which, prec); acb_clear(d); } if (!acb_is_finite(res)) acb_indeterminate(res); }
void acb_hypgeom_bessel_k_0f1(acb_t res, const acb_t nu, const acb_t z, slong prec) { if (acb_is_int(nu)) { acb_poly_t nux, zx, rx; acb_poly_init(nux); acb_poly_init(zx); acb_poly_init(rx); acb_poly_set_coeff_acb(nux, 0, nu); acb_poly_set_coeff_si(nux, 1, 1); acb_poly_set_acb(zx, z); acb_hypgeom_bessel_k_0f1_series(rx, nux, zx, 1, prec); acb_poly_get_coeff_acb(res, rx, 0); acb_poly_clear(nux); acb_poly_clear(zx); acb_poly_clear(rx); } else { acb_t t, u, v, w; acb_struct b[2]; acb_init(t); acb_init(u); acb_init(v); acb_init(w); acb_init(b + 0); acb_init(b + 1); /* u = 0F1(1+nu), v = 0F1(1-nu) */ acb_mul(t, z, z, prec); acb_mul_2exp_si(t, t, -2); acb_add_ui(b, nu, 1, prec); acb_one(b + 1); acb_hypgeom_pfq_direct(u, NULL, 0, b, 2, t, -1, prec); acb_sub_ui(b, nu, 1, prec); acb_neg(b, b); acb_hypgeom_pfq_direct(v, NULL, 0, b, 2, t, -1, prec); /* v = v * gamma(nu) / (z/2)^nu */ acb_mul_2exp_si(t, z, -1); acb_pow(t, t, nu, prec); acb_gamma(w, nu, prec); acb_mul(v, v, w, prec); acb_div(v, v, t, prec); /* u = u * t * pi / (gamma(nu) * nu * sin(pi nu)) */ acb_mul(u, u, t, prec); acb_const_pi(t, prec); acb_mul(u, u, t, prec); acb_sin_pi(t, nu, prec); acb_mul(t, t, w, prec); acb_mul(t, t, nu, prec); acb_div(u, u, t, prec); acb_sub(res, v, u, prec); acb_mul_2exp_si(res, res, -1); acb_clear(t); acb_clear(u); acb_clear(v); acb_clear(w); acb_clear(b + 0); acb_clear(b + 1); } }
void _acb_hypgeom_m_1f1(acb_t res, const acb_t a, const acb_t b, const acb_t z, int regularized, slong prec, slong gamma_prec, int kummer) { if (regularized) { /* Remove singularity */ if (acb_is_int(b) && arb_is_nonpositive(acb_realref(b)) && arf_cmpabs_2exp_si(arb_midref(acb_realref(b)), 30) < 0) { acb_t c, d, t, u; slong n; n = arf_get_si(arb_midref(acb_realref(b)), ARF_RND_DOWN); acb_init(c); acb_init(d); acb_init(t); acb_init(u); acb_sub(c, a, b, prec); acb_add_ui(c, c, 1, prec); acb_neg(d, b); acb_add_ui(d, d, 2, prec); _acb_hypgeom_m_1f1(t, c, d, z, 0, prec, gamma_prec, kummer); acb_pow_ui(u, z, 1 - n, prec); acb_mul(t, t, u, prec); acb_rising_ui(u, a, 1 - n, prec); acb_mul(t, t, u, prec); arb_fac_ui(acb_realref(u), 1 - n, prec); acb_div_arb(res, t, acb_realref(u), prec); acb_clear(c); acb_clear(d); acb_clear(t); acb_clear(u); } else { acb_t t; acb_init(t); acb_rgamma(t, b, gamma_prec); _acb_hypgeom_m_1f1(res, a, b, z, 0, prec, gamma_prec, kummer); acb_mul(res, res, t, prec); acb_clear(t); } return; } /* Kummer's transformation */ if (kummer) { acb_t u, v; acb_init(u); acb_init(v); acb_sub(u, b, a, prec); acb_neg(v, z); _acb_hypgeom_m_1f1(u, u, b, v, regularized, prec, gamma_prec, 0); acb_exp(v, z, prec); acb_mul(res, u, v, prec); acb_clear(u); acb_clear(v); return; } if (acb_is_one(a)) { acb_hypgeom_pfq_direct(res, NULL, 0, b, 1, z, -1, prec); } else { acb_struct c[3]; c[0] = *a; c[1] = *b; acb_init(c + 2); acb_one(c + 2); acb_hypgeom_pfq_direct(res, c, 1, c + 1, 2, z, -1, prec); acb_clear(c + 2); } }
/* todo: use euler product for complex s, and check efficiency for large negative integers */ void acb_dirichlet_zeta(acb_t res, const acb_t s, slong prec) { acb_t a; double cutoff; if (acb_is_int(s) && arf_cmpabs_2exp_si(arb_midref(acb_realref(s)), FLINT_BITS - 1) < 0) { acb_zeta_si(res, arf_get_si(arb_midref(acb_realref(s)), ARF_RND_DOWN), prec); return; } cutoff = 24.0 * prec * sqrt(prec); if (arf_cmpabs_d(arb_midref(acb_imagref(s)), cutoff) >= 0 && arf_cmpabs_d(arb_midref(acb_realref(s)), 10 + prec * 0.1) <= 0) { acb_dirichlet_zeta_rs(res, s, 0, prec); return; } acb_init(a); acb_one(a); if (arf_sgn(arb_midref(acb_realref(s))) < 0) { acb_t t, u, v; slong wp = prec + 6; acb_init(t); acb_init(u); acb_init(v); acb_sub_ui(t, s, 1, wp); /* 2 * (2pi)^(s-1) */ arb_const_pi(acb_realref(u), wp); acb_mul_2exp_si(u, u, 1); acb_pow(u, u, t, wp); acb_mul_2exp_si(u, u, 1); /* sin(pi*s/2) */ acb_mul_2exp_si(v, s, -1); acb_sin_pi(v, v, wp); acb_mul(u, u, v, wp); /* gamma(1-s) zeta(1-s) */ acb_neg(t, t); acb_gamma(v, t, wp); acb_mul(u, u, v, wp); acb_hurwitz_zeta(v, t, a, wp); acb_mul(res, u, v, prec); acb_clear(t); acb_clear(u); acb_clear(v); } else { acb_hurwitz_zeta(res, s, a, prec); } acb_clear(a); }
void acb_hypgeom_pfq_series_direct(acb_poly_t res, const acb_poly_struct * a, long p, const acb_poly_struct * b, long q, const acb_poly_t z, int regularized, long n, long len, long prec) { acb_poly_t s, t, err; arb_poly_t C, T; long i; int is_real; int terminating; /* default algorithm to choose number of terms */ if (n < 0) { n = acb_hypgeom_pfq_series_choose_n(a, p, b, q, z, len, prec); } terminating = 0; /* check if it terminates due to a root of the numerator */ for (i = 0; i < p; i++) { if (acb_poly_length(a + i) == 0 && n > 0) { terminating = 1; } else if (acb_poly_length(a + i) == 1) { acb_srcptr c = acb_poly_get_coeff_ptr(a + i, 0); if (acb_is_int(c) && arb_is_negative(acb_realref(c)) && arf_cmpabs_ui(arb_midref(acb_realref(c)), n) < 0) { terminating = 1; } } } /* check if it terminates (to order n) due to z */ /* the following tests could be made stronger... */ if (z->length == 0 && n >= 1) { terminating = 1; } else if (!terminating && z->length > 0 && acb_is_zero(z->coeffs) && n >= len) { if (regularized) { terminating = 1; } else { terminating = 1; for (i = 0; i < q; i++) { acb_srcptr c = acb_poly_get_coeff_ptr(b + i, 0); if (!arb_is_positive(acb_realref(c)) && acb_contains_int(c)) terminating = 0; } } } acb_poly_init(s); acb_poly_init(t); acb_poly_init(err); arb_poly_init(C); arb_poly_init(T); acb_hypgeom_pfq_series_sum_forward(s, t, a, p, b, q, z, regularized, n, len, prec); if (!terminating) { is_real = acb_poly_is_real(z); for (i = 0; i < p; i++) is_real = is_real && acb_poly_is_real(a + i); for (i = 0; i < q; i++) is_real = is_real && acb_poly_is_real(b + i); acb_poly_majorant(T, t, MAG_BITS); acb_hypgeom_pfq_series_bound_factor(C, a, p, b, q, z, n, len, MAG_BITS); if (!_arb_vec_is_finite(T->coeffs, T->length) || !_arb_vec_is_finite(C->coeffs, C->length)) { arb_poly_fit_length(T, len); _arb_vec_indeterminate(T->coeffs, len); _arb_poly_set_length(T, len); } else { arb_poly_mullow(T, T, C, len, MAG_BITS); } /* create polynomial of errors */ acb_poly_fit_length(err, len); for (i = 0; i < FLINT_MIN(len, T->length); i++) { arb_add_error(acb_realref(err->coeffs + i), T->coeffs + i); if (!is_real) arb_add_error(acb_imagref(err->coeffs + i), T->coeffs + i); } _acb_poly_set_length(err, len); _acb_poly_normalise(err); acb_poly_add(s, s, err, prec); } acb_poly_set(res, s); acb_poly_clear(s); acb_poly_clear(t); acb_poly_clear(err); arb_poly_clear(C); arb_poly_clear(T); }