home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-05 | 66.1 KB | 2,033 lines |
- #############################################################################
- ##
- #A agclass.g GAP library J\"urgen Mnich
- ##
- #A @(#)$Id: agclass.g,v 3.9 1993/01/15 12:06:27 fceller Rel $
- ##
- #Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
- ##
- ## This file contains functions for calculating classes of elements in
- ## groups given by a pcp-presentation.
- ##
- #H $Log: agclass.g,v $
- #H Revision 3.9 1993/01/15 12:06:27 fceller
- #H fixed ".domain" entry, but the 'ConjugacyClass' command
- #H is still very strange (and maybe buggy) and should be
- #H correct soon
- #H
- #H Revision 3.8 1992/12/16 19:47:27 martin
- #H replaced quoted record names with escaped ones
- #H
- #H Revision 3.7 1992/05/12 11:45:54 jmnich
- #H inserted missing 'return' statement.
- #H
- #H Revision 3.6 1992/04/07 16:15:32 jmnich
- #H adapted to changes in the finite field module
- #H
- #H Revision 3.5 1992/04/01 06:50:42 jmnich
- #H changed use of 'Exponents'
- #H
- #H Revision 3.4 1992/03/17 12:31:20 jmnich
- #H minor style changes, more bug fixes
- #H
- #H Revision 3.3 1992/02/29 13:25:11 jmnich
- #H general library review, some bug fixes
- #H
- #H Revision 3.1 1992/02/12 15:37:22 martin
- #H initial revision under RCS
- #H
- ##
-
-
- #############################################################################
- ##
- #F InfoAgClass1(...) . . . . . . . . . . . . . . . . . . package information
- #F InfoAgClass2(...) . . . . . . . . . . . . . . . package debug information
- ##
- if not IsBound( InfoAgClass1 ) then InfoAgClass1 := Ignore; fi;
- if not IsBound( InfoAgClass2 ) then InfoAgClass2 := Ignore; fi;
-
-
- #############################################################################
- ##
- #V Statistics Variables . . . . . . . . . . . . . . . . . . . . . . . . . .
- ##
- ecs_ag_time := 0;
- ecs_ag_centrality_cnt := 0;
- ecs_ag_central_cnt := [ 0, 0 ];
- ecs_ag_non_central_cnt := [ 0, 0, 0, 0, 0, 0 ];
- ncs_ag_time := 0;
- ncs_ag_central_cnt := [ 0 ];
- ncs_ag_non_central_cnt := [ 0, 0 ];
- scs_ag_time := 0;
- scs_ag_central_cnt := [ 0 ];
- scs_ag_non_central_cnt := [ 0, 0 ];
-
-
- #############################################################################
- ##
- #F InHomSolutions( <oldmat>, <newmat>, <vec>, <field> ) . . . . . . . . . .
- ##
- ## 'InHomSolutions' solves the inhomogeneous system of linear equations that
- ## is given by the concatenation of the first two arguments as the left side
- ## and the third argument as the part of the right side belonging to the
- ## second argument. The triangulized matrix (for iterative use) is returned
- ## as well as the cardinality of the set of solutions.
- ##
- ## returns
- ##
- ## rec(
- ## matrix := [ [ <ffelem> ] ],
- ## cardinality := <integer>
- ## )
- ##
- InHomSolutions := function( A, B, b, field )
- local len, bad, pos, num, v, i;
-
- len := Length( B[1] ) + 1;
- for i in [1..Length( b )] do B[i][len] := b[i]; od;
-
- Append( A, B );
- TriangulizeMat( A );
-
- bad := false;
- pos := 0;
- i := 1;
- for v in A do
- while i <= len and v[i] = field.zero do i := i + 1; od;
- if i <= len then pos := pos + 1; fi;
- if i = len then bad := true; fi;
- od;
-
- if bad then num := 0;
- else num := field.char ^ (len - 1 - pos);
- fi;
-
- return rec(
- matrix := A,
- cardinality := num
- );
- end;
-
-
- #############################################################################
- ##
- #F CommutatorGauss( <mat>, <field> ) . . . . . . . . . . . . . . . . . . . .
- ##
- ## 'CommutatorGauss' performs a gauss algorithm on the supplied finite field
- ## matrix and extracts all information from the triangulized form which
- ## may be interpreted as a special way of calculating centralizers and
- ## commutator groups under certain conditions.
- ##
- ## returns
- ##
- ## rec(
- ## commutator := [ [ <integer> ] ],
- ## commutatorFactor := [ [ <integer> ] ],
- ## centralizer := [ [ <integer> ] ],
- ## )
- ##
- CommutatorGauss := function( A, field )
- local res, ndim, cdim, pos, v, i, j;
-
- cdim := Length( A );
- ndim := Length( A[1] );
-
- for i in [ndim+1..ndim+cdim] do
- for j in [1..cdim] do
- A[j][i] := field.zero;
- od;
- A[i-ndim][i] := field.one;
- od;
-
- #T as soon as martin fixes the 'Append' bug
- #T
- #T local c;
- #T
- #T c := [];
- #T for i in [1..cdim] do
- #T c[i] := field.zero;
- #T od;
- #T IsVector( c );
- #T
- #T
- #T for i in [1..cdim] do
- #T Append( A[i], c );
- #T A[i][ndim+i] := field.one;
- #T od;
-
- TriangulizeMat( A );
-
- res := rec(
- matrix := A,
- commutator := 0,
- commutatorFactor := [1..ndim],
- centralizer := 0,
- integers := [],
- dimensionN := ndim,
- dimensionC := cdim
- );
-
- pos := [];
- i := 1;
- for v in A do
- while v[i] = field.zero do i := i + 1; od;
- Add( pos, i );
- if i <= ndim then res.commutator := res.commutator + 1;
- else res.centralizer := res.centralizer + 1;
- fi;
- od;
- SubtractSet( res.commutatorFactor, pos );
-
- res.integers := IntegerTable( field );
-
- return res;
- end;
-
-
- #############################################################################
- ##
- #F CorrectedStabilizer( <mat>, <N>, <S>, <M>, <h>, <n>, <hom> ) . . . . . .
- ##
- ## 'CorrectedStabilizer' solves a special problem that arises when the
- ## classes of elements are calculated for a solvable group using linear
- ## methods. For short, a stabilizer of an affine operation on a factor group
- ## has to be modified (corrected) to eliminate a non-trivial operation in
- ## the normal subgroup. Of course this must be possible by theory.
- ##
- ## returns
- ##
- ## <list>
- ##
- CorrectedStabilizer := function( A, N, S, M, h, n, hom )
- local integers, pos, v, res, sol, s, g, gens, len, map, z, i;
-
- InfoAgClass2( "#I ecs: correcting stabilizer ", S, "\n" );
-
- if hom = false then map := x -> x;
- else map := x -> FactorAgWord( x, hom.source.identity );
- fi;
-
- integers := IntegerTable( N.field );
-
- A := AbstractBaseMat( M, A, N.field );
- gens := A[1];
- A := A[2];
-
- pos := [];
- i := 1;
- for v in A do
- while v[i] = N.field.zero do i := i + 1; od;
- Add( pos, i );
- od;
- len := Length( pos );
-
- res := [];
- for s in S do
- s := map( s );
- sol := Exponents( N, Comm( n, s ) * Comm( h, s ), N.field );
- g := N.identity;
- for i in [1..len] do
- z := LogVecFFE( sol, pos[i] );
- if z <> false then
- g := g * gens[i] ^ integers[z+1];
- fi;
- od;
- Add( res, s / g );
- od;
-
- #T alternative avoiding AbstractBaseMat
- #T
- #T gens := M;
- #T len := Length( gens );
- #T res := [];
- #T for s in S do
- #T s := map( s );
- #T sol := SolutionMat( A, Exponents( N, Comm( n, s ) * Comm( h, s ), N.field ) );
- #T g := N.identity;
- #T for i in [1..len] do
- #T z := LogVecFFE( sol, i );
- #T if z <> false then
- #T g := g * gens[i] ^ integers[z+1];
- #T fi;
- #T od;
- #T Add( res, s / g );
- #T od;
-
- InfoAgClass2( "#I ecs: correcting stabilizer done\n" );
-
- return res;
- end;
-
-
- #############################################################################
- ##
- #F AffineOrbitsAgGroup( <G>, <matrices>, <field> ) . . . . . . . . . . . . .
- ##
- ## This function is one of those that are mainly used by the author's
- ## ag-modules. It determines all the orbits of a soluble group acting affine
- ## on a full vector space.
- ##
- ## returns
- ##
- ## rec(
- ## representatives := <vectors>,
- ## stabilizers := <aggroups>,
- ## orbits := <integer>,
- ## integers := <list>
- ## )
- ##
- AffineOrbitsAgGroup := function( G, mats, field )
- local space, reps, stabs, spsize, orb, vs, v, w, z, next, enum, num,
- orbs, dim, i;
-
- reps := [];
- stabs := [];
- dim := Length( mats[1] ) - 1;
- vs := RowSpace( dim, field );
- spsize := Size( vs );
- enum := Enumeration( vs );
-
- orbs := 0;
- space := BlistList( [1..spsize], [] );
- next := Position( space, false );
- while next <> false do
- v := MakeVecFFE( CoefficientsInt( enum.exponents, next-1 ), enum.field.one );
-
- #T testing the performance enhancement of 'CoefficientsInt'
- #T
- #T v := ShallowCopy( enum.exponents );
- #T next := next - 1;
- #T for i in Reversed( [1..dim] ) do
- #T v[i] := next mod enum.exponents[i];
- #T next := QuoInt( next, enum.exponents[i] );
- #T od;
- #T v := MakeVecFFE( v, enum.field.one );
-
- v[dim+1] := field.one;
- orb := AgOrbitStabilizer( G, mats, v );
- for w in orb.orbit do
- #T num := 1;
- #T for i in [1..enum.dimension] do
- #T z := LogVecFFE( w, i );
- #T if z <> false then
- #T num := num + enum.powers[i] * enum.integers[z+1];
- #T fi;
- #T od;
- num := NumberVecFFE( w, enum.powers, enum.integers );
- space[num] := true;
- od;
- orbs := orbs + 1;
- reps[orbs] := v;
- stabs[orbs] := orb.stabilizer;
- next := Position( space, false, next );
- od;
- return rec(
- representatives := reps,
- stabilizers := stabs,
- orbits := orbs,
- integers := enum.integers
- );
- end;
-
-
- #############################################################################
- ##
- #F MinimalVectorAgOrbit( <G>, <matrices>, <vector>, <field> ) . . . . . . .
- ##
- ## This function is more or less only used by the author's ag modules.
- ## It determines the 'smallest' vector in the orbit under an affine action
- ## of an aggroup on a vector space. This is necessary, when using linear
- ## methods for soluble groups, to determine a canonical class representative
- ## for the conjugacy classes.
- ##
- ## returns
- ##
- ## rec(
- ## vector := <vector>
- ## operator := <agword>,
- ## stabilizer := <aggroup>
- ## )
- ##
- MinimalVectorAgOrbit := function( group, mats, vec, field )
- local vs, orbit, torbit, stab, gen, orbpos, operator, pv, gn,
- dim, enum, mvec, mnum, num, p, z, i, j, k;
-
- dim := Length( mats[1] ) - 1;
- vs := RowSpace( dim, field );
- enum := Enumeration( vs );
-
- orbit := [ vec ];
- stab := [];
- pv := [ 1 ];
- gn := [];
-
- for i in Reversed( [1..Length( group.generators )] ) do
- gen := group.generators[i];
- orbpos := Position( orbit, vec * mats[i] );
- if orbpos = false then
- p := RelativeOrderAgWord( gen );
- Add( pv, pv[Length( pv )] * p );
- Add( gn, i );
- torbit := ShallowCopy( orbit );
- for j in [1..p-1] do
- for k in [1..Length( torbit )] do
- torbit[k] := torbit[k] * mats[i];
- od;
- Append( orbit, torbit );
- od;
- elif orbpos = 1 then Add( stab, gen );
- else
- operator := group.identity;
- orbpos := orbpos - 1;
- j := Length( pv ) - 1;
- while orbpos > 0 and j > 0 do
- operator := group.generators[gn[j]] ^ QuoInt( orbpos, pv[j] ) * operator;
- orbpos := orbpos mod pv[j];
- j := j - 1;
- od;
- Add( stab, gen / operator );
- fi;
- od;
-
- mvec := vec;
- #T mnum := 1;
- #T for i in [1..enum.dimension] do
- #T z := LogVecFFE( vec, i );
- #T if z <> false then
- #T mnum := mnum + enum.powers[i] * enum.integers[z+1];
- #T fi;
- #T od;
- mnum := NumberVecFFE( vec, enum.powers, enum.integers );
-
- orbpos := 1;
- j := Length( orbit );
- while j > 1 and mnum > 1 do
- #T num := 1;
- #T for i in [1..enum.dimension] do
- #T z := LogVecFFE( orbit[j], i );
- #T if z <> false then
- #T num := num + enum.powers[i] * enum.integers[z+1];
- #T fi;
- #T od;
- num := NumberVecFFE( orbit[j], enum.powers, enum.integers );
-
- if num < mnum then
- mnum := num;
- mvec := orbit[j];
- orbpos := j;
- fi;
- j := j - 1;
- od;
- operator := group.identity;
- orbpos := orbpos - 1;
- j := Length( pv ) - 1;
- while orbpos > 0 and j > 0 do
- operator := group.generators[gn[j]] ^ QuoInt( orbpos, pv[j] ) * operator;
- orbpos := orbpos mod pv[j];
- j := j - 1;
- od;
-
- return rec(
- vector := mvec,
- operator := operator,
- stabilizer := AgSubgroup( group, Reversed( stab ), false )
- );
- end;
-
-
- #############################################################################
- ##
- #F CentralCaseECSAgGroup( <G>, <N>, <C>, <M>, <h>, <hom> ) . . . . . . . . .
- ##
- ## 'CentralCaseECSAgGroup' implements the central part of the
- ## algorithm for the calculation of conjugacy classes in soluble groups using
- ## linear methods.
- ## In the case where the elementary abelian normal subgroup is central in
- ## a (somehow defined) group, the algorithm basically simplifies to solving
- ## a system of linear equations.
- ##
- ## returns
- ##
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ [ <agword> ] ]
- ## )
- ##
- CentralCaseECSAgGroup := function( G, N, C, M, h, hom )
- local h_C_comm, cg, rep2, cent2, ncgs, cigs, migs, tmp, v, z, g, i, j;
-
- InfoAgClass1( "#I ecs: central case main dispatcher\n" );
-
- if not IsBound( N.field ) then
- N.field := GF( RelativeOrderAgWord( N.generators[1] ) );
- fi;
-
- if C.generators = [] then
- InfoAgClass2( "#I ecs: central_1\n" );
- ecs_ag_central_cnt[1] := ecs_ag_central_cnt[1] + 1;
-
- h := FactorAgWord( h, hom.source.identity );
- rep2 := Elements( N );
- cent2 := ShallowCopy( rep2 );
- for i in [1..Length( rep2 )] do
- rep2[i] := h * rep2[i];
- cent2[i] := M;
- od;
- else
- InfoAgClass2( "#I ecs: central_2\n" );
- ecs_ag_central_cnt[2] := ecs_ag_central_cnt[2] + 1;
-
- ncgs := Cgs( N );
- cigs := ShallowCopy( Igs( C ) );
- migs := Igs( M );
-
- h := FactorAgWord( h, hom.source.identity );
- h_C_comm := [];
- for i in [1..Length( cigs )] do
- cigs[i] := FactorAgWord( cigs[i], hom.source.identity );
- h_C_comm[i] := Exponents( N, Comm( h, cigs[i] ), N.field );
- od;
-
- cg := CommutatorGauss( Copy( h_C_comm ), N.field );
-
- cg.commutatorFactor := AgSubgroup(
- G,
- Sublist( ncgs, cg.commutatorFactor ),
- true
- );
-
- tmp := [];
- for i in [cg.commutator+1..cg.commutator+cg.centralizer] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [cg.dimensionN+1..cg.dimensionN+cg.dimensionC] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * cigs[j-cg.dimensionN] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i-cg.commutator] := g;
- od;
- Append( tmp, migs );
- cg.centralizer := AgSubgroup( G, tmp, false );
-
- rep2 := Elements( cg.commutatorFactor );
- cent2 := ShallowCopy( rep2 );
- for i in [1..Length( rep2 )] do
- rep2[i] := h * rep2[i];
- cent2[i] := cg.centralizer;
- od;
- fi;
-
- return rec(
- representatives := rep2,
- centralizers := cent2
- );
- end;
-
-
- #############################################################################
- ##
- #F GeneralCaseECSAgGroup( <G>, <N>, <C>, <M>, <h>, <hom> ) . . . . . . . . .
- ##
- ## 'GeneralCaseECSAgGroup' implements the non-central part of the
- ## algorithm for the calculation of conjugacy classes in soluble groups using
- ## linear methods.
- ##
- ## returns
- ##
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ <aggroup> ]
- ## )
- ##
- GeneralCaseECSAgGroup := function( G, N, C, M, h, hom )
- local ncgs, cigs, migs, centrala, centralb, N_C_pow, h_M_comm, h_C_comm,
- ndim, clen, mlen, N2, n2cgs, wn2cgs, n2dim, N2_C_pow, cg, cg2,
- orb, rep2, cent2, tmp, v, z, g, i, j;
-
- InfoAgClass1( "#I ecs: general case main dispatcher\n" );
-
- if not IsBound( N.field ) then
- N.field := GF( RelativeOrderAgWord( N.generators[1] ) );
- fi;
-
- ncgs := Cgs( N );
- cigs := ShallowCopy( Igs( C ) );
- migs := Igs( M );
- ndim := Length( ncgs );
- clen := Length( cigs );
- mlen := Length( migs );
-
- centrala := true;
- centralb := true;
- N_C_pow := [];
- for i in [1..clen] do
- cigs[i] := FactorAgWord( cigs[i], hom.source.identity );
- N_C_pow[i] := [];
- for j in [1..ndim] do
- N_C_pow[i][j] := ncgs[j] ^ cigs[i];
- if N_C_pow[i][j] <> ncgs[j] then centrala := false; fi;
- od;
- od;
-
- h_M_comm := [];
- h := FactorAgWord( h, hom.source.identity );
- for i in [1..mlen] do
- h_M_comm[i] := Comm( h, migs[i] );
- if h_M_comm[i] <> N.identity then centralb := false; fi;
- od;
-
- if centrala and centralb then
- InfoAgClass2( "#I ecs: non_central_1 ->\n" );
- ecs_ag_non_central_cnt[1] := ecs_ag_non_central_cnt[1] + 1;
-
- return CentralCaseECSAgGroup( G, N, C, M, h, hom );
- fi;
-
- if centralb then
- InfoAgClass2( "#I ecs: non_central_2\n" );
- ecs_ag_non_central_cnt[2] := ecs_ag_non_central_cnt[2] + 1;
-
- for i in [1..clen] do
- tmp := N_C_pow[i];
- for j in [1..ndim] do
- tmp[j] := Exponents( N, tmp[j], N.field );
- tmp[j][ndim+1] := N.field.zero;
- od;
- tmp[ndim+1] := Exponents( N, Comm( h, cigs[i] ), N.field );
- tmp[ndim+1][ndim+1] := N.field.one;
- od;
- orb := AffineOrbitsAgGroup( C, N_C_pow, N.field );
-
- rep2 := orb.representatives;
- cent2 := orb.stabilizers;
- for i in [1..orb.orbits] do
- g := h;
- for j in [1..ndim] do
- z := LogVecFFE( rep2[i], j );
- if z <> false then
- g := g * ncgs[j] ^ orb.integers[z+1];
- fi;
- od;
- rep2[i] := g;
- tmp := ShallowCopy( Igs( cent2[i] ) );
- for j in [1..Length( tmp )] do
- tmp[j] := FactorAgWord( tmp[j], hom.source.identity );
- od;
- Append( tmp, migs );
- cent2[i] := AgSubgroup( G, tmp, false );
- od;
-
- return rec(
- representatives := rep2,
- centralizers := cent2
- );
- fi;
-
- for i in [1..mlen] do
- h_M_comm[i] := Exponents( N, h_M_comm[i], N.field );
- od;
-
- if centrala then
- InfoAgClass2( "#I ecs: non_central_3\n" );
- ecs_ag_non_central_cnt[3] := ecs_ag_non_central_cnt[3] + 1;
-
- h_C_comm := [];
- for i in [1..clen] do
- h_C_comm[i] := Exponents( N, Comm( h, cigs[i] ), N.field );
- od;
- Append( cigs, migs );
- Append( h_C_comm, h_M_comm );
-
- cg := CommutatorGauss( Copy( h_C_comm ), N.field );
- cg.commutatorFactor := AgSubgroup(
- G,
- Sublist( ncgs, cg.commutatorFactor ),
- true
- );
-
- tmp := [];
- for i in [cg.commutator+1..cg.commutator+cg.centralizer] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [cg.dimensionN+1..cg.dimensionN+cg.dimensionC] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * cigs[j-cg.dimensionN] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i-cg.commutator] := g;
- od;
- cg.centralizer := AgSubgroup( G, tmp, false );
-
- rep2 := Elements( cg.commutatorFactor );
- cent2 := ShallowCopy( rep2 );
- for i in [1..Length( rep2 )] do
- rep2[i] := h * rep2[i];
- cent2[i] := cg.centralizer;
- od;
-
- return rec(
- representatives := rep2,
- centralizers := cent2
- );
- fi;
-
- cg := CommutatorGauss( Copy( h_M_comm ), N.field );
-
- if cg.commutatorFactor = [] then
- InfoAgClass2( "#I ecs: non_central_4\n" );
- ecs_ag_non_central_cnt[4] := ecs_ag_non_central_cnt[4] + 1;
-
- rep2 := [ h ];
- cent2 := [
- AgSubgroup(
- G,
- CorrectedStabilizer( h_M_comm, N, Igs( C ), Igs( M ), h, N.identity, hom ),
- false
- )
- ];
- else
- tmp := [];
- for i in [1..cg.commutator] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [1..cg.dimensionN] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * ncgs[j] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i] := g;
- od;
-
- # don't bound cg.commutator to tmp here. this field is re-used later.
-
- N2 := N mod AgSubgroup( G, tmp, false );
- N2.field := N.field;
- n2cgs := N2.generators;
- n2dim := Length( n2cgs );
- tmp := DepthAgWord( ncgs[1] ) - 1;
- wn2cgs := List( n2cgs, x -> DepthAgWord( x ) - tmp );
- centrala := true;
-
- N2_C_pow := [];
- for i in [1..clen] do
- N2_C_pow[i] := [];
- for j in [1..n2dim] do
- N2_C_pow[i][j] := N_C_pow[i][wn2cgs[j]];
- if centrala
- and not N2_C_pow[i][j] / n2cgs[j] in N2.factorDen then
- centrala := false;
- fi;
- od;
- od;
-
- if centrala then
- InfoAgClass2( "#I ecs: non_central_5\n" );
- ecs_ag_non_central_cnt[5] := ecs_ag_non_central_cnt[5] + 1;
-
- h_C_comm := [];
- for i in [1..clen] do
- h_C_comm[i] := Exponents( N2, Comm( h, cigs[i] ), N2.field );
- od;
-
- cg2 := CommutatorGauss( Copy( h_C_comm ), N.field );
-
- tmp := [];
- for i in [cg.commutator+1..cg.commutator+cg.centralizer] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [cg.dimensionN+1..cg.dimensionN+cg.dimensionC] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * migs[j-cg.dimensionN] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i-cg.commutator] := g;
- od;
- cg.centralizer := tmp;
-
- tmp := [];
- for i in [cg2.commutator+1..cg2.commutator+cg2.centralizer] do
- v := cg2.matrix[i];
- g := C.identity;
- for j in [cg2.dimensionN+1..cg2.dimensionN+cg2.dimensionC] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * C.generators[j-cg2.dimensionN] ^ cg2.integers[z+1];
- fi;
- od;
- tmp[i-cg2.commutator] := g;
- od;
- cg2.centralizer := tmp;
- cg2.commutatorFactor := Sublist( n2cgs, cg2.commutatorFactor );
-
- rep2 := Elements( AgSubgroup( N, cg2.commutatorFactor, true ) );
- cent2 := ShallowCopy( rep2 );
- for i in [1..Length( rep2 )] do
- cent2[i] := CorrectedStabilizer( h_M_comm, N, cg2.centralizer, Igs( M ), h, rep2[i], hom );
- Append( cent2[i], cg.centralizer );
- cent2[i] := AgSubgroup( G, cent2[i], false );
- rep2[i] := h * rep2[i];
- od;
- else
- InfoAgClass2( "#I ecs: non_central_6\n" );
- ecs_ag_non_central_cnt[6] := ecs_ag_non_central_cnt[6] + 1;
-
- for i in [1..clen] do
- tmp := N2_C_pow[i];
- for j in [1..n2dim] do
- tmp[j] := Exponents( N2, tmp[j], N2.field );
- tmp[j][n2dim+1] := N.field.zero;
- od;
- tmp[n2dim+1] := Exponents( N2, Comm( h, cigs[i] ), N2.field );
- tmp[n2dim+1][n2dim+1] := N.field.one;
- od;
-
- tmp := [];
- for i in [cg.commutator+1..cg.commutator+cg.centralizer] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [cg.dimensionN+1..cg.dimensionN+cg.dimensionC] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * migs[j-cg.dimensionN] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i-cg.commutator] := g;
- od;
- cg.centralizer := tmp;
-
- orb := AffineOrbitsAgGroup( C, N2_C_pow, N2.field );
-
- rep2 := orb.representatives;
- cent2 := orb.stabilizers;
- for i in [1..orb.orbits] do
- g := G.identity;
- for j in [1..n2dim] do
- z := LogVecFFE( rep2[i], j );
- if z <> false then
- g := g * n2cgs[j] ^ orb.integers[z+1];
- fi;
- od;
- tmp := CorrectedStabilizer( h_M_comm, N, Igs( cent2[i] ), Igs( M ), h, g, hom );
- Append( tmp, cg.centralizer );
- cent2[i] := AgSubgroup( G, tmp, false );
- rep2[i] := h * g;
- od;
- fi;
- fi;
-
- return rec(
- representatives := rep2,
- centralizers := cent2
- );
- end;
-
-
- #############################################################################
- ##
- #F MainEntryECSAgGroup( <G>, <U>, <H>, <ser>, <skip> ) . . . . . . . . . . .
- #F . . . . . . . . . . . . main entry point for the conjugacy class function
- ##
- ## This is main routine for the computation of conjugacy classes in soluble
- ## groups. It handles all initialization, takes care of the inductive nature
- ## of the algorithm and dispatches to the case-handling functions as
- ## far as centrality is obvious.
- ##
- ## returns
- ##
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ <aggroup> ]
- ## )
- ## or
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ <aggroup> ]
- ## naturalHomomorphisms := [ <aghom> ],
- ## domains := [ <aggroup> ],
- ## nextStep := <integer>,
- ## elementaryAbelianSeries := [ <aggroup> ]
- ## )
- ##
- ## A short explanation of the arguments for those who decide to go through
- ## this function rather than using the supplied top-level funtion.
- ## By the way, greetings to H.U. 8-)
- ##
- ## G the supergroup
- ## U the subgroup of G acting on H
- ## H a normal composition subgroup of G, an element of elabser
- ## elabser an elementary abelian composition series of G containing H
- ## skip the number of steps to skip at the end of the algorithm
- ##
- ## the last argument is basically implemented to provide programs such as
- ## the computation of the number of conjugacy classes with an easy way to
- ## compute the classes of the whole group modulo the last elementary abelian
- ## normal subgroup. If this feature is used, i.e. 'skip' is positive, the
- ## second form of the return record is returned otherwise always a return
- ## record of the first type is returned.
- ##
- ## Remark: the conditions that are implicitly given by the above description
- ## of the arguments is not tested by the function.
- ## So you hacker, be aware !
- ##
- MainEntryECSAgGroup := function( G, U, H, elabser, skip )
- local rep, cent, step, repnum, newclasses, newrep, newcent,
- fachom, facU, facN, facC, fach, fhom, tmpU, idx;
-
- if U.generators = [] then
- rep := Elements( H );
- cent := List( rep, x -> U );
- return rec(
- representatives := rep,
- centralizers := cent
- );
- fi;
-
- if H.generators = [] then
- return rec(
- representatives := [ H.identity ],
- centralizers := [ U ]
- );
- fi;
-
- ecs_ag_time := Runtime();
- ecs_ag_centrality_cnt := 0;
- ecs_ag_central_cnt := [ 0, 0 ];
- ecs_ag_non_central_cnt := [ 0, 0, 0, 0, 0, 0 ];
-
- idx := 1;
- while elabser[idx] <> H do idx := idx + 1; od;
- while IsSubgroup( elabser[idx+1], U ) do idx := idx + 1; od;
-
- if idx <> 1 then
- elabser := Sublist( elabser, [idx..Length( elabser )] );
- fi;
- fachom := HomomorphismsSeries( G, elabser );
-
-
- # initialize the inductive algorithm
-
- tmpU := Image( fachom[1], U );
- rep := Elements( Image( fachom[1], H ) );
- cent := List( rep, x -> tmpU );
-
- # prepare the involved data for each following step
-
- tmpU := U;
- U := [];
- U[Length( elabser )] := tmpU;
- for step in Reversed( [2..Length( elabser )] ) do
- tmpU := Image( fachom[step], tmpU );
- U[step-1] := tmpU;
- od;
-
- # loop over the elementary abelian series
-
- for step in [2..Length( elabser )-skip] do
-
- InfoAgClass1( "#I ecs: step ", step, " / (", Length( elabser ), "-", skip, ")\n" );
-
- # get the appropriate new data
-
- fhom := fachom[step];
- facN := PreImage( fhom, TrivialSubgroup( fhom.range ) );
- facU := Intersection( U[step], facN );
-
- # initialize data for this step
-
- newrep := [];
- newcent := [];
-
- if IsCentral( fhom.source, facN ) then
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I ecs: coset ", repnum, " / ", Length( rep ), "\n" );
- ecs_ag_centrality_cnt := ecs_ag_centrality_cnt + 1;
- newclasses := CentralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
- od;
- else
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I ecs: coset ", repnum, " / ", Length( rep ), "\n" );
- newclasses := GeneralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
- od;
- fi;
-
- rep := newrep;
- cent := newcent;
- od;
-
- ecs_ag_time := Runtime() - ecs_ag_time;
- if skip = 0 then
- return rec(
- representatives := rep,
- centralizers := cent
- );
- else
- return rec(
- representatives := rep,
- centralizers := cent,
- naturalHomomorphisms := fachom,
- domains := U,
- nextStep := Length( elabser ) - skip + 1,
- elementaryAbelianSeries := elabser
- );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F AgGroupOps.ConjugacyClasses( [<U>, ]<obj> ) . . . . . . . . . . . . . . .
- #F . . . . . . . . . . . compute conjugacyclasses of elements in an ag-group
- ##
- ## This function determines all conjugacyclasses of elements of an ag-group
- ## under the operation of an other ag-group which may be passed as an
- ## optional first argument. The function implements an algorithm that uses
- ## linear methods for calculations in a soluble group.
- ## If <obj> is a list of elements instead of an ag group, the classes of the
- ## elements, i.e. especially their canonical representative is determined.
- ##
- ## returns
- ##
- ## <list>
- ##
- AgGroupOps.ConjugacyClasses := function( arg )
- local G, H, U, HU, T, elabser, natisom, classes, res, i;
-
- if Length( arg ) = 1 then H := arg[1]; U := H;
- elif Length( arg ) = 2 then H := arg[2]; U := arg[1];
- else
- Error( "usage: ConjugacyClasses( [<U>, ]<obj> )" );
- fi;
-
- G := Parent( U );
- T := TrivialSubgroup( G );
-
- if IsList( H ) then
- if not IsElementaryAbelianAgSeries( G ) then
- elabser := ElementaryAbelianSeries( G );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- res := MainEntryECAgWords( natisom.range,
- Image( natisom, U ), List( H, x -> Image( natisom, x ) ), elabser );
-
- # now construct the conjugacy classes with additional entries
- # from the data returned in 'res'.
-
- classes := ShallowCopy( res.representatives );
-
- for i in [1..Length( classes )] do
- classes[i] := ConjugacyClass( U,
- PreImagesRepresentative( natisom, res.representatives[i] ) );
- classes[i].element :=
- PreImagesRepresentative( natisom, res.elements[i] );
- classes[i].conjugand :=
- PreImagesRepresentative( natisom, res.conjugands[i] );
- classes[i].centralizer :=
- PreImage( natisom, res.centralizers[i] );
- od;
- else
- elabser := ElementaryAbelianSeries( G );
- res := MainEntryECAgWords( G, U, H, elabser );
-
- classes := ShallowCopy( res.representatives );
-
- for i in [1..Length( classes )] do
- classes[i] := ConjugacyClass( U, res.representatives[i] );
- classes[i].element := res.elements[i];
- classes[i].conjugand := res.conjugands[i];
- classes[i].centralizer := res.centralizers[i];
- od;
- fi;
- elif IsNormal( G, H ) then
- if IsElementaryAbelianAgSeries( G )
- and IsElementAgSeries( H ) then
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- res := MainEntryECSAgGroup( G, U, H, elabser, 0 );
-
- classes := ShallowCopy( res.representatives );
-
- for i in [1..Length( classes )] do
- classes[i] := ConjugacyClass( U, res.representatives[i] );
- classes[i].centralizer := res.centralizers[i];
- od;
- else
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- res := MainEntryECSAgGroup( natisom.range,
- Image( natisom, U ), Image( natisom, H ), elabser, 0 );
-
- classes := ShallowCopy( res.representatives );
-
- for i in [1..Length( classes )] do
- classes[i] := ConjugacyClass( U,
- PreImagesRepresentative( natisom, res.representatives[i] ) );
- classes[i].centralizer :=
- PreImage( natisom, res.centralizers[i] );
- od;
- fi;
- elif IsNormal( U, H ) then
- HU := SumAgGroup( H, U );
- elabser := ElementaryAbelianSeries( [ HU, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- res := MainEntryECSAgGroup( natisom.range,
- Image( natisom, U ), Image( natisom, H ), elabser, 0 );
-
- classes := ShallowCopy( res.representatives );
-
- for i in [1..Length( classes )] do
- classes[i] := ConjugacyClass( U,
- PreImagesRepresentative( natisom, res.representatives[i] ) );
- classes[i].centralizer :=
- PreImage( natisom, res.centralizers[i] );
- od;
- else
- Error( "sorry, U must operate on H" );
- fi;
-
- return classes;
- end;
-
-
- #############################################################################
- ##
- #F FusionsECSAgGroup( <G>, <U>, <H>, <ser>, <split> ) . . . . . . . . . . .
- #F . . . . . . . . . . . . . . . . . . compute conjugacy classes and fusions
- ##
- ##
- ## returns
- ##
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ <aggroup> ]
- ## naturalHomomorphisms := [ <aghom> ],
- ## domains := [ <aggroup> ],
- ## elementaryAbelianSeries := [ <aggroup> ]
- ## representativeTree := [ <agword> ],
- ## centralizerTree := [ <aggroup> ],
- ## fusionTree := [ <integer> ]
- ## )
- ##
- ## A short explanation of the arguments.
- ##
- ## G the supergroup
- ## U the subgroup of G acting on H
- ## H a normal composition subgroup of G, an element of elabser
- ## elabser an elementary abelian composition series of G containing H
- ## split steps in which a check for a complete split is performed
- ## only classes that completely split are considered in further
- ## computations
- ##
- ##
- ## Remark: the conditions that are implicitly given by the above description
- ## of the arguments is not tested by the function.
- ##
- FusionsECSAgGroup := function( G, U, H, elabser, split )
- local rep, cent, step, repnum, newclasses, newrep, newcent, fachom,
- facU, facN, facC, fach, fhom, tmpU, idx, rtree, ctree, ftree;
-
-
- if U.generators = [] then
- rep := Elements( H );
- cent := List( rep, x -> U );
- return rec(
- representatives := rep,
- centralizers := cent
- );
- fi;
-
- if H.generators = [] then
- return rec(
- representatives := [ H.identity ],
- centralizers := [ U ]
- );
- fi;
-
- ecs_ag_time := Runtime();
- ecs_ag_centrality_cnt := 0;
- ecs_ag_central_cnt := [ 0, 0 ];
- ecs_ag_non_central_cnt := [ 0, 0, 0, 0, 0, 0 ];
-
- idx := 1;
- while elabser[idx] <> H do idx := idx + 1; od;
- while IsSubgroup( elabser[idx+1], U ) do idx := idx + 1; od;
-
- if idx <> 1 then
- elabser := Sublist( elabser, [idx..Length( elabser )] );
- fi;
- fachom := HomomorphismsSeries( G, elabser );
-
- if split <> [] then split := split + 1 - idx; fi;
-
-
- # initialize the inductive algorithm
-
- tmpU := Image( fachom[1], U );
- rep := Elements( Image( fachom[1], H ) );
- cent := List( rep, x -> tmpU );
-
- rtree := [ rep ];
- ctree := [ cent ];
- ftree := [ [] ];
-
- # prepare the involved data for each following step
-
- tmpU := U;
- U := [];
- U[Length( elabser )] := tmpU;
- for step in Reversed( [2..Length( elabser )] ) do
- tmpU := Image( fachom[step], tmpU );
- U[step-1] := tmpU;
- od;
-
- # loop over the elementary abelian series
-
- for step in [2..Length( elabser )] do
-
- InfoAgClass1( "#I becs: step ", step, " / ", Length( elabser ), "\n" );
-
- # get the appropriate new data
-
- fhom := fachom[step];
- facN := PreImage( fhom, TrivialSubgroup( fhom.range ) );
- facU := Intersection( U[step], facN );
-
- # initialize data for this step
-
- newrep := [];
- newcent := [];
- ftree[step] := [];
-
- if IsCentral( fhom.source, facN ) then
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I becs: coset ", repnum, " / ", Length( rep ), "\n" );
- ecs_ag_centrality_cnt := ecs_ag_centrality_cnt + 1;
- newclasses := CentralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- if not step in split
- or Length( newclasses.representatives ) = Size( facN ) then
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
-
- Append( ftree[step],
- List( newclasses.representatives, x -> repnum ) );
- fi;
- od;
- else
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I becs: coset ", repnum, " / ", Length( rep ), "\n" );
- newclasses := GeneralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- if not step in split
- or Length( newclasses.representatives ) = Size( facN ) then
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
-
- Append( ftree[step],
- List( newclasses.representatives, x -> repnum ) );
- fi;
- od;
- fi;
-
- rep := newrep;
- cent := newcent;
-
- rtree[step] := newrep;
- ctree[step] := newcent;
- od;
-
- ecs_ag_time := Runtime() - ecs_ag_time;
- return rec(
- representatives := rep,
- centralizers := cent,
- naturalHomomorphisms := fachom,
- domains := U,
- elementaryAbelianSeries := elabser,
- representativeTree := rtree,
- centralizerTree := ctree,
- fusionTree := ftree
- );
- end;
-
-
- #############################################################################
- ##
- #F Fusions2ECSAgGroup( <G>, <U>, <H>, <ser>, <idx>, <reps>, <cents>, <split> )
- #F . . . . . . . . . compute conjugacy classes and fusions from lower level
- ##
- ##
- ## returns
- ##
- ## rec(
- ## representatives := [ <agword> ],
- ## centralizers := [ <aggroup> ]
- ## naturalHomomorphisms := [ <aghom> ],
- ## domains := [ <aggroup> ],
- ## elementaryAbelianSeries := [ <aggroup> ]
- ## representativeTree := [ <agword> ],
- ## centralizerTree := [ <aggroup> ],
- ## fusionTree := [ <integer> ]
- ## )
- ##
- ## A short explanation of the arguments.
- ##
- ## G the supergroup
- ## U the subgroup of G acting on H
- ## H a normal composition subgroup of G, an element of elabser
- ## elabser an elementary abelian composition series of G containing H
- ## idx start index to begin computation
- ## rep list of representatives so far
- ## cent list of centralizers (as groups !) relative to rep
- ## split steps in which a check for a complete split is performed
- ## only classes that completely split are considered in further
- ## computations
- ##
- ##
- ## Remark: the conditions that are implicitly given by the above description
- ## of the arguments is not tested by the function.
- ##
- Fusions2ECSAgGroup := function( G, U, H, elabser, idx, rep, cent, split )
- local step, repnum, newclasses, newrep, newcent, fachom,
- facU, facN, facC, fach, fhom, tmpU, rtree, ctree, ftree;
-
-
- if U.generators = [] then
- cent := List( rep, x -> U );
- return rec(
- representatives := rep,
- centralizers := cent
- );
- fi;
-
- if H.generators = [] then
- return rec(
- representatives := [ H.identity ],
- centralizers := [ U ]
- );
- fi;
-
- ecs_ag_time := Runtime();
- ecs_ag_centrality_cnt := 0;
- ecs_ag_central_cnt := [ 0, 0 ];
- ecs_ag_non_central_cnt := [ 0, 0, 0, 0, 0, 0 ];
-
- if idx <> 1 then
- elabser := Sublist( elabser, [idx..Length( elabser )] );
- fi;
- fachom := HomomorphismsSeries( G, elabser );
-
- if split <> [] then split := split + 1 - idx; fi;
-
-
- # initialize the inductive algorithm
-
- Apply( rep, x -> Image( fachom[1], x ) );
- Apply( cent, x -> Image( fachom[1], x ) );
-
- rtree := [ rep ];
- ctree := [ cent ];
- ftree := [ [] ];
-
- # prepare the involved data for each following step
-
- tmpU := U;
- U := [];
- U[Length( elabser )] := tmpU;
- for step in Reversed( [2..Length( elabser )] ) do
- tmpU := Image( fachom[step], tmpU );
- U[step-1] := tmpU;
- od;
-
- # loop over the elementary abelian series
-
- for step in [2..Length( elabser )] do
-
- InfoAgClass1( "#I becs2: step ", step, " / ", Length( elabser ), "\n" );
-
- # get the appropriate new data
-
- fhom := fachom[step];
- facN := PreImage( fhom, TrivialSubgroup( fhom.range ) );
- facU := Intersection( U[step], facN );
-
- # initialize data for this step
-
- newrep := [];
- newcent := [];
- ftree[step] := [];
-
- if IsCentral( fhom.source, facN ) then
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I becs2: coset ", repnum, " / ", Length( rep ), "\n" );
- ecs_ag_centrality_cnt := ecs_ag_centrality_cnt + 1;
- newclasses := CentralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- if not step in split
- or Length( newclasses.representatives ) = Size( facN ) then
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
-
- Append( ftree[step],
- List( newclasses.representatives, x -> repnum ) );
- fi;
- od;
- else
- for repnum in [1..Length( rep )] do
- InfoAgClass2( "#I becs2: coset ", repnum, " / ", Length( rep ), "\n" );
- newclasses := GeneralCaseECSAgGroup(
- fhom.source, facN, cent[repnum], facU, rep[repnum], fhom );
- if not step in split
- or Length( newclasses.representatives ) = Size( facN ) then
- Append( newrep, newclasses.representatives );
- Append( newcent, newclasses.centralizers );
-
- Append( ftree[step],
- List( newclasses.representatives, x -> repnum ) );
- fi;
- od;
- fi;
-
- rep := newrep;
- cent := newcent;
-
- rtree[step] := newrep;
- ctree[step] := newcent;
- od;
-
- ecs_ag_time := Runtime() - ecs_ag_time;
- return rec(
- representatives := rep,
- centralizers := cent,
- naturalHomomorphisms := fachom,
- domains := U,
- elementaryAbelianSeries := elabser,
- representativeTree := rtree,
- centralizerTree := ctree,
- fusionTree := ftree
- );
- end;
-
-
- #############################################################################
- ##
- #F SubEntryNECSAgGroup( <G>, <N>, <C>, <M>, <h>, <cl>, <hom> ) . . . . . . .
- ##
- ## This is the basic subroutine of the function for calculating the number
- ## of conjugacy classes in a soluble group. Its main duty is to solve some
- ## inhomogeneous systems of linear equations and determine the cardinality
- ## of the corresponding set of solutions.
- ##
- ## returns
- ##
- ## <integer>
- ##
- SubEntryNECSAgGroup := function( G, N, C, M, h, cl, hom )
- local num, ncgs, cigs, migs, ndim, clen, mlen, central, h_M_comm,
- N2, n2cgs, N2_c_comm, cg, sol, repnum, rep, tmp, v, g, z, i, j;
-
- if not IsBound( N.field ) then
- N.field := GF( RelativeOrderAgWord( N.generators[1] ) );
- fi;
-
- num := 0;
-
- ncgs := Cgs( N );
- cigs := ShallowCopy( Igs( C ) );
- migs := Igs( M );
- ndim := Length( ncgs );
- clen := Length( cigs );
- mlen := Length( migs );
-
- central := true;
- h_M_comm := [];
- h := FactorAgWord( h, hom.source.identity );
- for i in [1..mlen] do
- h_M_comm[i] := Comm( h, migs[i] );
- if h_M_comm[i] <> N.identity then central := false; fi;
- od;
-
- if central then
- ncs_ag_central_cnt[1] := ncs_ag_central_cnt[1] + 1;
-
- N2 := N;
- n2cgs := ncgs;
- else
- for i in [1..mlen] do
- h_M_comm[i] := Exponents( N, h_M_comm[i], N.field );
- od;
- cg := CommutatorGauss( Copy( h_M_comm ), N.field );
- if cg.commutatorFactor = [] then
- ncs_ag_non_central_cnt[1] := ncs_ag_non_central_cnt[1] + 1;
-
- return 1;
- else
- ncs_ag_non_central_cnt[2] := ncs_ag_non_central_cnt[2] + 1;
-
- tmp := [];
- for i in [1..cg.commutator] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [1..cg.dimensionN] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * ncgs[j] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i] := g;
- od;
- cg.commutator := tmp;
-
- N2 := N mod AgSubgroup( G, cg.commutator, true );
- n2cgs := N2.generators;
- N2.field := N.field;
- fi;
- fi;
-
- for repnum in [1..Length( cl.representatives )] do
- rep := FactorAgWord( cl.representatives[repnum], hom.source.identity );
- N2_c_comm := [];
- for i in [1..Length( n2cgs )] do
- N2_c_comm[i] := Exponents( N2, Comm( n2cgs[i], rep ), N2.field );
- od;
-
- sol := SolutionMat( N2_c_comm, Exponents( N2, Comm( h, rep ), N2.field ) );
-
- if sol <> false then
- num := num + cl.classlengths[repnum]
- * Size( RowSpace( NullspaceMat( N2_c_comm ), N2.field, 0 * sol ) );
- fi;
- od;
-
- return num / Size( C );
- end;
-
-
- #############################################################################
- ##
- #F MainEntryNECSAgGroup( <aggroup>, <aggroup>, <aggroup>, [ <aggroup> ] ) .
- ##
- ## This is the main function of the algorithm for calculating the number of
- ## conjugacy classes in a soluble group. Due to the used algorithm, this
- ## function makes calls to 'MainEntryECSAgGroup' described above for calculating
- ## the conjugacy classes of the found centralizers in the last factorgroup and
- ## then calls its only special subroutine to determine, following the lemma
- ## of cauchy/frobenius, the number of conjugacy classes that are found in each
- ## coset.
- ##
- ## returns
- ##
- ## <integer>
- ##
- MainEntryNECSAgGroup := function( G, U, H, elabser )
- local num, cl, cl2, ec, step, rep, cent, fhom, facN, facU, h, ser, cnum,
- grp, isom, order, tmp, tmp2, i;
-
- if U.generators = [] then return Size( H ); fi;
- if H.generators = [] then return 1; fi;
-
- ncs_ag_time := Runtime();
- ncs_ag_central_cnt := [ 0 ];
- ncs_ag_non_central_cnt := [ 0, 0 ];
-
- # get the conjugacy classes for the biggest factorgroup
-
- cl := MainEntryECSAgGroup( G, U, H, elabser, 1 );
- ec := Equivalenceclasses( cl.centralizers,
- function ( x, y ) return x = y; end );
- Apply( ec.classes, x -> [ x[1], Length( x ) ] );
-
- rep := cl.representatives;
- step := cl.nextStep;
- fhom := cl.naturalHomomorphisms[step];
- facN := PreImage( fhom, TrivialSubgroup( fhom.range ) );
- facU := Intersection( cl.domains[step], facN );
- ser := cl.elementaryAbelianSeries;
-
- # compute elementary abelian series for factor group
-
- elabser := [];
- for i in [1..Length( ser )-1] do Add( elabser, Image( fhom, ser[i] ) ); od;
-
- # initialize the inductive algorithm
-
- num := 0;
-
- # loop over all conjugacy classes of the factor group
-
- for cnum in [1..Length( ec.classes )] do
- cent := ec.classes[cnum][1];
-
- if fhom.range = cent then
- order := Size( fhom.range );
- cl2 := rec(
- representatives := cl.representatives,
- classlengths := List( cl.centralizers, x -> order / Size( x ) )
- );
- else
- tmp := TrivialSubgroup( fhom.range );
- ser := [];
- for grp in elabser do
- tmp2 := Intersection( grp, cent );
- if tmp <> tmp2 then
- Add( ser, tmp2 );
- tmp := tmp2;
- fi;
- od;
- if ser = [] then ser := [ tmp ]; fi;
-
- isom := IsomorphismAgGroup( ser );
- ser := ElementaryAbelianSeries( isom.range );
- cl2 := MainEntryECSAgGroup( isom.range, isom.range, isom.range, ser, 0 );
- order := Size( isom.range );
- cl2 := rec(
- representatives := List( cl2.representatives, x -> PreImagesRepresentative( isom, x ) ),
- classlengths := List( cl2.centralizers, x -> order / Size( x ) )
- );
- fi;
- for i in [1..ec.classes[cnum][2]] do
- h := rep[ec.indices[cnum][i]];
- num := num + SubEntryNECSAgGroup( fhom.source, facN, cent, facU, h, cl2, fhom );
- od;
- od;
- ncs_ag_time := Runtime() - ncs_ag_time;
- return num;
- end;
-
-
- #############################################################################
- ##
- #F SubEntrySECSAgGroup( <G>, <N>, <C>, <M>, <h>, <latt>, <mat>, <integer>, <hom> )
- ##
- ## This is the basic subroutine for the function that calculates the types
- ## of conjugacy classes in a soluble group. It uses the subgroup lattice of the
- ## operating centralizer to determine the transitive constituents of the
- ## operation, which itself is computed via inhomogeneous systems of linear
- ## equations. From this information the desired results are computed.
- ##
- ## returns
- ##
- ## rec(
- ## classlengths := [ <integer> ],
- ## occurences := [ <integer> ]
- ## )
- ##
- SubEntrySECSAgGroup := function( G, N, C, M, h, latt, bs, opord, hom )
- local ncgs, cigs, migs, ndim, clen, mlen, v, g, z,
- central, h_M_comm, N2, n2cgs, cg, facord, bsvec, cllen,
- clnum, group, ugens, gennum, res, N2_c_comm, tmp, i, j;
-
- if not IsBound( N.field ) then
- N.field := GF( RelativeOrderAgWord( N.generators[1] ) );
- fi;
-
- ncgs := Cgs( N );
- cigs := ShallowCopy( Igs( C ) );
- migs := Igs( M );
- ndim := Length( ncgs );
- clen := Length( cigs );
- mlen := Length( migs );
-
- central := true;
- h_M_comm := [];
- h := FactorAgWord( h, hom.source.identity );
- for i in [1..mlen] do
- h_M_comm[i] := Comm( h, migs[i] );
- if h_M_comm[i] <> N.identity then central := false; fi;
- od;
-
- if central then
- scs_ag_central_cnt[1] := scs_ag_central_cnt[1] + 1;
-
- N2 := N;
- n2cgs := ncgs;
- facord := Size( N2 );
- else
- for i in [1..mlen] do
- h_M_comm[i] := Exponents( N, h_M_comm[i], N.field );
- od;
- cg := CommutatorGauss( Copy( h_M_comm ), N.field );
- if cg.commutatorFactor = [] then
- scs_ag_non_central_cnt[1] := scs_ag_non_central_cnt[1] + 1;
-
- return rec(
- classlengths := [ opord / Size( latt.group ) ],
- occurences := [ 1 ]
- );
- else
- scs_ag_non_central_cnt[2] := scs_ag_non_central_cnt[2] + 1;
-
- tmp := [];
- for i in [1..cg.commutator] do
- v := cg.matrix[i];
- g := G.identity;
- for j in [1..cg.dimensionN] do
- z := LogVecFFE( v, j );
- if z <> false then
- g := g * ncgs[j] ^ cg.integers[z+1];
- fi;
- od;
- tmp[i] := g;
- od;
- cg.commutator := tmp;
-
- N2 := N mod AgSubgroup( G, cg.commutator, true );
- n2cgs := N2.generators;
- N2.field := N.field;
- facord := Size( N2.factorNum ) / Size( N2.factorDen );
- fi;
- fi;
-
- bsvec := [ facord ];
- cllen := [ opord / facord ];
- for clnum in [2..Length( latt.classes )] do
- group := latt.classes[clnum].representative;
- ugens := group.generators;
- Apply( ugens, x -> FactorAgWord( x, hom.source.identity ) );
- cllen[clnum] := opord / (Size( group ) * facord);
- gennum := 1;
- res := rec( matrix := [] );
- repeat
- N2_c_comm := [];
- for i in [1..Length( n2cgs )] do
- N2_c_comm[i] := Exponents( N2, Comm( n2cgs[i], ugens[gennum] ), N2.field );
- od;
- res := InHomSolutions( res.matrix, N2_c_comm,
- Exponents( N2, Comm( h, ugens[gennum] ), N2.field ), N2.field );
- gennum := gennum + 1;
- until gennum > Length( ugens ) or res.cardinality = 0;
- bsvec[clnum] := res.cardinality;
- od;
- for i in Reversed( [1..Length( bsvec )-1] ) do
- for j in [i+1..Length( bsvec )] do
- bsvec[i] := bsvec[i] - bsvec[j] * bs[j][i];
- od;
- bsvec[i] := bsvec[i] / bs[i][i];
- od;
- return rec(
- classlengths := cllen,
- occurences := bsvec
- );
- end;
-
-
- #############################################################################
- ##
- #F MainEntrySECSAgGroup( <aggroup>, <aggroup>, <aggroup>, [ <aggroup> ] ) .
- ##
- ## This is the main function for the calculation of the types of
- ## conjugacy classes in a soluble group. This function makes calls to
- ## 'MainEntryECSAgGroup' to determine the classes of elements up to the last
- ## factorgroup and then calculates for each centralizer the whole lattice
- ## of subgroups and the burnside matrix using the author's lattice module.
- ## This information is then passed to the subgoup 'SubEntrySECSAgGroup' which finally
- ## determines the desired result.
- ##
- ## returns
- ##
- ## rec(
- ## classlengths := [ <integer> ],
- ## occurences := [ <integer> ]
- ## )
- ##
- MainEntrySECSAgGroup := function( G, U, H, elabser )
- local cllen, clcnt, cl, ec, step, rep, cent, h, facN, facU,
- ser, cnum, fhom, isom, uord, latt, bs, layer, crep, res, tmp, tmp2, i;
-
- if U.generators = [] then
- return rec(
- classlengths := [ 1 ],
- occurences := [ Size( H ) ]
- );
- fi;
-
- if H.generators = [] then
- return rec(
- classlengths := [ 1 ],
- occurences := [ 1 ]
- );
- fi;
-
- scs_ag_time := Runtime();
- scs_ag_central_cnt := [ 0 ];
- scs_ag_non_central_cnt := [ 0, 0 ];
-
- # get the conjugacy classes for the biggest factorgroup
-
- cl := MainEntryECSAgGroup( G, U, H, elabser, 1 );
- ec := Equivalenceclasses( cl.centralizers,
- function ( x, y ) return x = y; end );
- Apply( ec.classes, x -> [ x[1], Length( x ) ] );
-
- rep := cl.representatives;
- step := cl.nextStep;
- fhom := cl.naturalHomomorphisms[step];
- facN := PreImage( fhom, TrivialSubgroup( fhom.range ) );
- facU := Intersection( cl.domains[step], facN );
- ser := cl.elementaryAbelianSeries;
- uord := Size( U );
-
- # compute elementary abelian series for factor group
-
- elabser := [];
- for i in [1..Length( ser )-1] do Add( elabser, Image( fhom, ser[i] ) ); od;
-
- # initialize the inductive algorithm
-
- cllen := [];
- clcnt := [];
-
- # loop over all conjugacy classes of the factor group
-
- for cnum in [1..Length( ec.classes )] do
- cent := ec.classes[cnum][1];
- isom := NaturalHomomorphism( cent, cent / TrivialSubgroup( cent ) );
- latt := Lattice( isom.range );
- Sort( latt.classes,
- function ( x, y )
- return x.representative.size < y.representative.size;
- end );
- bs := TableOfMarks( latt );
- Apply( latt.classes, x -> ConjugacyClassSubgroups( isom.source,
- PreImage( isom, x.representative ) ) );
-
- for i in [1..ec.classes[cnum][2]] do
- h := rep[ec.indices[cnum][i]];
- res := SubEntrySECSAgGroup( fhom.source, facN, cent, facU, h, latt, bs, uord, fhom );
- Append( cllen, res.classlengths );
- Append( clcnt, res.occurences );
- od;
- od;
-
- # now sort out those entries that do not occur really, i.e. which have
- # an occurence count of zero
-
- tmp := cllen;
- tmp2 := clcnt;
- cllen := [];
- clcnt := [];
- for i in [1..Length( tmp )] do
- if tmp2[i] <> 0 then
- Add( cllen, tmp[i] );
- Add( clcnt, tmp2[i] );
- fi;
- od;
-
- scs_ag_time := Runtime() - scs_ag_time;
- return rec(
- classlengths := cllen,
- occurences := clcnt
- );
- end;
-
-
- #############################################################################
- ##
- #F NumberConjugacyClasses( [<U>, ]<H> ) . . . . . . . . . . . . . . . . . .
- #F . . . . . compute the number of conjugacy classes of elements in a group
- ##
- NumberConjugacyClasses := function( arg )
- if Length( arg ) = 1 then
- return arg[1].operations.NumberConjugacyClasses( arg[1] );
- elif Length( arg ) = 2 then
- return arg[1].operations.NumberConjugacyClasses( arg[1], arg[2] );
- else
- Error( "usage: NumberConjugacyClasses( [<U>, ]<H> )" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F AgGroupOps.NumberConjugacyClasses( [<U>, ]<H> ) . . . . . . . . . . . . .
- #F . . . compute the number of conjugacy classes of elements in an ag-group
- ##
- ## This function determines the number of conjugacy classes of elements in
- ## an ag-group using linear methods. First the conjugacy classes of the group
- ## modulo the last normal subgroup in an elementary abelian series are
- ## computed using 'MainEntryECSAgGroup'. Then for each coset and corresponding
- ## centralizer the number of classes in that coset under the operation of
- ## the centralizer is determined using the lemma of cauchy/frobenius. This
- ## may, for soluble groups, efficiently be done by solving inhomogeneous
- ## systems of linear equations and by determining the conjugacy classes of the
- ## centralizer.
- ##
- ## returns
- ##
- ## <integer>
- ##
- AgGroupOps.NumberConjugacyClasses := function( arg )
- local usage, G, H, U, HU, T, elabser, natisom, number;
-
- if Length( arg ) = 1 then H := arg[1]; U := H;
- elif Length( arg ) = 2 then H := arg[2]; U := arg[1];
- else
- Error( "usage: NumberConjugacyClasses( [<U>, ]<H> )" );
- fi;
-
- G := Parent( H );
- T := TrivialSubgroup( G );
-
- if IsNormal( G, H ) then
- if IsElementaryAbelianAgSeries( G )
- and IsElementAgSeries( H ) then
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- number := MainEntryNECSAgGroup( G, U, H, elabser );
- else
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- number := MainEntryNECSAgGroup(
- natisom.range, Image( natisom, U ), Image( natisom, H ),
- elabser );
- fi;
- elif IsNormal( U, H ) then
- HU := SumAgGroup( H, U );
- elabser := ElementaryAbelianSeries( [ HU, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- number := MainEntryNECSAgGroup(
- natisom.range, Image( natisom, U ), Image( natisom, H ), elabser );
- else
- Error( "sorry, U must operate on H" );
- fi;
-
- return number;
- end;
-
-
- #############################################################################
- ##
- #F StructureConjugacyClasses( [<U>, ]<H> ) . . . . . . . . . . . . . . . . .
- #F . . . . compute the structure of conjugacy classes of elements in a group
- ##
- StructureConjugacyClasses := function( arg )
- if Length( arg ) = 1 then
- return arg[1].operations.StructureConjugacyClasses( arg[1] );
- elif Length( arg ) = 2 then
- return arg[1].operations.StructureConjugacyClasses( arg[1], arg[2] );
- else
- Error( "usage: StructureConjugacyClasses( [<U>, ]<H> )" );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F AgGroupOps.StructureConjugacyClasses( [<U>, ]<H> ) . . . . . . . . . . .
- #F . determine the structure of conjugacy classes of elements in an ag-group
- ##
- ## This function determines the structure of conjugacy classes of elements
- ## in an ag-group using linear methods. First the conjugacy classes of the
- ## group modulo the last normal subgroup in an elementary abelian series are
- ## computed using 'MainEntryECSAgGroup'. Then for each coset and corresponding
- ## centralizer the structure of classes in that coset under the operation of
- ## the centralizer is determined using the burnside matrix of the
- ## centralizer.
- ##
- ## returns
- ##
- ## rec(
- ## classlengths := [ <integer> ],
- ## occurences := [ <integer> ]
- ## )
- ##
- AgGroupOps.StructureConjugacyClasses := function( arg )
- local usage, G, H, U, HU, T, elabser, natisom, strct;
-
- if Length( arg ) = 1 then H := arg[1]; U := H;
- elif Length( arg ) = 2 then H := arg[2]; U := arg[1];
- else
- Error( "usage: StructureConjugacyClasses( [<U>, ]<H> )" );
- fi;
-
- G := Parent( H );
- T := TrivialSubgroup( G );
-
- if IsNormal( G, H ) then
- if IsElementaryAbelianAgSeries( G )
- and IsElementAgSeries( H ) then
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- strct := MainEntrySECSAgGroup( G, U, H, elabser );
- else
- elabser := ElementaryAbelianSeries( [ G, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- strct := MainEntrySECSAgGroup(
- natisom.range, Image( natisom, U ), Image( natisom, H ),
- elabser );
- fi;
- elif IsNormal( U, H ) then
- HU := SumAgGroup( H, U );
- elabser := ElementaryAbelianSeries( [ HU, H, T ] );
- natisom := IsomorphismAgGroup( elabser );
- elabser := ElementaryAbelianSeries( natisom.range );
- strct := MainEntrySECSAgGroup(
- natisom.range, Image( natisom, U ), Image( natisom, H ), elabser );
- else
- Error( "sorry, U must operate on H" );
- fi;
-
- return strct;
- end;
-
-
- AgGroupOps.ConjugacyClass := function( G, g )
- local c;
-
- c := GroupOps.ConjugacyClass( G, g );
- c.operations := ConjugacyClassAgGroupOps;
- return c;
- end;
-
-
- ConjugacyClassAgGroupOps := Copy( ConjugacyClassGroupOps );
-
-
- ConjugacyClassAgGroupOps.\= := function( C, D )
- local isEql;
-
- if IsRec( C ) and IsBound( C.isConjugacyClass )
- and IsRec( D ) and IsBound( D.isConjugacyClass )
- and C.group = D.group
- then
- isEql := C.group.operations.ConjugacyTest( C.group,
- [ C.representative, D.representative ] ) <> false;
- else
- isEql := DomainOps.\=( C, D );
- fi;
- return isEql;
- end;
-
-
- ConjugacyClassAgGroupOps.\in := function( g, C )
- return C.group.operations.ConjugacyTest( C.group, [g,C.representative] )
- <>
- false;
- end;
-
-
- #############################################################################
- ##
- #E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
- ##
- ## Local Variables:
- ## mode: outline
- ## outline-regexp: "#F\\|#V\\|#E"
- ## fill-column: 73
- ## fill-prefix: "## "
- ## eval: (hide-body)
- ## End:
- ##
-