mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
834 lines
24 KiB
C
834 lines
24 KiB
C
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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);
|
|
}
|
|
|