CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Path: gap4r8 / pkg / Browse / doc / chapA.txt
Views: 418346
1
2
A Some Tools for Database Handling
3
4
Two aims of the tools described in this appendix are
5
6
 speeding up selection functions such as AllCharacterTableNames
7
(CTblLib: AllCharacterTableNames) for certain data libraries of GAP
8
(with not too many entries), in the sense that users can extend the
9
list of attributes that are treated in a special way
10
11
 and a programmatic extension for rendering overviews of information
12
about the contents of databases, using
13
BrowseTableFromDatabaseIdEnumerator (A.2-2).
14
15
The GAP objects introduced for that are database id enumerators (see A.1-1)
16
and database attributes (see A.1-2).
17
18
Contrary to the individual interfaces to the GAP manuals (see Section 6.6),
19
the GAP bibliography (see Section 6.7), and the overviews of GAP packages,
20
GAP methods, and Conway polynomials available in GAP (see Section 6.11), the
21
approach that will be described here assumes a special way to access
22
database entries. Thus it depends on the structure of a given database
23
whether the tools described here are useful, or whether an individual
24
interface fits better. Perhaps the example shown in Section A.3 gives an
25
impression what is possible.
26
27
28
A.1 GAP Objects for Database Handling
29
30
31
A.1-1 Database Id Enumerators
32
33
A database id enumerator is a record r with at least the following
34
components.
35
36
identifiers
37
a list of identifiers of the database entries, which provides a
38
bijection with these entries,
39
40
entry
41
a function that takes r and an entry in the identifiers list, and
42
returns the corresponding database entry,
43
44
attributes
45
the record whose components are the database attribute records (see
46
Section A.1-2) for r; this components is automatically initialized
47
when r is created with DatabaseIdEnumerator (A.1-4); database
48
attributes can be entered with DatabaseAttributeAdd (A.1-5).
49
50
If the identifiers list may change over the time (because the database is
51
extended or corrected) then the following components are supported. They are
52
used by DatabaseIdEnumeratorUpdate (A.1-7).
53
54
version
55
a GAP object that describes the version of the identifiers component,
56
this can be for example a string describing the time of the last
57
change (this time need not coincide with the time of the last update);
58
the default value (useful only for the case that the identifiers
59
component is never changed) is an empty string,
60
61
update
62
a function that takes r as its argument, replaces its identifiers and
63
version values by up-to-date versions if necessary (for example by
64
downloading the data), and returns true or false, depending on whether
65
the update process was successful or not; the default value is
66
ReturnTrue (Reference: ReturnTrue),
67
68
The following component is optional.
69
70
isSorted
71
true means that the identifiers list is sorted w.r.t. GAP's ordering
72
\<; the default is false.
73
74
The idea behind database id enumerator objects is that such an object
75
defines the set of data covered by database attributes (see Section A.1-2),
76
it provides the mapping between identifiers and the actual entries of the
77
database, and it defines when precomputed data of database attributes are
78
outdated.
79
80
81
A.1-2 Database Attributes
82
83
A database attribute is a record a whose components belong to the aspects of
84
defining the attribute, accessing the attribute's data, computing (and
85
recomputing) data, storing data on files, and checking data. (Additional
86
parameters used for creating browse table columns from database attributes
87
are described in Section A.2-1.)
88
89
The following components are defining, except description they are
90
mandatory.
91
92
idenumerator
93
the database id enumerator to which the attribute a is related,
94
95
identifier
96
a string that identifies a among all database attributes for the
97
underlying database id enumerator (this is used by
98
BrowseTableFromDatabaseIdEnumerator (A.2-2) and when the data of a are
99
entered with DatabaseAttributeSetData (A.1-9), for example when
100
precomputed values are read from a file),
101
102
description
103
a string that describes the attribute in human readable form
104
(currently just for convenience, the default is an empty string).
105
106
The following components are used for accessing data. Except type, they are
107
optional, but enough information must be provided in order to make the
108
database attribute meaningful. If an individual attributeValue function is
109
available then this function decides what is needed; for the default
110
function DatabaseAttributeValueDefault (A.1-6), at least one of the
111
components name, data, datafile must be bound (see
112
DatabaseAttributeValueDefault (A.1-6) for the behaviour in this case).
113
114
type
115
one of the strings "values" or "pairs"; the format of the component
116
data is different for these cases,
117
118
name
119
if bound, a string that is the name of a GAP function such that the
120
database attribute encodes the values of this function for the
121
database entries; besides the computation of attribute values on
122
demand (see DatabaseAttributeValueDefault (A.1-6)), this component can
123
be used by selection functions such as OneCharacterTableName (CTblLib:
124
OneCharacterTableName) or AllCharacterTableNames (CTblLib:
125
AllCharacterTableNames), which take GAP functions and prescribed
126
return values as their arguments –of course these functions must then
127
be prepared to deal with database attributes.
128
129
data
130
if bound, the data for this attribute; if the component type has the
131
value "values" then the value is a list, where the entry at position
132
i, if bound, belongs to the i-th entry of the identifiers list of
133
idenumerator; if type is "pairs" then the value is a record with the
134
components automatic and nonautomatic, and the values of these
135
components are lists such that each entry is a list of length two
136
whose first entry occurs in the identifiers list of a.idenumerator and
137
whose second entry encodes the corresponding attribute value,
138
139
datafile
140
if bound, the absolute name of a file that contains the data for this
141
attribute,
142
143
attributeValue
144
a function that takes a and an identifiers entry of its idenumerator
145
value, and returns the attribute value for this identifier; typically
146
this is not a table cell data object that can be shown in a browse
147
table, cf. the viewValue component; the default is
148
DatabaseAttributeValueDefault (A.1-6) (Note that using individual
149
attributeValue functions, one can deal with database attributes
150
independent of actually stored data, for example without precomputed
151
values, such that the values are computed on demand and afterwards are
152
cached.),
153
154
dataDefault
155
a GAP object that is regarded as the attribute value for those
156
database entries for which data, datafile, and name do not provide
157
values; the default value is an empty string "",
158
159
eval
160
if this component is bound, the value is assumed to be a function that
161
takes a and a value from its data component, and returns the actual
162
attribute value; this can be useful if one does not want to create all
163
attribute values in advance, because this would be space or time
164
consuming; another possible aspect of the eval component is that it
165
may be used to strip off comments that are perhaps contained in data
166
entries,
167
168
isSorted
169
if this component is bound to true and if type is "pairs" then it is
170
assumed that the two lists in the data record of a are sorted w.r.t.
171
GAP's ordering \<; the default is false,
172
173
The following optional components are needed for computing (or recomputing)
174
data with DatabaseAttributeCompute (A.1-8). This is useful mainly for
175
databases which can change over the time.
176
177
version
178
the GAP object that is the version component of the idenumerator
179
component at the time when the stored data were entered; this value is
180
used by DatabaseIdEnumeratorUpdate (A.1-7) for deciding whether the
181
attribute values are outdated; if a.datafile is bound then it is
182
assumed that the version component is set when this file is read, for
183
example in the function DatabaseAttributeSetData (A.1-9),
184
185
update
186
a function that takes a as its argument, adjusts its data components
187
to the current values of a.dbidenum if necessary, sets the version
188
component to that of a.dbidenum, and returns true or false, depending
189
on whether the update process was successful or not; the default value
190
is ReturnTrue (Reference: ReturnTrue),
191
192
neededAttributes
193
a list of attribute identifier strings such that the values of these
194
attributes are needed in the computations for the current one, and
195
therefore these should be updated/recomputed in advance; it is assumed
196
that the neededAttributes components of all database attributes of
197
a.idenumerator define a partial ordering; the default is an empty
198
list,
199
200
prepareAttributeComputation
201
a function with argument a that must be called before the computations
202
for the current attribute are started; the default value is ReturnTrue
203
(Reference: ReturnTrue),
204
205
cleanupAfterAttibuteComputation
206
a function with argument a that must be called after the computations
207
for the current attribute are finished; the default value is
208
ReturnTrue (Reference: ReturnTrue), and
209
210
create
211
a function that takes a database attribute and an entry in the
212
identifiers list of its database id enumerator, and returns either the
213
entry that shall be stored in the data component, as the value for the
214
given identifier (if this value shall be stored in the data component
215
of a) or the dataDefault component of a (if this value shall not be
216
stored); in order to get the actual attribute value, the eval function
217
of a, if bound, must be called with the return value. This function
218
may assume that the prepareAttributeComputation function has been
219
called in advance, and that the cleanupAfterAttibuteComputation
220
function will be called later. The create function is not intended to
221
compute an individual attribute value on demand, use a name component
222
for that. (A stored name function is used to provide a default for the
223
create function; without name component, there is no default for
224
create.)
225
226
The following optional component is needed for storing data on files.
227
228
string
229
if bound, a function that takes the pair consisting of an identifier
230
and the return value of the create function for this identifier, and
231
returns a string that shall represent this value when the data are
232
printed to a file; the default function returns the String (Reference:
233
String) value of the second argument.
234
235
The following optional component is needed for checking stored data.
236
237
check
238
a function that takes a string that occurs in the identifiers list of
239
the idenumerator record, and returns true if the attribute value
240
stored for this string is reasonable, and something different from
241
true if an error was detected. (One could argue that these tests can
242
be performed also when the values are computed, but consistency checks
243
may involve several entries; besides that, checking may be cheaper
244
than recomputing.)
245
246
247
A.1-3 How to Deal with Database Id Enumerators and Database Attributes
248
249
The idea is to start with a database id enumerator (see A.1-1), constructed
250
with DatabaseIdEnumerator (A.1-4), and to define database attributes for it
251
(see A.1-2), using DatabaseAttributeAdd (A.1-5). The attribute values can be
252
precomputed and stored on files, or they are computed when the attribute
253
gets defined, or they are computed on demand.
254
255
The function DatabaseAttributeCompute (A.1-8) can be used to refresh the
256
attribute values, that is, all values or selected values can be recomputed;
257
this can be necessary for example when the underlying database id enumerator
258
gets extended.
259
260
In data files, the function DatabaseAttributeSetData (A.1-9) can be used to
261
fill the data component of the attribute.
262
263
A.1-4 DatabaseIdEnumerator
264
265
DatabaseIdEnumerator( arec )  function
266
Returns: a shallow copy of the record arec, extended by default values.
267
268
For a record arec, DatabaseIdEnumerator checks whether the mandatory
269
components of a database id enumerator (see Section A.1-1) are present,
270
initializes the attributes component, sets the defaults for unbound optional
271
components (see A.2-1), and returns the resulting record.
272
273
A special database attribute (see Section A.1-2) with identifier value
274
"self" is constructed automatically for the returned record by
275
DatabaseIdEnumerator; its attributeValue function simply returns its second
276
argument (the identifier). The optional components of this attribute are
277
derived from components of the database id enumerator, so these components
278
(see A.2-1) are supported for arec. A typical use of the "self" attribute is
279
to provide the first column in browse tables constructed by
280
BrowseTableFromDatabaseIdEnumerator (A.2-2).
281
282
A.1-5 DatabaseAttributeAdd
283
284
DatabaseAttributeAdd( dbidenum, arec )  function
285
286
For a database id enumerator dbidenum and a record arec,
287
DatabaseAttributeAdd checks whether the mandatory components of a database
288
attribute, except idenumerator, are present in arec (see Section A.1-2),
289
sets the idenumerator component, and sets the defaults for unbound optional
290
components (see A.2-1).
291
292
A.1-6 DatabaseAttributeValueDefault
293
294
DatabaseAttributeValueDefault( attr, id )  function
295
Returns: the value of the database attribute attr at id.
296
297
For a database attribute attr and an entry id of the identifiers list of the
298
underlying database id enumerator, DatabaseAttributeValueDefault takes the
299
data entry for id, applies the eval function of attr to it if available and
300
returns the result.
301
302
So the question is how to get the data entry.
303
304
First, if the data component of attr is not bound then the file given by the
305
datafile component of attr, if available, is read, and otherwise
306
DatabaseAttributeCompute (A.1-8) is called; afterwards it is assumed that
307
the data component is bound.
308
309
The further steps depend on the type value of attr.
310
311
If the type value of attr is "pairs" then the data entry for id is either
312
contained in the automatic or in the nonautomatic list of attr.data, or it
313
is given by the dataDefault value of attr. (So a perhaps available name
314
function is not used to compute the value for a missing data entry.)
315
316
If the type value of attr is "values" then the data entry for id is computed
317
as follows. Let n be the position of id in the identifiers component of the
318
database id enumerator. If the n-th entry of the data component of attr is
319
bound then take it; otherwise if the name component is bound then apply it
320
to id and take the return value; otherwise take the dataDefault value.
321
322
If one wants to introduce a database attribute where this functionality is
323
not suitable then another –more specific– function must be entered as the
324
component attributeValue of such an attribute.
325
326
A.1-7 DatabaseIdEnumeratorUpdate
327
328
DatabaseIdEnumeratorUpdate( dbidenum )  function
329
Returns: true or false.
330
331
For a database id enumerator dbidenum (see Section A.1-1),
332
DatabaseIdEnumeratorUpdate first calls the update function of dbidenum.
333
Afterwards, the update components of those of its attributes records are
334
called for which the version component differs from that of dbidenum.
335
336
The order in which the database attributes are updates is determined by the
337
neededAttributes component.
338
339
The return value is true if all these functions return true, and false
340
otherwise.
341
342
When DatabaseIdEnumeratorUpdate has returned true, the data described by
343
dbidenum and its database attributes are consistent and up to date.
344
345
A.1-8 DatabaseAttributeCompute
346
347
DatabaseAttributeCompute( dbidenum, attridentifier[, what] )  function
348
Returns: true or false.
349
350
This function returns false if dbidenum is not a database id enumerator, or
351
if it does not have a database attribute with identifier value
352
attridentifier, or if this attribute does not have a create function.
353
354
Otherwise the prepareAttributeComputation function is called, the data
355
entries for the database attribute are (re)computed, the
356
cleanupAfterAttibuteComputation function is called, and true is returned.
357
358
The optional argument what determines which values are computed. Admissible
359
values are
360
361
"all"
362
all identifiers entries of dbidenum,
363
364
"automatic" (the default)
365
the same as "all" if the type value of the database attribute is
366
"values", otherwise only the values for the "automatic" component are
367
computed,
368
369
"new"
370
stored values are not recomputed.
371
372
A.1-9 DatabaseAttributeSetData
373
374
DatabaseAttributeSetData( dbidenum, attridentifier, version, data )  function
375
376
Let dbidenum be a database id enumerator (see Section A.1-1), attridentifier
377
be a string that is the identifier value of a database attribute of
378
dbidenum, data be the data list or record for the database attribute
379
(depending on its type value), and version be the corresponding version
380
value.
381
382
DatabaseAttributeSetData sets the data and version components of the
383
attribute. This function can be used for example in data files.
384
385
386
A.2 Using Database Attributes for Browse Tables
387
388
389
A.2-1 Browse Relevant Components of Database Attributes
390
391
The following optional components of database id enumerators and database
392
attributes are used by BrowseTableFromDatabaseIdEnumerator (A.2-2).
393
394
viewLabel
395
if bound, a table cell data object (see
396
BrowseData.IsBrowseTableCellData (4.2-1)) that gives a short
397
description of the attribute, which is used as the column label in
398
browse tables created with BrowseTableFromDatabaseIdEnumerator
399
(A.2-2); the default for database attributes is the name component, if
400
bound, and otherwise the identifier component; the default for
401
database id enumerators is the string "name",
402
403
viewValue
404
if bound, a function that takes the output of the attributeValue
405
function and returns a table cell data object (see
406
BrowseData.IsBrowseTableCellData (4.2-1)) that is used as the entry of
407
the corresponding column in browse tables created with
408
BrowseTableFromDatabaseIdEnumerator (A.2-2); the default is String
409
(Reference: String),
410
411
viewSort
412
if bound, a comparison function that takes two database attribute
413
values and returns true if the first value is regarded as smaller than
414
the second when the column corresponding to the attribute in the
415
browse table constructed by BrowseTableFromDatabaseIdEnumerator
416
(A.2-2) gets sorted, and false otherwise; the default is GAP's \<
417
operation,
418
419
sortParameters
420
if bound, a list in the same format as the last argument of
421
BrowseData.SetSortParameters, which is used for the column
422
corresponding to the attribute in the browse table constructed by
423
BrowseTableFromDatabaseIdEnumerator (A.2-2); the default is an empty
424
list,
425
426
widthCol
427
if bound, the width of the column in the browse table constructed by
428
BrowseTableFromDatabaseIdEnumerator (A.2-2); if a column width is
429
prescribed this way then the function stored in the attributeValue
430
component must return either a list of attribute lines that fit into
431
the column or a plain string (which then gets formatted as required);
432
there is no default for this component, meaning that the column width
433
is computed as the maximum of the widths of the column label and of
434
all entries in the column if no value is bound,
435
436
align
437
if bound, the alignment of the values in the column of the browse
438
table constructed by BrowseTableFromDatabaseIdEnumerator (A.2-2);
439
admissible values are substrings of "bclt", see
440
BrowseData.IsBrowseTableCellData (4.2-1); the default is right and
441
vertically centered, but note that if the viewValues function returns
442
a record (see BrowseData.IsBrowseTableCellData (4.2-1)) then the
443
alignment prescribed by this record is preferred,
444
445
categoryValue
446
if bound, a function that is similar to the viewValue component but
447
may return a different value; for example if the column in the browse
448
table belongs to a property and the viewValue function returns
449
something like "+" or "-", it may be useful that the category rows
450
show a textual description of the property values; the default value
451
is the viewValue component; if the value is a record then its rows
452
component is taken for forming category rows, if the value is an
453
attribute line (see NCurses.IsAttributeLine (2.2-3)) then there is
454
exactly this category row, and otherwise the value is regarded as a
455
list of attribute lines, which is either concatenated to one category
456
row or turned into individual category rows, depending on the
457
sortParameters value.
458
459
A.2-2 BrowseTableFromDatabaseIdEnumerator
460
461
BrowseTableFromDatabaseIdEnumerator( dbidenum, labelids, columnids[, header[, footer[, choice]]] )  function
462
Returns: a record that can be used as the input of NCurses.BrowseGeneric
463
(4.3-1).
464
465
For a database id enumerator dbidenum (see Section A.1-1) and two lists
466
labelids and columnids of identifier values of database attributes stored in
467
dbidenum, BrowseTableFromDatabaseIdEnumerator returns a browse table
468
(see BrowseData.IsBrowseTable (4.2-3)) whose columns are given by the values
469
of the specified database attributes. The columns listed in labelids are
470
used to provide row label columns of the browse table, the columns listed in
471
columnids yield main table columns. columnids must be nonempty.
472
473
If the optional arguments header and footer are given then they must be
474
lists or functions or records that are admissible for the header and footer
475
components of the work record of the browse table, see
476
BrowseData.IsBrowseTable (4.2-3).
477
478
The optional argument choice, if given, must be a subset of
479
dbidenum.identifiers. The rows of the returned browse table are then
480
restricted to this subset.
481
482
The returned browse table does not support Click events or return values.
483
484
485
A.3 Example: Database Id Enumerators and Database Attributes
486
487
As an example for the functions introduced in this appendix, we introduce
488
the database of small integers. For that, we fix a positive integer n and
489
consider the integers from 1 to n as the entries of our database. Using
490
these integers as their own identifiers, we construct the database id
491
enumerator.
492
493
 Example 
494
gap> n:= 100;;
495
gap> smallintenum1:= DatabaseIdEnumerator( rec(
496
>  identifiers:= [ 1 .. n ],
497
>  entry:= function( dbidenum, id ) return id; end,
498
>  ) );;
499

500
501
Examples of attributes for this database are the properties whether or not
502
an integer is a prime or a prime power. There are global GAP functions
503
IsPrimeInt (Reference: IsPrimeInt) and IsPrimePowerInt (Reference:
504
IsPrimePowerInt) for computing these properties, so we can define these
505
database attributes via a name component; we choose "values" as the type
506
value, so the values (true or false) are stored in a list of length n for
507
each of the two database attributes.
508
509
 Example 
510
gap> DatabaseAttributeAdd( smallintenum1, rec(
511
>  identifier:= "primes",
512
>  type:= "values",
513
>  name:= "IsPrimeInt",
514
>  ) );
515
gap> DatabaseAttributeAdd( smallintenum1, rec(
516
>  identifier:= "prime powers",
517
>  type:= "values",
518
>  name:= "IsPrimePowerInt",
519
>  ) );
520

521
522
Similarly, we consider the prime factors as a database attribute.
523
524
 Example 
525
gap> DatabaseAttributeAdd( smallintenum1, rec(
526
>  identifier:= "factors",
527
>  type:= "values",
528
>  name:= "Factors",
529
>  ) );
530

531
532
Another example of an attribute of integers is the residue modulo 11. We do
533
not want to introduce a global GAP function for computing the value, so we
534
use the create component in order to define the attribute; again, the values
535
(integers from 0 to 10) are stored in a list of length n.
536
537
 Example 
538
gap> DatabaseAttributeAdd( smallintenum1, rec(
539
>  identifier:= "residue mod 11",
540
>  type:= "values",
541
>  create:= function( attr, id ) return id mod 11; end,
542
>  ) );
543

544
545
Some integers are values of Factorial (Reference: Factorial), and we want to
546
record this information and show it in a browse table. For most integers,
547
nothing is stored and shown for this attribute, so we choose the type value
548
"pairs" and precompute the information for the data component. (The default
549
for the dataDefault component is an empty string, which is fine; so we need
550
not prescribe this component.)
551
552
 Example 
553
gap> factorialdata:= function( n )
554
>  local result, i, f;
555
>  result:= []; i:= 1; f:= 1;;
556
>  while f <= n do
557
>  Add( result, [ f, i ] ); i:= i + 1; f:= f * i;
558
>  od;
559
>  return result;
560
>  end;;
561
gap> DatabaseAttributeAdd( smallintenum1, rec(
562
>  identifier:= "inverse factorial",
563
>  type:= "pairs",
564
>  data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
565
>  isSorted:= true,
566
>  ) );
567

568
569
We use this setup for creating a browse table. The integers are shown as the
570
first column, using the "self" attribute. This attribute can be used as a
571
column of row labels (useful if we want to keep the column visible when one
572
scrolls the table to the right) or as a column in the main table (useful if
573
we want to search for the values); here we choose the former possibility.
574
575
 Example 
576
gap> t1:= BrowseTableFromDatabaseIdEnumerator( smallintenum1,
577
>  [ "self" ],
578
>  [ "primes", "prime powers", "factors", "residue mod 11",
579
>  "inverse factorial" ] );;
580

581
582
The following session shows some of the features of the browse table.
583
584
 Example 
585
gap> nop:= [ 14, 14, 14, 14, 14, 14 ];; # ``do nothing''
586
gap> sample_session:= Concatenation(
587
>  # categorize by the first column, expand categories, wait, reset
588
>  nop, "scsc", nop, "X", nop, "!",
589
>  # sort the residue column, wait, reset
590
>  "scrrrso", nop, "!",
591
>  # categorize by the inverse factorial column
592
>  "rscsrdx", nop, "!",
593
>  # and quit the application
594
>  "qQ" );;
595
gap> BrowseData.SetReplay( sample_session );
596
gap> NCurses.BrowseGeneric( t1 );
597
gap> BrowseData.SetReplay( false );
598
gap> Unbind( t1.dynamic.replay );
599

600
601
(Note that the last statement above is necessary to run the session more
602
than once.) The result is not too bad but we can improve the table, using
603
the optional components of database attributes, as follows.
604
605
 The strings "true" and "false" shown for the Boolean valued database
606
attributes can be replaced by the perhaps more suggestive strings "+"
607
and "-" (or perhaps an empty string instead of "-").
608
609
 The alignment of values inside their columns can be customized.
610
611
 When the browse table is categorized by a column then the values in
612
this column do usually not provide suitable category rows; we can
613
prescribe individual category values.
614
615
 The column labels can be customized.
616
617
 Where the lexicographic order is not appropriate for sorting table
618
entries, we can prescribe an individual comparison function.
619
620
 Sort parameters can be customized.
621
622
 We can prescribe the width of a column, and thus distribute the
623
attribute values for this column to several rows when the values are
624
too long.
625
626
 Finally, in the call of BrowseTableFromDatabaseIdEnumerator (A.2-2),
627
we can add a header to the browse table.
628
629
We create a new database id enumerator and the corresponding browse table,
630
in order to be able to compare the behaviour of the two objects. However, we
631
assume that the variables n and factorialdata are already available.
632
633
 Example 
634
gap> smallintenum2:= DatabaseIdEnumerator( rec(
635
>  identifiers:= [ 1 .. n ],
636
>  entry:= function( dbidenum, id ) return id; end,
637
>  viewLabel:= "",
638
>  ) );;
639
gap> DatabaseAttributeAdd( smallintenum2, rec(
640
>  identifier:= "primes",
641
>  type:= "values",
642
>  name:= "IsPrimeInt",
643
>  viewLabel:= "prime?",
644
>  viewValue:= value -> BrowseData.ReplacedEntry( value,
645
>  [ true, false ], [ "+", "-" ] ),
646
>  sortParameters:= [ "add counter on categorizing", "yes" ],
647
>  align:= "c",
648
>  categoryValue:= value -> BrowseData.ReplacedEntry( value,
649
>  [ true, false ], [ "prime", "nonprime" ] ),
650
>  ) );
651
gap> DatabaseAttributeAdd( smallintenum2, rec(
652
>  identifier:= "prime powers",
653
>  type:= "values",
654
>  name:= "IsPrimePowerInt",
655
>  viewLabel:= "prime power?",
656
>  viewValue:= value -> BrowseData.ReplacedEntry( value,
657
>  [ true, false ], [ "+", "-" ] ),
658
>  sortParameters:= [ "add counter on categorizing", "yes" ],
659
>  align:= "c",
660
>  categoryValue:= value -> BrowseData.ReplacedEntry( value,
661
>  [ true, false ], [ "prime power", "not prime power" ] ),
662
>  ) );
663
gap> DatabaseAttributeAdd( smallintenum2, rec(
664
>  identifier:= "factors",
665
>  type:= "values",
666
>  name:= "Factors",
667
>  viewLabel:= "factors",
668
>  viewValue:= value -> JoinStringsWithSeparator( List( value, String ),
669
>  " * "),
670
>  widthCol:= 10,
671
>  ) );
672
gap> DatabaseAttributeAdd( smallintenum2, rec(
673
>  identifier:= "residue mod 11",
674
>  type:= "values",
675
>  create:= function( attr, id ) return id mod 11; end,
676
>  viewSort:= BrowseData.SortAsIntegers,
677
>  categoryValue:= res -> Concatenation( String( res ), " mod 11" ),
678
>  ) );
679
gap> DatabaseAttributeAdd( smallintenum2, rec(
680
>  identifier:= "inverse factorial",
681
>  type:= "pairs",
682
>  data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
683
>  isSorted:= true,
684
>  categoryValue:= function( k )
685
>  if k = "" then
686
>  return "(no factorial)";
687
>  else
688
>  return Concatenation( String( k ), "!" );
689
>  fi;
690
>  end,
691
>  ) );
692
gap> t2:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,
693
>  [ "self" ],
694
>  [ "primes", "prime powers", "factors", "residue mod 11",
695
>  "inverse factorial" ],
696
>  t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;
697

698
699
We run the same session as with the browse table for smallintenum1.
700
701
 Example 
702
gap> BrowseData.SetReplay( sample_session );
703
gap> NCurses.BrowseGeneric( t2 );
704
gap> BrowseData.SetReplay( false );
705
gap> Unbind( t2.dynamic.replay );
706

707
708
Another possibility to change the look of the table is to combine the
709
columns for the two Boolean valued database attributes in one column, by
710
showing the string "+" for prime powers, as before, and showing this string
711
in boldface red if the number in question is a prime. We implement this idea
712
in the following database attribute. However, note that this can be a bad
713
idea because text attributes may be not supported in the user's terminal
714
(see Section 2.1-7), or the user may have difficulties to see or to
715
distinguish colors; also, it must be documented which information is encoded
716
in the table, and the column label might be not sufficient for explaining
717
what the text attributes mean. Alternatively, we could show for example
718
combined symbols such as ++, +-, -- for primes, prime powers, and
719
non-prime-powers, respectively. (We see that besides these issues, the
720
required GAP code is more involved than what is needed for the examples
721
above.)
722
723
 Example 
724
gap> DatabaseAttributeAdd( smallintenum2, rec(
725
>  identifier:= "primes & prime powers",
726
>  type:= "values",
727
>  create:= function( attr, id )
728
>  if IsPrimeInt( id ) then
729
>  return 2;
730
>  elif IsPrimePowerInt( id ) then
731
>  return 1;
732
>  else
733
>  return 0;
734
>  fi;
735
>  end,
736
>  viewLabel:= [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),
737
>  "prime", NCurses.attrs.NORMAL, " power?" ],
738
>  viewValue:= value -> BrowseData.ReplacedEntry( value,
739
>  [ 0, 1, 2 ], [ "-", "+",
740
>  [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),
741
>  true, "+",
742
>  NCurses.ColorAttr( "red", -1 ), false ] ] ),
743
>  sortParameters:= [ "add counter on categorizing", "yes" ],
744
>  align:= "c",
745
>  categoryValue:= value -> BrowseData.ReplacedEntry( value,
746
>  [ 0, 1, 2 ],
747
>  [ "not prime power", "prime power, not prime", "prime" ] ),
748
>  ) );
749
gap> t3:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,
750
>  [ "self" ],
751
>  [ "primes & prime powers", "residue mod 11",
752
>  "inverse factorial" ],
753
>  t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;
754
gap> sample_session2:= Concatenation(
755
>  # categorize by the first column, expand categories, wait, reset
756
>  nop, "scsc", nop, "X", nop, "!", "Q" );;
757
gap> BrowseData.SetReplay( sample_session2 );
758
gap> NCurses.BrowseGeneric( t3 );
759
gap> BrowseData.SetReplay( false );
760
gap> Unbind( t3.dynamic.replay );
761

762
763
Now we want to consider the database as extendible, that is, we want to be
764
able to increase n after constructing the database attributes. For that, we
765
use n as the version value of the database id enumerator, and provide
766
version and update components for all attributes.
767
768
Again, we start the construction from scratch.
769
770
 Example 
771
gap> smallintenum3:= DatabaseIdEnumerator( rec(
772
>  identifiers:= [ 1 .. n ],
773
>  entry:= function( dbidenum, id ) return id; end,
774
>  viewLabel:= "",
775
>  version:= n,
776
>  update:= function( dbidenum )
777
>  dbidenum.identifiers:= [ 1 .. n ];
778
>  dbidenum.version:= n;
779
>  return true;
780
>  end,
781
>  ) );;
782
gap> updateByUnbindData:= function( attr )
783
>  Unbind( attr.data );
784
>  return true;
785
>  end;;
786
gap> DatabaseAttributeAdd( smallintenum3, rec(
787
>  identifier:= "primes",
788
>  type:= "values",
789
>  name:= "IsPrimeInt",
790
>  viewLabel:= "prime?",
791
>  viewValue:= value -> BrowseData.ReplacedEntry( value,
792
>  [ true, false ], [ "+", "-" ] ),
793
>  sortParameters:= [ "add counter on categorizing", "yes" ],
794
>  align:= "c",
795
>  categoryValue:= value -> BrowseData.ReplacedEntry( value,
796
>  [ true, false ], [ "prime", "nonprime" ] ),
797
>  version:= n,
798
>  update:= updateByUnbindData,
799
>  ) );
800
gap> DatabaseAttributeAdd( smallintenum3, rec(
801
>  identifier:= "prime powers",
802
>  type:= "values",
803
>  name:= "IsPrimePowerInt",
804
>  viewLabel:= "prime power?",
805
>  viewValue:= value -> BrowseData.ReplacedEntry( value,
806
>  [ true, false ], [ "+", "-" ] ),
807
>  sortParameters:= [ "add counter on categorizing", "yes" ],
808
>  align:= "c",
809
>  categoryValue:= value -> BrowseData.ReplacedEntry( value,
810
>  [ true, false ], [ "prime power", "not prime power" ] ),
811
>  version:= n,
812
>  update:= updateByUnbindData,
813
>  ) );
814
gap> DatabaseAttributeAdd( smallintenum3, rec(
815
>  identifier:= "factors",
816
>  type:= "values",
817
>  name:= "Factors",
818
>  viewLabel:= "factors",
819
>  viewValue:= value -> JoinStringsWithSeparator( List( value, String ),
820
>  " * "),
821
>  widthCol:= 10,
822
>  version:= n,
823
>  update:= updateByUnbindData,
824
>  ) );
825
gap> DatabaseAttributeAdd( smallintenum3, rec(
826
>  identifier:= "residue mod 11",
827
>  type:= "values",
828
>  create:= function( attr, id ) return id mod 11; end,
829
>  viewSort:= BrowseData.SortAsIntegers,
830
>  categoryValue:= res -> Concatenation( String( res ), " mod 11" ),
831
>  version:= n,
832
>  update:= updateByUnbindData,
833
>  ) );
834
gap> DatabaseAttributeAdd( smallintenum3, rec(
835
>  identifier:= "inverse factorial",
836
>  type:= "pairs",
837
>  data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
838
>  isSorted:= true,
839
>  categoryValue:= function( k )
840
>  if k = "" then
841
>  return "(no factorial)";
842
>  else
843
>  return Concatenation( String( k ), "!" );
844
>  fi;
845
>  end,
846
>  version:= n,
847
>  update:= function( attr )
848
>  attr.data.automatic:= factorialdata( n );
849
>  return true;
850
>  end,
851
>  ) );
852

853
854
Now we can change the set of database entries by assigning a new value to
855
the variable n, and then calling DatabaseIdEnumeratorUpdate (A.1-7).
856
857
 Example 
858
gap> n:= 200;;
859
gap> DatabaseIdEnumeratorUpdate( smallintenum3 );
860
true
861
gap> t4:= BrowseTableFromDatabaseIdEnumerator( smallintenum3,
862
>  [ "self" ], [ "primes", "prime powers", "factors", "residue mod 11",
863
>  "inverse factorial" ],
864
>  t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;
865
gap> BrowseData.SetReplay( sample_session );
866
gap> NCurses.BrowseGeneric( t4 );
867
gap> BrowseData.SetReplay( false );
868
gap> Unbind( t4.dynamic.replay );
869

870
871
872
A.4 Example: An Overview of the GAP Library of Tables of Marks
873
874
The example shown in this section deals with GAP's Library of Tables of
875
Marks (the TomLib package [NMP13]).
876
877
A.4-1 BrowseTomLibInfo
878
879
BrowseTomLibInfo( )  function
880
Returns: nothing.
881
882
This function shows the contents of the GAP Library of Tables of Marks (the
883
TomLib package, see [NMP13]) in a browse table.
884
885
The first call may take substantial time (about 40 seconds), because the
886
data files of the TomLib package are evaluated. This could be improved by
887
precomputing and caching the values. Another possibility would be to call
888
BrowseTomLibInfo once before creating a GAP workspace. The subsequent calls
889
are not expensive.
890
891
The table rows correspond to the tables of marks, one column of row labels
892
shows the identifier of the table. The columns of the table contain
893
information about the group order, the number of conjugacy classes of
894
subgroups, the identifiers of tables of marks with fusions to and from the
895
given table, and the name of the file that contains the table of marks data.
896
897
The full functionality of the function NCurses.BrowseGeneric (4.3-1) is
898
available.
899
900
 Example 
901
gap> c:= [ NCurses.keys.ENTER ];;
902
gap> n:= [ 14, 14, 14 ];; # ``do nothing''
903
gap> BrowseData.SetReplay( Concatenation(
904
>  "scrrsc", # categorize the list by source tables of fusions,
905
>  "srdd", # choose a source table,
906
>  "x", # expand the list of targets of fusions
907
>  n,
908
>  "!", # revert the categorization
909
>  "q", # leave the mode in which a row is selected
910
>  "scrrrrsc", # categorize the list by filenames
911
>  "X", # expand all categories
912
>  n,
913
>  "!", # revert the categorization
914
>  "scso", # sort the list by group order
915
>  n,
916
>  "!q", # revert the sorting and selection
917
>  "?", # open the help window
918
>  n,
919
>  "Q", # close the help window
920
>  "/A5", c, # search for the first occurrence of "A5"
921
>  n,
922
>  "Q" ) );; # and quit the browse table
923
gap> BrowseTomLibInfo();
924
gap> BrowseData.SetReplay( false );
925

926
927
928