Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/ctbllib/gap4/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 14.10.2024 mit Größe 153 kB image not shown  

SSL construc.gi   Sprache: unbekannt

 
#############################################################################
##
#W  construc.gi          GAP 4 package CTblLib                  Thomas Breuer
##
##  1. Character Tables of Groups of Structure $M.G.A$
##  2. Character Tables of Groups of Structure $G.S_3$
##  3. Character Tables of Groups of Structure $G.2^2$
##  4. Character Tables of Groups of Structure $2^2.G$
##  5. Character Tables of Subdirect Products of Index Two
##  6. Brauer Tables of Extensions by $p$-regular Automorphisms
##  7. Construction Functions used in the Character Table Library
##  8. Character Tables of Coprime Central Extensions
##  9. Miscellaneous
##


#############################################################################
##
##  1. Character Tables of Groups of Structure $M.G.A$
##


#############################################################################
##
#F  IrreducibleCharactersOfTypeMGA( <tblMG>, <tblGA>, <Mclasses>, <MGAfusGA>,
#F                                  <orbs>, <a> )
##
##  <Mclasses> is assumed to be the set of classes in <tblMG> that are mapped
##  to the identity in the factor group $G$
##  that is a normal subgroup of <tblGA>.
##  Note that the table of $G$ is not needed at all in the construction,
##  only the quotient $|G.a| / |G|$ seems to be a necessary parameter.
##
BindGlobal( "IrreducibleCharactersOfTypeMGA",
    function( tblMG, tblGA, Mclasses, MGAfusGA, orbs, a )
    local irr, p, m, ordtbl, zero, chi, ind, i;

    irr:= List( Irr( tblGA ), chi -> CompositionMaps( chi, MGAfusGA ) );
    p:= UnderlyingCharacteristic( tblMG );
    m:= Sum( SizesConjugacyClasses( tblMG ){ Mclasses }, 0 );
    if p <> 0 then
      # Consider the ordinary tables, and divide the group orders by the
      # orders of the `p'-cores.
      # Note that we may construct the 3-modular table of $6.A_6.2_1$ from
      # the table of its derived subgroup and the table of one of the factor
      # groups $3.A_6.2_1$ or $A_6.2_1$.
      ordtbl:= OrdinaryCharacterTable( tblMG );
      m:= m * Sum( SizesConjugacyClasses( ordtbl ){
                       ClassPositionsOfPCore( ordtbl, p ) }, 0 );
      ordtbl:= OrdinaryCharacterTable( tblGA );
      m:= m / Sum( SizesConjugacyClasses( ordtbl ){
                       ClassPositionsOfPCore( ordtbl, p ) }, 0 );
    fi;
    zero:= Zero( MGAfusGA );
    for chi in Irr( tblMG ) do
      if not IsSubset( ClassPositionsOfKernel( chi ), Mclasses ) then
        ind:= ShallowCopy( zero );
        for i in [ 1 .. Length( orbs ) ] do
          if IsBound( orbs[i] ) then
            ind[i]:= Sum( chi{ orbs[i] }, 0 ) * ( a / Length( orbs[i] ) );
          fi;
        od;
        if not ind in irr then
          Add( irr, ind );
        fi;
      fi;
    od;

    return irr;
    end );


#############################################################################
##
#F  PossibleCharacterTablesOfTypeMGA( <tblMG>, <tblG>, <tblGA>, <orbs>,
#F      <identifier> )
##
InstallGlobalFunction( PossibleCharacterTablesOfTypeMGA,
    function( tblMG, tblG, tblGA, orbs, identifier )
    local MGfusG,        # factor fusion map from `tblMG' onto `tblG'
          GfusGA,        # subgroup fusion map from `tblG' into `tblGA'
          tblMGA,        # record for the desired table
          MGfusMGA,      # subgroup fusion map from `tblMG' into `tblMGA'
          factouter,     # positions of classes of `tblGA' outside `tblG'
          MGAfusGA,      # factor fusion map from `tblMGA' onto `tblGA'
          inner,         # inner classes of `tblMGA'
          outer,         # outer classes of `tblMGA'
          nccl,          # class number of `tblMG'
          classes,       # class lengths of `tblMG'
          i,             # loop variable
          primes,        # prime divisors of the order of `tblMGA'
          invMGAfusGA,   # inverse of `MGAfusGA'
          p,             # loop variable
          GAmapp,        # `p'-th power map of `tblGA'
          orders,        # element orders of `tblMGA'
          suborders,     # element orders of `tblMG'
          outerorders,   # outer part of the orders
          gcd,           # g.c.d. of the orders of `M' and `A'
          matautos,      # matrix automorphisms of the irred. of `tblMGA'
          tblrecord,     # record of `tblMGA' (power maps perhaps ambiguous)
          info,          # list of possible tables
          newinfo,       # list of possible tables for the next step
          pair,          # loop variable
          pow,           # one possible power map
          newmatautos,   # automorphisms respecting one more power map
          newtblMGA,     # intermediate table with one more unique power map
          oldfus;

    # Check the arguments.
    if not ForAll( [ tblMG, tblG, tblGA ], IsOrdinaryTable ) then
      Error( "<tblG>, <tblMG>, <tblGA> must be ordinary character tables" );
    fi;

    # Fetch the stored fusions.
    MGfusG:= GetFusionMap( tblMG, tblG );
    GfusGA:= GetFusionMap( tblG, tblGA );
    if MGfusG = fail or GfusGA = fail then
      Error( "fusions <tblMG> -> <tblG>, <tblG> -> <tblGA> must be stored" );
    fi;

    # Initialize the table record `tblMGA' of $m.G.a$.
    tblMGA:= rec( UnderlyingCharacteristic := 0,
                  Identifier := identifier,
                  Size := Size( tblMG ) * Size( tblGA ) / Size( tblG ),
                  ComputedPowerMaps := [] );

    # The class fusion of `tblMG' into `tblMGA' is given by `orbs'.
    MGfusMGA:= InverseMap( orbs );

    # Determine the outer classes of `tblGA'.
    factouter:= Difference( [ 1 .. NrConjugacyClasses( tblGA ) ], GfusGA );

    # Compute the fusion of `tblMGA' onto `tblGA'.
    MGAfusGA:= CompositionMaps( GfusGA, CompositionMaps( MGfusG, orbs ) );
    Append( MGAfusGA, factouter );

    # Distinguish inner and outer classes of `tblMGA'.
    inner:= [ 1 .. Maximum( MGfusMGA ) ];
    outer:= [ Maximum( MGfusMGA ) + 1 .. Length( MGAfusGA ) ];
    nccl:= Length( inner ) + Length( outer );

    # Compute the class lengths of `tblMGA'.
    tblMGA.SizesConjugacyClasses:= Concatenation( Zero( inner ),
        ( Size( tblMG ) / Size( tblG ) )
          * SizesConjugacyClasses( tblGA ){ factouter } );
    classes:= SizesConjugacyClasses( tblMG );
    for i in inner do
      tblMGA.SizesConjugacyClasses[i]:= Sum( classes{ orbs[i] } );
    od;

    # Compute the centralizer orders of `tblMGA'.
    tblMGA.SizesCentralizers:= List( tblMGA.SizesConjugacyClasses,
                                     x -> tblMGA.Size / x );

    # Compute the irreducible characters of `tblMGA'.
    tblMGA.Irr:= IrreducibleCharactersOfTypeMGA( tblMG, tblGA,
                     ClassPositionsOfKernel( MGfusG ), MGAfusGA, orbs,
                     Size( tblGA ) / Size( tblG ) );

    # Compute approximations for power maps of `tblMGA'.
    # (All $p$-th power maps for $p$ coprime to $|A|$ are uniquely
    # determined this way, since inner and outer part are kept separately.)
#T We know more:
#T If |A| is a prime and does not divide |M| then the action is
#T semiregular; we have a unique fixed point for any element in N
#T that has a p-th root outside N.
    primes:= PrimeDivisors( tblMGA.Size );
    invMGAfusGA:= InverseMap( MGAfusGA );

    for p in primes do

      # inner part: Transfer the map from `tblMG' to `tblMGA'.
      tblMGA.ComputedPowerMaps[p]:= CompositionMaps( MGfusMGA,
           CompositionMaps( PowerMap( tblMG, p ), orbs ) );

      # outer part: Use the map of `tblGA' for an approximation.
      GAmapp:= PowerMap( tblGA, p );
      for i in outer do
        tblMGA.ComputedPowerMaps[p][i]:=
            invMGAfusGA[ GAmapp[ MGAfusGA[i] ] ];
      od;

    od;

    # Enter the element orders.
    # (If $|A|$ and $|M|$ are coprime then the orders of outer elements
    # are uniquely determined; otherwise there may be ambiguities.)
    orders:= [];
    suborders:= OrdersClassRepresentatives( tblMG );
    for i in [ 1 .. Length( MGfusMGA ) ] do
      orders[ MGfusMGA[i] ]:= suborders[i];
    od;
    outerorders:= OrdersClassRepresentatives( tblGA ){ factouter };
    gcd:= Gcd( Size( tblMG ), Size( tblGA ) ) / Size( tblG );
    if gcd <> 1 then
      gcd:= DivisorsInt( gcd );
      outerorders:= List( outerorders, x -> gcd * x );
    fi;
    tblMGA.OrdersClassRepresentatives:= Concatenation( orders, outerorders );

    # Compute the automorphisms of the matrix of characters.
    if gcd = 1 then
      matautos:= [ tblMGA.SizesCentralizers,
                   tblMGA.OrdersClassRepresentatives ];
    else
      matautos:= [ tblMGA.SizesCentralizers ];
    fi;
    matautos:= MatrixAutomorphisms( tblMGA.Irr, matautos,
                   GroupByGenerators( [], () ) );

    # Convert the record to a character table object.
    # (Keep a record for the case that we need copies later.)
    tblrecord:= ShallowCopy( tblMGA );
    Unbind( tblrecord.ComputedPowerMaps );
    ConvertToCharacterTableNC( tblMGA );

    # Test and improve the (perhaps ambiguous) power maps
    # (and update the automorphisms if necessary) using characters.
    # Whenever several $p$-th power maps are possible then we branch,
    # so we end up with a list of possible character tables.
    info:= [ [ tblMGA, matautos ] ];
    for p in primes do

      newinfo:= [];
      for pair in info do
        tblMGA:= pair[1];
        matautos:= pair[2];
        pow:= ComputedPowerMaps( tblMGA )[p];
        pow:= PossiblePowerMaps( tblMGA, p, rec( powermap:= pow ) );
        if not IsEmpty( pow ) then

          # Consider representatives up to matrix automorphisms.
          for pow in RepresentativesPowerMaps( pow, matautos ) do
            newmatautos:= SubgroupProperty( matautos,
                       perm -> ForAll( [ 1 .. nccl ],
                                   i -> pow[ i^perm ] = pow[i]^perm ),
                       TrivialSubgroup( matautos ),
                       TrivialSubgroup( matautos ) );
            newtblMGA:= ConvertToLibraryCharacterTableNC(
                            ShallowCopy( tblrecord ) );
            SetComputedPowerMaps( newtblMGA,
                StructuralCopy( ComputedPowerMaps( tblMGA ) ) );
            ComputedPowerMaps( newtblMGA )[p]:= pow;
            Add( newinfo, [ newtblMGA, newmatautos ] );
          od;

        fi;
      od;

      # Hand over the list for the next step.
      info:= newinfo;

    od;

    # Here we have the final list of tables.
    for pair in info do

      tblMGA:= pair[1];
      SetAutomorphismsOfTable( tblMGA, pair[2] );
      StoreFusion( tblMGA, MGAfusGA, tblGA );
      oldfus:= ShallowCopy( ComputedClassFusions( tblMG ) );
      StoreFusion( tblMG, MGfusMGA, tblMGA );
      SetConstructionInfoCharacterTable( tblMGA,
          ConstructMGAInfo( tblMGA, tblMG, tblGA ) );
      if Length( oldfus ) < Length( ComputedClassFusions( tblMG ) ) then
        Unbind( ComputedClassFusions( tblMG )[
                    Length( ComputedClassFusions( tblMG ) ) ] );
      fi;
      SetInfoText( tblMGA,
          "constructed using `PossibleCharacterTablesOfTypeMGA'" );

      # Store the unique element orders if necessary.
      if gcd <> 1 then
        ResetFilterObj( tblMGA, HasOrdersClassRepresentatives );
        SetOrdersClassRepresentatives( tblMGA,
            ElementOrdersPowerMap( ComputedPowerMaps( tblMGA ) ) );
      fi;

    od;

    # Return the result list.
    return List( info, pair -> rec( table    := pair[1],
                                    MGfusMGA := MGfusMGA ) );
end );


#############################################################################
##
#F  BrauerTableOfTypeMGA( <modtblMG>, <modtblGA>, <ordtblMGA> )
##
InstallGlobalFunction( BrauerTableOfTypeMGA,
    function( modtblMG, modtblGA, ordtblMGA )
    local p, modtblMGA, MGfusMGA, MGAfusGA, orbs, i, kernel;

    # Fetch the underlying characteristic, and check the arguments.
    p:= UnderlyingCharacteristic( modtblMG );
    if UnderlyingCharacteristic( modtblGA ) <> p then
      Info( InfoCharacterTable, 1,
            "BrauerTableOfTypeMGA: UnderlyingCharacteristic values differ\n",
            "#I  for <modtblMG>, <modtblGA>" );
      return fail;
    elif not IsOrdinaryTable( ordtblMGA ) then
      Info( InfoCharacterTable, 1,
            "BrauerTableOfTypeMGA: <ordtblMGA> must be the ordinary table\n",
            "#I  of M.G.A" );
      return fail;
    fi;

    # We cannot assume that the ordinary table of `tblMGA' has the same
    # ordering of classes as is guaranteed for the table to be constructed.
    # (Consider the case of $M.G = 3.U.3$ and $G.A = U.6$, where the
    # outer classes of $U.2$ precede the outer classes of $U.3$.)
    modtblMGA:= CharacterTableRegular( ordtblMGA, p );

    # Compute the restriction of the action to the `p'-regular classes.
    MGfusMGA:= GetFusionMap( modtblMG, modtblMGA );
    if MGfusMGA = fail then
      Info( InfoCharacterTable, 1,
            "BrauerTableOfTypeMGA: the class fusion\n",
            "#I  OrdinaryCharacterTable( <modtblMG> ) -> <ordtblMGA> ",
            "must be stored" );
      return fail;
    fi;

    # Compute the irreducibles.
    MGAfusGA:= GetFusionMap( modtblMGA, modtblGA );
    orbs:= InverseMap( MGfusMGA );
    for i in [ 1 .. Length( orbs ) ] do
      if IsBound( orbs[i] ) and IsInt( orbs[i] ) then
        orbs[i]:= [ orbs[i] ];
      fi;
    od;
    kernel:= Filtered( [ 1 .. NrConjugacyClasses( modtblMG ) ],
                       i -> MGAfusGA[ MGfusMGA[i] ] = 1 );
    SetIrr( modtblMGA, List( IrreducibleCharactersOfTypeMGA( modtblMG, 
                                 modtblGA, kernel, MGAfusGA, orbs,
                                 Size( ordtblMGA ) / Size( modtblMG ) ),
                             x -> Character( modtblMGA, x ) ) );
    SetInfoText( modtblMGA, "constructed using `BrauerTableOfTypeMGA'" );

    # Return the result.
    return rec( table:= modtblMGA, MGfusMGA:= MGfusMGA );
end );


#############################################################################
##
#F  PossibleActionsForTypeMGA( <tblMG>, <tblG>, <tblGA> )
##
InstallGlobalFunction( PossibleActionsForTypeMGA,
    function( tblMG, tblG, tblGA )
    local tfustA,
          Mtfust,
          ker,
          index,
          inner,
          i,
          elms,
          cenMG,
          cenG,
          inv,
          factorbits,
          img,
          newelms,
          chars;

    # Check that the function is applicable.
    tfustA:= GetFusionMap( tblG, tblGA );
    if tfustA = fail then
      Error( "class fusion <tblG> -> <tblGA> must be stored on <tblG>" );
    fi;
    Mtfust:= GetFusionMap( tblMG, tblG );
    if Mtfust = fail then
      Error( "class fusion <tblMG> -> <tblG> must be stored on <tblMG>" );
    fi;
    index:= Size( tblGA ) / Size( tblG );
    if not IsPrimeInt( index ) then
      inner:= Set( tfustA );
      for i in PrimeDivisors( index ) do
        if ForAll( PowerMap( tblGA, index / i ), j -> j in inner ) then
          Error( "factor of <tblGA> by <tblG> must be cyclic" );
        fi;
      od;
    fi;

    # The automorphism must have order equal to the order of $A$.
    # We need to consider only one generator for each cyclic group of
    # the right order.
    elms:= Filtered( Elements( AutomorphismsOfTable( tblMG ) ),
#T better avoid computing all elements
                     x -> Order( x ) = index );
    elms:= Set( List( elms, SmallestGeneratorPerm ) );
    Info( InfoCharacterTable, 1,
          Length( elms ), " automorphism(s) of order ", index );

    # The automorphism respects the fusion of classes of $G$ into $G.A$.
    inv:= InverseMap( Mtfust );
    for i in [ 1 .. Length( inv ) ] do
      if IsInt( inv[i] ) then
        inv[i]:= [ inv[i] ];
      fi;
    od;
    factorbits:= Filtered( InverseMap( tfustA ), IsList );
    for i in [ 1 .. Length( inv ) ] do
      img:= First( factorbits, orb -> i in orb );
      if img = fail then
        img:= inv[i];
        newelms:= Filtered( elms, x -> OnSets( img, x ) = img );
      else
        img:= Union( inv{ Difference( img, [ i ] ) } );
        newelms:= Filtered( elms, x -> IsSubset( img, OnSets( inv[i], x ) ) );
      fi;
      if newelms <> elms then
        elms:= newelms;
        Info( InfoCharacterTable, 1,
              Length( elms ), " automorphism(s) mapping ",i," compatibly" );
      fi;
    od;

    # The automorphism must act semiregularly on those characters of $M.G$
    # that are not characters of $G$.
    # (Think of the case that the centres of $G$ and $M.G$ have orders
    # $2$ and $6$, respectively, and $A$ is of order $2$.)
    ker:= ClassPositionsOfKernel( Mtfust );
    chars:= Filtered( Irr( tblMG ),
                chi -> not IsSubset( ClassPositionsOfKernel( chi ), ker ) );
    elms:= Filtered( elms,
                     x -> Set( OrbitLengths( Group(x), chars, Permuted ) )
                          = [ index ] );
    Info( InfoCharacterTable, 1,
          Length( elms ), " automorphism(s) acting semiregularly" );

    # Form the orbits on the class positions.
    elms:= Set( List( elms, x -> Set( List( Orbits( Group(x),
                  [ 1 .. NrConjugacyClasses( tblMG ) ] ), Set ) ) ) );

    # Return the result.
    return elms;
end );


#############################################################################
##
#F  ConstructMGA( <tbl>, <subname>, <factname>, <plan>, <perm> )
##
InstallGlobalFunction( ConstructMGA,
    function( tbl, subname, factname, plan, perm )
    local factfus, subfus, proj, irreds, zero, irr, newirr, entry, sum, chi,
          i;

    factfus  := First( tbl.ComputedClassFusions,
                       fus -> fus.name = factname ).map;
    factname := CharacterTableFromLibrary( factname );
    subname  := CharacterTableFromLibrary( subname );
    subfus   := First( ComputedClassFusions( subname ),
                       fus -> fus.name = tbl.Identifier ).map;
    proj    := ProjectionMap( subfus );
    irreds  := List( Irr( factname ),
                     x -> ValuesOfClassFunction( x ){ factfus } );
    zero:= [ 1 .. Length( factfus ) ] * 0;
    irr:= Irr( subname );
    newirr:= [];
    for entry in plan do
      # Note that `proj' need not be dense.
      sum:= Sum( irr{ entry } );
      chi:= ShallowCopy( zero );
      for i in [ 1 .. Length( chi ) ] do
        if IsBound( proj[i] ) then
          chi[i]:= sum[ proj[i] ];
        fi;
      od;
      Add( newirr, chi );
    od;
    Append( irreds, newirr );
    tbl.Irr:= Permuted( irreds, perm );
end );


#############################################################################
##
##  2. Character Tables of Groups of Structure $G.S_3$
##


#############################################################################
##
#F  IrreducibleCharactersOfTypeGS3( <tbl>, <tblC>, <tblK>, <aut>,
#F     <tblfustblC>, <tblfustblK>, <tblCfustblKC>, <tblKfustblKC>, <outerC> )
##
BindGlobal( "IrreducibleCharactersOfTypeGS3",
    function( tbl, tblC, tblK, aut, tblfustblC, tblfustblK, tblCfustblKC,
              tblKfustblKC, outerC )
    local irreducibles,  # list of irreducible characters, result
          zero,          # zero vector on the classes of `tblC' \ `tbl'
          irrtbl,        # irreducible of `tbl'
          irrtblC,       # irreducible of `tblC'
          irrtblK,       # irreducible of `tblK'
          done,          # Boolean list, `true' for all processed characters
          outerKC,       # position of classes outside `tblK'
          k,             # order of the factor `tblK / tbl'
          c,             # order of the factor `tblC / tbl'
          p,             # characteristic of `tbl'
          r,             # ramification index
          i,             # loop over the irreducibles of `tblK'
          chi,           # currently processed character of `tblK'
          img,           # image of `chi' under `aut'
          rest,          # restriction of `chi' to `tbl' (via `tblfustblK')
          e,             # current ramification
          const,         # irreducible constituents of `rest'
          ext,           # extensions of an extendible constituent to `tblC'
          chitilde,      # one extension
          irr,           # one irreducible character
          j,             # loop over the classes of `tblK'
          sum;           # an induced character

    # Initializations.
    irreducibles:= [];
    zero:= 0 * outerC;
    irrtbl:= Irr( tbl );
    irrtblC:= Irr( tblC );
    irrtblK:= Irr( tblK );
    done:= BlistList( [ 1 .. Length( irrtblK ) ], [] );
    outerKC:= tblCfustblKC{ outerC };
    k:= Size( tblK ) / Size( tbl );
    c:= Size( tblC ) / Size( tbl );
    p:= UnderlyingCharacteristic( tbl );

    r:= RootInt( k );
    if r^2 <> k then
      r:= 1;
    fi;

    # Loop over the irreducibles of `tblK'.
    for i in [ 1 .. Length( irrtblK ) ] do
      if not done[i] then

        done[i]:= true;
        chi:= irrtblK[i];
        img:= Permuted( chi, aut );

        if img = chi then

          # `chi' extends.
          rest:= chi{ tblfustblK };
          e:= 1;
          if rest in irrtbl then
            # `rest' is invariant in `tblKC', so we take the values
            # of its extensions to `tblC' on the outer classes.
            const:= [ rest ];
          elif r <> 1 and rest / r in irrtbl then
            # `rest' is a multiple of an irreducible character of `tbl'.
            const:= [ rest / r ];
            e:= r;
          else
            # `rest' is a sum of `k' irreducibles of `tbl';
            # exactly one of them is fixed under the action of `tblC',
            # so we take the values of the extensions of this constituent
            # on the outer classes.
            const:= Filtered( irrtbl,
                        x -> x[1] = rest[1] / k and
                          Induced( tbl, tblK, [ x ], tblfustblK )[1] = chi );
            Assert( 1, Length( const ) = k,
                    "Strange number of constituents.\n" );
          fi;
          ext:= Filtered( irrtblC, x ->     x[1] = const[1][1]
                                        and x{ tblfustblC } in const );
          Assert( 1, ( p = c and Length( ext ) = 1 ) or
                     ( p <> c and Length( ext ) = c ),
                  "Extendible constituent is not unique.\n" );

          # We can handle only a few cases where $e \neq 1$:
          if   e <> 1 and e = c - 1 then
            # If $e = |C|-1$ then sum up all except one extension.
            ext:= List( ext, x -> Sum( ext ) - x );
          elif e <> 1 and e = c + 1 then
            # If $e = |C|+1$ then sum up all plus one extension.
            ext:= List( ext, x -> Sum( ext ) + x );
          elif e <> 1 then
            Error( "cannot handle a case where <e> > 1" );
          fi;
          for chitilde in ext do
            irr:= [];
            for j in [ 1 .. Length( tblKfustblKC ) ] do
              irr[ tblKfustblKC[j] ]:= chi[j];
            od;
            irr{ outerKC }:= chitilde{ outerC };
            Add( irreducibles, irr );
          od;

        else

          # `chi' induces irreducibly.
          irr:= [];
          done[ Position( irrtblK, img ) ]:= true;
          sum:= chi + img;
          for j in [ 3 .. c ] do
            img:= Permuted( img, aut );
            done[ Position( irrtblK, img ) ]:= true;
            sum:= sum + img;
          od;
          for j in [ 1 .. Length( tblKfustblKC ) ] do
            irr[ tblKfustblKC[j] ]:= sum[j];
          od;
          irr{ outerKC }:= zero;
          Add( irreducibles, irr );

        fi;

      fi;
    od;

    # Return the result.
    Assert( 1, Length( irreducibles ) = Length( irreducibles[1] ),
            Concatenation( "Not all irreducibles found (have ",
                String( Length( irreducibles ) ), " of ",
                String( Length( irreducibles[1] ) ), ")\n" ) );
    return irreducibles;
end );


#############################################################################
##
#F  CharacterTableOfTypeGS3( <tbl>, <tblC>, <tblK>, <aut>, <identifier> )
#F  CharacterTableOfTypeGS3( <modtbl>, <modtblC>, <modtblK>, <ordtblKC>,
#F                           <identifier> )
##
InstallGlobalFunction( CharacterTableOfTypeGS3,
    function( tbl, tblC, tblK, aut, identifier )
    local p,             # prime integer
          tblfustblC,    # class fusion from `tbl' into `tblC'
          tblfustblK,    # class fusion from `tbl' into `tblK'
          tblKfustblKC,  # class fusion from `tblK' into the desired table
          tblCfustblKC,  # class fusion from `tblC' into the desired table
          outer,         # positions of the classes of `tblC' \ `tbl'
          i,
          tblKC,
          classes,
          subclasses,
          k,
          orders,
          suborders,
          powermap,
          pow,
          oldfusC,
          oldfusK;

    # Fetch the underlying characteristic, and check the arguments.
    p:= UnderlyingCharacteristic( tbl );
    if    UnderlyingCharacteristic( tblC ) <> p
       or UnderlyingCharacteristic( tblK ) <> p then
      Error( "UnderlyingCharacteristic values differ for <tbl>, <tblC>, ",
             "<tblK>" );
    elif 0 < p and not IsOrdinaryTable( aut ) then
      Error( "enter the ordinary table of G.KC as the fourth argument" );
    elif 0 = p and not IsPerm( aut ) then
      Error( "enter a permutation as the fourth argument" );
    fi;

    # Fetch the stored fusions from `tbl'.
    tblfustblC:= GetFusionMap( tbl, tblC );
    tblfustblK:= GetFusionMap( tbl, tblK );
    if tblfustblC = fail or tblfustblK = fail then
      Error( "fusions <tbl> -> <tblC>, <tbl> -> <tblK> must be stored" );
    fi;
    outer:= Difference( [ 1 .. NrConjugacyClasses( tblC ) ], tblfustblC );

    if 0 < p then

      # We assume that the ordinary table of `tblKC' (given as the argument
      # `aut') has the same ordering of classes as is guaranteed for the
      # table to be constructed.
      tblKC:= CharacterTableRegular( aut, p );

      # Compute the restriction of the action to the `p'-regular classes.
      tblKfustblKC:= GetFusionMap( tblK, tblKC );
      if tblKfustblKC = fail then
        Error( "fusion <tblK> -> <tblKC> must be stored" );
      fi;
      aut:= Product( List( Filtered( InverseMap( tblKfustblKC ), IsList ),
                           x -> MappingPermListList( x,
                                    Concatenation( x{ [ 2 .. Length(x) ] },
                                                   [ x[1] ] ) ) ),
                     () );

      # Fetch fusions for the result.
      tblKfustblKC:= GetFusionMap( tblK, tblKC );
      tblCfustblKC:= GetFusionMap( tblC, tblKC );

    else

      # Compute the needed fusions into `tblKC'.
      tblKfustblKC:= InverseMap( Set( Orbits( Group( aut ),
                         [ 1 .. NrConjugacyClasses( tblK ) ] ) ) );
      tblCfustblKC:= CompositionMaps( tblKfustblKC,
          CompositionMaps( tblfustblK, InverseMap( tblfustblC ) ) );
      tblCfustblKC{ outer }:= [ 1 .. Length( outer ) ]
                              + Maximum( tblKfustblKC );

      # Initialize the record for the character table `tblKC'.
      tblKC:= rec( UnderlyingCharacteristic := 0,
                   Identifier := identifier,
                   Size := Size( tblK ) * Size( tblC ) / Size( tbl ) );

      # Compute class lengths and centralizer orders.
      classes:= ListWithIdenticalEntries( Maximum( tblCfustblKC ), 0 );
      subclasses:= SizesConjugacyClasses( tblK );
      for i in [ 1 .. Length( subclasses) ] do
        classes[ tblKfustblKC[i] ]:= classes[ tblKfustblKC[i] ]
                                     + subclasses[i];
      od;
      subclasses:= SizesConjugacyClasses( tblC );
      k:= Size( tblK ) / Size( tbl );
      for i in outer do
        classes[ tblCfustblKC[i] ]:= classes[ tblCfustblKC[i] ]
                                     + k * subclasses[i];
      od;
      tblKC.SizesConjugacyClasses:= classes;
      tblKC.SizesCentralizers:= List( classes, x -> tblKC.Size / x );

      # Compute element orders.
      orders:= [];
      suborders:= OrdersClassRepresentatives( tblK );
      for i in [ 1 .. Length( tblKfustblKC ) ] do
        orders[ tblKfustblKC[i] ]:= suborders[i];
      od;
      suborders:= OrdersClassRepresentatives( tblC );
      for i in outer do
        orders[ tblCfustblKC[i] ]:= suborders[i];
      od;
      tblKC.OrdersClassRepresentatives:= orders;

      # Convert the record to a table object.
      ConvertToLibraryCharacterTableNC( tblKC );

      # Put the power maps together.
      powermap:= ComputedPowerMaps( tblKC );
      for p in PrimeDivisors( Size( tblKC ) ) do
        pow:= InitPowerMap( tblKC, p );
        TransferDiagram( PowerMap( tblC, p ), tblCfustblKC, pow );
        TransferDiagram( PowerMap( tblK, p ), tblKfustblKC, pow );
        powermap[p]:= pow;
        Assert( 1, ForAll( pow, IsInt ),
                Concatenation( Ordinal( p ),
                               " power map not uniquely determined" ) );
      od;

    fi;

    # Compute the irreducibles.
    SetIrr( tblKC,
            List( IrreducibleCharactersOfTypeGS3( tbl, tblC, tblK, aut,
                      tblfustblC, tblfustblK, tblCfustblKC, tblKfustblKC,
                      outer ),
                  chi -> Character( tblKC, chi ) ) );

    if IsOrdinaryTable( tblKC ) then
      oldfusC:= ShallowCopy( ComputedClassFusions( tblC ) );
      StoreFusion( tblC, tblCfustblKC, tblKC );
      oldfusK:= ShallowCopy( ComputedClassFusions( tblK ) );
      StoreFusion( tblK, tblKfustblKC, tblKC );
      SetConstructionInfoCharacterTable( tblKC,
          ConstructGS3Info( tblC, tblK, tblKC ).list );
      if Length( oldfusC ) < Length( ComputedClassFusions( tblC ) ) then
        Unbind( ComputedClassFusions( tblC )[
                    Length( ComputedClassFusions( tblC ) ) ] );
      fi;
      if Length( oldfusK ) < Length( ComputedClassFusions( tblK ) ) then
        Unbind( ComputedClassFusions( tblK )[
                    Length( ComputedClassFusions( tblK ) ) ] );
      fi;
    fi;
    SetInfoText( tblKC, "constructed using `CharacterTableOfTypeGS3'" );

    # Return the result.
    return rec( table        := tblKC,
                tblCfustblKC := tblCfustblKC,
                tblKfustblKC := tblKfustblKC );
end );


#############################################################################
##
#F  PossibleActionsForTypeGS3( <tbl>, <tblC>, <tbl3> )
##
#T Do we need a function that computes also compatible fusions if necessary?
#T (The condition is that the orbits on the classes of <tbl> describe an
#T action of S_3.)
##
InstallGlobalFunction( PossibleActionsForTypeGS3, function( tbl, tblC, tblK )
    local tfustC, tfustK, c, elms, inner, linK, i, vals, c1, c2, newelms,
          inv, orbs, orb;

    # Check that the function is applicable.
    tfustC:= GetFusionMap( tbl, tblC );
    if tfustC = fail then
      Error( "class fusion <tbl> -> <tblC> must be stored on <tbl>" );
    fi;
    tfustK:= GetFusionMap( tbl, tblK );
    if tfustK = fail then
      Error( "class fusion <tbl> -> <tblK> must be stored on <tbl>" );
    fi;

    # The automorphism must have order `c'.
    c:= Size( tblC ) / Size( tbl );
    elms:= Filtered( Elements( AutomorphismsOfTable( tblK ) ),
#T better avoid computing all elements
                     x -> Order( x ) = c );
    Info( InfoCharacterTable, 1,
          Length( elms ), " automorphism(s) of order ", c );
    if Length( elms ) <= 1 then
      return elms;
    fi;

    # The automorphism must permute the outer cosets of `tblK'.
    inner:= Set( tfustK );
    linK:= Filtered( Irr( tblK ),
               chi -> IsSubset( ClassPositionsOfKernel( chi ), inner ) );
    linK:= Difference( linK, [ TrivialCharacter( tblK ) ] );
    elms:= Filtered( elms, x -> Permuted( linK[1], x ) = linK[2] );
    Info( InfoCharacterTable, 1,
          Length( elms ), " automorphism(s) permuting the cosets" );
    if Length( elms ) <= 1 then
      return elms;
    fi;

    # The automorphism respects the fusion of classes of `tbl' into `tblC'.
    for i in InverseMap( tfustC ) do
      if IsList( i ) then
        vals:= SortedList( tfustK{ i } );
        c1:= vals[1];
        c2:= vals[2];
        if c1 <> c2 then
          RemoveSet( vals, c1 );
          newelms:= Filtered( elms, x -> c1^x in vals );
          if newelms <> elms then
            elms:= newelms;
            Info( InfoCharacterTable, 1,
                  Length( elms ), " automorphism(s) fusing ", c1, " and ",
                  c2 );
            if Length( elms ) <= 1 then
              return elms;
            fi;
          fi;
        fi;
      fi;
    od;

    # Two inner classes that are not fused in `tblC'
    # cannot be conjugate in `tKC'.
    # (Note that the centralizer order in `tblC' is `c' times larger than
    # in `tbl', and this extra factor does not occur in the centralizer
    # order in `tblK'.)
    inv:= InverseMap( tfustK );
    orbs:= Union( List( elms, i -> Filtered( Orbits( Group( i ), inner ),
                                              orb -> Length( orb ) = c ) ) );
    orbs:= Filtered( orbs,
               x -> ( ForAll( inv{ x }, IsInt )
                      and Number( Set( tfustC{ inv{ x } } ) ) > 1 )
                 or ( ForAll( inv{ x }, IsList )
                      and ForAny( inv[ x[1] ],
                            y -> SizesCentralizers( tbl )[y]
                              < SizesCentralizers( tblC )[ tfustC[y] ] ) ) );
    for orb in orbs do
      c1:= orb[1];
      c2:= orb[2];
      newelms:= Filtered( elms, x -> c1^x <> c2 );
      if newelms <> elms then
        elms:= newelms;
        Info( InfoCharacterTable, 1,
              Length( elms ),
              " automorphism(s) not fusing ", c1, " and ", c2 );
        if Length( elms ) <= 1 then
          return elms;
        fi;
      fi;
    od;

    # Return the result.
    return elms;
end );


#############################################################################
##
##  3. Character Tables of Groups of Structure $G.2^2$
##


#############################################################################
##
#F  PossibleActionsForTypeGV4( <tblG>, <tblsG2> )
##
InstallGlobalFunction( PossibleActionsForTypeGV4,
    function( tblG, tblsG2 )
    local tfust2, perms, actonG, fixedinG, i, j, k, inv, stabs, elms,
          domains, triples, elm, comp, nccl, filt2, filt3;

    # Check that the function is applicable.
    tfust2:= List( tblsG2, t2 -> GetFusionMap( tblG, t2 ) );
    if fail in tfust2 then
      Error( "class fusions <tblG> -> <tblsG2> must be stored on <tblG>" );
    elif ForAny( tblsG2, t2 -> Size( t2 ) <> 2 * Size( tblG ) ) then
      Error( "<tblG> must have index 2 in all tables in <tblsG2>" );
    fi;

    # For computing compatible actions on the tables in `tblsG2',
    # we rearrange these tables such that the fusions are sorted.
    # In particular, the classes of <tblG> shall come first.
    perms:= [];
    actonG:= [];
    fixedinG:= [];
    for i in [ 1 .. 3 ] do
      perms[i]:= [];
      j:= 1;
      for k in [ 1 .. Length( tfust2[i] ) ] do
        if not IsBound( perms[i][ tfust2[i][k] ] ) then
          perms[i][ tfust2[i][k] ]:= j;
          j:= j+1;
        fi;
      od;
      for k in [ 1 .. NrConjugacyClasses( tblsG2[i] ) ] do
        if not IsBound( perms[i][k] ) then
          perms[i][k]:= j;
          j:= j+1;
        fi;
      od;
      perms[i]:= PermList( perms[i] );
      tfust2[i]:= OnTuples( tfust2[i], perms[i] );
      inv:= InverseMap( tfust2[i] );
      actonG[i]:= Product( List( Filtered( inv, IsList ),
                                 x -> (x[1], x[2]) ),
                           () );
      fixedinG[i]:= Filtered( inv, IsInt );
    od;

    # Check that the three fusions are compatible in the sense that
    # the product of the three permutations induced on the classes of
    # <tblG> is the identity.
    if not IsOne( Product( actonG ) ) then
      Info( InfoCharacterTable, 1,
            "the three subgroup fusions are not compatible" );
      return [];
    fi;

    # The automorphisms must have order at most 2.
    fixedinG:= Intersection( fixedinG );
    stabs:= [];
    for i in [ 1 .. 3 ] do
      stabs[i]:= Stabilizer( AutomorphismsOfTable( tblsG2[i] ),
                     OnTuples( tfust2[i]{ fixedinG }, perms[i]^-1 ), OnTuples );
    od;
    elms:= List( stabs, H -> Filtered( H, x -> Order( x ) <= 2 ) );
    Info( InfoCharacterTable, 1,
          Product( List( elms, Length ) ),
          " triple(s) of automorphisms of order <= 2" );

    # Two classes of $G$ that are not conjugate in any $G.2_i$
    # are not conjugate in $G.2^2$.
    # (By the compatibility, we need to test nonconjugacy only in $G.2_1$.)
    elms[1]:= Filtered( elms[1],
                        x -> ForAll( tfust2[1]{ fixedinG },
                                     p -> p^( x^perms[1] ) = p ) );
    Info( InfoCharacterTable, 1,
          Product( List( elms, Length ) ),
          " triple(s) of automorphisms respecting inner classes" );

    # The automorphisms must act compatibly on `tblG', and
    # they must result in the same number of classes for $G.2^2$.
    # (Note that the class number corresponds to the number of cycles.)
    domains:= List( tblsG2, t -> [ 1 .. NrConjugacyClasses( t ) ] );
    triples:= [];
    for elm in elms[1] do
      comp:= CompositionMaps( InverseMap(
                 OrbitsPerms( [ elm^perms[1] ], domains[1] ) ), tfust2[1] );
      nccl:= 2 * NrConjugacyClasses( tblsG2[1] )
             - 3 * NrMovedPointsPerm( elm ) / 2;
      filt2:= Filtered( elms[2], x -> comp = CompositionMaps(
                     InverseMap( OrbitsPerms( [ x^perms[2] ], domains[2] ) ),
                     tfust2[2] )
                  and nccl = 2 * NrConjugacyClasses( tblsG2[2] )
                             - 3 * NrMovedPointsPerm( x ) / 2 );
      filt3:= Filtered( elms[3], x -> comp = CompositionMaps(
                     InverseMap( OrbitsPerms( [ x^perms[3] ], domains[3] ) ),
                     tfust2[3] )
                  and nccl = 2 * NrConjugacyClasses( tblsG2[3] )
                             - 3 * NrMovedPointsPerm( x ) / 2 );
      Append( triples, Cartesian( [ elm ], filt2, filt3 ) );
    od;
    Info( InfoCharacterTable, 1,
          Length( triples ),
          " triple(s) of automorphisms acting compatibly" );

    # Return the result.
    return triples;
end );


#############################################################################
##
#F  PossibleCharacterTablesOfTypeGV4( <tblG>, <tblsG2>, <acts>, <identifier>
#F                                    [, <tblGfustblsG2>] )
#F  PossibleCharacterTablesOfTypeGV4( <modtblG>, <modtblsG2>, <ordtblGV4>
#F                                    [, <ordtblsG2fusordtblG4>] )
##
InstallGlobalFunction( PossibleCharacterTablesOfTypeGV4,
    function( arg )
    local tblG, tblsG2, ordtblGV4, GfusG2, acts, identifier, char, tblGV4,
          G2fusGV4, classes, cosets, G2fusGV4outer, i, k, tblfusordtbl, rest,
          defectzero, intrest, G2fusGV4inner, ncclinner, tblrec,
          subclasses, orders, suborders, map, powermap, p, pow, irr, ind,
          indirr, triv, done, bad, num2, ext, numinv, poss1, poss2, chi,
          intmat1, intmat2, todo, minus, nexttodo, poss, j, modrest;

    # Get and check the arguments.
    if   Length( arg ) = 3 and
       IsBrauerTable( arg[1] ) and IsList( arg[2] )
       and IsOrdinaryTable( arg[3] ) then
      tblG       := arg[1];
      tblsG2     := arg[2];
      ordtblGV4  := arg[3];
      GfusG2     := List( tblsG2, t -> GetFusionMap( tblG, t ) );
    elif Length( arg ) = 4 and
       IsBrauerTable( arg[1] ) and IsList( arg[2] )
       and IsOrdinaryTable( arg[3] ) and IsList( arg[4] ) then
      tblG       := arg[1];
      tblsG2     := arg[2];
      ordtblGV4  := arg[3];
      GfusG2     := List( tblsG2, t -> GetFusionMap( tblG, t ) );
      G2fusGV4   := arg[4];
    elif Length( arg ) = 4 and
       IsOrdinaryTable( arg[1] ) and IsList( arg[2] ) and IsList( arg[3] )
       and IsString( arg[4] ) then
      tblG       := arg[1];
      tblsG2     := arg[2];
      acts       := arg[3];
      identifier := arg[4];
      GfusG2     := List( tblsG2, t -> GetFusionMap( tblG, t ) );
    elif Length( arg ) = 5 and
       IsCharacterTable( arg[1] ) and IsList( arg[2] ) and IsList( arg[3] )
       and IsString( arg[4] ) and IsList( arg[5] ) then
      tblG       := arg[1];
      tblsG2     := arg[2];
      acts       := arg[3];
      identifier := arg[4];
      GfusG2     := arg[5];
    else
      Error( "usage: PossibleCharacterTablesOfTypeGV4( <tlbG>, <tblsG2>, ",
             "<acts>, <identifier>[, <fusions>] ) or\n",
             "PossibleCharacterTablesOfTypeGV4( <modtblG>, <modtblsG2>, ",
             "<ordtblGV4>[, <fusions>] )" );
    fi;

    if fail in GfusG2 then
      Error( "the class fusions <tblG> -> <tblsG2> must be stored" );
    fi;

    # Fetch the underlying characteristic.
    char:= UnderlyingCharacteristic( tblG );

    if 0 < char then

      # We assume that the ordinary table of `tblGV4' (given as an argument)
      # has the same ordering of classes as is guaranteed for the
      # table to be constructed.
      tblGV4:= CharacterTableRegular( ordtblGV4, char );

      if not IsBound( G2fusGV4 ) then
        # Fetch the three fusions if they were not entered.
        G2fusGV4:= List( tblsG2, t -> GetFusionMap( t, tblGV4 ) );
        if fail in G2fusGV4 then
          Error( "fusions <tblsG2> -> <tblGV4> must be stored" );
        fi;
      else
        # Transfer the given fusions to the Brauer tables.
        G2fusGV4:= List( [ 1 .. 3 ],
            i -> CompositionMaps(
                     InverseMap( GetFusionMap( tblGV4, ordtblGV4 ) ),
                     CompositionMaps( G2fusGV4[i],
                         GetFusionMap( tblsG2[i],
                             OrdinaryCharacterTable( tblsG2[i] ) ) ) ) );
      fi;

      acts:= List( G2fusGV4,
                map -> Product( List( Filtered( InverseMap( map ), IsList ),
                                pair -> ( pair[1], pair[2] ) ), () ) );
      classes:= ShallowCopy( SizesConjugacyClasses( tblGV4 ) );
      cosets:= Intersection( G2fusGV4 );
      cosets:= List( G2fusGV4, map -> Difference( map, cosets ) );
      G2fusGV4outer:= List( G2fusGV4, ShallowCopy );
      for i in [ 1 .. 3 ] do
        for k in GfusG2[i] do
          Unbind( G2fusGV4outer[i][k] );
        od;
      od;

      # We will use that defect zero characters must occur.
      tblfusordtbl:= GetFusionMap( tblGV4, ordtblGV4 );
      rest:= List( Irr( ordtblGV4 ), x -> x{ tblfusordtbl } );
      defectzero:= Filtered( rest, x -> Size( tblGV4 ) / x[1] mod char <> 0 );
      intrest:= IntegralizedMat( rest );

    else

      if not ( Length( acts ) = 3 and ForAll( acts, IsPerm ) ) then
        Error( "<acts> must contain three permutations" );
      fi;

      # Construct the three fusions into $G.2^2$, via the three embeddings.
      # The classes of $G$ come first in each map; note that we must choose
      # the classes of $G$ compatibly in all three maps.
      G2fusGV4inner:= [];
      G2fusGV4inner[1]:= InverseMap( Set( Orbits( Group( acts[1] ),
          Set( GfusG2[1] ) ) ) );
      G2fusGV4inner[2]:= CompositionMaps( G2fusGV4inner[1],
          CompositionMaps( GfusG2[1], InverseMap( GfusG2[2] ) ) );
      G2fusGV4inner[3]:= CompositionMaps( G2fusGV4inner[1],
          CompositionMaps( GfusG2[1], InverseMap( GfusG2[3] ) ) );
      ncclinner:= Maximum( G2fusGV4inner[1] );

      G2fusGV4outer:= [];
      G2fusGV4outer[1]:= InverseMap( Set( Orbits( Group( acts[1] ),
          Difference( [ 1 .. NrConjugacyClasses( tblsG2[1] ) ],
              Set( GfusG2[1] ) ) ) ) ) + ncclinner;
      G2fusGV4outer[2]:= InverseMap( Set( Orbits( Group( acts[2] ),
          Difference( [ 1 .. NrConjugacyClasses( tblsG2[2] ) ],
              Set( GfusG2[2] ) ) ) ) ) + Maximum( G2fusGV4outer[1] );
      G2fusGV4outer[3]:= InverseMap( Set( Orbits( Group( acts[3] ),
          Difference( [ 1 .. NrConjugacyClasses( tblsG2[3] ) ],
              Set( GfusG2[3] ) ) ) ) ) + Maximum( G2fusGV4outer[2] );

      cosets:= List( G2fusGV4outer, Set );

      # Compute class lengths, centralizer orders, and element orders.
      G2fusGV4:= G2fusGV4inner + G2fusGV4outer;
      classes:= ListWithIdenticalEntries( Maximum( G2fusGV4[3] ), 0 );
      subclasses:= SizesConjugacyClasses( tblsG2[1] );
      orders:= [];
      suborders:= OrdersClassRepresentatives( tblsG2[1] );
      for i in [ 1 .. Length( G2fusGV4inner[1] ) ] do
        if IsBound( G2fusGV4inner[1][i] ) then
          classes[ G2fusGV4inner[1][i] ]:= classes[ G2fusGV4inner[1][i] ]
                                           + subclasses[i];
          orders[ G2fusGV4inner[1][i] ]:= suborders[i];
        fi;
      od;
      for k in [ 1 .. 3 ] do
        subclasses:= SizesConjugacyClasses( tblsG2[k] );
        suborders:= OrdersClassRepresentatives( tblsG2[k] );
        map:= G2fusGV4outer[k];
        for i in [ 1 .. Length( map ) ] do
          if IsBound( map[i] ) then
            classes[ map[i] ]:= classes[ map[i] ] + subclasses[i];
            orders[ map[i] ]:= suborders[i];
          fi;
        od;
      od;

      # Initialize the record for the character table `tblGV4'.
      tblrec:= rec( UnderlyingCharacteristic   := 0,
                    Identifier                 := identifier,
                    Size                       := 4 * Size( tblG ),
                    SizesConjugacyClasses      := Immutable( classes ),
                    OrdersClassRepresentatives := orders );
      tblrec.SizesCentralizers:= List( classes, x -> tblrec.Size / x );

      # Convert the record to a table object.
      tblGV4:= ConvertToCharacterTableNC( ShallowCopy( tblrec ) );

      # Put the power maps together.
      powermap:= ComputedPowerMaps( tblGV4 );
      for p in PrimeDivisors( Size( tblGV4 ) ) do
        pow:= InitPowerMap( tblGV4, p );
        for k in [ 1 .. 3 ] do
          TransferDiagram( PowerMap( tblsG2[k], p ), G2fusGV4[k], pow );
        od;
        powermap[p]:= pow;
        Assert( 1, ForAll( pow, IsInt ),
                Concatenation( Ordinal( p ),
                               " power map not uniquely determined" ) );
      od;
      tblrec.ComputedPowerMaps:= ComputedPowerMaps( tblGV4 );

    fi;

    # Compute the irreducibles, starting from the irreducibles of $G$.
    # First we compute the known extensions of the trivial character,
    # then add the characters which are induced from some table in `tblsG2',
    # then try to determine the extensions of the remaining characters.
    irr:= List( Irr( tblG ), ValuesOfClassFunction );
    ind:= List( [ 1 .. 3 ],
                i -> InducedClassFunctionsByFusionMap( tblG, tblsG2[i], irr,
                         GfusG2[i] ) );
    indirr:= List( [ 1 .. NrConjugacyClasses( tblG ) ],
                   k -> List( [ 1 .. 3 ],
                              i -> ind[i][k] in Irr( tblsG2[i] ) ) );
    irr:= [];
    triv:= Position( Irr( tblG ), TrivialCharacter( tblG ) );

    if char = 2 then
      irr[ triv ]:= [ 0 * classes + 1 ];
    else
      irr[ triv ]:= List( [ 1 .. 4 ], i -> 0 * classes + 1 );
      irr[ triv ][3]{ cosets[1] }:= 0 * cosets[1] - 1;
      irr[ triv ][4]{ cosets[1] }:= 0 * cosets[1] - 1;
      irr[ triv ][2]{ cosets[2] }:= 0 * cosets[2] - 1;
      irr[ triv ][4]{ cosets[2] }:= 0 * cosets[2] - 1;
      irr[ triv ][2]{ cosets[3] }:= 0 * cosets[3] - 1;
      irr[ triv ][3]{ cosets[3] }:= 0 * cosets[3] - 1;
    fi;

    done:= [ triv ];
    bad:= [];
    for i in [ 1 .. NrConjugacyClasses( tblG ) ] do
      if not i in done then
        num2:= Number( indirr[i], x -> x = false );
        if   num2 = 2 then
          # This cannot happen, so the actions must be wrong.
          Info( InfoCharacterTable, 1,
                "PossibleCharacterTablesOfTypeGV4: contradiction, ",
                "imposs. inertia subgroup" );
          return [];
        elif num2 = 0 then
          # The character has inertia subgroup $G$.
          irr[i]:= Induced( tblsG2[1], tblGV4, [ ind[1][i] ], G2fusGV4[1] );
          AddSet( done, i );
          AddSet( done, Position( ind[1], ind[1][i], i ) );
          AddSet( done, Position( ind[2], ind[2][i], i ) );
          AddSet( done, Position( ind[3], ind[3][i], i ) );
        elif num2 = 1 then
          # The character has inertia subgroup one of the $G.2_k$.
          k:= Position( indirr[i], false );
          ext:= Filtered( Irr( tblsG2[k] ),
                    x -> x{ GfusG2[k] } = Irr( tblG )[i] );
          irr[i]:= Induced( tblsG2[k], tblGV4, ext, G2fusGV4[k] );
          k:= ( ( k+1 ) mod 3 ) + 1;
          AddSet( done, i );
          AddSet( done, Position( ind[k], ind[k][i], i ) );
        else
          # The character has inertia subgroup $G.2^2$.
          ext:= List( [ 1 .. 3 ], j -> Filtered( Irr( tblsG2[j] ),
                    x -> x{ GfusG2[j] } = Irr( tblG )[i] ) );
          numinv:= Number( [ 1 .. 3 ],
                           x -> Permuted( ext[x][1], acts[x] ) = ext[x][1] );
          ext:= ext[1];
          if numinv in [ 1, 2 ] then
            Info( InfoCharacterTable, 1,
                  "PossibleCharacterTablesOfTypeGV4: contradiction, ",
                  "impossible inertia subgroup" );
            return [];
          elif Permuted( ext[1], acts[1] ) <> ext[1] then
            # The character induces from any of the $G.2_i$.
            irr[i]:= Induced( tblsG2[1], tblGV4, ext{[1]}, G2fusGV4[1] );
            AddSet( done, i );
          else
            # In characteristic $2$, we get a unique extension.
            # Otherwise the character extends $4$-fold,
            # and we have two possibilities for combining the different
            # extensions to the tables in `tblsG2'.
            ext:= List( ext, chi -> CompositionMaps( chi,
                                         InverseMap( G2fusGV4[1] ) ) );
            if char = 2 then
              irr[i]:= ext;
              AddSet( done, i );
            else
              poss1:= [ ShallowCopy( ext[1] ),
                        ShallowCopy( ext[1] ),
                        ShallowCopy( ext[2] ),
                        ShallowCopy( ext[2] ) ];
              ext:= Filtered( Irr( tblsG2[2] ),
                        x -> x{ GfusG2[2] } = Irr( tblG )[i] );
              for k in [ 1 .. Length( G2fusGV4outer[2] ) ] do
                if IsBound( G2fusGV4outer[2][k] ) then
                  poss1{ [ 1 .. 4 ] }[ G2fusGV4outer[2][k] ]:=
                      ext[1][k] * [ 1, -1, 1, -1 ];
                fi;
              od;
              ext:= Filtered( Irr( tblsG2[3] ),
                        x -> x{ GfusG2[3] } = Irr( tblG )[i] );
              for k in [ 1 .. Length( G2fusGV4outer[3] ) ] do
                if IsBound( G2fusGV4outer[3][k] ) then
                  poss1{ [ 1 .. 4 ] }[ G2fusGV4outer[3][k] ]:=
                      ext[1][k] * [ 1, -1, -1, 1 ];
                fi;
              od;
              poss2:= List( poss1, ShallowCopy );
              for chi in poss2 do
                chi{ cosets[3] }:= - chi{ cosets[3] };
              od;
              if 0 < char and Size( tblGV4 ) / ext[1][1] mod char <> 0 then
                if   ForAll( poss1, x -> x in defectzero ) then
                  irr[i]:= poss1;
                elif ForAll( poss2, x -> x in defectzero ) then
                  irr[i]:= poss2;
                else
                  Error( "inconsistency involving defect zero characters" );
                fi;
                AddSet( done, i );
              elif 0 < char then
                # Check whether the possibilities are in the Z-span of the
                # restricted ordinary characters.
                intmat1:= IntegralizedMat( [ poss1[1] ],
                                           intrest.inforec ).mat[1];
                intmat2:= IntegralizedMat( [ poss2[1] ],
                                           intrest.inforec ).mat[1];
                if   intmat1 = fail or
                     SolutionIntMat( intrest.mat, intmat1 ) = fail then
                  if intmat2 = fail or
                     SolutionIntMat( intrest.mat, intmat2 ) = fail then
                    # No combination of Brauer characters fits.
                    return [];
                  fi;
                  irr[i]:= poss2;
                  AddSet( done, i );
                elif intmat2 = fail or
                     SolutionIntMat( intrest.mat, intmat2 ) = fail then
                  irr[i]:= poss1;
                  AddSet( done, i );
                else
                  irr[i]:= [ poss1, poss2 ];
                fi;
              else
                irr[i]:= [ poss1, poss2 ];
              fi;
            fi;
          fi;
        fi;
      fi;
    od;

    # Deal with the extension case.
    todo:= Difference( [ 1 .. NrConjugacyClasses( tblG ) ], done );
    if char = 0 then

      # For each set of four extensions of one character,
      # check the scalar products with the characters $\chi^{2-}$,
      # for all known irreducible (nonlinear) characters $\chi$.
      pow:= ComputedPowerMaps( tblGV4 )[2];
      minus:= Set( List( Union( Filtered( irr,
                                    x -> x[1] <> 1 and
                                         NestingDepthA( x ) = 2 ) ),
                         chi -> MinusCharacter( chi, pow, 2 ) ) );
      nexttodo:= todo;
      repeat
        todo:= ShallowCopy( nexttodo );
        for i in todo do
          # Try to exclude one of the two possibilities via scalar products.
          poss1:= NonnegIntScalarProducts( tblGV4, minus, irr[i][1][1] );
          poss2:= NonnegIntScalarProducts( tblGV4, minus, irr[i][2][1] );
          if   not poss1 and not poss2 then
            # Something must be wrong, for example the given actions.
            Info( InfoCharacterTable, 1,
                  "PossibleCharacterTablesOfTypeGV4: contradiction, ",
                  "incompat. scalar products" );
            return [];
          elif poss1 and not poss2 then
            irr[i]:= irr[i][1];
            UniteSet( minus,
                Set( List( irr[i], chi -> MinusCharacter( chi, pow, 2 ) ) ) );
            RemoveSet( nexttodo, i );
          elif poss2 and not poss1 then
            irr[i]:= irr[i][2];
            UniteSet( minus,
                Set( List( irr[i], chi -> MinusCharacter( chi, pow, 2 ) ) ) );
            RemoveSet( nexttodo, i );
          fi;
        od;

      until todo = nexttodo;

      # Form all combinations of extensions that are still possible.
      poss:= [ irr ];
      for i in todo do
        poss:= Concatenation( [ List( poss, ShallowCopy ),
                                List( poss, ShallowCopy ) ] );
        for j in [ 1 .. Length( poss ) / 2 ] do
          poss[j][i]:= irr[i][1];
        od;
        for j in [ Length( poss ) / 2 + 1 .. Length( poss ) ] do
          poss[j][i]:= irr[i][2];
        od;
      od;

      for i in [ 1 .. Length( poss ) ] do
        # Check that the irreducibles are closed under multiplication
        # with linear characters,
        # and that the power maps are admissible.
        # Note that `PossiblePowerMaps' is not sufficient here,
        # we check whether all symmetrizations decompose.
        # An example where this excludes a candidate table is
        # `2.U4(3).(2^2)_{133}'.
        # Note that for large primes, constructing the symmetrizations
        # is not feasible.
        # An example where this happens is the table of `S4(9).2^2',
        # the group order is divisible by 41.
        tblGV4:= ConvertToCharacterTableNC( ShallowCopy( tblrec ) );
        SetIrr( tblGV4, List( Concatenation( Compacted( poss[i] ) ),
                              chi -> Character( tblGV4, chi ) ) );
        if ForAll( Irr( tblGV4 ), x -> ForAll( LinearCharacters( tblGV4 ),
                   y -> y * x in Irr( tblGV4 ) ) )
           and ForAll( PrimeDivisors( Size( tblGV4 ) ),
                 p -> p > 20 or
                      ForAll( Symmetrizations( tblGV4, Irr( tblGV4 ), p ),
                              x -> NonnegIntScalarProducts( tblGV4,
                                       Irr( tblGV4 ), x ) ) ) then
          SetInfoText( tblGV4,
              "constructed using `PossibleCharacterTablesOfTypeGV4'" );
          AutomorphismsOfTable( tblGV4 );
          poss[i]:= rec( table:= tblGV4, G2fusGV4:= G2fusGV4 );
        else
          Unbind( poss[i] );
        fi;
      od;
      poss:= Compacted( poss );

    else

      # `char'-modular case:
      # Form all combinations.
#T improve: consider blockwise, and perhaps for increasing degree
      poss:= [ irr ];
      for i in todo do
        poss:= Concatenation( [ List( poss, ShallowCopy ),
                                List( poss, ShallowCopy ) ] );
        for j in [ 1 .. Length( poss ) / 2 ] do
          poss[j][i]:= poss[j][i][1];
        od;
        for j in [ Length( poss ) / 2 + 1 .. Length( poss ) ] do
          poss[j][i]:= poss[j][i][2];
        od;
      od;

      # Check each combination.
      for i in [ 1 .. Length( poss ) ] do
        # Test the decomposability of ordinary irreducibles.
        poss[i]:= Concatenation( Compacted( poss[i] ) );
        if fail in Decomposition( poss[i], rest, "nonnegative" ) then
          Unbind( poss[i] );
        else
          # Test the decomposability of the restrictions
          # to the subgroups of index two.
          for j in [ 1 .. 3 ] do
            modrest:= List( poss[i], x -> x{ G2fusGV4[j] } );
            if fail in Decomposition( Irr( tblsG2[j] ), modrest,
                                      "nonnegative" ) then
              Unbind( poss[i] );
              break;
            fi;
          od;
        fi;
      od;
      poss:= Compacted( poss );

      for i in [ 1 .. Length( poss ) ] do
        tblGV4:= CharacterTableRegular( ordtblGV4, char );
        SetIrr( tblGV4, List( poss[i],
                              chi -> Character( tblGV4, chi ) ) );
        SetInfoText( tblGV4,
                     "constructed using `PossibleCharacterTablesOfTypeGV4'" );
        AutomorphismsOfTable( tblGV4 );
        poss[i]:= rec( table:= tblGV4, G2fusGV4:= G2fusGV4 );
      od;

    fi;

    return poss;
    end );


#############################################################################
##
#F  PossibleActionsForTypeGA( <tblG>, <tblGA> )
##
InstallGlobalFunction( PossibleActionsForTypeGA,
    function( tblG, tblGA )
    local tfustA, A, elms, i, newelms;

    # Check that the function is applicable.
    tfustA:= GetFusionMap( tblG, tblGA );
    if tfustA = fail then
      Error( "class fusion <tblG> -> <tblGA> must be stored on <tblG>" );
    fi;

    # The automorphism must have order dividing `A'.
    A:= Size( tblGA ) / Size( tblG );
    elms:= Filtered( Elements( AutomorphismsOfTable( tblG ) ),
#T better avoid computing all elements
                     x -> A mod Order( x ) = 0 );
    Info( InfoCharacterTable, 1,
          Length( elms ), " automorphism(s) of order dividing ", A );
    if Length( elms ) <= 1 then
      return elms;
    fi;

    # The automorphism respects the fusion of classes of `tblG' into `tblGA'.
    for i in InverseMap( tfustA ) do
      if IsList( i ) then
        newelms:= Filtered( elms, x -> OnSets( i, x ) = i and
                                       OnPoints( i[1], x ) <> i[1] );
      else
        newelms:= Filtered( elms, x -> OnPoints( i, x ) = i );
      fi;
      if newelms <> elms then
        elms:= newelms;
        Info( InfoCharacterTable, 1,
              Length( elms ), " automorphism(s) acting on ", i );
        if Length( elms ) <= 1 then
          return elms;
        fi;
      fi;
    od;

    # Return the result.
    return elms;
end );


#############################################################################
##
#F  ConstructMGAInfo( <tblmGa>, <tblmG>, <tblGa> )
##
InstallGlobalFunction( ConstructMGAInfo, function( tblmGa, tblmG, tblGa )
    local factfus, subfus, kernel, nccl, irr, plan, chi, rest, nonfaith,
          proj, zero, faithful, entry, sum, i, perm;

    factfus:= GetFusionMap( tblmGa, tblGa );
    subfus:= GetFusionMap( tblmG, tblmGa );
    if factfus = fail or subfus = fail then
      Error( "fusions <tblmG> -> <tblmGa> -> <tblGa> must be stored" );
    fi;

    kernel:= ClassPositionsOfKernel( factfus );

    nccl:= NrConjugacyClasses( tblmG );
    irr:= Irr( tblmG );
    plan:= [];
    for chi in Irr( tblmGa ) do
      if not IsSubset( ClassPositionsOfKernel( chi ), kernel ) then
        rest:= chi{ subfus };
        Add( plan, Filtered( [ 1 .. nccl ],
                       i -> ScalarProduct( tblmG, rest, irr[i] ) <> 0 ) );
      fi;
    od;

    nonfaith:= List( Irr( tblGa ), chi -> chi{ factfus } );
    proj:= ProjectionMap( subfus );
    zero:= [ 1 .. NrConjugacyClasses( tblmGa ) ] * 0;
    faithful:= [];
    for entry in plan do
      # Note that `proj' need not be dense.
      sum:= Sum( irr{ entry } );
      chi:= ShallowCopy( zero );
      for i in [ 1 .. Length( chi ) ] do
        if IsBound( proj[i] ) then
          chi[i]:= sum[ proj[i] ];
        fi;
      od;
      Add( faithful, chi );
    od;
    perm:= Sortex( Concatenation( nonfaith, faithful ) ) /
           Sortex( ShallowCopy( Irr( tblmGa ) ) );

    return [ "ConstructMGA",
             Identifier( tblmG ), Identifier( tblGa ), plan, perm ];
end );


#############################################################################
##
#F  ConstructProj( <tbl>, <irrinfo> )
#F  ConstructProjInfo( <tbl>, <kernel> )
##
InstallGlobalFunction( ConstructProj, function( tbl, irrinfo )
    local i, j, factor, fus, mult, irreds, linear, omegasquare, I,
          d, name, factfus, proj, adjust, Adjust,
          ext, lin, chi, faith, nccl, partner, divs, prox, foll,
          vals;

    nccl:= Length( tbl.SizesCentralizers );
    factor:= CharacterTableFromLibrary( irrinfo[1][1] );
    fus:= First( tbl.ComputedClassFusions,
                 fus -> fus.name = irrinfo[1][1] ).map;
    mult:= tbl.SizesCentralizers[1] / Size( factor );
    irreds:= List( Irr( factor ), x -> ValuesOfClassFunction( x ){ fus } );
    linear:= Filtered( irreds, x -> x[1] = 1 );
    linear:= Filtered( linear, x -> ForAny( x, y -> y <> 1 ) );

    # some roots of unity
    omegasquare:= E(3)^2;
    I:= E(4);

    # Loop over the divisors of `mult' (a divisor of 12).
    # Note the succession for `mult = 12'!
    if mult <> 12 then
      divs:= Difference( DivisorsInt( mult ), [ 1 ] );
    else
      divs:= [ 2, 4, 3, 6, 12 ];
    fi;

    for d in divs do

      # Construct the faithful irreducibles for an extension by `d'.
      # For that, we split and adjust the portion of characters (stored
      # on the small table `factor') as if we would create this extension,
      # and then we blow up these characters to the whole table.

      name:= irrinfo[d][1];
      partner:= irrinfo[d][2];
      proj:= First( ProjectivesInfo( factor ), x -> x.name = name );
      faith:= List( proj.chars, y -> y{ fus } );

      if name = tbl.Identifier then
        factfus:= [ 1 .. Length( tbl.SizesCentralizers ) ];
      else
        factfus:= First( tbl.ComputedClassFusions, x -> x.name = name ).map;
      fi;
      adjust:= First( tbl.ComputedClassFusions,
                      r -> r.name = Identifier( factor ) ).map;
      proj:= ProjectionMap( CompositionMaps( adjust,
                                InverseMap( factfus ) ) );
      Add( proj, Length( factfus ) + 1 );    # for termination of loop
      adjust:= [];
      for i in [ 1 .. Length( proj ) - 1 ] do
        for j in [ proj[i] .. proj[i+1]-1 ] do
          adjust[ j ]:= proj[i];
        od;
      od;

      # Now we have to multiply the values on certain classes `j' with
      # roots of unity, depending on the value of `d':
#T Note that we do not have the factor fusion from d.G to G available,
#T since the only tables we have are those of mult.G and G,
#T together with the projective characters for the various intermediate
#T tables!
#T -> wait: in the sit. m.G -->> d.G -->> G,
#T          we know the fusions m.G -->> d.G and m.G -->> G and thus can
#T          compute d.G -->> G as a composition!

      Adjust:= [];
      for i in [ 1 .. d-1 ] do
        Adjust[i]:= Filtered( [ 1 .. Length( factfus ) ],
                              x -> adjust[ factfus[x] ] = factfus[x] - i );
      od;
#T this means to adjust also in many zero columns;
#T if d = 6 and a class has only 2 or 3 preimages, the second preimage class
#T need not be adjusted for the faithful characters ...

      # d =  2: classes in `Adjust[1]' multiply with `-1'
      # d =  3: classes in `Adjust[x]' multiply
      #                     with `E(3)^x' for the proxy cohort,
      #                     with `E(3)^(2*x)' for the follower cohort
      # d =  4: classes in `Adjust[x]' multiply
      #                     with `E(4)^x' for the proxy cohort,
      #                     with `(-E(4))^x' for the follower cohort,
      # d =  6: classes in `Adjust[x]' multiply with `(-E(3))^x'
      # d = 12: classes in `Adjust[x]' multiply with `(E(12)^7)^x'
      #
      # (*Note* that follower cohorts of classes never occur in projective
      #  ATLAS tables ... )

      # Determine proxy classes and follower classes:
      if Length( linear ) in [ 2, 5 ] then  # out in [ 3, 6 ]
        prox:= [];
        foll:= [];
        chi:= irreds[ Length( linear ) ];
--> --------------------

--> maximum size reached

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

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