|
#############################################################################
##
## 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 ) ) ) );
InstallMethod( AdditiveInverseOp,
"for a virtual character",
[ IsClassFunction and IsVirtualCharacter ],
psi -> VirtualCharacter( 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 );
if 0 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] = 1 then
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 ) = 0 then
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 ) = 1 then
#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 ) = 1 then
#T why not `min' ?
# necessarily fixed point
images[ list[1] ]:= list[1];
elif Length( Set( values{ list } ) ) = 1 then
# 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 );
InstallMethod( ViewObj,
"for a virtual character",
[ IsClassFunction and IsVirtualCharacter ],
function( psi )
Print( "VirtualCharacter( " );
View( UnderlyingCharacterTable( psi ) );
Print( ",\<\<\<\>\>\> " );
View( ValuesOfClassFunction( psi ) );
Print( " )" );
end );
InstallMethod( ViewObj,
"for a character",
[ IsClassFunction and IsCharacter ],
function( psi )
Print( "Character( " );
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 VirtualCharacter( <tbl>, <values> )
##
InstallMethod( VirtualCharacter,
"for nearly character table, and dense list",
[ IsNearlyCharacterTable, IsDenseList ],
function( tbl, values )
values:= ClassFunction( tbl, values );
SetIsVirtualCharacter( values, true );
return values;
end );
#############################################################################
##
#M VirtualCharacter( <G>, <values> )
##
InstallMethod( VirtualCharacter,
"for a group, and a dense list",
[ IsGroup, IsDenseList ],
function( G, values )
return VirtualCharacter( OrdinaryCharacterTable( G ), values );
end );
#############################################################################
##
#M Character( <tbl>, <values> )
##
InstallMethod( Character,
"for nearly character table, and dense list",
[ IsNearlyCharacterTable, IsDenseList ],
function( tbl, values )
values:= ClassFunction( tbl, values );
SetIsCharacter( values, true );
return 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;
chi:= Character( tbl,
ListWithIdenticalEntries( NrConjugacyClasses( tbl ), 1 ) );
SetIsIrreducibleCharacter( chi, true );
return chi;
end );
#############################################################################
##
#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 ) = 0 then
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 ) = 0 then
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>, <D>, <opr> ) . . . . . . . . for group action
##
InstallMethod( PermutationCharacter,
"group action on domain",
[ IsGroup, IsCollection, IsFunction ],
function( G, dom, opr )
local tbl;
tbl:= OrdinaryCharacterTable( G );
return Character( tbl, List( ConjugacyClasses( tbl ),
i -> Number( dom, j -> j = opr( j, Representative(i) ) ) ) );
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] <= 0 then
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 < 0 then
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] <= 0 then
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 <> 0 then
if found or i <> 1 then
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]<>0 then
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 );
nccl:= NrConjugacyClasses( tbl );
weight:= SizesConjugacyClasses( tbl );
order:= Size( tbl );
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 );
nccl:= NrConjugacyClasses( tbl );
weight:= SizesConjugacyClasses( tbl );
order:= Size( tbl );
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;
while 0 < deg and i <= Length( irr ) do
irrdeg:= DegreeOfCharacter( irr[i] );
if irrdeg <= deg then
scpr:= ScalarProduct( tbl, chi, irr[i] );
if scpr <> 0 then
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 <> 0 then
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 ) = 1 then
return H;
elif ScalarProduct( tbl, chi, chi ) = 1 then
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] = 0 then
# 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
--> --------------------
--> maximum size reached
--> --------------------
[ Dauer der Verarbeitung: 0.62 Sekunden
(vorverarbeitet)
]
|