############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Thomas Breuer. ## ## Copyright of GAP belongs to its developers, whose names are too numerous ## to list here. Please refer to the COPYRIGHT file for details. ## ## SPDX-License-Identifier: GPL-2.0-or-later ## ## This file contains generic methods for class functions. ## ## 2. Basic Operations for Class Functions ## 3. Comparison of Class Functions ## 4. Arithmetic Operations for Class Functions ## 5. Printing Class Functions ## 6. Creating Class Functions from Values Lists ## 7. Creating Class Functions using Groups ## 8. Operations for Class Functions ## 9. Restricted and Induced Class Functions ## 10. Reducing Virtual Characters ## 11. Symmetrizations of Class Functions ## 12. Operations for Brauer Characters ## 13. Domains Generated by Class Functions ## 14. Auxiliary operations ##
############################################################################# ## #F CharacterString( <char>, <str> ) . . . . . character information string ##
InstallGlobalFunction( CharacterString, function( char, str )
str:= Concatenation( str, " of degree ", String( char[1] ) );
ConvertToStringRep( str );
return str; end );
############################################################################# ## ## 2. Basic Operations for Class Functions ##
############################################################################# ## #M ValuesOfClassFunction( <list> ) ## ## In order to treat lists as class functions where this makes sense, ## we define that `ValuesOfClassFunction' returns the list <list> itself. ##
InstallOtherMethod( ValuesOfClassFunction, "for a dense list",
[ IsDenseList ], function( list ) if IsClassFunction( list ) and not HasValuesOfClassFunction( list ) then
Error( "class function <list> must store its values list" ); else
return list; fi; end );
############################################################################# ## #M \[\]( <psi>, <i> ) #M Length( <psi> ) #M IsBound\[\]( <psi>, <i> ) #M Position( <psi>, <obj>, 0 ) ## ## Class functions shall behave as immutable lists, ## we install methods for `\[\]', `Length', `IsBound\[\]', `Position', ## and `ShallowCopy'. ##
InstallMethod( \[\], "for class function and positive integer",
[ IsClassFunction, IsPosInt ], function( chi, i )
return ValuesOfClassFunction( chi )[i]; end );
InstallMethod( Length, "for class function",
[ IsClassFunction ],
chi -> Length( ValuesOfClassFunction( chi ) ) );
InstallMethod( IsBound\[\], "for class function and positive integer",
[ IsClassFunction, IsPosInt ], function( chi, i )
return IsBound( ValuesOfClassFunction( chi )[i] ); end );
InstallMethod( Position, "for class function, cyclotomic, and nonnegative integer",
[ IsClassFunction, IsCyc, IsInt ], function( chi, obj, pos )
return Position( ValuesOfClassFunction( chi ), obj, pos ); end );
InstallMethod( ShallowCopy, "for class function",
[ IsClassFunction ],
chi -> ShallowCopy( ValuesOfClassFunction( chi ) ) );
############################################################################# ## #M UnderlyingGroup( <chi> ) ##
InstallOtherMethod( UnderlyingGroup, "for a class function",
[ IsClassFunction ],
chi -> UnderlyingGroup( UnderlyingCharacterTable( chi ) ) );
############################################################################# ## ## 3. Comparison of Class Functions ##
############################################################################# ## #M \=( <chi>, <psi> ) . . . . . . . . . . . . . equality of class functions ##
InstallMethod( \=, "for two class functions",
[ IsClassFunction, IsClassFunction ], function( chi, psi )
return ValuesOfClassFunction( chi ) = ValuesOfClassFunction( psi ); end );
InstallMethod( \=, "for a class function and a list",
[ IsClassFunction, IsList ], function( chi, list ) if IsClassFunction( list ) then
return ValuesOfClassFunction( chi ) = ValuesOfClassFunction( list ); else
return ValuesOfClassFunction( chi ) = list; fi; end );
InstallMethod( \=, "for a list and a class function",
[ IsList, IsClassFunction ], function( list, chi ) if IsClassFunction( list ) then
return ValuesOfClassFunction( list ) = ValuesOfClassFunction( chi ); else
return list = ValuesOfClassFunction( chi ); fi; end );
############################################################################# ## #M \<( <chi>, <psi> ) . . . . . . . . . . . . comparison of class functions ##
InstallMethod( \<, "for two class functions",
[ IsClassFunction, IsClassFunction ], function( chi, psi )
return ValuesOfClassFunction( chi ) < ValuesOfClassFunction( psi ); end );
InstallMethod( \<, "for a class function and a list",
[ IsClassFunction, IsList ], function( chi, list ) if IsClassFunction( list ) then
return ValuesOfClassFunction( chi ) < ValuesOfClassFunction( list ); else
return ValuesOfClassFunction( chi ) < list; fi; end );
InstallMethod( \<, "for a list and a class function",
[ IsClassFunction, IsList ], function( list, chi ) if IsClassFunction( list ) then
return ValuesOfClassFunction( list ) < ValuesOfClassFunction( chi ); else
return list < ValuesOfClassFunction( chi ); fi; end );
############################################################################# ## ## 4. Arithmetic Operations for Class Functions ##
############################################################################# ## #M \+( <chi>, <obj> ) . . . . . . . . . . sum of class function and object #M \+( <obj>, <chi> ) . . . . . . . . . . sum of object and class function #M \+( <chi>, <psi> ) . . . . . . . . . . . . . . sum of virtual characters #M \+( <chi>, <psi> ) . . . . . . . . . . . . . . . . . . sum of characters ## ## The sum of two class functions (virtual characters, characters) of the ## same character table is again a class function (virtual character, ## character) of this table. ## In all other cases, the addition is delegated to the list of values of ## the class function(s). ##
InstallOtherMethod( \+, "for class function, and object",
[ IsClassFunction, IsObject ], function( chi, obj )
local tbl, sum;
tbl:= UnderlyingCharacterTable( chi ); if IsClassFunction( obj ) and
IsIdenticalObj( tbl, UnderlyingCharacterTable( obj ) ) then
sum:= ClassFunction( tbl,
ValuesOfClassFunction( chi ) + ValuesOfClassFunction( obj ) ); else
sum:= ValuesOfClassFunction( chi ) + obj; fi;
return sum; end );
InstallOtherMethod( \+, "for object, and class function",
[ IsObject, IsClassFunction ], function( obj, chi )
local tbl, sum;
tbl:= UnderlyingCharacterTable( chi ); if IsClassFunction( obj ) and
IsIdenticalObj( tbl, UnderlyingCharacterTable( obj ) ) then
sum:= ClassFunction( tbl,
ValuesOfClassFunction( obj ) + ValuesOfClassFunction( chi ) ); else
sum:= obj + ValuesOfClassFunction( chi ); fi;
return sum; end );
InstallMethod( \+, "for two virtual characters",
IsIdenticalObj,
[ IsClassFunction and IsVirtualCharacter,
IsClassFunction and IsVirtualCharacter ], function( chi, psi )
local tbl, sum;
tbl:= UnderlyingCharacterTable( chi );
sum:= ValuesOfClassFunction( chi ) + ValuesOfClassFunction( psi ); if IsIdenticalObj( tbl, UnderlyingCharacterTable( psi ) ) then
sum:= VirtualCharacter( tbl, sum ); fi;
return sum; end );
InstallMethod( \+, "for two characters",
IsIdenticalObj,
[ IsClassFunction and IsCharacter, IsClassFunction and IsCharacter ], function( chi, psi )
local tbl, sum;
tbl:= UnderlyingCharacterTable( chi );
sum:= ValuesOfClassFunction( chi ) + ValuesOfClassFunction( psi ); if IsIdenticalObj( tbl, UnderlyingCharacterTable( psi ) ) then
sum:= Character( tbl, sum ); fi;
return sum; end );
############################################################################# ## #M AdditiveInverseOp( <psi> ) . . . . . . . . . . . . for a class function ## ## The additive inverse of a virtual character is again a virtual character, ## but the additive inverse of a character is not a character, ## so we cannot use `ClassFunctionSameType'. ##
InstallMethod( AdditiveInverseOp, "for a class function",
[ IsClassFunction ],
psi -> ClassFunction( UnderlyingCharacterTable( psi ),
AdditiveInverse( ValuesOfClassFunction( psi ) ) ) );
############################################################################# ## #M ZeroOp( <psi> ) . . . . . . . . . . . . . . . . . . for a class function ##
InstallMethod( ZeroOp, "for a class function",
[ IsClassFunction ],
psi -> VirtualCharacter( UnderlyingCharacterTable( psi ),
Zero( ValuesOfClassFunction( psi ) ) ) );
############################################################################# ## #M \*( <cyc>, <psi> ) . . . . . . . . . scalar multiple of a class function #M \*( <psi>, <cyc> ) . . . . . . . . . scalar multiple of a class function ## ## We define a multiplication only for two class functions (being the tensor ## product), for scalar multiplication with cyclotomics, ## and for default list times class function (where the class function acts ## as a scalar). ## Note that more is not needed, since class functions are not in ## `IsMultiplicativeGeneralizedRowVector'. ##
InstallMethod( \*, "for cyclotomic, and class function",
[ IsCyc, IsClassFunction ], function( cyc, chi )
return ClassFunction( UnderlyingCharacterTable( chi ),
cyc * ValuesOfClassFunction( chi ) ); end );
InstallMethod( \*, "for integer, and virtual character",
[ IsInt, IsVirtualCharacter ], function( cyc, chi )
return VirtualCharacter( UnderlyingCharacterTable( chi ),
cyc * ValuesOfClassFunction( chi ) ); end );
InstallMethod( \*, "for positive integer, and character",
[ IsPosInt, IsCharacter ], function( cyc, chi )
return Character( UnderlyingCharacterTable( chi ),
cyc * ValuesOfClassFunction( chi ) ); end );
InstallMethod( \*, "for class function, and cyclotomic",
[ IsClassFunction, IsCyc ], function( chi, cyc )
return ClassFunction( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) * cyc ); end );
InstallMethod( \*, "for virtual character, and integer",
[ IsVirtualCharacter, IsInt ], function( chi, cyc )
return VirtualCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) * cyc ); end );
InstallMethod( \*, "for character, and positive integer",
[ IsCharacter, IsPosInt ], function( chi, cyc )
return Character( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) * cyc ); end );
############################################################################# ## #M OneOp( <psi> ) . . . . . . . . . . . . . . . . . . for a class function ##
InstallMethod( OneOp, "for class function",
[ IsClassFunction ],
psi -> TrivialCharacter( UnderlyingCharacterTable( psi ) ) );
############################################################################# ## #M \*( <chi>, <psi> ) . . . . . . . . . . tensor product of class functions ##
InstallMethod( \*, "for two class functions",
[ IsClassFunction, IsClassFunction ], function( chi, psi )
local tbl, valschi, valspsi;
tbl:= UnderlyingCharacterTable( chi ); if not IsIdenticalObj( tbl, UnderlyingCharacterTable( psi ) ) then
Error( "no product of class functions of different tables" ); fi;
valschi:= ValuesOfClassFunction( chi );
valspsi:= ValuesOfClassFunction( psi );
return ClassFunction( tbl,
List( [ 1 .. Length( valschi ) ],
x -> valschi[x] * valspsi[x] ) ); end );
InstallMethod( \*, "for two virtual characters",
IsIdenticalObj,
[ IsVirtualCharacter, IsVirtualCharacter ], function( chi, psi )
local tbl, valschi, valspsi;
tbl:= UnderlyingCharacterTable( chi ); if not IsIdenticalObj( tbl, UnderlyingCharacterTable( psi ) ) then
Error( "no product of class functions of different tables" ); fi;
valschi:= ValuesOfClassFunction( chi );
valspsi:= ValuesOfClassFunction( psi );
return VirtualCharacter( tbl,
List( [ 1 .. Length( valschi ) ],
x -> valschi[x] * valspsi[x] ) ); end );
InstallMethod( \*, "for two characters",
IsIdenticalObj,
[ IsCharacter, IsCharacter ], function( chi, psi )
local tbl, valschi, valspsi;
tbl:= UnderlyingCharacterTable( chi ); if not IsIdenticalObj( tbl, UnderlyingCharacterTable( psi ) ) then
Error( "no product of class functions of different tables" ); fi;
valschi:= ValuesOfClassFunction( chi );
valspsi:= ValuesOfClassFunction( psi );
return Character( tbl,
List( [ 1 .. Length( valschi ) ],
x -> valschi[x] * valspsi[x] ) ); end );
############################################################################# ## #M \*( <chi>, <list> ) . . . . . . . . . . class function times default list #M \*( <list>, <chi> ) . . . . . . . . . . default list times class function ##
InstallOtherMethod( \*, "for class function, and list in `IsListDefault'",
[ IsClassFunction, IsListDefault ], function( chi, list )
return List( list, entry -> chi * entry ); end );
InstallOtherMethod( \*, "for list in `IsListDefault', and class function",
[ IsListDefault, IsClassFunction ], function( list, chi )
return List( list, entry -> entry * chi ); end );
############################################################################# ## #M Order( <chi> ) . . . . . . . . . . . . . . . . order of a class function ## ## Note that we are not allowed to regard the determinantal order of an ## arbitrary (virtual) character as its order, ## since nonlinear characters do not have an order as mult. elements. ##
InstallMethod( Order, "for a class function",
[ IsClassFunction ], function( chi )
local order, values;
values:= ValuesOfClassFunction( chi ); if0 in values then
Error( "<chi> is not invertible" ); elif ForAny( values, cyc -> not IsIntegralCyclotomic( cyc )
or cyc * GaloisCyc( cyc, -1 ) <> 1 ) then
return infinity; fi;
order:= Conductor( values ); if order mod 2 = 1 and ForAny( values, i -> i^order <> 1 ) then
order:= 2*order; fi;
return order; end );
############################################################################# ## #M InverseOp( <chi> ) . . . . . . . . . . . . . . . . for a class function ##
InstallMethod( InverseOp, "for a class function",
[ IsClassFunction ], function( chi )
local values;
values:= List( ValuesOfClassFunction( chi ), Inverse ); if fail in values then
return fail; elif HasIsCharacter( chi ) and IsCharacter( chi ) and values[1] = 1then
return Character( UnderlyingCharacterTable( chi ), values ); else
return ClassFunction( UnderlyingCharacterTable( chi ), values ); fi; end );
############################################################################# ## #M \^( <chi>, <n> ) . . . . . . . . . . for class function and pos. integer ##
InstallOtherMethod( \^, "for class function and positive integer (pointwise powering)",
[ IsClassFunction, IsPosInt ], function( chi, n )
return ClassFunctionSameType( UnderlyingCharacterTable( chi ),
chi,
List( ValuesOfClassFunction( chi ), x -> x^n ) ); end );
############################################################################# ## #M \^( <chi>, <g> ) . . . . . conjugate class function under action of <g> ##
InstallMethod( \^, "for class function and group element",
[ IsClassFunction, IsMultiplicativeElementWithInverse ], function( chi, g )
local tbl, G, mtbl, pi, fus, inv, imgs;
tbl:= UnderlyingCharacterTable( chi ); if HasUnderlyingGroup( tbl ) then # 'chi' is an ordinary character.
G:= UnderlyingGroup( tbl ); if IsElmsColls( FamilyObj( g ), FamilyObj( G ) ) then
return ClassFunctionSameType( tbl, chi,
Permuted( ValuesOfClassFunction( chi ),
CorrespondingPermutations( tbl, chi, [ g ] )[1] ) ); fi; elif HasOrdinaryCharacterTable( tbl ) then # 'chi' is a Brauer character.
mtbl:= tbl;
tbl:= OrdinaryCharacterTable( mtbl ); if HasUnderlyingGroup( tbl ) then
G:= UnderlyingGroup( tbl ); if IsElmsColls( FamilyObj( g ), FamilyObj( G ) ) then
pi:= CorrespondingPermutations( tbl, [ g ] )[1]^-1;
fus:= GetFusionMap( mtbl, tbl );
inv:= InverseMap( fus );
imgs:= List( [ 1 .. Length( fus ) ], i -> inv[ fus[i]^pi ] );
return ClassFunctionSameType( mtbl, chi,
ValuesOfClassFunction( chi ){ imgs } ); fi; fi; fi;
TryNextMethod(); end );
############################################################################# ## #M \^( <chi>, <galaut> ) . . . Galois automorphism <galaut> applied to <chi> ##
InstallOtherMethod( \^, "for class function and Galois automorphism",
[ IsClassFunction, IsGeneralMapping ], function( chi, galaut ) if IsANFAutomorphismRep( galaut ) then
galaut:= galaut!.galois;
return ClassFunctionSameType( UnderlyingCharacterTable( chi ), chi,
List( ValuesOfClassFunction( chi ),
x -> GaloisCyc( x, galaut ) ) ); elif IsOne( galaut ) then
return chi; else
TryNextMethod(); fi; end );
############################################################################# ## #M \^( <chi>, <G> ) . . . . . . . . . . . . . . . . induced class function #M \^( <chi>, <tbl> ) . . . . . . . . . . . . . . . induced class function ##
InstallOtherMethod( \^, "for class function and group",
[ IsClassFunction, IsGroup ],
InducedClassFunction );
InstallOtherMethod( \^, "for class function and nearly character table",
[ IsClassFunction, IsNearlyCharacterTable ],
InducedClassFunction );
############################################################################# ## #M \^( <g>, <chi> ) . . . . . . . . . . value of <chi> on group element <g> ##
InstallOtherMethod( \^,
[ IsMultiplicativeElementWithInverse, IsClassFunction ], function( g, chi )
local tbl, mtbl, ccl, i;
tbl:= UnderlyingCharacterTable( chi ); if HasOrdinaryCharacterTable( tbl ) then # 'chi' is a Brauer character.
mtbl:= tbl;
tbl:= OrdinaryCharacterTable( mtbl ); if not HasUnderlyingGroup( tbl ) then
Error( "table <tbl> of <chi> does not store its group" ); elif not g in UnderlyingGroup( tbl )
or Order( g ) mod UnderlyingCharacteristic( mtbl ) = 0then
Error( "<g> must be p-regular and lie in the underlying group of <chi>" ); else
ccl:= ConjugacyClasses( tbl ){ GetFusionMap( mtbl, tbl ) }; fi; elif not HasUnderlyingGroup( tbl ) then
Error( "table <tbl> of <chi> does not store its group" ); elif not g in UnderlyingGroup( tbl ) then
Error( "<g> must lie in the underlying group of <chi>" ); else
ccl:= ConjugacyClasses( tbl ); fi;
for i in [ 1 .. Length( ccl ) ] do if g in ccl[i] then
return ValuesOfClassFunction( chi )[i]; fi;
od; end );
############################################################################# ## #M \^( <psi>, <chi> ) . . . . . . . . . . conjugation of linear characters ##
InstallOtherMethod( \^, "for two class functions (conjugation, trivial action)",
[ IsClassFunction, IsClassFunction ],
ReturnFirst);
############################################################################# ## #M GlobalPartitionOfClasses( <tbl> ) ##
InstallMethod( GlobalPartitionOfClasses, "for an ordinary character table",
[ IsOrdinaryTable ], function( tbl )
local part, # partition that has to be respected
list, # list of all maps to be respected
map, # one map in 'list'
inv, # contains number of root classes
newpart, #
values, #
j, # loop over 'orb'
pt; # one point to map
if HasAutomorphismsOfTable( tbl ) then
# The orbits define the finest possible global partition.
part:= OrbitsDomain( AutomorphismsOfTable( tbl ),
[ 1 .. Length( NrConjugacyClasses( tbl ) ) ] );
else
# Conjugate classes must have same representative order and # same centralizer order.
list:= [ OrdersClassRepresentatives( tbl ),
SizesCentralizers( tbl ) ];
# The number of root classes is by definition invariant under # table automorphisms. for map in Compacted( ComputedPowerMaps( tbl ) ) do
inv:= ZeroMutable( map ); for j in map do
inv[j]:= inv[j] + 1;
od;
Add( list, inv );
od;
# All elements in `list' must be respected. # Transform each of them into a partition, # and form the intersection of these partitions.
part:= Partition( [ [ 1 .. Length( list[1] ) ] ] ); for map in list do
newpart := [];
values := []; for j in [ 1 .. Length( map ) ] do
pt:= Position( values, map[j] ); if pt = fail then
Add( values, map[j] );
Add( newpart, [ j ] ); else
Add( newpart[ pt ], j ); fi;
od;
StratMeetPartition( part, Partition( newpart ) );
od;
part:= List( Cells( part ), Set ); #T unfortunately `Set' necessary ...
fi;
return part; end );
############################################################################# ## #M CorrespondingPermutations( <tbl>, <elms> ) . action on the conj. classes ##
InstallMethod( CorrespondingPermutations, "for character table and list of group elements",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, elms )
local classes, # list of conjugacy classes
perms, # list of permutations, result
part, # partition that has to be respected
base, # base of aut. group
g, # loop over `elms'
images, # list of images
pt, # one point to map
im, # actual image class
orb, # possible image points
found, # image point found? (boolean value)
j, # loop over 'orb'
list, # one list in 'part'
first, # first point in orbit of 'g'
min; # minimal length of nontrivial orbit of 'g'
classes:= ConjugacyClasses( tbl );
perms:= [];
# If the table automorphisms are known then we only must determine # the images of a base of this group. if HasAutomorphismsOfTable( tbl ) then
part:= AutomorphismsOfTable( tbl );
if IsTrivial( part ) then
return ListWithIdenticalEntries( Length( elms ), () ); fi;
# Compute the images of the base points of this group.
base:= BaseOfGroup( part );
for g in elms do
if IsOne( g ) then
# If `g' is the identity then nothing is to do.
Add( perms, () );
else
images:= []; for pt in base do
im:= Representative( classes[ pt ] ) ^ g;
found:= false; for j in Orbit( part, pt ) do #T better CanonicalClassElement ?? if im in classes[j] then
Add( images, j );
found:= true;
break; fi;
od;
od;
# Compute a group element.
Add( perms,
RepresentativeAction( part, base, images, OnTuples ) );
fi;
od;
else
# We can use only a partition into unions of orbits.
part:= GlobalPartitionOfClasses( tbl ); if Length( part ) = Length( classes ) then
return ListWithIdenticalEntries( Length( elms ), () ); fi;
for g in elms do #T It would be more natural to write #T Permutation( g, ConjugacyClasses( tbl ), OnPoints ), #T *BUT* the `Permutation' method in question first asks whether #T the list of classes is sorted, #T and there is no method to compare the classes!
if IsOne( g ) then
# If `g' is the identity then nothing is to do.
Add( perms, () );
else
# Compute orbits of `g' on the lists in `part', store the images. # Note that if we have taken away a union of orbits such that the # number of remaining points is smaller than the smallest prime # divisor of the order of `g' then all these points must be fixed.
min:= Factors(Integers, Order( g ) )[1];
images:= [];
for list in part do
if Length( list ) = 1then #T why not `min' ?
# necessarily fixed point
images[ list[1] ]:= list[1];
else
orb:= ShallowCopy( list ); while min <= Length( orb ) do
# There may be nontrivial orbits.
pt:= orb[1];
first:= pt;
j:= 1;
while j <= Length( orb ) do
im:= Representative( classes[ pt ] ) ^ g;
found:= false; while j <= Length( orb ) and not found do #T better CanonicalClassElement ?? if im in classes[ orb[j] ] then
images[pt]:= orb[j];
found:= true; fi;
j:= j+1;
od;
RemoveSet( orb, pt );
if found and pt <> images[ pt ] then
pt:= images[ pt ];
j:= 1; fi;
od;
# The image must be the first point of the orbit under `g'.
images[pt]:= first;
od;
# The remaining points of the orbit must be fixed. for pt in orb do
images[pt]:= pt;
od;
fi;
od;
# Compute a group element.
Add( perms, PermList( images ) );
fi;
od;
fi;
return perms; end );
############################################################################# ## #M CorrespondingPermutations( <tbl>, <chi>, <elms> ) ##
InstallOtherMethod( CorrespondingPermutations, "for a char. table, a hom. list, and a list of group elements",
[ IsOrdinaryTable, IsHomogeneousList, IsHomogeneousList ], function( tbl, values, elms )
local classes, # list of conjugacy classes
perms, # list of permutations, result
part, # partition that has to be respected
base, # base of aut. group
g, # loop over `elms'
images, # list of images
pt, # one point to map
im, # actual image class
orb, # possible image points
found, # image point found? (boolean value)
j, # loop over 'orb'
list, # one list in 'part'
first, # first point in orbit of 'g'
min; # minimal length of nontrivial orbit of 'g'
classes:= ConjugacyClasses( tbl );
perms:= [];
# If the table automorphisms are known then we only must determine # the images of a base of this group. if HasAutomorphismsOfTable( tbl ) then
part:= AutomorphismsOfTable( tbl );
if IsTrivial( part ) then
return ListWithIdenticalEntries( Length( elms ), () ); fi;
# Compute the images of the base points of this group.
base:= BaseOfGroup( part );
for g in elms do
if IsOne( g ) then
# If `g' is the identity then nothing is to do.
Add( perms, () );
else
images:= []; for pt in base do
im:= Representative( classes[ pt ] ) ^ g;
found:= false; for j in Orbit( part, pt ) do #T better CanonicalClassElement ?? if im in classes[j] then
Add( images, j );
found:= true;
break; fi;
j:= j+1;
od;
od;
# Compute a group element (if possible).
Add( perms,
RepresentativeAction( part, base, images, OnTuples ) );
fi;
od;
else
# We can use only a partition into unions of orbits.
part:= GlobalPartitionOfClasses( tbl ); if Length( part ) = Length( classes ) then
return ListWithIdenticalEntries( Length( elms ), () ); fi;
for g in elms do
if IsOne( g ) then
# If `g' is the identity then nothing is to do.
Add( perms, () );
else
# Compute orbits of `g' on the lists in `part', store the images. # Note that if we have taken away a union of orbits such that the # number of remaining points is smaller than the smallest prime # divisor of the order of `g' then all these points must be fixed.
min:= Factors(Integers, Order( g ) )[1];
images:= [];
for list in part do
if Length( list ) = 1then #T why not `min' ?
# necessarily fixed point
images[ list[1] ]:= list[1];
elif Length( Set( values{ list } ) ) = 1then
# We may take any permutation of the orbit. for j in list do
images[j]:= j;
od;
else
orb:= ShallowCopy( list ); while Length( orb ) >= min do #T fishy for S4 acting on V4 !!
# There may be nontrivial orbits.
pt:= orb[1];
first:= pt;
j:= 1;
while j <= Length( orb ) do
im:= Representative( classes[ pt ] ) ^ g;
found:= false; while j <= Length( orb ) and not found do #T better CanonicalClassElement ?? if im in classes[ orb[j] ] then
images[pt]:= orb[j];
found:= true; fi;
j:= j+1;
od;
RemoveSet( orb, pt );
if found then
j:= 1;
pt:= images[pt]; fi;
od;
# The image must be the first point of the orbit under `g'.
images[pt]:= first;
od;
# The remaining points of the orbit must be fixed. for pt in orb do
images[pt]:= pt;
od;
fi;
od;
# Compute a group element.
Add( perms, PermList( images ) );
fi;
od;
fi;
return perms; end );
############################################################################# ## #M ComplexConjugate( <chi> ) ## ## We use `InstallOtherMethod' because class functions are both scalars and ## lists, so the method matches two declarations of the operation. ##
InstallOtherMethod( ComplexConjugate, "for a class function",
[ IsClassFunction and IsCyclotomicCollection ],
chi -> GaloisCyc( chi, -1 ) );
############################################################################# ## #M GaloisCyc( <chi>, <k> ) ##
InstallMethod( GaloisCyc, "for a class function, and an integer",
[ IsClassFunction and IsCyclotomicCollection, IsInt ], function( chi, k )
local tbl, char, n, g;
tbl:= UnderlyingCharacterTable( chi );
char:= UnderlyingCharacteristic( tbl );
n:= Conductor( chi );
g:= Gcd( k, n );
if k = -1 or
( char = 0 and g = 1 ) then
return ClassFunctionSameType( tbl, chi,
GaloisCyc( ValuesOfClassFunction( chi ), k ) ); #T also if k acts as some *(p^d) for char = p #T (reduce k mod n, and then what?) else
return ClassFunction( tbl,
GaloisCyc( ValuesOfClassFunction( chi ), k ) ); fi; end );
############################################################################# ## #M Permuted( <chi>, <perm> ) ##
InstallMethod( Permuted, "for a class function, and a permutation",
[ IsClassFunction, IsPerm ], function( chi, perm )
return ClassFunction( UnderlyingCharacterTable( chi ),
Permuted( ValuesOfClassFunction( chi ), perm ) ); end );
############################################################################# ## ## 5. Printing Class Functions ##
############################################################################# ## #M ViewObj( <psi> ) . . . . . . . . . . . . . . . . . view a class function ## ## Note that class functions are finite lists, so the default `ViewObj' ## method for finite lists should be avoided. ##
InstallMethod( ViewObj, "for a class function",
[ IsClassFunction ], function( psi )
Print( "ClassFunction( " );
View( UnderlyingCharacterTable( psi ) );
Print( ",\<\<\<\>\>\> " );
View( ValuesOfClassFunction( psi ) );
Print( " )" ); end );
############################################################################# ## #M PrintObj( <psi> ) . . . . . . . . . . . . . . . . print a class function ##
InstallMethod( PrintObj, "for a class function",
[ IsClassFunction ], function( psi )
Print( "ClassFunction( ", UnderlyingCharacterTable( psi ), ", ", ValuesOfClassFunction( psi ), " )" ); end );
InstallMethod( PrintObj, "for a virtual character",
[ IsClassFunction and IsVirtualCharacter ], function( psi )
Print( "VirtualCharacter( ", UnderlyingCharacterTable( psi ), ", ", ValuesOfClassFunction( psi ), " )" ); end );
InstallMethod( PrintObj, "for a character",
[ IsClassFunction and IsCharacter ], function( psi )
Print( "Character( ", UnderlyingCharacterTable( psi ), ", ", ValuesOfClassFunction( psi ), " )" ); end );
############################################################################# ## #M Display( <chi> ) . . . . . . . . . . . . . . . display a class function #M Display( <chi>, <arec> ) ##
InstallMethod( Display, "for a class function",
[ IsClassFunction ], function( chi )
Display( UnderlyingCharacterTable( chi ), rec( chars:= [ chi ] ) ); end );
InstallOtherMethod( Display, "for a class function, and a record",
[ IsClassFunction, IsRecord ], function( chi, arec )
arec:= ShallowCopy( arec );
arec.chars:= [ chi ];
Display( UnderlyingCharacterTable( chi ), arec ); end );
############################################################################# ## ## 6. Creating Class Functions from Values Lists ##
############################################################################# ## #M ClassFunction( <tbl>, <values> ) ##
InstallMethod( ClassFunction, "for nearly character table, and dense list",
[ IsNearlyCharacterTable, IsDenseList ], function( tbl, values )
local chi;
# Check the no. of classes. if NrConjugacyClasses( tbl ) <> Length( values ) then
Error( "no. of classes in <tbl> and <values> must be equal" ); fi;
# Create the object.
chi:= Objectify( NewType( FamilyObj( values ),
IsClassFunction
and IsAttributeStoringRep ),
rec() );
# Store the defining attribute values.
SetValuesOfClassFunction( chi, ValuesOfClassFunction( values ) );
SetUnderlyingCharacterTable( chi, tbl );
# Store useful information. if IsSmallList( values ) then
SetIsSmallList( chi, true ); fi;
return chi; end );
############################################################################# ## #M ClassFunction( <G>, <values> ) ##
InstallMethod( ClassFunction, "for a group, and a dense list",
[ IsGroup, IsDenseList ], function( G, values )
return ClassFunction( OrdinaryCharacterTable( G ), values ); end );
############################################################################# ## #M Character( <G>, <values> ) ##
InstallMethod( Character, "for a group, and a dense list",
[ IsGroup, IsDenseList ], function( G, values )
return Character( OrdinaryCharacterTable( G ), values ); end );
############################################################################# ## #F ClassFunctionSameType( <tbl>, <chi>, <values> ) ##
InstallGlobalFunction( ClassFunctionSameType, function( tbl, chi, values ) if not IsClassFunction( chi ) then
return values; elif HasIsCharacter( chi ) and IsCharacter( chi ) then
return Character( tbl, values ); elif HasIsVirtualCharacter( chi ) and IsVirtualCharacter( chi ) then
return VirtualCharacter( tbl, values ); else
return ClassFunction( tbl, values ); fi; end );
############################################################################# ## ## 7. Creating Class Functions using Groups ##
############################################################################# ## #M TrivialCharacter( <tbl> ) . . . . . . . . . . . . . for a character table ##
InstallMethod( TrivialCharacter, "for a character table",
[ IsNearlyCharacterTable ], function( tbl )
local chi;
############################################################################# ## #M TrivialCharacter( <G> ) . . . . . . . . . . . . . . . . . . . for a group ##
InstallMethod( TrivialCharacter, "for a group (delegate to the table)",
[ IsGroup ],
G -> TrivialCharacter( OrdinaryCharacterTable( G ) ) );
############################################################################# ## #M NaturalCharacter( <G> ) . . . . . . . . . . . . . for a permutation group ##
InstallMethod( NaturalCharacter, "for a permutation group",
[ IsGroup and IsPermCollection ], function( G )
local deg, tbl;
deg:= NrMovedPoints( G );
tbl:= OrdinaryCharacterTable( G );
return Character( tbl,
List( ConjugacyClasses( tbl ),
C -> deg - NrMovedPoints( Representative( C ) ) ) ); end );
############################################################################# ## #M NaturalCharacter( <G> ) . . . . for a matrix group in characteristic zero ##
InstallMethod( NaturalCharacter, "for a matrix group in characteristic zero",
[ IsGroup and IsRingElementCollCollColl ], function( G )
local tbl; if Characteristic( G ) = 0then
tbl:= OrdinaryCharacterTable( G );
return Character( tbl,
List( ConjugacyClasses( tbl ),
C -> TraceMat( Representative( C ) ) ) ); else
TryNextMethod(); fi; end );
############################################################################# ## #M NaturalCharacter( <hom> ) . . . . . . . . . . . for a group homomorphism ## ## We use shortcuts for homomorphisms onto permutation groups and matrix ## groups in characteristic zero, ## since the meaning of `NaturalCharacter' is clear for these cases and ## we can avoid explicit conjugacy tests in the image. ## For other cases, we use a generic way. ##
InstallMethod( NaturalCharacter, "for a group general mapping",
[ IsGeneralMapping ], function( hom )
local G, R, deg, tbl, chi;
G:= Source( hom );
R:= Range( hom );
tbl:= OrdinaryCharacterTable( G ); if IsPermGroup( R ) then
deg:= NrMovedPoints( R );
return Character( tbl,
List( ConjugacyClasses( tbl ),
C -> deg - NrMovedPoints( ImagesRepresentative( hom,
Representative( C ) ) ) ) ); elif IsMatrixGroup( R ) and Characteristic( R ) = 0then
return Character( tbl,
List( ConjugacyClasses( tbl ),
C -> TraceMat( ImagesRepresentative( hom,
Representative( C ) ) ) ) ); else
chi:= NaturalCharacter( Image( hom ) );
return Character( tbl,
List( ConjugacyClasses( tbl ),
C -> ImagesRepresentative( hom,
Representative( C ) ) ^ chi ) ); fi; end );
############################################################################# ## #M PermutationCharacter( <G>, <U> ) . . . . . . . . . . . . for two groups ##
InstallMethod( PermutationCharacter, "for two groups (use double cosets)",
IsIdenticalObj,
[ IsGroup, IsGroup ], function( G, U )
local tbl, C, c, s, i;
tbl:= OrdinaryCharacterTable( G );
C := ConjugacyClasses( tbl );
c := [ Index( G, U ) ];
s := Size( U );
for i in [ 2 .. Length(C) ] do
c[i]:= Number( DoubleCosets( G, U,
SubgroupNC( G, [ Representative( C[i] ) ] ) ),
x -> Size( x ) = s );
od;
# Return the character.
return Character( tbl, c ); end );
#T ############################################################################# #T ## #T #M PermutationCharacter( <G>, <U> ) . . . . . . . . . for two small groups #T ## #T InstallMethod( PermutationCharacter, #T "for two small groups", #T IsIdenticalObj, #T [ IsGroup and IsSmallGroup, IsGroup and IsSmallGroup ], #T function( G, U ) #T local E, I, tbl; #T #T E := AsList( U ); #T I := Size( G ) / Length( E ); #T tbl:= OrdinaryCharacterTable( G ); #T return Character( tbl, #T List( ConjugacyClasses( tbl ), #T C -> I * Length( Intersection2( AsList( C ), E ) ) / Size( C ) ) ); #T end );
############################################################################# ## ## 8. Operations for Class Functions ##
############################################################################# ## #M IsCharacter( <obj> ) . . . . . . . . . . . . . . for a virtual character ##
InstallMethod( IsCharacter, "for a virtual character",
[ IsClassFunction and IsVirtualCharacter ],
obj -> IsCharacter( UnderlyingCharacterTable( obj ),
ValuesOfClassFunction( obj ) ) );
InstallMethod( IsCharacter, "for a class function",
[ IsClassFunction ], function( obj ) if HasIsVirtualCharacter( obj ) and not IsVirtualCharacter( obj ) then #T can disappear when inverse implications are supported!
return false; fi;
return IsCharacter( UnderlyingCharacterTable( obj ),
ValuesOfClassFunction( obj ) ); end );
InstallMethod( IsCharacter, "for an ordinary character table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, list )
local chi, scpr;
# Proper characters have positive degree. if list[1] <= 0then
return false; fi;
# Check the scalar products with all irreducibles. for chi in Irr( tbl ) do
scpr:= ScalarProduct( tbl, chi, list ); if not IsInt( scpr ) or scpr < 0then
return false; fi;
od;
return true; end );
InstallMethod( IsCharacter, "for a Brauer table, and a homogeneous list",
[ IsBrauerTable, IsHomogeneousList ], function( tbl, list ) # Proper characters have positive degree. if list[1] <= 0then
return false; fi;
# Check the decomposition.
return Decomposition( Irr( tbl ), [ list ], "nonnegative" )[1] <> fail; end );
############################################################################# ## #M IsVirtualCharacter( <chi> ) . . . . . . . . . . . . for a class function ##
InstallMethod( IsVirtualCharacter, "for a class function",
[ IsClassFunction ],
chi -> IsVirtualCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ) );
InstallMethod( IsVirtualCharacter, "for an ordinary character table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, list )
local chi;
# Check the scalar products with all irreducibles. for chi in Irr( tbl ) do if not IsInt( ScalarProduct( tbl, chi, list ) ) then
return false; fi;
od;
return true; end );
# InstallMethod( IsVirtualCharacter, # "for a Brauer table, and a homogeneous list", # [ IsBrauerTable, IsHomogeneousList ], # function( tbl, list ) # ??? # end );
############################################################################# ## #M IsIrreducibleCharacter( <chi> ) . . . . . . . . . for a class function ##
InstallMethod( IsIrreducibleCharacter, "for a class function",
[ IsClassFunction ],
chi -> IsIrreducibleCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ) );
InstallMethod( IsIrreducibleCharacter, "for an ordinary character table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, list )
return IsVirtualCharacter( tbl, list )
and ScalarProduct( tbl, list, list) = 1
and list[1] > 0; end );
InstallMethod( IsIrreducibleCharacter, "for a Brauer table, and a homogeneous list",
[ IsBrauerTable, IsHomogeneousList ], function( tbl, list )
local i, found;
list:= Decomposition( Irr( tbl ), [ list ], "nonnegative" )[1]; if list = fail then
return false; fi;
found:= false; for i in list do if i <> 0then if found or i <> 1then
return false; else
found:= true; fi; fi;
od;
return found; end );
############################################################################# ## #M ScalarProduct( <chi>, <psi> ) . . . . . . . . . . for two class functions ##
InstallMethod( ScalarProduct, "for two class functions",
[ IsClassFunction, IsClassFunction ], function( chi, psi )
local tbl;
tbl:= UnderlyingCharacterTable( chi ); if tbl <> UnderlyingCharacterTable( psi ) then
Error( "<chi> and <psi> have different character tables" ); fi;
return ScalarProduct( tbl, ValuesOfClassFunction( chi ),
ValuesOfClassFunction( psi ) ); end );
############################################################################# ## #M ScalarProduct( <tbl>, <chi>, <psi> ) . scalar product of class functions ##
InstallMethod( ScalarProduct, "for character table and two homogeneous lists",
[ IsCharacterTable, IsRowVector, IsRowVector ], function( tbl, x1, x2 )
local i, # loop variable
scpr, # scalar product, result
weight; # lengths of conjugacy classes
weight:= SizesConjugacyClasses( tbl );
x1:= ValuesOfClassFunction( x1 );
x2:= ValuesOfClassFunction( x2 );
scpr:= 0; for i in [ 1 .. Length( x1 ) ] do if x1[i]<>0 and x2[i]<>0then
scpr:= scpr + x1[i] * GaloisCyc( x2[i], -1 ) * weight[i]; fi;
od;
return scpr / Size( tbl ); end );
############################################################################# ## #F MatScalarProducts( [<tbl>, ]<list1>, <list2> ) #F MatScalarProducts( [<tbl>, ]<list> ) ##
InstallMethod( MatScalarProducts, "for two homogeneous lists",
[ IsHomogeneousList, IsHomogeneousList ], function( list1, list2 ) if IsEmpty( list1 ) then
return []; elif not IsClassFunction( list1[1] ) then
Error( "<list1> must consist of class functions" ); else
return MatScalarProducts( UnderlyingCharacterTable( list1[1] ),
list1, list2 ); fi; end );
InstallMethod( MatScalarProducts, "for a homogeneous list",
[ IsHomogeneousList ], function( list ) if IsEmpty( list ) then
return []; elif not IsClassFunction( list[1] ) then
Error( "<list> must consist of class functions" ); else
return MatScalarProducts( UnderlyingCharacterTable( list[1] ), list ); fi; end );
InstallMethod( MatScalarProducts, "for an ordinary table, and two homogeneous lists",
[ IsOrdinaryTable, IsHomogeneousList, IsHomogeneousList ], function( tbl, list1, list2 )
local i, j, chi, nccl, weight, scprmatrix, order, scpr;
if IsEmpty( list1 ) then
return []; fi;
list1:= List( list1, ValuesOfClassFunction );
scprmatrix:= []; for i in [ 1 .. Length( list2 ) ] do
scprmatrix[i]:= [];
chi:= List( ValuesOfClassFunction( list2[i] ), x -> GaloisCyc(x,-1) ); for j in [ 1 .. nccl ] do
chi[j]:= chi[j] * weight[j];
od; for j in list1 do
scpr:= ( chi * j ) / order;
Add( scprmatrix[i], scpr ); if not IsInt( scpr ) then if IsRat( scpr ) then
Info( InfoCharacterTable, 2, "MatScalarProducts: sum not divisible by group order" ); elif IsCyc( scpr ) then
Info( InfoCharacterTable, 2, "MatScalarProducts: summation not integer valued"); fi; fi;
od;
od;
return scprmatrix; end );
InstallMethod( MatScalarProducts, "for an ordinary table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, list )
local i, j, chi, nccl, weight, scprmatrix, order, scpr;
if IsEmpty( list ) then
return []; fi;
list:= List( list, ValuesOfClassFunction );
scprmatrix:= []; for i in [ 1 .. Length( list ) ] do
scprmatrix[i]:= [];
chi:= List( list[i], x -> GaloisCyc( x, -1 ) ); for j in [ 1 .. nccl ] do
chi[j]:= chi[j] * weight[j];
od; for j in [ 1 .. i ] do
scpr:= ( chi * list[j] ) / order;
Add( scprmatrix[i], scpr ); if not IsInt( scpr ) then if IsRat( scpr ) then
Info( InfoCharacterTable, 2, "MatScalarProducts: sum not divisible by group order" ); elif IsCyc( scpr ) then
Info( InfoCharacterTable, 2, "MatScalarProducts: summation not integer valued"); fi; fi;
od;
od;
return scprmatrix; end );
############################################################################# ## #M Norm( [<tbl>, ]<chi> ) . . . . . . . . . . . . . . norm of class function ##
InstallOtherMethod( Norm, "for a class function",
[ IsClassFunction ],
chi -> ScalarProduct( chi, chi ) );
InstallOtherMethod( Norm, "for an ordinary character table and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, chi )
return ScalarProduct( tbl, chi, chi ); end );
############################################################################# ## #M CentreOfCharacter( [<tbl>, ]<chi> ) . . . . . . . . centre of a character ##
InstallMethod( CentreOfCharacter, "for a class function",
[ IsClassFunction ],
chi -> CentreOfCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ) );
InstallMethod( CentreOfCharacter, "for an ordinary table, and a homogeneous list ",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, list ) if not HasUnderlyingGroup( tbl ) then
Error( "<tbl> does not store its group" ); fi;
return NormalSubgroupClasses( tbl, ClassPositionsOfCentre( list ) ); end );
############################################################################# ## #M ClassPositionsOfCentre( <chi> ) . . classes in the centre of a character ## ## We know that an algebraic integer $\alpha$ is a root of unity ## if and only if all conjugates of $\alpha$ have absolute value at most 1. ## Since $\alpha^{\ast} \overline{\alpha^{\ast}} = 1$ holds for a Galois ## automorphism $\ast$ if and only if $\alpha \overline{\alpha} = 1$ holds, ## a cyclotomic integer is a root of unity iff its absolute value is $1$. ## ## Cf. the comment about the `Order' method for cyclotomics in the file ## `lib/cyclotom.g'. ## ## The `IsCyc' test is necessary to avoid errors in the case that <chi> ## contains unknowns. ##
InstallMethod( ClassPositionsOfCentre, "for a homogeneous list",
[ IsHomogeneousList ], function( chi )
local deg, mdeg, degsquare;
deg:= chi[1];
mdeg:= - deg;
degsquare:= deg^2;
return PositionsProperty( chi,
x -> x = deg or x = mdeg or
( ( not IsInt( x ) ) and IsCyc( x ) and IsCycInt( x )
and x * GaloisCyc( x, -1 ) = degsquare ) ); end );
############################################################################# ## #M ConstituentsOfCharacter( [<tbl>, ]<chi> ) . irred. constituents of <chi> ##
InstallMethod( ConstituentsOfCharacter,
[ IsClassFunction ],
chi -> ConstituentsOfCharacter( UnderlyingCharacterTable( chi ), chi ) );
InstallMethod( ConstituentsOfCharacter, "for an ordinary table, and a character",
[ IsOrdinaryTable, IsClassFunction and IsCharacter ], function( tbl, chi )
local irr, # irreducible characters of `tbl'
values, # character values
deg, # degree of `chi'
const, # list of constituents, result
i, # loop over `irr'
irrdeg, # degree of an irred. character
scpr; # one scalar product
tbl:= UnderlyingCharacterTable( chi );
irr:= Irr( tbl );
values:= ValuesOfClassFunction( chi );
deg:= values[1];
const:= [];
i:= 1; while0 < deg and i <= Length( irr ) do
irrdeg:= DegreeOfCharacter( irr[i] ); if irrdeg <= deg then
scpr:= ScalarProduct( tbl, chi, irr[i] ); if scpr <> 0then
deg:= deg - scpr * irrdeg;
Add( const, irr[i] ); fi; fi;
i:= i+1;
od;
return Set( const ); end );
InstallMethod( ConstituentsOfCharacter, "for an ordinary table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, chi )
local const, # list of constituents, result
proper, # is `chi' a proper character
i, # loop over `irr'
scpr; # one scalar product
const:= [];
proper:= true; for i in Irr( tbl ) do
scpr:= ScalarProduct( tbl, chi, i ); if scpr <> 0then
Add( const, i );
proper:= proper and IsPosInt( scpr ); fi;
od;
# In the case `proper = true' we know that `chi' is a character. if proper then
SetIsCharacter( chi, true ); fi;
return Set( const ); end );
InstallMethod( ConstituentsOfCharacter, "for a Brauer table, and a homogeneous list",
[ IsBrauerTable, IsHomogeneousList ], function( tbl, chi )
local irr, intA, intB, dec;
irr:= Irr( tbl );
intA:= IntegralizedMat( irr );
intB:= IntegralizedMat( [ chi ], intA.inforec );
dec:= SolutionIntMat( intA.mat, intB.mat[1] ); if dec = fail then
Error( "<chi> is not a virtual character of <tbl>" ); fi;
return SortedList( irr{ Filtered( [ 1 .. Length( dec ) ],
i -> dec[i] <> 0 ) } ); end );
############################################################################# ## #M DegreeOfCharacter( <chi> ) . . . . . . . . . . . . for a class function ##
InstallMethod( DegreeOfCharacter, "for a class function",
[ IsClassFunction ],
chi -> ValuesOfClassFunction( chi )[1] );
############################################################################# ## #M InertiaSubgroup( [<tbl>, ]<G>, <chi> ) . inertia subgroup of a character ##
InstallMethod( InertiaSubgroup, "for a group, and a class function",
[ IsGroup, IsClassFunction ], function( G, chi )
return InertiaSubgroup( UnderlyingCharacterTable( chi ), G,
ValuesOfClassFunction( chi ) ); end );
InstallMethod( InertiaSubgroup, "for an ordinary table, a group, and a homogeneous list",
[ IsOrdinaryTable, IsGroup, IsHomogeneousList ], function( tbl, G, chi )
local H, # group of `chi'
index, # index of `H' in `G'
induced, # induced of `chi' from `H' to `G'
global, # global partition of classes
part, # refined partition
p, # one set in `global' and `part'
val, # one value in `p'
values, # list of character values on `p'
new, # list of refinements of `p'
i, # loop over stored partitions
pos, # position where to store new partition later
perms, # permutations corresp. to generators of `G'
permgrp, # group generated by `perms'
stab; # the inertia subgroup, result
# `G' must normalize the group of `chi'.
H:= UnderlyingGroup( tbl ); if not ( IsSubset( G, H ) and IsNormal( G, H ) ) then
Error( "<H> must be a normal subgroup in <G>" ); fi;
# For prime index, check the norm of the induced character. # (We get a decision if `chi' is irreducible.)
index:= Index( G, H ); if IsPrimeInt( index ) then
induced:= InducedClassFunction( tbl, chi, G ); if ScalarProduct( CharacterTable( G ), induced, induced ) = 1then
return H; elif ScalarProduct( tbl, chi, chi ) = 1then
return G; fi; fi;
# Compute the partition that must be stabilized. #T Why is `StabilizerPartition' no longer available? #T In GAP 3.5, there was such a function. # (We need only those cells where `chi' really yields a refinement.)
global:= GlobalPartitionOfClasses( tbl );
part:= []; for p in global do #T only if `p' has length > 1 !
val:= chi[ p[1] ]; if ForAny( p, x -> chi[x] <> val ) then
# proper refinement will yield a condition.
values:= [];
new:= []; for i in p do
pos:= Position( values, chi[i] ); if pos = fail then
Add( values, chi[i] );
Add( new, [ i ] ); else
Add( new[ pos ], i ); fi;
od;
Append( part, new );
fi;
od;
# If no refinement occurs, the character is necessarily invariant in <G>. if IsEmpty( part ) then
return G; fi;
# Compute the permutations corresponding to the generators of `G'.
perms:= CorrespondingPermutations( tbl, chi, GeneratorsOfGroup( G ) );
permgrp:= GroupByGenerators( perms );
# `G' acts on the set of conjugacy classes given by each cell of `part'.
stab:= permgrp; for p in part do
stab:= Stabilizer( stab, p, OnSets ); #T Better one step (partition stabilizer) ??
od;
# Construct and return the result. if stab = permgrp then
return G; else
return PreImagesSet( GroupHomomorphismByImages( G, permgrp,
GeneratorsOfGroup( G ), perms ),
stab ); fi; end );
############################################################################# ## #M KernelOfCharacter( [<tbl>, ]<chi> ) . . . . . . . . for a class function ##
InstallMethod( KernelOfCharacter, "for a class function",
[ IsClassFunction ],
chi -> KernelOfCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ) );
InstallMethod( KernelOfCharacter, "for an ordinary table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, chi )
return NormalSubgroupClasses( tbl, ClassPositionsOfKernel( chi ) ); end );
############################################################################# ## #M ClassPositionsOfKernel( <char> ) . the set of classes forming the kernel ##
InstallMethod( ClassPositionsOfKernel, "for a homogeneous list",
[ IsHomogeneousList ], function( char )
local degree;
degree:= char[1];
return Filtered( [ 1 .. Length( char ) ], x -> char[x] = degree ); end );
############################################################################# ## #M CycleStructureClass( [<tbl>, ]<permchar>, <class> ) ## ## For a permutation character $\pi$ and an element $g$ of $G$, the number ## of $n$-cycles in the underlying permutation representation is equal to ## $\frac{1}{n} \sum_{r|n} \mu(\frac{n}{r}) \pi(g^r)$. ##
InstallMethod( CycleStructureClass, "for a class function, and a class position",
[ IsClassFunction, IsPosInt ], function( permchar, class )
return CycleStructureClass( UnderlyingCharacterTable( permchar ),
ValuesOfClassFunction( permchar ), class ); end );
InstallMethod( CycleStructureClass, "for an ordinary table, a list, and a class position",
[ IsOrdinaryTable, IsHomogeneousList, IsPosInt ], function( tbl, permchar, class )
local n, # element order of `class'
divs, # divisors of `n'
i, d, j, # loop over `divs'
fixed, # numbers of fixed points
cycstruct; # cycle structure, result
# Compute the numbers of fixed points of powers.
n:= OrdersClassRepresentatives( tbl )[ class ];
divs:= DivisorsInt( n );
fixed:= []; for i in [ 1 .. Length( divs ) ] do
# Compute the number of cycles of the element of order `n / d'.
d:= divs[i];
fixed[d]:= permchar[ PowerMap( tbl, d, class ) ]; for j in [ 1 .. i-1 ] do if d mod divs[j] = 0then
# Subtract the number of fixed points with stabilizer exactly # of order `n / divs[j]'.
fixed[d]:= fixed[d] - fixed[ divs[j] ];
fi;
od;
od;
# Convert these numbers into numbers of cycles.
cycstruct:= []; for i in divs do if fixed[i] <> 0 and 1 < i then
cycstruct[ i-1 ]:= fixed[i] / i; fi;
od;
# Return the cycle structure.
return cycstruct; end );
############################################################################# ## #M IsTransitive( [<tbl>, ]<permchar> ) ##
InstallMethod( IsTransitive, "for a class function",
[ IsClassFunction ], function( permchar )
local tbl;
tbl:= UnderlyingCharacterTable( permchar );
return ValuesOfClassFunction( permchar ) * SizesConjugacyClasses( tbl )
= Size( tbl ); end );
InstallMethod( IsTransitive, "for an ordinary table and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, permchar )
return permchar * SizesConjugacyClasses( tbl ) = Size( tbl ); end );
############################################################################# ## #M Transitivity( [<tbl>, ]<permchar> ) ## ## The transitivity of a permutation character $\pi$ corresponding to the ## action on the $G$-set $\Omega$ is computed as follows ## (cf.~\cite{Hup98}, Theorem~11.8). ## Let $\Omega_k = \{ (\omega_1, \omega_2, \ldots, \omega_k) \mid ## \omega_i \in \Omega, \omega_i {\rm\ pairwise distinct} \}$. ## Then $\Omega_k$ is a $G$-set w.r.t.~componentwise action, ## and the permutation character $\pi_k$ is given by ## $\pi_k(g) = \pi(g) (\pi(g)-1) (\pi(g)-2) \cdots (\pi(g)-k+1)$. ## $\Omega$ is $k$-transitive if and only if $\Omega_k$ is transitive. ##
InstallMethod( Transitivity, "for a class function",
[ IsClassFunction ],
pi -> Transitivity( UnderlyingCharacterTable( pi ),
ValuesOfClassFunction( pi ) ) );
InstallMethod( Transitivity, "for an ordinary table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, values )
local order,
classes,
n,
k,
pik;
# Check the argument. if not ForAll( values, IsInt ) then
Error( "<values> is not integral" ); fi;
k:= 1;
pik:= values; while pik * classes = order do
k:= k + 1;
pik:= List( [ 1 .. n ], x -> pik[x] * ( values[x] - k + 1 ) );
od;
return k - 1; end );
############################################################################# ## #M CentralCharacter( [<tbl>, ]<chi> ) . . . . . . . . . . . for a character ##
InstallMethod( CentralCharacter, "for a class function",
[ IsClassFunction ],
chi -> CentralCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ) );
InstallMethod( CentralCharacter, "for an ordinary table, and a homogeneous list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, char )
local classes;
classes:= SizesConjugacyClasses( tbl ); if Length( classes ) <> Length( char ) then
Error( "<classes> and <char> must have same length" ); fi;
return ClassFunction( tbl, List( [ 1 .. Length( char ) ],
x -> classes[x] * char[x] / char[1] ) ); end );
############################################################################## ## #M DeterminantOfCharacter( [<tbl>, ]<chi> ) ## ## The determinant is computed as follows. ## Diagonalize the matrix; the determinant is the product of the diagonal ## entries, which can be computed by `Eigenvalues'. ## ## Note that the determinant of a virtual character $\chi - \psi$ is ## well-defined as the quotient of the determinants of the characters $\chi$ ## and $\psi$, since the determinant of a sum of characters is the product ## of the determinants of the summands. ##
InstallMethod( DeterminantOfCharacter, "for a class function",
[ IsClassFunction ], function( chi )
local det;
if chi[1] = 1then
return chi; fi;
det:= DeterminantOfCharacter( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ) ); if HasIsVirtualCharacter( chi ) and IsVirtualCharacter( chi ) then
SetIsCharacter( det, true ); fi;
return det; end );
InstallMethod( DeterminantOfCharacter, "for a nearly character table, and a class function",
[ IsCharacterTable, IsHomogeneousList ], function( tbl, chi )
local det, # result list
ev, # eigenvalues
ord, # one element order
i; # loop over classes
if chi[1] = 1then
return ClassFunction( tbl, chi ); fi;
det:= [];
for i in [ 1 .. Length( chi ) ] do
ev:= EigenvaluesChar( tbl, chi, i );
ord:= Length( ev );
# The determinant is 'E(ord)' to the 'exp'-th power, # where $'exp' = \sum_{j=1}^{ord} j 'ev'[j]$. # (Note that the $j$-th entry in 'ev' is the multiplicity of # 'E(ord)^j' as eigenvalue.)
det[i]:= E(ord) ^ ( [ 1 .. ord ] * ev );
od;
return ClassFunction( tbl, det ); end );
############################################################################# ## #M EigenvaluesChar( [<tbl>, ]<char>, <class> ) ## ## The eigenvalues can be computed from the values of the character ## <char> together with the power maps up to the order of elements in the ## <class>-th class of <tbl>, see page~231 in~\cite{NPP84}; ## note that the multiplicity of a given $n$-th root of unity $\zeta$ ## as an eigenvalue of $M$ is equal to the multiplicity of the irreducible ## character of the cyclic group spanned by $g$ that maps $g$ to $\zeta$, ## and this can be computed from the restriction of <char> to this cyclic ## subgroup or, equivalently, by the power maps of <tbl>. ## #T > I would like to know if there is a quicker way to compute the #T > characteristic polynomial f=f(G) of a representative G #T > of a conjugacy class mentioned #T > above, than using Eigenvalues(). #T > (The latter function involves using algebraic numbers, #T > whereas it might happen #T > that f has rational or integer coefficients , #T > i.e. all the irrationalies cancel) #T #T For example, if the character values in question are rational #T one can use Galois sums of the irreducible characters of the cyclic #T subgroup instead of the irreducible characters when computing #T scalar products, #T because the multiplicities of Galois conjugate eigenvalues are equal #T in such a case. #T This avoids computations with non-rational numbers. ##
InstallMethod( EigenvaluesChar, "for a class function and a positive integer",
[ IsClassFunction, IsPosInt ], function( chi, class )
return EigenvaluesChar( UnderlyingCharacterTable( chi ),
ValuesOfClassFunction( chi ), class ); end );
InstallMethod( EigenvaluesChar, "for a character table and a hom. list, and a pos.",
[ IsCharacterTable, IsHomogeneousList, IsPosInt ], function( tbl, char, class )
local i, j, n, powers, eigen, e, val;
n:= OrdersClassRepresentatives( tbl )[ class ]; if n = 1then return [ char[ class ] ]; fi;
# Compute necessary power maps and the restricted character.
powers:= [];
powers[n]:= char[1]; for i in [ 1 .. n-1 ] do if not IsBound( powers[i] ) then
# necessarily 'i' divides 'n', since 'i/Gcd(n,i)' is invertible # mod 'n', and thus powering with 'i' is Galois conjugate to # powering with 'Gcd(n,i)'
powers[i]:= char[ PowerMap( tbl, i, class ) ]; #T better approach: #T only write down values for one representative of each #T Galois family, and compute traces; #T for rational characters, this avoids computation with #T non-rational values at all. #T (how much does this help?) for j in PrimeResidues( n/i ) do
# Note that the position cannot be 0.
powers[ ( i*j ) mod n ]:= GaloisCyc( powers[i], j );
od; fi;
od;
# compute the scalar products of the characters given by 'E(n)->E(n)^i' # with the restriction of <char> to the cyclic group generated by # <class>
eigen:= []; for i in [ 1 .. n ] do
e:= E(n)^(-i);
val:= 0; for j in [ 1 .. n ] do val:= val + e^j * powers[j]; od;
eigen[i]:= val / n;
od;
return eigen; end );
############################################################################# ## #M Tensored( <chars1>, <chars2> ) . . . . for two lists of class functions ##
InstallMethod( Tensored, "method for two homogeneous lists",
[ IsHomogeneousList, IsHomogeneousList ], function( chars1, chars2 )
local i, j, k, nccl, tensored, single;
if IsEmpty( chars1 ) or IsEmpty( chars2 ) then
return []; fi;
nccl:= Length( chars1[1] );
tensored:= [];
for i in chars1 do for j in chars2 do
single:= []; for k in [ 1 .. nccl ] do
single[k]:= i[k] * j[k];
od;
if HasIsCharacter( i ) and IsCharacter( i ) and
HasIsCharacter( j ) and IsCharacter( j ) and
UnderlyingCharacterTable( i ) = UnderlyingCharacterTable( j ) then
single:= Character( UnderlyingCharacterTable( i ), single ); elif HasIsVirtualCharacter( i ) and IsVirtualCharacter( i ) and
HasIsVirtualCharacter( j ) and IsVirtualCharacter( j ) and
UnderlyingCharacterTable( i ) = UnderlyingCharacterTable( j ) then
single:= VirtualCharacter( UnderlyingCharacterTable( i ), single ); elif IsClassFunction( i ) and IsClassFunction( j ) and
UnderlyingCharacterTable( i ) = UnderlyingCharacterTable( j ) then
single:= ClassFunction( UnderlyingCharacterTable( i ), single ); fi;
Add( tensored, single );
od;
od;
return tensored; end );
############################################################################# ## #M TensorProductOp( <chi>, <psi> ) ##
InstallMethod( TensorProductOp, "for a list of class functions and a class function",
[ IsDenseList, IsClassFunction ], function( list, chi ) if Length( list ) = 0then
return One( chi ); else
return Iterated( list, \* ); fi; end );
############################################################################# ## ## 9. Restricted and Induced Class Functions ##
############################################################################# ## #M RestrictedClassFunction( [<tbl>, ]<chi>, <H> ) #M RestrictedClassFunction( [<tbl>, ]<chi>, <hom> ) #M RestrictedClassFunction( [<tbl>, ]<chi>, <subtbl> ) ##
InstallMethod( RestrictedClassFunction, "for a class function, and a group",
[ IsClassFunction, IsGroup ], function( chi, H )
local subtbl, tbl, fus;
subtbl:= OrdinaryCharacterTable( H );
tbl:= UnderlyingCharacterTable( chi ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "no fusion from <subtbl> to <tbl>" ); fi;
return ClassFunctionSameType( subtbl, chi, chi{ fus } ); end );
InstallMethod( RestrictedClassFunction, "for a character table, a homogeneous list, and a group",
[ IsNearlyCharacterTable, IsHomogeneousList, IsGroup ], function( tbl, chi, H )
local subtbl, fus;
subtbl:= OrdinaryCharacterTable( H ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "no fusion from <subtbl> to <tbl>" ); fi;
return ClassFunction( subtbl, chi{ fus } ); end );
InstallMethod( RestrictedClassFunction, "for a class function and a group homomorphism",
[ IsClassFunction, IsGeneralMapping ], function( chi, hom )
local tbl, subtbl, fus;
subtbl:= CharacterTable( PreImage( hom ) );
tbl:= UnderlyingCharacterTable( chi ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, subtbl, tbl ); if fus = fail then
Error( "no fusion from <subtbl> to <tbl>" ); fi;
return ClassFunctionSameType( subtbl, chi,
ValuesOfClassFunction( chi ){ fus } ); end );
InstallMethod( RestrictedClassFunction, "for a character table, a homogeneous list, and a group homomorphism",
[ IsNearlyCharacterTable, IsHomogeneousList, IsGeneralMapping ], function( tbl, chi, hom )
local subtbl, fus;
subtbl:= CharacterTable( PreImage( hom ) ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, subtbl, tbl ); if fus = fail then
Error( "no fusion from <subtbl> to <tbl>" ); fi;
return ClassFunction( subtbl, chi{ fus } ); end );
InstallMethod( RestrictedClassFunction, "for class function and nearly character table",
[ IsClassFunction, IsNearlyCharacterTable ], function( chi, subtbl )
local fus;
fus:= FusionConjugacyClasses( subtbl, UnderlyingCharacterTable( chi ) ); if fus = fail then
Error( "class fusion not available" ); fi;
return ClassFunctionSameType( subtbl, chi,
ValuesOfClassFunction( chi ){ fus } ); end );
InstallMethod( RestrictedClassFunction, "for a character table, a homogeneous list, and a character table",
[ IsNearlyCharacterTable, IsHomogeneousList, IsNearlyCharacterTable ], function( tbl, chi, subtbl )
local fus;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "class fusion not available" ); fi;
return ClassFunction( subtbl, chi{ fus } ); end );
############################################################################# ## #M RestrictedClassFunctions( [<tbl>, ]<chars>, <H> ) #M RestrictedClassFunctions( [<tbl>, ]<chars>, <hom> ) #M RestrictedClassFunctions( [<tbl>, ]<chars>, <subtbl> ) ##
InstallMethod( RestrictedClassFunctions, "for list and group",
[ IsList, IsGroup ], function( chars, H )
return List( chars, chi -> RestrictedClassFunction( chi, H ) ); end );
InstallMethod( RestrictedClassFunctions, "for list and group homomorphism",
[ IsList, IsGeneralMapping ], function( chars, hom )
return List( chars, chi -> RestrictedClassFunction( chi, hom ) ); end );
InstallMethod( RestrictedClassFunctions, "for list and character table",
[ IsList, IsCharacterTable ], function( chars, subtbl )
return List( chars, chi -> RestrictedClassFunction( chi, subtbl ) ); end );
InstallMethod( RestrictedClassFunctions, "for a character table, a list, and a group",
[ IsCharacterTable, IsList, IsGroup ], function( tbl, chars, H )
local subtbl, fus;
subtbl:= OrdinaryCharacterTable( H ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "no fusion from <subtbl> to <tbl>" ); fi;
return List( chars, chi -> ClassFunctionSameType( subtbl, chi,
ValuesOfClassFunction( chi ){ fus } ) ); end );
InstallMethod( RestrictedClassFunctions, "for a character table, a list, and a group homomorphism",
[ IsCharacterTable, IsList, IsGeneralMapping ], function( tbl, chars, hom )
local subtbl, fus;
subtbl:= CharacterTable( PreImage( hom ) ); if UnderlyingCharacteristic( tbl ) <> 0then
subtbl:= subtbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, subtbl, tbl ); if fus = fail then
Error( "class fusion not available" ); fi;
return List( chars, chi -> ClassFunctionSameType( subtbl, chi,
ValuesOfClassFunction( chi ){ fus } ) ); end );
InstallMethod( RestrictedClassFunctions, "for a character table, a list, and a character table",
[ IsCharacterTable, IsList, IsCharacterTable ], function( tbl, chars, subtbl )
local fus;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "class fusion not available" ); fi;
return List( chars, chi -> ClassFunctionSameType( subtbl, chi,
ValuesOfClassFunction( chi ){ fus } ) ); end );
############################################################################# ## #M Restricted( <tbl>, <subtbl>, <chars> ) #M Restricted( <tbl>, <subtbl>, <chars>, <specification> ) #M Restricted( <chars>, <fusionmap> ) ## ## These methods are installed just for compatibility with {\GAP}~3. ##
InstallMethod( Restricted,
[ IsNearlyCharacterTable, IsNearlyCharacterTable, IsHomogeneousList ], function( tbl, subtbl, chars )
local fus;
fus:= FusionConjugacyClasses( subtbl, tbl ); if fus = fail then
Error( "class fusion not available" ); fi;
return List( chars, row -> ClassFunction( subtbl, row{ fus } ) ); end );
InstallMethod( Restricted,
[ IsCharacterTable, IsHomogeneousList, IsGroup ], function( tbl, list, H ) if IsMatrix( list ) then
return RestrictedClassFunctions( tbl, list, H ); else
return RestrictedClassFunction( tbl, list, H ); fi; end );
InstallMethod( Restricted,
[ IsCharacterTable, IsClassFunction, IsGroupHomomorphism ], function( tbl, list, hom ) if IsMatrix( list ) then
return RestrictedClassFunctions( tbl, list, hom ); else
return RestrictedClassFunction( tbl, list, hom ); fi; end );
InstallMethod( Restricted,
[ IsCharacterTable, IsClassFunction, IsNearlyCharacterTable ], function( tbl, list, subtbl ) if IsMatrix( list ) then
return RestrictedClassFunctions( tbl, list, subtbl ); else
return RestrictedClassFunction( tbl, list, subtbl ); fi; end );
InstallMethod( Restricted,
[ IsHomogeneousList, IsGroup ], function( list, H ) if ForAll( list, IsClassFunction ) then
return RestrictedClassFunctions( list, H ); else
TryNextMethod(); fi; end );
InstallMethod( Restricted,
[ IsHomogeneousList, IsGroupHomomorphism ], function( list, hom ) if ForAll( list, IsClassFunction ) then
return RestrictedClassFunctions( list, hom ); else
TryNextMethod(); fi; end );
InstallMethod( Restricted,
[ IsHomogeneousList, IsNearlyCharacterTable ], function( list, subtbl ) if ForAll( list, IsClassFunction ) then
return RestrictedClassFunctions( list, subtbl ); else
TryNextMethod(); fi; end );
############################################################################# ## #F InducedClassFunctionsByFusionMap( <subtbl>, <tbl>, <chars>, <fusionmap> ) ##
InstallGlobalFunction( InducedClassFunctionsByFusionMap, function( subtbl, tbl, chars, fusion )
local j, im, # loop variables
centralizers, # centralizer orders in the supergroup
nccl, # number of conjugacy classes of the group
subnccl, # number of conjugacy classes of the subgroup
suborder, # order of the subgroup
subclasses, # class lengths in the subgroup
induced, # list of induced characters, result
singleinduced, # one induced character
char; # one character to be induced
# Preset the character with zeros.
singleinduced:= ListWithIdenticalEntries( nccl, 0 );
# Add the contribution of each class of the subgroup. for j in [ 1 .. subnccl ] do if char[j] <> 0then if IsInt( fusion[j] ) then
singleinduced[ fusion[j] ]:= singleinduced[ fusion[j] ]
+ char[j] * subclasses[j]; else for im in fusion[j] do singleinduced[ im ]:= Unknown(); od; #T only for TableInProgress! fi; fi;
od;
# Adjust the values by multiplication. for j in [ 1 .. nccl ] do
singleinduced[j]:= singleinduced[j] * centralizers[j] / suborder; if not IsCycInt( singleinduced[j] ) then
singleinduced[j]:= Unknown();
Info( InfoCharacterTable, 1, "Induced: subgroup order not dividing sum in character ",
Length( induced ) + 1, " at class ", j ); fi;
od;
# Create the class function object. if IsClassFunction( char ) then
singleinduced:= ClassFunctionSameType( tbl, char, singleinduced ); else
singleinduced:= ClassFunction( tbl, singleinduced ); fi;
Add( induced, singleinduced );
od;
# Return the list of induced characters.
return induced; end );
############################################################################# ## #M InducedClassFunction( [<tbl>, ]<chi>, <H> ) #M InducedClassFunction( [<tbl>, ]<chi>, <hom> ) #M InducedClassFunction( [<tbl>, ]<chi>, <suptbl> ) ##
InstallMethod( InducedClassFunction, "for a class function and a group",
[ IsClassFunction, IsGroup ], function( chi, G )
local tbl, suptbl, fus;
tbl:= UnderlyingCharacterTable( chi );
suptbl:= OrdinaryCharacterTable( G ); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
InstallMethod( InducedClassFunction, "for a character table, a homogeneous list, and a group",
[ IsCharacterTable, IsHomogeneousList, IsGroup ], function( tbl, chi, G )
local suptbl, fus;
suptbl:= OrdinaryCharacterTable( G ); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
InstallMethod( InducedClassFunction, "for class function and nearly character table",
[ IsClassFunction, IsNearlyCharacterTable ], function( chi, suptbl )
local tbl, fus;
tbl:= UnderlyingCharacterTable( chi );
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
InstallMethod( InducedClassFunction, "for character table, homogeneous list, and nearly character table",
[ IsCharacterTable, IsHomogeneousList, IsNearlyCharacterTable ], function( tbl, chi, suptbl )
local fus;
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
InstallMethod( InducedClassFunction, "for a class function and a group homomorphism",
[ IsClassFunction, IsGeneralMapping ], function( chi, hom )
local tbl, suptbl, fus;
tbl:= UnderlyingCharacterTable( chi );
suptbl:= OrdinaryCharacterTable(Image( hom )); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
InstallMethod( InducedClassFunction, "for a character table, a homogeneous list, and a group homomorphism",
[ IsCharacterTable, IsHomogeneousList, IsGeneralMapping ], function( tbl, chi, hom )
local suptbl, fus;
suptbl:= OrdinaryCharacterTable(Image( hom )); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, [ chi ], fus )[1]; end );
############################################################################# ## #M InducedClassFunctions( [<tbl>, ]<chars>, <H> ) #M InducedClassFunctions( [<tbl>, ]<chars>, <hom> ) #M InducedClassFunctions( [<tbl>, ]<chars>, <suptbl> ) ##
InstallMethod( InducedClassFunctions, "for list, and group",
[ IsList, IsGroup ], function( chars, H )
return List( chars, chi -> InducedClassFunction( chi, H ) ); end );
InstallMethod( InducedClassFunctions, "for list, and group homomorphism",
[ IsList, IsGeneralMapping ], function( chars, hom )
return List( chars, chi -> InducedClassFunction( chi, hom ) ); end );
InstallMethod( InducedClassFunctions, "for list, and group homomorphism",
[ IsList, IsCharacterTable ], function( chars, suptbl )
return List( chars, chi -> InducedClassFunction( chi, suptbl ) ); end );
InstallMethod( InducedClassFunctions, "for a character table, a homogeneous list, and a group",
[ IsCharacterTable, IsHomogeneousList, IsGroup ], function( tbl, chars, G )
local suptbl, fus;
suptbl:= OrdinaryCharacterTable( G ); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, chars, fus ); end );
InstallMethod( InducedClassFunctions, "for character table, homogeneous list, and nearly character table",
[ IsCharacterTable, IsHomogeneousList, IsNearlyCharacterTable ], function( tbl, chars, suptbl )
local fus;
fus:= FusionConjugacyClasses( tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, chars, fus ); end );
InstallMethod( InducedClassFunctions, "for a character table, a homogeneous list, and a group homomorphism",
[ IsCharacterTable, IsHomogeneousList, IsGeneralMapping ], function( tbl, chars, hom )
local suptbl, fus;
suptbl:= Image( hom ); if UnderlyingCharacteristic( tbl ) <> 0then
suptbl:= suptbl mod UnderlyingCharacteristic( tbl ); fi;
fus:= FusionConjugacyClasses( hom, tbl, suptbl );
return InducedClassFunctionsByFusionMap( tbl, suptbl, chars, fus ); end );
InstallMethod( Induced,
[ IsCharacterTable, IsHomogeneousList, IsGroup ], function( tbl, list, H ) if IsMatrix( list ) then
return InducedClassFunctions( tbl, list, H ); else
return InducedClassFunction( tbl, list, H ); fi; end );
InstallMethod( Induced,
[ IsCharacterTable, IsHomogeneousList, IsGroupHomomorphism ], function( tbl, list, hom ) if IsMatrix( list ) then
return InducedClassFunctions( tbl, list, hom ); else
return InducedClassFunction( tbl, list, hom ); fi; end );
InstallMethod( Induced,
[ IsCharacterTable, IsHomogeneousList, IsNearlyCharacterTable ], function( tbl, list, suptbl ) if IsMatrix( list ) then
return InducedClassFunctions( tbl, list, suptbl ); else
return InducedClassFunction( tbl, list, suptbl ); fi; end );
InstallMethod( Induced,
[ IsHomogeneousList, IsGroup ], function( list, H ) if ForAll( list, IsClassFunction ) then
return InducedClassFunctions( list, H ); else
TryNextMethod(); fi; end );
InstallMethod( Induced,
[ IsHomogeneousList, IsGeneralMapping ], function( list, hom ) if ForAll( list, IsClassFunction ) then
return InducedClassFunctions( list, hom ); else
TryNextMethod(); fi; end );
InstallMethod( Induced,
[ IsHomogeneousList, IsCharacterTable ], function( list, suptbl ) if ForAll( list, IsClassFunction ) then
return InducedClassFunctions( list, suptbl ); else
TryNextMethod(); fi; end );
############################################################################# ## #M Induced( <subtbl>, <tbl>, <chars> ) #M Induced( <subtbl>, <tbl>, <chars>, <specification> ) #M Induced( <subtbl>, <tbl>, <chars>, <fusionmap> ) ## ## These methods are installed just for compatibility with {\GAP}~3. ##
InstallMethod( Induced, "for two nearly character tables, and homog list",
[ IsNearlyCharacterTable, IsNearlyCharacterTable, IsHomogeneousList ], function( subtbl, tbl, chars )
return InducedClassFunctionsByFusionMap( subtbl, tbl, chars,
FusionConjugacyClasses( subtbl, tbl ) ); end );
InstallMethod( Induced, "for two nearly character tables, homog list, and string",
[ IsNearlyCharacterTable, IsNearlyCharacterTable,
IsHomogeneousList, IsString ], function( subtbl, tbl, chars, specification )
return InducedClassFunctionsByFusionMap( subtbl, tbl, chars,
FusionConjugacyClasses( subtbl, tbl, specification ) ); end );
InstallMethod( Induced, "for two nearly character tables and two homog. lists",
[ IsNearlyCharacterTable, IsNearlyCharacterTable,
IsHomogeneousList, IsHomogeneousList and IsCyclotomicCollection ],
InducedClassFunctionsByFusionMap );
InstallMethod( InducedCyclic, "for a character table and a string",
[ IsOrdinaryTable, IsString ], # The `string' should overrule over the `homogeneous list' installed in # the next method 1, function( tbl, all )
return InducedCyclic( tbl, [ 1 .. NrConjugacyClasses( tbl ) ], all ); end );
InstallMethod( InducedCyclic, "for a character table and a hom. list",
[ IsOrdinaryTable, IsHomogeneousList ], function( tbl, classes )
local centralizers,
orders,
independent,
inducedcyclic,
i,
fusion,
j,
single;
if HasUnderlyingGroup( tbl ) then # Precompute the power maps if possible.
ComputeAllPowerMaps( tbl ); fi;
centralizers:= SizesCentralizers( tbl );
orders:= OrdersClassRepresentatives( tbl );
independent:= List( orders, ReturnTrue );
inducedcyclic:= []; for i in classes do# induce from i-th class if independent[i] then
fusion:= [ i ]; for j in [ 2 .. orders[i] ] do
fusion[j]:= PowerMap( tbl, j, i ); # j-th powermap at class i
od;
single:= ListWithIdenticalEntries(Length(orders),0); for j in fusion do if orders[j] = orders[i] then # position is Galois conjugate to 'i'
independent[j]:= false; fi;
single[j]:= single[j] + 1;
od; for j in [ 1 .. Length( orders ) ] do
single[j]:= single[j] * centralizers[j] / orders[i]; if not IsInt( single[j] ) then
single[j]:= Unknown();
Info( InfoCharacterTable, 1, "InducedCyclic: subgroup order not dividing sum", " (induce from class ", i, ")" ); fi;
od;
AddSet( inducedcyclic, Character( tbl, single ) ); fi;
od;
return inducedcyclic; end );
InstallMethod( InducedCyclic, "for a character table, a hom. list, and a string",
[ IsOrdinaryTable, IsHomogeneousList, IsString ], function( tbl, classes, all )
local centralizers,
orders,
independent,
inducedcyclic,
i,
fusion,
j,
k,
single;
centralizers:= SizesCentralizers( tbl );
orders:= OrdersClassRepresentatives( tbl );
independent:= List( orders, ReturnTrue );
inducedcyclic:= []; for i in classes do# induce from i-th class if independent[i] then
fusion:= [ i ]; for j in [ 2 .. orders[i] ] do
fusion[j]:= PowerMap( tbl, j, i ); # j-th powermap at class i
od;
for k in [ 0 .. orders[i] - 1 ] do# induce k-th character
single:= ListWithIdenticalEntries(Length(orders),0);
single[i]:= E( orders[i] ) ^ ( k ); for j in [ 2 .. orders[i] ] do if orders[ fusion[j] ] = orders[i] then
# position is Galois conjugate
independent[ fusion[j] ]:= false; fi;
single[ fusion[j] ]:=
single[ fusion[j] ] + E( orders[i] )^( k*j mod orders[i] );
od; for j in [ 1 .. Length( orders ) ] do
single[j]:= single[j] * centralizers[j] / orders[i]; if not IsCycInt( single[j] ) then
single[j]:= Unknown();
Info( InfoCharacterTable, 1, "InducedCyclic: subgroup order not dividing sum", " (induce from class ", i, ")" ); fi;
od;
AddSet( inducedcyclic, Character( tbl, single ) );
od; fi;
od;
return inducedcyclic; end );
InstallMethod( ReducedClassFunctions, "for a list (of class functions)",
[ IsHomogeneousList ], function( reducibles ) if IsEmpty( reducibles ) then
return rec( irreducibles:= [],
remainders:= [] ); elif IsClassFunction( reducibles[1] ) then
return ReducedClassFunctions(
UnderlyingCharacterTable( reducibles[1] ),
reducibles ); else
TryNextMethod(); fi; end );
InstallMethod( ReducedClassFunctions, "for ordinary character table, and two lists (of class functions)",
[ IsOrdinaryTable, IsHomogeneousList , IsHomogeneousList ], function( ordtbl, constituents, reducibles )
local i, j,
normsquare,
upper,
found, # list of found irreducible characters
remainders, # list of reducible remainders after reduction
single,
reduced,
scpr;
upper:= Length( constituents );
upper:= List( reducibles, x -> upper );
normsquare:= List( constituents, x -> ScalarProduct( ordtbl, x, x ) );
found:= [];
remainders:= [];
for i in [ 1 .. Length( reducibles ) ] do
single:= reducibles[i];
j:=1; while j<=upper[i] do
scpr:= ScalarProduct( ordtbl, single, constituents[j] ); if IsInt( scpr ) then
scpr:= Int( scpr / normsquare[j] ); if scpr <> 0then
single:= single - scpr * constituents[j]; if ForAll(single,x->x=0) then
j:=upper[i]; fi; fi; else
Info( InfoCharacterTable, 1, "ReducedClassFunctions: scalar product of X[", j, "] with Y[", i, "] not integral (ignore)" ); fi;
j:=j+1;
od; if ForAny( single, x -> x <> 0 ) then if single[1] < 0then
single:= - single; fi; if ScalarProduct( ordtbl, single, single ) = 1then if not single in found and not single in constituents then
Info( InfoCharacterTable, 2, "ReducedClassFunctions: irreducible character of degree ",
single[1], " found" ); if IsClassFunction( single ) then
SetIsCharacter( single, true ); fi;
AddSet( found, single ); fi; else
AddSet( remainders, single ); fi; fi;
od;
# If no irreducibles were found, return the remainders. if IsEmpty( found ) then
return rec( remainders:= remainders, irreducibles:= [] ); fi;
# Try to find new irreducibles by recursively calling the reduction.
reduced:= ReducedClassFunctions( ordtbl, found, remainders );
# Return the result.
return rec( remainders:= reduced.remainders,
irreducibles:= Union( found, reduced.irreducibles ) ); end );
InstallMethod( ReducedClassFunctions, "for ordinary character table, and list of class functions",
[ IsOrdinaryTable, IsHomogeneousList ], function( ordtbl, reducibles )
local upper,
normsquare,
found, # list of found irreducible characters
remainders, # list of reducible remainders after reduction
i, j,
single,
reduced,
scpr;
for i in [ 1 .. Length( reducibles ) ] do if normsquare[i] = 1then if0 < reducibles[i][1] then
AddSet( found, reducibles[i] ); else
AddSet( found, - reducibles[i] ); fi; fi;
od;
for i in [ 1 .. Length( reducibles ) ] do
single:= reducibles[i]; for j in [ 1 .. upper[i] ] do
scpr:= ScalarProduct( ordtbl, single, reducibles[j] ); if IsInt( scpr ) then
scpr:= Int( scpr / normsquare[j] ); if scpr <> 0then
single:= single - scpr * reducibles[j]; fi; else
Info( InfoCharacterTable, 1, "ReducedClassFunctions: scalar product of X[", j, "] with Y[", i, "] not integral (ignore)" ); fi;
od; if ForAny( single, x -> x <> 0 ) then if single[1] < 0then
single:= - single; fi; if ScalarProduct( ordtbl, single, single ) = 1then if not single in found and not single in reducibles then
Info( InfoCharacterTable, 2, "ReducedClassFunctions: irreducible character of degree ",
single[1], " found" ); if IsClassFunction( single ) then
SetIsCharacter( single, true ); fi;
AddSet( found, single ); fi; else
AddSet( remainders, single ); fi; fi;
od;
# If no irreducibles were found, return the remainders. if IsEmpty( found ) then
return rec( remainders:= remainders, irreducibles:= [] ); fi;
# Try to find new irreducibles by recursively calling the reduction.
reduced:= ReducedClassFunctions( ordtbl, found, remainders );
# Return the result.
return rec( remainders:= reduced.remainders,
irreducibles:= Union( found, reduced.irreducibles ) ); end );
InstallMethod( ReducedCharacters, "for ordinary character table, and two lists of characters",
[ IsOrdinaryTable, IsHomogeneousList , IsHomogeneousList ], function( ordtbl, constituents, reducibles )
local normsquare,
found,
remainders,
single,
i, j,
nchars,
reduced,
scpr;
normsquare:= List( constituents, x -> ScalarProduct( ordtbl, x, x ) );
found:= [];
remainders:= [];
nchars:= Length( constituents ); for i in [ 1 .. Length( reducibles ) ] do
single:= reducibles[i]; for j in [ 1 .. nchars ] do if constituents[j][1] <= single[1] then
scpr:= ScalarProduct( ordtbl, single, constituents[j] ); if IsInt( scpr ) then
scpr:= Int( scpr / normsquare[j] ); if scpr <> 0then
single:= single - scpr * constituents[j]; fi; else
Info( InfoCharacterTable, 1, "ReducedCharacters: scalar product of X[", j, "] with Y[",
i, "] not integral (ignore)" ); fi; fi;
od;
if ForAny( single, x -> x <> 0 ) then if ScalarProduct( ordtbl, single, single ) = 1then if single[1] < 0then single:= - single; fi; if not single in found and not single in constituents then
Info( InfoCharacterTable, 2, "ReducedCharacters: irreducible character of", " degree ", single[1], " found" ); if IsClassFunction( single ) then
SetIsCharacter( single, true ); fi;
AddSet( found, single ); fi; else
AddSet( remainders, single ); fi; fi;
od;
# If no irreducibles were found, return the remainders. if IsEmpty( found ) then
return rec( remainders:= remainders, irreducibles:= [] ); fi;
# Try to find new irreducibles by recursively calling the reduction.
reduced:= ReducedCharacters( ordtbl, found, remainders );
# Return the result.
return rec( remainders:= reduced.remainders,
irreducibles:= Union( found, reduced.irreducibles ) ); end );
############################################################################# ## #F IrreducibleDifferences( <tbl>, <reducibles>, <reducibles2> ) #F IrreducibleDifferences( <tbl>, <reducibles>, <reducibles2>, <scprmat> ) #F IrreducibleDifferences( <tbl>, <reducibles>, \"triangle\" ) #F IrreducibleDifferences( <tbl>, <reducibles>, \"triangle\", <scprmat> ) ## #T compute/consider scalar product of i-th and j-th character only if the #T norms have different parity! ##
InstallGlobalFunction( IrreducibleDifferences, function( arg )
local tbl,
reducibles,
irreducibledifferences,
scprmatrix,
i, j,
diff,
reducibles2,
norms, norms2;
if not ( Length( arg ) in [ 3, 4 ] and IsOrdinaryTable( arg[1] ) and
IsList( arg[2] ) and ( IsList( arg[3] ) or IsString( arg[3] ) ) )
or ( Length( arg ) = 4 and not IsList( arg[4] ) ) then
Error( "usage: IrreducibleDifferences(tbl,reducibles,\"triangle\")\n", "resp. IrreducibleDifferences(tbl,reducibles,\"triangle\",scprmat)", "\n resp. IrreducibleDifferences(tbl,reducibles,reducibles2)\nresp.", " IrreducibleDifferences(tbl,reducibles,reducibles2,scprmat)" ); fi;
tbl:= arg[1];
reducibles:= arg[2];
irreducibledifferences:= []; if IsString( arg[3] ) then# "triangle" if Length( arg ) = 3then
scprmatrix:= MatScalarProducts( tbl, reducibles ); else
scprmatrix:= arg[4]; fi; for i in [ 1 .. Length( scprmatrix ) ] do for j in [ 1 .. i-1 ] do if scprmatrix[i][i] + scprmatrix[j][j] - 2*scprmatrix[i][j] = 1then if reducibles[i][1] > reducibles[j][1] then
diff:= reducibles[i] - reducibles[j];
Info( InfoCharacterTable, 2, "IrreducibleDifferences: X[",i, "] - X[",j, "] found" ); else
diff:= reducibles[j] - reducibles[i];
Info( InfoCharacterTable, 2, "IrreducibleDifferences: X[",j, "] - X[",i, "] found" ); fi; if IsClassFunction( diff ) then
SetIsCharacter( diff, true ); fi;
AddSet( irreducibledifferences, diff ); fi;
od;
od; else# not "triangle"
reducibles2:= arg[3]; if Length( arg ) = 3then
scprmatrix:= MatScalarProducts( tbl, reducibles, reducibles2 ); else
scprmatrix:= arg[4]; fi;
norms := List( reducibles , x -> ScalarProduct(tbl,x,x) );
norms2:= List( reducibles2, x -> ScalarProduct(tbl,x,x) ); for i in [ 1 .. Length( norms ) ] do for j in [ 1 .. Length( norms2 ) ] do if norms[i] + norms2[j] - 2 * scprmatrix[i][j] = 1then if reducibles[j][1] > reducibles2[i][1] then
diff:= reducibles[j] - reducibles2[i];
Info( InfoCharacterTable, 2, "IrreducibleDifferences: X[",j, "] - Y[",i, "] found" ); else
diff:= reducibles2[i] - reducibles[j];
Info( InfoCharacterTable, 2, "IrreducibleDifferences: Y[",i, "] - X[",j, "] found" ); fi; if IsClassFunction( diff ) then
SetIsCharacter( diff, true ); fi;
AddSet( irreducibledifferences, diff ); fi;
od;
od; fi;
return irreducibledifferences; end );
############################################################################# ## ## 11. Symmetrizations of Class Functions ##
############################################################################# ## #F Symmetrizations( [<tbl>, ]<characters>, <n> ) #F Symmetrizations( [<tbl>, ]<characters>, <Sn> ) #F Symmetrizations( <tbl>, <characters>, <arec> ) ##
InstallMethod( Symmetrizations, "for homogeneous list (of class functions) and positive integer",
[ IsHomogeneousList, IsPosInt ], function( list, n ) if IsEmpty( list ) then
return []; elif IsClassFunction( list[1] ) then
return Symmetrizations( UnderlyingCharacterTable( list[1] ), list, n ); else
TryNextMethod(); fi; end );
InstallMethod( Symmetrizations, "for homogeneous list (of class functions) and character table",
[ IsHomogeneousList, IsOrdinaryTable ], function( list, Sn ) if IsEmpty( list ) then
return []; elif IsClassFunction( list[1] ) then
return Symmetrizations( UnderlyingCharacterTable( list[1] ),
list, Sn ); else
TryNextMethod(); fi; end );
InstallMethod( Symmetrizations, "for char. table, homog. list (of class functions), and pos. integer",
[ IsCharacterTable, IsHomogeneousList, IsPosInt ], function( tbl, characters, n )
local gensymm, classparam, siz, classes;
gensymm:= CharTableSymmetric;
classparam:= gensymm.classparam[1]( n );
siz:= gensymm.size( n );
classes:= List( classparam, p -> siz / gensymm.centralizers[1]( n, p ) );
return Symmetrizations( tbl, characters,
rec( classparam := List( classparam, x -> [ 1, x ] ),
symmirreds := gensymm.matrix( n ),
symmclasses := classes,
symmorder := siz ) ); end );
InstallMethod( Symmetrizations, "for char. table, homog. list (of class functions), and table of Sn",
[ IsCharacterTable, IsHomogeneousList, IsOrdinaryTable ], function( tbl, characters, Sn )
if not HasClassParameters( Sn ) then
Error( "partitions corresponding to classes must be stored", " as `ClassParameters( <Sn> )'" ); fi;
return Symmetrizations( tbl, characters,
rec( classparam := ClassParameters( Sn ),
symmirreds := List( Irr( Sn ), ValuesOfClassFunction ),
symmclasses := SizesConjugacyClasses( Sn ),
symmorder := Size( Sn ) ) ); end );
InstallOtherMethod( Symmetrizations, "for char. table, homog. list (of class functions), and record",
[ IsCharacterTable, IsHomogeneousList, IsRecord ], function( tbl, characters, arec )
local i, j, l, n,
powermap,
cyclestruct,
classparam,
symmirreds,
symmclasses,
symmorder,
cycl,
symmetrizations,
chi,
psi,
prodmatrix,
single,
value,
val;
cyclestruct:= []; for i in [ 1 .. Length( classparam ) ] do if Length( classparam[i][2] ) = 1then
n:= classparam[i][2][1]; fi;
cyclestruct[i]:= []; for j in [ 1 .. Maximum( classparam[i][2] ) ] do
cyclestruct[i][j]:= 0;
od; for j in classparam[i][2] do
cyclestruct[i][j]:= cyclestruct[i][j] + 1;
od;
od;
# Compute necessary power maps.
powermap:= ComputedPowerMaps( tbl ); for i in [ 1 .. n ] do if not IsBound( powermap[i] ) then
powermap[i]:= MakeImmutable( PowerMap( tbl, i ) ); fi;
od;
symmetrizations:= []; for chi in characters do
# Symmetrize the character `chi' of `tbl' ...
prodmatrix:= []; for i in [ 1 .. Length( characters[1] ) ] do
prodmatrix[i]:= []; for j in [ 1 .. Length( symmclasses ) ] do
value:= symmclasses[j];
cycl:= cyclestruct[j]; for l in [ 1 .. Length( cycl ) ] do if cycl[l] <> 0then if IsInt( powermap[l][i] ) then
value:= value * ( chi[ powermap[l][i] ] ^ cycl[l] ); else
val:= CompositionMaps( chi, powermap[l][i] ); if IsInt( val ) then
value:= value * ( val ^ cycl[l] ); else
value:= Unknown(); fi; fi; fi;
od;
prodmatrix[i][j]:= value;
od;
od;
# ... with the character `psi' ... for psi in symmirreds do
single:= []; for i in [ 1 .. Length( chi ) ] do
# ... at class `i'
single[i]:= psi * prodmatrix[i] / symmorder; if not ( IsCycInt( single[i] ) or IsUnknown( single[i] ) ) then
single[i]:= Unknown();
Print( "#E Symmetrizations: value not dividing group order,", " set to ", single[i], "\n" ); fi;
od; if IsClassFunction( chi ) and single[1] > 0then
single:= ClassFunctionSameType( tbl, chi, single ); elif HasIsVirtualCharacter( chi ) and IsVirtualCharacter( chi ) then
single:= VirtualCharacter( tbl, single ); fi;
Add( symmetrizations, single );
od;
od;
# Return the symmetrizations.
return symmetrizations; end );
############################################################################# ## #F SymmetricParts( <tbl>, <characters>, <n> ) ##
InstallGlobalFunction( SymmetricParts, function( tbl, characters, n )
local i,
j,
k,
nccl,
exponents,
symcentralizers, # list of symmetrizations, result
symmetricparts,
chi, # loop over 'characters'
sym,
exp,
factor,
powermap; # list of computed power maps of 'tbl'
if IsEmpty( characters ) then
return []; fi;
nccl:= NrConjugacyClasses( tbl );
exponents:= Partitions( n );
symcentralizers:= CharTableSymmetric.centralizers[1];
symcentralizers:= List( exponents, x -> symcentralizers( n, x ) );
for i in [ 1 .. Length( exponents ) ] do
# Transform partitions to exponent vectors. # At position $i$ we store the number of cycles of length $i$.
exp:= []; for j in [ 1 .. Maximum( exponents[i] ) ] do exp[j]:= 0; od; for j in exponents[i] do exp[j]:= exp[j] + 1; od;
exponents[i]:= exp;
od;
# Compute necessary power maps.
powermap:= ComputedPowerMaps( tbl ); for i in [ 1 .. n ] do if not IsBound( powermap[i] ) then
powermap[i]:= MakeImmutable( PowerMap( tbl, i ) ); fi;
od;
# Loop over the conjugacy classes of the symmetric group. for j in [ 1 .. Length( symcentralizers ) ] do
exp:= exponents[j];
for k in [ 1 .. nccl ] do
factor:= 1; for i in [ 1 .. Length( exp ) ] do if IsBound( exp[i] ) then
factor:= factor * chi[ powermap[i][k] ]^exp[i]; fi;
od;
sym[k]:= sym[k] + factor / symcentralizers[j];
od;
od; if IsClassFunction( chi ) then
sym:= ClassFunctionSameType( tbl, chi, sym ); fi;
Add( symmetricparts, sym );
od;
# Return the symmetrizations.
return symmetricparts; end );
############################################################################# ## #F AntiSymmetricParts( <tbl>, <character>, <n> ) ##
InstallGlobalFunction( AntiSymmetricParts, function( tbl, characters, n )
local i,
j,
k,
nccl,
exponents,
symcentralizers,
antisymmetricparts,
chi,
sym,
exp,
factor,
powermap;
if IsEmpty( characters ) then
return []; fi;
nccl:= NrConjugacyClasses( tbl );
exponents:= Partitions( n );
symcentralizers:= CharTableSymmetric.centralizers[1];
symcentralizers:= List( exponents, x -> symcentralizers( n, x ) );
for i in [ 1 .. Length( exponents ) ] do
# Transform partitions to exponent vectors. # At position $i$ we store the number of cycles of length $i$.
exp:= []; for j in [ 1 .. Maximum( exponents[i] ) ] do exp[j]:= 0; od; for j in exponents[i] do exp[j]:= exp[j] + 1; od;
exponents[i]:= exp;
od;
# Compute necessary power maps.
powermap:= ComputedPowerMaps( tbl ); for i in [ 1 .. n ] do if not IsBound( powermap[i] ) then
powermap[i]:= MakeImmutable( PowerMap( tbl, i ) ); fi;
od;
# Compute the symmetrizations.
antisymmetricparts:= []; for chi in characters do
Info( InfoCharacterTable, 2, "AntiSymmetricParts: chi[.]" );
sym:= List( chi, x -> 0 ); for j in [ 1 .. Length( exponents ) ] do
exp:= exponents[j];
for k in [ 1 .. nccl ] do
factor:= 1; for i in [ 1 .. Length( exp ) ] do if IsBound( exp[i] ) then if i mod 2 = 0 and exp[i] mod 2 = 1then
factor:= -factor * chi[ powermap[i][k] ]^exp[i]; else
factor:= factor * chi[ powermap[i][k] ]^exp[i]; fi; fi;
od;
sym[k]:= sym[k] + factor / symcentralizers[j];
od;
od; if IsClassFunction( chi ) then if IsZero( sym ) then
sym:= VirtualCharacter( tbl, sym ); else
sym:= ClassFunctionSameType( tbl, chi, sym ); fi; fi;
Add( antisymmetricparts, sym );
od;
# Return the symmetrizations.
return antisymmetricparts; end );
############################################################################# ## #M ExteriorPower( <chi>, <n> ) ##
InstallMethod( ExteriorPower, "for a class function and a pos. integer",
[ IsClassFunction, IsPosInt ], function( chi, n )
return AntiSymmetricParts( UnderlyingCharacterTable( chi ), [ chi ], n )[1]; end );
############################################################################# ## #M SymmetricPower( <chi>, <n> ) ##
InstallMethod( SymmetricPower, "for a class function and a pos. integer",
[ IsClassFunction, IsPosInt ], function( chi, n )
return SymmetricParts( UnderlyingCharacterTable( chi ), [ chi ], n )[1]; end );
############################################################################# ## #F RefinedSymmetrizations( <tbl>, <chars>, <m>, <func> ) ## ## (Note: It suffices to change `F2' and `F4' in order to get the ## symplectic components from the orthogonal ones.) ## ## We have (see J.S. Frame, Recursive computation of tensor power ## components, Bayreuther Mathematische Schriften 10, 153--159) ## ## \begintt ## component orthogonal symplectic ## M0 = L0 L0 ( = 1 ) ## M1 = L1 L1 ## M11 = L11 L11-L0 ## M2 = L2-L0 L2 ## M111 = L111 L111-L1 ## M21 = L21-L1 L21-L1 ## M3 = L3-L1 L3 ## M1111 = L1111 L1111-L11 ## M211 = L211-L11 L211-L11-L2+L0 ## M22 = L22-L2 L22-L11 ## M31 = L31-L2-L11+L0 L31-L2 ## M4 = L4-L2 L4 ## M11111 = L11111 L11111-L111 ## M2111 = L2111-L111 L2111-L111-L21+L1 ## M221 = L221-L21 L221-L111-L21+L1 ## M311 = L311-L21-L111+L1 L311-L21-L3+L1 ## M32 = L32-L3-L21+L1 L32-L21 ## M41 = L41-L3-L21+L1 L41-L3 ## M5 = L5-L3 L5 ## M111111 = L111111 L111111-L1111 ## M21111 = L21111-L1111 L21111-L1111-L211+L11 ## M2211 = L2211-L211 L2211-L1111-L211-L22+L11+L2 ## M3111 = L3111-L211-L1111+L11 L3111-L211-L31+L11+L2-L0 ## M222 = L222-L22 L222-L211+L11-L0 ## M321 = L321-L31-L22-L211+L2+L11 L321-L31-L22-L211+L2+L11 ## M33 = L33-L31+L2-L0 L33-L22 ## M411 = L411-L31-L211+L2+L11-L0 L411-L31-L4+L2 ## M42 = L42-L4-L31-L22+L2+L11 L42-L31 ## M51 = L51-L4-L31+L2 L51-L4 ## M6 = L6-L4 L6 ## \endtt ##
RefinedSymmetrizations
( +
localtbl,sumjava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
,, , F5 F6,
M1,
M2, M11,
M3, M21, M111,
M4 ,M22,M211 ,
M5, M41, M32, M311, M221, ## but the additive inverse of a character is not a character,
))))
# Linear characters are not allowed since their symmetrizations need not
racters.
chars:= Filtered( chars, x -> 1#M \*( <psi>, <cyc> ) . . . . . . . . . scalar multiple of a class function
=;
classess:= [1 ... NrConjugacyClasses( tbl ) ];
IsElmsColls(FamilyObj( g ), FamilyObj( G ) ) then
M2111CorrespondingPermutations(tbl, chi,[ g )1] ;
M311= ( ,x> M2[*x-[x-M21[]
-[])
M221: ( java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 70
M11111:= List( classes, x-> M1[x]*M1111[x]-M2111[x]-M111[x]);
M32:= List( classes, x-> M1[x]*M22[x]-M221[x]-M21[x] );
M41:= java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 9
-M3[x##
M5:= List( java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 27
Append( components, [ M2111, M311,java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
if)
M3111:= List##
M411: tbl:=UnderlyingCharacterTable(chi )
java.lang.StringIndexOutOfBoundsException: Range [36, 31) out of bounds for length 43
: List x>M2[x]M1111[x]M3111[]
]])java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
M111111Error <java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 63
gin[i]
M2211:= List( java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 2
-M21111[x] java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 17
M321:java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 56
-M411[x]-M31[x] , # loop over 'orb'
M33:= List( classes, [1. java.lang.StringIndexOutOfBoundsException: Range [56, 54) out of bounds for length 68
-M31[x]-M22[x]-M211[x]F2[x]);
M51:= List( classes, x-> java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 28
x]);
M42:= List( java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
-M31[]M4x )
M222:= ifpt =failthen
*M5[x]-M51[]M4x )java.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70
if [
andIsInt(m) and <mand m < 7then
return RefinedSymmetrizations( tbl, chars, m, function( x, y ) return x; java.lang.StringIndexOutOfBoundsException: Range [0, 67) out of bounds for length 16 else
Error(in [j then "integer 2 <= m <= 6" );
end;
############################################################################# ## #F SymplecticComponents( <tbl>, <chars>, <m> ) ##
InstallGlobalFunction( SymplecticComponents, java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56 if first,# first point in orbit of 'g' If the table automorphisms are known then we only must determine
retu java.lang.StringIndexOutOfBoundsException: Range [41, 39) out of bounds for length 62 function( x, y ) return x-y; end ); else
Error ": SymplecticComponents( <tbl>, <chars>, <m> ) with ",
java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 37 fi; end );
############################################################################# ## ## 12. Operations for Brauer Characters ##
############################################################################### ## #F FrobeniusCharacterValue( <value>, <p> ) ## ## Let $n$ be the conductor of $v$. ## Let $k$ be the order of $p$ modulo $n$, that is, $\F_{p^k}$ is the ## smallest field of characteristic $p$ containing $n$-th roots of unity. ## Let $m$ be minimal with $v^{\ast p^m} = v$, that is, $\F_{p^m}$ is a ## (not necessarily minimal) field containing the Frobenius character value ## $\overline{v}$. ## ## Let $C_k$ and $C_m$ be the Conway polynomials of degrees $k$ and $m$, ## and $z = X + (C_k)$ in $\F_{p^k} = \F_p[X] / (C_k)$. ## Then $\hat{y} = z^{\frac{p^k-1}{p^m-1}}$ may be identified with ## $y = X + (C_m)$ in $\F_{p^m} = \F_p[X] / (C_m)$. ## ## For $v = \sum_{i=1}^n a_i E(n)^i$, a representation of $\overline{v}$ in ## $\F_{p^k}$ is $\sum_{i=1}^n \overline{a_i} z^{\frac{p^k-1}{n} i}$ where ## $\overline{a_i}$ is the reduction of $a_i$ modulo $p$, viewed as ## element of $\F_p$. ## ## A representation of $\overline{v}$ in $\F_{p^m}$ can be found by ## solving the linear equation system ## $\overline{v} = \sum_{i=0}^{m-1} c_i \hat{y}^i$ over $\F_p$, which ## gives us $\overline{v} = \sum{i=0}^{m-1} c_i y^i$ in $\F_{p^m}$. ##
###############################################################################
java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 46
## 5. Printing Class Functions
size,#M ViewObj( <psi> ) . . . . . . . . . . . . . . . . . view a class function
power, # `( size - 1 ) / n'
ffe, # primitive `n'-th root in `GF( size )' # canonical basis of `CF(n)'
, degree of some field containing the result
image value java.lang.StringIndexOutOfBoundsException: Range [49, 48) out of bounds for length 67
primefield, # `GF(p)'
zero,##
one, # identity of `primefield'
java.lang.StringIndexOutOfBoundsException: Range [15, 13) out of bounds for length 24
x, acharacter"
y,
lastvalue,
fieldbase, #M Display( <chi> ) . . . . . . . . . . . . . . . display a class function
# If <value> belongs to a <p>-singular element then return `fail'.(chi)
n:= Conductor( value ); if n mod p = 0 )java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
return fail; elif n = 1then if DenominatorRat##
return fail; else
return value * One( GFf(tbl fi;
)
return Zero( GF(p) ); fi;
# Compute the size $p^k$ of the smallest finite field of characteristic
k:= OrderMod( p, n );
size= kjava.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
# The root `E(n)' is identified with the smallest primitive `n'-th # root in the finite field, that is, the `(size-1) / n'-th power of
theprimitive root of the field # (which is given by the Conway polynomial).
power:= ( size - 1 ) / n;
if size < java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 44
# Use GAP's internal finite fields. # (Express the Brauer character value in terms of the Zumbroich basis # of the underlying cyclotomic field.)
ffe:= PrimitiveRoot( GF( size ) ) ^ power;
cf:= CanonicalBasis( CF( n ) );
value [IsNearlyCharacterTable,IsDenseList ]],
List( ZumbroichBase( n, 1 ), exp -> ffe ^ exp );
elif not IsCheapConwayPolynomial( p, k ) then
# Give up if the required Conway polynomial is hard to compute.
Info( InfoWarning, 1, "the Conway polynomial of degree ", k, " for p = ## " is not known" ); elifchi (chi)then
else
# Compute a finite field that contains the Frobenius character value. # An upper bound is given by the field of order $p^m$ # where $m$ is the smallest number such that <value> is fixed # by the Galois automorphism that raises roots of unity # to the $p^m$-th power.
m:= 1;
image:= GaloisCyc( value, p ); while image <> value do
m:= m+1;
image:= GaloisCyc( image,G >TrivialCharacter( )) ;
od;
conwaypol:= ConwayPol( p, k ) * one;
x:= [ zero, one ];
value:= COEFFS_CYC( value ) * one;
java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 30
ConvertToVectorRepNC( x, p );
ConvertToVectorRepNC( value, p );
value:= PowerModEvalPol( conwaypol,
value, ## if IsEmpty( value ) then
i - Number( dom,j - j = opr( j, Representative(i) ) ) ) ); fi;
PadCoeffs( value, k, zero )#
# Compute a $\F_p$-basis $(\hat{y}^i; 0\leq i\leq m-1)$ of # the subfield of $\F_{p^k}$ isomorphic with $\F_{p^m}$.
y:= PowerModCoeffs( x, 2, (size - 1) / (
lastvalue:= [ one ];
fieldbase:= [ [ one ] ];
PadCoeffs( fieldbase[1], k, zero );
ConvertToVectorRepNC( fieldbase[1], p );
for i in [ 2 .. m ] do
lastvalue:= ProductCoeffs( y, java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 2
ReduceCoeffs( lastvalue, conwaypol );
ShrinkRowVector( lastvalue );
PadCoeffs( lastvalue, k, zero
fieldbase[i]:= lastvalue;
ConvertToVectorRepNC( fieldbase[i], p );
od;
( SolutionMatDestructive(fieldbase,value )java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
Z( p, m ) ); fi;
# Return the Frobenius character value.
return value; end ,
############################################################################## ## #F ReductionToFiniteField( <value>, <p> ) ##
InstallGlobalFunction( ReductionToFiniteFieldifnotIsInt(scpr ) orscpr < 0then
local n, primefield, one, zero, return true;
conwaypol,
i, redsol;
the
n:= Conductor( value ); if n mod p =#M IsVirtualCharacter( <chi> ) . . . . . . . . . . . . for a class function
return fail; fi;
primefield:= GF(p);
# Catch the case where the reduction trivially lies in the prime field. if n = 1then if DenominatorRat( value ) mod p = 0then
return fail; else
return [ value * One( Indeterminate( primefield ) ), 1 ]; fi;
( value /p )then
return [ Zero( Indeterminate( primefield ) ), 1 ]; fi;
# Compute the size $p^k$ of the smallest finite field of characteristic # `p' that contains `n'-th roots of unity.
k:= OrderMod( p, n );
size:= p^k;
# The root `E(n)' is identified with the smallest primitive `n'-th # root in the finite field, that is, the `(size-1) / n'-th power of # the primitive root of the field # (which is given by the Conway polynomial).
power ;
if size <= MAXSIZE_GF_INTERNAL then # Use GAP's internal finite fields. # (Compute the Frobenius character value and the corresponding pol.)
ffe:= PrimitiveRoot( GF( size ) ) ^ power;
cf:= CanonicalBasis( CF( n" twofunctions"
frob: Coefficients( cf, value )*
List( tbl; if IsZero( frob ) then
return [ ) fi;
d:= DegreeFFE## if d = 1then
local i # loop variable fi;
# Note that `LogFFE' returns a nonzero value.
conwaypol:= ConwayPol( p, d ) * one;
x:= [ zero, one ];
epNC conwaypol ;
ConvertToVectorRepNC( x, p );
frob:= PowerModCoeffs( x, 2, LogFFE( frob, Z( p, d ) ), conwaypol, d+1 );
return [ UnivariatePolynomialByCoefficients( FamilyObj( one ),
, ,
; elif notreturn [ # Give up if the required Conway polynomial is hard to compute.
Info( InfoWarning, 1, "the Conway polynomial of degree ", k, " for p = ", p, "is known )
return if IsEmpty( li )then fi;
conwaypol:= ConwayPol( p, k ) * one;
x:= [ zero, one ];
value:= COEFFS_CYC( value ) * one;
ConvertToVectorRepNC( conwaypol, p );
ConvertToVectorRepNC( x,
ConvertToVectorRepNC( value, p ) weight: SizesConjugacyClasses( tbl );
# Reduce the representation into the smallest finite field. # The currently known field has size `p^k'.
m:= k;
if k <> 1then
primes:= ShallowCopy( PrimeDivisors( m ) );
solnccl: NrConjugacyClasses( tbl );
while not IsEmpty(primes ) do
for l in ShallowCopy( primes ) do
# `p^(m/l)' is the candidate for next smaller field.
mc:= m / l;
$basis $(\hat{y}^i; 0 \leq i \leq m/ -1) # the subfield of $\F_{p^k}$ isomorphic with $\F_{p^{(m/l)}}$.
IsCyc( java.lang.StringIndexOutOfBoundsException: Range [33, 34) out of bounds for length 33
leny:= Length( y );
lastvalue:= [ one ];
PadCoeffs( lastvalue, k, zero );
fieldbase: ] ;
PadCoeffs( fieldbase[1], k, zero );
ConvertToVectorRepNC( lastvalue, p );
ConvertToVectorRepNC
for i in [ 2 .. mc ] java.lang.StringIndexOutOfBoundsException: Range [0, 33) out of bounds for length 0
lastvalue:= ProductCoeffs( y,
ReduceCoeffs( lastvalue, ( chi
PadCoeffs( lastvalue, k, zero );
onvertToVectorRepNC lastvalue, p ); #T needed?
fieldbase[i]:= lastvaluejava.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 72
od;
## a cyclotomic integer is a root of unity iff its absolute value is $1$.
## `lib/cyclotom.g'. if redsol = fail then
"for a homogeneoufor alist" else
sol:= redsol;
mc; fi;
od;
IntersectSet( primes, Factors( m ) java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
od;
if sol # We have found a smaller field.
value:= sol; fi;
# Return the reduction into the minimal field.
return [ =]
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17 end );
# # alternative implementation # ReductionToFiniteField2:= function( value, p ) # local frob, d, z, one, zero, conwaypol, x; # # frob:= FrobeniusCharacterValue( value, p ); # if frob = fail then # return fail; # elif IsZero( frob ) then # return [ Zero( Indeterminate( GF(p) ) ), 1 ]; # fi; # # d:= DegreeFFE( frob ); # # if d = 1 then # return [ frob * One( Indeterminate( GF(p) ) ), 1 ]; # elif p^d <= MAXSIZE_GF_INTERNAL then # z:= Z( p, d ); # one:= One( z ); # zero:= Zero( z ); # conwaypol:= ConwayPol( p, d ) * one; # x:= [ zero, one ]; # ConvertToVectorRepNC( conwaypol, p ); # ConvertToVectorRepNC( x, p ); # # # Note that `LogFFE' returns a nonzero value. # frob:= PowerModCoeffs( x, 2, LogFFE( frob, z ), conwaypol, d+1 ); # frob:= UnivariatePolynomialByCoefficients( FamilyObj( one ), # frob, 1 ); # elif IsCoeffsModConwayPolRep( frob ) then # frob:= UnivariatePolynomialByCoefficients( FamilyObj( Z(p) ), # frob![1], 1 ); # else # # This should never happen, since `FrobeniusCharacterValue' worked. # Info( InfoWarning, 1, # "no coefficients w.r.t. the Conway polynomial available" ); # return fail; # fi; # return [ frob, d ]; # end;
############################################################################## ## #F SizeOfFieldOfDefinition( <val>, <p> ) ## ## Typically, <val> is a (Brauer) character, that is, a list of cyclotomic ## integers with conductor coprime to <p>, which is closed under Galois ## conjugacy. ## In this situation, the size of the field of definition is the smallest ## power <q> of <p> such that the difference of <val> and its image under ## the Galois automorphism 'GaloisCyc( ., <q> )' is divisible by <p> in the ## ring of cyclotomic integers. ## (This follows with the same number theoretic argument that is used in the ## proof of <Cite Key="Isa76" Where="Theorem 15.18."/>.) ## ## If <val> is not closed under Galois automorphisms then the result depends ## on the definition of the reduction from cyclotomics to finite fields, ## and in general there is no way to avoid computing the reduction of <val>. ## For example, if we assume the reduction w.r.t. Conway polynomials then ## the reduction of the value 'EX(63)' in characteristic 2 lies in the prime ## field, whereas the reduction of its complex conjugate does not lie in the ## prime field. ## If we choose a different reduction homomorphism ## (for example, if we choose other polynomials to define the fields) ## then the situation may be the other way round. ## ## If the coefficients of the Zumbroich basis representation of the ## difference $\alpha^{\ast p} - \alpha$ are divisible by $p$ ## then $\alpha$ is mapped to an element of the prime field under ## the reduction modulo any maximal ideal. ## (This covers the special cases that $\alpha$ is fixed under the ## automorphism $\ast p$ or that all coefficients of $\alpha$ ## are divisible by $p$.) ##
(,java.lang.StringIndexOutOfBoundsException: Range [65, 64) out of bounds for length 66
local closed, values, entry, q;
closed:= false;
# The first argument may be a cyclotomic or a list of cyclotomics. if IsInt( val ) then
return p; elif IsCyc( val ) then
val:= [ val ]; elif IsClassFunction( val ) java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 33 # This is expected to be the typical situation. # We know in advance that 'val' is closed under Galois conjugacy.
closed:= true;
val:= ValuesOfClassFunction; elif not ( IsList( val ) and IsCyclotomicCollection( val ) ) then
Error( "<val> must be a cyclotomic or a list of cyclotomics" ); fi;
values:= []; for entry in val do if DenominatorCyc( entry ) mod p = 0 or
Conductor( entry ) mod p = 0then
return fail; elif not IsRat( entry[ ]
Add( values, entry : java.lang.StringIndexOutOfBoundsException: Range [36, 34) out of bounds for length 47 fi;
od;
if ForAll( values, x -> IsCycInt( ( GaloisCyc( x, end )java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10 # All reductions lie in the prime field.
return p; elif closed then # It is sufficient to look at powers of the map '*p'.##
q=; while true do
q:= q * p; if ForAll( values,
- (GaloisCyc( x q)- p ) )then
return q; fi;
od; fi;
=( ; # Galois conjugacy, or check some generalization of this condition, # but this is probably not worth the effort.)
=List( values,x >FrobeniusCharacterValue( , p ) ); if fail in values then
return fail;
return p ^ DegreeFFE( values ); end );
############################################################################# ## #M BrauerCharacterValue( <mat> ) ## ## Let $M$ be a matrix of order $n$, with entries in the finite field $F$, ## and suppose that $M$ is diagonalizable over the extension field $K$ with ## $p^d$ elements. ## ## It could in principle be computed by determining the diagonal form, ## identifying the entries in the diagonal with $(p^d -1)$-th complex roots ## of unity, ## and then summing up these roots. ## ## But one can do better. ## (This is the approach used by the C-{\MeatAxe}.) ## For each irreducible factor $f$ of $X^n - 1$ over $F$, the multiplicities ## of its roots over $K$ as eigenvalues of $M$ are equal, ## hence one needs to compute these multiplicities and the corresponding ## sums of roots of unity. ## The former means to solve an equation system over $F$, ## and the latter depends only on $n$ and $F$, but not on $M$; ## so one can use a database for speeding up the computations. ## This database is implemented by the global variable `ZEV_DATA' and the ## functions `ZevData' and `ZevDataValue'. ##
InstallMethod( BrauerCharacterValue, "for a matrix",
[ IsMatrix ], functionSetIsCharacter( det, true );
local n, # order of `mat'
p, # characteristic of `mat'InstallMethod DeterminantOfCharacter,
info, # list of pairs returned by `ZevData'
value, # Brauer character value, result
pair, # loop over `info'
f, # polynomial part of `pair'
nullity; # dimension of a nullspace
n:= Order( mat );
# Handle the trivial cases first. if n = 1then
return ( mat ) fi;
p:= Characteristic( mat ); if n mod p = 0then
return fail; fi;
# Get the complex values corresponding to the irreducible # factors of $X^n - 1$ over $F$.
#T > (The latter function involves using algebraic numbers,
# Compute the coefficients of the complex summands, # as quotients of nullities and degrees.
value:= 0; for pair #T in such a case.
f:= pair[1];
nullity (java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 61 if nullity <> 0then
Assert( 1, IsInt( nullity ), "degree of <f> must divide <nullity>" );
value:= value + nullity * pair[2 #T for rational characters, this avoids computation with
od;
return value; end );
############################################################################# ## #F ZevDataValue( <q>, <n> ) ##
InstallGlobalFunction( ZevDataValue, function( q, n )
local F, dimext, extfieldsize, Ee, value, K, z, quot, R, f, y, fac,
p, one, conw, conwlen, x, zpol, zpollen, zeta, zetalen, coeffs, l,
power, powerlen, i, exp, res, reslen, j;
# Compute the field $F$ of matrix entries and the smallest field $K # over which a matrix of order `n' is diagonalizable. )and IsClassFunction( j)and
F:= GF( q );
dimext: DegreeOverPrimeField( F *OrderMod(q n );
extfieldsize:= Characteristic( F ) ^ dimext;
Ee:= E( n );
value:= [];
if extfieldsize <= MAXSIZE_GF_INTERNAL then
# The splitting field is supported in {\GAP}, # and the stored primitive root is given by the Conway polynomial.
K:= GF( extfieldsize );
z: PrimitiveRoot( );
quot:= ( extfieldsize - 1 ) / n;
R:= PolynomialRing( K ); for f in return One( chi
y:= 0; for fac in Factors( R, f ) do
# The factors are all linear, i.e., of the form $X - \alpha$. # Sum up the lifts of the numbers $\alpha$.#M RestrictedClassFunction( [<tbl>, ]<chi>, <H> )
y:= y + Ee^ ( LogFFE##
-CoefficientsOfLaurentPolynomial( fac )[1][1], z java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 33
od;
Add( value, [ CoefficientsOfLaurentPolynomial( f )[1], y ] );
od;
else
# The splitting field is not available in {\GAP}, # use computations with polynomials.
p:= Characteristic( F );
z:= PrimitiveRoot( F );
one:= One( F );
conw: ConwayPol(p dimext ) ;
conwlen:= dimext + 1;
x:= [ Zero( F ), one ];
# polynomial corresponding to the primitive root of `F'
=(x,2,(extfieldsize-)/ (Size(F)1 ),
conw, conwlen );
zpollen:= Length( zpol );
# polynomial corresponding to a primitive `n'-th root $\zeta$
zeta:= PowerModCoeffs( x, 2, ( extfieldsize-1 ) / n,
conw, [ IsNearlyCharacterTable, IsHomogeneousLi ]java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
zetalen:= Length( zeta );
for f in Factors( PolynomialRing( F ), Indeterminate(F)^n - 1 ) do
y:= 0;
coeffs:= CoefficientsOfUnivariatePolynomial( f );
l:= Length( coeffs );
power:= [ one ];
powerlen:= 1;
i 0. 1]do
# Compute $\sum_{j=0}^{l-1} c_j \zeta^{i j}$, where `f' has the form $\sum_{j=0}^{l-1} c_j X^j$.
exp:= if exp = 0then
res:= [ one ]; else
res:= PowerModCoeffs( zpol, zpollen############################################################################# fi;
reslen:= Length( res );
j 1 .l-] do
reslen:= MultCoeffs( res, res, reslen, power, powerlen ); if IsZero( coeffs[-]) then
exp:= LogFFE( coeffs[l-j], z ); if exp = 0then
] else
res:= res + PowerModCoeffs( zpol, zpollen, exp,
java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 35 fi; fi;
reslen table, a list, and a group",
ShrinkRowVector( res ); # needed?
reslen:= Length( res ); # needed?
od;
fi; # complex root of unity. if reslen = 0then
y:= y + Ee^i; fiValuesOfClassFunction ) fus}))java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
powerlen:= MultCoeffs( power, power, powerlen, zeta, java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 51
powerlen:= ReduceCoeffs( power, powerlen, conw, conwlen );
od;
Add( value, [ coeffs, y ] );
od;
fi;
return value;
############################################################################# ## #F ZevData( <q>, <n> ) #F ZevData( <q>, <n>, <listofpairs> ) ##
InstallGlobalFunction( ZevData, functionjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
local aux, result;
aux := GET_FROM_SORTED_CACHE(ZEV_DATA, q, {} -> NEW_SORTED_CACHE(false));
if Length( listofpairs ) = 1then
listofpairs := listofpairs[1];
result := GET_FROM_SORTED_CACHE(aux, n, {} -> Immutable(listofpairs)); if
Error( "incompatible ZevData( ", q, ", ", n, " )" ); fi;
return result;
else
return GET_FROM_SORTED_CACHE(aux, n, {} -> ZevDataValue( q, n )); fi; end );
############################################################################## ## #F RealizableBrauerCharacters( <matrix>, <q> ) ##
InstallGlobalFunction( java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 24
local result, factors, p, m, done, row, d, g, qq, image, newrow, i;
for row in matrix do if not row in donethen
d:= SizeOfFieldOfDefinition( row, p ) if d = fail then
IsMatrix(list )then fi;
d:= Length( Factors( d ) );
g:= Gcd( d, m );
qq:= p^g;
image:= row;
newrow:= row;
Add( done, row );
for i in [ 1 .. d ;
image:= GaloisCyc( image, qq );
= +;
Add( done, image );
if not newrow in result then
Add( result, newrow ); fi; fi;
return result; end );
############################################################################# ## ## 13. Domains Generated by Class Functions ##
############################################################################# ## #M GroupWithGenerators( <classfuns>[, <id>] ) ##
InstallOtherMethod( GroupWithGenerators, "java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
[ IsHomogeneousList ], function( gens )
local filter, G;
# Check that the list consists of invertible class functions. if IsEmpty( gens ) or not ForAll( gens, IsClassFunction ) then
TryNextMethod(); elif ForAny( gens, psi ->e( psi ) = fail ) then
Error( "class functions in <gens> must be invertible" ); #T move to `IsGeneratorsOfGroup' fi ]j;
filter:= IsGroup and IsAttributeStoringRep; if IsFinite( gens ) then
filter:= filter and IsFinitelyGeneratedGroupjava.lang.StringIndexOutOfBoundsException: Range [46, 21) out of bounds for length 73 fi;
# Construct the group.
G:= Objectify( NewType( # Create the class function
SetGeneratorsOfMagmaWithInverses( G, AsList( gens ) );
return G; end );
InstallOtherMethod( GroupWithGenerators, "for list (of class functions) and class function",
IsCollsElms,
[ IsHomogeneousList, IsClassFunction ], function( gens, id )
,G;
# Check that the class functions are invertible. if not ForAll( gens, IsClassFunction ) then
TryNextMethod(); elif ForAny( gens, psi -> Inverse( psi ) = fail ) then
Error( "class functions in <gens> must be invertible" ); #T move to `IsGeneratorsOfGroup' elif not IsOne( id ) then
Error( "<id> must be an identity" ); fi;
filter:= IsGroup andInstallMethod java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 36 if IsFinite( localfus;
filter:= filter and IsFinitelyGeneratedGroup; fi;
# Construct the group.
G:= Objectify( NewType( FamilyObj( gens ), filter), rec() );
SetGeneratorsOfMagmaWithInverses( G, AsList( gens ) );
SetOne( G, id );
return G; end );
InstallOtherMethod( GroupWithGenerators, "for empty list and trivial character",
[ IsList and IsEmpty, IsClassFunction ], function( empty, id )
local G;
if not IsOne( id ) then
Error( "<id> must be an identity" ); fi;
# Construct the group.
InstallMethod InducedClassFunctions,
IsGroup and IsAttributeStoringRep and
IsFinitelyGeneratedGroup and IsTrivial ),
rec() );
SetGeneratorsOfMagmaWithInverses( G, empty );
SetOne( G, id );
return G; end );
############################################################################# ## ## 5. vector spaces of class functions ## ## Free left modules and algebras of class functions are handled by nice ## bases, ## for admitting the default procedure of closure under multiplication. ## In order to apply `NiceVector' and `UglyVector', algebras of class ## functions are in the filter `IsClassFunctionsSpace'. ##
InstallHandlingByNiceBasis( "IsClassFunctionsSpace", rec(
detect:= function( R, gens, V, zero )
local tbl; if not ForAll( gens, ftable list nearly character",
return false; elif zero = false then
tbl:= UnderlyingCharacterTable( gens[1] ); elif not IsClassFunction( zero ) then
return false; else
tbl:= UnderlyingCharacterTable( zero ); fi; fi; if ForAny( gens, chi return (,,fus ;
return false; fi;
return true; end,
NiceFreeLeftModuleInfo := function( V )
return UnderlyingCharacterTable( Zero( V ) ); end,
NiceVector := function( V, v ) if UnderlyingCharacterTable( v ) = NiceFreeLeftModuleInfo( V ) then
return ValuesOfClassFunction( v ); else
return fail; fi; end,
UglyVector := function( V, r )
return ClassFunction( NiceFreeLeftModuleInfo( V ), r ); end ) );
############################################################################# ## #M ScalarProduct( <V>, <chi>, <psi> ) . . . . for module of class functions ## ## Left modules of class functions carry the usual bilinear form. ##
InstallOtherMethod( ScalarProduct, "for left module of class functions, and two class functions",
IsCollsElmsElms,
[ IsFreeLeftModule, IsClassFunction, IsClassFunction ], function( V, x1, x2 )
local tbl;
tbl:= UnderlyingCharacterTable( x1 ); if tbl = UnderlyingCharacterTable( x2 ) then
return ScalarProduct( tbl, x1, x2 ); else
TryNextMethod(); fi; end );
############################################################################# ## #M ScalarProduct( <V>, <chivals>, <psivals> ) . . for module of class funs. ## ## Left modules of class functions carry the usual bilinear form. ##
InstallOtherMethod( ScalarProduct, "for module of class functions, and two values lists",
[ IsFreeLeftModule and IsClassFunctionsSpace,
IsHomogeneousList, IsHomogeneousList ], function( V, x1, x2 )
return ScalarProduct end ; end );
############################################################################## ## #F OrbitChar( <chi>, <linear> ) ##
InstallGlobalFunction( OrbitChar, function( chi, ( java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
local classes, # range of positions in `chi'
nofcyc, # describes the conductor of values of `chi'
gens, # generators of Galois automorphism group
orb, # the orbit, result
gen, # loop over `gens'
image; # one image of `chi' under operation
classes:= [ 1 .. Length( chi ) ];
nofcyc:= Conductor( chi );
# Apply Galois automorphisms if necessary.
orb:= [ chi ]; if1 < nofcyc then
gens:= Flat( GeneratorsPrimeResidues( nofcyc ).generators ); for chi in orb do for gen in gens do
-> GaloisCyc( x gen ); if not image in orb then
Add( orb, image ); fi;
od;
od; fi;
# Apply multiplication with linear characters. for chi in orb do for gen in linear do
image:= return InducedCyclic java.lang.StringIndexOutOfBoundsException: Range [57, 56) out of bounds for length 73 if not image in orb then
(,image ) fi;
od;
od;
# Return the orbit.
return orb; end );
############################################################################## ## #F OrbitsCharacters( <irr> ) ##
InstallGlobalFunction( OrbitsCharacters, function( irr )
local irrvals, # list of value lists
oldirrvals, # store original succession
tbl, # underlying character table
linear, # linear characters of `tbl'
orbits,#list of orbits, result
indices, # from 1 to number of conjugacy classes of `tbl'
orb, # one orbit
gens, # generators of the acting group
chi, # one irreducible character
gen, # one generator of the acting group
image, # image of a character
i, # loop over one orbit
pos; # position of value list in `oldirrvals'
orbits:= [];
if not IsEmpty( irr ) then
if IsClassFunction( irr[1] ) then
# Replace group characters by their value lists. # Store the succession in the original list.
irrvals:= OrdersClassRepresentatives )java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
oldirrvals:= ShallowCopy( irrvals );
irrvals:= Set( irrvals );
else
irrvals:= Set( irr ); fi;
indices:= [ 1 .. Length( irrvals[1] ) ];
# Compute the orbit of linear characters if there are any.
linear:= Filtered( irrvals, x -> x[1] = 1 );
if0< Length( linear ) then
# The linear characters form an orbit. # position is Galois conjugate # and remove the trivial character from `linear'.
orb:= ShallowCopy( linear );
SubtractSet( irrvals, linear );
RemoveSet( linear, List( linear[1], x -> 1 ) );
# Make `linear' closed under Galois automorphisms.
gens:= Flat( GeneratorsPrimeResidues(
(Flat( linear ) ) ).generators )java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
for chi in orb do for gen in gens do
image:= List( chi, x -> GaloisCyc( x, gen ) ); if not image in orb then
Add( orb, image ); fi;
od;
od;
# Make `linear' closed under multiplication with linear characters. for chi in orb do for gen in linear do
imagejava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 2 if not image in orb then
Add#M ReducedClassFunctions( [<ordtbl>, ]<constituents>, <reducibles> ) fi;
;
od;
orbits[1]:= orb;
fi;
# Compute the other orbits. while Length( irrvals ) > 0do
=OrbitChar(irrvals[] linear )java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
Add( orbits, orb );
SubtractSet(irrvals,orb ;
od;
# Replace the value lists by the group characters # if the input was a list of characters. # Be careful not to copy characters if not necessary. if IsCharacter( irr[1] ) then
java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49 for orb in orbits do
i in[ 1 . Length(orb do
pos:= Position( oldirrvals, orb[i] ); if pos = fail then
orb[i]:= Character( tbl, orb[i] ); else
orb[i]:= irr[ pos ]; fijava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
od;
fi;
fi;
return orbits; end );
############################################################################## ## #F OrbitRepresentativesCharacters( <irr> ) ##
InstallGlobalFunction( OrbitRepresentativesCharacters, function( irr )
local irrvals, # list of value lists
oldirrvals # store original succession
chi,
linear, # linear characters in `irr'
nonlin, # nonlinear characters in `irr'
repres, # list of representatives, result
orb; # one orbit
repres:= [];
if not IsEmpty( irr ) then
AddSet( found, single );
# Replace group characters by their value lists. fi
irrvals:= List( irr, ValuesOfClassFunction );
oldirrvals:= ShallowCopy( irrvals );
irrvals:= Set( irrvals );
else
irrvals:= Set( irr ); fi;
# Get the linear characters.
linear := [];
nonlin := []; for chi in irrvals do if chi[1] = 1then
Add( remainders, else
Add( nonlin, chi ); fi;
od; if Length( linear ) > 0then
[]= 1]java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30 fi AddSet(found,reducibles[])java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
# Compute orbits and remove them until the set is empty. while Length( nonlin ) > 0do
Add( repres, nonlin[1] = []
orb:= OrbitChar( nonlin[1], linear );
SubtractSet( nonlin, orb );
# Replace the value lists by the group characters # if the input was a list of characters. # Do not copy characters! if IsCharacter( irr[1] ) then
repres:if >x>0 fi;
fi;
# Return the representatives.
return repres; end );
# Compute successivly the partition of column families defined by # the rows already processed.
nontrivblocks:= [ [ 1 .. Length( mat[1] ) ] ]; for row in Concatenation( maps, mat ) do
newblocks:= []; for nontrivblock in nontrivblocks do
values:= [];
blocks:= []; for k in nontrivblock do
pos:= 1; while pos <= Length( values ) and values[ pos ] <> row[k] do
pos:= pos + 1;
od; if Length( values ) < pos then
values[ pos ]:= row[k];
blocks[pos ]=[k ] else
AddSet( blocks[ pos ], k ); fi j in [1 . nchars do
od; for k in blocks do if1 < Length( k ) then Add( scpr:= Int( scpr / normsquare
od;
od;
nontrivblocks:= newblocks;
od;
minima:= List( nontrivblocks, Minimum );
nontrivblocks:= Permuted( nontrivblocks, Sortex( minima ) );
minima:= Concatenation( [ 0 ], minima od;
fusion:= [];
pos:= 1; for i in [ 1 .. Length( minima ) - 1 ] do for j in [ minima[i] + 1 .. minima[i+1] - 1 ] do if not IsBoundC InfoCharacterTable,2
fusion[j]:= pos;
pos:= pos + 1; fi
od; for j in nontrivblocks[i] do fusion[j]:= pos; od;
pos:= pos + 1;
od; for i in [ Last(minima) + 1 .. Length( mat[1] ) ] do if not IsBound( fusion[i] ) then
i]: pos;
pos:= pos + 1; fi;
od;
values:= ProjectionMap( fusion );
return rec( mat:= List( mat, x -> x{ values } ), #T do I really need the component 'mat'?
fusion:= fusion ); end );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.