arb/acb_dft/crt.c

223 lines
4.6 KiB
C

/*
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);
if (n)
n_factor(&fac, n, 1);
else
fac.num = 0;
nmod_init(&c->n, FLINT_MAX(n, 1));
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_init(acb_dft_crt_t crt, slong len, slong prec)
{
crt->n = len;
crt_init(crt->c, len);
crt->dv = 1;
crt->cyc = _acb_dft_steps_prod(crt->c->m, crt->c->num, prec);
}
void
acb_dft_crt_clear(acb_dft_crt_t crt)
{
slong i;
for (i = 0; i < crt->c->num; i++)
acb_dft_precomp_clear(crt->cyc[i].pre);
flint_free(crt->cyc);
}
void
acb_dft_crt_precomp(acb_ptr w, acb_srcptr v, const acb_dft_crt_t crt, slong prec)
{
if (crt->n <= 1)
{
if (crt->n == 1)
acb_set(w, v);
}
else
{
acb_ptr t;
t = _acb_vec_init(crt->n);
if (w == v)
{
_acb_vec_set(t, v, crt->n);
v = t;
}
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)
{
if (len <= 1)
{
if (len == 1)
acb_set(w, v);
}
else
{
crt_t c;
acb_ptr t;
t = _acb_vec_init(len);
if (w == v)
{
_acb_vec_set(t, v, len);
v = t;
}
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);
}
}