dirichlet.h
#include <flint/dirichlet.h>This module works with Dirichlet characters modulo a word-size integer q algebraically. A character \chi modulo q takes the value 0 on integers not coprime to q and roots of unity on the others; the module represents a value e^{2\pi i v/e} exactly by the exponent v modulo the exponent e of the group, and computes characters, their products and powers, their conductors, parities and orders, and vectors of values, using discrete logarithms from dlog. Characters are labelled in the Conrey numbering of the LMFDB [LMFDB], in which the characters modulo q are indexed by the residues m \in (\mathbb{Z}/q\mathbb{Z})^\times, written \chi_q(m, \cdot). Numerical values and L-functions are in acb_dirichlet.
Warning: the interfaces in this module are experimental and may change without notice.
The guide Characters in the Conrey numbering explains the numbering and the representation with an example; Dirichlet characters gives the mathematics and the algorithms.
AlgorithmDirichlet charactersRepresents the Dirichlet characters modulo q through the decomposition of the unit group into cyclic components with Conrey's generators, so that characters, values, conductors, parities and orders are computed from discrete logarithms in each component or directly from the Conrey number.Guides#
The group modulo q#
The group (\mathbb{Z}/q\mathbb{Z})^\times is a product of cyclic groups, one for each odd prime power p^e \| q and up to two for the power of 2. The structure dirichlet_group_t stores this decomposition with one Conrey generator per component; an element (and the character it labels) is then described by its number m \in (\mathbb{Z}/q\mathbb{Z})^\times or by its log, the vector of exponents of m on the generators.
The group (\mathbb{Z}/q\mathbb{Z})^\times with its decomposition: the modulus q, the number of components num, the group order phi_q = \varphi(q), the group exponent expo, the generators lifted modulo q and, per component, the prime power, the order phi of the component and optional discrete logarithm tables. A dirichlet_group_t is an array of length one of dirichlet_group_struct.
The size (16) of some fixed arrays indexed by the components: the largest number of components of a 64-bit modulus, two for the 2-part and 14 for the odd primes, as for q = 8 \cdot 3 \cdot 5 \cdots 47.
int dirichlet_group_init(dirichlet_group_t G, ulong q)Initialises G as the group of characters modulo q \ge 1, computing the factorisation of q, the Conrey generators and the exponent. No discrete logarithm tables are computed, so this is cheap even for large q. Returns 1 on success, and 0 (without allocating) if a prime factor of q exceeds 10^{16}, for which the generator is not implemented.
Morevoid dirichlet_subgroup_init(dirichlet_group_t H, const dirichlet_group_t G, ulong h)Initialises H as the group modulo h, for h \mid q, sharing the components of G (in particular its discrete logarithm tables, which must not be cleared while H is in use).
Frees the memory used by G, but not its discrete logarithm tables, which may be shared with subgroups; free them first with dirichlet_group_dlog_clear.
ulong dirichlet_group_size(const dirichlet_group_t G)Returns the number \varphi(q) of elements of G, which is also the number of characters modulo q.
Returns the number of primitive characters modulo q: 0 if q \equiv 2 \pmod 4, and otherwise the product over the components of p - 2 for p^1 \| q (p odd), (p-1)^2 p^{e-2} for p^e \| q (e \ge 2), 1 for 4 \| q and 2^{e-2} for 2^e \| q, e \ge 3.
void dirichlet_group_dlog_precompute(dirichlet_group_t G, ulong num)Precomputes discrete logarithm tables in every component for about num subsequent logarithms, with dlog_precomp_modpe_init. This speeds up dirichlet_char_log, dirichlet_chi and dirichlet_pairing when they are called many times. For very large num the whole group may be tabulated.
Frees the discrete logarithm tables of G. Subgroups sharing them must be cleared first.
Characters#
An element of G, used as the character \chi_q(m, \cdot): its number n = m and its log, an array log of num exponents with m \equiv \prod_k g_k^{\mathit{log}[k]} \pmod q. A dirichlet_char_t is an array of length one of dirichlet_char_struct.
void dirichlet_char_init(dirichlet_char_t x, const dirichlet_group_t G)Initialises x as an element of G and sets it to the principal character (m = 1).
void dirichlet_char_clear(dirichlet_char_t x)Frees the memory used by x.
void dirichlet_char_print(const dirichlet_group_t G, const dirichlet_char_t x)Prints the log of x as a list [a_0, a_1, ...].
void dirichlet_char_set(dirichlet_char_t x, const dirichlet_group_t G, const dirichlet_char_t y)Sets x to a copy of y.
int dirichlet_char_eq(const dirichlet_char_t x, const dirichlet_char_t y)int dirichlet_char_eq_deep(const dirichlet_group_t G, const dirichlet_char_t x, const dirichlet_char_t y)Return 1 if x and y are equal, otherwise 0. The first function compares the numbers only; the second also compares the logs and is meant for testing the consistency of the two representations.
void dirichlet_char_log(dirichlet_char_t x, const dirichlet_group_t G, ulong m)Sets x to the character of number m, which must be coprime to q and reduced modulo q, computing its log by discrete logarithms in each component (with the tables of G if present).
ulong dirichlet_char_exp(const dirichlet_group_t G, const dirichlet_char_t x)ulong _dirichlet_char_exp(dirichlet_char_t x, const dirichlet_group_t G)Return the number of x. The first function reads the stored number; the second recomputes it from the log, stores it in x and returns it.
void dirichlet_char_one(dirichlet_char_t x, const dirichlet_group_t G)Sets x to the principal character, with log [0, \ldots, 0] and number 1.
void dirichlet_char_first_primitive(dirichlet_char_t x, const dirichlet_group_t G)Sets x to the first primitive character in the order of dirichlet_char_next_primitive, with log [1, \ldots, 1], or [0, 1, \ldots, 1] if 8 \mid q. Throws if q \equiv 2 \pmod 4, where no primitive character exists.
int dirichlet_char_next(dirichlet_char_t x, const dirichlet_group_t G)Sets x to the next element of G in the lexicographic order of the logs (the last component varying fastest), updating the number with one multiplication. Returns the index of the most significant component that changed, or -1 after the last element (when x wraps around to the principal character).
Moreint dirichlet_char_next_primitive(dirichlet_char_t x, const dirichlet_group_t G)As dirichlet_char_next, but skips to the next primitive character, in the same order. Start from dirichlet_char_first_primitive.
ulong dirichlet_index_char(const dirichlet_group_t G, const dirichlet_char_t x)void dirichlet_char_index(dirichlet_char_t x, const dirichlet_group_t G, ulong j)Convert between an element and its index j \in [0, \varphi(q)) in the lexicographic order of the logs, the mixed-radix number with digits \mathit{log}[k] in base \varphi_k.
Properties#
In the Conrey numbering the conductor, parity and order of \chi_q(m, \cdot) can be computed either from the number m (the _ui functions) or from the log (the _char functions); neither needs a discrete logarithm.
int dirichlet_char_is_principal(const dirichlet_group_t G, const dirichlet_char_t chi)Returns 1 if \chi is the principal character (m = 1).
ulong dirichlet_conductor_ui(const dirichlet_group_t G, ulong a)ulong dirichlet_conductor_char(const dirichlet_group_t G, const dirichlet_char_t x)Return the conductor of \chi_q(a, \cdot), the smallest f \mid q such that the character is induced by a character modulo f.
int dirichlet_parity_ui(const dirichlet_group_t G, ulong a)int dirichlet_parity_char(const dirichlet_group_t G, const dirichlet_char_t x)Return the parity \lambda \in \{0, 1\} of \chi_q(a, \cdot), defined by \chi(-1) = (-1)^\lambda: 0 for even and 1 for odd characters.
ulong dirichlet_order_ui(const dirichlet_group_t G, ulong a)ulong dirichlet_order_char(const dirichlet_group_t G, const dirichlet_char_t x)Return the order of \chi_q(a, \cdot) in the character group, which is the multiplicative order of a modulo q.
int dirichlet_char_is_real(const dirichlet_group_t G, const dirichlet_char_t chi)Returns 1 if \chi is real, that is, has order at most 2 (its number satisfies m^2 \equiv 1 \pmod q).
int dirichlet_char_is_primitive(const dirichlet_group_t G, const dirichlet_char_t chi)Returns 1 if \chi is primitive, that is, its conductor is q.
Values#
A value \chi(n) is returned as an exponent v with \chi(n) = e^{2\pi i v/e}, where e is the exponent G->expo of the group (or a given order), and the value 0 is encoded by the special exponent DIRICHLET_CHI_NULL. See Values as exponents.
The exponent UWORD_MAX that encodes the value \chi(n) = 0, for n not coprime to q.
ulong dirichlet_pairing(const dirichlet_group_t G, ulong m, ulong n)ulong dirichlet_pairing_char(const dirichlet_group_t G, const dirichlet_char_t a, const dirichlet_char_t b)Return the exponent of \chi_q(m, n) modulo G->expo, or DIRICHLET_CHI_NULL if m or n is not coprime to q. The pairing is symmetric: \chi_q(m, n) = \chi_q(n, m). The _char version takes both arguments as elements with their logs and needs no discrete logarithm; the other computes two.
ulong dirichlet_chi(const dirichlet_group_t G, const dirichlet_char_t chi, ulong n)Returns the exponent of \chi(n) modulo G->expo, or DIRICHLET_CHI_NULL if \gcd(n, q) > 1. Costs one discrete logarithm per component of G.
void dirichlet_chi_vec(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, slong nv)void dirichlet_chi_vec_order(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, ulong order, slong nv)Set v[k] to the exponent of \chi(k) for 0 \le k < \mathit{nv}, modulo G->expo or modulo order, which must be a multiple of the order of \chi; entries with \gcd(k, q) > 1 are set to DIRICHLET_CHI_NULL. The functions call the loop versions if 2\,\mathit{nv} > \varphi(q) and the primeloop versions otherwise. v[0] is DIRICHLET_CHI_NULL for q > 1, and for q = 1, where the trivial character is 1 everywhere, every entry is 0.
void dirichlet_chi_vec_loop(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, slong nv)void dirichlet_chi_vec_loop_order(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, ulong order, slong nv)As dirichlet_chi_vec, by enumerating the whole group with dirichlet_char_next and updating the value by one addition per step; entries k \ge q are copied by periodicity. Costs O(\varphi(q) + \mathit{nv}) and needs no discrete logarithm. Requires \mathit{nv} \ge 2: the function writes v[1].
void dirichlet_chi_vec_primeloop(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, slong nv)void dirichlet_chi_vec_primeloop_order(ulong * v, const dirichlet_group_t G, const dirichlet_char_t chi, ulong order, slong nv)As dirichlet_chi_vec, by adding the contributions of the components: the 2-part directly, and each odd prime power with dlog_vec_add, which computes the discrete logarithms of all k < \mathit{nv} by sieving (using the tables of G if present). See the warning about v[0] at dirichlet_chi_vec.
void dirichlet_vec_set_null(ulong * v, const dirichlet_group_t G, slong nv)Sets v[k] to DIRICHLET_CHI_NULL for 0 < k < \mathit{nv} divisible by a prime factor of q (except v[0], which is not changed).
Operations on characters#
void dirichlet_char_mul(dirichlet_char_t c, const dirichlet_group_t G, const dirichlet_char_t a, const dirichlet_char_t b)Sets c to the product ab: the logs are added and the numbers multiplied.
void dirichlet_char_pow(dirichlet_char_t c, const dirichlet_group_t G, const dirichlet_char_t a, ulong n)Sets c to a^n.
void dirichlet_char_lift(dirichlet_char_t chi_G, const dirichlet_group_t G, const dirichlet_char_t chi_H, const dirichlet_group_t H)Given a character \chi_H modulo h \mid q (with H a subgroup of G created by dirichlet_subgroup_init), sets \chi_G to the character modulo q that it induces. Throws if h \nmid q.
void dirichlet_char_lower(dirichlet_char_t chi_H, const dirichlet_group_t H, const dirichlet_char_t chi_G, const dirichlet_group_t G)Given a character \chi_G modulo q whose conductor divides h, with h \mid q the modulus of H, sets \chi_H to the character modulo h that induces it. Throws if h \nmid q or the conductor does not divide h.
References#
- [LMFDB] The LMFDB Collaboration, The L-functions and modular forms database, https://www.lmfdb.org (Dirichlet characters: https://www.lmfdb.org/Character/Dirichlet/).
The FLINT team, “dirichlet.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/dirichlet/index.html (generated 2026-10-20).
@misc{flint-doc-dirichlet-index,
author = {{The FLINT team}},
title = {{dirichlet.h (module overview)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/dirichlet/index.html},
note = {Generated 2026-10-20}
}