Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ctblfuns.gi   Sprache: unbekannt

 
#############################################################################
##
##  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

--> --------------------

[ Verzeichnis aufwärts0.19unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge