GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#############################################################################
##
#W cong.g The Congruence package Ann Dooms
#W Eric Jespers
#W Alexander Konovalov
##
##
#############################################################################
#############################################################################
#
# CanEasilyCompareCongruenceSubgroups( G, H )
#
InstallMethod( CanEasilyCompareCongruenceSubgroups,
"for two congruence subgroups",
[ IsCongruenceSubgroup, IsCongruenceSubgroup ],
function ( G, H )
local i;
if ForAll( [ G, H ], IsPrincipalCongruenceSubgroup ) or
ForAll( [ G, H ], IsCongruenceSubgroupGamma0 ) or
ForAll( [ G, H ], IsCongruenceSubgroupGammaUpper0 ) or
ForAll( [ G, H ], IsCongruenceSubgroupGamma1 ) or
ForAll( [ G, H ], IsCongruenceSubgroupGammaUpper1 ) then
return LevelOfCongruenceSubgroup(G)=LevelOfCongruenceSubgroup(H);
elif ForAll( [ G, H ], IsIntersectionOfCongruenceSubgroups ) then
# we use the canonical ordering of subgroups
# in the intersection of congruence subgroups
if Length(DefiningCongruenceSubgroups(G)) <>
Length(DefiningCongruenceSubgroups(H)) then
return false;
else
return ForAll( [ 1 .. Length(DefiningCongruenceSubgroups(G)) ], i ->
CanEasilyCompareCongruenceSubgroups(
DefiningCongruenceSubgroups(G)[i],
DefiningCongruenceSubgroups(H)[i]) );
fi;
else
return false;
fi;
end);
#############################################################################
#
# CanReduceIntersectionOfCongruenceSubgroups( G, H )
#
# This function mimics the structure of the method for Intersection for
# congruence subgroups. It returns true, if their intersection can be reduced
# to one of the canonical congruence subgroups, and false otherwise, i.e. the
# intersection can be expressed only as IntersectionOfCongruenceSubgroups.
# This is used in IntersectionOfCongruenceSubgroups to reduce the list of
# canonical subgroups forming the intersection.
#
InstallMethod( CanReduceIntersectionOfCongruenceSubgroups,
"for two congruence subgroups",
[ IsCongruenceSubgroup, IsCongruenceSubgroup ],
function( G, H )
#
# Case 1 - at least one subgroup is an intersection of congruence subgroups
#
if IsIntersectionOfCongruenceSubgroups(G) or
IsIntersectionOfCongruenceSubgroups(H) then
return false;
#
# Case 2 - the diagonal (both subgroups has the same type)
#
elif IsPrincipalCongruenceSubgroup(G) and IsPrincipalCongruenceSubgroup(H) then
return true;
elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma1(H) then
return true;
elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper1(H) then
return true;
elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma0(H) then
return true;
elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper0(H) then
return true;
#
# Case 3 - Subgroups has different level
#
elif LevelOfCongruenceSubgroup(G) <> LevelOfCongruenceSubgroup(H) then
return false;
#
# Now subgroups have the same level
#
elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma0(H) then
return true;
elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma1(H) then
return true;
elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper0(H) then
return true;
elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper1(H) then
return true;
elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGammaUpper0(H) or IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGamma0(H) then
return false;
else
return true;
fi;
end);
#############################################################################
#
# NumeratorOfGFSElement( gfs, i )
#
# Returns the numerator of the i-th term of the generalised Farey sequence
# gfs: for the 1st infinite entry returns -1, for the last one returns 1,
# for all other entries returns usual numerator.
#
InstallGlobalFunction( "NumeratorOfGFSElement",
function(gfs,i)
if i in [ 2 .. Length(gfs)-1 ] then
return NumeratorRat( gfs[i] );
elif i=1 then
return -1; # infinity on the left
elif i=Length(gfs) then
return 1; # infinity on the right
else
Error("There is no entry number ", i, " in <gfs> !!! \n");
fi;
end);
#############################################################################
#
# DenominatorOfGFSElement( gfs, i )
#
# Returns the denominator of the i-th term of the generalised Farey sequence
# gfs: for both infinite entries returns 0, for the other ones returns usual
# denominator.
#
InstallGlobalFunction( "DenominatorOfGFSElement",
function(gfs,i)
if i in [ 2 .. Length(gfs)-1 ] then
return DenominatorRat( gfs[i] );
elif i=1 or i=Length(gfs) then
return 0;
else
Error("There is no entry number ", i, " in <gfs> !!! \n");
fi;
end);
#############################################################################
#
# IsValidFareySymbol( fs )
#
# This function is used in FareySymbolByData to validate its output
#
InstallGlobalFunction( "IsValidFareySymbol" ,
function( fs )
local gfs, labels, n, i, t;
gfs := GeneralizedFareySequence(fs);
labels := LabelsOfFareySymbol(fs);
n := Length(gfs);
if ForAny( [ 1 .. Length(labels) ], t -> not IsBound(labels[t] ) ) then
Error("<labels> must not contain holes !!! \n");
fi;
if Length(labels)<>n-1 then
Error("Lengths of <gfs> and <labels> do not match !!! \n");
fi;
if gfs[1]<>infinity or gfs[n]<>infinity then
Error("First and last elements of <gfs> must be infinity !!! \n");
fi;
if not 0 in gfs then
Error("<gfs> must contain at least one zero element !!! \n");
fi;
for i in [ 1 .. n-1 ] do
if NumeratorOfGFSElement(gfs,i+1) * DenominatorOfGFSElement(gfs,i) -
NumeratorOfGFSElement(gfs,i) * DenominatorOfGFSElement(gfs,i+1) <> 1 then
Error("a", i+1, "*b", i, " - a", i, "*b", i+1, " <> 1 !!! \n");
fi;
od;
if ForAny( Collected(labels), t -> IsInt(t[1]) and t[2]<>2 ) then
Error("<labels> are not properly paired !!! \n");
fi;
return true;
end);
#############################################################################
#
# MatrixByEvenInterval( gfs, i )
#
InstallGlobalFunction( "MatrixByEvenInterval",
function(gfs,i)
local ai, bi, ai1, bi1;
ai := NumeratorOfGFSElement(gfs,i);
bi := DenominatorOfGFSElement(gfs,i);
ai1 := NumeratorOfGFSElement(gfs,i+1);
bi1 := DenominatorOfGFSElement(gfs,i+1);
return [ [ ai1*bi1 + ai*bi, -ai^2 - ai1^2 ],
[ bi^2 + bi1^2, -ai1*bi1 - ai*bi ] ];
end);
#############################################################################
#
# MatrixByOddInterval( gfs, i )
#
InstallGlobalFunction( "MatrixByOddInterval",
function(gfs,j)
local aj, bj, aj1, bj1;
aj := NumeratorOfGFSElement(gfs,j);
bj := DenominatorOfGFSElement(gfs,j);
aj1 := NumeratorOfGFSElement(gfs,j+1);
bj1 := DenominatorOfGFSElement(gfs,j+1);
return [ [ aj1*bj1 + aj*bj1 + aj*bj, -aj^2 - aj*aj1 - aj1^2 ],
[ bj^2 + bj*bj1 + bj1^2, -aj1*bj1 - aj1*bj - aj*bj ] ];
end);
#############################################################################
#
# MatrixByFreePairOfIntervals( gfs, k, kp )
#
InstallGlobalFunction( "MatrixByFreePairOfIntervals",
function(gfs,k,kp)
local ak, bk, ak1, bk1, akp, bkp, akp1, bkp1;
ak := NumeratorOfGFSElement(gfs,k);
bk := DenominatorOfGFSElement(gfs,k);
ak1 := NumeratorOfGFSElement(gfs,k+1);
bk1 := DenominatorOfGFSElement(gfs,k+1);
akp := NumeratorOfGFSElement(gfs,kp);
bkp := DenominatorOfGFSElement(gfs,kp);
akp1 := NumeratorOfGFSElement(gfs,kp+1);
bkp1 := DenominatorOfGFSElement(gfs,kp+1);
return [ [ akp1*bk1 + akp*bk, -akp*ak - akp1*ak1 ],
[ bkp*bk + bkp1*bk1, -ak1*bkp1 - ak*bkp ] ];
end);
#############################################################################
##
#E
##