2015-06-12 14:46:55 +02:00
|
|
|
/*=============================================================================
|
|
|
|
|
|
|
|
This file is part of ARB.
|
|
|
|
|
|
|
|
ARB is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
ARB is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with ARB; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
=============================================================================*/
|
|
|
|
/******************************************************************************
|
|
|
|
|
|
|
|
Copyright (C) 2014 Fredrik Johansson
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "acb_hypgeom.h"
|
|
|
|
|
|
|
|
static void
|
2015-11-05 17:46:43 +00:00
|
|
|
evaluate(acb_poly_t A, acb_srcptr a, slong p, const acb_t z, slong n, slong prec)
|
2015-06-12 14:46:55 +02:00
|
|
|
{
|
|
|
|
acb_poly_fit_length(A, p + 1);
|
|
|
|
|
|
|
|
if (p == 1)
|
|
|
|
{
|
|
|
|
acb_add_ui(A->coeffs, a, n, prec);
|
|
|
|
if (z != NULL)
|
|
|
|
acb_mul(A->coeffs, A->coeffs, z, prec);
|
|
|
|
}
|
|
|
|
else if (p == 2)
|
|
|
|
{
|
|
|
|
acb_add(A->coeffs, a + 0, a + 1, prec);
|
|
|
|
acb_add_ui(A->coeffs + 1, A->coeffs, 2 * n, prec);
|
|
|
|
acb_add_ui(A->coeffs, A->coeffs, n, prec);
|
|
|
|
acb_mul_ui(A->coeffs, A->coeffs, n, prec);
|
|
|
|
acb_addmul(A->coeffs, a + 0, a + 1, prec);
|
|
|
|
if (z != NULL)
|
|
|
|
{
|
|
|
|
acb_mul(A->coeffs, A->coeffs, z, prec);
|
|
|
|
acb_mul(A->coeffs + 1, A->coeffs + 1, z, prec);
|
|
|
|
}
|
|
|
|
}
|
2015-07-14 15:34:41 +02:00
|
|
|
else if (p == 3)
|
|
|
|
{
|
|
|
|
acb_t t, u;
|
|
|
|
acb_init(t);
|
|
|
|
acb_init(u);
|
|
|
|
|
|
|
|
acb_add(t, a + 0, a + 1, prec);
|
|
|
|
acb_add(t, t, a + 2, prec);
|
|
|
|
|
|
|
|
acb_mul(u, a + 0, a + 1, prec);
|
|
|
|
acb_mul(A->coeffs, u, a + 2, prec);
|
|
|
|
|
|
|
|
acb_addmul(u, a + 0, a + 2, prec);
|
|
|
|
acb_addmul(u, a + 1, a + 2, prec);
|
|
|
|
|
|
|
|
/*
|
|
|
|
(a0 + n)(a1 + n)(a2 + n) = a0 a1 a2 + (a0 a1 + a0 a2 + a1 a2) n + (a0 + a1 + a2) n^2 + n^3
|
|
|
|
(a0 a1 + a0 a2 + a1 a2) + 2 (a0 + a1 + a2) n + 3 n^2
|
|
|
|
(a0 + a1 + a2) + 3n
|
|
|
|
1
|
|
|
|
*/
|
|
|
|
|
|
|
|
acb_addmul_ui(A->coeffs, u, n, prec);
|
|
|
|
acb_addmul_ui(A->coeffs, t, n * n, prec);
|
|
|
|
acb_add_ui(A->coeffs, A->coeffs, n * n * n, prec);
|
|
|
|
|
|
|
|
acb_set(A->coeffs + 1, u);
|
|
|
|
acb_addmul_ui(A->coeffs + 1, t, 2 * n, prec);
|
|
|
|
acb_add_ui(A->coeffs + 1, A->coeffs + 1, 3 * n * n, prec);
|
|
|
|
|
|
|
|
acb_add_ui(A->coeffs + 2, t, 3 * n, prec);
|
|
|
|
|
|
|
|
if (z != NULL)
|
|
|
|
{
|
|
|
|
acb_mul(A->coeffs + 0, A->coeffs + 0, z, prec);
|
|
|
|
acb_mul(A->coeffs + 1, A->coeffs + 1, z, prec);
|
|
|
|
acb_mul(A->coeffs + 2, A->coeffs + 2, z, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_clear(t);
|
|
|
|
acb_clear(u);
|
|
|
|
}
|
2015-06-12 14:46:55 +02:00
|
|
|
else if (p != 0)
|
|
|
|
{
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (z != NULL)
|
|
|
|
acb_set(A->coeffs + p, z);
|
|
|
|
else
|
|
|
|
acb_one(A->coeffs + p);
|
|
|
|
|
|
|
|
_acb_poly_set_length(A, p + 1);
|
|
|
|
_acb_poly_normalise(A);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* todo: do this using underscore methods */
|
|
|
|
static void
|
|
|
|
bsplit(acb_poly_t A, acb_poly_t B, acb_poly_t C,
|
2015-11-05 17:46:43 +00:00
|
|
|
acb_srcptr a, slong p, acb_srcptr b, slong q,
|
|
|
|
const acb_t z, slong an, slong bn, slong prec)
|
2015-06-12 14:46:55 +02:00
|
|
|
{
|
|
|
|
if (bn - an == 1)
|
|
|
|
{
|
|
|
|
evaluate(A, a, p, z, an, prec);
|
|
|
|
evaluate(B, b, q, NULL, an, prec);
|
|
|
|
acb_poly_set(C, B);
|
|
|
|
}
|
|
|
|
else if (bn - an == 2) /* inlined */
|
|
|
|
{
|
|
|
|
acb_poly_t A2, B2;
|
|
|
|
|
|
|
|
acb_poly_init(A2);
|
|
|
|
acb_poly_init(B2);
|
|
|
|
|
|
|
|
evaluate(A, a, p, z, an, prec);
|
|
|
|
evaluate(A2, a, p, z, an + 1, prec);
|
|
|
|
evaluate(B, b, q, NULL, an, prec);
|
|
|
|
evaluate(B2, b, q, NULL, an + 1, prec);
|
|
|
|
|
|
|
|
acb_poly_mul(C, B, B2, prec);
|
|
|
|
acb_poly_set(B, C);
|
|
|
|
acb_poly_mul(C, A, B2, prec);
|
|
|
|
acb_poly_add(C, C, B, prec);
|
|
|
|
acb_poly_mul(A2, A, A2, prec);
|
|
|
|
acb_poly_swap(A, A2);
|
|
|
|
|
|
|
|
acb_poly_clear(A2);
|
|
|
|
acb_poly_clear(B2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-05 17:46:43 +00:00
|
|
|
slong m = an + (bn - an) / 2;
|
2015-06-12 14:46:55 +02:00
|
|
|
|
|
|
|
acb_poly_t A2, B2, C2, T;
|
|
|
|
|
|
|
|
acb_poly_init(A2);
|
|
|
|
acb_poly_init(B2);
|
|
|
|
acb_poly_init(C2);
|
|
|
|
acb_poly_init(T);
|
|
|
|
|
|
|
|
bsplit(A, B, C, a, p, b, q, z, an, m, prec);
|
|
|
|
bsplit(A2, B2, C2, a, p, b, q, z, m, bn, prec);
|
|
|
|
|
|
|
|
acb_poly_mul(T, B2, C, prec);
|
|
|
|
acb_poly_mul(C, A, C2, prec);
|
|
|
|
acb_poly_add(C, C, T, prec);
|
|
|
|
acb_poly_mul(C2, B, B2, prec);
|
|
|
|
acb_poly_swap(B, C2);
|
|
|
|
acb_poly_mul(B2, A, A2, prec);
|
|
|
|
acb_poly_swap(A, B2);
|
|
|
|
|
|
|
|
acb_poly_clear(A2);
|
|
|
|
acb_poly_clear(B2);
|
|
|
|
acb_poly_clear(C2);
|
|
|
|
acb_poly_clear(T);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
acb_hypgeom_pfq_sum_fme(acb_t s, acb_t t,
|
2015-11-05 17:46:43 +00:00
|
|
|
acb_srcptr a, slong p, acb_srcptr b, slong q,
|
|
|
|
const acb_t z, slong n, slong prec)
|
2015-06-12 14:46:55 +02:00
|
|
|
{
|
|
|
|
acb_poly_t A, B, C;
|
|
|
|
acb_ptr ks, As, Bs, Cs;
|
|
|
|
acb_t u, v;
|
|
|
|
acb_ptr * tree;
|
2015-11-05 17:46:43 +00:00
|
|
|
slong i, k, m, w;
|
2015-06-12 14:46:55 +02:00
|
|
|
|
|
|
|
m = n_sqrt(n) / 4; /* tuning parameter */
|
|
|
|
w = n / FLINT_MAX(m, 1);
|
|
|
|
|
2015-07-14 15:34:41 +02:00
|
|
|
if (m < 1 || w < 1 || p > 3 || q > 3)
|
2015-06-12 14:46:55 +02:00
|
|
|
{
|
|
|
|
acb_hypgeom_pfq_sum_forward(s, t, a, p, b, q, z, n, prec);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_poly_init(A);
|
|
|
|
acb_poly_init(B);
|
|
|
|
acb_poly_init(C);
|
|
|
|
|
|
|
|
acb_init(u);
|
|
|
|
acb_init(v);
|
|
|
|
|
|
|
|
ks = _acb_vec_init(w);
|
|
|
|
As = _acb_vec_init(w);
|
|
|
|
Bs = _acb_vec_init(w);
|
|
|
|
Cs = _acb_vec_init(w);
|
|
|
|
|
|
|
|
bsplit(A, B, C, a, p, b, q, z, 0, m, prec);
|
|
|
|
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
acb_set_ui(ks + i, i * m);
|
|
|
|
|
|
|
|
tree = _acb_poly_tree_alloc(w);
|
|
|
|
_acb_poly_tree_build(tree, ks, w, prec);
|
|
|
|
_acb_poly_evaluate_vec_fast_precomp(As, A->coeffs, A->length, tree, w, prec);
|
|
|
|
_acb_poly_evaluate_vec_fast_precomp(Bs, B->coeffs, B->length, tree, w, prec);
|
|
|
|
_acb_poly_evaluate_vec_fast_precomp(Cs, C->coeffs, C->length, tree, w, prec);
|
|
|
|
_acb_poly_tree_free(tree, w);
|
|
|
|
|
|
|
|
/* todo: use binary splitting here for improved numerical stability */
|
|
|
|
for (i = 1; i < w; i++)
|
|
|
|
{
|
|
|
|
acb_mul(Cs, Cs, Bs + i, prec);
|
|
|
|
acb_addmul(Cs, As, Cs + i, prec);
|
|
|
|
acb_mul(As, As, As + i, prec);
|
|
|
|
acb_mul(Bs, Bs, Bs + i, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_div(s, Cs, Bs, prec);
|
|
|
|
acb_div(t, As, Bs, prec);
|
|
|
|
|
|
|
|
for (k = w * m; k < n && !acb_is_zero(t); k++)
|
|
|
|
{
|
|
|
|
acb_add(s, s, t, prec);
|
|
|
|
|
|
|
|
if (p > 0)
|
|
|
|
{
|
|
|
|
acb_add_ui(u, a, k, prec);
|
|
|
|
|
|
|
|
for (i = 1; i < p; i++)
|
|
|
|
{
|
|
|
|
acb_add_ui(v, a + i, k, prec);
|
|
|
|
acb_mul(u, u, v, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_mul(t, t, u, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q > 0)
|
|
|
|
{
|
|
|
|
acb_add_ui(u, b, k, prec);
|
|
|
|
|
|
|
|
for (i = 1; i < q; i++)
|
|
|
|
{
|
|
|
|
acb_add_ui(v, b + i, k, prec);
|
|
|
|
acb_mul(u, u, v, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_div(t, t, u, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_mul(t, t, z, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_clear(u);
|
|
|
|
acb_clear(v);
|
|
|
|
|
|
|
|
_acb_vec_clear(ks, w);
|
|
|
|
_acb_vec_clear(As, w);
|
|
|
|
_acb_vec_clear(Bs, w);
|
|
|
|
_acb_vec_clear(Cs, w);
|
|
|
|
|
|
|
|
acb_poly_clear(A);
|
|
|
|
acb_poly_clear(B);
|
|
|
|
acb_poly_clear(C);
|
|
|
|
}
|
|
|
|
|