Goto Chapter: Top 1 2 3 4 5 6 A Bib Ind
 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 

6 Examples of Applications based on NCurses.BrowseGeneric
 6.1 The Operation Browse
 6.2 Matrix Display
 6.3 Character Table Display
 6.4 Table of Marks Display
 6.5 Table of Contents of AtlasRep
 6.6 Access to GAP Manuals–a Variant
 6.7 Overview of Bibliographies
 6.8 Profiling GAP functions–a Variant
 6.9 Variables defined in GAP packages–a Variant
 6.10 Configuring User preferences–a Variant
 6.11 Overview of GAP Data
 6.12 Navigating in a Directory Tree
 6.13 A Puzzle
 6.14 Peg Solitaire
 6.15 Rubik's Cube
 6.16 Changing Sides
 6.17 Sudoku
 6.18 Managing simple Workflows
 6.19 Utility for GAP Demos

6 Examples of Applications based on NCurses.BrowseGeneric

This chapter introduces the operation Browse (6.1-1) and lists several examples how the function NCurses.BrowseGeneric (4.3-1) can be utilized for rendering GAP related data or for playing games. Each section describes the relevant GAP functions and briefly sketches the technical aspects of the implementation; more details can be found in the GAP files, in the app directory of the package.

Only Section 6.4 describes a standard application in the sense of the introduction to Chapter 4, perhaps except for a special function that is needed to compare table entries. The other examples in this chapter require some of the programming described in Chapter 5.

The GAP examples in this chapter use the "replay" feature of NCurses.BrowseGeneric (4.3-1), see Section 4.1. This means that the NCurses.BrowseGeneric (4.3-1) based function is called between two calls of BrowseData.SetReplay (5.4-2). If you want to paste these examples into the GAP session with the mouse then do not paste the final BrowseData.SetReplay (5.4-2) call, since NCurses.BrowseGeneric (4.3-1) would regard the additional input as a user interrupt.

6.1 The Operation Browse

6.1-1 Browse
‣ Browse( obj[, arec] )( operation )

This operation displays the GAP object obj in a nice, formatted way, similar to the operation Display (Reference: Display). The difference is that Browse is intended to use ncurses facilities.

Currently there are methods for matrices (see Browse (6.2-2)), for character tables (see Browse (6.3-1)) and for tables of marks (see Browse (6.4-1)).

6.2 Matrix Display

The GAP library provides several Display (Reference: Display) methods for matrices. In order to cover the functionality of these methods, Browse provides the function NCurses.BrowseDenseList (6.2-1) that uses the standard facilities of the function NCurses.BrowseGeneric (4.3-1), i. e., one can scroll in the matrix, searching and sorting are provided etc.

The idea is to customize this function for different special cases, and to install corresponding Browse (6.1-1) methods. Examples are methods for matrices over finite fields and residue class rings of the rational integers, see Browse (6.2-2).

The code can be found in the file app/matdisp.g of the package.

6.2-1 NCurses.BrowseDenseList
‣ NCurses.BrowseDenseList( list, arec )( function )

Returns: nothing.

Let list be a dense list whose entries are lists, for example a matrix, and let arec be a record. This function displays list in a window, as a two-dimensional array with row and column positions as row and column labels, respectively.

The following components of arec are supported.

header

If bound, the value must be a valid value of the work.header component of a browse table, see BrowseData.IsBrowseTable (4.2-3); for example, the value can be a list of strings. If this component is not bound then the browse table has no header.

footer

If bound, the value must be a valid value of the work.footer component of a browse table, see BrowseData.IsBrowseTable (4.2-3); for example, the value can be a list of strings. If this component is not bound then the browse table has no footer.

convertEntry

If bound, the value must be a unary function that returns a string describing its argument. The default is the operation String (Reference: String). Another possible value is NCurses.ReplaceZeroByDot, which returns the string "." if the argument is a zero element in the sense of IsZero (Reference: IsZero), and returns the String (Reference: String) value otherwise. For each entry in a row of list, the convertEntry value is shown in the browse table.

labelsRow

If bound, the value must be a list of row label rows for list, as described in Section BrowseData.IsBrowseTable (4.2-3). The default is [ [ "1" ], [ "2" ], ... ].

labelsCol

If bound, the value must be a list of column label rows for list, as described in Section BrowseData.IsBrowseTable (4.2-3). The default is [ [ "1", "2", ... ] ].

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

6.2-2 Browse
‣ Browse( list )( method )

Returns: nothing.

Several methods for the operation Browse (6.1-1) are installed for the case that the argument is a list of lists. These methods cover a default method for lists of lists and the Display (Reference: Display) methods for matrices over finite fields and residue class rings of the rational integers. Note that matrices over finite prime fields, small extension fields, and large extension fields are displayed differently, and the same holds for the corresponding Browse (6.1-1) methods.

gap> n:= [ 14, 14, 14, 14 ];;
gap> input:= Concatenation( n, n, n, "Q" );;  # ``do nothing and quit''
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, Integers ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF(3) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF(4) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, Integers mod 6 ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF( NextPrimeInt( 2^16 ) ) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF( 2^20 ) ) );
gap> BrowseData.SetReplay( false );

6.3 Character Table Display

The GAP library provides a Display (Reference: Display) 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 NCurses.BrowseGeneric (4.3-1), i. e., one can scroll in the matrix of character values, searching and sorting are provided etc.

The Browse (6.1-1) method for character tables can be called instead of Display (Reference: Display). For convenience, one can additionally make this function the default Display (Reference: Display) method for character tables, by assigning it to the Display component in the global record CharacterTableDisplayDefaults.User, see Reference: Printing Character Tables; for example, one can do this in one's gaprc file, see Reference: The gap.ini and gaprc files. (This can be undone by unbinding the component CharacterTableDisplayDefaults.User.Display.)

The function BrowseDecompositionMatrix (6.3-2) can be used to display decomposition matrices for Brauer character tables.

6.3-1 Browse
‣ Browse( tbl[, options] )( method )

This method displays the character table tbl in a window. The optional record options describes what shall be displayed, the supported components and the default values are described in Reference: Printing Character Tables.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

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;

Implementation remarks: The first part of the code in the Browse (6.1-1) 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 CharacterTableDisplayDefault. 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.

The standard modes in BrowseData (5.4-1) (except the help 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 I and the i 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 Display (Reference: Display) method for character tables; this is in general not the case, for example when a row-wise search in the table is performed.) The third new action, which is associated with the p key, toggles the visibility status of the column label rows for centralizer orders and power maps.

An individual minyx 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 p key. In this case, the labels are automatically collapsed, and the p key is disabled.

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 Main function in the work 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.

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).

The code can be found in the file app/ctbldisp.g of the package.

6.3-2 BrowseDecompositionMatrix
‣ BrowseDecompositionMatrix( modtbl[, b][, options] )( function )

This method displays the decomposition matrix of (the b-th block of) the Brauer character table modtbl in a window. The arguments are the same as for LaTeXStringDecompositionMatrix (Reference: LaTeXStringDecompositionMatrix).

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.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

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 );

The code can be found in the file app/ctbldisp.g of the package.

6.4 Table of Marks Display

The GAP library provides a Display (Reference: Display) method for tables of marks that breaks the table into columns fitting on the screen. Similar to the situation with character tables, see Section 6.3, but with a much simpler implementation, Browse provides an alternative based on the function NCurses.BrowseGeneric (4.3-1).

Browse (6.1-1) can be called instead of Display (Reference: Display) for tables of marks, cf. Reference: Printing Tables of Marks.

6.4-1 Browse
‣ Browse( tom[, options] )( method )

This method displays the table of marks tom in a window. The optional record options describes what shall be displayed, the supported components and the default values are described in Reference: Printing Tables of Marks.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> if TestPackageAvailability( "TomLib" ) = true then
>      BrowseData.SetReplay( Concatenation(
>         # scroll in the table
>         "DDRRR",
>         # search for the (exact) value 100 (three times)
>         "/100",
>         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.RIGHT ],
>         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.DOWN ],
>         [ NCurses.keys.RIGHT, NCurses.keys.ENTER ], "nn",
>         # no more occurrences of 100, confirm
>         [ NCurses.keys.ENTER ],
>         # and quit the application
>         "Q" ) );
>      Browse( TableOfMarks( "A10" ) );
>      BrowseData.SetReplay( false );
>    fi;

Implementation remarks: Rows and columns are indexed by their positions. The identifier of the table is used as the static header, there is no footer.

In order to keep the required space small also for large tables of marks, caching of formatted matrix entries is disabled, and the strings to be displayed are computed on demand with a Main function in the work component of the browse table. For the same reason, the constant height one for the table rows is set in advance. (For example, the table of marks of the group with identifier "O8+(2)", with \(11171\) rows and columns, can be shown with Browse (6.1-1) in a GAP session requiring about \(100\) MB.)

The code can be found in the file app/tomdisp.g of the package.

6.5 Table of Contents of AtlasRep

The GAP package AtlasRep (see [WPN+19]) is an interface to a database of representations and related data. The table of contents of this database can be displayed via the function DisplayAtlasInfo (AtlasRep: DisplayAtlasInfo) of this package. The Browse package provides an alternative based on the function NCurses.BrowseGeneric (4.3-1); one can scroll, search, and fetch data for later use.

6.5-1 BrowseAtlasInfo
‣ BrowseAtlasInfo( [listofnames][,] ["contents", sources][,] [...] )( function )
‣ BrowseAtlasInfo( gapname[, std][, ...] )( function )

Returns: the list of "clicked" info records.

This function shows the information available via the GAP package AtlasRep in a browse table, cf. Section AtlasRep: Accessing Data via AtlasRep in the AtlasRep manual.

The optional arguments can be used to restrict the table to core data or data extensions, or to show an overview for one particular group. The arguments are the same as for DisplayAtlasInfo (AtlasRep: DisplayAtlasInfo), see the documentation of this function for details. (Note that additional conditions such as IsPermGroup (Reference: IsPermGroup) can be entered also in the case that no gapname is given. In this situation, the additional conditions are evaluated for the "second level tables" that are opened by "clicking" on a table row or entry.)

When one "clicks" on one of the table rows or entries then a browse table with an overview of the information available for this group is shown, and "clicking" on one of the rows in these tables adds the corresponding info record (see OneAtlasGeneratingSetInfo (AtlasRep: OneAtlasGeneratingSetInfo)) to the list of return values of BrowseAtlasInfo.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

The following example shows how BrowseAtlasInfo can be used to fetch info records about permutation representations of the alternating groups \(A_5\) and \(A_6\): We search for the group name "A5" in the overview table, and the first cell in the table row for \(A_5\) becomes selected; hitting the Enter key causes a new window to be opened, with an overview of the data available for \(A_5\); moving down two rows and hitting the Enter key again causes the second representation to be added to the result list; hitting Q closes the second window, and we are back in the overview table; we move the selection down twice (to the row for the group \(A_6\)), and choose the first representation for this group; finally we leave the table, and the return value is the list with the data for the two representations.

gap> d:= [ NCurses.keys.DOWN ];;  r:= [ NCurses.keys.RIGHT ];;
gap> c:= [ NCurses.keys.ENTER ];;
gap> BrowseData.SetReplay( Concatenation(
>        "/A5",         # Find the string A5 ...
>        d, d, r,       # ... such that just the word matches,
>        c,             # start the search,
>        c,             # click the table entry A5,
>        d, d,          # move down two rows,
>        c,             # click the row for this representation,
>        "Q",           # quit the second level table,
>        d, d,          # move down two rows,
>        c,             # click the table entry A6,
>        d,             # move down one row,
>        c,             # click the first row,
>        "Q",           # quit the second level table,
>        "Q" ) );       # and quit the application.
gap> if IsBound( BrowseAtlasInfo ) and IsBound( AtlasProgramInfo ) then
>      SetUserPreference( "AtlasRep", "AtlasRepMarkNonCoreData", "" );
>      tworeps:= BrowseAtlasInfo();
>    else
>      tworeps:= [ fail ];
>    fi;
gap> BrowseData.SetReplay( false );
gap> if fail in tworeps then
>      Print( "no access to the Web ATLAS\n" );
>    else
>      Print( List( tworeps, x -> x.identifier[1] ), "\n" );
>    fi;
[ "A5", "A6" ]

Implementation remarks: The first browse table shown has a static header, no footer and row labels, one row of column labels describing the type of data summarized in the columns.

Row and column separators are drawn as grids (cf. NCurses.Grid (2.2-8)) composed from the special characters described in Section 2.1-6, using the component work.SpecialGrid of the browse table, see BrowseData (5.4-1).

When a row is selected, the "click" functionality opens a new window (via a second level call to NCurses.BrowseGeneric (4.3-1)), in which a browse table with the list of available data for the given group is shown; in this table, "click" results in adding the info for the selected row to the result list, and a message about this addition is shown in the footer row. One can choose further data, return to the first browse table, and perhaps iterate the process for other groups. When the first level table is left, the list of info records for the chosen data is returned.

For the two kinds of browse tables, the standard modes in BrowseData (5.4-1) (except the help mode) have been extended by a new action that opens a pager giving an overview of all data that have been chosen in the current call. The corresponding user input is the Y key.

This function is available only if the GAP package AtlasRep is available.

The code can be found in the file app/atlasbrowse.g of the package.

6.6 Access to GAP Manuals–a Variant

A Browse adapted way to access several manuals is to show the hierarchy of books, chapters, sections, and subsections as collapsible category rows, and to regard the contents of each subsection as a data row of a matrix with only one column.

This application is mainly intended as an example with table cells that exceed the screen, and as an example with several category levels.

6.6-1 BrowseGapManuals
‣ BrowseGapManuals( [start] )( function )

This function displays the contents of the GAP manuals (the main GAP manuals as well as the loaded package manuals) in a window. The optional argument start describes the initial status, admissible values are the strings "inline/collapsed", "inline/expanded", "pager/collapsed", and "pager/expanded".

In the inline cases, the parts of the manuals are shown in the browse table, and in the pager case, the parts of the manuals are shown in a different window when they are "clicked", using the user's favourite help viewer, see Reference: Changing the Help Viewer.

In the collapsed cases, all category rows are collapsed, and the first row is selected; typical next steps are moving down the selection and expanding single category rows. In the expanded cases, all category rows are expanded, and nothing is selected; a typical next step in the inline/expanded case is a search for a string in the manuals. (Note that searching in quite slow: For viewing a part of a manual, the file with the corresponding section is read into GAP, the text is formatted, the relevant part is cut out from the section, perhaps markup is stripped off, and finally the search is performed in the resulting strings.)

If no argument is given then the user is asked for selecting an initial status, using NCurses.Select (3.1-2).

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> BrowseData.SetReplay( Concatenation(
>        "xdxd",                             # expand a Tutorial section
>        n, "Q" ) );                         # and quit
gap> BrowseGapManuals( "inline/collapsed" );
gap> BrowseData.SetReplay( Concatenation(
>        "/Browse", [ NCurses.keys.ENTER ],  # search for "Browse"
>        "xdxddxd",                          # expand a section
>        n, "Q" ) );                         # and quit
gap> BrowseGapManuals( "inline/collapsed" );
gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header showing the name of the currently selected manual, no footer, no row or column labels, and exactly one column of fixed width equal to the screen width. The category rows are precomputed, i. e., they do not arise from a table column; this way, the contents of each data cell can be computed on demand, as soon as it is shown on the screen, in particular the category hierarchy is computed without reading the manuals into GAP. Also, the data rows are not cached. There is no return value. The heights of many cells are bigger than the screen height, so scrolling is a mixture of scrolling to the next cell and scrolling inside a cell. The different initial states are realized via executing different initial steps before the table is shown to the user.

For the variants that show the manuals in a pager, the code temporarily replaces the show function of the default viewer "screen" (see Reference: Changing the Help Viewer) by a function that uses NCurses.Pager (3.1-4). Note that in the case that the manual bit in question fits into one screen, the default show function writes this text directly to the screen, but this is used already by the browse table.

The implementation should be regarded as a sketch.

For example, the markup available in the text file format of GAPDoc manuals (using Esc sequences) is stripped off instead of being transferred to the attribute lines that arise, because of the highlighting problem mentioned in Section 2.2-3.

Some heuristics used in the code are due to deficiencies of the manual formats.

For the inline variant of the browse table, the titles of chapters, sections, and subsections are not regarded as parts of the actual text since they appear already as category rows; however, the functions of the GAP help system deliver the text together with these titles, so these lines must be stripped off afterwards.

The category hierarchy representing the tables of contents is created from the manual.six files of the manuals. These files do not contain enough information for determining whether several functions define the same subsection, in the sense that there is a common description text after a series of manual lines introducing different functions. In such cases, the browse table contains a category row for each of these functions (with its own number), but the corresponding text appears only under the last of these category rows, the data rows for the others are empty. (This problem does not occur in the GAPDoc manual format because this introduces explicit subsection titles, involving only the first of several function definitions.)

Also, index entries and sectioning entries in manual.six files of manuals in GAPDoc format are not explicitly distinguished.

The code can be found in the file app/manual.g of the package.

6.7 Overview of Bibliographies

The function BrowseBibliography (6.7-1) can be used to turn the contents of bibliography files in BibTeX or BibXMLext format (see GAPDoc: The BibXMLext Format) into a Browse table, such that one can scroll in the list, search for entries, sort by year, sort and categorize by authors etc.

The default bibliography used by BrowseBibliography (6.7-1) is the bibliography of GAP related publications, see [GAP]. The Browse package contains a (perhaps outdated) version of this bibliography. One can get an updated version as follows.

wget -N http://www.gap-system.org/Doc/Bib/gap-publishednicer.bib

The columns of the Browse table that is shown by BrowseBibliography (6.7-1) can be customized, two examples for that are given by the functions BrowseBibliographySporadicSimple (AtlasRep: BrowseBibliographySporadicSimple) and BrowseBibliographyGapPackages (6.7-2).

The function BrowseMSC (6.7-3) shows an overview of the AMS Mathematics Subject Classification codes.

6.7-1 BrowseBibliography
‣ BrowseBibliography( [bibfiles] )( function )

Returns: a record as returned by ParseBibXMLExtFiles (GAPDoc: ParseBibXMLextFiles).

This function shows the list of bibliography entries in the files given by bibfiles, which may be a string or a list of strings (denoting a filename or a list of filenames, respectively) or a record (see below for the supported components).

If no argument is given then the file bibl/gap-publishednicer.bib in the Browse package directory is taken, and "GAP Bibliography" is used as the header.

Another perhaps interesting data file that should be available in the GAP distribution is doc/manualbib.xml. This file can be located as follows.

gap> file:= Filename( DirectoriesLibrary( "doc" ), "manualbib.xml" );;

Both BibTeX format and the XML based extended format provided by the GAPDoc package are supported by BrowseBibliography, see Chapter GAPDoc: Utilities for Bibliographies.

In the case of BibTeX format input, first a conversion to the extended format takes place, via StringBibAsXMLext (GAPDoc: StringBibAsXMLext) and ParseBibXMLextString (GAPDoc: ParseBibXMLextString). Note that syntactically incorrect entries are rejected in this conversion –this is signaled with InfoBibTools (GAPDoc: InfoBibTools) warnings– and that only a subset of the possible LaTeX markup is recognized –other markup appears in the browse table except that the leading backslash is removed.

In both cases of input, the problem arises that in visual mode, currently we can show only ASCII characters (and the symbols in NCurses.lineDraw, but these are handled differently, see Section 2.1-6). Therefore, we use the function SimplifiedUnicodeString (GAPDoc: SimplifiedUnicodeString) for replacing other unicode characters by ASCII text.

The return value is a record as returned by ParseBibXMLExtFiles (GAPDoc: ParseBibXMLextFiles), its entries component corresponds to the bibliography entries that have been "clicked" in visual mode. This record can be used as input for WriteBibFile (GAPDoc: WriteBibFile) or WriteBibXMLextFile (GAPDoc: WriteBibXMLextFile), in order to produce a bibliography file, or it can be used as input for StringBibXMLEntry (GAPDoc: StringBibXMLEntry), in order to produce strings from the entries, in various formats.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> # sort and categorize by year, scroll down, expand a category row
gap> BrowseData.SetReplay( "scrrscsedddddxdddddQ" );
gap> BrowseBibliography();;
gap> # sort & categorize by authors, expand all category rows, scroll down
gap> BrowseData.SetReplay( "scscXseddddddQ" );
gap> BrowseBibliography();;
gap> # sort and categorize by journal, search for a journal name, expand
gap> BrowseData.SetReplay( Concatenation( "scrrrsc/J. Algebra",
>        [ NCurses.keys.ENTER ], "nxdddQ" ) );
gap> BrowseBibliography();;
gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header (showing the number of entries, which can vary when the table is restricted), no footer and row labels; one row of column labels is given by the descriptions of the table columns (authors, title, year, journal, MSC code).

Row and column separators are drawn as grids (cf. NCurses.Grid (2.2-8)) composed from the special characters described in Section 2.1-6, using the component work.SpecialGrid of the browse table, see BrowseData (5.4-1).

For categorizing by authors (or by MSC codes), the sort parameter "split rows on categorizing" is set to "yes", so the authors (codes) are distributed to different category rows, hence each entry appears once for each of its authors (or its MSC codes) in the categorized table. When a data row or an entry in a data row is selected, "click" adds the corresponding bibliographhy entry to the result.

The width of the title column is preset; usually titles are too long for one line, and the contents of this column is formatted as a paragraph, using the function FormatParagraph (GAPDoc: FormatParagraph). For the authors and journal columns, maximal widths are prescribed, and FormatParagraph (GAPDoc: FormatParagraph) is used for longer entries.

For four columns, the sort parameters are defined as follows: The authors and MSC code columns do not become hidden when the table is categorized according to this column, sorting by the year yields a descending order, and the category rows arising from these columns and the journal column show the numbers of the data rows that belong to them.

Those standard modes in BrowseData (5.4-1) where an entry or a row of the table is selected have been extended by three new actions, which open a pager showing the BibTeX, HTML, and Text format of the selected entry, respectively. The corresponding user inputs are the vb, vh, and vt. If the MSC code column is available then also the user input vm is admissible; it opens a pager showing the descriptions of the MSC codes attached to the selected entry.

This function requires some of the utilities provided by the GAP package GAPDoc (see [LN07]), such as FormatParagraph (GAPDoc: FormatParagraph), NormalizeNameAndKey (GAPDoc: NormalizeNameAndKey), NormalizedNameAndKey (GAPDoc: NormalizedNameAndKey), ParseBibFiles (GAPDoc: ParseBibFiles), ParseBibXMLextFiles (GAPDoc: ParseBibXMLextFiles), ParseBibXMLextString (GAPDoc: ParseBibXMLextString), RecBibXMLEntry (GAPDoc: RecBibXMLEntry), and StringBibAsXMLext (GAPDoc: StringBibAsXMLext).

The code can be found in the file app/gapbibl.g of the package.

The browse table can be customized by entering a record as the argument of BrowseBibliography, with the following supported components.

files

a nonempty list of filenames containing the data to be shown; there is no default for this component.

filesshort

a list of the same length as the files component, the entries are strings which are shown in the "sourcefilename" column of the table (if this column is present); the default is the list of filenames.

filecontents

a list of the same length as the files component, the entries are strings which are shown as category values when the table is categorized by the "sourcefilename" column; the default is the list of filenames.

header

is the constant part of the header shown above the browse table, the default is the first filename.

columns

is a list of records that are valid as the second argument of DatabaseAttributeAdd (A.1-5), where the first argument is a database id enumerator created from the bibliography entries in the files in question. Each entry (and also the corresponding identifier) of this database id enumerator is a list of records obtained from ParseBibXMLextFiles (GAPDoc: ParseBibXMLextFiles) and RecBibXMLEntry (GAPDoc: RecBibXMLEntry), or from ParseBibFiles (GAPDoc: ParseBibFiles), such that the list elements are regarded as equal, in the sense that their fingerprints (see below) are equal. The records in the columns list are available for constructing the desired browse table, the actual appearance is controlled by the choice component described below. Columns showing authors, title, year, journal, MSC code, and filename are predefined and need not be listed here.

choice

a list of strings denoting the identifier components of those columns that shall actually be shown in the table, the default is [ "authors", "title", "year", "journal", "mrclass" ].

fingerprint

a list of strings denoting component names of the entries of the database id enumerator that is constructed from the data (see above); two data records are regarded as equal if the values of these components are equal; the default is [ "mrnumber", "title", "authorAsList", "editorAsList", "author" ].

sortKeyFunction

either fail or a function that takes a record as returned by RecBibXMLEntry (GAPDoc: RecBibXMLEntry) and returns a list that is used for comparing and thus sorting the records; the default is fail, which means that the rows of the table appear in the same ordering as in the source files.

6.7-2 BrowseBibliographyGapPackages
‣ BrowseBibliographyGapPackages( )( function )

Returns: a record as returned by BrowseBibliography (6.7-1).

This function collects the information from the *.bib and *bib.xml files in those subdirectories of installed GAP packages which contain the package documentation, and shows it in a Browse table, using the function BrowseBibliography (6.7-1).

This function is experimental. The result is not really satisfactory, for the following reasons.

6.7-3 BrowseMSC
‣ BrowseMSC( [version] )( function )

Returns: nothing.

This function shows the valid MSC codes in a browse table that is categorized by the ..-XX and the ...xx codes. (Use X for expanding all categories or x for expanding the currently selected category.) Due to the categorization, only two columns of the table are visible, showing the codes and their descriptions.

If version is given then it must be one of the numbers \(2010\) or \(2020\), meaning that the MSC2010 or MSC2020 codes are shown; the default for version is \(2020\).

6.8 Profiling GAP functions–a Variant

A Browse adapted way to evaluate profiling results is to show the overview that is printed by the GAP function DisplayProfile (Reference: DisplayProfile) in a Browse table, which allows one to sort the profiled functions according to the numbers of calls, the time spent, etc., and to search for certain functions one is interested in.

6.8-1 BrowseProfile
‣ BrowseProfile( [functions][,] [mincount, mintime] )( function )

The arguments and their meaning are the same as for the function DisplayProfile (Reference: DisplayProfile), in the sense that the lines printed by that function correspond to the rows of the list that is shown by BrowseProfile. Initially, the table is sorted in the same way as the list shown by BrowseProfile; sorting the table by any of the first five columns will yield a non-increasing order of the rows.

The threshold values mincount and mintime can be changed in visual mode via the user input e. If mouse events are enabled (see NCurses.UseMouse (2.2-10)) then one can also use a mouse click on the current parameter value shown in the table header in order to enter the mode for changing the parameters.

When a row or an entry in a row is selected, "click" shows the code of the corresponding function in a pager (see NCurses.Pager (3.1-4)) whenever this is possible, as follows. If the function was read from a file then this file is opened, if the function was entered interactively then the code of the function is shown in the format produced by Print (Reference: Print); other functions (for example GAP kernel functions) cannot be shown, one gets an alert message (see NCurses.Alert (3.1-1)) in such a case.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> n:= [ 14, 14, 14, 14, 14 ];;  # ``do nothing''
gap> ProfileOperationsAndMethods( true );    # collect some data
gap> ConjugacyClasses( PrimitiveGroup( 24, 1 ) );;
gap> ProfileOperationsAndMethods( false );
gap> BrowseData.SetReplay( Concatenation(
>        "e",                                    # edit threshold paras
>        [ NCurses.keys.DC ], "2", "\t",         # replace 10000 by 20000
>        [ NCurses.keys.DC ], "2",               # replace 30 by 20
>        [ NCurses.keys.ENTER ],                 # commit the changes
>        "scso",                                 # sort by column 1,
>        n,
>        "rso",                                  # sort by column 2,
>        n,
>        "rso",                                  # sort by column 3,
>        n,
>        "q",                                    # deselect the column,
>        "/Normalizer", [ NCurses.keys.ENTER ],  # search for a function,
>        n, n, n, "Q" ) );                       # and quit
gap> BrowseProfile();
gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a dynamic header, which shows the current values of mincount and mintime, and a dynamic footer, which shows the sums of counts and timings for the rows in the table (label TOTAL) and if applicable the sums for the profiled functions not shown in the table (label OTHER). There are no row labels, and the obvious column labels. There is no return value.

The standard modes in BrowseData (5.4-1) (except the help mode) have been modified by adding a new action for changing the threshold parameters mincount and mintime (user input e). The way how this in implemented made it necessary to change the standard "reset" action (user input !) of the table; note that resetting (a sorting or filtering of) the table must not make those rows visible that shall be hidden because of the threshold parameters.

The code can be found in the file app/profile.g of the package.

6.9 Variables defined in GAP packages–a Variant

A Browse adapted way to list the variables that are defined in a GAP package is to show the overview that is printed by the GAP function ShowPackageVariables (Reference: ShowPackageVariables) in a Browse table.

6.9-1 BrowsePackageVariables
‣ BrowsePackageVariables( pkgname[, version][, arec] )( function )

Returns: nothing.

The arguments can be the same as for ShowPackageVariables (Reference: ShowPackageVariables), that is, pkgname is the name of a GAP package, and the optional arguments version and arec are a version number of this package and a record used for customizing the output, respectively.

Alternatively, the second argument can be the output info of PackageVariablesInfo (Reference: PackageVariablesInfo) for the package in question, instead of the version number.

BrowsePackageVariables opens a browse table that shows the global variables that become bound and the methods that become installed when GAP loads the package pkgname.

The table is categorized by the kinds of variables (new or redeclared operations, methods, info classes, synonyms, other globals). The column "Doc.?" distinguishes undocumented and documented variables, so one can use this column as a filter or for categorizing. The column "Filename" shows the names of the package files. Clicking a selected row of the table opens the relevant package file at the code in question.

The idea behind the argument info is that using the same arguments as for ShowPackageVariables (Reference: ShowPackageVariables) does not allow one to apply BrowsePackageVariables to packages that have been loaded before the Browse package. Thus one can compute the underlying data info first, using PackageVariablesInfo (Reference: PackageVariablesInfo), then load the Browse package, and finally call BrowsePackageVariables.

For example, the overview of package variables for Browse can be shown by starting GAP without packages and then entering the following lines.

gap> pkgname:= "Browse";;
gap> info:= PackageVariablesInfo( pkgname, "" );;
gap> LoadPackage( "Browse" );;
gap> BrowsePackageVariables( pkgname, info );

If the arguments are the same as for ShowPackageVariables (Reference: ShowPackageVariables) then this function is actually called, with the consequence that the package gets loaded when BrowsePackageVariables is called. This is not the case if the output of PackageVariablesInfo (Reference: PackageVariablesInfo) is entered as the second argument.

6.10 Configuring User preferences–a Variant

A Browse adapted way to show and edit GAP's user preferences is to show the overview that is printed by the GAP function ShowUserPreferences (Reference: ShowUserPreferences) in a Browse table.

6.10-1 BrowseUserPreferences
‣ BrowseUserPreferences( package1, package2, ... )( function )

Returns: nothing.

The arguments are the same as for ShowUserPreferences (Reference: ShowUserPreferences), that is, calling the function with no argument yields an overview of all known user preferences, and if one or more strings package1, \(\ldots\) are given then only the user preferences for these packages are shown.

BrowseUserPreferences opens a browse table with the following columns:

"Package"

contains the names of the GAP packages to which the user preferences belong,

"Pref. names"

contains the names of the user preferences, and

"Description"

contains the description texts from the DeclareUserPreference (Reference: DeclareUserPreference) calls and the default values (if applicable), and the actual values.

When one "clicks" on one of the table rows or entries then the values of the user preference in question can be edited. If a list of admissible values is known then this means that one can choose from this list via NCurses.Select (3.1-2), otherwise one can enter the desired value as text.

The values of the user preferences are not changed before one closes the browse table. When the table is left and if one has changed at least one value, one is asked whether the changes shall be applied.

gap> d:= [ NCurses.keys.DOWN ];;  
gap> c:= [ NCurses.keys.ENTER ];; 
gap> BrowseData.SetReplay( Concatenation(
>        "/PackagesToLoad",  # enter a search string,
>        c,                  # start the search,
>        c,                  # edit the entry (a list of choices),
>        " ", d,             # toggle the first four values,
>        " ", d,             #
>        " ", d,             #
>        " ", d,             #
>        c,                  # submit the values,
>        "Q",                # quit the table,
>        c ) );              # choose "cancel": do not apply the changes.
gap> BrowseUserPreferences();
gap> BrowseData.SetReplay( false );

The code can be found in the file app/userpref.g of the package.

6.11 Overview of GAP Data

The GAP system contains several data collections such as libraries of groups and character tables. Clearly the function NCurses.BrowseGeneric (4.3-1) can be used to visualize interesting information about such data collections, in the form of an "overview table" whose rows correspond to the objects in the collection; each column of the table shows a piece of information about the objects. (One possibility to create such overviews is given by BrowseTableFromDatabaseIdEnumerator (A.2-2).)

6.11-1 BrowseGapData
‣ BrowseGapData( )( function )

Returns: the return value of the chosen application if there is one.

The function BrowseGapData shows the choices in the list BrowseData.GapDataOverviews, in a browse table with one column. When an entry is "clicked" then the associated function is called, and the table of choices is closed.

The idea is that each entry of BrowseData.GapDataOverviews describes an overview of a data collection.

The Browse package provides overviews of

Other GAP packages may add more overviews, using the function BrowseGapDataAdd (6.11-2). For example, there are overviews of

Except that always one table cell is selected, the full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> # open the overview of Conway polynomials
gap> BrowseData.SetReplay( Concatenation( "/Conway Polynomials",
>      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "srdddd", n, "Q" ) );
gap> BrowseGapData();;
gap> # open the overview of GAP packages
gap> BrowseData.SetReplay( Concatenation( "/GAP Packages",
>      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "/Browse",
>      [ NCurses.keys.ENTER ], "n", n, "Q" ) );
gap> BrowseGapData();;
gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a static header, a dynamic footer showing the description of the currently selected entry, no row or column labels, and exactly one column of fixed width equal to the screen width. If the chosen application has a return value then this is returned by BrowseGapData, otherwise nothing is returned. The component work.SpecialGrid of the browse table is used to draw a border around the list of choices and another border around the footer. Only one mode is needed in which an entry is selected.

The code can be found in the file app/gapdata.g of the package.

6.11-2 BrowseGapDataAdd
‣ BrowseGapDataAdd( title, call[, ret], documentation )( function )

This function extends the list BrowseData.GapDataOverviews by a new entry. The list is used by BrowseGapData (6.11-1).

title must be a string of length at most \(76\); it will be shown in the browse table that is opened by BrowseGapData (6.11-1). call must be a function that takes no arguments; it will be called when title is "clicked". ret, if given, must be true if call has a return value and if BrowseGapData (6.11-1) shall return this value, and false otherwise. documentation must be a string that describes what happens when the function call is called; it will be shown in the footer of the table opened by BrowseGapData (6.11-1) when title is selected.

6.12 Navigating in a Directory Tree

A natural way to visualize the contents of a directory is via a tree whose leaves denote plain files, and the other vertices denote subdirectories. Browse provides a function based on NCurses.BrowseGeneric (4.3-1) for displaying such trees; the leaves correspond to the data rows, and the other vertices correspond to category rows.

6.12-1 BrowseDirectory
‣ BrowseDirectory( [dir] )( function )

Returns: a list of the "clicked" filenames.

If no argument is given then the contents of the current directory is shown, see DirectoryCurrent (Reference: DirectoryCurrent). If a directory object dir (see Directory (Reference: Directory)) is given as the only argument then the contents of this directory is shown; alternatively, dir may also be a string which is then understood as a directory path.

The full functionality of the function NCurses.BrowseGeneric (4.3-1) is available.

gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> BrowseData.SetReplay( Concatenation(
>        "q",                                  # leave the selection
>        "X",                                  # expand all categories
>        "/filetree", [ NCurses.keys.ENTER ],  # search for "filetree"
>        n, "Q" ) );                           # and quit
gap> dir:= DirectoriesPackageLibrary( "Browse", "" )[1];;
gap> if IsBound( BrowseDirectory ) then
>      BrowseDirectory( dir );
>    fi;
gap> BrowseData.SetReplay( false );

Implementation remarks: The browse table has a static header, no footer, no row or column labels, and exactly one data column. The category rows are precomputed, i. e., they do not arise from a table column. The tree structure is visualized via a special grid that is shown in the separator column in front of the table column; the width of this column is computed from the largest nesting depth of files. For technical reasons, category rows representing empty directories are realized via "dummy" table rows; a special ShowTables function guarantees that these rows are always hidden.

When a data row or an entry in this row is selected, "click" adds the corresponding filename to the result list. Initially, the first row is selected. (So if you want to search in the whole tree then you should quit this selection by hitting the q key.)

The category hierarchy is computed using DirectoryContents (Reference: DirectoryContents).

This function is available only if the GAP package IO (see [Neu07]) is available, because the check for cycles uses the function IO_stat (IO: IO_stat) from this package.

The code can be found in the file app/filetree.g of the package.

6.13 A Puzzle

We consider an \(m\) by \(n\) rectangle of squares numbered from \(1\) to \(m n - 1\), the bottom right square is left empty. The numbered squares are permuted by successively exchanging the empty square and a neighboring square such that in the end, the empty cell is again in the bottom right corner.

\( 7\) \(13\) \(14\) \( 2\)
\( 1\) \( 4\) \(15\) \(11\)
\( 6\) \( 8\) \( 3\) \( 9\)
\(10\) \( 5\) \(12\) \( \)

The aim of the game is to order the numbered squares via these moves.

For the case \(m = n = 4\), the puzzle is (erroneously?) known under the name "Sam Loyd's Fifteen", see [Bog] and [OR] for more information and references.

6.13-1 BrowsePuzzle
‣ BrowsePuzzle( [m, n[, pi]] )( function )

Returns: a record describing the initial and final status of the puzzle.

This function shows the rectangle in a window.

The arguments m and n are the dimensions of the rectangle, the default for both values is \(4\). The initial distribution of the numbers in the squares can be prescribed via a permutation pi, the default is a random element in the alternating group on the points \(1, 2, \ldots, \textit{m} \textit{n} - 1\). (Note that the game has not always a solution.)

In any case, the empty cell is selected, and the selection can be moved to neighboring cells via the arrow keys, or to any place in the same row or column via a mouse click.

The return value is a record with the components dim (the pair [ m, n ]), init (the initial permutation), final (the final permutation), and steps (the number of transpositions that were needed).

gap> BrowseData.SetReplay( Concatenation(
>        BrowsePuzzleSolution.steps, "Q" ) );
gap> BrowsePuzzle( 4, 4, BrowsePuzzleSolution.init );;
gap> BrowseData.SetReplay( false );

An implementation using only mouse clicks but no key strokes is available in the GAP package XGAP (see [CN04]).

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual minyx function. Only one mode is needed in which one cell is selected, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only the four moves via the arrow keys and mouse clicks are admissible.

Some standard NCurses.BrowseGeneric (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file app/puzzle.g of the package.

6.14 Peg Solitaire

Peg solitaire is a board game for one player. The game board consists of several holes some of which contain pegs. In each step of the game, one peg is moved horizontally or vertically to an empty hole at distance two, by jumping over a neighboring peg which is then removed from the board.

[solitaire image]

We consider the game that in the beginning, exactly one hole is empty, and in the end, exactly one peg is left.

6.14-1 PegSolitaire
‣ PegSolitaire( [format][,] [nrholes][,] [twoModes] )( function )

This function shows the game board in a window.

If the argument format is one of the strings "small" or "large" then small or large pegs are shown, the default is "small".

Three shapes of the game board are supported, with \(33\), \(37\), and \(45\) holes, respectively; this number can be specified via the argument nrholes, the default is \(33\). In the cases of \(33\) and \(45\) holes, the position of both the initial hole and the destination of the final peg is the middle cell, whereas in the case of \(37\) holes, the initial hole is in the top left position and the final peg has to be placed in the bottom right position.

If a Boolean twoModes is entered as an argument then it determines whether a browse table with one or two modes is used; the default false yields a browse table with only one mode.

In any case, one cell of the board is selected, and the selection can be moved to neighboring cells via the arrow keys. A peg in the selected cell jumps over a neighboring peg to an adjacent hole via the j key followed by the appropriate arrow key.

gap> for n in [ 33, 37, 45 ] do
>      BrowseData.SetReplay( Concatenation(
>          PegSolitaireSolutions.( String( n ) ), "Q" ) );
>      PegSolitaire( n );
>      PegSolitaire( "large", n );
>      PegSolitaire( n, true );
>      PegSolitaire( "large", n, true );
> od;
gap> BrowseData.SetReplay( false );

For more information such as variations of the game and references, see [Köla]. Also the solutions stored in the variable PegSolitaireSolutions have been taken from this web page.

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual minyx function. In fact, two implementations are provided. The first one needs only one mode in which one cell is selected; moving the selection and jumping with the peg in the selected cell in one of the four directions are the supported user actions. The second implementation needs two modes, one for moving the selection and one for jumping.

Some standard NCurses.BrowseGeneric (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file app/solitair.g of the package.

6.15 Rubik's Cube

We visualize the transformations of Rubik's magic cube in a model that is given by "unfolding" the faces and numbering them as follows.

[unfolded Rubik's cube image]

Clockwise turns of the six layers (top, left, front, right, back, and down) are represented by the following permutations.

gap> cubegens := [
>   ( 1, 3, 8, 6)( 2, 5, 7, 4)( 9,33,25,17)(10,34,26,18)(11,35,27,19),
>   ( 9,11,16,14)(10,13,15,12)( 1,17,41,40)( 4,20,44,37)( 6,22,46,35),
>   (17,19,24,22)(18,21,23,20)( 6,25,43,16)( 7,28,42,13)( 8,30,41,11),
>   (25,27,32,30)(26,29,31,28)( 3,38,43,19)( 5,36,45,21)( 8,33,48,24),
>   (33,35,40,38)(34,37,39,36)( 3, 9,46,32)( 2,12,47,29)( 1,14,48,27),
>   (41,43,48,46)(42,45,47,44)(14,22,30,38)(15,23,31,39)(16,24,32,40)
> ];;

GAP computations analyzing this permutation group have been part of the announcements of GAP 3 releases. For a GAP 4 equivalent, see [Sch]. For more information and references (not GAP related) about Rubik's cube, see [Kölb].

6.15-1 BrowseRubiksCube
‣ BrowseRubiksCube( [format][,] [pi] )( function )

This function shows the model of the cube in a window.

If the argument format is one of the strings "small" or "large" then small or large cells are shown, the default is "small".

The argument pi is the initial permutation of the faces, the default is a random permutation in the cube group, see Reference: Random.

Supported user inputs are the keys t, l, f, r, b, and d for clockwise turns of the six layers, and the corresponding capital letters for counter-clockwise turns. If the terminal supports colors, according to the global variable NCurses.attrs.has_colors (2.2-1), the input s switches between a screen that shows only the colors of the faces and a screen that shows the numbers; the color screen is the default.

The return value is a record with the components inputs (a string describing the user inputs), init, and final (the initial and final permutation of the faces, respectively). (The inputs component can be used for the replay feature, see the example below.)

In the following example, a word in terms of the generators is used to initialize the browse table, and then the letters in this word are used as a series of input steps, except that in between, the display is switched once from colors to numbers and back.

gap> choice:= List( [ 1 .. 30 ], i -> Random( [ 1 .. 6 ] ) );;
gap> input:= List( "tlfrbd", IntChar ){ choice };;
gap> BrowseData.SetReplay( Concatenation(
>        input{ [ 1 .. 20 ] },
>        "s",                    # switch to number display
>        input{ [ 21 .. 25 ] },
>        "s",                    # switch to color display
>        input{ [ 26 .. 30 ] },
>        "Q" ) );;               # quit the browse table
gap> BrowseRubiksCube( Product( cubegens{ choice } ) );;
gap> BrowseRubiksCube( "large", Product( cubegens{ choice } ) );;
gap> BrowseData.SetReplay( false );

Implementation remarks: The cube is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual minyx function. Only one mode is needed, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only the twelve moves and the switch between color and number display are admissible.

Switching between the two display formats is implemented via a function work.Main, so this relies on not caching the formatted cells in work.main.

Row and column separators of the browse table are whitespace of height and width one. The separating lines are drawn using an individual SpecialGrid function in the browse table. Note that the relevant cells do not form a rectangular array.

Some standard NCurses.BrowseGeneric (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file app/rubik.g of the package.

6.16 Changing Sides

We consider a \(5\) by \(5\) board of squares filled with two types of stones, as follows. The square in the middle is left empty.

XXXXX
OXXXX
OOXX
OOOOX
OOOOO

The aim of the game is to exchange the two types of stones via a sequence of single steps that move one stone to the empty position on the board. Only those moves are allowed that increase or decrease one coordinate by \(2\) and increase or decrease the other by \(1\); these are the allowed moves of the knight in chess.

This game has been part of the MacTutor system [OR00].

6.16-1 BrowseChangeSides
‣ BrowseChangeSides( )( function )

This function shows the game board in a window.

Each move is encoded as a sequence of three arrow keys; there are \(24\) admissible inputs.

gap> for entry in BrowseChangeSidesSolutions do
>      BrowseData.SetReplay( Concatenation( entry, "Q" ) );
>      BrowseChangeSides();
> od;
gap> BrowseData.SetReplay( false );

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual minyx function. Only one mode is needed, and besides the standard actions for quitting the table, asking for help, and saving the current window contents, only moves via combinations of the four arrow keys are admissible.

The separating lines are drawn using an individual SpecialGrid function in the browse table.

Some standard NCurses.BrowseGeneric (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file app/knight.g of the package.

6.17 Sudoku

We consider a \(9\) by \(9\) board of squares. Some squares are initially filled with numbers from \(1\) to \(9\). The aim of the game is to fill the empty squares in such a way that each row, each column, and each of the marked \(3\) by \(3\) subsquares contains all numbers from \(1\) to \(9\). A proper Sudoku game is defined as one with a unique solution. Here is an example.

1 5
9
4 6
5
5
2
3
6 4
8
8
9
5 3
4
9
5
7
1
2
8

The Browse package contains functions to create, play and solve these games. There are basic command line functions for this, which we describe first, and there is a user interface PlaySudoku (6.17-8) which is implemented using the generic browse functionality described in Chapter 4.

6.17-1 Sudoku.Init
‣ Sudoku.Init( [arg] )( function )

Returns: A record describing a Sudoku board or fail.

This function constructs a record describing a Sudoku game. This is used by the other functions described below. There a several possibilities for the argument arg.

arg is a string

The entries of a Sudoku board are numbered row-wise from 1 to 81. A board is encoded as a string as follows. If one of the numbers 1 to 9 is in entry \(i\) then the corresponding digit character is written in position \(i\) of the string. If an entry is empty any character, except '1' to '9' or '|' is written in position \(i\) of the string. Trailing empty entries can be left out. Afterwards '|'-characters can be inserted in the string (for example to mark line ends). Such strings can be used for arg.

arg is a matrix

A Sudoku board can also be encoded as a 9 by 9-matrix, that is a list of 9 lists of length 9, whose (i,j)-th entry is the (i,j)-th entry of the board as integer if it is not empty. Empty entries of the board correspond to unbound entries in the matrix.

arg is a list of integers

Instead of the matrix just described the argument can also be given by the concatenation of the rows of the matrix (so, a list of integers and holes).

gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;

6.17-2 Sudoku.Place
‣ Sudoku.Place( game, i, n )( function )
‣ Sudoku.Remove( game, i )( function )

Returns: The changed game.

Here game is a record describing a Sudoku board, as returned by Sudoku.Init (6.17-1). The argument i is the number of an entry, counted row-wise from 1 to 81, and n is an integer from 1 to 9 to be placed on the board. These functions change game.

Sudoku.Place tries to place number n on entry i. It is an error if entry i is not empty. The number is not placed if n is already used in the row, column or subsquare of entry i. In this case the component game.impossible is bound.

Sudoku.Remove tries to remove the number placed on position i of the board. It does not change the board if entry i is empty, or if entry i was given when the board game was created. In the latter case game.impossible is bound.

gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
gap> Sudoku.Place(game, 1, 3);; # 3 is already in first row
gap> IsBound(game.impossible);
true
gap> Sudoku.Place(game, 1, 2);; # 2 is not in row, col or subsquare
gap> IsBound(game.impossible);
false

6.17-3 Sudoku.RandomGame
‣ Sudoku.RandomGame( [seed] )( function )

Returns: A pair [str, seed] of string and seed.

The optional argument seed, if given, must be an integer. If not given some random integer from the current GAP session is used. This function returns a random proper Sudoku game, where the board is described by a string str, as explained in Sudoku.Init (6.17-1). With the same seed the same board is returned.

The games computed by this function have the property that after removing any given entry the puzzle does no longer have a unique solution.

gap> Sudoku.RandomGame(5833750);
[ " 1         2     43  2   68   72    8     6 2   1 9 8  8 3   9     \
47 3   7  18  ", 5833750 ]
gap> last = Sudoku.RandomGame(last[2]);
true

6.17-4 Sudoku.SimpleDisplay
‣ Sudoku.SimpleDisplay( game )( function )

Displays a Sudoku board on the terminal. (But see PlaySudoku (6.17-8) for a fancier interface.)

gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
gap> Sudoku.SimpleDisplay(game);
 3 |  6|8  
 85|  1| 69
  9|7  | 53
-----------
   |   |79 
 6 | 47|   
45 | 2 |   
-----------
89 |  2| 1 
 4 |  8| 7 
   |   |   

6.17-5 Sudoku.DisplayString
‣ Sudoku.DisplayString( game )( function )

The string returned by this function can be used to display the Sudoku board game on the terminal, using PrintFormattedString (GAPDoc: PrintFormattedString). The result depends on the value of GAPInfo.TermEncoding.

gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
gap> str:= Sudoku.DisplayString( game );;
gap> PrintFormattedString( str );
                     ┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓
                     ┃   │ 3 │   ┃   │   │ 6 ┃ 8 │   │   ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃   │ 8 │ 5 ┃   │   │ 1 ┃   │ 6 │ 9 ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃   │   │ 9 ┃ 7 │   │   ┃   │ 5 │ 3 ┃
                     ┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫
                     ┃   │   │   ┃   │   │   ┃ 7 │ 9 │   ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃   │ 6 │   ┃   │ 4 │ 7 ┃   │   │   ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃ 4 │ 5 │   ┃   │ 2 │   ┃   │   │   ┃
                     ┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫
                     ┃ 8 │ 9 │   ┃   │   │ 2 ┃   │ 1 │   ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃   │ 4 │   ┃   │   │ 8 ┃   │ 7 │   ┃
                     ┠───┼───┼───╂───┼───┼───╂───┼───┼───┨
                     ┃   │   │   ┃   │   │   ┃   │   │   ┃
                     ┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛

6.17-6 Sudoku.OneSolution
‣ Sudoku.OneSolution( game )( function )

Returns: A completed Sudoku board that solves game, or fail.

Here game must be a Sudoku board as returned by Sudoku.Init (6.17-1). It is not necessary that game describes a proper Sudoku game (has a unique solution). It may have several solutions, then one random solution is returned. Or it may have no solution, then fail is returned.

gap> Sudoku.SimpleDisplay(Sudoku.OneSolution(Sudoku.Init("  3")));
493|876|251
861|542|739
527|193|648
-----------
942|618|573
156|739|482
738|425|916
-----------
289|354|167
375|961|824
614|287|395

6.17-7 Sudoku.UniqueSolution
‣ Sudoku.UniqueSolution( game )( function )

Returns: A completed Sudoku board that solves game, or false, or fail.

Here game must be a Sudoku board as returned by Sudoku.Init (6.17-1). It is not necessary that game describes a proper Sudoku game. If it has several solutions, then false is returned. If it has no solution, then fail is returned. Otherwise a board with the unique solution is returned.

gap> s := "      5  | 154 6 2 |9   5 3  |6 4      |   8     |8  9   53\
> |     5   | 4   7  2|  91  8  ";;
gap> sol := Sudoku.UniqueSolution(Sudoku.Init(s));;
gap> Sudoku.SimpleDisplay(sol);
438|219|576
715|436|928
962|758|314
-----------
694|573|281
153|862|749
827|941|653
-----------
281|695|437
546|387|192
379|124|865

6.17-8 PlaySudoku
‣ PlaySudoku( [arg] )( function )

Returns: A record describing the latest status of a Sudoku board.

This function allows one to solve Sudoku puzzles interactively. There are several possibilities for the optional argument arg. It can either be a string, matrix or list of holes and integers as described in Sudoku.Init (6.17-1), or a board as returned by Sudoku.Init (6.17-1). Furthermore arg can be an integer or not be given, in that case Sudoku.RandomGame (6.17-3) is called to produce a random game.

The usage of this function is self-explanatory, pressing the ? key displays a help screen. Here, we mention two keys with a particular action: Pressing the h key you get a hint, either an empty entry is filled or the program tells you that there is no solution (so you must delete some entries and try others). Pressing the s key the puzzle is solved by the program or it tells you that there is no or no unique solution.

Implementation remarks: The game board is implemented via a browse table, without row and column labels, with static header, dynamic footer, and individual minyx function. Two modes are supported, with the standard actions for quitting the table and asking for help; one cell is selected in each mode. The first mode provides actions for moving the selected cell via arrow keys, for changing the value in the selected cell, for getting a hint or the (unique) solution. (Initial entries of the matrix cannot be changed via user input. They are shown in boldface.) The second mode serves for error handling: When the user enters an invalid number, i. e., a number that occurs already in the current row or column or subsquare, then the application switches to this mode, which causes that a message is shown in the footer, and the invalid entry is shown in red and blinking; similarly, error mode is entered if a hint or solution does not exist.

The separating lines are drawn using an individual SpecialGrid function in the browse table, since they cannot be specified within the generic browse table functions.

Some standard NCurses.BrowseGeneric (4.3-1) functionality, such as scrolling, selecting, and searching, are not available in this application.

The code can be found in the file app/sudoku.g of the package.

6.17-9 Sudoku.HTMLGame
‣ Sudoku.HTMLGame( game )( function )
‣ Sudoku.LaTeXGame( game )( function )

Returns: A string with HTML or LaTeX code, respectively.

The argument of these functions is a record describing a Sudoku game. These functions return code for including the current status of the board into a webpage or a LaTeX document.

6.18 Managing simple Workflows

The idea behind the function BrowseWizard (6.18-1) is that one wants to collect interactively information from a user, by asking a series of questions. Default answers for these questions can be provided, perhaps depending on the answers to earlier questions. The questions and answers are shown in a browse table, the current question is highlighted, and this selection is automatically moved to the next question after a valid answer has been entered. One may move up in the table, in order to change previous answers, but one can move down only to the first unanswered question. When the browse table gets closed (by submitting or canceling), a record with the collected information is returned.

6.18-1 BrowseWizard
‣ BrowseWizard( data )( function )

Returns: a record.

The argument data must be a record with the components steps (a list of records, each representing one step in the questionnaire) and defaults (a record). The component header, if present, must be a string that is used as a header line; the default for it is "BrowseWizard".

BrowseWizard opens a browse table whose rows correspond to the entries of data.steps. The components of data.defaults are used as default values if they are present.

Beginning with the first entry, the user is asked to enter information, one record component per entry; this may be done by entering some text, by choosing keys from a given list of choices, or by editing a list of tabular data. Then one can go to the next step by hitting the ArrowDown key (or by entering d), and edit this step by hitting the Enter key. One can also go back to previous steps and edit them again.

Some steps may be hidden from the user, depending on the information that has been entered for the previous steps. The hide conditions are evaluated after each step.

An implementation of a questionnaire is given by BrowseData.ChooseSimpleGroupQuestions, which is used in the following example. The idea is to choose the description of a finite simple group by entering first the type (cyclic, alternating, classical, exceptional, or sporadic) and then the relevant parameter values. The information is then evaluated by BrowseData.InterpretSimpleGroupDescription, which returns a description that fits to the return values of IsomorphismTypeInfoFiniteSimpleGroup (Reference: IsomorphismTypeInfoFiniteSimpleGroup). For example, this function identifies the group PSL\((4,2)\) as \(A_8\).)

gap> d:= [ NCurses.keys.DOWN ];;  r:= [ NCurses.keys.RIGHT ];;
gap> c:= [ NCurses.keys.ENTER ];;
gap> BrowseData.SetReplay( Concatenation(
>        c,             # confirm the initial message
>        d,             # enter the first step
>        d, d,          # go to the choice of classical groups
>        c,             # confirm this choice
>        c,             # enter the next step
>        d, d,          # go to the choice of unitary groups
>        c,             # confirm this choice
>        c,             # enter the next step
>        "5", c,        # enter the dimension and confirm
>        c,             # enter the next step
>        "3", c,        # enter the field size and confirm
>        c ) );         # confirm all choices (closes the table)
gap> res:= BrowseWizard( rec(
>      steps:= BrowseData.ChooseSimpleGroupQuestions,
>      defaults:= rec(),
>      header:= "Choose a finite simple group" ) );;
gap> BrowseData.SetReplay( false );
gap> BrowseData.InterpretSimpleGroupDescription( res );
rec( parameter := [ 4, 3 ], requestedname := "U5(3)", series := "2A", 
  shortname := "U5(3)" )

The supported components of each entry in data.steps are as follows.

key

a string, the name of the component of the result record that gets bound for this entry.

description

a string describing what information shall be entered.

type

one of "editstring", "edittable", "key", "keys", "ok", "okcancel", "submitcancelcontinue".

keys (only if type is "key" or "keys")

either the list of pairs [ key, alias ] such that the user shall choose from the list of key values (strings), and the alias values (any GAP object) corresponding to the chosen values are entered into the result record, or a function that takes steps and the current result record as its arguments and returns the desired list of pairs.

validation (optional)

a function that takes steps, the current result record, and a result candidate for the current step as its arguments; it returns true if the result candidate is valid, and a string describing the reason for the failure otherwise.

default (optional)

depending on the type value, the alias part(s) of the chosen key(s) or the string or the list of data records, or alternatively a function that takes steps and the current result record as its arguments and returns the desired value. If the key component of data.defaults is bound and valid (according to the validation function) then this value is taken as the default; otherwise, the default component of the entry is taken as the default.

isVisible (optional)

a function that takes steps and the current result record as its arguments and returns true if the step shall be visible, and false otherwise,

If the type value of a step is "edittable" then also the following components are mandatory.

list

the current list of records to be edited; only strings are supported as the values of the record components.

mapping

a list of pairs [ component, label ] such that component is the name of a component in the entries in list, and label is the label shown in the dialog box for editing the record.

choices (optional)

a list of records which can be added to list.

rectodisp

a function that takes a record from list and returns a string that is shown in the browse table.

title

a string, the header line of the dialog box for editing an entry.

The code of BrowseWizard, BrowseData.ChooseSimpleGroupQuestions, and BrowseData.InterpretSimpleGroupDescription can be found in the file app/wizard.g of the package.

6.19 Utility for GAP Demos

This application can be used with GAP if the user interface has readline support. The purpose is to simplify the typing during a demonstration of GAP commands.

The file format to specify GAP code for a demonstration is very simple: it contains blocks of lines with GAP input, separated by lines starting with the sequence #%. Comments in such a file can be added to one or several lines starting with #%. Here is the content of an example file demo.demo:


#% Add comments after #% characters at the beginning of a line.
#% A comment can have several lines.
#% Here is a multi-line input block:
g := MathieuGroup(11);;
cl := ConjugacyClasses(g);
#% Calling a help page
?MathieuGroup
#% The next line contains a comment in the GAP session:
a := 12;; b := 13;; # assign two numbers
#%
a*b;
#%

(Single % in the beginning of a line will also work as separators.)

A demonstration can be loaded into a GAP session with the command

6.19-1 LoadDemoFile
‣ LoadDemoFile( demoname, demofile[, singleline] )( function )

Returns: Nothing.

This function loads a demo file in the format described above. The argument demoname is a string containing a name for the demo, and demofile is the file name containing the demo.

If the optional argument singleline is given and its value is true, the demo behaves differently with respect to input blocks that span several lines. By default full blocks are treated as a single input line for readline (maybe spanning several physical lines in the terminal). If singleline is true then all input lines of a block except the last one are sent to GAP and are evaluated automatically before the last line of the block is displayed.

gap> dirs := DirectoriesPackageLibrary("Browse");;
gap> demofile := Filename(dirs, "../app/demo.demo");;
gap> if IsBound(GAPInfo.UseReadline) and GAPInfo.UseReadline = true then
>   LoadDemoFile("My first demo", demofile);
>   LoadDemoFile("My first demo (single lines)", demofile, true);
> fi;

Many demos can be loaded at the same time. They are used with the PageDown and PageUp keys.

The PageUp key leads to a (Browse) menu which allows one to choose a demo to start (if several are loaded), to stop a demo or to move to another position in the current demo (e.g., to go back to a previous point or to skip part of a demo).

The next input block of the current demo is copied into the current input line of the GAP session by pressing the PageDown key. This line is not yet sent to GAP, use the Return key if you want to evaluate the input. (You can also still edit the input line before evaluation.)

So, in the simplest case a demo can be done by just pressing PageDown and Return in turns. But it is always possible to type extra input during a demo by hand or to change the input lines from the demo file before evaluation. It is no problem if commands are interrupted by Ctrl-C. During a demo you are in a normal GAP session, this application only saves you some typing. The input lines from the demo are put into the history of the session as if they were typed by hand.

Try it yourself with the two demos loaded in the example. This also shows the different behaviour between default and single line mode.

 [Top of Book]  [Contents]   [Previous Chapter]   [Next Chapter] 
Goto Chapter: Top 1 2 3 4 5 6 A Bib Ind

generated by GAPDoc2HTML