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 numberNminus
- 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 functionsself.sign()
,self.t()
andself.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 workx
- 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). Ifembedding
is None, then the image ofself.gamma
under the local splitting associated toself.Y
is used. Ifembedding
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 mapself.gamma
underembedding
.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 splittingEXAMPLES:
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 selfEXAMPLES:
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
- if
-
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 ofself
.target
- The target vertex ofself
.links
- (Default: empty list) A list of elements of \(\Gamma\) which identify different edges in the Bruhat-Tits tree which are equivalent toself
.opposite
- (Default: None) The edge opposite toself
determinant
- (Default: None) The determinant ofrep
, if known.valuation
- (Default: None) The valuation of the determinant ofrep
, 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 ofrep
, if known.valuation
- (default: None) The valuation of the determinant ofrep
, 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)