File: factor.g

package info (click to toggle)
gap-congruence 1.2.7-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 928 kB
  • sloc: xml: 1,000; javascript: 155; makefile: 108
file content (259 lines) | stat: -rw-r--r-- 7,911 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#############################################################################
##
#W factor.gi               The Congruence package              Helena Verrill
##
##
#############################################################################

# it will be useful to find the maximum value of the labels
# though if space is not a problem, this could just return
# the Length of the labels.

__congruence_max_label:= function(L)
  local s, i;
  s:=1;
  for i in [1..Length(L)] do
    if (not L[i] = "even") and (not L[i] = "odd")  and  L[i] > s then
       s := L[i];
    fi;
  od;
  return s;
end;;

# For a list of labels L such as
# [1,3,4,7,4,7,3,1,"odd","even"], for reference, indices are:
#  1 2 3 4 5 6 7 8  9     10
# want to produce a list:
# [[9],[10],[1,8],[],[2,7],[3,5],...]
# this is the list of the form:
# [[all indices with L[x] = "odd"],[all indices with L[x] = "even"],
# [all indices with L[x] = 1], ....]

# assume L is a list of integers, or "odd" or "even".

__congruence_edgepairs := function(L)
  local max, pairs, i;
  pairs:=[];
  max:=__congruence_max_label(L);
  for i in [1..max+2] do
      pairs[i] := [];
  od;
  for i in [1..Length(L)] do
      if L[i]="odd" then
        Add(pairs[1],i);
      elif L[i]="even" then
        Add(pairs[2],i);
      else
        Add(pairs[L[i]+2],i);
      fi;
  od;
  return pairs;
end;;

# for each edge of a Farey Symbol, we compute the generator
# which maps that edge to another edge.
# (this is done at the same time as the fundamental
# domain is computed, but the data may not have been stored,
# and has to be recomputed; suggest change for a future version)

# this function gives "edge gluing matrices" as a number in the
# list of generators (gens); negative entries mean the inverse matrix,
# e.g., -5 would mean (5th generator)^(-1)
# (note, the list of labels in a Farey sequence says which edge is
# glued to which; -2 and -3 means there is an elliptic point order
# 2 or 3)
#
# the input is assumed to be a FareySymbol;
# another version of this function could take input to be the group
#
# Note, if the output of this function was
# stored as an attribute of the FareySymbol,
# then it would not have to be recomputed
#

__congruence_gluing_matrices := function(FS)
   local cusps, gens, label_list, glue_list, l, i, index, gfs, labels, matrix;
   # the following is a list of the cusps of the sequence,
   # and other data extracted from the FareySymbol
   gfs := GeneralizedFareySequence(FS);
   labels := LabelsOfFareySymbol(FS);
   gens := GeneratorsByFareySymbol( FS );
   # make a list of which edges have a given label:
   label_list := __congruence_edgepairs(labels);
   # the following list will be what is finally returned, 
   # a list of integers as described above.
   glue_list := [];
   # make list of which generator joins two edges,
   # in the non elliptic case
   for i in [3..Length(label_list)] do
      l := label_list[i];
      matrix := MatrixByFreePairOfIntervals( gfs, l[1], l[2] );
      index := PositionNthOccurrence( gens ,matrix,1);
      if index = "fail" then
        index := -PositionNthOccurrence(gens,matrix^(-1),1);
      fi;
      glue_list[l[1]] := index;
      glue_list[l[2]] := -index;
   od;
   # Now deal with elliptic elements:
   for i in label_list[1] do
      matrix := MatrixByOddInterval( gfs, i );
      index := PositionNthOccurrence(gens,matrix,1);
      if index = "fail" then
         index := -PositionNthOccurrence(gens,matrix^(-1),1);
         glue_list[i] := -index;
      else
         glue_list[i] := -index;
      fi;
   od;
   for i in label_list[2] do
      matrix := MatrixByEvenInterval( gfs, i );
      index := PositionNthOccurrence(gens,matrix,1);
      if index = "fail" then
         index := -PositionNthOccurrence(gens,matrix^(-1),1);
         glue_list[i] := -index;
      else
         glue_list[i] := -index;
      fi;
   od;
   return glue_list;     
end;;

# following function determines which edge an image ImL of
# a domain is the longest
#
# The function either returns a index of an edge
# which is a number between 1 and #L-1,
# or it returns "overlap" meaning that there is overlap, but not equality.

__congruence_longest_edge := function(ImL)
   local i, minImL, maxImL, maxindex, minindex;
   for i in [1..Length(ImL)] do
      if ImL[i] = infinity then
        return "infinity";
      fi; 
   od;
   minImL := Minimum(ImL);
   maxImL := Maximum(ImL);
   maxindex := PositionNthOccurrence( ImL ,maxImL,1);
      return maxindex;
end;;

# Need to be able to apply action of matrices to cusps

__congruence_fractionallineartransformation:= function(g,c)
  local den, num;
  if c = infinity then
    if g[2][1] = 0 then
      return infinity;
    else    
      return g[1][1]/g[2][1];
    fi;  
  else
    num:=g[1][1]*c + g[1][2];
    den:=g[2][1]*c + g[2][2];
    if den = 0 then
      return infinity;
    else
      return num/den;
    fi;
  fi;
end;;

__congruence_PSL2multiply := function(g,L)
  local imL, i;
  imL := [];
  for i in [1..Length(L)] do
    Add(imL,__congruence_fractionallineartransformation(g,L[i]));
  od;
  return imL;
end;;

# this an algorithm to determine a word for
# a given matrix g in G in terms of the generators:

find_word_ver2 := function(FS,glue_list,g)
   local gens, L, ImL, done, word,letter,i, edge, h, maybesame, inf;
   gens := GeneratorsByFareySymbol( FS );
   L := GeneralizedFareySequence( FS );
   ImL := __congruence_PSL2multiply(g,L);
   word:=[];
   h := g;
   done := false;
   while not done do;      
      edge := __congruence_longest_edge(ImL);
      if edge = "infinity" then
         # check equality of L and ImL:
         maybesame := true;
         i := 1;
         while i < Length(L) and maybesame do
            if not L[i] = ImL[i] then
              maybesame := false;
            fi;
            i := i+1;
         od;
         if maybesame then
            done := true;
            return Reversed(word);
         fi;         
         # now assume the domains are not equal
         inf := PositionNthOccurrence( ImL , infinity ,1);
         if inf = 1 and
            ImL[2]<L[Length(L)-1] and
            ImL[Length(L)-1]>L[2] then              
            return "g is not in the group";
         elif
            ImL[i+1]<L[Length(L)-1] and
            ImL[i-1]>L[2] then              
            return "g is not in the group";
         fi;
         # now assume the domains do not overlap
         if ImL[inf+1] >= L[2] then
            letter := glue_list[inf];
         elif inf = 1 then
            letter := glue_list[Length(glue_list)];
         else
            letter := glue_list[inf-1];
         fi;
         Add(word,letter);
         h:=h*gens[AbsoluteValue(letter)]^(-SignInt(letter));
         ImL := __congruence_PSL2multiply(h,L);
      else
         # get next "letter" in the word for the matrix:
         letter := glue_list[edge];
         Add(word,letter);
      h:=h*gens[AbsoluteValue(letter)]^(-SignInt(letter));
      ImL := __congruence_PSL2multiply(h,L);
      fi;
   od;
   return Reversed(word);
end;;


#############################################################################
#
# FactorizeMat( G, g )
#
__congruence_FactorizeMat := function( G, g )
return find_word_ver2( FareySymbol(G), 
                       __congruence_gluing_matrices(FareySymbol(G)),
                       g );
end;

#############################################################################
#
# CheckFactorizeMat(gens,word)
#
# the following function is for testing purposes:
# gens is a list of generators, "word" a sequence of integers, none 
# of which is bigger than the size of the list of generators.  
# a word [4,6,-3] will return the product gens[4]*gens[6]*gens[3]^(-1)
#
__congruence_CheckFactorizeMat := function(gens,word)
local g, i;
g := [[1,0],[0,1]];
for i in word do
  g := g*gens[AbsoluteValue(i)]^SignInt(i);
od;
return g;
end;