############################################################################# ## ## FareySymbolByData( <gfs>, <labels> ) ## ## This constructor creates Farey symbol with the given generalized Farey ## sequence and list of labels. It also checks conditions from the definition ## of Farey symbol and returns an error if they are not satisfied ##
InstallMethod( FareySymbolByData, "for two lists that are g.F.S. and labels for Farey symbol",
[ IsList, IsList ], 0, function( gfs, labels)
local fs;
fs :=Objectify( NewType( NewFamily("FareySymbolsFamily", IsFareySymbol),
IsFareySymbol), [ gfs, labels ] ); if IsValidFareySymbol(fs) then
return fs; else
Error("<fs> is not a valid Farey symbol !!! \n"); fi; end);
############################################################################# ## ## GeneralizedFareySequence( <fs> ) ## LabelsOfFareySymbol( <fs> ) ## ## The data used to create the Farey symbol are stored as its attributes ##
InstallMethod( GeneralizedFareySequence, "for Farey symbol in default representation",
[ IsFareySymbol ],
fs -> fs![1]);
InstallMethod( LabelsOfFareySymbol, "for Farey symbol in default representation",
[ IsFareySymbol ],
fs -> fs![2] );
############################################################################# ## ## FareySymbol( <G> ) ## ## For a subgroup of a finite index G, this attribute stores the ## corresponding Farey symbol. The algorithm for its computation must work ## with any matrix group for which the membership test is available ##
InstallMethod( FareySymbol, "for a congruence subgroup",
[ IsCongruenceSubgroup ], 0, function( G )
local gfs, # generalized Farey sequence (g.F.S.)
labels, # labels of this g.F.S.
fs, # resulting Farey symbol
i, j, k, t, # counters
stepnr, # number of the inductive ste
newvertex, # new vertex to be inserted on the current inductive step
unpairednr, # number of the 1st vertex of the unpaired side
lastlabel, # last used label
mat, # matrix by free pair of intervals
unpairednumbers, # list of positions with assigned labels
denominators, # denominators of current g.F.S. elements
possibledenominators, # list of denominators arising from these positions
minden, # minimum of possible denominators
pos, # chosen position of minden in possibledenominators
nrlabels, # number of labels assigned
range1, # range for the search of odd and even labels
range2, # range for the search of free (i.e.numerical) labels
isfirstlabelssearch; # flag for determining of the range1 and range2 # # Initial data setup # if LevelOfCongruenceSubgroup(G)=1then
return FareySymbolByData( [ infinity, 0, infinity ], ["even","odd"]) ; fi;
gfs := [ infinity, 0, infinity ];
labels:=[];
nrlabels:=0;
stepnr:=0;
lastlabel:=0;
isfirstlabelssearch:=true; # # we perform the next loop until we will have fully labeled gfs # while nrlabels < Length( gfs ) - 1do
stepnr:=stepnr+1;
Info( InfoCongruence, 2, "Step ", stepnr, " : g.F.S. of length ", Length(gfs), " with ", nrlabels, " labels");
Info( InfoCongruence, 3, " gfs = ", gfs );
Info( InfoCongruence, 3, "labels = ", labels ); # # 1. Choose any of the unpaired sides and insert new vertex # # 1.1. Find unpaired side that will give us a new vertex # with the minimal denominator (on the first step we # do some trick to get [infinity,0,1,infinity])
unpairednumbers := Filtered( [ 1 .. Length(gfs)-1 ], i ->
not IsBound( labels[ i ] ) );
Info( InfoCongruence, 3, "Positions of unpaired labels : ", unpairednumbers ); # to avoid repeated calls of DenominatorOfGFSElement, we are caching # values of denominators from required positions
denominators := []; for i in unpairednumbers do if not IsBound(denominators[i]) then
denominators[i]:=DenominatorOfGFSElement(gfs,i); fi;
denominators[i+1]:=DenominatorOfGFSElement(gfs,i+1);
od;
possibledenominators := List( unpairednumbers, i ->
denominators[i] + denominators[i+1] );
Info( InfoCongruence, 3, "Possible denominators : ", possibledenominators );
minden := Minimum(possibledenominators); # we give priority to positive numbers in g.F.S.
pos:=PositionProperty( [ 1 .. Length(unpairednumbers) ], i ->
( possibledenominators[i] = minden ) and
( NumeratorOfGFSElement( gfs, unpairednumbers[i] ) >=0 ) ); if pos=fail then
pos:=PositionProperty( [ 1 .. Length(unpairednumbers) ], i ->
possibledenominators[i] = minden ); fi;
unpairednr := unpairednumbers[ pos ]; #i:=1; #repeat # pos := PositionNthOccurrence( possibledenominators, minden, i ); # i := i+1; # unpairednr := unpairednumbers[ pos ]; #until NumeratorOfGFSElement(gfs, unpairednr) >= 0; # # 1.2. Compute new vertex by the Farey sequence rule #
newvertex := ( NumeratorOfGFSElement(gfs, unpairednr) +
NumeratorOfGFSElement(gfs, unpairednr+1) ) / minden; # # 1.3. Insert this new vertex and an empty spot for the label #
Info( InfoCongruence, 2, "Inserting ", newvertex, " at position ", unpairednr+1);
Add( gfs, newvertex, unpairednr+1);
Add( unpairednumbers, unpairednr, pos ); for i in [ pos+1 .. Length(unpairednumbers) ] do
unpairednumbers[i] := unpairednumbers[i]+1;
od;
Add( labels, "hole" , unpairednr );
Unbind(labels[unpairednr]); # # 2. For each of new sides, we check if they are paired and # assign labels, if this is the case # if isfirstlabelssearch then
range1 := [ 1 .. Length(gfs)-1 ];
range2 := [ 1 .. Length(gfs)-1 ]; else # if we already checked all cases for all possible labels, # on each new step it is enough to check only new intervals
range1 := [ unpairednr, unpairednr+1 ]; # Slower but more obvious options for range2 could be: # range2 := [ 1 .. Length(gfs)-1 ]; # range2:= Filtered( [ 1 .. Length(gfs)-1 ], i -> not IsBound( labels[ i ] ) ); # but we use the fastest one
range2 := unpairednumbers; fi; if not ( IsPrincipalCongruenceSubgroup(G) and
LevelOfCongruenceSubgroup(G) > 2 ) then for i in range1 do # we do not check that labels[i] is not bound because this is # guaranteed by the algorithm
mat := MatrixByOddInterval( gfs, i ); if mat in G or -mat in G then
labels[i]:="odd";
nrlabels:=nrlabels+1;
Info( InfoCongruence, 2, "Putting label ", lastlabel, " at position ", i ); else
mat := MatrixByEvenInterval( gfs, i ); if mat in G or -mat in G then
labels[i]:="even";
nrlabels:=nrlabels+1;
Info( InfoCongruence, 2, "Putting label ", lastlabel, " at position ", i ); fi; fi;
od; fi; for i in range1 do for j in range2 do # we eliminate the case i=j since we always check different intervals # now we check that both labels[i] and labels[j] are not bound for a case # if they were already assigned during the search for odd/even labels if i<>j and not IsBound( labels[i] ) and not IsBound( labels[j] ) then
mat := MatrixByFreePairOfIntervals( gfs, i, j ); if mat in G or -mat in G then
lastlabel := lastlabel+1;
labels[i]:=lastlabel;
labels[j]:=lastlabel;
nrlabels:=nrlabels+2;
Info( InfoCongruence, 2, "Putting label ", lastlabel, " at positions ", i, " and ", j ); # since i-th interval can be paired only with one j-th interval, # we quit from inner loop and go to the next i
break; fi; fi;
od;
od;
isfirstlabelssearch:=false; if stepnr mod 25000 = 0then
Error("You reached the checkpoint on the ", stepnr, "th iteration \n", "Currently you have g.F.S. of length ", Length(gfs), " with ", nrlabels, " labels assigned \n", "Use the index of the subgroup to get an idea about possible length of the g.F.S.:\n", "it will be equal to the index of <G> in PSL_2Z minus the number of odd intervals in g.F.S.\n"); fi;
od;
fs := FareySymbolByData( gfs, labels) ;
return fs; end);
############################################################################# # # GeneratorsByFareySymbol( fs ) #
InstallGlobalFunction( GeneratorsByFareySymbol, function( fs )
local gfs, labels, usedlabels, gens, i, j, m;
gfs := GeneralizedFareySequence(fs);
labels := LabelsOfFareySymbol(fs);
usedlabels:=[];
gens:=[]; for i in [ 1 .. Length(labels) ] do if labels[i]="even"then
Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i] );
m := MatrixByEvenInterval( gfs, i );
Add( gens, m ); if InfoLevel( InfoCongruence ) = 2then
Display(m); fi; elif labels[i]="odd"then
Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i] );
m := MatrixByOddInterval( gfs, i );
Add( gens, m ); if InfoLevel( InfoCongruence ) = 2then
Display(m); fi; elif not labels[i] in usedlabels then
j := PositionNthOccurrence( labels, labels[i], 2 );
Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i], " = labels[", j, "]" );
m := MatrixByFreePairOfIntervals( gfs, i, j );
Add( gens, m );
Add( usedlabels, labels[i] ); if InfoLevel( InfoCongruence ) = 2then
Display(m); fi; fi;
od;
return gens; end);
############################################################################# # # IndexInPSL2ZByFareySymbol( fs ) # # By the proposition 7.2 [Kulkarni], for the Farey symbol with underlying # generalized Farey sequence { infinity, x0, x1, ..., xn, infinity }, the # index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the # number of odd intervals. #
InstallGlobalFunction( IndexInPSL2ZByFareySymbol, function( fs )
local n, e3, x, d;
n := Length( GeneralizedFareySequence(fs) ) - 3;
e3:= Number( LabelsOfFareySymbol(fs), x -> x = "odd" );
d := 3 * n + e3;
return d; end);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.