From 19dd200fa55fb70e071d6e7937dab0f02d83078c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giulia=20Orr=C3=B9?= Date: Mon, 14 Sep 2026 16:45:55 +0100 Subject: [PATCH 1/4] Delete prime power case --- lib/Orru/sl2methodsExtra.gi | 137 ------------------------------------ 1 file changed, 137 deletions(-) diff --git a/lib/Orru/sl2methodsExtra.gi b/lib/Orru/sl2methodsExtra.gi index de2aeec7..992f37db 100644 --- a/lib/Orru/sl2methodsExtra.gi +++ b/lib/Orru/sl2methodsExtra.gi @@ -1,137 +1,4 @@ -# methods for power of primes - InstallMethod(AmbientPosition, - "Returns cosetPos(g) function for the congruence subgroup G", - [ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], - function(G) - local cosetPos, canonicalRep, n, countRep; - - if DimensionOfMatrixGroup(G) <> 2 then - TryNextMethod(); - fi; - - n := LevelOfCongruenceSubgroup(G); - - if not IsPrimePowerInt(n) then - TryNextMethod(); - fi; - - if IsPrime(n) then - TryNextMethod(); - fi; - - canonicalRep := function(g) - local v, vv, U, d, dd, x, y; - v := [g[1][1], g[2][1]]; - vv := List(v, x -> x mod n); - U := Filtered([0..n],i->Gcd(i,n)=1); - if vv[1] mod n = 0 then - return [0,1]; - elif vv[1] mod n in U then - return [1,(Inverse(vv[1]) mod n)*vv[2] mod n]; - else - d := Gcd(vv[1],n); - dd := n/d; - x := vv[1]/d; - y := vv[2]/x mod dd; - while not Gcd(d,y) = 1 do - y := y + dd; - od; - return [d, y]; - fi; - end; - - countRep := function(m) - local p, e, i, countp; - - p := Set(Factors(m))[1]; - e := Length(Factors(m)); - - countp := [1,m]; - - for i in [2..e] do - Add(countp, p^(e-i)*(p-1)); - od; - - return countp; - end; - - cosetPos := function(g) - local w, count, e, U; - w := canonicalRep(g); - - count := countRep(n); - - if w[1] = 0 then - return 1; - elif w[1] = 1 then - U := [0..n-1]; - return 1 + Position(U,w[2]); - else - e := Length(Factors(w[1])); - U := Filtered([0..n/w[1]], i-> Gcd(i,n/w[1]) = 1); - return Sum(count{[1..1 + e]}) + Position(U, w[2]); - fi; - end; - - return cosetPos; - end); - -#InstallMethod(AmbientPosition, -# "Returns cosetPos(g) function for the congruence subgroup G", -# [ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], -# function(G) -# local cosetPos, canonicalRep, n, ProjLine, U; -# -# if DimensionOfMatrixGroup(G) <> 2 then -# TryNextMethod(); -# fi; -# -# n := LevelOfCongruenceSubgroup(G); -# -# if IsPrime(n) then -# TryNextMethod(); -# fi; -# -# if IsPrimePowerInt(n) then -# TryNextMethod(); -# fi; -# -# ProjLine := ProjectiveSpace(G); -# -# U := Filtered([0..n],i -> Gcd(i,n) = 1); -# -# canonicalRep := function(g) -# local v, vv, d, dd, x, y; -# v := [g[1][1], g[2][1]]; -# vv := List(v, x -> x mod n); -# if vv[1] mod n = 0 then -# return [0,1]; -# elif (vv[1] mod n) in U then -# return [1,(Inverse(vv[1]) mod n)*vv[2] mod n]; -# else -# d := Gcd(vv[1],n); -# dd := n/d; -# x := vv[1]/d; -# y := vv[2]/x mod dd; -# while not Gcd(d,y) = 1 do -# y := y + dd; -# od; -# return [d, y]; -# fi; -# end; -# -# cosetPos := function(g) -# local w; -# w := canonicalRep(g); -# return Position(ProjLine,w); -# end; -# -# return cosetPos; -# end); - -## New implementation just to try, with a better formula for the position. - InstallMethod(AmbientPosition, "Returns cosetPos(g) function for the congruence subgroup G", [ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], function(G) @@ -147,10 +14,6 @@ InstallMethod(AmbientPosition, TryNextMethod(); fi; - if IsPrimePowerInt(n) then - TryNextMethod(); - fi; - countRep := function(m) local d, q, count; From 450fb3719cdfb8f4214ddef0dcf0f97ac1a85fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giulia=20Orr=C3=B9?= Date: Thu, 24 Sep 2026 17:05:14 +0100 Subject: [PATCH 2/4] Add alternative construction of finite projective plane --- lib/Orru/decsOrru.gd | 2 ++ lib/Orru/finiteProjectiveSpaces.gi | 49 +++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/Orru/decsOrru.gd b/lib/Orru/decsOrru.gd index 90dd2368..0e728693 100644 --- a/lib/Orru/decsOrru.gd +++ b/lib/Orru/decsOrru.gd @@ -4,9 +4,11 @@ DeclareGlobalFunction("HAP_GenericCongruenceSubgroup"); DeclareOperation("FiniteProjectiveLine",[IsInt]); DeclareOperation("FiniteProjectivePlane",[IsInt]); DeclareOperation("FiniteProjectiveLine_alt",[IsInt]); +DeclareOperation("FiniteProjectivePlane_alt",[IsInt]); DeclareGlobalFunction("HAP_FiniteProjectiveLineIntegers"); DeclareGlobalFunction("HAP_FiniteProjectiveLineIntegers_alt"); DeclareGlobalFunction("HAP_FiniteProjectivePlaneIntegers"); +DeclareGlobalFunction("HAP_FiniteProjectivePlaneIntegers_alt"); DeclareGlobalFunction("HAP_SL3ZSubgroupTree_fast"); DeclareOperation("HAPCongruenceSubgroupGamma0",[IsInt,IsInt]); DeclareOperation("HAPCongruenceSubgroupGamma0_alt",[IsInt,IsInt]); diff --git a/lib/Orru/finiteProjectiveSpaces.gi b/lib/Orru/finiteProjectiveSpaces.gi index 27bc7aaf..9c2be5b0 100644 --- a/lib/Orru/finiteProjectiveSpaces.gi +++ b/lib/Orru/finiteProjectiveSpaces.gi @@ -27,6 +27,13 @@ function(n) return HAP_FiniteProjectiveLineIntegers_alt(n); end); +InstallMethod(FiniteProjectivePlane_alt, +"Finite projective line for the ring Z/nZ", +[IsInt], +function(n) +return HAP_FiniteProjectivePlaneIntegers_alt(n); +end); + @@ -72,7 +79,7 @@ function(n) ); end); -InstallGlobalFunction(HAP_FiniteProjectivePlaneIntegers, +InstallGlobalFunction(HAP_FiniteProjectivePlaneIntegers_alt, function(n) local UnitEls, x, y, z, i, c, d, u, UnitsAction, Representatives, RepOf, r, v, w, m, min; @@ -160,4 +167,44 @@ function(n) return Rep; end); +InstallGlobalFunction(HAP_FiniteProjectivePlaneIntegers, +function(n) + local divs, Rep, d, q, g, q_g, m, u, U_m, dd, qq, z, uu, zz; + + divs := List(DivisorsInt(n)); + Remove(divs); + divs := Concatenation([n],divs); + Rep := []; + + for d in divs do + q := n/d; + for g in divs do + q_g := n/g; + m := Gcd(q,q_g); + U_m := Filtered([0..m-1], z -> Gcd(z,m) = 1); + + for u in U_m do + uu := u; + while Gcd(uu, q_g) <> 1 do + uu := uu + m; + od; + + dd := Gcd(d,g); + qq := n/dd; + + for z in [0..qq-1] do + if Gcd(z,dd,qq) = 1 then + zz := z; + while Gcd(zz, dd) <> 1 do + zz := zz + qq; + od; + + Add(Rep, [d mod n,g*uu mod n,zz]); + fi; + od; + od; + od; + od; + return rec(Reps := Set(List(Rep, Immutable)));; +end); \ No newline at end of file From cebc380261fc9db8504734b118a57c9d778959ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giulia=20Orr=C3=B9?= Date: Sat, 26 Sep 2026 12:07:25 +0100 Subject: [PATCH 3/4] Update AmbientPosition and AmbientTree for SL(3,Z) --- lib/CongruenceGroups/congGroups.gi | 6 ++-- lib/Orru/sl3methods.gi | 55 ++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lib/CongruenceGroups/congGroups.gi b/lib/CongruenceGroups/congGroups.gi index d4e560ba..53f8766f 100644 --- a/lib/CongruenceGroups/congGroups.gi +++ b/lib/CongruenceGroups/congGroups.gi @@ -532,8 +532,10 @@ InstallMethod( IsSubset, vertex2word, one, cosetPos, cosetRep, triple2word, i,j,u,c,a,b; - if DimensionOfMatrixGroup(G)>2 then TryNextMethod(); fi; - n:=LevelOfCongruenceSubgroup(G); + if DimensionOfMatrixGroup(G)>2 and + not (DimensionOfMatrixGroup(G)=3 and IsHAPCongruenceSubgroupGamma0(G)) + then TryNextMethod(); fi; + n:=LevelOfCongruenceSubgroup(G); GG:=AmbientGroupOfCongruenceSubgroup(G); ambientGenerators:=GeneratorsOfGroup(GG); diff --git a/lib/Orru/sl3methods.gi b/lib/Orru/sl3methods.gi index a43f5760..16cbb4c0 100644 --- a/lib/Orru/sl3methods.gi +++ b/lib/Orru/sl3methods.gi @@ -28,30 +28,49 @@ InstallMethod(AmbientPosition, "Returns cosetPos(g) function for the congruence subgroup G", [ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], function(G) - local cosetPos, n, ProjPlane, U, UU; + local cosetPos, canonicalRep, n, ProjPlane; if DimensionOfMatrixGroup(G) <> 3 then TryNextMethod(); fi; n := LevelOfCongruenceSubgroup(G); - - ProjPlane := ProjectiveSpace(G); - if not IsBound(G!.Units) then - UU := Units(Integers mod n); #Graham - G!.Units:=List(UU,Int); #Graham - fi; - - cosetPos := function(g) - local v, vv, u, w, p; - v := [g[1][1], g[2][1], g[3][1]]; - vv := List(v, x -> x mod n); - - for u in G!.Units do #Graham - w := List(vv, x -> (u*x) mod n); #Graham - p:=Position(ProjPlane.Reps,w); #Graham - if not p=fail then return p; fi; #Graham + canonicalRep := function(g) + local x, y, z, d_x, q_x, a, d_y, q_y, y_0, b, d, q, z_0; + + x := g[1][1] mod n; + y := g[2][1] mod n; + z := g[3][1] mod n; + + d_x := Gcd(x,n); + q_x := n/d_x; + a := Gcdex(x/d_x, q_x).coeff1 mod q_x; + + d_y := Gcd(y,n); + q_y := n/d_y; + y_0 := a*(y/d_y) mod Gcd(q_y,q_x); + + while not Gcd(y_0, q_y) = 1 do + y_0 := y_0 + Gcd(q_y,q_x); od; + + b := ChineseRem([q_x,q_y],[a, Gcdex(y/d_y, q_y).coeff1*y_0 mod q_y]); + + d := Gcd(d_x,d_y); + q := n/d; + + z_0 := b*z mod q; + while not Gcd(z_0, d) = 1 do + z_0 := z_0 + q; + od; + + return [d_x mod n, d_y*y_0 mod n, z_0]; + end; + + ProjPlane := ProjectiveSpace(G); + + cosetPos := function(g) + return Position(ProjPlane.Reps, canonicalRep(g)); end; return cosetPos; @@ -60,7 +79,7 @@ InstallMethod(AmbientPosition, ## ## AmbientRepresentation( ) ## -## Returns a function cosetPos(g) giving a canonical rpresentative of the +## Returns a function, cosetRep(g), giving a canonical representative of the ## coset gG in the ambient group. InstallMethod(AmbientRepresentation, "Returns cosetRep(g) function for the congruence subgroup G", From abbd6c2fba99a1d5e368fc415dae9a833116f6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giulia=20Orr=C3=B9?= Date: Sun, 27 Sep 2026 01:37:49 +0100 Subject: [PATCH 4/4] Add first implementation of congruence subgroups for SL(4,Z) --- lib/CongruenceGroups/congGroups.gi | 4 +- lib/Orru/decsOrru.gd | 4 + lib/Orru/finiteProjectiveSpaces.gi | 116 ++++++++++++++++++ lib/Orru/initOrru.gi | 1 + lib/Orru/sl4methods.gi | 182 +++++++++++++++++++++++++++++ 5 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 lib/Orru/sl4methods.gi diff --git a/lib/CongruenceGroups/congGroups.gi b/lib/CongruenceGroups/congGroups.gi index 53f8766f..ba966fee 100644 --- a/lib/CongruenceGroups/congGroups.gi +++ b/lib/CongruenceGroups/congGroups.gi @@ -101,7 +101,7 @@ InstallMethod( CongruenceSubgroupGamma0, "for integer matrix group and positive ################################################## ## ## Remaining components to be computed in other functions. - if DimensionOfMatrixGroup(GG)<4 then ProjectiveSpace(G);fi; + if DimensionOfMatrixGroup(GG)<5 then ProjectiveSpace(G);fi; AmbientTransversal(G); AmbientPosition(G); #A generic method will be used to construct the AmbientRepresentation(G); #these two functions except for cases with a @@ -533,7 +533,7 @@ InstallMethod( IsSubset, i,j,u,c,a,b; if DimensionOfMatrixGroup(G)>2 and - not (DimensionOfMatrixGroup(G)=3 and IsHAPCongruenceSubgroupGamma0(G)) + not (DimensionOfMatrixGroup(G) in [3,4] and IsHAPCongruenceSubgroupGamma0(G)) then TryNextMethod(); fi; n:=LevelOfCongruenceSubgroup(G); diff --git a/lib/Orru/decsOrru.gd b/lib/Orru/decsOrru.gd index 0e728693..73554931 100644 --- a/lib/Orru/decsOrru.gd +++ b/lib/Orru/decsOrru.gd @@ -5,10 +5,14 @@ DeclareOperation("FiniteProjectiveLine",[IsInt]); DeclareOperation("FiniteProjectivePlane",[IsInt]); DeclareOperation("FiniteProjectiveLine_alt",[IsInt]); DeclareOperation("FiniteProjectivePlane_alt",[IsInt]); +DeclareOperation("FiniteProjectiveSpace3",[IsInt]); +DeclareOperation("FiniteProjectiveSpace3_alt",[IsInt]); DeclareGlobalFunction("HAP_FiniteProjectiveLineIntegers"); DeclareGlobalFunction("HAP_FiniteProjectiveLineIntegers_alt"); DeclareGlobalFunction("HAP_FiniteProjectivePlaneIntegers"); DeclareGlobalFunction("HAP_FiniteProjectivePlaneIntegers_alt"); +DeclareGlobalFunction("HAP_FiniteProjectiveSpace3Integers"); +DeclareGlobalFunction("HAP_FiniteProjectiveSpace3Integers_alt"); DeclareGlobalFunction("HAP_SL3ZSubgroupTree_fast"); DeclareOperation("HAPCongruenceSubgroupGamma0",[IsInt,IsInt]); DeclareOperation("HAPCongruenceSubgroupGamma0_alt",[IsInt,IsInt]); diff --git a/lib/Orru/finiteProjectiveSpaces.gi b/lib/Orru/finiteProjectiveSpaces.gi index 9c2be5b0..ea5db8f7 100644 --- a/lib/Orru/finiteProjectiveSpaces.gi +++ b/lib/Orru/finiteProjectiveSpaces.gi @@ -34,7 +34,19 @@ function(n) return HAP_FiniteProjectivePlaneIntegers_alt(n); end); +InstallMethod(FiniteProjectiveSpace3_alt, +"3 dimensional finite projective space for the ring Z/nZ", +[IsInt], +function(n) +return HAP_FiniteProjectiveSpace3Integers_alt(n); +end); +InstallMethod(FiniteProjectiveSpace3, +"3 dimensional finite projective space for the ring Z/nZ", +[IsInt], +function(n) +return HAP_FiniteProjectiveSpace3Integers(n); +end); InstallGlobalFunction(HAP_FiniteProjectiveLineIntegers_alt, @@ -207,4 +219,108 @@ function(n) od; return rec(Reps := Set(List(Rep, Immutable)));; +end); + +InstallGlobalFunction(HAP_FiniteProjectiveSpace3Integers, +function(n) + local divs, Rep, d_x, q_x, d_y, q_y, q_xy, d_z, q_z, Q, y_0, y_00, Y_0, z_0, z_00, Z_0, QQ, t, tt; + + divs := List(DivisorsInt(n)); + Remove(divs); + divs := Concatenation([n],divs); + Rep := []; + + for d_x in divs do + q_x := n/d_x; + for d_y in divs do + q_y := n/d_y; + q_xy := Gcd(q_x,q_y); + Y_0 := Filtered([0..q_xy-1], e -> Gcd(e,q_xy) = 1); + Q := Lcm(q_x,q_y); + + for y_0 in Y_0 do + y_00 := y_0; + while Gcd(y_00, q_y) <> 1 do + y_00 := y_00 + q_xy; + od; + + for d_z in divs do + q_z := n/d_z; + QQ := Lcm(Q,q_z); + + Z_0 := Filtered([0..Gcd(Q,q_z)-1], e -> Gcd(e,Gcd(Q,q_z)) = 1); + for z_0 in Z_0 do + z_00 := z_0; + while Gcd(z_00, q_z) <> 1 do + z_00 := z_00 + Gcd(Q,q_z); + od; + for t in [0..QQ-1] do + if Gcd(t,QQ,n/QQ) = 1 then + tt := t; + while Gcd(tt, n/QQ) <> 1 do + tt := tt + QQ; + od; + Add(Rep, [d_x mod n,d_y*y_00 mod n,d_z*z_00 mod n, tt]); + fi; + od; + od; + od; + od; + od; + od; + + return rec(Reps := Set(List(Rep, Immutable)));; +end); + + +InstallGlobalFunction(HAP_FiniteProjectiveSpace3Integers_alt, +function(n) + local UnitEls, x, y, z, t, i, c, d, u, UnitsAction, Representatives, + RepOf, r, v, w, m, min; + + UnitEls := Units(Integers mod n); + + UnitsAction := function(c, u) + local uu; + uu :=Int (u); + return List(c, x -> (uu * x) mod n); + end; + + Representatives := []; + + RepOf := []; + for x in [1..n] do + RepOf[x] := []; + for y in [1..n] do + RepOf[x][y] := []; + for z in [1..n] do + RepOf[x][y][z] := []; + od; + od; + od; + + for x in [0..n-1] do + for y in [0..n-1] do + for z in [0..n-1] do + for t in [0..n-1] do + if Gcd(x,y,z,t,n) = 1 then + v := [x,y,z,t]; + if not IsBound(RepOf[x+1][y+1][z+1][t+1]) then + m := Orbit(UnitEls,v,UnitsAction); + min := Minimum(m); + AddSet(Representatives,min); + for w in m + 1 do + RepOf[w[1]][w[2]][w[3]][w[4]] := min; + od; + fi; + fi; + od; + od; + od; + od; + + return rec( + Reps := Set(Representatives), + RepOf:= RepOf + ); end); \ No newline at end of file diff --git a/lib/Orru/initOrru.gi b/lib/Orru/initOrru.gi index 0402f3cd..b4bc88ee 100644 --- a/lib/Orru/initOrru.gi +++ b/lib/Orru/initOrru.gi @@ -4,3 +4,4 @@ ReadPackageHap( "lib/Orru/HAP_SL3ZSubgroupTree_fast.gi"); ReadPackageHap( "lib/Orru/SL3ZTopHomology.gi"); ReadPackageHap( "lib/Orru/sl2methodsExtra.gi"); ReadPackageHap( "lib/Orru/sl3methods.gi"); +ReadPackageHap( "lib/Orru/sl4methods.gi"); diff --git a/lib/Orru/sl4methods.gi b/lib/Orru/sl4methods.gi new file mode 100644 index 00000000..1e7546df --- /dev/null +++ b/lib/Orru/sl4methods.gi @@ -0,0 +1,182 @@ +########################################################################## +## +## Methods for 4x4 congruence subgroups of SL4 + +########################################################################## +## +## ProjectiveSpace( ) +## + +InstallMethod(ProjectiveSpace, + "Projective space", + [ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], + function(G) + local n; + if DimensionOfMatrixGroup(G)<>4 then TryNextMethod(); fi; + + n := LevelOfCongruenceSubgroup(G); + + return FiniteProjectiveSpace3(n); + end); +########################################################################## +## +## AmbientPosition( ) +## +## Returns a function cosetPos(g) giving the position of the coset gG in +## the ambient group. +InstallMethod(AmbientPosition, +"Returns cosetPos(g) function for the congruence subgroup G", +[ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], + function(G) + local cosetPos, canonicalRep, n, ProjSpace; + if DimensionOfMatrixGroup(G) <> 4 then + TryNextMethod(); + fi; + + n := LevelOfCongruenceSubgroup(G); + + canonicalRep := function(g) + local x, y, z, t, d_x, q_x, a, d_y, q_y, y_0, b, d_z, q_z, z_0, c, t_0, d, q; + + x := g[1][1] mod n; + y := g[2][1] mod n; + z := g[3][1] mod n; + t := g[4][1] mod n; + + d_x := Gcd(x,n); + q_x := n/d_x; + a := Gcdex(x/d_x, q_x).coeff1 mod q_x; + + d_y := Gcd(y,n); + q_y := n/d_y; + y_0 := a*(y/d_y) mod Gcd(q_y,q_x); + + while not Gcd(y_0, q_y) = 1 do + y_0 := y_0 + Gcd(q_y,q_x); + od; + + b := ChineseRem([q_x,q_y],[a, Gcdex(y/d_y, q_y).coeff1*y_0 mod q_y]); + + d_z := Gcd(z,n); + q_z := n/d_z; + z_0 := b*(z/d_z) mod Gcd(LcmInt(q_x,q_y),q_z); + + while not Gcd(z_0, q_z) = 1 do + z_0 := z_0 + Gcd(LcmInt(q_x,q_y),q_z); + od; + + c := ChineseRem([LcmInt(q_x,q_y),q_z],[b, Gcdex(z/d_z, q_z).coeff1*z_0 mod q_z]); + + d := Gcd(d_x,d_y,d_z); + q := n/d; + + t_0 := c*t mod q; + while not Gcd(t_0, d) = 1 do + t_0 := t_0 + q; + od; + + return [d_x mod n, d_y*y_0 mod n, d_z*z_0 mod n, t_0]; + end; + + ProjSpace := ProjectiveSpace(G); + + cosetPos := function(g) + return Position(ProjSpace.Reps, canonicalRep(g)); + end; + + return cosetPos; + end); +########################################################################## +## +## AmbientRepresentation( ) +## +## Returns a function, cosetRep(g), giving a canonical representative of the +## coset gG in the ambient group. +InstallMethod(AmbientRepresentation, +"Returns cosetRep(g) function for the congruence subgroup G", +[ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], + function(G) + local MatrixInSL4_Hermite, cosetOfInt, cosetRep, n, ProjSpace, cosetPos; + if DimensionOfMatrixGroup(G) <> 4 then + TryNextMethod(); + fi; + + n := LevelOfCongruenceSubgroup(G); + + MatrixInSL4_Hermite := function(v) + local Herm; + Herm := HermiteNormalFormIntegerMatTransform([[v[1]],[v[2]],[v[3]],[v[4]]]); + return Inverse(Herm!.rowtrans); + end; + + ProjSpace := ProjectiveSpace(G); + + cosetOfInt:=function(i) + local x,y,z,t; + x := ProjSpace.Reps[i][1]; + y := ProjSpace.Reps[i][2]; + z := ProjSpace.Reps[i][3]; + t := ProjSpace.Reps[i][4]; + + return MatrixInSL4_Hermite([x,y,z,t]); + end; + + cosetPos := AmbientPosition(G); + + cosetRep:=function(g); + return cosetOfInt(cosetPos(g)); + end; + + return cosetRep; + end); + + ## +## AmbientTransversal( ) +## +## Right transversal for a congruence subgroup G in its ambient group GG +InstallMethod(AmbientTransversal, +"Right transversal for a congruence subgroup G in its ambient group", +[ IsIntegerMatrixGroup and IsHAPCongruenceSubgroupGamma0 ], +function(G) + local n, GG, poscan, cosetPos, transversal, ProjSpace, cosetOfInt, MatrixInSL4_Hermite; + + if DimensionOfMatrixGroup(G) <> 4 then + TryNextMethod(); + fi; + + n := LevelOfCongruenceSubgroup(G); + ProjSpace := ProjectiveSpace(G); + + GG:=AmbientGroupOfCongruenceSubgroup(G); + cosetPos:=AmbientPosition(G); + + MatrixInSL4_Hermite := function(v) + local Herm; + Herm := HermiteNormalFormIntegerMatTransform([[v[1]],[v[2]],[v[3]],[v[4]]]); + return Inverse(Herm!.rowtrans); + end; + + cosetOfInt:=function(i) + local x,y,z,t; + x := ProjSpace.Reps[i][1]; + y := ProjSpace.Reps[i][2]; + z := ProjSpace.Reps[i][3]; + t := ProjSpace.Reps[i][4]; + return MatrixInSL4_Hermite([x,y,z,t]); + end; + + poscan := function(g) + return cosetPos(g^-1); + end; + + transversal := List([1..Length(ProjSpace.Reps)],i->cosetOfInt(i)^-1); + + return Objectify( NewType( FamilyObj( GG ), + IsHapRightTransversalSLnZSubgroup and IsList and #SL2??? + IsDuplicateFreeList and IsAttributeStoringRep ), + rec( group := GG, + subgroup := G, + cosets:=transversal, + poscan:=poscan + )); +end);