mirror of
https://github.com/vale981/arb
synced 2025-03-04 17:01:40 -05:00
more hypergeometric series code; new implementation of arb_hypgeom_si
This commit is contained in:
parent
0a7c01edf3
commit
fcffcf32b8
16 changed files with 888 additions and 107 deletions
|
@ -9,6 +9,7 @@
|
|||
(at your option) any later version. See <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "arb_hypgeom.h"
|
||||
#include "acb_hypgeom.h"
|
||||
|
||||
void
|
||||
|
@ -122,9 +123,15 @@ acb_hypgeom_si_1f2(acb_t res, const acb_t z, slong prec)
|
|||
void
|
||||
acb_hypgeom_si(acb_t res, const acb_t z, slong prec)
|
||||
{
|
||||
if (acb_is_real(z) && arb_is_finite(acb_realref(z)))
|
||||
{
|
||||
arb_hypgeom_si(acb_realref(res), acb_realref(z), prec);
|
||||
arb_zero(acb_imagref(res));
|
||||
return;
|
||||
}
|
||||
|
||||
if (acb_hypgeom_u_use_asymp(z, prec))
|
||||
acb_hypgeom_si_asymp(res, z, prec);
|
||||
else
|
||||
acb_hypgeom_si_1f2(res, z, prec);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,11 @@ void arb_hypgeom_ei(arb_t res, const arb_t z, slong prec);
|
|||
void _arb_hypgeom_ei_series(arb_ptr g, arb_srcptr h, slong hlen, slong len, slong prec);
|
||||
void arb_hypgeom_ei_series(arb_poly_t g, const arb_poly_t h, slong len, slong prec);
|
||||
|
||||
|
||||
void _arb_hypgeom_si_asymp(arb_t res, const arb_t z, slong N, slong prec);
|
||||
void _arb_hypgeom_si_1f2(arb_t res, const arb_t z, slong N, slong wp, slong prec);
|
||||
void arb_hypgeom_si(arb_t res, const arb_t z, slong prec);
|
||||
|
||||
void _arb_hypgeom_si_series(arb_ptr g, arb_srcptr h, slong hlen, slong len, slong prec);
|
||||
void arb_hypgeom_si_series(arb_poly_t g, const arb_poly_t h, slong len, slong prec);
|
||||
|
||||
|
@ -196,13 +200,15 @@ slong _arb_hypgeom_gamma_upper_singular_si_choose_N(mag_t err, slong n, const ar
|
|||
void _arb_hypgeom_gamma_upper_singular_si_bsplit(arb_t res, slong n, const arb_t z, slong N, slong prec);
|
||||
int arb_hypgeom_erf_bb(arb_t res, const arb_t z, int complementary, slong prec);
|
||||
|
||||
void arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb_bs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_bs(arb_t res_real, arb_t res_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
void arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
261
arb_hypgeom/si.c
Normal file
261
arb_hypgeom/si.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Copyright (C) 2021 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 "arb_hypgeom.h"
|
||||
|
||||
#define LOG2 0.69314718055994531
|
||||
#define INV_LOG2 1.4426950408889634074
|
||||
#define EXP1 2.7182818284590452
|
||||
|
||||
double arf_get_d_log2_abs_approx_clamped(const arf_t x);
|
||||
|
||||
/* todo: minima and maxima at multiples of pi */
|
||||
void
|
||||
arb_hypgeom_si_wide(arb_t res, const arb_t z, slong prec)
|
||||
{
|
||||
mag_set_ui_2exp_si(arb_radref(res), 1988502269, -30);
|
||||
arf_zero(arb_midref(res));
|
||||
}
|
||||
|
||||
void
|
||||
_arb_hypgeom_si_asymp(arb_t res, const arb_t z, slong N, slong prec)
|
||||
{
|
||||
arb_t s, c, sz, cz, u;
|
||||
fmpq a[1];
|
||||
slong wp;
|
||||
mag_t err, t;
|
||||
int negative;
|
||||
|
||||
negative = arf_sgn(arb_midref(z)) < 0;
|
||||
|
||||
if (negative)
|
||||
{
|
||||
arb_neg(res, z);
|
||||
_arb_hypgeom_si_asymp(res, res, N, prec);
|
||||
arb_neg(res, res);
|
||||
return;
|
||||
}
|
||||
|
||||
N = FLINT_MAX(N, 1);
|
||||
|
||||
arb_init(s);
|
||||
arb_init(c);
|
||||
arb_init(sz);
|
||||
arb_init(cz);
|
||||
arb_init(u);
|
||||
mag_init(err);
|
||||
mag_init(t);
|
||||
|
||||
/* Error is bounded by first omitted term, N! / z^N */
|
||||
arb_get_mag_lower(err, z);
|
||||
|
||||
/* Do something better on wide intervals */
|
||||
if (mag_cmp_2exp_si(err, 1) < 0)
|
||||
{
|
||||
arb_hypgeom_si_wide(res, z, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
mag_inv(err, err);
|
||||
mag_pow_ui(err, err, N);
|
||||
mag_fac_ui(t, N);
|
||||
mag_mul(err, err, t);
|
||||
|
||||
wp = prec * 1.001 + 5;
|
||||
|
||||
arb_set(u, z);
|
||||
*fmpq_numref(&a[0]) = 1;
|
||||
*fmpq_denref(&a[0]) = 1;
|
||||
arb_hypgeom_sum_fmpq_imag_arb(c, s, a, 1, NULL, 0, u, 1, N, wp);
|
||||
arb_add_error_mag(c, err);
|
||||
arb_add_error_mag(s, err);
|
||||
|
||||
arb_sin_cos(sz, cz, z, wp);
|
||||
arb_mul(s, s, sz, wp);
|
||||
arb_addmul(s, c, cz, wp);
|
||||
arb_div(s, s, z, wp);
|
||||
arb_const_pi(u, wp);
|
||||
arb_mul_2exp_si(u, u, -1);
|
||||
|
||||
arb_sub(res, u, s, prec);
|
||||
}
|
||||
|
||||
arb_clear(s);
|
||||
arb_clear(c);
|
||||
arb_clear(sz);
|
||||
arb_clear(cz);
|
||||
arb_clear(u);
|
||||
mag_clear(err);
|
||||
mag_clear(t);
|
||||
}
|
||||
|
||||
void
|
||||
_arb_hypgeom_si_1f2(arb_t res, const arb_t z, slong N, slong wp, slong prec)
|
||||
{
|
||||
mag_t err, t;
|
||||
arb_t s, u;
|
||||
fmpq a[1];
|
||||
fmpq b[3];
|
||||
|
||||
N = FLINT_MAX(N, 1);
|
||||
|
||||
mag_init(err);
|
||||
mag_init(t);
|
||||
arb_init(s);
|
||||
arb_init(u);
|
||||
|
||||
arb_sqr(u, z, wp);
|
||||
arb_mul_2exp_si(u, u, -2);
|
||||
arb_neg(u, u);
|
||||
|
||||
*fmpq_numref(&a[0]) = 1;
|
||||
*fmpq_denref(&a[0]) = 2;
|
||||
*fmpq_numref(&b[0]) = 3;
|
||||
*fmpq_denref(&b[0]) = 2;
|
||||
*fmpq_numref(&b[1]) = 3;
|
||||
*fmpq_denref(&b[1]) = 2;
|
||||
*fmpq_numref(&b[2]) = 1;
|
||||
*fmpq_denref(&b[2]) = 1;
|
||||
|
||||
/* Terms are bounded by u^N / (4 (N!)^2) */
|
||||
arb_get_mag(err, u);
|
||||
|
||||
/* u^N */
|
||||
mag_set(t, err);
|
||||
mag_pow_ui(t, t, N);
|
||||
|
||||
/* geometric factor for u/N^2 */
|
||||
mag_div_ui(err, err, N);
|
||||
mag_div_ui(err, err, N);
|
||||
mag_geom_series(err, err, 0);
|
||||
mag_mul(t, t, err);
|
||||
|
||||
/* 1/(N!)^2 */
|
||||
mag_rfac_ui(err, N);
|
||||
mag_mul(err, err, err);
|
||||
mag_mul(err, err, t);
|
||||
|
||||
/* 1/4 */
|
||||
mag_mul_2exp_si(err, err, -2);
|
||||
|
||||
arb_hypgeom_sum_fmpq_arb(s, a, 1, b, 3, u, 0, N, wp);
|
||||
|
||||
arb_add_error_mag(s, err);
|
||||
arb_mul(res, s, z, prec);
|
||||
|
||||
mag_clear(err);
|
||||
mag_clear(t);
|
||||
arb_clear(u);
|
||||
arb_clear(s);
|
||||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_si(arb_t res, const arb_t z, slong prec)
|
||||
{
|
||||
slong wp, N, acc;
|
||||
double dz, du;
|
||||
|
||||
if (!arb_is_finite(z))
|
||||
{
|
||||
arb_indeterminate(res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (arb_is_zero(z))
|
||||
{
|
||||
arb_zero(res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ARF_IS_LAGOM(arb_midref(z)))
|
||||
{
|
||||
acc = arb_rel_accuracy_bits(z);
|
||||
acc = FLINT_MAX(acc, 0);
|
||||
acc = FLINT_MIN(acc, prec);
|
||||
acc += FLINT_MAX(0, ARF_EXP(arb_midref(z)));
|
||||
prec = FLINT_MIN(prec, acc + 32);
|
||||
}
|
||||
|
||||
dz = fabs(arf_get_d(arb_midref(z), ARF_RND_DOWN));
|
||||
dz = FLINT_MIN(dz, 1e300);
|
||||
|
||||
if (dz > 2.0)
|
||||
{
|
||||
double log2_err, err_prev, log2dz;
|
||||
|
||||
log2dz = arf_get_d_log2_abs_approx_clamped(arb_midref(z));
|
||||
|
||||
err_prev = 0.0;
|
||||
for (N = 1; N < 2 * prec; N++)
|
||||
{
|
||||
log2_err = ((N + 1.0) * (log(N + 1.0) - 1.0)) * INV_LOG2 - N * log2dz;
|
||||
|
||||
if (log2_err > err_prev)
|
||||
break;
|
||||
|
||||
if (log2_err < -prec - 2)
|
||||
{
|
||||
_arb_hypgeom_si_asymp(res, z, N, prec);
|
||||
return;
|
||||
}
|
||||
|
||||
err_prev = log2_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (arf_cmpabs_2exp_si(arb_midref(z), -30) < 0)
|
||||
{
|
||||
N = -arf_abs_bound_lt_2exp_si(arb_midref(z));
|
||||
wp = prec * 1.001 + 10;
|
||||
N = (prec + N - 1) / N;
|
||||
}
|
||||
else
|
||||
{
|
||||
du = 0.25 * dz * dz;
|
||||
wp = prec * 1.001 + 10;
|
||||
if (du > 1.0)
|
||||
wp += dz * 1.4426950408889634;
|
||||
|
||||
N = (prec + 5) * LOG2 / (2 * d_lambertw((prec + 5) * LOG2 / (2 * EXP1 * sqrt(du)))) + 1;
|
||||
}
|
||||
|
||||
if (arb_is_exact(z))
|
||||
{
|
||||
_arb_hypgeom_si_1f2(res, z, N, wp, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
mag_t err;
|
||||
arb_t zmid;
|
||||
|
||||
mag_init(err);
|
||||
arb_init(zmid);
|
||||
|
||||
arb_get_mid_arb(zmid, z);
|
||||
|
||||
/* |si'(z)| = |sinc(z)| <= min(1, 1/z) */
|
||||
arb_get_mag_lower(err, z);
|
||||
mag_inv(err, err);
|
||||
if (mag_cmp_2exp_si(err, 0) > 0)
|
||||
mag_one(err);
|
||||
mag_mul(err, err, arb_radref(z));
|
||||
|
||||
/* |si(a) - si(b)| < 4 */
|
||||
if (mag_cmp_2exp_si(err, 2) > 0)
|
||||
mag_set_ui(err, 4);
|
||||
|
||||
_arb_hypgeom_si_1f2(res, zmid, N, wp, prec);
|
||||
arb_add_error_mag(res, err);
|
||||
|
||||
arb_clear(zmid);
|
||||
mag_clear(err);
|
||||
}
|
||||
}
|
|
@ -12,11 +12,12 @@
|
|||
#include "arb_hypgeom.h"
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
if (N <= 2 || (prec <= 1024 && N <= 8) || (prec <= 4096 && N <= 4))
|
||||
arb_hypgeom_sum_fmpq_arb_forward(res, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_forward(res, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
else if (prec >= 8192 && arb_bits(z) <= 0.001 * prec)
|
||||
arb_hypgeom_sum_fmpq_arb_bs(res, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
else
|
||||
arb_hypgeom_sum_fmpq_arb_rs(res, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_rs(res, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
}
|
||||
|
||||
|
|
159
arb_hypgeom/sum_fmpq_arb_bs.c
Normal file
159
arb_hypgeom/sum_fmpq_arb_bs.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
Copyright (C) 2021 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 "arb_hypgeom.h"
|
||||
|
||||
static void
|
||||
factor(arb_t A, const fmpq * a, slong alen, const fmpq * b, slong blen, const fmpz_t bden, const arb_t z, slong k, slong prec)
|
||||
{
|
||||
slong i;
|
||||
|
||||
fmpz_t t, u;
|
||||
fmpz_init(t);
|
||||
fmpz_init(u);
|
||||
|
||||
if (alen == 0)
|
||||
{
|
||||
if (z == NULL)
|
||||
arb_set_fmpz(A, bden);
|
||||
else if (fmpz_is_one(bden))
|
||||
arb_set(A, z);
|
||||
else
|
||||
arb_mul_fmpz(A, z, bden, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* product of a_i + k = p/q + k = (p + k*q)/q */
|
||||
fmpz_mul_ui(t, fmpq_denref(a + 0), k);
|
||||
fmpz_add(t, t, fmpq_numref(a + 0));
|
||||
|
||||
for (i = 1; i < alen; i++)
|
||||
{
|
||||
fmpz_mul_ui(u, fmpq_denref(a + i), k);
|
||||
fmpz_add(u, u, fmpq_numref(a + i));
|
||||
fmpz_mul(t, t, u);
|
||||
}
|
||||
|
||||
if (!fmpz_is_one(bden))
|
||||
fmpz_mul(t, t, bden);
|
||||
|
||||
if (z == NULL)
|
||||
arb_set_fmpz(A, t);
|
||||
else
|
||||
arb_mul_fmpz(A, z, t, prec);
|
||||
}
|
||||
|
||||
fmpz_clear(t);
|
||||
fmpz_clear(u);
|
||||
}
|
||||
|
||||
static void
|
||||
bsplit(arb_t A1, arb_t B1, arb_t C1,
|
||||
const fmpq * a, slong alen, const fmpz_t aden,
|
||||
const fmpq * b, slong blen, const fmpz_t bden,
|
||||
const arb_t z, int reciprocal,
|
||||
slong aa,
|
||||
slong bb,
|
||||
slong prec)
|
||||
{
|
||||
if (bb - aa == 1)
|
||||
{
|
||||
factor(A1, a, alen, b, blen, bden, reciprocal ? NULL : z, aa, prec);
|
||||
factor(C1, b, blen, a, alen, aden, reciprocal ? z : NULL, aa, prec);
|
||||
/* arb_set(B1, C1); but we skip this */
|
||||
}
|
||||
else
|
||||
{
|
||||
slong m;
|
||||
|
||||
arb_t A2, B2, C2;
|
||||
|
||||
arb_init(A2);
|
||||
arb_init(B2);
|
||||
arb_init(C2);
|
||||
|
||||
m = aa + (bb - aa) / 2;
|
||||
|
||||
bsplit(A1, B1, C1, a, alen, aden, b, blen, bden, z, reciprocal, aa, m, prec);
|
||||
bsplit(A2, B2, C2, a, alen, aden, b, blen, bden, z, reciprocal, m, bb, prec);
|
||||
|
||||
if (bb - m == 1) /* B2 = C2 */
|
||||
{
|
||||
if (m - aa == 1)
|
||||
arb_add(B2, A1, C1, prec);
|
||||
else
|
||||
arb_add(B2, A1, B1, prec);
|
||||
|
||||
arb_mul(B1, B2, C2, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m - aa == 1)
|
||||
arb_mul(B1, C1, C2, prec);
|
||||
else
|
||||
arb_mul(B1, B1, C2, prec);
|
||||
|
||||
arb_addmul(B1, A1, B2, prec);
|
||||
}
|
||||
|
||||
arb_mul(A1, A1, A2, prec);
|
||||
arb_mul(C1, C1, C2, prec);
|
||||
|
||||
arb_clear(A2);
|
||||
arb_clear(B2);
|
||||
arb_clear(C2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_arb_bs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
arb_t u, v, w;
|
||||
fmpz_t aden, bden;
|
||||
slong i;
|
||||
|
||||
if (N <= 3)
|
||||
{
|
||||
arb_hypgeom_sum_fmpq_arb_forward(res, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
return;
|
||||
}
|
||||
|
||||
arb_init(u);
|
||||
arb_init(v);
|
||||
arb_init(w);
|
||||
|
||||
fmpz_init(aden);
|
||||
fmpz_init(bden);
|
||||
|
||||
fmpz_one(aden);
|
||||
fmpz_one(bden);
|
||||
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(aden, aden, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(bden, bden, fmpq_denref(b + i));
|
||||
|
||||
/* we compute to N-1 instead of N to avoid dividing by 0 in the
|
||||
denominator when computing a hypergeometric polynomial
|
||||
that terminates right before a pole */
|
||||
bsplit(u, v, w, a, alen, aden, b, blen, bden, z, reciprocal, 0, N - 1, prec);
|
||||
|
||||
arb_add(res, u, v, prec); /* s = s + t */
|
||||
arb_div(res, res, w, prec);
|
||||
|
||||
arb_clear(u);
|
||||
arb_clear(v);
|
||||
arb_clear(w);
|
||||
|
||||
fmpz_clear(aden);
|
||||
fmpz_clear(bden);
|
||||
}
|
||||
|
|
@ -12,13 +12,16 @@
|
|||
#include "arb_hypgeom.h"
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
arb_t t, u, sden;
|
||||
slong i, k, num_max_bits, den_max_bits, bits1, bits2, Nbits, den_prec;
|
||||
|
||||
if (N <= 1)
|
||||
{
|
||||
if (N == 1)
|
||||
arb_one(res);
|
||||
else
|
||||
arb_zero(res);
|
||||
return;
|
||||
}
|
||||
|
@ -51,14 +54,23 @@ arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fm
|
|||
slong num, den;
|
||||
|
||||
den = 1;
|
||||
for (i = 0; i < blen; i++)
|
||||
den *= *fmpq_denref(b + i);
|
||||
arb_mul_si(u, z, den, prec);
|
||||
|
||||
den = 1;
|
||||
num = 1;
|
||||
for (i = 0; i < alen; i++)
|
||||
den *= *fmpq_denref(a + i);
|
||||
for (i = 0; i < blen; i++)
|
||||
num *= *fmpq_denref(b + i);
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_si(u, z, den, prec);
|
||||
arb_set_si(t, num);
|
||||
arb_div(u, t, u, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_si(u, z, num, prec);
|
||||
arb_div_si(u, u, den, prec);
|
||||
}
|
||||
|
||||
arb_one(res);
|
||||
arb_one(t);
|
||||
|
@ -105,14 +117,23 @@ arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fm
|
|||
fmpz_init(c);
|
||||
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(b + i));
|
||||
arb_mul_fmpz(u, z, den, prec);
|
||||
|
||||
fmpz_one(den);
|
||||
fmpz_one(num);
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(num, num, fmpq_denref(b + i));
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_fmpz(u, z, den, prec);
|
||||
arb_set_fmpz(t, num);
|
||||
arb_div(u, t, u, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_fmpz(u, z, num, prec);
|
||||
arb_div_fmpz(u, u, den, prec);
|
||||
}
|
||||
|
||||
arb_one(res);
|
||||
arb_one(t);
|
||||
|
@ -169,4 +190,3 @@ arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fm
|
|||
arb_clear(u);
|
||||
arb_clear(sden);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,24 +18,24 @@ d_log2_fac(double n)
|
|||
}
|
||||
|
||||
static slong
|
||||
tail_precision(slong k, slong alen, slong blen, double log2z, double log2max, slong prec)
|
||||
tail_precision(slong k, double min_k, slong alen, slong blen, double log2z, double log2max, slong prec)
|
||||
{
|
||||
double term_magnitude;
|
||||
slong new_prec;
|
||||
|
||||
if (prec <= 128 || k <= 5)
|
||||
if (prec <= 128 || k <= 5 || k <= min_k)
|
||||
return prec;
|
||||
|
||||
term_magnitude = k * log2z;
|
||||
if (alen != blen)
|
||||
term_magnitude += (alen - blen) * d_log2_fac(k);
|
||||
|
||||
/* printf("term %ld, max %f, log2x %f, magn %f\n", k, log2z, log2max, term_magnitude); */
|
||||
|
||||
new_prec = prec - (log2max - term_magnitude) + 10;
|
||||
new_prec = FLINT_MIN(new_prec, prec);
|
||||
new_prec = FLINT_MAX(new_prec, 32);
|
||||
|
||||
/* printf("term %ld, max %f, log2x %f, magn %f new_prec %ld\n", k, log2z, log2max, term_magnitude, new_prec); */
|
||||
|
||||
return new_prec;
|
||||
}
|
||||
|
||||
|
@ -70,10 +70,10 @@ arf_get_d_log2_abs_approx_clamped(const arf_t x)
|
|||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
slong m, i, j, k, l, jlen, jbot, jtop, wp;
|
||||
double log2z, log2max;
|
||||
double log2z, log2max, adaptive_min_k;
|
||||
int want_adaptive_precision;
|
||||
arb_t s, t;
|
||||
arb_ptr zpow;
|
||||
|
@ -83,6 +83,9 @@ arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq *
|
|||
|
||||
if (N <= 1)
|
||||
{
|
||||
if (N == 1)
|
||||
arb_one(res);
|
||||
else
|
||||
arb_zero(res);
|
||||
return;
|
||||
}
|
||||
|
@ -101,15 +104,24 @@ arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq *
|
|||
zpow = _arb_vec_init(m + 1);
|
||||
cs = _fmpz_vec_init(m + 1);
|
||||
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(b + i));
|
||||
arb_mul_fmpz(zpow + m, z, den, prec);
|
||||
|
||||
fmpz_one(c);
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(c, c, fmpq_denref(b + i));
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_fmpz(zpow + m, z, den, prec);
|
||||
arb_set_fmpz(t, c);
|
||||
arb_div(zpow + m, t, zpow + m, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_fmpz(zpow + m, z, c, prec);
|
||||
arb_div_fmpz(zpow + m, zpow + m, den, prec);
|
||||
}
|
||||
|
||||
want_adaptive_precision = N > 5;
|
||||
|
||||
|
@ -134,10 +146,12 @@ arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq *
|
|||
|
||||
log2max = 0.0;
|
||||
log2z = 0.0;
|
||||
adaptive_min_k = 0.0;
|
||||
if (want_adaptive_precision)
|
||||
{
|
||||
|
||||
log2z = arf_get_d_log2_abs_approx_clamped(arb_midref(z));
|
||||
if (reciprocal)
|
||||
log2z = -log2z;
|
||||
|
||||
/* Terms are increasing, so don't change the precision. */
|
||||
if (alen >= blen && log2z >= 0.0)
|
||||
|
@ -159,6 +173,12 @@ arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq *
|
|||
/* r = 3 -> exp(3*z^(1/3)) */
|
||||
/* ... */
|
||||
log2max = r * exp(log2z * 0.693147180559945 / r) * 1.44269504088896;
|
||||
|
||||
/* fixme */
|
||||
if (r == 1)
|
||||
adaptive_min_k = exp(log2z * log(2));
|
||||
else
|
||||
adaptive_min_k = exp(0.5 * log2z * log(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +302,7 @@ arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq *
|
|||
}
|
||||
|
||||
if (want_adaptive_precision)
|
||||
wp = tail_precision(k - jlen, alen, blen, log2z, log2max, prec);
|
||||
wp = tail_precision(k - jlen, adaptive_min_k, alen, blen, log2z, log2max, prec);
|
||||
else
|
||||
wp = prec;
|
||||
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
#include "arb_hypgeom.h"
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
if (N <= 10 || (prec <= 1024 && N <= 16))
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(res1, res2, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(res1, res2, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
else if (prec >= 8192 && arb_bits(z) <= 0.001 * prec)
|
||||
arb_hypgeom_sum_fmpq_imag_arb_bs(res1, res2, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
else
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(res1, res2, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(res1, res2, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
}
|
||||
|
||||
|
|
172
arb_hypgeom/sum_fmpq_imag_arb_bs.c
Normal file
172
arb_hypgeom/sum_fmpq_imag_arb_bs.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
Copyright (C) 2021 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 "arb_hypgeom.h"
|
||||
|
||||
static void
|
||||
factor(arb_t A, const fmpq * a, slong alen, const fmpq * b, slong blen, const fmpz_t bden, const arb_t z, slong k, slong prec)
|
||||
{
|
||||
slong i;
|
||||
|
||||
fmpz_t t, u;
|
||||
fmpz_init(t);
|
||||
fmpz_init(u);
|
||||
|
||||
if (alen == 0)
|
||||
{
|
||||
if (z == NULL)
|
||||
arb_set_fmpz(A, bden);
|
||||
else if (fmpz_is_one(bden))
|
||||
arb_set(A, z);
|
||||
else
|
||||
arb_mul_fmpz(A, z, bden, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* product of a_i + k = p/q + k = (p + k*q)/q */
|
||||
fmpz_mul_ui(t, fmpq_denref(a + 0), k);
|
||||
fmpz_add(t, t, fmpq_numref(a + 0));
|
||||
|
||||
for (i = 1; i < alen; i++)
|
||||
{
|
||||
fmpz_mul_ui(u, fmpq_denref(a + i), k);
|
||||
fmpz_add(u, u, fmpq_numref(a + i));
|
||||
fmpz_mul(t, t, u);
|
||||
}
|
||||
|
||||
if (!fmpz_is_one(bden))
|
||||
fmpz_mul(t, t, bden);
|
||||
|
||||
if (z == NULL)
|
||||
arb_set_fmpz(A, t);
|
||||
else
|
||||
arb_mul_fmpz(A, z, t, prec);
|
||||
}
|
||||
|
||||
fmpz_clear(t);
|
||||
fmpz_clear(u);
|
||||
}
|
||||
|
||||
static void
|
||||
bsplit(acb_t A1, acb_t B1, acb_t C1,
|
||||
const fmpq * a, slong alen, const fmpz_t aden,
|
||||
const fmpq * b, slong blen, const fmpz_t bden,
|
||||
const arb_t z, int reciprocal,
|
||||
slong aa,
|
||||
slong bb,
|
||||
slong prec)
|
||||
{
|
||||
if (bb - aa == 1)
|
||||
{
|
||||
factor(acb_realref(A1), a, alen, b, blen, bden, reciprocal ? NULL : z, aa, prec);
|
||||
factor(acb_realref(C1), b, blen, a, alen, aden, reciprocal ? z : NULL, aa, prec);
|
||||
arb_zero(acb_imagref(A1));
|
||||
arb_zero(acb_imagref(C1));
|
||||
|
||||
if (reciprocal)
|
||||
acb_div_onei(C1, C1);
|
||||
else
|
||||
acb_mul_onei(A1, A1);
|
||||
|
||||
/* arb_set(B1, C1); but we skip this */
|
||||
}
|
||||
else
|
||||
{
|
||||
slong m;
|
||||
|
||||
acb_t A2, B2, C2;
|
||||
|
||||
acb_init(A2);
|
||||
acb_init(B2);
|
||||
acb_init(C2);
|
||||
|
||||
m = aa + (bb - aa) / 2;
|
||||
|
||||
bsplit(A1, B1, C1, a, alen, aden, b, blen, bden, z, reciprocal, aa, m, prec);
|
||||
bsplit(A2, B2, C2, a, alen, aden, b, blen, bden, z, reciprocal, m, bb, prec);
|
||||
|
||||
if (bb - m == 1) /* B2 = C2 */
|
||||
{
|
||||
if (m - aa == 1)
|
||||
acb_add(B2, A1, C1, prec);
|
||||
else
|
||||
acb_add(B2, A1, B1, prec);
|
||||
|
||||
acb_mul(B1, B2, C2, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m - aa == 1)
|
||||
acb_mul(B1, C1, C2, prec);
|
||||
else
|
||||
acb_mul(B1, B1, C2, prec);
|
||||
|
||||
acb_addmul(B1, A1, B2, prec);
|
||||
}
|
||||
|
||||
acb_mul(A1, A1, A2, prec);
|
||||
acb_mul(C1, C1, C2, prec);
|
||||
|
||||
acb_clear(A2);
|
||||
acb_clear(B2);
|
||||
acb_clear(C2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_imag_arb_bs(arb_t res_real, arb_t res_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
acb_t u, v, w;
|
||||
fmpz_t aden, bden;
|
||||
slong i;
|
||||
|
||||
if (N <= 3)
|
||||
{
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(res_real, res_imag, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
return;
|
||||
}
|
||||
|
||||
acb_init(u);
|
||||
acb_init(v);
|
||||
acb_init(w);
|
||||
|
||||
fmpz_init(aden);
|
||||
fmpz_init(bden);
|
||||
|
||||
fmpz_one(aden);
|
||||
fmpz_one(bden);
|
||||
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(aden, aden, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(bden, bden, fmpq_denref(b + i));
|
||||
|
||||
/* we compute to N-1 instead of N to avoid dividing by 0 in the
|
||||
denominator when computing a hypergeometric polynomial
|
||||
that terminates right before a pole */
|
||||
bsplit(u, v, w, a, alen, aden, b, blen, bden, z, reciprocal, 0, N - 1, prec);
|
||||
|
||||
acb_add(u, u, v, prec); /* s = s + t */
|
||||
acb_div(u, u, w, prec);
|
||||
|
||||
if (!acb_is_finite(u))
|
||||
acb_indeterminate(u);
|
||||
|
||||
arb_swap(res_real, acb_realref(u));
|
||||
arb_swap(res_imag, acb_imagref(u));
|
||||
|
||||
acb_clear(u);
|
||||
acb_clear(v);
|
||||
acb_clear(w);
|
||||
|
||||
fmpz_clear(aden);
|
||||
fmpz_clear(bden);
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
#include "arb_hypgeom.h"
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t s_real, arb_t s_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t s_real, arb_t s_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
arb_t t, u, sden;
|
||||
slong i, k, num_max_bits, den_max_bits, bits1, bits2, Nbits, den_prec;;
|
||||
|
@ -56,14 +56,23 @@ arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t s_real, arb_t s_imag, const fmpq * a
|
|||
slong num, den;
|
||||
|
||||
den = 1;
|
||||
for (i = 0; i < blen; i++)
|
||||
den *= *fmpq_denref(b + i);
|
||||
arb_mul_si(u, z, den, prec);
|
||||
|
||||
den = 1;
|
||||
num = 1;
|
||||
for (i = 0; i < alen; i++)
|
||||
den *= *fmpq_denref(a + i);
|
||||
for (i = 0; i < blen; i++)
|
||||
num *= *fmpq_denref(b + i);
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_si(u, z, den, prec);
|
||||
arb_set_si(t, num);
|
||||
arb_div(u, t, u, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_si(u, z, num, prec);
|
||||
arb_div_si(u, u, den, prec);
|
||||
}
|
||||
|
||||
arb_one(s_real);
|
||||
arb_zero(s_imag);
|
||||
|
@ -143,14 +152,23 @@ arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t s_real, arb_t s_imag, const fmpq * a
|
|||
fmpz_init(c);
|
||||
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(b + i));
|
||||
arb_mul_fmpz(u, z, den, prec);
|
||||
|
||||
fmpz_one(den);
|
||||
fmpz_one(num);
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(num, num, fmpq_denref(b + i));
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_fmpz(u, z, den, prec);
|
||||
arb_set_fmpz(t, num);
|
||||
arb_div(u, t, u, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_fmpz(u, z, num, prec);
|
||||
arb_div_fmpz(u, u, den, prec);
|
||||
}
|
||||
|
||||
arb_one(s_real);
|
||||
arb_zero(s_imag);
|
||||
|
|
|
@ -18,24 +18,24 @@ d_log2_fac(double n)
|
|||
}
|
||||
|
||||
static slong
|
||||
tail_precision(slong k, slong alen, slong blen, double log2z, double log2max, slong prec)
|
||||
tail_precision(slong k, double min_k, slong alen, slong blen, double log2z, double log2max, slong prec)
|
||||
{
|
||||
double term_magnitude;
|
||||
slong new_prec;
|
||||
|
||||
if (prec <= 128 || k <= 5)
|
||||
if (prec <= 128 || k <= 5 || k <= min_k)
|
||||
return prec;
|
||||
|
||||
term_magnitude = k * log2z;
|
||||
if (alen != blen)
|
||||
term_magnitude += (alen - blen) * d_log2_fac(k);
|
||||
|
||||
/* printf("term %ld, max %f, log2x %f, magn %f\n", k, log2z, log2max, term_magnitude); */
|
||||
|
||||
new_prec = prec - (log2max - term_magnitude) + 10;
|
||||
new_prec = FLINT_MIN(new_prec, prec);
|
||||
new_prec = FLINT_MAX(new_prec, 32);
|
||||
|
||||
/* printf("term %ld, max %f, log2x %f, magn %f new_prec %ld\n", k, log2z, log2max, term_magnitude, new_prec); */
|
||||
|
||||
return new_prec;
|
||||
}
|
||||
|
||||
|
@ -43,10 +43,10 @@ tail_precision(slong k, slong alen, slong blen, double log2z, double log2max, sl
|
|||
double arf_get_d_log2_abs_approx_clamped(const arf_t x);
|
||||
|
||||
void
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
{
|
||||
slong m, i, j, k, l, jlen, jbot, jtop, wp;
|
||||
double log2z, log2max;
|
||||
double log2z, log2max, adaptive_min_k;
|
||||
int want_adaptive_precision;
|
||||
arb_t s_real, s_imag, t_real, t_imag;
|
||||
arb_ptr zpow;
|
||||
|
@ -70,15 +70,24 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
zpow = _arb_vec_init(m + 1);
|
||||
cs = _fmpz_vec_init(m + 1);
|
||||
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(b + i));
|
||||
arb_mul_fmpz(zpow + m, z, den, prec);
|
||||
|
||||
fmpz_one(c);
|
||||
fmpz_one(den);
|
||||
for (i = 0; i < alen; i++)
|
||||
fmpz_mul(den, den, fmpq_denref(a + i));
|
||||
for (i = 0; i < blen; i++)
|
||||
fmpz_mul(c, c, fmpq_denref(b + i));
|
||||
|
||||
if (reciprocal)
|
||||
{
|
||||
arb_mul_fmpz(zpow + m, z, den, prec);
|
||||
arb_set_fmpz(t_real, c);
|
||||
arb_div(zpow + m, t_real, zpow + m, prec);
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_mul_fmpz(zpow + m, z, c, prec);
|
||||
arb_div_fmpz(zpow + m, zpow + m, den, prec);
|
||||
}
|
||||
|
||||
want_adaptive_precision = N > 5;
|
||||
|
||||
|
@ -103,10 +112,12 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
|
||||
log2max = 0.0;
|
||||
log2z = 0.0;
|
||||
adaptive_min_k = 0.0;
|
||||
if (want_adaptive_precision)
|
||||
{
|
||||
|
||||
log2z = arf_get_d_log2_abs_approx_clamped(arb_midref(z));
|
||||
if (reciprocal)
|
||||
log2z = -log2z;
|
||||
|
||||
/* Terms are increasing, so don't change the precision. */
|
||||
if (alen >= blen && log2z >= 0.0)
|
||||
|
@ -118,6 +129,7 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
if (alen >= blen)
|
||||
{
|
||||
log2max = 0.0;
|
||||
adaptive_min_k = N;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -128,6 +140,12 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
/* r = 3 -> exp(3*z^(1/3)) */
|
||||
/* ... */
|
||||
log2max = r * exp(log2z * 0.693147180559945 / r) * 1.44269504088896;
|
||||
|
||||
/* fixme */
|
||||
if (r == 1)
|
||||
adaptive_min_k = exp(log2z * log(2));
|
||||
else
|
||||
adaptive_min_k = exp(0.5 * log2z * log(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +159,7 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
|
||||
if (jtop > 0)
|
||||
{
|
||||
while (jlen <= j && jlen <= 8 && jbot >= 2)
|
||||
while (jlen <= j && jlen <= 12 && jbot >= 2)
|
||||
{
|
||||
jbot--;
|
||||
jlen++;
|
||||
|
@ -251,7 +269,7 @@ arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res_real, arb_t res_imag, const fmpq * a,
|
|||
}
|
||||
|
||||
if (want_adaptive_precision)
|
||||
wp = tail_precision(k - jlen, alen, blen, log2z, log2max, prec);
|
||||
wp = tail_precision(k - jlen, adaptive_min_k, alen, blen, log2z, log2max, prec);
|
||||
else
|
||||
wp = prec;
|
||||
|
||||
|
|
95
arb_hypgeom/test/t-si.c
Normal file
95
arb_hypgeom/test/t-si.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright (C) 2018 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 "arb_hypgeom.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
slong iter;
|
||||
flint_rand_t state;
|
||||
|
||||
flint_printf("si....");
|
||||
fflush(stdout);
|
||||
|
||||
flint_randinit(state);
|
||||
|
||||
for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++)
|
||||
{
|
||||
arb_t x, s, t;
|
||||
slong prec1, prec2;
|
||||
|
||||
arb_init(x);
|
||||
arb_init(s);
|
||||
arb_init(t);
|
||||
|
||||
if (n_randint(state, 10) == 0)
|
||||
{
|
||||
prec1 = 2 + n_randint(state, 2000);
|
||||
prec2 = 2 + n_randint(state, 2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
prec1 = 2 + n_randint(state, 200);
|
||||
prec2 = 2 + n_randint(state, 200);
|
||||
}
|
||||
|
||||
arb_randtest(x, state, 2 + n_randint(state, prec1), 2 + n_randint(state, 100));
|
||||
arb_randtest(s, state, 2 + n_randint(state, prec1), 2 + n_randint(state, 100));
|
||||
arb_randtest(t, state, 2 + n_randint(state, prec1), 2 + n_randint(state, 100));
|
||||
|
||||
switch (n_randint(state, 3))
|
||||
{
|
||||
case 0:
|
||||
arb_hypgeom_si(s, x, prec1);
|
||||
break;
|
||||
case 1:
|
||||
_arb_hypgeom_si_1f2(s, x, n_randint(state, prec1), prec1, prec1);
|
||||
break;
|
||||
default:
|
||||
_arb_hypgeom_si_asymp(s, x, n_randint(state, prec1 / 2), prec1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (n_randint(state, 3))
|
||||
{
|
||||
case 0:
|
||||
arb_hypgeom_si(t, x, prec2);
|
||||
break;
|
||||
case 1:
|
||||
_arb_hypgeom_si_1f2(t, x, n_randint(state, prec2), prec2, prec2);
|
||||
break;
|
||||
default:
|
||||
_arb_hypgeom_si_asymp(t, x, n_randint(state, prec2 / 2), prec2);
|
||||
break;
|
||||
}
|
||||
|
||||
arb_hypgeom_si(s, x, prec1);
|
||||
_arb_hypgeom_si_asymp(t, x, n_randint(state, prec2 / 2), prec2);
|
||||
|
||||
if (!arb_overlaps(s, t))
|
||||
{
|
||||
flint_printf("FAIL: overlap\n\n");
|
||||
flint_printf("x = "); arb_printn(x, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s = "); arb_printn(s, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("t = "); arb_printn(t, 100, 0); flint_printf("\n\n");
|
||||
flint_abort();
|
||||
}
|
||||
|
||||
arb_clear(x);
|
||||
arb_clear(s);
|
||||
arb_clear(t);
|
||||
}
|
||||
|
||||
flint_randclear(state);
|
||||
flint_cleanup();
|
||||
flint_printf("PASS\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -24,9 +24,10 @@ int main()
|
|||
|
||||
for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++)
|
||||
{
|
||||
arb_t s1, s2, z;
|
||||
arb_t s1, s2, s3, z;
|
||||
fmpq *a, *b;
|
||||
slong alen, blen, N, prec;
|
||||
int reciprocal;
|
||||
|
||||
alen = n_randint(state, 5);
|
||||
blen = n_randint(state, 5);
|
||||
|
@ -34,11 +35,13 @@ int main()
|
|||
|
||||
arb_init(s1);
|
||||
arb_init(s2);
|
||||
arb_init(s3);
|
||||
arb_init(z);
|
||||
a = _fmpq_vec_init(alen);
|
||||
b = _fmpq_vec_init(blen);
|
||||
|
||||
prec = 2 + n_randint(state, 500);
|
||||
reciprocal = n_randint(state, 2);
|
||||
|
||||
if (n_randint(state, 10) == 0)
|
||||
arb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 100));
|
||||
|
@ -50,10 +53,11 @@ int main()
|
|||
_fmpq_vec_randtest(a, state, alen, 1 + n_randint(state, 100));
|
||||
_fmpq_vec_randtest(b, state, blen, 1 + n_randint(state, 100));
|
||||
|
||||
arb_hypgeom_sum_fmpq_arb_forward(s1, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_rs(s2, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_forward(s1, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_rs(s2, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
arb_hypgeom_sum_fmpq_arb_bs(s3, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
|
||||
if (!arb_overlaps(s1, s2))
|
||||
if (!arb_overlaps(s1, s2) || !arb_overlaps(s1, s3))
|
||||
{
|
||||
flint_printf("FAIL: overlap\n\n");
|
||||
flint_printf("N = %wd\n\n", N);
|
||||
|
@ -62,11 +66,13 @@ int main()
|
|||
flint_printf("z = "); arb_printn(z, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s1 = "); arb_printn(s1, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s2 = "); arb_printn(s2, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s3 = "); arb_printn(s3, 100, 0); flint_printf("\n\n");
|
||||
flint_abort();
|
||||
}
|
||||
|
||||
arb_clear(s1);
|
||||
arb_clear(s2);
|
||||
arb_clear(s3);
|
||||
arb_clear(z);
|
||||
_fmpq_vec_clear(a, alen);
|
||||
_fmpq_vec_clear(b, blen);
|
||||
|
|
|
@ -24,9 +24,10 @@ int main()
|
|||
|
||||
for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++)
|
||||
{
|
||||
arb_t s1, s2, r1, r2, z;
|
||||
arb_t s1, s2, s3, r1, r2, r3, z;
|
||||
fmpq *a, *b;
|
||||
slong alen, blen, N, prec;
|
||||
int reciprocal;
|
||||
|
||||
alen = n_randint(state, 5);
|
||||
blen = n_randint(state, 5);
|
||||
|
@ -34,13 +35,16 @@ int main()
|
|||
|
||||
arb_init(s1);
|
||||
arb_init(s2);
|
||||
arb_init(s3);
|
||||
arb_init(r1);
|
||||
arb_init(r2);
|
||||
arb_init(r3);
|
||||
arb_init(z);
|
||||
a = _fmpq_vec_init(alen);
|
||||
b = _fmpq_vec_init(blen);
|
||||
|
||||
prec = 2 + n_randint(state, 500);
|
||||
reciprocal = n_randint(state, 2);
|
||||
|
||||
if (n_randint(state, 10) == 0)
|
||||
arb_randtest_special(z, state, 1 + n_randint(state, 200), 1 + n_randint(state, 100));
|
||||
|
@ -54,10 +58,12 @@ int main()
|
|||
_fmpq_vec_randtest(a, state, alen, 1 + n_randint(state, 100));
|
||||
_fmpq_vec_randtest(b, state, blen, 1 + n_randint(state, 100));
|
||||
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(r1, s1, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(r2, s2, a, alen, b, blen, z, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_forward(r1, s1, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_rs(r2, s2, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
arb_hypgeom_sum_fmpq_imag_arb_bs(r3, s3, a, alen, b, blen, z, reciprocal, N, prec);
|
||||
|
||||
if (!arb_overlaps(r1, r2) || !arb_overlaps(s1, s2))
|
||||
if (!arb_overlaps(r1, r2) || !arb_overlaps(s1, s2) ||
|
||||
!arb_overlaps(r1, r3) || !arb_overlaps(s1, s3))
|
||||
{
|
||||
flint_printf("FAIL: overlap\n\n");
|
||||
flint_printf("N = %wd\n\n", N);
|
||||
|
@ -68,13 +74,17 @@ int main()
|
|||
flint_printf("s1 = "); arb_printn(s1, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("r2 = "); arb_printn(r2, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s2 = "); arb_printn(s2, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("r3 = "); arb_printn(r3, 100, 0); flint_printf("\n\n");
|
||||
flint_printf("s3 = "); arb_printn(s3, 100, 0); flint_printf("\n\n");
|
||||
flint_abort();
|
||||
}
|
||||
|
||||
arb_clear(s1);
|
||||
arb_clear(s2);
|
||||
arb_clear(s3);
|
||||
arb_clear(r1);
|
||||
arb_clear(r2);
|
||||
arb_clear(r3);
|
||||
arb_clear(z);
|
||||
_fmpq_vec_clear(a, alen);
|
||||
_fmpq_vec_clear(b, blen);
|
||||
|
|
|
@ -70,24 +70,6 @@ arb_hypgeom_ei(arb_t res, const arb_t z, slong prec)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_si(arb_t res, const arb_t z, slong prec)
|
||||
{
|
||||
if (!arb_is_finite(z))
|
||||
{
|
||||
arb_indeterminate(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
acb_t t;
|
||||
acb_init(t);
|
||||
arb_set(acb_realref(t), z);
|
||||
acb_hypgeom_si(t, t, prec);
|
||||
arb_swap(res, acb_realref(t));
|
||||
acb_clear(t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arb_hypgeom_ci(arb_t res, const arb_t z, slong prec)
|
||||
{
|
||||
|
|
|
@ -410,7 +410,9 @@ Exponential and trigonometric integrals
|
|||
Computes the exponential integral of the power series *z*,
|
||||
truncated to length *len*.
|
||||
|
||||
.. function:: void arb_hypgeom_si(arb_t res, const arb_t z, slong prec)
|
||||
.. function:: void _arb_hypgeom_si_asymp(arb_t res, const arb_t z, slong N, slong prec)
|
||||
void _arb_hypgeom_si_1f2(arb_t res, const arb_t z, slong N, slong wp, slong prec)
|
||||
void arb_hypgeom_si(arb_t res, const arb_t z, slong prec)
|
||||
|
||||
Computes the sine integral `\operatorname{Si}(z)`.
|
||||
|
||||
|
@ -652,25 +654,27 @@ Dilogarithm
|
|||
Hypergeometric sums
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
.. function:: void arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
.. function:: void arb_hypgeom_sum_fmpq_arb_forward(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_arb_rs(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_arb(arb_t res, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
|
||||
Sets *res* to the finite hypergeometric sum
|
||||
`\sum_{n=0}^{N-1} (\textbf{a})_n z^n / (\textbf{b})_n`
|
||||
where `\textbf{x}_n = (x_1)_n (x_2)_n \cdots`,
|
||||
given vectors of rational parameters *a* (of length *alen*)
|
||||
and *b* (of length *blen*).
|
||||
If *reciprocal* is set, replace `z` by `1 / z`.
|
||||
The *forward* version uses the forward recurrence, optimized by
|
||||
delaying divisions, the *rs* version
|
||||
uses rectangular splitting, and the default version uses
|
||||
an automatic algorithm choice.
|
||||
|
||||
.. function:: void arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, slong N, slong prec)
|
||||
.. function:: void arb_hypgeom_sum_fmpq_imag_arb_forward(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_rs(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_imag_arb_bs(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
void arb_hypgeom_sum_fmpq_imag_arb(arb_t res1, arb_t res2, const fmpq * a, slong alen, const fmpq * b, slong blen, const arb_t z, int reciprocal, slong N, slong prec)
|
||||
|
||||
Sets *res1* and *res2* to the real and imaginary part of the
|
||||
finite hypergeometric sum
|
||||
`\sum_{n=0}^{N-1} (\textbf{a})_n (i z^n) / (\textbf{b})_n`.
|
||||
|
||||
`\sum_{n=0}^{N-1} (\textbf{a})_n (i z)^n / (\textbf{b})_n`.
|
||||
If *reciprocal* is set, replace `z` by `1 / z`.
|
||||
|
|
Loading…
Add table
Reference in a new issue