############################################################################# ## #W unitri.gi Polycyclic Werner Nickel ##
InfoMatrixNq := Ignore;
## ## Test if a matrix is the identity matrix. ## ## For non-identity matrices this is faster than comparing with an identity ## matrix. ##
InstallGlobalFunction( "IsIdentityMat", function( M )
local zero, one, i, j;
zero := Zero( M[1][1] );
one := zero + 1;
if Set( List( M, Length ) ) <> [Length(M)] then
return false; fi;
for i in [1..Length(M)] do if M[i][i] <> one then return false; fi; for j in [i+1..Length(M)] do if M[i][j] <> zero then return false; fi; if M[j][i] <> zero then return false; fi;
od;
od;
return true; end );
## ## Test if a matrix is upper triangular with 1s on the diagonal. ##
InstallGlobalFunction( "IsUpperUnitriMat", function( M )
local one, i;
one := One( M[1][1] ); if not IsUpperTriangularMat( M ) then return false; fi;
for i in [1..Length(M)] do if M[i][i] <> one then return false; fi;
od;
return true; end );
## ## The weight of an upper unitriangular matrix is the number of diagonals ## above the main diagonal that contain only zeroes. ##
InstallGlobalFunction( "WeightUpperUnitriMat", function( M )
local n, s, i, w;
n := Length(M); w := 0; s := 1; while s < n do
s := s+1; for i in [1..n-s+1] do if M[i][i+s-1] <> 0then return w; fi;
od;
w := w+1;
od;
return w; end );
## ## UpperDiagonal() returns the <s>-th diagonal above the main diagonal of ## the matrix <M>. ##
InstallGlobalFunction( "UpperDiagonalOfMat", function( M, s )
local d, i;
d := []; for i in [1..Length(M)-s] do d[i] := M[i][i+s]; od;
return d; end );
## ## Initialise a new level for the recursive sifting structure. ## ## At each level we store matrices of the apprpriate weight and for each ## matrix its inverse and the diagonal of the correct weight. ##
InstallGlobalFunction( "MakeNewLevel", function( w )
## ## When a matrix was added to a level of the sifting structure, then ## commutators with this matrix and the generators of the group have to be ## computed and sifted in order to keep the sifting structure from this ## level on closed under taking commutators. ## ## This function computes the necessary commutators and sifts each of ## them. ##
InstallGlobalFunction( "FormCommutators", function( gens, level, j )
local C, Mj, i;
InfoMatrixNq( "#I Forming commutators on level ", level.weight, "\n" );
Mj := level.matrices[j]; for i in [1..Length(gens)] do
C := Comm( Mj,gens[i] ); if not IsIdentityMat(C) then if not IsBound( level.nextlevel ) then
level.nextlevel := MakeNewLevel( level.weight+1 ); fi;
SiftUpperUnitriMat( gens, level.nextlevel, C ); fi;
od;
return; end );
## ## Sift the unitriangular matrix <M> through the recursive sifting ## structure <level>. It is assumed that the weight of <M> is equal to or ## larger than the weight of <level>. ## ## This function checks, if there is a matrix N at this level such that M ## N^k for suitable k has higher weight than M. If N does not exist, M is ## added to <level> and all commutators of M with the generators of the ## group are formed and sifted. If there is such a matrix N, then M N^k ## is sifted through the next level. ##
InstallGlobalFunction( "SiftUpperUnitriMat", function( gens, level, M )
local w, d, h, r, R, Ri, c, rr, RR;
w := WeightUpperUnitriMat( M ); if w > level.weight then if not IsBound( level.nextlevel ) then
level.nextlevel := MakeNewLevel( level.weight+1 ); fi;
SiftUpperUnitriMat( gens, level.nextlevel, M );
return; fi;
InfoMatrixNq( "#I Sifting at level ", level.weight, " with " );
d := UpperDiagonalOfMat( M, w+1 );
h := 1; while h <= Length(d) and d[h] = 0do h := h+1; od;
while h <= Length(d) do if IsBound(level.diags[h]) then
r := level.diags[ h ];
R := level.matrices[ h ];
Ri := level.inverses[ h ];
c := Int( d[h] / r[h] );
InfoMatrixNq( " ", c ); if c <> 0then
d := d - c * r; if c > 0then M := Ri^c * M; else M := R^(-c) * M; fi; fi;
rr := r; r := d; d := rr;
RR := R; R := M; M := RR; while r[h] <> 0do
c := Int( d[h] / r[h] );
InfoMatrixNq( " ", c ); if c <> 0then
d := d - c * r;
M := R^(-c) * M; fi;
rr := r; r := d; d := rr;
RR := R; R := M; M := RR;
od; if d <> level.diags[ h ] then
level.diags[ h ] := d;
level.matrices[ h ] := M;
level.inverses[ h ] := M^-1;
InfoMatrixNq( "\n" );
FormCommutators( gens, level, h );
InfoMatrixNq( "#I continuing reduction on level ", level.weight, " with " ); fi;
d := r;
M := R; else
level.matrices[ h ] := M;
level.inverses[ h ] := M^-1;
level.diags[ h ] := d;
InfoMatrixNq( "\n" );
FormCommutators( gens, level, h );
return; fi; while h <= Length(d) and d[h] = 0do h := h+1; od;
od;
InfoMatrixNq( "\n" );
if WeightUpperUnitriMat(M) < Length(M)-1then if not IsBound( level.nextlevel ) then
level.nextlevel := MakeNewLevel( level.weight+1 ); fi;
SiftUpperUnitriMat( gens, level.nextlevel, M ); fi; end );
## ## The subgroup U of GL(n,Z) of upper unitriangular matrices is a ## nilpotent group. The n-th term of the lower central series of U ## consists of all unitriangular matrices of weight at least n-1. This ## defines a filtration on each subgroup of U. ## ## This function computes this filtration for the unitriangular matrix ## group G. ##
InstallGlobalFunction( "SiftUpperUnitriMatGroup", function( G )
local firstlevel, g;
firstlevel := MakeNewLevel( 0 ); for g in GeneratorsOfGroup(G) do
SiftUpperUnitriMat( GeneratorsOfGroup(G), firstlevel, g );
od;
return firstlevel; end );
## ## Return the Z-ranks of the level of the sifting structure. ##
InstallGlobalFunction( "RanksLevels", function( L )
local ranks;
ranks := [];
Add( ranks, Length( Filtered( L.diags, x->IsBound(x) ) ) ); while IsBound( L.nextlevel ) do
L := L.nextlevel;
Add( ranks, Length( Filtered( L.diags, x->IsBound(x) ) ) );
od;
return ranks; end );
## ## This function decomposes the given matrix <M> into the generators of ## the sifting structure <level>. ##
InstallGlobalFunction( "DecomposeUpperUnitriMat", function( level, M )
local w, d, h, r, R, c;
InfoMatrixNq( "#I Decomposition on level ", level.weight, "\n" );
w := WeightUpperUnitriMat(M); if w = Length(M[1])-1then return []; fi; if w > level.weight then if not IsBound( level.nextlevel ) then return false; fi;
return DecomposeUpperUnitriMat( level.nextlevel, M ); fi;
w := [];
d := UpperDiagonalOfMat( M, WeightUpperUnitriMat(M)+1 );
h := 1; while h <= Length(d) and d[h] = 0do h := h+1; od;
while h <= Length(d) do if not IsBound( level.diags[ h ] ) then return false; fi;
r := level.diags[ h ];
R := level.matrices[ h ]; if d[h] mod r[h] <> 0then return false; fi;
c := Int( d[h] / r[h] );
d := d - c * r;
M := R^(-c) * M;
Add( w, [[level.weight, h], c] );
InfoMatrixNq( "#I gen: ", h );
InfoMatrixNq( " coeff: ", c, "\n" ); while h <= Length(d) and d[h] = 0do h := h+1; od;
od;
if not IsIdentityMat( M ) then if not IsBound( level.nextlevel ) then return false; fi;
h := DecomposeUpperUnitriMat( level.nextlevel, M ); if h = false then return false; fi;
return Concatenation( w,h ); fi;
return w; end );
##
InstallGlobalFunction( "PolycyclicGenerators", function( L )
local matrices, gens, i, l;
matrices := Compacted( L.matrices );
gens := []; for i in [1..Length(L.diags)] do if IsBound( L.diags[i] ) then Add( gens, [L.weight,i] ); fi;
od;
l := L; while IsBound( l.nextlevel ) do
l := l.nextlevel;
Append( matrices, Compacted( l.matrices ) );
for i in [1..Length(l.diags)] do if IsBound( l.diags[i] ) then Add( gens, [l.weight,i] ); fi;
od;
InstallGlobalFunction( "WordPolycyclicGens", function( gens, w )
local r, g;
r := ShallowCopy(w); for g in r do
g[1] := Position( gens.gens, g[1] );
od;
return Flat( r ); end );
InstallGlobalFunction( "PresentationMatNq", function( L )
local matrices, gens, i, l, rels, j, r, g;
matrices := Compacted( L.matrices );
gens := []; for i in [1..Length(L.diags)] do if IsBound( L.diags[i] ) then Add( gens, [L.weight,i] ); fi;
od;
l := L; while IsBound( l.nextlevel ) do
l := l.nextlevel;
Append( matrices, Compacted( l.matrices ) );
for i in [1..Length(l.diags)] do if IsBound( l.diags[i] ) then Add( gens, [l.weight,i] ); fi;
od;
od;
rels :=[]; for j in [1..Length(matrices)] do
rels[j] := []; for i in [1..j-1] do
r := DecomposeUpperUnitriMat( L,Comm( matrices[j],matrices[i] ) ); for g in r do
g[1] := Position( gens, g[1] );
od;
rels[j][i] := r;
od;
od;
s := "< "; for i in P.generators do
Append(s,x); Append(s,String(i)); Append(s,",");
od;
Unbind( s[ Length(s) ] ); # remove trailing comma
Append( s, " | \n" );
for j in P.generators do for i in [1..j-1] do
r := P.relators[j][i];
Append( s, " " );
Append( s, CommString( j, i ) ); if r <> [] then Append( s, " = " ); fi; for g in r do
Append( s, PowerString(g) );
od; # remove trailing asterisk if s[ Length(s) ] = '*'then Unbind( s[ Length(s) ] ); fi;
Append( s, ",\n" );
od;
od;
Unbind( s[ Length(s) ] );
Unbind( s[ Length(s) ] ); # remove trailing comma & newline
Append( s, "\n>\n" );
return s; end );
InstallGlobalFunction( "CollectorByMatNq", function( levels )
local pres, n, coll, j, i;
pres := PresentationMatNq( levels );
n := Length( pres.generators );
coll := FromTheLeftCollector( n );
for j in [1..n] do for i in [1..j-1] do if IsBound( pres.relators[j][i] ) and
pres.relators[j][i] <> [] then
SetCommutator( coll, j, i, Flat( pres.relators[j][i] ) ); fi;
od;
od;
UpdatePolycyclicCollector( coll );
return coll; end );
InstallGlobalFunction( "IsomorphismUpperUnitriMatGroupPcpGroup", function( G )
local levs, pcgens, coll, H, images, M, w, phi;
levs := SiftUpperUnitriMatGroup( G );
pcgens := PolycyclicGenerators( levs );
coll := CollectorByMatNq( levs );
H := PcpGroupByCollectorNC( coll );
images := []; for M in GeneratorsOfGroup( G ) do
w := DecomposeUpperUnitriMat( levs, M );
w := WordPolycyclicGens( pcgens, w );
Add( images, PcpElementByGenExpListNC( coll, w ) );
od;
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.