mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
172 lines
4.2 KiB
C
172 lines
4.2 KiB
C
/*
|
|
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);
|
|
}
|