# General $L$-series

In addition to the built-in $L$-series for the standard objects, Magma provides machinery that allows the user to define $L$-series for arbitrary objects, provided that they admit a meromorphic continuation to the whole complex plane and satisfy a functional equation of the standard kind. To describe how this may be done, we need to introduce some terminology.

## Terminology

Recall that an $L$*-series* is a sum

$$
L(s) = \sum_{n=1}^\infty {a_n\over n^s},
$$

where the coefficients $a_n$ are complex numbers, known as the Dirichlet coefficients of the $L$-series. For example, the Dirichlet coefficients of the classical Riemann zeta function are $a_n=1$ for all $n$. We assume that, as in the case of Riemann zeta function, every $L(s)$ has a meromorphic continuation to the complex plane and has a functional equation. Technically, our assumptions are as follows:

**Assumption 1.** The defining series for $L(s)$ converges for Re$(s)$ sufficiently large. Equivalently, the *coefficients* $a_n$ grow at worst as a polynomial function of $n$.

**Assumption 2.** $L(s)$ admits a meromorphic continuation to the entire complex plane.

**Assumption 3.** The following exist: real positive *weight*, complex *sign* of absolute value 1, real positive *conductor* and the $\Gamma$*-factor*

$$
\gamma(s) = \Gamma\Bigl({s\!+\!\lambda_1\over2}\Bigr)
\cdots\Gamma\Bigl({s\!+\!\lambda_d\over2}\Bigr)
$$

of *dimension* $d\ge 1$ and rational $\gamma$*-shifts* $\lambda_1,\ldots \lambda_d$, such that

$$
L^*(s)=\Bigl({{\rm conductor}\over\pi^d}\Bigr)^{s/2}\,\gamma(s)\,L(s)
$$

satisfies the *functional equation*

$$
L^*(s) = {\rm sign} \cdot \bar L^*({\rm weight}-s).
$$

Here $\bar L$ is the *dual* $L$-series with complex conjugate coefficients $L(s)=\sum_{n=1}^\infty\overline{a_n}/n^s$. Note that the “weight” here is one more than the usual motivic notion of weight.

**Assumption 4.** The series $L^*(s)$ has finitely many simple *poles* and no other singularities.

Assumption 1 will almost certainly be true for any naturally arising $L$-function and Assumptions 2–4 are expected (but not proven) to be satisfied for most of the $L$-functions arising in geometry and number theory. In fact, there is a large class of so-called *motivic* $L$*-functions* for which all of the above assumptions are conjectured to be true. Essentially this class consists of $L$-functions associated to cohomology groups of varieties over number fields. This is an extremely large class of $L$-functions that includes all of the standard examples.

## Constructing a General $L$-Series

When computing the values $L(s)$ for a complex number $s$, Magma relies heavily on the functional equation. This means that the *emphasized* parameters in Assumptions 1–4 (coefficients, weight, conductor, poles, etc.) must be known before the computations can be carried out.

The generic `LSeries` function allows the user to construct an $L$-series for a new object by specifying values for these parameters. In fact, this function is used to construct all of the built-in $L$-series in Magma and some of these will be used as examples to illustrate its use (see the advanced examples section).

### `LSeries({weight, gamma, conductor, }{cffun}): FldReElt, [FldRatElt], FldReElt, Any -> LSer`

```magma
Sign             : FldComElt                      Default: 0
Poles            : SeqEnum                        Default: []
Residues         : SeqEnum                        Default: []
Parent           : Any                            Default: 
CoefficientGrowth: UserProgram                    Default: 
Precision        : RngIntElt                      Default: 
ImS              : FldReElt                       Default: 0
Asymptotics      : BoolElt                        Default: true
```

The function takes four arguments: real positive $weight$, sequence of rational numbers $gamma$, real positive $conductor$ and a coefficient function *cffun* together with a number of optional parameters. It constructs an $L$-series with specified coefficients and the form of the functional equation.

Compulsory arguments (see Section [Terminology](#terminology) for terminology):

$weight$ — weight of the $L$-series.

Specifies the functional equation; for instance, it is `1` for the Riemann zeta function, `2` for curves over the rationals and `Weight(f)` for modular forms $f$.

Note that the “weight” in this sense is the $w$ such that $s\rightarrow w-s$ satisfies a functional equation. The usual motivic notion of weight is thus one less than this – for instance, a weight $k$ modular form has weight $k$ in Magma, but weight $k-1$ for motives, as its coefficients are typically of size $(\sqrt p)^{k-1}$.

$gamma$ — gamma shifts/parameters.

List (of type `SeqEnum`) of rational numbers that specify the gamma factor. For instance, this is `[0]` for the Riemann zeta function, `[0,1]` for an elliptic curve over ${\mathbb{Q}}$ and `[0,...,0,1,...,1]` with $r_1+r_2$ zeros and $r_2$ ones for the Dedekind zeta function of a number field $K$ with $r_1$ real and $r_2$ pairs of complex embeddings.

$conductor$ — conductor of the $L$-series.

Part of the exponential factor $({{\rm conductor}\over\pi^d})^{s/2}$ in the functional equation. It is usually an integer and is 1 for the Riemann zeta function, the level for a modular form, $|$Discriminant$(K)|$ for the Dedekind zeta of a number field $K$ and the conductor of the Jacobian for an algebraic curve over the rationals.

*cffun* — specifies the coefficients $a_n$. The following possibilities are allowed:

- $\qquad$ A finite sequence $[a_1,...,a_n]$;

- $\qquad$ A function $f(n)$ that returns $a_n$;

- $\qquad$ A function $f(p,d)$ that computes the inverse of the local factor at $p$ up to degree $d$;

- $\qquad$ The value `0`, signifying that the coefficients will be provided later with a call to `LSetCoefficients`.

See Section [Setting the Coefficients](#lsetcoeff) for a detailed explanation and examples.

Optional parameters for `Lseries:`:

`Sign` — the sign appearing in the functional equation.

This is the sign that enters the functional equation and is usually $\pm 1$. It must be a complex number of absolute value 1. Alternatively, this can be set to 0 (default), in which case Magma will determine it numerically from the functional equation.

Instead of providing the actual sign, the user may also use an option `Sign:=s` where $s$ is the name of a function $s(p)$ or $s(L,p)$ that computes the sign to precision $p$.

`Poles` — the poles $z$ of $L^*(s)$ with Re $z\ge$weight/2 and

`Residues` — the residues at these poles

If $L^*(s)$ happens to have poles, there are only finitely many of them and each must be simple by Assumption 4 of the previous subsection. The poles have to be known and specified here when the $L$-function is created. The poles are symmetric about the point $s=$weight/2 by the functional equation and only the “right half” of the set of them has to be supplied in the form of a sequence as the value of the parameter `Poles`. The default setting is that $L^*(s)$ has no poles.

The residues at the poles of $L^*(s)$ are also required and they can be specified using the `Residues` parameter, which also takes a sequence as its value. It can be either a sequence of the same length as `Poles` or left to its default setting `[]`. In that case, Magma will attempt to determine the residues numerically using the functional equation. However, this is only possible if `Sign` is known and will not work to full precision if there is more than one pair of poles.

As an example, the Riemann zeta function has weight 1 and the modified function $\zeta^*(s)$ has poles at $s=0$ and $s=1$ with residues $1$ and $-1$ respectively. So the parameter assignments `Poles:=[1], Residues:=[-1]` would be used in its definition.

As in the case of `Sign`, instead of providing the actual residues, the user may give the name of a function $r(p)$ or $r(L,p)$ that computes the residues up to precision $p$ and returns them as a sequence.

`Parent` — any Magma object.

This is only used for printing purposes. When a variable type `LSer` is printed, Magma prints “L-series of” and then prints the parent object.

`Precision` — the precision to which $L$-values are to be computed (default is 0, use current precision).

`CoefficientGrowth` — name $f$ of a function $f(x)$ or $f(L,x)$ such that $|a_n|<f(n)$.

`ImS` — the largest imaginary part of $s$ for which $L(s)$ will be evaluated.

`Asymptotics` — whether to use asymptotic expansions (default is yes).

These four settings are related to the precision to which values are calculated in $L$-series computations. They are the same as for the `SetPrecision` function and are described in detail in Section [Precision](precision.md#precision).

As an illustration, the following code creates the Riemann zeta function from its invariants. This is essentially what `RiemannZeta()` does:

```
   > Z := LSeries(1, [0], 1, func<n|1>
   >                         : Sign:=1, Poles:=[1], Residues:=[-1]);
   > CFENew(Z);
   0.0000000000000000000000000000000

```

### `LSeries(HS, N, cffun): HodgeStruc, RngIntElt, Any -> LSer`

This is an alternative way to specify a generic $L$-series, with all the varargs of before. Instead of giving a real number for the functional equation reflection together with $\gamma$-shifts, one passes a Hodge structure to the LSeries intrinsic instead.

For more examples, see the “Advanced Examples” Section [Examples](../../LatticesQuadraticForms/LatticesOverNumberFields/examples.md#examples).

It is strongly advised that whenever a generic $L$-series is defined the user apply one of the functions `CFENew` or `CheckFunctionalEquation`. If one of the specified parameters (conductor, sign, etc.) happens to be incorrect, the resulting $L$-series will not have a functional equation and the values returned by the evaluation functions will be nonsense. Only by checking the functional equation will the user have an indication that something is wrong.

### `CheckFunctionalEquation(L): LSer -> FldComElt`

### `CFENew(L): LSer -> FldReElt`

```magma
t: FldReElt                    Default: 1.2
```

Given an $L$-series $L$, this intrinsic tests the functional equation numerically and should ideally return 0 (to the current precision), meaning that the test was passed.

The new preferred version is `CFENew`, which in many cases of reasonable interest can often require signficantly fewer terms (using a dynamic criterion, rather than a static one), sometimes by a factor of 5 or more. It also is much superior at keeping track of internal precision. However, it does not completely replicate the old machinery (particularly when poles/residues are present), and so `CheckFunctionalEquation` is also still available.

If the value returned is a significant distance from 0, either the $L$-function does not have a functional equation or some of the defining parameters (conductor, poles etc.) have been incorrectly specified or not enough coefficients have been given. In the latter case, `CFENew` or `CheckFunctionalEquation` is likely to return a number reasonably close to 0 that measures the accuracy of computations.

As already mentioned, Magma can only work with $L$-functions that satisfy the functional equation as in Section [Terminology](#terminology). Whenever an $L$-function is constructed, its functional equation is implicitly used in all the $L$-series evaluations, even when $L$ is evaluated in the region where the original Dirichlet series is absolutely convergent.

If either the sign in the functional equation or the residues of $L^*(s)$ have not yet been computed, this function will first compute them. If the sign was undefined, it returns $|$`Sign`$|-1$ which, again, must be 0.

The optional technical parameter `t` is a point on the real line where Magma evaluates the two Theta functions associated to the $L$-series and subtracts one from the other to get the value returned by `CFENew` or `CheckFunctionalEquation`.

### `Example: Lseries Checkfun (ex-37a053)`

We attempt to define a truncated $L$-series of a quadratic character mod 3 (so $\chi(n) =0,1,-1$ if $n$ is 0, 1 or 2 mod 3 respectively.)

```magma
> L := LSeries(1, [0], 3, [1,-1,0,1,-1,0] : Sign:=-1);
> CFENew(L);
0.222346257403989419245646558069

```

This does not look right. In fact, the $\gamma$-shifts are $0$ for even quadratic characters, but $1$ for odd ones,

```magma
> L := LSeries(1, [1], 3, [1,-1,0,1,-1,0] : Sign:=-1);
> CheckFunctionalEquation(L);
1.06372623587922089871296822624
> CFENew(L);
7.47942058598558334301138589732E-18

```

This still does not look right (though `CFENew` will ignore `Sign`). We gave the wrong sign in the functional equation.

```magma
> L := LSeries(1, [1], 3, [1,-1,0,1,-1,0] : Sign:=1);
> CFENew(L);
7.47942058598558334301138589732E-18

```

This certainly looks better but it indicates that we did not give enough coefficients to our $L$-series. We determine how many coefficients are needed to do computations with default precision (30 digits),

```magma
> LCfRequired(L); // approx for old CheckFunctionalEquation
11

```

So 11 coefficients are needed and we provide them in the code below.

```magma
> L := LSeries(1, [1], 3, [1,-1,0,1,-1,0,1,-1,0,1] : Sign:=1);
> CFENew(L);
0.000000000000000000000000000000

```

This a correct way to define our $L$-series. Even better is the following variant:

```magma
> L := LSeries(1, [1], 3, func<n|((n+1) mod 3)-1> : Sign:=1);
> CFENew(L);
0.000000000000000000000000000000

```

This allows Magma to calculate as many $a_n$ as it deems necessary using the provided function.

## Setting the Coefficients

### `LSetCoefficients(L, cffun): LSer, Any -> {}`

This function defines the coefficients $a_n$ of the $L$-series $L$. The argument *cffun* can be one of the following:

- A sequence $[a_1,...,a_n]$;

- A function $f(n)$ that returns $a_n$;

- A function $f(p,d)$ that computes the inverse of the local factor at $p$ up to degree $d$.

When a user-defined $L$-series is constructed by invoking the function

```{.magma
> L := LSeries(weight,gamma,conductor,cffun: <optional parameters>);

```

this is actually equivalent to invoking the pair of functions

```{.magma
> L := LSeries(weight,gamma,conductor,0: <optional parameters>);
> LSetCoefficients(L,cffun);

```

where the first line indicates that the coefficients will be supplied later and the second line actually specifies the coefficients. So the following description of the *cffun* argument for the function `LSetCoefficients(L,cffun)` applies to the main `LSeries` signature as well.

The first two ways to specify the $a_n$ are either to give a pre-computed sequence of coefficients up to a certain bound or to give the name of a function $f(n)$ that computes the $a_n$. (The other two ways are described in the two subsections that follow.) For instance, the following both define the Riemann zeta function with weight 1, one $\gamma$-shift 0, conductor 1, sign 1, pole at $s=1$ with residue $-1$, all $a_n=1$:

```{.magma
> V := [ 1 : k in [1..100] ];
> L := LSeries(1, [0], 1, V : Sign:=1, Poles:=[1], Residues:=[-1]);

```

or

```{.magma
> f := func<n|1>;
> L := LSeries(1, [0], 1, f : Sign:=1, Poles:=[1], Residues:=[-1]);

```

Of the two possibilities, the second one is safer to use in a sense that it lets Magma decide how many coefficients it needs in order to perform the calculations to the required precision. However, if the computation of $a_n$ is costly and it involves previous coefficients, then it is probably better to write a function that computes $a_n$ recursively, storing them in a sequence and then passing it to `LSeries`.

## Specifying the Coefficients Later

When specifying a finite list of coefficients it is necessary to know in advance how many coefficients have to be computed. For this, Magma provides a function `LCfRequired(L)` (see Section [Accessing the Invariants](invariants.md#lseries-invariants)).

### `Example: Lseries Lcfrequired (ex-147e8a)`

We define $L$ to be our own version of the Riemann zeta function (weight 1, one $\gamma$-shift 0, conductor 1, sign 1, pole at $s=1$ with residue $-1$), but tell Magma that we will specify the coefficients later with the 4th parameter set to 0. Then we ask how many coefficients it needs to perform computations:

```magma
> L := LSeries(1, [0], 1, 0: Sign:=1, Poles:=[1], Residues:=[-1]);
> N := LCfRequired(L); N;
6

```

Now we compute the coefficient vector $[a_1,...,a_N]$.

```magma
> vec := [1, 1, 1, 1, 1, 1];
> LSetCoefficients(L,vec);

```

Now we can evaluate our $\zeta$-function

```magma
> Evaluate(L,2);
1.64493406684822643647241516665
> Pi(RealField())^2/6;
1.64493406684822643647241516665

```

If we provide fewer coefficients, the computations will not have full precision but we can use `CFENew` or `CheckFunctionalEquation` to get an indication of the resulting accuracy.

```magma
> LSetCoefficients(L, [1,1]);
> CFENew(L);
1.49504837351354351195383363489E-10
> Evaluate(L, 2);
1.64493406707833102002503055804
> $1 - Pi(RealField(28))^2/6;
2.301045835526153913058838556E-10

```

Note that such good accuracy with just two coefficients is a singular phenomenon that only happens for $L$-functions with very small conductors. Normally, at least hundreds of coefficients are needed to compute $L$-values to this precision.

Note also that the last value `Evaluate(L,2)` in the example is much more precise than what one would get with the truncated version of the original defining series $\zeta_{trunc}(s)=1+1/2^s$ at $s=2$. The reason for this is that even in the region where the original Dirichlet series converges, the use of the functional equation usually speeds up the convergence.

## Generating the Coefficients from Local Factors

The final and, in many cases, mathematically the most natural way to supply the coefficients is by specifying the so-called *local factors*. Recall that the coefficients for most $L$-series are *weakly multiplicative*, meaning that $a_{mn}=a_ma_n$ for $m$ coprime to $n$. For such $L$-series, $L(s)$ admits a *product formula*

$$
L(s) = \prod_{p {\rm\ prime}} {1\over F_p(p^{-s})},
$$

where $F_p(x)$ is a formal power series in $x$ with complex coefficients. For example, if $L(s)$ arises from a variety over a number field (and this, as we already mentioned, essentially covers everything), then such a product formula holds. In this case the $F_p(x)$ are polynomials of degree $d$ for those primes $p$ not dividing the conductor and are of smaller degree otherwise. Moreover, their coefficients lie in the ring of integers of the field of definition of the variety.

For $L$-functions with weakly multiplicative coefficients, Magma allows the coefficients to be defined by specifying the local factors, using the function `LSetCoefficients(L,f)` where $f$ is a user-defined function with two arguments $p$ and $d$ that computes $F_p(x)$, either as a full polynomial in $x$ or as a power series in $x$ of precision $O(x^{d+1})$. For example, the Riemann zeta function has $F_p(x)=1-x$ for all $p$, so we can define it as follows,

```
> Z := LSeries(1, [0], 1, 0 : Poles:=[1], Residues:=[-1], Sign:=1);
> P<x> := PolynomialRing(Integers());
> LSetCoefficients(Z, func<p,d | 1-x> );

```

or as

```
> P<x> := PowerSeriesRing(Integers());
> Z := LSeries(1, [0], 1, func<p,d|1-x+O(x^(d+1))> :
               Poles:=[1], Residues:=[-1], Sign:=1);

```
