############################################################################# ## #W series.gi POLENTA package Bjoern Assmann ## ## Methods for the calculation of ## radical series, homogeneous series and composition series of matrix groups ## #Y 2003 ##
############################################################################# ## #F POL_SplitSemisimple( base ) ##
POL_SplitSemisimple := function( base )
local d, b, f, s, i;
d := Length( base );
b := PrimitiveAlgebraElement( [ ], base );
f := Factors( b.poly ); if Length( f ) = 1then
return [ rec(
basis := IdentityMat( Length( b.elem ) ),
poly := f ) ]; fi;
s := List( f,
x -> NullspaceRatMat( Value( x, b.elem ) )
);
s := List( [ 1 .. Length( f ) ],
x -> rec( basis := s[x], poly := f[x] )
);
return s; end;
############################################################################# ## #F RadicalOfAbelianRMGroup( mats, d ) ## ## <mats> is an abelian rational matrix group ##
RadicalOfAbelianRMGroup := function( mats, d )
local coms, i, j, new, base, full, nath, indm, l, algb, newv, tmpb, subb,
f, g, h, mat;
base := [];
full := IdentityMat( d ); # nath is the natural hom. from V to V/W
nath := NaturalHomomorphismBySemiEchelonBases( full, base ); # indm for induced matrices
indm := mats;
# start spinning up basis and look for nilpotent elements
i := 1;
algb := []; while i <= Length( indm ) do
# add next element to algebra basis
l := Length( algb );
newv := Flat( indm[i] );
tmpb := SpinnUpEchelonBase(algb, [newv], indm{[1..i]},OnMatVector );
# check whether we have added a non-semi-simple element
subb := []; for j in [l+1..Length(tmpb)] do
mat := MatByVector( tmpb[j], Length(indm[i]) );
f := MinimalPolynomial( Rationals, mat );
g := Collected( Factors( f ) ); if ForAny( g, x -> x[2] > 1 ) then
h := Product( List( g, x -> Value( x[1], mat ) ) );
Append( subb, List( h, x -> ShallowCopy(x) ) ); fi;
od; #Print("found nilpotent submodule of dimension ", Length(subb),"\n");
# spin up new subspace of radical
subb := SpinnUpEchelonBase( [], subb, indm, OnRight ); if Length( subb ) > 0then
base := PreimageByNHSEB( subb, nath ); if Length( base ) = d then # radical cannot be so big
return fail; fi;
nath := NaturalHomomorphismBySemiEchelonBases( full, base );
indm := List( mats, x -> InducedActionFactorByNHSEB( x, nath ) );
algb := [];
i := 1; else
i := i + 1; fi;
od;
return rec( radical := base, nathom := nath, algebra := algb ); end;
############################################################################# ## #F POL_RadicalNormalGens( gens, mats, d ) ## ## ## mats are normal subgroup generators for the Kernel K_p in G =<gens> ## ## returned is ## radical .... a basis for the radical ## nathom ..... homomorphism for Q^d to Q^d/radical ## algebra .... basis for the algebra Q[K_p^G] in flat form ## where K_p and G are induced to Q^d/radical ##
POL_RadicalNormalGens := function( gens, mats, d )
local coms, i, j, new, base, full, nath, indm, l, algb,
newv, tmpb, subb, f, g, h, mat,k,a,left,inducedk,right,
commutes,extended,comElement,a2,y;
# get commutators # because Q^d ( k-1 ) \subset Rad, where k in the commutator # subgroup <mats>'
coms := []; for i in [1..Length( mats )] do for j in [i+1..Length( mats )] do
new := mats[i] * mats[j] - mats[j] * mats[i];
Append(coms, new );
od;
od;
# base is a basis for the module W, the radical
base := SpinnUpEchelonBase( [], coms, gens, OnRight ); if Length( base ) = d then # for a radical to big
return fail; fi;
full := IdentityMat( d ); # nath is the natural hom. from V to V/W
nath := NaturalHomomorphismBySemiEchelonBases( full, base ); # indm for induced matrices
indm := List( mats, x -> InducedActionFactorByNHSEB( x, nath ) );
# start spinning up basis and look for nilpotent elements
i := 1;
algb := []; while i <= Length( indm ) do # check if the new element commutes with all elements in algb # if not we get a nontrivial element of the commutator
commutes:=true; for a in algb do
a2 := MatByVector( a, Length(indm[i]) );
left := indm[i]*a2;
right := a2*indm[i]; if not left=right then
commutes:=false;
break; fi;
od; # if it doesn't commute with all, spin up new subspace of # the radical
extended := false; if not commutes then
subb := left-right;
subb := SpinnUpEchelonBase( [], subb, indm, OnRight ); if Length( subb ) > 0then
base := PreimageByNHSEB( subb, nath ); # Rad_K_p(Q^d) = Rad_G(Q^d) # therefore <base> must be also a G-module
base := SpinnUpEchelonBase( [], base, gens, OnRight ); if Length( base ) = d then # radical cannot be so big
return fail; fi;
nath := NaturalHomomorphismBySemiEchelonBases( full, base );
indm := List( mats, x ->InducedActionFactorByNHSEB(x,nath ));
algb := [];
i := 1;
extended:=true; fi; fi; if not extended then # add next element to algebra basis
l := Length( algb );
newv := Flat( indm[i] );
tmpb := SpinnUpEchelonBase(algb, [newv], indm{[1..i]},
OnMatVector ); # close the basis under the conjugation action of G for k in gens do
inducedk:=InducedActionFactorByNHSEB(k,nath);
y:=indm[i]^inducedk;
newv:=Flat(y);
tmpb := SpinnUpEchelonBase( algb, [newv], indm{[1..i]},
OnMatVector );
od; # check whether we have added a non-semi-simple element
subb := []; for j in [l+1..Length(tmpb)] do
mat := MatByVector( tmpb[j], Length(indm[i]) );
f := MinimalPolynomial( Rationals, mat );
g := Collected( Factors( f ) ); if ForAny( g, x -> x[2] > 1 ) then
h := Product( List( g, x -> Value( x[1], mat ) ) );
Append( subb, List( h, x -> ShallowCopy(x) ) ); fi;
od; # spin up new subspace of radical
subb := SpinnUpEchelonBase( [], subb, indm, OnRight ); if Length( subb ) > 0then
base := PreimageByNHSEB( subb, nath ); # Rad_K_p(Q^d) = Rad_G(Q^d) # therefore <base> must be also a G-module
base := SpinnUpEchelonBase( [], base, gens, OnRight ); if Length( base ) = d then # radical cannot be so big
return fail; fi;
nath := NaturalHomomorphismBySemiEchelonBases( full, base );
indm := List( mats,x->InducedActionFactorByNHSEB( x, nath ));
algb := [];
i := 1; else
i := i + 1; fi; fi;
od;
return rec( radical := base, nathom := nath, algebra := algb ); end;
############################################################################# ## #F POL_HomogeneousSeriesNormalGens(gens, mats, d ) ## ## mats are normal subgroup generators for the Kernel K_p in G =<gens> ## returned is a homogeneous series of of K_p module Q^d ##
POL_HomogeneousSeriesNormalGens := function(gens, mats, d )
local radb, splt, nath,inducedgens, l, sers, i, sub, full, acts, rads;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := POL_RadicalNormalGens(gens, mats, d ); if radb = fail then return fail; fi;
splt := POL_SplitSemisimple( radb.algebra );
nath := radb.nathom;
# refine radical factor and initialize series
l := Length( splt ); for i in [2..l] do
sub := Concatenation( List( [i..l], x -> splt[x].basis ) );
TriangulizeMat( sub );
Add( sers, PreimageByNHSEB( sub, nath ) );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
inducedgens:=List( gens, x -> InducedActionSubspaceByNHSEB( x, nath ) );
# use recursive call to refine radical
rads := POL_HomogeneousSeriesNormalGens(inducedgens,acts,
Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_RadicalSeriesNormalGens(gens, mats, d ) ## ## mats are normal subgroup generators for the Kernel K_p in G=<gens>, ## which is a rational polycyclic matrix group. ## returned is a radical series of Q^d ##
POL_RadicalSeriesNormalGens := function(gens, mats, d )
local radb, splt, nath,inducedgens, l, sers, i, sub, full, acts, rads;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := POL_RadicalNormalGens(gens, mats, d ); if radb = fail then return fail; fi;
nath := radb.nathom;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
inducedgens:=List( gens, x -> InducedActionSubspaceByNHSEB( x, nath ) );
# use recursive call to refine radical
rads := POL_RadicalSeriesNormalGens(inducedgens,acts,
Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_RadicalSeriesNormalGensFullData(gens, mats, d ) ## ## mats are normal subgroup generators for the Kernel K_p in G=<gens>, ## which is a rational polycyclic matrix group. ## returned is a radical series of Q^d ## and full data of the used homomorphisms and algebras ##
POL_RadicalSeriesNormalGensFullData := function(gens, mats, d )
local radb, splt, nath,inducedgens, l, sers, i, sub, full, acts,
sersFullData, rads, radsFullData, record;
# catch the trivial case and set up if d = 0then
return rec( sers := [], sersFullData := [] ); fi;
full := IdentityMat( d ); if Length( mats ) = 0then
sers := [full, []];
sersFullData :=
[ rec(radical := [], nathom := [], algebra := []) ];
return rec( sers:= sers, sersFullData := sersFullData ); fi;
sers := [full];
# get the radical
radb := POL_RadicalNormalGens(gens, mats, d ); if radb = fail then return fail; fi;
nath := radb.nathom;
Add( sers, radb.radical );
sersFullData := [radb ];
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
inducedgens:=List( gens, x -> InducedActionSubspaceByNHSEB( x, nath ) );
# use recursive call to refine radical
record := POL_RadicalSeriesNormalGensFullData(inducedgens,acts,
Length(radb.radical) );
if record = fail then return fail; fi;
rads := record.sers;
radsFullData := record.sersFullData;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
Append( sersFullData , radsFullData );
############################################################################# ## #F RadicalSeriesAbelianRMGroup( mats, d ) ## ## G is an abelian rational matrix group ##
RadicalSeriesAbelianRMGroup := function( mats, d )
local radb, splt, nath, l, sers, i, sub, full, acts, rads;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := RadicalOfAbelianRMGroup( mats, d ); if radb = fail then return fail; fi;
nath := radb.nathom;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := RadicalSeriesAbelianRMGroup(acts, Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_HomogeneousSeriesAbelianRMGroup( mats, d ) ## ## <mats> is an abelian rational matrix group ##
POL_HomogeneousSeriesAbelianRMGroup := function( mats, d )
local radb, splt, nath,inducedgens, l, sers, i, sub, full, acts, rads;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := RadicalOfAbelianRMGroup( mats, d ); if radb = fail then return fail; fi;
splt := POL_SplitSemisimple( radb.algebra );
nath := radb.nathom;
# refine radical factor and initialize series
l := Length( splt ); for i in [2..l] do
sub := Concatenation( List( [i..l], x -> splt[x].basis ) );
TriangulizeMat( sub );
Add( sers, PreimageByNHSEB( sub, nath ) );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := POL_HomogeneousSeriesAbelianRMGroup( acts, Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F HomogeneousSeriesAbelianMatGroup( G ) ## ## <G> is an abelian rational matrix group ## # FIXME: This function is documented and should be turned into a GlobalFunction
HomogeneousSeriesAbelianMatGroup := function( G )
local mats,d; if not IsRationalMatrixGroup( G ) or not IsAbelian( G ) then
Print( "input must be an abelian rational matrix group.\n" );
return fail; fi;
mats := GeneratorsOfGroup( G );
d := Length( mats[1] );
return POL_HomogeneousSeriesAbelianRMGroup( mats, d ); end;
############################################################################# ## #F RadicalSeriesPRMGroup( G ) ## ## G is a rational polycyclic matrix group ##
RadicalSeriesPRMGroup := function( G )
local p,d,gens_p,bound_derivedLength,pcgs_I_p,gens_K_p,
radicalSeries,gens_K_p_m, gens, gens_K_p_mutableCopy;
gens := GeneratorsOfGroup( G );
d := Length(gens[1][1]);
# determine an admissible prime
p := DetermineAdmissiblePrime(gens);
Info( InfoPolenta, 1, "Chosen admissible prime: " , p );
Info( InfoPolenta, 1, " " );
# calculate the gens of the group phi_p(<gens>) where phi_p is # natural homomorphism to GL(d,p)
gens_p := InducedByField( gens, GF(p) );
# determine an upper bound for the derived length of G
bound_derivedLength := d+2;
Info( InfoPolenta, 1,"Determine a constructive polycyclic sequence\n", " for the image under the p-congruence homomorphism ..." );
pcgs_I_p := CPCS_finite_word( gens_p, bound_derivedLength ); if pcgs_I_p = fail then return fail; fi;
Info(InfoPolenta,1,"finished.");
Info( InfoPolenta, 1, "Finite image has relative orders ",
RelativeOrdersPcgs_finite( pcgs_I_p ), "." );
Info( InfoPolenta, 1, " " );
# compute the normal the subgroup gens. for the kernel of phi_p
Info( InfoPolenta, 1,"Compute normal subgroup generators for the kernel\n", " of the p-congruence homomorphism ...");
gens_K_p := POL_NormalSubgroupGeneratorsOfK_p( pcgs_I_p, gens );
gens_K_p := Filtered( gens_K_p, x -> not x = IdentityMat(d) );
Info( InfoPolenta, 1,"finished.");
Info( InfoPolenta, 2,"The normal subgroup generators are" );
Info( InfoPolenta, 2, gens_K_p );
Info( InfoPolenta, 1, " " );
# radical series
gens_K_p_mutableCopy := CopyMatrixList( gens_K_p );
radicalSeries := POL_RadicalSeriesNormalGens( gens,
gens_K_p_mutableCopy,
d ); if radicalSeries=fail then return fail; fi;
return radicalSeries; end;
############################################################################# ## #F POL_HomogeneousSeriesPRMGroup( G ) ## ## G is a rational polycyclic matrix group, ## returned is a homogeneous series of the natural K_p-module Q^d ##
POL_HomogeneousSeriesPRMGroup := function( G )
local p,d,gens_p,bound_derivedLength,pcgs_I_p,gens_K_p,
homSeries,gens_K_p_m, gens, gens_K_p_mutableCopy;
gens := GeneratorsOfGroup( G );
d := Length(gens[1][1]);
# determine an admissible prime
p := DetermineAdmissiblePrime(gens);
# calculate the gens of the group phi_p(<gens>) where phi_p is # natural homomorphism to GL(d,p)
gens_p := InducedByField( gens, GF(p) );
# determine an upper bound for the derived length of G
bound_derivedLength := d+2;
Info( InfoPolenta, 1,"determine a constructive polycyclic sequence");
Info( InfoPolenta, 1,"for the image under the p-congruence homomorph.");
pcgs_I_p := CPCS_finite_word( gens_p, bound_derivedLength );
Info( InfoPolenta, 1, "finite image has relative orders ",
RelativeOrdersPcgs_finite( pcgs_I_p ) );
# step 4
Info( InfoPolenta, 1, "compute the radical series \n");
gens_K_p_mutableCopy := CopyMatrixList( gens_K_p );
homSeries := POL_HomogeneousSeriesNormalGens( gens,
gens_K_p_mutableCopy,
d );
return homSeries; end;
############################################################################# ## #F POL_InducedActionToSeries (gens_K_p, radicalSeries) ## ## returns the action of the matrices in gens_K_p induced to the ## factors of radicalSeries ##
POL_InducedActionToSeries := function(gens_K_p,radicalSeries)
local action,blockGens,sizeOfBlock,d,homs,l,i,g,
actionParts,hom,image_of_g,c,a,j;
d:=Length(gens_K_p[1][1]);
homs:=[];
blockGens:=[];
l:=Length(radicalSeries)-1; for i in [1..l] do
radicalSeries[i] := SemiEchelonMat( radicalSeries[i] ).vectors; #TriangulizeMat( radicalSeries[i] ); # we cannot use TriangulizeMat, because # TriangulizeMat( radicalSeries[i] ) can change # radicalSeries[i+1]! Then radicalSeries[i+1] can fail to be # a module.
od; for i in [1..l] do
homs[i]:=NaturalHomomorphismBySemiEchelonBases( radicalSeries[i],
radicalSeries[i+1]);
od; for hom in homs do
actionParts:=[]; for g in gens_K_p do
action:=InducedActionFactorByNHSEB( g, hom );
Add(actionParts,action);
od;
Add(blockGens,actionParts);
od;
return blockGens; end;
############################################################################# ## #M RadicalSeriesSolvableMatGroup( G ) ## ## G is a matrix group over the Rationals ##
InstallMethod( RadicalSeriesSolvableMatGroup, "for solvable matrix groups (Polenta)",
true, [ IsCyclotomicMatrixGroup ], 0, function( G )
local mats, d; if not IsRationalMatrixGroup( G ) then
Print( "matrix groups must defined over the rationals" );
return fail; fi; if IsAbelian( G ) then
mats := GeneratorsOfGroup( G );
d := Length( mats[1] );
return RadicalSeriesAbelianRMGroup( mats, d ); else
return RadicalSeriesPRMGroup( G ); fi; end );
############################################################################# ## #F POL_SplitHomogeneous( base, mats ) ## ## split the homogeneous module <base> into irreducibles ##
POL_SplitHomogeneous := function( base, mats )
local IrreducibleList,b,space_basis, space, basis;
IrreducibleList :=[]; # spinn up new irreducible module
basis := SpinnUpEchelonBase( [], [base[1]], mats, OnRight );
Add( IrreducibleList, basis ); # check if basis is already big enough if Length( basis ) = Length( base ) then # <base> = <basis> but base has nicer form
return [base]; fi;
for b in base do # check if b is not already contained in one of the irreducible # modules in IrreducibleList
space_basis := Concatenation( IrreducibleList );
space := VectorSpace( Rationals, space_basis, "basis" ); if not b in space then # spin up new irreducible module
basis := SpinnUpEchelonBase( [], [b], mats, OnRight );
Add( IrreducibleList, basis ); fi;
od;
return IrreducibleList; end;
############################################################################# ## #F POL_IsRationalModule( base, mats ) ##
POL_IsRationalModule := function( base, mats )
local V, b, m; if Length( base ) = 0then
return true; fi;
V := VectorSpace( Rationals, base ); for b in base do for m in mats do if not b*m in V then
return false; fi;
od;
od;
return true; end;
############################################################################# ## #F POL_CompositionSeriesNormalGens(gens, mats, d ) ## ## mats are normal subgroup generators for the Kernel K_p in G =<gens> ## returned is composition series of the K_p-module Q^d ##
POL_CompositionSeriesNormalGens := function(gens, mats, d )
local radb, splt, nath,inducedgens, l, sers, i,j, sub, full, acts,
preImageSub, irreducibleList, k, rads, induced,
irreducibles, factorMats, isomIrreds, basis, sub2;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := POL_RadicalNormalGens(gens, mats, d ); if radb = fail then return fail; fi;
splt := POL_SplitSemisimple( radb.algebra );
nath := radb.nathom;
# refine radical factor to irreducible components
l := Length( splt );
irreducibles := []; # induce action to factor
factorMats := List( mats, x -> InducedActionFactorByNHSEB( x, nath )); for i in [1..l] do # split i^th homogeneous component into isomorphic comp.
basis := POL_CopyVectorList( splt[i].basis );
Assert( 2, POL_IsRationalModule( basis, factorMats ), "hom. component fails to be a module" );
isomIrreds := POL_SplitHomogeneous( basis, factorMats ); for j in [1..Length( isomIrreds )] do
Assert( 2, POL_IsRationalModule( isomIrreds[j], factorMats ), "irred. component fails to be a module" );
od;
irreducibles := Concatenation( irreducibles, isomIrreds );
od;
# initialize series
k := Length( irreducibles ); for i in [2..k] do
sub := Concatenation( List( [i..k], x -> irreducibles[x] ) );
sub2 := POL_CopyVectorList( sub );
TriangulizeMat( sub2 );
Assert( 2, POL_IsRationalModule( sub2, factorMats ), "sum of irred. components fails to be a module\n" );
preImageSub := PreimageByNHSEB( sub2, nath );
Assert( 2, POL_IsRationalModule( preImageSub, mats ), "sum of irred. components fails to be a module\n" );
Add( sers, preImageSub );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
inducedgens:=List( gens, x -> InducedActionSubspaceByNHSEB( x, nath ) );
# use recursive call to refine radical
rads := POL_CompositionSeriesNormalGens(inducedgens,acts,
Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_CompositionSeriesByRadicalSeries( mats , d, sersFullData, pos ) ## ## mats are generators of a triangularizable matrix group ## sersFullData contains the full data, which were obtained in the ## computation of the radical series ## returned is composition series of the <mats>-module Q^d ##
POL_CompositionSeriesByRadicalSeries := function( mats, d, sersFullData, pos)
local radb, splt, nath,inducedgens, l, sers, i,j, sub, full, acts,
preImageSub, irreducibleList, k, rads, induced,
irreducibles, factorMats, isomIrreds, basis, sub2, indm,
indm_flat, algebra;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := sersFullData[pos]; if radb = fail then return fail; fi;
nath := radb.nathom;
splt := POL_SplitSemisimple( radb.algebra );
# refine radical factor to irreducible components
l := Length( splt );
irreducibles := []; # induce action to factor
factorMats := List( mats, x -> InducedActionFactorByNHSEB( x, nath )); for i in [1..l] do # split i^th homogeneous component into isomorphic comp.
basis := POL_CopyVectorList( splt[i].basis );
Assert( 2, POL_IsRationalModule( basis, factorMats ), "hom. component fails to be a module" );
isomIrreds := POL_SplitHomogeneous( basis, factorMats ); for j in [1..Length( isomIrreds )] do
Assert( 2, POL_IsRationalModule( isomIrreds[j], factorMats ), "irred. component fails to be a module" );
od;
irreducibles := Concatenation( irreducibles, isomIrreds );
od;
# initialize series
k := Length( irreducibles ); for i in [2..k] do
sub := Concatenation( List( [i..k], x -> irreducibles[x] ) );
sub2 := POL_CopyVectorList( sub );
TriangulizeMat( sub2 );
Assert( 2, POL_IsRationalModule( sub2, factorMats ), "sum of irred. components fails to be a module\n" );
preImageSub := PreimageByNHSEB( sub2, nath );
Assert( 2, POL_IsRationalModule( preImageSub, mats ), "sum of irred. components fails to be a module\n" );
Add( sers, preImageSub );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := POL_CompositionSeriesByRadicalSeries(acts,
Length(radb.radical),
sersFullData,
pos +1 ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_CompositionSeriesByRadicalSeriesRecalAlg( mats , d, sersFullData, pos ) ## ## mats are generators of a triangularizable matrix group ## sersFullData contains the full data, which were obtained in the ## computation of the radical series ## returned is composition series of the <mats>-module Q^d ## ## the algebras which are used for the splitting are recalculated in this ## version. This is for example necessary if the algebra basis in ## sersFullData are computed with a different group (for example K_p(<mats>)) ## than <mats>. ##
POL_CompositionSeriesByRadicalSeriesRecalAlg
:= function( mats, d, sersFullData, pos)
local radb, splt, nath,inducedgens, l, sers, i,j, sub, full, acts,
preImageSub, irreducibleList, k, rads, induced,
irreducibles, factorMats, isomIrreds, basis, sub2, indm,
indm_flat, algebra;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := sersFullData[pos]; if radb = fail then return fail; fi;
nath := radb.nathom;
#compute a base for the algebra Q[ indmats ] where #indmats is the induced action of Q^d/radical #and bring it in flat format
indm := List( mats, x ->InducedActionFactorByNHSEB(x,nath ));
indm_flat := List( indm, x-> Flat( x ));
algebra := SpinnUpEchelonBase( [ ], indm_flat, indm, OnMatVector );
# refine radical factor to irreducible components
l := Length( splt );
irreducibles := []; # induce action to factor
factorMats := List( mats, x -> InducedActionFactorByNHSEB( x, nath )); for i in [1..l] do # split i^th homogeneous component into isomorphic comp.
basis := POL_CopyVectorList( splt[i].basis );
Assert( 2, POL_IsRationalModule( basis, factorMats ), "hom. component fails to be a module" );
isomIrreds := POL_SplitHomogeneous( basis, factorMats ); for j in [1..Length( isomIrreds )] do
Assert( 2, POL_IsRationalModule( isomIrreds[j], factorMats ), "irred. component fails to be a module" );
od;
irreducibles := Concatenation( irreducibles, isomIrreds );
od;
# initialize series
k := Length( irreducibles ); for i in [2..k] do
sub := Concatenation( List( [i..k], x -> irreducibles[x] ) );
sub2 := POL_CopyVectorList( sub );
TriangulizeMat( sub2 );
Assert( 2, POL_IsRationalModule( sub2, factorMats ), "sum of irred. components fails to be a module\n" );
preImageSub := PreimageByNHSEB( sub2, nath );
Assert( 2, POL_IsRationalModule( preImageSub, mats ), "sum of irred. components fails to be a module\n" );
Add( sers, preImageSub );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := POL_CompositionSeriesByRadicalSeriesRecalAlg(acts,
Length(radb.radical),
sersFullData,
pos +1 ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_CompositionSeriesAbelianRMGroup( mats, d ) ## ## <mats> is an abelian rational matrix group ## returned is a composition series for the natrual <mats>-module Q^d ##
POL_CompositionSeriesAbelianRMGroup := function( mats, d )
local radb, splt, nath,inducedgens, l, sers, i, sub, full, acts,
rads, preImageSub, irreducibleList, k,
irreducibles, factorMats, isomIrreds, basis, sub2;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := RadicalOfAbelianRMGroup( mats, d ); if radb = fail then return fail; fi;
splt := POL_SplitSemisimple( radb.algebra );
nath := radb.nathom;
# refine radical factor to irreducible components
l := Length( splt );
irreducibles := []; # induce action to factor
factorMats := List( mats, x -> InducedActionFactorByNHSEB( x, nath )); for i in [1..l] do # split i^th homogeneous component into isomorphic comp.
basis := POL_CopyVectorList( splt[i].basis );
isomIrreds := POL_SplitHomogeneous( basis, factorMats );
irreducibles := Concatenation( irreducibles, isomIrreds );
od;
# initialize series
k := Length( irreducibles ); for i in [2..k] do
sub := Concatenation( List( [i..k], x -> irreducibles[x] ) );
sub2 := POL_CopyVectorList( sub );
TriangulizeMat( sub2 );
Assert( 2, POL_IsRationalModule( sub2, factorMats ), "sum of irred. components fails to be a module\n" );
preImageSub := PreimageByNHSEB( sub2, nath );
Add( sers, preImageSub );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := POL_CompositionSeriesAbelianRMGroup( acts, Length(radb.radical) ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F CompositionSeriesAbelianMatGroup( G ) ## ## <G> is an abelian rational matrix group ## # FIXME: This function is documented and should be turned into a GlobalFunction
CompositionSeriesAbelianMatGroup := function( G )
local mats,d; if not IsRationalMatrixGroup( G ) or not IsAbelian( G ) then
Print( "input must be an abelian rational matrix group.\n" );
return fail; fi;
mats := GeneratorsOfGroup( G );
d := Length( mats[1] );
return POL_CompositionSeriesAbelianRMGroup( mats, d ); end;
############################################################################# ## #F POL_CompositionSeriesTriangularizablRMGroup( gens, d ) ## ## <mats> is a triang. rational matrix group ## returned is a composition series for the natural <gens>-module Q^d ##
POL_CompositionSeriesTriangularizableRMGroup := function( gens, d )
local p, gens_p,G, bound_derivedLength, pcgs_I_p, gens_K_p,
gens_K_p_m, gens_K_p_mutableCopy, pcgs,
gensOfBlockAction,
radSeries, comSeries, recordSeries, isTriang,gens_mutableCopy;
# determine an admissible prime
p := DetermineAdmissiblePrime(gens);
Info( InfoPolenta, 1, "Chosen admissible prime: " , p );
Info( InfoPolenta, 1, " " );
# calculate the gens of the group phi_p(<gens>) where phi_p is # natural homomorphism to GL(d,p)
gens_p := InducedByField( gens, GF(p) );
# determine an upper bound for the derived length of G
bound_derivedLength := d+2;
# finite part
Info( InfoPolenta, 1,"Determine a constructive polycyclic sequence\n", " for the image under the p-congruence homomorphism ..." );
pcgs_I_p := CPCS_finite_word( gens_p, bound_derivedLength ); if pcgs_I_p = fail then return fail; fi;
Info(InfoPolenta,1,"finished.");
Info( InfoPolenta, 1, "Finite image has relative orders ",
RelativeOrdersPcgs_finite( pcgs_I_p ), "." );
Info( InfoPolenta, 1, " " );
# compute the normal the subgroup gens. for the kernel of phi_p
Info( InfoPolenta, 1,"Compute normal subgroup generators for the kernel\n", " of the p-congruence homomorphism ...");
gens_K_p := POL_NormalSubgroupGeneratorsOfK_p( pcgs_I_p, gens );
gens_K_p := Filtered( gens_K_p, x -> not x = IdentityMat(d) );
Info( InfoPolenta, 1,"finished.");
Info( InfoPolenta, 2,"The normal subgroup generators are" );
Info( InfoPolenta, 2, gens_K_p );
Info( InfoPolenta, 1, " " );
# radical series
Info( InfoPolenta, 1, "Compute the radical series ...");
gens_K_p_mutableCopy := CopyMatrixList( gens_K_p );
recordSeries := POL_RadicalSeriesNormalGensFullData( gens,
gens_K_p_mutableCopy,
d ); if recordSeries=fail then return fail; fi;
radSeries := recordSeries.sers;
Info( InfoPolenta, 1,"finished.");
Info( InfoPolenta, 1, "The radical series has length ",
Length( radSeries ), "." );
Info( InfoPolenta, 2, "The radical series is" );
Info( InfoPolenta, 2, radSeries );
Info( InfoPolenta, 1, " " );
# test if G is unipotent by abelian
isTriang := POL_TestIsUnipotenByAbelianGroupByRadSeries( gens, radSeries ); if isTriang then
Info( InfoPolenta, 1, "Group is triangularizable!" );
gens_mutableCopy := CopyMatrixList( gens );
# compositions series
comSeries := POL_CompositionSeriesByRadicalSeriesRecalAlg(
gens_mutableCopy,
d,
recordSeries.sersFullData, 1 ); if comSeries=fail then return fail; fi;
return comSeries; else
Print( "The input group is not triangularizable.\n" );
return fail; fi; end;
############################################################################# ## #F CompositionSeriesTriangularizableMatGroup( G ) ## ## <G> is a triangularizable rational matrix group ## # FIXME: This function is documented and should be turned into a GlobalFunction
CompositionSeriesTriangularizableMatGroup := function( G )
local mats,d; if not IsRationalMatrixGroup( G ) then
Print( "input must be a rational matrix group.\n" );
return fail; fi;
mats := GeneratorsOfGroup( G );
d := Length( mats[1] ); if IsAbelian( G ) then
return POL_CompositionSeriesAbelianRMGroup( mats, d ); else
return POL_CompositionSeriesTriangularizableRMGroup( mats, d ); fi;
end;
############################################################################# ## #F POL_HomogeneousSeriesByRadicalSeriesRecalAlg( mats , d, sersFullData, pos ) ## ## mats are generators of a triangularizable matrix group ## sersFullData contains the full data, which were obtained in the ## computation of the radical series ## returned is homog. series of the <mats>-module Q^d ## ## the algebras which are used for the splitting are recalculated in this ## version. This is for example necessary if the algebra basis in ## sersFullData are computed with a different group (for example K_p(<mats>)) ## than <mats>. ##
POL_HomogeneousSeriesByRadicalSeriesRecalAlg
:= function( mats, d, sersFullData, pos)
local radb, splt, nath,inducedgens, l, sers, i,j, sub, full, acts,
preImageSub, irreducibleList, k, rads, induced,
irreducibles, factorMats, isomIrreds, basis, sub2, indm,
indm_flat, algebra;
# catch the trivial case and set up if d = 0then
return []; fi;
full := IdentityMat( d ); if Length( mats ) = 0then
return [full, []]; fi;
sers := [full];
# get the radical
radb := sersFullData[pos]; if radb = fail then return fail; fi;
nath := radb.nathom;
#compute a base for the algebra Q[ indmats ] where #indmats is the induced action of Q^d/radical #and bring it in flat format
indm := List( mats, x ->InducedActionFactorByNHSEB(x,nath ));
indm_flat := List( indm, x-> Flat( x ));
algebra := SpinnUpEchelonBase( [ ], indm_flat, indm, OnMatVector );
# refine radical factor and initialize series
l := Length( splt ); for i in [2..l] do
sub := Concatenation( List( [i..l], x -> splt[x].basis ) );
TriangulizeMat( sub );
Add( sers, PreimageByNHSEB( sub, nath ) );
od;
Add( sers, radb.radical );
# induce action to radical
nath := NaturalHomomorphismBySemiEchelonBases( full, radb.radical);
acts := List( mats, x -> InducedActionSubspaceByNHSEB( x, nath ));
# use recursive call to refine radical
rads := POL_HomogeneousSeriesByRadicalSeriesRecalAlg(acts,
Length(radb.radical),
sersFullData,
pos +1 ); if rads = fail then return fail; fi;
rads := List( rads, function(x) if x=[] then return []; else
return x * radb.radical; fi;end );
Append( sers, rads{[2..Length(rads)]} );
return sers; end;
############################################################################# ## #F POL_HomogeneousSeriesTriangularizablRMGroup( gens, d ) ## ## <mats> is a triang. rational matrix group ## returned is a homogeneous series for the natural <gens>-module Q^d ##
POL_HomogeneousSeriesTriangularizableRMGroup := function( gens, d )
local p, gens_p,G, bound_derivedLength, pcgs_I_p, gens_K_p,
gens_K_p_m, gens_K_p_mutableCopy, pcgs,
gensOfBlockAction,
radSeries, comSeries, recordSeries, isTriang,gens_mutableCopy;
# determine an admissible prime
p := DetermineAdmissiblePrime(gens);
Info( InfoPolenta, 1, "Chosen admissible prime: " , p );
Info( InfoPolenta, 1, " " );
# calculate the gens of the group phi_p(<gens>) where phi_p is # natural homomorphism to GL(d,p)
gens_p := InducedByField( gens, GF(p) );
# determine an upper bound for the derived length of G
bound_derivedLength := d+2;
# finite part
Info( InfoPolenta, 1,"Determine a constructive polycyclic sequence\n", " for the image under the p-congruence homomorphism ..." );
pcgs_I_p := CPCS_finite_word( gens_p, bound_derivedLength ); if pcgs_I_p = fail then return fail; fi;
Info(InfoPolenta,1,"finished.");
Info( InfoPolenta, 1, "Finite image has relative orders ",
RelativeOrdersPcgs_finite( pcgs_I_p ), "." );
Info( InfoPolenta, 1, " " );
# compute the normal the subgroup gens. for the kernel of phi_p
Info( InfoPolenta, 1,"Compute normal subgroup generators for the kernel\n", " of the p-congruence homomorphism ...");
gens_K_p := POL_NormalSubgroupGeneratorsOfK_p( pcgs_I_p, gens );
gens_K_p := Filtered( gens_K_p, x -> not x = IdentityMat(d) );
Info( InfoPolenta, 1,"finished.");
Info( InfoPolenta, 2,"The normal subgroup generators are" );
Info( InfoPolenta, 2, gens_K_p );
Info( InfoPolenta, 1, " " );
# radical series
Info( InfoPolenta, 1, "Compute the radical series ...");
gens_K_p_mutableCopy := CopyMatrixList( gens_K_p );
recordSeries := POL_RadicalSeriesNormalGensFullData( gens,
gens_K_p_mutableCopy,
d );
if recordSeries=fail then return fail; fi;
radSeries := recordSeries.sers;
Info( InfoPolenta, 1,"finished.");
Info( InfoPolenta, 1, "The radical series has length ",
Length( radSeries ), "." );
Info( InfoPolenta, 2, "The radical series is" );
Info( InfoPolenta, 2, radSeries );
Info( InfoPolenta, 1, " " );
# test if G is unipotent by abelian
isTriang := POL_TestIsUnipotenByAbelianGroupByRadSeries( gens, radSeries ); if isTriang then
Info( InfoPolenta, 1, "Group is triangularizable!" );
gens_mutableCopy := CopyMatrixList( gens );
# homogeneous series
comSeries := POL_HomogeneousSeriesByRadicalSeriesRecalAlg(
gens_mutableCopy,
d,
recordSeries.sersFullData, 1 ); if comSeries=fail then return fail; fi;
return comSeries; else
Print( "The input group is not triangularizable.\n" );
return fail; fi; end;
############################################################################# ## #F HomogeneousSeriesTriangularizableMatGroup( G ) ## ## <G> is a triangularizable rational matrix group ## # FIXME: This function is documented and should be turned into a GlobalFunction
HomogeneousSeriesTriangularizableMatGroup := function( G )
local mats,d; if not IsRationalMatrixGroup( G ) then
Print( "input must be a rational matrix group.\n" );
return fail; fi;
mats := GeneratorsOfGroup( G );
d := Length( mats[1] ); if IsAbelian( G ) then
return POL_HomogeneousSeriesAbelianRMGroup( mats, d ); else
return POL_HomogeneousSeriesTriangularizableRMGroup( mats, d ); fi;
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.