mirror of
https://github.com/vale981/arb
synced 2025-03-05 09:21:38 -05:00
226 lines
5.1 KiB
C
226 lines
5.1 KiB
C
/*
|
|
Copyright (C) 2015 Jonathan Bober
|
|
Copyright (C) 2016 Fredrik Johansson
|
|
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 "dirichlet.h"
|
|
|
|
static ulong
|
|
primitive_root_p_and_p2(ulong p)
|
|
{
|
|
if (p == 40487)
|
|
return 10;
|
|
|
|
#if FLINT_BITS == 64
|
|
if (p == UWORD(6692367337))
|
|
return 7;
|
|
|
|
if (p > UWORD(1000000000000))
|
|
{
|
|
printf("primitive root: p > 10^12 not implemented");
|
|
flint_abort();
|
|
}
|
|
#endif
|
|
|
|
return n_primitive_root_prime(p);
|
|
}
|
|
|
|
void
|
|
dirichlet_prime_group_init(dirichlet_prime_group_struct * P, ulong p, int e)
|
|
{
|
|
P->p = p;
|
|
P->e = e;
|
|
if (p == 2 || p == 4)
|
|
{
|
|
P->p = 2;
|
|
nmod_init(&P->pe, UWORD(1) << e);
|
|
if (p == 2)
|
|
{
|
|
P->e = 2;
|
|
nmod_init(&P->phi, 2);
|
|
P->g = (UWORD(1) << e) - 1;
|
|
}
|
|
else
|
|
{
|
|
nmod_init(&P->phi, UWORD(1) << (e - 2));
|
|
P->g = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ulong pe1;
|
|
pe1 = n_pow(p, e - 1);
|
|
nmod_init(&P->phi, (p-1) * pe1);
|
|
nmod_init(&P->pe, p * pe1);
|
|
P->g = primitive_root_p_and_p2(p);
|
|
}
|
|
P->dlog = NULL;
|
|
}
|
|
|
|
static void
|
|
dirichlet_group_lift_generators(dirichlet_group_t G)
|
|
{
|
|
slong k;
|
|
dirichlet_prime_group_struct * P = G->P;
|
|
|
|
G->expo = G->phi_q = 1;
|
|
if (G->neven)
|
|
{
|
|
G->phi_q = G->q_even / 2;
|
|
G->expo = P[G->neven - 1].phi.n;
|
|
}
|
|
for (k = G->neven; k < G->num; k++)
|
|
{
|
|
G->phi_q *= P[k].phi.n;
|
|
G->expo *= P[k].phi.n / n_gcd(G->expo, P[k].p - 1);
|
|
}
|
|
|
|
for (k = 0; k < G->num; k++)
|
|
{
|
|
nmod_t pe;
|
|
ulong qpe, v;
|
|
G->PHI[k] = G->expo / G->P[k].phi.n;
|
|
/* lift generators mod q */
|
|
/* u * p^e + v * q/p^e = 1 -> g mod q = 1 + (g-1) * v*(q/p^e) */
|
|
pe = G->P[k].pe;
|
|
qpe = G->q / pe.n;
|
|
if (G->q < G->P[k].pe.n)
|
|
{
|
|
flint_printf("lift generator %wu from %wu to %wu e=%wu\n",
|
|
G->P[k].g, G->P[k].pe.n, G->q, G->P[k].e);
|
|
}
|
|
v = nmod_inv(qpe % pe.n, pe);
|
|
/* v * qpe < q */
|
|
G->generators[k] = (1 + nmod_mul(G->P[k].g-1, v * qpe, G->mod)) % G->q;
|
|
}
|
|
}
|
|
|
|
void
|
|
dirichlet_group_init(dirichlet_group_t G, ulong q)
|
|
{
|
|
slong k;
|
|
ulong e2;
|
|
n_factor_t fac;
|
|
|
|
G->q = q;
|
|
nmod_init(&G->mod, q);
|
|
|
|
|
|
e2 = n_remove(&q, 2);
|
|
G->q_even = UWORD(1) << e2;
|
|
/* number of components at p=2 */
|
|
G->neven = (e2 >= 3) ? 2 : (e2 == 2) ? 1 : 0;
|
|
|
|
/* warning: only factor odd part */
|
|
n_factor_init(&fac);
|
|
n_factor(&fac, q, 1);
|
|
|
|
G->num = fac.num + G->neven;
|
|
G->P = flint_malloc(G->num * sizeof(dirichlet_prime_group_struct));
|
|
G->generators = flint_malloc(G->num * sizeof(ulong));
|
|
G->PHI = flint_malloc(G->num * sizeof(ulong));
|
|
|
|
/* even part */
|
|
if (G->neven >= 1)
|
|
dirichlet_prime_group_init(&G->P[0], 2, e2);
|
|
if (G->neven == 2)
|
|
dirichlet_prime_group_init(&G->P[1], 4, e2);
|
|
|
|
/* odd part */
|
|
G->rad_q = 1;
|
|
for (k = G->neven; k < G->num; k++)
|
|
{
|
|
ulong p, e;
|
|
p = fac.p[k - G->neven];
|
|
e = fac.exp[k - G->neven];
|
|
G->rad_q *= p;
|
|
dirichlet_prime_group_init(&G->P[k], p, e);
|
|
}
|
|
dirichlet_group_lift_generators(G);
|
|
}
|
|
|
|
void
|
|
dirichlet_subgroup_init(dirichlet_group_t H, const dirichlet_group_t G, ulong h)
|
|
{
|
|
int s[15]; /* selected components */
|
|
slong k, j, e2;
|
|
|
|
H->q = h;
|
|
nmod_init(&H->mod, h);
|
|
|
|
/* even components */
|
|
|
|
e2 = n_remove(&h, 2);
|
|
H->q_even = UWORD(1) << e2;
|
|
|
|
s[0] = s[1] = 0;
|
|
j = 0;
|
|
if (e2 >= 2)
|
|
s[j++] = 2;
|
|
if (e2 >= 3)
|
|
s[j++] = e2;
|
|
|
|
H->neven = j;
|
|
|
|
/* odd components */
|
|
for (k = G->neven; k < G->num; k++)
|
|
{
|
|
ulong p = G->P[k].p;
|
|
|
|
s[k] = n_remove(&h, p);
|
|
|
|
if (s[k] > 0)
|
|
{
|
|
j++;
|
|
H->rad_q *= p;
|
|
}
|
|
}
|
|
|
|
H->num = j;
|
|
H->P = flint_malloc(j * sizeof(dirichlet_prime_group_struct));
|
|
H->generators = flint_malloc(j * sizeof(ulong));
|
|
H->PHI = flint_malloc(j * sizeof(ulong));
|
|
|
|
j = 0;
|
|
for (k = 0; k < H->neven; k++)
|
|
{
|
|
H->P[j] = G->P[k];
|
|
if (H->q_even < G->q_even)
|
|
{
|
|
nmod_init(&H->P[j].pe, H->q_even);
|
|
H->P[j].e = s[k];
|
|
if (k == 0)
|
|
H->P[j].g = H->q_even - 1;
|
|
else
|
|
nmod_init(&H->P[j].phi, H->q_even / 4);
|
|
}
|
|
j++;
|
|
}
|
|
|
|
for (k = G->neven; k < G->num; k++)
|
|
{
|
|
if (s[k])
|
|
{
|
|
H->P[j] = G->P[k];
|
|
if (s[k] < G->P[k].e)
|
|
{
|
|
ulong pf, p = H->P[j].p;
|
|
H->P[j].e = s[k];
|
|
pf = n_pow(p, s[k]);
|
|
nmod_init(&H->P[j].pe, pf);
|
|
nmod_init(&H->P[j].phi, (p-1) * pf / p);
|
|
}
|
|
j++;
|
|
}
|
|
}
|
|
|
|
dirichlet_group_lift_generators(H);
|
|
}
|