arb/arb_hypgeom/rising_ui_jet_powsum.c
2021-07-11 08:06:18 +02:00

159 lines
4 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"
void
arb_hypgeom_rising_ui_jet_powsum(arb_ptr res, const arb_t x, ulong n, slong len, slong prec)
{
slong i, j, k, wp;
arb_ptr xpow;
TMP_INIT;
if (len == 0)
return;
if (len > n + 1)
{
_arb_vec_zero(res + n + 1, len - n - 1);
len = n + 1;
}
if (len == n + 1)
{
arb_one(res + n);
len = n;
}
if (n <= 1)
{
if (n == 1)
arb_set_round(res, x, prec);
return;
}
if (len == 1)
{
arb_hypgeom_rising_ui_rs(res, x, n, 0, prec);
return;
}
if (n == 2)
{
arb_mul_2exp_si(res + 1, x, 1);
arb_add_ui(res + 1, res + 1, 1, prec);
arb_mul(res, x, x, prec + 4);
arb_add(res, res, x, prec);
return;
}
if (n <= 12 || (FLINT_BITS == 64 && n <= 20))
{
mp_ptr c;
TMP_START;
wp = ARF_PREC_ADD(prec, FLINT_BIT_COUNT(n));
c = TMP_ALLOC(sizeof(mp_limb_t) * (n + 1) * len);
_nmod_vec_zero(c, (n + 1) * len);
c[0] = 0;
c[1] = 1;
c[(n + 1) + 0] = 1;
for (i = 2; i <= n; i++)
{
for (j = FLINT_MIN(len - 1, i); j >= 0; j--)
{
slong ln, pos;
ln = i + 1 - j;
pos = (n + 1) * j;
if (i == j)
{
c[pos] = 1;
}
else
{
c[pos + ln - 1] = c[pos + ln - 2];
for (k = ln - 2; k >= 1; k--)
c[pos + k] = c[pos + k] * (i - 1) + c[pos + k - 1];
c[pos + 0] *= (i - 1);
if (j != 0)
for (k = ln - 1; k >= 0; k--)
c[pos + k] += c[pos - (n + 1) + k];
}
}
}
xpow = _arb_vec_init(n + 1);
_arb_vec_set_powers(xpow, x, n + 1, wp);
arb_dot_ui(res, NULL, 0, xpow + 1, 1, c + 1, 1, n, prec);
for (i = 1; i < len; i++)
arb_dot_ui(res + i, NULL, 0, xpow, 1, c + (n + 1) * i, 1, n + 1 - i, prec);
_arb_vec_clear(xpow, n + 1);
TMP_END;
}
else
{
fmpz * c;
wp = ARF_PREC_ADD(prec, FLINT_BIT_COUNT(n));
c = _fmpz_vec_init((n + 1) * len);
fmpz_one(c + 1);
fmpz_one(c + (n + 1) + 0);
for (i = 2; i <= n; i++)
{
for (j = FLINT_MIN(len - 1, i); j >= 0; j--)
{
slong ln, pos;
ln = i + 1 - j;
pos = (n + 1) * j;
if (i == j)
{
fmpz_one(c + pos);
}
else
{
fmpz_set(c + pos + ln - 1, c + pos + ln - 2);
for (k = ln - 2; k >= 1; k--)
{
fmpz_mul_ui(c + pos + k, c + pos + k, i - 1);
fmpz_add(c + pos + k, c + pos + k, c + pos + k - 1);
}
fmpz_mul_ui(c + pos + 0, c + pos + 0, i - 1);
if (j != 0)
for (k = ln - 1; k >= 0; k--)
fmpz_add(c + pos + k, c + pos + k, c + pos - (n + 1) + k);
}
}
}
xpow = _arb_vec_init(n + 1);
_arb_vec_set_powers(xpow, x, n + 1, wp);
arb_dot_fmpz(res, NULL, 0, xpow + 1, 1, c + 1, 1, n, prec);
for (i = 1; i < len; i++)
arb_dot_fmpz(res + i, NULL, 0, xpow, 1, c + (n + 1) * i, 1, n + 1 - i, prec);
_arb_vec_clear(xpow, n + 1);
_fmpz_vec_clear(c, (n + 1) * len);
}
}