Quotients of the Bruhat-Tits tree

This package contains all the functionality described and developed in [FM]. 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)

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

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

REFERENCES:

[FM]Computing fundamental domains for the Bruhat-Tits tree for \(\textrm{GL}_2(\QQ_p)\), \(p\)-adic automorphic forms, and the canonical embedding of Shimura curves Cameron Franc, Marc Masdeu LMS Journal of Computation and Mathematics (2014), volume 17, issue 01, pp. 1-23.
sage.modular.btquotients.btquotient.BruhatTitsQuotient

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 - an 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

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

Note

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

AUTHORS:

  • Marc Masdeu (2012-02-20)
sage.modular.btquotients.btquotient.BruhatTitsTree

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

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

AUTHORS:

  • Marc Masdeu (2012-02-20)
class sage.modular.btquotients.btquotient.DoubleCosetReduction(Y, x, extrapow=0)

Bases: sage.structure.sage_object.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

AUTHORS:

  • Cameron Franc (2012-02-20)
  • Marc Masdeu
igamma(embedding=None, scale=1)

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 - an 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)]
sign()

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
t(prec=None)

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
class sage.modular.btquotients.btquotient.Edge(p, label, rep, origin, target, links=None, opposite=None, determinant=None, valuation=None)

Bases: sage.structure.sage_object.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 - a prime integer.
  • label - An 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) A 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]

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)

Bases: sage.structure.sage_object.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 - a prime integer.
  • label - An integer which uniquely identifies this vertex.
  • rep - A 2x2 matrix in reduced form representing this vertex.
  • leaving_edges - (default: empty list) A list of edges leaving this vertex.
  • entering_edges - (default: empty list) A 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
[]

AUTHORS:

  • Marc Masdeu (2012-02-20)