change interface to switch acb / ui output

This commit is contained in:
Pascal 2016-04-05 12:18:39 +02:00
parent 88a2725e98
commit 286ca6c84d
19 changed files with 270 additions and 151 deletions

View file

@ -84,11 +84,11 @@ int acb_dirichlet_conrey_next_primitive(acb_dirichlet_conrey_t x, const acb_diri
#define ACB_DIRICHLET_CHI_NULL UWORD_MAX
ulong acb_dirichlet_pairing_conrey(const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b);
ulong acb_dirichlet_pairing(const acb_dirichlet_group_t G, ulong m, ulong n);
ulong acb_dirichlet_ui_pairing_conrey(const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b);
ulong acb_dirichlet_ui_pairing(const acb_dirichlet_group_t G, ulong m, ulong n);
void acb_dirichlet_acb_pairing_conrey(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b, slong prec);
void acb_dirichlet_acb_pairing(acb_t res, const acb_dirichlet_group_t G, ulong m, ulong n, slong prec);
void acb_dirichlet_pairing_conrey(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b, slong prec);
void acb_dirichlet_pairing(acb_t res, const acb_dirichlet_group_t G, ulong m, ulong n, slong prec);
/* introducing character type */
@ -132,19 +132,18 @@ ulong acb_dirichlet_char_conductor(const acb_dirichlet_group_t G, const acb_diri
void acb_dirichlet_char_one(acb_dirichlet_char_t chi, const acb_dirichlet_group_t G);
void acb_dirichlet_char_first_primitive(acb_dirichlet_char_t chi, const acb_dirichlet_group_t G);
ulong acb_dirichlet_chi(const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n);
void acb_dirichlet_acb_chi(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n, slong prec);
ulong acb_dirichlet_ui_chi(const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n);
void acb_dirichlet_vec_set_null(ulong *v, const acb_dirichlet_group_t G, slong nv);
void acb_dirichlet_chi_vec_loop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_chi_vec_primeloop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_chi_vec_sieve(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_chi_vec(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_ui_vec_set_null(ulong *v, const acb_dirichlet_group_t G, slong nv);
void acb_dirichlet_ui_chi_vec_loop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_ui_chi_vec_primeloop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_ui_chi_vec_sieve(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_ui_chi_vec(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv);
void acb_dirichlet_char_vec(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n, slong prec);
void acb_dirichlet_nth_root(acb_t res, ulong order, slong prec);
void acb_dirichlet_chi(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n, slong prec);
void acb_dirichlet_zeta(acb_t res, ulong order, slong prec);
void acb_dirichlet_arb_quadratic_powers(arb_ptr v, slong nv, const arb_t x, slong prec);
ulong acb_dirichlet_theta_length(ulong q, double x, slong prec);

View file

@ -1,45 +0,0 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2015 Jonathan Bober
Copyright (C) 2016 Fredrik Johansson
Copyright (C) 2016 Pascal Molin
******************************************************************************/
#include "acb_dirichlet.h"
void
acb_dirichlet_acb_chi(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n, slong prec)
{
ulong expo;
expo = acb_dirichlet_chi(G, chi, n);
if (expo == ACB_DIRICHLET_CHI_NULL)
acb_zero(res);
else
{
fmpq_t t;
fmpq_init(t);
fmpq_set_si(t, 2 * expo , chi->order);
arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), t, prec);
fmpq_clear(t);
}
}

View file

@ -31,7 +31,7 @@ acb_dirichlet_l(acb_t res, const acb_t s,
while (1) {
/* todo: use n_dirichlet_chi and precomputed roots instead */
acb_dirichlet_acb_pairing_conrey(chi, G, cm, cn, prec);
acb_dirichlet_pairing_conrey(chi, G, cm, cn, prec);
acb_set_ui(a, cn->n);
acb_div_ui(a, a, G->q, prec);
@ -55,4 +55,3 @@ acb_dirichlet_l(acb_t res, const acb_t s,
acb_clear(u);
acb_clear(a);
}

View file

@ -26,7 +26,7 @@
#include "acb_dirichlet.h"
void
acb_dirichlet_zeta(acb_t res, ulong order, slong prec)
acb_dirichlet_nth_root(acb_t res, ulong order, slong prec)
{
fmpq_t t;
fmpq_init(t);

View file

@ -19,30 +19,26 @@
=============================================================================*/
/******************************************************************************
Copyright (C) 2016 Pascal Molin
Copyright (C) 2015 Jonathan Bober
Copyright (C) 2016 Fredrik Johansson
******************************************************************************/
#include "acb_dirichlet.h"
ulong
acb_dirichlet_pairing(const acb_dirichlet_group_t G, ulong m, ulong n)
void
acb_dirichlet_pairing(acb_t res, const acb_dirichlet_group_t G, ulong m, ulong n, slong prec)
{
ulong x;
acb_dirichlet_conrey_t a, b;
if (n_gcd(G->q, m) > 1 || n_gcd(G->q, n) > 1)
return ACB_DIRICHLET_CHI_NULL;
acb_dirichlet_conrey_init(a, G);
acb_dirichlet_conrey_init(b, G);
acb_dirichlet_conrey_log(a, G, m);
acb_dirichlet_conrey_log(b, G, n);
x = acb_dirichlet_pairing_conrey(G, a, b);
acb_dirichlet_conrey_clear(a);
acb_dirichlet_conrey_clear(b);
return x;
ulong expo;
expo = acb_dirichlet_ui_pairing(G, m, n);
if (expo == ACB_DIRICHLET_CHI_NULL)
acb_zero(res);
else
{
fmpq_t t;
fmpq_init(t);
fmpq_set_si(t, 2 * expo, G->expo);
arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), t, prec);
fmpq_clear(t);
}
}

View file

@ -19,24 +19,25 @@
=============================================================================*/
/******************************************************************************
Copyright (C) 2015 Jonathan Bober
Copyright (C) 2016 Fredrik Johansson
Copyright (C) 2016 Pascal Molin
******************************************************************************/
#include "acb_dirichlet.h"
/* todo: modular arithmetic */
ulong
acb_dirichlet_pairing_conrey(const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b)
void
acb_dirichlet_pairing_conrey(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b, slong prec)
{
ulong x, k;
x = 0;
for (k = 0; k < G->num; k++)
x = (x + G->PHI[k] * a->log[k] * b->log[k]) % G->expo;
return x;
ulong expo;
expo = acb_dirichlet_ui_pairing_conrey(G, a, b);
if (expo == ACB_DIRICHLET_CHI_NULL)
acb_zero(res);
else
{
fmpq_t t;
fmpq_init(t);
fmpq_set_si(t, 2 * expo, G->expo);
arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), t, prec);
fmpq_clear(t);
}
}

View file

@ -97,7 +97,7 @@ int main()
abort();
}
chim1 = acb_dirichlet_chi(G, chi, q - 1);
chim1 = acb_dirichlet_ui_chi(G, chi, q - 1);
if (acb_dirichlet_char_parity(chi) != (chim1 != 0))
{
flint_printf("FAIL: parity\n\n");
@ -114,10 +114,10 @@ int main()
while (n_gcd(q, n) > 1);
acb_dirichlet_char(chi2, G, n);
pairing = acb_dirichlet_pairing(G, m, n);
pairing = acb_dirichlet_ui_pairing(G, m, n);
if (pairing != acb_dirichlet_chi(G, chi, n) * (G->expo / chi->order)
|| pairing != acb_dirichlet_chi(G, chi2, m) * (G->expo / chi2->order))
if (pairing != acb_dirichlet_ui_chi(G, chi, n) * (G->expo / chi->order)
|| pairing != acb_dirichlet_ui_chi(G, chi2, m) * (G->expo / chi2->order))
{
flint_printf("FAIL: pairing\n\n");
flint_printf("q = %wu\n\n", q);

View file

@ -49,8 +49,8 @@ int main()
n1 = n_randint(state, 1000);
n2 = n_randint(state, 1000);
acb_dirichlet_acb_chi(zn1, G, chi, n1, 53);
acb_dirichlet_acb_pairing(zn2, G, m, n1, 53);
acb_dirichlet_chi(zn1, G, chi, n1, 53);
acb_dirichlet_pairing(zn2, G, m, n1, 53);
if (!acb_overlaps(zn1, zn2))
{
acb_dirichlet_conrey_t x;
@ -69,8 +69,8 @@ int main()
abort();
}
acb_dirichlet_acb_pairing(zn2, G, m, n2, 53);
acb_dirichlet_acb_pairing(zn1n2, G, m, n1 * n2, 53);
acb_dirichlet_pairing(zn2, G, m, n2, 53);
acb_dirichlet_pairing(zn1n2, G, m, n1 * n2, 53);
acb_mul(zn1zn2, zn1, zn2, 53);
if (!acb_overlaps(zn1n2, zn1zn2))
@ -97,7 +97,7 @@ int main()
{
if (n_gcd(q, m) == 1)
{
acb_dirichlet_acb_pairing(zn2, G, m, n1, 53);
acb_dirichlet_pairing(zn2, G, m, n1, 53);
acb_add(zn1, zn1, zn2, 53);
}
}

View file

@ -61,7 +61,7 @@ int main()
acb_dirichlet_char_init(chi, G);
acb_init(zeta);
acb_dirichlet_zeta(zeta, G->expo, prec);
acb_dirichlet_nth_root(zeta, G->expo, prec);
z = _acb_vec_init(G->expo);
_acb_vec_set_powers(z, zeta, G->expo, prec);
@ -91,7 +91,7 @@ int main()
acb_zero(sum);
acb_dirichlet_char_conrey(chi, G, x);
acb_dirichlet_chi_vec(v, G, chi, nv);
acb_dirichlet_ui_chi_vec(v, G, chi, nv);
m = G->expo / chi->order;
tt = acb_dirichlet_char_parity(chi) ? kt : t;

View file

@ -63,8 +63,8 @@ int main()
acb_dirichlet_char_conrey(chi, G, x);
acb_dirichlet_chi_vec_loop(v1, G, chi, nv);
acb_dirichlet_chi_vec_primeloop(v2, G, chi, nv);
acb_dirichlet_ui_chi_vec_loop(v1, G, chi, nv);
acb_dirichlet_ui_chi_vec_primeloop(v2, G, chi, nv);
if ((k = vec_diff(v1, v2, nv)))
{

View file

@ -25,19 +25,22 @@
#include "acb_dirichlet.h"
void
acb_dirichlet_acb_pairing_conrey(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b, slong prec)
ulong
acb_dirichlet_ui_chi(const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n)
{
ulong expo;
expo = acb_dirichlet_pairing_conrey(G, a, b);
if (expo == ACB_DIRICHLET_CHI_NULL)
acb_zero(res);
if (n_gcd(G->q, n) > 1)
{
return ACB_DIRICHLET_CHI_NULL;
}
else
{
fmpq_t t;
fmpq_init(t);
fmpq_set_si(t, 2 * expo, G->expo);
arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), t, prec);
fmpq_clear(t);
ulong v = 0, k;
acb_dirichlet_conrey_t x;
acb_dirichlet_conrey_init(x, G);
acb_dirichlet_conrey_log(x, G, n);
for (k = 0; k < G->num; k++)
v = (v + chi->expo[k] * x->log[k]) % chi->order;
acb_dirichlet_conrey_clear(x);
return v;
}
}

View file

@ -26,10 +26,10 @@
#include "acb_dirichlet.h"
void
acb_dirichlet_chi_vec(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
acb_dirichlet_ui_chi_vec(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
{
if (3 * nv > G->q)
acb_dirichlet_chi_vec_loop(v, G, chi, nv);
acb_dirichlet_ui_chi_vec_loop(v, G, chi, nv);
else
acb_dirichlet_chi_vec_primeloop(v, G, chi, nv);
acb_dirichlet_ui_chi_vec_primeloop(v, G, chi, nv);
}

View file

@ -27,7 +27,7 @@
/* loop over whole group */
void
acb_dirichlet_chi_vec_loop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
acb_dirichlet_ui_chi_vec_loop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
{
int j;
ulong t;

View file

@ -25,7 +25,7 @@
#include "acb_dirichlet.h"
void
static void
chi_vec_evenpart(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
{
@ -60,7 +60,7 @@ chi_vec_evenpart(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_ch
/* loop over primary components */
void
acb_dirichlet_chi_vec_primeloop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
acb_dirichlet_ui_chi_vec_primeloop(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
{
slong k, l;
@ -93,5 +93,5 @@ acb_dirichlet_chi_vec_primeloop(ulong *v, const acb_dirichlet_group_t G, const a
vx = (vx + vp) % chi->order;
}
}
acb_dirichlet_vec_set_null(v, G, nv);
acb_dirichlet_ui_vec_set_null(v, G, nv);
}

View file

@ -27,7 +27,7 @@
/* sieve on primes */
void
acb_dirichlet_chi_vec_sieve(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
acb_dirichlet_ui_chi_vec_sieve(ulong *v, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, slong nv)
{
slong k, p, pmax;
n_primes_t iter;
@ -47,7 +47,7 @@ acb_dirichlet_chi_vec_sieve(ulong *v, const acb_dirichlet_group_t G, const acb_d
else
{
long chip;
chip = acb_dirichlet_chi(G, chi, p);
chip = acb_dirichlet_ui_chi(G, chi, p);
for (k = p; k < nv; k += p)
if (v[k] != -1)

View file

@ -0,0 +1,48 @@
/*=============================================================================
This file is part of ARB.
ARB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ARB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ARB; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2016 Pascal Molin
******************************************************************************/
#include "acb_dirichlet.h"
ulong
acb_dirichlet_ui_pairing(const acb_dirichlet_group_t G, ulong m, ulong n)
{
ulong x;
acb_dirichlet_conrey_t a, b;
if (n_gcd(G->q, m) > 1 || n_gcd(G->q, n) > 1)
return ACB_DIRICHLET_CHI_NULL;
acb_dirichlet_conrey_init(a, G);
acb_dirichlet_conrey_init(b, G);
acb_dirichlet_conrey_log(a, G, m);
acb_dirichlet_conrey_log(b, G, n);
x = acb_dirichlet_ui_pairing_conrey(G, a, b);
acb_dirichlet_conrey_clear(a);
acb_dirichlet_conrey_clear(b);
return x;
}

View file

@ -21,24 +21,22 @@
Copyright (C) 2015 Jonathan Bober
Copyright (C) 2016 Fredrik Johansson
Copyright (C) 2016 Pascal Molin
******************************************************************************/
#include "acb_dirichlet.h"
void
acb_dirichlet_acb_pairing(acb_t res, const acb_dirichlet_group_t G, ulong m, ulong n, slong prec)
/* todo: modular arithmetic */
ulong
acb_dirichlet_ui_pairing_conrey(const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b)
{
ulong expo;
expo = acb_dirichlet_pairing(G, m, n);
if (expo == ACB_DIRICHLET_CHI_NULL)
acb_zero(res);
else
{
fmpq_t t;
fmpq_init(t);
fmpq_set_si(t, 2 * expo, G->expo);
arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), t, prec);
fmpq_clear(t);
}
ulong x, k;
x = 0;
for (k = 0; k < G->num; k++)
x = (x + G->PHI[k] * a->log[k] * b->log[k]) % G->expo;
return x;
}

View file

@ -26,7 +26,7 @@
#include "acb_dirichlet.h"
void
acb_dirichlet_vec_set_null(ulong *v, const acb_dirichlet_group_t G, slong nv)
acb_dirichlet_ui_vec_set_null(ulong *v, const acb_dirichlet_group_t G, slong nv)
{
slong k, l;
if (G->q_even > 1)

View file

@ -22,26 +22,48 @@ A Dirichlet L-function is the analytic continuation of an L-series
where `\chi(k)` is a Dirichlet character.
Dirichlet characters
Multiplicative group modulo *q*
-------------------------------------------------------------------------------
Working with Dirichlet characters mod *q* consists mainly
in going from residue classes mod *q* to exponents on a set
of generators of the group.
This implementation relies on the Conrey generators introduced
in the LMFDB. We call *number* a residue class, and *index* the
corresponding vector of exponents.
Going from an *index* to the corresponding *number* is a cheap
operation while the converse requires computing discrete
logarithms.
.. type:: acb_dirichlet_group_struct
.. type:: acb_dirichlet_group_t
Represents the group of Dirichlet characters mod *q*.
An *acb_dirichlet_group_t* is defined as an array of *acb_dirichlet_struct*
An *acb_dirichlet_group_t* is defined as an array of *acb_dirichlet_group_struct*
of length 1, permitting it to be passed by reference.
.. function:: void acb_dirichlet_group_init(acb_dirichlet_group_t G, ulong q)
Initializes *G* to the group of Dirichlet characters mod *q*.
This method computes the prime factorization of *q* and other useful
invariants. It does *not* automatically precompute lookup tables
This method computes a canonical decomposition of *G* in terms of cyclic
groups, which are the mod `p^e` subgroups for `p^e\|q`.
In particular *G* contains:
- the number *num* of components
- the generators
- the exponent *expo* of the group
It does *not* automatically precompute lookup tables
of discrete logarithms or numerical roots of unity, and can therefore
safely be called even with large *q*.
For implementation reasons, the largest prime factor of *q* must not
exceed `10^{12}` (an abort will be raised). This restriction could
be removed in the future.
@ -50,13 +72,111 @@ Dirichlet characters
Clears *G*.
.. function:: void acb_dirichlet_chi(acb_t res, const acb_dirichlet_group_t G, ulong m, ulong n, slong prec)
.. function:: void acb_dirichlet_group_dlog_precompute(acb_dirichlet_group_t G, ulong num)
Sets *res* to `\chi_m(n)`, the value of the Dirichlet character
of index *m* evaluated at the integer *n*.
Precompute decomposition and tables for discrete log computations in *G*,
so as to minimize the complexity of *num* calls to discrete logarithms.
Requires that *m* is a valid index, that is, `1 \le m \le q` and *m* is
coprime to *q*. There are no restrictions on *n*.
If *num* gets very large, the entire group may be indexed.
.. type:: acb_dirichlet_conrey_struct
.. type:: acb_dirichlet_conrey_t
Represents elements of the unit group mod *q*, keeping both the
*number* (residue class) and *index* (exponents on the group
generators).
.. function:: void acb_dirichlet_conrey_log(acb_dirichlet_conrey_t x, const acb_dirichlet_group_t G, ulong m)
Sets *x* to the element of number *m*, computing its index using discrete
logarithm in *G*.
.. function:: ulong acb_dirichlet_conrey_exp(acb_dirichlet_conrey_t x, const acb_dirichlet_group_t G)
Compute the reverse operation.
.. function:: void acb_dirichlet_conrey_one(acb_dirichlet_conrey_t x, const acb_dirichlet_group_t G)
Sets *x* to the *number* `1\in G`, having *index* `[0,\dots 0]`.
.. function:: int acb_dirichlet_conrey_next(acb_dirichlet_conrey_t x, const acb_dirichlet_group_t G)
This function allows to iterate on the elements of *G* looping on the *index*.
It produces elements in seemingly random *number* order. The return value
is the index of the last updated exponent of *x*, or *G->num* if the last
element has been reached.
Dirichlet characters
-------------------------------------------------------------------------------
Dirichlet characters take value in a finite cyclic group of roots of unity plus zero.
When evaluation functions return a *ulong*, this number corresponds to the
power of a primitive root of unity, the special value *ACB_DIRICHLET_CHI_NULL*
encoding the zero value.
The Conrey numbering scheme makes explicit the mathematical fact that
the group *G* is isomorphic to its dual.
.. function:: ulong acb_dirichlet_ui_pairing(const acb_dirichlet_group_t G, ulong m, ulong n)
.. function:: ulong acb_dirichlet_ui_pairing_conrey(const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t a, const acb_dirichlet_conrey_t b)
Compute the value of the Dirichlet pairing on numbers *m* and *n*, as
exponent modulo *G->expo*.
The second form takes the index *a* and *b*, and does not take discrete
logarithms.
The returned value is the numerator of the actual value exponent mod the group exponent *G->expo*.
.. type:: acb_dirichlet_char_struct
.. type:: acb_dirichlet_char_t
Represents a Dirichlet character. This structure contains various
useful invariants such as the order of the character.
An *acb_dirichlet_char_t* is defined as an array of *acb_dirichlet_char_struct*
of length 1, permitting it to be passed by reference.
.. function:: void acb_dirichlet_char_init(acb_dirichlet_char_t chi, const acb_dirichlet_group_t G);
.. function:: void acb_dirichlet_char_clear(acb_dirichlet_char_t chi);
Initializes and clear *chi*.
.. function:: void acb_dirichlet_char(acb_dirichlet_char_t chi, const acb_dirichlet_group_t G, ulong n);
Sets *chi* to the Dirichlet character of number *n*, using Conrey numbering scheme.
This function performs a discrete logarithm in *G*.
.. function:: void acb_dirichlet_char_conrey(acb_dirichlet_char_t chi, const acb_dirichlet_group_t G, const acb_dirichlet_conrey_t x);
Sets *chi* to the Dirichlet character of Conrey index *x*.
Character properties
-------------------------------------------------------------------------------
.. function:: ulong acb_dirichlet_char_order(const acb_dirichlet_char_t chi)
.. function:: int acb_dirichlet_char_parity(const acb_dirichlet_char_t chi)
.. function:: ulong acb_dirichlet_char_conductor(const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi)
Character evaluation
-------------------------------------------------------------------------------
The image of a Dirichlet character is a finite cyclic group. Dirichlet
character evaluations are either exponents in this group, or an *acb_t* root of
unity.
.. function:: void acb_dirichlet_chi(acb_t res, const acb_dirichlet_group_t G, const acb_dirichlet_char_t chi, ulong n, slong prec)
Sets *res* to `\chi(n)`, the value of the Dirichlet character *chi*
at the integer *n*.
There are no restrictions on *n*.
Euler products
-------------------------------------------------------------------------------