/* Copyright (C) 2017, 2020 Fredrik Johansson This file is part of Arb. Arb is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "acb_elliptic.h" #include "acb_calc.h" static const unsigned short den_ratio_tab[512] = { 1,1,14,3,44,13,10,17,152,1,46,1,12,29,62,1, 16,37,2,41,172,1,94,7,8,53,2,1,236,61,2,1, 2144,1,142,73,20,1,158,3,664,1,2,89,4,1,2,97, 16,101,206,1,428,109,2,113,8,1,2,11,4,1,254,1, 8384,1,2,137,556,1,2,1,8,149,302,1,4,157,2,1, 2608,1,334,13,4,173,2,1,1432,181,2,1,4,1,382,193, 32,197,398,1,4,1,2,1,1688,1,2,1,4,1,446,1, 3632,229,2,233,4,1,478,241,24,1,2,1,1004,1,2,257, 128,1,526,1,4,269,542,1,8,277,2,281,1132,1,2,17, 16,293,2,1,4,1,2,1,2456,1,622,313,4,317,2,1, 32,1,2,1,1324,1,2,337,8,1,14,1,1388,349,2,353, 16,1,718,19,4,1,734,1,8,373,10,1,1516,1,766,1, 64,389,2,1,4,397,2,401,8,1,2,409,4,1,2,1, 6704,421,2,1,4,1,862,433,8,1,878,1,1772,1,2,449, 32,1,2,457,4,461,926,1,3736,1,2,1,4,1,958,1, 16,1,974,1,1964,1,2,1,3992,1,1006,1,4,509,2,1, 256,1,2,521,2092,1,2,23,8,1,2,1,4,541,2,1, 8752,1,2,1,4,557,2,1,4504,1,2,569,2284,1,2,577, 32,1,2,1,2348,1,2,593,8,1,1198,601,4,1,1214,1, 16,613,2,617,2476,1,2,1,8,1,1262,1,4,1,2,641, 41152,1,1294,1,4,653,2,1,5272,661,2,1,4,1,2,673, 16,677,2,1,2732,1,2,1,5528,1,2,1,4,701,2,1, 32,709,2,1,4,1,1438,1,8,1,1454,3,4,733,2,1, 11824,1,1486,1,4,1,1502,1,8,757,2,761,4,1,2,769, 128,773,2,1,4,1,2,1,6296,1,2,1,4,797,2,1, 16,1,2,809,3244,1,2,1,8,821,1646,1,3308,829,2,1, 32,1,1678,29,4,1,2,1,8,853,2,857,3436,1,1726,1, 16,1,2,1,4,877,2,881,7064,1,1774,1,4,1,2,1, 64,1,2,1,3628,1,1822,1,8,1,1838,1,4,1,2,929, 16,1,2,937,4,941,2,1,7576,1,2,953,4,1,2,31, 32,1,1934,1,3884,1,2,977,8,1,1966,1,4,1,1982,1, 16,997,2,1,4,1,2,1009,8,1013,2,1,4076,1021,2,1 }; static __inline__ slong rj_fdiv(slong x, slong y) { if (x < 0) return -1; else return x / y; } void acb_elliptic_rj_taylor_sum(acb_t res, const acb_t E2, const acb_t E3, const acb_t E4, const acb_t E5, slong nterms, slong prec) { slong m2, m3, m4, m5, m2start, m3start, m4start, m5start, NMAX, N, M; slong m2dim, m3dim; acb_t s2, s3, s4, s5; acb_ptr powtab; fmpz_t c2, c3, c4, c5, den, t; acb_init(s2); acb_init(s3); acb_init(s4); acb_init(s5); fmpz_init(c2); fmpz_init(c3); fmpz_init(c4); fmpz_init(c5); fmpz_init(den); fmpz_init(t); NMAX = nterms - 1; m2dim = NMAX / 2 + 1; m3dim = NMAX / 3 + 1; powtab = _acb_vec_init(m2dim * m3dim); /* Compute universal denominator */ fmpz_one(den); for (N = 1; N <= NMAX; N++) fmpz_mul_ui(den, den, den_ratio_tab[N]); /* Precompute powers of E2 and E3 */ for (m2 = 0; m2 <= NMAX / 2; m2++) { for (m3 = 0; m3 <= rj_fdiv(NMAX - 2 * m2, 3); m3++) { slong i, j, k; i = m3 * m2dim + m2; if (m2 <= 1 && m3 <= 1) { if (m2 == 0 && m3 == 0) acb_one(powtab + i); else if (m2 == 0 && m3 == 1) acb_set(powtab + i, E3); else if (m2 == 1 && m3 == 0) acb_set(powtab + i, E2); else acb_mul(powtab + i, E2, E3, prec); } else { j = (m3 / 2) * m2dim + (m2 / 2); k = (m3 - (m3 / 2)) * m2dim + (m2 - (m2 / 2)); acb_mul(powtab + i, powtab + j, powtab + k, prec); } } } acb_zero(s5); m5start = NMAX / 5; fmpz_mul_ui(c5, den, 3); for (m5 = 0; m5 < m5start; m5++) { fmpz_mul_ui(c5, c5, 2 * m5 + 1); fmpz_divexact_ui(c5, c5, 2 * m5 + 2); } for (m5 = m5start; m5 >= 0; m5--) { acb_zero(s4); m4start = rj_fdiv(NMAX - 5 * m5, 4); if (m5 != m5start) { fmpz_mul_ui(c5, c5, 2 * m5 + 2); fmpz_divexact_ui(c5, c5, 2 * m5 + 1); } fmpz_set(c4, c5); for (m4 = 0; m4 < m4start; m4++) { fmpz_mul_ui(c4, c4, 2 * m5 + 2 * m4 + 1); fmpz_divexact_ui(c4, c4, 2 * m4 + 2); } for (m4 = m4start; m4 >= 0; m4--) { acb_zero(s3); m3start = rj_fdiv(NMAX - 5 * m5 - 4 * m4, 3); if (m4 != m4start) { fmpz_mul_ui(c4, c4, 2 * m4 + 2); fmpz_divexact_ui(c4, c4, 2 * m5 + 2 * m4 + 1); } fmpz_set(c3, c4); for (m3 = 0; m3 <= m3start; m3++) { m2start = rj_fdiv(NMAX - 5 * m5 - 4 * m4 - 3 * m3, 2); fmpz_set(c2, c3); for (m2 = 0; m2 <= m2start; m2++) { M = m5 + m4 + m3 + m2; N = 5 * m5 + 4 * m4 + 3 * m3 + 2 * m2; if (N > NMAX) flint_abort(); fmpz_divexact_ui(t, c2, 2 * N + 3); if ((M + N) % 2) fmpz_neg(t, t); acb_addmul_fmpz(s3, powtab + m3 * m2dim + m2, t, prec); if (m2 < m2start) { fmpz_mul_ui(c2, c2, 2 * m5 + 2 * m4 + 2 * m3 + 2 * m2 + 1); fmpz_divexact_ui(c2, c2, 2 * m2 + 2); } } if (m3 < m3start) { fmpz_mul_ui(c3, c3, 2 * m5 + 2 * m4 + 2 * m3 + 1); fmpz_divexact_ui(c3, c3, 2 * m3 + 2); } } /* Horner with respect to E4. */ acb_mul(s4, s4, E4, prec); acb_add(s4, s4, s3, prec); } /* Horner with respect to E5. */ acb_mul(s5, s5, E5, prec); acb_add(s5, s5, s4, prec); } acb_div_fmpz(res, s5, den, prec); _acb_vec_clear(powtab, m2dim * m3dim); acb_clear(s2); acb_clear(s3); acb_clear(s4); acb_clear(s5); fmpz_clear(c2); fmpz_clear(c3); fmpz_clear(c4); fmpz_clear(c5); fmpz_clear(den); fmpz_clear(t); } void acb_elliptic_rj_carlson(acb_t res, const acb_t x, const acb_t y, const acb_t z, const acb_t p, int flags, slong prec) { acb_t xx, yy, zz, pp, sx, sy, sz, sp, t, d, delta, S; acb_t A, AA, X, Y, Z, P, E2, E3, E4, E5; mag_t err, err2, prev_err; slong k, wp, accx, accy, accz, accp, order; int rd, real; /* printf("RJ carlson "); acb_printn(x, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(y, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(z, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(p, 6, ARB_STR_NO_RADIUS); printf(" "); printf("\n"); */ if (!acb_is_finite(x) || !acb_is_finite(y) || !acb_is_finite(z) || !acb_is_finite(p)) { acb_indeterminate(res); return; } if ((acb_contains_zero(x) + acb_contains_zero(y) + acb_contains_zero(z) > 1) || acb_contains_zero(p)) { acb_indeterminate(res); return; } /* Special case computing R_D(x,y,z) */ rd = (z == p) || acb_eq(z, p); acb_init(xx); acb_init(yy); acb_init(zz); acb_init(pp); acb_init(sx); acb_init(sy); acb_init(sz); acb_init(sp); acb_init(S); acb_init(A); acb_init(AA); acb_init(X); acb_init(Y); acb_init(Z); acb_init(P); acb_init(E2); acb_init(E3); acb_init(E4); acb_init(E5); acb_init(t); acb_init(d); acb_init(delta); mag_init(err); mag_init(err2); mag_init(prev_err); acb_set(xx, x); acb_set(yy, y); acb_set(zz, z); acb_set(pp, p); acb_zero(S); real = acb_is_real(x) && acb_is_real(y) && acb_is_real(z) && acb_is_real(p) && arb_is_nonnegative(acb_realref(x)) && arb_is_nonnegative(acb_realref(y)) && arb_is_nonnegative(acb_realref(z)) && arb_is_nonnegative(acb_realref(p)); order = 5; /* will be set later */ /* First guess precision based on the inputs. */ /* This does not account for mixing. */ accx = acb_rel_accuracy_bits(xx); accy = acb_rel_accuracy_bits(yy); accz = acb_rel_accuracy_bits(zz); accp = acb_rel_accuracy_bits(pp); accx = FLINT_MAX(accx, accy); accx = FLINT_MAX(accx, accz); accx = FLINT_MAX(accx, accp); if (accx < prec - 20) prec = FLINT_MAX(2, accx + 20); wp = prec + 4 + FLINT_BIT_COUNT(prec); if (!rd) { acb_mul_2exp_si(A, p, 1); acb_add(A, A, z, wp); } else { acb_mul_ui(A, z, 3, wp); } acb_add(A, A, x, wp); acb_add(A, A, y, wp); acb_div_ui(A, A, 5, wp); acb_set(AA, A); if (!rd) { acb_sub(delta, p, x, wp); acb_sub(t, p, y, wp); acb_mul(delta, delta, t, wp); acb_sub(t, p, z, wp); acb_mul(delta, delta, t, wp); } /* must do at least one iteration */ for (k = 0; k < prec; k++) { acb_sqrt(sx, xx, wp); acb_sqrt(sy, yy, wp); acb_sqrt(sz, zz, wp); if (!rd) acb_sqrt(sp, pp, wp); acb_add(t, sy, sz, wp); acb_mul(t, t, sx, wp); acb_addmul(t, sy, sz, wp); acb_add(xx, xx, t, wp); acb_add(yy, yy, t, wp); acb_add(zz, zz, t, wp); if (!rd) acb_add(pp, pp, t, wp); acb_add(AA, AA, t, wp); acb_mul_2exp_si(xx, xx, -2); acb_mul_2exp_si(yy, yy, -2); acb_mul_2exp_si(zz, zz, -2); if (!rd) acb_mul_2exp_si(pp, pp, -2); acb_mul_2exp_si(AA, AA, -2); if (!rd) { /* d = (sp+sx)(sp+sy)(sp+sz) */ /* e = 4^(-3k) delta / d^2 */ /* S += 4^(-k) RC(1, 1+e) / d */ acb_add(d, sp, sx, wp); acb_add(t, sp, sy, wp); acb_mul(d, d, t, wp); acb_add(t, sp, sz, wp); acb_mul(d, d, t, wp); /* E2 = e */ acb_mul(E2, d, d, wp); acb_div(E2, delta, E2, wp); acb_mul_2exp_si(E2, E2, -6 * k); acb_elliptic_rc1(E4, E2, wp); acb_div(E4, E4, d, wp); acb_mul_2exp_si(E4, E4, -2 * k); acb_add(S, S, E4, wp); } else { acb_mul(t, sz, zz, wp); acb_mul_2exp_si(t, t, 2); acb_inv(t, t, wp); acb_mul_2exp_si(t, t, -2 * k); acb_mul_2exp_si(t, t, -1); acb_add(S, S, t, wp); } /* Improve precision estimate and set expansion order. */ /* Should this done for other k also? */ if (k == 0) { accx = acb_rel_accuracy_bits(xx); accy = acb_rel_accuracy_bits(yy); accz = acb_rel_accuracy_bits(zz); accp = acb_rel_accuracy_bits(pp); accx = FLINT_MAX(accx, accy); accx = FLINT_MAX(accx, accz); accx = FLINT_MAX(accx, accp); if (accx < prec - 20) prec = FLINT_MAX(2, accx + 20); wp = prec + 4 + FLINT_BIT_COUNT(prec); if (!rd) if (real) order = 2.3 * pow(prec, 0.34); else order = 2.5 * pow(prec, 0.35); else if (real) order = 2.0 * pow(prec, 0.33); else order = 2.2 * pow(prec, 0.33); order = FLINT_MIN(order, 500); order = FLINT_MAX(order, 5); } /* Close enough? */ acb_sub(t, xx, yy, wp); acb_get_mag(err, t); acb_sub(t, xx, zz, wp); acb_get_mag(err2, t); mag_max(err, err, err2); if (!rd) { acb_sub(t, xx, pp, wp); acb_get_mag(err2, t); mag_max(err, err, err2); } acb_get_mag_lower(err2, xx); mag_div(err, err, err2); mag_pow_ui(err, err, order); if (mag_cmp_2exp_si(err, -prec) < 0 || (k > 2 && mag_cmp(err, prev_err) > 0)) { k++; break; } mag_set(prev_err, err); } /* X = (A-x)/(4^k AA) */ /* Y = (A-y)/(4^k AA) */ /* Z = (A-z)/(4^k AA) */ /* P = (-X-Y-Z)/2 */ acb_mul_2exp_si(t, AA, 2 * k); acb_inv(t, t, prec); acb_sub(X, A, x, prec); acb_mul(X, X, t, prec); acb_sub(Y, A, y, prec); acb_mul(Y, Y, t, prec); acb_sub(Z, A, z, prec); acb_mul(Z, Z, t, prec); acb_add(P, X, Y, prec); acb_add(P, P, Z, prec); acb_neg(P, P); acb_mul_2exp_si(P, P, -1); /* todo: improve for R_D */ /* E2 = XY + XZ + YZ - 3 P^2 */ /* E3 = XYZ + 2 E2 P + 4 P^3 */ /* E4 = (2 XYZ + E2 P + 3 P^3) P */ /* E5 = XYZP^2 */ acb_mul(t, P, P, prec); /* t = P^2 */ acb_mul(E2, X, Y, prec); acb_mul(E3, E2, Z, prec); acb_mul_2exp_si(E4, E3, 1); acb_mul(E5, E3, t, prec); acb_add(sx, X, Y, prec); acb_addmul(E2, sx, Z, prec); acb_submul_ui(E2, t, 3, prec); acb_mul(sx, E2, P, prec); acb_add(E4, E4, sx, prec); acb_mul_2exp_si(sx, sx, 1); acb_add(E3, E3, sx, prec); acb_mul(t, t, P, prec); /* t = P^3 */ acb_addmul_ui(E3, t, 4, prec); acb_addmul_ui(E4, t, 3, prec); acb_mul(E4, E4, P, prec); /* Error bound. */ acb_get_mag(err, X); acb_get_mag(err2, Y); mag_max(err, err, err2); acb_get_mag(err2, Z); mag_max(err, err, err2); acb_get_mag(err2, P); mag_max(err, err, err2); mag_mul_ui(err, err, 9); mag_mul_2exp_si(err, err, -3); mag_geom_series(err, err, order); mag_mul_2exp_si(err, err, 1); acb_elliptic_rj_taylor_sum(sx, E2, E3, E4, E5, order, wp); if (acb_is_real(X) && acb_is_real(Y) && acb_is_real(Z)) arb_add_error_mag(acb_realref(sx), err); else acb_add_error_mag(sx, err); acb_rsqrt(t, AA, wp); acb_div(t, t, AA, wp); acb_mul_2exp_si(t, t, -2 * k); acb_mul(t, t, sx, wp); acb_addmul_ui(t, S, 6, prec); acb_set(res, t); acb_clear(xx); acb_clear(yy); acb_clear(zz); acb_clear(pp); acb_clear(sx); acb_clear(sy); acb_clear(sz); acb_clear(sp); acb_clear(S); acb_clear(A); acb_clear(AA); acb_clear(X); acb_clear(Y); acb_clear(Z); acb_clear(P); acb_clear(E2); acb_clear(E3); acb_clear(E4); acb_clear(E5); acb_clear(t); acb_clear(d); acb_clear(delta); mag_clear(err); mag_clear(err2); mag_clear(prev_err); } static int acb_eq_conj(const acb_t x, const acb_t y) { int res; acb_t t; acb_init(t); acb_conj(t, y); res = acb_eq(x, t); acb_clear(t); return res; } /* todo: speed up this function -- early abort -- only compute single rsqrt or sqrt when evaluating precisely (but need to make sure branch is correct!) */ static int RJ_integrand(acb_ptr res, const acb_t t, void * param, slong order, slong prec) { acb_ptr x, y, z, p; acb_t xt, yt, zt, pt; int analytic, deflated; if (order > 1) flint_abort(); /* Would be needed for Taylor method. */ x = ((acb_ptr) param); y = ((acb_ptr) param) + 1; z = ((acb_ptr) param) + 2; p = ((acb_ptr) param) + 3; deflated = acb_is_zero(x); analytic = (order != 0); acb_init(xt); acb_init(yt); acb_init(zt); acb_init(pt); /* if x = 0, change of variables t -> t^2 to remove singularity at 0 */ if (deflated) { acb_sqr(xt, t, prec); acb_add(yt, y, xt, prec); acb_add(zt, z, xt, prec); acb_add(pt, p, xt, prec); if (acb_contains_zero(yt) || acb_contains_zero(zt) || acb_contains_zero(pt)) { acb_indeterminate(res); } else { acb_rsqrt_analytic(yt, yt, analytic, prec); acb_rsqrt_analytic(zt, zt, analytic, prec); acb_mul(xt, yt, zt, prec); acb_div(xt, xt, pt, prec); acb_mul_2exp_si(xt, xt, 1); acb_set(res, xt); } } else { acb_add(xt, x, t, prec); acb_add(yt, y, t, prec); acb_add(zt, z, t, prec); acb_add(pt, p, t, prec); if (acb_contains_zero(xt) || acb_contains_zero(yt) || acb_contains_zero(zt) || acb_contains_zero(pt)) { acb_indeterminate(res); } else { acb_rsqrt_analytic(xt, xt, analytic, prec); acb_rsqrt_analytic(yt, yt, analytic, prec); acb_rsqrt_analytic(zt, zt, analytic, prec); acb_mul(xt, xt, yt, prec); acb_mul(xt, xt, zt, prec); acb_div(xt, xt, pt, prec); acb_set(res, xt); } } acb_clear(xt); acb_clear(yt); acb_clear(zt); acb_clear(pt); return 0; } void acb_elliptic_rj_integration(acb_t res, const acb_t x, const acb_t y, const acb_t z, const acb_t p, int flags, slong prec) { acb_t a, b, N, I, J; arb_t A; acb_ptr xyzp; mag_t tol; int deflated; /* printf("RJ integration: "); acb_printn(x, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(y, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(z, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(p, 6, ARB_STR_NO_RADIUS); printf(" "); printf("\n"); */ acb_init(N); acb_init(a); acb_init(b); acb_init(I); acb_init(J); arb_init(A); xyzp = _acb_vec_init(4); mag_init(tol); /* compute shift that puts parameters in right half-plane */ arb_min(A, acb_realref(x), acb_realref(y), prec); arb_min(A, A, acb_realref(z), prec); arb_min(A, A, acb_realref(p), prec); arb_neg(A, A); arb_one(acb_realref(a)); arb_max(A, A, acb_realref(a), prec); arb_add_ui(A, A, 2, prec); arb_get_ubound_arf(arb_midref(A), A, prec); mag_zero(arb_radref(A)); acb_set(xyzp, x); acb_set(xyzp + 1, y); acb_set(xyzp + 2, z); acb_set(xyzp + 3, p); /* If there is a zero among x, y, z, put it first. */ if (acb_is_zero(y)) acb_swap(xyzp, xyzp + 1); if (acb_is_zero(z)) acb_swap(xyzp, xyzp + 2); deflated = acb_is_zero(xyzp); acb_set_arb(N, A); /* Path deformation to avoid 0 */ if ((arb_is_nonnegative(acb_imagref(x)) || arb_is_positive(acb_realref(x))) && (arb_is_nonnegative(acb_imagref(y)) || arb_is_positive(acb_realref(y))) && (arb_is_nonnegative(acb_imagref(z)) || arb_is_positive(acb_realref(z))) && (arb_is_nonnegative(acb_imagref(p)) || arb_is_positive(acb_realref(p)))) { arb_set_si(acb_imagref(N), 1); } else if ((arb_is_negative(acb_imagref(x)) || arb_is_positive(acb_realref(x))) && (arb_is_negative(acb_imagref(y)) || arb_is_positive(acb_realref(y))) && (arb_is_negative(acb_imagref(z)) || arb_is_positive(acb_realref(z))) && (arb_is_negative(acb_imagref(p)) || arb_is_positive(acb_realref(p)))) { arb_set_si(acb_imagref(N), -1); } else { int i; arb_set_si(acb_imagref(N), 2); /* Go through the upper half-plane, but low enough that any parameter starting in the lower plane doesn't cross the branch cut */ for (i = 0; i < 4; i++) { if (deflated && (i == 0)) continue; if (arb_is_nonnegative(acb_imagref(xyzp + i)) || arb_is_positive(acb_realref(xyzp + i))) continue; arb_zero(acb_realref(a)); /* use as tmp var */ arb_get_abs_lbound_arf(arb_midref(acb_realref(a)), acb_imagref(xyzp + i), prec); arb_min(acb_imagref(N), acb_imagref(N), acb_realref(a), prec); } arb_mul_2exp_si(acb_imagref(N), acb_imagref(N), -1); } mag_one(tol); mag_mul_2exp_si(tol, tol, -prec); acb_zero(a); if (deflated) acb_sqrt(b, N, prec); else acb_set(b, N); /* flint_printf("integrate "); flint_printf("%d\n", deflated); flint_printf("x = "); acb_printd(xyzp, 10); flint_printf("\n"); flint_printf("y = "); acb_printd(xyzp + 1, 10); flint_printf("\n"); flint_printf("z = "); acb_printd(xyzp + 2, 10); flint_printf("\n"); flint_printf("p = "); acb_printd(xyzp + 3, 10); flint_printf("\n"); flint_printf("a = "); acb_printd(a, 10); flint_printf("\n"); flint_printf("b = "); acb_printd(b, 10); flint_printf("\n"); flint_printf("N = "); acb_printd(N, 10); flint_printf("\n"); */ acb_calc_integrate(I, RJ_integrand, xyzp, a, b, prec, tol, NULL, prec); acb_mul_ui(I, I, 3, prec); acb_mul_2exp_si(I, I, -1); /* flint_printf("I = "); acb_printd(I, 10); flint_printf("\n"); */ acb_add(xyzp, x, N, prec); acb_add(xyzp + 1, y, N, prec); acb_add(xyzp + 2, z, N, prec); acb_add(xyzp + 3, p, N, prec); acb_elliptic_rj_carlson(J, xyzp, xyzp + 1, xyzp + 2, xyzp + 3, 0, prec); acb_add(res, I, J, prec); acb_clear(N); acb_clear(a); acb_clear(b); acb_clear(I); acb_clear(J); arb_clear(A); _acb_vec_clear(xyzp, 4); mag_clear(tol); } void acb_elliptic_rj(acb_t res, const acb_t x, const acb_t y, const acb_t z, const acb_t p, int flags, slong prec) { /* printf("RJ: "); acb_printn(x, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(y, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(z, 6, ARB_STR_NO_RADIUS); printf(" "); acb_printn(p, 6, ARB_STR_NO_RADIUS); printf(" "); printf("\n"); */ if (!acb_is_finite(x) || !acb_is_finite(y) || !acb_is_finite(z) || !acb_is_finite(p)) { acb_indeterminate(res); return; } if ((acb_contains_zero(x) + acb_contains_zero(y) + acb_contains_zero(z) > 1) || acb_contains_zero(p)) { acb_indeterminate(res); return; } /* Carlson's algorithm is correct in the degenerate case computing R_D */ if (x == p || acb_eq(x, p)) { acb_elliptic_rj_carlson(res, y, z, x, p, flags, prec); return; } if (y == p || acb_eq(y, p)) { acb_elliptic_rj_carlson(res, x, z, y, p, flags, prec); return; } if (z == p || acb_eq(z, p)) { acb_elliptic_rj_carlson(res, x, y, z, p, flags, prec); return; } /* Sufficient condition for correctness */ if (arb_is_nonnegative(acb_realref(x)) && arb_is_nonnegative(acb_realref(y)) && arb_is_nonnegative(acb_realref(z)) && arb_is_positive(acb_realref(p))) { acb_elliptic_rj_carlson(res, x, y, z, p, flags, prec); return; } /* Sufficient condition for correctness */ if (acb_is_real(x) && acb_is_real(y) && acb_is_real(z) && acb_is_real(p)) { acb_elliptic_rj_carlson(res, x, y, z, p, flags, prec); return; } /* Also a sufficient condition */ if (arb_is_nonnegative(acb_realref(p)) || arb_is_nonzero(acb_imagref(p))) { if ((arb_is_zero(acb_imagref(x)) && arb_is_nonnegative(acb_realref(x)) && acb_eq_conj(y, z)) || (arb_is_zero(acb_imagref(y)) && arb_is_nonnegative(acb_realref(y)) && acb_eq_conj(x, z)) || (arb_is_zero(acb_imagref(z)) && arb_is_nonnegative(acb_realref(z)) && acb_eq_conj(x, y))) { acb_elliptic_rj_carlson(res, x, y, z, p, flags, prec); return; } } /* Fast abort for input straddling branch cuts */ if ((arb_contains_zero(acb_imagref(x)) && !(arb_is_nonnegative(acb_imagref(x)) || arb_is_nonnegative(acb_realref(x)))) || (arb_contains_zero(acb_imagref(y)) && !(arb_is_nonnegative(acb_imagref(y)) || arb_is_nonnegative(acb_realref(y)))) || (arb_contains_zero(acb_imagref(z)) && !(arb_is_nonnegative(acb_imagref(z)) || arb_is_nonnegative(acb_realref(z)))) || (arb_contains_zero(acb_imagref(p)) && !(arb_is_nonnegative(acb_imagref(p)) || arb_is_nonnegative(acb_realref(p))))) { acb_indeterminate(res); return; } /* Use integration as fallback */ acb_elliptic_rj_integration(res, x, y, z, p, flags, prec); }