Torsion subgroups of modular abelian varieties - Modular Abelian Varieties

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

# Torsion subgroups of modular abelian varieties

Sage can compute information about the structure of the torsion subgroup of a modular abelian variety. Sage computes a multiple of the order by computing the greatest common divisor of the orders of the torsion subgroup of the reduction of the abelian variety modulo p for various primes p. Sage computes a divisor of the order by computing the rational cuspidal subgroup. When these two bounds agree (which is often the case), we determine the exact structure of the torsion subgroup.

AUTHORS:

- William Stein (2007-03)

EXAMPLES: First we consider \(J_0(50)\) where everything works out nicely:

Sage

    sage: J = J0(50)
    sage: T = J.rational_torsion_subgroup(); T
    Torsion subgroup of Abelian variety J0(50) of dimension 2
    sage: T.multiple_of_order()
    15
    sage: T.divisor_of_order()
    15
    sage: T.gens()
    ([(1/15, 3/5, 2/5, 14/15)],)
    sage: T.invariants()
    [15]
    sage: d = J.decomposition(); d
    [Simple abelian subvariety 50a(1,50) of dimension 1 of J0(50),
     Simple abelian subvariety 50b(1,50) of dimension 1 of J0(50)]
    sage: d[0].rational_torsion_subgroup().order()
    3
    sage: d[1].rational_torsion_subgroup().order()
    5

Python

    >>> from sage.all import *
    >>> J = J0(Integer(50))
    >>> T = J.rational_torsion_subgroup(); T
    Torsion subgroup of Abelian variety J0(50) of dimension 2
    >>> T.multiple_of_order()
    15
    >>> T.divisor_of_order()
    15
    >>> T.gens()
    ([(1/15, 3/5, 2/5, 14/15)],)
    >>> T.invariants()
    [15]
    >>> d = J.decomposition(); d
    [Simple abelian subvariety 50a(1,50) of dimension 1 of J0(50),
     Simple abelian subvariety 50b(1,50) of dimension 1 of J0(50)]
    >>> d[Integer(0)].rational_torsion_subgroup().order()
    3
    >>> d[Integer(1)].rational_torsion_subgroup().order()
    5

Next we make a table of the upper and lower bounds for each new factor.

Sage

    sage: for N in range(1,38):
    ....:    for A in J0(N).new_subvariety().decomposition():
    ....:        T = A.rational_torsion_subgroup()
    ....:        print('%-5s%-5s%-5s%-5s'%(N, A.dimension(), T.divisor_of_order(), T.multiple_of_order()))
    11   1    5    5
    14   1    6    6
    15   1    8    8
    17   1    4    4
    19   1    3    3
    20   1    6    6
    21   1    8    8
    23   2    11   11
    24   1    8    8
    26   1    3    3
    26   1    7    7
    27   1    3    3
    29   2    7    7
    30   1    6    6
    31   2    5    5
    32   1    4    4
    33   1    4    4
    34   1    6    6
    35   1    3    3
    35   2    16   16
    36   1    6    6
    37   1    1    1
    37   1    3    3

[Python]

    >>> from sage.all import *
    >>> for N in range(Integer(1),Integer(38)):
    ...    for A in J0(N).new_subvariety().decomposition():
    ...        T = A.rational_torsion_subgroup()
    ...        print('%-5s%-5s%-5s%-5s'%(N, A.dimension(), T.divisor_of_order(), T.multiple_of_order()))
    11   1    5    5
    14   1    6    6
    15   1    8    8
    17   1    4    4
    19   1    3    3
    20   1    6    6
    21   1    8    8
    23   2    11   11
    24   1    8    8
    26   1    3    3
    26   1    7    7
    27   1    3    3
    29   2    7    7
    30   1    6    6
    31   2    5    5
    32   1    4    4
    33   1    4    4
    34   1    6    6
    35   1    3    3
    35   2    16   16
    36   1    6    6
    37   1    1    1
    37   1    3    3

class sage.modular.abvar.torsion_subgroup.QQbarTorsionSubgroup(abvar)

  Bases: `Module`

  Group of all torsion points over the algebraic closure on an abelian variety.

  INPUT:

  - `abvar` – an abelian variety

  EXAMPLES:

  Sage

      sage: A = J0(23)
      sage: A.qbar_torsion_subgroup()                                             # needs sage.rings.number_field
      Group of all torsion points in QQbar on Abelian variety J0(23) of dimension 2

  Python

      >>> from sage.all import *
      >>> A = J0(Integer(23))
      >>> A.qbar_torsion_subgroup()                                             # needs sage.rings.number_field
      Group of all torsion points in QQbar on Abelian variety J0(23) of dimension 2

  Element

    alias of `TorsionPoint`

  abelian_variety()

    Return the abelian variety that this is the set of all torsion points on.

    OUTPUT: abelian variety

    EXAMPLES:

    Sage

        sage: J0(23).qbar_torsion_subgroup().abelian_variety()                      # needs sage.rings.number_field
        Abelian variety J0(23) of dimension 2

    Python

        >>> from sage.all import *
        >>> J0(Integer(23)).qbar_torsion_subgroup().abelian_variety()                      # needs sage.rings.number_field
        Abelian variety J0(23) of dimension 2

  field_of_definition()

    Return the field of definition of this subgroup. Since this is the group of all torsion it is defined over the base field of this abelian variety.

    OUTPUT: a field

    EXAMPLES:

    Sage

        sage: J0(23).qbar_torsion_subgroup().field_of_definition()                  # needs sage.rings.number_field
        Rational Field

    Python

        >>> from sage.all import *
        >>> J0(Integer(23)).qbar_torsion_subgroup().field_of_definition()                  # needs sage.rings.number_field
        Rational Field

class sage.modular.abvar.torsion_subgroup.RationalTorsionSubgroup(abvar)

  Bases: `FiniteSubgroup`

  The torsion subgroup of a modular abelian variety.

  divisor_of_order()

    Return a divisor of the order of this torsion subgroup of a modular abelian variety.

    OUTPUT: a divisor of this torsion subgroup

    EXAMPLES:

    Sage

        sage: t = J0(37)[1].rational_torsion_subgroup()
        sage: t.divisor_of_order()
        3

        sage: J = J1(19)
        sage: J.rational_torsion_subgroup().divisor_of_order()
        4383

        sage: J = J0(45)
        sage: J.rational_cusp_subgroup().order()
        32
        sage: J.rational_cuspidal_subgroup().order()
        64
        sage: J.rational_torsion_subgroup().divisor_of_order()
        64

    Python

        >>> from sage.all import *
        >>> t = J0(Integer(37))[Integer(1)].rational_torsion_subgroup()
        >>> t.divisor_of_order()
        3

        >>> J = J1(Integer(19))
        >>> J.rational_torsion_subgroup().divisor_of_order()
        4383

        >>> J = J0(Integer(45))
        >>> J.rational_cusp_subgroup().order()
        32
        >>> J.rational_cuspidal_subgroup().order()
        64
        >>> J.rational_torsion_subgroup().divisor_of_order()
        64

  lattice()

    Return lattice that defines this torsion subgroup, if possible.

    Warning

    There is no known algorithm in general to compute the rational torsion subgroup. Use rational_cusp_group to obtain a subgroup of the rational torsion subgroup in general.

    EXAMPLES:

    Sage

        sage: J0(11).rational_torsion_subgroup().lattice()
        Free module of degree 2 and rank 2 over Integer Ring
        Echelon basis matrix:
        [  1   0]
        [  0 1/5]

    Python

        >>> from sage.all import *
        >>> J0(Integer(11)).rational_torsion_subgroup().lattice()
        Free module of degree 2 and rank 2 over Integer Ring
        Echelon basis matrix:
        [  1   0]
        [  0 1/5]

    The following fails because in fact I know of no (reasonable) algorithm to provably compute the torsion subgroup in general.

    Sage

        sage: T = J0(33).rational_torsion_subgroup()
        sage: T.lattice()
        Traceback (most recent call last):
        ...
        NotImplementedError: unable to compute the rational torsion subgroup
        in this case (there is no known general algorithm yet)

    [Python]

        >>> from sage.all import *
        >>> T = J0(Integer(33)).rational_torsion_subgroup()
        >>> T.lattice()
        Traceback (most recent call last):
        ...
        NotImplementedError: unable to compute the rational torsion subgroup
        in this case (there is no known general algorithm yet)

    The problem is that the multiple of the order obtained by counting points over finite fields is twice the divisor of the order got from the rational cuspidal subgroup.

    Sage

        sage: T.multiple_of_order(30)
        200
        sage: J0(33).rational_cusp_subgroup().order()
        100

    Python

        >>> from sage.all import *
        >>> T.multiple_of_order(Integer(30))
        200
        >>> J0(Integer(33)).rational_cusp_subgroup().order()
        100

  multiple_of_order(maxp=None, proof=True)

    Return a multiple of the order.

    INPUT:

    - `proof` – boolean (default: `True`)

    The computation of the rational torsion order of J1(p) is conjectural and will only be used if proof=False. See Section 6.2.3 of [CES2003].

    EXAMPLES:

    Sage

        sage: J = J1(11); J
        Abelian variety J1(11) of dimension 1
        sage: J.rational_torsion_subgroup().multiple_of_order()
        5

        sage: J = J0(17)
        sage: J.rational_torsion_subgroup().order()
        4

    Python

        >>> from sage.all import *
        >>> J = J1(Integer(11)); J
        Abelian variety J1(11) of dimension 1
        >>> J.rational_torsion_subgroup().multiple_of_order()
        5

        >>> J = J0(Integer(17))
        >>> J.rational_torsion_subgroup().order()
        4

    This is an example where proof=False leads to a better bound and better performance.

    Sage

        sage: J = J1(23)
        sage: J.rational_torsion_subgroup().multiple_of_order()  # long time (2s)
        9406793
        sage: J.rational_torsion_subgroup().multiple_of_order(proof=False)
        408991

    [Python]

        >>> from sage.all import *
        >>> J = J1(Integer(23))
        >>> J.rational_torsion_subgroup().multiple_of_order()  # long time (2s)
        9406793
        >>> J.rational_torsion_subgroup().multiple_of_order(proof=False)
        408991

  multiple_of_order_using_frobp(maxp=None)

    Return a multiple of the order of this torsion group.

    In the \(Gamma_0\) case, the multiple is computed using characteristic polynomials of Hecke operators of odd index not dividing the level. In the \(Gamma_1\) case, the multiple is computed by expressing the frobenius polynomial in terms of the characteristic polynomial of left multiplication by \(a_p\) for odd primes p not dividing the level.

    INPUT:

    - `maxp` – (default: `None`) if `maxp` is `None`, return gcd of best bound computed so far with bound obtained by computing GCD’s of orders modulo \(p\) until this gcd stabilizes for 3 successive primes. If `maxp` is given, just use all primes up to and including `maxp`.

    EXAMPLES:

    Sage

        sage: J = J0(11)
        sage: G = J.rational_torsion_subgroup()
        sage: G.multiple_of_order_using_frobp(11)
        5

    Python

        >>> from sage.all import *
        >>> J = J0(Integer(11))
        >>> G = J.rational_torsion_subgroup()
        >>> G.multiple_of_order_using_frobp(Integer(11))
        5

    Increasing maxp may yield a tighter bound. If maxp=None, then Sage will use more primes until the multiple stabilizes for 3 successive primes.

    Sage

        sage: J = J0(389)
        sage: G = J.rational_torsion_subgroup(); G
        Torsion subgroup of Abelian variety J0(389) of dimension 32
        sage: G.multiple_of_order_using_frobp()
        97
        sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,11)]
        [92645296242160800, 7275, 291]
        sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,13)]
        [92645296242160800, 7275, 291, 97]
        sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,19)]
        [92645296242160800, 7275, 291, 97, 97, 97]

    [Python]

        >>> from sage.all import *
        >>> J = J0(Integer(389))
        >>> G = J.rational_torsion_subgroup(); G
        Torsion subgroup of Abelian variety J0(389) of dimension 32
        >>> G.multiple_of_order_using_frobp()
        97
        >>> [G.multiple_of_order_using_frobp(p) for p in prime_range(Integer(3),Integer(11))]
        [92645296242160800, 7275, 291]
        >>> [G.multiple_of_order_using_frobp(p) for p in prime_range(Integer(3),Integer(13))]
        [92645296242160800, 7275, 291, 97]
        >>> [G.multiple_of_order_using_frobp(p) for p in prime_range(Integer(3),Integer(19))]
        [92645296242160800, 7275, 291, 97, 97, 97]

    We can compute the multiple of order of the torsion subgroup for Gamma0 and Gamma1 varieties, and their products.

    Sage

        sage: A = J0(11) * J0(33)
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        1000

        sage: A = J1(23)
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        9406793
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp(maxp=50)
        408991

        sage: A = J1(19) * J0(21)
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        35064

    Python

        >>> from sage.all import *
        >>> A = J0(Integer(11)) * J0(Integer(33))
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        1000

        >>> A = J1(Integer(23))
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        9406793
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp(maxp=Integer(50))
        408991

        >>> A = J1(Integer(19)) * J0(Integer(21))
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        35064

    The next example illustrates calling this function with a larger input and how the result may be cached when maxp is None:

    Sage

        sage: T = J0(43)[1].rational_torsion_subgroup()
        sage: T.multiple_of_order_using_frobp()
        14
        sage: T.multiple_of_order_using_frobp(50)
        7
        sage: T.multiple_of_order_using_frobp()
        7

    [Python]

        >>> from sage.all import *
        >>> T = J0(Integer(43))[Integer(1)].rational_torsion_subgroup()
        >>> T.multiple_of_order_using_frobp()
        14
        >>> T.multiple_of_order_using_frobp(Integer(50))
        7
        >>> T.multiple_of_order_using_frobp()
        7

    This function is not implemented for general congruence subgroups unless the dimension is zero.

    Sage

        sage: A = JH(13,[2]); A
        Abelian variety J0(13) of dimension 0
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        1

        sage: A = JH(15, [2]); A
        Abelian variety JH(15,[2]) of dimension 1
        sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        Traceback (most recent call last):
        ...
        NotImplementedError: torsion multiple only implemented for Gamma0 and Gamma1

    Python

        >>> from sage.all import *
        >>> A = JH(Integer(13),[Integer(2)]); A
        Abelian variety J0(13) of dimension 0
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        1

        >>> A = JH(Integer(15), [Integer(2)]); A
        Abelian variety JH(15,[2]) of dimension 1
        >>> A.rational_torsion_subgroup().multiple_of_order_using_frobp()
        Traceback (most recent call last):
        ...
        NotImplementedError: torsion multiple only implemented for Gamma0 and Gamma1

  order(proof=True)

    Return the order of the torsion subgroup of this modular abelian variety.

    This function may fail if the multiple obtained by counting points modulo \(p\) exceeds the divisor obtained from the rational cuspidal subgroup.

    The computation of the rational torsion order of J1(p) is conjectural and will only be used if `proof=False`. See Section 6.2.3 of [CES2003].

    INPUT:

    - `proof` – boolean (default: `True`)

    OUTPUT: the order of this torsion subgroup

    EXAMPLES:

    Sage

        sage: A = J0(11)
        sage: A.rational_torsion_subgroup().order()
        5
        sage: A = J0(23)
        sage: A.rational_torsion_subgroup().order()
        11
        sage: T = J0(37)[1].rational_torsion_subgroup()
        sage: T.order()
        3

        sage: J = J1(13)
        sage: J.rational_torsion_subgroup().order()
        19

    Python

        >>> from sage.all import *
        >>> A = J0(Integer(11))
        >>> A.rational_torsion_subgroup().order()
        5
        >>> A = J0(Integer(23))
        >>> A.rational_torsion_subgroup().order()
        11
        >>> T = J0(Integer(37))[Integer(1)].rational_torsion_subgroup()
        >>> T.order()
        3

        >>> J = J1(Integer(13))
        >>> J.rational_torsion_subgroup().order()
        19

    Sometimes the order can only be computed with `proof=False`.

    Sage

        sage: J = J1(23)
        sage: J.rational_torsion_subgroup().order()
        Traceback (most recent call last):
        ...
        RuntimeError: Unable to compute order of torsion subgroup
        (it is in [408991, 9406793])

        sage: J.rational_torsion_subgroup().order(proof=False)
        408991

    [Python]

        >>> from sage.all import *
        >>> J = J1(Integer(23))
        >>> J.rational_torsion_subgroup().order()
        Traceback (most recent call last):
        ...
        RuntimeError: Unable to compute order of torsion subgroup
        (it is in [408991, 9406793])

        >>> J.rational_torsion_subgroup().order(proof=False)
        408991

  possible_orders(proof=True)

    Return the possible orders of this torsion subgroup. Outside of special cases, this is done by computing a divisor and multiple of the order.

    INPUT:

    - `proof` – boolean (default: `True`)

    OUTPUT: an array of positive integers

    The computation of the rational torsion order of J1(p) is conjectural and will only be used if `proof=False`. See Section 6.2.3 of [CES2003].

    EXAMPLES:

    Sage

        sage: J0(11).rational_torsion_subgroup().possible_orders()
        [5]
        sage: J0(33).rational_torsion_subgroup().possible_orders()
        [100, 200]

        sage: J1(13).rational_torsion_subgroup().possible_orders()
        [19]
        sage: J1(16).rational_torsion_subgroup().possible_orders()
        [1, 2, 4, 5, 10, 20]

    Python

        >>> from sage.all import *
        >>> J0(Integer(11)).rational_torsion_subgroup().possible_orders()
        [5]
        >>> J0(Integer(33)).rational_torsion_subgroup().possible_orders()
        [100, 200]

        >>> J1(Integer(13)).rational_torsion_subgroup().possible_orders()
        [19]
        >>> J1(Integer(16)).rational_torsion_subgroup().possible_orders()
        [1, 2, 4, 5, 10, 20]