[GAP Forum] Displaying character table with different conjugacy class labels

Thomas Breuer sam at Math.RWTH-Aachen.De
Wed Aug 14 09:18:19 BST 2019


Dear GAP Forum,

David Madore asked

> I'm not sure whether my question concerns GAP proper or the character
> table library: I'm using GAP from Debian stretch (now oldstable) which
> identifies as follows (although I can easily switch to a different
> version if this is relevant):
> 
> [...]
> 
> Anyway, I'd like to display a character table (tbl, say, computed by
> something like tbl := CharacterTable("W(E8)")) but with a different
> labeling of the conjugacy classes.  It turns out that the function
> AtlasClassNames(tbl) gives the labels I want, but I couldn't figure
> out a way to either get Display(tbl) to use this set of labels or
> modify tbl so as to replace the origina labels.
> 
> This is merely a display issue.  I'm not trying to change anything in
> the computation or even in the order of the classes.

Currently the relevant function does not support prescribed class names,
but I think it is a good idea to add such an option to the 'Display'
and 'Browse' methods for character tables.

For the moment, reading the GAP code appended below into a GAP session
yields the desired functionality.
One can then enter

    gap> tbl:= CharacterTable( "W(E8)" );;
    gap> Display( tbl, rec( classnames:= AtlasClassNames( tbl ) ) );

and gets the given class names as labels of the columns.

Thanks for the suggestion.

All the best,
Thomas


#############################################################################
##
#F  CharacterTableDisplayDefault( <tbl>, <options> )
##
##  changed: admit component "classnames" in <options>
##
if not IsBound( CambridgeMaps ) then
  CambridgeMaps:= "dummy";  # the function is in the character table library
fi;

MakeReadWriteGVar( "REREADING" );
REREADING:= true;

InstallGlobalFunction( CharacterTableDisplayDefault,
    function( tbl, options )
    local i, j,              # loop variables
          colWidth,          # local function
          record,            # loop over options records
          printLegend,       # local function
          legend,            # local function
          cletter,           # character name
          chars_from_irr,    # are the characters contained in `Irr( tbl )'?
          chars,             # list of characters
          cnr,               # list of character numbers
          classes,           # list of classes
          powermap,          # list of primes
          centralizers,      # boolean
          cen,               # factorized centralizers
          fak,               # factorization
          prime,             # loop over primes
          primes,            # prime factors of order
          prin,              # column widths
          nam,               # classnames
          col,               # number of columns already printed
          acol,              # nuber of columns on next page
          len,               # width of next page
          ncols,             # total number of columns
          linelen,           # line length
          q,                 # quadratic cyc / powermap entry
          indicator,         # list of primes
          indic,             # indicators
          iw,                # width of indicator column
          stringEntry,       # local function
          stringEntryData,   # data accessed by `stringEntry'
          cc,                # column number
          charnames,         # list of character names
          charvals,          # matrix of strings of character values
          tbl_powermap,
          tbl_centralizers;

    # compute the width of column `col'
    colWidth:= function( col )
       local len, width;

       if IsRecord( powermap ) then
         # the three components should fit into the column
         width:= Length( powermap.power[ col ] );
         len:= Length( powermap.prime[ col ] );
         if len > width then
           width:= len;
         fi;
         len:= Length( powermap.names[ col ] );
         if len > width then
           width:= len;
         fi;
       else
         # the class name should fit into the column
         width:= Length( nam[col] );

         # the class names of power classes should fit into the column
         for i in powermap do
           len:= tbl_powermap[i][ col ];
           if IsInt( len ) then
             len:= Length( nam[ len ] );
             if len > width then
               width:= len;
             fi;
           fi;
         od;
       fi;

       if centralizers = "ATLAS" then
         # The centralizer orders should fit into the column.
         len:= Length( String( tbl_centralizers[ col ] ) );
         if len > width then
           width:= len;
         fi;
       fi;

       # each character value should fit into the column
       for i in [ 1 .. Length( cnr ) ] do
         len:= Length( charvals[i][ col ] );
         if len > width then
           width:= len;
         fi;
       od;

       # at least one blank should separate the column entries
       return width + 1;
    end;

    # Prepare a list of the available options records.
    options:= [ options ];
    if HasDisplayOptions( tbl ) and
       not IsIdenticalObj( options[1], DisplayOptions( tbl ) ) then
      Add( options, DisplayOptions( tbl ) );
    fi;
    if IsBound( CharacterTableDisplayDefaults.User ) and
       not IsIdenticalObj( options[1],
               CharacterTableDisplayDefaults.User ) then
      Add( options, CharacterTableDisplayDefaults.User );
    fi;
    if not IsIdenticalObj( options[1],
                CharacterTableDisplayDefaults.Global ) then
      Add( options, CharacterTableDisplayDefaults.Global );
    fi;

    # Get the options that are in at least one record.
    for record in options do
      if IsBound( record.StringEntry ) then
        stringEntry:= record.StringEntry;
        break;
      fi;
    od;
    for record in options do
      if IsBound( record.StringEntryData ) then
        stringEntryData:= record.StringEntryData( tbl );
        break;
      fi;
    od;
    for record in options do
      if   IsBound( record.PrintLegend ) then
        # for backwards compatibility with GAP 4.4 ...
        printLegend:= record.PrintLegend;
        break;
      elif IsBound( record.Legend ) then
        legend:= record.Legend;
        printLegend:= function( data ) Print( legend( data ) ); end;
        break;
      fi;
    od;
    for record in options do
      if IsBound( record.letter ) and Length( record.letter ) = 1 then
        cletter:= record.letter;
        break;
      fi;
    od;
    for record in options do
      if IsBound( record.centralizers ) then
        centralizers:= record.centralizers;
        break;
      fi;
    od;

    # Get the options that have no global default.
    # choice of characters and character names
    chars_from_irr:= true;
    for record in options do
      if IsBound( record.chars ) then
        if IsList( record.chars ) and ForAll( record.chars, IsPosInt ) then
          cnr:= record.chars;
          chars:= List( Irr( tbl ){ cnr }, ValuesOfClassFunction );
        elif IsInt( record.chars ) then
          cnr:= [ record.chars ];
          chars:= List( Irr( tbl ){ cnr }, ValuesOfClassFunction );
        elif IsHomogeneousList( record.chars ) then
          chars:= record.chars;
          cnr:= [ 1 .. Length( chars ) ];
          chars_from_irr:= false;
          if not IsBound( cletter ) then
            cletter:= "Y";
          fi;
        else
          cnr:= [];
          chars:= [];
        fi;
        break;
      fi;
    od;
    if not IsBound( chars ) then
      # Perhaps the irreducibles have to be computed here,
      # so we do not use this before evaluating the options.
      chars:= List( Irr( tbl ), ValuesOfClassFunction );
      cnr:= [ 1 .. Length( chars ) ];
      if HasCharacterNames( tbl ) then
        charnames:= CharacterNames( tbl );
      fi;
    fi;
    if not IsBound( cletter ) then
      cletter:= "X";
    fi;
    if not IsBound( charnames ) then
      charnames:= List( cnr,
          i -> Concatenation( cletter, ".", String( i ) ) );
    fi;

    # choice of classes
    classes:= [ 1 .. NrConjugacyClasses( tbl ) ];
    for record in options do
      if IsBound( record.classes ) then
        if IsInt( record.classes ) then
          classes:= [ record.classes ];
        else
          classes:= record.classes;
        fi;
        break;
      fi;
    od;

    # choice of power maps
    tbl_powermap:= ComputedPowerMaps( tbl );
    powermap:= Filtered( [ 2 .. Length( tbl_powermap ) ],
                         x -> IsBound( tbl_powermap[x] ) );
    for record in options do
      if IsBound( record.powermap ) then
        if IsInt( record.powermap ) then
          IntersectSet( powermap, [ record.powermap ] );
        elif record.powermap = "ATLAS" and IsBound( CambridgeMaps ) then
          powermap:= "ATLAS";
          powermap:= CambridgeMaps( tbl );
        elif IsList( record.powermap ) then
          IntersectSet( powermap, record.powermap );
        elif record.powermap = false then
          powermap:= [];
        fi;
        break;
      fi;
    od;

    # print Frobenius-Schur indicators?
    indicator:= [];
    for record in options do
      if IsBound( record.indicator ) then
        if record.indicator = true then
          indicator:= [ 2 ];
        elif IsList( record.indicator ) then
          indicator:= Set( Filtered( record.indicator, IsPosInt ) );
        fi;
        break;
      fi;
    od;

    # (end of options handling)

    # line length
    linelen:= SizeScreen()[1] - 1;

    # prepare centralizers
    if centralizers = "ATLAS" then
      tbl_centralizers:= SizesCentralizers( tbl );
    elif centralizers = true then
      tbl_centralizers:= SizesCentralizers( tbl );
      primes:= PrimeDivisors( Size( tbl ) );
      cen:= [];
      for prime in primes do
        cen[ prime ]:= [];
      od;
    fi;

    # prepare class names
    if IsRecord( powermap ) then
      nam:= ClassNames( tbl, "ATLAS" );
    else
      nam:= ClassNames( tbl );
      for record in options do
        if IsBound( record.classnames ) and IsList( record.classnames ) then
          nam:= record.classnames;
          break;
        fi;
      od;
    fi;

    # prepare indicator
    # (compute the values if they are not stored but use stored values)
    iw:= [ 0 ];
    if indicator <> [] then
      indic:= [];
      for i in indicator do
        if chars_from_irr and IsBound( ComputedIndicators( tbl )[i] ) then
          indic[i]:= ComputedIndicators( tbl )[i]{ cnr };
        else
          indic[i]:= Indicator( tbl, Irr( tbl ){ cnr }, i );
        fi;
        if i = 2 then
          iw[i]:= 2;
        else
          iw[i]:= Maximum( Length( String( Maximum( Set( indic[i] ) ) ) ),
                           Length( String( Minimum( Set( indic[i] ) ) ) ),
                           Length( String( i ) ) ) + 1;
        fi;
        iw[1]:= iw[1] + iw[i];
      od;
      iw[1]:= iw[1] + 1;
    fi;

    if Length( cnr ) = 0 then
      prin:= [ 3 ];
    else
      prin:= [ Maximum( List( charnames, Length ) ) + 3 ];
    fi;

    # prepare list for strings of character values
    charvals:= List( chars, x -> [] );

    # total number of columns
    ncols:= Length(classes) + 1;

    # number of columns already displayed
    col:= 1;

    # A character table has a name.
    Print( Identifier( tbl ), "\n" );

    while col < ncols do

       # determine number of cols for next page
       acol:= 0;
       if indicator <> [] then
          prin[1]:= prin[1] + iw[1];
       fi;
       len:= prin[1];
       while col+acol < ncols and len < linelen do
          acol:= acol + 1;
          if Length(prin) < col + acol then
            cc:= classes[ col + acol - 1 ];
            for i in [ 1 .. Length( cnr ) ] do
              charvals[i][ cc ]:= stringEntry( chars[i][ cc ],
                                               stringEntryData );
            od;
            prin[ col + acol ]:= colWidth( cc );
          fi;
          len:= len + prin[col+acol];
       od;
       if len >= linelen then
          acol:= acol-1;
       fi;

       # Check whether we are able to print at least one column.
       if acol = 0 then
         Error( "line length too small (perhaps resize with `SizeScreen')" );
       fi;

       # centralizers
       if centralizers = "ATLAS" then
#T Admit splitting into two lines,
#T admit that the first centralizer starts in the character names' area.
         Print( "\n" );
         Print( String( "", prin[1] ) );
         for j in [ col + 1 .. col + acol ] do
           Print( String( tbl_centralizers[ j-1 ], prin[j] ) );
         od;
         Print( "\n" );
       elif centralizers = true then
          Print( "\n" );
          for i in [col..col+acol-1] do
             fak:= Factors( Integers, tbl_centralizers[ classes[i] ] );
             for prime in Set( fak ) do
               if prime <> 1 then
                 cen[prime][i]:= Number( fak, x -> x = prime );
               fi;
             od;
          od;
          for j in [1..Length(cen)] do
             if IsBound(cen[j]) then
                for i in [col..col+acol-1] do
                   if not IsBound(cen[j][i]) then
                      cen[j][i]:= ".";
                   fi;
                od;
             fi;
          od;

          for prime in primes do
             Print( String( prime, prin[1] ) );
             for j in [1..acol] do
               Print( String( cen[prime][col+j-1], prin[col+j] ) );
             od;
             Print( "\n" );
          od;
       fi;

       # class names and power maps
       if IsRecord( powermap ) then
         # three lines: power maps, p' part, and class names
         Print( "\n" );
         Print( String( "p ", prin[1] ) );
         for j in [ 1 .. acol ] do
           Print( String( powermap.power[classes[col+j-1]],
                                   prin[col+j] ) );
         od;
         Print( "\n" );
         Print( String( "p'", prin[1] ) );
         for j in [ 1 .. acol ] do
           Print( String( powermap.prime[classes[col+j-1]],
                                   prin[col+j] ) );
         od;
         Print( "\n" );
         Print( String( "", prin[1] ) );
         for j in [ 1 .. acol ] do
           Print( String( powermap.names[classes[col+j-1]],
                                   prin[col+j] ) );
         od;

       else

         # first class names, then a line for each power map
         Print( "\n" );
         Print( String( "", prin[1] ) );
         for i in [ 1 .. acol ] do
           Print( String( nam[classes[col+i-1]], prin[col+i] ) );
         od;
         for i in powermap do
           Print( "\n" );
           Print( String( Concatenation( String(i), "P" ),
                                   prin[1] ) );
           for j in [ 1 .. acol ] do
             q:= tbl_powermap[i][classes[col+j-1]];
             if IsInt( q ) then
                Print( String( nam[q], prin[col+j] ) );
             else
                Print( String( "?", prin[col+j] ) );
             fi;
           od;
         od;

       fi;

       # empty column resp. indicators
       Print( "\n" );
       if indicator <> [] then
          prin[1]:= prin[1] - iw[1];
          Print( String( "", prin[1] ) );
          for i in indicator do
             Print( String( i, iw[i] ) );
          od;
       fi;

       # the characters
       for i in [1..Length(chars)] do

          Print( "\n" );

          # character name
          Print( String( charnames[i], -prin[1] ) );

          # indicators
          for j in indicator do
            if j = 2 then
               if indic[j][i] = 0 then
                 Print( String( "o", iw[j] ) );
               elif indic[j][i] = 1 then
                 Print( String( "+", iw[j] ) );
               elif indic[j][i] = -1 then
                 Print( String( "-", iw[j] ) );
               fi;
            else
               if indic[j][i] = 0 then
                 Print( String( "0", iw[j] ) );
               else
                 Print( String( stringEntry( indic[j][i],
                                                      stringEntryData ),
                                         iw[j]) );
              fi;
            fi;
          od;
          if indicator <> [] then
            Print(" ");
          fi;
          for j in [ 1 .. acol ] do
            Print( String( charvals[i][ classes[col+j-1] ],
                                    prin[ col+j ] ) );
          od;
       od;
       col:= col + acol;
       Print("\n");

       # Indicators are printed only with the first portion of columns.
       indicator:= [];

    od;

    # print legend for cyclos
    printLegend( stringEntryData );
    end );

REREADING:= false;
MakeReadOnlyGVar( "REREADING" );

if IsString( CambridgeMaps ) then
  Unbind( CambridgeMaps );
fi;





More information about the Forum mailing list