diff --git a/acb_dirichlet/platt_ws_interpolation.c b/acb_dirichlet/platt_ws_interpolation.c index 60da2210..d93aa993 100644 --- a/acb_dirichlet/platt_ws_interpolation.c +++ b/acb_dirichlet/platt_ws_interpolation.c @@ -11,6 +11,7 @@ #include "acb_dirichlet.h" #include "arb_hypgeom.h" +#include "arb_poly.h" /* Increase precision adaptively. */ static void @@ -413,45 +414,6 @@ _interpolation_helper_raw(arb_t res, arb_clear(c); } -static void -_arb_poly_sinc_pi_series(arb_ptr g, arb_srcptr h, slong hlen, slong n, slong prec) -{ - hlen = FLINT_MIN(hlen, n); - if (hlen == 1) - { - arb_sinc_pi(g, h, prec); - _arb_vec_zero(g + 1, n - 1); - } - else - { - arb_t pi; - arb_ptr t, u; - - arb_init(pi); - t = _arb_vec_init(n + 1); - u = _arb_vec_init(hlen); - - arb_const_pi(pi, prec); - _arb_vec_set(u, h, hlen); - - if (arb_is_zero(h)) - { - _arb_poly_sin_pi_series(t, u, hlen, n + 1, prec); - _arb_poly_div_series(g, t + 1, n, u + 1, hlen - 1, n, prec); - } - else - { - _arb_poly_sin_pi_series(t, u, hlen, n, prec); - _arb_poly_div_series(g, t, n, u, hlen, n, prec); - } - _arb_vec_scalar_div(g, g, n, pi, prec); - - arb_clear(pi); - _arb_vec_clear(t, n + 1); - _arb_vec_clear(u, hlen); - } -} - /* Sets res to the function (a * exp(-(b-h)^2 / c)) * sinc_pi(d*(b-h))) * of the power series h, for the purpose of computing derivatives * of the Gaussian-windowed Whittaker-Shannon interpolation. diff --git a/arb_poly.h b/arb_poly.h index 03464c29..60da6ad0 100644 --- a/arb_poly.h +++ b/arb_poly.h @@ -636,6 +636,9 @@ void arb_poly_tan_series(arb_poly_t g, const arb_poly_t h, slong n, slong prec); void _arb_poly_sinc_series(arb_ptr g, arb_srcptr h, slong hlen, slong n, slong prec); void arb_poly_sinc_series(arb_poly_t g, const arb_poly_t h, slong n, slong prec); +void _arb_poly_sinc_pi_series(arb_ptr g, arb_srcptr h, slong hlen, slong n, slong prec); +void arb_poly_sinc_pi_series(arb_poly_t g, const arb_poly_t h, slong n, slong prec); + void _arb_poly_compose_series_brent_kung(arb_ptr res, arb_srcptr poly1, slong len1, arb_srcptr poly2, slong len2, slong n, slong prec); diff --git a/arb_poly/sinc_pi_series.c b/arb_poly/sinc_pi_series.c new file mode 100644 index 00000000..c91f8cc8 --- /dev/null +++ b/arb_poly/sinc_pi_series.c @@ -0,0 +1,80 @@ +/* + Copyright (C) 2016 Fredrik Johansson + Copyright (C) 2019 D.H.J. Polymath + + 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 . +*/ + +#include "arb_poly.h" + +void +_arb_poly_sinc_pi_series(arb_ptr g, arb_srcptr h, slong hlen, slong n, slong prec) +{ + hlen = FLINT_MIN(hlen, n); + + if (hlen == 1) + { + arb_sinc_pi(g, h, prec); + _arb_vec_zero(g + 1, n - 1); + } + else + { + arb_t pi; + arb_ptr t, u; + + arb_init(pi); + t = _arb_vec_init(n + 1); + u = _arb_vec_init(hlen); + + arb_const_pi(pi, prec); + _arb_vec_set(u, h, hlen); + + if (arb_is_zero(h)) + { + _arb_poly_sin_pi_series(t, u, hlen, n + 1, prec); + _arb_poly_div_series(g, t + 1, n, u + 1, hlen - 1, n, prec); + } + else + { + _arb_poly_sin_pi_series(t, u, hlen, n, prec); + _arb_poly_div_series(g, t, n, u, hlen, n, prec); + } + _arb_vec_scalar_div(g, g, n, pi, prec); + + arb_clear(pi); + _arb_vec_clear(t, n + 1); + _arb_vec_clear(u, hlen); + } +} + +void +arb_poly_sinc_pi_series(arb_poly_t g, const arb_poly_t h, slong n, slong prec) +{ + slong hlen = h->length; + + if (n == 0) + { + arb_poly_zero(g); + return; + } + + if (hlen == 0) + { + arb_poly_one(g); + return; + } + + if (hlen == 1) + n = 1; + + arb_poly_fit_length(g, n); + _arb_poly_sinc_pi_series(g->coeffs, h->coeffs, hlen, n, prec); + _arb_poly_set_length(g, n); + _arb_poly_normalise(g); +} + diff --git a/arb_poly/test/t-sinc_pi_series.c b/arb_poly/test/t-sinc_pi_series.c new file mode 100644 index 00000000..1beb075a --- /dev/null +++ b/arb_poly/test/t-sinc_pi_series.c @@ -0,0 +1,104 @@ +/* + Copyright (C) 2012, 2013 Fredrik Johansson + Copyright (C) 2019 D.H.J. Polymath + + 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 . +*/ + +#include "arb_poly.h" + +int main() +{ + slong iter; + flint_rand_t state; + + flint_printf("sinc_pi_series...."); + fflush(stdout); + + flint_randinit(state); + + for (iter = 0; iter < 200 * arb_test_multiplier(); iter++) + { + slong m, n1, n2, rbits1, rbits2, rbits3, rbits4; + arb_poly_t a, b, c, d; + arb_t pi; + + rbits1 = 2 + n_randint(state, 300); + rbits2 = 2 + n_randint(state, 300); + rbits3 = 2 + n_randint(state, 300); + rbits4 = 2 + n_randint(state, 300); + + m = n_randint(state, 15); + n1 = n_randint(state, 15); + n2 = n_randint(state, 15); + + arb_poly_init(a); + arb_poly_init(b); + arb_poly_init(c); + arb_poly_init(d); + arb_init(pi); + + arb_poly_randtest(a, state, m, rbits1, 10); + arb_poly_randtest(b, state, 10, rbits1, 10); + arb_poly_randtest(c, state, 10, rbits1, 10); + + arb_poly_sinc_pi_series(b, a, n1, rbits2); + arb_poly_sinc_pi_series(c, a, n2, rbits3); + + arb_poly_set(d, b); + arb_poly_truncate(d, FLINT_MIN(n1, n2)); + arb_poly_truncate(c, FLINT_MIN(n1, n2)); + + arb_const_pi(pi, rbits4); + + if (!arb_poly_overlaps(c, d)) + { + flint_printf("FAIL\n\n"); + flint_printf("n1 = %wd, n2 = %wd, bits2 = %wd, bits3 = %wd, bits4 = %wd\n", n1, n2, rbits2, rbits3, rbits4); + flint_printf("a = "); arb_poly_printd(a, 50); flint_printf("\n\n"); + flint_printf("b = "); arb_poly_printd(b, 50); flint_printf("\n\n"); + flint_printf("c = "); arb_poly_printd(c, 50); flint_printf("\n\n"); + flint_abort(); + } + + /* check pi x sinc_pi(x) = sin_pi(x) */ + arb_poly_mullow(c, b, a, n1, rbits2); + arb_poly_scalar_mul(c, c, pi, rbits2); + arb_poly_sin_pi_series(d, a, n1, rbits2); + + if (!arb_poly_overlaps(c, d)) + { + flint_printf("FAIL (functional equation)\n\n"); + flint_printf("a = "); arb_poly_printd(a, 15); flint_printf("\n\n"); + flint_printf("b = "); arb_poly_printd(b, 15); flint_printf("\n\n"); + flint_printf("c = "); arb_poly_printd(c, 15); flint_printf("\n\n"); + flint_printf("d = "); arb_poly_printd(d, 15); flint_printf("\n\n"); + flint_abort(); + } + + arb_poly_sinc_pi_series(a, a, n1, rbits2); + + if (!arb_poly_overlaps(a, b)) + { + flint_printf("FAIL (aliasing)\n\n"); + flint_abort(); + } + + arb_poly_clear(a); + arb_poly_clear(b); + arb_poly_clear(c); + arb_poly_clear(d); + arb_clear(pi); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} + diff --git a/doc/source/arb_poly.rst b/doc/source/arb_poly.rst index a1ec6e33..74708b82 100644 --- a/doc/source/arb_poly.rst +++ b/doc/source/arb_poly.rst @@ -983,6 +983,12 @@ Powers and elementary functions Sets *c* to the sinc function of the power series *h*, truncated to length *n*. +.. function:: void _arb_poly_sinc_pi_series(arb_ptr s, arb_srcptr h, slong hlen, slong n, slong prec) + +.. function:: void arb_poly_sinc_pi_series(arb_poly_t s, const arb_poly_t h, slong n, slong prec) + + Compute the sinc function of the input multiplied by `\pi`. + Lambert W function -------------------------------------------------------------------------------