// Some Magma code for computing quaternionic modular forms as in my paper // on zeroes of quaternionic modular forms with Jordan Wiebe (JNT 2020) // // Author: Kimball Martin // Updated: May 2020 // // The main functions are eigbasis(N) and cuspbasis(N), which compute // quaternionic modular eigenforms of trivial weight for a maximal order // in a definite quaternion algebra of discriminant N /* Input: polynomial f Output: true if f has a repeat factor, false otherwise */ repeatfactor:=function(f) f:=Factorization(f); marker:=false; for i in [1 .. #f] do if f[i][2] ne 1 then marker:=true; end if; end for; return marker; end function; /* Input: vector v Output: multiple of v which has integral elements */ intscale:=function(v) d:=[]; for j in [1 .. #v] do d:=Append(d,Denominator(v[j])); end for; l:=LCM(d); for k in [1 .. #v] do v[k]:=l*v[k]; end for; return v; end function; /* input an n-by-n matrix T and an n-by-n permutation matrix W of order 2 output T wrt a reordered basis e1, ..., en so that e1, ..., er are fixed points of W and W permutes successive pairs of e_(r+1) ... e_n */ function changebasis(T,W) n := NumberOfRows(T); w := []; for i in [1..n] do for j in [1..n] do if W[i][j] eq 1 then w[i] := j; end if; end for; end for; neword := []; for i in [1..n] do if w[i] eq i then neword:=Append(neword,i); end if; end for; for i in [1..n] do if w[i] gt i then neword:=Append(neword,i); neword:=Append(neword,w[i]); end if; end for; newpos := [: i in [1..n]]; U := Matrix(n, n, newpos); return Transpose(U)*T*U; end function; /* Input: level N (disc of def quat alg/Q) Output: a basis of eigen QMFs of level N if ordered is set to true, the values of the eigenforms are ordered to be eigenfunctions of Hecke operators T which are the output of changebasis(T,T_N) in the ordered case, QMFs are returned as tuples (phi,poly,N,root no,Tr T_N) where phi is the sequence of values of the form in terms of a root of poly in the unordered (default) case, return (phi,poly,N) */ function eigbasis(N: ordered := false) B:=BrandtModule(N); p:=2; h:=CharacteristicPolynomial(HeckeOperator(B,p)); while repeatfactor(h) do p:=NextPrime(p); h:=CharacteristicPolynomial(HeckeOperator(B,p)); end while; T:=Transpose(HeckeOperator(B,p)); if ordered then W := HeckeOperator(B,N); T := changebasis(T,W); W := changebasis(W,W); end if; f:=CharacteristicPolynomial(T); g:=Factorization(f); counter:=0; QMFs:=[]; for i in [1 .. #g] do if Degree(g[i][1]) ne 1 then K:=NumberField(g[i][1]); else K:=RationalField(); a:=-ConstantCoefficient(g[i][1]); end if; TK:=Matrix(K,T); U:=Eigenspace(TK,a); phi:=intscale(Eltseq(Basis(U)[1])); if ordered then v := ColumnMatrix(phi); WK := Matrix(K,W); if WK*v eq v then sgn := 1; end if; if WK*v eq -v then sgn := -1; end if; QMFs[i] := [* phi, g[i][1], N, sgn, Trace(W) *]; else QMFs[i] := [* phi, g[i][1], N *]; end if; end for; return QMFs; end function; /* Input: level N (disc of def quat alg/Q) Output: a basis of cuspidal QMFs of level N see comments on eigbasis for more details */ function cuspbasis(N: ordered := false) QMFs := eigbasis(N: ordered); M0 := []; one := [1: j in [1..#(QMFs[1][1])]]; for x in QMFs do if x[1] ne one then M0 := Append(M0,x); end if; end for; return M0; end function;