QQ := Rationals(); intrinsic MDCongruenceSubgroup(M :: ModSym) -> GrpPSL2 { Return the congruence subgroup that was used to define the ambient space of this modular symbols space. } M := AmbientSpace(M); if IsTrivial(DirichletCharacter(M)) then return Gamma0(Level(M)); elif IsMultiChar(M) then if assigned M`isgamma1 and M`isgamma1 then return Gamma1(Level(M)); elif assigned M`isgamma and M`isgamma then return CongruenceSubgroup(Integers()!Sqrt(Level(M))); end if; end if; require false : "Only implemented for Gamma0(N), Gamma1(N) and Gamma(N)"; end intrinsic; intrinsic MDDiagonalALBasis(decomposition :: SeqEnum[ModSym]) -> SeqEnum[SeqEnum[ModFrmElt]], SeqEnum[SeqEnum[SeqEnum[FldRatElt]]] { Given a decomposition of the modular symbols of weight k for some group Gamma0(N) it gives a corresponding basis of the modular in S_k(Gamma0(N)) respecting this decomposition such that further more the Atkin-Lehner operators act diagonally. The second return value are the Atkin-Lehner eigenvalues on this basis } if #decomposition eq 0 then return [],[]; end if; G := MDCongruenceSubgroup(decomposition[1]); N := Level(G); require G eq Gamma0(N) : "Only implemented for Gamma0(N)"; g := Genus(G); prec := 2*g; k := Weight(decomposition[1]); M := ModularForms(G,k); S := CuspidalSubspace(M); V, VtoS, StoV := RSpace(S); al_divisors := [pe[1]^pe[2] : pe in Factorisation(N)]; al := [AtkinLehnerOperator(S,d) : d in al_divisors]; q_basis := [qIntegralBasis(Si, prec) : Si in decomposition]; V_basis := [[StoV(S ! f) : f in B] : B in q_basis]; V_dec := [ChangeRing(sub< V | B>, QQ) : B in V_basis]; V_basis_diag := []; al_diag := [[] : w_p in al]; for Vi in V_dec do al_res := [MDRestriction(w_p, Vi) : w_p in al]; diag, t := Diagonalisation(al_res); basis := [ClearDenominator(v) : v in Rows(t*BasisMatrix(Vi))]; Append(~V_basis_diag, basis); for i in [1..#diag] do Append(~al_diag[i],Diagonal(diag[i])); end for; end for; q_basis_diag := [[VtoS(f) : f in B] : B in V_basis_diag]; return q_basis_diag,al_diag; end intrinsic;