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


SSL ctblgrp.gi   Interaktion und
Portierbarkeitunbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Alexander Hulpke.
##
##  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 the implementation of the Dixon-Schneider algorithm
##


#############################################################################
##
#V  USECTPGROUP . . . . . . . . . . indicates,whether CharTablePGroup should
##                                  always be called
USECTPGROUP := false;


#############################################################################
##
#V  DXLARGEGROUPORDER
##
##  If a group is small,we may use enumerations of the elements to speed up
##  the computations. The criterion is the size, compared to the global
##  variable DXLARGEGROUPORDER.
##
if not IsBound(DXLARGEGROUPORDER) then
  DXLARGEGROUPORDER:=10000;
fi;

InstallGlobalFunction( IsDxLargeGroup, G -> Size(G) > DXLARGEGROUPORDER );


#############################################################################
##
#F  ClassComparison(<c>,<d>)  . . . . . . . . . . . . compare classes c and d
##
##  comparison is based first on the size of the class and afterwards on the
##  order of the representatives. Thus the 1-Class is in the first position,
##  as required. Since sorting is primary by the class sizes,smaller
##  classes are in earlier positions,making the active columns those to
##  smaller classes,reducing the work for calculating class matrices!
##  Additionally galois conjugated classes are together,thus increasing the
##  chance,that with one columns of them active to be several acitive,
##  reducing computation time !
##
InstallGlobalFunction( ClassComparison, function(c,d)
  if Size(c)=Size(d) then
    return Order(Representative(c))<Order(Representative(d));
  else
    return Size(c)<Size(d);
  fi;
end );


#############################################################################
##
#M  DixonRecord(<G>) . . . . . . . . . .  generic
##
InstallMethod(DixonRecord,"generic",true,[IsGroup],0,
function(G)
local D,C,cl,pl;
  D:=rec(
          group:=G,# workgroup
          deg:=Size(G),
          size:=Size(G),
          # when do we consider a class as large, so we might do something
          # special?
          classlimit:=10^6,
          calculatedMats:=[],
          yetmats:=[],
          modulars:=[]
        );

  # Do not leave the computation of power maps to 'CharacterTable',
  # since here we are in a better situation (use inverse map,use
  # class identification,use the fact that all power maps for primes
  # up to the maximal element order are computed).
  C:=CharacterTable(G);

  # Store the conjugacy classes compatibly with other information
  # about the character table.
  D.classes:= ConjugacyClasses( C );
  cl:=ShallowCopy(D.classes);
  D.classreps:=List(cl,Representative);
  D.centfachom:=[];
  D.klanz:=Length(cl);
  D.classrange:=[1..D.klanz];
  Info(InfoCharacterTable,1,D.klanz," classes");

  # compute the permutation we apply to the classes
  pl:=[1..D.klanz];
  SortParallel(cl,pl,ClassComparison);
  D.perm:=PermList(pl);
  D.permlist:=pl;
  D.invpermlist:=ListPerm(D.perm^-1,Length(D.permlist));
  D.currentInverseClassNo:=0;

  D.characterTable:=C;
  D.classiz:=SizesConjugacyClasses(C);
  D.centralizers:=SizesCentralizers(C);
  D.orders:=OrdersClassRepresentatives(C);

  IsAbelian(G); # force computation
  DxPreparation(G,D);

  return D;
end);

#############################################################################
##
#F  DxCalcAllPowerMaps(<D>) . . . . . . . calculate power maps for char.table
##
BindGlobal( "DxCalcAllPowerMaps", function(D)
local p,primes,i,cl,spr,j,allpowermaps,pm,ex;

  # compute the inverse classes
  p:=[1];
  for i in [2..D.klanz] do
    p[i]:=D.ClassElement(D,D.classreps[i]^-1);
  od;
  SetInverseClasses(D.characterTable,p);
  D.inversemap:=p;

  allpowermaps:=ComputedPowerMaps(D.characterTable);
  allpowermaps[1]:= Immutable( D.classrange );
  D.powermap:=allpowermaps;

  # get all primes smaller than the largest element order
  primes:=[];
  p:=2;
  pm:=Maximum(D.orders);
  while p<=pm do
    Add(primes,p);
    p:=NextPrimeInt(p);
  od;

  for p in primes do
    if not IsBound( allpowermaps[p] ) then
      allpowermaps[p]:=List(D.classrange,i->ShallowCopy(D.classrange));
      allpowermaps[p][1]:=1;
    fi;
  od;

  for p in primes do
#T ConsiderSmallerPowermaps?
# eventuell,bei kleinen Gruppen kostet das aber zu viel. Hier ist es
# vermutlich sinnvoller erst von Hand anzufangen.
    spr:=Filtered(primes,i->i<p);
    pm:=allpowermaps[p];

    # First try to compute cheap images.
    for i in D.classrange do
      if IsList(pm[i]) and Length(pm[i])=1 then
        pm[i]:=pm[i][1];
      fi;

      if not IsInt(pm[i]) then
        cl:=i;
        ex:=p mod D.orders[i];
if ex=0 then
  pm[i]:=1;
else
        if ex>D.orders[i]/2 then
          # can we get it cheaper via the inverse
          ex:=AbsInt(D.orders[i]-ex);
          cl:=D.inversemap[i];
        fi;
        if ex<p or (ex=p and IsInt(pm[cl])) then
          # compose the ex-th power
          j:=Factors(ex);
          while Length(j)>0 do
            cl:=allpowermaps[j[1]][cl];
            j:=j{[2..Length(j)]};
          od;
          pm[i]:=cl;
        fi;
fi;
      fi;
    od;

    # Do the hard computations.
    for i in Reversed(D.classrange) do
      if not IsInt(pm[i]) then
          pm[i]:=D.ClassElement(D,D.classreps[i]^(p mod D.orders[i]));
#T TestConsistencyMaps (local improvement!) after each calculation?
        # note following powers: (x^a)^b=(x^b)^a
        for j in spr do
          cl:=allpowermaps[j][i];
          if not IsInt(pm[cl]) then
            pm[cl]:=allpowermaps[j][pm[i]];
          fi;
        od;
      fi;
    od;

    MakeImmutable( pm );
  od;
end );


#############################################################################
##
#F  ComputeAllPowerMaps( <tbl> )
##
##  Computing all power maps is cheaper than successively computing some
##  values of individual power maps.
##  The current code is a hack.
##  (Apparently 'DxCalcAllPowerMaps' is much faster than other available
##  functions.)
##  It should be improved as soon as we have a general tool for the
##  identification of conjugacy classes.
##
BindGlobal( "ComputeAllPowerMaps", function( tbl )
  tbl:= UnderlyingGroup( tbl );
  if not HasDixonRecord( tbl ) then
    DxCalcAllPowerMaps( DixonRecord( tbl ) );
  fi;
end );


#############################################################################
##
#F  DxCalcPrimeClasses(<D>)
##
##  Compute primary classes of the group $G$,that is,every class of $G$
##  is the power of one of these classes.
##  'DxCalcPrimeClasses(<D>)' returns a list,each entry being a list whose
##  $i$-th entry is the $i$-th power of a primary class.
##
##  It is assumed that the power maps for all primes up to the maximal
##  representative order of $G$ are known.
##
BindGlobal( "DxCalcPrimeClasses", function(D)
local primeClasses,
      classes,
      i,
      j,
      class,
      p;

  primeClasses:=[];
  classes:=[1..D.klanz];
  for i in Reversed(classes) do
    primeClasses[i]:=[];
    if IsBound(classes[i]) then
      class:=i;
      j:=1;
      while 1<class do
        if class<>i then
          Unbind(classes[class]);
        fi;
        primeClasses[i][j]:=class;
        j:=j+1;
        class:=i;
        for p in Factors(j) do
          class:=D.powermap[p][class];
        od;
      od;
    fi;
  od;
  D.primeClasses:=[];
  for i in classes do
    Add(D.primeClasses,primeClasses[i]);
  od;
  D.primeClasses[1]:=[1];

end );

#############################################################################
##
#F  DxIsInSpace(v,space)
##
BindGlobal( "DxIsInSpace", function(v,r)
  return SolutionMat(Matrix(BaseDomain(r.base[1]),r.base),v)<>fail;
end );

#############################################################################
##
#F  DxNiceBasis(D,space) . . . . . . . . . . . . . nice basis of space record
##
BindGlobal( "DxNiceBasis", function(d,r)
local b;
  if not IsBound(r.niceBasis) then
    b:=Matrix(BaseDomain(r.base[1]),List(r.base,i->i{d.permlist})); # copied and permuted according to order
    TriangulizeMat(b);
    b:=List(b,i->i{d.invpermlist}); # permuted back
    r.niceBasis:=Immutable(b);
  fi;
  Assert(1,Length(r.niceBasis)=Length(r.base));
  return r.niceBasis;
end );

#############################################################################
##
#F  DxActiveCols(D,<space|base>)  . . . . . . active columns of space or base
##
BindGlobal( "DxActiveCols", function(D,raum)
local base,activeCols,j,n,l;
  activeCols:=[];
  if IsRecord(raum) then
    n:=Zero(D.field);
    if IsBound(raum.activeCols) then
      return raum.activeCols;
    fi;
    base:=DxNiceBasis(D,raum);
  else
    n:=Zero(D.field);
    base:=DxNiceBasis(D,rec(base:=raum));
  fi;
  l:=1;
  # find columns in order as given in pl as active
  for j in [1..Length(base)] do
    while base[j][D.permlist[l]]=n do
      l:=l+1;
    od;
    Add(activeCols,D.permlist[l]);
  od;
  if IsRecord(raum) then
    raum.activeCols:=activeCols;
  fi;
  return activeCols;
end );


#############################################################################
##
#F  DxRegisterModularChar(<D>,<c>)  . . . . .  note newly found irreducible
#F                                                     character modulo prime
##
BindGlobal( "DxRegisterModularChar", function(D,c)
local d,p;
  # it may happen,that an irreducible character will be registered twice:
  # 2-dim space,1 Orbit,combinatoric split. Avoid this!
  if IsPlistRep(c) then c:=Vector(c); fi;
  if not(c in D.modulars) then
    Add(D.modulars,c);
    d:=Int(c[1]);
    D.deg:=D.deg-d^2;
    D.num:=D.num-1;
    p:=1;
    while p<=Length(D.degreePool) do
      if D.degreePool[p][1]=d then
        D.degreePool[p][2]:=D.degreePool[p][2]-1;
        # filter still possible character degrees:
        p:=1;
        d:=1;
        # determinate smallest possible degree (nonlinear)
        while p<=Length(D.degreePool) and d=1 do
          if D.degreePool[p][2]>1 then
            d:=D.degreePool[p][1];
          fi;
          p:=p+1;
        od;
        # degreeBound
        d:=RootInt(D.deg-(D.num-1)*d);
        D.degreePool:=Filtered(D.degreePool,i->i[2]>0 and i[1]<=d);
        p:=Length(D.degreePool)+1;
      fi;
      p:=p+1;
    od;
  fi;
end );

#############################################################################
##
#F  DxIncludeIrreducibles(<D>,<new>,[<newmod>]) . . . . handle (newly?) found
#F                                                               irreducibles
##
##  This routine will do all handling,whenever characters have been found
##  by other means,than the Dixon/Schneider algorithm. First the routine
##  checks,which characters are not new (this allows one to include huge bulks
##  of irreducibles got by tensoring). Then the characters are closed under
##  images of the CharacterMorphisms. Afterwards the character spaces are
##  stripped of the new characters,the characters are included as
##  irreducibles and possible degrees etc. are corrected. If the modular
##  images of the irreducibles are known, they may be given in newmod.
##
InstallGlobalFunction( DxIncludeIrreducibles, function(arg)
local i,pcomp,m,r,D,neue,tm,news,opt;

  D:=arg[1];
  opt:=ValueOption("noproject");
  # force computation of all images under $\cal T$. We will need this
  # (among others),to be sure,that we can keep the stabilizers
  neue:=arg[2];
  if Length(neue) = 0 then return; fi;

  if IsBound(D.characterMorphisms) then
    tm:=D.characterMorphisms;
    news:=Union(List(neue,i->Orbit(tm,i,D.asCharacterMorphism)));
    if Length(news)>Length(neue) then
      Info(InfoCharacterTable,1,"new Characters by character morphisms found");
    fi;
    neue:=news;
  fi;
  neue:=Difference(neue,D.irreducibles);
  D.irreducibles:=Concatenation(D.irreducibles,neue);
  if Length(arg)=3 then
    m:=Difference(arg[3],D.modulars);
    if IsBound(D.characterMorphisms) then
      m:=Union(List(m,i->Orbit(tm,i,D.asCharacterMorphism)));
    fi;
  else
    m:=List(neue,i->List(i,D.modularMap));
  fi;
  for i in m do
    DxRegisterModularChar(D,i);
  od;

  if opt<>true then
    pcomp:=NullspaceMat(D.projectionMat*TransposedMatImmutable(Matrix(D.field,D.modulars)));
    if Length(pcomp)>0 then
      for i in [1..Length(D.raeume)] do
        r:=D.raeume[i];
        if r.dim = Length(r.base[1]) then
          # trivial case: Intersection with full space in the beginning
          r:=rec(base:=pcomp);
        else
          r:=rec(base:=SumIntersectionMat(pcomp,
            Matrix(BaseDomain(r.base[1]),r.base))[2]);
        fi;
        r.dim:=Length(r.base);
        # note stabilizer
        if IsBound(D.raeume[i].stabilizer) then
          r.stabilizer:=D.raeume[i].stabilizer;
        fi;
        if r.dim>0 then
          DxActiveCols(D,r);
        fi;
        D.raeume[i]:=r;
      od;
    fi;
  fi;
  D.raeume:=Filtered(D.raeume,i->i.dim>0);
end );


#############################################################################
##
#F  DxLinearCharacters(<D>) . . . .   calculate characters of G of degree 1
##
##  These characters are computed as characters of G/G'. This can be done
##  easily by using the fact,that an abelian group is direct product of
##  cyclic groups. Thus we get the characters as "direct products" of the
##  characters of cyclic groups,which can be easily computed. They are
##  lifted afterwards back to G.
##
BindGlobal( "DxLinearCharacters", function(D)
local H,T,c,a,e,f,i,j,k,l,m,p,ch,el,ur,s,hom,gens,onc,G;
  G:=D.group;
  onc:=List([1..D.klanz],i->1);
  D.trivialCharacter:=onc;
  H:=DerivedSubgroup(G);
  hom:=NaturalHomomorphismByNormalSubgroup(G,H);
  H:=Image(hom,G);
  e:=ShallowCopy(AsList(H));
  s:=Length(e); # Size(H)
  if s=1 then # perfekter Fall
    D.tensorMorphisms:=rec(a:=[],
                           c:=[],
                           els:=[[[],onc]]);
    return [onc];
  else
    a:=Reversed(AbelianInvariants(H));
    gens:=[];
    T:=Subgroup(H,gens);
    for i in a do
      # was: m:=First(e,el->Order(el)=i);
      m:=First(e,
          el->Order(el)=i and ForAll([2..Order(el)-1],i->el^i in e));
      T:=ClosureGroup(T,m);
      e:=Difference(e,AsList(T));
      Add(gens,m);
    od;
    e:=AsList(H);
    f:=List(e,i->[]);
    for i in [1..D.klanz] do # create classimages
      Add(f[Position(e,Image(hom,D.classreps[i]))],i);
   od;

    m:=Length(a);
    c:=List([1..m],i->[]);
    i:=m;
    # run through all Elements of H by trying every combination of the
    # generators
    p:=List([1..m],i->0);
    while i>0 do
      el:=One(H); # Element berechnen
      for j in [1..m] do
        el:=el*gens[j]^p[j];
      od;
      ur:=f[Position(e,el)];
      for j in [1..m] do # all character values for this element
        ch:=E(a[j])^p[j];
        for l in ur do
          c[j][l]:=ch;
        od;
      od;
      while (i>0) and (p[i]=a[i]-1) do
        p[i]:=0;
        i:=i-1;
      od;
      if i>0 then
        p[i]:=p[i]+1;
        i:=m;
      fi;
    od;

    ch:=[];
    i:=m;
    p:=List([1..m],i->0);
    while i>0 do
      # construct tensor product systematically
      el:=ShallowCopy(onc);
      for j in [1..m] do
        for k in [1..D.klanz] do
          el[k]:=el[k]*c[j][k]^p[j];
        od;
      od;
      Add(ch,[ShallowCopy(p),el]);
      while (i>0) and (p[i]=a[i]-1) do
        p[i]:=0;
        i:=i-1;
      od;
      if i>0 then
        p[i]:=p[i]+1;
        i:=m;
      fi;
    od;
    D.tensorMorphisms:=rec(a:=a,
                           c:=c,
                           els:=ch);

    ch:=List(ch,i->i[2]);
    return ch;
  fi;
end );


#############################################################################
##
#F  DxLiftCharacter(<D>,<modChi>) . recalculate character in characteristic 0
##
BindGlobal( "DxLiftCharacter", function(D,modular)
local modularchi,chi,zeta,degree,sum,M,l,s,n,j,polynom,chipolynom,
      family,prime;
  prime:=D.prime;
  modularchi:=List(modular,Int);
  degree:=modularchi[1];
  chi:=[degree];
  for family in D.primeClasses do
    # we need to compute the polynomial only for prime classes. Powers are
    # obtained by simply inserting powers in this polynomial
    j:=family[1];
    l:=Order(D.classreps[j]);
    zeta:=E(l);
    polynom:=[degree,modularchi[j]];
    for n in [2..l-1] do
      s:=family[n];
      polynom[n+1]:=modularchi[s];
    od;
    chipolynom:=[];
    s:=0;
    sum:=degree;
    while sum>0 do
      M:=DxModularValuePol(polynom,
                         PowerModInt(D.z,-s*Exponent(D.group)/l,prime),
                         #PowerModInt(D.z,-s*D.irrexp/l,prime),
                         prime)/l mod prime;
      Add(chipolynom,M);
      sum:=sum-M;
      s:=s+1;
    od;
    for n in [1..l-1] do
      s:=family[n];
      if not IsBound(chi[s]) then
        chi[s]:=ValuePol(chipolynom,zeta^n);
      fi;
    od;
  od;
  return chi;
end );


#############################################################################
##
#F  SplitCharacters(<D>,<list>)   split characters according to the spaces
#F   this function can be applied to ordinary characters. It splits them
#F   according to the character spaces yet known. This can be used
#F   interactively to utilize partially computed spaces
##
InstallGlobalFunction( SplitCharacters, function(D,l)
local ml,nu,ret,r,p,v,alo,ofs,orb,i,j,inv,b;
  b:=Filtered(l,i->(i[1]>1) and (i[1]<D.prime/2));
  l:=Difference(l,b);
  ml:=List(b,i->List(i,D.modularMap));
  nu:=List(D.classrange,i->Zero(D.field));
  ret:=[];
  b:=ShallowCopy(D.modulars);
  alo:=Length(b);
  ofs:=[];
  for r in D.raeume do
    # recreate all images
    orb:=Orbit(D.characterMorphisms,r,
      function(raum,el)
      local img;
        img:=D.asCharacterMorphism(raum.base[1],el);
        img:=First(D.raeume,
          function(i)
          local c;
            c:=Concatenation(List(i.base,ShallowCopy),[ShallowCopy(img)]);
            return RankMat(c)=Length(i.base);
          end);
        if img=fail then
          img:=rec(base:=List(raum.base,i->D.asCharacterMorphism(i,el)),
                   dim:=raum.dim);
        fi;
        return img;
      end);
    for i in orb do
      if not IsMutable(i) then
        i:=ShallowCopy(i);
      fi;
      b:=Concatenation(b,DxNiceBasis(D,i));
      Add(ofs,[alo+1..Length(b)]);
      alo:=Length(b);
    od;
  od;
  inv:=Matrix(BaseDomain(b[1]),b)^(-1);
  for i in ml do
    v:=i*inv;
    for r in [1..Length(D.raeume)] do
      p:=ShallowCopy(nu);
      for j in ofs[r] do
        p[j]:=v[j];
      od;
      p:=p*b;
      if not IsZero(p) then
        AddSet(ret,DxLiftCharacter(D,p));
      fi;
    od;
  od;
  return Union(ret,l);
end );


#############################################################################
##
#F  DxEigenbase(<mat>) . . . . . components of Eigenvects resp. base
##
BindGlobal( "DxEigenbase", function(M)
  local dim,i,eigenvalues,base,minpol,bases;

  minpol:=MinimalPolynomial(BaseDomain(M),M);

  Assert(2,IsDuplicateFree(RootsOfUPol(minpol)));
  eigenvalues:=Set(RootsOfUPol(minpol));
  dim:=0;
  bases:=[];
  for i in eigenvalues do
    base:=NullspaceMat(M-i*M^0);
    if base=[] then
      Error("This can`t happen: Wrong Eigenvalue ???");
    else
      dim:=dim+Length(base);
      Add(bases,base);
    fi;
  od;
  if dim<>Length(M) then
    Error("Failed to calculate eigenspaces.");
  fi;

  Assert(3, ForAll([1..Length(bases)],j->bases[j]*M = bases[j]*eigenvalues[j]));
  return rec(base:=bases,
             values:=eigenvalues);
end );


#############################################################################
##
#F  SplitStep(<D>,<bestMat>)  . . . . . .  calculate matrix bestMat as far as
#F                                                    needed and split spaces
##
InstallGlobalFunction(SplitStep,function(D,bestMat)
  local raeume,base,M,bestMatCol,bestMatSplit,i,j,k,N,row,col,Row,o,dim,
        newRaeume,raum,ra,f,activeCols,eigenbase,eigen,v,vo,partial;

  if not bestMat in D.matrices then
    Error("matrix <bestMat> not indicated for splitting");
  fi;

  k:=D.klanz;

  f:=D.field;
  o:=D.one;
  raeume:=D.raeume;

  if ForAny(raeume,i->i.dim>1) then
    bestMatCol:=D.requiredCols[bestMat];
    bestMatSplit:=D.splitBases[bestMat];
    M:= ZeroMatrix(Integers,k,k);

    Info(InfoCharacterTable,1,"Matrix ",bestMat,",Representative of Order ",
       Order(D.classreps[bestMat]),
       ",Centralizer: ",D.centralizers[bestMat]);
    Info(InfoCharacterTable,2,"Splitting Nr.s",bestMatSplit,
      "of dimensions ",List(D.raeume{bestMatSplit},x->x.dim));

    partial:=false;
    if D.classiz[bestMat]>D.classlimit then
      Info(InfoWarning,1,"computing class matrix for class of size >",
        D.classlimit);
      if Length(bestMatSplit)>1 then
        i:=List(bestMatSplit,x->D.raeume[x].dim);
        i:=bestMatSplit[Position(i,Minimum(i))];
        bestMatSplit:=[i];
        bestMatCol:=Set(D.raeume[i].activeCols);
        if not IsBound(D.calculatedMats[bestMat]) then
          D.calculatedMats[bestMat]:=
            List([1..k],x->ListWithIdenticalEntries(k,0));
        fi;
        # need and known
        col:=Union(bestMatCol,Filtered([1..k],num->ForAny([1..k],
          x->not IsZero(D.calculatedMats[bestMat][x][num]))));
        # do we get other spaces for free ?
        i:=Filtered(D.splitBases[bestMat],
          x->IsSubset(col,D.raeume[x].activeCols));
        if i<>bestMatSplit then
          bestMatSplit:=Union(i,bestMatSplit);
          bestMatCol:=Union(List(bestMatSplit,x->D.raeume[x].activeCols));
        fi;

        Info(InfoCharacterTable,1,"Partial:",bestMatSplit);
        partial:=true;
      fi;
    fi;

    if not partial then
      Add(D.yetmats,bestMat);
      SubtractSet(D.matrices,[bestMat]);
    fi;
    Info(InfoCharacterTable,2,"Columns: ",bestMatCol);

    for col in bestMatCol do
      if IsBound(D.calculatedMats[bestMat]) and
        ForAny([1..k],x->not IsZero(D.calculatedMats[bestMat][x][col])) then
        Info(InfoCharacterTable,2,"Re-using cached column ",col);
        for i in [1..k] do
          M[i][col]:=D.calculatedMats[bestMat][i][col];
        od;
      else
        D.ClassMatrixColumn(D,M,bestMat,col);
        if partial then
          for i in [1..k] do
            D.calculatedMats[bestMat][i][col]:=M[i][col];
          od;
        fi;
      fi;
    od;

    M:=Matrix(D.field,Unpack(M)*o);

    # note,that we will have calculated yet one!
    D.maycent:=true;

    newRaeume:=[];
    for i in bestMatSplit do
      raum:=raeume[i];
      base:=DxNiceBasis(D,raum);
      dim:=raum.dim;
      # cut out the 'active part' for computation of an eigenbase
      activeCols:=DxActiveCols(D,raum);
      N:= ZeroMatrix(f,dim,dim);
      for row in [1..dim] do
        #Row:=base[row]*M;
        Row:=CompatibleVector(M);
        for col in [1..Length(Row)] do
          Row[col]:=base[row,col];
        od;
        Row:=Row*M;
        for col in [1..dim] do
          N[row,col]:=Row[activeCols[col]];
        od;
      od;
      eigen:=DxEigenbase(N);
      # Base umrechnen
      base:=Matrix(BaseDomain(base[1]),base);
      eigenbase:=List(eigen.base,i->List(i,j->j*base));

      Assert(1,Length(eigenbase)>1);

      ra:=List(eigenbase,i->rec(base:=i,dim:=Length(i)));

      # throw away Galois-images
      for i in [1..Length(ra)] do
        if IsBound(ra[i]) then
          vo:=Orbit(raum.stabilizer,ra[i].base[1],
                   D.asCharacterMorphism);
          for v in vo do
            for j in [i+1..Length(ra)] do
              if IsBound(ra[j])

                # ahulpke, 11-jan-00: If we map into a larger space, the
                # extra dimension of the larger space might somehow get
                # lost. Therefore we can't be that tricky as the following
                # argument supposes.
                  # In characteristic p the split may be
                  # not as well,as in characteristic 0. In this
                  # case,we may find a smaller image in another space.
                  # As character morphisms are a group we will also
                  # have the inverse image of the complement, we can
                  # throw away the space without doing harm!
                  # the only ugly disadvantage is,that we will have to
                  # do some more inclusion tests.

                and ra[i].dim=ra[j].dim
                and DxIsInSpace(v,ra[j]) then
                  Unbind(ra[j]);
              fi;
            od;
          od;
        fi;
      od;

      for i in ra do
        # force computation of base
        i.dim:=Length(i.base);
        DxNiceBasis(D,i);
        if IsBound(raum.stabilizer) then
          i.approxStab:=raum.stabilizer;
        fi;
        Add(newRaeume,i);
      od;

    od;
    # add the ones that did not split
    for i in [1..Length(raeume)] do
      if not i in bestMatSplit then
        Add(newRaeume,raeume[i]);
      fi;
    od;
    raeume:=newRaeume;
  fi;

  for i in [1..Length(raeume)] do
    if raeume[i].dim>1 then
      DxActiveCols(D,raeume[i]);
    fi;
  od;

  Info(InfoCharacterTable,1,"Dimensions: ",Collected(List(raeume,i->i.dim)));
  D.raeume:=raeume;
  return true;
end);


#############################################################################
##
#F  CharacterMorphismOrbits(<D>,<space>) . . stabilizer and invariantspace
##
BindGlobal( "CharacterMorphismOrbits", function(D,space)
  local a,b,s,o,gen,b1;
  if not IsBound(space.stabilizer) then
    if IsBound(space.approxStab) then
      a:=space.approxStab;
    else
      a:=D.characterMorphisms;
    fi;
    space.stabilizer:=Stabilizer(a,VectorSpace(D.field,space.base),
                                 D.asCharacterMorphism);
  fi;
  if not IsBound(space.invariantbase) then
    o:=D.one;
    s:=space.stabilizer;
    b:=DxNiceBasis(D,space);
    a:=DxActiveCols(D,space);
    # calculate invariant space as intersection of E.S to E.V. 1
    for gen in GeneratorsOfGroup(s) do
      if Length(b)>0 then
        b1:=NullspaceMat(List(b,i->D.asCharacterMorphism(i,gen){a})
                -IdentityMat(Length(b),o));
        if Length(b1)=0 then
          b:=[];
        else
          b:=b1*b;
        fi;
      fi;
#T cheaper!
      b:=rec(base:=b,dim:=Length(b));
      a:=DxActiveCols(D,b);
      b:=DxNiceBasis(D,b);
    od;
    space.invariantbase:=b;
  fi;
  return rec(invariantbase:=space.invariantbase,
             number:=Length(space.invariantbase),
             stabilizer:=space.stabilizer);
end );



#############################################################################
##
#F  DxModProduct(<D>,<vector1>,<vector2>) . . . product of two characters mod p
##
BindGlobal( "DxModProduct", function(D,v1,v2)
  local prod,i;
  prod:=0*D.one;
  for i in [1..D.klanz] do
    prod:=prod+ (D.classiz[i] mod D.prime)*v1[i]
                *v2[D.inversemap[i]];
  od;
  prod:=prod/(D.size mod D.prime);
  return prod;
end );


#############################################################################
##
#F  DxFrobSchurInd(<D>,<char>) . . . . . . modular Frobenius-Schur indicator
##
BindGlobal( "DxFrobSchurInd", function(D,char)
  local FSInd,classes,l,ll,L,family;
  FSInd:=char[1];
  classes:=[2..D.klanz];
  for family in D.primeClasses do
    L:=Length(family)+1;
    for l in [1..L-1] do
      if family[l] in classes then
        ll:=2*l mod L;
        if ll=0 then
          FSInd:=FSInd+(D.classiz[family[l]] mod D.prime)
                       *char[1];
        else
          FSInd:=FSInd+(D.classiz[family[l]] mod D.prime)
                       *char[family[ll]];
       fi;
        SubtractSet(classes,[family[l]]);
      fi;
    od;
  od;
  return FSInd/(D.size mod D.prime);
end );


#############################################################################
##
#F  SplitTwoSpace(<D>,<raum>) . . . split two-dim space by combinatoric means
##
##  If the room is 2-dimensional, this is meant to be the standard split.
##  Otherwise,the two-dim invariant space of raum is to be split
##
BindGlobal( "SplitTwoSpace", function(D,raum)
  local v1,v2,v1v1,v1v2,v2v1,v2v2,degrees,d1,d2,deg2,prime,o,f,d,degrees2,
        lift,root,p,q,n,char,char1,char2,a1,a2,i,NotFailed,k,l,m,test,ol,
        di,rp,mdeg2,mult,str;

  mult:=Index(D.characterMorphisms,CharacterMorphismOrbits(D,raum).stabilizer);
  f:=raum.dim=2; # space or invariant space split indicator flag
  prime:=D.prime;
  rp:=Int(prime/2);
  o:=D.one;
  if f then
    v1:=DxNiceBasis(D,raum);
    v2:=v1[2];
    v1:=v1[1];
    ol:=[1];
  else
    Info(InfoCharacterTable,1,"Attempt:",raum.dim);
    v1:=raum.invariantbase[1];
    v2:=raum.invariantbase[2];
    ol:=Filtered(DivisorsInt(Size(raum.stabilizer)),i->i<raum.dim/2+1);
  fi;
  v1v1:=DxModProduct(D,v1,v1);
  v1v2:=DxModProduct(D,v1,v2);
  v2v1:=DxModProduct(D,v2,v1);
  v2v2:=DxModProduct(D,v2,v2);
  char:=[];
  char2:=[];
  NotFailed:=not IsZero(v2v2);
  di:=1;
  while di<=Length(ol) and NotFailed do
    d:=ol[di];
    degrees:=DxDegreeCandidates(D,d*mult);
    if f then
      degrees2:=degrees;
    else
      degrees2:=DxDegreeCandidates(D,(raum.dim-d)*mult);
    fi;
    mdeg2:=List(degrees2,i->i mod prime);
    i:=1;
    while i<=Length(degrees) and NotFailed do
      lift:=true;
      d1:=degrees[i];
      if d1*d>rp then
        lift:=false;
      fi;
      p:=(v2v1+v1v2)/v2v2;
      q:=(v1v1-o/(d*(d1^2) mod D.prime))/v2v2;

      for root in SquareRoots(D.field,(p/2)^2-q) do
        a1:=(-p/2+root);
        n:=v1v2+a1*v2v2;
        if (n=0*o) then
          # proceeding would force a division by zero
          NotFailed:=false;
        else
          a2:=-(v1v1+a1*v2v1)/n;
          n:=v1v1+a2*(v1v2+v2v1)+a2^2*v2v2;
          if n<>0*o then
            deg2:=List(SquareRoots(D.field,o/(raum.dim-d)/n),Int);
            for d2 in deg2 do
              if d2 in mdeg2 then
                if not d2 in degrees2 or d2*(raum.dim-d)>rp then
                  # degree is too big for lifting
                  lift:=false;
                fi;
                char1:=[d*d1*(v1+a1*v2),(raum.dim-d)*d2*(v1+a2*v2)];

                if Length(char)>0 and
                  (char[1].base[1]=char1[2]) and
                  (char[2].base[1]=char1[1]) then
                    test:=false;
                else
                  test:=true;
                fi;
                l:=1;
                while (l<3) and test do
                  if f then
                    n:=1;
                  elif l=1 then
                    n:=d;
                  else
                    n:=raum.dim-d;
                  fi;
                  if not DxFrobSchurInd(D,char1[l]) in o*[-n..n]
                    then test:=false;
                  fi;
                  m:=DxLiftCharacter(D,char1[l]);
                  char2[l]:=m;
                  if test and lift then
                    for k in [2..Length(m)] do
                      if IsInt(m[k]) and AbsInt(m[k])>m[1] then
                        test:=false;
                      fi;
                    od;
                    if test and not IsInt(Sum(m)) then
                      test:=false;
                    fi;
                  fi;
                  l:=l+1;
                od;

                if test then
                  if Length(char)>0 then
                    NotFailed:=false;
                  else
                    char:=[rec(base:=[char1[1]],
                               char:=[char2[1]],
                               d:=d),
                           rec(base:=[char1[2]],
                               char:=[char2[2]],
                               d:=raum.dim-d)];
                  fi;
                fi;
              fi;
            od;
          fi;
        fi;
      od;
      i:=i+1;
    od;
    di:=di+1;
  od;
  if f then
    str:="Two-dim";
  else
    str:="Two orbit";
  fi;
  if NotFailed then
    Info(InfoCharacterTable,2,str," space split");
    return char;
  else
    Info(InfoCharacterTable,2,str," split failed");
    raum.twofail:=true;
    return [];
  fi;
end );


#############################################################################
##
#F  CombinatoricSplit(<D>)  . . . . . . . . .  split two-dimensional spaces
##
BindGlobal( "CombinatoricSplit", function(D)
local i,newRaeume,raum,neuer,j,ch,irrs,mods,incirrs,incmods,nb,rt,neuc;
  newRaeume:=[];
  incirrs:=[];
  incmods:=[];
  for i in [1..Length(D.raeume)] do
    raum:=D.raeume[i];
    if raum.dim=2 and not IsBound(raum.twofail) then
      neuer:=SplitTwoSpace(D,raum);
    else
      neuer:=[];
      if raum.dim=2 then
        # next attempt might work due to fewer degrees
        Unbind(raum.twofail);
      fi;
    fi;
    if Length(neuer)=2 then
      rt:=Difference(RightTransversal(D.characterMorphisms,
           CharacterMorphismOrbits(D,raum).stabilizer),
           [One(D.characterMorphisms)]);
      mods:=[];
      irrs:=[];
      for j in [1,2] do
        Info(InfoCharacterTable,2,"lifting character no.",
                        Length(D.irreducibles)+Length(incirrs));
        if IsBound(neuer[j].char) then
          ch:=neuer[j].char[1];
        else
          ch:=DxLiftCharacter(D,neuer[j].base[1]);
        fi;
        if not ch in D.irreducibles then
          Add(mods,neuer[j].base[1]);
          Add(incmods,neuer[j].base[1]);
          Add(irrs,ch);
          Add(incirrs,ch);
        fi;
      od;
      for j in rt do
        Info(InfoCharacterTable,1,"TwoDimSpace image");
        nb:=D.asCharacterMorphism(raum.base[1],j);
        neuc:=List(irrs,i->D.asCharacterMorphism(i,j));
        if not ForAny([i+1..Length(D.raeume)],i->DxIsInSpace(nb,D.raeume[i])) then
          incirrs:=Union(incirrs,neuc);
          incmods:=Union(incmods,List(mods,i->D.asCharacterMorphism(i,j)));
        else
          Error("#W  strange spaces due to inclusion of irreducibles!\n");
          Add(D.irreducibles,neuc[1]);
          Add(D.irreducibles,neuc[2]);
        fi;
      od;
    else
      Add(newRaeume,raum);
    fi;
  od;
  D.raeume:=newRaeume;
  if Length(incirrs)>0 then
    DxIncludeIrreducibles(D,incirrs,incmods:noproject);
  fi;
end );

#############################################################################
##
#F  OrbitSplit(<D>) . . . . . . . . . . . . . . try to split two-orbit-spaces
##
InstallGlobalFunction( OrbitSplit, function(D)
local i,s,ni,nm;
  ni:=[];
  nm:=[];
  for i in D.raeume do
    if i.dim=3 and not IsBound(i.twofail) and
       CharacterMorphismOrbits(D,i).number=2 then
      s:=SplitTwoSpace(D,i);
      if Length(s)=2 and s[1].d=1 then
        # character extracted
        Add(ni,s[1].char[1]);
        Add(nm,s[1].base[1]);
      fi;
    fi;
  od;
  if ni<>[] then
    DxIncludeIrreducibles(D,ni,nm);
  fi;
  CombinatoricSplit(D);
end );


#############################################################################
##
#F  DxModularValuePol(<f>,<x>,<p>)  . evaluate polynomial at a point,mod p
##
##  'DxModularValuePol' returns the value of the polynomial<f>at<x>,
##  regarding the result modulo p.<x>must be an integer number.
##
##  'DxModularValuePol' uses Horners rule to evaluate the polynom.
##
InstallGlobalFunction( DxModularValuePol, function (f,x,p)
local  value,i;
  value := 0;
  i := Length(f);
  while i>0  do
    value := (value * x + f[i]) mod p;
    i := i-1;
  od;
  return value;
end );


#############################################################################
##
#F  ModularCharacterDegree(<D>,<chi>) . . . . . . . . .  degree of normalized
#F                                                         character modulo p
##
BindGlobal( "ModularCharacterDegree", function(D,chi)
  local j,j1,d,sum,prime;
  prime:=D.prime;
  sum:=0*D.one;
  for j in [1..D.klanz] do
    j1:=D.inversemap[j];
    sum:=sum+chi[j]*chi[j1]*(D.classiz[j] mod prime);
  od;
  d:=RootMod(D.size/Int(sum) mod prime,prime);
  # take correct (smaller) root
  if 2*d>prime then
    d:=prime-d;
  fi;
  return d;
end );


#############################################################################
##
#F  DxDegreeCandidates(<D>,[<anz>]) . Potential degrees for anz characters of
#F     same degree,if num characters of total degree deg are yet to be found
##
InstallGlobalFunction( DxDegreeCandidates, function(arg)
  local D,anz,degrees,i,r;
  D:=arg[1];
  if Length(arg)>1 then
    anz:=arg[2];
    degrees:=[];
    if Length(D.degreePool)=0 then
      return [];
    fi;
    r:=RootInt(Int((D.deg-(D.num-anz)*D.degreePool[1][1]^2)/anz));
    i:=1;
    while i<=Length(D.degreePool) and D.degreePool[i][1]<=r do
      if D.degreePool[i][2]>anz then
        Add(degrees,D.degreePool[i][1]);
      fi;
      i:=i+1;
    od;
    return degrees;
  else
    return List(D.degreePool,i->i[1]);
  fi;
end );


#############################################################################
##
#F  DxSplitDegree(<D>,<space>,<r>)  estimate number of parts when splitting
##                space with matrix number r,according to charactermorphisms
##
InstallGlobalFunction( DxSplitDegree, function(D,space,r)
  local a,s,o,fix,k,l,i,j,gorb,v,w,
        base;
  # is perfect split guaranteed ?
  if IsBound(space.split) then
    return space.split;
  fi;
  o:=D.one;
  a:=CharacterMorphismOrbits(D,space);
  if a.number=space.dim then
    return 2; #worst possible split
  fi;
  if a.number=1 and IsPrime(space.dim) then
    # spaces of prime dimension with one orbit must split perfectly
    space.split:=space.dim;
    return space.dim;
  fi;
  # both cases,but MultiOrbit is not as effective
  s:=a.stabilizer;
  gorb:=D.galoisOrbits[r];
  fix:=Length(gorb)=1;
  if not fix then
    # Galois group acts trivial ? (seen if constant values on
    # rational class)
    i:=1;
    fix:=true;
    base:=DxNiceBasis(D,space);
    while fix and i<=Length(base) do
      v:=base[i];
      w:=v[r];
      for j in gorb do
        if v[j]<>w then
          fix:=false;
        fi;
      od;
      i:=i+1;
    od;
  fi;
  if fix then
    #l:=List(s.generators,i->i.tens[r]);
    l:=List(GeneratorsOfGroup(s),i->D.asCharacterMorphism(1,i).tens[r]);
    v:=[o];
    for i in v do
      for j in l do
        w:=i*j;
        if not w in v then
          Add(v,w);
        fi;
      od;
    od;
    return Length(v); #Length(Set(AsList(s),i->i.tens[r]));
  else
    # nonfix
    # v is an element from the space with non-galois-fix parts.
    l:=Maximum(List(TransposedMat(List(Orbit(s,v,D.asCharacterMorphism),
               i->i{D.galoisOrbits[r]})),i->Length(Set(i))));
    if a.number=1 then
# One orbit: number of resultant spaces must be a divisor of the dimension
      k:=DivisorsInt(space.dim);
      while l<space.dim and not l in k do
        l:=l+1;
      od;
    fi;
    return l;
  fi;
end );


#############################################################################
##
#F  DxGaloisOrbits(<D>,<f>) .  orbits of Stab_Gal(f) when acting on the classes
##
InstallGlobalFunction(DxGaloisOrbits,function(D,f)
local i,k,l,u,ga,galOp,p;
  k:=D.klanz;
  if not IsBound(D.galOp[f]) then
    galOp:=D.galOp;
    if f in MovedPoints(D.galMorphisms) then
      ga:=Stabilizer(D.galMorphisms,f);
    else
      ga:=D.galMorphisms;
    fi;
    p:=true;
    i:=1;
    while p and i<=Length(galOp) do
      if IsBound(galOp[i]) and
         galOp[i].group=ga then
          galOp[f]:=galOp[i];
          p:=false;
      else
        i:=i+1;
      fi;
    od;
    if p then
      galOp[f]:=rec(group:=ga);
      l:=List([1..k],i->Set(Orbit(ga,i)));
      galOp[f].orbits:=l;
      u:=List(Filtered(Collected(
        List(Set(l,i->i[1]),j->D.rids[j])),n->n[2]=1),t->t[1]);
      galOp[f].uniqueIdentifications:=u;
      galOp[f].identifees:=Filtered([1..k],i->D.rids[i] in u);
    fi;
  fi;
  return D.galOp[f];
end);

#############################################################################
##
#F  BestSplittingMatrix(<D>) . number of the matrix,that will yield the best
#F                                                                      split
##
##  This routine calculates also all required columns etc. and stores the
##  result in D
##
InstallGlobalFunction( BestSplittingMatrix, function(D)
local n,i,val,b,requiredCols,splitBases,wert,nu,r,rs,rc,bn,bw,split,
      orb,os,lim,ksl,dmats,imp;

  nu:=Zero(D.field);
  requiredCols:=List([1..D.klanz],x->[]);
  splitBases:=List([1..D.klanz],x->[]);
  wert:=[];
  os:=ForAll(D.raeume,i->i.dim<20); #only small spaces left?

  if Length(D.raeume)=0 then
    Error("nothing left to split!");
  fi;

  lim:=ValueOption("maxclasslen");
  if lim=fail then
    lim:=infinity;
  fi;

  ksl:=1;
  # try matrics by class sizes
  dmats:=[1..Length(D.classiz)];
  SortParallel(ShallowCopy(D.classiz),dmats);
  dmats:=Filtered(dmats,x->x in D.matrices);

  repeat
    for n in dmats do
      requiredCols[n]:=[];
      splitBases[n]:=[];
      wert[n]:=0;
      imp:=false;

      # only take classes small enough
      if D.classiz[n]<=lim and
      # dont start with central classes in small groups!
      (D.classiz[n]>ksl or IsBound(D.maycent)) then
        for i in [1..Length(D.raeume)] do
          r:=D.raeume[i];
          if IsBound(r.splits) then
            rs:=r.splits;
          else
            rs:=[];
            r.splits:=rs;
          fi;

          if r.dim>1 then

            if IsBound(rs[n]) then
              split:=rs[n].split;
              val:=rs[n].val;
            else
              b:=DxNiceBasis(D,r);
              split:=ForAny(b{[2..r.dim]},i->i[n]<>nu);
              imp:=imp or split;
              if split then
                if r.dim<4 then
                  # very small spaces will split nearly perfect
                  val:=8;
                else
                  bn:=DxSplitDegree(D,r,n);
                  if os then
                    if IsPerfectGroup(D.group) then
                      # G is perfect,no linear characters
                      # we can't predict much about the splitting
                      val:=Maximum(1,9-r.dim/bn);
                    else
                      val:=bn*Maximum(1,9-r.dim/bn);
                    fi;
                  else
                    val:=bn;
                  fi;
                fi;
                # note the images,which split as well
                val:=val*Index(D.characterMorphisms,
                              CharacterMorphismOrbits(D,r).stabilizer);
              else
                val:=0;
              fi;
              rs[n]:=rec(split:=split,val:=val);
            fi;
            if split then
              wert[n]:=wert[n]+val;
              Add(splitBases[n],i);
              requiredCols[n]:=Union(requiredCols[n],
                                      D.raeume[i].activeCols);
            fi;
          fi;
        od;
        if Length(splitBases[n])>0 then
          # can we use Galois-Conjugation
          orb:=DxGaloisOrbits(D,n);
          rc:=[];
          for i in requiredCols[n] do
            rc:=Union(rc,[orb.orbits[i][1]]);
          od;

          wert[n]:=wert[n]*D.centralizers[n] # *G/|K|
                  /(Length(rc)); # We count -mistakening - also the first
            # column,that is available for free. Its "costs" are meant to
            # compensate for the splitting process.
        fi;
      fi;
      # is there one that does all already? If so don't bother testing the
      # rest, as we go by cost
      if imp and Length(D.raeume)<=20
        and ForAll(D.raeume,x->IsBound(x.splits)) then

        rc:=Intersection(List(D.raeume,x->Filtered([1..Length(x.splits)],
          y->IsBound(x.splits[y]) and x.splits[y].split=true)));
        if Length(rc)>0 then
          for bw in rc do
            if not IsBound(wert[bw]) or wert[bw]=0 then
              wert[bw]:=Sum(D.raeume,x->x.splits[bw].val);
            fi;
            splitBases[bw]:=Union(splitBases[bw],[1..Length(D.raeume)]);
            for bn in D.raeume do
              requiredCols[bw]:=Union(requiredCols[bw],
                                      bn.activeCols);
            od;
          od;
          break;
        fi;
      fi;
    od;

    for r in D.raeume do
      if IsBound(r.splits) and Number(r.splits,x->x.split=true)=1 then
        # is room split by only ONE matrix?(then we need this sooner or later)
        n:=1;
        while not IsBound(r.splits[n]) or r.splits[n].split=false do
          n:=n+1;
        od;
        wert[n]:=wert[n]*10; #arbitrary increase of value
      fi;
    od;

    bn:=fail;
    bw:=0;
    # run through them in pl sequence
    for n in Filtered(D.permlist,i->i in D.matrices) do
      if IsBound(wert[n]) then
        Info(InfoCharacterTable,3,n,":",Int(wert[n]));
        if wert[n]>bw then
          bn:=n;
          bw:=wert[n];
        fi;
      fi;
    od;

    ksl:=ksl-1;
  until bn<>fail or ksl<0;

  if bn<>fail then
    D.requiredCols:=requiredCols;
    D.splitBases:=splitBases;
  fi;

  return bn;
end );


#############################################################################
##
#F  AsCharacterMorphismFunction(<pcgs>,<gals>,<tensormorphisms>)  operation
#F                               function for operation of charactermorphisms
##
BindGlobal( "AsCharacterMorphismFunction", function(pcgs,gals,tme)
  local i,j,k,x,g,c,lg,gens;
  lg:=Length(gals);
  return function(p,e)
    x:=ExponentsOfPcElement(pcgs,e);
    g:=();
    for i in [1..lg] do
      g:=g*gals[i]^x[i];
    od;
    x:=x{[lg+1..Length(x)]};
    i:=1;
    while tme[i][1]<>x do
      i:=i+1;
    od;
    x:=tme[i][3];
    if IsInt(p) then # integer works only as indicator: return galois and
                     # tensor part
      return rec(gal:=g,
                 tens:=x);
    elif IsList(p) and not IsList(p[1]) then
      if not IsFFE(p[1]) then
        # operation on characteristic 0 characters;
        x:=tme[i][2];
      fi;
      c:=[];
      for i in [1..Length(p)] do
        c[i]:=p[i/g]*x[i];
      od;
      return c;
    elif IsVectorSpace(p) then # Space
      gens:=BasisVectors(Basis(p));
      c:=List(gens,i ->[]);
      for i in [1..Length(gens[1])] do
        j:=i/g;
        for k in [1..Length(gens)] do
          c[k][i]:=gens[k][j] * x[i];
        od;
      od;
      return VectorSpace(LeftActingDomain(p),gens);
    else
      Error("action not defined");
    fi;
  end;
end );

#############################################################################
##
#F  CharacterMorphismGroup(<D>) . . . . create group of character morphisms
##
##  The group is stored in .characterMorphisms. It is an AgGroup,
##  according to the decomposition K=tens:gal as semidirect product. The
##  group acts as linear mappings that permute characters via the operation
##  .asCharacterMorphism.
##
BindGlobal( "CharacterMorphismGroup", function(D)
local tm,tme,piso,gpcgs,gals,ord,l,l2,f,fgens,rws,pow,pos,i,j,k,gen,
      cof,comm;
  tm:=D.tensorMorphisms;
  tme:=tm.els;

  piso:=IsomorphismPcGroup(D.galMorphisms);
  k:=Image(piso,D.galMorphisms);
  # Temporary workaround, 7/30/07, AH. It seems that permuting classes does
  # not easily transfer to mod p.
  k:=Image(piso,TrivialSubgroup(D.galMorphisms));
  gpcgs:=Pcgs(k);
  gals:=List(gpcgs,i->PreImagesRepresentative(piso,i));
  ord:=List(gpcgs,i->RelativeOrderOfPcElement(gpcgs,i));
  l:=Length(gpcgs);

  # add tensor relative orders
  tm.ro:=[];
  tm.re:=[];
  for i in tm.a do
    f:=Factors(i);

    Add(tm.ro,f[1]);
    Add(tm.re,Length(f));
  od;
  l2:=Length(ord)-l;

  f:=FreeGroup(IsSyllableWordsFamily,Length(ord));
  fgens:=GeneratorsOfGroup(f);
  rws:=SingleCollector(f,ord);

  # translate the gal-Relations:
  for i in [1..l] do
      SetPower( rws, i, ObjByExponents( rws,
              Concatenation(
                      ExponentsOfPcElement( gpcgs, gpcgs[i]^ord[i] ),
                      [1..l2] * 0 ) ) );
      for j in [i+1..l] do
          SetConjugate( rws, j, i, ObjByExponents( rws,
                  Concatenation(
                          ExponentsOfPcElement( gpcgs, gpcgs[j]^gpcgs[i] ),
                          [1..l2] * 0 ) ) );
      od;
  od;

  # correct the first and add last tme entries
  for i in tme do
    for j in [1..Length(i[1])] do
      cof:=CoefficientsQadic(i[1][j],tm.ro[j]);
      while Length(cof)<tm.re[j] do
        Add(cof,0);
      od;
      i[1][j]:=cof;
    od;
    i[1]:=Concatenation(i[1]);
    Add(i,List(i[2],D.modularMap));
  od;

  pow:=1;
  pos:=0;
  for i in [l+1..Length(ord)] do
    # get generator
    if pow=1 then
      # new position, new generator
      pos:=pos+1;
      gen:=tm.c[pos];
      pow:=tm.a[pos];
    else
      # power generator of last step
      gen:=List(gen,j->j^ord[i-1]);
    fi;

    # add the necessary tensor power relations
    if pow>ord[i] then
      SetPower(rws,i,fgens[i+1]);
    fi;

    pow:=pow/ord[i];

    # add commutator relations between galois and tensor
    for j in [1..l] do
      # compute commutator Comm(tens[i],gal[j])
      #comm:=Permuted(gen,gals[j]);
      #for k in [1..Length(comm)] do
      #  comm[k]:=gen[k]^-1*comm[k];
      #od;
      comm:=[];
      for k in [1..Length(comm)] do
        comm[k]:=gen[k]^-1*gen[k/gals[j]];
      od;

      # find decomposition
      k:=PositionProperty(tme,i->i[2]=comm);
      cof:=tme[k][1];
      comm:=One(f);
      for k in [1..Length(cof)] do
        comm:=comm*fgens[l+k]^cof[k];
      od;
      SetCommutator(rws,i,j,comm);
    od;
  od;
  tm:=GroupByRwsNC(rws);

  D.characterMorphisms:=tm;
  D.asCharacterMorphism:=AsCharacterMorphismFunction(HomePcgs(tm),
                           gals,tme);
  D.tensorMorphisms:=tme;
  return tm;
end );


#############################################################################
##
#F  ClassElementLargeGroup(D,<el>[,<possible>]) ident. class of el in D.group
##
##  First,the (hopefully) cheap identification is used,to filter the
##  possible classes. If still not unique,a hard conjugacy test is applied
##
BindGlobal( "ClassElementLargeGroup", function(arg)
local D,el,possible,i,id;
  D:=arg[1];
  el:=arg[2];
  id:=D.identification(D,el);
  possible:=Filtered([1..D.klanz],i->D.ids[i]=id);
  if Length(arg)>2 then
    possible:=Intersection(possible,arg[3]);
  fi;
  i:=1;
  while i<Length(possible) do
    if el in D.classes[possible[i]] then
      return possible[i];
    else
      i:=i+1;
    fi;
  od;
  return possible[i];
end );


#############################################################################
##
#F  ClassElementSmallGroup(<D>,<el>[,<poss>]) identify class of el in D.group
##
##  Since we have stored the complete classmap,this is done by simply
##  looking the class number up in this list.
##
BindGlobal( "ClassElementSmallGroup", function(arg)
local D;
  D:=arg[1];
  return D.classMap[Position(D.enum,arg[2])];
end );


#############################################################################
##
#F  DoubleCentralizerOrbit(<D>,<c1>,<c2>)
##
##  Let g_i be the representative of Class i.
##  Compute orbits of C(g_2) on (g_1^(-1))^G. Since we want to evaluate
##  x^(-1)*z for x\in Cl(g_1),and we only need the class of the result,we
##  may conjugate with z-centralizing elements and still obtain the same
##  results! The orbits are calculated either by simple orbit algorithms or
##  whenever they might become bigger using double cosets of the
##  centralizers.
##
InstallGlobalFunction(DoubleCentralizerOrbit,function(D,c1,c2)
local often,trans,e,neu,i,inv,cent,l,s,s1,x,dom;
  inv:=D.inversemap[c1];
  s1:=D.classiz[c1];
  # criteria for using simple orbit part: only for small groups,note that
  # computing ascending chains can be very expensive.
  if s1<500 or
     (not (HasStabilizerOfExternalSet(D.classes[inv])
           and Tester(ComputedAscendingChains)(Centralizer(D.classes[inv])))
        and s1<1000)

  then
    if D.currentInverseClassNo<>c1 then
      D.currentInverseClassNo:=c1;
      # compute (x^(-1))^G
      D.currentInverseClass:=Orbit(D.group,D.classreps[inv]);
    fi;
    trans:=[];
    cent:=Centralizer(D.classes[c2]);
    for e in D.currentInverseClass do
      neu:=true;
      i:=1;
      while neu and (i<=Length(trans)) do
        if e in trans[i] then neu:=false;
        fi;
        i:=i+1;
      od;
      if neu then
        Add(trans,Orbit(cent,e));
      fi;
    od;
    often:=List(trans,Length);
    return [List(trans,i->i[1]),often];
  else
    #Info(InfoCharacterTable,3,"using DoubleCosets;");
    cent:=Centralizer(D.classes[inv]);
    if IndexNC(D.group,cent)<=10^5 then
      dom:=fail;
      if not IsBound(D.centfachom[inv]) then
        #e:=ActionHomomorphism(D.group,RightTransversal(D.group,cent),OnRight,
        #  "surjective");
        #TODO: both in one
        e:=SubgroupNC(D.group,SmallGeneratingSet(D.group));
        SetSize(e,Size(D.group));
        dom:=Orbit(e,Representative(D.classes[inv]));
        e:=ActionHomomorphism(e,dom,"surjective");
        s:=Image(e);
        StabChainOptions(s).limit:=Size(D.group);
        # do not use action later on

        # rebuild from scratch to not carry through the orbit in
        # centfachom
        #e:=AsGroupGeneralMappingByImages(e);
        s:=MappingGeneratorsImages(e);
        e:=GroupHomomorphismByImagesNC(Source(e),Image(e),s[1],s[2]);
        SetIsSurjective(e,true);
        D.centfachom[inv]:=e;
        D.lastOrbit:=[e,dom];
      else
        e:=D.centfachom[inv];
        if IsBound(D.lastOrbit) and IsIdenticalObj(D.lastOrbit[1],e) then
          dom:=D.lastOrbit[2];
        fi;
      fi;
      s:=Orbits(Image(e,Centralizer(D.classes[c2])),[1..IndexNC(D.group,cent)]);
      if dom=fail then
        x:=D.classreps[inv];

        l:=List(s,i->[x^PreImagesRepresentative(e,
          RepresentativeAction(Image(e),1,i[1])),Size(cent)*Length(i)]);
      else
        l:=List(s,i->[dom[i[1]],Size(cent)*Length(i)]);
      fi;
    else
      l:=DoubleCosetRepsAndSizes(D.group,cent,Centralizer(D.classes[c2]));
      x:=D.classreps[inv];
      l:=List(l,i->[x^i[1],i[2]]);
    fi;
    s1:=Size(cent);
    e:=[];
    s:=[];
    for i in l do
      Add(e,i[1]);
      Add(s,i[2]/s1);
    od;
    return [e,s];
  fi;
end);


#############################################################################
##
#F  StandardClassMatrixColumn(<D>,<mat>,<r>,<t>)  . calculate the t-th column
#F       of the r-th class matrix and store it in the appropriate column of M
##
BindGlobal( "StandardClassMatrixColumn", function(D,M,r,t)
  local c,gt,s,z,i,T,w,e,j,p,orb;
  if t=1 then
    M[D.inversemap[r],t]:=D.classiz[r];
  else
    orb:=DxGaloisOrbits(D,r);
    z:=D.classreps[t];
    c:=orb.orbits[t][1];
    if c<>t then
      p:=RepresentativeAction(Stabilizer(orb.group,r),c,t);
      if p<>fail then
        # was the first column of the galois class active?
        if ForAny([1..NrRows(M)],i->M[i,c]>0) then
          for i in D.classrange do
            M[i^p,t]:=M[i,c];
          od;
          Info(InfoCharacterTable,2,"Computing column ",t,
            " : by GaloisImage");
          return;
        fi;
      fi;
    fi;

    T:=DoubleCentralizerOrbit(D,r,t);
    Info(InfoCharacterTable,2,"Computing column ",t," :",
      Length(T[1])," instead of ",D.classiz[r]);

    if IsDxLargeGroup(D.group) then
      # if r and t are unique,the conjugation test can be weak (i.e. up to
      # galois automorphisms)
      w:=Length(orb.orbits[t])=1 and Length(orb.orbits[r])=1;
      for i in [1..Length(T[1])] do
        e:=T[1][i]*z;
        Unbind(T[1][i]);
        if w then
          c:=D.rationalidentification(D,e);
          if c in orb.uniqueIdentifications then
            s:=orb.orbits[
              First([1..D.klanz],j->D.rids[j]=c)][1];
          else
            s:=D.ClassElement(D,e);
          fi;
        else # only strong test possible
          s:=D.ClassElement(D,e);
        fi;
        M[s,t]:=M[s,t]+T[2][i];
      od;
      if w then # weak discrimination possible ?
        gt:=Set(Filtered(orb.orbits,i->Length(i)>1));
        for i in gt do
          if i[1] in orb.identifees then
            # were these classes detected weakly ?
            e:=M[i[1],t];
            if e>0 then
              Info(InfoCharacterTable,3,"GaloisIdentification ",i,": ",e);
            fi;
            for j in i do
              M[j,t]:=e/Length(i);
            od;
          fi;
        od;
      fi;
    else # Small Group
      for i in [1..Length(T[1])] do
        s:=D.ClassElement(D,T[1][i] * z);
        Unbind(T[1][i]);
        M[s,t]:=M[s,t]+T[2][i];
      od;
    fi;
  fi;
end );


#############################################################################
##
#F  IdentificationGenericGroup(<D>,<el>) . .  class invariants for el in G
##
BindGlobal( "IdentificationGenericGroup", function(D,el)
  return Order(el);
end );


#############################################################################
##
#F  DxAbelianPreparation(<G>) . . specific initialisation for abelian groups
##
InstallMethod(DxPreparation,"abelian",true,[IsGroup and IsAbelian,IsRecord],0,
function(G,D)
  local i;
  D.identification:=function(a,b) return b; end;
  D.rationalidentification:=D.identification;
  D.ClassMatrixColumn:=StandardClassMatrixColumn;

  D.ids:=[];
  for i in D.classrange do
    D.ids[i]:=D.identification(D,D.classreps[i]);
  od;
  D.rids:=D.ids;

  D.ClassElement:=ClassElementLargeGroup;

  return D;

end);

#############################################################################
##
#M  DxPreparation(<G>,<D>)
##
InstallMethod(DxPreparation,"generic",true,[IsGroup,IsRecord],0,
function(G,D)
local i,j,enum,cl;
  D.identification:=IdentificationGenericGroup;
  D.rationalidentification:=IdentificationGenericGroup;
  D.ClassMatrixColumn:=StandardClassMatrixColumn;

  cl:=D.classes;
  D.ids:=[];
  for i in D.classrange do
    D.ids[i]:=D.identification(D,D.classreps[i]);
  od;
  D.rids:=D.ids;

  if IsDxLargeGroup(G) then
    D.ClassElement:=ClassElementLargeGroup;
  else
    D.ClassElement:=ClassElementSmallGroup;
    enum:=Enumerator(G);
    D.enum:=enum;
    D.classMap:=List([1..Size(G)],i->D.klanz);
    for j in [1..D.klanz-1] do
      for i in Orbit(G,Representative(cl[j])) do
        D.classMap[Position(D.enum,i)]:=j;
      od;
    od;
  fi;

  return D;

end);


#############################################################################
##
##  CharacterDegreePool(G)  . . possible character degrees,using thm. of Ito
##
BindGlobal( "CharacterDegreePool", function(G)
  local k,r,s;
  r:=RootInt(Size(G));
  #if Size(G)>10^6 and not IsSolvableGroup(G) then
  #  s:=Filtered(NormalSubgroups(G),IsAbelian);
  #  s:=Lcm(List(s,i->Index(G,i)));
  #else
  s:=Size(G);
  #fi;
  k:=Length(ConjugacyClasses(G));
  return List(Filtered(DivisorsInt(s),i->i<=r),i->[i,k]);
end );

#############################################################################
##
##  ClassNumbersElements(<G>,<l>) . .  class numbers in G for elements in l
##
BindGlobal( "ClassNumbersElements", function(G,l)
local D;
  D:=DixonRecord(G);
  return List(l,i->D.ClassElement(D,i));
end );

#############################################################################
##
#F  DxGeneratePrimeCyclotomic(<e>,<r>) . . . . . . . . .  ring homomorphisms
##
##  $\Q(\varepsilon_e)\to\F_p$. r is e-th root in F_p.
##
BindGlobal( "DxGeneratePrimeCyclotomic", function(e,r) # exponent,Primitive Root
  return function(a)
  local l,n,w,s,i,o;
    l:=COEFFS_CYC(a);
    n:=Length(l);
    o:=r^0;
    w:=0*o;
    s:=r^(e/n); # calculate corresponding power of modular root of unity
   for i in [1..n] do
      if i=1 then
        w:=w+l[i]*o;
      else
        w:=w+s^(i-1)*l[i];
      fi;
    od;
    return w;
  end;
end );

#############################################################################
##
#F  DixonInit(<G>) . . . . . . . . . . initialize Dixon-Schneider algorithm
##
##
InstallGlobalFunction( DixonInit, function(G, opt...)
local D,     # Dixon record,result
      k,z,exp,prime,M,m,f,r,ga,i,fk, knownirr;

  # Force computation of the size of the group.
  Size(G);

  D:=DixonRecord(G);
  k:=D.klanz;

  DxCalcAllPowerMaps(D);
  DxCalcPrimeClasses(D);

  # estimate the irrationality of the table
  exp:=Exponent(G);
  z:=RootInt(Size(G));
  prime:=12*exp+1;

  fk:=ValueOption("prime");
  if not IsPosInt(fk) or fk<5*k then
    fk:=5*k;
  fi;

  while prime<Maximum(100,fk) do
    prime:=prime+exp;
  od;

  # try to calculate approximate degrees
  D.degreePool:=CharacterDegreePool(G);
  z:=2*Maximum(List(D.degreePool,i->i[1]));

  # throw away (unneeded) linear degrees!
  D.degreePool:=Filtered(D.degreePool,i->i[1]>1 and i[1]<=z/2);

  while prime<z do
    prime:=prime+exp;
  od;
  while not IsPrimeInt(prime) do
    prime:=prime+exp;
  od;

  f:=GF(prime);
  Info(InfoCharacterTable,1,"choosing prime ",prime);

  z:=PowerModInt(PrimitiveRootMod(prime),(prime-1)/exp,prime);
  D.modularMap:=DxGeneratePrimeCyclotomic(exp,z* One(f));

  D.num:=D.klanz;
  D.prime:=prime;
  D.field:=f;
  D.one:=One(f);
  D.z:=z;
  r:=rec(base:=List(IdentityMat(k,D.one),Vector),dim:=k);
  D.raeume:=[r];

  # Galois group operating on the columns
  ga:= GroupByGenerators( Set( Flat( GeneratorsPrimeResidues(
                      Exponent(G)).generators),
    i->PermList(List([1..k],j->PowerMap(D.characterTable,i,j)))),());

  D.galMorphisms:=ga;
  D.galoisOrbits:=List([1..k],i->Set(Orbit(ga,i)));
  D.matrices:=Difference(Set(D.galoisOrbits,i->i[1]),[1]);
  D.galOp:=[];
  D.irreducibles:=[];

  fk:=D.one/(Size(G) mod prime);
  M:= ZeroMatrix(D.field,k,k);
  for i in [1..k] do
    M[i,i]:=(D.classiz[i] mod prime)*D.one*fk;
  od;
  D.projectionMat:=M;

  DxIncludeIrreducibles(D,DxLinearCharacters(D));
  if Length( opt ) = 1 and IsRecord( opt[1] ) and IsBound( opt[1].knownirreducibles ) then
    # The ordering of classes for these characters refers to
    # the 'ConjugacyClasses' value of their character table.
    # We check whether these classes coincide with 'D.classes'.
    knownirr:= opt[1].knownirreducibles;
    if 0 < Length( knownirr ) and
       IsIdenticalObj( D.classes,
           ConjugacyClasses( UnderlyingCharacterTable( knownirr[1] ) ) ) then
      DxIncludeIrreducibles( D, knownirr );
    fi;
  fi;

  if Length(D.raeume)>0 then
    # indicate Stabilizer of the whole orbit,simultaneously compute
    # CharacterMorphisms.
    D.raeume[1].stabilizer:=CharacterMorphismGroup(D);
    m:=First(D.classes,i->Size(i)>1);
    if m<>fail and Size(m)>8 then
      D.maycent:=true;
    fi;
  fi;

  return D;
end );

InstallGlobalFunction(DxOnedimCleanout,function(D)
local i,j,r,ch,kill,gens,ra;
  kill:=false;
  for i in [1..Length(D.raeume)] do
    r:=D.raeume[i];
    if r.dim=1 then
      Info(InfoCharacterTable,2,"lifting character no.",
                      Length(D.irreducibles)+1);
      if IsBound(r.char) then
        ch:=r.char[1];
      else
        gens:=r.base[1];
        gens:=gens/gens[1];
        gens:=gens * ModularCharacterDegree(D,gens);
        for j in Orbit(D.characterMorphisms,
                          gens,D.asCharacterMorphism) do
          DxRegisterModularChar(D,j);
        od;
        ch:=DxLiftCharacter(D,gens);
      fi;
      for j in Orbit(D.characterMorphisms,ch,D.asCharacterMorphism) do
        Add(D.irreducibles,j);
      od;
      Unbind(D.raeume[i]);
      kill:=true;
    fi;
  od;
  if kill then
    # Throw away lifted spaces
    ra:=[];
    for i in D.raeume do
      Add(ra,i);
    od;
    D.raeume:=ra;
  fi;
end);

#############################################################################
##
#F  DixonSplit(<D>) . .  calculate matrix,split spaces and obtain characters
##
InstallGlobalFunction( DixonSplit, function(arg)
local D,bsm;

  D:=arg[1];
  if Length(arg)>1 then
    bsm:=arg[2];
  else
    bsm:=BestSplittingMatrix(D);
  fi;
  if bsm<>fail then
    SplitStep(D,bsm);
  fi;

  DxOnedimCleanout(D);

  CombinatoricSplit(D);
  return bsm;
end );


#############################################################################
##
#F  DixontinI(<D>)  . . . . . . . . . . . . . . . .  reverse initialisation
##
##  Return everything modified by the Dixon-Algorithm to its former status.
##  the old group is returned,character table is sorted according to its
##  classes
##
InstallGlobalFunction( DixontinI, function(D)
local C,u,irr;

  if IsBound(D.shorttests) then
    Info(InfoCharacterTable,2,D.shorttests," shortened conjugation tests");
  fi;
  Info(InfoCharacterTable,1,"Total:",Length(D.yetmats)," matrices,",
                 D.yetmats);
  C:=D.characterTable;

  irr:=List(D.irreducibles,i->Character(C,i));

  # Sort the characters by degrees.
  irr:=SortedCharacters(C,irr);

  # Throw away not any longer used components of the Dixon record.
  for u in Difference(RecNames(D),
    ["ClassElement","centmulCandidates","centmulMults","characterTable",
    "classMap","facs","fingerprintCandidates",
    "group","identification","ids","iscentral","klanz","name","operations",
    "replist","shorttests","uniques",
    "lastOrbit","centfachom"])
    do
    Unbind(D.(u));
  od;

  return irr;
end );


#############################################################################
##
#M  IrrDixonSchneider( <G>[, <options>] ) . . . . irr. chars. of finite group
##
##  Compute the irreducible characters of <G>,
##  using the Dixon/Schneider method.
##
InstallMethod( IrrDixonSchneider,
    "Dixon/Schneider",
    true,
    [ IsGroup ], 0,
--> --------------------

--> maximum size reached

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

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

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge