mirror of
https://github.com/vale981/arb
synced 2025-03-04 17:01:40 -05:00

This will allow us to not loose the julia session on error. See also https://github.com/wbhart/flint2/pull/243
262 lines
6.9 KiB
C
262 lines
6.9 KiB
C
/*
|
|
Copyright (C) 2017 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_hypgeom.h"
|
|
|
|
static void
|
|
bsplit(acb_ptr VA, const acb_t z, const acb_t z2,
|
|
const acb_t a, const acb_t a1a, slong k, slong h, slong prec)
|
|
{
|
|
if (h - k == 1)
|
|
{
|
|
acb_zero(VA + 0);
|
|
acb_mul_ui(VA + 1, a1a, (k+1)*(k+2), prec);
|
|
acb_mul_si(VA + 2, z2, -k*k, prec);
|
|
acb_mul_ui(VA + 3, a, (k+1)*(2*k+1), prec);
|
|
acb_sub_ui(VA + 3, VA + 3, (k+1)*(k+1), prec);
|
|
acb_mul(VA + 3, VA + 3, z, prec);
|
|
acb_neg(VA + 3, VA + 3);
|
|
acb_set(VA + 4, VA + 1);
|
|
acb_zero(VA + 5);
|
|
acb_set(VA + 6, VA + 1);
|
|
}
|
|
else
|
|
{
|
|
slong m;
|
|
acb_ptr VB;
|
|
|
|
if (h <= k) flint_abort();
|
|
|
|
m = k + (h - k) / 2;
|
|
VB = _acb_vec_init(7);
|
|
|
|
bsplit(VA, z, z2, a, a1a, k, m, prec);
|
|
bsplit(VB, z, z2, a, a1a, m, h, prec);
|
|
|
|
acb_mul(VA + 6, VA + 6, VB + 6, prec);
|
|
acb_mul(VA + 4, VA + 4, VB + 6, prec);
|
|
acb_addmul(VA + 4, VA + 0, VB + 4, prec);
|
|
acb_addmul(VA + 4, VA + 2, VB + 5, prec);
|
|
acb_mul(VA + 5, VA + 5, VB + 6, prec);
|
|
acb_addmul(VA + 5, VA + 1, VB + 4, prec);
|
|
acb_addmul(VA + 5, VA + 3, VB + 5, prec);
|
|
acb_set(VB + 6, VA + 3);
|
|
acb_mul(VA + 3, VA + 3, VB + 3, prec);
|
|
acb_addmul(VA + 3, VA + 1, VB + 2, prec);
|
|
acb_set(VB + 5, VA + 2);
|
|
acb_mul(VA + 2, VA + 2, VB + 3, prec);
|
|
acb_addmul(VA + 2, VA + 0, VB + 2, prec);
|
|
acb_mul(VA + 1, VA + 1, VB + 0, prec);
|
|
acb_addmul(VA + 1, VB + 6, VB + 1, prec);
|
|
acb_mul(VA + 0, VA + 0, VB + 0, prec);
|
|
acb_addmul(VA + 0, VB + 5, VB + 1, prec);
|
|
|
|
_acb_vec_clear(VB, 7);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Some possible approaches to bounding the Taylor coefficients c_k at
|
|
the expansion point a:
|
|
|
|
1. Inspection of the symbolic derivatives gives the trivial bound
|
|
|
|
|c_k| <= (1+|log(1-a)|) / min(|a|,|a-1|)^k
|
|
|
|
which is good enough when not close to 0.
|
|
|
|
2. Using Cauchy's integral formula, some explicit computation gives
|
|
|c_k| <= 4/|1-a|^k when |a| <= 1/2 or a = +/- i. The constant
|
|
could certainly be improved.
|
|
|
|
3. For k >= 1, c_k = 2F1(k,k,k+1,a) / k^2. Can we use monotonicity to get
|
|
good estimates here when a is complex? Note that 2F1(k,k,k,a) = (1-a)^-k.
|
|
|
|
*/
|
|
|
|
void
|
|
acb_hypgeom_dilog_continuation(acb_t res, const acb_t a, const acb_t z, slong prec)
|
|
{
|
|
acb_t za, a1, a1a, za2, log1a;
|
|
acb_ptr V;
|
|
slong n;
|
|
double tr;
|
|
mag_t tm, err, am;
|
|
int real;
|
|
|
|
if (acb_is_zero(a))
|
|
{
|
|
acb_hypgeom_dilog_zero_taylor(res, z, prec);
|
|
return;
|
|
}
|
|
|
|
if (acb_eq(a, z))
|
|
{
|
|
acb_zero(res);
|
|
return;
|
|
}
|
|
|
|
acb_init(za);
|
|
acb_init(a1);
|
|
acb_init(a1a);
|
|
acb_init(za2);
|
|
acb_init(log1a);
|
|
mag_init(tm);
|
|
mag_init(err);
|
|
mag_init(am);
|
|
|
|
acb_sub(za, z, a, prec); /* z-a */
|
|
acb_sub_ui(a1, a, 1, prec); /* a-1 */
|
|
acb_mul(a1a, a1, a, prec); /* (a-1)a */
|
|
acb_mul(za2, za, za, prec); /* (z-a)^2 */
|
|
acb_neg(log1a, a1);
|
|
acb_log(log1a, log1a, prec); /* log(1-a) */
|
|
|
|
acb_get_mag(am, a);
|
|
if (mag_cmp_2exp_si(am, -1) <= 0 ||
|
|
(acb_is_exact(a) && arb_is_zero(acb_realref(a)) &&
|
|
arf_cmpabs_ui(arb_midref(acb_imagref(a)), 1) == 0))
|
|
{
|
|
acb_get_mag_lower(am, a1);
|
|
acb_get_mag(tm, za);
|
|
mag_div(tm, tm, am); /* tm = ratio */
|
|
mag_set_ui(am, 4); /* am = prefactor */
|
|
}
|
|
else
|
|
{
|
|
acb_get_mag_lower(am, a);
|
|
acb_get_mag_lower(tm, a1);
|
|
mag_min(am, am, tm);
|
|
acb_get_mag(tm, za);
|
|
mag_div(tm, tm, am); /* tm = ratio */
|
|
acb_get_mag(am, log1a);
|
|
mag_add_ui(am, am, 1); /* am = prefactor */
|
|
}
|
|
|
|
tr = mag_get_d_log2_approx(tm);
|
|
if (tr < -0.1)
|
|
{
|
|
arf_srcptr rr, ii;
|
|
|
|
rr = arb_midref(acb_realref(z));
|
|
ii = arb_midref(acb_imagref(z));
|
|
if (arf_cmpabs(ii, rr) > 0)
|
|
rr = ii;
|
|
|
|
/* target relative accuracy near 0 */
|
|
if (arf_cmpabs_2exp_si(rr, -2) < 0 && arf_cmpabs_2exp_si(rr, -prec) > 0)
|
|
n = (prec - arf_abs_bound_lt_2exp_si(rr)) / (-tr) + 1;
|
|
else
|
|
n = prec / (-tr) + 1;
|
|
|
|
n = FLINT_MAX(n, 2);
|
|
}
|
|
else
|
|
{
|
|
n = 2;
|
|
}
|
|
|
|
mag_geom_series(err, tm, n);
|
|
mag_mul(err, err, am);
|
|
|
|
real = acb_is_real(a) && acb_is_real(z) &&
|
|
arb_is_negative(acb_realref(a1)) &&
|
|
mag_is_finite(err);
|
|
|
|
if (n < 10)
|
|
{
|
|
/* forward recurrence - faster for small n and/or low precision, but
|
|
must be avoided for large n since complex intervals blow up */
|
|
acb_t s, t, u, v;
|
|
slong k;
|
|
|
|
acb_init(s);
|
|
acb_init(t);
|
|
acb_init(u);
|
|
acb_init(v);
|
|
|
|
acb_div(u, log1a, a, prec);
|
|
acb_neg(u, u);
|
|
|
|
if (n >= 3)
|
|
{
|
|
acb_inv(v, a1, prec);
|
|
acb_add(v, v, u, prec);
|
|
acb_div(v, v, a, prec);
|
|
acb_mul_2exp_si(v, v, -1);
|
|
acb_neg(v, v);
|
|
acb_mul(v, v, za2, prec);
|
|
}
|
|
|
|
acb_mul(u, u, za, prec);
|
|
acb_add(s, u, v, prec);
|
|
|
|
for (k = 3; k < n; k++)
|
|
{
|
|
acb_mul_ui(u, u, (k - 2) * (k - 2), prec);
|
|
acb_mul(u, u, za2, prec);
|
|
acb_mul_ui(t, a, (k - 1) * (2 * k - 3), prec);
|
|
acb_sub_ui(t, t, (k - 1) * (k - 1), prec);
|
|
acb_mul(t, t, v, prec);
|
|
acb_addmul(u, t, za, prec);
|
|
acb_mul_ui(t, a1a, (k - 1) * k, prec);
|
|
acb_neg(t, t);
|
|
acb_div(u, u, t, prec);
|
|
acb_add(s, s, u, prec);
|
|
acb_swap(v, u);
|
|
}
|
|
|
|
acb_set(res, s);
|
|
|
|
acb_clear(s);
|
|
acb_clear(t);
|
|
acb_clear(u);
|
|
acb_clear(v);
|
|
}
|
|
else
|
|
{
|
|
/* binary splitting */
|
|
V = _acb_vec_init(7);
|
|
|
|
bsplit(V, za, za2, a, a1a, 1, 1 + n, prec);
|
|
|
|
acb_mul(V + 1, V + 4, log1a, prec);
|
|
acb_neg(V + 1, V + 1);
|
|
acb_mul(V + 2, V + 5, za2, prec);
|
|
acb_mul_2exp_si(V + 2, V + 2, -1);
|
|
acb_mul(V + 1, V + 1, za, prec);
|
|
acb_div(V + 3, V + 2, a1, prec);
|
|
acb_sub(V + 1, V + 1, V + 3, prec);
|
|
acb_div(V + 0, log1a, a, prec);
|
|
acb_addmul(V + 1, V + 2, V + 0, prec);
|
|
acb_mul(V + 6, V + 6, a, prec);
|
|
|
|
acb_div(V + 0, V + 1, V + 6, prec);
|
|
acb_set(res, V + 0);
|
|
|
|
_acb_vec_clear(V, 7);
|
|
}
|
|
|
|
if (real)
|
|
arb_add_error_mag(acb_realref(res), err);
|
|
else
|
|
acb_add_error_mag(res, err);
|
|
|
|
acb_clear(za);
|
|
acb_clear(a1);
|
|
acb_clear(a1a);
|
|
acb_clear(za2);
|
|
acb_clear(log1a);
|
|
mag_clear(tm);
|
|
mag_clear(err);
|
|
mag_clear(am);
|
|
}
|
|
|