------------------------------------------------------------------- Time-stamp: <2000-09-05 19:32:41 apacetti> Description: Quaternion Algebras and Modular Forms Authors: Fernando Rodriguez-Villegas villegas@math.utexas.edu University of Texas at Austin Ariel Martin Pacetti apacetti@math.utexas.edu University of Texas at Austin ------------------------------------------------------------------- This file describes the PARI-GP routines in the file qalgmodforms.gp. To use: in a GP session, you need to download the files "qforms.gp", "qalg.gp" and "bforms.gp" in your GP running directory, and then issue the command \r qalgmodforms.gp This file contains routines for doing arithmetic over quaternion algebras, and for computing the Brandt matrices, wich is the action of the Hecke operators on the weight 2 modular forms associated to this matrices. Most of these routines are based on the paper: "An Algorithm for Computing Modular Forms on \Gamma_0(N)", by "Arnold Pizer" (Journal of Algebra 64, pages 340-390, 1980). For constructing this matrices, we'll be interested on algebras ramified at a prime p and infinity. For working with such an algebra, first set some information, for example, for the prime 11, we use: qsetprime(11) which will output: [[1/2, 0, 1/2, 0], [0, 1/2, 0, 1/2], [0, 0, 1, 0], [0, 0, 0, 1], 1] The output is a maximal order in the algebra. The way the algebra is represented is as Q[1,i,j,k], and there's a global variable which is set with the previous command, called qdef, so if you type: qdef it will output: [-1, -11] which means that the number i^2 = -1, and j^2 = -11, which completely determines the algebra. There are some general arithmetic routines in the file "qalg.gp" for quaternion algebras in general, so we suggest to take a look at this file for the general case. There are some routines for working with orders, like checking if an order is maximal, with the command: qorderismaximal([[1/2, 0, 1/2, 0], [0, 1/2, 0, 1/2], [0, 0, 1, 0], [0, 0, 0, 1], 1]) which will output: 1 Or to computing the discriminant of a lattice L, for example: qdisc([[1/2, 1, -1/2, 0], [-1/2, 1, 1/2, 0], [1, 1/2, 0, -1/2],[-1, 1/2, 0, -1/2], 2]) which will output: 1936 One important routine, is to determine the level N of an order (if it satisfies the definition of being an order of level N for some N), with the routine: qlevel([[1/2, 0, 1/2, 1], [0, 1/2, 0, 3/2], [0, 0, 1, 2], [0, 0, 0, 13], 1]) which will output: 143 We will just work with orders of level p^(2*r+1)*M , or p^2*M, where p does not divide M, and p is the ramified prime. The other case is not implemented yet. And for this cases, there are explicit formulas for computing the class number of the order (see Thetha Series and modular Forms of Level p^2*m, by Arnold Pizer, Compositio Mathematica, Vol. 40, Fasc.2 1980, pag.177-241 fos this case). And for example, we have: qclassnumber([[1/2, 0, 1/2, 1], [0, 1/2, 0, 3/2], [0, 0, 1,2], [0, 0,0, 13], 1]) will output: 5 Where this is an order of level 11*13. For the order: qclassnumber([[1/2, 0, 1/2, 0], [0, 11/2, 0, 11/2], [0, 0, 1, 0], [0, 0, 0, 1], 1]) will output: 10 And: qlevel([[1/2, 0, 1/2, 0], [0, 11/2, 0, 11/2], [0, 0, 1, 0], [0, 0, 0, 1], 1]) will output: 121 The way we compute this examples, is with two specific routines, for computing an order of the first type (i.e. of level p^(2r+1)*M), called: qorderlevel(11*13) will output: [[1/2, 0, 1/2, 1], [0, 1/2, 0, 3/2], [0, 0, 1, 2], [0, 0, 0, 13], 1] and for the other case, with the command: qorderlevel2(11^2) which will output: [[1/2, 0, 1/2, 0], [0, 11/2, 0, 11/2], [0, 0, 1, 0], [0, 0, 0, 1], 1] Another important routine is for computing ideals representatives of the class number of ideals of an order, which can be done with; qidcl([[1/2, 0, 1/2, 1], [0, 1/2, 0, 3/2], [0, 0, 1, 2], [0, 0, 0, 13], 1]) which will output: [[[1/2, 0, 1/2, 1], [0, 1/2, 0, 3/2], [0, 0, 1, 2], [0, 0, 0, 13], 1], [[-2, 0, 0, 0], [1/2, 1/2, -1/2, 1/2], [1/2, -9/2, 1/2, 1/2], [0, 4, 1, 1], 2], [[-3, 0, 0, 0], [-1, -1/2, 1, 1/2], [1, -7/2, -1, 1/2], [-1/2, -5, 1/2, -1], 3], [[-4, 0, 0, 0], [1, 1, -1, 1], [-1, -4, 0, 1], [1/2, -7/2, -3/2, -1/2], 4], [[-3, -4, 0, 1], [-3, 4, 0, -1], [-1, -3, -2, 0], [3/2, 3/2, -3/2, 3/2], 6], [[1/2, -7/2, -3/2, -1/2], [2, 5, -1, 0], [0, 3, 1, -2], [-8, 0, 0, 0], 8], [[0, -5, 1, 0], [-6, 0, 0, 0], [3/2, -7/2, -1/2, 3/2], [2, 4, 1, 1], 6], [[-2, 0, 0, 0], [1/2, -1/2, 1/2, -1/2], [1/2, 0, -1/2, -1], [1, 17/2, 0, -1/2], 2], [[-1, -1/2, 1, 1/2], [-5, 0, 0, 0], [-1/2, -7/2, -1/2, 3/2], [-1, -5, 0, -2], 5], [[-1/2, -7/2, -1/2, 3/2], [-2, -1, 2, 1], [-1, -5, 0, -2], [-10, 0, 0, 0], 10], [[3/2, -9/2, -1/2, -3/2], [2, -1, 2, 1], [-4, -3, -1, 2], [13/2, 11/2, -3/2, 1/2], 10], [[1/2, -1, 3/2, 0], [-4, -17/2, 0, 1/2], [2, -5/2, -1, 7/2], [17/2, -15/2, -3/2, 1/2], 13], [[-2, -2, 2, -2], [-7/2, 15/2, 3/2, -1/2], [-9/2, 11/2, -5/2, -3/2], [-35/2, -7/2, 1/2, 7/2], 24], [[-5/2, -4, -1/2, 0], [-5/2, 4, 1/2, 0], [-1/2, 1/2, -3/2, -3/2], [3/2, 1, -1/2, 2], 5]] which is a verctor with 14 components, each one an ideal of the given order, and all of them are non-equivalent. With all this routines, we can compute the Brandt matrices, which is the main routine of thie files, which can be done for any order (of one of the previous types), and any number n, so for example, for the maximal order, we have: brandt([[1/2, 0, 1/2, 0], [0, 1/2, 0, 1/2], [0, 0, 1, 0], [0, 0, 0, 1], 1],0) which will output: [1/4 1/6] [1/4 1/6] We just want to remark that the first time one computes the Brandt matrix for a given order, the routine sets some information, and keeps it in memory, so if we are going to compute several Brandt matrices, the process takes some time just for the first time. If we want to compute some other Brandt matrices for the same order, we just change the n: brandt([[1/2, 0, 1/2, 0], [0, 1/2, 0, 1/2], [0, 0, 1, 0], [0, 0, 0, 1], 1],3) which will output: [2 2] [3 1] We are working in some faster routines for the case of level p^2, we hope they will be ready soon, and put on the web page. If you have any comment or improve, or any bug you can find, please email us, saying the problem.