/*
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 .
*/
#include
#include "acb_dirichlet.h"
static int usage(char *argv[])
{
printf("usage: %s [--progress ] [--all] [--odd] [--prec ] [--onlymod] {qmin qmax | --value q a}\n", argv[0]);
return 1;
}
static void
value(ulong q, ulong a, slong prec, slong digits)
{
dirichlet_group_t G;
dirichlet_char_t chi;
acb_t res;
arb_t one;
dirichlet_group_init(G, q);
dirichlet_char_init(chi, G);
dirichlet_char_log(chi, G, a);
acb_init(res);
arb_init(one);
arb_one(one);
acb_dirichlet_theta_arb(res, G, chi, one, prec);
acb_printd(res, digits);
flint_printf("\n");
arb_clear(one);
acb_clear(res);
dirichlet_group_clear(G);
dirichlet_char_clear(chi);
}
static void
check_q(ulong q, int odd, slong prec, slong digits, int onlymod)
{
slong s;
ulong k, len;
dirichlet_group_t G;
dirichlet_char_t x;
dirichlet_group_init(G, q);
dirichlet_char_init(x, G);
acb_ptr theta, z;
arb_t z1;
arb_ptr t;
theta = _acb_vec_init(G->phi_q);
z = _acb_vec_init(G->phi_q);
arb_init(z1);
arb_const_pi(z1, prec);
arb_div_ui(z1, z1, q, prec);
arb_neg(z1, z1);
arb_exp(z1, z1, prec);
/* len = acb_dirichlet_theta_length_d(q, 1., prec); */
t = _arb_vec_init(q);
acb_dirichlet_arb_quadratic_powers(t, q, z1, prec);
for (s = 0; s <= odd; s++)
{
k = 0;
dirichlet_char_one(x, G);
do {
acb_set_arb(z + k, t + x->n);
k++;
} while (dirichlet_char_next(x, G) >= 0);
acb_dirichlet_dft_index(theta, z, G, prec);
/* check zeros */
dirichlet_char_one(x, G);
for (k = 0; k < G->phi_q; k++)
{
if (acb_contains_zero(theta + k)
&& dirichlet_conductor_char(G, x) == q
&& dirichlet_parity_char(G, x) == s)
{
if (onlymod)
{
flint_printf("%wu,%wu\n",q,x->n);
}
else
{
flint_printf("\ntheta null q = %wu, n = %wu\n",q, x->n);
acb_printd(theta + k, digits);
flint_printf("\n");
}
}
dirichlet_char_next(x, G);
}
if (odd)
{
/* change t for odd characters */
for (k = 0; k < q; k++)
arb_mul_ui(t + k, t + k, k, prec);
}
}
_arb_vec_clear(t, q);
_acb_vec_clear(theta, G->phi_q);
_acb_vec_clear(z, G->phi_q);
arb_clear(z1);
dirichlet_char_clear(x);
dirichlet_group_clear(G);
}
int main(int argc, char *argv[])
{
int i, all = 0, odd = 0, onlymod = 0, eval = 0;
slong prec = 50, digits = 10;
slong step = 0;
ulong q, qmin, qmax;
n_primes_t iter;
if (argc < 3)
return usage(argv);
for (i = 1; i < argc - 2; i++)
{
if (!strcmp(argv[i],"--eval"))
eval = 1;
if (!strcmp(argv[i],"--all"))
all = 1;
if (!strcmp(argv[i],"--onlymod"))
onlymod = 1;
else if (!strcmp(argv[i],"--odd"))
odd = 1;
else if (!strcmp(argv[i],"--progress"))
{
i++;
step = atol(argv[i]);
}
else if (!strcmp(argv[i],"--prec"))
{
i++;
prec = atol(argv[i]);
digits = floor(prec * 0.3);
}
}
if (argc < i + 2)
return usage(argv);
qmin = atol(argv[i]);
qmax = atol(argv[i+1]);
if (eval)
{
value(qmin, qmax, prec, digits);
}
else
{
if (all)
{
for (q = qmin; q <= qmax; q++)
{
if (q % 4 == 2)
continue;
check_q(q, odd, prec, digits, onlymod);
if (step && q % step == 0)
flint_printf("[%wu]",q);
}
}
else
{
ulong p;
slong it = 0;
/* look for vanishing theta values for prime power moduli */
n_primes_init(iter);
while ((p = n_primes_next(iter)) < qmax)
{
for (q = p; q < qmin; q*= p);
for (; q < qmax; q *= p)
check_q(q, odd, prec, digits, onlymod);
if (step && (it++ % step == 0))
flint_printf("[%wu]",p);
}
n_primes_clear(iter);
}
}
flint_cleanup();
return EXIT_SUCCESS;
}