Quotients of the Bruhat-Tits tree

This package contains all the functionality described and developed in [FM2014]. It allows for computations with fundamental domains of the Bruhat-Tits tree, under the action of arithmetic groups arising from units in definite quaternion algebras.

EXAMPLES:

Create the quotient attached to a maximal order of the quaternion algebra of discriminant \(13\), at the prime \(p = 5\):

sage: Y = BruhatTitsQuotient(5, 13)
>>> from sage.all import *
>>> Y = BruhatTitsQuotient(Integer(5), Integer(13))
Y = BruhatTitsQuotient(5, 13)

We can query for its genus, as well as get it back as a graph:

sage: Y.genus()
5
sage: Y.get_graph()
Multi-graph on 2 vertices
>>> from sage.all import *
>>> Y.genus()
5
>>> Y.get_graph()
Multi-graph on 2 vertices
Y.genus()
Y.get_graph()

The rest of functionality can be found in the docstrings below.

AUTHORS:

  • Cameron Franc and Marc Masdeu (2011): initial version

class sage.modular.btquotients.btquotient.BruhatTitsQuotient(p, Nminus, Nplus=1, character=None, use_magma=False, seed=None, magma_session=None)[source]

Bases: SageObject, UniqueRepresentation

This function computes the quotient of the Bruhat-Tits tree by an arithmetic quaternionic group. The group in question is the group of norm 1 elements in an Eichler \(\ZZ[1/p]\)-order of some (tame) level inside of a definite quaternion algebra that is unramified at the prime \(p\). Note that this routine relies in Magma in the case \(p = 2\) or when \(N^{+} > 1\).

INPUT:

  • p – a prime number

  • Nminus – squarefree integer divisible by an odd number of distinct primes and relatively prime to p. This is the discriminant of the definite quaternion algebra that one is quotienting by.

  • Nplus – integer coprime to pNminus (default: 1). This is the tame level. It need not be squarefree! If Nplus is not 1 then the user currently needs magma installed due to sage’s inability to compute well with nonmaximal Eichler orders in rational (definite) quaternion algebras.

  • character – a Dirichlet character (default: None) of modulus \(pN^-N^+\)

  • use_magma – boolean (default: False); if True, uses Magma for quaternion arithmetic

  • magma_session – (default: None) if specified, the Magma session to use

EXAMPLES:

Here is an example without a Dirichlet character:

sage: X = BruhatTitsQuotient(13, 19)
sage: X.genus()
19
sage: G = X.get_graph(); G
Multi-graph on 4 vertices
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(13), Integer(19))
>>> X.genus()
19
>>> G = X.get_graph(); G
Multi-graph on 4 vertices
X = BruhatTitsQuotient(13, 19)
X.genus()
G = X.get_graph(); G

And an example with a Dirichlet character:

sage: f = DirichletGroup(6)[1]
sage: X = BruhatTitsQuotient(3,2*5*7,character = f)
sage: X.genus()
5
>>> from sage.all import *
>>> f = DirichletGroup(Integer(6))[Integer(1)]
>>> X = BruhatTitsQuotient(Integer(3),Integer(2)*Integer(5)*Integer(7),character = f)
>>> X.genus()
5
f = DirichletGroup(6)[1]
X = BruhatTitsQuotient(3,2*5*7,character = f)
X.genus()

Note

A sage implementation of Eichler orders in rational quaternions algebras would remove the dependency on magma.

AUTHORS:

  • Marc Masdeu (2012-02-20)

B_one()[source]

Return the coordinates of \(1\) in the basis for the quaternion order.

EXAMPLES:

sage: X = BruhatTitsQuotient(7,11)
sage: v,pow = X.B_one()
sage: X._conv(v) == 1
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(11))
>>> v,pow = X.B_one()
>>> X._conv(v) == Integer(1)
True
X = BruhatTitsQuotient(7,11)
v,pow = X.B_one()
X._conv(v) == 1
Nminus()[source]

Return the discriminant of the relevant definite quaternion algebra.

OUTPUT:

An integer equal to \(N^-\).

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.Nminus()
7
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.Nminus()
7
X = BruhatTitsQuotient(5,7)
X.Nminus()
Nplus()[source]

Return the tame level \(N^+\).

OUTPUT: integer equal to \(N^+\)

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7,1)
sage: X.Nplus()
1
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7),Integer(1))
>>> X.Nplus()
1
X = BruhatTitsQuotient(5,7,1)
X.Nplus()
dimension_harmonic_cocycles(k, lev=None, Nplus=None, character=None)[source]

Compute the dimension of the space of harmonic cocycles of weight \(k\) on self.

OUTPUT: integer equal to the dimension

EXAMPLES:

sage: X = BruhatTitsQuotient(3,7)
sage: [X.dimension_harmonic_cocycles(k) for k in range(2,20,2)]
[1, 4, 4, 8, 8, 12, 12, 16, 16]

sage: X = BruhatTitsQuotient(2,5) # optional - magma
sage: [X.dimension_harmonic_cocycles(k) for k in range(2,40,2)] # optional - magma
[0, 1, 3, 1, 3, 5, 3, 5, 7, 5, 7, 9, 7, 9, 11, 9, 11, 13, 11]

sage: X = BruhatTitsQuotient(7, 2 * 3 * 5)
sage: X.dimension_harmonic_cocycles(4)
12
sage: X = BruhatTitsQuotient(7, 2 * 3 * 5 * 11 * 13)
sage: X.dimension_harmonic_cocycles(2)
481
sage: X.dimension_harmonic_cocycles(4)
1440
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(7))
>>> [X.dimension_harmonic_cocycles(k) for k in range(Integer(2),Integer(20),Integer(2))]
[1, 4, 4, 8, 8, 12, 12, 16, 16]

>>> X = BruhatTitsQuotient(Integer(2),Integer(5)) # optional - magma
>>> [X.dimension_harmonic_cocycles(k) for k in range(Integer(2),Integer(40),Integer(2))] # optional - magma
[0, 1, 3, 1, 3, 5, 3, 5, 7, 5, 7, 9, 7, 9, 11, 9, 11, 13, 11]

>>> X = BruhatTitsQuotient(Integer(7), Integer(2) * Integer(3) * Integer(5))
>>> X.dimension_harmonic_cocycles(Integer(4))
12
>>> X = BruhatTitsQuotient(Integer(7), Integer(2) * Integer(3) * Integer(5) * Integer(11) * Integer(13))
>>> X.dimension_harmonic_cocycles(Integer(2))
481
>>> X.dimension_harmonic_cocycles(Integer(4))
1440
X = BruhatTitsQuotient(3,7)
[X.dimension_harmonic_cocycles(k) for k in range(2,20,2)]
X = BruhatTitsQuotient(2,5) # optional - magma
[X.dimension_harmonic_cocycles(k) for k in range(2,40,2)] # optional - magma
X = BruhatTitsQuotient(7, 2 * 3 * 5)
X.dimension_harmonic_cocycles(4)
X = BruhatTitsQuotient(7, 2 * 3 * 5 * 11 * 13)
X.dimension_harmonic_cocycles(2)
X.dimension_harmonic_cocycles(4)
e3()[source]

Compute the \(e_3\) invariant defined by the formula

\[e_k =\prod_{\ell\mid pN^-}\left(1-\left(\frac{-3}{\ell}\right)\right)\prod_{\ell \| N^+}\left(1+\left(\frac{-3}{\ell}\right)\right)\prod_{\ell^2\mid N^+} \nu_\ell(3)\]

OUTPUT: integer

EXAMPLES:

sage: X = BruhatTitsQuotient(31,3)
sage: X.e3
1
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(31),Integer(3))
>>> X.e3
1
X = BruhatTitsQuotient(31,3)
X.e3
e4()[source]

Compute the \(e_4\) invariant defined by the formula

\[e_k =\prod_{\ell\mid pN^-}\left(1-\left(\frac{-k}{\ell}\right)\right)\prod_{\ell \| N^+}\left(1+\left(\frac{-k}{\ell}\right)\right)\prod_{\ell^2\mid N^+} \nu_\ell(k)\]

OUTPUT: integer

EXAMPLES:

sage: X = BruhatTitsQuotient(31,3)
sage: X.e4
2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(31),Integer(3))
>>> X.e4
2
X = BruhatTitsQuotient(31,3)
X.e4
embed(g, exact=False, prec=None)[source]

Embed the quaternion element g into a matrix algebra.

INPUT:

  • g – a row vector of size \(4\) whose entries represent a quaternion in our basis

  • exact – boolean (default: False); if True, tries to embed g into a matrix algebra over a number field. If False, the target is the matrix algebra over \(\QQ_p\).

OUTPUT:

A 2x2 matrix with coefficients in \(\QQ_p\) if exact is False, or a number field if exact is True.

EXAMPLES:

sage: X = BruhatTitsQuotient(7,2)
sage: l = X.get_units_of_order()
sage: len(l)
12
sage: l[3] # random
[-1]
[ 0]
[ 1]
[ 1]
sage: u = X.embed_quaternion(l[3]); u # random
[    O(7) 3 + O(7)]
[2 + O(7) 6 + O(7)]
sage: X._increase_precision(5)
sage: v = X.embed_quaternion(l[3]); v # random
[                7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)             3 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)]
[            2 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6) 6 + 5*7 + 3*7^2 + 5*7^3 + 2*7^4 + 6*7^5 + O(7^6)]
sage: u == v
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(2))
>>> l = X.get_units_of_order()
>>> len(l)
12
>>> l[Integer(3)] # random
[-1]
[ 0]
[ 1]
[ 1]
>>> u = X.embed_quaternion(l[Integer(3)]); u # random
[    O(7) 3 + O(7)]
[2 + O(7) 6 + O(7)]
>>> X._increase_precision(Integer(5))
>>> v = X.embed_quaternion(l[Integer(3)]); v # random
[                7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)             3 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)]
[            2 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6) 6 + 5*7 + 3*7^2 + 5*7^3 + 2*7^4 + 6*7^5 + O(7^6)]
>>> u == v
True
X = BruhatTitsQuotient(7,2)
l = X.get_units_of_order()
len(l)
l[3] # random
u = X.embed_quaternion(l[3]); u # random
X._increase_precision(5)
v = X.embed_quaternion(l[3]); v # random
u == v
embed_quaternion(g, exact=False, prec=None)[source]

Embed the quaternion element g into a matrix algebra.

INPUT:

  • g – a row vector of size \(4\) whose entries represent a quaternion in our basis

  • exact – boolean (default: False); if True, tries to embed g into a matrix algebra over a number field. If False, the target is the matrix algebra over \(\QQ_p\).

OUTPUT:

A 2x2 matrix with coefficients in \(\QQ_p\) if exact is False, or a number field if exact is True.

EXAMPLES:

sage: X = BruhatTitsQuotient(7,2)
sage: l = X.get_units_of_order()
sage: len(l)
12
sage: l[3] # random
[-1]
[ 0]
[ 1]
[ 1]
sage: u = X.embed_quaternion(l[3]); u # random
[    O(7) 3 + O(7)]
[2 + O(7) 6 + O(7)]
sage: X._increase_precision(5)
sage: v = X.embed_quaternion(l[3]); v # random
[                7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)             3 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)]
[            2 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6) 6 + 5*7 + 3*7^2 + 5*7^3 + 2*7^4 + 6*7^5 + O(7^6)]
sage: u == v
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(2))
>>> l = X.get_units_of_order()
>>> len(l)
12
>>> l[Integer(3)] # random
[-1]
[ 0]
[ 1]
[ 1]
>>> u = X.embed_quaternion(l[Integer(3)]); u # random
[    O(7) 3 + O(7)]
[2 + O(7) 6 + O(7)]
>>> X._increase_precision(Integer(5))
>>> v = X.embed_quaternion(l[Integer(3)]); v # random
[                7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)             3 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6)]
[            2 + 7 + 3*7^2 + 7^3 + 4*7^4 + O(7^6) 6 + 5*7 + 3*7^2 + 5*7^3 + 2*7^4 + 6*7^5 + O(7^6)]
>>> u == v
True
X = BruhatTitsQuotient(7,2)
l = X.get_units_of_order()
len(l)
l[3] # random
u = X.embed_quaternion(l[3]); u # random
X._increase_precision(5)
v = X.embed_quaternion(l[3]); v # random
u == v
fundom_rep(v1)[source]

Find an equivalent vertex in the fundamental domain.

INPUT:

  • v1 – a 2x2 matrix representing a normalized vertex

OUTPUT: a Vertex equivalent to v1, in the fundamental domain

EXAMPLES:

sage: X = BruhatTitsQuotient(3,7)
sage: M = Matrix(ZZ,2,2,[1,3,2,7])
sage: M.set_immutable()
sage: X.fundom_rep(M)
Vertex of Bruhat-Tits tree for p = 3
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(7))
>>> M = Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(3),Integer(2),Integer(7)])
>>> M.set_immutable()
>>> X.fundom_rep(M)
Vertex of Bruhat-Tits tree for p = 3
X = BruhatTitsQuotient(3,7)
M = Matrix(ZZ,2,2,[1,3,2,7])
M.set_immutable()
X.fundom_rep(M)
genus()[source]

Compute the genus of the quotient graph using a formula This should agree with self.genus_no_formula().

Compute the genus of the Shimura curve corresponding to this quotient via Cerednik-Drinfeld. It is computed via a formula and not in terms of the quotient graph.

INPUT:

  • level – integer (default: None); a level. By default, use that of self.

  • Nplus – integer (default: None); a conductor. By default, use that of self.

OUTPUT: integer equal to the genus

EXAMPLES:

sage: X = BruhatTitsQuotient(3,2*5*31)
sage: X.genus()
21
sage: X.genus() == X.genus_no_formula()
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(2)*Integer(5)*Integer(31))
>>> X.genus()
21
>>> X.genus() == X.genus_no_formula()
True
X = BruhatTitsQuotient(3,2*5*31)
X.genus()
X.genus() == X.genus_no_formula()
genus_no_formula()[source]

Compute the genus of the quotient from the data of the quotient graph. This should agree with self.genus().

OUTPUT: integer

EXAMPLES:

sage: X = BruhatTitsQuotient(5,2*3*29)
sage: X.genus_no_formula()
17
sage: X.genus_no_formula() == X.genus()
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(2)*Integer(3)*Integer(29))
>>> X.genus_no_formula()
17
>>> X.genus_no_formula() == X.genus()
True
X = BruhatTitsQuotient(5,2*3*29)
X.genus_no_formula()
X.genus_no_formula() == X.genus()
get_edge_list()[source]

Return a list of Edge which represent a fundamental domain inside the Bruhat-Tits tree for the quotient.

EXAMPLES:

sage: X = BruhatTitsQuotient(37,3)
sage: len(X.get_edge_list())
8
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(37),Integer(3))
>>> len(X.get_edge_list())
8
X = BruhatTitsQuotient(37,3)
len(X.get_edge_list())
get_edge_stabilizers()[source]

Compute the stabilizers in the arithmetic group of all edges in the Bruhat-Tits tree within a fundamental domain for the quotient graph. The stabilizers of an edge and its opposite are equal, and so we only store half the data.

OUTPUT:

A list of lists encoding edge stabilizers. It contains one entry for each edge. Each entry is a list of data corresponding to the group elements in the stabilizer of the edge. The data consists of: (0) a column matrix representing a quaternion, (1) the power of \(p\) that one needs to divide by in order to obtain a quaternion of norm 1, and hence an element of the arithmetic group \(\Gamma\), (2) a boolean that is only used to compute spaces of modular forms.

EXAMPLES:

sage: X = BruhatTitsQuotient(3,2)
sage: s = X.get_edge_stabilizers()
sage: len(s) == X.get_num_ordered_edges()/2
True
sage: len(s[0])
3
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(2))
>>> s = X.get_edge_stabilizers()
>>> len(s) == X.get_num_ordered_edges()/Integer(2)
True
>>> len(s[Integer(0)])
3
X = BruhatTitsQuotient(3,2)
s = X.get_edge_stabilizers()
len(s) == X.get_num_ordered_edges()/2
len(s[0])
get_eichler_order(magma=False, force_computation=False)[source]

Return the underlying Eichler order of level \(N^+\).

OUTPUT: an Eichler order

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.get_eichler_order()
Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.get_eichler_order()
Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
X = BruhatTitsQuotient(5,7)
X.get_eichler_order()
get_eichler_order_basis()[source]

Return a basis for the global Eichler order.

OUTPUT: basis for the underlying Eichler order of level Nplus

EXAMPLES:

sage: X = BruhatTitsQuotient(7,11)
sage: X.get_eichler_order_basis()
[1/2 + 1/2*j, 1/2*i + 1/2*k, j, k]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(11))
>>> X.get_eichler_order_basis()
[1/2 + 1/2*j, 1/2*i + 1/2*k, j, k]
X = BruhatTitsQuotient(7,11)
X.get_eichler_order_basis()
get_eichler_order_quadform()[source]

This function return the norm form for the underlying Eichler order of level Nplus. Required for finding elements in the arithmetic subgroup Gamma.

OUTPUT: the norm form of the underlying Eichler order

EXAMPLES:

sage: X = BruhatTitsQuotient(7,11)
sage: X.get_eichler_order_quadform()
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 3 0 11 0 ]
[ * 3 0 11 ]
[ * * 11 0 ]
[ * * * 11 ]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(11))
>>> X.get_eichler_order_quadform()
Quadratic form in 4 variables over Integer Ring with coefficients:
[ 3 0 11 0 ]
[ * 3 0 11 ]
[ * * 11 0 ]
[ * * * 11 ]
X = BruhatTitsQuotient(7,11)
X.get_eichler_order_quadform()
get_eichler_order_quadmatrix()[source]

This function returns the matrix of the quadratic form of the underlying Eichler order in the fixed basis.

OUTPUT: a 4x4 integral matrix describing the norm form

EXAMPLES:

sage: X = BruhatTitsQuotient(7,11)
sage: X.get_eichler_order_quadmatrix()
[ 6  0 11  0]
[ 0  6  0 11]
[11  0 22  0]
[ 0 11  0 22]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(11))
>>> X.get_eichler_order_quadmatrix()
[ 6  0 11  0]
[ 0  6  0 11]
[11  0 22  0]
[ 0 11  0 22]
X = BruhatTitsQuotient(7,11)
X.get_eichler_order_quadmatrix()
get_embedding(prec=None)[source]

Return a function which embeds quaternions into a matrix algebra.

EXAMPLES:

sage: X = BruhatTitsQuotient(5,3)
sage: f = X.get_embedding(prec = 4)
sage: b = Matrix(ZZ,4,1,[1,2,3,4])
sage: f(b)
[2 + 3*5 + 2*5^2 + 4*5^3 + O(5^4)       3 + 2*5^2 + 4*5^3 + O(5^4)]
[        5 + 5^2 + 3*5^3 + O(5^4)           4 + 5 + 2*5^2 + O(5^4)]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(3))
>>> f = X.get_embedding(prec = Integer(4))
>>> b = Matrix(ZZ,Integer(4),Integer(1),[Integer(1),Integer(2),Integer(3),Integer(4)])
>>> f(b)
[2 + 3*5 + 2*5^2 + 4*5^3 + O(5^4)       3 + 2*5^2 + 4*5^3 + O(5^4)]
[        5 + 5^2 + 3*5^3 + O(5^4)           4 + 5 + 2*5^2 + O(5^4)]
X = BruhatTitsQuotient(5,3)
f = X.get_embedding(prec = 4)
b = Matrix(ZZ,4,1,[1,2,3,4])
f(b)
get_embedding_matrix(prec=None, exact=False)[source]

Return the matrix of the embedding.

INPUT:

  • exact – boolean (default: False); if True, return an embedding into a matrix algebra with coefficients in a number field. Otherwise, embed into matrices over \(p\)-adic numbers.

  • prec – integer (default: None); if specified, return the matrix with precision prec. Otherwise, return the cached matrix (with the current working precision).

OUTPUT: a 4x4 matrix representing the embedding

EXAMPLES:

sage: X = BruhatTitsQuotient(7,2*3*5)
sage: X.get_embedding_matrix(4)
[                      1 + O(7^4)         5 + 2*7 + 3*7^3 + O(7^4) 4 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)       6 + 3*7^2 + 4*7^3 + O(7^4)]
[                          O(7^4)                           O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
[                          O(7^4)         2 + 5*7 + 6*7^3 + O(7^4) 3 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)         3 + 3*7 + 3*7^2 + O(7^4)]
[                      1 + O(7^4) 3 + 4*7 + 6*7^2 + 3*7^3 + O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
sage: X.get_embedding_matrix(3)
[                      1 + O(7^4)         5 + 2*7 + 3*7^3 + O(7^4) 4 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)       6 + 3*7^2 + 4*7^3 + O(7^4)]
[                          O(7^4)                           O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
[                          O(7^4)         2 + 5*7 + 6*7^3 + O(7^4) 3 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)         3 + 3*7 + 3*7^2 + O(7^4)]
[                      1 + O(7^4) 3 + 4*7 + 6*7^2 + 3*7^3 + O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
sage: X.get_embedding_matrix(5)
[                              1 + O(7^5)         5 + 2*7 + 3*7^3 + 6*7^4 + O(7^5) 4 + 5*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)       6 + 3*7^2 + 4*7^3 + 5*7^4 + O(7^5)]
[                                  O(7^5)                                   O(7^5)                           3 + 7 + O(7^5)   1 + 6*7 + 3*7^2 + 2*7^3 + 7^4 + O(7^5)]
[                                  O(7^5)         2 + 5*7 + 6*7^3 + 5*7^4 + O(7^5) 3 + 5*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)         3 + 3*7 + 3*7^2 + 5*7^4 + O(7^5)]
[                              1 + O(7^5)         3 + 4*7 + 6*7^2 + 3*7^3 + O(7^5)                           3 + 7 + O(7^5)   1 + 6*7 + 3*7^2 + 2*7^3 + 7^4 + O(7^5)]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(2)*Integer(3)*Integer(5))
>>> X.get_embedding_matrix(Integer(4))
[                      1 + O(7^4)         5 + 2*7 + 3*7^3 + O(7^4) 4 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)       6 + 3*7^2 + 4*7^3 + O(7^4)]
[                          O(7^4)                           O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
[                          O(7^4)         2 + 5*7 + 6*7^3 + O(7^4) 3 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)         3 + 3*7 + 3*7^2 + O(7^4)]
[                      1 + O(7^4) 3 + 4*7 + 6*7^2 + 3*7^3 + O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
>>> X.get_embedding_matrix(Integer(3))
[                      1 + O(7^4)         5 + 2*7 + 3*7^3 + O(7^4) 4 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)       6 + 3*7^2 + 4*7^3 + O(7^4)]
[                          O(7^4)                           O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
[                          O(7^4)         2 + 5*7 + 6*7^3 + O(7^4) 3 + 5*7 + 6*7^2 + 6*7^3 + O(7^4)         3 + 3*7 + 3*7^2 + O(7^4)]
[                      1 + O(7^4) 3 + 4*7 + 6*7^2 + 3*7^3 + O(7^4)                   3 + 7 + O(7^4) 1 + 6*7 + 3*7^2 + 2*7^3 + O(7^4)]
>>> X.get_embedding_matrix(Integer(5))
[                              1 + O(7^5)         5 + 2*7 + 3*7^3 + 6*7^4 + O(7^5) 4 + 5*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)       6 + 3*7^2 + 4*7^3 + 5*7^4 + O(7^5)]
[                                  O(7^5)                                   O(7^5)                           3 + 7 + O(7^5)   1 + 6*7 + 3*7^2 + 2*7^3 + 7^4 + O(7^5)]
[                                  O(7^5)         2 + 5*7 + 6*7^3 + 5*7^4 + O(7^5) 3 + 5*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)         3 + 3*7 + 3*7^2 + 5*7^4 + O(7^5)]
[                              1 + O(7^5)         3 + 4*7 + 6*7^2 + 3*7^3 + O(7^5)                           3 + 7 + O(7^5)   1 + 6*7 + 3*7^2 + 2*7^3 + 7^4 + O(7^5)]
X = BruhatTitsQuotient(7,2*3*5)
X.get_embedding_matrix(4)
X.get_embedding_matrix(3)
X.get_embedding_matrix(5)
get_extra_embedding_matrices()[source]

Return a list of matrices representing the different embeddings.

Note

The precision is very low (currently set to 5 digits), since these embeddings are only used to apply a character.

EXAMPLES:

This portion of the code is only relevant when working with a nontrivial Dirichlet character. If there is no such character then the code returns an empty list. Even if the character is not trivial it might return an empty list:

sage: f = DirichletGroup(6)[1]
sage: X = BruhatTitsQuotient(3,2*5*7,character = f)
sage: X.get_extra_embedding_matrices()
[]
>>> from sage.all import *
>>> f = DirichletGroup(Integer(6))[Integer(1)]
>>> X = BruhatTitsQuotient(Integer(3),Integer(2)*Integer(5)*Integer(7),character = f)
>>> X.get_extra_embedding_matrices()
[]
f = DirichletGroup(6)[1]
X = BruhatTitsQuotient(3,2*5*7,character = f)
X.get_extra_embedding_matrices()
sage: f = DirichletGroup(6)[1]
sage: X = BruhatTitsQuotient(5,2,3, character = f, use_magma=True) # optional - magma
sage: X.get_extra_embedding_matrices() # optional - magma
[
[1 0 2 0]
[0 0 2 0]
[0 0 0 0]
[1 0 2 2]
]
>>> from sage.all import *
>>> f = DirichletGroup(Integer(6))[Integer(1)]
>>> X = BruhatTitsQuotient(Integer(5),Integer(2),Integer(3), character = f, use_magma=True) # optional - magma
>>> X.get_extra_embedding_matrices() # optional - magma
[
[1 0 2 0]
[0 0 2 0]
[0 0 0 0]
[1 0 2 2]
]
f = DirichletGroup(6)[1]
X = BruhatTitsQuotient(5,2,3, character = f, use_magma=True) # optional - magma
X.get_extra_embedding_matrices() # optional - magma
>>> from sage.all import *
>>> f = DirichletGroup(Integer(6))[Integer(1)]
>>> X = BruhatTitsQuotient(Integer(5),Integer(2),Integer(3), character = f, use_magma=True) # optional - magma
>>> X.get_extra_embedding_matrices() # optional - magma
[
[1 0 2 0]
[0 0 2 0]
[0 0 0 0]
[1 0 2 2]
]
f = DirichletGroup(6)[1]
X = BruhatTitsQuotient(5,2,3, character = f, use_magma=True) # optional - magma
X.get_extra_embedding_matrices() # optional - magma
get_fundom_graph()[source]

Return the fundamental domain (and computes it if needed).

OUTPUT: a fundamental domain for the action of \(\Gamma\)

EXAMPLES:

sage: X = BruhatTitsQuotient(11,5)
sage: X.get_fundom_graph()
Graph on 24 vertices
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(11),Integer(5))
>>> X.get_fundom_graph()
Graph on 24 vertices
X = BruhatTitsQuotient(11,5)
X.get_fundom_graph()
get_generators()[source]

Use a fundamental domain in the Bruhat-Tits tree, and certain gluing data for boundary vertices, in order to compute a collection of generators for the arithmetic quaternionic group that one is quotienting by. This is analogous to using a polygonal rep. of a compact real surface to present its fundamental domain.

OUTPUT:

  • A generating list of elements of an arithmetic quaternionic group.

EXAMPLES:

sage: X = BruhatTitsQuotient(3,2)
sage: len(X.get_generators())
2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(2))
>>> len(X.get_generators())
2
X = BruhatTitsQuotient(3,2)
len(X.get_generators())
get_graph()[source]

Return the quotient graph (and compute it if needed).

OUTPUT: a graph representing the quotient of the Bruhat-Tits tree

EXAMPLES:

sage: X = BruhatTitsQuotient(11,5)
sage: X.get_graph()
Multi-graph on 2 vertices
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(11),Integer(5))
>>> X.get_graph()
Multi-graph on 2 vertices
X = BruhatTitsQuotient(11,5)
X.get_graph()
get_list()[source]

Return a list of Edge which represent a fundamental domain inside the Bruhat-Tits tree for the quotient, together with a list of the opposite edges. This is used to work with automorphic forms.

EXAMPLES:

sage: X = BruhatTitsQuotient(37,3)
sage: len(X.get_list())
16
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(37),Integer(3))
>>> len(X.get_list())
16
X = BruhatTitsQuotient(37,3)
len(X.get_list())
get_maximal_order(magma=False, force_computation=False)[source]

Return the underlying maximal order containing the Eichler order.

OUTPUT: a maximal order

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.get_maximal_order()
Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.get_maximal_order()
Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
X = BruhatTitsQuotient(5,7)
X.get_maximal_order()
get_nontorsion_generators()[source]

Use a fundamental domain in the Bruhat-Tits tree, and certain gluing data for boundary vertices, in order to compute a collection of generators for the nontorsion part of the arithmetic quaternionic group that one is quotienting by. This is analogous to using a polygonal rep. of a compact real surface to present its fundamental domain.

OUTPUT:

  • A generating list of elements of an arithmetic quaternionic group.

EXAMPLES:

sage: X = BruhatTitsQuotient(3,13)
sage: len(X.get_nontorsion_generators())
3
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(13))
>>> len(X.get_nontorsion_generators())
3
X = BruhatTitsQuotient(3,13)
len(X.get_nontorsion_generators())
get_num_ordered_edges()[source]

Return the number of ordered edges \(E\) in the quotient using the formula relating the genus \(g\) with the number of vertices \(V\) and that of unordered edges \(E/2\): \(E = 2(g + V - 1)\).

OUTPUT: integer

EXAMPLES:

sage: X = BruhatTitsQuotient(3,2)
sage: X.get_num_ordered_edges()
2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(2))
>>> X.get_num_ordered_edges()
2
X = BruhatTitsQuotient(3,2)
X.get_num_ordered_edges()
get_num_verts()[source]

Return the number of vertices in the quotient using the formula \(V = 2(\mu/12 + e_3/3 + e_4/4)\).

OUTPUT:

  • An integer (the number of vertices)

EXAMPLES:

sage: X = BruhatTitsQuotient(29,11)
sage: X.get_num_verts()
4
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(29),Integer(11))
>>> X.get_num_verts()
4
X = BruhatTitsQuotient(29,11)
X.get_num_verts()
get_quaternion_algebra()[source]

Return the underlying quaternion algebra.

OUTPUT: the underlying definite quaternion algebra

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.get_quaternion_algebra()
Quaternion Algebra (-1, -7) with base ring Rational Field
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.get_quaternion_algebra()
Quaternion Algebra (-1, -7) with base ring Rational Field
X = BruhatTitsQuotient(5,7)
X.get_quaternion_algebra()
get_splitting_field()[source]

Return a quadratic field that splits the quaternion algebra attached to self. Currently requires Magma.

EXAMPLES:

sage: X = BruhatTitsQuotient(5,11)
sage: X.get_splitting_field()
Traceback (most recent call last):
...
NotImplementedError: Sage does not know yet how to work with the kind of orders that you are trying to use. Try installing Magma first and set it up so that Sage can use it.
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(11))
>>> X.get_splitting_field()
Traceback (most recent call last):
...
NotImplementedError: Sage does not know yet how to work with the kind of orders that you are trying to use. Try installing Magma first and set it up so that Sage can use it.
X = BruhatTitsQuotient(5,11)
X.get_splitting_field()

If we do have Magma installed, then it works:

sage: X = BruhatTitsQuotient(5,11,use_magma=True) # optional - magma
sage: X.get_splitting_field() # optional - magma
Number Field in a with defining polynomial X1^2 + 11
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(11),use_magma=True) # optional - magma
>>> X.get_splitting_field() # optional - magma
Number Field in a with defining polynomial X1^2 + 11
X = BruhatTitsQuotient(5,11,use_magma=True) # optional - magma
X.get_splitting_field() # optional - magma
get_stabilizers()[source]

Compute the stabilizers in the arithmetic group of all edges in the Bruhat-Tits tree within a fundamental domain for the quotient graph. This is similar to get_edge_stabilizers, except that here we also store the stabilizers of the opposites.

OUTPUT:

A list of lists encoding edge stabilizers. It contains one entry for each edge. Each entry is a list of data corresponding to the group elements in the stabilizer of the edge. The data consists of: (0) a column matrix representing a quaternion, (1) the power of \(p\) that one needs to divide by in order to obtain a quaternion of norm 1, and hence an element of the arithmetic group \(\Gamma\), (2) a boolean that is only used to compute spaces of modular forms.

EXAMPLES:

sage: X = BruhatTitsQuotient(3,5)
sage: s = X.get_stabilizers()
sage: len(s) == X.get_num_ordered_edges()
True
sage: gamma = X.embed_quaternion(s[1][0][0][0],prec = 20)
sage: v = X.get_edge_list()[0].rep
sage: X._BT.edge(gamma*v) == v
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(3),Integer(5))
>>> s = X.get_stabilizers()
>>> len(s) == X.get_num_ordered_edges()
True
>>> gamma = X.embed_quaternion(s[Integer(1)][Integer(0)][Integer(0)][Integer(0)],prec = Integer(20))
>>> v = X.get_edge_list()[Integer(0)].rep
>>> X._BT.edge(gamma*v) == v
True
X = BruhatTitsQuotient(3,5)
s = X.get_stabilizers()
len(s) == X.get_num_ordered_edges()
gamma = X.embed_quaternion(s[1][0][0][0],prec = 20)
v = X.get_edge_list()[0].rep
X._BT.edge(gamma*v) == v
get_units_of_order()[source]

Return the units of the underlying Eichler \(\ZZ\)-order. This is a finite group since the order lives in a definite quaternion algebra over \(\QQ\).

OUTPUT:

A list of elements of the global Eichler \(\ZZ\)-order of level \(N^+\).

EXAMPLES:

sage: X = BruhatTitsQuotient(7,11)
sage: X.get_units_of_order()
[
[ 0]  [-2]
[-2]  [ 0]
[ 0]  [ 1]
[ 1], [ 0]
]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(11))
>>> X.get_units_of_order()
[
[ 0]  [-2]
[-2]  [ 0]
[ 0]  [ 1]
[ 1], [ 0]
]
X = BruhatTitsQuotient(7,11)
X.get_units_of_order()
get_vertex_dict()[source]

This function returns the vertices of the quotient viewed as a dict.

OUTPUT: a Python dict with the vertices of the quotient

EXAMPLES:

sage: X = BruhatTitsQuotient(37,3)
sage: X.get_vertex_dict()
{[1 0]
[0 1]: Vertex of Bruhat-Tits tree for p = 37, [ 1  0]
[ 0 37]: Vertex of Bruhat-Tits tree for p = 37}
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(37),Integer(3))
>>> X.get_vertex_dict()
{[1 0]
[0 1]: Vertex of Bruhat-Tits tree for p = 37, [ 1  0]
[ 0 37]: Vertex of Bruhat-Tits tree for p = 37}
X = BruhatTitsQuotient(37,3)
X.get_vertex_dict()
get_vertex_list()[source]

Return a list of the vertices of the quotient.

EXAMPLES:

sage: X = BruhatTitsQuotient(37,3)
sage: X.get_vertex_list()
[Vertex of Bruhat-Tits tree for p = 37, Vertex of Bruhat-Tits tree for p = 37]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(37),Integer(3))
>>> X.get_vertex_list()
[Vertex of Bruhat-Tits tree for p = 37, Vertex of Bruhat-Tits tree for p = 37]
X = BruhatTitsQuotient(37,3)
X.get_vertex_list()
get_vertex_stabs()[source]

This function computes the stabilizers in the arithmetic group of all vertices in the Bruhat-Tits tree within a fundamental domain for the quotient graph.

OUTPUT:

A list of vertex stabilizers. Each vertex stabilizer is a finite cyclic subgroup, so we return generators for these subgroups.

EXAMPLES:

sage: X = BruhatTitsQuotient(13,2)
sage: S = X.get_vertex_stabs()
sage: gamma = X.embed_quaternion(S[0][0][0],prec = 20)
sage: v = X.get_vertex_list()[0].rep
sage: X._BT.vertex(gamma*v) == v
True
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(13),Integer(2))
>>> S = X.get_vertex_stabs()
>>> gamma = X.embed_quaternion(S[Integer(0)][Integer(0)][Integer(0)],prec = Integer(20))
>>> v = X.get_vertex_list()[Integer(0)].rep
>>> X._BT.vertex(gamma*v) == v
True
X = BruhatTitsQuotient(13,2)
S = X.get_vertex_stabs()
gamma = X.embed_quaternion(S[0][0][0],prec = 20)
v = X.get_vertex_list()[0].rep
X._BT.vertex(gamma*v) == v
harmonic_cocycle_from_elliptic_curve(E, prec=None)[source]

Return a harmonic cocycle with the same Hecke eigenvalues as E.

Given an elliptic curve \(E\) having a conductor \(N\) of the form \(pN^-N^+\), return the harmonic cocycle over self which is attached to E via modularity. The result is only well-defined up to scaling.

INPUT:

  • E – an elliptic curve over the rational numbers

  • prec – (default: None) if specified, the harmonic cocycle will take values in \(\QQ_p\) with precision prec. Otherwise it will take values in \(\ZZ\).

OUTPUT: a harmonic cocycle attached via modularity to the given elliptic curve

EXAMPLES:

sage: E = EllipticCurve('21a1')
sage: X = BruhatTitsQuotient(7,3)
sage: f = X.harmonic_cocycle_from_elliptic_curve(E,10)
sage: T29 = f.parent().hecke_operator(29)
sage: T29(f) == E.ap(29) * f
True
sage: E = EllipticCurve('51a1')
sage: X = BruhatTitsQuotient(3,17)
sage: f = X.harmonic_cocycle_from_elliptic_curve(E,20)
sage: T31 = f.parent().hecke_operator(31)
sage: T31(f) == E.ap(31) * f
True
>>> from sage.all import *
>>> E = EllipticCurve('21a1')
>>> X = BruhatTitsQuotient(Integer(7),Integer(3))
>>> f = X.harmonic_cocycle_from_elliptic_curve(E,Integer(10))
>>> T29 = f.parent().hecke_operator(Integer(29))
>>> T29(f) == E.ap(Integer(29)) * f
True
>>> E = EllipticCurve('51a1')
>>> X = BruhatTitsQuotient(Integer(3),Integer(17))
>>> f = X.harmonic_cocycle_from_elliptic_curve(E,Integer(20))
>>> T31 = f.parent().hecke_operator(Integer(31))
>>> T31(f) == E.ap(Integer(31)) * f
True
E = EllipticCurve('21a1')
X = BruhatTitsQuotient(7,3)
f = X.harmonic_cocycle_from_elliptic_curve(E,10)
T29 = f.parent().hecke_operator(29)
T29(f) == E.ap(29) * f
E = EllipticCurve('51a1')
X = BruhatTitsQuotient(3,17)
f = X.harmonic_cocycle_from_elliptic_curve(E,20)
T31 = f.parent().hecke_operator(31)
T31(f) == E.ap(31) * f
harmonic_cocycles(k, prec=None, basis_matrix=None, base_field=None)[source]

Compute the space of harmonic cocycles of a given even weight k.

INPUT:

  • k – integer; the weight. It must be even.

  • prec – integer (default: None); if specified, the precision for the coefficient module

  • basis_matrix – a matrix (default: None)

  • base_field – a ring (default: None)

OUTPUT: a space of harmonic cocycles

EXAMPLES:

sage: X = BruhatTitsQuotient(31,7)
sage: H = X.harmonic_cocycles(2,prec=10)
sage: H
Space of harmonic cocycles of weight 2 on Quotient of the Bruhat Tits tree of GL_2(QQ_31) with discriminant 7 and level 1
sage: H.basis()[0]
Harmonic cocycle with values in Sym^0 Q_31^2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(31),Integer(7))
>>> H = X.harmonic_cocycles(Integer(2),prec=Integer(10))
>>> H
Space of harmonic cocycles of weight 2 on Quotient of the Bruhat Tits tree of GL_2(QQ_31) with discriminant 7 and level 1
>>> H.basis()[Integer(0)]
Harmonic cocycle with values in Sym^0 Q_31^2
X = BruhatTitsQuotient(31,7)
H = X.harmonic_cocycles(2,prec=10)
H
H.basis()[0]
is_admissible(D)[source]

Test whether the imaginary quadratic field of discriminant \(D\) embeds in the quaternion algebra. It furthermore tests the Heegner hypothesis in this setting (e.g., is \(p\) inert in the field, etc).

INPUT:

  • D – integer whose squarefree part will define the quadratic field

OUTPUT: boolean describing whether the quadratic field is admissible

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: [X.is_admissible(D) for D in range(-1,-20,-1)]
[False, True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, True, False]
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> [X.is_admissible(D) for D in range(-Integer(1),-Integer(20),-Integer(1))]
[False, True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, True, False]
X = BruhatTitsQuotient(5,7)
[X.is_admissible(D) for D in range(-1,-20,-1)]
level()[source]

Return \(p N^-\), which is the discriminant of the indefinite quaternion algebra that is uniformed by Cerednik-Drinfeld.

OUTPUT:

An integer equal to \(p N^-\).

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.level()
35
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.level()
35
X = BruhatTitsQuotient(5,7)
X.level()
mu()[source]

Compute the mu invariant of self.

OUTPUT: integer

EXAMPLES:

sage: X = BruhatTitsQuotient(29,3)
sage: X.mu
2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(29),Integer(3))
>>> X.mu
2
X = BruhatTitsQuotient(29,3)
X.mu
padic_automorphic_forms(U, prec=None, t=None, R=None, overconvergent=False)[source]

The module of (quaternionic) \(p\)-adic automorphic forms over self.

INPUT:

  • U – a distributions module or an integer. If U is a distributions module then this creates the relevant space of automorphic forms. If U is an integer then the coefficients are the (\(U-2\))nd power of the symmetric representation of \(GL_2(\QQ_p)\).

  • prec – a precision (default: None). if not None should be a positive integer

  • t – (default: None) the number of additional moments to store. If None, determine it automatically from prec, U and the overconvergent flag

  • R – (default: None) if specified, coefficient field of the automorphic forms. If not specified it defaults to the base ring of the distributions U, or to \(\QQ_p\) with the working precision prec.

  • overconvergent – boolean (default: False); if True, will construct overconvergent \(p\)-adic automorphic forms. Otherwise it constructs the finite dimensional space of \(p\)-adic automorphic forms which is isomorphic to the space of harmonic cocycles.

EXAMPLES:

sage: X = BruhatTitsQuotient(11,5)
sage: X.padic_automorphic_forms(2,prec=10)
Space of automorphic forms on Quotient of the Bruhat Tits tree of GL_2(QQ_11) with discriminant 5 and level 1 with values in Sym^0 Q_11^2
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(11),Integer(5))
>>> X.padic_automorphic_forms(Integer(2),prec=Integer(10))
Space of automorphic forms on Quotient of the Bruhat Tits tree of GL_2(QQ_11) with discriminant 5 and level 1 with values in Sym^0 Q_11^2
X = BruhatTitsQuotient(11,5)
X.padic_automorphic_forms(2,prec=10)
plot(*args, **kwargs)[source]

Plot the quotient graph.

OUTPUT: a plot of the quotient graph

EXAMPLES:

sage: X = BruhatTitsQuotient(7,23)
sage: X.plot()                                                              # needs sage.plot
Graphics object consisting of 17 graphics primitives
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(23))
>>> X.plot()                                                              # needs sage.plot
Graphics object consisting of 17 graphics primitives
X = BruhatTitsQuotient(7,23)
X.plot()                                                              # needs sage.plot
plot_fundom(*args, **kwargs)[source]

Plot a fundamental domain.

OUTPUT: a plot of the fundamental domain

EXAMPLES:

sage: X = BruhatTitsQuotient(7,23)
sage: X.plot_fundom()                                                       # needs sage.plot
Graphics object consisting of 88 graphics primitives
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(7),Integer(23))
>>> X.plot_fundom()                                                       # needs sage.plot
Graphics object consisting of 88 graphics primitives
X = BruhatTitsQuotient(7,23)
X.plot_fundom()                                                       # needs sage.plot
prime()[source]

Return the prime one is working with.

OUTPUT: integer equal to the fixed prime \(p\)

EXAMPLES:

sage: X = BruhatTitsQuotient(5,7)
sage: X.prime()
5
>>> from sage.all import *
>>> X = BruhatTitsQuotient(Integer(5),Integer(7))
>>> X.prime()
5
X = BruhatTitsQuotient(5,7)
X.prime()
class sage.modular.btquotients.btquotient.BruhatTitsTree(p)[source]

Bases: SageObject, UniqueRepresentation

An implementation of the Bruhat-Tits tree for \(GL_2(\QQ_p)\).

INPUT:

  • p – a prime number. The corresponding tree is then \(p+1\) regular

EXAMPLES:

We create the tree for \(GL_2(\QQ_5)\):

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 5
sage: T = BruhatTitsTree(p)
sage: m = Matrix(ZZ,2,2,[p**5,p**2,p**3,1+p+p*3])
sage: e = T.edge(m); e
[  0  25]
[625  21]
sage: v0 = T.origin(e); v0
[ 25   0]
[ 21 125]
sage: v1 = T.target(e); v1
[ 25   0]
[ 21 625]
sage: T.origin(T.opposite(e)) == v1
True
sage: T.target(T.opposite(e)) == v0
True
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(5)
>>> T = BruhatTitsTree(p)
>>> m = Matrix(ZZ,Integer(2),Integer(2),[p**Integer(5),p**Integer(2),p**Integer(3),Integer(1)+p+p*Integer(3)])
>>> e = T.edge(m); e
[  0  25]
[625  21]
>>> v0 = T.origin(e); v0
[ 25   0]
[ 21 125]
>>> v1 = T.target(e); v1
[ 25   0]
[ 21 625]
>>> T.origin(T.opposite(e)) == v1
True
>>> T.target(T.opposite(e)) == v0
True
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 5
T = BruhatTitsTree(p)
m = Matrix(ZZ,2,2,[p**5,p**2,p**3,1+p+p*3])
e = T.edge(m); e
v0 = T.origin(e); v0
v1 = T.target(e); v1
T.origin(T.opposite(e)) == v1
T.target(T.opposite(e)) == v0

A value error is raised if a prime is not passed:

sage: T = BruhatTitsTree(4)
Traceback (most recent call last):
...
ValueError: input (4) must be prime
>>> from sage.all import *
>>> T = BruhatTitsTree(Integer(4))
Traceback (most recent call last):
...
ValueError: input (4) must be prime
T = BruhatTitsTree(4)

AUTHORS:

  • Marc Masdeu (2012-02-20)

edge(M)[source]

Normalize a matrix to the correct normalized edge representative.

INPUT:

  • M – 2x2 integer matrix

OUTPUT: newM – 2x2 integer matrix

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: T = BruhatTitsTree(3)
sage: T.edge( Matrix(ZZ,2,2,[0,-1,3,0]) )
[0 1]
[3 0]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> T = BruhatTitsTree(Integer(3))
>>> T.edge( Matrix(ZZ,Integer(2),Integer(2),[Integer(0),-Integer(1),Integer(3),Integer(0)]) )
[0 1]
[3 0]
from sage.modular.btquotients.btquotient import BruhatTitsTree
T = BruhatTitsTree(3)
T.edge( Matrix(ZZ,2,2,[0,-1,3,0]) )
edge_between_vertices(v1, v2, normalized=False)[source]

Compute the normalized matrix rep. for the edge passing between two vertices.

INPUT:

  • v1 – 2x2 integer matrix

  • v2 – 2x2 integer matrix

  • normalized – boolean (default: False); whether the vertices are normalized

OUTPUT:

  • 2x2 integer matrix, representing the edge from v1 to v2. If v1 and v2 are not at distance \(1\), raise a ValueError.

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 7
sage: T = BruhatTitsTree(p)
sage: v1 = T.vertex(Matrix(ZZ,2,2,[p,0,0,1])); v1
[7 0]
[0 1]
sage: v2 = T.vertex(Matrix(ZZ,2,2,[p,1,0,1])); v2
[1 0]
[1 7]
sage: T.edge_between_vertices(v1,v2)
Traceback (most recent call last):
...
ValueError: Vertices are not adjacent.

sage: v3 = T.vertex(Matrix(ZZ,2,2,[1,0,0,1])); v3
[1 0]
[0 1]
sage: T.edge_between_vertices(v1,v3)
[0 1]
[1 0]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(7)
>>> T = BruhatTitsTree(p)
>>> v1 = T.vertex(Matrix(ZZ,Integer(2),Integer(2),[p,Integer(0),Integer(0),Integer(1)])); v1
[7 0]
[0 1]
>>> v2 = T.vertex(Matrix(ZZ,Integer(2),Integer(2),[p,Integer(1),Integer(0),Integer(1)])); v2
[1 0]
[1 7]
>>> T.edge_between_vertices(v1,v2)
Traceback (most recent call last):
...
ValueError: Vertices are not adjacent.

>>> v3 = T.vertex(Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(0),Integer(0),Integer(1)])); v3
[1 0]
[0 1]
>>> T.edge_between_vertices(v1,v3)
[0 1]
[1 0]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 7
T = BruhatTitsTree(p)
v1 = T.vertex(Matrix(ZZ,2,2,[p,0,0,1])); v1
v2 = T.vertex(Matrix(ZZ,2,2,[p,1,0,1])); v2
T.edge_between_vertices(v1,v2)
v3 = T.vertex(Matrix(ZZ,2,2,[1,0,0,1])); v3
T.edge_between_vertices(v1,v3)
edges_leaving_origin()[source]

Find normalized representatives for the \(p+1\) edges leaving the origin vertex corresponding to the homothety class of \(\ZZ_p^2\). These are cached.

OUTPUT: list of size \(p+1\) of 2x2 integer matrices

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: T = BruhatTitsTree(3)
sage: T.edges_leaving_origin()
[
[0 1]  [3 0]  [0 1]  [0 1]
[3 0], [0 1], [3 1], [3 2]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> T = BruhatTitsTree(Integer(3))
>>> T.edges_leaving_origin()
[
[0 1]  [3 0]  [0 1]  [0 1]
[3 0], [0 1], [3 1], [3 2]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
T = BruhatTitsTree(3)
T.edges_leaving_origin()
entering_edges(v)[source]

This function returns the edges entering a given vertex.

INPUT:

  • v – 2x2 integer matrix

OUTPUT: list of size \(p+1\) of 2x2 integer matrices

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 7
sage: T = BruhatTitsTree(p)
sage: T.entering_edges(Matrix(ZZ,2,2,[1,0,0,1]))
[
[1 0]  [0 1]  [1 0]  [1 0]  [1 0]  [1 0]  [1 0]  [1 0]
[0 1], [1 0], [1 1], [4 1], [5 1], [2 1], [3 1], [6 1]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(7)
>>> T = BruhatTitsTree(p)
>>> T.entering_edges(Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(0),Integer(0),Integer(1)]))
[
[1 0]  [0 1]  [1 0]  [1 0]  [1 0]  [1 0]  [1 0]  [1 0]
[0 1], [1 0], [1 1], [4 1], [5 1], [2 1], [3 1], [6 1]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 7
T = BruhatTitsTree(p)
T.entering_edges(Matrix(ZZ,2,2,[1,0,0,1]))
find_containing_affinoid(z)[source]

Return the vertex corresponding to the affinoid in the \(p\)-adic upper half plane that a given (unramified!) point reduces to.

INPUT:

  • z – an element of an unramified extension of \(\QQ_p\) that is not contained in \(\QQ_p\)

OUTPUT: a 2x2 integer matrix representing a vertex of self

EXAMPLES:

sage: # needs sage.rings.padics
sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: T = BruhatTitsTree(5)
sage: K.<a> = Qq(5^2,20)
sage: T.find_containing_affinoid(a)
[1 0]
[0 1]
sage: z = 5*a+3
sage: v = T.find_containing_affinoid(z).inverse(); v
[   1    0]
[-2/5  1/5]
>>> from sage.all import *
>>> # needs sage.rings.padics
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> T = BruhatTitsTree(Integer(5))
>>> K = Qq(Integer(5)**Integer(2),Integer(20), names=('a',)); (a,) = K._first_ngens(1)
>>> T.find_containing_affinoid(a)
[1 0]
[0 1]
>>> z = Integer(5)*a+Integer(3)
>>> v = T.find_containing_affinoid(z).inverse(); v
[   1    0]
[-2/5  1/5]
# needs sage.rings.padics
from sage.modular.btquotients.btquotient import BruhatTitsTree
T = BruhatTitsTree(5)
K.<a> = Qq(5^2,20)
T.find_containing_affinoid(a)
z = 5*a+3
v = T.find_containing_affinoid(z).inverse(); v

Note that the translate of z belongs to the standard affinoid. That is, it is a \(p\)-adic unit and its reduction modulo \(p\) is not in \(\GF{p}\):

sage: gz = (v[0,0]*z+v[0,1])/(v[1,0]*z+v[1,1]); gz                          # needs sage.rings.padics
(a + 1) + O(5^19)
sage: gz.valuation() == 0                                                   # needs sage.rings.padics
True
>>> from sage.all import *
>>> gz = (v[Integer(0),Integer(0)]*z+v[Integer(0),Integer(1)])/(v[Integer(1),Integer(0)]*z+v[Integer(1),Integer(1)]); gz                          # needs sage.rings.padics
(a + 1) + O(5^19)
>>> gz.valuation() == Integer(0)                                                   # needs sage.rings.padics
True
gz = (v[0,0]*z+v[0,1])/(v[1,0]*z+v[1,1]); gz                          # needs sage.rings.padics
gz.valuation() == 0                                                   # needs sage.rings.padics
find_covering(z1, z2, level=0)[source]

Compute a covering of \(P^1(\QQ_p)\) adapted to a certain geodesic in self.

More precisely, the \(p\)-adic upper half plane points z1 and z2 reduce to vertices \(v_1\), \(v_2\). The returned covering consists of all the edges leaving the geodesic from \(v_1\) to \(v_2\).

INPUT:

  • z1, z2 – unramified algebraic points of h_p

OUTPUT: list of 2x2 integer matrices representing edges of self

EXAMPLES:

sage: # needs sage.rings.padics
sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 3
sage: K.<a> = Qq(p^2)
sage: T = BruhatTitsTree(p)
sage: z1 = a + a*p
sage: z2 = 1 + a*p + a*p^2 - p^6
sage: T.find_covering(z1,z2)
[
[0 1]  [3 0]  [0 1]  [0 1]  [0 1]  [0 1]
[3 0], [0 1], [3 2], [9 1], [9 4], [9 7]
]
>>> from sage.all import *
>>> # needs sage.rings.padics
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(3)
>>> K = Qq(p**Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> T = BruhatTitsTree(p)
>>> z1 = a + a*p
>>> z2 = Integer(1) + a*p + a*p**Integer(2) - p**Integer(6)
>>> T.find_covering(z1,z2)
[
[0 1]  [3 0]  [0 1]  [0 1]  [0 1]  [0 1]
[3 0], [0 1], [3 2], [9 1], [9 4], [9 7]
]
# needs sage.rings.padics
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 3
K.<a> = Qq(p^2)
T = BruhatTitsTree(p)
z1 = a + a*p
z2 = 1 + a*p + a*p^2 - p^6
T.find_covering(z1,z2)

Note

This function is used to compute certain Coleman integrals on \(P^1\). That’s why the input consists of two points of the \(p\)-adic upper half plane, but decomposes \(P^1(\QQ_p)\). This decomposition is what allows us to represent the relevant integrand as a locally analytic function. The z1 and z2 appear in the integrand.

find_geodesic(v1, v2, normalized=True)[source]

This function computes the geodesic between two vertices.

INPUT:

  • v1 – 2x2 integer matrix representing a vertex

  • v2 – 2x2 integer matrix representing a vertex

  • normalized – boolean (default: True)

OUTPUT:

An ordered list of 2x2 integer matrices representing the vertices of the paths joining v1 and v2.

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 3
sage: T = BruhatTitsTree(p)
sage: v1 = T.vertex( Matrix(ZZ,2,2,[p^3, 0, 1, p^1]) ); v1
[27  0]
[ 1  3]
sage: v2 = T.vertex( Matrix(ZZ,2,2,[p,2,0,p]) ); v2
[1 0]
[6 9]
sage: T.find_geodesic(v1,v2)
[
[27  0]  [27  0]  [9 0]  [3 0]  [1 0]  [1 0]  [1 0]
[ 1  3], [ 0  1], [0 1], [0 1], [0 1], [0 3], [6 9]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(3)
>>> T = BruhatTitsTree(p)
>>> v1 = T.vertex( Matrix(ZZ,Integer(2),Integer(2),[p**Integer(3), Integer(0), Integer(1), p**Integer(1)]) ); v1
[27  0]
[ 1  3]
>>> v2 = T.vertex( Matrix(ZZ,Integer(2),Integer(2),[p,Integer(2),Integer(0),p]) ); v2
[1 0]
[6 9]
>>> T.find_geodesic(v1,v2)
[
[27  0]  [27  0]  [9 0]  [3 0]  [1 0]  [1 0]  [1 0]
[ 1  3], [ 0  1], [0 1], [0 1], [0 1], [0 3], [6 9]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 3
T = BruhatTitsTree(p)
v1 = T.vertex( Matrix(ZZ,2,2,[p^3, 0, 1, p^1]) ); v1
v2 = T.vertex( Matrix(ZZ,2,2,[p,2,0,p]) ); v2
T.find_geodesic(v1,v2)
find_path(v, boundary=None)[source]

Compute a path from a vertex to a given set of so-called boundary vertices, whose interior must contain the origin vertex. In the case that the boundary is not specified, it computes the geodesic between the given vertex and the origin. In the case that the boundary contains more than one vertex, it computes the geodesic to some point of the boundary.

INPUT:

  • v – a 2x2 matrix representing a vertex boundary

  • a list of matrices (default: None); if omitted, finds the geodesic from v to the central vertex

OUTPUT:

An ordered list of vertices describing the geodesic from v to boundary, followed by the vertex in the boundary that is closest to v.

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 3
sage: T = BruhatTitsTree(p)
sage: T.find_path( Matrix(ZZ,2,2,[p^4,0,0,1]) )
(
[[81  0]
[ 0  1], [27  0]
[ 0  1], [9 0]
[0 1], [3 0]      [1 0]
[0 1]]          , [0 1]
)
sage: T.find_path( Matrix(ZZ,2,2,[p^3,0,134,p^2]) )
(
[[27  0]
[ 8  9], [27  0]
[ 2  3], [27  0]
[ 0  1], [9 0]
[0 1], [3 0]      [1 0]
[0 1]]          , [0 1]
)
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(3)
>>> T = BruhatTitsTree(p)
>>> T.find_path( Matrix(ZZ,Integer(2),Integer(2),[p**Integer(4),Integer(0),Integer(0),Integer(1)]) )
(
[[81  0]
[ 0  1], [27  0]
[ 0  1], [9 0]
[0 1], [3 0]      [1 0]
[0 1]]          , [0 1]
)
>>> T.find_path( Matrix(ZZ,Integer(2),Integer(2),[p**Integer(3),Integer(0),Integer(134),p**Integer(2)]) )
(
[[27  0]
[ 8  9], [27  0]
[ 2  3], [27  0]
[ 0  1], [9 0]
[0 1], [3 0]      [1 0]
[0 1]]          , [0 1]
)
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 3
T = BruhatTitsTree(p)
T.find_path( Matrix(ZZ,2,2,[p^4,0,0,1]) )
T.find_path( Matrix(ZZ,2,2,[p^3,0,134,p^2]) )
get_balls(center=1, level=1)[source]

Return a decomposition of \(P^1(\QQ_p)\) into compact open balls.

Each vertex in the Bruhat-Tits tree gives a decomposition of \(P^1(\QQ_p)\) into \(p+1\) open balls. Each of these balls may be further subdivided, to get a finer decomposition.

This function returns the decomposition of \(P^1(\QQ_p)\) corresponding to center into \((p+1)p^{\mbox{level}}\) balls.

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 2
sage: T = BruhatTitsTree(p)
sage: T.get_balls(Matrix(ZZ,2,2,[p,0,0,1]),1)
[
[0 1]  [0 1]  [8 0]  [0 4]  [0 2]  [0 2]
[2 0], [2 1], [0 1], [2 1], [4 1], [4 3]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(2)
>>> T = BruhatTitsTree(p)
>>> T.get_balls(Matrix(ZZ,Integer(2),Integer(2),[p,Integer(0),Integer(0),Integer(1)]),Integer(1))
[
[0 1]  [0 1]  [8 0]  [0 4]  [0 2]  [0 2]
[2 0], [2 1], [0 1], [2 1], [4 1], [4 3]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 2
T = BruhatTitsTree(p)
T.get_balls(Matrix(ZZ,2,2,[p,0,0,1]),1)
leaving_edges(M)[source]

Return edges leaving a vertex.

INPUT:

  • M – 2x2 integer matrix

OUTPUT: list of size \(p+1\) of 2x2 integer matrices

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 7
sage: T = BruhatTitsTree(p)
sage: T.leaving_edges(Matrix(ZZ,2,2,[1,0,0,1]))
[
[0 1]  [7 0]  [0 1]  [0 1]  [0 1]  [0 1]  [0 1]  [0 1]
[7 0], [0 1], [7 1], [7 4], [7 5], [7 2], [7 3], [7 6]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(7)
>>> T = BruhatTitsTree(p)
>>> T.leaving_edges(Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(0),Integer(0),Integer(1)]))
[
[0 1]  [7 0]  [0 1]  [0 1]  [0 1]  [0 1]  [0 1]  [0 1]
[7 0], [0 1], [7 1], [7 4], [7 5], [7 2], [7 3], [7 6]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 7
T = BruhatTitsTree(p)
T.leaving_edges(Matrix(ZZ,2,2,[1,0,0,1]))
opposite(e)[source]

This function returns the edge oriented oppositely to a given edge.

INPUT:

  • e – 2x2 integer matrix

OUTPUT: 2x2 integer matrix

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 7
sage: T = BruhatTitsTree(p)
sage: e = Matrix(ZZ,2,2,[1,0,0,1])
sage: T.opposite(e)
[0 1]
[7 0]
sage: T.opposite(T.opposite(e)) == e
True
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(7)
>>> T = BruhatTitsTree(p)
>>> e = Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(0),Integer(0),Integer(1)])
>>> T.opposite(e)
[0 1]
[7 0]
>>> T.opposite(T.opposite(e)) == e
True
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 7
T = BruhatTitsTree(p)
e = Matrix(ZZ,2,2,[1,0,0,1])
T.opposite(e)
T.opposite(T.opposite(e)) == e
origin(e, normalized=False)[source]

Return the origin vertex of the edge represented by the input matrix e.

INPUT:

  • e – a 2x2 matrix with integer entries

  • normalized – boolean (default: False); if True then the input matrix M is assumed to be normalized

OUTPUT: e – 2x2 integer matrix

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: T = BruhatTitsTree(7)
sage: T.origin(Matrix(ZZ,2,2,[1,5,8,9]))
[1 0]
[1 7]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> T = BruhatTitsTree(Integer(7))
>>> T.origin(Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(5),Integer(8),Integer(9)]))
[1 0]
[1 7]
from sage.modular.btquotients.btquotient import BruhatTitsTree
T = BruhatTitsTree(7)
T.origin(Matrix(ZZ,2,2,[1,5,8,9]))
subdivide(edgelist, level)[source]

(Ordered) edges of self may be regarded as open balls in \(P^1(\QQ_p)\). Given a list of edges, this function return a list of edges corresponding to the level-th subdivision of the corresponding opens. That is, each open ball of the input is broken up into \(p^{\mbox{level}}\) subballs of equal radius.

INPUT:

  • edgelist – list of edges

  • level – integer

OUTPUT: list of 2x2 integer matrices

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 3
sage: T = BruhatTitsTree(p)
sage: T.subdivide([Matrix(ZZ,2,2,[p,0,0,1])],2)
[
[27  0]  [0 9]  [0 9]  [0 3]  [0 3]  [0 3]  [0 3]  [0 3]  [0 3]
[ 0  1], [3 1], [3 2], [9 1], [9 4], [9 7], [9 2], [9 5], [9 8]
]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(3)
>>> T = BruhatTitsTree(p)
>>> T.subdivide([Matrix(ZZ,Integer(2),Integer(2),[p,Integer(0),Integer(0),Integer(1)])],Integer(2))
[
[27  0]  [0 9]  [0 9]  [0 3]  [0 3]  [0 3]  [0 3]  [0 3]  [0 3]
[ 0  1], [3 1], [3 2], [9 1], [9 4], [9 7], [9 2], [9 5], [9 8]
]
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 3
T = BruhatTitsTree(p)
T.subdivide([Matrix(ZZ,2,2,[p,0,0,1])],2)
target(e, normalized=False)[source]

Return the target vertex of the edge represented by the input matrix e.

INPUT:

  • e – a 2x2 matrix with integer entries

  • normalized – boolean (default: False); if True

    then the input matrix is assumed to be normalized

OUTPUT:

  • e – 2x2 integer matrix representing the target of the input edge

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: T = BruhatTitsTree(7)
sage: T.target(Matrix(ZZ,2,2,[1,5,8,9]))
[1 0]
[0 1]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> T = BruhatTitsTree(Integer(7))
>>> T.target(Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(5),Integer(8),Integer(9)]))
[1 0]
[0 1]
from sage.modular.btquotients.btquotient import BruhatTitsTree
T = BruhatTitsTree(7)
T.target(Matrix(ZZ,2,2,[1,5,8,9]))
vertex(M)[source]

Normalize a matrix to the corresponding normalized vertex representative

INPUT:

  • M – 2x2 integer matrix

OUTPUT: a 2x2 integer matrix

EXAMPLES:

sage: # needs sage.rings.padics
sage: from sage.modular.btquotients.btquotient import BruhatTitsTree
sage: p = 5
sage: T = BruhatTitsTree(p)
sage: m = Matrix(ZZ,2,2,[p**5,p**2,p**3,1+p+p*3])
sage: e = T.edge(m)
sage: t = m.inverse()*e
sage: scaling = Qp(p,20)(t.determinant()).sqrt()
sage: t = 1/scaling * t
sage: min([t[ii,jj].valuation(p) for ii in range(2) for jj in range(2)]) >= 0
True
sage: t[1,0].valuation(p) > 0
True
>>> from sage.all import *
>>> # needs sage.rings.padics
>>> from sage.modular.btquotients.btquotient import BruhatTitsTree
>>> p = Integer(5)
>>> T = BruhatTitsTree(p)
>>> m = Matrix(ZZ,Integer(2),Integer(2),[p**Integer(5),p**Integer(2),p**Integer(3),Integer(1)+p+p*Integer(3)])
>>> e = T.edge(m)
>>> t = m.inverse()*e
>>> scaling = Qp(p,Integer(20))(t.determinant()).sqrt()
>>> t = Integer(1)/scaling * t
>>> min([t[ii,jj].valuation(p) for ii in range(Integer(2)) for jj in range(Integer(2))]) >= Integer(0)
True
>>> t[Integer(1),Integer(0)].valuation(p) > Integer(0)
True
# needs sage.rings.padics
from sage.modular.btquotients.btquotient import BruhatTitsTree
p = 5
T = BruhatTitsTree(p)
m = Matrix(ZZ,2,2,[p**5,p**2,p**3,1+p+p*3])
e = T.edge(m)
t = m.inverse()*e
scaling = Qp(p,20)(t.determinant()).sqrt()
t = 1/scaling * t
min([t[ii,jj].valuation(p) for ii in range(2) for jj in range(2)]) >= 0
t[1,0].valuation(p) > 0
class sage.modular.btquotients.btquotient.DoubleCosetReduction(Y, x, extrapow=0)[source]

Bases: SageObject

Edges in the Bruhat-Tits tree are represented by cosets of matrices in \(GL_2\). Given a matrix \(x\) in \(GL_2\), this class computes and stores the data corresponding to the double coset representation of \(x\) in terms of a fundamental domain of edges for the action of the arithmetic group \(\Gamma\).

More precisely:

Initialized with an element \(x\) of \(GL_2(\ZZ)\), finds elements \(\gamma\) in \(\Gamma\), \(t\) and an edge \(e\) such that \(get=x\). It stores these values as members gamma, label and functions self.sign(), self.t() and self.igamma(), satisfying:

  • if self.sign() == +1: igamma() * edge_list[label].rep * t() == x

  • if self.sign() == -1: igamma() * edge_list[label].opposite.rep * t() == x

It also stores a member called power so that:

p**(2*power) = gamma.reduced_norm()

The usual decomposition \(get=x\) would be:

  • g = gamma / (p ** power)

  • e = edge_list[label]

  • t’ = t * p ** power

Here usual denotes that we have rescaled gamma to have unit determinant, and so that the result is honestly an element of the arithmetic quaternion group under consideration. In practice we store integral multiples and keep track of the powers of \(p\).

INPUT:

  • Y – BruhatTitsQuotient object in which to work

  • x – Something coercible into a matrix in \(GL_2(\ZZ)\). In principle we should allow elements in \(GL_2(\QQ_p)\), but it is enough to work with integral entries

  • extrapow – gets added to the power attribute, and it is used for the Hecke action

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import DoubleCosetReduction
sage: Y = BruhatTitsQuotient(5, 13)
sage: x = Matrix(ZZ,2,2,[123,153,1231,1231])
sage: d = DoubleCosetReduction(Y,x)
sage: d.sign()
-1
sage: d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
True
sage: x = Matrix(ZZ,2,2,[1423,113553,11231,12313])
sage: d = DoubleCosetReduction(Y,x)
sage: d.sign()
1
sage: d.igamma()*Y._edge_list[d.label].rep*d.t() == x
True
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import DoubleCosetReduction
>>> Y = BruhatTitsQuotient(Integer(5), Integer(13))
>>> x = Matrix(ZZ,Integer(2),Integer(2),[Integer(123),Integer(153),Integer(1231),Integer(1231)])
>>> d = DoubleCosetReduction(Y,x)
>>> d.sign()
-1
>>> d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
True
>>> x = Matrix(ZZ,Integer(2),Integer(2),[Integer(1423),Integer(113553),Integer(11231),Integer(12313)])
>>> d = DoubleCosetReduction(Y,x)
>>> d.sign()
1
>>> d.igamma()*Y._edge_list[d.label].rep*d.t() == x
True
from sage.modular.btquotients.btquotient import DoubleCosetReduction
Y = BruhatTitsQuotient(5, 13)
x = Matrix(ZZ,2,2,[123,153,1231,1231])
d = DoubleCosetReduction(Y,x)
d.sign()
d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
x = Matrix(ZZ,2,2,[1423,113553,11231,12313])
d = DoubleCosetReduction(Y,x)
d.sign()
d.igamma()*Y._edge_list[d.label].rep*d.t() == x

AUTHORS:

  • Cameron Franc (2012-02-20)

  • Marc Masdeu

igamma(embedding=None, scale=1)[source]

Image under gamma.

Elements of the arithmetic group can be regarded as elements of the global quaternion order, and hence may be represented exactly. This function computes the image of such an element under the local splitting and returns the corresponding \(p\)-adic approximation.

INPUT:

  • embedding – integer; or a function (default: none). If embedding is None, then the image of self.gamma under the local splitting associated to self.Y is used. If embedding is an integer, then the precision of the local splitting of self.Y is raised (if necessary) to be larger than this integer, and this new local splitting is used. If a function is passed, then map self.gamma under embedding.

  • scale – (default: 1) scaling factor applied to the output

OUTPUT:

a 2x2 matrix with \(p\)-adic entries encoding the image of self under the local splitting

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import DoubleCosetReduction
sage: Y = BruhatTitsQuotient(7, 11)
sage: d = DoubleCosetReduction(Y,Matrix(ZZ,2,2,[123,45,88,1]))
sage: d.igamma()
[6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)                                   O(7^5)]
[                                  O(7^5) 6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)]
sage: d.igamma(embedding = 7)
[6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7^6 + O(7^7)                                                   O(7^7)]
[                                                  O(7^7) 6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7^6 + O(7^7)]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import DoubleCosetReduction
>>> Y = BruhatTitsQuotient(Integer(7), Integer(11))
>>> d = DoubleCosetReduction(Y,Matrix(ZZ,Integer(2),Integer(2),[Integer(123),Integer(45),Integer(88),Integer(1)]))
>>> d.igamma()
[6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)                                   O(7^5)]
[                                  O(7^5) 6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + O(7^5)]
>>> d.igamma(embedding = Integer(7))
[6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7^6 + O(7^7)                                                   O(7^7)]
[                                                  O(7^7) 6 + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 + 6*7^5 + 6*7^6 + O(7^7)]
from sage.modular.btquotients.btquotient import DoubleCosetReduction
Y = BruhatTitsQuotient(7, 11)
d = DoubleCosetReduction(Y,Matrix(ZZ,2,2,[123,45,88,1]))
d.igamma()
d.igamma(embedding = 7)
sign()[source]

Return the direction of the edge.

The Bruhat-Tits quotients are directed graphs but we only store half the edges (we treat them more like unordered graphs). The sign tells whether the matrix self.x is equivalent to the representative in the quotient (sign = +1), or to the opposite of one of the representatives (sign = -1).

OUTPUT:

an int that is +1 or -1 according to the sign of self

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import DoubleCosetReduction
sage: Y = BruhatTitsQuotient(3, 11)
sage: x = Matrix(ZZ,2,2,[123,153,1231,1231])
sage: d = DoubleCosetReduction(Y,x)
sage: d.sign()
-1
sage: d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
True
sage: x = Matrix(ZZ,2,2,[1423,113553,11231,12313])
sage: d = DoubleCosetReduction(Y,x)
sage: d.sign()
1
sage: d.igamma()*Y._edge_list[d.label].rep*d.t() == x
True
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import DoubleCosetReduction
>>> Y = BruhatTitsQuotient(Integer(3), Integer(11))
>>> x = Matrix(ZZ,Integer(2),Integer(2),[Integer(123),Integer(153),Integer(1231),Integer(1231)])
>>> d = DoubleCosetReduction(Y,x)
>>> d.sign()
-1
>>> d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
True
>>> x = Matrix(ZZ,Integer(2),Integer(2),[Integer(1423),Integer(113553),Integer(11231),Integer(12313)])
>>> d = DoubleCosetReduction(Y,x)
>>> d.sign()
1
>>> d.igamma()*Y._edge_list[d.label].rep*d.t() == x
True
from sage.modular.btquotients.btquotient import DoubleCosetReduction
Y = BruhatTitsQuotient(3, 11)
x = Matrix(ZZ,2,2,[123,153,1231,1231])
d = DoubleCosetReduction(Y,x)
d.sign()
d.igamma()*Y._edge_list[d.label - len(Y.get_edge_list())].opposite.rep*d.t() == x
x = Matrix(ZZ,2,2,[1423,113553,11231,12313])
d = DoubleCosetReduction(Y,x)
d.sign()
d.igamma()*Y._edge_list[d.label].rep*d.t() == x
t(prec=None)[source]

Return the ‘t part’ of the decomposition using the rest of the data.

INPUT:

  • prec – a \(p\)-adic precision that t will be computed to. Defaults to the default working precision of self.

OUTPUT:

a 2x2 \(p\)-adic matrix with entries of precision prec that is the ‘t-part’ of the decomposition of self

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import DoubleCosetReduction
sage: Y = BruhatTitsQuotient(5, 13)
sage: x = Matrix(ZZ,2,2,[123,153,1231,1232])
sage: d = DoubleCosetReduction(Y,x)
sage: t = d.t(20)
sage: t[1,0].valuation() > 0
True
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import DoubleCosetReduction
>>> Y = BruhatTitsQuotient(Integer(5), Integer(13))
>>> x = Matrix(ZZ,Integer(2),Integer(2),[Integer(123),Integer(153),Integer(1231),Integer(1232)])
>>> d = DoubleCosetReduction(Y,x)
>>> t = d.t(Integer(20))
>>> t[Integer(1),Integer(0)].valuation() > Integer(0)
True
from sage.modular.btquotients.btquotient import DoubleCosetReduction
Y = BruhatTitsQuotient(5, 13)
x = Matrix(ZZ,2,2,[123,153,1231,1232])
d = DoubleCosetReduction(Y,x)
t = d.t(20)
t[1,0].valuation() > 0
class sage.modular.btquotients.btquotient.Edge(p, label, rep, origin, target, links=None, opposite=None, determinant=None, valuation=None)[source]

Bases: SageObject

This is a structure to represent edges of quotients of the Bruhat-Tits tree. It is useful to enrich the representation of an edge as a matrix with extra data.

INPUT:

  • p – prime integer

  • label – integer which uniquely identifies this edge

  • rep – a 2x2 matrix in reduced form representing this edge

  • origin – the origin vertex of self

  • target – the target vertex of self

  • links – (default: empty list) list of elements of \(\Gamma\) which identify different edges in the Bruhat-Tits tree which are equivalent to self

  • opposite – (default: None) the edge opposite to self

  • determinant – (default: None) the determinant of rep, if known

  • valuation – (default: None) the valuation of the determinant of rep, if known

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import Edge, Vertex
sage: v1 = Vertex(7,0,Matrix(ZZ,2,2,[1,2,3,18]))
sage: v2 = Vertex(7,0,Matrix(ZZ,2,2,[3,2,1,18]))
sage: e1 = Edge(7,0,Matrix(ZZ,2,2,[1,2,3,18]),v1,v2)
sage: e1.rep
[ 1  2]
[ 3 18]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import Edge, Vertex
>>> v1 = Vertex(Integer(7),Integer(0),Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(2),Integer(3),Integer(18)]))
>>> v2 = Vertex(Integer(7),Integer(0),Matrix(ZZ,Integer(2),Integer(2),[Integer(3),Integer(2),Integer(1),Integer(18)]))
>>> e1 = Edge(Integer(7),Integer(0),Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(2),Integer(3),Integer(18)]),v1,v2)
>>> e1.rep
[ 1  2]
[ 3 18]
from sage.modular.btquotients.btquotient import Edge, Vertex
v1 = Vertex(7,0,Matrix(ZZ,2,2,[1,2,3,18]))
v2 = Vertex(7,0,Matrix(ZZ,2,2,[3,2,1,18]))
e1 = Edge(7,0,Matrix(ZZ,2,2,[1,2,3,18]),v1,v2)
e1.rep

AUTHORS:

  • Marc Masdeu (2012-02-20)

class sage.modular.btquotients.btquotient.Vertex(p, label, rep, leaving_edges=None, entering_edges=None, determinant=None, valuation=None)[source]

Bases: SageObject

This is a structure to represent vertices of quotients of the Bruhat-Tits tree. It is useful to enrich the representation of the vertex as a matrix with extra data.

INPUT:

  • p – prime integer

  • label – integer which uniquely identifies this vertex

  • rep – a 2x2 matrix in reduced form representing this vertex

  • leaving_edges – (default: empty list) list of edges leaving this vertex

  • entering_edges – (default: empty list) list of edges entering this vertex

  • determinant – (default: None) the determinant of rep, if known

  • valuation – (default: None) the valuation of the determinant of rep, if known

EXAMPLES:

sage: from sage.modular.btquotients.btquotient import Vertex
sage: v1 = Vertex(5,0,Matrix(ZZ,2,2,[1,2,3,18]))
sage: v1.rep
[ 1  2]
[ 3 18]
sage: v1.entering_edges
[]
>>> from sage.all import *
>>> from sage.modular.btquotients.btquotient import Vertex
>>> v1 = Vertex(Integer(5),Integer(0),Matrix(ZZ,Integer(2),Integer(2),[Integer(1),Integer(2),Integer(3),Integer(18)]))
>>> v1.rep
[ 1  2]
[ 3 18]
>>> v1.entering_edges
[]
from sage.modular.btquotients.btquotient import Vertex
v1 = Vertex(5,0,Matrix(ZZ,2,2,[1,2,3,18]))
v1.rep
v1.entering_edges

AUTHORS:

  • Marc Masdeu (2012-02-20)