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


Quelle  ctbldisp.g   Sprache: unbekannt

 
#############################################################################
##
#W  ctbldisp.g            GAP 4 package `browse'                Thomas Breuer
##
##  <#GAPDoc Label="Ctbl_section">
##  <Section Label="sec:ctbldisp">
##  <Heading>Character Table Display</Heading>
##
##  The &GAP; library provides a <Ref Oper="Display" BookName="ref"/> method
##  for character tables
##  that breaks the table into columns fitting on the screen.
##  &Browse; provides an alternative,
##  using the standard facilities of the function
##  <Ref Func="NCurses.BrowseGeneric"/>, i. e.,
##  one can scroll in the matrix of character values,
##  searching and sorting are provided etc.
##  <P/>
##  The <Ref Oper="Browse"/> method for character tables can be called
##  instead of <Ref Oper="Display" BookName="ref"/>.
##  For convenience, one can additionally make this function the default
##  <Ref Oper="Display" BookName="ref"/> method for character tables,
##  by assigning it to the <C>Display</C> component in the global record
##  <C>CharacterTableDisplayDefaults.User</C>,
##  see <Ref Sect="Printing Character Tables" BookName="ref"/>;
##  for example, one can do this in one's <F>gaprc</F> file,
##  see <Ref Sect="The gap.ini and gaprc files" BookName="ref"/>.
##  (This can be undone by unbinding the component
##  <C>CharacterTableDisplayDefaults.User.Display</C>.)
##  <P/>
##  The function <Ref Func="BrowseDecompositionMatrix"/> can be used to
##  display decomposition matrices for Brauer character tables.
##
##  <#Include Label="Browse_Ctbl">
##  <#Include Label="BrowseDecompositionMatrix">
##
##  </Section>
##  <#/GAPDoc>
##


#############################################################################
##
#M  Browse( <tbl>[, <options>] )
##
##  <#GAPDoc Label="Browse_Ctbl">
##  <ManSection>
##  <Meth Name="Browse" Arg="tbl[, options]" Label="for character tables"/>
##
##  <Description>
##  This method displays the character table <A>tbl</A> in a window.
##  The optional record <A>options</A> describes what shall be displayed,
##  the supported components and the default values are described
##  in <Ref Sect="Printing Character Tables" BookName="ref"/>.
##  <P/>
##  The full functionality of the function
##  <Ref Func="NCurses.BrowseGeneric"/> is available.
##  <P/>
##  <Example><![CDATA[
##  gap> if TestPackageAvailability( "CTblLib" ) = true then
##  >      BrowseData.SetReplay( Concatenation(
##  >         # scroll in the table
##  >         "DRULdddddrrrrrlluu",
##  >         # select an entry and move it around
##  >         "seddrruuuddlll",
##  >         # search for the pattern 135 (six times)
##  >         "/135", [ NCurses.keys.ENTER ], "nnnnn",
##  >         # deselect the entry, select the first column
##  >         "qLsc",
##  >         # sort and categorize by this column
##  >         "sc",
##  >         # select the first row, move down the selection
##  >         "srdddd",
##  >         # expand the selected category, scroll the selection down
##  >         "xd",
##  >         # and quit the application
##  >         "Q" ) );
##  >      Browse( CharacterTable( "HN" ) );
##  >      BrowseData.SetReplay( false );
##  > fi;
##  ]]></Example>
##  <P/>
##  <E>Implementation remarks</E>:
##  The first part of the code in the <Ref Oper="Browse"/> method
##  for character tables is almost identical with the code for extracting
##  the data to be displayed from the input data in the &GAP; library
##  function <C>CharacterTableDisplayDefault</C>.
##  The second part of the code transforms these data into a browse table.
##  Character names and (if applicable) indicator values are used as row
##  labels,
##  and centralizer orders, power maps, and class names are used as column
##  labels.
##  The identifier of the table is used as the static header.
##  When an irrational entry is selected, a description of this entry is
##  shown in the dynamic footer.
##  <P/>
##  The standard modes in <Ref Var="BrowseData"/> (except the <C>help</C>
##  mode) have been extended by three new actions.
##  The first two of them open pagers giving an overview of all
##  irrationalities in the table, or of all those irrationalities that have
##  been shown on the screen in the current call, respectively.
##  The corresponding user inputs are the <B>I</B> and the <B>i</B> key.
##  (The names assigned to the irrationalities are generated column-wise.
##  If one just scrolls through the table, without jumping,
##  then these names coincide with the names generated by the default
##  <Ref Oper="Display" BookName="ref"/> method for character tables;
##  this is in general <E>not</E> the case,
##  for example when a row-wise search in the table is performed.)
##  The third new action, which is associated with the <B>p</B> key,
##  toggles the visibility status of the column label rows for centralizer
##  orders and power maps.
##  <P/>
##  An individual <C>minyx</C> function does not only check whether the
##  desired table fits into the window but also whether a table with too high
##  column labels (centralizer orders and power maps) would fit if these
##  labels get collapsed via the <B>p</B> key.
##  In this case, the labels are automatically collapsed, and the <B>p</B>
##  key is disabled.
##  <P/>
##  In order to keep the required space small also for large character
##  tables, caching of formatted matrix entries is disabled,
##  and the strings to be displayed are computed on demand with a
##  <C>Main</C> function in the <C>work</C> component of the browse table.
##  For the same reason, the constant height one for all table rows is set
##  in advance, so one need not inspect a whole character if only a few
##  values of it shall be shown.
##  <P/>
##  Special functions are provided for
##  sorting (concerning the comparison of character values,
##  which can be integers or irrationalities) and
##  categorizing the table by a column (the value in the category row
##  involves the class name of the column in question).
##  <P/>
##  The code can be found in the file <F>app/ctbldisp.g</F> of the package.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
if not IsBound( CambridgeMaps ) then
  CambridgeMaps:= "dummy";
fi;

InstallMethod( Browse,
    [ "IsNearlyCharacterTable" ],
    function( tbl )
    if   HasDisplayOptions( tbl ) then
      Browse( tbl, DisplayOptions( tbl ) );
    elif IsBound( CharacterTableDisplayDefaults.User ) then
      Browse( tbl, CharacterTableDisplayDefaults.User );
    else
      Browse( tbl, CharacterTableDisplayDefaults.Global );
    fi;
    end );


InstallOtherMethod( Browse,
    [ "IsNearlyCharacterTable", "IsList" ],
    function( tbl, chars )
    Browse( tbl, rec( chars:= chars ) );
    end );


InstallMethod( Browse,
    [ "IsNearlyCharacterTable", "IsRecord" ],
    function( tbl, options )
    local log, replay, record, stringEntry, stringEntryData, legend,
          cletter, centralizers, chars_from_irr, cnr, chars, charnames,
          classes, tbl_powermap, powermap, field_degrees, indicator, OD, nam,
          indic, i, oddata, ind2, entry, heights, modes, table, ind, p,
          degrees, j, list, hidecollabelspos, mode, pos;

    # Use only the argument record for the history.
    if IsBound( options.log ) and IsBound( options.replay ) then
      log:= options.log;
      replay:= options.replay;
    else
      log:= fail;
    fi;

    # 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.Legend ) then
        legend:= record.Legend;
        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;
    for record in options do
      if IsBound( record.charnames ) and IsList( record.charnames ) then
        charnames:= record.charnames;
        break;
      fi;
    od;
    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 degrees of character fields?
    field_degrees:= false;
    for record in options do
      if IsBound( record.characterField ) then
        if record.characterField = true then
          field_degrees:= true;
        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;

    # print orthogonal discriminants
    OD:= false;
    if chars_from_irr then
      for record in options do
        if IsBound( record.OD ) then
          if record.OD = true then
            OD:= true;
          fi;
          break;
        fi;
      od;
    fi;

    # (end of options handling)

    # prepare class names
    if powermap = "ATLAS" 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 and OD
    indic:= [];
    if OD then
      if not 2 in indicator then
        indicator:= Concatenation( [ 2 ], indicator );
      fi;
      indicator:= Concatenation( [ "OD" ], indicator );
    fi;
    if indicator <> [] then
      for i in [ 1 .. Length( indicator ) ] do
        if indicator[i] = "OD" then
          indic[1]:= ListWithIdenticalEntries( Length( cnr ), "" );
          if IsBoundGlobal( "OrthogonalDiscriminants" ) then
            oddata:= ValueGlobal( "OrthogonalDiscriminants" )( tbl );
            for j in [ 1 .. Length( cnr ) ] do
              if IsBound( oddata[ cnr[j] ] ) then
                indic[1][j]:= oddata[ cnr[j] ];
              fi;
            od;
          else
            # Show '?' and empty strings.
            ind2:= Indicator( tbl, Irr( tbl ){ cnr }, 2 );
            for j in [ 1 .. Length( cnr ) ] do
              if ( not ind2[ cnr[j] ] in [ -1, 0 ] ) and
                 Irr( tbl )[ cnr[j] ][1] mod 2 = 0 then
                indic[1][j]:= "?";
              fi;
            od;
          fi;
        else
          if chars_from_irr and
             IsBound( ComputedIndicators( tbl )[ indicator[i] ] ) then
            indic[i]:= ComputedIndicators( tbl )[ indicator[i] ]{ cnr };
          else
            indic[i]:= Indicator( tbl, chars, indicator[i] );
          fi;
        fi;
      od;
    fi;

    heights:= ListWithIdenticalEntries( 2 * Length( chars ) + 1, 0 );
    for i in [ 2, 4 .. 2 * Length( chars ) ] do
      heights[i]:= 1;
    od;

    # Construct the extended modes if necessary.
    if not IsBound( BrowseData.defaults.work.customizedModes.ctbldisp ) then
      # Create a shallow copy of each default mode for `Browse',
      # and add new actions to all available modes (except the help mode):
      # - i: Show a pager with the irrationalities that have been shown.
      # - I: Show a pager with all irrationalities in the table.
      # - p: Toggle power maps and centralizer orders (but not class names).
      modes:= List( BrowseData.defaults.work.availableModes,
                    BrowseData.ShallowCopyMode );
      BrowseData.defaults.work.customizedModes.ctbldisp:= modes;
      for mode in modes do
        if mode.name <> "help" then
          BrowseData.SetActions( mode, [
            [ [ "i" ], rec( helplines := [
                 "show an overview of those irrationalities in the table",
                 "that have been displayed in the current call" ],
              action := function( t )
                local str;

                str:= legend( t.work.legend );
                if IsEmpty( str ) then
                  str:= "(no irrationalities yet in this table)";
                fi;
                if BrowseData.IsDoneReplay( t.dynamic.replay ) then
                  NCurses.Pager( str );
                  NCurses.update_panels();
                  NCurses.doupdate();
                  NCurses.curs_set( 0 );
                fi;
                return t.dynamic.changed;
              end ) ],
            [ [ "I" ], rec( helplines := [
                 "show an overview of all irrationalities in the table" ],
              action := function( t )
                local j, i, str;

                # We proceed column-wise, like the traditional `Display'.
                for j in [ 1 .. t.work.n ] do
                  for i in [ 1 .. t.work.m ] do
                    stringEntry( t.dynamic.chars[i][ classes[j] ],
                                 t.work.legend );
                  od;
                od;
                str:= legend( t.work.legend );
                if IsEmpty( str ) then
                  str:= "(no irrationalities in this table)";
                fi;
                if BrowseData.IsDoneReplay( t.dynamic.replay ) then
                  NCurses.Pager( str );
                  NCurses.update_panels();
                  NCurses.doupdate();
                  NCurses.curs_set( 0 );
                fi;
                return t.dynamic.changed;
              end ) ],
            [ [ "p" ], rec( helplines := [
                 "toggle power maps and centralizer orders" ],
              action := function( t )
                local i;

                if t.dynamic.togglePowerMaps then
                  for i in t.dynamic.hidecollabelspos do
                    t.dynamic.isRejectedLabelsCol[i]:=
                        not t.dynamic.isRejectedLabelsCol[i];
                  od;
                  t.dynamic.changed:= true;
                else
                  BrowseData.AlertWithReplay( t,
                      "The screen is too small for expanding power maps.",
                      NCurses.attrs.BOLD );
                fi;
                return t.dynamic.changed;
              end ) ],
          ] );
        fi;
      od;
    else
      modes:= BrowseData.defaults.work.customizedModes.ctbldisp;
    fi;

    # Store the positions of centralizer orders and power maps.
    hidecollabelspos:= [];

    # Construct the browse table.
    table:= rec(
      work:= rec(
        align:= "ct",
        header:= [ Identifier( tbl ) ],
        footer:= rec(
          # Show a description of a selected irrational value.
          select_entry:= function( t )
            local entry, result, pos, q;

            if t.dynamic.selectedEntry = [ 0, 0 ] then
              entry:= First( t.dynamic.categories[2],
                x -> [ x.pos, x.level ] = t.dynamic.selectedCategory ).value;
              pos:= PositionSublist( entry, " = " );
              entry:= entry{ [ pos+3 .. Length( entry ) ] };
            else
              entry:= t.work.Main( t,
                t.dynamic.indexRow[ t.dynamic.selectedEntry[1] ] / 2,
                t.dynamic.indexCol[ t.dynamic.selectedEntry[2] ] / 2 );
            fi;
            result:= [ "", "", "" ];
            if Int( entry ) = fail then
              while 0 < Length( entry ) and entry[1] in "-/*" do
                entry:= entry{ [ 2 .. Length( entry ) ] };
              od;
              pos:= Position( t.work.legend.irrnames, entry );
              if pos <> fail then
                result[2]:= Concatenation( t.work.legend.irrnames[ pos ],
                    " = ", String( t.work.legend.irrstack[ pos ] ) );
                q:= Quadratic( t.work.legend.irrstack[ pos ] );
                if q = fail then
                  result[3]:= "";
                else
                  result[3]:= Concatenation( RepeatedString( " ",
                        Length( t.work.legend.irrnames[ pos ] ) ), " = ",
                      q.display, " = ", q.ATLAS );
                fi;
              fi;
            fi;
            return result;
          end ),
        CategoryValues:= function( t, i, j )
          return [ Concatenation( nam[ classes[ j/2 ] ], " = ",
                       t.work.Main( t, i/2, j/2 ) ) ];
          end,
        availableModes:= modes,

        # Avoid computing strings for all character values in advance.
        main:= [],
        Main:= function( t, i, j )
          return stringEntry( t.dynamic.chars[i][ classes[j] ],
                              t.work.legend );
        end,
        m:= Length( chars ),
        n:= Length( classes ),

        # The labels lists will be filled below.
        labelsRow:= [ List( charnames,
                        x -> rec( rows:= [ String( x ) ], align:= "l" ) ) ],
        labelsCol:= [],
        sepLabelsRow:= [ "" ],
        sepLabelsCol:= [],
        sepCol:= [ " " ],
        corner:= [],

        # Avoid computing all entries in a row for determining the heights.
        heightRow:= heights,

        legend:= stringEntryData,
      ),
      dynamic:= rec(
        activeModes:= [ First( modes, x -> x.name = "browse" ) ],
        sortFunctionForTableDefault:= BrowseData.CompareCharacterValues,
        sortFunctionForColumnsDefault:= BrowseData.CompareCharacterValues,
        sortFunctionForRowsDefault:= BrowseData.CompareCharacterValues,

        chars:= chars,

        # Store the indices relevant for hiding power maps.
        hidecollabelspos:= hidecollabelspos,

        # On small screens, it may be forbidden to expand power maps.
        togglePowerMaps:= true,
      ),
    );

    # Provide indicator columns.
    ind:= ListWithIdenticalEntries( Maximum( 1, Length( indicator ) ), "" );

    for i in [ 1 .. Length( indicator ) ] do
      Add( table.work.sepLabelsRow, " " );
      if indicator[i] = 2 then
        list:= [];
        for j in cnr do
          if   indic[i][j] = 0 then
            Add( list, "o" );
          elif indic[i][j] = 1 then
            Add( list, "+" );
          elif indic[i][j] = -1 then
            Add( list, "-" );
          else
            Add( list, "?" );
          fi;
        od;
        Add( table.work.labelsRow, list );
      else
        Add( table.work.labelsRow, List( indic[i]{ cnr }, String ) );
      fi;
    od;

    # Provide a column for the degrees of the character fields
    # as the first column after the character labels, with label "d".
    if field_degrees then
      Add( indicator, "d", 1 );
      Add( ind, " ", 1 );
      Add( table.work.sepLabelsRow, " " );
      p:= UnderlyingCharacteristic( tbl );
      if p = 0 then
        degrees:= List( chars, x -> Dimension( Field( Rationals, x ) ) );
      else
        degrees:= List( chars, x -> Length( Factors( SizeOfFieldOfDefinition(
          ClassFunction( tbl, x ), p ) ) ) );
      fi;
      Add( table.work.labelsRow, List( degrees, String ), 2 );
    fi;

    table.work.labelsRow:= TransposedMat( table.work.labelsRow );
    if indicator = [] then
      Append( table.work.sepLabelsRow, [ "", "" ] );
    else
      Append( table.work.sepLabelsRow, [ "" ] );
    fi;

    if centralizers = "ATLAS" then
      # Add centralizers themselves as column labels.
      Add( table.work.sepLabelsCol, " " );
      Add( table.work.corner, [ "" ] );
      Add( table.work.labelsCol,
           List( SizesCentralizers( tbl ){ classes }, String ) );
#T admit splitting into two rows!
      Append( hidecollabelspos,
              2 * Length( table.work.labelsCol ) + [ 0, 1 ] );
    elif centralizers = true then
      # Add factored centralizer orders to the column labels.
      Add( table.work.sepLabelsCol, " " );
      for p in PrimeDivisors( Size( tbl ) ) do
        Add( table.work.labelsCol, List( SizesCentralizers( tbl ){ classes },
               x -> stringEntry( Number( Factors( x ), y -> y = p ),
                                 stringEntryData ) ) );
        Append( hidecollabelspos,
                2 * Length( table.work.labelsCol ) + [ 0, 1 ] );
        Add( table.work.corner,
             Concatenation( ind, [ stringEntry( p, stringEntryData ) ] ) );
        Add( table.work.sepLabelsCol, "" );
      od;
      Unbind( table.work.sepLabelsCol[ Length( table.work.sepLabelsCol ) ] );
    fi;

    # class names and power maps
    if IsRecord( powermap ) then

      # three lines: power maps, p' part, and class names
      Append( table.work.sepLabelsCol, [ " ", "", "", " " ] );
      Append( hidecollabelspos,
              2 * Length( table.work.labelsCol ) + [ 2 .. 7 ] );
      Append( table.work.labelsCol, [ powermap.power{ classes },
                                      powermap.prime{ classes },
                                      powermap.names{ classes } ] );
      Append( table.work.corner, [ Concatenation( ind, [ "p " ] ),
                                   Concatenation( ind, [ "p'" ] ) ] );
      if   indicator = [] then
        Add( table.work.corner, [ "", "" ] );
      elif indicator = [ 2 ] then
        Add( table.work.corner, [ "", "ind" ] );
      else
        Add( table.work.corner,
             Concatenation( [ "ind" ], List( indicator, String ) ) );
      fi;

    else

      # first class names, then a row for each power map
      Add( table.work.sepLabelsCol, " " );
      Add( table.work.labelsCol, List( nam{ classes }, String ) );
      Add( table.work.corner, Concatenation( ind, [ "" ] ) );

      for p in powermap do
        list:= CompositionMaps( nam, tbl_powermap[p] ){ classes };
        for i in [ 1 .. Length( list ) ] do
          if not IsString( list[i] ) then
            list[i]:= "?";
          fi;
        od;
        Add( table.work.labelsCol, list );
        Append( hidecollabelspos,
                2 * Length( table.work.labelsCol ) + [ 0, 1 ] );
        Add( table.work.corner,
             Concatenation( ind, [ Concatenation( String( p ), "P" ) ] ) );
        Add( table.work.sepLabelsCol, "" );
      od;

      # Add a data row showing the indicator header (may be empty).
      Add( table.work.sepLabelsCol, "" );
      Add( table.work.sepLabelsCol, "" );
      Add( table.work.corner,
           Concatenation( [ "" ], List( indicator, String ) ) );

    fi;

    if indicator <> [] and powermap <> [] then
      # Replace the separator before the last indicator by empty
      # if its column is only one character wide
      # and if power maps are shown.
      pos:= Length( indicator ) + 1;
      if indicator[ Length( indicator ) ] < 10 and
         ForAll( table.work.labelsRow, x -> Length( x[ pos ] ) <= 1 ) then
        table.work.sepLabelsRow[ pos ]:= "";
      fi;
    fi;

    # Check whether at least one character and at least the degree column
    # fit into the window (the footer needs at most three lines).
    # If the window is not high enough for the column labels then hide them
    # and forbid expanding them.
    table.work.minyx:= [ function( t )
      local maxyx, minyx;

      maxyx:= NCurses.getmaxyx( 0 );
      minyx:= BrowseData.MinimalWindowHeight( t ) + 3;
      if maxyx[1] < minyx then
        # Try to collapse power maps.
        if t.dynamic.togglePowerMaps then
          for i in t.dynamic.hidecollabelspos do
            t.dynamic.isRejectedLabelsCol[i]:= true;
          od;
          t.dynamic.togglePowerMaps:= false;
          minyx:= BrowseData.MinimalWindowHeight( t ) + 3;
        fi;
      fi;

      return minyx;
      end,
      BrowseData.MinimalWindowWidth ];

    # Enter the history if available.
    if log <> fail then
      table.dynamic.log:= log;
      table.dynamic.replay:= replay;
    fi;

    # Show the table.
    NCurses.BrowseGeneric( table );
end );

if CambridgeMaps = "dummy" then
  Unbind( CambridgeMaps );
fi;


#############################################################################
##
#F  BrowseDecompositionMatrix( <modtbl>[, <b>][, <options>] )
##
##  <#GAPDoc Label="BrowseDecompositionMatrix">
##  <ManSection>
##  <Func Name="BrowseDecompositionMatrix" Arg="modtbl[, b][, options]"/>
##
##  <Description>
##  This method displays the decomposition matrix of (the <A>b</A>-th block
##  of) the Brauer character table <A>modtbl</A> in a window.
##  The arguments are the same as for
##  <Ref Func="LaTeXStringDecompositionMatrix" BookName="ref"/>.
##  <P/>
##  The positions of the ordinary and modular irreducible characters
##  are shown in the labels of the rows and columns, respectively,
##  that are indexed by these characters.
##  When an entry in the decomposition matrix is selected then information
##  about the degrees of these characters is shown in the table footer.
##  <P/>
##  The full functionality of the function
##  <Ref Func="NCurses.BrowseGeneric"/> is available.
##  <P/>
##  <Example><![CDATA[
##  gap> BrowseData.SetReplay( Concatenation(
##  >         # select the first entry
##  >         "se",
##  >         # scroll in the table
##  >         "drrrr",
##  >         # keep the table open for a while
##  >         [ 14, 14, 14, 14, 14 ],
##  >         # and quit the application
##  >         "Q" ) );
##  gap> BrowseDecompositionMatrix( CharacterTable( "J1" ) mod 2 );
##  gap> BrowseData.SetReplay( false );
##  ]]></Example>
##  <P/>
##  The code can be found in the file <F>app/ctbldisp.g</F> of the package.
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##
BindGlobal( "BrowseDecompositionMatrix", function( arg )
    local options,       # record with labels, optional third argument
          blocknr,       # number of the block, optional second argument
          modtbl,        # Brauer character table, first argument
          decmat,        # decomposition matrix
          r, j,
          phi,           # string used for Brauer characters
          chi,           # string used for ordinary irreducibles
          collabels,     # indices of Brauer characters
          rowlabels,     # indices of ordinary characters
          block,         # block information on `modtbl'
          ordtbl, p, irr, orddegrees, moddegrees, extrowlabels, extcollabels,
          header, table;

    # Get and check the arguments.
    if   Length( arg ) = 2 and IsBrauerTable( arg[1] )
                           and IsRecord( arg[2] ) then
      options := arg[2];
    elif Length( arg ) = 2 and IsBrauerTable( arg[1] )
                           and IsInt( arg[2] ) then
      blocknr := arg[2];
      options := rec();
    elif Length( arg ) = 3 and IsBrauerTable( arg[1] )
                           and IsInt( arg[2] )
                           and IsRecord( arg[3] ) then
      blocknr := arg[2];
      options := arg[3];
    elif Length( arg ) = 1 and IsBrauerTable( arg[1] ) then
      options := rec();
    else
      Error( "usage: BrowseDecompositionMatrix(",
             " <modtbl>[, <blocknr>][, <options>] )" );
    fi;

    # Compute the decomposition matrix.
    modtbl:= arg[1];
    if IsBound( options.decmat ) then
      decmat:= options.decmat;
    elif IsBound( blocknr ) then
      decmat:= DecompositionMatrix( modtbl, blocknr );
    else
      decmat:= DecompositionMatrix( modtbl );
    fi;
    decmat:= List( decmat, ShallowCopy );
    for r in decmat do
      for j in [ 1 .. Length( r ) ] do
        if r[j] = 0 then
          r[j]:= ".";
        else
          r[j]:= String( r[j] );
        fi;
      od;
    od;

    # Choose default labels if necessary.
    phi:= "Y";
    chi:= "X";

    # Construct the labels if necessary.
    if IsBound( options.phi ) then
      phi:= options.phi;
    fi;
    if IsBound( options.chi ) then
      chi:= options.chi;
    fi;
    if IsBound( options.collabels ) then
      collabels:= options.collabels;
      if ForAll( collabels, IsInt ) then
        collabels:= List( collabels,
            i -> Concatenation( phi, "_", String(i) ) );
      fi;
    fi;
    if IsBound( options.rowlabels ) then
      rowlabels:= options.rowlabels;
      if ForAll( rowlabels, IsInt ) then
        rowlabels:= List( rowlabels,
            i -> Concatenation( chi, "_", String(i) ) );
      fi;
    fi;

    # Construct the labels if they are still missing.
    if not IsBound( collabels ) then
      if IsBound( blocknr ) then
        block     := BlocksInfo( modtbl )[ blocknr ];
        collabels := List( block.modchars, String );
      else
        collabels := List( [ 1 .. Length( decmat[1] ) ], String );
      fi;
      collabels:= List( collabels, i -> Concatenation( phi, "_", i ) );
    fi;
    if not IsBound( rowlabels ) then
      if IsBound( blocknr ) then
        block     := BlocksInfo( modtbl )[ blocknr ];
        rowlabels := List( block.ordchars, String );
      else
        rowlabels := List( [ 1 .. Length( decmat ) ], String );
      fi;
      rowlabels:= List( rowlabels, i -> Concatenation( chi, "_", i ) );
    fi;

    # Construct the information to be shown in the footer.
    ordtbl:= OrdinaryCharacterTable( modtbl );
    p:= UnderlyingCharacteristic( modtbl );
    irr:= List( Irr( ordtbl ), x -> x[1] );
    orddegrees:= List( [ 1 .. Length( irr ) ],
                       i -> Concatenation( String( irr[i] ), "_",
                                String( Number( [ 1 .. i ],
                                              x -> irr[x] = irr[i] ) ) ) );
    irr:= List( Irr( modtbl ), x -> x[1] );
    moddegrees:= List( [ 1 .. Length( irr ) ],
                       i -> Concatenation( String( irr[i] ), "_",
                                String( Number( [ 1 .. i ],
                                              x -> irr[x] = irr[i] ) ) ) );
    if IsBound( blocknr ) then
      orddegrees:= orddegrees{ block.ordchars };
      moddegrees:= moddegrees{ block.modchars };
    fi;
    extcollabels:= List( [ 1 .. Length( collabels ) ],
        i -> Concatenation( collabels[i], " = ", moddegrees[i] ) );
    extrowlabels:= List( [ 1 .. Length( rowlabels ) ],
        i -> Concatenation( rowlabels[i], " = ", orddegrees[i] ) );

    header:= Concatenation( Identifier( ordtbl ), " mod ", String( p ) );
    if IsBound( blocknr ) then
      Append( header, ", block " );
      Append( header, String( blocknr ) );
      Append( header, ", defect " );
      Append( header, String( PrimeBlocks( ordtbl, p ).defect[ blocknr ] ) );
    fi;

    # Construct the browse table.
    table:= rec(
      work:= rec(
        align:= "ct",
        header:= [ header, "" ],
        footer:= rec(
          # Show the degrees of the two irreducibles involved.
          select_entry:= function( t )
            local pos;

            if t.dynamic.selectedEntry = [ 0, 0 ] then
              return [ "", "", "" ];
            else
              pos:= [ t.dynamic.indexRow[ t.dynamic.selectedEntry[1] ] / 2,
                      t.dynamic.indexCol[ t.dynamic.selectedEntry[2] ] / 2 ];
              return [ "", extrowlabels[ pos[1] ], extcollabels[ pos[2] ] ];
            fi;
          end ),
        main:= decmat,
        labelsRow:= List( rowlabels,
                          x -> [ rec( rows:= [ x ], align:= "l" ) ] ),
        labelsCol:= [ List( collabels,
                            x -> rec( rows:= [ x ], align:= "l" ) ) ],
        sepLabelsRow:= [ "", "|" ],
        sepLabelsCol:= [ "", "-" ],
        sepCol:= [ " " ],
        corner:= [],
        SpecialGrid:= BrowseData.SpecialGridLineDrawPlus,
      ),
      dynamic:= rec(
      ),
    );

    # Enter the history if available.
    if IsBound( options.log ) and IsBound( options.replay ) then
      table.dynamic.log:= options.log;
      table.dynamic.replay:= options.replay;
    fi;

    NCurses.BrowseGeneric( table );
end );


#############################################################################
##
#E


[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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