temporary remove acb_dft and hide theta internals

This commit is contained in:
Pascal 2016-10-06 14:59:37 +02:00
parent 0428ebf806
commit 30525ec26a
23 changed files with 1 additions and 1988 deletions

View file

@ -13,7 +13,7 @@ QUIET_AR = @echo ' ' AR ' ' $@;
AT=@
BUILD_DIRS = fmpr arf mag arb arb_mat arb_poly arb_calc acb acb_mat acb_poly \
acb_calc acb_hypgeom acb_modular dirichlet acb_dft acb_dirichlet arb_hypgeom bernoulli hypgeom \
acb_calc acb_hypgeom acb_modular dirichlet acb_dirichlet arb_hypgeom bernoulli hypgeom \
fmpz_extras bool_mat partitions dlog \
$(EXTRA_BUILD_DIRS)

View file

@ -1,67 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
void
acb_dft_bluestein_init(acb_dft_bluestein_t t, slong n, slong prec)
{
nmod_t n2;
slong k, k2;
acb_ptr z2n;
int e = n_clog(2 * n - 1, 2);
acb_dft_rad2_init(t->rad2, e, prec);
z2n = _acb_vec_init(2 * n);
_acb_vec_nth_roots(z2n, 2 * n, prec);
nmod_init(&n2, 2 * n);
t->n = n;
t->z = _acb_vec_init(n);
for (k = 0, k2 = 0; k < n; k++)
{
acb_conj(t->z + k, z2n + k2);
k2 = nmod_add(k2, 2 * k + 1, n2);
}
_acb_vec_clear(z2n, 2 * n);
}
void
acb_dft_bluestein_precomp(acb_ptr w, acb_srcptr v, const acb_dft_bluestein_t t, slong prec)
{
slong n = t->n;
acb_ptr vz, wz, z;
z = t->z;
/* TODO: allocate directly length 2^e and pad */
flint_printf("\n\n====================\n\nv\n");
acb_vec_printd_index(v, n, 10);
vz = _acb_vec_init(n);
acb_vec_kronecker_mul_conj(vz, z, v, n, prec);
flint_printf("\nvz\n");
acb_vec_printd_index(vz, n, 10);
wz = _acb_vec_init(n);
acb_dft_convol_rad2_precomp(wz, vz, z, n, t->rad2, prec);
flint_printf("\nwz\n");
acb_vec_printd_index(wz, n, 10);
acb_vec_kronecker_mul_conj(w, z, wz, n, prec);
flint_printf("\nw\n");
acb_vec_printd_index(w, n, 10);
_acb_vec_clear(wz, n);
_acb_vec_clear(vz, n);
}
void
acb_dft_bluestein(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
acb_dft_bluestein_t t;
acb_dft_bluestein_init(t, len, prec);
acb_dft_bluestein_precomp(w, v, t, prec);
acb_dft_bluestein_clear(t);
}

View file

@ -1,105 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
/* assume np >= 2 * n - 1 */
void
acb_dft_convol_pad(acb_ptr fp, acb_ptr gp, acb_srcptr f, acb_srcptr g, slong n, slong np)
{
slong k;
if (np < 2 * n - 1)
{
flint_printf("dft_convol_pad: overlapping padding %ld < 2*%ld-1\n", np, n);
abort();
}
for (k = 0; k < n; k++)
acb_set(gp + k, g + k);
for (; k < np; k++)
acb_zero(gp + k);
for (k = 0; k < n; k++)
acb_set(fp + k, f + k);
for (k = 1; k < n; k++)
acb_set(fp + np - k, f + n - k);
for (k = n; k <= np - n; k++)
acb_zero(fp + k);
}
void
acb_dft_inverse_cyc(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
/* divide before to keep v const */
_acb_vec_scalar_div_ui(w, v, len, len, prec);
acb_vec_swap_ri(w, len);
acb_dft_cyc(w, w, len, prec);
acb_vec_swap_ri(w, len);
}
void
acb_dft_convol_rad2_precomp(acb_ptr w, acb_srcptr f, acb_srcptr g, slong len, const acb_dft_rad2_t rad2, slong prec)
{
slong np;
acb_ptr fp, gp;
np = rad2->n;
flint_printf("\nf\n");
acb_vec_printd_index(f, len, 10);
flint_printf("\ng\n");
acb_vec_printd_index(g, len, 10);
fp = _acb_vec_init(np);
gp = _acb_vec_init(np);
acb_dft_convol_pad(fp, gp, f, g, len, np);
flint_printf("\nF\n");
acb_vec_printd_index(fp, np, 10);
flint_printf("\nG\n");
acb_vec_printd_index(gp, np, 10);
acb_dft_rad2_precomp(fp, rad2, prec);
flint_printf("\nDFT F\n");
acb_vec_printd_index(fp, np, 10);
acb_dft_rad2_precomp(gp, rad2, prec);
flint_printf("\nDFT G\n");
acb_vec_printd_index(gp, np, 10);
_acb_vec_kronecker_mul(gp, gp, fp, np, prec);
flint_printf("\n(DFT F)(DFT G)=DFT(F*G)\n");
acb_vec_printd_index(gp, np, 10);
acb_dft_inverse_rad2_precomp(gp, rad2, prec);
flint_printf("\nF*G\n");
acb_vec_printd_index(gp, np, 10);
_acb_vec_set(w, gp, len);
_acb_vec_clear(fp, np);
_acb_vec_clear(gp, np);
}
void
acb_dft_convol_rad2(acb_ptr w, acb_srcptr f, acb_srcptr g, slong len, slong prec)
{
int e;
acb_dft_rad2_t dft;
e = n_clog(2 * len - 1, 2);
acb_dft_rad2_init(dft, e, prec);
acb_dft_convol_rad2_precomp(w, f, g, len, dft, prec);
acb_dft_rad2_clear(dft);
}

View file

@ -1,31 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
void
acb_dft_convol_naive(acb_ptr w, acb_srcptr f, acb_srcptr g, slong len, slong prec)
{
slong x, y;
for (x = 0; x < len; x ++)
{
acb_ptr wx;
acb_srcptr fx, gy;
wx = w + x;
fx = f + x;
gy = g;
acb_zero(wx);
for (y = 0; y <= x; y++)
acb_addmul(wx, fx - y, g + y, prec);
for (; y < len; y++)
acb_addmul(wx, fx + (len - y), g + y, prec);
}
}

View file

@ -1,176 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
void
crt_init(crt_t c, ulong n)
{
int k;
n_factor_t fac;
n_factor_init(&fac);
n_factor(&fac, n, 1);
nmod_init(&c->n, n);
c->num = fac.num;
for (k = 0; k < fac.num; k++)
{
c->m[k] = n_pow(fac.p[k], fac.exp[k]);
c->M[k] = n / c->m[k];
c->vM[k] = c->M[k] * n_invmod(c->M[k] % c->m[k], c->m[k]);
/*
flint_printf("m[%ld]=%ld, M[%ld]=%wu, vM[%ld]=%wu\n",
k, c->m[k], k, c->M[k], k, c->vM[k]);
*/
}
}
void
crt_print(const crt_t c)
{
slong k;
if (c->num == 0)
{
flint_printf("trivial group\n");
abort();
}
for (k = 0; k < c->num; k++)
flint_printf("Z/%wuZ ", c->m[k]);
flint_printf("\n");
}
#if 0
/* lexicographic index of crt elt j */
static ulong
index_crt(crt_t c, ulong j)
{
int k;
ulong res = 0;
for (k = 0; k < c->num; k ++)
res = res * c->m[k] + (j % c->m[k]);
return res;
}
/* crt elt of lexicographic index i */
static ulong
crt_index(crt_t c, ulong i)
{
int k;
ulong j, res = 0;
for (k = 0; k < c->num; k ++)
{
j = i % c->m[k];
i = i / c->m[k];
res = nmod_add(res, j * c->vM[k], c->n);
}
return res;
}
/* for all elements can do fast conrey-like loop just adding vM[k] */
static acb_ptr
reorder_to_crt(acb_srcptr v, crt_t c, ulong len)
{
ulong k;
acb_ptr res;
res = flint_malloc(len * sizeof(acb_struct));
for (k = 0; k < len; k++)
res[index_crt(c, k)] = v[k];
return res;
}
static acb_ptr
reorder_from_crt(acb_srcptr v, crt_t c, ulong len)
{
ulong k;
acb_ptr res;
res = flint_malloc(len * sizeof(acb_struct));
for (k = 0; k < len; k++)
res[k] = v[index_crt(c, k)];
return res;
}
#endif
void
crt_decomp(acb_ptr y, acb_srcptr x, slong dv, const crt_t c, ulong len)
{
int j, e[CRT_MAX];
ulong k, l;
for (j = 0; j < c->num; j++)
e[j] = 0;
l = 0;
for(k = 0; k < len; k++)
{
acb_set(y + k, x + l * dv);
for (j = c->num - 1; j >= 0; e[j] = 0, j--)
{
e[j]++; l = nmod_add(l, c->vM[j], c->n);
if (e[j] < c->m[j])
break;
}
}
}
void
crt_recomp(acb_ptr y, acb_srcptr x, const crt_t c, ulong len)
{
int j, e[CRT_MAX];
ulong k, l;
for (j = 0; j < c->num; j++)
e[j] = 0;
l = 0;
for(k = 0; k < len; k++)
{
acb_set(y + l, x + k);
for (j = c->num - 1; j >= 0; e[j] = 0, j--)
{
e[j]++; l = nmod_add(l, c->M[j], c->n);
if (e[j] < c->m[j])
break;
}
}
}
void
_acb_dft_crt_init(acb_dft_crt_t crt, slong dv, slong len, slong prec)
{
crt->n = len;
crt_init(crt->c, len);
crt->dv = dv;
crt->cyc = _acb_dft_steps_prod(crt->c->m, crt->c->num, prec);
}
void
acb_dft_crt_precomp(acb_ptr w, acb_srcptr v, const acb_dft_crt_t crt, slong prec)
{
acb_ptr t;
t = _acb_vec_init(crt->n);
crt_decomp(w, v, crt->dv, crt->c, crt->n);
acb_dft_step(t, w, crt->cyc, crt->c->num, prec);
crt_recomp(w, t, crt->c, crt->n);
_acb_vec_clear(t, crt->n);
}
void
acb_dft_crt(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
crt_t c;
acb_ptr t;
t = _acb_vec_init(len);
crt_init(c, len);
crt_decomp(w, v, 1, c, len);
acb_dft_prod(t, w, c->m, c->num, prec);
crt_recomp(w, t, c, len);
_acb_vec_clear(t, len);
}

View file

@ -1,93 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
void
_acb_dft_cyc_init_z_fac(acb_dft_cyc_t t, n_factor_t fac, slong dv, acb_ptr z, slong dz, slong len, slong prec)
{
slong i, j, num;
t->n = len;
num = 0;
for (i = 0; i < fac.num; i++)
num += fac.exp[i];
t->num = num;
t->cyc = flint_malloc(num * sizeof(acb_dft_step_struct));
if (z == NULL)
{
z = _acb_vec_init(t->n);
_acb_vec_nth_roots(z, t->n, prec);
dz = 1;
t->zclear = 1;
}
else
{
if (DFT_VERB)
flint_printf("dft_cyc: roots of order %wu already computed\n", t->n);
t->zclear = 0;
}
t->z = z;
num = 0;
for (i = 0; i < fac.num; i++)
{
for (j = 0; j < fac.exp[i]; j++)
{
slong m, M;
m = fac.p[i];
M = (len /= m);
t->cyc[num].m = m;
t->cyc[num].M = M;
t->cyc[num].dv = dv;
t->cyc[num].z = z;
t->cyc[num].dz = dz;
/* TODO: ugly, reorder should solve this */
if (num == t->num - 1)
_acb_dft_precomp_init(t->cyc[num].pre, dv, z, dz, m, prec);
else
_acb_dft_precomp_init(t->cyc[num].pre, M, z, dz * M, m, prec);
dv *= m;
dz *= m;
num++;
}
}
}
void
_acb_dft_cyc_init(acb_dft_cyc_t t, slong dv, slong len, slong prec)
{
n_factor_t fac;
n_factor_init(&fac);
n_factor(&fac, len, 0);
_acb_dft_cyc_init_z_fac(t, fac, dv, NULL, 0, len, prec);
}
void
acb_dft_cyc_clear(acb_dft_cyc_t t)
{
slong i;
for (i = 0; i < t->num; i++)
acb_dft_precomp_clear(t->cyc[i].pre);
if (t->zclear)
_acb_vec_clear(t->z, t->n);
flint_free(t->cyc);
}
void
acb_dft_cyc(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
acb_dft_cyc_t cyc;
acb_dft_cyc_init(cyc, len, prec);
acb_dft_cyc_precomp(w, v, cyc, prec);
acb_dft_cyc_clear(cyc);
}

View file

@ -1,278 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dirichlet.h"
/* shallow extract */
static acb_ptr
vec_extract(acb_srcptr v, slong step, slong len)
{
slong k, l;
acb_ptr res;
res = flint_malloc(len * sizeof(acb_struct));
for (k = 0, l = 0; k < len; k++, l+=step)
res[k] = v[l];
return res;
}
void
_acb_dft_base(acb_ptr w, acb_srcptr v, slong dv, acb_srcptr z, slong dz, slong n, slong prec)
{
acb_ptr v1, z1;
v1 = vec_extract(v, dv, n);
z1 = vec_extract(z, dz, n);
_acb_dirichlet_dft_pol(w, v1, z1, n, prec);
flint_free(v1);
flint_free(z1);
}
typedef struct
{
slong m;
slong M;
slong dv;
acb_srcptr z;
slong dz;
}
dft_cyc_step;
typedef struct
{
slong n;
acb_ptr z;
slong num;
dft_cyc_step * cyc;
}
acb_dft_cyc_struct;
typedef acb_dft_cyc_struct acb_dft_cyc_t[1];
typedef struct
{
slong m;
slong M;
slong dv;
acb_dft_cyc_t pre;
}
dft_prod_step;
typedef struct
{
slong n;
slong num;
dft_prod_step * cyc;
}
acb_dft_prod_struct;
typedef acb_dft_prod_struct acb_dft_prod_t[1];
void
_acb_dirichlet_dft_cyc_init(acb_dft_cyc_t t, slong len, slong dv, slong prec)
{
slong i, j, num, dz;
n_factor_t fac;
acb_ptr z;
t->n = len;
n_factor_init(&fac);
n_factor(&fac, len, 0);
num = 0;
for (i = 0; i < fac.num; i++)
num += fac.exp[i];
t->num = num;
t->cyc = flint_malloc(num * sizeof(dft_cyc_step));
t->z = z = _acb_vec_init(t->n);
acb_dirichlet_vec_nth_roots(z, t->n, prec);
num = 0;
dz = 1;
for (i = 0; i < fac.num; i++)
{
for (j = 0; j < fac.exp[i]; j++)
{
slong m = fac.p[i];
t->cyc[num].m = m;
t->cyc[num].M = (len /= m);
t->cyc[num].dv = dv;
t->cyc[num].z = z;
t->cyc[num].dz = dz;
dv *= m;
dz *= m;
num++;
}
}
}
static void
acb_dirichlet_dft_cyc_init(acb_dft_cyc_t t, slong len, slong prec)
{
_acb_dirichlet_dft_cyc_init(t, len, 1, prec);
}
void
acb_dirichlet_dft_cyc_clear(acb_dft_cyc_t t)
{
_acb_vec_clear(t->z, t->n);
flint_free(t->cyc);
}
void
_acb_dft_cyc(acb_ptr w, acb_srcptr v, dft_cyc_step * cyc, slong num, slong prec)
{
dft_cyc_step c;
if (num == 0)
abort(); /* or just copy v to w */
c = cyc[0];
if (num == 1)
{
_acb_dft_base(w, v, c.dv, c.z, c.dz, c.m, prec);
}
else
{
slong i, j;
slong m = c.m, M = c.M, dv = c.dv, dz = c.dz;
acb_srcptr z = c.z, vi;
acb_ptr t, wi;
t = _acb_vec_init(m * M);
wi = w; vi = v;
for (i = 0; i < m; i++)
{
_acb_dft_cyc(wi, vi, cyc + 1, num - 1, prec);
if (i)
{
for (j = 1; j < M; j++)
acb_mul(wi + j, wi + j, z + dz * i * j, prec);
}
wi += M;
vi += dv;
}
/* after first pass */
for (j = 0; j < M; j++)
_acb_dft_base(t + m * j, w + j, M, z, dz * M, m, prec);
/* reorder */
for (i = 0; i < m; i++)
for (j = 0; j < M; j++)
acb_set(w + j + M * i, t + i + m * j);
_acb_vec_clear(t, m * M);
}
}
void
acb_dirichlet_dft_cyc_precomp(acb_ptr w, acb_srcptr v, acb_dft_cyc_t t, slong prec)
{
_acb_dft_cyc(w, v, t->cyc, t->num, prec);
}
void
acb_dirichlet_dft_fast(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
acb_dft_cyc_t t;
acb_dirichlet_dft_cyc_init(t, len, prec);
acb_dirichlet_dft_cyc_precomp(w, v, t, prec);
acb_dirichlet_dft_cyc_clear(t);
}
void
_acb_dft_prod(acb_ptr w, acb_srcptr v, dft_prod_step * cyc, slong num, slong prec)
{
dft_prod_step c;
if (num == 0)
{
flint_printf("error: reached num = 0 in dft_prod\n");
abort(); /* or just copy v to w */
}
c = cyc[0];
if (num == 1)
{
acb_dirichlet_dft_cyc_precomp(w, v, c.pre, prec);
}
else
{
slong i, j;
slong m = c.m, M = c.M, dv = c.dv;
acb_srcptr vi;
acb_ptr t, wi;
t = _acb_vec_init(m * M);
wi = w; vi = v;
for (i = 0; i < m; i++)
{
_acb_dft_prod(wi, vi, cyc + 1, num - 1, prec);
wi += M;
vi += dv; /* here = M */
}
/* after first pass */
for (j = 0; j < M; j++)
acb_dirichlet_dft_cyc_precomp(t + m * j, w + j, c.pre, prec);
/* reorder */
for (i = 0; i < m; i++)
for (j = 0; j < M; j++)
acb_set(w + j + M * i, t + i + m * j);
_acb_vec_clear(t, m * M);
}
}
void
acb_dirichlet_dft_prod_precomp(acb_ptr w, acb_srcptr v, acb_dft_prod_t t, slong prec)
{
if (t->num == 0)
{
acb_set(w + 0, v + 0);
}
else
{
_acb_dft_prod(w, v, t->cyc, t->num, prec);
}
}
void
acb_dirichlet_dft_prod_init(acb_dft_prod_t t, slong * cyc, slong num, slong prec)
{
slong i, len, dv;
t->num = num;
t->cyc = flint_malloc(num * sizeof(dft_prod_step));
len = 1; dv = 1;
for (i = 0; i < num; i++)
len *= cyc[i];
for (i = 0; i < num; i++)
{
slong m = cyc[i];
len /= m;
t->cyc[i].m = m;
t->cyc[i].M = len;
t->cyc[i].dv = len;
_acb_dirichlet_dft_cyc_init(t->cyc[i].pre, m, len, prec);
dv *= m;
}
}
void
acb_dirichlet_dft_prod_clear(acb_dft_prod_t t)
{
slong i;
for (i = 0; i < t->num; i++)
acb_dirichlet_dft_cyc_clear(t->cyc[i].pre);
flint_free(t->cyc);
}
void
acb_dirichlet_dft_prod(acb_ptr w, acb_srcptr v, slong * cyc, slong num, slong prec)
{
acb_dft_prod_t t;
acb_dirichlet_dft_prod_init(t, cyc, num, prec);
acb_dirichlet_dft_prod_precomp(w, v, t, prec);
acb_dirichlet_dft_prod_clear(t);
}

View file

@ -1,62 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_poly.h"
#include "acb_dft.h"
/* all roots are already computed */
void
_acb_dft_pol(acb_ptr w, acb_srcptr v, slong dv, acb_srcptr z, slong dz, slong len, slong prec)
{
slong i, j;
acb_ptr wi;
acb_srcptr vj;
for (i = 0, wi = w; i < len; i++, wi++)
{
acb_zero(wi);
for (j = 0, vj = v; j < len; j++, vj += dv)
acb_addmul(wi, vj, z + dz * (i * j % len), prec);
}
}
void
acb_dft_pol(acb_ptr w, acb_srcptr v, slong len, slong prec)
{
acb_ptr z;
z = _acb_vec_init(len);
_acb_vec_nth_roots(z, len, prec);
_acb_dft_pol(w, v, 1, z, 1, len, prec);
_acb_vec_clear(z, len);
}
void
_acb_dft_pol_init(acb_dft_pol_t pol, slong dv, acb_ptr z, slong dz, slong len, slong prec)
{
pol->n = len;
pol->dv = dv;
if (z == NULL)
{
if (DFT_VERB)
flint_printf("warning: init z[%ld] in dft_pol, should be avoided\n",len);
pol->z = _acb_vec_init(len);
_acb_vec_nth_roots(pol->z, len, prec);
pol->dz = 1;
pol->zclear = 1;
}
else
{
pol->z = z;
pol->dz = dz;
pol->zclear = 0;
}
}

View file

@ -1,101 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
void
_acb_dft_precomp_init(acb_dft_pre_t pre, slong dv, acb_ptr z, slong dz, slong len, slong prec)
{
if (len <= 1)
{
flint_printf("precomp init: trivial group. abort.\n");
abort();
}
if (n_is_prime(len))
{
/* TODO: need convolution if len is large */
pre->type = DFT_POL;
_acb_dft_pol_init(pre->t.pol, dv, z, dz, len, prec);
}
else
{
n_factor_t fac;
n_factor_init(&fac);
n_factor(&fac, len, 1);
if (fac.num == 1)
{
/* TODO: could be p^e, or 2^e */
pre->type = DFT_CYC;
_acb_dft_cyc_init_z_fac(pre->t.cyc, fac, dv, z, dz, len, prec);
}
else
{
pre->type = DFT_CRT;
_acb_dft_crt_init(pre->t.crt, dv, len, prec);
}
}
}
void
acb_dft_precomp_init(acb_dft_pre_t pre, slong len, slong prec)
{
_acb_dft_precomp_init(pre, 1, NULL, 0, len, prec);
}
void
acb_dft_precomp_clear(acb_dft_pre_t pre)
{
switch (pre->type)
{
case DFT_POL:
acb_dft_pol_clear(pre->t.pol);
break;
case DFT_CYC:
acb_dft_cyc_clear(pre->t.cyc);
break;
case DFT_PROD:
acb_dft_prod_clear(pre->t.prod);
break;
case DFT_CRT:
acb_dft_crt_clear(pre->t.crt);
break;
default:
flint_printf("acb_dft_clear: unknown strategy code %i\n", pre->type);
abort();
break;
}
}
void
acb_dft_precomp(acb_ptr w, acb_srcptr v, const acb_dft_pre_t pre, slong prec)
{
switch (pre->type)
{
case DFT_POL:
acb_dft_pol_precomp(w, v, pre->t.pol, prec);
break;
case DFT_CYC:
acb_dft_cyc_precomp(w, v, pre->t.cyc, prec);
break;
case DFT_PROD:
acb_dft_prod_precomp(w, v, pre->t.prod, prec);
break;
case DFT_CRT:
acb_dft_crt_precomp(w, v, pre->t.crt, prec);
break;
default:
flint_printf("acb_dft_precomp: unknown strategy code %i\n", pre->type);
abort();
break;
}
}

View file

@ -1,67 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
acb_dft_step_ptr
_acb_dft_steps_prod(slong * cyc, slong num, slong prec)
{
slong i, len;
acb_dft_step_ptr s;
s = flint_malloc(num * sizeof(acb_dft_step_struct));
len = 1;
for (i = 0; i < num; i++)
len *= cyc[i];
for (i = 0; i < num; i++)
{
slong m, M;
m = cyc[i];
M = (len /= m);
s[i].m = m;
s[i].M = M;
s[i].dv = M;
s[i].dz = 0;
s[i].z = NULL;
_acb_dft_precomp_init(s[i].pre, M, NULL, 0, m, prec);
}
return s;
}
void
acb_dft_prod_clear(acb_dft_prod_t t)
{
slong i;
for (i = 0; i < t->num; i++)
acb_dft_precomp_clear(t->cyc[i].pre);
flint_free(t->cyc);
}
void
acb_dft_prod_precomp(acb_ptr w, acb_srcptr v, const acb_dft_prod_t prod, slong prec)
{
if (prod->num == 0)
acb_set(w + 0, v + 0);
else
acb_dft_step(w, v, prod->cyc, prod->num, prec);
}
void
acb_dft_prod(acb_ptr w, acb_srcptr v, slong * cyc, slong num, slong prec)
{
acb_dft_prod_t t;
acb_dft_prod_init(t, cyc, num, prec);
acb_dft_prod_precomp(w, v, t, prec);
acb_dft_prod_clear(t);
}

View file

@ -1,80 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
/* swap each element with one with bit-reversed index */
void
acb_dft_rad2_reorder(acb_ptr v, slong n)
{
slong i, j, k, l;
for (i = 0, l = n>>1; i < l; i++)
{
/* j = bit reversal of i */
for (k = 1, j = 0; k < n; k <<= 1)
{
j <<= 1;
if (i & k)
j |= 1;
}
if (i < j)
acb_swap(v + i, v + j);
else if (i > j)
acb_swap(v + n - 1 - i, v + n - 1 - j);
i++, j |= l;
acb_swap(v + i, v + j);
}
}
/* remark: can use same rad2 with smaller power of 2 */
void
acb_dft_rad2_precomp(acb_ptr v, const acb_dft_rad2_t rad2, slong prec)
{
slong j, k, l;
slong n = rad2->n, nz = rad2->nz;
acb_ptr p, vend = v + n, w = rad2->z;
acb_t tmp;
acb_init(tmp);
acb_dft_rad2_reorder(v, n);
for (k = 1, l = nz; k < n; k <<= 1, l >>= 1)
for (p = v; p < vend; p += k)
for (j = 0; j < nz; j += l, p++)
{
acb_mul(tmp, p + k, w + j, prec);
acb_sub(p + k, p + 0, tmp, prec);
acb_add(p + 0, p + 0, tmp, prec);
}
acb_clear(tmp);
}
void
acb_dft_inverse_rad2_precomp(acb_ptr v, const acb_dft_rad2_t rad2, slong prec)
{
slong k, n = rad2->n;
acb_dft_rad2_precomp(v, rad2, prec);
_acb_vec_scalar_mul_2exp_si(v, v, n, - rad2->e);
for (k = 1; k < n / 2; k++)
acb_swap(v + k, v + n - k);
}
void
acb_dft_rad2(acb_ptr v, int e, slong prec)
{
acb_dft_rad2_t rad2;
acb_dft_rad2_init(rad2, e, prec);
acb_dft_rad2_precomp(v, rad2, prec);
acb_dft_rad2_clear(rad2);
}

View file

@ -1,75 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
#define REORDER 0
void
acb_dft_step(acb_ptr w, acb_srcptr v, acb_dft_step_ptr cyc, slong num, slong prec)
{
acb_dft_step_struct c;
if (num == 0)
{
flint_printf("error: reached num = 0 in acb_dft_step\n");
abort(); /* or just copy v to w */
}
c = cyc[0];
if (num == 1)
{
acb_dft_precomp(w, v, c.pre, prec);
/*_acb_dft_base(w, v, c.dv, c.z, c.dz, c.m, prec);*/
}
else
{
slong i, j;
slong m = c.m, M = c.M, dv = c.dv, dz = c.dz;
acb_srcptr z = c.z;
acb_ptr t;
#if REORDER
acb_ptr w2;
#endif
t = _acb_vec_init(m * M);
/* m DFT of size M */
for (i = 0; i < m; i++)
acb_dft_step(w + i * M, v + i * dv, cyc + 1, num - 1, prec);
/* twiddle if non trivial product */
if (c.z != NULL)
{
acb_ptr wi;
for (wi = w + M, i = 1; i < m; i++, wi += M)
for (j = 1; j < M; j++)
acb_mul(wi + j, wi + j, z + dz * i * j, prec);
}
#if REORDER
/* reorder w to avoid dv shifts in next DFT */
w2 = flint_malloc(m * M * sizeof(acb_struct));
for (j = 0; j < M; j++)
for (i = 0; i < m; i++)
w2[j + M * i] = w[i + m * j];
#endif
/* M DFT of size m */
for (j = 0; j < M; j++)
acb_dft_precomp(t + m * j, w + j, c.pre, prec);
/* reorder */
for (i = 0; i < m; i++)
for (j = 0; j < M; j++)
acb_set(w + j + M * i, t + i + m * j);
_acb_vec_clear(t, m * M);
}
}

View file

@ -1,118 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
typedef void (*do_f) (acb_ptr z, acb_srcptr x, acb_srcptr y, slong len, slong prec);
void
check_vec_eq_prec(acb_srcptr w1, acb_srcptr w2, slong len, slong prec, slong digits, ulong q, char f1[], char f2[])
{
slong i;
for (i = 0; i < len; i++)
{
if (!acb_overlaps(w1 + i, w2 + i))
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu, size = %wu\n", q, len);
flint_printf("\nDFT differ from index %ld / %ld \n", i, len);
flint_printf("\n%s =\n", f1);
acb_vec_printd_index(w1, len, digits);
flint_printf("\n%s =\n", f2);
acb_vec_printd_index(w2, len, digits);
flint_printf("\n\n");
abort();
}
else if (!acb_is_zero(w1+i) && (acb_rel_accuracy_bits(w1 + i) < 30
|| acb_rel_accuracy_bits(w2 + i) < 30))
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu\n", q);
flint_printf("\nDFT inaccurate from index %ld / %ld \n", i, len);
flint_printf("\nnaive =\n");
acb_printd(w1 + i, digits);
flint_printf("\nfast =\n");
acb_printd(w2 + i, digits);
flint_printf("\nerrors %ld & %ld [prec = %wu]\n",
acb_rel_accuracy_bits(w1 + i),
acb_rel_accuracy_bits(w2 + i), prec);
abort();
}
}
}
int main()
{
slong k;
slong prec = 100, digits = 30;
slong nq = 13;
ulong q[13] = { 2, 3, 4, 5, 6, 23, 10, 15, 30, 59, 308, 335, 961};
flint_rand_t state;
slong f, nf = 2;
do_f func[2] = { acb_dft_convol_naive, acb_dft_convol_rad2 };
char * name[4] = { "naive", "rad2" };
flint_printf("convol....");
fflush(stdout);
flint_randinit(state);
for (k = 0; k < nq; k++)
{
slong i;
acb_ptr z1, z2, x, y;
z1 = _acb_vec_init(q[k]);
z2 = _acb_vec_init(q[k]);
x = _acb_vec_init(q[k]);
y = _acb_vec_init(q[k]);
for (i = 0; i < q[k]; i++)
{
acb_set_si(x + i, q[k] - i);
acb_set_si(y + i, i * i);
/*
acb_set_si(x + i, n_randint(state, q[k]));
acb_set_si(y + i, n_randint(state, q[k]));
*/
}
for (f = 0; f < nf; f++)
{
acb_ptr z = (f == 0) ? z1 : z2;
func[f](z, x, y, q[k], prec);
if (f == 0)
continue;
check_vec_eq_prec(z1, z2, q[k], prec, digits, q[k], name[0], name[f]);
}
_acb_vec_clear(x, q[k]);
_acb_vec_clear(y, q[k]);
_acb_vec_clear(z1, q[k]);
_acb_vec_clear(z2, q[k]);
}
flint_randclear(state);
flint_cleanup();
flint_printf("PASS\n");
return EXIT_SUCCESS;
}

View file

@ -1,127 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
typedef void (*do_f) (acb_ptr w, acb_srcptr v, slong len, slong prec);
void
check_vec_eq_prec(acb_srcptr w1, acb_srcptr w2, slong len, slong prec, slong digits, ulong q, char f1[], char f2[])
{
slong i;
for (i = 0; i < len; i++)
{
if (!acb_overlaps(w1 + i, w2 + i))
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu, size = %wu\n", q, len);
flint_printf("\nDFT differ from index %ld / %ld \n", i, len);
flint_printf("\n%s =\n", f1);
acb_vec_printd_index(w1, len, digits);
flint_printf("\n%s =\n", f2);
acb_vec_printd_index(w2, len, digits);
flint_printf("\n\n");
abort();
}
else if (acb_rel_accuracy_bits(w1 + i) < 30
|| acb_rel_accuracy_bits(w2 + i) < 30)
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu\n", q);
flint_printf("\nDFT inaccurate from index %ld / %ld \n", i, len);
flint_printf("\nnaive =\n");
acb_printd(w1 + i, digits);
flint_printf("\nfast =\n");
acb_printd(w2 + i, digits);
flint_printf("\nerrors %ld & %ld [prec = %wu]\n",
acb_rel_accuracy_bits(w1 + i),
acb_rel_accuracy_bits(w2 + i), prec);
abort();
}
}
}
int main()
{
slong k;
slong prec = 100, digits = 30;
slong nq = 13;
ulong q[13] = { 2, 3, 4, 5, 6, 23, 10, 15, 30, 59, 308, 335, 961};
flint_rand_t state;
slong f, nf = 4;
do_f func[4] = { acb_dft_pol, acb_dft_cyc, acb_dft_crt , acb_dft_bluestein };
char * name[4] = { "pol", "cyc", "crt", "bluestein" };
flint_printf("dft....");
fflush(stdout);
flint_randinit(state);
/* cyclic dft */
for (k = 0; k < nq; k++)
{
slong i;
acb_ptr v, w1, w2;
v = _acb_vec_init(q[k]);
w1 = _acb_vec_init(q[k]);
w2 = _acb_vec_init(q[k]);
for (i = 0; i < q[k]; i++)
acb_set_si(v + i, i);
for (f = 0; f < nf; f++)
{
acb_ptr w = (f == 0) ? w1 : w2;
func[f](w, v, q[k], prec);
if (f == 0)
continue;
check_vec_eq_prec(w1, w2, q[k], prec, digits, q[k], name[0], name[f]);
}
_acb_vec_clear(v, q[k]);
_acb_vec_clear(w1, q[k]);
_acb_vec_clear(w2, q[k]);
}
/* radix2 dft */
for (k = 1; k < 12; k++)
{
slong n = 1 << k, j;
acb_ptr v, w1, w2;
v = w2 = _acb_vec_init(n);
w1 = _acb_vec_init(n);
for (j = 0; j < n; j++)
acb_set_si(v + k, k);
acb_dft_pol(w1, v, n, prec);
acb_dft_rad2(v, k, prec);
check_vec_eq_prec(w1, w2, n, prec, digits, n, "pol", "rad2");
}
flint_randclear(state);
flint_cleanup();
flint_printf("PASS\n");
return EXIT_SUCCESS;
}

View file

@ -88,12 +88,6 @@ void acb_dirichlet_jacobi_sum(acb_t res, const dirichlet_group_t G, const dirich
void acb_dirichlet_jacobi_sum_ui(acb_t res, const dirichlet_group_t G, ulong a, ulong b, slong prec);
void acb_dirichlet_l_hurwitz(acb_t res, const acb_t s, const dirichlet_group_t G, const dirichlet_char_t chi, slong prec);
void acb_dirichlet_l_vec_hurwitz(acb_ptr res, const acb_t s, const dirichlet_group_t G, slong prec);
/* Discrete Fourier Transform */
void acb_dirichlet_dft_conrey(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec);
void acb_dirichlet_dft(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec);
/* utils */

View file

@ -1,60 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dft.h"
#include "acb_dirichlet.h"
/* dft, lexicographic conrey indexing, array size G->phi_q */
void
acb_dirichlet_dft_conrey(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)
{
slong k, l, * cyc;
cyc = flint_malloc(G->num * sizeof(slong));
for (k = 0, l = G->num - 1; l >= 0; k++, l--)
cyc[k] = G->P[k].phi;
acb_dft_prod(w, v, cyc, G->num, prec);
flint_free(cyc);
}
/* dft, number indexing, array size G->q */
void
acb_dirichlet_dft(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)
{
ulong i, len;
acb_ptr t1, t2;
dirichlet_conrey_t x;
len = G->phi_q;
t1 = flint_malloc(len * sizeof(acb_struct));
dirichlet_conrey_init(x, G);
dirichlet_conrey_one(x, G);
for (i = 0; i < len; i++)
{
t1[i] = v[x->n];
dirichlet_conrey_next(x, G);
};
t2 = _acb_vec_init(len);
acb_dirichlet_dft_conrey(t2, t1, G, prec);
dirichlet_conrey_one(x, G);
for (i = 0; i < len; i++)
{
acb_set(w + x->n, t2 + i);
dirichlet_conrey_next(x, G);
};
_acb_vec_clear(t2, len);
dirichlet_conrey_clear(x);
flint_free(t1);
}

View file

@ -1,65 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dirichlet.h"
#include "acb_poly.h"
void
acb_dirichlet_l_vec_hurwitz(acb_ptr res, const acb_t s,
const dirichlet_group_t G, slong prec)
{
acb_t a, qs;
acb_ptr zeta, z;
dirichlet_conrey_t cn;
int deflate;
/* remove pole in Hurwitz zeta at s = 1 */
deflate = acb_is_one(s);
dirichlet_conrey_init(cn, G);
acb_init(qs);
acb_init(a);
prec += n_clog(G->phi_q, 2);
acb_set_ui(qs, G->q);
acb_neg(a, s);
acb_pow(qs, qs, a, prec);
zeta = z = _acb_vec_init(G->phi_q);
dirichlet_conrey_one(cn, G);
do {
acb_set_ui(a, cn->n);
acb_div_ui(a, a, G->q, prec);
if (!deflate)
acb_hurwitz_zeta(z, s, a, prec);
else
_acb_poly_zeta_cpx_series(z, s, a, 1, 1, prec);
acb_mul(z, z, qs, prec);
z++;
} while (dirichlet_conrey_next(cn, G) >= 0);
acb_dirichlet_dft_conrey(res, zeta, G, prec);
/* restore pole for the principal character */
if (deflate)
acb_indeterminate(res);
dirichlet_conrey_clear(cn);
_acb_vec_clear(zeta, G->phi_q);
acb_clear(qs);
acb_clear(a);
}

View file

@ -1,125 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dirichlet.h"
typedef void (*do_f) (acb_ptr w, acb_srcptr v, slong len, slong prec);
void
check_vec_eq_prec(acb_srcptr w1, acb_srcptr w2, slong len, slong prec, slong digits, ulong q, char f1[], char f2[])
{
slong i;
for (i = 0; i < len; i++)
{
if (!acb_overlaps(w1 + i, w2 + i))
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu, size = %wu\n", q, len);
flint_printf("\nDFT differ from index %ld / %ld \n", i, len);
flint_printf("\n%s =\n", f1);
acb_vec_printd(w1, len, digits);
flint_printf("\n%s =\n", f2);
acb_vec_printd(w2, len, digits);
flint_printf("\n\n");
abort();
}
else if (acb_rel_accuracy_bits(w1 + i) < 30
|| acb_rel_accuracy_bits(w2 + i) < 30)
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu\n", q);
flint_printf("\nDFT inaccurate from index %ld / %ld \n", i, len);
flint_printf("\nnaive =\n");
acb_printd(w1 + i, digits);
flint_printf("\nfast =\n");
acb_printd(w2 + i, digits);
flint_printf("\nerrors %ld & %ld [prec = %wu]\n",
acb_rel_accuracy_bits(w1 + i),
acb_rel_accuracy_bits(w2 + i), prec);
abort();
}
}
}
int main()
{
slong k;
slong prec = 100, digits = 30;
slong nq = 13;
ulong q[13] = { 2, 3, 4, 5, 6, 23, 10, 15, 30, 59, 308, 335, 961};
flint_rand_t state;
flint_printf("dft....");
fflush(stdout);
flint_randinit(state);
/* Dirichlet group DFT */
for (k = 0; k < nq; k++)
{
slong i, j, len;
dirichlet_group_t G;
dirichlet_conrey_t x, y;
acb_t chiy;
acb_ptr v, w1, w2;
dirichlet_group_init(G, q[k]);
len = G->phi_q;
v = _acb_vec_init(len);
w1 = _acb_vec_init(len);
w2 = _acb_vec_init(len);
dirichlet_conrey_init(x, G);
dirichlet_conrey_one(x, G);
for (i = 0; i < len; i++)
acb_randtest_precise(v + i, state, prec, 0);
/* naive */
acb_init(chiy);
dirichlet_conrey_init(y, G);
dirichlet_conrey_one(x, G);
for (i = 0; i < len; i++)
{
acb_zero(w1 + i);
dirichlet_conrey_one(y, G);
for (j = 0; j < len; j++)
{
acb_dirichlet_pairing_conrey(chiy, G, x, y, prec);
acb_addmul(w1 + i, chiy, v + j, prec);
dirichlet_conrey_next(y, G);
}
dirichlet_conrey_next(x, G);
}
acb_clear(chiy);
dirichlet_conrey_clear(y);
dirichlet_conrey_clear(x);
/* dft */
acb_dirichlet_dft_conrey(w2, v, G, prec);
check_vec_eq_prec(w1, w2, len, prec, digits, q[k], "naive", "group");
_acb_vec_clear(v, len);
_acb_vec_clear(w1, len);
_acb_vec_clear(w2, len);
dirichlet_group_clear(G);
}
flint_randclear(state);
flint_cleanup();
flint_printf("PASS\n");
return EXIT_SUCCESS;
}

View file

@ -14,77 +14,6 @@
#define nq 5
#define nx 3
void
test_dft(ulong q)
{
ulong i;
slong prec = 100;
dirichlet_group_t G;
dirichlet_conrey_t x;
dirichlet_char_t chi;
acb_t s, z;
acb_ptr v;
dirichlet_group_init(G, q);
dirichlet_conrey_init(x, G);
dirichlet_char_init(chi, G);
acb_init(s);
acb_one(s);
acb_div_si(s, s, 2, prec);
v = _acb_vec_init(G->phi_q);
/* all at once */
acb_dirichlet_l_vec_hurwitz(v, s, G, prec);
/* check with complete loop */
i = 0;
acb_init(z);
dirichlet_conrey_one(x, G);
do {
dirichlet_char_conrey(chi, G, x);
acb_dirichlet_l_hurwitz(z, s, G, chi, prec);
if (!acb_overlaps(z, v + i))
{
flint_printf("\n L value differ");
flint_printf("\nL(1/2, %wu) single = ", x->n);
acb_printd(z, 20);
flint_printf("\nL(1/2, %wu) multi = ", x->n);
acb_printd(v + i, 20);
flint_printf("\n\n");
acb_vec_printd(v, G->phi_q, 10);
flint_printf("\n\n");
}
else if (acb_rel_accuracy_bits(z) < prec - 8
|| acb_rel_accuracy_bits(v + i) < prec - 8)
{
flint_printf("FAIL\n\n");
flint_printf("q = %wu\n", q);
flint_printf("\nL(1/2,chi_%wu(%wu,)) inaccurate\n", q, x->n);
flint_printf("\nsingle =\n");
acb_printd(z, 30);
flint_printf("\ndft =\n");
acb_printd(v + i, 30);
flint_printf("\nerrors %ld & %ld [prec = %wu]\n",
acb_rel_accuracy_bits(z),
acb_rel_accuracy_bits(v + i), prec);
abort();
}
i++;
} while (dirichlet_conrey_next(x, G) >= 0);
acb_clear(s);
_acb_vec_clear(v, G->phi_q);
dirichlet_char_clear(chi);
dirichlet_conrey_clear(x);
dirichlet_group_clear(G);
}
int main()
{
@ -204,9 +133,6 @@ int main()
dirichlet_char_clear(chi);
dirichlet_group_clear(G);
/* test using dft */
test_dft(q[i]);
}
acb_clear(ref);
acb_clear(res);

View file

@ -1,56 +0,0 @@
/*
Copyright (C) 2016 Pascal Molin
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 "acb_dirichlet.h"
void
acb_dirichlet_vec_mellin_arb(acb_ptr res, const dirichlet_group_t G, const dirichlet_char_t chi, slong len, const arb_t t, slong n, slong prec)
{
slong k;
arb_t tk, xt, stk, st;
acb_ptr a;
mag_t e;
a = _acb_vec_init(len);
acb_dirichlet_chi_vec(a, G, chi, len, prec);
if (chi->parity)
{
for (k = 2; k < len; k++)
acb_mul_si(a + k, a + k, k, prec);
}
arb_init(tk);
arb_init(xt);
arb_init(st);
arb_init(stk);
mag_init(e);
arb_sqrt(st, t, prec);
arb_one(tk);
arb_one(stk);
for (k = 0; k < n; k++)
{
_acb_dirichlet_theta_argument_at_arb(xt, G->q, tk, prec);
mag_tail_kexpk2_arb(e, xt, len);
arb_neg(xt, xt);
arb_exp(xt, xt, prec);
/* TODO: reduce len */
acb_dirichlet_qseries_arb(res + k, a, xt, len, prec);
acb_add_error_mag(res + k, e);
acb_mul_arb(res + k, res + k, stk, prec);
arb_mul(tk, tk, t, prec);
arb_mul(stk, stk, st, prec);
}
mag_clear(e);
arb_clear(xt);
arb_clear(tk);
arb_clear(stk);
arb_clear(st);
_acb_vec_clear(a, len);
}

View file

@ -1,110 +0,0 @@
.. _acb-dft:
**acb_dft.h** -- Discrete Fourier Transform on finite abelian groups
===================================================================================
*Warning: the interfaces in this module are experimental and may change
without notice.*
Let *G* be a finite abelian group, and `\chi` a character of *G*.
For any map `f:G\to\mathbb C`, the discrete fourier transform
`\hat f:\hat G\to \mathbb C` is defined by
.. math::
\hat f(\chi) = \sum_{x\in G}\overline{\chi(x)}f(x)
Fast Fourier Transform techniques allow to compute efficiently
all values `\hat f(\chi)` by reusing common computations.
Specifically, if `H\triangleleft G` is a subgroup of size `M` and index
`[G:H]=m`, then writing `f_x(h)=f(xh)` the translate of `f` by representatives
`x` of `G/H`, one has a decomposition
.. math::
\hat f(\chi) = \sum_{x\in G/H} \overline{\chi(x)} \hat{f_x}(\chi_{H})
so that the DFT on `G` can be computed using `m` DFT on `H` (of
appropriate translates of `f`), then `M` DFT on `G/H`, one for
each restriction `\chi_{H}`.
This decomposition can be done recursively.
Note that by inversion formula
.. math::
\widehat{\hat f}(\chi) = \#G\times f(\chi^{-1})
it is straightforward to recover `f` from its DFT `\hat f`.
DFT on Z/nZ
-------------------------------------------------------------------------------
If `G=\mathbb Z/n\mathbb Z`, we compute the DFT according to the usual convention
.. math::
w_x = \sum_{y\bmod n} v_y e^{-\frac{2iπ}nxy}
.. function:: void acb_dirichlet_dft_pol(acb_ptr w, acb_srcptr v, slong n, slong prec)
.. function:: void acb_dirichlet_dft_crt(acb_ptr w, acb_srcptr v, slong n, slong prec)
.. function:: void acb_dirichlet_dft_cyc(acb_ptr w, acb_srcptr v, slong n, slong prec)
Set *w* to the DFT of *v* of length *len*.
The first variant uses the naive `O(n^2)` algorithm.
The second one uses CRT to express `Z/nZ` as a product of cyclic groups.
The *cyc* version uses each prime factor of `m` of `n` to decompose with
the subgroup `H=m\mathbb Z/n\mathbb Z`.
DFT on products
-------------------------------------------------------------------------------
A finite abelian group is isomorphic to a product of cyclic components
.. math::
G = \bigoplus_{i=1}^r \mathbb Z/n_i\mathbb Z
then a character is a product of characters of all components and the DFT reads
.. math::
\hat f(x_1,\dots x_r) = \sum_{y_1\dots y_r} f(y_1,\dots y_r)
e^{-2iπ\sum\frac{x_i y_i}{n_i}}
We assume that `f` is given by a vector of length `\prod n_i` corresponding
to a lexicographic ordering of the values `y_1,\dots y_r`, and the computation
returns the same indexing for values of `\hat f`.
.. function:: void acb_dirichlet_dft_prod(acb_ptr w, acb_srcptr v, slong * cyc, slong num, slong prec);
Computes the DFT on the group product of *num* cyclic components of sizes *cyc*.
Precomputations
-------------------------------------------------------------------------------
Convolution
-------------------------------------------------------------------------------
For functions `f` and `g` on `G` we consider the convolution
.. math::
(f \star g)(x) = \sum_{y\in G} f(x-y)g(y)
which satisfies
.. math::
\widehat{f \star g}(\chi) = \hat f(\chi)\hat g(\chi)

View file

@ -34,38 +34,6 @@ Character evaluation
Compute the *nv* first Dirichlet values.
Roots of unity
-------------------------------------------------------------------------------
.. type:: acb_dirichlet_powers_struct
.. type:: acb_dirichlet_powers_t
This structure allows to compute *n* powers of a fixed root of unity of order *m*
using precomputations. Extremal cases are
- all powers are stored: `O(m)` initialization + storage, `O(n)` evaluations
- nothing stored: `O(1)` initialization + storage, `O(\log(m)n)` evaluations
- `k` step decomposition: `O(k m^{\frac1k})` init + storage, `O((k-1)n)` evaluations.
Currently, only baby-step giant-step decomposition (i.e. `k=2`)
is implemented, allowing to obtain each power using one multiplication.
.. function:: void acb_dirichlet_powers_init(acb_dirichlet_powers_t t, ulong order, slong num, slong prec)
Initialize the powers structure for *num* evaluations of powers of the root of unity
of order *order*.
.. function:: void acb_dirichlet_powers_clear(acb_dirichlet_powers_t t)
Clears *t*.
.. function:: void acb_dirichlet_power(acb_t z, const acb_dirichlet_powers_t t, ulong n, slong prec)
Sets *z* to `x^n` where *t* contains precomputed powers of `x`.
Gauss and Jacobi sums
-------------------------------------------------------------------------------
@ -163,77 +131,6 @@ For `\Re(t)>0` we write `x(t)=\exp(-\frac{\pi}{N}t^2)` and define
should be used, which is not done automatically (to avoid recomputing the
Gauss sum).
.. function:: ulong acb_dirichlet_theta_length(ulong q, const arb_t t, slong prec)
Compute the number of terms to be summed in the theta series of argument *t*
so that the tail is less than `2^{-\mathrm{prec}}`.
.. function:: void acb_dirichlet_qseries_powers_naive(acb_t res, const arb_t x, int p, const ulong * a, const acb_dirichlet_powers_t z, slong len, slong prec)
.. function:: void acb_dirichlet_qseries_powers_smallorder(acb_t res, const arb_t x, int p, const ulong * a, const acb_dirichlet_powers_t z, slong len, slong prec)
Compute the series `\sum n^p z^{a_n} x^{n^2}` for exponent list *a*,
precomputed powers *z* and parity *p* (being 0 or 1).
The *naive* version sums the series as defined, while the *smallorder*
variant evaluates the series on the quotient ring by a cyclotomic polynomial
before evaluating at the root of unity, ignoring its argument *z*.
Discrete Fourier Transforms (DFT)
-------------------------------------------------------------------------------
Let *G* be a finite abelian group, and `\chi` a character of *G*.
For any map `f:G\to\mathbb C`, the discrete fourier transform
`\hat f:\hat G\to \mathbb C` is defined by
.. math::
\hat f(\chi) = \sum_{x\in G}\chi(x)f(x)
Fast Fourier Transform techniques allow to compute efficiently
all values `\hat f(\chi)`.
For a Dirichlet group `G` modulo `q`, we take advantage
of the Conrey isomorphism `G \to \hat G` to consider the
the Fourier transform on Conrey labels as
.. math::
g(a) = \sum_{b\bmod q}\chi_q(a,b)f(b)
.. function:: void acb_dirichlet_dft_conrey(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)
Compute the DFT of *v* using Conrey indices.
This function assumes *v* and *w* are vectors
of size *G->phi_q*, whose values correspond to a lexicographic ordering
of Conrey logs (as obtained using :func:`dirichlet_conrey_next` or
by :func:`dirichlet_index_conrey`).
For example, if `q=15`, the Conrey elements are stored in following
order
======= ============= =====================
index log = [e,f] number = 7^e 11^f
======= ============= =====================
0 [0, 0] 1
1 [0, 1] 7
2 [0, 2] 4
3 [0, 3] 13
4 [0, 4] 1
5 [1, 0] 11
6 [1, 1] 2
7 [1, 2] 14
8 [1, 3] 8
9 [1, 4] 11
======= ============= =====================
.. function:: void acb_dirichlet_dft(acb_ptr w, acb_srcptr v, const dirichlet_group_t G, slong prec)
Compute the DFT of *v* using Conrey numbers.
This function assumes *v* and *w* are vectors of size *G->q*.
All values at index not coprime to *G->q* are ignored.
Euler products
-------------------------------------------------------------------------------
@ -301,10 +198,3 @@ L-functions
is used to avoid poles.
This formula is slow for large *q*.
.. function:: void acb_dirichlet_l_vec_hurwitz(acb_ptr res, const acb_t s, const dirichlet_group_t G, slong prec)
Compute all values `L(s,\chi)` for `\chi` mod `q`, by Hurwitz formula and
discrete Fourier transform.
*res* is assumed to have length *G->phi_q* and values are stored by lexicographically ordered
Conrey logs. See :func:`acb_dirichlet_dft_conrey`.

View file

@ -123,7 +123,6 @@ modules.
bernoulli.rst
hypgeom.rst
partitions.rst
acb_dft.rst
Calculus
::::::::::::::::::::::::::::::::::::