Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/PVS/   (Beweissystem der NASA Version 6.0.9©) image not shown  

Quelle  ctblsolv.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Hans Ulrich Besche, 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 character table methods for solvable groups.
##

##  We take advantage of knowing conjugacy class representatives
##  as words in generators.
InstallMethod(LinearCharacters, ["CanEasilyComputePcgs"], function(G)
  local pcgs, hom, Gab, abinv, exp, e, Ee, genexp,
        clexps, tab, irgens, a, lin, c, res, j, i, sz, chi;
  if Size(G) = 1 then
    return [TrivialCharacter(G)];
  fi;
  pcgs := Pcgs(G);
  # this yields the homomorphism onto G/G'
  hom := MaximalAbelianQuotient(G);
  # G/G'
  Gab := Image(hom);
  abinv := AbelianInvariants(Gab);
  sz := Product(abinv);
  # all character values are powers of e
  exp := Lcm(abinv);
  e := E(exp);
  Ee := [1];
  for i in [1..exp-1] do
    Add(Ee, Ee[i]*e);
  od;
  # write generators of G mod G' as in abelian generators of G/G'
  IndependentGeneratorsOfAbelianGroup(Gab);
  genexp := List(pcgs, x-> IndependentGeneratorExponents(Gab, x^hom));
  # exponent vectors of class representatives of G
  clexps := List(ConjugacyClasses(G),
                 c-> ExponentsOfPcElement(pcgs, Representative(c)));
  # irgens are the dual generators of G/G'
  tab := CharacterTable(G);
  irgens := [];
  for i in [1..Length(abinv)] do
    a := exp/abinv[i];
    Add(irgens, List(genexp, g-> g[i]*a));
  od;
  # now it is easy to find values of all linear characters on generators of G
  # -> and so on class representatives
  lin := 0*[1..Length(pcgs)];
  res := [];
  # c is the abinv-adic decomposition of i in [0..sz-1], used as
  # coefficients of a linear combination of irgens
  c := 0*[1..Length(abinv)];
  for i in [1..sz] do
    chi:= Character(tab, Ee{((clexps * lin) mod exp)+1});
    SetIsIrreducibleCharacter( chi, true );
    Add(res, chi);
    if i < sz then
      c[1] := c[1]+1;
      lin := lin + irgens[1];
      j := 1;
      while c[j] >= abinv[j] do
        c[j] := 0;
        lin := lin - abinv[j]*irgens[j];
        j := j+1;
        c[j] := c[j]+1;
        lin := lin + irgens[j];
      od;
    fi;
  od;
  return res;
end);


#############################################################################
##
#F  AppendCollectedList( <list1>, <list2> )
##
BindGlobal( "AppendCollectedList", function( list1, list2 )
    local pair1, pair2, toadd;
    for pair2 in list2 do
      toadd:= true;
      for pair1 in list1 do
        if pair1[1] = pair2[1] then
          pair1[2]:= pair1[2] + pair2[2];
          toadd:= false;
          break;
        fi;
      od;
      if toadd then
        AddSet( list1, pair2 );
      fi;
    od;
end );


#############################################################################
##
#F  KernelUnderDualAction( <N>, <Npcgs>, <v> )  . . . . . . .  local function
##
##  <Npcgs> is a PCGS of an elementary abelian group <N>.
##  <v> is a vector in the dual space of <N>, w.r.t. <Npcgs>.
##  The kernel of <v> is returned.
##
BindGlobal( "KernelUnderDualAction", function( N, Npcgs, v )
    local gens, # generators list
          i, j;

    gens:= [];
    for i in Reversed( [ 1 .. Length( v ) ] ) do
      if IsZero( v[i] ) then
        Add( gens, Npcgs[i] );
      else
        # `i' is the position of the last nonzero entry of `v'.
        for j in Reversed( [ 1 .. i-1 ] ) do
          Add( gens, Npcgs[j]*Npcgs[i]^( Int(-v[j]/v[i]) ) );
        od;
        return SubgroupNC( N, Reversed( gens ) );
      fi;
    od;
end );


#############################################################################
##
#F  ProjectiveCharDeg( <G> ,<z> ,<q> )
##
InstallGlobalFunction( ProjectiveCharDeg, function( G, z, q )
    local oz,       # the order of `z'
          N,        # normal subgroup of `G'
          t,
          r,        # collected list of character degrees, result
          h,        # natural homomorphism
          img,
          k,
          c,
          ci,
          zn,
          i,
          p,        # prime divisor of the size of `N'
          P,        # Sylow `p' subgroup of `N'
          O,
          L,
          Gpcgs,    # PCGS of `G'
          Ppcgs,    # PCGS of `P'
          Opcgs,    # PCGS of `O'
          mats,
          orbs,
          orb,      # loop over `orbs'
          stab;     # stabilizer of canonical representative of `orb'

    oz:= Order( z );

    # For abelian groups, there are only linear characters.
    if IsAbelian( G ) then
      G:= Size( G );
      if q <> 0 then
        while G mod q = 0 do
          G:= G / q;
        od;
      fi;
      return [ [ 1, G/oz ] ];
    fi;

    # Now `G' is not abelian.
    h:= NaturalHomomorphismByNormalSubgroupNC( G, SubgroupNC( G, [ z ] ) );
    img:= ImagesSource( h );
    N:= ElementaryAbelianSeriesLargeSteps( img );
    N:= N[ Length( N )-1 ];
    if not IsPrime( Size( N ) ) then
      N:= ChiefSeriesUnderAction( img, N );
      N:= N[ Length( N )-1 ];
    fi;

    # `N' is a normal subgroup such that `N/<z>' is a chief factor of `G'
    # of order `i' which is a power of `p'.
    N:= PreImagesSet( h, N );
    i:= Size( N ) / oz;
    p:= Factors( i )[1];

    if not IsAbelian( N ) then

      # `c' is a list of complement classes of `N' modulo `z'
      c:= List( ComplementClassesRepresentatives( ImagesSource( h ), ImagesSet( h, N ) ),
                x -> PreImagesSet( h, x ) );
      r:= Centralizer( G, N );
      for L in c do
        if IsSubset( L, r ) then

          # L is a complement to N in G modulo <z> which centralizes N
          r:= RootInt( Size(N) / oz );
          return List( ProjectiveCharDeg( L, z, q ),
                       x -> [ x[1]*r, x[2] ] );

        fi;
      od;
      Error( "this should not happen" );

    fi;

    # `N' is abelian, `P' is its Sylow `p' subgroup.
    P:= SylowSubgroup( N, p );

    if p = q then

      # Factor out `P' (lies in the kernel of the repr.)
      h:= NaturalHomomorphismByNormalSubgroupNC( G, P );
      return ProjectiveCharDeg( ImagesSource( h ), ImageElm( h, z ), q );

    elif i = Size( P ) then

      # `z' is a p'-element, `P' is elementary abelian.
      # Find the characters of the factor group needed.
      h:= NaturalHomomorphismByNormalSubgroupNC( G, P );
      r:= ProjectiveCharDeg( ImagesSource( h ), ImageElm( h, z ), q );

      if p = i then

        # `P' has order `p'.
        zn:= First( GeneratorsOfGroup( P ), g -> not IsOne( g ) );
        t:=  Stabilizer( G, zn );
        i:= Size(G) / Size(t);
        AppendCollectedList( r,
            List( ProjectiveCharDeg( t, zn*z, q ),
                  x -> [ x[1]*i, x[2]*(p-1)/i ] ) );
        return r;

      else

        # `P' has order strictly larger than `p'.
        # `mats' describes the contragredient operation of `G' on `P'.
        Gpcgs:= Pcgs( G );
        Ppcgs:= Pcgs( P );
        mats:= List( List( Gpcgs, Inverse ),
                   x -> TransposedMat( List( Ppcgs,
                   y -> ExponentsConjugateLayer( Ppcgs, y,x ) )*Z(p)^0 ) );
        orbs:= ExternalOrbitsStabilizers( G,
                   NormedRowVectors( GF(p)^Length( Ppcgs ) ),
                   Gpcgs, mats, OnLines );
        orbs:= Filtered( orbs,
              o -> not IsZero( CanonicalRepresentativeOfExternalSet( o ) ) );

        for orb in orbs do

          # `k' is the kernel of the character.
          stab:= StabilizerOfExternalSet( orb );
          h:= NaturalHomomorphismByNormalSubgroupNC( stab,
                  KernelUnderDualAction( P, Ppcgs,
                      CanonicalRepresentativeOfExternalSet( orb ) ) );
          img:= ImagesSource( h );

          # `zn' is an element of `img'.
          # Note that the image of `P' under `h' has order `p'.
          zn:= First( GeneratorsOfGroup( ImagesSet( h, P) ),
                      g -> not IsOne( g ) )
               * ImageElm( h, z );

          # `c' is stabilizer of the character,
          # `ci' is the number of orbits of characters with equal kernels
          if p = 2 then
            c  := img;
            ci := 1;
          else
            c  := Stabilizer( img, zn );
            ci := Size( img ) / Size( c );
          fi;
          k:= Size( G ) / Size( stab ) * ci;
          AppendCollectedList( r,
              List( ProjectiveCharDeg( c, zn, q ),
                    x -> [ x[1]*k, x[2]*(p-1)/ci ] ) );

        od;
        return r;

      fi;

    elif IsCyclic( P ) then

      # Choose a generator `zn' of `P'.
      zn := Pcgs( P )[1];
      t  := Stabilizer( G, zn, OnPoints );
      if G = t then
        # `P' is a central subgroup of `G'.
        return List( ProjectiveCharDeg( G, zn*z, q ),
                     x -> [ x[1], x[2]*p ] );
      else
        # `P' is not central in `G'.
        return List( ProjectiveCharDeg( t, zn*z, q ),
                     x -> [ x[1]*p, x[2] ] );
      fi;

    fi;

    # `P' is the direct product of the Sylow `p' subgroup of `z'
    # and an elementary abelian `p' subgroup.
    O:= Omega( P, p );
    Opcgs:= Pcgs( O );
    Gpcgs:= Pcgs( G );

    # `zn' is a generator of the intersection of <z> and `O'
    zn := z^(oz/p);
    r  := [];
    mats:= List( List( Gpcgs, Inverse ),
                 x -> TransposedMat( List( Opcgs,
                      y -> ExponentsConjugateLayer( Opcgs, y,x ) ) * Z(p)^0 ) );
    orbs:= ExternalOrbitsStabilizers( G,
               NormedRowVectors( GF(p)^Length( Opcgs ) ),
               Gpcgs, mats, OnLines );
    orbs:= Filtered( orbs,
              o -> not IsZero( CanonicalRepresentativeOfExternalSet( o ) ) );

    # In this case the stabilizers of the kernels are already the
    # stabilizers of the characters.
    for orb in orbs do
      k:= KernelUnderDualAction( O, Opcgs,
              CanonicalRepresentativeOfExternalSet( orb ) );
      if not zn in k then
        # The kernel avoids `zn'.
        t:= StabilizerOfExternalSet( orb );
        h:= NaturalHomomorphismByNormalSubgroupNC( t, k );
        img:= ImagesSource( h );
        t:= Size(G) / Size(t);
        AppendCollectedList( r, List( ProjectiveCharDeg( img,
                                          ImageElm( h, z ), q ),
                                      x -> [ x[1]*t, x[2] ] ) );
      fi;
    od;
    return r;
end );


#############################################################################
##
#M  CharacterDegrees( <G>, <p> )  . . . . . . . . . . .  for a solvable group
##
##  The algorithm used is based on~\cite{Con90b},
##  its main tool is Clifford theory.
##
##  Given a solvable group $G$ and a nonnegative integer $q$,
##  we first choose an elementary abelian normal subgroup $N$.
##  (Note that $N$ need not be a *minimal* normal subgroup, this requirement
##  in~\cite{Con90b} applies only to the computation of projective degrees
##  where nonabelian normal subgroups $N$ occur.)
##  By recursion, the $q$-modular character degrees of the factor group $G/N$
##  are computed next.
##  So it remains to compute the degrees of those $q$-modular irreducible
##  characters whose kernels do not contain $N$.
##  This last step follows~\cite{Con90b}, for the special case of a *trivial*
##  central subgroup $Z$.
##  Namely, we compute the $G$-orbits on the linear spaces of the nontrivial
##  irreducible characters of $N$, under projective action.
##  (The orbit consisting of the trivial character corresponds to those
##  $q$-modular irreducible $G$-characters with $N$ in their kernels.)
##  For each orbit, we use the function `ProjectiveCharDeg' to compute the
##  degrees arising from a representative $\chi$,
##  in the group $S/K$ with central cyclic subgroup $N/K$,
##  where $S$ is the (subspace) stabilizer of $\chi$ and $K$ is the kernel of
##  $\chi$.
##
##  One recursive step of the algorithm is described in the following.
##
##  Let $G$ be a solvable group, $z$ a central element in $G$,
##  and let $q$ be the characteristic of the algebraic closed field $F$.
##  Without loss of generality, we may assume that $G$ is nonabelian.
##  Consider a faithful linear character $\lambda$ of $\langle z \rangle$.
##  We calculate the character degrees $(G,z,q)$ of those absolutely
##  irreducible characters of $G$ whose restrictions to $\langle z \rangle$
##  are a multiple of $\lambda$.
##
##  We choose a normal subgroup $N$ of $G$ such that the factor
##  $N / \langle z \rangle$ is a chief factor in $G$, and consider
##  the following cases.
##
##  If $N$ is nonabelian then we calculate a subgroup $L$ of $G$ such that
##  $N \cap L = \langle z \rangle$, $L$ centralizes $N$, and $N L = G$.
##  One can show that the order of $N / \langle z \rangle$ is a square $r^2$,
##  and that the degrees $(G,z,q)$ are obtained from the degrees $(L,z,q)$
##  on multiplying each with $r$.
##
##  If $N$ is abelian then the order of $N / \langle z \rangle$ is a prime
##  power $p^i$.
##  Let $P$ denote the Sylow $p$ subgroup of $N$.
##  Following Clifford's theorem, we calculate orbit representatives and
##  inertia subgroups with respect to the action of $G$ on those irreducible
##  characters of $P$ that restrict to multiples of $\lambda_P$.
##  For that, we distinguish three cases.
##  \beginlist
##  \item{(a)}
##      $z$ is a $p^{\prime}$ element.
##      Then we compute first the character degrees $(G/P,zP,q)$,
##      corresponding to the (orbit of the) trivial character.
##      The action on the nontrivial irreducible characters of $P$
##      is dual to the action on the nonzero vectors of the vector space
##      $P$.
##      For each representative, we compute the kernel $K$, and the degrees
##      $(S/K,zK,q)$, where $S$ denotes the inertia subgroup.
##
##  \item{(b)}
##      $z$ is not a $p^{\prime}$ element, and $P$ cyclic (not prime order).
##      Let $y$ be a generator of $P$.
##      If $y$ is central in $G$ then we have to return $p$ copies of the
##      degrees $(G,zy,q)$.
##      Otherwise we compute the degrees $(C_G(y),zy,q)$, and multiply
##      each with $p$.
##
##  \item{(c)}
##      $z$ is not a $p^{\prime}$ element, and $P$ is not cyclic.
##      We compute $O = \Omega(P)$.
##      As above, we consider the dual operation to that in $O$,
##      and for each orbit representative we check whether its restriction
##      to $O$ is a multiple of $\lambda_O$, and if yes compute the degrees
##      $(S/K,zK,q)$.
##  \endlist
##
BindGlobal( "CharacterDegreesConlon", function( G, q )
    local r,      # list of degrees, result
          N,      # elementary abelian normal subgroup of `G'
          p,      # prime divisor of the order of `N'
          z,      # one generator of `N'
          t,      # stabilizer of `z' in `G'
          i,      # index of `t' in `G'
          Gpcgs,  # PCGS of `G'
          Npcgs,  # PCGS of `N'
          mats,   # matrices describing the action of `Gpcgs' w.r.t. `Npcgs'
          orbs,   # orbits of the action
          orb,    # loop over `orbs'
          rep,    # canonical representative of `orb'
          stab,   # stabilizer of `rep'
          h,      # nat. hom. by the kernel of a character
          img,    # image of `h'
          c,
          ci,
          k;

    Info( InfoCharacterTable, 1,
          "CharacterDegrees: called for group of order ", Size( G ) );

    # If the group is abelian, we must give up because this method
    # needs a proper elementary abelian normal subgroup for its
    # reduction step.
    # (Note that we must not call `TryNextMethod' because the method
    # for abelian groups has higher rank.)
    if IsAbelian( G ) then
      r:= CharacterDegreesAbelian( G, q );
      Info( InfoCharacterTable, 1,
            "CharacterDegrees: returns ", r );
      return r;
    elif not ( q = 0 or IsPrimeInt( q ) ) then
      Error( "<q> must be zero or a prime" );
    fi;

    # Choose a normal elementary abelian `p'-subgroup `N',
    # not necessarily minimal.
    N:= ElementaryAbelianSeriesLargeSteps( G );
    N:= N[ Length( N ) - 1 ];
    r:= CharacterDegreesConlon( G / N, q );
    p:= Factors( Size( N ) )[1];

    if p = q then

      # If `N' is a `q'-group we are done.
      Info( InfoCharacterTable, 1,
            "CharacterDegrees: returns ", r );
      return r;

    elif Size( N ) = p then

      # `N' is of prime order.
      z:= Pcgs( N )[1];
      t:= Stabilizer( G, z, OnPoints );
      i:= Size( G ) / Size( t );
      AppendCollectedList( r, List( ProjectiveCharDeg( t, z, q ),
                                    x -> [ x[1]*i, x[2]*(p-1)/i ] ) );

    else

      # `N' is an elementary abelian `p'-group of nonprime order.
      Gpcgs:= Pcgs( G );
      Npcgs:= Pcgs( N );
      mats:= List( Gpcgs, x -> TransposedMat( List( Npcgs,
                 y -> ExponentsConjugateLayer( Npcgs, y,x ) ) * Z(p)^0 )^-1 );
      orbs:= ExternalOrbitsStabilizers( G,
                 NormedRowVectors( GF( p )^Length( Npcgs ) ),
                 Gpcgs, mats, OnLines );
#T may fail because the list is too long!
      orbs:= Filtered( orbs,
              o -> not IsZero( CanonicalRepresentativeOfExternalSet( o ) ) );

      for orb in orbs do

        stab:= StabilizerOfExternalSet( orb );
        rep:= CanonicalRepresentativeOfExternalSet( orb );
        h:= NaturalHomomorphismByNormalSubgroupNC( stab,
                KernelUnderDualAction( N, Npcgs, rep ) );
        img:= ImagesSource( h );

        # The kernel has index `p' in `stab'.
        z:= First( GeneratorsOfGroup( ImagesSet( h, N ) ),
                   g -> not IsOne( g ) );
        if p = 2 then
          c  := img;
          ci := 1;
        else
          c  := Stabilizer( img, z );
          ci := Size( img ) / Size( c );
        fi;
        k:= Size( G ) / Size( stab ) * ci;
        AppendCollectedList( r, List( ProjectiveCharDeg( c, z, q ),
                                      x -> [ x[1]*k, x[2]*(p-1)/ci ] ) );

      od;

    fi;

    Info( InfoCharacterTable, 1,
          "CharacterDegrees: returns ", r );
    return r;
    end );


#############################################################################
##
#F  CoveringTriplesCharacters( <G>, <z> ) . . . . . . . . . . . . . . . local
##
InstallGlobalFunction( CoveringTriplesCharacters, function( G, z )
    local oz,
          h,
          img,
          N,
          t,
          r,
          k,
          c,
          zn,
          i,
          p,
          P,
          O,
          Gpcgs,
          Ppcgs,
          Opcgs,
          mats,
          orbs,
          orb;

    # The trivial character will be dealt with separately.
    if IsTrivial( G ) then
      return [];
    fi;

    oz:= Order( z );
    if Size( G ) = oz then
      return [ [ G, TrivialSubgroup( G ), z ] ];
    fi;

    h:= NaturalHomomorphismByNormalSubgroupNC( G, SubgroupNC( G, [ z ] ) );
    img:= ImagesSource( h );
    N:= ElementaryAbelianSeriesLargeSteps( img );
    N:= N[ Length( N ) - 1 ];
    if not IsPrime( Size( N ) ) then
      N:= ChiefSeriesUnderAction( img, N );
      N:= N[ Length( N ) - 1 ];
    fi;
    N:= PreImagesSet( h, N );

    if not IsAbelian( N ) then
      Info( InfoCharacterTable, 2,
            "#I misuse of `CoveringTriplesCharacters'!\n" );
      return [];
    fi;

    i:= Size( N ) / oz;
    p:= Factors( i )[1];
    P:= SylowSubgroup( N, p );

    if i = Size( P ) then

      # `z' is a p'-element, `P' is elementary abelian.
      # Find the characters of the factor group needed.
      h:= NaturalHomomorphismByNormalSubgroupNC( G, P );
      r:= List( CoveringTriplesCharacters( ImagesSource( h ),
                                           ImageElm( h, z ) ),
                x -> [ PreImagesSet( h, x[1] ),
                       PreImagesSet( h, x[2] ),
                       PreImagesRepresentative( h, x[3] ) ] );

      if p = i then

        # `P' has order `p'.
        zn:= First( GeneratorsOfGroup( P ), g -> not IsOne( g ) );
        return Concatenation( r,
                   CoveringTriplesCharacters( Stabilizer( G, zn ), zn*z ) );

      else

        Gpcgs:= Pcgs( G );
        Ppcgs:= Pcgs( P );
        mats:= List( List( Gpcgs, Inverse ),
                   x -> TransposedMat( List( Ppcgs,
                   y -> ExponentsConjugateLayer( Ppcgs, y,x ) )*Z(p)^0 ) );
        orbs:= ExternalOrbitsStabilizers( G,
                   NormedRowVectors( GF(p)^Length( Ppcgs ) ),
                   Gpcgs, mats, OnLines );
        orbs:= Filtered( orbs,
              o -> not IsZero( CanonicalRepresentativeOfExternalSet( o ) ) );

        for orb in orbs do
          h:= NaturalHomomorphismByNormalSubgroupNC(
                  StabilizerOfExternalSet( orb ),
                  KernelUnderDualAction( P, Ppcgs,
                      CanonicalRepresentativeOfExternalSet( orb ) ) );
          img:= ImagesSource( h );
          zn:= First( GeneratorsOfGroup( ImagesSet( h, P ) ),
                      g -> not IsOne( g ) )
               * ImageElm( h, z );

          if p = 2 then
            c:= img;
          else
            c:= Stabilizer( img, zn );
          fi;
          Append( r, List( CoveringTriplesCharacters( c, zn ),
                           x -> [ PreImagesSet( h, x[1] ),
                                  PreImagesSet( h, x[2] ),
                                  PreImagesRepresentative( h, x[3] ) ] ) );
        od;
        return r;

      fi;

    elif IsCyclic( P ) then

      zn:= Pcgs( P )[1];
      return CoveringTriplesCharacters( Stabilizer( G, zn ), zn*z );

    fi;

    O:= Omega( P, p );
    Opcgs:= Pcgs( O );
    Gpcgs:= Pcgs( G );

    zn := z^(oz/p);
    r  := [];
    mats:= List( List( Gpcgs, Inverse ),
                 x -> TransposedMat( List( Opcgs,
                      y -> ExponentsConjugateLayer( Opcgs, y,x ) )*Z(p)^0 ) );
    orbs:= ExternalOrbitsStabilizers( G,
               NormedRowVectors( GF(p)^Length( Opcgs ) ),
               Gpcgs, mats, OnLines );
    orbs:= Filtered( orbs,
              o -> not IsZero( CanonicalRepresentativeOfExternalSet( o ) ) );

    for orb in orbs do
      k:= KernelUnderDualAction( O, Opcgs,
              CanonicalRepresentativeOfExternalSet( orb ) );
      if not zn in k then
        t:= StabilizerOfExternalSet( orb );
        Assert( 1, IsIdenticalObj( Parent( t ), G ) );
        h:= NaturalHomomorphismByNormalSubgroupNC( t, k );
        img:= ImagesSource( h );
        Append( r,
            List( CoveringTriplesCharacters( img, ImageElm( h, z ) ),
                  x -> [ PreImagesSet( h, x[1] ),
                         PreImagesSet( h, x[2] ),
                         PreImagesRepresentative( h, x[3] ) ] ) );
      fi;
    od;
    return r;
end );


#############################################################################
##
#M  IrrConlon( <G> )
##
##  This algorithm is a generalization of the algorithm to compute the
##  absolutely irreducible degrees of a solvable group to the computation
##  of the absolutely irreducible characters of a supersolvable group,
##  using an idea like in
##
##      S. B. Conlon, J. Symbolic Computation (1990) 9, 535-550.
##
##  The function `CoveringTriplesCharacters' is used to compute a list of
##  triples describing linear representations of subgroups of <G>.
##  These linear representations are induced to <G> and then evaluated on
##  representatives of the conjugacy classes.
##
##  For every irreducible character the monomiality information is stored as
##  value of the attribute `TestMonomial'.
##
InstallMethod( IrrConlon, [ "IsGroup" ],
function( G )
  local pcgs, clreps, ct, irr, tr, Cs, normal, N, hom, Cab, abgens,
        ind, coreps, evals, xg, K, sz, h, qu, genqu, multi, mods,
        ch, c, ms, vals, cval, k, C, x, g, t, i, j, r, tm, new;
  pcgs := Pcgs(G);
  # return no characters if G is not solvable
  if pcgs = fail then
    return [];
  fi;
  clreps := List( ConjugacyClasses( G ), Representative );
  ct := CharacterTable( G );
  irr := [];
  # linear characters without covering triples
  Append( irr, LinearCharacters( G ) );
  tm := rec( isMonomial := true, comment := "linear character" );
  for ch in irr do
    SetTestMonomial( ch, tm );
  od;
  tm := rec( isMonomial := true, comment := "induced from given subgroup" );

  # we now only need the triples for proper subgroups
  tr := Filtered( CoveringTriplesCharacters( G, One( G ) ), a-> a[1] <> G );
  # subgroups to induce from
  Cs := Set( List(tr, a-> a[1] ) );
  for C in Cs do
    # monomiality information
    tm := ShallowCopy(tm);
    tm.subgroup := C;
    # only classes in N can have non-zero values
    if IsNormal( G, C ) then
      normal := true;
      N := C;
    else
      normal := false;
      N := NormalClosure( G, C );
    fi;
    # only linear characters of C are induced, need homomorphism onto C/C'
    hom := MaximalAbelianQuotient( C );
    Cab := Image( hom );
    abgens := IndependentGeneratorsOfAbelianGroup( Cab );
    # we compute the generic induced linear character from C,
    # eigenvalues expressed as product of values on generators of C/C'
    ind := [];
    coreps := List( RightCosets( G, C ), Representative );
    for x in clreps do
      if x in N then
        evals := [];
        for g in coreps do
          xg := x^(g^-1);
          if normal or xg in C then
            # if true then x^((cg)^-1) is in the same C-class for all c in C
            Add( evals, IndependentGeneratorExponents( Cab, xg^hom ));
          fi;
        od;
        if Length(evals) > 0 then
          Add( ind, evals );
        else
          Add( ind, 0 );
        fi;
      else
        Add( ind, 0 );
      fi;
    od;
    # now we evaluate ind at the relevant linear characters of C
    for t in tr do
      if t[1] = C then
        # C/K is cyclic of order sz
        # this triple is for all characters of order sz with kernel K
        K := t[2];
        sz := Size( C ) / Size( K );
        # find the characters with kernel K
        #    (maybe better with Hermite normal form?)
        h := NaturalHomomorphismByNormalSubgroupNC( Cab,
               SubgroupNC( Cab, List( GeneratorsOfGroup( K ), y-> y^hom ) ) );
        qu := Image( h );
        # if sz is not a prime power there are several generators
        genqu := IndependentGeneratorsOfAbelianGroup( qu );
        if Length(genqu) > 1 then
          multi := true;
          mods := List(genqu, Order);
        else
          multi := false;
        fi;
        ch := [];
        for g in abgens do
          c := IndependentGeneratorExponents( qu, g^h );
          if multi then
            Add( ch, ChineseRem( mods, c ) );
          else
            Add( ch, c[1] );
          fi;
        od;
        # these multiples of ch are needed
        ms := Filtered( [1..sz-1], m-> Gcd( m, sz ) = 1 );
        vals := List( ms, m-> [] );
        for i in [1..Length(ind)] do
          if ind[i] = 0 then
            for j in [ 1..Length(ms) ] do
              Add( vals[j], 0 );
            od;
          else
            cval := 0*[1..sz];
            for r in ind[i] do
              k := (r * ch) mod sz + 1;
              cval[k] := cval[k] + 1;
            od;
            cval := CycList( cval );
            Add( vals[1], cval );
            for j in [2..Length(ms)] do
              Add( vals[j], GaloisCyc( cval, ms[j] ) );
            od;
          fi;
        od;
        new := List( vals, l-> Character( ct, l ) );
        for ch in new do
          SetTestMonomial( ch, tm );
        od;
        Append( irr, new );
      fi;
    od;
  od;
  return irr;
end);

#############################################################################
##
#M  Irr( <G>, 0 ) . . . . . .  for a supersolvable group (Conlon's algorithm)
##
InstallMethod( Irr,
    "for a supersolvable group (Conlon's algorithm)",
    [ IsGroup and IsSupersolvableGroup, IsZeroCyc ],
    function( G, zero )
    local irr;
    irr:= IrrConlon( G );
    SetIrr( OrdinaryCharacterTable( G ), irr );
    return irr;
    end );

InstallMethod( Irr,
    "for a supersolvable group with known `IrrConlon'",
    [ IsGroup and IsSupersolvableGroup and HasIrrConlon, IsZeroCyc ],
    function( G, zero )
    local irr;
    irr:= IrrConlon( G );
    SetIrr( OrdinaryCharacterTable( G ), irr );
    return irr;
    end );


#############################################################################
##
#M  Irr( <G>, 0 ) . . . .  for a supersolvable group (Baum-Clausen algorithm)
##
InstallMethod( Irr,
    "for a supersolvable group (Baum-Clausen algorithm)",
    [ IsGroup and IsSupersolvableGroup, IsZeroCyc ],
    function( G, zero )
    local irr, tbl;
    irr:= IrrBaumClausen( G );
    tbl:= OrdinaryCharacterTable( G );
    SetIrr( tbl, irr );
    ComputeAllPowerMaps( tbl );
    return irr;
    end );

InstallMethod( Irr,
    "for a supersolvable group with known `IrrBaumClausen'",
    [ IsGroup and IsSupersolvableGroup and HasIrrBaumClausen, IsZeroCyc ],
    function( G, zero )
    local irr, tbl;
    irr:= IrrBaumClausen( G );
    tbl:= OrdinaryCharacterTable( G );
    SetIrr( tbl, irr );
    ComputeAllPowerMaps( tbl );
    return irr;
    end );


#############################################################################
##
#V  BaumClausenInfoDebug  . . . . . . . . . . . . . . testing BaumClausenInfo
##
BindGlobal( "BaumClausenInfoDebug", rec(
    makemat:= function( record, e )
        local dim, mat, diag, gcd, i;
        dim:= Length( record.diag );
        mat:= NullMat( dim, dim );
        diag:= record.diag;
        gcd:= Gcd( diag );
        if gcd = 0 then
          e:= 1;
        else
          gcd:= GcdInt( gcd, e );
          e:= E( e / gcd );
          diag:= diag / gcd;
        fi;
        for i in [ 1 .. dim ] do
          mat[i][ record.perm[i] ]:= e^diag[ record.perm[i] ];
        od;
        return mat;
    end,

    testrep:= function( pcgs, rep, e )
        local images, hom;
        images:= List( rep,
                       record -> BaumClausenInfoDebug.makemat( record, e ) );
        hom:= GroupGeneralMappingByImagesNC( Group( pcgs ), Group( images ),
                                           pcgs, images );
        return IsGroupHomomorphism( hom );
    end,

    checkconj:= function( pcgs, i, lg, j, rep1, rep2, X, e )
        local ii, exps, mat, jj;
        X:= BaumClausenInfoDebug.makemat( X, e );
        for ii in [ i .. lg ] do
          exps:= ExponentsOfPcElement( pcgs, pcgs[ii]^pcgs[j], [ i .. lg ] );
          mat:= One( X );
          for jj in [ 1 .. lg-i+1 ] do
            mat:= mat * BaumClausenInfoDebug.makemat( rep1[jj], e )^exps[jj];
          od;
          if X * mat <>
             BaumClausenInfoDebug.makemat( rep2[ ii-i+1 ], e ) * X then
            return false;
          fi;
        od;
        return true;
    end ) );

MakeImmutable(BaumClausenInfoDebug);


#############################################################################
##
#M  BaumClausenInfo( <G> )  . . . . .  info about irreducible representations
##
#T generalize to characteristic p !!
##
InstallMethod( BaumClausenInfo,
    "for a (solvable) group",
    [ IsGroup ],
    function( G )
    local e,             # occurring roots of unity are `e'-th roots
          pcgs,          # Pcgs of `G'
          lg,            # length of `pcgs'
          cs,            # composition series of `G' corresp. to `pcgs'
          abel,          # position of abelian normal comp. subgroup
          ExtLinRep,     # local function
          indices,       # sizes of composition factors in `cs'
          linear,        # list of linear representations
          i,             # current position in the iteration: $G_i$
          p,             # size of current composition factor
          pexp,          # exponent vector of `pcgs[i]^p'
          root,          # value of an extension
          roots,         # list of $p$-th roots (relative to `e')
          mulmoma,       # product of two monomial matrices
          poweval,       # representing matrix for power of generator
          pilinear,      # action of $g_1, \ldots, g_i$ on `linear'
          d, j, k, l,    # loop variables
          u, v, w,       # loop variables
          M,             #
          pos,           # position in a list
          nonlin,        # list of nonlinear representations
          pinonlin,      # action of $g_1, \ldots, g_i$ on `nonlin'
          Xlist,         # conjugating matrices:
                         # for $X = `Xlist[j][k]'$, we have
                         # $X \cdot {`nonlin[k]'}^{g_j} \cdot X^{-1} =
                         #    `nonlin[ pinonlin[j][k] ]'$
          min,           #
          minval,        #
          ssr,           #
          X,             # one matrix for `Xlist'
          nextlinear,    # extensions of `linear'
          nextnonlin1,   # nonlinear repr. arising from `linear'
          nextnonlin2,   # nonlinear repr. arising from `nonlin'
          pinextlinear,  # action of $g_1, \ldots, g_i$ on `nextlinear'
          pinextnonlin1, # action of $g_1, \ldots, g_i$ on `nextnonlin1'
          pinextnonlin2, # action of $g_1, \ldots, g_i$ on `nextnonlin2'
          nextXlist1,    # conjugating matrices for `nextnonlin1'
          nextXlist2,    # conjugating matrices for `nextnonlin2'
          cexp,          # exponent vector of `pcgs[i]^pcgs[j]'
          poli,          # list that encodes `pexp'
          rep,           # one representation
          D, C,          #
          value,         #
          image,         #
          used,          # boolean list
          Dpos1,         # positions of extension resp. induced repres.
                         # that arise from linear representations
          Dpos2,         # positions of extension resp. induced repres.
                         # that arise from nonlinear representations
          dim,           # dimension of the current representation
          invX,          # inverse of `X'
          D_gi,          #
          hom,           # homomorphism to adjust the composition series
          orb,           #
          Forb,          #
          sigma, pi,     # permutations needed in the fusion case
          constants,     # vector $(c_0, c_1, \ldots, c_{p-1})$
          kernel;        # kernel of `hom'

    if not IsSolvableGroup( G ) then
      Error( "<G> must be solvable" );
    fi;


    # Step 0:
    # Treat the case of the trivial group,
    # and initialize some variables.

    pcgs:= SpecialPcgs( G );
#T because I need a ``prime orders pcgs''
    lg:= Length( pcgs );

    if lg = 0 then
      return rec( pcgs     := pcgs,
                  kernel   := G,
                  exponent := 1,
                  nonlin   := [],
                  lin      := [ [] ]
                  );
    fi;

    cs:= PcSeries( pcgs );

    if HasExponent( G ) then
      e:= Exponent( G );
    else
      e:= Size(G);
#T better adjust on the fly
    fi;


    # Step 1:
    # If necessary then adjust the composition series of $G$
    # and get the largest factor group of $G$ that has an abelian normal
    # subgroup such that the factor group modulo this subgroup is
    # supersolvable.

    abel:= 1;
    while IsNormal( G, cs[ abel ] ) and not IsAbelian( cs[ abel ] ) do
      abel:= abel + 1;
    od;

    # If `cs[ abel ]' is abelian then we compute its representations first,
    # and then loop over the initial part of the composition series;
    # note that the factor group is supersolvable.
    # If `cs[ abel ]' is not abelian then we try to switch to a better
    # composition series, namely one through the derived subgroup of the
    # supersolvable residuum.

    if not IsNormal( G, cs[ abel ] ) then

      # We have reached a non-normal nonabelian composition subgroup
      # so we have to adjust the composition series.

      Info( InfoGroup, 2,
            "BaumClausenInfo: switching to a suitable comp. ser." );

      ssr:= SupersolvableResiduumDefault( G );
      hom:= NaturalHomomorphismByNormalSubgroupNC( G,
                DerivedSubgroup( ssr.ssr ) );

      # `SupersolvableResiduumDefault' contains a component `ds',
      # a list of subgroups such that any composition series through
      # `ds' from `G' down to the residuum is a chief series.
      pcgs:= [];
      for i in [ 2 .. Length( ssr.ds ) ] do
        j:= NaturalHomomorphismByNormalSubgroupNC( ssr.ds[ i-1 ], ssr.ds[i] );
        Append( pcgs, List( SpecialPcgs( ImagesSource( j ) ),
                            x -> PreImagesRepresentative( j, x ) ) );
      od;
      Append( pcgs, SpecialPcgs( Last(ssr.ds) ) );
      G:= ImagesSource( hom );
      pcgs:= List( pcgs, x -> ImagesRepresentative( hom, x ) );
      pcgs:= Filtered( pcgs, x -> Order( x ) <> 1 );
      pcgs:= PcgsByPcSequence( ElementsFamily( FamilyObj( G ) ), pcgs );
      cs:= PcSeries( pcgs );
      lg:= Length( pcgs );

      # The image of `ssr' under `hom' is abelian,
      # compute its position in the composition series.
      abel:= Position( cs, ImagesSet( hom, ssr.ssr ) );

      # If `G' is supersolvable then `abel = lg+1',
      # but the last *nontrivial* member of the chain is normal and abelian,
      # so we choose this group.
      # (Otherwise we would have the technical problem in step 4 that the
      # matrix `M' would be empty.)
      if lg < abel then
        abel:= lg;
      fi;

    fi;

    # Step 2:
    # Compute the representations of `cs[ abel ]',
    # each a list of images of $g_{abel}, \ldots, g_{lg}$.

    # The local function `ExtLinRep' computes the extensions of the
    # linear $G_{i+1}$-representations $F$ in the list `linear' to $G_i$.
    # The only condition that must be satisfied is that
    # $F(g_i)^p = F(g_i^p)$.
    # (Roughly speaking, we just compute $p$-th roots.)

    ExtLinRep:= function( i, linear, pexp, roots )

      local nextlinear, rep, j, shift;

      nextlinear:= [];
      if IsZero( pexp ) then

        # $g_i^p$ is the identity
        for rep in linear do
          for j in roots do
            Add( nextlinear, Concatenation( [ j ], rep ) );
          od;
        od;

      else

        pexp:= pexp{ [ i+1 .. lg ] };
#T cut this outside the function!
        for rep in linear do

          # Compute the value of `rep' on $g_i^p$.
          shift:= pexp * rep;

          if shift mod p <> 0 then
            # We must enlarge the exponent.
            Error("wrong exponent");
#T if not integral then enlarge the exponent!
#T (is this possible here at all?)
          fi;
          shift:= shift / p;
          for j in roots do
            Add( nextlinear, Concatenation( [ (j+shift) mod e ], rep ) );
          od;

        od;

      fi;

      return nextlinear;
    end;


    indices:= RelativeOrders( pcgs );
#T here set the exponent `e' to `indices[ lg ]' !
    Info( InfoGroup, 2,
          "BaumClausenInfo: There are ", lg, " steps" );

    linear:= List( [ 0 .. indices[lg]-1 ] * ( e / indices[lg] ),
                   x -> [ x ] );

    for i in [ lg-1, lg-2 .. abel ] do

      Info( InfoGroup, 2,
            "BaumClausenInfo: Compute repres. of step ", i,
            " (central case)" );

      p:= indices[i];

      # `pexp' describes $g_i^p$.
      pexp:= ExponentsOfRelativePower( pcgs,i);
# { ? } ??

      root:= e/p;
#T enlarge the exponent if necessary!
      roots:= [ 0, root .. (p-1)*root ];
      linear:= ExtLinRep( i, linear, pexp, roots );

    od;

    # We are done if $G$ is abelian.
    if abel = 1 then
      return rec( pcgs     := pcgs,
                  kernel   := TrivialSubgroup( G ),
                  exponent := e,
                  nonlin   := [],
                  lin      := linear
                  );
    fi;


    # Step 3:
    # Define some local functions.
    # (We did not need them for abelian groups.)

    # `mulmoma' returns the product of two monomial matrices.
    mulmoma:= function( a, b )
      local prod, i;
      prod:= rec( perm := b.perm{ a.perm },
                  diag := [] );
      for i in [ 1 .. Length( a.perm ) ] do
        prod.diag[ b.perm[i] ]:= ( b.diag[ b.perm[i] ] + a.diag[i] ) mod e;
      od;
      return prod;
    end;

    # `poweval' evaluates the representation `rep' on the $p$-th power of
    # the conjugating element.
    # This $p$-th power is described by `poli'.
    poweval:= function( rep, poli )
      local pow, i;
      if IsEmpty( poli ) then
        return rec( perm:= [ 1 .. Length( rep[1].perm ) ],
                    diag:= [ 1 .. Length( rep[1].perm ) ] * 0 );
      fi;
      pow:= rep[ poli[1] ];
      for i in [ 2 .. Length( poli ) ] do
        pow:= mulmoma( pow, rep[ poli[i] ] );
      od;
      return pow;
    end;


    # Step 4:
    # Compute the actions of $g_j$, $j < abel$, on the representations
    # of $G_{abel}$.
    # Let $g_i^{g_j} = \prod_{k=1}^n g_k^{\alpha_{ik}^j}$,
    # and set $A_j = [ \alpha_{ik}^j} ]_{i,k}$.
    # Then the representation that maps $g_i$ to the root $\zeta_e^{c_i}$
    # is mapped to the representation that has images exponents
    # $A_j * (c_1, \ldots, c_n)$ under $g_j$.

    Info( InfoGroup, 2,
          "BaumClausenInfo: Initialize actions on abelian normal subgroup" );

    pilinear:= [];
    for j in [ 1 .. abel-1 ] do

      # Compute the matrix $A_j$.
      M:= List( [ abel .. lg ],
                i -> ExponentsOfPcElement( pcgs, pcgs[i]^pcgs[j],
                                           [ abel .. lg ] ) );

      # Compute the permutation corresponding to the action of $g_j$.
      pilinear[j]:= List( linear,
                          rep -> Position( linear,
                                           List( M * rep, x -> x mod e ) ) );

    od;


    # Step 5:
    # Run up the composition series from `abel' to `1',
    # and compute extensions resp. induced representations.
    # For each index, we have to update `linear', `pilinear',
    # `nonlin', `pinonlin', and `Xlist'.

    nonlin   := [];
    pinonlin := [];
    Xlist    := [];

    for i in [ abel-1, abel-2 .. 1 ] do

      p:= indices[i];

      # `poli' describes $g_i^p$.
      #was pexp:= ExponentsOfPcElement( pcgs, pcgs[i]^p );
      pexp:= ExponentsOfRelativePower( pcgs, i );
      poli:= Concatenation( List( [ i+1 .. lg ],
                                  x -> List( [ 1 .. pexp[x] ],
                                             y -> x-i ) ) );

      # `p'-th roots of unity
      roots:= [ 0 .. p-1 ] * ( e/p );

      Info( InfoGroup, 2,
            "BaumClausenInfo: Compute repres. of step ", i );

      # Step A:
      # Compute representations of $G_i$ arising from *linear*
      # representations of $G_{i+1}$.

      used        := BlistList( [ 1 .. Length( linear ) ], [] );
      nextlinear  := [];
      nextnonlin1 := [];
      d           := 1;

      pexp:= pexp{ [ i+1 .. lg ] };

      # At position `d', store the position of either the first extension
      # of `linear[d]' in `nextlinear' or the position of the induced
      # representation of `linear[d]' in `nextnonlin1'.
      Dpos1:= [];

      while d <> fail do

        rep:= linear[d];
        used[d]:= true;

        # `root' is the value of `rep' on $g_i^p$.
        root:= ( pexp * rep ) mod e;

        if pilinear[i][d] = d then

          # `linear[d]' extends to $G_i$.
          Dpos1[d]:= Length( nextlinear ) + 1;

          # Take a `p'-th root.
          root:= root / p;
#T enlarge the exponent if necessary!

          for j in roots do
            Add( nextlinear, Concatenation( [ root+j ], rep ) );
          od;

        else

          # We must fuse the representations in the orbit of `d'
          # under `pilinear[i]';
          # so we construct the induced representation `D'.

          Dpos1[d]:= Length( nextnonlin1 ) + 1;

          D:= List( rep, x -> rec( perm := [ 1 .. p ],
                                   diag := [ x ]
                                  ) );
          pos:= d;
          for j in [ 2 .. p ] do

            pos:= pilinear[i][ pos ];
            for k in [ 1 .. Length( rep ) ] do
              D[k].diag[j]:= linear[ pos ][k];
            od;
            used[ pos ]:= true;
            Dpos1[ pos ]:= Length( nextnonlin1 ) + 1;

          od;

          Add( nextnonlin1,
               Concatenation( [ rec( perm := Concatenation( [p], [1..p-1]),
                                     diag := Concatenation( [ 1 .. p-1 ] * 0,
                                                            [ root ] ) ) ],
                              D ) );
          Assert( 2, BaumClausenInfoDebug.testrep( pcgs{ [ i .. lg ] },
                              Last(nextnonlin1), e ),
                  Concatenation( "BaumClausenInfo: failed assertion in ",
                      "inducing linear representations ",
                      "(i = ", String( i ), ")\n" ) );

        fi;

        d:= Position( used, false, d );

      od;


      # Step B:
      # Now compute representations of $G_i$ arising from *nonlinear*
      # representations of $G_{i+1}$ (if there are some).

      used:= BlistList( [ 1 .. Length( nonlin ) ], [] );
      nextnonlin2:= [];
      if Length( nonlin ) = 0 then
        d:= fail;
      else
        d:= 1;
      fi;

      # At position `d', store the position of the first extension resp.
      # of the induced representation of `nonlin[d]'in `nextnonlin2'.
      Dpos2:= [];

      while d <> fail do

        used[d]:= true;
        rep:= nonlin[d];

        if pinonlin[i][d] = d then

          # The representation $F = `rep'$ has `p' different extensions.
          # For `X = Xlist[i][d]', we have $`rep ^ X' = `rep'^{g_i}$,
          # i.e., $X^{-1} F X = F^{g_i}$.
          # Representing matrix $F(g_i)$ is $c X$ with $c^p X^p = F(g_i^p)$,
          # so $c^p X^p.diag[k] = F(g_i^p).diag[k]$ for all $k$ ;
          # for determination of $c$ we look at `k = X^p.perm[1]'.

          X:= Xlist[i][d];
          image:= X.perm[1];
          value:= X.diag[ image ];
          for j in [ 2 .. p ] do

            image:= X.perm[ image ];
            value:= X.diag[ image ] + value;
            # now `image = X^j.perm[1]', `value = X^j.diag[ image ]'

          od;

          # Subtract this from $F(g_i^p).diag[k]$;
          # note that `image' is the image of 1 under `X^p', so also
          # under $F(g_i^p)$.
          value:= - value;
          image:= 1;
          for j in poli do
            image:= rep[j].perm[ image ];
            value:= rep[j].diag[ image ] + value;
          od;

          value:= ( value / p ) mod e;
#T enlarge the exponent if necessary!

          Dpos2[d]:= Length( nextnonlin2 ) + 1;

          # Compute the `p' extensions.
          for k in roots do
            Add( nextnonlin2, Concatenation(
                    [ rec( perm := X.perm,
                      diag := List( X.diag,
                             x -> ( x  + k + value ) mod e ) ) ], rep ) );
            Assert( 2, BaumClausenInfoDebug.testrep( pcgs{ [ i .. lg ] },
                                Last(nextnonlin2), e ),
                    Concatenation( "BaumClausenInfo: failed assertion in ",
                        "extending nonlinear representations ",
                        "(i = ", String( i ), ")\n" ) );
          od;

        else

          # `$F$ = nonlin[d]' fuses with `p-1' partners given by the orbit
          # of `d' under `pinonlin[i]'.
          # The new irreducible representation of $G_i$ will be
          # $X Ind( F ) X^{-1}$ with $X$ the block diagonal matrix
          # consisting of blocks $X_{i,F}^{(k)}$ defined by
          # $X_{i,F}^{(0)} = Id$,
          # and $X_{i,F}^{(k)} = X_{i,\pi_i^{k-1} F} X_{i,F}^{(k-1)}$
          # for $k > 0$.

          # The matrix for $g_i$ in the induced representation $Ind( F )$ is
          # of the form
          #       | 0   F(g_i^p) |
          #       | I      0     |
          # Thus $X Ind(F) X^{-1} ( g_i )$ is the block diagonal matrix
          # consisting of the blocks
          # $X_{i,F}, X_{i,\pi_i F}, \ldots, X_{i,\pi_i^{p-2} F}$, and
          # $F(g_i^p) \cdot ( X_{i,F}^{(p-1)} )^{-1}$.

          dim:= Length( rep[1].diag );
          Dpos2[d]:= Length( nextnonlin2 ) + 1;

          # We make a copy of `rep' because we want to change it.
          D:= List( rep, record -> rec( perm := ShallowCopy( record.perm ),
                                        diag := ShallowCopy( record.diag )
                                       ) );

          # matrices for $g_j, i\< j \leq n$
          pos:= d;
          for j in [ 1 .. p-1 ] * dim do
            pos:= pinonlin[i][ pos ];
            for k in [ 1 .. Length( rep ) ] do
              Append( D[k].diag, nonlin[ pos ][k].diag );
              Append( D[k].perm, nonlin[ pos ][k].perm + j );
            od;

            used[ pos ]:= true;
            Dpos2[ pos ]:= Length( nextnonlin2 ) + 1;

          od;

          # The matrix of $g_i$ is a block-cycle with blocks
          # $X_{i,\pi_i^k(F)}$ for $0 \leq k \leq p-2$,
          # and $F(g_i^p) \cdot (X_{i,F}^{(p-1)})^{-1}$.

          X:= Xlist[i][d];      # $X_{i,F}$
          pos:= d;
          for j in [ 1 .. p-2 ] do
            pos:= pinonlin[i][ pos ];
            X:= mulmoma( Xlist[i][ pos ], X );
          od;

          # `invX' is the inverse of `X'.
          invX:= rec( perm := [], diag := [] );
          for j in [ 1 .. Length( X.diag ) ] do
            invX.perm[ X.perm[j] ]:= j;
            invX.diag[j]:= e - X.diag[ X.perm[j] ];
          od;
#T improve this using the {} operator!

          X:= mulmoma( poweval( rep, poli ), invX );
          D_gi:= rec( perm:= List( X.perm, x -> x  + ( p-1 ) * dim ),
                      diag:= [] );

          pos:= d;
          for j in [ 0 .. p-2 ] * dim do

            # $X_{i,\pi_i^j F}$
            Append( D_gi.diag, Xlist[i][ pos ].diag);
            Append( D_gi.perm, Xlist[i][ pos ].perm + j);
            pos:= pinonlin[i][ pos ];

          od;

          Append( D_gi.diag, X.diag );

          Add( nextnonlin2, Concatenation( [ D_gi ], D ) );
          Assert( 2, BaumClausenInfoDebug.testrep( pcgs{ [ i .. lg ] },
                              Last(nextnonlin2), e ),
                  Concatenation( "BaumClausenInfo: failed assertion in ",
                      "inducing nonlinear representations ",
                      "(i = ", String( i ), ")\n" ) );

        fi;

        d:= Position( used, false, d );

      od;


      # Step C:
      # Compute `pilinear', `pinonlin', and `Xlist'.

      pinextlinear  := [];
      pinextnonlin1 := [];
      nextXlist1    := [];

      pinextnonlin2 := [];
      nextXlist2    := [];

      for j in [ 1 .. i-1 ] do

        pinextlinear[j]  := [];
        pinextnonlin1[j] := [];
        nextXlist1[j]    := [];

        # `cexp' describes $g_i^{g_j}$.
        cexp:= ExponentsOfPcElement( pcgs, pcgs[i]^pcgs[j], [ i .. lg ] );

        # Compute `pilinear', and the parts of `pinonlin', `Xlist'
        # arising from *linear* representations for the next step,
        # that is, compute the action of $g_j$ on `nextlinear' and
        # `nextnonlin1'.

        for k in [ 1 .. Length( linear ) ] do

          if pilinear[i][k] = k then

            # Let $F = `linear[k]'$ extend to
            # $D = D_0, D_1, \ldots, D_{p-1}$,
            # $C$ the first extension of $\pi_j(F)$.
            # We have $D( g_i^{g_j} ) = D^{g_j}(g_i) = ( C \chi^l )(g_i)$
            # where $\chi^l(g_i)$ is the $l$-th power of the chosen
            # primitive $p$-th root of unity.

            D:= nextlinear[ Dpos1[k] ];

            # `pos' is the position of $C$ in `nextlinear'.
            pos:= Dpos1[ pilinear[j][k] ];
            l:= ( (  cexp * D                   # $D( g_i^{g_j} )$
                     - nextlinear[ pos ][1] )   # $C(g_i)$
                  * p / e ) mod p;

            for u in [ 0 .. p-1 ] do
              Add( pinextlinear[j], pos + ( ( l + u * cexp[1] ) mod p ) );
            od;

          elif not IsBound( pinextnonlin1[j][ Dpos1[k] ] ) then

            # $F$ fuses with its conjugates under $g_i$,
            # the conjugating matrix describing the action of $g_j$
            # is a permutation matrix.
            # Let $D = F^{g_j}$, then the permutation corresponds to
            # the mapping between the lists
            # $[ D, (F^{g_i})^{g_j}, \ldots, (F^{g_i^{p-1}})^{g_j} ]$
            # and $[ D, D^{g_i}, \ldots, D^{g_i^{p-1}} ]$;
            # The constituents in the first list are the images of
            # the induced representation of $F$ under $g_j$,
            # and those in the second list are the constituents of the
            # induced representation of $D$.

            # While `u' runs from $1$ to $p$,
            # `pos' runs over the positions of $(F^{g_i^u})^{g_j}$ in
            # `linear'.
            # `orb' is the list of positions of the $(F^{g_j})^{g_i^u}$,
            # cyclically permuted such that the smallest entry is the
            # first.

            pinextnonlin1[j][ Dpos1[k] ]:= Dpos1[ pilinear[j][k] ];
            pos:= pilinear[j][k];
            orb:= [ pos ];
            min:= 1;
            minval:= pos;
            for u in [ 2 .. p ] do
              pos:= pilinear[i][ pos ];
              orb[u]:= pos;
              if pos < minval then
                minval:= pos;
                min:= u;
              fi;
            od;
            if 1 < min then
              orb:= Concatenation( orb{ [ min .. p ] },
                                   orb{ [ 1 .. min-1 ] } );
            fi;

            # Compute the conjugating matrix `X'.
            # Let $C$ be the stored representation $\tau_j D$
            # equivalent to $D^{g_j}$.
            # Compute the position of $C$ in `pinextnonlin1'.

            C:= nextnonlin1[ pinextnonlin1[j][ Dpos1[k] ] ];
            D:= nextnonlin1[ Dpos1[k] ];

            # `sigma' is the bijection of constituents in the restrictions
            # of $D$ and $\tau_j D$ to $G_{i-1}$.
            # More precisely, $\pi_j(\pi_i^{u-1} F) = \Phi_{\sigma(u-1)}$.
            sigma:= [];
            pos:= k;
            for u in [ 1 .. p ] do
              sigma[u]:= Position( orb, pilinear[j][ pos ] );
              pos:= pilinear[i][ pos ];
            od;

            # Compute $\pi = \sigma^{-1} (1,2,\ldots,p) \sigma$.
            pi:= [];
            pi[ sigma[p] ]:= sigma[1];
            for u in [ 1 .. p-1 ] do
              pi[ sigma[u] ]:= sigma[ u+1 ];
            od;

            # Compute the values $c_{\pi^u(0)}$, for $0 \leq u \leq p-1$.
            # Note that $c_0 = 1$.
            # (Here we encode of course the exponents.)
            constants:= [ 0 ];
            l:= 1;

            for u in [ 1 .. p-1 ] do

              # Compute $c_{\pi^u(0)}$.
              # (We have $`l' = 1 + \pi^{u-1}(0)$.)
              # Note that $B_u = [ [ 1 ] ]$ for $0\leq u\leq p-2$,
              # and $B_{p-1} = \Phi_0(g_i^p)$.

              # Next we compute the image under $A_{\pi^{u-1}(0)}$;
              # this matrix is in the $(\pi^{u-1}(0)+1)$-th column block
              # and in the $(\pi^u(0)+1)$-th row block of $D^{g_j}$.
              # Since we do not have this matrix explicitly,
              # we use the conjugate representation and the action
              # encoded by `cexp'.
              # Note the necessary initial shift because we use the
              # whole representation $D$ and not a single constituent;
              # so we shift by $\pi^u(0)+1$.
#T `perm' is nontrivial only for v = 1, this should make life easier.
              value:= 0;
              image:= pi[l];
              for v in [ 1 .. lg-i+1 ] do
                for w in [ 1 .. cexp[v] ] do
                  image:= D[v].perm[ image ];
                  value:= value + D[v].diag[ image ];
                od;
              od;

              # Next we divide by the corresponding value in
              # the image of the first standard basis vector under
              # $B_{\sigma\pi^{u-1}(0)}$.
              value:= value - C[1].diag[ sigma[l] ];
              constants[ pi[l] ]:= ( constants[l] - value ) mod e;
              l:= pi[l];

            od;

            # Put the conjugating matrix together.
            X:= rec( perm := [],
                     diag := constants );
            for u in [ 1 .. p ] do
              X.perm[ sigma[u] ]:= u;
            od;

            Assert( 2, BaumClausenInfoDebug.checkconj( pcgs, i, lg, j,
                         nextnonlin1[ Dpos1[k] ],
                         nextnonlin1[ pinextnonlin1[j][ Dpos1[k] ] ],
                         X, e ),
                  Concatenation( "BaumClausenInfo: failed assertion on ",
                      "conjugating matrices for linear repres. ",
                      "(i = ", String( i ), ")\n" ) );
            nextXlist1[j][ Dpos1[k] ]:= X;

          fi;

        od;


        # Compute the remaining parts of `pinonlin' and `Xlist' for
        # the next step, namely for those *nonlinear* representations
        # arising from *nonlinear* ones.

        nextXlist2[j]    := [];
        pinextnonlin2[j] := [];

        # `cexp' describes $g_i^{g_j}$.
        cexp:= ExponentsOfPcElement( pcgs, pcgs[i]^pcgs[j], [ i .. lg ] );

        # Compute the action of $g_j$ on `nextnonlin2'.

        for k in [ 1 .. Length( nonlin ) ] do

          if pinonlin[i][k] = k then

            # Let $F = `nonlin[k]'$ extend to
            # $D = D_0, D_1, \ldots, D_{p-1}$,
            # $C$ the first extension of $\pi_j(F)$.
            # We have $X_{j,F} \cdot F^{g_j} = \pi_j(F) \cdot X_{j,F}$,
            # thus $X_{j,F} \cdot D( g_i^{g_j} )
            # = X_{j,F} \cdot D^{g_j}(g_i)
            # = ( C \chi^l )(g_i) \cdot X_{j,F}$
            # where $\chi^l(g_i)$ is the $l$-th power of the chosen
            # primitive $p$-th root of unity.

            D:= nextnonlin2[ Dpos2[k] ];

            # `pos' is the position of $C$ in `nextnonlin2'.
            pos:= Dpos2[ pinonlin[j][k] ];

            # Find a nonzero entry in $X_{j,F} \cdot D( g_i^{g_j} )$.
            image:= Xlist[j][k].perm[1];
            value:= Xlist[j][k].diag[ image ];
            for u in [ 1 .. lg-i+1 ] do
              for v in [ 1 .. cexp[u] ] do
                image:= D[u].perm[ image ];
                value:= value + D[u].diag[ image ];
              od;
            od;

            # Subtract the corresponding value in $C(g_i) \cdot X_{j,F}$.
            C:= nextnonlin2[ pos ];
            Assert( 2, image = Xlist[j][k].perm[ C[1].perm[1] ],
                    "BaumClausenInfo: failed assertion on conj. matrices" );
            value:= value -
                ( C[1].diag[ C[1].perm[1] ] + Xlist[j][k].diag[ image ] );
            l:= ( value * p / e ) mod p;

            for u in [ 0 .. p-1 ] do
              pinextnonlin2[j][ Dpos2[k] + u ]:=
                     pos + ( ( l + u * cexp[1] ) mod p );
              nextXlist2[j][ Dpos2[k] + u ]:= Xlist[j][k];
            od;

            Assert( 2, BaumClausenInfoDebug.checkconj( pcgs, i, lg, j,
                         nextnonlin2[ Dpos2[k] ],
                         nextnonlin2[ pinextnonlin2[j][ Dpos2[k] ] ],
                         Xlist[j][k], e ),
                  Concatenation( "BaumClausenInfo: failed assertion on ",
                      "conjugating matrices for nonlinear repres. ",
                      "(i = ", String( i ), ")\n" ) );

          elif not IsBound( pinextnonlin2[j][ Dpos2[k] ] ) then

            # $F$ fuses with its conjugates under $g_i$, yielding $D$.

            dim:= Length( nonlin[k][1].diag );

            # Let $C$ be the stored representation $\tau_j D$
            # equivalent to $D^{g_j}$.
            # Compute the position of $C$ in `pinextnonlin2'.
            pinextnonlin2[j][ Dpos2[k] ]:= Dpos2[ pinonlin[j][k] ];

            C:= nextnonlin2[ pinextnonlin2[j][ Dpos2[k] ] ];
            D:= nextnonlin2[ Dpos2[k] ];

            # Compute the positions of the constituents;
            # `orb[k]' is the position of $\Phi_{k-1}$ in `nonlin'.
            pos:= pinonlin[j][k];
            orb:= [ pos ];
            min:= 1;
            minval:= pos;
            for u in [ 2 .. p ] do
              pos:= pinonlin[i][ pos ];
              orb[u]:= pos;
              if pos < minval then
                minval:= pos;
                min:= u;
              fi;
            od;
            if 1 < min then
              orb:= Concatenation( orb{ [ min .. p ] },
                                   orb{ [ 1 .. min-1 ] } );
            fi;

            # `sigma' is the bijection of constituents in the restrictions
            # of $D$ and $\tau_j D$ to $G_{i-1}$.
            # More precisely, $\pi_j(\pi_i^{u-1} F) = \Phi_{\sigma(u-1)}$.
            sigma:= [];
            pos:= k;
            for u in [ 1 .. p ] do
              sigma[u]:= Position( orb, pinonlin[j][ pos ] );
              pos:= pinonlin[i][ pos ];
            od;

            # Compute $\pi = \sigma^{-1} (1,2,\ldots,p) \sigma$.
            pi:= [];
            pi[ sigma[p] ]:= sigma[1];
            for u in [ 1 .. p-1 ] do
              pi[ sigma[u] ]:= sigma[ u+1 ];
            od;

            # Compute the positions of the constituents
            # $F_0, F_{\pi(0)}, \ldots, F_{\pi^{p-1}(0)}$.
            Forb:= [ k ];
            pos:= k;
            for u in [ 2 .. p ] do
              pos:= pinonlin[i][ pos ];
              Forb[u]:= pos;
            od;

            # Compute the values $c_{\pi^u(0)}$, for $0 \leq u \leq p-1$.
            # Note that $c_0 = 1$.
            # (Here we encode of course the exponents.)
            constants:= [ 0 ];
            l:= 1;

            for u in [ 1 .. p-1 ] do

              # Compute $c_{\pi^u(0)}$.
              # (We have $`l' = 1 + \pi^{u-1}(0)$.)
              # Note that $B_u = X_{j,\pi_j^u \Phi_0}$ for $0\leq u\leq p-2$,
              # and $B_{p-1} =
              #      \Phi_0(g_i^p) \cdot ( X_{j,\Phi_0}^{(p-1)} )^{-1}$

              # First we get the image and diagonal value of
              # the first standard basis vector under $X_{j,\pi^u(0)}$.
              image:= Xlist[j][ Forb[ pi[l] ] ].perm[1];
              value:= Xlist[j][ Forb[ pi[l] ] ].diag[ image ];

              # Next we compute the image under $A_{\pi^{u-1}(0)}$;
              # this matrix is in the $(\pi^{u-1}(0)+1)$-th column block
              # and in the $(\pi^u(0)+1)$-th row block of $D^{g_j}$.
              # Since we do not have this matrix explicitly,
              # we use the conjugate representation and the action
              # encoded by `cexp'.
              # Note the necessary initial shift because we use the
              # whole representation $D$ and not a single constituent;
              # so we shift by `dim' times $\pi^u(0)+1$.
              image:= dim * ( pi[l] - 1 ) + image;
              for v in [ 1 .. lg-i+1 ] do
                for w in [ 1 .. cexp[v] ] do
                  image:= D[v].perm[ image ];
                  value:= value + D[v].diag[ image ];
                od;
              od;

              # Next we divide by the corresponding value in
              # the image of the first standard basis vector under
              # $B_{\sigma\pi^{u-1}(0)} X_{j,\pi^{u-1}(0)}$.
              # Note that $B_v$ is in the $(v+2)$-th row block for
              # $0 \leq v \leq p-2$, in the first row block for $v = p-1$,
              # and in the $(v+1)$-th column block of $C$.
              v:= sigma[l];
              if v = p then
                image:= C[1].perm[1];
              else
                image:= C[1].perm[ v*dim + 1 ];
              fi;
              value:= value - C[1].diag[ image ];
              image:= Xlist[j][ Forb[l] ].perm[ image - ( v - 1 ) * dim ];
              value:= value - Xlist[j][ Forb[l] ].diag[ image ];
              constants[ pi[l] ]:= ( constants[l] - value ) mod e;
              l:= pi[l];

            od;

            # Put the conjugating matrix together.
            X:= rec( perm:= [],
                     diag:= [] );
            pos:= k;
            for u in [ 1 .. p ] do
              Append( X.diag, List( Xlist[j][ pos ].diag,
                                    x -> ( x + constants[u] ) mod e ) );
              X.perm{ [ ( sigma[u] - 1 )*dim+1 .. sigma[u]*dim ] }:=
                  Xlist[j][ pos ].perm + (u-1) * dim;
              pos:= pinonlin[i][ pos ];
            od;

            Assert( 2, BaumClausenInfoDebug.checkconj( pcgs, i, lg, j,
                         nextnonlin2[ Dpos2[k] ],
                         nextnonlin2[ pinextnonlin2[j][ Dpos2[k] ] ],
                         X, e ),
                  Concatenation( "BaumClausenInfo: failed assertion on ",
                      "conjugating matrices for nonlinear repres. ",
                      "(i = ", String( i ), ")\n" ) );
            nextXlist2[j][ Dpos2[k] ]:= X;

          fi;

        od;

      od;

      # Finish the update for the next index.
      linear   := nextlinear;
      pilinear := pinextlinear;

      nonlin   := Concatenation( nextnonlin1, nextnonlin2 );
      pinonlin := List( [ 1 .. i-1 ],
                       j -> Concatenation( pinextnonlin1[j],
                         pinextnonlin2[j] + Length( pinextnonlin1[j] ) ) );
      Xlist    := List( [ 1 .. i-1 ],
                    j -> Concatenation( nextXlist1[j], nextXlist2[j] ) );

    od;


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

--> maximum size reached

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

[ Dauer der Verarbeitung: 0.71 Sekunden  (vorverarbeitet)  ]