Dokchitser’s \(L\)-functions calculator - $L$-Functions

Skip to content
Back to top
View this page
Edit this page

# Dokchitser’s \(L\)-functions calculator

Todo

- add more examples from SAGE_EXTCODE/pari/dokchitser that illustrate use with Eisenstein series, number fields, etc.

- plug this code into number fields and modular forms code (elliptic curves are done).

AUTHORS:

- Tim Dokchitser (2002): original PARI code and algorithm (and the documentation below is based on Dokchitser’s docs).

- William Stein (2006-03-08): Sage interface

class sage.lfunctions.dokchitser.Dokchitser(*args, **kwargs)

  Bases: `SageObject`

  Dokchitser’s \(L\)-functions Calculator.

  PARI code can be found on Dokchitser’s homepage.

  Create a Dokchitser \(L\)-series with

  Dokchitser(conductor, gammaV, weight, eps, poles, residues, init, prec)

  where

  - `conductor` – integer; the conductor

  - `gammaV` – list of Gamma-factor parameters, e.g. [0] for Riemann zeta, [0,1] for ell.curves, (see examples)

  - `weight` – positive real number, usually an integer e.g. 1 for Riemann zeta, 2 for \(H^1\) of curves/\(\QQ\)

  - `eps` – complex number; sign in functional equation

  - `poles` – (default: `[]`) list of points where \(L^*(s)\) has (simple) poles; only poles with \(Re(s)>weight/2\) should be included

  - `residues` – vector of residues of \(L^*(s)\) in those poles or set `residues='automatic'` (default)

  - `prec` – integer (default: 53); number of bits of precision

  RIEMANN ZETA FUNCTION:

  We compute with the Riemann Zeta function.

  Sage

      sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
      sage: L
      Dokchitser L-series of conductor 1 and weight 1
      sage: L(1)
      Traceback (most recent call last):
      ...
      ArithmeticError
      sage: L(2)
      1.64493406684823
      sage: L(2, 1.1)
      1.64493406684823
      sage: L.derivative(2)
      -0.937548254315844
      sage: h = RR('0.0000000000001')
      sage: (zeta(2+h) - zeta(2.))/h
      -0.937028232783632
      sage: L.taylor_series(2, k=5)
      1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)

  Python

      >>> from sage.all import *
      >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0)], weight=Integer(1), eps=Integer(1), poles=[Integer(1)], residues=[-Integer(1)], init='1')
      >>> L
      Dokchitser L-series of conductor 1 and weight 1
      >>> L(Integer(1))
      Traceback (most recent call last):
      ...
      ArithmeticError
      >>> L(Integer(2))
      1.64493406684823
      >>> L(Integer(2), RealNumber('1.1'))
      1.64493406684823
      >>> L.derivative(Integer(2))
      -0.937548254315844
      >>> h = RR('0.0000000000001')
      >>> (zeta(Integer(2)+h) - zeta(RealNumber('2.')))/h
      -0.937028232783632
      >>> L.taylor_series(Integer(2), k=Integer(5))
      1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5)

  RANK 1 ELLIPTIC CURVE:

  We compute with the \(L\)-series of a rank \(1\) curve.

  Sage

      sage: E = EllipticCurve('37a')
      sage: L = E.lseries().dokchitser(algorithm='pari'); L
      PARI L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
      sage: L(1)
      0.000000000000000
      sage: L.derivative(1)
      0.305999773834052
      sage: L.derivative(1,2)
      0.373095594536324
      sage: L.cost()
      205
      sage: L.taylor_series(1,4)
      0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
      sage: L.check_functional_equation()  # abs tol 1e-17
      6.04442711160669e-18

  [Python]

      >>> from sage.all import *
      >>> E = EllipticCurve('37a')
      >>> L = E.lseries().dokchitser(algorithm='pari'); L
      PARI L-function associated to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
      >>> L(Integer(1))
      0.000000000000000
      >>> L.derivative(Integer(1))
      0.305999773834052
      >>> L.derivative(Integer(1),Integer(2))
      0.373095594536324
      >>> L.cost()
      205
      >>> L.taylor_series(Integer(1),Integer(4))
      0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4)
      >>> L.check_functional_equation()  # abs tol 1e-17
      6.04442711160669e-18

  RANK 2 ELLIPTIC CURVE:

  We compute the leading coefficient and Taylor expansion of the \(L\)-series of a rank \(2\) elliptic curve.

  Sage

      sage: E = EllipticCurve('389a')
      sage: L = E.lseries().dokchitser(algorithm='pari')
      sage: L.cost()
      666
      sage: L.derivative(1,E.rank())
      1.51863300057685
      sage: L.taylor_series(1,4)
      ...e-19 + (...e-19)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)

  Python

      >>> from sage.all import *
      >>> E = EllipticCurve('389a')
      >>> L = E.lseries().dokchitser(algorithm='pari')
      >>> L.cost()
      666
      >>> L.derivative(Integer(1),E.rank())
      1.51863300057685
      >>> L.taylor_series(Integer(1),Integer(4))
      ...e-19 + (...e-19)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4)

  NUMBER FIELD:

  We compute with the Dedekind zeta function of a number field.

  Sage

      sage: x = var('x')
      sage: K = NumberField(x**4 - x**2 - 1,'a')
      sage: L = K.zeta_function(algorithm='gp')
      sage: L.conductor
      400
      sage: L.cost()
      5499
      sage: L(2)
      1.10398438736918
      sage: L.taylor_series(2,3)
      1.10398438736918 - 0.215822638498759*z + 0.279836437522536*z^2 + O(z^3)

  [Python]

      >>> from sage.all import *
      >>> x = var('x')
      >>> K = NumberField(x**Integer(4) - x**Integer(2) - Integer(1),'a')
      >>> L = K.zeta_function(algorithm='gp')
      >>> L.conductor
      400
      >>> L.cost()
      5499
      >>> L(Integer(2))
      1.10398438736918
      >>> L.taylor_series(Integer(2),Integer(3))
      1.10398438736918 - 0.215822638498759*z + 0.279836437522536*z^2 + O(z^3)

  RAMANUJAN DELTA L-FUNCTION:

  The coefficients are given by Ramanujan’s tau function:

  Sage

      sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
      sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
      sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

  Python

      >>> from sage.all import *
      >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0),Integer(1)], weight=Integer(12), eps=Integer(1))
      >>> pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
      >>> L.init_coeffs('tau(k)', pari_precode=pari_precode)

  We redefine the default bound on the coefficients: Deligne’s estimate on tau(n) is better than the default coefgrow(n)= \((4n)^{11/2}\) (by a factor 1024), so re-defining coefgrow() improves efficiency (slightly faster).

  Sage

      sage: L.cost()
      12
      sage: L.set_coeff_growth('2*n^(11/2)')
      sage: L.cost()
      11

  [Python]

      >>> from sage.all import *
      >>> L.cost()
      12
      >>> L.set_coeff_growth('2*n^(11/2)')
      >>> L.cost()
      11

  Now we’re ready to evaluate, etc.

  Sage

      sage: L(1)
      0.0374412812685155
      sage: L(1, 1.1)
      0.0374412812685155
      sage: L.taylor_series(1,3)
      0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)

  Python

      >>> from sage.all import *
      >>> L(Integer(1))
      0.0374412812685155
      >>> L(Integer(1), RealNumber('1.1'))
      0.0374412812685155
      >>> L.taylor_series(Integer(1),Integer(3))
      0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3)

  check_functional_equation(T=1.2)

    Verifies how well numerically the functional equation is satisfied, and also determines the residues if `self.poles != []` and residues=’automatic’.

    More specifically: for \(T>1\) (default: 1.2), `self.check_functional_equation(T)` should ideally return 0 (to the current precision).

    - if what this function returns does not look like 0 at all, probably the functional equation is wrong (i.e. some of the parameters gammaV, conductor etc., or the coefficients are wrong),

    - if checkfeq(T) is to be used, more coefficients have to be generated (approximately T times more), e.g. call cflength(1.3), initLdata(“a(k)”,1.3), checkfeq(1.3)

    - T=1 always (!) returns 0, so T has to be away from 1

    - default value \(T=1.2\) seems to give a reasonable balance

    - if you don’t have to verify the functional equation or the L-values, call cost(1) and initLdata(“a(k)”,1), you need slightly less coefficients.

    EXAMPLES:

    Sage

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L.check_functional_equation()  # abs tol 1e-19
        -2.71050543121376e-20

    Python

        >>> from sage.all import *
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0)], weight=Integer(1), eps=Integer(1), poles=[Integer(1)], residues=[-Integer(1)], init='1')
        >>> L.check_functional_equation()  # abs tol 1e-19
        -2.71050543121376e-20

    If we choose the sign in functional equation for the \(\zeta\) function incorrectly, the functional equation doesn’t check out.

    Sage

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=-11, poles=[1], residues=[-1], init='1')
        sage: L.check_functional_equation()
        -9.73967861488124

    [Python]

        >>> from sage.all import *
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0)], weight=Integer(1), eps=-Integer(11), poles=[Integer(1)], residues=[-Integer(1)], init='1')
        >>> L.check_functional_equation()
        -9.73967861488124

  cost(T=1)

    Return the number of coefficients \(a_n\) that are needed in order to perform most relevant \(L\)-function computations to the desired precision.

    EXAMPLES:

    Sage

        sage: E = EllipticCurve('11a')
        sage: L = E.lseries().dokchitser(algorithm='pari')
        sage: L.cost()
        112
        sage: E = EllipticCurve('5077a')
        sage: L = E.lseries().dokchitser(algorithm='pari')
        sage: L.cost()
        2406
        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L.cost()
        4

    Python

        >>> from sage.all import *
        >>> E = EllipticCurve('11a')
        >>> L = E.lseries().dokchitser(algorithm='pari')
        >>> L.cost()
        112
        >>> E = EllipticCurve('5077a')
        >>> L = E.lseries().dokchitser(algorithm='pari')
        >>> L.cost()
        2406
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0)], weight=Integer(1), eps=Integer(1), poles=[Integer(1)], residues=[-Integer(1)], init='1')
        >>> L.cost()
        4

    Verify that `cost` works with non-real spectral parameters, e.g. for the \(L\)-function of the level 10 Maass form with eigenvalue 2.7341055592527126:

    Sage

        sage: ev = 2.7341055592527126
        sage: L = Dokchitser(conductor=10, gammaV=[ev*i, -ev*i],weight=2,eps=1)
        sage: L.cost()
        26

    [Python]

        >>> from sage.all import *
        >>> ev = RealNumber('2.7341055592527126')
        >>> L = Dokchitser(conductor=Integer(10), gammaV=[ev*i, -ev*i],weight=Integer(2),eps=Integer(1))
        >>> L.cost()
        26

  derivative(s, k=1)

    Return the \(k\)-th derivative of the \(L\)-series at \(s\).

    Warning

    If \(k\) is greater than the order of vanishing of \(L\) at \(s\) you may get nonsense.

    EXAMPLES:

    Sage

        sage: E = EllipticCurve('389a')
        sage: L = E.lseries().dokchitser(algorithm='pari')
        sage: L.derivative(1,E.rank())
        1.51863300057685

    Python

        >>> from sage.all import *
        >>> E = EllipticCurve('389a')
        >>> L = E.lseries().dokchitser(algorithm='pari')
        >>> L.derivative(Integer(1),E.rank())
        1.51863300057685

  gp()

    Return the gp interpreter that is used to implement this Dokchitser \(L\)-function.

  init_coeffs(v, cutoff=1, w=None, pari_precode='', max_imaginary_part=0, max_asymp_coeffs=40)

    Set the coefficients \(a_n\) of the \(L\)-series.

    If \(L(s)\) is not equal to its dual, pass the coefficients of the dual as the second optional argument.

    INPUT:

    - `v` – list of complex numbers or string (pari function of k)

    - `cutoff` – real number (default: 1)

    - `w` – list of complex numbers or string (pari function of k)

    - `pari_precode` – some code to execute in pari before calling initLdata

    - `max_imaginary_part` – (default: 0) redefine if you want to compute L(s) for s having large imaginary part

    - `max_asymp_coeffs` – (default: 40) at most this many terms are generated in asymptotic series for phi(t) and G(s,t)

    EXAMPLES:

    Sage

        sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)

    Python

        >>> from sage.all import *
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0),Integer(1)], weight=Integer(12), eps=Integer(1))
        >>> pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        >>> L.init_coeffs('tau(k)', pari_precode=pari_precode)

    Evaluate the resulting \(L\)-function at a point, and compare with the answer that one gets “by definition” (of \(L\)-function attached to a modular form):

    Sage

        sage: L(14)
        0.998583063162746
        sage: a = delta_qexp(1000)
        sage: sum(a[n]/float(n)^14 for n in reversed(range(1,1000)))
        0.9985830631627461

    [Python]

        >>> from sage.all import *
        >>> L(Integer(14))
        0.998583063162746
        >>> a = delta_qexp(Integer(1000))
        >>> sum(a[n]/float(n)**Integer(14) for n in reversed(range(Integer(1),Integer(1000))))
        0.9985830631627461

    Illustrate that one can give a list of complex numbers for v (see Issue #10937):

    Sage

        sage: L2 = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: L2.init_coeffs(list(delta_qexp(1000))[1:])
        sage: L2(14)
        0.998583063162746

    Python

        >>> from sage.all import *
        >>> L2 = Dokchitser(conductor=Integer(1), gammaV=[Integer(0),Integer(1)], weight=Integer(12), eps=Integer(1))
        >>> L2.init_coeffs(list(delta_qexp(Integer(1000)))[Integer(1):])
        >>> L2(Integer(14))
        0.998583063162746

  num_coeffs(T=1)

    alias of `cost()`.

  set_coeff_growth(coefgrow)

    You might have to redefine the coefficient growth function if the \(a_n\) of the \(L\)-series are not given by the following PARI function:

        coefgrow(n) = if(length(Lpoles),
                          1.5*n^(vecmax(real(Lpoles))-1),
                          sqrt(4*n)^(weight-1));

    INPUT:

    - `coefgrow` – string that evaluates to a PARI function of n that defines a coefgrow function

    EXAMPLES:

    Sage

        sage: L = Dokchitser(conductor=1, gammaV=[0,1], weight=12, eps=1)
        sage: pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        sage: L.init_coeffs('tau(k)', pari_precode=pari_precode)
        sage: L.set_coeff_growth('2*n^(11/2)')
        sage: L(1)
        0.0374412812685155

    Python

        >>> from sage.all import *
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0),Integer(1)], weight=Integer(12), eps=Integer(1))
        >>> pari_precode = 'tau(n)=(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5))'
        >>> L.init_coeffs('tau(k)', pari_precode=pari_precode)
        >>> L.set_coeff_growth('2*n^(11/2)')
        >>> L(Integer(1))
        0.0374412812685155

  taylor_series(a=0, k=6, var='z')

    Return the first \(k\) terms of the Taylor series expansion of the \(L\)-series about \(a\).

    This is returned as a series in `var`, where you should view `var` as equal to \(s-a\). Thus this function returns the formal power series whose coefficients are \(L^{(n)}(a)/n!\).

    INPUT:

    - `a` – complex number (default: 0); point about which to expand

    - `k` – integer (default: 6); series is \(O(\texttt{var}^k)\)

    - `var` – string (default: `'z'`); variable of power series

    EXAMPLES:

    Sage

        sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
        sage: L.taylor_series(2, 3)
        1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
        sage: E = EllipticCurve('37a')
        sage: L = E.lseries().dokchitser(algorithm='pari')
        sage: L.taylor_series(1)
        0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)

    Python

        >>> from sage.all import *
        >>> L = Dokchitser(conductor=Integer(1), gammaV=[Integer(0)], weight=Integer(1), eps=Integer(1), poles=[Integer(1)], residues=[-Integer(1)], init='1')
        >>> L.taylor_series(Integer(2), Integer(3))
        1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 + O(z^3)
        >>> E = EllipticCurve('37a')
        >>> L = E.lseries().dokchitser(algorithm='pari')
        >>> L.taylor_series(Integer(1))
        0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + 0.0161066468496401*z^4 + 0.0185955175398802*z^5 + O(z^6)

    We compute a Taylor series where each coefficient is to high precision.

    Sage

        sage: E = EllipticCurve('389a')
        sage: L = E.lseries().dokchitser(200, algorithm='pari')
        sage: L.taylor_series(1,3)
        ...e-63 + (...e-63)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)

    [Python]

        >>> from sage.all import *
        >>> E = EllipticCurve('389a')
        >>> L = E.lseries().dokchitser(Integer(200), algorithm='pari')
        >>> L.taylor_series(Integer(1),Integer(3))
        ...e-63 + (...e-63)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3)

    Check that Issue #25402 is fixed:

    Sage

        sage: L = EllipticCurve("24a1").modular_form().lseries()
        sage: L.taylor_series(-1, 3)
        0.000000000000000 - 0.702565506265199*z + 0.638929001045535*z^2 + O(z^3)

    Python

        >>> from sage.all import *
        >>> L = EllipticCurve("24a1").modular_form().lseries()
        >>> L.taylor_series(-Integer(1), Integer(3))
        0.000000000000000 - 0.702565506265199*z + 0.638929001045535*z^2 + O(z^3)

    Check that Issue #25965 is fixed:

    Sage

        sage: L2 = EllipticCurve("37a1").modular_form().lseries(); L2
        L-series associated to the cusp form q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + O(q^6)
        sage: L2.taylor_series(0,4)
        0.000000000000000 - 0.357620466127498*z + 0.273373112603865*z^2 + 0.303362857047671*z^3 + O(z^4)
        sage: L2.taylor_series(0,1)
        O(z^1)
        sage: L2(0)
        0.000000000000000

    [Python]

        >>> from sage.all import *
        >>> L2 = EllipticCurve("37a1").modular_form().lseries(); L2
        L-series associated to the cusp form q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + O(q^6)
        >>> L2.taylor_series(Integer(0),Integer(4))
        0.000000000000000 - 0.357620466127498*z + 0.273373112603865*z^2 + 0.303362857047671*z^3 + O(z^4)
        >>> L2.taylor_series(Integer(0),Integer(1))
        O(z^1)
        >>> L2(Integer(0))
        0.000000000000000

sage.lfunctions.dokchitser.reduce_load_dokchitser(D)