home *** CD-ROM | disk | FTP | other *** search
/ Math Solutions 1995 October / Math_Solutions_CD-ROM_Walnut_Creek_October_1995.iso / pc / mac / discrete / doc / aboutgap.tex next >
Encoding:
Text File  |  1993-05-05  |  301.7 KB  |  7,012 lines

  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %%
  3. %A  aboutgap.tex                GAP documentation               Thomas Breuer
  4. %A                                                             & Frank Celler
  5. %A                                                            & Juergen Mnich
  6. %A                                                           & Goetz Pfeiffer
  7. %A                                                         & Martin Schoenert
  8. %%
  9. %A  @(#)$Id: aboutgap.tex,v 3.49 1993/02/19 10:48:42 gap Exp $
  10. %%
  11. %Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  12. %%
  13. %%  This file contains a tutorial introduction to the GAP system.
  14. %%
  15. %H  $Log: aboutgap.tex,v $
  16. %H  Revision 3.49  1993/02/19  10:48:42  gap
  17. %H  adjustments in line length and spelling
  18. %H
  19. %H  Revision 3.48  1993/02/18  13:51:52  felsch
  20. %H  still another example fixed
  21. %H
  22. %H  Revision 3.47  1993/02/18  08:19:33  felsch
  23. %H  correction in tex
  24. %H
  25. %H  Revision 3.46  1993/02/18  08:04:34  felsch
  26. %H  another example fixed
  27. %H
  28. %H  Revision 3.45  1993/02/17  15:13:27  felsch
  29. %H  examples fixed
  30. %H
  31. %H  Revision 3.44  1993/02/11  12:20:47  martin
  32. %H  changed reference "Strings" to "Strings and Characters"
  33. %H
  34. %H  Revision 3.43  1993/02/10  19:15:24  martin
  35. %H  changed a couple of informations to information
  36. %H
  37. %H  Revision 3.42  1992/08/07  14:36:02  sam
  38. %H  added pictures for online help
  39. %H
  40. %H  Revision 3.41  1992/07/03  12:30:43  sam
  41. %H  little change in 'CharTableSplitClasses'
  42. %H
  43. %H  Revision 3.40  1992/04/30  12:39:59  martin
  44. %H  inserted a *not*
  45. %H
  46. %H  Revision 3.39  1992/04/30  11:53:53  martin
  47. %H  changed a few sentences to avoid bold non-roman fonts
  48. %H
  49. %H  Revision 3.38  1992/04/06  11:10:46  martin
  50. %H  fixed a few more typos
  51. %H
  52. %H  Revision 3.37  1992/04/02  21:06:23  martin
  53. %H  changed *domain functions* to *set theoretic functions*
  54. %H
  55. %H  Revision 3.36  1992/04/02  18:03:40  martin
  56. %H  added the banner
  57. %H
  58. %H  Revision 3.35  1992/04/02  14:11:40  martin
  59. %H  made the final corrections
  60. %H
  61. %H  Revision 3.34  1992/04/02  10:46:31  martin
  62. %H  reformatted sam's sections
  63. %H
  64. %H  Revision 3.33  1992/04/01  13:12:27  martin
  65. %H  added "About Group Libraries"
  66. %H
  67. %H  Revision 3.32  1992/04/01  08:22:11  fceller
  68. %H  fixed typos in "About Mappings and Homomoprhisms"
  69. %H
  70. %H  Revision 3.31  1992/04/01  07:38:57  sam
  71. %H  some more corrections in 'About Character Tables'
  72. %H
  73. %H  Revision 3.30  1992/03/31  12:16:18  martin
  74. %H  added new versions of "About Fields" and "About Matrix Groups"
  75. %H
  76. %H  Revision 3.29  1992/03/31  10:32:57  martin
  77. %H  renamed chapter to "About GAP" and fixed a few typos
  78. %H
  79. %H  Revision 3.28  1992/03/31  10:04:29  martin
  80. %H  added examples for 'InnerAutomorphism'
  81. %H
  82. %H  Revision 3.27  1992/03/30  07:53:07  fceller
  83. %H  changed "About Mappings and Homomorphisms"
  84. %H
  85. %H  Revision 3.26  1992/03/26  15:18:05  martin
  86. %H  changed 'SemiDirectProduct' to 'SemidirectProduct'
  87. %H
  88. %H  Revision 3.25  1992/03/23  16:04:57  martin
  89. %H  added "About Defining New Parametrized Domains"
  90. %H
  91. %H  Revision 3.24  1992/03/23  13:58:42  martin
  92. %H  fixed several typos in the first sections
  93. %H
  94. %H  Revision 3.23  1992/03/18  18:44:00  martin
  95. %H  added a new "About Domains and Categories"
  96. %H
  97. %H  Revision 3.22  1992/03/13  17:54:28  sam
  98. %H  some corrections
  99. %H
  100. %H  Revision 3.21  1992/03/13  15:24:38  goetz
  101. %H  slight improvements.
  102. %H
  103. %H  Revision 3.20  1992/03/13  14:19:33  martin
  104. %H  fixed some more typos
  105. %H
  106. %H  Revision 3.19  1992/03/13  12:04:05  goetz
  107. %H  split "About Ranges and Loops", renamed "About Operators" to
  108. %H  "About Constants and Operators", introduced perms and strings.
  109. %H
  110. %H  Revision 3.18  1992/03/13  11:37:51  martin
  111. %H  fixed several typos
  112. %H
  113. %H  Revision 3.17  1992/03/13  11:03:53  martin
  114. %H  improved "About Operations of Groups"
  115. %H
  116. %H  Revision 3.16  1992/03/12  17:14:50  sam
  117. %H  improvements in 'About Groups'
  118. %H
  119. %H  Revision 3.15  1992/03/12  16:40:20  martin
  120. %H  fixed several typos in "About Operations of Groups"
  121. %H
  122. %H  Revision 3.14  1992/03/12  16:18:51  martin
  123. %H  added "About Defining New Domains"
  124. %H
  125. %H  Revision 3.13  1992/03/12  11:01:37  martin
  126. %H  extended 'ResidueClassOps' to allow cyclic group definitions
  127. %H
  128. %H  Revision 3.12  1992/03/12  10:46:26  martin
  129. %H  extended "About Operations of Groups" to mention normal forms
  130. %H
  131. %H  Revision 3.11  1992/03/11  17:23:32  martin
  132. %H  fixed several typos
  133. %H
  134. %H  Revision 3.10  1992/03/11  16:05:04  sam
  135. %H  renamed chapter "Number Fields" to "Subfields of Cyclotomic Fields"
  136. %H
  137. %H  Revision 3.9  1992/03/11  12:40:52  martin
  138. %H  fixed a few things in "About Operations of Groups"
  139. %H
  140. %H  Revision 3.8  1992/03/10  20:45:15  martin
  141. %H  added "About Operations of Groups"
  142. %H
  143. %H  Revision 3.7  1992/03/10  18:30:27  goetz
  144. %H  some remarks about 'List' and 'Filtered'.
  145. %H
  146. %H  Revision 3.6  1992/03/10  11:55:51  sam
  147. %H  some more corrections in 'About Character Tables'
  148. %H
  149. %H  Revision 3.5  1992/03/09  13:12:44  martin
  150. %H  added "About Domain" and "About Mappings and Homomorphisms"
  151. %H
  152. %H  Revision 3.4  1992/03/09  10:06:17  sam
  153. %H  corrections in 'About Character Tables'
  154. %H
  155. %H  Revision 3.3  1992/03/04  12:28:02  goetz
  156. %H  some corrections.
  157. %H
  158. %H  Revision 3.2  1992/03/03  15:43:28  sam
  159. %H  improvements in 'About Groups'
  160. %H
  161. %H  Revision 3.1  1992/03/03  08:56:48  sam
  162. %H  added Juergen's sections  'About Fields' and 'About Matrix Groups'
  163. %H
  164. %H  Revision 3.0  1992/02/24  17:58:17  goetz
  165. %H  initial revision.
  166. %H
  167. %%
  168. \Chapter{About GAP}
  169.  
  170. This  chapter introduces you to  the {\GAP} system.  It  describes how to
  171. start {\GAP} (you may have to ask your system administrator to install it
  172. correctly) and  how to leave it.  Then a step by step introduction should
  173. give you an impression of how the {\GAP} system  works.  Further sections
  174. will give an overview about the features of {\GAP}.   After  reading this
  175. chapter the reader should know what kind of problems can be handled  with
  176. {\GAP} and how they can be handled.
  177.  
  178. There is  some  repetition in  this chapter and much  of the material  is
  179. repeated in later chapters in a more compact and precise way.  Yes, there
  180. are even  some little inaccuracies in this chapter simplifying things for
  181. better understanding.  It should be used as a tutorial introduction while
  182. later chapters form the reference manual.
  183.  
  184. {\GAP}   is  an  interactive  system.    It   continuously   executes   a
  185. read--evaluate--print cycle.  Each expression you type at the keyboard is
  186. read by {\GAP}, evaluated, and then the result is printed.
  187.  
  188. The interactive nature of {\GAP} allows you to type  an expression at the
  189. keyboard and see its value immediately.  You can  define a  function  and
  190. apply it to arguments  to  see how  it  works.  You may  even write whole
  191. programs containing lots  of functions and test them without leaving  the
  192. program.
  193.  
  194. When  your program  is large it will be  more convenient to write it on a
  195. file and then read that file into {\GAP}.  Preparing  your functions in a
  196. file  has  several  advantages.   You  can  compose  your functions  more
  197. carefully in a file (with  your  favorite text  editor),  you can correct
  198. errors without retyping the whole  function and you  can keep a copy  for
  199. later  use.   Moreover you  can write lots  of comments into the  program
  200. text, which are ignored  by {\GAP}, but are very useful for human readers
  201. of your program text.
  202.  
  203. {\GAP} treats input from a file in the same way that it treats input from
  204. the keyboard.
  205.  
  206. The printed examples in this first chapter  encourage  you to try running
  207. {\GAP} on your computer.  This will  support your feeling for {\GAP} as a
  208. tool, which is  the  leading  aim  of this chapter.   Do  not believe any
  209. statement in this  chapter so  long as you cannot verify it  for your own
  210. version  of  {\GAP}.   You  will  learn   to  distinguish  between  small
  211. deviations  of the behavior  of your  personal  {\GAP} from  the  printed
  212. examples and serious nonsense.
  213.  
  214. Since the printing routines of {\GAP} are in some sense machine dependent
  215. you will for instance encounter a different layout of the printed objects
  216. in different environments.  But the contents should always be the same.
  217.  
  218. In case  you encounter serious nonsense it is highly recommended that you
  219. send a bug report to 'gap-forum@samson.math.rwth-aachen.de'.
  220.  
  221. If you read this introduction on-line you should now enter ?> to read the
  222. next section.
  223.  
  224. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  225. \Section{About Conventions}
  226.  
  227. Throughout this manual both the input given to {\GAP} and the output that
  228. {\GAP} returns are printed  in 'typewriter'  font  just  as if  they were
  229. typed at the keyboard.
  230.  
  231. An  <italic>  font is used for keys that have no printed  representation,
  232. such as e.g.\  the <newline> key and the <ctl>  key.   This  font is also
  233. used for the formal parameters of functions  that  are described in later
  234. chapters.
  235.  
  236. A combination  like <ctl>-'P' means pressing both keys,  that is  holding
  237. the  control key  <ctl> and pressing  the key  'P'  while <ctl> is  still
  238. pressed.
  239.  
  240. New terms are introduced in *bold face*.
  241.  
  242. In  most  places  *whitespace*  characters  (i.e.   <space>s, <tab>s  and
  243. <newline>s)   are  insignificant  for  the   meaning  of   {\GAP}  input.
  244. Identifiers and keywords must however not contain any whitespace.  On the
  245. other  hand,  sometimes there  must be whitespace around identifiers  and
  246. keywords to separate them from each other and from numbers.  We  will use
  247. whitespace to format more complicated commands for better readability.
  248.  
  249. A *comment* in {\GAP} starts  with  the  symbol '\#' and continues to the
  250. end of the line.  Comments are treated like whitespace by {\GAP}.
  251.  
  252. Besides of such comments which are part of the input of a {\GAP} session,
  253. we use additional comments  which are part of the manual description, but
  254. not  of the  respective {\GAP} session.  In the  printed version  of this
  255. manual  these comments  will  be printed  in  a normal  font  for  better
  256. readability, hence they start with the symbol \#.
  257.  
  258. The example of {\GAP} sessions given in ths manual have been run with the
  259. line  length set to 72  (by the 'SizeScreen' command). You should be able
  260. to reproduce the results except of  a few lines of  output which  we have
  261. edited a  little  bit with  respect  to blanks or line breaks in order to
  262. improve the readability. Note, however, that for each  particular section
  263. we have run the  examples  in  one continuous session. Hence, as  soon as
  264. random  processes  are  involved,  you may  get  differnt results  if you
  265. extract single examples and run them separately.
  266.  
  267. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  268. \Section{About Starting and Leaving GAP}
  269.  
  270. If the  program  is correctly installed then  you start {\GAP}  by simply
  271. typing 'gap'  at  the prompt  of your  operating  system  followed by the
  272. <return> or the <newline> key.
  273.  
  274. |    $ gap|
  275.  
  276. {\GAP} answers your  request with  its beautiful  banner  (which you  can
  277. surpress with the command line  option  '-b')  and then  it shows its own
  278. prompt 'gap>' asking you for further input.
  279.  
  280. |    gap>|
  281.  
  282. The usual way  to end a {\GAP} session  is to type  'quit;' at the 'gap>'
  283. prompt.  Do not omit the semicolon!
  284.  
  285. |    gap> quit;
  286.     $ |
  287.  
  288. On some systems you may as well type <ctl>-'D' to  yield the same effect.
  289. In any situation  {\GAP} is ended by   typing <ctl>-'C'  twice  within  a
  290. second.
  291.  
  292. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  293. \Section{About First Steps}
  294.  
  295. A simple calculation with {\GAP} is as easy as one can imagine.  You type
  296. the problem just after the prompt, terminate it with a semicolon and then
  297. pass the problem to the  program with the <return> key.  For  example, to
  298. multiply the difference between 9 and 7 by the sum of 5 and 6, that is to
  299. calculate  $(9 - 7) \* (5 + 6)$, you type exactly this  last sequence  of
  300. symbols followed by ';' and <return>.
  301.  
  302. |    gap> (9 - 7) * (5 + 6);
  303.     22
  304.     gap> |
  305.  
  306. Then {\GAP} echoes the result   22 on the  next line  and shows with  the
  307. prompt that it is ready for the next problem.
  308.  
  309. If you did omit the semicolon at the  end of  the  line but have  already
  310. typed <return>, then {\GAP} has read everything you  typed, but does  not
  311. know  that the command is  complete.  The  program is waiting for further
  312. input and indicates this with a partial prompt '>'.   This little problem
  313. is solved by  simply typing  the missing  semicolon on  the next line  of
  314. input.  Then the result is printed and the normal prompt returns.
  315.  
  316. |    gap> (9 - 7) * (5 + 6)
  317.     > ;
  318.     22
  319.     gap> |
  320.  
  321. Whenever you see this partial prompt and you cannot decide what {\GAP} is
  322. still  waiting  for,  then you have  to type  semicolons until the normal
  323. prompt returns.
  324.  
  325. In every situation this is the exact meaning of the prompt 'gap>' \:\ the
  326. program is waiting for  a new problem.  In the following examples we will
  327. omit this prompt  on the line after the result.  Considering each example
  328. as a  continuation  of  its  predecessor  this prompt occurs in  the next
  329. example.
  330.  
  331. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  332. In  this  section you  have  seen how simple  arithmetic  problems can be
  333. solved by  {\GAP} by  simply  typing  them in.   You have  seen  that  it
  334. doesn\'t  matter whether you complete  your  input on  one  line.  {\GAP}
  335. reads  your input line  by line and starts evaluating if it  has seen the
  336. terminating semicolon and <return>.
  337.  
  338. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  339. \Section{About Syntax Errors}
  340.  
  341. Even if you mistyped the command you do not have to  type it all again as
  342. {\GAP}  permits a lot of  command  line editing.   Maybe you mistyped  or
  343. forgot the last closing parenthesis.  Then  your command is syntactically
  344. incorrect and  {\GAP} will  notice it, incapable of computing the desired
  345. result.
  346.  
  347. |    gap> (9 - 7) * (5 + 6;
  348.     Syntax error: ) expected
  349.     (9 - 7) * (5 + 6;
  350.                     ^|
  351.  
  352. Instead of the result an error message occurs  indicating the place where
  353. an unexpected  symbol  occurred with  an arrow sign '\^' under  it.  As a
  354. computer program cannot know  what  your  intentions really were, this is
  355. only a hint.  But  in this  case {\GAP} is right  by  claiming that there
  356. should be a closing  parenthesis before the semicolon.  Now  you can type
  357. <ctl>-'P' to  recover the last line of  input.  It  will be written after
  358. the prompt with the cursor in the first position.  Type <ctl>-'E' to take
  359. the cursor  to the end of the line, then <ctl>-'B' to move the cursor one
  360. character  back.  The  cursor  is  now  on the position of the semicolon.
  361. Enter  the missing  parenthesis  by simply typing ')'.  Now  the  line is
  362. correct and may be passed to {\GAP} by  hitting  the <newline> key.  Note
  363. that for this action it is not necessary to move the cursor past the last
  364. character of the input line.
  365.  
  366. Each  line  of commands you  type  is  sent to  {\GAP} for  evaluation by
  367. pressing <newline> regardless of the position of the cursor in that line.
  368. We will no longer mention the <newline> key from now on.
  369.  
  370. Sometimes a syntax error will cause {\GAP} to enter a *break loop*.  This
  371. is indicated by the special prompt 'brk>'.  You can leave  the break loop
  372. by either typing 'return;'  or  by hitting  <ctl>-'D'.  Then  {\GAP} will
  373. return to its normal state and show its normal prompt again.
  374.  
  375. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  376. In  this section you learned that mistyped  input will  not  lead to  big
  377. confusion.   If  {\GAP} detects a syntax  error  it will print  an  error
  378. message and return  to its normal state.  The command line editing allows
  379. you in a comfortable way to manipulate earlier input lines.
  380.  
  381. For  the  definition  of the {\GAP}  syntax  see chapter "The Programming
  382. Language".  A complete list of command line editing facilities  is  found
  383. in "Line Editing".  The break loop is described in "Break Loops".
  384.  
  385. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  386. \Section{About Constants and Operators}
  387.  
  388. In an expression like  |(9 - 7) * (5 +  6)| the constants  5, 6, 7, and 9
  389. are being composed by the operators |+|, |*| and |-|  to result in a  new
  390. value.
  391.  
  392. There are  three kinds  of operators in  {\GAP}, arithmetical  operators,
  393. comparison operators, and logical operators.  You  have already seen that
  394. it is possible to form  the sum,  the  difference, and the product of two
  395. integer values.  There are some  more operators applicable to integers in
  396. {\GAP}.   Of  course integers  may  be divided  by  each other,  possibly
  397. resulting in noninteger rational values.
  398.  
  399. |    gap> 12345/25;
  400.     2469/5 |
  401.  
  402. Note  that  the numerator and denominator  are divided by their  greatest
  403. common divisor  and that the result is uniquely represented as a division
  404. instruction.
  405.  
  406. We  haven\'t  met  negative  numbers  yet.   So  consider  the  following
  407. self--explanatory examples.
  408.  
  409. |    gap> -3; 17 - 23;
  410.     -3
  411.     -6 |
  412.  
  413. The exponentiation  operator  is  written  as  '\^'.   This  operation in
  414. particular might lead to  very  large  numbers.  This  is  no problem for
  415. {\GAP} as it can handle numbers of (almost) arbitrary size.
  416.  
  417. |    gap> 3^132;
  418.     955004950796825236893190701774414011919935138974343129836853841 |
  419.  
  420. The 'mod' operator allows you to compute one value modulo another.
  421.  
  422. |    gap> 17 mod 3;
  423.     2 |
  424.  
  425. Note that  there  must be  whitespace  around  the  keyword 'mod' in this
  426. example since '17mod3' or '17mod' would be interpreted as  identifiers.
  427.  
  428. {\GAP}  knows a  precedence  between operators that may be overridden  by
  429. parentheses.
  430.  
  431. |    gap> (9 - 7) * 5 = 9 - 7  * 5;
  432.     false |
  433.  
  434. Besides these  arithmetical  operators  there are comparison operators in
  435. {\GAP}.  A comparison results in a *boolean value* which is another  kind
  436. of constant.   Every  two  objects within {\GAP} are comparable via  |=|,
  437.  |<>|,  |<|,  |<=|,  |>|  and  |>=|,  that  is  the  tests  for equality,
  438. inequality, less than, less than  or equal, greater than and greater than
  439. or equal.  There is an ordering  defined on the set of all {\GAP} objects
  440. that  respects orders on subsets that one  might expect.  For example the
  441. integers are ordered in the usual way.
  442.  
  443. |    gap> 10^5 < 10^4;
  444.     false |
  445.  
  446. The boolean values  'true' and   'false'  can be  manipulated via logical
  447. operators, i.~e., the unary operator 'not' and the binary operators 'and'
  448. and 'or'.  Of course boolean values can be compared, too.
  449.  
  450. |    gap> not true; true and false; true or false;
  451.     false
  452.     false
  453.     true
  454.     gap> 10 > 0 and 10 < 100;
  455.     true |
  456.  
  457. Another important type of constants  in {\GAP}  are *permutations*.  They
  458. are written in cycle notation and they can be multiplied.
  459.  
  460. |    gap> (1,2,3);
  461.     (1,2,3)
  462.     gap> (1,2,3) * (1,2);
  463.     (2,3) |
  464.  
  465. The  inverse  of the  permutation '(1,2,3)'  is denoted by  |(1,2,3)^-1|.
  466. Moreover the caret operator |^| is used to determine the image of a point
  467. under a permutation and to conjugate one permutation by another.
  468.  
  469. |    gap> (1,2,3)^-1;
  470.     (1,3,2)
  471.     gap> 2^(1,2,3);
  472.     3
  473.     gap> (1,2,3)^(1,2);
  474.     (1,3,2) |
  475.  
  476. The last  type of constants we want to introduce  here are the *strings*.
  477. In {\GAP} strings are just normal text enclosed in double quotes.
  478.  
  479. |    gap> "This is a string";
  480.     "This is a string"
  481.     gap> "Whitespace                           is relevant in strings.";
  482.     "Whitespace                           is relevant in strings." |
  483.  
  484. There are  no operators defined  for strings  except  that strings can be
  485. compared.
  486.  
  487. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  488. In this  section  you  have seen that values  may  be preceded  by  unary
  489. operators  and combined by binary operators placed  between the operands.
  490. There are  rules for precedence  which  may be overridden by parentheses.
  491. It is  possible  to  compare any two  objects.  A comparison results in a
  492. boolean  value.   Boolean  values  are  combined  via logical  operators.
  493. Moreover  you have seen that {\GAP} handles  numbers  of arbitrary  size.
  494. Numbers  and  boolean  values  are  constants.  There are  other types of
  495. constants in  {\GAP} like permutations  and strings.   You are  now in  a
  496. position to use {\GAP} as a simple desktop calculator.
  497.  
  498. Operators are explained in more detail in "Comparisons" and "Operations".
  499. Moreover there are sections about  operators  and comparisons for special
  500. types of objects in almost every  chapter of this  manual.  You will find
  501. more information about boolean values in chapters "Booleans" and "Boolean
  502. Lists".  Permutations are described in chapter "Permutations" and strings
  503. are described in chapter "Strings and Characters".
  504.  
  505. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  506. \Section{About Variables and Assignments}
  507.  
  508. Values  may be assigned to variables.  A variable enables you to refer to
  509. an object via a name.  The name of a variable is  called an *identifier*.
  510. The assignment operator is  |:=|.   There must  be no white space between
  511. the |:| and the  |=|.  Do  not confuse the assignment operator  |:=| with
  512. the single equality sign |=| which is in {\GAP} only used for the test of
  513. equality.
  514.  
  515. |    gap> a:= (9 - 7) * (5 + 6);
  516.     22
  517.     gap> a;
  518.     22
  519.     gap> a * (a + 1);
  520.     506
  521.     gap> a:= 10;
  522.     10
  523.     gap> a * (a + 1);
  524.     110 |
  525.  
  526. After an  assignment the assigned value is echoed on the next  line.  The
  527. printing of the value of  a statement  may be in every case prevented  by
  528. typing a double semicolon.
  529.  
  530. |    gap> w:= 2;; |
  531.  
  532. After the  assignment the variable evaluates to that  value if evaluated.
  533. Thus it is possible to refer to that value by the name of the variable in
  534. any situation.
  535.  
  536. This is  in  fact the whole  secret  of an assignment.  An  identifier is
  537. bound  to a value and from  this moment  points  to that value.   Nothing
  538. more.  This binding is changed by the next assignment to that identifier.
  539. An  identifier  does  not  denote  a  block of  memory as  in some  other
  540. programming languages.  It simply points to a value, which has been given
  541. its place in memory by the {\GAP} storage manager.  This place may change
  542. during a {\GAP} session, but that doesn\'t bother the identifier.
  543.  
  544. *The identifier points to the value, not to a place in the memory.*
  545.  
  546. For the same  it  is  reason  not the identifier that has a  type but the
  547. object.   This means on  the other hand that the identifier 'a' which now
  548. is bound to an  integer value may in the  same session point to any other
  549. value regardless of its type.
  550.  
  551. Identifiers  may be sequences  of letters and digits containing at  least
  552. one letter.   For example  'abc' and 'a0bc1'  are valid identifiers.  But
  553. also '123a'  is  a valid identifier as  it cannot be  confused  with  any
  554. number.  Just '1234' indicates the  number 1234 and cannot be at the same
  555. time the name of a variable.
  556.  
  557. Since  {\GAP} distinguishes  upper and  lower  case, 'a1'  and  'A1'  are
  558. different  identifiers.   Keywords  such as 'quit'  must not  be used  as
  559. identifiers.  You will see more keywords in the following sections.
  560.  
  561. In  the remaining part of  this manual  we  will  ignore  the  difference
  562. between  variables, their names  (identifiers), and the values they point
  563. at.  It  may  be  useful to think from time to time about  what is really
  564. meant by terms such as the integer 'w'.
  565.  
  566. There are some predefined variables coming with {\GAP}.  Many of them you
  567. will find in the remaining  chapters of  this manual, since functions are
  568. also referred to via identifiers.
  569.  
  570. This seems to be the right place to state the following rule.
  571.  
  572. The name  of every  function in the {\GAP} library starts with a *capital
  573. letter.*
  574.  
  575. Thus  if you choose  only names starting with a small letter for your own
  576. variables you will not overwrite any predefined function.
  577.  
  578. But there are some  further interesting  variables  one of which shall be
  579. introduced now.
  580.  
  581. Whenever {\GAP} returns   a value by printing  it  on the next line  this
  582. value is assigned to the variable 'last'.  So if you computed
  583.  
  584. |    gap> (9 - 7) * (5 + 6);
  585.     22 |
  586.  
  587. and forgot to assign the value to the variable  'a' for further use,  you
  588. can still do it by the following assignment.
  589.  
  590. |    gap> a:= last;
  591.     22 |
  592.  
  593. Moreover there are variables 'last2' and 'last3', guess their values.
  594.  
  595. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  596. In  this section you have seen how to assign values to  variables.  These
  597. values  can  later  be accessed through  the  name of the  variable,  its
  598. identifier.  You  have also encountered the useful concept  of the 'last'
  599. variables storing the latest returned values.  And  you have learned that
  600. a double semicolon prevents the result of a statement from being printed.
  601.  
  602. Variables and assignments are described in more detail in "Variables" and
  603. "Assignments".  A complete list of keywords is contained in "Keywords".
  604.  
  605. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  606. \Section{About Functions}
  607.  
  608. A  program  written  in  the  {\GAP} language  is  called  a  *function*.
  609. Functions  are   special  {\GAP}  objects.   Most  of  them  behave  like
  610. mathematical functions.  They are applied to  objects and  will return  a
  611. new  object  depending  on  the input.   The  function  'Factorial',  for
  612. example,  can be applied to an  integer and will  return the factorial of
  613. this integer.
  614.  
  615. |    gap> Factorial(17);
  616.     355687428096000 |
  617.  
  618. Applying  a  function  to arguments  means  to  write  the  arguments  in
  619. parentheses following the function.   Several arguments are  separated by
  620. commas, as for the  function  'Gcd' which  computes  the greatest  common
  621. divisor of two integers.
  622.  
  623. |    gap> Gcd(1234, 5678);
  624.     2 |
  625.  
  626. There are other functions that do not return a value but  only  produce a
  627. side effect.  They  change for  example  one of  their  arguments.  These
  628. functions are sometimes called procedures.  The function 'Print' is  only
  629. called for the side effect to print something on the screen.
  630.  
  631. |    gap> Print(1234, "\n");
  632.     1234 |
  633.  
  634. In order to be able to compose arbitrary text with 'Print', this function
  635. itself will not produce a line break after printing.  Thus we had another
  636. newline character |"\n"| printed to start a new line.
  637.  
  638. Some functions will both change an argument and return a  value  such  as
  639. the function  'Sortex' that sorts a  list  and returns the permutation of
  640. the list elements that it has performed.
  641.  
  642. You will not  understand right now what it means to change an object.  We
  643. will return to this subject several times in the next sections.
  644.  
  645. A comfortable  way  to  define  a  function  is  given by  the *maps--to*
  646. operator '->'  consisting  of a minus  sign and  a greater  sign  with no
  647. whitespace between them.  The function 'cubed' which maps a number to its
  648. cube is defined on the following line.
  649.  
  650. |    gap> cubed:= x -> x^3;
  651.     function ( x ) ... end |
  652.  
  653. After the function has been defined, it can now be applied.
  654.  
  655. |    gap> cubed(5);
  656.     125 |
  657.  
  658. Not every {\GAP} function can be defined in this  way.   You will see how
  659. to write your own {\GAP} functions in a later section.
  660.  
  661. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  662. In this section you have seen {\GAP} objects of  type function.  You have
  663. learned how to apply a function to  arguments.  This  yields as result  a
  664. new object or a side effect.  A side effect may change an argument of the
  665. function.   Moreover you have seen an easy  way  to define a  function in
  666. {\GAP} with the maps-to operator.
  667.  
  668. Function  calls are described   in   "Function  Calls" and in  "Procedure
  669. Calls".  The functions  of the {\GAP} library are  described in detail in
  670. the remaining chapters of this manual, the Reference Manual.
  671.  
  672. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  673. \Section{About Lists}
  674.  
  675. A *list* is a collection of objects separated by  commas and enclosed  in
  676. brackets.  Let us for example construct the list 'primes' of the first 10
  677. prime numbers.
  678.  
  679. |    gap> primes:= [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
  680.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ] |
  681.  
  682. The next two primes are  31 and 37.  They may be appended to the existing
  683. list by the function 'Append' which takes  the existing list as its first
  684. and another list as a second argument.  The  second argument  is appended
  685. to the list 'primes' and  no  value is returned.  Note that  by appending
  686. another list the object 'primes' is changed.
  687.  
  688. |    gap> Append(primes, [31, 37]);
  689.     gap> primes;
  690.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 ] |
  691.  
  692. You can as well add single new elements to existing lists by the function
  693. 'Add'  which takes  the existing list  as its  first argument  and  a new
  694. element as  its second argument.  The  new  element  is added to the list
  695. 'primes' and again no value is returned but the list 'primes' is changed.
  696.  
  697. |    gap> Add(primes, 41);
  698.     gap> primes;
  699.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41 ] |
  700.  
  701. Single elements of a list are referred to by their position in the  list.
  702. To get the value  of the seventh prime, that is the seventh entry in  our
  703. list 'primes', you simply type
  704.  
  705. |    gap> primes[7];
  706.     17 |
  707.  
  708. and you  will get the  value  of the  seventh prime.  This  value  can be
  709. handled like any other value, for example multiplied by 2 or  assigned to
  710. a variable.  On the other hand this mechanism allows to assign a value to
  711. a  position in  a list.  So the next prime 43 may be inserted in the list
  712. directly  after  the  last  occupied  position  of 'primes'.   This  last
  713. occupied position is returned by the function 'Length'.
  714.  
  715. |    gap> Length(primes);
  716.     13
  717.     gap> primes[14]:= 43;
  718.     43
  719.     gap> primes;
  720.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43 ] |
  721.  
  722. Note that this operation again has changed the object 'primes'.  Not only
  723. the next position of a list is capable  of taking  a  new  value.  If you
  724. know that 71 is the 20th prime, you can as well enter it right now in the
  725. 20th position of 'primes'.   This  will result in a list with holes which
  726. is however still a list and has length 20 now.
  727.  
  728. |    gap> primes[20]:= 71;
  729.     71
  730.     gap> primes;
  731.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,,,,,, 71 ]
  732.     gap> Length(primes);
  733.     20 |
  734.  
  735. The list itself however must  exist before a  value can be  assigned to a
  736. position of the list.  This list may be the empty list '[ ]'.
  737.  
  738. |    gap> lll[1]:= 2;
  739.     Error, Variable: 'lll' must have a value
  740.     gap> lll:= [];
  741.     [  ]
  742.     gap> lll[1]:= 2;
  743.     2 |
  744.  
  745. Of course  existing  entries of a  list can be changed by this mechanism,
  746. too.  We will not do it here  because  'primes' then may no  longer  be a
  747. list of primes.  Try for yourself to change the 17 in the list into a 9.
  748.  
  749. To  get  the  position  of  17  in  the  list  'primes' use  the function
  750. 'Position'  which takes the list as its first argument and the element as
  751. its second  argument and returns the position of  the first occurrence of
  752. the element 17 in  the list 'primes'.  'Position' will return 'false'  if
  753. the element is not contained in the list.
  754.  
  755. |    gap> Position(primes, 17);
  756.     7
  757.     gap> Position(primes, 20);
  758.     false |
  759.  
  760. In  all  of the  above changes to  the  list 'primes',  the list has been
  761. automatically resized.  There  is no need  for you to tell {\GAP} how big
  762. you want a list to be.  This is all done dynamically.
  763.  
  764. It is not necessary for the objects collected in a list to be of the same
  765. type.
  766.  
  767. |    gap> lll:= [true, "This is a String",,, 3];
  768.     [ true, "This is a String",,, 3 ] |
  769.  
  770. In the same way a list may be part of another  list.  A list  may even be
  771. part of itself.
  772.  
  773. |    gap> lll[3]:= [4,5,6];; lll;
  774.     [ true, "This is a String", [ 4, 5, 6 ],, 3 ]
  775.     gap> lll[4]:= lll;
  776.     [ true, "This is a String", [ 4, 5, 6 ], ~, 3 ] |
  777.  
  778. Now the tilde |~| in the fourth position of 'lll' denotes the object that
  779. is currently printed.  Note that the  result of the last operation is the
  780. actual  value of  the  object  'lll'  on  the  right  hand  side  of  the
  781. assignment.  But in fact  it is identical to the value  of the whole list
  782. 'lll' on the left hand side of the assignment.
  783.  
  784. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  785. In  this long  section you have  encountered the fundamental concept of a
  786. list.  You have  seen  how to construct lists, how to extend them and how
  787. to refer to single elements of a list.  Moreover you have seen that lists
  788. may  contain elements of different types,  even holes (unbound  entries).
  789. But this is still not all we have to tell you about lists.
  790.  
  791. You will find a  discussion  about identity and  equality of lists in the
  792. next section.  Moreover you will see special kinds of lists like sets (in
  793. "About Sets"), vectors and matrices (in "About Vectors and Matrices") and
  794. ranges (in "About Ranges").
  795.  
  796. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  797. \Section{About Identical Lists}
  798.  
  799. This second section  about lists  is dedicated  to the subtle  difference
  800. between equality and  identity of   lists.  It  is really  important   to
  801. understand  this difference  in  order  to  understand  how  complex data
  802. structures  are  realized in {\GAP}.  This section applies  to all {\GAP}
  803. objects  that  have subobjects, i.~e., to  lists  and to records.   After
  804. reading the section about records ("About Records")  you should return to
  805. this section and translate it into the record context.
  806.  
  807. Two  lists are equal if all their entries are equal.  This means that the
  808. equality operator '=' returns 'true' for the  comparison of  two lists if
  809. and  only if these two lists are of the same length and for each position
  810. the values in the respective lists are equal.
  811.  
  812. |    gap> numbers:= primes;
  813.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,,,,,, 71 ]
  814.     gap> numbers = primes;
  815.     true |
  816.  
  817. We assigned  the  list 'primes' to the variable  'numbers' and, of course
  818. they are equal as they have  both  the same length  and the same entries.
  819. Now we  will change the  third number to  4 and  compare the result again
  820. with 'primes'.
  821.  
  822. |    gap> numbers[3]:= 4;
  823.     4
  824.     gap> numbers = primes;
  825.     true |
  826.  
  827. You  see that  'numbers'  and  'primes' are  still  equal, check  this by
  828. printing the value of 'primes'.  The list 'primes' is no longer a list of
  829. primes!   What has happened?  The truth  is that the  lists  'primes' and
  830. 'numbers'  are not  only  equal  but  they  are identical.   'primes' and
  831. 'numbers' are two variables pointing to the same list.  If you change the
  832. value of the subobject 'numbers[3]' of 'numbers'  this will  also  change
  833. 'primes'.   Variables do *not* point to a certain block of storage memory
  834. but they  do point  to an  object  that occupies storage  memory.  So the
  835. assignment |numbers:= primes| did *not* create a new list in  a different
  836. place of memory but only  created the new name 'numbers' for the same old
  837. list of primes.
  838.  
  839. *The same object can have several names.*
  840.  
  841. If  you want to change a list with the contents of 'primes' independently
  842. from 'primes' you will have to  make a *copy* of 'primes' by the function
  843. 'Copy'  which takes an object as its argument  and returns a copy  of the
  844. argument.  (We will first restore the old value of 'primes'.)
  845.  
  846. |    gap> primes[3]:= 5;
  847.     5
  848.     gap> primes;
  849.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,,,,,, 71 ]
  850.     gap> numbers:= Copy(primes);
  851.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,,,,,, 71 ]
  852.     gap> numbers = primes;
  853.     true
  854.     gap> numbers[3]:= 4;
  855.     4
  856.     gap> numbers = primes;
  857.     false |
  858.  
  859. Now 'numbers' is no longer equal to 'primes' and 'primes' still is a list
  860. of primes.  Check this by printing the values of 'numbers' and 'primes'.
  861.  
  862. The  only objects  that can be  changed  this way  are records and lists,
  863. because only {\GAP} objects of  these  types have subobjects.  To clarify
  864. this statement consider the following example.
  865.  
  866. |    gap> i:= 1;; j:= i;; i:= i+1;; |
  867.  
  868. By adding 1  to 'i'  the value of 'i' has  changed.  What happens to 'j'?
  869. After the  second statement  'j' points to the same object as 'i', namely
  870. to the  integer 1.   The addition  does *not* change the  object '1'  but
  871. creates a new object according to  the instruction 'i+1'.  It is actually
  872. the assignment that changes the value of 'i'.  Therefore 'j' still points
  873. to  the  object  '1'.   Integers  (like strings  and  booleans)  have  no
  874. subobjects.  Objects  of  these types cannot  be changed but  can only be
  875. replaced by other  objects.  And a replacement does not change the values
  876. of other variables.  In the above example an assignment of a new value to
  877. the variable 'numbers' would also not change the value of 'primes'.
  878.  
  879. Finally try the following examples and explain the results.
  880.  
  881. |    gap> l:= [];
  882.     [  ]
  883.     gap> l:= [l];
  884.     [ [  ] ]
  885.     gap> l[1]:= l;
  886.     [ ~ ] |
  887.  
  888. Now return to the  preceding section  "About Lists" and  find out whether
  889. the functions 'Add' and 'Append' change their arguments.
  890.  
  891. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  892. In this section you  have  seen the  difference between  equal lists  and
  893. identical lists.  Lists are  objects  that have  subobjects and therefore
  894. can  be  changed.  Changing an  object  will  change  the values  of  all
  895. variables that point to  that object.  Be careful, since  one object  can
  896. have several names.  The  function 'Copy' creates a copy of  a list which
  897. is then a new object.
  898.  
  899. You  will find  more  about  lists  in chapter  "Lists",  and more  about
  900. identical lists in "Identical Lists".
  901.  
  902. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  903. \Section{About Sets}
  904.  
  905. {\GAP}  knows  several  special kinds  of lists.   A set in  {\GAP}  is a
  906. special kind  of  list.  A set contains no  holes  and  its  elements are
  907. sorted according to  the {\GAP} ordering  of all its objects.  Moreover a
  908. set contains no object twice.
  909.  
  910. The function  'IsSet'  tests whether an  object  is a set.  It returns  a
  911. boolean value.  For any list there exists  a corresponding set.  This set
  912. is constructed by the function 'Set' which takes the list as its argument
  913. and  returns  a  set  obtained  from  this  list  by ignoring  holes  and
  914. duplicates and by sorting the elements.
  915.  
  916. The  elements  of  the  sets used  in  the  examples of this  section are
  917. strings.
  918.  
  919. |    gap> fruits:= ["apple", "strawberry", "cherry", "plum"];
  920.     [ "apple", "strawberry", "cherry", "plum" ]
  921.     gap> IsSet(fruits);
  922.     false
  923.     gap> fruits:= Set(fruits);
  924.     [ "apple", "cherry", "plum", "strawberry" ] |
  925.  
  926. Note that  the  original list 'fruits'  is not  changed   by the function
  927. 'Set'.   We have to  make  a new assignment to   the variable 'fruits' in
  928. order to make it a set.
  929.  
  930. The 'in' operator is  used  to test whether an  object is an element of a
  931. set.  It returns a boolean value 'true' or 'false'.
  932.  
  933. |    gap> "apple" in fruits;
  934.     true
  935.     gap> "banana" in fruits;
  936.     false |
  937.  
  938. The  'in' operator may  as  well  be  applied  to ordinary lists.  It  is
  939. however  much faster to perform a membership test for sets since sets are
  940. always sorted and a binary search can be used instead of a linear search.
  941.  
  942. New elements may be added to  a set by the  function 'AddSet' which takes
  943. the set 'fruits'   as its first argument  and  an element  as its  second
  944. argument and adds  the element to  the set  if it wasn\'t  already there.
  945. Note that the object 'fruits' is changed.
  946.  
  947. |    gap> AddSet(fruits, "banana");
  948.     gap> fruits;        #  The banana is inserted in the right place.
  949.     [ "apple", "banana", "cherry", "plum", "strawberry" ]
  950.     gap> AddSet(fruits, "apple");
  951.     gap> fruits;        #  'fruits' has not changed.
  952.     [ "apple", "banana", "cherry", "plum", "strawberry" ] |
  953.  
  954. Sets can be intersected by the function 'Intersection'  and united by the
  955. function 'Union' which both take  two sets as their arguments  and return
  956. the intersection (union) of the two sets as a new object.
  957.  
  958. |    gap> breakfast:= ["tea", "apple", "egg"];
  959.     [ "tea", "apple", "egg" ]
  960.     gap> Intersection(breakfast, fruits);
  961.     [ "apple" ] |
  962.  
  963. It is however not  necessary for the objects collected in a set to be  of
  964. the same type.  You  may  as well  have additional  integers  and boolean
  965. values for 'breakfast'.
  966.  
  967. The arguments of the functions 'Intersection' and 'Union' may  as well be
  968. ordinary lists, while their  result is always  a set.  Note  that in  the
  969. preceding example at least one argument of 'Intersection' was not a set.
  970.  
  971. The  functions  'IntersectSet' and  'UniteSet' also form the intersection
  972. resp.~union of  two sets.  They will however  not return  the result  but
  973. change their first argument to be the result.  Try them carefully.
  974.  
  975. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  976. In this  section you have  seen  that  sets  are a  special kind of list.
  977. There are functions to expand sets, intersect or unite sets, and there is
  978. the membership test with the 'in' operator.
  979.  
  980. A more detailed  description of strings is contained in chapter  "Strings
  981. and Characters".  Sets are described in more detail in chapter "Sets".
  982.  
  983. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  984. \Section{About Vectors and Matrices}
  985.  
  986. A *vector* is a list  of  elements  from a common field.  A *matrix* is a
  987. list of vectors of  equal length.  Vectors and matrices are special kinds
  988. of lists without holes.
  989.  
  990. |    gap> v:= [3, 6, 2, 5/2];
  991.     [ 3, 6, 2, 5/2 ]
  992.     gap> IsVector(v);
  993.     true |
  994.  
  995. Vectors may be multiplied by scalars from their field.  Multiplication of
  996. vectors of equal length results in their scalar product.
  997.  
  998. |    gap> 2 * v;
  999.     [ 6, 12, 4, 5 ]
  1000.     gap> v * 1/3;
  1001.     [ 1, 2, 2/3, 5/6 ]
  1002.     gap> v * v;
  1003.     221/4  # the scalar product of 'v' with itself |
  1004.  
  1005. Note  that  the expression 'v  \*\ 1/3'  is  actually evaluated  by first
  1006. multiplying 'v' by 1 (which yields again 'v') and by then dividing by  3.
  1007. This is  also an allowed  scalar  operation.   The expression 'v/3' would
  1008. result in the same value.
  1009.  
  1010. A matrix is a list of vectors of equal length.
  1011.  
  1012. |    gap> m:= [[1, -1, 1],
  1013.     >         [2, 0, -1],
  1014.     >         [1, 1, 1]];
  1015.     [ [ 1, -1, 1 ], [ 2, 0, -1 ], [ 1, 1, 1 ] ]
  1016.     gap> m[2][1];
  1017.     2 |
  1018.  
  1019. Syntactically a matrix is a list of lists.  So the number 2 in the second
  1020. row and  the first  column of the matrix 'm' is referred to as  the first
  1021. element of the second element of the list 'm' via 'm[2][1]'.
  1022.  
  1023. A matrix may be multiplied by  scalars, vectors  and other matrices.  The
  1024. vectors and  matrices involved in such a multiplication must however have
  1025. suitable dimensions.
  1026.  
  1027. |    gap> m:= [[1, 2, 3, 4],
  1028.     >         [5, 6, 7, 8],
  1029.     >         [9,10,11,12]];
  1030.     [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ] ]
  1031.     gap> PrintArray(m);
  1032.     [ [   1,   2,   3,   4 ],
  1033.       [   5,   6,   7,   8 ],
  1034.       [   9,  10,  11,  12 ] ]
  1035.     gap> [1, 0, 0, 0] * m;
  1036.     Error, Vector *: vectors must have the same length
  1037.     gap> [1, 0, 0] * m;
  1038.     [ 1, 2, 3, 4 ]
  1039.     gap> m * [1, 0, 0];
  1040.     Error, Vector *: vectors must have the same length
  1041.     gap> m * [1, 0, 0, 0];
  1042.     [ 1, 5, 9 ]
  1043.     gap> m * [0, 1, 0, 0];
  1044.     [ 2, 6, 10 ] |
  1045.  
  1046. Note that  multiplication  of a  vector  with a  matrix  will result in a
  1047. linear combination of  the rows of the matrix, while multiplication  of a
  1048. matrix with a  vector results in a linear  combination of  the columns of
  1049. the  matrix.  In the  latter  case  the vector is considered  as a column
  1050. vector.
  1051.  
  1052. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1053. In this section you have met vectors and matrices as  special lists.  You
  1054. have seen  how  to refer  to elements of  a  matrix and  how  to multiply
  1055. scalars, vectors, and matrices.
  1056.  
  1057. Fields are described in chapter "Fields".  The known fields in {\GAP} are
  1058. described in chapters "Rationals", "Cyclotomics", "Gaussians", "Subfields
  1059. of Cyclotomic  Fields" and "Finite  Fields".  Vectors  and  matrices  are
  1060. described in more detail  in  chapters "Vectors"  and "Matrices".  Vector
  1061. spaces  are described  in  chapter  "Vector  Spaces" and  further  matrix
  1062. related structures are described in  chapters "Matrix Rings"  and "Matrix
  1063. Groups".
  1064.  
  1065. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1066. \Section{About Records}
  1067.  
  1068. A record provides another way to  build new data structures.  Like a list
  1069. a record is a collection of other  objects.  In a record the elements are
  1070. not indexed by numbers but by  names (i.e., identifiers).   An entry in a
  1071. record is called a *record component* (or sometimes also record field).
  1072.  
  1073. |    gap> date:= rec(year:= 1992,
  1074.     >               month:= "Jan",
  1075.     >               day:= 13);
  1076.     rec(
  1077.       year := 1992,
  1078.       month := "Jan",
  1079.       day := 13 ) |
  1080.  
  1081. Initially a record is defined as a comma separated list of assignments to
  1082. its  record  components.   Then  the  value  of  a  record  component  is
  1083. accessible by the record name  and the record component name separated by
  1084. one dot as the record component selector.
  1085.  
  1086. |    gap> date.year;
  1087.     1992
  1088.     gap> date.time:= rec(hour:= 19, minute:= 23, second:= 12);
  1089.     rec(
  1090.       hour := 19,
  1091.       minute := 23,
  1092.       second := 12 )
  1093.     gap> date;
  1094.     rec(
  1095.       year := 1992,
  1096.       month := "Jan",
  1097.       day := 13,
  1098.       time := rec(
  1099.           hour := 19,
  1100.           minute := 23,
  1101.           second := 12 ) ) |
  1102.  
  1103. Assignments to  new record components are possible in the same way.   The
  1104. record is automatically resized to hold the new component.
  1105.  
  1106. Most of the complex structures that are handled by {\GAP} are represented
  1107. as records, for instance groups and character tables.
  1108.  
  1109. Records  are objects  that may  be changed.   An  assignment to a  record
  1110. component changes the original  object.  There are  many functions in the
  1111. library that will do  such assignments  to a  record component  of one of
  1112. their arguments.  The function 'Size' for  example, will compute the size
  1113. of its  argument which  may be a group for instance, and  then store  the
  1114. value in the record component 'size'.   The  next call of 'Size' for this
  1115. object will use this stored value rather than compute it again.
  1116.  
  1117. Lists and  records are  the *only*  types of {\GAP}  objects that  can be
  1118. changed.
  1119.  
  1120. Sometimes it is interesting  to know which components of a certain record
  1121. are bound.  This  information is available from the  function 'RecFields'
  1122. (yes, this  function should be called 'RecComponentNames'), which takes a
  1123. record as its argument and returns a list of all bound components of this
  1124. record as a list of strings.
  1125.  
  1126. |    gap> RecFields(date);
  1127.     [ "year", "month", "day", "time" ] |
  1128.  
  1129. Finally try the following examples and explain the results.
  1130.  
  1131. |    gap> r:= rec();
  1132.     rec(
  1133.        )
  1134.     gap> r:= rec(r:= r);
  1135.     rec(
  1136.       r := rec(
  1137.            ) )
  1138.     gap> r.r:= r;
  1139.     rec(
  1140.       r := ~ ) |
  1141.  
  1142. Now return to section  "About Identical Lists"  and  find  out what  that
  1143. section means for records.
  1144.  
  1145. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1146. In  this section you have   seen how to  define and  how to use  records.
  1147. Record objects are  changed by assignments to  record fields.  Lists  and
  1148. records are the only types of objects that can be changed.
  1149.  
  1150. Records and functions  for records are  described in  detail  in  chapter
  1151. "Records".  More about identical records is found in "Identical Records".
  1152.  
  1153. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1154. \Section{About Ranges}
  1155.  
  1156. A *range* is  a finite ascending sequence of  consecutive integers.  This
  1157. is another special kind of list.  A range is described by its minimum and
  1158. its maximum separated by two dots and enclosed in brackets.
  1159.  
  1160. |    gap> [1..999999];    #  a range of almost a million numbers
  1161.     [ 1 .. 999999 ] |
  1162.  
  1163. This compact printed representation of a fairly long list corresponds  to
  1164. a compact internal representation.  The  function 'IsRange' tests whether
  1165. an object is a range.  If this is true for a list but the list is not yet
  1166. represented in the compact form of a range this will be done then.
  1167.  
  1168. |    gap> a:= [-2,-1,0,1,2,3,4,5];
  1169.     [ -2, -1, 0, 1, 2, 3, 4, 5 ]
  1170.     gap> IsRange(a);
  1171.     true
  1172.     gap> a;
  1173.     [ -2 .. 5 ]
  1174.     gap> a[5];
  1175.     2
  1176.     gap> Length(a);
  1177.     8 |
  1178.  
  1179. Note that this change  of representation  does *not* change  the value of
  1180. the list 'a'.   The list 'a' still behaves in any context in the same way
  1181. as it would have in the long representation.
  1182.  
  1183. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1184. In  this  section you  have seen  that  ascending  lists  of  consecutive
  1185. integers can be represented in a compact way as ranges.
  1186.  
  1187. Chapter  "Ranges"  contains   a   detailed   description  of  ranges.   A
  1188. fundamental application of ranges is introduced in the next section.
  1189.  
  1190. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1191. \Section{About Loops}
  1192.  
  1193. Given a list 'pp' of permutations we can form their product by means of a
  1194. 'for' loop instead of writing down the product explicitly.
  1195.  
  1196. |    gap> pp:= [ (1,3,2,6,8)(4,5,9), (1,6)(2,7,8)(4,9), (1,5,7)(2,3,8,6),
  1197.     >           (1,8,9)(2,3,5,6,4), (1,9,8,6,3,4,7,2) ];;
  1198.     gap> prod:= ();
  1199.     ()
  1200.     gap> for p in pp do
  1201.     >       prod:= prod * p;
  1202.     >    od;
  1203.     gap> prod;
  1204.     (1,8,4,2,3,6,5) |
  1205.  
  1206. First  a  new variable 'prod' is initialized to the  identity permutation
  1207. '()'.  Then  the  loop variable 'p'  takes as its  value one  permutation
  1208. after the other from  the  list  'pp' and is multiplied with  the present
  1209. value of  'prod'  resulting in a new  value  which  is then  assigned  to
  1210. 'prod'.
  1211.  
  1212. The 'for' loop has the following syntax.
  1213.  
  1214. 'for <var> in <list> do <statements> od;'
  1215.  
  1216. The  effect of the 'for'  loop  is to execute the <statements> for  every
  1217. element  of  the <list>.   A 'for'  loop  is  a  statement  and therefore
  1218. terminated by a semicolon.  The list of <statements>  is enclosed by  the
  1219. keywords 'do' and 'od'  (reverse  'do').  A 'for'  loop returns no value.
  1220. Therefore we had  to  ask  explicitly for  the  value  of  'prod' in  the
  1221. preceding example.
  1222.  
  1223. The 'for'  loop  can loop over any kind of  list, even a list with holes.
  1224. In many  programming languages (and  in  former versions  of {\GAP}, too)
  1225. the 'for' loop has the form
  1226.  
  1227. 'for <var> from <first> to <last> do <statements> od;'
  1228.  
  1229. But this is merely a special  case of  the general  'for' loop as defined
  1230. above where the <list> in the loop body is a range.
  1231.  
  1232. 'for <var> in [<first>..<last>] do <statements> od;'
  1233.  
  1234. You can for instance loop over a range to  compute the factorial $15!$ of
  1235. the number 15 in the following way.
  1236.  
  1237. |    gap> ff:= 1;
  1238.     1
  1239.     gap> for i in [1..15] do
  1240.     >       ff:= ff * i;
  1241.     >    od;
  1242.     gap> ff;
  1243.     1307674368000 |
  1244.  
  1245. The following example introduces the 'while' loop which has the following
  1246. syntax.
  1247.  
  1248. 'while <condition> do <statements> od;'
  1249.  
  1250. The 'while' loop loops over the <statements>  as  long as the <condition>
  1251. evaluates to 'true'.  Like the 'for' loop the  'while' loop is terminated
  1252. by the keyword 'od' followed by a semicolon.
  1253.  
  1254. We can use  our list 'primes' to perform a very simple factorization.  We
  1255. begin by  initializing a list 'factors' to the empty list.   In this list
  1256. we want to collect the prime factors of the number 1333.  Remember that a
  1257. list has to exist  before any values  can be assigned to positions of the
  1258. list.  Then we  will loop over the list 'primes' and  test for each prime
  1259. whether it divides the  number.  If it does we will  divide the number by
  1260. that prime, add it to the list 'factors' and continue.
  1261.  
  1262. |    gap> n:= 1333;
  1263.     1333
  1264.     gap> factors:= [];
  1265.     [  ]
  1266.     gap> for p in primes do
  1267.     >       while n mod p = 0 do
  1268.     >          n:= n/p;
  1269.     >          Add(factors, p);
  1270.     >       od;
  1271.     >    od;
  1272.     gap> factors;
  1273.     [ 31, 43 ]
  1274.     gap> n;
  1275.     1 |
  1276.  
  1277. As 'n' now has the value 1 all prime factors  of 1333 have been found and
  1278. 'factors' contains a complete factorization of  1333.  This can of course
  1279. be verified by multiplying 31 and 43.
  1280.  
  1281. This loop  may  be applied  to arbitrary  numbers in order  to find prime
  1282. factors.  But  as 'primes' is not a complete list of all primes this loop
  1283. may fail  to find all prime factors of  a number greater than 2000,  say.
  1284. You  can try to improve it in such a way that new primes are added to the
  1285. list 'primes' if needed.
  1286.  
  1287. You have already seen that list objects may be  changed.   This holds  of
  1288. course also for the  list in a loop body.  In most  cases  you have to be
  1289. careful not  to change this list, but there are situations  where this is
  1290. quite useful.  The following example  shows a quick way  to determine the
  1291. primes smaller than 1000 by a sieve method.  Here we will make use of the
  1292. function 'Unbind' to delete entries from a list.
  1293.  
  1294. |    gap> primes:= [];
  1295.     [  ]
  1296.     gap> numbers:= [2..1000];
  1297.     [ 2 .. 1000 ]
  1298.     gap> for p in numbers do
  1299.     >       Add(primes, p);
  1300.     >       for n in numbers do
  1301.     >          if n mod p = 0 then
  1302.     >             Unbind(numbers[n-1]);
  1303.     >          fi;
  1304.     >       od;
  1305.     >    od; |
  1306.  
  1307. The inner loop  removes all entries from 'numbers' that are  divisible by
  1308. the last detected prime 'p'.  This is done by the function 'Unbind' which
  1309. deletes the binding of the list position  'numbers[n-1]' to the value 'n'
  1310. so that afterwards 'numbers[n-1]' no longer has  an  assigned value.  The
  1311. next  element encountered in 'numbers'  by the outer  loop necessarily is
  1312. the next prime.
  1313.  
  1314. In a similar way it is possible to enlarge the list which is looped over.
  1315. This yields a nice and short orbit  algorithm for the  action of a group,
  1316. for example.
  1317.  
  1318. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1319. In this section  you have learned how  to loop over a  list by the  'for'
  1320. loop and how to loop with respect to a logical condition with the 'while'
  1321. loop.  You have seen that even the list in the loop body can be changed.
  1322.  
  1323. The  'for' loop is described in "For".  The 'while'  loop is described in
  1324. "While".
  1325.  
  1326. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1327. \Section{About Further List Operations}
  1328.  
  1329. There is however a more comfortable way to  compute the product of a list
  1330. of numbers or permutations.
  1331.  
  1332. |    gap> Product([1..15]);
  1333.     1307674368000
  1334.     gap> Product(pp);
  1335.     (1,8,4,2,3,6,5) |
  1336.  
  1337. The function  'Product'  takes a  list as  its argument and computes  the
  1338. product  of  the  elements  of the  list.   This  is possible whenever  a
  1339. multiplication of  the elements of the list is defined.  So  'Product' is
  1340. just an implementation of the loop in the example above as a function.
  1341.  
  1342. There are other often used loops available as functions.   Guess what the
  1343. function 'Sum' does.  The function 'List' may  take a list and a function
  1344. as its arguments.  It will then apply the function to each element of the
  1345. list  and return  the corresponding list of results.   A list of cubes is
  1346. produced as follows with the function 'cubed' from "About Functions".
  1347.  
  1348. |    gap> List([2..10], cubed);
  1349.     [ 8, 27, 64, 125, 216, 343, 512, 729, 1000 ] |
  1350.  
  1351. To add all these cubes  we might apply the  function  'Sum' to  the  last
  1352. list.  But we may  as well  give the  function  'cubed' to  'Sum'  as  an
  1353. additional argument.
  1354.  
  1355. |    gap> Sum(last) = Sum([2..10], cubed);
  1356.     true |
  1357.  
  1358. The primes  less  than 30  can be retrieved out of the list 'primes' from
  1359. section "About Lists" by  the function 'Filtered'.   This  function takes
  1360. the list 'primes' and a  property  as its arguments  and will return  the
  1361. list  of those  elements  of 'primes'  which have  this property.  Such a
  1362. property will be  represented by a function that returns a boolean value.
  1363. In this example  the property of being less than 30  can be reresented by
  1364. the  function 'x-> x \< 30'  since 'x \< 30' will evaluate  to 'true' for
  1365. values 'x' less than 30 and to 'false' otherwise.
  1366.  
  1367. |    gap> Filtered(primes, x-> x < 30);
  1368.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ] |
  1369.  
  1370. Another useful thing  is the function 'Sublist'.  It takes a list as  its
  1371. first and argument another list of  positions as its  second argument and
  1372. will return the list of elements from the first list corresponding to the
  1373. positions given in the second list.
  1374.  
  1375. |    gap> Sublist(primes, [1 .. 10]);
  1376.     [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ] |
  1377.  
  1378. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1379. In this section you have seen  some functions which implement  often used
  1380. 'for' loops.  There are functions  like 'Product'  to form the product of
  1381. the elements of a list.  The function 'List' can apply  a function to all
  1382. elements of  a list  and  the functions  'Filtered'  and 'Sublist' create
  1383. sublists of a given list.
  1384.  
  1385. You will find more predefined 'for' loops in chapter "Lists".
  1386.  
  1387. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1388. \Section{About Writing Functions}
  1389.  
  1390. You  have  already seen how  to use the functions of the  {\GAP} library,
  1391. i.e., how to  apply them to arguments.  This section will show you how to
  1392. write your own functions.
  1393.  
  1394. Writing a function that prints 'hello, world.'  on the screen is a simple
  1395. exercise in {\GAP}.
  1396.  
  1397. |    gap> sayhello:= function()
  1398.     > Print("hello, world.\n");
  1399.     > end;
  1400.     function (  ) ... end |
  1401.  
  1402. This function when called will only execute the 'Print' statement in  the
  1403. second  line.  This will print the  string 'hello, world.' on the  screen
  1404. followed by a  newline character |\n| that  causes  the {\GAP}  prompt to
  1405. appear  on the next line  rather  than  immediately following the printed
  1406. characters.
  1407.  
  1408. The function definition has the following syntax.
  1409.  
  1410. 'function(<arguments>) <statements> end'
  1411.  
  1412. A function definition starts with the keyword 'function' followed  by the
  1413. formal  parameter list <arguments> enclosed  in  parenthesis.  The formal
  1414. parameter list  may be empty as in  the example.  Several  parameters are
  1415. separated by commas.  Note that there  must be  *no* semicolon behind the
  1416. closing   parenthesis.   The  function  definition  is  terminated by the
  1417. keyword 'end'.
  1418.  
  1419. A {\GAP}  function is an expression  like integers,  sums and  lists.  It
  1420. therefore  may  be assigned to  a variable.  The terminating semicolon in
  1421. the example does not belong to the function definition but terminates the
  1422. assignment of the function to the name 'sayhello'.  Unlike in the case of
  1423. integers, sums, and lists  the value of the function 'sayhello' is echoed
  1424. in  the abbreviated fashion 'function ( ) ...  end'.  This shows the most
  1425. interesting  part of  a function\:\ its formal parameter list  (which  is
  1426. empty in this example).  The complete value of  'sayhello' is returned if
  1427. you use the function 'Print'.
  1428.  
  1429. |    gap> Print(sayhello, "\n");
  1430.     function (  )
  1431.         Print( "hello, world.\n" );
  1432.     end |
  1433.  
  1434. Note  the  additional newline character |"\n"| in  the 'Print' statement.
  1435. It is printed after the object 'sayhello' to start a new line.
  1436.  
  1437. The newly defined function 'sayhello' is executed by calling 'sayhello()'
  1438. with an empty argument list.
  1439.  
  1440. |    gap> sayhello();
  1441.     hello, world. |
  1442.  
  1443. This is however not a typical example as no  value is returned but only a
  1444. string is printed.
  1445.  
  1446. A  more useful function is given in the following  example.   We define a
  1447. function 'sign' which shall determine the sign of a number.
  1448.  
  1449. |    gap> sign:= function(n)
  1450.     >        if n < 0 then
  1451.     >           return -1;
  1452.     >        elif n = 0 then
  1453.     >           return 0;
  1454.     >        else
  1455.     >           return 1;
  1456.     >        fi;
  1457.     >    end;
  1458.     function ( n ) ... end
  1459.     gap> sign(0); sign(-99); sign(11);
  1460.     0
  1461.     -1
  1462.     1
  1463.     gap> sign("abc");
  1464.     1        # strings are defined to be greater than 0 |
  1465.  
  1466. This example also introduces the 'if' statement which is  used to execute
  1467. statements  depending  on  a  condition.   The  'if'  statement  has  the
  1468. following syntax.
  1469.  
  1470. 'if <condition> then <statements> elif <condition> then <statements> else
  1471. <statements> fi;'
  1472.  
  1473. There may be several 'elif' parts.  The 'elif' part as well as the 'else'
  1474. part  of the  'if' statement may be omitted.   An  'if'  statement  is no
  1475. expression and  can therefore not be assigned to a variable.  Furthermore
  1476. an 'if' statement does not return a value.
  1477.  
  1478. Fibonacci numbers are defined recursively by $f(1) = f(2) =  1$ and $f(n)
  1479. =  f(n-1) + f(n-2)$.  Since  functions in {\GAP} may call  themselves,  a
  1480. function  'fib'  that  computes  Fibonacci  numbers  can  be  implemented
  1481. basically by typing the above equations.
  1482.  
  1483. |    gap> fib:= function(n)
  1484.     >       if n in [1, 2] then
  1485.     >          return 1;
  1486.     >       else
  1487.     >          return fib(n-1) + fib(n-2);
  1488.     >       fi;
  1489.     >    end;
  1490.     function ( n ) ... end
  1491.     gap> fib(15);
  1492.     610 |
  1493.  
  1494. There should be additional tests for the  argument  'n' being  a positive
  1495. integer.   This  function 'fib' might  lead to strange  results if called
  1496. with other arguments.  Try to insert the tests in this example.
  1497.  
  1498. A  function  'gcd'  that computes the   greatest  common  divisor of  two
  1499. integers  by Euclid\'s algorithm will need  a variable in addition to the
  1500. formal arguments.
  1501.  
  1502. |    gap> gcd:= function(a, b)
  1503.     >       local c;
  1504.     >       while b <> 0 do
  1505.     >          c:= b;
  1506.     >          b:= a mod b;
  1507.     >          a:= c;
  1508.     >       od;
  1509.     >       return c;
  1510.     >    end;
  1511.     function ( a, b ) ... end
  1512.     gap> gcd(30, 63);
  1513.     3 |
  1514.  
  1515. The additional  variable 'c'  is declared as  a  *local*  variable in the
  1516. 'local' statement  of the function definition.  The 'local' statement, if
  1517. present, must  be the first  statement of  a function  definition.   When
  1518. several local variables are  declared in only one  'local' statement they
  1519. are separated by commas.
  1520.  
  1521. The  variable 'c'  is  indeed  a local  variable,  that  is local to  the
  1522. function 'gcd'.  If you try  to use the value of 'c' in the main loop you
  1523. will see that 'c'  has no assigned value unless you have already assigned
  1524. a value to the variable 'c'  in  the  main loop.  In this case  the local
  1525. nature of 'c' in the function 'gcd' prevents  the value of the 'c' in the
  1526. main loop from being overwritten.
  1527.  
  1528. We say  that in a given scope an identifier identifies a unique variable.
  1529. A *scope* is a lexical part of a program text.  There is the global scope
  1530. that encloses  the  entire program text, and there are local  scopes that
  1531. range from the 'function'  keyword, denoting the beginning of  a function
  1532. definition, to the corresponding 'end' keyword.  A local scope introduces
  1533. new  variables, whose identifiers are  given in the formal argument  list
  1534. and the local declaration of the function.  The usage of an identifier in
  1535. a program text refers to  the  variable in  the  innermost scope that has
  1536. this identifier as its name.
  1537.  
  1538. We will now write  a function to  determine the number of partitions of a
  1539. positive integer.  A partition of a positive integer is a descending list
  1540. of  numbers whose sum is the given integer.  For example $[4,2,1,1]$ is a
  1541. partition of 8.  The complete set of all partitions of an integer $n$ may
  1542. be divided into subsets with respect to the largest  element.  The number
  1543. of  partitions of  $n$  therefore  equals  the  sum  of  the  numbers  of
  1544. partitions  of $n-i$ with  elements less than  $i$ for all possible  $i$.
  1545. More generally the  number of partitions of  $n$ with elements  less than
  1546. $m$ is the sum  of  the numbers of partitions of $n-i$ with elements less
  1547. than  $i$ for $i$ less than  $m$ and  $n$.  This description  yields  the
  1548. following function.
  1549.  
  1550. |    gap> nrparts:= function(n)
  1551.     >    local np;
  1552.     >    np:= function(n, m)
  1553.     >       local i, res;
  1554.     >       if n = 0 then
  1555.     >          return 1;
  1556.     >       fi;
  1557.     >       res:= 0;
  1558.     >       for i in [1..Minimum(n,m)] do
  1559.     >          res:= res + np(n-i, i);
  1560.     >       od;
  1561.     >       return res;
  1562.     >    end;
  1563.     >    return np(n,n);
  1564.     > end;
  1565.     function ( n ) ... end |
  1566.  
  1567. We wanted to  write a function that  takes one argument.   We solved  the
  1568. problem of determining the number  of partitions in  terms of a recursive
  1569. procedure with two arguments.  So we had to write  in fact two functions.
  1570. The  function  'nrparts' that  can  be  used  to  compute the  number  of
  1571. partitions takes indeed only one  argument.  The  function 'np' takes two
  1572. arguments and solves the problem in the indicated way.  The  only task of
  1573. the function 'nrparts' is to call 'np' with two equal arguments.
  1574.  
  1575. We made 'np'  local to 'nrparts'.   This  illustrates the  possibility of
  1576. having local functions in {\GAP}.   It is however not necessary to put it
  1577. there.  'np' could as  well be defined on the main level.   But  then the
  1578. identifier 'np'  would be bound and could not be used for other purposes.
  1579. And  if  it were used  the essential  function  'np' would no  longer  be
  1580. available for 'nrparts'.
  1581.  
  1582. Now have  a look at the function  'np'.  It has two local variables 'res'
  1583. and 'i'.  The variable 'res' is used to collect the sum and 'i' is a loop
  1584. variable.  In the loop  the  function 'np' calls itself again with  other
  1585. arguments.  It would be  very disturbing if this call of  'np' would  use
  1586. the same 'i' and 'res'  as  the calling 'np'.  Since the new call of 'np'
  1587. creates a new scope with new variables this is fortunately not the case.
  1588.  
  1589. The formal parameters $n$ and $m$ are treated like local variables.
  1590.  
  1591. It  is however  cheaper  (in  terms of  computing time)  to avoid such  a
  1592. recursive solution if this is possible (and it is possible in this case),
  1593. because a function call is not very cheap.
  1594.  
  1595. %%  Summary  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1596. In this section you  have  seen  how  to  write  functions in  the {\GAP}
  1597. language.  You have  also seen how to use the 'if' statement.   Functions
  1598. may  have  local  variables which  are  declared in  an  initial  'local'
  1599. statement in the function definition.  Functions may call themselves.
  1600.  
  1601. The function syntax is described  in "Functions".   The 'if' statement is
  1602. described in more detail in "If".  More about  Fibonacci numbers is found
  1603. in "Fibonacci" and more about partitions in "Partitions".
  1604.  
  1605. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1606. \Section{About Groups}
  1607.  
  1608. In this  section  we will show some  easy computations with  groups.  The
  1609. example uses permutation groups,  but this  is visible  for the user only
  1610. because the output  contains  permutations.  The functions, like 'Group',
  1611. 'Size'   or  'SylowSubgroup'  (for  detailed  information,  see  chapters
  1612. "Domains", "Groups"), are the same for all kinds of groups, although  the
  1613. algorithms which  compute the  information of course will be different in
  1614. most cases.
  1615.  
  1616. It is not even necessary  to know more  about permutations  than  the two
  1617. facts that  they  are  elements of  permutation groups and that  they are
  1618. written  in  disjoint cycle  notation (see chapter  "Permutations").   So
  1619. let\'s construct a permutation group\:
  1620.  
  1621. |    gap> s8:= Group( (1,2), (1,2,3,4,5,6,7,8) );
  1622.     Group( (1,2), (1,2,3,4,5,6,7,8) )|
  1623.  
  1624. We   formed  the  group  generated  by   the  permutations  '(1,2)'   and
  1625. '(1,2,3,4,5,6,7,8)',  which is well known as the symmetric group on eight
  1626. points,  and  assigned  it  to the  identifier 's8'.   's8' contains  the
  1627. alternating group on eight points which can be described in several ways,
  1628. e.g., as group of  all even permutations in  's8',  or  as its commutator
  1629. subgroup.
  1630.  
  1631. |    gap> a8:= CommutatorSubgroup( s8, s8 );
  1632.     Subgroup( Group( (1,2), (1,2,3,4,5,6,7,8) ), 
  1633.     [ (1,3,2), (2,4,3), (3,5,4), (4,6,5), (5,7,6), (6,8,7) ] )|
  1634.  
  1635. The  alternating group 'a8'  is printed as  instruction  to  compute that
  1636. subgroup   of  the  group  's8'  that  is  generated  by  the  given  six
  1637. permutations.   This representation  is  much shorter than  the  internal
  1638. structure,  and  it  is  completely  self--explanatory;  one  could,  for
  1639. example, print such a group to a file and read it into {\GAP} later.  But
  1640. if one object occurs several times it is useful to refer  to this object;
  1641. this can be settled by assigning a name to the group.
  1642.  
  1643. |    gap> s8.name:= "s8";
  1644.     "s8"
  1645.     gap> a8;
  1646.     Subgroup( s8, [ (1,3,2), (2,4,3), (3,5,4), (4,6,5), (5,7,6), (6,8,7) 
  1647.      ] )
  1648.     gap> a8.name:= "a8";
  1649.     "a8"
  1650.     gap> a8;
  1651.     a8|
  1652.  
  1653. Whenever a group has a component 'name',  {\GAP} prints this name instead
  1654. of the group itself.  Note that there is no link between the name and the
  1655. identifier, but  it is  of  course  useful to choose name and  identifier
  1656. compatible.
  1657.  
  1658. |    gap> copya8:= Copy( a8 );
  1659.     a8|
  1660.  
  1661. We examine  the group 'a8'.  Like  all  complex {\GAP} structures,  it is
  1662. represented as a record (see "Group Records").
  1663.  
  1664. |    gap> RecFields( a8 );
  1665.     [ "isDomain", "isGroup", "parent", "identity", "generators", 
  1666.       "operations", "isPermGroup", "1", "2", "3", "4", "5", "orbit",
  1667.       "transversal", "stabilizer", "name" ]|
  1668.  
  1669. Many functions store information  about the  group  in this group record,
  1670. this avoids  duplicate computations.   But  we are  not interested in the
  1671. organisation of data but  in the group, e.g., some of its properties (see
  1672. chapter "Groups", especially "Properties and Property Tests")\:
  1673.  
  1674. |    gap> Size( a8 ); IsAbelian( a8 ); IsPerfect( a8 );
  1675.     20160
  1676.     false
  1677.     true|
  1678.  
  1679. Some interesting subgroups are the Sylow $p$ subgroups for prime divisors
  1680. $p$ of the  group order; a call  of  'SylowSubgroup' stores the  required
  1681. subgroup in the group record\:
  1682.  
  1683. |    gap> Set( Factors( Size( a8 ) ) );
  1684.     [ 2, 3, 5, 7 ]
  1685.     gap> for p in last do
  1686.     >      SylowSubgroup( a8, p );
  1687.     >    od;
  1688.     gap> a8.sylowSubgroups;
  1689.     [ , Subgroup( s8, [ (1,7)(5,6), (2,3)(5,6), (1,7)(4,8), (2,5)(3,6),
  1690.           (1,4)(2,5)(3,6)(7,8), (1,2)(3,7)(4,5)(6,8) ] ),
  1691.       Subgroup( s8, [ (3,6,4), (2,5,8)(3,4,6) ] ),,
  1692.       Subgroup( s8, [ (3,4,8,6,5) ] ),,
  1693.       Subgroup( s8, [ (2,6,3,8,4,7,5) ] ) ]|
  1694.  
  1695. The record component  'sylowSubgroups'  is a  list  which  stores at  the
  1696. $p$--th position, if bound, the Sylow $p$ subgroup; in  this example this
  1697. means that there are holes at  positions 1, 4 and 6.  Note that a call of
  1698. 'SylowSubgroup'  for the cyclic group of  order 65521  and for  the prime
  1699. 65521 would cause  {\GAP} to store the group  at  the end  of  a  list of
  1700. length  65521, so  there are special situations where  it is possible  to
  1701. bring {\GAP} and yourselves into troubles.
  1702.  
  1703. We now can investigate the Sylow 2 subgroup.
  1704.  
  1705. |    gap> syl2:= last[2];;
  1706.     gap> Size( syl2 );
  1707.     64
  1708.     gap> Normalizer( a8, syl2 );
  1709.     Subgroup( s8, [ (1,7)(5,6), (2,3)(5,6), (1,7)(4,8), (2,5)(3,6),
  1710.       (1,4)(2,5)(3,6)(7,8), (1,2)(3,7)(4,5)(6,8), (4,8)(5,6) ] )
  1711.     gap> last = syl2;
  1712.     true
  1713.     gap> Centre( syl2 );
  1714.     Subgroup( s8, [ ( 1, 7)( 2, 3)( 4, 8)( 5, 6) ] )
  1715.     gap> cent:= Centralizer( a8, last );
  1716.     Subgroup( s8, [ ( 1, 7)( 2, 3)( 4, 8)( 5, 6), (4,5)(6,8), (4,6)(5,8),
  1717.       (2,3)(5,6), (2,4)(3,8), (1,2)(3,7) ] )
  1718.     gap> Size( cent );
  1719.     192
  1720.     gap> DerivedSeries( cent );
  1721.     [ Subgroup( s8, [ ( 1, 7)( 2, 3)( 4, 8)( 5, 6), (4,5)(6,8),
  1722.           (4,6)(5,8), (2,3)(5,6), (2,4)(3,8), (1,2)(3,7) ] ),
  1723.       Subgroup( s8, [ (4,8)(5,6), (2,4,5)(3,8,6), (1,7)(2,3),
  1724.           (1,2,4)(3,8,7) ] ),
  1725.       Subgroup( s8, [ (2,3)(4,8), (1,7)(4,8), (1,5)(2,4)(3,8)(6,7),
  1726.           (1,2)(3,7)(4,5)(6,8) ] ),
  1727.       Subgroup( s8, [ (1,7)(2,3)(4,8)(5,6) ] ), Subgroup( s8, [  ] ) ]
  1728.     gap> List( last, Size );
  1729.     [ 192, 96, 32, 2, 1 ]
  1730.     gap> low:= LowerCentralSeries( cent );
  1731.     [ Subgroup( s8, [ ( 1, 7)( 2, 3)( 4, 8)( 5, 6), (4,5)(6,8),
  1732.           (4,6)(5,8), (2,3)(5,6), (2,4)(3,8), (1,2)(3,7) ] ),
  1733.       Subgroup( s8, [ (4,8)(5,6), (2,4,5)(3,8,6), (1,7)(2,3),
  1734.           (1,2,4)(3,8,7) ] ) ]|
  1735.  
  1736. Another kind of subgroups is given by the point stabilizers.
  1737.  
  1738. |    gap> stab:= Stabilizer( a8, 1 );
  1739.     Subgroup( s8, [ (2,7,3), (2,4,3), (3,8,4), (4,6,8), (5,6,8) ] )
  1740.     gap> Size( stab );
  1741.     2520
  1742.     gap> Index( a8, stab );
  1743.     8|
  1744.  
  1745. We  can  fetch an arbitrary group element and  look at its centralizer in
  1746. 'a8',  and then get  other subgroups by  conjugation  and intersection of
  1747. already  known subgroups.  Note that  we form  the subgroups inside 'a8',
  1748. but {\GAP} regards these groups as subgroups  of 's8' because this is the
  1749. common  ``parent\'\'\ group of all these groups and of 'a8' (for the idea
  1750. of parent groups, see "More about Groups and Subgroups").
  1751.  
  1752. |    gap> Random( a8 );
  1753.     (1,4,3,8,2,5,7)
  1754.     gap> Random( a8 );
  1755.     (1,5,7,6,2,4)(3,8)
  1756.     gap> cent:= Centralizer( a8, (1,2)(3,4)(5,8)(6,7) );
  1757.     Subgroup( s8, [ (1,2)(3,4)(5,8)(6,7), (5,6)(7,8), (5,7)(6,8), 
  1758.       (3,4)(6,7), (3,5)(4,8), (1,3)(2,4) ] )
  1759.     gap> Size( cent );
  1760.     192
  1761.     gap> conj:= ConjugateSubgroup( cent, (2,3,4) );
  1762.     Subgroup( s8, [ (1,3)(2,4)(5,8)(6,7), (5,6)(7,8), (5,7)(6,8),
  1763.       (2,4)(6,7), (2,8)(4,5), (1,4)(2,3) ] )
  1764.     gap> inter:= Intersection( cent, conj );
  1765.     Subgroup( s8, [ (5,6)(7,8), (5,7)(6,8), (1,2)(3,4), (1,3)(2,4) ] )
  1766.     gap> Size( inter );
  1767.     16
  1768.     gap> IsElementaryAbelian( inter );
  1769.     true
  1770.     gap> norm:= Normalizer( a8, inter );
  1771.     Subgroup( s8, [ (5,6)(7,8), (5,7)(6,8), (1,2)(3,4), (1,3)(2,4), 
  1772.       (6,7,8), (3,4)(7,8), (2,3)(7,8), (1,5)(2,6)(3,7)(4,8) ] )
  1773.     gap> Size( norm );
  1774.     576|
  1775.  
  1776. Suppose we do  not only  look which funny  things may appear in our group
  1777. but  want   to   construct  a  subgroup,  e.g.,  a  group   of  structure
  1778. $2^3\:L_3(2)$ in 'a8'.   One idea is  to  look for an  appropriate  $2^3$
  1779. which is specified by the fact that all its involutions  are  fixed point
  1780. free, and then compute its normalizer in 'a8'\:
  1781.  
  1782. |    gap> elab:= Group( (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8),
  1783.     >                  (1,5)(2,6)(3,7)(4,8) );;
  1784.     gap> Size( elab );
  1785.     8
  1786.     gap> IsElementaryAbelian( elab );
  1787.     true
  1788.     gap> norm:= Normalizer( a8, AsSubgroup( s8, elab ) );
  1789.     Subgroup( s8, [ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), 
  1790.       (1,5)(2,6)(3,7)(4,8), (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), 
  1791.       (3,5)(4,6), (2,3)(6,7) ] )
  1792.     gap> Size( norm );
  1793.     1344|
  1794.  
  1795. Note that 'elab'  was defined as separate  group, thus  we  had  to  call
  1796. 'AsSubgroup'  to  achieve that  it  has  the  same parent  group as 'a8'.
  1797. Let\'s look at some usual misuses\:
  1798.  
  1799. |    gap> Normalizer( a8, elab );
  1800.     Error, <G> and <H> must have the same parent group in
  1801.     arg[1].operations.Parent( arg ) called from
  1802.     Parent( G, U ) called from
  1803.     Normalizer( a8, elab ) called from
  1804.     main loop
  1805.     brk> quit;|
  1806.  
  1807. Intuitively,  it is  clear that we wanted  to compute  the normalizer  of
  1808. 'elab'  in 'a8'.  But {\GAP} expects the subgroup to be explicitly  given
  1809. as subgroup; for that, we must apply 'AsSubgroup'.
  1810.  
  1811. |    gap> IsSubgroup( a8, AsSubgroup( a8, elab ) );
  1812.     Error, <G> must be a parent group in
  1813.     AsSubgroup( a8, elab ) called from
  1814.     main loop
  1815.     brk> quit;
  1816.     gap> IsSubgroup( a8, AsSubgroup( s8, elab ) );
  1817.     true|
  1818.  
  1819. What  we tried  next  was better but  not good  enough.   Since  all  our
  1820. computations up to now are  done inside 's8' which is the parent of 'a8',
  1821. it is  easy to understand that 'IsSubgroup' works for two  subgroups with
  1822. this parent.
  1823.  
  1824. By the way, you should not try the operator '\<'  instead of the function
  1825. 'IsSubgroup'.  Something like
  1826.  
  1827. |    gap> elab < a8;
  1828.     false|
  1829.  
  1830. or
  1831.  
  1832. |    gap> AsSubgroup( s8, elab ) < a8;
  1833.     false|
  1834.  
  1835. will not cause an error, but the result does not tell anything  about the
  1836. inclusion of one  group in another; '\<' looks at the  element  lists for
  1837. the two domains which means that it computes them if they are not already
  1838. stored  --which is not desirable to do for large groups-- and then simply
  1839. compares  the   lists  with  respect   to  lexicographical   order   (see
  1840. "Comparisons of Domains").
  1841.  
  1842. On  the  other  hand, the  equality operator  '='  in  fact does test the
  1843. equality of groups.  Thus
  1844.  
  1845. |    gap> elab = AsSubgroup( s8, elab );
  1846.     true|
  1847.  
  1848. means that the two  groups are equal in the sense that they have the same
  1849. elements.   Note  that  they  may  behave  differently  since  they  have
  1850. different parent groups.  In our example,  it  is  necessary to work with
  1851. subgroups of 's8'\:
  1852.  
  1853. |    gap> elab:= AsSubgroup( s8, elab );;
  1854.     gap> elab.name:= "elab";;|
  1855.  
  1856. If  we are  given the  subgroup  'norm' of  order  1344  and its subgroup
  1857. 'elab', the factor group can be considered.
  1858.  
  1859. |    gap> f:= norm / elab;
  1860.     (Subgroup( s8, [ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), 
  1861.       (1,5)(2,6)(3,7)(4,8), (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), 
  1862.       (3,5)(4,6), (2,3)(6,7) ] ) / elab)
  1863.     gap> Size( f );
  1864.     168|
  1865.  
  1866. As the output shows, this is not  a permutation group.  The  factor group
  1867. and its elements can, however, be handled in the usual way.
  1868.  
  1869. |    gap> Random( f );
  1870.     FactorGroupElement( elab, (2,8,7)(4,6,5) )
  1871.     gap> Order( f, last );
  1872.     3|
  1873.  
  1874. The natural link between the group 'norm' and its factor group 'f' is the
  1875. natural  homomorphism onto 'f', mapping each element  of  'norm'  to  its
  1876. coset  modulo  the  kernel  'elab'.   In {\GAP}  you  can  construct  the
  1877. homomorphism, but note that the images lie in 'f' since they are elements
  1878. of  the  factor group, but the preimage  of each  such  element is only a
  1879. coset,  not a  group element (for  cosets,  see  the relevant sections in
  1880. chapter  "Groups", for homomorphisms  see chapters "Operations of Groups"
  1881. and "Mappings").
  1882.  
  1883. |    gap> f.name:= "f";;
  1884.     gap> hom:= NaturalHomomorphism( norm, f );
  1885.     NaturalHomomorphism( Subgroup( s8, 
  1886.     [ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,5)(2,6)(3,7)(4,8),
  1887.       (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7)
  1888.      ] ), (Subgroup( s8, [ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8),
  1889.       (1,5)(2,6)(3,7)(4,8), (5,6)(7,8), (5,7)(6,8), (3,4)(7,8),
  1890.       (3,5)(4,6), (2,3)(6,7) ] ) / elab) )
  1891.     gap> Kernel( hom ) = elab;
  1892.     true
  1893.     gap> x:= Random( norm );
  1894.     (1,5,6,2)(3,4,8,7)
  1895.     gap> Image( hom, x );
  1896.     FactorGroupElement( elab, (2,5)(3,8) )
  1897.     gap> coset:= PreImages( hom, last );
  1898.     (elab*(2,5)(3,8))
  1899.     gap> IsCoset( coset );
  1900.     true
  1901.     gap> x in coset;
  1902.     true
  1903.     gap> coset in f;
  1904.     false|
  1905.  
  1906. The  group 'f'  acts  on  its elements (*not*  on the  cosets)  via right
  1907. multiplication,  yielding the  regular permutation representation of  'f'
  1908. and thus  a new permutation group, namely  the linear  group $L_3(2)$.  A
  1909. more elaborate discussion of operations of groups can be found in section
  1910. "About Operations of Groups" and chapter "Operations of Groups".
  1911.  
  1912. |    gap> op:= Operation( f, Elements( f ), OnRight );;
  1913.     gap> IsPermGroup( op );
  1914.     true
  1915.     gap> Maximum( List( op.generators, LargestMovedPointPerm ) );
  1916.     168
  1917.     gap> IsSimple( op );
  1918.     true|
  1919.  
  1920. 'norm'  acts  on the seven  nontrivial elements  of its  normal  subgroup
  1921. 'elab' by  conjugation,  yielding a  representation of $L_3(2)$  on seven
  1922. points.  We embed this permutation group in 'norm' and deduce that 'norm'
  1923. is a split extension of an elementary abelian group $2^3$ with $L_3(2)$.
  1924.  
  1925. |    gap> op:= Operation( norm, Elements( elab ), OnPoints );
  1926.     Group( (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7) )
  1927.     gap> IsSubgroup(   a8, AsSubgroup( s8, op ) );
  1928.     true
  1929.     gap> IsSubgroup( norm, AsSubgroup( s8, op ) );
  1930.     true
  1931.     gap> Intersection( elab, op );
  1932.     Group( () )|
  1933.  
  1934. Yet another kind of  information about our 'a8'  concerns  its  conjugacy
  1935. classes.
  1936.  
  1937. |    gap> ccl:= ConjugacyClasses( a8 );
  1938.     [ ConjugacyClass( a8, () ), ConjugacyClass( a8, (6,7,8) ),
  1939.       ConjugacyClass( a8, (5,6)(7,8) ), ConjugacyClass( a8, (4,5,6,7,8) ),
  1940.       ConjugacyClass( a8, (3,4)(5,6,7,8) ),
  1941.       ConjugacyClass( a8, (3,4,5)(6,7,8) ),
  1942.       ConjugacyClass( a8, (2,3)(4,5)(6,7,8) ),
  1943.       ConjugacyClass( a8, (2,3,4,5,6,7,8) ),
  1944.       ConjugacyClass( a8, (2,3,4,5,6,8,7) ),
  1945.       ConjugacyClass( a8, (1,2)(3,4)(5,6)(7,8) ),
  1946.       ConjugacyClass( a8, (1,2)(3,4,5,6,7,8) ),
  1947.       ConjugacyClass( a8, (1,2,3)(4,5,6,7,8) ),
  1948.       ConjugacyClass( a8, (1,2,3)(4,5,6,8,7) ),
  1949.       ConjugacyClass( a8, (1,2,3,4)(5,6,7,8) ) ]
  1950.     gap> Length( ccl );
  1951.     14
  1952.     gap> reps:= List( ccl, Representative );
  1953.     [ (), (6,7,8), (5,6)(7,8), (4,5,6,7,8), (3,4)(5,6,7,8),
  1954.       (3,4,5)(6,7,8), (2,3)(4,5)(6,7,8), (2,3,4,5,6,7,8), (2,3,4,5,6,8,7),
  1955.       (1,2)(3,4)(5,6)(7,8), (1,2)(3,4,5,6,7,8), (1,2,3)(4,5,6,7,8),
  1956.       (1,2,3)(4,5,6,8,7), (1,2,3,4)(5,6,7,8) ]
  1957.     gap> List( reps, r -> Order( a8, r ) );
  1958.     [ 1, 3, 2, 5, 4, 3, 6, 7, 7, 2, 6, 15, 15, 4 ]
  1959.     gap> List( ccl, Size );
  1960.     [ 1, 112, 210, 1344, 2520, 1120, 1680, 2880, 2880, 105, 3360, 1344,
  1961.       1344, 1260 ]|
  1962.  
  1963. Note the  difference  between  'Order'  (which means the  element order),
  1964. 'Size' (which means the size of the conjugacy  class) and 'Length' (which
  1965. means the length of a list).
  1966.  
  1967. Having the conjugacy classes, we can consider class functions, i.e., maps
  1968. that  are defined  on the group elements, and  that are constant on  each
  1969. conjugacy class.  One nice example is the number of fixed points; here we
  1970. use that permutations act on points via '\^'.
  1971.  
  1972. |    gap> nrfixedpoints:= function( perm, support )
  1973.     > return Number( [ 1 .. support ], x -> x^perm = x );
  1974.     > end;
  1975.     function ( perm, support ) ... end|
  1976.  
  1977. Note that we must specify the support  since a permutation does not  know
  1978. about the group it is  an element of; e.g.  the trivial permutation  '()'
  1979. has as many fixed points as the support denotes.
  1980.  
  1981. |    gap> permchar1:= List( reps, x -> nrfixedpoints( x, 8 ) );
  1982.     [ 8, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0 ]|
  1983.  
  1984. This is the character of  the natural permutation  representation of 'a8'
  1985. (More about characters can  be found in chapters "Character Tables" ff.).
  1986. In order to  get  another representation  of 'a8',  we  consider  another
  1987. action, namely that on the elements of a conjugacy  class by conjugation;
  1988. note that this is denoted by 'OnPoints', too.
  1989.  
  1990. |    gap> class:= ccl[2];;
  1991.     gap> op:= Operation( a8, Elements( class ), OnPoints );;|
  1992.  
  1993. We get a  permutation  representation 'op'  on 112 points.   It  is  more
  1994. useful to look for properties than at the permutations.
  1995.  
  1996. |    gap> IsPrimitive( op, [ 1 .. 112 ] );
  1997.     false
  1998.     gap> blocks:= Blocks( op, [ 1 .. 112 ] );
  1999.     [ [ 1, 2 ], [ 6, 8 ], [ 4, 7 ], [ 17, 20 ], [ 3, 5 ], [ 14, 19 ],
  2000.       [ 11, 18 ], [ 36, 40 ], [ 13, 16 ], [ 10, 15 ], [ 32, 39 ],
  2001.       [ 28, 38 ], [ 24, 37 ], [ 65, 70 ], [ 31, 35 ], [ 9, 12 ],
  2002.       [ 27, 34 ], [ 23, 33 ], [ 60, 69 ], [ 55, 68 ], [ 50, 67 ],
  2003.       [ 45, 66 ], [ 106, 112 ], [ 59, 64 ], [ 26, 30 ], [ 22, 29 ],
  2004.       [ 54, 63 ], [ 49, 62 ], [ 44, 61 ], [ 100, 111 ], [ 94, 110 ],
  2005.       [ 88, 109 ], [ 76, 107 ], [ 99, 105 ], [ 53, 58 ], [ 21, 25 ],
  2006.       [ 48, 57 ], [ 43, 56 ], [ 93, 104 ], [ 87, 103 ], [ 75, 101 ],
  2007.       [ 82, 108 ], [ 92, 98 ], [ 47, 52 ], [ 42, 51 ], [ 86, 97 ],
  2008.       [ 74, 95 ], [ 81, 102 ], [ 85, 91 ], [ 41, 46 ], [ 73, 89 ],
  2009.       [ 80, 96 ], [ 79, 90 ], [ 78, 84 ], [ 72, 83 ], [ 71, 77 ] ]
  2010.     gap> op2:= Operation( op, blocks, OnSets );;
  2011.     gap> IsPrimitive( op2, [ 1 .. 56 ] );
  2012.     true|
  2013.  
  2014. The action of 'op' on the given block system gave us a new representation
  2015. on 56 points which is primitive,  i.e., the point stabilizer is a maximal
  2016. subgroup.  We compute its preimage in  the representation on eight points
  2017. using homomorphisms (which of course are monomorphisms).
  2018.  
  2019. |    gap> ophom := OperationHomomorphism( a8, op  );;
  2020.     gap> Kernel(ophom);
  2021.     Subgroup( s8, [  ] )
  2022.     gap> ophom2:= OperationHomomorphism( op, op2 );;
  2023.     gap> stab:= Stabilizer( op2, 1 );;
  2024.     gap> Size( stab );
  2025.     360
  2026.     gap> composition:= ophom * ophom2;;
  2027.     gap> preim:= PreImage( composition, stab );
  2028.     Subgroup( s8, [ (1,3,2), (2,4,3), (1,2)(7,8), (3,5,4), (6,8,7) ] )|
  2029.  
  2030. And this is the permutation character (with respect to the succession  of
  2031. conjugacy classes in 'ccl')\:
  2032.  
  2033. |    gap> permchar2:= List( reps, x->nrfixedpoints(x^composition,56) );
  2034.     [ 56, 11, 12, 1, 2, 2, 3, 0, 0, 0, 0, 1, 1, 0 ]|
  2035.  
  2036. The normalizer of an element in the conjugacy class 'class' is a group of
  2037. order 360,  too.   In fact,  it is  essentially the  same  as the maximal
  2038. subgroup we had found before:
  2039.  
  2040. |    gap> sgp:= Normalizer( a8,
  2041.     >                      Subgroup( s8, [ Representative(class) ] ) );
  2042.     Subgroup( s8, [ (6,7,8), (3,4,5), (2,3)(4,5), (1,2)(4,5), (4,5)(7,8)
  2043.      ] )
  2044.     gap> Size( sgp );
  2045.     360
  2046.     gap> IsConjugate( a8, sgp, preim );
  2047.     true|
  2048.  
  2049. The scalar product  of permutation characters of two subgroups  $U$, $V$,
  2050. say,  equals the  number of $(U,V)$--double cosets  (again, see  chapters
  2051. "Character Tables" ff.  for the details).   For example,  the norm of the
  2052. permutation character 'permchar1' of degree eight is two since the action
  2053. of  'a8'  on the  cosets  of  a  point  stabilizer  is  at  least  doubly
  2054. transitive\:
  2055.  
  2056. |    gap> stab:= Stabilizer( a8, 1 );;
  2057.     gap> double:= DoubleCosets( a8, stab, stab );
  2058.     [ DoubleCoset( Subgroup( s8, [ (3,8,7), (2,3,8), (2,3,4), (2,6,4),
  2059.           (4,5,6) ] ), (2,5,8,3,4,6,7), Subgroup( s8,
  2060.         [ (3,8,7), (2,3,8), (2,3,4), (2,6,4), (4,5,6) ] ) ),
  2061.       DoubleCoset( Subgroup( s8, [ (3,8,7), (2,3,8), (2,3,4), (2,6,4),
  2062.           (4,5,6) ] ), (1,2,5,7)(3,4,6,8), Subgroup( s8,
  2063.         [ (3,8,7), (2,3,8), (2,3,4), (2,6,4), (4,5,6) ] ) ) ]
  2064.     gap> Length( double );
  2065.     2|
  2066.  
  2067. We compute the  numbers of $('sgp','sgp')$  and  $('sgp','stab')$  double
  2068. cosets.
  2069.  
  2070. |    gap> Length( DoubleCosets( a8, sgp, sgp ) );
  2071.     4
  2072.     gap> Length( DoubleCosets( a8, sgp, stab ) );
  2073.     2|
  2074.  
  2075. Thus both irreducible  constituents  of 'permchar1' are also constituents
  2076. of 'permchar2', i.e., the difference of the two permutation characters is
  2077. a proper character of 'a8' of norm two.
  2078.  
  2079. |    gap> permchar2 - permchar1;
  2080.     [ 48, 6, 8, -2, 0, 0, 2, -1, -1, 0, 0, 1, 1, 0 ]|
  2081.  
  2082. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2083. \Section{About Operations of Groups}
  2084.  
  2085. One of the most  important tools in  group  theory is the *operation*  or
  2086. *action* of a group on a certain set.
  2087.  
  2088. We say that a  group $G$ operates on a set $D$ if we have a function that
  2089. takes each pair $(d,g)$ with $d \in  D$ and $g  \in G$ to another element
  2090. $d^g  \in  D$, which  we  call  the image of  $d$  under  $g$,  such that
  2091. $d^{identity} = d$ and $(d^g)^h = d^{gh}$ for each $d \in D$ and $g,h \in
  2092. G$.
  2093.  
  2094. This is equivalent to saying that  an operation is  a homomorphism of the
  2095. group $G$ into the full symmetric group on $D$.  We  usually call $D$ the
  2096. *domain* of the operation and its elements *points*.
  2097.  
  2098. In this section  we will demonstrate how you can  compute with operations
  2099. of groups.  For an example we will use the alternating group on 8 points.
  2100.  
  2101. |    gap> a8 := Group( (1,2,3), (2,3,4,5,6,7,8) );;
  2102.     gap> a8.name := "a8";; |
  2103.  
  2104. It is important to note however, that the applicability  of the functions
  2105. from the operation package is not restricted to  permutation groups.  All
  2106. the  functions mentioned in this section can also be used to compute with
  2107. the operation of  a  matrix  group on the vectors, etc.   We only  use  a
  2108. permutation group here because this makes the examples more compact.
  2109.  
  2110. The standard  operation in {\GAP} is always  denoted  by the caret ('\^')
  2111. operator.  That means that when no other operation  is specified (we will
  2112. see below  how this  can be  done) all the functions from the  operations
  2113. package will  compute the image of a point <p>  under  an  element <g> as
  2114. '<p>\^<g>'.  Note  that  this  can  already  denote different operations,
  2115. depending on the type of points and the type of elements.  For example if
  2116. the  group elements  are  permutations it can  either denote  the  normal
  2117. operation when the points are integers or the conjugation when the points
  2118. are permutations  themselves  (see  "Operations for  Permutations").  For
  2119. another  example if the group elements are matrices  it can either denote
  2120. the multiplication from  the right  when  the points are vectors or again
  2121. the conjugation  when  the  points are  matrices (of the same  dimension)
  2122. themselves  (see  "Operations  for  Matrices").    Which  operations  are
  2123. available through  the caret  operator  for  a particular  type of  group
  2124. elements is described in the chapter for this type of group elements.
  2125.  
  2126. |    gap> 2 ^ (1,2,3);
  2127.     3
  2128.     gap> 1 ^ a8.2;
  2129.     1
  2130.     gap> (2,4) ^ (1,2,3);
  2131.     (3,4) |
  2132.  
  2133. The most  basic  function  of  the  operations  package  is the  function
  2134. 'Orbit', which computes  the  orbit of a point under the operation of the
  2135. group.
  2136.  
  2137. |    gap> Orbit( a8, 2 );
  2138.     [ 2, 3, 1, 4, 5, 6, 7, 8 ] |
  2139.  
  2140. Note  that the orbit is not a set, because it is not sorted.  See "Orbit"
  2141. for the definition in which order the points appear in an orbit.
  2142.  
  2143. We will  try to  find several  subgroups  in  'a8' using  the  operations
  2144. package.  One subgroup is immediately available, namely the stabilizer of
  2145. one  point.  The index  of the stabilizer must of  course be equal to the
  2146. length of the orbit, i.e., 8.
  2147.  
  2148. |    gap> u8 := Stabilizer( a8, 1 );
  2149.     Subgroup( a8, [ (2,3,4,5,6,7,8), (3,8,7) ] )
  2150.     gap> Index( a8, u8 );
  2151.     8 |
  2152.  
  2153. This gives us a hint how to find further subgroups.  Each subgroup is the
  2154. stabilizer of a point of an appropriate transitive operation  (namely the
  2155. operation on  the  cosets of that subgroup or  another  operation that is
  2156. equivalent to this operation).
  2157.  
  2158. So the question is how to find other operations.  The obvious thing is to
  2159. operate  on  pairs  of  points.   So  using  the  function 'Tuples'  (see
  2160. "Tuples") we first generate a list of all pairs.
  2161.  
  2162. |    gap> pairs := Tuples( [1..8], 2 );
  2163.     [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 1, 5 ], [ 1, 6 ],
  2164.       [ 1, 7 ], [ 1, 8 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ], [ 2, 4 ],
  2165.       [ 2, 5 ], [ 2, 6 ], [ 2, 7 ], [ 2, 8 ], [ 3, 1 ], [ 3, 2 ],
  2166.       [ 3, 3 ], [ 3, 4 ], [ 3, 5 ], [ 3, 6 ], [ 3, 7 ], [ 3, 8 ],
  2167.       [ 4, 1 ], [ 4, 2 ], [ 4, 3 ], [ 4, 4 ], [ 4, 5 ], [ 4, 6 ],
  2168.       [ 4, 7 ], [ 4, 8 ], [ 5, 1 ], [ 5, 2 ], [ 5, 3 ], [ 5, 4 ],
  2169.       [ 5, 5 ], [ 5, 6 ], [ 5, 7 ], [ 5, 8 ], [ 6, 1 ], [ 6, 2 ],
  2170.       [ 6, 3 ], [ 6, 4 ], [ 6, 5 ], [ 6, 6 ], [ 6, 7 ], [ 6, 8 ],
  2171.       [ 7, 1 ], [ 7, 2 ], [ 7, 3 ], [ 7, 4 ], [ 7, 5 ], [ 7, 6 ],
  2172.       [ 7, 7 ], [ 7, 8 ], [ 8, 1 ], [ 8, 2 ], [ 8, 3 ], [ 8, 4 ],
  2173.       [ 8, 5 ], [ 8, 6 ], [ 8, 7 ], [ 8, 8 ] ] |
  2174.  
  2175. Now we would like to have 'a8' operate on this domain.  But we cannot use
  2176. the default operation (denoted by the caret) because '<list> \^\  <perm>'
  2177. is  not defined.  So we  must  tell the  functions  from  the  operations
  2178. package how the group elements operate on the elements of the domain.  In
  2179. our example we can do this by simply passing  'OnPairs' as  optional last
  2180. argument.  All functions from  the  operations  package  accept  such  an
  2181. optional  argument  that describes the operation.  See "Other Operations"
  2182. for a list of the available nonstandard operations.
  2183.  
  2184. Note  that those operations are in  fact simply functions  that  take  an
  2185. element of the domain and an element of the group and return the image of
  2186. the element of the domain under  the group element.   So  to  compute the
  2187. image of the  pair '[1,2]' under  the permutation '(1,4,5)' we can simply
  2188. write
  2189.  
  2190. |    gap> OnPairs( [1,2], (1,4,5) );
  2191.     [ 4, 2 ] |
  2192.  
  2193. As  was  mentioned  above we  have  to  make sure  that the operation  is
  2194. transitive.  So we check this.
  2195.  
  2196. |    gap> IsTransitive( a8, pairs, OnPairs );
  2197.     false |
  2198.  
  2199. The operation is not transitive,  so we want to  find out what the orbits
  2200. are.  The function 'Orbits' does that for you.  It returns a list  of all
  2201. the orbits.
  2202.  
  2203. |    gap> orbs := Orbits( a8, pairs, OnPairs );
  2204.     [ [ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ], [ 5, 5 ], [ 6, 6 ],
  2205.           [ 7, 7 ], [ 8, 8 ] ],
  2206.       [ [ 1, 2 ], [ 2, 3 ], [ 1, 3 ], [ 3, 1 ], [ 3, 4 ], [ 2, 1 ],
  2207.           [ 1, 4 ], [ 4, 1 ], [ 4, 5 ], [ 3, 2 ], [ 2, 4 ], [ 1, 5 ],
  2208.           [ 4, 2 ], [ 5, 1 ], [ 5, 6 ], [ 4, 3 ], [ 3, 5 ], [ 2, 5 ],
  2209.           [ 1, 6 ], [ 5, 3 ], [ 5, 2 ], [ 6, 1 ], [ 6, 7 ], [ 5, 4 ],
  2210.           [ 4, 6 ], [ 3, 6 ], [ 2, 6 ], [ 1, 7 ], [ 6, 4 ], [ 6, 3 ],
  2211.           [ 6, 2 ], [ 7, 1 ], [ 7, 8 ], [ 6, 5 ], [ 5, 7 ], [ 4, 7 ],
  2212.           [ 3, 7 ], [ 2, 7 ], [ 1, 8 ], [ 7, 5 ], [ 7, 4 ], [ 7, 3 ],
  2213.           [ 7, 2 ], [ 8, 1 ], [ 8, 2 ], [ 7, 6 ], [ 6, 8 ], [ 5, 8 ],
  2214.           [ 4, 8 ], [ 3, 8 ], [ 2, 8 ], [ 8, 6 ], [ 8, 5 ], [ 8, 4 ],
  2215.           [ 8, 3 ], [ 8, 7 ] ] ] |
  2216.  
  2217. The  operation of 'a8' on the first orbit is of course equivalent to  the
  2218. original operation, so we ignore it and work with the second orbit.
  2219.  
  2220. |    gap> u56 := Stabilizer( a8, [1,2], OnPairs );
  2221.     Subgroup( a8, [ (3,8,7), (3,6)(4,7,5,8), (6,7,8) ] )
  2222.     gap> Index( a8, u56 );
  2223.     56 |
  2224.  
  2225. So  now  we  have  found  a  second  subgroup.   To  make  the  following
  2226. computations a  little bit easier and more efficient we would now like to
  2227. work on the points '[1..56]' instead of the  list of pairs.  The function
  2228. 'Operation' does what we need.  It creates a  new group that  operates on
  2229. '[1..56]' in the same way that 'a8' operates on the second orbit.
  2230.  
  2231. |    gap> a8_56 := Operation( a8, orbs[2], OnPairs );
  2232.     Group( ( 1, 2, 4)( 3, 6,10)( 5, 7,11)( 8,13,16)(12,18,17)(14,21,20)
  2233.     (19,27,26)(22,31,30)(28,38,37)(32,43,42)(39,51,50)(44,45,55),
  2234.     ( 1, 3, 7,12,19,28,39)( 2, 5, 9,15,23,33,45)( 4, 8,14,22,32,44, 6)
  2235.     (10,16,24,34,46,56,51)(11,17,25,35,47,43,55)(13,20,29,40,52,38,50)
  2236.     (18,26,36,48,31,42,54)(21,30,41,53,27,37,49) )
  2237.     gap> a8_56.name := "a8_56";; |
  2238.  
  2239. We would now like to know if the subgroup 'u56' of index 56 that we found
  2240. is  maximal or  not.   Again  we can make  use  of  a function  from  the
  2241. operations package.  Namely a subgroup is maximal if the operation on the
  2242. cosets of  this subgroup is primitive, i.e., if there is no  partition of
  2243. the  set of  cosets into subsets such that  the group operates setwise on
  2244. those subsets.
  2245.  
  2246. |    gap> IsPrimitive( a8_56, [1..56] );
  2247.     false |
  2248.  
  2249. Note that we must specify  the domain of the operation.  You  might think
  2250. that in  the last  example 'IsPrimitive' could  use  '[1..56]' as default
  2251. domain if  no domain was given.  But  this is not so simple,  for example
  2252. would the default domain of 'Group( (2,3,4) )'  be '[1..4]' or  '[2..4]'?
  2253. To avoid  confusion, all  operations  package functions require  that you
  2254. specify the domain of operation.
  2255.  
  2256. We see that 'a8\_56' is  not  primitive.  This means of course  that  the
  2257. operation of  'a8'  on  'orb[2]'  is  not  primitive,  because  those two
  2258. operations are equivalent.   So the stabilizer 'u56' is not maximal.  Let
  2259. us  try to find its supergroups.  We use the  function 'Blocks' to find a
  2260. block  system.   The (optional) third argument  in the following  example
  2261. tells 'Blocks' that we  want a  block  system where  1 and 10 lie in  one
  2262. block.  There are several other block systems, which we could compute  by
  2263. specifying a  different pair, it just  turns out that  '[1,10]' makes the
  2264. following computation more interesting.
  2265.  
  2266. |    gap> blocks := Blocks( a8_56, [1..56], [1,10] );
  2267.     [ [ 1, 10, 13, 21, 31, 43, 45 ], [ 2, 3, 16, 20, 30, 42, 55 ],
  2268.       [ 4, 6, 8, 14, 22, 32, 44 ], [ 5, 7, 11, 24, 29, 41, 54 ],
  2269.       [ 9, 12, 17, 18, 34, 40, 53 ], [ 15, 19, 25, 26, 27, 46, 52 ],
  2270.       [ 23, 28, 35, 36, 37, 38, 56 ], [ 33, 39, 47, 48, 49, 50, 51 ] ] |
  2271.  
  2272. The result is a  list of  sets,  i.e., sorted  lists,  such that 'a8\_56'
  2273. operates on  those  sets.  Now  we  would  like  the  stabilizer of  this
  2274. operation on the sets.  Because  we wanted to operate on the sets we have
  2275. to pass 'OnSets' as third argument.
  2276.  
  2277. |    gap> u8_56 := Stabilizer( a8_56, blocks[1], OnSets );
  2278.     Subgroup( a8_56, 
  2279.     [ (15,35,48)(19,28,39)(22,32,44)(23,33,52)(25,36,49)(26,37,50)
  2280.         (27,38,51)(29,41,54)(30,42,55)(31,43,45)(34,40,53)(46,56,47), 
  2281.       ( 9,25)(12,19)(14,22)(15,34)(17,26)(18,27)(20,30)(21,31)(23,48)
  2282.         (24,29)(28,39)(32,44)(33,56)(35,47)(36,49)(37,50)(38,51)(40,52)
  2283.         (41,54)(42,55)(43,45)(46,53), ( 5,17)( 7,12)( 8,14)( 9,24)(11,18)
  2284.         (13,21)(15,25)(16,20)(23,47)(28,39)(29,34)(32,44)(33,56)(35,49)
  2285.         (36,48)(37,50)(38,51)(40,54)(41,53)(42,55)(43,45)(46,52), 
  2286.       ( 2,11)( 3, 7)( 4, 8)( 5,16)( 9,17)(10,13)(20,24)(23,47)(25,26)
  2287.         (28,39)(29,30)(32,44)(33,56)(35,48)(36,50)(37,49)(38,51)(40,53)
  2288.         (41,55)(42,54)(43,45)(46,52), ( 1,10)( 2, 6)( 3, 4)( 5, 7)( 8,16)
  2289.         (12,17)(14,20)(19,26)(22,30)(23,47)(28,50)(32,55)(33,56)(35,48)
  2290.         (36,49)(37,39)(38,51)(40,53)(41,54)(42,44)(43,45)(46,52) ] )
  2291.     gap> Index( a8_56, u8_56 );
  2292.     8 |
  2293.  
  2294. Now  we have  a problem.   We  have found a  new  subgroup, but not  as a
  2295. subgroup of 'a8', instead  it  is a subgroup of 'a8\_56'.   We  know that
  2296. 'a8\_56' is isomorphic to 'a8' (in  general the  result of 'Operation' is
  2297. only isomorphic to a factor group of the original group, but in this case
  2298. it must be  isomorphic to 'a8', because 'a8'  is  simple and has only the
  2299. full  group as  nontrivial  factor group).   But we  only  know  that  an
  2300. isomorphism exists, we do not know it.
  2301.  
  2302. Another  function comes  to our rescue.  'OperationHomomorphism'  returns
  2303. the  homomorphism of a  group  onto  the group  that  was  constructed by
  2304. 'Operation'.  A later section in this chapter will introduce mappings and
  2305. homomorphisms  in  general,  but  for the  moment we  can just regard the
  2306. result  of 'OperationHomomorphism' as  a  black box that  we can  use  to
  2307. transfer information from 'a8' to 'a8\_56' and back.
  2308.  
  2309. |    gap> h56 := OperationHomomorphism( a8, a8_56 );
  2310.     OperationHomomorphism( a8, a8_56 )
  2311.     gap> u8b := PreImages( h56, u8_56 );
  2312.     Subgroup( a8, [ (6,7,8), (5,6)(7,8), (4,5)(7,8), (3,4)(7,8),
  2313.       (1,3)(7,8) ] )
  2314.     gap> Index( a8, u8b );
  2315.     8
  2316.     gap> u8 = u8b;
  2317.     false |
  2318.  
  2319. So we have  in fact found a new subgroup.   However if we  look closer we
  2320. note that 'u8b' is not  totally new.  It fixes  the point 2, thus it lies
  2321. in  the  stabilizer of  2, and because  it  has the  same  index  as this
  2322. stabilizer it must in fact be the stabilizer.  Thus  'u8b' is  conjugated
  2323. to 'u8'.  A nice way to check  this is to check that the operation on the
  2324. 8 blocks is equivalent to the original operation.
  2325.  
  2326. |    gap> IsEquivalentOperation( a8, [1..8], a8_56, blocks, OnSets );
  2327.     true |
  2328.  
  2329. Now the choice of the third  argument '[1,10]' of 'Blocks' becomes clear.
  2330. Had  we not  given that argument  we would have obtained the block system
  2331. that  has  '[1,3,7,12,19,28,39]' as first  block.   The  preimage of  the
  2332. stabilizer of this set would have been 'u8' itself, and we would not have
  2333. been able to  introduce 'IsEquivalentOperation'.  Of course we could also
  2334. use the  general  function  'IsConjugate',  but  we  want  to demonstrate
  2335. 'IsEquivalentOperation'.
  2336.  
  2337. Actually there  is a  third block system of 'a8\_56' that gives rise to a
  2338. third subgroup.
  2339.  
  2340. |    gap> blocks := Blocks( a8_56, [1..56], [1,6] );
  2341.     [ [ 1, 6 ], [ 2, 10 ], [ 3, 4 ], [ 5, 16 ], [ 7, 8 ], [ 9, 24 ], 
  2342.       [ 11, 13 ], [ 12, 14 ], [ 15, 34 ], [ 17, 20 ], [ 18, 21 ], 
  2343.       [ 19, 22 ], [ 23, 46 ], [ 25, 29 ], [ 26, 30 ], [ 27, 31 ], 
  2344.       [ 28, 32 ], [ 33, 56 ], [ 35, 40 ], [ 36, 41 ], [ 37, 42 ], 
  2345.       [ 38, 43 ], [ 39, 44 ], [ 45, 51 ], [ 47, 52 ], [ 48, 53 ], 
  2346.       [ 49, 54 ], [ 50, 55 ] ]
  2347.     gap> u28_56 := Stabilizer( a8_56, [1,6], OnSets );
  2348.     Subgroup( a8_56, 
  2349.     [ ( 2,38,51)( 3,28,39)( 4,32,44)( 5,41,54)(10,43,45)(16,36,49)
  2350.         (17,40,53)(20,35,48)(23,47,30)(26,46,52)(33,55,37)(42,56,50), 
  2351.       ( 5,17,26,37,50)( 7,12,19,28,39)( 8,14,22,32,44)( 9,15,23,33,54)
  2352.         (11,18,27,38,51)(13,21,31,43,45)(16,20,30,42,55)(24,34,46,56,49)
  2353.         (25,35,47,41,53)(29,40,52,36,48), 
  2354.       ( 1, 6)( 2,39,38,19,18, 7)( 3,51,28,27,12,11)( 4,45,32,31,14,13)
  2355.         ( 5,55,33,23,15, 9)( 8,10,44,43,22,21)(16,50,56,46,34,24)
  2356.         (17,54,42,47,35,25)(20,49,37,52,40,29)(26,53,41,30,48,36) ] )
  2357.     gap> u28 := PreImages( h56, u28_56 );
  2358.     Subgroup( a8, [ (3,7,8), (4,5,6,7,8), (1,2)(3,8,7,6,5,4) ] )
  2359.     gap> Index( a8, u28 );
  2360.     28 |
  2361.  
  2362. We know that the subgroup 'u28' of  index 28 is  maximal, because we know
  2363. that 'a8' has  no subgroups of  index 2,  4, or  7.  However  we can also
  2364. quickly verify this by checking that 'a8\_56' operates primitively on the
  2365. 28 blocks.
  2366.  
  2367. |    gap> IsPrimitive( a8_56, blocks, OnSets );
  2368.     true |
  2369.  
  2370. Note  that 'Stabilizer'  is not only applicable to groups like  'a8'  but
  2371. also  to their  subgroups  like  'u56'.  So another  method to find a new
  2372. subgroup  is  to compute the  stabilizer of another point in 'u56'.  Note
  2373. that 'u56' already leaves 1 and 2 fixed.
  2374.  
  2375. |    gap> u336 := Stabilizer( u56, 3 );
  2376.     Subgroup( a8, [ (4,6,5), (5,6)(7,8), (6,7,8) ] )
  2377.     gap> Index( a8, u336 );
  2378.     336 |
  2379.  
  2380. Other  functions are also applicable to subgroups.   In the  following we
  2381. show that 'u336'  operates regularly on the  60 triples of '[4..8]' which
  2382. contain no  element  twice, which means that this operation is equivalent
  2383. to the operations of 'u336' on its 60 elements from the right.  Note that
  2384. 'OnTuples' is a generalization of 'OnPairs'.
  2385.  
  2386. |    gap> IsRegular( u336, Orbit( u336, [4,5,6], OnTuples ), OnTuples );
  2387.     true |
  2388.  
  2389. Just as we did in the case  of  the operation on the pairs above, we  now
  2390. construct a new permutation group that operates on '[1..336]' in the same
  2391. way that 'a8' operates on the cosets of 'u336'.  Note that  the operation
  2392. of a group on  the  cosets is by  multiplication from the right, thus  we
  2393. have to specify 'OnRight'.
  2394.  
  2395. |    gap> a8_336 := Operation( a8, Cosets( a8, u336 ), OnRight );;
  2396.     gap> a8_336.name := "a8_336";; |
  2397.  
  2398. To find  subgroups above  'u336'  we  again  check if  the  operation  is
  2399. primitive.
  2400.  
  2401. |    gap> blocks := Blocks( a8_336, [1..336], [1,43] );
  2402.     [ [ 1, 43, 85 ], [ 2, 102, 205 ], [ 3, 95, 165 ], [ 4, 106, 251 ],
  2403.       [ 5, 117, 334 ], [ 6, 110, 294 ], [ 7, 122, 127 ], [ 8, 144, 247 ],
  2404.       [ 9, 137, 207 ], [ 10, 148, 293 ], [ 11, 45, 159 ],
  2405.       [ 12, 152, 336 ], [ 13, 164, 169 ], [ 14, 186, 289 ],
  2406.       [ 15, 179, 249 ], [ 16, 190, 335 ], [ 17, 124, 201 ],
  2407.       [ 18, 44, 194 ], [ 19, 206, 211 ], [ 20, 228, 331 ],
  2408.       [ 21, 221, 291 ], [ 22, 46, 232 ], [ 23, 166, 243 ],
  2409.       [ 24, 126, 236 ], [ 25, 248, 253 ], [ 26, 48, 270 ],
  2410.       [ 27, 263, 333 ], [ 28, 125, 274 ], [ 29, 208, 285 ],
  2411.       [ 30, 168, 278 ], [ 31, 290, 295 ], [ 32, 121, 312 ],
  2412.       [ 33, 47, 305 ], [ 34, 167, 316 ], [ 35, 250, 327 ],
  2413.       [ 36, 210, 320 ], [ 37, 74, 332 ], [ 38, 49, 163 ], [ 39, 81, 123 ],
  2414.       [ 40, 59, 209 ], [ 41, 70, 292 ], [ 42, 66, 252 ], [ 50, 142, 230 ],
  2415.       [ 51, 138, 196 ], [ 52, 146, 266 ], [ 53, 87, 131 ],
  2416.       [ 54, 153, 302 ], [ 55, 160, 174 ], [ 56, 182, 268 ],
  2417.       [ 57, 178, 234 ], [ 58, 189, 304 ], [ 60, 86, 199 ],
  2418.       [ 61, 198, 214 ], [ 62, 225, 306 ], [ 63, 218, 269 ],
  2419.       [ 64, 88, 235 ], [ 65, 162, 245 ], [ 67, 233, 254 ],
  2420.       [ 68, 90, 271 ], [ 69, 261, 301 ], [ 71, 197, 288 ],
  2421.       [ 72, 161, 281 ], [ 73, 265, 297 ], [ 75, 89, 307 ],
  2422.       [ 76, 157, 317 ], [ 77, 229, 328 ], [ 78, 193, 324 ],
  2423.       [ 79, 116, 303 ], [ 80, 91, 158 ], [ 82, 101, 195 ],
  2424.       [ 83, 112, 267 ], [ 84, 108, 231 ], [ 92, 143, 237 ],
  2425.       [ 93, 133, 200 ], [ 94, 150, 273 ], [ 96, 154, 309 ],
  2426.       [ 97, 129, 173 ], [ 98, 184, 272 ], [ 99, 180, 238 ],
  2427.       [ 100, 188, 308 ], [ 103, 202, 216 ], [ 104, 224, 310 ],
  2428.       [ 105, 220, 276 ], [ 107, 128, 241 ], [ 109, 240, 256 ],
  2429.       [ 111, 260, 311 ], [ 113, 204, 287 ], [ 114, 130, 277 ],
  2430.       [ 115, 275, 296 ], [ 118, 132, 313 ], [ 119, 239, 330 ],
  2431.       [ 120, 203, 323 ], [ 134, 185, 279 ], [ 135, 175, 242 ],
  2432.       [ 136, 192, 315 ], [ 139, 171, 215 ], [ 140, 226, 314 ],
  2433.       [ 141, 222, 280 ], [ 145, 244, 258 ], [ 147, 262, 318 ],
  2434.       [ 149, 170, 283 ], [ 151, 282, 298 ], [ 155, 246, 329 ],
  2435.       [ 156, 172, 319 ], [ 176, 227, 321 ], [ 177, 217, 284 ],
  2436.       [ 181, 213, 257 ], [ 183, 264, 322 ], [ 187, 286, 300 ],
  2437.       [ 191, 212, 325 ], [ 219, 259, 326 ], [ 223, 255, 299 ] ] |
  2438.  
  2439. To find the subgroup of index 112 that belongs to this operation we could
  2440. use the  same methods  as before, but we actually use  a different trick.
  2441. From the  above we see that the subgroup is the union of 'u336'  with its
  2442. 43rd and its 85th coset.  Thus we simply add a representative of the 43rd
  2443. coset to the generators of 'u336'.
  2444.  
  2445. |    gap> u112 := Closure( u336, Representative( Cosets(a8,u336)[43] ) );
  2446.     Subgroup( a8, [ (4,6,5), (5,6)(7,8), (6,7,8), (1,3,2) ] )
  2447.     gap> Index( a8, u112 );
  2448.     112 |
  2449.  
  2450. Above this subgroup of index 112 lies a  subgroup  of index 56, which  is
  2451. not conjugate to 'u56'.  In fact, unlike 'u56' it is  maximal.  We obtain
  2452. this subgroup in  the same way that we obtained 'u112', this time forcing
  2453. two points, namely 39 and 43 into the first block.
  2454.  
  2455. |    gap> blocks := Blocks( a8_336, [1..336], [1,39,43] );;
  2456.     gap> Length( blocks );
  2457.     56
  2458.     gap> u56b := Closure( u112, Representative( Cosets(a8,u336)[39] ) );
  2459.     Subgroup( a8, [ (4,6,5), (5,6)(7,8), (6,7,8), (1,3,2), (2,3)(7,8) ] )
  2460.     gap> Index( a8, u56b );
  2461.     56
  2462.     gap> IsPrimitive( a8_336, blocks, OnSets );
  2463.     true |
  2464.  
  2465. We already mentioned  in the beginning  that  there  is another  standard
  2466. operation of  permutations, namely  the  conjugation.   E.g., because  no
  2467. other operation  is  specified  in the  following  example  'OrbitLength'
  2468. simply  operates  using the caret operator and because '<perm1>\^<perm2>'
  2469. is defined  as the  conjugation  of <perm2>  on  <perm1>  we  effectively
  2470. compute the length of the conjugacy class of '(1,2)(3,4)(5,6)(7,8)'.  (In
  2471. fact  '<element1>\^<element2>'  is  always defined  as the conjugation if
  2472. <element1> and <element2> are group elements of  the  same  type.  So the
  2473. length of a conjugacy class  of any  element <elm>  in an arbitrary group
  2474. <G> can be computed as 'OrbitLength( <G>, <elm>  )'.  In general  however
  2475. this may not be a good  idea, 'Size( ConjugacyClass( <G>,  <elm> ) )'  is
  2476. probably more efficient.)
  2477.  
  2478. |    gap> OrbitLength( a8, (1,2)(3,4)(5,6)(7,8) );
  2479.     105
  2480.     gap> orb := Orbit( a8, (1,2)(3,4)(5,6)(7,8) );;
  2481.     gap> u105 := Stabilizer( a8, (1,2)(3,4)(5,6)(7,8) );
  2482.     Subgroup( a8, [ (5,6)(7,8), (1,2)(3,4)(5,6)(7,8), (5,7)(6,8),
  2483.       (3,4)(7,8), (3,5)(4,6), (1,3)(2,4) ] )
  2484.     gap> Index( a8, u105 );
  2485.     105 |
  2486.  
  2487. Of course the last stabilizer  is in  fact the centralizer of the element
  2488. '(1,2)(3,4)(5,6)(7,8)'.   'Stabilizer'  notices  that  and  computes  the
  2489. stabilizer using the centralizer algorithm for permutation groups.
  2490.  
  2491. In the usual way we now look for the subgroups that lie above 'u105'.
  2492.  
  2493. |    gap> blocks := Blocks( a8, orb );;
  2494.     gap> Length( blocks );
  2495.     15
  2496.     gap> blocks[1];
  2497.     [ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,4)(2,3)(5,8)(6,7), 
  2498.       (1,5)(2,6)(3,7)(4,8), (1,6)(2,5)(3,8)(4,7), (1,7)(2,8)(3,5)(4,6), 
  2499.       (1,8)(2,7)(3,6)(4,5) ] |
  2500.  
  2501. To find the subgroup of index 15 we  again use closure.  Now we must be a
  2502. little bit  careful   to avoid  confusion.   'u105' is  the stabilizer of
  2503. '(1,2)(3,4)(5,6)(7,8)'.  We  know that there is a correspondence  between
  2504. the  points  of  the  orbit   and  the  cosets  of   'u105'.   The  point
  2505. '(1,2)(3,4)(5,6)(7,8)' corresponds  to 'u105'.   To  get  the subgroup of
  2506. index 15  we must add to 'u105' an element of the coset  that corresponds
  2507. to the point '(1,3)(2,4)(5,7)(6,8)'  (or any  other  point in  the  first
  2508. block).   That  means that  we must  use  an  element of 'a8'  that  maps
  2509. '(1,2)(3,4)(5,6)(7,8)' to '(1,3)(2,4)(5,7)(6,8)'.  The important thing is
  2510. that  '(1,3)(2,4)(5,7)(6,8)' will not do, in fact  '(1,3)(2,4)(5,7)(6,8)'
  2511. lies in 'u105'.
  2512.  
  2513. The  function  'RepresentativeOperation'  does what we need.  It  takes a
  2514. group and  two points and returns an  element  of the group that maps the
  2515. first point  to  the  second.  In fact it also allows  you to specify the
  2516. operation  as optional fourth argument as usual, but we do  not need this
  2517. here.  If no such element exists in the group, i.e., if the two points do
  2518. not lie in one orbit  under the group,  'RepresentativeOperation' returns
  2519. 'false'.
  2520.  
  2521. |    gap> rep := RepresentativeOperation( a8, (1,2)(3,4)(5,6)(7,8),
  2522.     >                                         (1,3)(2,4)(5,7)(6,8) );
  2523.     (2,3)(6,7)
  2524.     gap> u15 := Closure( u105, rep );
  2525.     Subgroup( a8, [ (5,6)(7,8), (1,2)(3,4)(5,6)(7,8), (5,7)(6,8),
  2526.       (3,4)(7,8), (3,5)(4,6), (1,3)(2,4), (2,3)(6,7) ] )
  2527.     gap> Index( a8, u15 );
  2528.     15 |
  2529.  
  2530. 'u15' is of course a maximal subgroup, because 'a8'  has  no subgroups of
  2531. index 3 or 5.
  2532.  
  2533. There is in fact another class of subgroups of index 15 above 'u105' that
  2534. we get by adding '(2,3)(6,8)' to 'u105'.
  2535.  
  2536. |    gap> u15b := Closure( u105, (2,3)(6,8) );
  2537.     Subgroup( a8, [ (5,6)(7,8), (1,2)(3,4)(5,6)(7,8), (5,7)(6,8),
  2538.       (3,4)(7,8), (3,5)(4,6), (1,3)(2,4), (2,3)(6,8) ] )
  2539.     gap> Index( a8, u15b );
  2540.     15 |
  2541.  
  2542. We now show that 'u15' and 'u15b' are not conjugate.  We showed that 'u8'
  2543. and  'u8b'  are conjugate by  showing that  the operations on  the cosets
  2544. where equivalent.  We could show that 'u15' and 'u15b' are not  conjugate
  2545. by showing  that  the  operations  on their  cosets  are not  equivalent.
  2546. Instead we simply call 'RepresentativeOperation' again.
  2547.  
  2548. |    gap> RepresentativeOperation( a8, u15, u15b );
  2549.     false |
  2550.  
  2551. 'RepresentativeOperation' tells us that there is no  element <g> in  'a8'
  2552. such that 'u15\^<g> = u15b'.   Because '\^' also  denotes the conjugation
  2553. of subgroups this tells us that 'u15' and 'u15b' are not conjugate.  Note
  2554. that this operation should only be used rarely, because it is usually not
  2555. very  efficient.  The  test in this case is however reasonable efficient,
  2556. and is in fact the one employed by 'IsConjugate' (see "IsConjugate").
  2557.  
  2558. This  concludes  our  example.   In  this  section  we demonstrated  some
  2559. functions  from  the operations  package.   There  is  a  whole class  of
  2560. functions that  we  did  not mention, namely  those that  take  a  single
  2561. element instead  of a  whole  group  as first argument, e.g., 'Cycle' and
  2562. 'Permutation'.  All functions are described in the chapter "Operations of
  2563. Groups".
  2564.  
  2565. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2566. \Section{About Fields}
  2567.  
  2568. In this  section  we will show  you some basic computations with  fields.
  2569. {\GAP}  supports  at  present  the  following  fields.   The   rationals,
  2570. cyclotomic extensions  of  rationals and their subfields  (which  we will
  2571. refer to as number fields in the following), and finite fields.
  2572.  
  2573. Let us  first take  a look at the infinite fields mentioned above.  While
  2574. the set of rational numbers is a predefined domain in {\GAP} to which you
  2575. may  refer  by  its   identifier  'Rationals',   cyclotomic   fields  are
  2576. constructed  by  using  the  function  'CyclotomicField',  which  may  be
  2577. abbreviated as 'CF'.
  2578.  
  2579. |    gap> IsField( Rationals );
  2580.     true
  2581.     gap> Size( Rationals );
  2582.     "infinity"
  2583.     gap> f := CyclotomicField( 8 );
  2584.     CF(8)
  2585.     gap> IsSubset( f, Rationals );
  2586.     true|
  2587.  
  2588. The integer argument 'n' of  the function call to 'CF' specifies that the
  2589. cyclotomic field containing all n-th roots of unity should be returned.
  2590.  
  2591. Cyclotomic  fields are constructed  as  extensions  of  the Rationals  by
  2592. primitive roots of unity.  Thus a primitive  n-th root of unity is always
  2593. an element  of CF(n), where  n  is a natural  number.  In {\GAP}, one may
  2594. construct a primitive n-th root of unity by calling 'E(n)'.
  2595.  
  2596. |    gap> (E(8) + E(8)^3)^2;
  2597.     -2
  2598.     gap> E(8) in f;
  2599.     true|
  2600.  
  2601. For every field  extension you  can compute  the  Galois group, i.e., the
  2602. group of automorphisms that  leave the subfield fixed.   For an  example,
  2603. cyclotomic fields are an extension of  the rationals, so  you can compute
  2604. their Galois group over the rationals.
  2605.  
  2606. |    gap> Galf := GaloisGroup( f );
  2607.     Group( NFAutomorphism( CF(8) , 7 ), NFAutomorphism( CF(8) , 5 ) )
  2608.     gap> Size( Galf );
  2609.     4|
  2610.  
  2611. The above cyclotomic field is  a small example where the  galois group is
  2612. not cyclic.
  2613.  
  2614. |    gap> IsCyclic( Galf );
  2615.     false
  2616.     gap> IsAbelian( Galf );
  2617.     true
  2618.     gap> AbelianInvariants( Galf );
  2619.     [ 2, 2 ]|
  2620.  
  2621. This shows us that the 8th  cyclotomic field has a  Galois group which is
  2622. isomorphic to group $V_4$.
  2623.  
  2624. The elements of the Galois group are {\GAP} automorphisms, so they may be
  2625. applied to the elements of the field in the  same way as all mappings are
  2626. usually applied to objects in {\GAP}.
  2627.  
  2628. |    gap> g := Galf.generators[1];
  2629.     NFAutomorphism( CF(8) , 7 )
  2630.     gap> E(8) ^ g;
  2631.     -E(8)^3|
  2632.  
  2633. There are two functions,  'Norm' and 'Trace',  which compute the norm and
  2634. the trace of elements of the field, respectively.  The norm and the trace
  2635. of an element $a$ are defined to be the product and the sum of the images
  2636. of $a$ under the Galois group.  You should usually specify the field as a
  2637. first  argument.   This argument  is  however  optional.  If  you omit  a
  2638. default field will be  used.   For a cyclotomic $a$ this is  the smallest
  2639. cyclotomic field  that contains $a$ (note  that this is not  the smallest
  2640. field that  contains $a$, which may  be  a  number  field  that  is not a
  2641. cyclotomic field).
  2642.  
  2643. |    gap> orb := List( Elements( Galf ), x -> E(8) ^ x );
  2644.     [ E(8), E(8)^3, -E(8), -E(8)^3 ]
  2645.     gap> Sum( orb ) = Trace( f, E(8) );
  2646.     true
  2647.     gap> Product( orb ) = Norm( f, E(8) );
  2648.     true
  2649.     gap> Trace( f, 1 );
  2650.     4|
  2651.  
  2652. The basic  way  to  construct  a finite  field  is to  use  the  function
  2653. 'GaloisField'  which may  be abbreviated, as  usual in algebra,  as 'GF'.
  2654. Thus
  2655.  
  2656. |    gap> k := GF( 3, 4 );
  2657.     GF(3^4)|
  2658.  
  2659. or
  2660.  
  2661. |    gap> k := GaloisField( 81 );
  2662.     GF(3^4)|
  2663.  
  2664. will assign the finite field of order $3^4$ to the variable 'k'.
  2665.  
  2666. In  fact, what  'GF'  does  is to  set  up a  record  which contains  all
  2667. necessary  information,  telling that  it represents  a  finite  field of
  2668. degree 4 over its prime field with  3 elements.  Of course, all arguments
  2669. to 'GF' others than those which represent a  prime power are rejected  --
  2670. for obvious reasons.
  2671.  
  2672. Some of the  more important entries of the field record are 'zero', 'one'
  2673. and 'root',  which hold the corresponding elements  of  the  field.   All
  2674. elements  of  a finite  field  are represented as a certain power  of  an
  2675. appropriate primitive root, which is written as 'Z(<q>)'.  As can be seen
  2676. below the smallest possible primitive root is used.
  2677.  
  2678. |    gap> k.one + k.root + k.root^10 - k.zero;
  2679.     Z(3^4)^52
  2680.     gap> k.root;
  2681.     Z(3^4)
  2682.     gap> k.root ^ 20;
  2683.     Z(3^2)^2
  2684.     gap> k.one;
  2685.     Z(3)^0|
  2686.  
  2687. Note that  of  course  elements from  fields of  different characteristic
  2688. cannot be combined in operations.
  2689.  
  2690. |    gap> Z(3^2) * k.root + k.zero + Z(3^8);
  2691.     Z(3^8)^6534
  2692.     gap> Z(2) * k.one;
  2693.     Error, Finite field *: operands must have the same characteristic|
  2694.  
  2695. In this example we tried to multiply a primitive  root of the  field with
  2696. two  elements  with  the  identity  element  of  the field  'k'.  As  the
  2697. characteristic  of  'k'  equals  3,  there  is  no  way  to  perform  the
  2698. multiplication.  The  first statement of the example shows,  that  if all
  2699. the   elements  of  the  expression   belong   to   fields  of  the  same
  2700. characteristic, the result will be computed.
  2701.  
  2702. As soon as  a primitive  root is demanded,  {\GAP} internally sets up all
  2703. relevant  data  structures   that  are  necessary  to   compute   in  the
  2704. corresponding  finite  field.  Each  finite field  is  constructed  as  a
  2705. splitting field  of a  Conway polynomial.   These polynomials, as a  set,
  2706. have  special  properties  that  make it easy to  embed smaller fields in
  2707. larger ones and to convert the representation of the  elements when doing
  2708. so.  All Conway polynomials for fields  up to an order of 65536 have been
  2709. computed and installed in the {\GAP} kernel.
  2710.  
  2711. But now look at the following example.
  2712.  
  2713. |    gap> Z(3^3) * Z(3^4);
  2714.     Error, Finite field *: smallest common superfield to large|
  2715.  
  2716. Although both factors are elements  of  fields of  characteristic 3,  the
  2717. product can not be evaluated by {\GAP}.  The reason for this is very easy
  2718. to explain\: In order to compute the product, {\GAP} has  to find a field
  2719. in which both of the factors lie.  Here in our example the smallest field
  2720. containing $Z(3^3)$ and  $Z(3^4)$ is $GF(3^12)$, the field with  $531441$
  2721. elements.  As we have mentioned above that the  size of finite  fields in
  2722. {\GAP}  is limited  at present by  $65536$ we  now see  that there  is no
  2723. chance to set up the internal  data structures  for the  common  field to
  2724. perform the computation.
  2725.  
  2726. As before with cyclotomic fields,  the Galois group of a finite field and
  2727. the  norm  and  trace of  its  elements  may  be  computed.  The  calling
  2728. conventions are the same as for cyclotomic fields.
  2729.  
  2730. |    gap> Galk := GaloisGroup( k );
  2731.     Group( FrobeniusAutomorphism( GF(3^4) ) )
  2732.     gap> Size( Galk );
  2733.     4
  2734.     gap> IsCyclic( Galk );
  2735.     true
  2736.     gap> Norm( k, k.root ^ 20 );
  2737.     Z(3)^0
  2738.     gap> Trace( k, k.root ^ 20 );
  2739.     0*Z(3)|
  2740.  
  2741. So far, in our examples, we were always interested in the Galois group of
  2742. a field extension $k$ over its prime field.  In fact it often  will occur
  2743. that, given a subfield $l$  of  $k$ the Galois  group of $k$  over $l$ is
  2744. desired.  In {\GAP} it is possible  to change the structure of a field by
  2745. using the '/' operator.  So typing
  2746.  
  2747. |    gap> l := GF(3^2);
  2748.     GF(3^2)
  2749.     gap> IsSubset( k, l );
  2750.     true
  2751.     gap> k / l;
  2752.     GF(3^4)/GF(3^2)|
  2753.  
  2754. changes the representation of $k$ from a field extension of degree 4 over
  2755. $GF(3)$ to a field given as an extension of degree 2 over $GF(3^2)$.  The
  2756. actual elements of the fields are still the same, only  the  structure of
  2757. the field has changed.
  2758.  
  2759. |    gap> k = k / l;
  2760.     true
  2761.     gap> Galkl := GaloisGroup( k / l );
  2762.     Group( FrobeniusAutomorphism( GF(3^4)/GF(3^2) )^2 )
  2763.     gap> Size( Galkl );
  2764.     2|
  2765.  
  2766. Of course, all the relevant functions behave in a different way when they
  2767. refer to 'k / l' instead of 'k'
  2768.  
  2769. |    gap> Norm( k / l, k.root ^ 20 );
  2770.     Z(3)
  2771.     gap> Trace( k / l, k.root ^ 20 );
  2772.     Z(3^2)^6|
  2773.  
  2774. This feature, to  change  the structure of the field without changing the
  2775. underlying  set  of elements,  is also  available for  cyclotomic fields,
  2776. which we have seen at the beginning of this chapter.
  2777.  
  2778. |    gap> g := CyclotomicField( 4 );
  2779.     GaussianRationals
  2780.     gap> IsSubset( f, g );
  2781.     true
  2782.     gap> f / g;
  2783.     CF(8)/GaussianRationals
  2784.     gap> Galfg := GaloisGroup( f / g );
  2785.     Group( NFAutomorphism( CF(8)/GaussianRationals , 5 ) )
  2786.     gap> Size( Galfg );
  2787.     2|
  2788.  
  2789. The examples should  have shown  that,  although the structure  of finite
  2790. fields and  cyclotomic  fields  is rather different, there  is a  similar
  2791. interface to them in {\GAP},  which  makes it easy to write programs that
  2792. deal with both types of fields in the same way.
  2793.  
  2794. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2795. \Section{About Matrix Groups}
  2796.  
  2797. This section intends to  show you  the  things  you  could do with matrix
  2798. groups in {\GAP}.  In principle all the set theoretic functions mentioned
  2799. in  chapter  "Domains"  and  all  group functions  mentioned  in  chapter
  2800. "Groups" can be applied to matrix groups.   However, you should note that
  2801. at  present only  very few  functions can  work  efficiently  with matrix
  2802. groups.   Especially  infinite  matrix  groups  (over  the  rationals  or
  2803. cyclotomic fields) can not be dealt with at all.
  2804.  
  2805. Matrix groups  are created in the same  way as the other types of groups,
  2806. by using the function 'Group'.  Of  course,  in this case  the  arguments
  2807. have to be invertable matrices over a field.
  2808.  
  2809. |    gap> m1 := [ [ Z(3)^0, Z(3)^0, Z(3) ],
  2810.     >             [ Z(3), 0*Z(3), Z(3) ],
  2811.     >             [ 0*Z(3), Z(3), 0*Z(3) ] ];;
  2812.     gap> m2 := [ [ Z(3), Z(3), Z(3)^0 ],
  2813.     >            [ Z(3), 0*Z(3), Z(3) ],
  2814.     >            [ Z(3)^0, 0*Z(3), Z(3) ] ];;
  2815.     gap> m := Group( m1, m2 );
  2816.     Group( [ [ Z(3)^0, Z(3)^0, Z(3) ], [ Z(3), 0*Z(3), Z(3) ],
  2817.       [ 0*Z(3), Z(3), 0*Z(3) ] ],
  2818.     [ [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ],
  2819.       [ Z(3)^0, 0*Z(3), Z(3) ] ] )|
  2820.  
  2821. As  usual for  groups,  the matrix  group  that  we  have  constructed is
  2822. represented  by  a record with several entries.  For matrix groups, there
  2823. is one additional entry which holds the field over which the matrix group
  2824. is written.
  2825.  
  2826. |    gap> m.field;
  2827.     GF(3)|
  2828.  
  2829. Note that  you  do not specify  the field  when you construct the  group.
  2830. 'Group'  automatically  takes  the  smallest field  over  which  all  its
  2831. arguments can be written.
  2832.  
  2833. At this point there is the question what  special functions are available
  2834. for matrix groups.  The size of our group, for  example, may  be computed
  2835. using the function 'Size'.
  2836.  
  2837. |    gap> Size( m );
  2838.     864|
  2839.  
  2840. If we now compute the size of the corresponding general linear group
  2841.  
  2842. |    gap> (3^3 - 3^0) * (3^3 - 3^1) * (3^3 - 3^2);
  2843.     11232|
  2844.  
  2845. we  see that  we have  constructed  a  proper subgroup  of  index  13  of
  2846. $GL(3,3)$.
  2847.  
  2848. Let  us now set  up a subgroup of  'm', which  is generated by the matrix
  2849. 'm2'.
  2850.  
  2851. |    gap> n := Subgroup( m, [ m2 ] );
  2852.     Subgroup( Group( [ [ Z(3)^0, Z(3)^0, Z(3) ], [ Z(3), 0*Z(3), Z(3) ],
  2853.       [ 0*Z(3), Z(3), 0*Z(3) ] ],
  2854.     [ [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ],
  2855.       [ Z(3)^0, 0*Z(3), Z(3) ] ] ),
  2856.     [ [ [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ],
  2857.           [ Z(3)^0, 0*Z(3), Z(3) ] ] ] )
  2858.     gap> Size( n );
  2859.     6|
  2860.  
  2861. And  to round up  this  example we now  compute the  centralizer  of this
  2862. subgroup in 'm'.
  2863.  
  2864. |    gap> c := Centralizer( m, n );
  2865.     Subgroup( Group( [ [ Z(3)^0, Z(3)^0, Z(3) ], [ Z(3), 0*Z(3), Z(3) ],
  2866.       [ 0*Z(3), Z(3), 0*Z(3) ] ],
  2867.     [ [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ],
  2868.       [ Z(3)^0, 0*Z(3), Z(3) ] ] ),
  2869.     [ [ [ Z(3), Z(3), Z(3)^0 ], [ Z(3), 0*Z(3), Z(3) ],
  2870.           [ Z(3)^0, 0*Z(3), Z(3) ] ],
  2871.       [ [ Z(3), 0*Z(3), 0*Z(3) ], [ 0*Z(3), Z(3), 0*Z(3) ],
  2872.           [ 0*Z(3), 0*Z(3), Z(3) ] ] ] )
  2873.     gap> Size( c );
  2874.     12|
  2875.  
  2876. In this section you have seen  that matrix groups  are constructed in the
  2877. same way that all groups are constructed.  You have also been warned that
  2878. only very few  functions  can work efficiently with matrix  groups.   See
  2879. chapter "Matrix Groups" to read more about matrix groups.
  2880.  
  2881. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2882. \Section{About Domains and Categories}
  2883.  
  2884. *Domain* is {\GAP}\'s name for structured sets.  We already saw  examples
  2885. of  domains in  the previous sections.  For example, the groups 's8'  and
  2886. 'a8' in sections  "About  Groups" and  "About  Operations of  Groups" are
  2887. domains.  Likewise the  fields  in section  "About Fields"  are  domains.
  2888. *Categories*  are  sets  of domains.  For example,  the set of all groups
  2889. forms a category, as does the set of all fields.
  2890.  
  2891. In those sections we  treated the domains   as  black boxes.    They were
  2892. constructed by  special functions such as 'Group'  and 'GaloisField', and
  2893. they could be passed as arguments to  other functions such  as 'Size' and
  2894. 'Orbits'.
  2895.  
  2896. In this section we  will also treat  domains  as  black  boxes.   We will
  2897. describe  how  domains are  created  in general and  what  functions  are
  2898. applicable to all domains.  Next we will  show how  domains with the same
  2899. structure are grouped into categories  and will give an  overview of  the
  2900. categories that are available.  Then we will discuss how the organization
  2901. of the {\GAP}  library around the concept  of  domains and  categories is
  2902. reflected in  this manual.  In a  later section  we will open  the  black
  2903. boxes and give an overview of the mechanism that makes all this work (see
  2904. "About the Implementation of Domains").
  2905.  
  2906. The  first thing you must know  is how you can  obtain domains.  You have
  2907. basically  three  possibilities.   You  can use    the domains   that are
  2908. predefined in  the  library,  you can create   new  domains  with  domain
  2909. constructors,  and  you can  use  the  domains  returned by  many library
  2910. functions.  We will now discuss those three possibilities in turn.
  2911.  
  2912. The {\GAP} library predefines some  domains.  That means that there  is a
  2913. global variable whose value is  this domain.  The following example shows
  2914. some of the more important predefined domains.
  2915.  
  2916. |    gap> Integers;
  2917.     Integers    # the ring of all integers
  2918.     gap> Size( Integers );
  2919.     "infinity"
  2920.     gap> GaussianRationals;
  2921.     GaussianRationals    # the field of all Gaussian 
  2922.     gap> (1/2+E(4)) in GaussianRationals;
  2923.     true    # 'E(4)' is {\GAP}\'s name for the complex root of -1
  2924.     gap> Permutations;
  2925.     Permutations    # the domain of all permutations |
  2926.  
  2927. Note that  {\GAP}  prints  those domains   using the  name  of the global
  2928. variable.
  2929.  
  2930. You can create  new domains  using *domain constructors* such as 'Group',
  2931. 'Field', etc.   A domain constructor is a  function that  takes a certain
  2932. number of arguments and returns the domain described by  those arguments.
  2933. For example, 'Group' takes an arbitrary number of  group elements (of the
  2934. same type) and returns the group generated by those elements.
  2935.  
  2936. |    gap> gf16 := GaloisField( 16 );
  2937.     GF(2^4)    # the finite field with 16 elements
  2938.     gap> Intersection( gf16, GaloisField( 64 ) );
  2939.     GF(2^2)    
  2940.     gap> a5 := Group( (1,2,3), (3,4,5) );
  2941.     Group( (1,2,3), (3,4,5) )    # the alternating group on 5 points
  2942.     gap> Size( a5 );
  2943.     60 |
  2944.  
  2945. Again {\GAP} prints those domains using more or less the expression that
  2946. you entered to obtain the domain.
  2947.  
  2948. As  with  groups  (see  "About  Groups") a  name can  be assigned  to  an
  2949. arbitrary domain <D> with the assignment '<D> \:= <string>;',  and {\GAP}
  2950. will use this name from then on in the output.
  2951.  
  2952. Many functions in the {\GAP} library return domains.  In the last example
  2953. you already  saw that   'Intersection'  returned a finite  field  domain.
  2954. Below are more examples.
  2955.  
  2956. |    gap> GaloisGroup( gf16 );
  2957.     Group( FrobeniusAutomorphism( GF(2^4) ) )
  2958.     gap> SylowSubgroup( a5, 2 );
  2959.     Subgroup( Group( (1,2,3), (3,4,5) ), [ (2,5)(3,4), (2,3)(4,5) ] ) |
  2960.  
  2961. The distinction between domain  constructors  and functions  that  return
  2962. domains is  a little  bit arbitrary.   It  is also not important  for the
  2963. understanding of what  follows.  If you are nevertheless interested, here
  2964. are the  principal differences.   A constructor  performs no computation,
  2965. while  a function  performs  a more  or less complicated computation.   A
  2966. constructor creates  the representation of the domain,  while a  function
  2967. relies on a constructor to create  the domain.   A constructor  knows the
  2968. dirty  details  of the domain\'s  representation, while a function may be
  2969. independent of the domain\'s representation.  A constructor may appear as
  2970. printed representation of a domain, while a function usually does not.
  2971.  
  2972. After showing how domains are created, we will now  discuss what  you can
  2973. do with  domains.   You  can assign  a domain to a variable, put a domain
  2974. into a list or into  a  record, pass a domain  as argument to a function,
  2975. and return a  domain as result of a function.  In this regard there is no
  2976. difference  between  an integer  value such as 17 and  a  domain such  as
  2977. 'Group( (1,2,3),  (3,4,5) )'.  Of  course  many functions  will signal an
  2978. error when  you call them with domains  as arguments.  For example, 'Gcd'
  2979. does not accept two groups as arguments, because they lie in no Euclidean
  2980. ring.
  2981.  
  2982. There  are  some functions  that  accept domains of  any  type  as  their
  2983. arguments.  Those functions  are called the  *set  theoretic  functions*.
  2984. The full list of set theoretic functions is given in chapter "Domains".
  2985.  
  2986. Above we already used one of those functions, namely 'Size'.  If you look
  2987. back you will see that we applied 'Size'  to the domain 'Integers', which
  2988. is a ring, and the domain 'a5', which is a group.  Remember that a domain
  2989. was a structured set.   The size of the domain  is the number of elements
  2990. in the set.  'Size' returns  this number or  the string '\"infinity\"' if
  2991. the domain  is infinite.  Below are more examples.
  2992.  
  2993. |    gap> Size( GaussianRationals );
  2994.     "infinity"    # this string is returned for infinite domains
  2995.     gap> Size( SylowSubgroup( a5, 2 ) );
  2996.     4 |
  2997.  
  2998. 'IsFinite( <D> )' returns 'true' if the domain <D> is  finite and 'false'
  2999. otherwise.  You could also test if a domain  is finite using 'Size( <D> )
  3000. \<\ \"infinity\"' ({\GAP} evaluates '<n> \<\  \"infinity\"' to 'true' for
  3001. any number <n>).  'IsFinite' is more efficient.  For example, if <D> is a
  3002. permutation group, 'IsFinite( <D> )' can immediately return 'true', while
  3003. 'Size( <D> )' may take quite a while to compute the size of <D>.
  3004.  
  3005. The other function  that you already  saw  is  'Intersection'.  Above  we
  3006. computed the intersection  of the field  with  16 elements  and the field
  3007. with 64 elements.  The following example is similar.
  3008.  
  3009. |    gap> Intersection( a5, Group( (1,2), (1,2,3,4) ) );
  3010.     Group( (2,3,4), (1,2)(3,4) )    # alternating group on 4 points |
  3011.  
  3012. In general 'Intersection' tries to return a domain.  In  general  this is
  3013. not possible  however.  Remember that a  domain is  a structured set.  If
  3014. the two domain arguments have different  structure  the  intersection may
  3015. not have any  structure at all.   In this case 'Intersection' returns the
  3016. result  as a   proper set, i.e.,  as   a sorted list  without holes   and
  3017. duplicates.  The following example shows  such a case.   'ConjugacyClass'
  3018. returns the conjugacy class of '(1,2,3,4,5)' in  the alternating group on
  3019. 6 points as  a domain.  If  we  intersect this  class  with the symmetric
  3020. group on  5 points we obtain a  proper set of  12 permutations,  which is
  3021. only one half of the conjugacy class of 5 cycles in 's5'.
  3022.  
  3023. |    gap> a6 := Group( (1,2,3), (2,3,4,5,6) );
  3024.     Group( (1,2,3), (2,3,4,5,6) )
  3025.     gap> class := ConjugacyClass( a6, (1,2,3,4,5) );
  3026.     ConjugacyClass( Group( (1,2,3), (2,3,4,5,6) ), (1,2,3,4,5) )
  3027.     gap> Size( class );
  3028.     72
  3029.     gap> s5 := Group( (1,2), (2,3,4,5) );
  3030.     Group( (1,2), (2,3,4,5) )
  3031.     gap> Intersection( class, s5 );
  3032.     [ (1,2,3,4,5), (1,2,4,5,3), (1,2,5,3,4), (1,3,5,4,2), (1,3,2,5,4), 
  3033.       (1,3,4,2,5), (1,4,3,5,2), (1,4,5,2,3), (1,4,2,3,5), (1,5,4,3,2), 
  3034.       (1,5,2,4,3), (1,5,3,2,4) ] |
  3035.  
  3036. You can intersect arbitrary domains as the following example shows.
  3037.  
  3038. |    gap> Intersection( Integers, a5 );
  3039.     [  ]    # the empty set |
  3040.  
  3041. Note  that we optimized 'Intersection' for typical cases, e.g., computing
  3042. the intersection  of two permutation  groups, etc.  The above computation
  3043. is  done with  a  very  simple--minded  method, all elements of  'a5' are
  3044. listed  (with   'Elements',  described  below),  and   for  each  element
  3045. 'Intersection' tests  whether it lies in 'Integers' (with 'in', described
  3046. below).   So the same computation with the alternating group on 10 points
  3047. instead of 'a5' will probably exhaust your patience.
  3048.  
  3049. Just as 'Intersection' returns a proper set occasionally, it also accepts
  3050. proper sets as arguments.  'Intersection' also takes  an arbitrary number
  3051. of arguments.  And finally it also accepts  a list of  domains or sets to
  3052. intersect as single argument.
  3053.  
  3054. |    gap> Intersection( a5, [ (1,2), (1,2,3), (1,2,3,4), (1,2,3,4,5) ] );
  3055.     [ (1,2,3), (1,2,3,4,5) ]
  3056.     gap> Intersection( [2,4,6,8,10], [3,6,9,12,15], [5,10,15,20,25] );
  3057.     [  ]
  3058.     gap> Intersection( [ [1,2,4], [2,3,4], [1,3,4] ] );
  3059.     [ 4 ] |
  3060.  
  3061. The function 'Union' is the obvious counterpart of 'Intersection'.   Note
  3062. that 'Union' usually does *not*  return  a domain.  This  is because  the
  3063. union  of  two  domains, even  of the same type,  is usually not  again a
  3064. domain  of that type.  For example,  the  union  of  two  subgroups  is a
  3065. subgroup if  and only if  one of the subgroups is  a subset of the other.
  3066. Of course this is  exactly the reason  why 'Union' is less important than
  3067. 'Intersection' in algebra.
  3068.  
  3069. Because  domains  are structured sets there ought to be a membership test
  3070. that tests whether an  object lies in this domain  or  not.  This is  not
  3071. implemented by a function, instead the operator 'in' is used.   '<elm> in
  3072. <D>' returns  'true' if the  element  <elm> lies  in the domain  <D>  and
  3073. 'false'  otherwise.   We  already used  the 'in'  operator above  when we
  3074. tested whether '1/2 + E(4)' lies in the domain of Gaussian integers.
  3075.  
  3076. |    gap> (1,2,3) in a5;
  3077.     true
  3078.     gap> (1,2) in a5;
  3079.     false
  3080.     gap> (1,2,3,4,5,6,7) in a5;
  3081.     false
  3082.     gap> 17 in a5;
  3083.     false    # of course an integer does not lie in a permutation group
  3084.     gap> a5 in a5;
  3085.     false |
  3086.  
  3087. As  you can see in the last example, 'in' only implements the  membership
  3088. test.  It does not  allow you to test  whether  a  domain is a subset  of
  3089. another domain.  For such tests the function 'IsSubset' is available.
  3090.  
  3091. |    gap> IsSubset( a5, a5 );
  3092.     true
  3093.     gap> IsSubset( a5, Group( (1,2,3) ) );
  3094.     true
  3095.     gap> IsSubset( Group( (1,2,3) ), a5 );
  3096.     false |
  3097.  
  3098. In the above example you can see that 'IsSubset' tests whether the second
  3099. argument is a  subset  of the first  argument.  As a  general rule {\GAP}
  3100. library functions  take as  *first* arguments those arguments that are in
  3101. some sense *larger* or more structured.
  3102.  
  3103. Suppose  that  you  want  to loop over all  elements  of  a domain.   For
  3104. example, suppose  that  you want to compute  the set of element orders of
  3105. elements in the group 'a5'.  To use  the 'for'  loop you  need  a list of
  3106. elements in the domain <D>, because 'for <var> in <D> do <statements> od'
  3107. will not work.  The function 'Elements'  does  exactly that.  It takes  a
  3108. domain <D> and returns the proper set of elements of <D>.
  3109.  
  3110. |    gap> Elements( Group( (1,2,3), (2,3,4) ) );
  3111.     [ (), (2,3,4), (2,4,3), (1,2)(3,4), (1,2,3), (1,2,4), (1,3,2),
  3112.       (1,3,4), (1,3)(2,4), (1,4,2), (1,4,3), (1,4)(2,3) ]
  3113.     gap> ords := [];;
  3114.     gap> for elm  in Elements( a5 )  do
  3115.     >        Add( ords, Order( a5, elm ) );
  3116.     >    od;
  3117.     gap> Set( ords );
  3118.     [ 1, 2, 3, 5 ]
  3119.     gap> Set( List( Elements( a5 ), elm -> Order( a5, elm ) ) );
  3120.     [ 1, 2, 3, 5 ]    # an easier way to compute the set of orders |
  3121.  
  3122. Of course, if you apply 'Elements' to an infinite domain, 'Elements' will
  3123. signal an error.  It is also not a good  idea to apply 'Elements' to very
  3124. large domains  because  the  list of  elements will  take  much space and
  3125. computing this large list will probably exhaust your patience.
  3126.  
  3127. |    gap> Elements( GaussianIntegers );
  3128.     Error, the ring <R> must be finite to compute its elements in
  3129.     D.operations.Elements( D ) called from
  3130.     Elements( GaussianIntegers ) called from
  3131.     main loop
  3132.     brk> quit;|
  3133.  
  3134. There are a  few more set theoretic functions.  See chapter "Domains" for
  3135. a complete list.
  3136.  
  3137. All  the  set theoretic functions treat  the  domains  as if they  had no
  3138. structure.  Now  a domain is  a  structured  set (excuse us for repeating
  3139. this again and again, but it is really important to get this across).  If
  3140. the functions  ignore the structure than they  are  effectively viewing a
  3141. domain only as the set of elements.
  3142.  
  3143. In fact all set theoretic functions also accept proper sets, i.e., sorted
  3144. lists  without holes and duplicates as arguments  (we  already  mentioned
  3145. this for 'Intersection').  Also set theoretic functions may  occasionally
  3146. return proper sets instead of domains as result.
  3147.  
  3148. This equivalence  of  a domain  and its  set of elements is  particularly
  3149. important for the definition of equality of domains.  Two domains <D> and
  3150. <E> are equal (in the sense that '<D>  = <E>' evaluates to 'true') if and
  3151. only if the set of elements of <D> is equal to the set of elements of <E>
  3152. (as returned by 'Elements(  <D> )' and 'Elements( <E> )').   As a special
  3153. case either  of  the  operands of '='  may also be a proper set,  and the
  3154. value  is  'true' if  this set  is equal  to the  set of elements of  the
  3155. domain.
  3156.  
  3157. |    gap> a4 := Group( (1,2,3), (2,3,4) );
  3158.     Group( (1,2,3), (2,3,4) )
  3159.     gap> elms := Elements( a4 );
  3160.     [ (), (2,3,4), (2,4,3), (1,2)(3,4), (1,2,3), (1,2,4), (1,3,2),
  3161.       (1,3,4), (1,3)(2,4), (1,4,2), (1,4,3), (1,4)(2,3) ]
  3162.     gap> elms = a4;
  3163.     true |
  3164.  
  3165. However the  following example shows  that this does not  imply  that all
  3166. functions  return  the same  answer  for two  domains (or a domain  and a
  3167. proper set) that are equal.   This is because those function may take the
  3168. structure into account.
  3169.  
  3170. |    gap> IsGroup( a4 );
  3171.     true
  3172.     gap> IsGroup( elms );
  3173.     false
  3174.     gap> Intersection( a4, Group( (1,2), (1,2,3) ) );
  3175.     Group( (1,2,3) )
  3176.     gap> Intersection( elms, Group( (1,2), (1,2,3) ) );
  3177.     [ (), (1,2,3), (1,3,2) ]    # this is not a group
  3178.     gap> last = last2;
  3179.     true                        # but it is equal to the above result
  3180.     gap> Centre( a4 );
  3181.     Subgroup( Group( (1,2,3), (2,3,4) ), [  ] )
  3182.     gap> Centre( elms );
  3183.     Error, <G> must be a group in
  3184.     Centre( elms ) called from
  3185.     main loop
  3186.     brk> quit;|
  3187.  
  3188. Generally three  things  may  happen if you have two domains <D>  and <E>
  3189. that are equal but have different structure (or a  domain <D>  and a  set
  3190. <E> that are equal).  First a  function that tests whether a domain has a
  3191. certain structure may return 'true' for <D> and 'false' for <E>.   Second
  3192. a function may return a domain for <D> and a proper set for <E>.  Third a
  3193. function may work  for  <D> and fail for  <E>,  because  it  requires the
  3194. structure.
  3195.  
  3196. A slightly more complex example for the second case is the following.
  3197.  
  3198. |    gap> v4 := Subgroup( a4, [ (1,2)(3,4), (1,3)(2,4) ] );
  3199.     Subgroup( Group( (1,2,3), (2,3,4) ), [ (1,2)(3,4), (1,3)(2,4) ] )
  3200.     gap> v4.name := "v4";;
  3201.     gap> rc := v4 * (1,2,3);
  3202.     (v4*(2,4,3))
  3203.     gap> lc := (1,2,3) * v4;
  3204.     ((1,2,3)*v4)
  3205.     gap> rc = lc;
  3206.     true
  3207.     gap> rc * (1,3,2);
  3208.     (v4*())
  3209.     gap> lc * (1,3,2);
  3210.     [ (1,3)(2,4), (), (1,2)(3,4), (1,4)(2,3) ]
  3211.     gap> last = last2;
  3212.     false |
  3213.  
  3214. The two  domains 'rc'  and 'lc'  (yes, cosets are domains too) are equal,
  3215. because they have the same set of elements.  However if we multiply  both
  3216. with '(1,3,2)' we obtain the trivial right coset for 'rc' and  a list for
  3217. 'lc'.   The  result for  'lc' is *not* a proper  set,  because it  is not
  3218. sorted,  therefore '='  evaluates to 'false'.   (For  the  curious.   The
  3219. multiplication  of  a  left coset  with  an element  from the right  will
  3220. generally not  yield  another  coset, i.e.,  nothing that  can easily  be
  3221. represented as a domain.   Thus  to  multiply 'lc' with '(1,3,2)'  {\GAP}
  3222. first converts 'lc' to the set  of its elements with 'Elements'.  But the
  3223. definition of multiplication  requires that a list <l>  multiplied  by an
  3224. element <e>  yields a new  list <n> such that each  element '<n>[<i>]' in
  3225. the new list is  the  product  of the  element  '<l>[<i>]'  at  the *same
  3226. position* of the operand list <l> with <e>.)
  3227.  
  3228. Note  that the  above  definition only defines  *what* the result  of the
  3229. equality comparison of two domains  <D> and <E>  should be.  It  does not
  3230. prescribe  that  this comparison  is actually performed  by  listing  all
  3231. elements  of  <D> and <E>.  For example, if <D> and <E> are groups, it is
  3232. sufficient to  check that  all generators of <D>  lie in <E> and that all
  3233. generators of <E> lie  in  <D>.  If {\GAP} would really compute the whole
  3234. set  of  elements, the  following  test could  not  be  performed  on any
  3235. computer.
  3236.  
  3237. |    gap> Group( (1,2), (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) )
  3238.     > = Group( (17,18), (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) );
  3239.     true |
  3240.  
  3241. If we could only  apply the set theoretic  functions to domains,  domains
  3242. would be of little use.  Luckily this is not so.  We already  saw that we
  3243. could  apply 'GaloisGroup' to  the  finite  field  with  16 elements, and
  3244. 'SylowSubgroup'  to   the  group  'a5'.   But  those  functions  are  not
  3245. applicable  to  all  domains.   The  argument of 'GaloisGroup' must be  a
  3246. field, and the argument of 'SylowSubgroup' must be a group.
  3247.  
  3248. A *category*  is a  set of  domains.   So we  say  that the  argument  of
  3249. 'GaloisGroup'  must  be  an element of  the  category  of fields, and the
  3250. argument of 'SylowSubgroup' must be an element of the category of groups.
  3251. The  most important  categories  are  *rings*,  *fields*,  *groups*,  and
  3252. *vector spaces*.    Which category  a domain belongs to determines  which
  3253. functions are  applicable  to this  domain and its elements.  We  want to
  3254. emphasize the each  domain belongs to *one and only  one* category.  This
  3255. is necessary  because domains  in  different categories  have,  sometimes
  3256. incompatible, representations.
  3257.  
  3258. Note that the categories only  exist conceptually.  That means that there
  3259. is  no  {\GAP}  object  for the  categories, e.g.,  there  is  no  object
  3260. 'Groups'.  For each category there exists a function that tests whether a
  3261. domain is an element of this category.
  3262.  
  3263. |    gap> IsRing( gf16 );
  3264.     false
  3265.     gap> IsField( gf16 );
  3266.     true
  3267.     gap> IsGroup( gf16 );
  3268.     false
  3269.     gap> IsVectorSpace( gf16 );
  3270.     false |
  3271.  
  3272. Note that of course mathematically the field 'gf16' is also a ring  and a
  3273. vector space.   However in  {\GAP}  a  domain  can  only  belong  to  one
  3274. category.   So  a domain is  conceptually  a set  of elements  with *one*
  3275. structure, e.g.,  a field  structure.  That  the same set of elements may
  3276. also  support  a  different structure,  e.g.,  a  ring  or  vector  space
  3277. structure,  can  not  be represented  by  this  domain.  So  you  need  a
  3278. different domain to represent this different structure.  (We are planning
  3279. to add functions that changes the  structure of  a domain, e.g.  'AsRing(
  3280. <field>  )' should return  a new domain with the same elements as <field>
  3281. but with a ring structure.)
  3282.  
  3283. Domains  may  have  certain  properties.   For  example  a  ring  may  be
  3284. commutative and a group may be nilpotent.  Whether a domain has a certain
  3285. property <Property> can be tested with the function 'Is<Property>'.
  3286.  
  3287. |    gap> IsCommutativeRing( GaussianIntegers );
  3288.     true
  3289.     gap> IsNilpotent( a5 );
  3290.     false |
  3291.  
  3292. There are also similar functions that test whether a domain (especially a
  3293. group) is represented in a certain way.  For example 'IsPermGroup'  tests
  3294. whether a group is represented as a permutation group.
  3295.  
  3296. |    gap> IsPermGroup( a5 );
  3297.     true
  3298.     gap> IsPermGroup( a4 / v4 );
  3299.     false    # 'a4 / v4' is represented as a generic factor group |
  3300.  
  3301. There is a slight difference between a function such as 'IsNilpotent' and
  3302. a function such  as 'IsPermGroup'.  The  former  tests  properties  of an
  3303. *abstract* group and its outcome is independent of the representation  of
  3304. that  group.  The  latter tests whether  a  group  is given in  a certain
  3305. representation.
  3306.  
  3307. This (rather philosophical) issue is further complicated by the fact that
  3308. sometimes  representations and properties are  not independent.  This  is
  3309. especially  subtle with 'IsSolvable' (see  "IsSolvable")  and 'IsAgGroup'
  3310. (see "IsAgGroup").  'IsSolvable' tests whether a group  <G>  is solvable.
  3311. 'IsAgGroup'  tests  whether  a  group  <G>  is  represented  as  a finite
  3312. polycyclic  group,  i.e.,  by  a  finite  presentation  that  allows   to
  3313. efficiently compute  canonical  normal forms  of  elements  (see  "Finite
  3314. Polycyclic  Groups").   Of   course  every  finite  polycyclic  group  is
  3315. solvable, so 'IsAgGroup(  <G> )'  implies 'IsSolvable( <G>  )'.   On  the
  3316. other  hand  'IsSolvable(  <G>  )'  does  not  imply 'IsAgGroup( <G>  )',
  3317. because, even though each solvable group *can* be represented as a finite
  3318. polycyclic group, it *need* not, e.g., it could also be represented  as a
  3319. permutation group.
  3320.  
  3321. The organization  of the  manual  follows the  structure  of  domains and
  3322. categories.
  3323.  
  3324. After  the  description  of the programming language and  the environment
  3325. chapter "Domains" describes the  domains and the  functions applicable to
  3326. all domains.
  3327.  
  3328. Next  come  the  chapters  that describe  the  categories  rings, fields,
  3329. groups, and vector  spaces.
  3330.  
  3331. The remaining chapters describe {\GAP}\'s data--types and the domains one
  3332. can  make with  those  elements of those data-types.   The order of those
  3333. chapters roughly follows the  order  of the categories.   The data--types
  3334. whose elements  form  rings and fields  come  first  (e.g.,  integers and
  3335. finite  fields), followed  by those  whose  elements  form  groups (e.g.,
  3336. permutations),  and so on.  The data--types whose elements support little
  3337. or  no  algebraic structure come last (e.g.,  booleans  and strings).  In
  3338. some cases there may be  two  chapters for one data--type, one describing
  3339. the  elements and the  other  describing  the  domains  made  with  those
  3340. elements (e.g., permutations and permutation groups).
  3341.  
  3342. The {\GAP} manual  not only describes what you can do, it also gives some
  3343. hints how {\GAP} performs its computations.  However, it can be tricky to
  3344. find those hints.  The index of this manual can help you.
  3345.  
  3346. Suppose that you want to intersect  two  permutation groups.  If you read
  3347. the   section   that   describes   the   function   'Intersection'   (see
  3348. "Intersection")  you  will see  that  the last  paragraph  describes  the
  3349. default  method  used  by 'Intersection'.   Such  a last  paragraph  that
  3350. describes  the  default method is  rather  typical.  In this case it says
  3351. that  'Intersection' computes the proper  set of elements of both domains
  3352. and intersect  them.   It also says that  this method is often   overlaid
  3353. with a more efficient  one.  You wonder whether  this  is  the  case  for
  3354. permutation groups.  How can you  find out?   Well you  look in the index
  3355. under *Intersection*.  There you will find a reference *Intersection, for
  3356. permutation groups* to  section  *Set Functions  for Permutation  Groups*
  3357. (see  "Set Functions  for  Permutation Groups").  This  section tells you
  3358. that 'Intersection' uses a backtrack for permutation groups (and cites  a
  3359. book where you can find a description of the backtrack).
  3360.  
  3361. Let us  now suppose that  you intersect two  factor groups.  There  is no
  3362. reference in the index for *Intersection,  for factor groups*.  But there
  3363. is  a  reference  for  *Intersection, for  groups*  to  the  section *Set
  3364. Functions  for  Groups* (see "Set  Functions for Groups").  Since this is
  3365. the next best thing, look there.  This section further directs you to the
  3366. section *Intersection for Groups* (see  "Intersection for Groups").  This
  3367. section finally  tells you that  'Intersection' computes the intersection
  3368. of two groups <G> and  <H> as the stabilizer in <G> of the trivial  coset
  3369. of <H> under the operation of <G> on the right cosets of <H>.
  3370.  
  3371. In this section we  introduced domains and categories.  You have  learned
  3372. that  a  domain  is  a  structured  set,  and  that  domains  are  either
  3373. predefined,  created  by  domain  constructors,  or returned  by  library
  3374. functions.   You  have  seen  most  functions that are applicable  to all
  3375. domains.   Those functions generally  ignore  the structure  and  treat a
  3376. domain as the set of  its elements.  You have learned that categories are
  3377. sets of domains,  and that  the category a  domain belongs  to determines
  3378. which functions are applicable to this domain.
  3379.  
  3380. More  information  about domains  can  be  found  in  chapter  "Domains".
  3381. Chapters "Rings",  "Fields",  "Groups", and  "Vector  Spaces" define  the
  3382. categories known to {\GAP}.   The section  "About  the  Implementation of
  3383. Domains" opens that black boxes and shows how all this works.
  3384.  
  3385. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3386. \Section{About Mappings and Homomorphisms}
  3387.  
  3388. A mapping is an  object which maps each element of its source to a  value
  3389. in its  range.  Source and  range can be arbitrary sets of elements.  But
  3390. in  most applications the source  and range are  structured sets  and the
  3391. mapping,  in  such applications  called homomorphism, is  compatible with
  3392. this structure.
  3393.  
  3394. In  the  last  sections  you  have   already  encountered   examples   of
  3395. homomorphisms, namely  natural homomorphisms of groups onto their  factor
  3396. groups and operation homomorphisms of groups into symmetric groups.
  3397.  
  3398. Finite fields also bear a structure and homomorphisms between  fields are
  3399. always  bijections.  The  galois group of a finite field is  generated by
  3400. the Frobenius automorphism.  It is very easy to construct.
  3401.  
  3402. |    gap> f := FrobeniusAutomorphism( GF(81) );
  3403.     FrobeniusAutomorphism( GF(3^4) )
  3404.     gap> Image( f, Z(3^4) );
  3405.     Z(3^4)^3
  3406.     gap> A := Group( f );
  3407.     Group( FrobeniusAutomorphism( GF(3^4) ) )
  3408.     gap> Size( A );
  3409.     4
  3410.     gap> IsCyclic( A );
  3411.     true
  3412.     gap> Order( Mappings, f );
  3413.     4
  3414.     gap> Kernel( f );
  3415.     [ 0*Z(3) ] |
  3416.  
  3417. For  finite fields and cyclotomic fields the function 'GaloisGroup' is an
  3418. easy way to construct the galois group.
  3419.  
  3420. |    gap> GaloisGroup( GF(81) );
  3421.     Group( FrobeniusAutomorphism( GF(3^4) ) )
  3422.     gap> Size( last );
  3423.     4
  3424.     gap> GaloisGroup( CyclotomicField( 18 ) );
  3425.     Group( NFAutomorphism( CF(9) , 2 ) )
  3426.     gap> Size( last );
  3427.     6 |
  3428.  
  3429. Not  all  group   homomorphisms   are   bijections   of  course,  natural
  3430. homomorphisms do have a kernel in  most cases and operation homomorphisms
  3431. need neither be surjective nor injective.
  3432.  
  3433. |    gap> s4 := Group( (1,2,3,4), (1,2) );
  3434.     Group( (1,2,3,4), (1,2) )
  3435.     gap> s4.name := "s4";;
  3436.     gap> v4 := Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] );
  3437.     Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] )
  3438.     gap> v4.name := "v4";;
  3439.     gap> s3 := s4 / v4;
  3440.     (s4 / v4)
  3441.     gap> f := NaturalHomomorphism( s4, s3 );
  3442.     NaturalHomomorphism( s4, (s4 / v4) )
  3443.     gap> IsHomomorphism( f );
  3444.     true
  3445.     gap> IsEpimorphism( f );
  3446.     true
  3447.     gap> Image( f ); 
  3448.     (s4 / v4)
  3449.     gap> IsMonomorphism( f );
  3450.     false
  3451.     gap> Kernel( f );
  3452.     v4 |
  3453.  
  3454. The image of a group homomorphism is always one element of the range  but
  3455. the preimage can be a coset.  In order to  get one representative of this
  3456. coset you can use the function 'PreImagesRepresentative'.
  3457.  
  3458. |    gap> Image( f, (1,2,3,4) ); 
  3459.     FactorGroupElement( v4, (2,4) )
  3460.     gap> PreImages( f, s3.generators[1] );
  3461.     (v4*(2,4))
  3462.     gap> PreImagesRepresentative( f, s3.generators[1] );  
  3463.     (2,4) |
  3464.  
  3465. But even if the homomorphism is a monomorphism but not surjective you can
  3466. use the  function 'PreImagesRepresentative' in  order to get the preimage
  3467. of an element of the range.
  3468.  
  3469. |    gap> A := Z(3) * [ [ 0, 1 ], [ 1, 0 ] ];;
  3470.     gap> B := Z(3) * [ [ 0, 1 ], [ -1, 0 ] ];;
  3471.     gap> G := Group( A, B );
  3472.     Group( [ [ 0*Z(3), Z(3) ], [ Z(3), 0*Z(3) ] ], 
  3473.     [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ] )
  3474.     gap> Size( G );
  3475.     8
  3476.     gap> G.name := "G";;
  3477.     gap> d8 := Operation( G, Orbit( G, Z(3)*[1,0] ) );
  3478.     Group( (1,2)(3,4), (1,2,3,4) )
  3479.     gap> e := OperationHomomorphism( Subgroup( G, [B] ), d8 );
  3480.     OperationHomomorphism( Subgroup( G, 
  3481.     [ [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ] ] ), Group( (1,2)(3,4), 
  3482.     (1,2,3,4) ) )
  3483.     gap> Kernel( e );
  3484.     Subgroup( G, [  ] )
  3485.     gap> IsSurjective( e );
  3486.     false
  3487.     gap> PreImages( e, (1,3)(2,4) );                    
  3488.     (Subgroup( G, [  ] )*[ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ])
  3489.     gap> PreImage( e, (1,3)(2,4) ); 
  3490.     Error, <bij> must be a bijection, not an arbitrary mapping in
  3491.     bij.operations.PreImageElm( bij, img ) called from
  3492.     PreImage( e, (1,3)(2,4) ) called from
  3493.     main loop
  3494.     brk> quit;
  3495.     gap> PreImagesRepresentative( e, (1,3)(2,4) );
  3496.     [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ] |
  3497.  
  3498. Only  bijections  allow 'PreImage'  in order  to  get the preimage  of an
  3499. element of the range.
  3500.  
  3501. |    gap> Operation( G, Orbit( G, Z(3)*[1,0] ) );
  3502.     Group( (1,2)(3,4), (1,2,3,4) )
  3503.     gap> d := OperationHomomorphism( G, last );
  3504.     OperationHomomorphism( G, Group( (1,2)(3,4), (1,2,3,4) ) )
  3505.     gap> PreImage( d, (1,3)(2,4) );               
  3506.     [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ] |
  3507.  
  3508. Both 'PreImage' and 'PreImages' can also be applied to sets.  They return
  3509. the complete preimage.
  3510.  
  3511. |    gap> PreImages( d, Group( (1,2)(3,4), (1,3)(2,4) ) );
  3512.     Subgroup( G, [ [ [ 0*Z(3), Z(3) ], [ Z(3), 0*Z(3) ] ], 
  3513.       [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ] ] )
  3514.     gap> Size( last );
  3515.     4
  3516.     gap> f := NaturalHomomorphism( s4, s3 );
  3517.     NaturalHomomorphism( s4, (s4 / v4) )
  3518.     gap> PreImages( f, s3 );           
  3519.     Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4), (2,4), (3,4) ] )
  3520.     gap> Size( last );
  3521.     24 |
  3522.  
  3523. Another  way to construct a group  automorphism is to use elements in the
  3524. normalizer  of  a subgroup and construct  the  induced  automorphism.   A
  3525. special  case is the inner automorphism induced by an element of a group,
  3526. a  more general  case is a surjective  homomorphism induced by  arbitrary
  3527. elements of the parent group.
  3528.  
  3529. |    gap> d12 := Group((1,2,3,4,5,6),(2,6)(3,5));;  d12.name := "d12";;
  3530.     gap> i1 := InnerAutomorphism( d12, (1,2,3,4,5,6) );
  3531.     InnerAutomorphism( d12, (1,2,3,4,5,6) )
  3532.     gap> Image( i1, (2,6)(3,5) );
  3533.     (1,3)(4,6)
  3534.     gap> IsAutomorphism( i1 );
  3535.     true |
  3536.  
  3537. Mappings can also  be  multiplied, provided  that the range  of the first
  3538. mapping is  a  subgroup  of  the  source  of  the  second  mapping.   The
  3539. multiplication  is  of course defined as the  composition.  Note that, in
  3540. line with the fact that mappings operate *from the right*, 'Image( <map1>
  3541. \*\ <map2>, <elm> )' is defined as 'Image( <map2>, Image( <map1>, <elm> )
  3542. )'.
  3543.  
  3544. |    gap> i2 := InnerAutomorphism( d12, (2,6)(3,5) );
  3545.     InnerAutomorphism( d12, (2,6)(3,5) )
  3546.     gap> i1 * i2;
  3547.     InnerAutomorphism( d12, (1,6)(2,5)(3,4) )
  3548.     gap> Image( last, (2,6)(3,5) );
  3549.     (1,5)(2,4) |
  3550.  
  3551. Mappings can also be inverted, provided that they are bijections.
  3552.  
  3553. |    gap> i1 ^ -1;
  3554.     InnerAutomorphism( d12, (1,6,5,4,3,2) )
  3555.     gap> Image( last, (2,6)(3,5) );
  3556.     (1,5)(2,4) |
  3557.  
  3558. Whenever you have a set of bijective mappings on a finite set (or domain)
  3559. you can construct  the  group generated  by those mappings.   So  in  the
  3560. following example we create the group of inner automorphisms of 'd12'.
  3561.  
  3562. |    gap> autd12 := Group( i1, i2 );
  3563.     Group( InnerAutomorphism( d12, 
  3564.     (1,2,3,4,5,6) ), InnerAutomorphism( d12, (2,6)(3,5) ) )
  3565.     gap> Size( autd12 );
  3566.     6
  3567.     gap> Index( d12, Centre( d12 ) );
  3568.     6 |
  3569.  
  3570. Note that the computation with such automorphism  groups in their present
  3571. implementation is not very efficient.  For example to compute the size of
  3572. such  an  automorphism group  all elements  are computed.  Thus work with
  3573. such automorphism groups should be restricted to very small examples.
  3574.  
  3575. The  function  'ConjugationGroupHomomorphism'  is  a   generalization  of
  3576. 'InnerAutomorphism'.  It accepts a source and a range and an element that
  3577. conjugates the source  into the range.   Source and range must  lie in  a
  3578. common parent group, and the conjugating element must  also lie  in  this
  3579. parent group.
  3580.  
  3581. |    gap> c2 := Subgroup( d12, [ (2,6)(3,5) ] );
  3582.     Subgroup( d12, [ (2,6)(3,5) ] )
  3583.     gap> v4 := Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6) ] );
  3584.     Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6) ] )
  3585.     gap> x := ConjugationGroupHomomorphism( c2, v4, (1,3,5)(2,4,6) );
  3586.     ConjugationGroupHomomorphism( Subgroup( d12,
  3587.     [ (2,6)(3,5) ] ), Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6)
  3588.      ] ), (1,3,5)(2,4,6) )
  3589.     gap> IsSurjective( x );
  3590.     false
  3591.     gap> Image( x );
  3592.     Subgroup( d12, [ (1,5)(2,4) ] ) |
  3593.  
  3594. But how  can we construct homomorphisms which are not induced by elements
  3595. of  the  parent  group?   The  most  general  way  to  construct a  group
  3596. homomorphism is  to define the  source,  range  and  the  images  of  the
  3597. generators under the homomorphism in mind.
  3598.  
  3599. |    gap> c := GroupHomomorphismByImages( G, s4, [A,B], [(1,2),(3,4)] );
  3600.     GroupHomomorphismByImages( G, s4,
  3601.     [ [ [ 0*Z(3), Z(3) ], [ Z(3), 0*Z(3) ] ], 
  3602.       [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ] ], [ (1,2), (3,4) ] )
  3603.     gap> Kernel( c );
  3604.     Subgroup( G, [ [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ] ] )
  3605.     gap> Image( c );
  3606.     Subgroup( s4, [ (1,2), (3,4) ] )
  3607.     gap> IsHomomorphism( c );
  3608.     true
  3609.     gap> Image( c, A );
  3610.     (1,2)
  3611.     gap> PreImages( c, (1,2) );
  3612.     (Subgroup( G, [ [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ] ] )*
  3613.     [ [ 0*Z(3), Z(3) ], [ Z(3), 0*Z(3) ] ]) |
  3614.  
  3615. Note that it is possible to construct  a general mapping this way that is
  3616. not a homomorphism, because 'GroupHomomorphismByImages' does not check if
  3617. the given images fulfill the relations of the generators.
  3618.  
  3619. |    gap> b := GroupHomomorphismByImages( G, s4, [A,B], [(1,2,3),(3,4)] );
  3620.     GroupHomomorphismByImages( G, s4,
  3621.     [ [ [ 0*Z(3), Z(3) ], [ Z(3), 0*Z(3) ] ], 
  3622.       [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ] ], [ (1,2,3), (3,4) ] )
  3623.     gap> IsHomomorphism( b );
  3624.     false
  3625.     gap> Images( b, A );  
  3626.     (Subgroup( s4, [ (1,3,2), (2,3,4), (1,3,4), (1,4)(2,3), (1,4,2)
  3627.      ] )*()) |
  3628.  
  3629. The result is a *multi valued mapping*, i.e., one that  maps each element
  3630. of its source to a set of elements in its range.   The set of  images  of
  3631. 'A' under 'b' is defined as follows.  Take all the words  of  two letters
  3632. $w( x, y )$ such that $w( A, B ) = A$, e.g., $x$ and $x y  x  y x$.  Then
  3633. the set of images is the set of  elements  that you get by  inserting the
  3634. images of 'A' and 'B' in  those words, i.e., $w( (1,2,3), (3,4) )$, e.g.,
  3635. $(1,2,3)$ and $(1,4,2)$.  One can  show  that the set  of  images  of the
  3636. identity under a multi valued mapping such as  'b' is a subgroup and that
  3637. the set of images of other elements are cosets of this subgroup.
  3638.  
  3639. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3640. \Section{About Character Tables}
  3641.  
  3642. \def\colon{\char58}
  3643.  
  3644. This  section contains some examples  of the use  of {\GAP}  in character
  3645. theory.  First a few very  simple commands for  handling character tables
  3646. are  introduced, and afterwards we will construct the character tables of
  3647. $(A_5\times 3)\!\colon\!2$ and of $A_6.2^2$.
  3648.  
  3649. {\GAP} has  a large library of character tables, so let us look at one of
  3650. these tables, e.g., the table of the Mathieu group $M_{11}$\:
  3651.  
  3652. |    gap> m11:= CharTable( "M11" );;|
  3653.  
  3654. The double  semicolon is very  useful for character tables since they are
  3655. printed in full length, and they contain a lot of information.
  3656.  
  3657. |    gap> DisplayCharTable( m11 );
  3658.     M11
  3659.     
  3660.         2  4  4  1  3  .  1   3   3   .   .
  3661.         3  2  1  2  .  .  1   .   .   .   .
  3662.         5  1  .  .  .  1  .   .   .   .   .
  3663.        11  1  .  .  .  .  .   .   .   1   1
  3664.     
  3665.           1a 2a 3a 4a 5a 6a  8a  8b 11a 11b
  3666.        2P 1a 1a 3a 2a 5a 3a  4a  4a 11b 11a
  3667.        3P 1a 2a 1a 4a 5a 2a  8a  8b 11a 11b
  3668.        5P 1a 2a 3a 4a 1a 6a  8b  8a 11a 11b
  3669.       11P 1a 2a 3a 4a 5a 6a  8a  8b  1a  1a
  3670.     
  3671.     X.1    1  1  1  1  1  1   1   1   1   1
  3672.     X.2   10  2  1  2  . -1   .   .  -1  -1
  3673.     X.3   10 -2  1  .  .  1   A  -A  -1  -1
  3674.     X.4   10 -2  1  .  .  1  -A   A  -1  -1
  3675.     X.5   11  3  2 -1  1  .  -1  -1   .   .
  3676.     X.6   16  . -2  .  1  .   .   .   B  /B
  3677.     X.7   16  . -2  .  1  .   .   .  /B   B
  3678.     X.8   44  4 -1  . -1  1   .   .   .   .
  3679.     X.9   45 -3  .  1  .  .  -1  -1   1   1
  3680.     X.10  55 -1  1 -1  . -1   1   1   .   .
  3681.     
  3682.     A = E(8)+E(8)^3
  3683.       = ER(-2) = i2
  3684.     B = E(11)+E(11)^3+E(11)^4+E(11)^5+E(11)^9
  3685.       = (-1+ER(-11))/2 = b11|
  3686.  
  3687. We  are not  too  much interested  in  the  internal  structure  of  this
  3688. character table (see  "Character Table Records");  but  of course  we can
  3689. access all information  about the  centralizer orders (first four lines),
  3690. element  orders  (next  line), power  maps for the prime  divisors of the
  3691. group order (next four lines), irreducible characters (lines parametrized
  3692. by  'X.1'  \ldots 'X.10')  and irrational  character  values  (last  four
  3693. lines), see "DisplayCharTable" for a  detailed description  of the format
  3694. of the displayed table.  E.g., the irreducible characters are a list with
  3695. name  'm11.irreducibles',  and each  character  is a  list  of cyclotomic
  3696. integers (see chapter "Cyclotomics").  There are various ways to describe
  3697. the  irrationalities; e.g.,  the  square root  of $-2$  can be entered as
  3698. 'E(8)   +   E(8)\^3'   or   'ER(-2)',  the   famous   ATLAS   of   Finite
  3699. Groups~\cite{CCN85} denotes it as 'i2'.
  3700.  
  3701. |    gap> m11.irreducibles[3];
  3702.     [ 10, -2, 1, 0, 0, 1, E(8)+E(8)^3, -E(8)-E(8)^3, -1, -1 ]|
  3703.  
  3704. We  can  for  instance form tensor products of  this  character  with all
  3705. irreducibles, and compute the decomposition into irreducibles.
  3706.  
  3707. |    gap> tens:= Tensored( [ last ], m11.irreducibles );;
  3708.     gap> MatScalarProducts( m11, m11.irreducibles, tens );
  3709.     [ [ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 ], 
  3710.       [ 0, 0, 0, 0, 1, 0, 0, 1, 1, 0 ], [ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 ], 
  3711.       [ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1 ], [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 ], 
  3712.       [ 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 ], [ 0, 0, 1, 1, 0, 1, 1, 2, 3, 3 ], 
  3713.       [ 0, 1, 0, 1, 1, 1, 1, 3, 2, 3 ], [ 0, 1, 1, 0, 1, 1, 1, 3, 3, 4 ] ]|
  3714.  
  3715. The decomposition means for example that the third character in the  list
  3716. 'tens' is the sum of the irreducible characters at positions 5, 8 and 9.
  3717.  
  3718. |    gap> tens[3];
  3719.     [ 100, 4, 1, 0, 0, 1, -2, -2, 1, 1 ]
  3720.     gap> tens[3] = Sum( Sublist( m11.irreducibles, [ 5, 8, 9 ] ) );
  3721.     true|
  3722.  
  3723. Or  we  can  compute symmetrizations,  e.g.,  the characters $\chi^{2+}$,
  3724. defined by  $\chi^{2+}(g)  = \frac{1}{2} ( \chi^2(g) +  \chi(g^2) )$, for
  3725. all irreducibles.
  3726.  
  3727. |    gap> sym:= SymmetricParts( m11, m11.irreducibles, 2 );;
  3728.     gap> MatScalarProducts( m11, m11.irreducibles, sym );
  3729.     [ [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 ],
  3730.       [ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 ],
  3731.       [ 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 ], [ 0, 1, 0, 0, 1, 0, 1, 1, 0, 1 ],
  3732.       [ 0, 1, 0, 0, 1, 1, 0, 1, 0, 1 ], [ 1, 3, 0, 0, 3, 2, 2, 8, 4, 6 ],
  3733.       [ 1, 2, 0, 0, 3, 2, 2, 8, 4, 7 ], 
  3734.       [ 1, 3, 1, 1, 4, 3, 3, 11, 7, 10 ] ]
  3735.     gap> sym[2];
  3736.     [ 55, 7, 1, 3, 0, 1, 1, 1, 0, 0 ]
  3737.     gap> sym[2] = Sum( Sublist( m11.irreducibles, [ 1, 2, 8 ] ) );
  3738.     true|
  3739.  
  3740. If  the  subgroup  fusion into a supergroup is  known, characters can  be
  3741. induced to this  group, e.g., to obtain the  permutation character of the
  3742. action of $M_{12}$ on the cosets of $M_{11}$.
  3743.  
  3744. |    gap> m12:= CharTable( "M12" );;
  3745.     gap> permchar:= Induced( m11, m12, [ m11.irreducibles[1] ] );
  3746.     [ [ 12, 0, 4, 3, 0, 4, 0, 2, 0, 1, 2, 0, 0, 1, 1 ] ]
  3747.     gap> MatScalarProducts( m12, m12.irreducibles, last );
  3748.     [ [ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ]
  3749.     gap> DisplayCharTable( m12, rec( chars:= permchar ) );
  3750.     M12
  3751.     
  3752.        2  6  4  6  1  2  5  5  1  2  1  3  3   1   .   .
  3753.        3  3  1  1  3  2  .  .  .  1  1  .  .   .   .   .
  3754.        5  1  1  .  .  .  .  .  1  .  .  .  .   1   .   .
  3755.       11  1  .  .  .  .  .  .  .  .  .  .  .   .   1   1
  3756.     
  3757.          1a 2a 2b 3a 3b 4a 4b 5a 6a 6b 8a 8b 10a 11a 11b
  3758.       2P 1a 1a 1a 3a 3b 2b 2b 5a 3b 3a 4a 4b  5a 11b 11a
  3759.       3P 1a 2a 2b 1a 1a 4a 4b 5a 2a 2b 8a 8b 10a 11a 11b
  3760.       5P 1a 2a 2b 3a 3b 4a 4b 1a 6a 6b 8a 8b  2a 11a 11b
  3761.      11P 1a 2a 2b 3a 3b 4a 4b 5a 6a 6b 8a 8b 10a  1a  1a
  3762.     
  3763.     Y.1  12  .  4  3  .  4  .  2  .  1  2  .   .   1   1|
  3764.  
  3765. It should  be  emphasized  that the heart  of character theory is dealing
  3766. with lists.  Characters are lists,  and  also  the  maps which  occur are
  3767. represented as lists.  Note that the multiplication of group elements  is
  3768. not available, so we neither have homomorphisms.  All we can talk  of are
  3769. class  functions, and the lists are regarded as such functions, being the
  3770. lists  of  images  with  respect to  a fixed order of  conjugacy classes.
  3771. Therefore we do not write 'chi( cl )'  or 'cl\^chi' for the value of  the
  3772. character 'chi' on the class 'cl', but 'chi[i]' where 'i' is the position
  3773. of the class 'cl'.
  3774.  
  3775. Since  the  data  structures  are  so  basic,  most  calculations involve
  3776. compositions of maps; for example, the embedding of a subgroup in a group
  3777. is described by the so--called subgroup  fusion which is a class function
  3778. that maps each class  $c$ of the subgroup to that class of the group that
  3779. contains $c$.  Consider the symmetric group $S_5 \cong A_5.2$ as subgroup
  3780. of $M_{11}$.  (Do not worry about the names that are used to get  library
  3781. tables, see "CharTable" for an overview.)
  3782.  
  3783. |    gap> s5:= CharTable("A5.2");;
  3784.     gap> map:= GetFusionMap( s5, m11 );
  3785.     [ 1, 2, 3, 5, 2, 4, 6 ]|
  3786.  
  3787. The subgroup fusion is already stored on the table.  We see  that class 1
  3788. of 's5' is mapped  to class 1 of 'm11' (which means that the  identity of
  3789. $S_5$ maps to the identity of $M_{11}$), classes 2 and 5 of 's5' both map
  3790. to  class 2 of  'm11'  (which  means that  all involutions  of $S_5$  are
  3791. conjugate in $M_{11}$), and so on.
  3792.  
  3793. The restriction  of a character of 'm11' to 's5' is just the  composition
  3794. of this character with the subgroup fusion map.  Viewing this map as list
  3795. one would call this composition an indirection.
  3796.  
  3797. |    gap> chi:= m11.irreducibles[3];
  3798.     [ 10, -2, 1, 0, 0, 1, E(8)+E(8)^3, -E(8)-E(8)^3, -1, -1 ]
  3799.     gap> rest:= List( map, x -> chi[x] );
  3800.     [ 10, -2, 1, 0, -2, 0, 1 ]|
  3801.  
  3802. This looks very easy, and many  {\GAP}  functions  in character theory do
  3803. such simple calculations.  But note that  it is not always obvious that a
  3804. list is  regarded  as a  map,  where preimages  and/or  images  refer  to
  3805. positions of certain conjugacy classes.
  3806.  
  3807. |    gap> alt:= s5.irreducibles[2];
  3808.     [ 1, 1, 1, 1, -1, -1, -1 ]
  3809.     gap> kernel:= KernelChar( last );
  3810.     [ 1, 2, 3, 4 ]|
  3811.  
  3812. The kernel of a character  is  represented as the  list of (positions of)
  3813. classes lying in the kernel.  We know that the kernel of  the alternating
  3814. character 'alt' of 's5' is the alternating group $A_5$.  The order of the
  3815. kernel  can  be computed as sum of the lengths of the  contained  classes
  3816. from the character table, using that the  classlengths  are stored in the
  3817. 'classes' component of the table.
  3818.  
  3819. |    gap> s5.classes;
  3820.     [ 1, 15, 20, 24, 10, 30, 20 ]
  3821.     gap> Sublist( last, kernel );
  3822.     [ 1, 15, 20, 24 ]
  3823.     gap> Sum( last );
  3824.     60|
  3825.  
  3826. We  chose those classlengths of  's5' that belong  to the  $S_5$--classes
  3827. contained  in the  alternating group.   The  same  thing  is  done in the
  3828. following command, reflecting the view of the kernel as map.
  3829.  
  3830. |    gap> List( kernel, x -> s5.classes[x] );
  3831.     [ 1, 15, 20, 24 ]
  3832.     gap> Sum( kernel, x -> s5.classes[x] );
  3833.     60|
  3834.  
  3835. This small example shows how  the functions 'Sublist', 'List',  and 'Sum'
  3836. can be  used.  These functions as well  as  'Filtered' were introduced in
  3837. "About Further List Operations", and we will  make heavy use  of them; in
  3838. many cases  such a command might look  very strange,  but it  is just the
  3839. translation of  a  (hardly  less  complicated)  mathematical  formula  to
  3840. character theory.
  3841.  
  3842. And now let us construct some small character tables!
  3843.  
  3844. %ignore
  3845. \setlength{\unitlength}{0.1cm}
  3846. \begin{minipage}[t]{70mm}
  3847. The group  $G  = (A_5\times  3)\!\colon\!2$ is a maximal subgroup of  the
  3848. alternating group $A_8$;  $G$  extends to $S_5\times S_3$  in  $S_8$.  We
  3849. want to construct the character table of $G$.
  3850.  
  3851. First  the tables of  the  subgroup  $A_5\times  3$  and  the  supergroup
  3852. $S_5\times S_3$ are constructed; the tables of the factors of each direct
  3853. product are again got from the table  library using admissible names, see
  3854. "CharTable" for this.
  3855. \end{minipage} \ \ \begin{picture}(0,0)
  3856. % \catcode`\*=11
  3857. \put(10,-37){\begin{picture}(50,45)
  3858. \put(25,5){\circle{1}}
  3859. \put(15,15){\circle{1}}
  3860. \put(25,25){\circle{1}}
  3861. \put(25,30){\circle{1}}
  3862. \put(25,35){\circle{1}}
  3863. \put(35,15){\circle{1}}
  3864. \put(10,20){\circle{1}}
  3865. \put(40,20){\circle{1}}
  3866. \put(20,30){\circle{1}}
  3867. \put(30,30){\circle{1}}
  3868. \put(7,20){\makebox(0,0){$S_5$}}
  3869. \put(12,15){\makebox(0,0){$A_5$}}
  3870. \put(43,20){\makebox(0,0){$S_3$}}
  3871. \put(38,15){\makebox(0,0){$3$}}
  3872. \put(27,30){\makebox(0,0){$G$}}
  3873. \put(25,37){\makebox(0,0){$S_5\times S_3$}}
  3874. \put(14,30){\makebox(0,0){$S_5\times 3$}}
  3875. \put(38,30){\makebox(0,0){$A_5\times S_3$}}
  3876. \put(25,5){\line(-1,1){15}}
  3877. \put(25,5){\line(1,1){15}}
  3878. \put(35,15){\line(-1,1){15}}
  3879. \put(15,15){\line(1,1){15}}
  3880. \put(40,20){\line(-1,1){15}}
  3881. \put(10,20){\line(1,1){15}}
  3882. \put(25,25){\line(0,1){10}}
  3883. \end{picture}}
  3884. \end{picture}
  3885. %end
  3886. %display
  3887. %The group G = (A_5 x 3):2 is a                      S_5 x S_3 
  3888. %maximal subgroup of the alternating                   . | .
  3889. %group A_8; G extends to S_5 x S_3                   .   |   .
  3890. %in S_8.  We want to construct the             S_5 x 3   G   A_5 x S_3
  3891. %character table of G.                           .   .   |   .   .
  3892. %                                              .       . | .       .
  3893. %First the tables of the subgroup            .        A_5 x 3        .
  3894. %A_5 x 3 and the supergroup              S_5           .   .           S_3
  3895. %S_5 x S_3 are constructed; the              .       .       .       .
  3896. %tables of the factors of each direct          .   .           .   .
  3897. %product are again got from the table           A_5              3
  3898. %library using admissible names, see               .           .
  3899. %"CharTable" for this.                               .       .
  3900. %                                                      .   .
  3901. %                                                        .
  3902. %end
  3903.  
  3904. |    gap> a5:= CharTable( "A5" );;
  3905.     gap> c3:= CharTable( "Cyclic", 3 );;
  3906.     gap> a5xc3:= CharTableDirectProduct( a5, c3 );;
  3907.     gap> s5:= CharTable( "A5.2" );;
  3908.     gap> s3:= CharTable( "Symmetric", 3 );;
  3909.     gap> s3.irreducibles;
  3910.     [ [ 1, -1, 1 ], [ 2, 0, -1 ], [ 1, 1, 1 ] ]
  3911.     # The trivial character shall be the first one.
  3912.     gap> SortCharactersCharTable( s3 );  # returns the applied permutation
  3913.     (1,2,3)
  3914.     gap> s5xs3:= CharTableDirectProduct( s5, s3 );;|
  3915.  
  3916. $G$ is the normal subgroup of index  2 in $S_5\times  S_3$ which contains
  3917. neither  $S_5$ nor  the  normal  $S_3$.  We want to  find the  classes of
  3918. 's5xs3' whose union  is $G$.  For that, we compute the  set of kernels of
  3919. irreducibles --remember that they are given simply by lists of numbers of
  3920. contained  classes-- and  then  choose those  kernels belonging to normal
  3921. subgroups of index 2.
  3922.  
  3923. |    gap> kernels:= Set( List( s5xs3.irreducibles, KernelChar ) );
  3924.     [ [ 1 ], [ 1, 2, 3 ], [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], 
  3925.       [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 
  3926.           19, 20, 21 ], [ 1, 3 ], 
  3927.       [ 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21 ], 
  3928.       [ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ], [ 1, 4, 7, 10 ], 
  3929.       [ 1, 4, 7, 10, 13, 16, 19 ] ]
  3930.     gap> sizes:= List( kernels, x -> Sum( Sublist( s5xs3.classes, x ) ) );
  3931.     [ 1, 6, 360, 720, 3, 360, 360, 60, 120 ]
  3932.     gap> s5xs3.order;
  3933.     720
  3934.     gap> index2:= Sublist( kernels, [ 3, 6, 7 ] );
  3935.     [ [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], 
  3936.       [ 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21 ], 
  3937.       [ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ] ]|
  3938.  
  3939. In order to decide which kernel describes $G$, we consider the embeddings
  3940. of 's5' and 's3' in 's5xs3', given by the subgroup fusions.
  3941.  
  3942. |    gap> s5ins5xs3:= GetFusionMap( s5, s5xs3 );
  3943.     [ 1, 4, 7, 10, 13, 16, 19 ]
  3944.     gap> s3ins5xs3:= GetFusionMap( s3, s5xs3 );
  3945.     [ 1, 2, 3 ]
  3946.     gap> Filtered( index2, x->Intersection(x,s5ins5xs3)<>s5ins5xs3 and
  3947.     >                         Intersection(x,s3ins5xs3)<>s3ins5xs3     );
  3948.     [ [ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ] ]
  3949.     gap> nsg:= last[1];
  3950.     [ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ]|
  3951.  
  3952. We now construct  a first  approximation of  the character  table of this
  3953. normal  subgroup, namely the  restriction of 's5xs3' to the classes given
  3954. by 'nsg'.
  3955.  
  3956. |    gap> sub:= CharTableNormalSubgroup( s5xs3, nsg );
  3957.     &I CharTableNormalSubgroup: classes in [ 8 ] necessarily split
  3958.     rec( name := "Rest(A5.2xS3,[ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ])",\
  3959.      order := 360, centralizers := [ 360, 180, 24, 12, 18, 9, 15, 15/2,
  3960.       12, 4, 6 ], orders := [ 1, 3, 2, 6, 3, 3, 5, 15, 2, 4, 6
  3961.      ], powermap := [ , [ 1, 2, 1, 2, 5, 6, 7, 8, 1, 3, 5 ],
  3962.       [ 1, 1, 3, 3, 1, 1, 7, 7, 9, 10, 9 ],,
  3963.       [ 1, 2, 3, 4, 5, 6, 1, 2, 9, 10, 11 ] ], classes :=
  3964.     [ 1, 2, 15, 30, 20, 40, 24, 48, 30, 90, 60
  3965.      ], operations := CharTableOps, irreducibles :=
  3966.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  3967.       [ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1 ],
  3968.       [ 2, -1, 2, -1, 2, -1, 2, -1, 0, 0, 0 ],
  3969.       [ 6, 6, -2, -2, 0, 0, 1, 1, 0, 0, 0 ],
  3970.       [ 4, 4, 0, 0, 1, 1, -1, -1, 2, 0, -1 ],
  3971.       [ 4, 4, 0, 0, 1, 1, -1, -1, -2, 0, 1 ],
  3972.       [ 8, -4, 0, 0, 2, -1, -2, 1, 0, 0, 0 ],
  3973.       [ 5, 5, 1, 1, -1, -1, 0, 0, 1, -1, 1 ],
  3974.       [ 5, 5, 1, 1, -1, -1, 0, 0, -1, 1, -1 ],
  3975.       [ 10, -5, 2, -1, -2, 1, 0, 0, 0, 0, 0 ] ], fusions := [ rec(
  3976.           name := "A5.2xS3",
  3977.           map := [ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ] ) ] ) |
  3978.  
  3979. Not all restrictions of irreducible characters of 's5xs3' to 'sub' remain
  3980. irreducible.  We compute those restrictions with norm larger than 1.
  3981.  
  3982. |    gap> red:= Filtered( Restricted( s5xs3, sub, s5xs3.irreducibles ),
  3983.     >                    x -> ScalarProduct( sub, x, x ) > 1 );
  3984.     [ [ 12, -6, -4, 2, 0, 0, 2, -1, 0, 0, 0 ] ]
  3985.     gap> Filtered( [ 1 .. Length( nsg ) ],
  3986.     >              x -> not IsInt( sub.centralizers[x] ) );
  3987.     [ 8 ]|
  3988.  
  3989. Note that  'sub'  is not  actually  a  character table  in  the sense  of
  3990. mathematics  but  only  a  record with components like a character table.
  3991. {\GAP} does not know about this subtleties  and  treats it as a character
  3992. table.
  3993.  
  3994. As the list 'centralizers' of centralizer orders shows,  at least class 8
  3995. splits  into  two  conjugacy  classes  in $G$,  since  this  is  the only
  3996. possibility to achieve integral centralizer orders.
  3997.  
  3998. Since  10 restrictions of  irreducible characters remain  irreducible for
  3999. $G$ ('sub' contains 10 irreducibles), only  one of the 11 irreducibles of
  4000. $S_5\times S_3$ splits into  two irreducibles  of $G$,  in  other  words,
  4001. class 8 is the only splitting class.
  4002.  
  4003. Thus we create a  new approximation of the desired character table (which
  4004. we call 'split')  where  this class  is split; 8th and 9th  column of the
  4005. known  irreducibles are  of  course equal, and due  to the splitting  the
  4006. second powermap for these columns is ambiguous.
  4007.  
  4008. |    gap> splitting:= [ 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11 ];;
  4009.     gap> split:= CharTableSplitClasses( sub, splitting );
  4010.     rec( name := "Split(Rest(A5.2xS3,[ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 2\
  4011.     0 ]),[ 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11 ])", order :=
  4012.     360, centralizers := [ 360, 180, 24, 12, 18, 9, 15, 15, 15, 12, 4, 6
  4013.      ], classes := [ 1, 2, 15, 30, 20, 40, 24, 24, 24, 30, 90, 60
  4014.      ], orders := [ 1, 3, 2, 6, 3, 3, 5, 15, 15, 2, 4, 6 ], powermap :=
  4015.     [ , [ 1, 2, 1, 2, 5, 6, 7, [ 8, 9 ], [ 8, 9 ], 1, 3, 5 ],
  4016.       [ 1, 1, 3, 3, 1, 1, 7, 7, 7, 10, 11, 10 ],,
  4017.       [ 1, 2, 3, 4, 5, 6, 1, 2, 2, 10, 11, 12 ] ], irreducibles :=
  4018.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  4019.       [ 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1 ],
  4020.       [ 2, -1, 2, -1, 2, -1, 2, -1, -1, 0, 0, 0 ],
  4021.       [ 6, 6, -2, -2, 0, 0, 1, 1, 1, 0, 0, 0 ],
  4022.       [ 4, 4, 0, 0, 1, 1, -1, -1, -1, 2, 0, -1 ],
  4023.       [ 4, 4, 0, 0, 1, 1, -1, -1, -1, -2, 0, 1 ],
  4024.       [ 8, -4, 0, 0, 2, -1, -2, 1, 1, 0, 0, 0 ],
  4025.       [ 5, 5, 1, 1, -1, -1, 0, 0, 0, 1, -1, 1 ],
  4026.       [ 5, 5, 1, 1, -1, -1, 0, 0, 0, -1, 1, -1 ],
  4027.       [ 10, -5, 2, -1, -2, 1, 0, 0, 0, 0, 0, 0 ] ], fusions := [ rec(
  4028.           name := "Rest(A5.2xS3,[ 1, 3, 4, 6, 7, 9, 10, 12, 14, 17, 20 ])" 
  4029.            ,
  4030.           map := [ 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11 ] )
  4031.      ], operations := CharTableOps )
  4032.     gap> Restricted( sub, split, red );
  4033.     [ [ 12, -6, -4, 2, 0, 0, 2, -1, -1, 0, 0, 0 ] ]|
  4034.  
  4035. To  complete the table means to  find the missing two irreducibles and to
  4036. complete  the powermaps.   For this, there are  different  possibilities.
  4037. First, one can try to embed $G$ in $A_8$.
  4038.  
  4039. |    gap> a8:= CharTable( "A8" );;
  4040.     gap> fus:= SubgroupFusions( split, a8 );
  4041.     [ [ 1, 4, 3, 9, 4, 5, 8, 13, 14, 3, 7, 9 ], 
  4042.       [ 1, 4, 3, 9, 4, 5, 8, 14, 13, 3, 7, 9 ] ]
  4043.     gap> fus:= RepresentativesFusions( split, fus, a8 );
  4044.     &I RepresentativesFusions: no subtable automorphisms stored
  4045.     [ [ 1, 4, 3, 9, 4, 5, 8, 13, 14, 3, 7, 9 ] ]
  4046.     gap> StoreFusion( split, a8, fus[1] );|
  4047.  
  4048. The subgroup fusion is unique up to table automorphisms.  Now we restrict
  4049. the irreducibles of $A_8$ to $G$ and reduce.
  4050.  
  4051. |    gap> rest:= Restricted( a8, split, a8.irreducibles );;
  4052.     gap> red:= Reduced( split, split.irreducibles, rest );
  4053.     rec( 
  4054.       remainders := [  ], 
  4055.       irreducibles := 
  4056.        [ [ 6, -3, -2, 1, 0, 0, 1, -E(15)-E(15)^2-E(15)^4-E(15)^8, 
  4057.               -E(15)^7-E(15)^11-E(15)^13-E(15)^14, 0, 0, 0 ], 
  4058.           [ 6, -3, -2, 1, 0, 0, 1, -E(15)^7-E(15)^11-E(15)^13-E(15)^14, 
  4059.               -E(15)-E(15)^2-E(15)^4-E(15)^8, 0, 0, 0 ] ] )
  4060.     gap> Append( split.irreducibles, red.irreducibles );|
  4061.  
  4062. The list of irreducibles is now complete,  but  the powermaps are not yet
  4063. adjusted.  To complete the 2nd powermap, we transfer that of $A_8$ to $G$
  4064. using the subgroup fusion.
  4065.  
  4066. |    gap> split.powermap;
  4067.     [ , [ 1, 2, 1, 2, 5, 6, 7, [ 8, 9 ], [ 8, 9 ], 1, 3, 5 ], 
  4068.       [ 1, 1, 3, 3, 1, 1, 7, 7, 7, 10, 11, 10 ],, 
  4069.       [ 1, 2, 3, 4, 5, 6, 1, 2, 2, 10, 11, 12 ] ]
  4070.     gap> TransferDiagram( split.powermap[2], fus[1], a8.powermap[2] );;|
  4071.  
  4072. And this is the complete table.
  4073.  
  4074. |    gap> split.name:= "(A5x3):2";;
  4075.     gap> DisplayCharTable( split );
  4076.     (A5x3):2
  4077.     
  4078.         2  3  2  3  2  1  .  .   .   .  2  2  1
  4079.         3  2  2  1  1  2  2  1   1   1  1  .  1
  4080.         5  1  1  .  .  .  .  1   1   1  .  .  .
  4081.     
  4082.           1a 3a 2a 6a 3b 3c 5a 15a 15b 2b 4a 6b
  4083.        2P 1a 3a 1a 3a 3b 3c 5a 15a 15b 1a 2a 3b
  4084.        3P 1a 1a 2a 2a 1a 1a 5a  5a  5a 2b 4a 2b
  4085.        5P 1a 3a 2a 6a 3b 3c 1a  3a  3a 2b 4a 6b
  4086.     
  4087.     X.1    1  1  1  1  1  1  1   1   1  1  1  1
  4088.     X.2    1  1  1  1  1  1  1   1   1 -1 -1 -1
  4089.     X.3    2 -1  2 -1  2 -1  2  -1  -1  .  .  .
  4090.     X.4    6  6 -2 -2  .  .  1   1   1  .  .  .
  4091.     X.5    4  4  .  .  1  1 -1  -1  -1  2  . -1
  4092.     X.6    4  4  .  .  1  1 -1  -1  -1 -2  .  1
  4093.     X.7    8 -4  .  .  2 -1 -2   1   1  .  .  .
  4094.     X.8    5  5  1  1 -1 -1  .   .   .  1 -1  1
  4095.     X.9    5  5  1  1 -1 -1  .   .   . -1  1 -1
  4096.     X.10  10 -5  2 -1 -2  1  .   .   .  .  .  .
  4097.     X.11   6 -3 -2  1  .  .  1   A  /A  .  .  .
  4098.     X.12   6 -3 -2  1  .  .  1  /A   A  .  .  .
  4099.     
  4100.     A = -E(15)-E(15)^2-E(15)^4-E(15)^8
  4101.       = (-1-ER(-15))/2 = -1-b15|
  4102.  
  4103. There are many ways around the block, so two further methods  to complete
  4104. the table 'split' shall be demonstrated; but we will not go into details.
  4105.  
  4106. Without use of {\GAP} one could work as follows\:
  4107.  
  4108. The  irrationalities --and  there  must  be  irrational  entries  in  the
  4109. character table  of $G$, since the outer 2  can conjugate at most two  of
  4110. the four Galois conjugate classes  of  elements of  order 15-- could also
  4111. have  been found from  the  structure of  $G$ and  the restriction of the
  4112. irreducible $S_5\times S_3$ character of degree 12.
  4113.  
  4114. On the classes that did not split the  values of this character must just
  4115. be divided  by 2.  Let  $x$  be  one of  the irrationalities.  The second
  4116. orthogonality relation tells  us that $x\cdot\overline{x}  = 4$ (at class
  4117. '15a') and $x +  x\ast = -1$  (at classes '1a' and  '15a');  here $x\ast$
  4118. denotes the nontrivial Galois conjugate of $x$.  This has no solution for
  4119. $x  =  \overline{x}$,  otherwise  it  leads  to  the  quadratic  equation
  4120. $x^2+x+4 = 0$ with  solutions  $b15  =   \frac{1}{2}(-1+\sqrt{-15})$  and
  4121. $-1-b15$.
  4122.  
  4123. The third possibility to complete the table is to embed $A_5\times 3$\:
  4124.  
  4125. |    gap> split.irreducibles := split.irreducibles{ [ 1 .. 10 ] };;
  4126.     gap> SubgroupFusions( a5xc3, split );
  4127.     [ [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, [ 8, 9 ], [ 8, 9 ], 7, [ 8, 9 ],
  4128.           [ 8, 9 ] ] ]|
  4129.  
  4130. The images of the four  classes of element  order 15  are not determined,
  4131. the returned list parametrizes the $2^4$ possibilities.
  4132.  
  4133. |    gap> fus:= ContainedMaps( last[1] );;
  4134.     gap> Length( fus );
  4135.     16
  4136.     gap> fus[1];
  4137.     [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 7, 8, 8 ]|
  4138.  
  4139. Most of  these  16  possibilities are  excluded using  scalar products of
  4140. induced characters.  We  take a  suitable character 'chi'  of 'a5xc3' and
  4141. compute the norm  of the induced character with respect to  each possible
  4142. map.
  4143.  
  4144. |    gap> chi:= a5xc3.irreducibles[5];
  4145.     [ 3, 3*E(3), 3*E(3)^2, -1, -E(3), -E(3)^2, 0, 0, 0, -E(5)-E(5)^4, 
  4146.       -E(15)^2-E(15)^8, -E(15)^7-E(15)^13, -E(5)^2-E(5)^3,
  4147.       -E(15)^11-E(15)^14, -E(15)-E(15)^4 ]
  4148.     gap> List( fus, x -> List( Induced( a5xc3, split, [ chi ], x ), 
  4149.     >                          y -> ScalarProduct( split, y, y ) )[1] );
  4150.     [ 8/15, -2/3*E(5)-11/15*E(5)^2-11/15*E(5)^3-2/3*E(5)^4, 
  4151.       -2/3*E(5)-11/15*E(5)^2-11/15*E(5)^3-2/3*E(5)^4, 2/3, 
  4152.       -11/15*E(5)-2/3*E(5)^2-2/3*E(5)^3-11/15*E(5)^4, 3/5, 1, 
  4153.       -11/15*E(5)-2/3*E(5)^2-2/3*E(5)^3-11/15*E(5)^4, 
  4154.       -11/15*E(5)-2/3*E(5)^2-2/3*E(5)^3-11/15*E(5)^4, 1, 3/5, 
  4155.       -11/15*E(5)-2/3*E(5)^2-2/3*E(5)^3-11/15*E(5)^4, 2/3, 
  4156.       -2/3*E(5)-11/15*E(5)^2-11/15*E(5)^3-2/3*E(5)^4, 
  4157.       -2/3*E(5)-11/15*E(5)^2-11/15*E(5)^3-2/3*E(5)^4, 8/15 ]
  4158.     gap> Filtered( [ 1 .. Length( fus ) ], x -> IsInt( last[x] ) );
  4159.     [ 7, 10 ]|
  4160.  
  4161. So  only  fusions 7  and 10 may be possible.   They  are equivalent (with
  4162. respect to table  automorphisms), and  the  list  of  induced  characters
  4163. contains the missing irreducibles of $G$\:
  4164.  
  4165. |    gap> Sublist( fus, last );
  4166.     [ [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 7, 9, 8 ], 
  4167.       [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 9, 8, 7, 8, 9 ] ]
  4168.     gap> ind:= Induced( a5xc3, split, a5xc3.irreducibles, last[1] );;
  4169.     gap> Reduced( split, split.irreducibles, ind );
  4170.     rec( 
  4171.       remainders := [  ], 
  4172.       irreducibles := 
  4173.        [ [ 6, -3, -2, 1, 0, 0, 1, -E(15)-E(15)^2-E(15)^4-E(15)^8, 
  4174.               -E(15)^7-E(15)^11-E(15)^13-E(15)^14, 0, 0, 0 ], 
  4175.           [ 6, -3, -2, 1, 0, 0, 1, -E(15)^7-E(15)^11-E(15)^13-E(15)^14, 
  4176.               -E(15)-E(15)^2-E(15)^4-E(15)^8, 0, 0, 0 ] ] )|
  4177.  
  4178. \vspace{5mm}
  4179. The  following  example  is  thought   mainly  for  experts.    It  shall
  4180. demonstrate   how   one   can  work   together   with  {\GAP}   and   the
  4181. {\ATLAS}~\cite{CCN85}, so better leave out the rest  of this  section  if
  4182. you are not familiar with the {\ATLAS}.
  4183.  
  4184. %ignore
  4185. \setlength{\unitlength}{0.1cm}
  4186. \begin{minipage}[t]{90mm}
  4187. We shall construct the character table of the group
  4188. $G  =  A_6.2^2 \cong Aut( A_6 )$ from the tables of the  normal subgroups
  4189. $A_6.2_1 \cong S_6$, $A_6.2_2 \cong PGL(2,9)$ and $A_6.2_3 \cong M_{10}$.
  4190.  
  4191. We regard $G$ as a  downward extension of the Klein fourgroup  $2^2$ with
  4192. $A_6$.  The set of classes of all  preimages of cyclic subgroups of $2^2$
  4193. covers the classes  of $G$, but it  may happen that  some representatives
  4194. are conjugate in $G$, i.e., the classes fuse.
  4195.  
  4196. The {\ATLAS} denotes the character tables of $G$, $G.2_1$, $G.2_2$ and
  4197. $G.2_3$ as follows\:
  4198. \end{minipage} \ \ \begin{picture}(0,0)
  4199. \put(5,-40){\begin{picture}(50,45)
  4200. \put(25,5){\circle{1}}
  4201. \put(25,20){\makebox(0,0){$A_6$}}
  4202. \put(25,30){\makebox(0,0){$A_6.2_3$}}
  4203. \put(15,30){\makebox(0,0){$A_6.2_1$}}
  4204. \put(35,30){\makebox(0,0){$A_6.2_2$}}
  4205. \put(25,40){\makebox(0,0){$G$}}
  4206. \put(25,5){\line(0,1){12}}
  4207. \put(23,22){\line(-1,1){6}}
  4208. \put(27,22){\line(1,1){6}}
  4209. \put(25,22){\line(0,1){6}}
  4210. \put(23,38){\line(-1,-1){6}}
  4211. \put(27,38){\line(1,-1){6}}
  4212. \put(25,38){\line(0,-1){6}}
  4213. \end{picture}}
  4214. \end{picture}
  4215.  
  4216. \vbox{
  4217. \begin{picture}(0,0)\put(69.25,-76.25){\line(0,1){10}}\end{picture}
  4218.  
  4219. |     ;   @   @   @   @   @   @   @   ;   ;   @   @   @   @   @
  4220.  
  4221.        360   8   9   9   4   5   5          24  24   4   3   3
  4222.    p power   A   A   A   A   A   A           A   A   A  AB  BC
  4223.    p|%
  4224. \mbox{\tt\char13}%
  4225. | part   A   A   A   A   A   A           A   A   A  AB  BC
  4226.    ind  1A  2A  3A  3B  4A  5A  B* fus ind  2B  2C  4B  6A  6B
  4227.  
  4228. |$\chi_1$|   +   1   1   1   1   1   1   1   :  ++   1   1   1   1   1
  4229.  
  4230. |$\chi_2$|   +   5   1   2  -1  -1   0   0   :  ++   3  -1   1   0  -1
  4231.  
  4232. |$\chi_3$|   +   5   1  -1   2  -1   0   0   :  ++  -1   3   1  -1   0
  4233.  
  4234. |$\chi_4$|   +   8   0  -1  -1   0 -b5   *   .   +   0   0   0   0   0
  4235.  
  4236. |$\chi_5$|   +   8   0  -1  -1   0   * -b5   .
  4237.  
  4238. |$\chi_6$|   +   9   1   0   0   1  -1  -1   :  ++   3   3  -1   0   0
  4239.  
  4240. |$\chi_7$|   +  10  -2   1   1   0   0   0   :  ++   2  -2   0  -1   1|
  4241. }
  4242.  
  4243. \vbox{
  4244. \begin{picture}(0,0)
  4245. \put(6.5,-52){\line(0,1){8.5}}
  4246. \put(56.25,-69){\line(0,1){9}}
  4247. \put(56.25,-52){\line(0,1){8.5}}
  4248. \end{picture}
  4249.  
  4250. |   ;   ;  @   @   @   @   @   ;   ;  @   @   @
  4251.  
  4252.          10   4   4   5   5          2   4   4
  4253.           A   A   A  BD  AD          A   A   A
  4254.           A   A   A  AD  BD          A   A   A
  4255.  fus ind 2D  8A  B* 10A  B* fus ind 4C  8C D**
  4256.  
  4257.    :  ++  1   1   1   1   1   :  ++  1   1   1   |$\chi_1$|
  4258.  
  4259.    .   +  0   0   0   0   0   .   +  0   0   0   |$\chi_2$|
  4260.  
  4261.    .                          .                  |$\chi_3$|
  4262.  
  4263.    :  ++  2   0   0  b5   *   .   +  0   0   0   |$\chi_4$|
  4264.  
  4265.    :  ++  2   0   0   *  b5   .                  |$\chi_5$|
  4266.  
  4267.    :  ++ -1   1   1  -1  -1   :  ++  1  -1  -1   |$\chi_6$|
  4268.  
  4269.    :  ++  0  r2 -r2   0   0   :  oo  0  i2 -i2   |$\chi_7$|
  4270. |}
  4271. %end
  4272. %display
  4273. %We shall construct the character                  G
  4274. %table of the group G = A_6.2^2                  . | .
  4275. %which is isomorphic to Aut(A_6)               .   |   .
  4276. %from the tables of the normal               .     |     .
  4277. %subgroups A_6.2_1 (isom. to S_6),    A_6.2_1   A_6.2_3   A_6.2_2
  4278. %A_6.2_2 (isom. to PGL(2,9)), and            .     |     .
  4279. %A_6.2_3 (isom. to M_{10}).                    .   |   .
  4280. %                                                . | .
  4281. %We regard G as a downward extension              A_6
  4282. %of the Klein fourgroup 2^2 with A_6.              |
  4283. %The set of classes of all preimages               |
  4284. %of cyclic subgroups of 2^2 covers                 |
  4285. %the classes of G, but it may happen               |
  4286. %that  some representatives are
  4287. %conjugate in G, i.e., the classes fuse.
  4288. %
  4289. %The ATLAS denotes the character tables of G, G.2_1, G.2_2 and G.2_3
  4290. %as follows:
  4291. %
  4292. %     ;   @   @   @   @   @   @   @   ;   ;   @   @   @   @   @
  4293. %
  4294. %       360   8   9   9   4   5   5          24  24   4   3   3
  4295. %   p power   A   A   A   A   A   A           A   A   A  AB  BC
  4296. %   p' part   A   A   A   A   A   A           A   A   A  AB  BC
  4297. %   ind  1A  2A  3A  3B  4A  5A  B* fus ind  2B  2C  4B  6A  6B
  4298. %
  4299. %X1   +   1   1   1   1   1   1   1   :  ++   1   1   1   1   1
  4300. %
  4301. %X2   +   5   1   2  -1  -1   0   0   :  ++   3  -1   1   0  -1
  4302. %
  4303. %X3   +   5   1  -1   2  -1   0   0   :  ++  -1   3   1  -1   0
  4304. %
  4305. %X4   +   8   0  -1  -1   0 -b5   *   .   +   0   0   0   0   0
  4306. %                                     |
  4307. %X5   +   8   0  -1  -1   0   * -b5   .
  4308. %
  4309. %X6   +   9   1   0   0   1  -1  -1   :  ++   3   3  -1   0   0
  4310. %
  4311. %X7   +  10  -2   1   1   0   0   0   :  ++   2  -2   0  -1   1
  4312. %
  4313. %
  4314. %
  4315. %   ;   ;  @   @   @   @   @   ;   ;  @   @   @
  4316. %
  4317. %         10   4   4   5   5          2   4   4
  4318. %          A   A   A  BD  AD          A   A   A
  4319. %          A   A   A  AD  BD          A   A   A
  4320. % fus ind 2D  8A  B* 10A  B* fus ind 4C  8C D**
  4321. %
  4322. %   :  ++  1   1   1   1   1   :  ++  1   1   1   X1
  4323. %
  4324. %   .   +  0   0   0   0   0   .   +  0   0   0   X2
  4325. %   |                          |
  4326. %   .                          .                  X3
  4327. %
  4328. %   :  ++  2   0   0  b5   *   .   +  0   0   0   X4
  4329. %                              |
  4330. %   :  ++  2   0   0   *  b5   .                  X5
  4331. %
  4332. %   :  ++ -1   1   1  -1  -1   :  ++  1  -1  -1   X6
  4333. %
  4334. %   :  ++  0  r2 -r2   0   0   :  oo  0  i2 -i2   X7
  4335. %end
  4336.  
  4337. First we  construct  a  table  whose  classes  are  those  of  the  three
  4338. subgroups.  Note that the exponent of $A_6$  is 60, so the representative
  4339. orders could become at most 60 times the value in $2^2$.
  4340.  
  4341. |    gap> s1:= CharTable( "A6.2_1" );;
  4342.     gap> s2:= CharTable( "A6.2_2" );;
  4343.     gap> s3:= CharTable( "A6.2_3" );;
  4344.     gap> c2:= CharTable( "Cyclic", 2 );;
  4345.     gap> v4:= CharTableDirectProduct( c2, c2 );;
  4346.     &I CharTableDirectProduct: existing subgroup fusion on <tbl2> replaced
  4347.     &I    by actual one
  4348. 1513,1535c1559,1581
  4349.     gap> for tbl in [ s1, s2, s3 ] do
  4350.     >      Print( tbl.irreducibles[2], "\n" );
  4351.     >    od;
  4352.     [ 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 ]
  4353.     [ 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 ]
  4354.     [ 1, 1, 1, 1, 1, -1, -1, -1 ]
  4355.     gap> split:= CharTableSplitClasses( v4,
  4356.     >              [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4], 60 );
  4357.     rec( name := "Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, \
  4358.     3, 4, 4, 4 ])", order := 4, centralizers := 
  4359.     [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], classes := 
  4360.     [ 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 1/5, 
  4361.       1/5, 1/5, 1/3, 1/3, 1/3 ], orders := 
  4362.     [ 1, [ 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ], 
  4363.       [ 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ], 
  4364.       [ 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ], 
  4365.       [ 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ], 
  4366.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4367.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4368.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4369.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4370.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4371.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4372.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4373.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4374.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4375.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4376.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4377.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ], 
  4378.       [ 2, 4, 6, 8, 10, 12, 20, 24, 30, 40, 60, 120 ] ], powermap := 
  4379.     [ , [ 1, [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], 
  4380.           [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], 
  4381.           [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], 
  4382.           [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], 
  4383.           [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ], 
  4384.           [ 1, 2, 3, 4, 5 ], [ 1, 2, 3, 4, 5 ] ] ], irreducibles := 
  4385.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 
  4386.       [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1 ], 
  4387.       [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1 ], 
  4388.       [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1 ] 
  4389.      ], fusions := [ rec(
  4390.           name := "C2xC2",
  4391.           map := [ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 ] 
  4392.          ) ], operations := CharTableOps )|
  4393.  
  4394. Now  we   embed  the  subgroups  and  adjust  the   classlengths,  order,
  4395. centralizers, powermaps and thus the representative orders.
  4396.  
  4397. |    gap> StoreFusion( s1, split, [1,2,3,3,4,5,6,7,8,9,10]);
  4398.     gap> StoreFusion( s2, split, [1,2,3,4,5,5,11,12,13,14,15]);
  4399.     gap> StoreFusion( s3, split, [1,2,3,4,5,16,17,18]);
  4400.     gap> for tbl in [ s1, s2, s3 ] do
  4401.     >      fus:= GetFusionMap( tbl, split );
  4402.     >      for class in Difference( [ 1 .. Length( tbl.classes ) ],
  4403.     >                               KernelChar(tbl.irreducibles[2]) ) do
  4404.     >        split.classes[ fus[ class ] ]:= tbl.classes[ class ];
  4405.     >      od;
  4406.     >    od;
  4407.     gap> for class in [ 1 .. 5 ] do
  4408.     >      split.classes[ class ]:= s3.classes[ class ];
  4409.     >    od;
  4410.     gap> split.classes;
  4411.     [ 1, 45, 80, 90, 144, 15, 15, 90, 120, 120, 36, 90, 90, 72, 72, 180,
  4412.       90, 90 ]
  4413.     gap> split.order:= Sum( last );
  4414.     1440
  4415.     gap> split.centralizers:= List( last2, x -> split.order / x );
  4416.     [ 1440, 32, 18, 16, 10, 96, 96, 16, 12, 12, 40, 16, 16, 20, 20, 8, 
  4417.       16, 16 ]
  4418.     gap> split.powermap[3]:= InitPowermap( split, 3 );;
  4419.     gap> split.powermap[5]:= InitPowermap( split, 5 );;
  4420.     gap> for tbl in [ s1, s2, s3 ] do
  4421.     >      fus:= GetFusionMap( tbl, split );
  4422.     >      for p in [ 2, 3, 5 ] do
  4423.     >        TransferDiagram( tbl.powermap[p], fus, split.powermap[p] );
  4424.     >      od;
  4425.     >    od;
  4426.     gap> split.powermap;
  4427.     [ , [ 1, 1, 3, 2, 5, 1, 1, 2, 3, 3, 1, 4, 4, 5, 5, 2, 4, 4 ], 
  4428.       [ 1, 2, 1, 4, 5, 6, 7, 8, 6, 7, 11, 13, 12, 15, 14, 16, 17, 18 ],, 
  4429.       [ 1, 2, 3, 4, 1, 6, 7, 8, 9, 10, 11, 13, 12, 11, 11, 16, 18, 17 ] ]
  4430.     gap> split.orders:= ElementOrdersPowermap( split.powermap );
  4431.     [ 1, 2, 3, 4, 5, 2, 2, 4, 6, 6, 2, 8, 8, 10, 10, 4, 8, 8 ]|
  4432.  
  4433. In  order to decide which classes  fuse in $G$, we look  at  the norms of
  4434. suitable  induced  characters,  first  the  + extension  of  $\chi_2$  to
  4435. $A_6.2_1$.
  4436.  
  4437. |    gap> ind:= Induced( s1, split, [ s1.irreducibles[3] ] )[1];
  4438.     [ 10, 2, 1, -2, 0, 6, -2, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0 ]
  4439.     gap> ScalarProduct( split, ind, ind );
  4440.     3/2|
  4441.  
  4442. The inertia group  of this character is $A_6.2_1$,  thus  the norm of the
  4443. induced character  must be 1.  If  the classes  '2B' and '2C'  fuse,  the
  4444. contribution of these classes is changed from $15\cdot 6^2+15\cdot(-2)^2$
  4445. to $30  \cdot  2^2$, the difference is 480.  But we have to subtract  720
  4446. which is half the group  order, so also '6A' and  '6B' fuse.  This is not
  4447. surprising, since it reflects the action of the famous outer automorphism
  4448. of $S_6$.  Next we examine the + extension of $\chi_4$ to $A_6.2_2$.
  4449.  
  4450. |    gap> ind:= Induced( s2, split, [ s2.irreducibles[4] ] )[1];
  4451.     [ 16, 0, -2, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 2*E(5)+2*E(5)^4,
  4452.       2*E(5)^2+2*E(5)^3, 0, 0, 0 ]
  4453.     gap> ScalarProduct( split, ind, ind );
  4454.     3/2|
  4455.  
  4456. Again, the norm must be 1, '10A' and '10B' fuse.
  4457.  
  4458. |    gap> collaps:= CharTableCollapsedClasses( split,
  4459.     >                    [1,2,3,4,5,6,6,7,8,8,9,10,11,12,12,13,14,15] );
  4460.     rec( name := "Collapsed(Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3,\
  4461.      3, 3, 3, 3, 4, 4, 4 ]),[ 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12,\
  4462.      12, 13, 14, 15 ])", order := 1440, centralizers :=
  4463.     [ 1440, 32, 18, 16, 10, 48, 16, 6, 40, 16, 16, 10, 8, 16, 16
  4464.      ], orders := [ 1, 2, 3, 4, 5, 2, 4, 6, 2, 8, 8, 10, 4, 8, 8
  4465.      ], powermap := [ , [ 1, 1, 3, 2, 5, 1, 2, 3, 1, 4, 4, 5, 2, 4, 4 ],
  4466.       [ 1, 2, 1, 4, 5, 6, 7, 6, 9, 11, 10, 12, 13, 14, 15 ],,
  4467.       [ 1, 2, 3, 4, 1, 6, 7, 8, 9, 11, 10, 9, 13, 15, 14 ]
  4468.      ], fusionsource :=
  4469.     [ "Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 \
  4470.     ])" ], irreducibles :=
  4471.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  4472.       [ 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1 ],
  4473.       [ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1 ],
  4474.       [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1 ]
  4475.      ], classes := [ 1, 45, 80, 90, 144, 30, 90, 240, 36, 90, 90, 144,
  4476.       180, 90, 90 ], operations := CharTableOps )
  4477.     gap> split.fusions;
  4478.     [ rec(
  4479.           name := "C2xC2",
  4480.           map := [ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 ]
  4481.          ), rec(
  4482.           name :=
  4483.            "Collapsed(Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3,\
  4484.      3, 3, 4, 4, 4 ]),[ 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 12, 1\
  4485.     3, 14, 15 ])",
  4486.           map := [ 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 12, 13,
  4487.               14, 15 ] ) ]
  4488.     gap> for tbl in [ s1, s2, s3 ] do
  4489.     >      StoreFusion( tbl, collaps,
  4490.     >                   CompositionMaps( GetFusionMap( split, collaps ),
  4491.     >                                    GetFusionMap( tbl, split ) ) );
  4492.     >    od;
  4493.     gap> ind:= Induced( s1, collaps, [ s1.irreducibles[10] ] )[1];
  4494.     [ 20, -4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
  4495.     gap> ScalarProduct( collaps, ind, ind );
  4496.     1|
  4497.  
  4498. This character must be equal  to any induced  character of an irreducible
  4499. character  of degree 10  of $A_6.2_2$  and $A_6.2_3$.   That  means, '8A'
  4500. fuses with '8B', and '8C' with '8D'.
  4501.  
  4502. |    gap> a6v4:= CharTableCollapsedClasses( collaps,
  4503.     >     [1,2,3,4,5,6,7,8,9,10,10,11,12,13,13] );
  4504.     rec( name := "Collapsed(Collapsed(Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2\
  4505.     , 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 ]),[ 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 1\
  4506.     0, 11, 12, 12, 13, 14, 15 ]),[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, \
  4507.     12, 13, 13 ])", order := 1440, centralizers :=
  4508.     [ 1440, 32, 18, 16, 10, 48, 16, 6, 40, 8, 10, 8, 8 ], orders :=
  4509.     [ 1, 2, 3, 4, 5, 2, 4, 6, 2, 8, 10, 4, 8 ], powermap :=
  4510.     [ , [ 1, 1, 3, 2, 5, 1, 2, 3, 1, 4, 5, 2, 4 ],
  4511.       [ 1, 2, 1, 4, 5, 6, 7, 6, 9, 10, 11, 12, 13 ],,
  4512.       [ 1, 2, 3, 4, 1, 6, 7, 8, 9, 10, 9, 12, 13 ] ], fusionsource :=
  4513.     [ "Collapsed(Split(C2xC2,[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3\
  4514.     , 4, 4, 4 ]),[ 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 12, 13, 14\
  4515.     , 15 ])" ], irreducibles :=
  4516.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  4517.       [ 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1 ],
  4518.       [ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 ],
  4519.       [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1 ] ], classes :=
  4520.     [ 1, 45, 80, 90, 144, 30, 90, 240, 36, 180, 144, 180, 180
  4521.      ], operations := CharTableOps )
  4522.     gap> for tbl in [ s1, s2, s3 ] do
  4523.     >      StoreFusion( tbl, a6v4,
  4524.     >                   CompositionMaps( GetFusionMap( collaps, a6v4 ),
  4525.     >                                    GetFusionMap( tbl, collaps ) ) );
  4526.     >    od;|
  4527.  
  4528. Now the classes of $G$ are known, the only remaining work is  to  compute
  4529. the irreducibles.
  4530.  
  4531. |    gap> a6v4.irreducibles;
  4532.     [ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 
  4533.       [ 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1 ], 
  4534.       [ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 ], 
  4535.       [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1 ] ]
  4536.     gap> for tbl in [ s1, s2, s3 ] do
  4537.     >      ind:= Set( Induced( tbl, a6v4, tbl.irreducibles ) );
  4538.     >      Append( a6v4.irreducibles,
  4539.     >              Filtered( ind, x -> ScalarProduct( a6v4,x,x ) = 1 ) );
  4540.     >    od;
  4541.     gap> a6v4.irreducibles:= Set( a6v4.irreducibles );
  4542.     [ [ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1 ], 
  4543.       [ 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1 ], 
  4544.       [ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 ], 
  4545.       [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 
  4546.       [ 10, 2, 1, -2, 0, -2, -2, 1, 0, 0, 0, 0, 0 ], 
  4547.       [ 10, 2, 1, -2, 0, 2, 2, -1, 0, 0, 0, 0, 0 ], 
  4548.       [ 16, 0, -2, 0, 1, 0, 0, 0, -4, 0, 1, 0, 0 ], 
  4549.       [ 16, 0, -2, 0, 1, 0, 0, 0, 4, 0, -1, 0, 0 ], 
  4550.       [ 20, -4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ]
  4551.     gap> sym:= Symmetrizations( a6v4, [ a6v4.irreducibles[5] ], 2 );
  4552.     [ [ 45, -3, 0, 1, 0, -3, 1, 0, -5, 1, 0, -1, 1 ], 
  4553.       [ 55, 7, 1, 3, 0, 7, 3, 1, 5, -1, 0, 1, -1 ] ]
  4554.     gap> Reduced( a6v4, a6v4.irreducibles, sym );
  4555.     rec( 
  4556.       remainders := [ [ 27, 3, 0, 3, -3, 3, -1, 0, 1, -1, 1, 1, -1 ] ],
  4557.       irreducibles := [ [ 9, 1, 0, 1, -1, -3, 1, 0, -1, 1, -1, -1, 1 ] ] )
  4558.     gap> Append( a6v4.irreducibles,
  4559.     >            Tensored( last.irreducibles,
  4560.     >                      Sublist( a6v4.irreducibles, [ 1 .. 4 ] ) ) );
  4561.     gap> SortCharactersCharTable( a6v4,
  4562.     >                             (1,4)(2,3)(5,6)(7,8)(9,13,10,11,12) );;
  4563.     gap> a6v4.name:= "A6.2^2";;
  4564.     gap> DisplayCharTable( a6v4 );
  4565.     A6.2^2
  4566.     
  4567.         2  5  5  1  4  1  4  4  1  3  3   1  3  3
  4568.         3  2  .  2  .  .  1  .  1  .  .   .  .  .
  4569.         5  1  .  .  .  1  .  .  .  1  .   1  .  .
  4570.     
  4571.           1a 2a 3a 4a 5a 2b 4b 6a 2c 8a 10a 4c 8b
  4572.        2P 1a 1a 3a 2a 5a 1a 2a 3a 1a 4a  5a 2a 4a
  4573.        3P 1a 2a 1a 4a 5a 2b 4b 2b 2c 8a 10a 4c 8b
  4574.        5P 1a 2a 3a 4a 1a 2b 4b 6a 2c 8a  2c 4c 8b
  4575.     
  4576.     X.1    1  1  1  1  1  1  1  1  1  1   1  1  1
  4577.     X.2    1  1  1  1  1  1  1  1 -1 -1  -1 -1 -1
  4578.     X.3    1  1  1  1  1 -1 -1 -1  1  1   1 -1 -1
  4579.     X.4    1  1  1  1  1 -1 -1 -1 -1 -1  -1  1  1
  4580.     X.5   10  2  1 -2  .  2  2 -1  .  .   .  .  .
  4581.     X.6   10  2  1 -2  . -2 -2  1  .  .   .  .  .
  4582.     X.7   16  . -2  .  1  .  .  .  4  .  -1  .  .
  4583.     X.8   16  . -2  .  1  .  .  . -4  .   1  .  .
  4584.     X.9    9  1  .  1 -1 -3  1  .  1 -1   1  1 -1
  4585.     X.10   9  1  .  1 -1 -3  1  . -1  1  -1 -1  1
  4586.     X.11   9  1  .  1 -1  3 -1  .  1 -1   1 -1  1
  4587.     X.12   9  1  .  1 -1  3 -1  . -1  1  -1  1 -1
  4588.     X.13  20 -4  2  .  .  .  .  .  .  .   .  .  .|
  4589.  
  4590. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4591. \Section{About Group Libraries}
  4592.  
  4593. When you start {\GAP} it already knows several groups.  For example, some
  4594. basic  groups  such as cyclic  groups or symmetric groups, all  primitive
  4595. permutation groups of degree at most 50, and all 2-groups of size at most
  4596. 256.
  4597.  
  4598. Each of the sets  above  is called a *group  library*.   The set  of  all
  4599. groups that  {\GAP} knows  initially is called  the  *collection of group
  4600. libraries*.
  4601.  
  4602. In  this  section we  show  you how you  can  access the groups in  those
  4603. libraries and how you can extract  groups with  certain  properties  from
  4604. those libraries.
  4605.  
  4606. Let us start with the basic  groups, because they are not accessed in the
  4607. same way as the groups in the other libraries.
  4608.  
  4609. To access such a basic group you just call a function with an appropriate
  4610. name, such as 'CyclicGroup' or 'SymmetricGroup'.
  4611.  
  4612. |    gap> c13 := CyclicGroup( 13 );
  4613.     Group( ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13) )
  4614.     gap> Size( c13 );
  4615.     13
  4616.     gap> s8 := SymmetricGroup( 8 );
  4617.     Group( (1,8), (2,8), (3,8), (4,8), (5,8), (6,8), (7,8) )
  4618.     gap> Size( s8 );
  4619.     40320 |
  4620.  
  4621. The functions above also accept an optional first argument that describes
  4622. the type of group.   For example you can pass 'AgWords' to  'CyclicGroup'
  4623. to  get a  cyclic  group  as  a  finite  polycyclic  group  (see  "Finite
  4624. Polycyclic Groups").
  4625.  
  4626. |    gap> c13 := CyclicGroup( AgWords, 13 );
  4627.     Group( c13 ) |
  4628.  
  4629. Of  course  you   cannot  pass  'AgWords'  to  'SymmetricGroup',  because
  4630. symmetric groups are in general not polycyclic.
  4631.  
  4632. The default is to construct the groups as permutation groups, but you can
  4633. also  explicitly  pass  'Permutations'.   Other  possible  arguments  are
  4634. 'AgWords' for finite polycyclic  groups, 'Words' for  finitely  presented
  4635. groups, and 'Matrices' for matrix groups (however only 'Permutations' and
  4636. 'AgWords' currently work).
  4637.  
  4638. Let us now turn to the  other  libraries.   They  are all  accessed in  a
  4639. uniform  way.  For a  first example  we  will use  the  group library  of
  4640. primitive permutation groups.
  4641.  
  4642. To extract a group from a group library you generally use the *extraction
  4643. function*.  In  our example this function is called 'PrimitiveGroup'.  It
  4644. takes  two  arguments.   The  first  is  the  degree  of  the   primitive
  4645. permutation  group  that  you want  and  the second  is  an  integer that
  4646. specifies which of  the primitive permutation groups  of that  degree you
  4647. want.
  4648.  
  4649. |    gap> g := PrimitiveGroup( 12, 3 );
  4650.     M(11)
  4651.     gap> g.generators;
  4652.     [ ( 2, 6)( 3, 5)( 4, 7)( 9,10), ( 1, 5, 7)( 2, 9, 4)( 3, 8,10),
  4653.       ( 1,11)( 2, 7)( 3, 5)( 4, 6), ( 2, 5)( 3, 6)( 4, 7)(11,12) ]
  4654.     gap> Size( g );
  4655.     7920
  4656.     gap> IsSimple( g );
  4657.     true
  4658.     gap> h := PrimitiveGroup( 16, 19 );
  4659.     2^4.A(7)
  4660.     gap> Size( h );
  4661.     40320 |
  4662.  
  4663. The reason for the extraction function is as follows.  A group library is
  4664. usually  not  stored  as  a  list  of  groups.   Instead a  more  compact
  4665. representation for  the groups is used.   For  example  the groups in the
  4666. library  of  2-groups are  represented  by 4  integers.   The  extraction
  4667. function hides this representation from you, and allows you to access the
  4668. group library  as  if it was  a  table of groups  (two dimensional in the
  4669. above example).
  4670.  
  4671. What  arguments  the  extraction  function  accepts,  and  how  they  are
  4672. interpreted  is described in  the  sections that describe the  individual
  4673. group libraries in chapter  "Group  Libraries".  Those  functions will of
  4674. course signal an error when you pass illegal arguments.
  4675.  
  4676. Suppose that  you want to get a list of  all primitive permutation groups
  4677. that have  a degree  10 and are simple  but not cyclic.  It would be very
  4678. difficult  to use the extraction  function to extract  all groups in  the
  4679. group library,  and  test each  of those.  It is much simpler to  use the
  4680. *selection  function*.   The name of the selection function always begins
  4681. with  'All' and ends with  'Groups', in our  example  it  is  thus called
  4682. 'AllPrimitiveGroups'.
  4683.  
  4684. |    gap> AllPrimitiveGroups( DegreeOperation,   10,
  4685.     >                        IsSimple,          true,
  4686.     >                        IsCyclic,          false );
  4687.     [ A(5), PSL(2,9), A(10) ] |
  4688.  
  4689. 'AllPrimitiveGroups' takes a variable number of argument pairs consisting
  4690. of a  function  (e.g.  'DegreeOperation') and  a value  (e.g.   10).   To
  4691. understand what 'AllPrimitiveGroups' does, imagine that the group library
  4692. was stored  as a long list  of permutation groups.   'AllPrimitiveGroups'
  4693. takes all those groups  in  turn.  To each group it applies each function
  4694. argument and compares the result  with the corresponding value  argument.
  4695. It selects a group if and  only  if all the function results are equal to
  4696. the corresponding value.  So in our  example 'AllPrimitiveGroups' selects
  4697. those  groups  <g>   for   which  'DegreeOperation(<g>)   =   10'   *and*
  4698. 'IsSimple(<g>)  =  true'   *and*   'IsCyclic(<g>)   =   false'.   Finally
  4699. 'AllPrimitiveGroups' returns the list of the selected groups.
  4700.  
  4701. Next suppose that you want all the primitive permutation groups that have
  4702. degree  *at most*  10,  are simple but are not cyclic.  You  could obtain
  4703. such a list with 10 calls to 'AllPrimitiveGroups' (i.e., one call for the
  4704. degree 1 groups, another for the degree 2 groups and so on), but there is
  4705. a simple  way.  Instead of specifying a single value that a function must
  4706. return you can simply specify a list of such values.
  4707.  
  4708. |    gap> AllPrimitiveGroups( DegreeOperation,   [1..10],
  4709.     >                        IsSimple,          true,
  4710.     >                        IsCyclic,          false );
  4711.     [ A(5), PSL(2,5), A(6), PSL(3,2), A(7), PSL(2,7), A(8), PSL(2,8),
  4712.       A(9), A(5), PSL(2,9), A(10) ] |
  4713.  
  4714. Note that  the  list that  you get  contains  'A(5)' twice,  first in its
  4715. primitive   presentation  on  5  points  and   second  in  its  primitive
  4716. presentation on 10 points.
  4717.  
  4718. Thus  giving several argument pairs  to the selection function allows you
  4719. to  express the logical *and* of properties that a group  must have to be
  4720. selected,  and  giving  a  list   of  values  allows  you  to  express  a
  4721. (restricted) logical *or*  of properties  that a  group must  have to  be
  4722. selected.
  4723.  
  4724. There  is  no restriction on the functions that  you can use.  It is even
  4725. possible to use functions that you have written yourself.  Of course, the
  4726. functions must be unary, i.e., accept only one argument, and must be able
  4727. to deal with the groups.
  4728.  
  4729. |    gap> NumberConjugacyClasses := function ( g )
  4730.     >        return Length( ConjugacyClasses( g ) );
  4731.     > end;
  4732.     function ( g ) ... end
  4733.     gap> AllPrimitiveGroups( DegreeOperation,           [1..10],
  4734.     >                        IsSimple,                  true,
  4735.     >                        IsCyclic,                  false,
  4736.     >                        NumberConjugacyClasses,    9 );
  4737.     [ A(7), PSL(2,8) ] |
  4738.  
  4739. Note that in some cases a selection function  will issue a warning.   For
  4740. example if you call 'AllPrimitiveGroups'  without  specifying the degree,
  4741. it will issue such a warning.
  4742.  
  4743. |    gap> AllPrimitiveGroups( Size,      [100..400],
  4744.     >                        IsSimple,  true,
  4745.     >                        IsCyclic,  false );
  4746.     &W  AllPrimitiveGroups: degree automatically restricted to [1..50]
  4747.     [ A(6), PSL(3,2), PSL(2,7), PSL(2,9), A(6) ] |
  4748.  
  4749. If selection functions would really run over the list of all groups in  a
  4750. group  library  and apply the  function arguments to  each of those, they
  4751. would be  very inefficient.   For  example the  2-groups library contains
  4752. 58760 groups.  Simply  creating all those groups would take  a  very long
  4753. time.
  4754.  
  4755. Instead selection functions  recognize certain functions  and handle them
  4756. more    efficiently.    For   example   'AllPrimitiveGroups'   recognizes
  4757. 'DegreeOperation'.  If you pass 'DegreeOperation' to 'AllPrimitiveGroups'
  4758. it does not create a group to apply  'DegreeOperation' to it.  Instead it
  4759. simply consults  an index and quickly eliminates  all groups  that have a
  4760. different degree.  Other functions recognized by 'AllPrimitiveGroups' are
  4761. 'IsSimple', 'Size', and 'Transitivity'.
  4762.  
  4763. So in our examples  'AllPrimitiveGroups',  recognizing  'DegreeOperation'
  4764. and 'IsSimple',  eliminates  all but 16 groups.  Then it creates those 16
  4765. groups and  applies 'IsCyclic'  to them.  This eliminates 4  more  groups
  4766. ('C(2)', 'C(3)',  'C(5)', and  'C(7)').   Then in  our  last  example  it
  4767. applies  'NumberConjugacyClasses'  to   the  remaining   12   groups  and
  4768. eliminates all but 'A(7)' and 'PSL(2,8)'.
  4769.  
  4770. The catch is that the  selection  functions will  take a large amount  of
  4771. time  if they cannot  recognize any special  functions.  For example  the
  4772. following selection  will  take a  large  amount  of  time, because  only
  4773. 'IsSimple'  is  recognized,  and  there  are  116  simple  groups in  the
  4774. primitive groups library.
  4775.  
  4776. |    AllPrimitiveGroups( IsSimple, true, NumberConjugacyClasses, 9 );|
  4777.  
  4778. So you should specify as sufficiently large set of recognizable functions
  4779. when  you call  a selection function.   It is also advisable to put those
  4780. functions first (though in some group  libraries  the  selection function
  4781. will  automatically  rearrange the argument pairs so  that the recognized
  4782. functions come first).   The  sections  describing the  individual  group
  4783. libraries  in  chapter  "Group  Libraries"  tell you which  functions are
  4784. recognized by the selection function of that group library.
  4785.  
  4786. There is  another function,  called  the *example function*  that behaves
  4787. similar  to  the selection function.  Instead of returning a list of  all
  4788. groups with  a certain set of properties it  only returns one such group.
  4789. The name of the example function is obtained by replacing  'All' by 'One'
  4790. and stripping the 's' at the end of the name of the selection function.
  4791.  
  4792. |    gap> OnePrimitiveGroup( DegreeOperation,           [1..10],
  4793.     >                       IsSimple,                  true,
  4794.     >                       IsCyclic,                  false,
  4795.     >                       NumberConjugacyClasses,    9 );
  4796.     A(7) |
  4797.  
  4798. The example function works just like  the selection function.  That means
  4799. that  all  the  above  comments  about  the special  functions  that  are
  4800. recognized also apply to the example function.
  4801.  
  4802. Let us now look  at the 2-groups library.  It is accessed in the same way
  4803. as  the  primitive  groups  library.   There  is  an extraction  function
  4804. 'TwoGroup', a selection function 'AllTwoGroups', and  an example function
  4805. 'OneTwoGroup'.
  4806.  
  4807. |    gap> g := TwoGroup( 128, 5 );
  4808.     Group( a1, a2, a3, a4, a5, a6, a7 )
  4809.     gap> Size( g );
  4810.     128
  4811.     gap> NumberConjugacyClasses( g );
  4812.     80 |
  4813.  
  4814. The groups are all displayed as 'Group( a1, a2, ..., a<n> )', where $2^n$
  4815. is the size of the group.
  4816.  
  4817. |    gap> AllTwoGroups( Size,   256,
  4818.     >                  Rank,   3,
  4819.     >                  pClass, 2 );
  4820.     [ Group( a1, a2, a3, a4, a5, a6, a7, a8 ),
  4821.       Group( a1, a2, a3, a4, a5, a6, a7, a8 ),
  4822.       Group( a1, a2, a3, a4, a5, a6, a7, a8 ),
  4823.       Group( a1, a2, a3, a4, a5, a6, a7, a8 ) ]
  4824.     gap> l := AllTwoGroups( Size,                              256,
  4825.     >                       Rank,                              3,
  4826.     >                       pClass,                            5,
  4827.     >                       g -> Length( DerivedSeries( g ) ), 4 );;
  4828.     gap> Length( l );
  4829.     28 |
  4830.  
  4831. The  selection  and example  function  of the 2-groups  library recognize
  4832. 'Size',  'Rank',  and  'pClass'.   Note  that  'Rank'  and  'pClass'  are
  4833. functions that can in fact only  be  used in this context, i.e., they can
  4834. not be applied to arbitrary groups.
  4835.  
  4836. The following discussion is a bit technical and you can ignore it safely.
  4837.  
  4838. For  very  big  group libraries, such as the 2-groups library, the groups
  4839. (or their compact representations) are not stored on a single file.  This
  4840. is because this file would be very large and loading it would take a long
  4841. time and a lot of main memory.
  4842.  
  4843. Instead the groups are stored on a small number of files (27  in the case
  4844. of the 2-groups).   The selection  and example  functions  are careful to
  4845. load only those files that may actually contain groups with the specified
  4846. properties.  For example in the  above example the  files containing  the
  4847. groups of  size  less than 256 are never  loaded.  In fact  in the  above
  4848. example only one very small file is loaded.
  4849.  
  4850. When a file is loaded the selection and example functions also unload the
  4851. previously loaded  file.  That means that  they forget all the groups  in
  4852. this file  again (except those selected of  course).   Thus  even if  the
  4853. selection or  example  functions  have to search through  the whole group
  4854. library, only a  small part of the library is held in  main memory at any
  4855. time.   In principle it should  be possible to search the  whole 2-groups
  4856. library with as little as 2 MByte of main memory.
  4857.  
  4858. If you have  sufficient main memory  available you  can  explicitly  load
  4859. files  from the 2-groups  library  with  'ReadTwo(  <filename> )',  e.g.,
  4860. 'Read( \"twogp64\" )' to load the file with the groups of size 64.  Those
  4861. files will  then not  be unloaded again.   This  will take  up  more main
  4862. memory, but the  selection and example function will work faster, because
  4863. they do not have to load those files again each time they are needed.
  4864.  
  4865. In  this section  you have seen  the basic groups library  and  the group
  4866. libraries of primitive  groups and 2-groups.  You have seen how  you  can
  4867. extract a single group from such a library with the  extraction function.
  4868. You  have seen how you can select groups with certain properties with the
  4869. selection  and example function.   Chapter  "Group  Libraries"  tells you
  4870. which other group libraries are available.
  4871.  
  4872. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4873. \Section{About the Implementation of Domains}
  4874.  
  4875. In this section we will open the black  boxes  and describe  how all this
  4876. works.  This is complex and  you do not need to understand  it if you are
  4877. content to use domains only as black boxes.  So you may want to skip this
  4878. section (and the remainder of this chapter).
  4879.  
  4880. Domains are represented  by records, which we will call *domain  records*
  4881. in the following.  Which components have  to  be present,  which may, and
  4882. what  those components hold, differs from category to category, and, to a
  4883. smaller  extent,  from  domain  to domain.   It  is  possible, though, to
  4884. generally distinguish four types of components.
  4885.  
  4886. The  first type of components are called the *category components*.  They
  4887. determine to which category a domain belongs.  A domain <D> in a category
  4888. <Cat> has a component 'is<Cat>' with the value 'true'.  For example, each
  4889. group has the  component  'isGroup'.  Also each domain has  the component
  4890. 'isDomain' (again with the value 'true').  Finally a domain may also have
  4891. components that describe the representation of this domain.  For example,
  4892. each permutation  group  has  a component  'isPermGroup' (again with  the
  4893. value  'true').  Functions such  as  'IsPermGroup'  test  whether such  a
  4894. component is present, and whether it has the value 'true'.
  4895.  
  4896. The second type of components are called the *identification components*.
  4897. They distinguish the domain from other domains in the same category.  The
  4898. identification components uniquely identify the domain.  For example, for
  4899. groups the identification components are 'generators', which holds a list
  4900. of generators  of the group, and 'identity', which  holds the identity of
  4901. the group (needed for the trivial group, for which the list of generators
  4902. is empty).
  4903.  
  4904. The third type of  components are called *knowledge   components*.   They
  4905. hold all the knowledge {\GAP} has about the domain.  For example the size
  4906. of the domain <D>  is  stored in the  knowledge component '<D>.size', the
  4907. commutator subgroup of  a  group is stored   in  the  knowledge component
  4908. '<D>.commutatorSubgroup', etc.  Of  course, the knowledge about a certain
  4909. domain will usually increase as you  work with a domain.  For  example, a
  4910. group record may  initially hold  only the knowledge  that the  group  is
  4911. finite,  but may  later hold all   kinds  of knowledge, for  example  the
  4912. derived series, the Sylow subgroups, etc.
  4913.  
  4914. Finally  each  domain  record  contains   an *operations  record*.    The
  4915. operations record is discussed below.
  4916.  
  4917. We want to  emphasize that really all information that {\GAP} has about a
  4918. domain is stored  in  the knowledge components.  That  means that you can
  4919. access all this information, at least if you know  where to  look and how
  4920. to  interpret  what you see.   The  chapters  describing  categories  and
  4921. domains  will tell you  what  knowledge components a domain may have, and
  4922. how the knowledge is represented in those components.
  4923.  
  4924. For an example let us return  to the permutation group 'a5' from  section
  4925. "About  Domains  and  Categories".   If  we print  the  record  using the
  4926. function  'PrintRec'  we  see all the  information.   {\GAP}  stores  the
  4927. stabilizer chain of  'a5' in the  components 'orbit',  'transversal', and
  4928. 'stabilizer'.  It is not important that you understand what  a stabilizer
  4929. chain  is  (this  is  discussed  in  chapter "Permutation  Groups"),  the
  4930. important  point here  is that it  is the  vital  information that {\GAP}
  4931. needs to work efficiently with 'a5' and that you can access it.
  4932.  
  4933. |    gap> a5 := Group( (1,2,3), (3,4,5) );
  4934.     Group( (1,2,3), (3,4,5) )
  4935.     gap> Size( a5 );
  4936.     60
  4937.     gap> PrintRec( a5 );  Print( "\n" );
  4938.     rec(
  4939.       isDomain    := true,
  4940.       isGroup     := true,
  4941.       identity    := (),
  4942.       generators  := [ (1,2,3), (3,4,5) ],
  4943.       operations  := ...,
  4944.       isPermGroup := true,
  4945.       isFinite    := true,
  4946.       1           := (1,2,3),
  4947.       2           := (3,4,5),
  4948.       orbit       := [ 1, 3, 2, 5, 4 ],
  4949.       transversal := [ (), (1,2,3), (1,2,3), (3,4,5), (3,4,5) ],
  4950.       stabilizer  := rec(
  4951.         identity    := (),
  4952.         generators  := [ (3,4,5), (2,5,3) ],
  4953.         orbit       := [ 2, 3, 5, 4 ],
  4954.         transversal := [ , (), (2,5,3), (3,4,5), (3,4,5) ],
  4955.         stabilizer  := rec(
  4956.           identity    := (),
  4957.           generators  := [ (3,4,5) ],
  4958.           orbit       := [ 3, 5, 4 ],
  4959.           transversal := [ ,, (), (3,4,5), (3,4,5) ],
  4960.           stabilizer  := rec(
  4961.             identity   := (),
  4962.             generators := [  ],
  4963.             operations := ... ),
  4964.           operations  := ... ),
  4965.         operations  := ... ),
  4966.       size        := 60 ) |
  4967.  
  4968. Note that you can not only read this information, you can also modify it.
  4969. However, unless you  truly understand what  you are doing,  we discourage
  4970. you  from   playing around.     All  {\GAP}  functions   assume  that the
  4971. information in the domain record is in a consistent state, and everything
  4972. will go wrong if it is not.
  4973.  
  4974. |    gap> a5.size := 120;
  4975.     120
  4976.     gap> Size( ConjugacyClass( a5, (1,2,3,4,5) ) );
  4977.     24    # this is of course wrong |
  4978.  
  4979. As was mentioned above, each domain record has an operations  record.  We
  4980. have already seen that functions such as 'Size' can be applied to various
  4981. types of domains.  It is clear that there  is no general method that will
  4982. compute  the size  of all  domains efficiently.   So 'Size'  must somehow
  4983. decide which method to  apply to  a given  domain.  The operations record
  4984. makes this possible.
  4985.  
  4986. The operations  record of a domain  <D>  is the component  with  the name
  4987. '<D>.operations', its value is a record.  For each function that  you can
  4988. apply  to <D> this  record contains  a  function  that will  compute  the
  4989. required information (hopefully in an efficient way).
  4990.  
  4991. To understand  this let us take  a  look at what happens  when we compute
  4992. 'Size(    a5   )'.    Not    much   happens.     'Size'   simply    calls
  4993. 'a5.operations.Size(  a5 )'.  'a5.operations.Size'  is a function written
  4994. especially for permutation groups.   It computes  the size  of  'a5'  and
  4995. returns it.  Then 'Size' returns this value.
  4996.  
  4997. Actually 'Size' does a little bit more than that.  It first tests whether
  4998. 'a5' has the knowledge component 'a5.size'.  If this is  the case, 'Size'
  4999. simply returns that value.  Otherwise it calls 'a5.operations.Size( a5 )'
  5000. to  compute   the size.  'Size'  remembers   the result in  the knowledge
  5001. component 'a5.size' so that it is readily available the  next time 'Size(
  5002. a5 )' is called.  The complete definition of 'Size' is as follows.
  5003.  
  5004. |    Size := function ( D )
  5005.         local   size;
  5006.         if IsSet( D )  then
  5007.             size := Length( D );
  5008.         elif IsDomain( D )  and IsBound( D.size )  then
  5009.             size := D.size;
  5010.         elif IsDomain( D )  then
  5011.             D.size := D.operations.Size( D );
  5012.             size := D.size;
  5013.         else
  5014.             Error("<D> must be a domain or a set");
  5015.         fi;
  5016.         return size;
  5017.     end; |
  5018.  
  5019. Because  functions such as 'Size'  only  dispatch to the functions in the
  5020. operations record, they  are called  *dispatcher functions*.  Almost  all
  5021. functions that you call directly are dispatcher functions, and almost all
  5022. functions that do the hard work are components in an operations record.
  5023.  
  5024. Which function is called by a dispatcher obviously depends on  the domain
  5025. and its  operations  record  (that  is  the  whole  point  of  having  an
  5026. operations record).  In principle each domain could  have  its own 'Size'
  5027. function.  In  practice however, this would  require too many  functions.
  5028. So  different domains share the functions  in  their operations  records,
  5029. usually  all  domains  with  the  same  representation  share  all  their
  5030. operations record  functions.  For example all  permutation  groups share
  5031. the same 'Size' function.  Because this  shared  'Size' function must  be
  5032. able  to access  the  information in  the  domain  record to compute  the
  5033. correct result, the 'Size' dispatcher function (and all other dispatchers
  5034. as well) pass the domain as first argument
  5035.  
  5036. In fact the domains not only have  the same functions in their operations
  5037. record, they share the operations record.  So for example all permutation
  5038. groups share a  common operations record, which is called 'PermGroupOps'.
  5039. This means that changing a function in the operations record for a domain
  5040. <D> in the following  way '<D>.operations.<function> \:= <new-function>;'
  5041. will  also change this function for  all domains  of  the same type, even
  5042. those that do not yet exist at the moment of the assignment and will only
  5043. be constructed later.   This  is  usually not desirable, since supposedly
  5044. <new-function>  uses  some  special  properties of the domain <D> to work
  5045. more efficiently.  We suggest therefore that you first make a copy of the
  5046. operations record with '<D>.operations \:= Copy(  <D>.operations );'  and
  5047. only afterwards do '<D>.operations.<function> \:= <new-function>;'.
  5048.  
  5049. If a programmer that  implements a new domain <D>,  a  new type of groups
  5050. say, would have  to write all  functions  applicable  to  <D>, this would
  5051. require a lot  of  effort.   For example,  there are about 120  functions
  5052. applicable to groups.  Luckily many of those functions are independent of
  5053. the  particular type of groups.  For example the following function  will
  5054. compute  the   commutator   subgroup   of   any   group,  assuming   that
  5055. 'TrivialSubgroup', 'Closure', and 'NormalClosure' work.  We say that this
  5056. function is *generic*.
  5057.  
  5058. |    GroupOps.CommutatorSubgroup := function ( U, V )
  5059.         local   C, u, v, c;
  5060.         C := TrivialSubgroup( U );
  5061.         for u  in U.generators  do
  5062.             for v  in V.generators  do
  5063.                 c := Comm( u, v );
  5064.                 if not c in C  then
  5065.                     C := Closure( C, c );
  5066.                 fi;
  5067.             od;
  5068.         od;
  5069.         return NormalClosure( Closure( U, V ), C );
  5070.     end; |
  5071.  
  5072. So it should be possible to use this function for the new type of groups.
  5073. The mechanism  to do  this is  called *inheritance*.   How  it  works  is
  5074. described in "About  Defining  New Domains", but basically the programmer
  5075. just  copies the generic  functions from  the  generic  group  operations
  5076. record into the operations record for his new type of groups.
  5077.  
  5078. The generic functions  are also called  *default functions*, because they
  5079. are used by  default, unless the  programmer  *overlaid* them for the new
  5080. type of groups.
  5081.  
  5082. There is another mechanism  through which work can be  simplified.  It is
  5083. called *delegation*.  Suppose that  a  generic function works for the new
  5084. type of  groups,  but  that  some  special  cases  can  be  handled  more
  5085. efficiently for  the new type of  groups.  Then it is possible  to handle
  5086. only  those cases  and delegate  the  general  cases back  to the generic
  5087. function.  An example  of this is the function that computes the orbit of
  5088. a point under a permutation  group.  If the point is an integer  then the
  5089. generic algorithm can be improved by keeping a second list that remembers
  5090. which  points have  already  been seen.   The other cases (remember  that
  5091. 'Orbit' can also be used for  other operations, e.g., the operation of  a
  5092. permutation group on  pairs  of points or the operations on  subgroups by
  5093. conjugation)  are delegated back  to the generic  function.  How  this is
  5094. done can be seen in the following definition.
  5095.  
  5096. |    PermGroupOps.Orbit := function ( G, d, opr )
  5097.         local   orb,        # orbit of <d> under <G>, result
  5098.                 max,        # largest point moved by the group <G>
  5099.                 new,        # boolean list indicating if a point is new
  5100.                 gen,        # one generator of the group <G>
  5101.                 pnt,        # one point in the orbit <orb>
  5102.                 img;        # image of <pnt> under <gen>
  5103.  
  5104.         # standard operation
  5105.         if   opr = OnPoints  and IsInt(d)  then
  5106.  
  5107.             # get the largest point <max> moved by the group <G>
  5108.             max := 0;
  5109.             for gen  in G.generators  do
  5110.                 if max < LargestMovedPointPerm(gen)  then
  5111.                     max := LargestMovedPointPerm(gen);
  5112.                 fi;
  5113.             od;
  5114.  
  5115.             # handle fixpoints
  5116.             if not d in [1..max]  then
  5117.                 return [ d ];
  5118.             fi;
  5119.  
  5120.             # start with the singleton orbit
  5121.             orb := [ d ];
  5122.             new := BlistList( [1..max], [1..max] );
  5123.             new[d] := false;
  5124.  
  5125.             # loop over all points found
  5126.             for pnt  in orb  do
  5127.                 for gen  in G.generators  do
  5128.                     img := pnt ^ gen;
  5129.                     if new[img]  then
  5130.                         Add( orb, img );
  5131.                         new[img] := false;
  5132.                     fi;
  5133.                 od;
  5134.             od;
  5135.  
  5136.         # other operation, delegate back on default function
  5137.         else
  5138.             orb := GroupOps.Orbit( G, d, opr );
  5139.         fi;
  5140.  
  5141.         # return the orbit <orb>
  5142.         return orb;
  5143.     end; |
  5144.  
  5145. Inheritance  and delegation allow the programmer to implement a new  type
  5146. of  groups  by merely  specifying  how  those groups differ  from generic
  5147. groups.   This is far less  work than  having  to implement  all possible
  5148. functions (apart  from  the problem  that in this case it is very  likely
  5149. that the programmer would forget some of the more exotic functions).
  5150.  
  5151. To make all  this clearer let  us look at an extended example to show you
  5152. how a computation  in a domain may use  default and special  functions to
  5153. achieve its goal.  Suppose you defined 'g', 'x', and 'y' as follows.
  5154.  
  5155. |    gap> g := SymmetricGroup( 8 );;
  5156.     gap> x := [ (2,7,4)(3,5), (1,2,6)(4,8) ];;
  5157.     gap> y := [ (2,5,7)(4,6), (1,5)(3,8,7) ];; |
  5158.  
  5159. Now you ask  for an  element  of 'g' that  conjugates 'x' to 'y', i.e., a
  5160. permutation on 8  points that  takes '(2,7,4)(3,5)' to '(2,5,7)(4,6)' and
  5161. '(1,2,6)(4,8)'  to  '(1,5)(3,8,7)'.    This  is   done  as  follows  (see
  5162. "RepresentativeOperation" and "Other Operations").
  5163.  
  5164. |    gap> RepresentativeOperation( g, x, y, OnTuples );
  5165.     (1,8)(2,7)(3,4,5,6) |
  5166.  
  5167. Now   lets    look    at   what    happens   step   for   step.     First
  5168. 'RepresentativeOperation'  is  called.  After checking  the  arguments it
  5169. calls the function  'g.operations.RepresentativeOperation', which is  the
  5170. function    'SymmetricGroupOps.RepresentativeOperation',    passing   the
  5171. arguments 'g', 'x', 'y', and 'OnTuples'.
  5172.  
  5173. 'SymmetricGroupOps.RepresentativeOperation'  handles  a  lot   of   cases
  5174. special, but  the operation on tuples of permutations is not among  them.
  5175. Therefore it  delegates this problem to the function  that  it  overlays,
  5176. which is 'PermGroupOps.RepresentativeOperation'.
  5177.  
  5178. 'PermGroupOps.RepresentativeOperation' also does  not handle this special
  5179. case, and delegates the problem  to the function that it  overlays, which
  5180. is the default function called 'GroupOps.RepresentativeOperation'.
  5181.  
  5182. 'GroupOps.RepresentativeOperation' views this problem as a general tuples
  5183. problem, i.e., it  does not  care  whether  the  points in the tuples are
  5184. integers or permutations, and decides to solve it one step at a time.  So
  5185. first it looks for  an element taking '(2,7,4)(3,5)' to '(2,5,7)(4,6)' by
  5186. calling 'RepresentativeOperation( g, (2,7,4)(3,5), (2,5,7)(4,6) )'.
  5187.  
  5188. 'RepresentativeOperation'  calls   'g.operations.RepresentativeOperation'
  5189. next, which is  the function 'SymmetricGroupOps.RepresentativeOperation',
  5190. passing the arguments 'g', '(2,7,4)(3,5)', and '(2,5,7)(4,6)'.
  5191.  
  5192. 'SymmetricGroupOps.RepresentativeOperation'  can  handle this  case.   It
  5193. *knows* that 'g'  contains every permutation on  8 points, so it contains
  5194. '(3,4,7,5,6)', which obviously does what we  want, namely it takes 'x[1]'
  5195. to 'y[1]'.  We will call this element 't'.
  5196.  
  5197. Now 'GroupOps.RepresentativeOperation' (see above) looks for  an  's'  in
  5198. the stabilizer of 'x[1]' taking 'x[2]' to 'y[2]\^(t\^-1)', since then for
  5199. 'r=s\*t'  we have 'x[1]\^r  =  (x[1]\^s)\^t  =  x[1]\^t = y[1]'  and also
  5200. 'x[2]\^r = (x[2]\^s)\^t = (y[2]\^(t\^-1))\^t = y[2]'.   So the next  step
  5201. is  to  compute  the stabilizer  of 'x[1]' in 'g'.  To  do  this it calls
  5202. 'Stabilizer( g, (2,7,4)(3,5) )'.
  5203.  
  5204. 'Stabilizer'     calls      'g.operations.Stabilizer',      which      is
  5205. 'SymmetricGroupOps.Stabilizer',    passing   the    arguments   'g'   and
  5206. '(2,7,4)(3,5)'.  'SymmetricGroupOps.Stabilizer' detects  that  the second
  5207. argument is a  permutation,  i.e.,  an  element of  the group,  and calls
  5208. 'Centralizer(  g,  (2,7,4)(3,5)  )'.   'Centralizer'  calls the  function
  5209. 'g.operations.Centralizer',  which   is  'SymmetricGroupOps.Centralizer',
  5210. again passing the arguments 'g', '(2,7,4)(3,5)'.
  5211.  
  5212. 'SymmetricGroupOps.Centralizer'   again  *knows*   how   centralizer   in
  5213. symmetric   groups  look,   and   after   looking   at  the   permutation
  5214. '(2,7,4)(3,5)'  sharply  for  a  short while returns  the  centralizer as
  5215. 'Subgroup( g,  [ (1,6), (6,8),  (2,7,4), (3,5)  ] )', which we will  call
  5216. 'c'.   Note  that  'c'  is of  course not  a  symmetric group,  therefore
  5217. 'SymmetricGroupOps.Subgroup' gives it 'PermGroupOps' as operations record
  5218. and not 'SymmetricGroupOps'.
  5219.  
  5220. As explained above 'GroupOps.RepresentativeOperation' needs an element of
  5221. 'c' taking 'x[2]'  ('(1,2,6)(4,8)') to 'y[2]\^(t\^-1)'  ('(1,7)(4,6,8)').
  5222. So 'RepresentativeOperation( c, (1,2,6)(4,8), (1,7)(4,6,8) )' is  called.
  5223. 'RepresentativeOperation'     in     turn     calls     the      function
  5224. 'c.operations.RepresentativeOperation',  which   is,  since   'c'   is  a
  5225. permutation group,  the function  'PermGroupOps.RepresentativeOperation',
  5226. passing the arguments 'c', '(1,2,6)(4,8)', and '(1,7)(4,6,8)'.
  5227.  
  5228. 'PermGroupOps.RepresentativeOperation'  detects   that   the  points  are
  5229. permutations and and performs a backtrack  search through 'c'.  It  finds
  5230. and returns '(1,8)(2,4,7)(3,5)', which we call 's'.
  5231.  
  5232. Then   'GroupOps.RepresentativeOperation'    returns   'r    =   s\*t   =
  5233. (1,8)(2,7)(3,6)(4,5)', and we are done.
  5234.  
  5235. In  this example you have seen  how functions  use the structure of their
  5236. domain    to   solve   a   problem   most    efficiently,   for   example
  5237. 'SymmetricGroupOps.RepresentativeOperation' but also the backtrack search
  5238. in 'PermGroupOps.RepresentativeOperation', how they  use other functions,
  5239. for example 'SymmetricGroupOps.Stabilizer' called  'Centralizer', and how
  5240. they  delegate  cases which they can not handle  more efficiently back to
  5241. the        function        they        overlaid,        for       example
  5242. 'SymmetricGroupOps.RepresentativeOperation'         delegated          to
  5243. 'PermGroupOps.RepresentativeOperation', which in turn delegated to to the
  5244. function 'GroupOps.RepresentativeOperation'.
  5245.  
  5246. If  you think this  whole mechanism using  dispatcher  functions and  the
  5247. operations  record  is  overly  complex  let  us  look  at  some  of  the
  5248. alternatives.  This is even more technical than the previous part of this
  5249. section so you may want to skip the remainder of this section.
  5250.  
  5251. One alternative  would be to let the  dispatcher  know about  the various
  5252. types of domains, test which category  a domain lies in, and dispatch  to
  5253. an  appropriate function.  Then  we  would not need an operations record.
  5254. The dispatcher function 'CommutatorSubgroup' would then look as follows.
  5255. Note this is *not* how 'CommutatorSubgroup' is implemented in {\GAP}.
  5256.  
  5257. |    CommutatorSubgroup := function ( G )
  5258.         local   C;
  5259.         if IsAgGroup( G )  then
  5260.             C := CommutatorSubgroupAgGroup( G );
  5261.         elif IsMatGroup( G )  then
  5262.             C := CommutatorSubgroupMatGroup( G );
  5263.         elif IsPermGroup( G )  then
  5264.             C := CommutatorSubgroupPermGroup( G );
  5265.         elif IsFpGroup( G )  then
  5266.             C := CommutatorSubgroupFpGroup( G );
  5267.         elif IsFactorGroup( G )  then
  5268.             C := CommutatorSubgroupFactorGroup( G );
  5269.         elif IsDirectProduct( G )  then
  5270.             C := CommutatorSubgroupDirectProduct( G );
  5271.         elif IsDirectProductAgGroup( G )  then
  5272.             C := CommutatorSubgroupDirectProductAgGroup( G );
  5273.         elif IsSubdirectProduct( G )  then
  5274.             C := CommutatorSubgroupSubdirectProduct( G );
  5275.         elif IsSemidirectProduct( G )  then
  5276.             C := CommutatorSubgroupSemidirectProduct( G );
  5277.         elif IsWreathProduct( G )  then
  5278.             C := CommutatorSubgroupWreathProduct( G );
  5279.         elif IsGroup( G )  then
  5280.             C := CommutatorSubgroupGroup( G );
  5281.         else
  5282.             Error("<G> must be a group");
  5283.         fi;
  5284.         return C;
  5285.     end; |
  5286.  
  5287. You already see one problem with this approach.  The number of cases that
  5288. the  dispatcher functions  would have to test is  simply to large.  It is
  5289. even worse for set theoretic functions, because they would have to handle
  5290. all different types of domains (currently about 30).
  5291.  
  5292. The other problem arises when a programmer implements a new domain.  Then
  5293. he would  have  to  rewrite all dispatchers  and add a  new case to each.
  5294. Also the probability that the programmer forgets  one  dispatcher is very
  5295. high.
  5296.  
  5297. Another problem is that  inheritance becomes more difficult.  Instead  of
  5298. just copying one operations record the programmer would have to copy each
  5299. function that should be inherited.  Again the probability that he forgets
  5300. one is very high.
  5301.  
  5302. Another alternative would be  to  do completely without  dispatchers.  In
  5303. this  case  there  would  be  the  functions  'CommutatorSugroupAgGroup',
  5304. 'CommutatorSubgroupPermGroup', etc., and it  would be your responsibility
  5305. to call  the  right  function.   For  example to  compute the  size  of a
  5306. permutation group you would call 'SizePermGroup'  and to compute the size
  5307. of    a   coset   you    would   call   'SizeCoset'    (or   maybe   even
  5308. 'SizeCosetPermGroup').
  5309.  
  5310. The most  obvious problem  with  this  approach is  that it is  much more
  5311. cumbersome.  You would  always  have to know what  kind of domain you are
  5312. working with and which function you would have to call.
  5313.  
  5314. Another  problem  is that writing generic  functions would be impossible.
  5315. For example  the  above  generic  implementation of  'CommutatorSubgroup'
  5316. could  not work,  because for a  concrete  group  it  would have  to call
  5317. 'ClosurePermGroup' or 'ClosureAgGroup' etc.
  5318.  
  5319. If generic functions are impossible, inheritance and  delegation can  not
  5320. be used.  Thus for each type of domain all functions must be implemented.
  5321. This is clearly a lot of work, more work than we are willing to do.
  5322.  
  5323. So  we argue that  our  mechanism is the easiest possible that serves the
  5324. following two goals.  It is  reasonably  convenient for  you to use.   It
  5325. allows us to implement a large (and ever increasing) number of  different
  5326. types of domains.
  5327.  
  5328. This  may all sound a  lot like object oriented programming to you.  This
  5329. is not surprising because we want to solve the same problems that  object
  5330. oriented  programming  tries  to  solve.   Let  us  briefly  discuss  the
  5331. similarities and  differences to  object oriented programming, taking C++
  5332. as an example (because  it is probably  the widest known  object oriented
  5333. programming language  nowadays).   This  discussion is very technical and
  5334. again you may want to skip the remainder of this section.
  5335.  
  5336. Let us  first recall  the problems  that the  {\GAP} mechanism  wants  to
  5337. handle.
  5338.  
  5339. 1:      How can we  represent  domains in such  a way that we can  handle
  5340.         domains of different type in a common way?
  5341.  
  5342. 2:      How can we make it possible  to allow functions that take domains
  5343.         of  different  type  and  perform  the  same  operation for those
  5344.         domains (but using different methods)?
  5345.  
  5346. 3:      How can we make it possible that the implementation of a new type
  5347.         of domains  only requires  that one implements what distinguishes
  5348.         this new type of domains from domains of an old type (without the
  5349.         need to change any old code)?
  5350.  
  5351. For object oriented programming the  problems are  the  same, though  the
  5352. names  used  are  different.   We talk  about  domains,  object  oriented
  5353. programming  talks about objects,  and  we  talk about categories, object
  5354. oriented programming talks about classes.
  5355.  
  5356. 1:      How  can  we represent  objects in  such a way that we can handle
  5357.         objects  of different  classes  in a  common way  (e.g.,  declare
  5358.         variables that can hold objects of different classes)?
  5359.  
  5360. 2:      How can we make it possible to allow functions that take  objects
  5361.         of  different classes (with a common base  class) and perform the
  5362.         same operation for those objects (but using different methods)?
  5363.  
  5364. 3:      How can we  make it possible  that the implementation  of  a  new
  5365.         class   of  objects  only  requires   that  one  implements  what
  5366.         distinguishes the objects of  this new class from the  objects of
  5367.         an old (base) class (without the need to change any old code)?
  5368.  
  5369. In {\GAP}  the first problem  is solved by representing all domains using
  5370. records.   Actually because {\GAP} does  not  perform  strong static type
  5371. checking  each variable can  hold objects of  arbitrary type, so it would
  5372. even be possible to represent some domains using lists or something else.
  5373. But then, where would we put the operations record?
  5374.  
  5375. C++  does something  similar.  Objects  are represented by 'struct'-s  or
  5376. pointers to structures.  C++ then allows that a pointer to an object of a
  5377. base class actually holds a pointer to an object of a derived class.
  5378.  
  5379. In  {\GAP}  the  second  problem  is solved by  the  dispatchers and  the
  5380. operations  record.  The  operations record  of a  given domain holds the
  5381. methods that  should be  applied to that domain, and the dispatcher  does
  5382. nothing but call this method.
  5383.  
  5384. In C++ it is  again very  similar.  The difference is that the dispatcher
  5385. only  exists conceptually.  If  the compiler  can  already  decide  which
  5386. method will  be executed  by a given call to  the  dispatcher it directly
  5387. calls  this function.   Otherwise  (for virtual  functions  that  may  be
  5388. overlaid  in derived classes) it  basically inlines the dispatcher.  This
  5389. inlined  code  then  dispatches  through the  so--called *virtual  method
  5390. table*  ('vmt').  Note that this virtual  method table is the same as the
  5391. operations record, except that it is a table and not a record.
  5392.  
  5393. In {\GAP} the third problem is solved by inheritance and  delegation.  To
  5394. inherit  functions you simply  copy  them  from the operations record  of
  5395. domains  of the old category to the  operations  record of domains of the
  5396. new  category.  Delegation to  a  method of a larger  category is done by
  5397. calling '<super-category-operations-record>.<function>'
  5398.  
  5399. C++ also supports inheritance and delegation.  If you derive a class from
  5400. a base class, you  copy the methods  from  the base class to  the derived
  5401. class.  Again this copying is  only done conceptually in C++.  Delegation
  5402. is done by calling a qualified function '<base-class>\:\:<function>'.
  5403.  
  5404. Now that we have seen the similarities, let us discuss the differences.
  5405.  
  5406. The  first  differences  is  that  {\GAP}  is  not   an  object  oriented
  5407. programming  language.   We  only  programmed  the  library in an  object
  5408. oriented way  using very few features of  the  language (basically all we
  5409. need  is that {\GAP} has no strong static type checking, that records can
  5410. hold  functions,  and  that  records  can  grow  dynamically).  Following
  5411. Stroustrup\'s convention we  say that the {\GAP}  language only *enables*
  5412. object oriented programming, but does not *support* it.
  5413.  
  5414. The second  difference  is that  C++  adds  a  mechanism to  support data
  5415. hiding.   That  means that fields  of a 'struct'  can be  private.  Those
  5416. fields can only be accessed by the functions belonging to this class (and
  5417. 'friend'  functions).  This is not  possible  in {\GAP}.  Every field  of
  5418. every domain is accessible.  This means that  you  can also  modify those
  5419. fields, with probably catastrophic results.
  5420.  
  5421. The final difference  has  to do with the relation between categories and
  5422. their domains  and classes and  their objects.  In {\GAP} a category is a
  5423. set of domains, thus we  say that a domain is an element of  a  category.
  5424. In C++ (and most  other object oriented programming languages) a class is
  5425. a prototype for its objects, thus we say that an object is an instance of
  5426. the  class.   We  believe that  {\GAP}\'s  relation better resembles  the
  5427. mathematical model.
  5428.  
  5429. In this section you have  seen  that  domains  are represented by  domain
  5430. records, and that  you can therefore  access all information  that {\GAP}
  5431. has  about  a  certain  domain.  The  following  sections in this chapter
  5432. discuss how new domains can be created (see "About Defining New Domains",
  5433. and  "About Defining  New  Parametrized  Domains") and how you  can  even
  5434. define a new type of elements (see "About Defining New Group Elements").
  5435.  
  5436. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5437. \Section{About Defining New Domains}
  5438.  
  5439. In this section we will show how one can add a new domain to {\GAP}.  All
  5440. domains are implemented in the library in this way.  We will use the ring
  5441. of Gaussian integers as our example.
  5442.  
  5443. Note  that  everything  defined  here  is  already  in  the  library file
  5444. 'LIBNAME/\"gaussian.g\"', so there is no need for you to type it in.  You
  5445. may however like to make a copy of this file and modify it.
  5446.  
  5447. The  elements of  this domain  are  already available,  because  Gaussian
  5448. integers are just a special case of cyclotomic numbers.  As  is described
  5449. in chapter "Cyclotomics" 'E(4)' is {\GAP}\'s name for the complex root of
  5450. -1.  So all Gaussian  integers can be  represented as  '<a> + <b>\*E(4)',
  5451. where <a> and <b> are ordinary integers.
  5452.  
  5453. As  was  already mentioned each domain is represented by a record.  So we
  5454. create  a  record  to  represent the Gaussian  integers,  which  we  call
  5455. 'GaussianIntegers'.
  5456.  
  5457. |    GaussianIntegers := rec(); |
  5458.  
  5459. The first components  that this record must have are those  that identify
  5460. this record as  a  record denoting a  ring domain.  Those components  are
  5461. called the *category components*.
  5462.  
  5463. |    GaussianIntegers.isDomain := true;
  5464.     GaussianIntegers.isRing := true; |
  5465.  
  5466. The  next components  are those  that  uniquely  identify this ring.  For
  5467. rings this must be 'generators', 'zero', and 'one'.  Those components are
  5468. called  the *identification components* of  the  domain  record.  We also
  5469. assign a *name component*.  This name will be printed when the  domain is
  5470. printed.
  5471.  
  5472. |    GaussianIntegers.generators := [ 1, E(4) ];
  5473.     GaussianIntegers.zero := 0;
  5474.     GaussianIntegers.one := 1;
  5475.     GaussianIntegers.name := "GaussianIntegers"; |
  5476.  
  5477. Next we enter some components that represent knowledge that we have about
  5478. this domain.  Those components are called the *knowledge components*.  In
  5479. our  example  we  know  that  the  Gaussian  integers  form  a  infinite,
  5480. commutative,  integral, Euclidean ring, which has an unique factorization
  5481. property, with the four units 1, -1, 'E(4)', and '-E(4)'.
  5482.  
  5483. |    GaussianIntegers.size                       := "infinity";
  5484.     GaussianIntegers.isFinite                   := false;
  5485.     GaussianIntegers.isCommutativeRing          := true;
  5486.     GaussianIntegers.isIntegralRing             := true;
  5487.     GaussianIntegers.isUniqueFactorizationRing  := true;
  5488.     GaussianIntegers.isEuclideanRing            := true;
  5489.     GaussianIntegers.units                      := [1,-1,E(4),-E(4)]; |
  5490.  
  5491. This was  the  easy  part of  this  example.   Now  we  have  to  add  an
  5492. *operations  record*  to  the  domain  record.   This  operations  record
  5493. ('GaussianIntegers.operations') shall  contain functions  that  implement
  5494. all  the functions mentioned  in  chapter  "Rings", e.g.,  'DefaultRing',
  5495. 'IsCommutativeRing', 'Gcd', or 'Mod'.
  5496.  
  5497. Luckily we do not  have to implement all this functions.  The first class
  5498. of functions that we  need not implement are those that can simply derive
  5499. the  result from  the  knowledge components.   E.g.,  'IsCommutativeRing'
  5500. looks  for  the  knowledge  component  'isCommutativeRing', finds it  and
  5501. returns this value.   So  'GaussianIntegers.operations.IsCommutativeRing'
  5502. is never called.
  5503.  
  5504. |    gap> IsCommutativeRing( GaussianIntegers );
  5505.     true
  5506.     gap> Units( GaussianIntegers );
  5507.     [ 1, -1, E(4), -E(4) ] |
  5508.  
  5509. The second class of functions  that we need  not implement are those  for
  5510. which  there  is a  general algorithm  that can be applied for all rings.
  5511. For example once we can do a division with remainder (which  we will have
  5512. to  implement) we can use the  general Euclidean algorithm to compute the
  5513. greatest common divisor of elements.
  5514.  
  5515. So the question is,  how do  we get  those  general  functions  into  our
  5516. operations  record.   This  is  very  simple,  we  just  initialize   the
  5517. operations  record as a copy of the record  'RingOps', which contains all
  5518. those  general  functions.   We  say  that  'GaussianIntegers.operations'
  5519. *inherits* the general functions from 'RingOps'.
  5520.  
  5521. |    GaussianIntegersOps := Copy( RingOps );
  5522.     GaussianIntegers.operations := GaussianIntegersOps; |
  5523.  
  5524. Now we can  already test whether a Gaussian integer  is  a unit  or  not.
  5525. This  is  because the  default function  inherited  from 'RingOps'  tests
  5526. whether  the knowledge  component 'units'  is present, and if it  returns
  5527. 'true' if the element is in that list and 'false' otherwise.
  5528.  
  5529. |    gap> IsUnit( GaussianIntegers, E(4) );
  5530.     true
  5531.     gap> IsUnit( GaussianIntegers, 1 + E(4) );
  5532.     false |
  5533.  
  5534. So now we have  to add those functions whose  result can not (easily)  be
  5535. derived from the knowledge  components and that we can  not  inherit from
  5536. 'RingOps'.
  5537.  
  5538. The first such function is the membership test.  This  function must test
  5539. whether  an  object  is  an  element  of  the  domain 'GaussianIntegers'.
  5540. 'IsCycInt(<x>)'  tests   whether   <x>  is   a  cyclotomic   integer  and
  5541. 'NofCyc(<x>)'  returns the smallest <n> such that  the cyclotomic <x> can
  5542. be written as a linear combination of powers of the primitive <n>-th root
  5543. of unity  'E(<n>)'.  If  'E(<x>)' returns 1, <x>  is an ordinary rational
  5544. number.
  5545.  
  5546. |    GaussianIntegersOps.'in' := function ( x, GaussInt )
  5547.         return IsCycInt( x ) and ((NofCyc( x ) = 1 or NofCyc( x ) = 4);
  5548.     end; |
  5549.  
  5550. Note that  the second  argument  'GaussInt' is not used in  the function.
  5551. Whenever   this  function  is  called,   the  second  argument  must   be
  5552. 'GaussianIntegers', because 'GaussianIntegers' is the  only  domain  that
  5553. has this particular function in its operations record.  This also happens
  5554. for most  other  functions that we will write.  This argument can not  be
  5555. dropped though, because there are  other domains that share a common 'in'
  5556. function, for example all permutation groups have the same 'in' function.
  5557. If the operator 'in' would not pass  the second  argument,  this function
  5558. could  not  know  for which  permutation  group  it  should  perform  the
  5559. membership test.
  5560.  
  5561. So now we can test whether a certain object is a Gaussian integer or not.
  5562.  
  5563. |    gap> E(4) in GaussianIntegers;
  5564.     true
  5565.     gap> 1/2 in GaussianIntegers;
  5566.     false
  5567.     gap> GaussianIntegers in GaussianIntegers;
  5568.     false |
  5569.  
  5570. Another function that  is  just as  easy is the  function  'Random'  that
  5571. should return a random Gaussian integer.
  5572.  
  5573. |    GaussianIntegersOps.Random := function ( GaussInt )
  5574.         return Random( Integers ) + Random( Integers ) * E( 4 );
  5575.     end; |
  5576.  
  5577. Note that actually a 'Random' function was inherited from 'RingOps'.  But
  5578. this function can not be used.  It tries to  construct the sorted list of
  5579. all  elements of the domain and then  picks  a  random element from  that
  5580. list.  Therefor this function is only applicable for finite domains,  and
  5581. can not  be  used for 'GaussianIntegers'.   So  we *overlay* this default
  5582. function by simply putting another function in the operations record.
  5583.  
  5584. Now we finally  come to more  interesting stuff.  The function 'Quotient'
  5585. should  return  the  quotient of  its two  arguments <x> and <y>.  If the
  5586. quotient does not  exist  in  the ring (i.e.,  if it is a proper Gaussian
  5587. rational),  it must return 'false'.   (Without this last  requirement  we
  5588. could do  without the 'Quotient' function and  always simply  use the '/'
  5589. operator.)
  5590.  
  5591. |    GaussianIntegersOps.Quotient := function ( GaussInt, x, y )
  5592.         local   q;
  5593.         q := x / y;
  5594.         if not IsCycInt( q )  then
  5595.             q := false;
  5596.         fi;
  5597.         return q;
  5598.     end; |
  5599.  
  5600. The  next  function is used to test  if two elements are associate in the
  5601. ring of Gaussian integers.   In  fact we need not  implement this because
  5602. the function that we inherit  from 'RingOps' will do fine.  The following
  5603. function is a little bit faster though that the inherited one.
  5604.  
  5605. |    GaussianIntegersOps.IsAssociated := function ( GaussInt, x, y )
  5606.         return x = y  or x = -y  or x = E(4)*y  or x = -E(4)*y;
  5607.     end; |
  5608.  
  5609. We must however  implement the  function 'StandardAssociate'.   It should
  5610. return an associate that is in some  way standard.  That means,  whenever
  5611. we  apply 'StandardAssociate' to two  associated elements  we must obtain
  5612. the same value.  For Gaussian integers we return that associate that lies
  5613. in the first quadrant of the complex plane.  That is,  the result is that
  5614. associated element that has positive real part and  nonnegative imaginary
  5615. part.  0 is its  own standard associate  of course.  Note  that this is a
  5616. generalization    of    the   absolute    value    function,   which   is
  5617. 'StandardAssociate'  for the integers.  The reason that we must implement
  5618. 'StandardAssociate' is of  course that there is no general way to compute
  5619. a standard associate for an arbitrary ring, there is  not even a standard
  5620. way to define this!
  5621.  
  5622. |   GaussianIntegersOps.StandardAssociate := function ( GaussInt, x )
  5623.         if   IsRat(x)  and 0 <= x  then
  5624.             return x;
  5625.         elif IsRat(x)  then
  5626.             return -x;
  5627.         elif 0 <  COEFFSCYC(x)[1]      and 0 <= COEFFSCYC(x)[2]      then
  5628.             return x;
  5629.         elif      COEFFSCYC(x)[1] <= 0 and 0 <  COEFFSCYC(x)[2]      then
  5630.             return - E(4) * x;
  5631.         elif      COEFFSCYC(x)[1] <  0 and      COEFFSCYC(x)[2] <= 0 then
  5632.             return - x;
  5633.         else
  5634.             return E(4) * x;
  5635.         fi;
  5636.     end; |
  5637.  
  5638. Note  that  'COEFFSCYC'   is  an   internal  function  that  returns  the
  5639. coefficients of  a Gaussian integer (actually of an arbitrary cyclotomic)
  5640. as a list.
  5641.  
  5642. Now we  have  implemented  all functions that  are necessary to  view the
  5643. Gaussian integers plainly as a  ring.  Of course there is not much we can
  5644. do with such a plain ring, we can compute with its elements and can  do a
  5645. few things that are related to the group of units.
  5646.  
  5647. |    gap> Quotient( GaussianIntegers, 2, 1+E(4) );
  5648.     1-E(4)
  5649.     gap> Quotient( GaussianIntegers, 3, 1+E(4) );
  5650.     false
  5651.     gap> IsAssociated( GaussianIntegers, 1+E(4), 1-E(4) );
  5652.     true
  5653.     gap> StandardAssociate( GaussianIntegers, 3 - E(4) );
  5654.     1+3*E(4) |
  5655.  
  5656. The  remaining functions  are  related  to  the  fact that  the  Gaussian
  5657. integers  are  an Euclidean ring  (and thus also  a  unique factorization
  5658. ring).
  5659.  
  5660. The  first  such function  is  'EuclideanDegree'.   In  our  example  the
  5661. Euclidean degree  of a  Gaussian  integer  is of course simply its  norm.
  5662. Just as with 'StandardAssociate' we must implement this  function because
  5663. there is no general  way to compute the Euclidean degree for an arbitrary
  5664. Euclidean ring.  The function itself is again very simple.  The Euclidean
  5665. degree of a Gaussian  integer <x> is the  product of <x> with its complex
  5666. conjugate, which is denoted in {\GAP} by 'GaloisCyc( <x>, -1 )'.
  5667.  
  5668. |    GaussianIntegersOps.EuclideanDegree := function ( GaussInt, x )
  5669.         return x * GaloisCyc( x, -1 );
  5670.     end; |
  5671.  
  5672. Once  we have defined  the Euclidean degree we now  want to implement the
  5673. 'Mod' function that gives us the remainder of a division.
  5674.  
  5675. |    GaussianIntegersOps.Mod := function ( GaussInt, x, y )
  5676.         return x - RoundCyc( x/y ) * y;
  5677.     end; |
  5678.  
  5679. Note that in the definition of 'Mod' we must use the function 'RoundCyc',
  5680. which views the  Gaussian rational '<x>/<y>'  as a  point in  the complex
  5681. plane  and  returns the  point  of the  lattice spanned  by 1 and  'E(4)'
  5682. *closest* to the  point  '<x>/<y>'.   If  we  would truncate  towards the
  5683. origin  instead (this is  done  by  the function 'IntCyc') we  could  not
  5684. guarantee that the result of 'Mod' always has Euclidean  degree less than
  5685. the Euclidean degree of <y> as the following example shows.
  5686.  
  5687. |    gap> x := 2 - E(4);;  EuclideanDegree( GaussianIntegers, x );
  5688.     5
  5689.     gap> y := 2 + E(4);;  EuclideanDegree( GaussianIntegers, y );
  5690.     5
  5691.     gap> q := x / y;  q := IntCyc( q );
  5692.     3/5-4/5*E(4)
  5693.     0
  5694.     gap> EuclideanDegree( GaussianIntegers, x - q * y );
  5695.     5 |
  5696.  
  5697. Now that  we  have implemented the 'Mod' function we can compute greatest
  5698. common  divisors in  the ring of Gaussian integers.  This  is  because we
  5699. have  inherited from  'RingOps'  the general function 'Gcd' that computes
  5700. the  greatest  common divisor using  Euclid\'s algorithm, which only uses
  5701. 'Mod' (and 'StandardAssociate'  to  return the  result in a normal form).
  5702. Of course we can  now also compute  least common multiples, because  that
  5703. only uses 'Gcd'.
  5704.  
  5705. |    gap> Gcd( GaussianIntegers, 2, 5 - E(4) );
  5706.     1+E(4)
  5707.     gap> Lcm( GaussianIntegers, 2, 5 - E(4) );
  5708.     6+4*E(4) |
  5709.  
  5710. Since the  Gaussian integers are a Euclidean ring they  are also a unique
  5711. factorization ring.   The  next  two  functions implement  the  necessary
  5712. operations.  The first is the test for  primality.  A rational integer is
  5713. a prime in the ring of Gaussian  integers if and  only if it is congruent
  5714. to 3  modulo  4  (the  other  rational  integer  primes  split  into  two
  5715. irreducibles), and a Gaussian integer that is not a rational integer is a
  5716. prime if its norm is a rational integer prime.
  5717.  
  5718. |    GaussianIntegersOps.IsPrime := function ( GaussInt, x )
  5719.         if IsInt( x )  then
  5720.             return x mod 4 = 3  and IsPrimeInt( x );
  5721.         else
  5722.             return IsPrimeInt( x * GaloisCyc( x, -1 ) );
  5723.         fi;
  5724.     end; |
  5725.  
  5726. The  factorization  is  based on the same  observation.  We  compute  the
  5727. Euclidean degree of  the number that we  want  to factor, and factor this
  5728. rational  integer.   Then  for  every  rational  integer  prime  that  is
  5729. congruent to  3  modulo  4 we  get one factor,  and  we  split the  other
  5730. rational  integer primes using  the function 'TwoSquares' and  test which
  5731. irreducible divides.
  5732.  
  5733. |    GaussianIntegersOps.Factors := function ( GaussInt, x )
  5734.         local   facs,       # factors (result)
  5735.                 prm,        # prime factors of the norm
  5736.                 tsq;        # representation of prm as $x^2 + y^2$
  5737.  
  5738.         # handle trivial cases
  5739.         if x in [ 0, 1, -1, E(4), -E(4) ]  then
  5740.             return [ x ];
  5741.         fi;
  5742.  
  5743.         # loop over all factors of the norm of x
  5744.         facs := [];
  5745.         for prm  in Set( FactorsInt( EuclideanDegree( x ) ) )  do
  5746.  
  5747.             # $p=2$ and primes $p=1$ mod 4 split according to $p=x^2+y^2$
  5748.             if prm = 2  or prm mod 4 = 1  then
  5749.                 tsq := TwoSquares( prm );
  5750.                 while IsCycInt( x / (tsq[1]+tsq[2]*E(4)) )  do
  5751.                     Add( facs, (tsq[1]+tsq[2]*E(4)) );
  5752.                     x := x / (tsq[1]+tsq[2]*E(4));
  5753.                 od;
  5754.                 while IsCycInt( x / (tsq[2]+tsq[1]*E(4)) )  do
  5755.                     Add( facs, (tsq[2]+tsq[1]*E(4)) );
  5756.                     x := x / (tsq[2]+tsq[1]*E(4));
  5757.                 od;
  5758.  
  5759.             # primes $p = 3$ mod 4 stay prime
  5760.             else
  5761.                 while IsCycInt( x / prm )  do
  5762.                     Add( facs, prm );
  5763.                     x := x / prm;
  5764.                 od;
  5765.             fi;
  5766.  
  5767.         od;
  5768.  
  5769.         # the first factor takes the unit
  5770.         facs[1] := x * facs[1];
  5771.  
  5772.         # return the result
  5773.         return facs;
  5774.     end; |
  5775.  
  5776. So now we can factorize numbers in the ring of Gaussian integers.
  5777.  
  5778. |    gap> Factors( GaussianIntegers, 10 );
  5779.     [ -1-E(4), 1+E(4), 1+2*E(4), 2+E(4) ]
  5780.     gap> Factors( GaussianIntegers, 103 );
  5781.     [ 103 ] |
  5782.  
  5783. Now we have written  all  the functions for  the operations  record  that
  5784. implement the operations.  We would like one more thing  however.  Namely
  5785. that  we can simply write 'Gcd( 2, 5 - E(4) )' without having to  specify
  5786. 'GaussianIntegers' as  first  argument.  'Gcd'  and the  other  functions
  5787. should  be clever  enough to  find out  that  the arguments are  Gaussian
  5788. integers and call 'GaussianIntegers.operations.Gcd' automatically.
  5789.  
  5790. To do this we must  first understand  what happens when  'Gcd' is  called
  5791. without a ring as first argument.  For an  example  suppose that we  have
  5792. called 'Gcd( 66, 123 )' (and want to compute the gcd over the integers).
  5793.  
  5794. First 'Gcd'  calls 'DefaultRing( [ 66, 123 ]  )', to obtain  a ring  that
  5795. contains 66 and 123.  'DefaultRing' then calls 'Domain( [ 66, 123 ] )' to
  5796. obtain a domain,  which need  not be  a ring,  that contains 66  and 123.
  5797. 'Domain' is the *only*  function in the  whole {\GAP} library  that knows
  5798. about the various  types  of  elements.  So it looks  at its argument and
  5799. decides to return the domain 'Integers' (which is in fact already a ring,
  5800. but  it could in principle  also  return 'Rationals').  'DefaultRing' now
  5801. calls 'Integers.operations.DefaultRing( [ 66, 123 ] )' and expects a ring
  5802. in   which   the   requested   gcd   computation   can    be   performed.
  5803. 'Integers.operations.DefaultRing( [ 66, 123 ] )' also returns 'Integers'.
  5804. So  'DefaultRing' returns 'Integers'  to 'Gcd'  and 'Gcd'  finally  calls
  5805. 'Integers.operations.Gcd( Integers, 66, 123 )'.
  5806.  
  5807. So  the  first thing  we must  do is  to  tell  'Domain'  about  Gaussian
  5808. integers.  We do this by extending 'Domain' with the two lines
  5809.  
  5810. |        elif ForAll( elms, IsGaussInt )  then
  5811.             return GaussianIntegers; |
  5812.  
  5813. so that it now looks as follows.
  5814.  
  5815. |    Domain := function ( elms )
  5816.         local   elm;
  5817.         if   ForAll( elms, IsInt )  then
  5818.             return Integers;
  5819.         elif ForAll( elms, IsRat )  then
  5820.             return Rationals;
  5821.         elif ForAll( elms, IsFFE )  then
  5822.             return FiniteFieldElements;
  5823.         elif ForAll( elms, IsPerm )  then
  5824.             return Permutations;
  5825.         elif ForAll( elms, IsMat )  then
  5826.             return Matrices;
  5827.         elif ForAll( elms, IsWord )  then
  5828.             return Words;
  5829.         elif ForAll( elms, IsAgWord )  then
  5830.             return AgWords;
  5831.         elif ForAll( elms, IsGaussInt )  then
  5832.             return GaussianIntegers;
  5833.         elif ForAll( elms, IsCyc )  then
  5834.             return Cyclotomics;
  5835.         else
  5836.             for elm  in elms do
  5837.                 if    IsRec(elm)  and IsBound(elm.domain)
  5838.                   and ForAll( elms, l -> l in elm.domain )
  5839.                 then
  5840.                     return elm.domain;
  5841.                 fi;
  5842.             od;
  5843.             Error("sorry, the elements lie in no common domain");
  5844.         fi;
  5845.     end; |
  5846.  
  5847. Of course  we must define a  function 'IsGaussInt', otherwise this  could
  5848. not possibly work.  This  function is similar to  the membership test  we
  5849. already defined above.
  5850.  
  5851. |    IsGaussInt := function ( x )
  5852.         return IsCycInt( x ) and ((NofCyc( x ) = 1 or NofCyc( x ) = 4);
  5853.     end; |
  5854.  
  5855.  
  5856. Then  we must define a function 'DefaultRing'  for  the Gaussian integers
  5857. that does nothing but return 'GaussianIntegers'.
  5858.  
  5859. |    GaussianIntegersOps.DefaultRing := function ( elms )
  5860.         return GaussianIntegers;
  5861.     end; |
  5862.  
  5863. Now we can call 'Gcd' with two Gaussian  integers without  having to pass
  5864. 'GaussianIntegers' as first argument.
  5865.  
  5866. |    gap> Gcd( 2, 5 - E(4) );
  5867.     1+E(4) |
  5868.  
  5869. Of course {\GAP}  can  not  read your mind.  In the following  example it
  5870. assumes that you want to factor 10 over the  ring  of  integers, not over
  5871. the ring of  Gaussian  integers (because 'Integers'  is the default  ring
  5872. containing 10).  So if you want  to factor  a rational integer  over  the
  5873. ring  of Gaussian  integers you  must  pass  'GaussianIntegers' as  first
  5874. argument.
  5875.  
  5876. |    gap> Factors( 10 );
  5877.     [ 2, 5 ]
  5878.     gap> Factors( GaussianIntegers, 10 );
  5879.     [ -1-E(4), 1+E(4), 1+2*E(4), 2+E(4) ] |
  5880.  
  5881. This  concludes our example.   In  the file  'LIBNAME/\"gaussian.g\"' you
  5882. will also find the definition of the field of  Gaussian rationals.  It is
  5883. so similar to the above definition that  there  is no point in discussing
  5884. it here.  The  next section shows  you  what  further considerations  are
  5885. necessary when implementing a type of parametrized  domains (demonstrated
  5886. by implementing full symmetric permutation groups).   For further details
  5887. see chapter "Gaussians" for a  description of  the Gaussian integers  and
  5888. rationals and chapter  "Rings" for a list of  all functions applicable to
  5889. rings.
  5890.  
  5891. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5892. \Section{About Defining New Parametrized Domains}
  5893.  
  5894. In this section we will show you an example that is slightly more complex
  5895. than the example in the previous section.  Namely we will demonstrate how
  5896. one can implement  parametrized domains.  As an example we will implement
  5897. symmetric permutation groups.  This works similar to  the  implementation
  5898. of a  single domain.   Therefore  we  can be very brief.   Of course  you
  5899. should have read the previous section.
  5900.  
  5901. Note   that   everything   defined   here   is   already   in   the  file
  5902. 'GRPNAME/\"permgrp.grp\"',  so there  is no need  for  you to type it in.
  5903. You may however like to make a copy of this file and modify it.
  5904.  
  5905. In  the  example  of  the previous  section  we  simply  had  a  variable
  5906. ('GaussianIntegers'), whose value  was the domain.  This can  not work in
  5907. this  example, because  there is not  *one* symmetric  permutation group.
  5908. The solution is obvious.  We  simply  define a  function  that takes  the
  5909. degree and  returns the symmetric permutation group of this degree  (as a
  5910. domain).
  5911.  
  5912. |    SymmetricPermGroup := function ( n )
  5913.         local   G;          # symmetric group on <n> points, result
  5914.  
  5915.         # make the group generated by (1,n), (2,n), .., (n-1,n)
  5916.         G := Group( List( [1..n-1], i -> (i,n) ), () );
  5917.         G.degree := n;
  5918.  
  5919.         # give it the correct operations record
  5920.         G.operations := SymmetricPermGroupOps;
  5921.  
  5922.         # return the symmetric group
  5923.         return G;
  5924.     end; |
  5925.  
  5926. The key is of course to give the domains returned by 'SymmetricPermGroup'
  5927. a new operations record.  This operations record will hold functions that
  5928. are written especially for  symmetric permutation groups.   Note that all
  5929. symmetric groups  created by  'SymmetricPermGroup'  share one  operations
  5930. record.
  5931.  
  5932. Just as  we  inherited  in the example  in the previous section  from the
  5933. operations  record 'RingOps',  here  we can inherit  from  the operations
  5934. record 'PermGroupOps' (after  all, each symmetric  permutation  group  is
  5935. also a permutation group).
  5936.  
  5937. |    SymmetricPermGroupOps := Copy( PermGroupOps ); |
  5938.  
  5939. We will now overlay some of the functions in this operations record  with
  5940. new  functions  that make  use of the  fact that  the  domain  is  a full
  5941. symmetric  permutation group.  The first function that does  this is  the
  5942. membership test function.
  5943.  
  5944. |    SymmetricPermGroupOps.'in' := function ( g, G )
  5945.         return     IsPerm( g )
  5946.                and (   g = ()
  5947.                     or LargestMovedPointPerm( g ) <= G.degree);
  5948.     end; |
  5949.  
  5950. The most important knowledge  for a permutation  group is  a base  and  a
  5951. strong generating set  with respect to that base.  It  is  not  important
  5952. that you  understand at this  point  what  this  is mathematically.   The
  5953. important point here is that such a strong generating set with respect to
  5954. an appropriate  base is used by many generic permutation group functions,
  5955. most of  which we inherit for symmetric permutation groups.  Therefore it
  5956. is important that we are able to compute a strong generating  set as fast
  5957. as possible.  Luckily it is possible to  simply write down such a  strong
  5958. generating set for a full symmetric group.  This is done by the following
  5959. function.
  5960.  
  5961. |    SymmetricPermGroupOps.MakeStabChain := function ( G, base )
  5962.         local   sgs,        # strong generating system of <G> wrt. <base>
  5963.                 last;       # last point of the base
  5964.  
  5965.         # remove all unwanted points from the base
  5966.         base := Filtered( base, i -> i <= G.degree );
  5967.  
  5968.         # extend the base with those points not already in the base
  5969.         base := Concatenation( base, Difference( [1..G.degree], base ) );
  5970.  
  5971.         # take the last point
  5972.         last := base[ Length(base) ];
  5973.  
  5974.         # make the strong generating set
  5975.         sgs := List( [1..Length(base)-1], i -> ( base[i], last ) );
  5976.  
  5977.         # make the stabilizer chain
  5978.         MakeStabChainStrongGenerators( G, base, sgs );
  5979.     end; |
  5980.  
  5981. One  of the  things that  are  very  easy for  symmetric  groups  is  the
  5982. computation of  centralizers  of elements.  The next function does  this.
  5983. Again it  is not important that you understand  this mathematically.  The
  5984. centralizer of an element <g>  in the symmetric group is generated by the
  5985. cycles  <c> of  <g> and an element <x> for each pair  of cycles of <g> of
  5986. the same length that maps one cycle to the other.
  5987.  
  5988. |    SymmetricPermGroupOps.Centralizer := function ( G, g )
  5989.         local   C,      # centralizer of <g> in <G>, result
  5990.                 sgs,    # strong generating set of <C>
  5991.                 gen,    # one generator in <sgs>
  5992.                 cycles, # cycles of <g>
  5993.                 cycle,  # one cycle from <cycles>
  5994.                 lasts,  # '<lasts>[<l>]' is the last cycle of length <l>
  5995.                 last,   # one cycle from <lasts>
  5996.                 i;      # loop variable
  5997.  
  5998.         # handle special case
  5999.         if IsPerm( g )  and g in G  then
  6000.  
  6001.             # start with the empty strong generating system
  6002.             sgs := [];
  6003.  
  6004.             # compute the cycles and find for each length the last one
  6005.             cycles := Cycles( g, [1..G.degree] );
  6006.             lasts := [];
  6007.             for cycle  in cycles  do
  6008.                 lasts[Length(cycle)] := cycle;
  6009.             od;
  6010.  
  6011.             # loop over the cycles
  6012.             for cycle  in cycles  do
  6013.  
  6014.                 # add that cycle itself to the strong generators
  6015.                 if Length( cycle ) <> 1  then
  6016.                     gen := [1..G.degree];
  6017.                     for i  in [1..Length(cycle)-1]  do
  6018.                         gen[cycle[i]] := cycle[i+1];
  6019.                     od;
  6020.                     gen[cycle[Length(cycle)]] := cycle[1];
  6021.                     gen := PermList( gen );
  6022.                     Add( sgs, gen );
  6023.                 fi;
  6024.  
  6025.                 # and it can be mapped to the last cycle of this length
  6026.                 if cycle <> lasts[ Length(cycle) ]  then
  6027.                     last := lasts[ Length(cycle) ];
  6028.                     gen := [1..G.degree];
  6029.                     for i  in [1..Length(cycle)]  do
  6030.                         gen[cycle[i]] := last[i];
  6031.                         gen[last[i]] := cycle[i];
  6032.                     od;
  6033.                     gen := PermList( gen );
  6034.                     Add( sgs, gen );
  6035.                 fi;
  6036.  
  6037.             od;
  6038.  
  6039.             # make the centralizer
  6040.             C := Subgroup( G, sgs );
  6041.  
  6042.             # make the stabilizer chain
  6043.             MakeStabChainStrongGenerators( C, [1..G.degree], sgs );
  6044.  
  6045.         # delegate general case
  6046.         else
  6047.             C := PermGroupOps.Centralizer( G, g );
  6048.         fi;
  6049.  
  6050.         # return the centralizer
  6051.         return C;
  6052.     end; |
  6053.  
  6054. Note that the definition 'C \:=  Subgroup( G, sgs );'  defines a subgroup
  6055. of  a  symmetric permutation  group.  But  this subgroup is usually not a
  6056. full symmetric  permutation  group itself.   Thus  'C' must not  have the
  6057. operations  record 'SymmetricPermGroupOps', instead  it should  have  the
  6058. operations   record  'PermGroupOps'.   And  indeed  'C'  will  have  this
  6059. operations    record.      This     is     because    'Subgroup'    calls
  6060. '<G>.operations.Subgroup',   and   we   inherited  this   function   from
  6061. 'PermGroupOps'.
  6062.  
  6063. Note also that  we  only handle one  special  case in the function above.
  6064. Namely  the  computation of  a  centralizer  of  a  single element.  This
  6065. function can also  be called  to  compute  the  centralizer  of  a  whole
  6066. subgroup.   In  this   case   'SymmetricPermGroupOps.Centralizer'  simply
  6067. *delegates* the problem by calling 'PermGroupOps.Centralizer'.
  6068.  
  6069. The  next  function  computes the  conjugacy  classes of  elements  in  a
  6070. symmetric group.  This is very easy, because two  elements are conjugated
  6071. in a symmetric group  when  they have the  same cycle structure.  Thus we
  6072. can simply compute the partitions of the degree,  and for each  degree we
  6073. get one conjugacy class.
  6074.  
  6075. |    SymmetricPermGroupOps.ConjugacyClasses := function ( G )
  6076.         local   classes,    # conjugacy classes of <G>, result
  6077.                 prt,        # partition of <G>
  6078.                 sum,        # partial sum of the entries in <prt>
  6079.                 rep,        # representative of a conjugacy class of <G>
  6080.                 i;          # loop variable
  6081.  
  6082.         # loop over the partitions
  6083.         classes := [];
  6084.         for prt  in Partitions( G.degree )  do
  6085.  
  6086.             # compute the representative of the conjugacy class
  6087.             rep := [2..G.degree];
  6088.             sum := 1;
  6089.             for i  in prt  do
  6090.                 rep[sum+i-1] := sum;
  6091.                 sum := sum + i;
  6092.             od;
  6093.             rep := PermList( rep );
  6094.  
  6095.             # add the new class to the list of classes
  6096.             Add( classes, ConjugacyClass( G, rep ) );
  6097.  
  6098.         od;
  6099.  
  6100.         # return the classes
  6101.         return classes;
  6102.     end; |
  6103.  
  6104. This concludes this example.  You have seen that  the implementation of a
  6105. parametrized domain is not much more difficult than the implementation of
  6106. a single domain.  You have also seen  how functions  that overlay generic
  6107. functions  may  delegate  problems back  to  the  generic function.   The
  6108. library file for symmetric permutation groups contain some more functions
  6109. for symmetric permutation groups.
  6110.  
  6111. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  6112. \Section{About Defining New Group Elements}
  6113.  
  6114. In this section we will show how one can add a new type of group elements
  6115. to {\GAP}.  A lot  of group elements in {\GAP}  are implemented this way,
  6116. for example elements  of generic factor  groups,  or elements of  generic
  6117. direct products.
  6118.  
  6119. We will use prime residue classes modulo an integer as our example.  They
  6120. have the advantage that  the arithmetic is very simple, so  that  we  can
  6121. concentrate  on   the  implementation  without  being  carried   away  by
  6122. mathematical details.
  6123.  
  6124. Note  that  everything we  define is already in  the library  in the file
  6125. 'LIBNAME/\"numtheor.g\"', so there is no need for you to type it in.  You
  6126. may however like to make a copy of this file and modify it.
  6127.  
  6128. We will   represent  residue  classes  by  records.   This  is absolutely
  6129. typical, all group elements not built into the {\GAP} kernel are realized
  6130. by records.
  6131.  
  6132. To distinguish records representing residue classes from other records we
  6133. require   that residue  class records   have a  component   with the name
  6134. 'isResidueClass' and the value 'true'.  We also require that they  have a
  6135. component with the  name 'isGroupElement'  and  again  the value  'true'.
  6136. Those two components are called the tag components.
  6137.  
  6138. Next each residue  class record must  of course have components that tell
  6139. us which  residue class this record represents.    The component with the
  6140. name 'representative'  contains the  smallest nonnegative element  of the
  6141. residue class.   The  component  with  the  name 'modulus'  contains  the
  6142. modulus.  Those two components are called the identifying components.
  6143.  
  6144. Finally each  residue class record must  have a  component with  the name
  6145. 'operations' that contains an appropriate  operations record (see below).
  6146. In this way  we can make use of the possibility  to define operations for
  6147. records (see "Comparisons of Records" and "Operations for Records").
  6148.  
  6149. Below is an example of a residue class record.
  6150.  
  6151. |    r13mod43 := rec(
  6152.         isGroupElement := true,
  6153.         isResidueClass := true,
  6154.         representative := 13,
  6155.         modulus        := 43,
  6156.         domain         := GroupElements,
  6157.         operations     := ResidueClassOps ) |
  6158.  
  6159. The first function that  we have to write is  very simple.  Its only task
  6160. is to test whether an object is a residue class.  It does this by testing
  6161. for the tag component 'isResidueClass'.
  6162.  
  6163. |    IsResidueClass := function ( obj )
  6164.         return IsRec( obj )
  6165.                and IsBound( obj.isResidueClass )
  6166.                and obj.isResidueClass;
  6167.     end; |
  6168.  
  6169. Our next  function takes a representative and  a modulus and constructs a
  6170. new residue class.  Again this is not very difficult.
  6171.  
  6172. |    ResidueClass := function ( representative, modulus )
  6173.         local res;
  6174.         res := rec();
  6175.         res.isGroupElement  := true;
  6176.         res.isResidueClass  := true;
  6177.         res.representative  := representative mod modulus;
  6178.         res.modulus         := modulus;
  6179.         res.domain          := GroupElements;
  6180.         res.operations      := ResidueClassOps;
  6181.         return res;
  6182.     end; |
  6183.  
  6184. Now  we  have to   define   the operations record for   residue  classes.
  6185. Remember that this record contains a function  for each binary operation,
  6186. which is called to evaluate such a  binary operation (see "Comparisons of
  6187. Records" and "Operations for Records").  The  operations '=', '\<', '\*',
  6188. '/', 'mod', '\^', 'Comm', and 'Order' are the ones that are applicable to
  6189. all group  elements.  The meaning of those  operations for group elements
  6190. is described in "Comparisons of Group Elements" and "Operations for Group
  6191. Elements".
  6192.  
  6193. Luckily  we do  not have  to define everything.  Instead we can inherit a
  6194. lot of those functions from generic group elements.  For example, for all
  6195. group elements '<g>/<h>' should be equivalent to '<g>\*<h>\^-1'.  So  the
  6196. function for '/'  could  simply be 'function(g,h)  return g\*h\^-1; end'.
  6197. Note  that   this   function  can  be  applied  to  all  group  elements,
  6198. independently of their type, because all the dependencies are in '\*' and
  6199. '\^'.
  6200.  
  6201. The operations record 'GroupElementOps' contains  such functions that can
  6202. be used by all types of group elements.  Note  that there  is  no element
  6203. that has   'GroupElementsOps'   as  its   operations   record.   This  is
  6204. impossible, because there is for example no generic method to multiply or
  6205. invert group elements.   Thus 'GroupElementsOps' is  only used to inherit
  6206. general methods as is done below.
  6207.  
  6208. |    ResidueClassOps := Copy( GroupElementOps ); |
  6209.  
  6210. Note that  the copy  is  necessary, otherwise the  following  assignments
  6211. would not only change 'ResidueClassOps' but also 'GroupElementOps'.
  6212.  
  6213. The first function  we are implementing is  the equality comparison.  The
  6214. required operation is described  simply enough.   '='  should evaluate to
  6215. 'true' if the  operands are  equal and  'false' otherwise.   Two  residue
  6216. classes are of course equal  if they have the same representative and the
  6217. same modulus.   One complication is  that when  this  function is  called
  6218. either operand may not  be a residue class.  Of course at least one  must
  6219. be a residue  class otherwise this function would not have been called at
  6220. all.
  6221.  
  6222. |    ResidueClassOps.'=' := function ( l, r )
  6223.         local   isEql;
  6224.         if IsResidueClass( l )  then
  6225.             if IsResidueClass( r )  then
  6226.                 isEql :=    l.representative = r.representative
  6227.                         and l.modulus        = r.modulus;
  6228.             else
  6229.                 isEql := false;
  6230.             fi;
  6231.         else
  6232.             if IsResidueClass( r )  then
  6233.                 isEql := false;
  6234.             else
  6235.                 Error("panic, neither <l> nor <r> is a residue class");
  6236.             fi;
  6237.         fi;
  6238.         return isEql;
  6239.     end; |
  6240.  
  6241. Note that the quotes  around the equal sign  '=' are necessary, otherwise
  6242. it would not be taken as a record component name, as required, but as the
  6243. symbol for equality, which must not appear at this place.
  6244.  
  6245. Note  that  we do not   have to implement a   function for the inequality
  6246. operator  '\<>', because it  is in  the  {\GAP} kernel implemented by the
  6247. equivalence '<l> \<> <r>' is 'not <l> = <r>'.
  6248.  
  6249. The next operation is  the comparison.  We define that one residue  class
  6250. is smaller than another residue class if either it has  a smaller modulus
  6251. or, if  the moduli  are equal, it has a  smaller representative.  We must
  6252. also implement comparisons with other objects.
  6253.  
  6254. |    ResidueClassOps.'<' := function ( l, r )
  6255.         local   isLess;
  6256.         if IsResidueClass( l )  then
  6257.             if IsResidueClass( r )  then
  6258.                 isLess :=   l.representative < r.representative
  6259.                         or (l.representative = r.representative
  6260.                             and l.modulus    < r.modulus);
  6261.             else
  6262.                 isLess := not IsInt( r ) and not IsRat( r )
  6263.                       and not IsCyc( r ) and not IsPerm( r )
  6264.                       and not IsWord( r ) and not IsAgWord( r );
  6265.             fi;
  6266.         else
  6267.             if IsResidueClass( r )  then
  6268.                 isLess :=  IsInt( l ) or IsRat( l )
  6269.                         or IsCyc( l ) or IsPerm( l )
  6270.                         or IsWord( l ) or IsAgWord( l );
  6271.             else
  6272.                 Error("panic, neither <l> nor <r> is a residue class");
  6273.             fi;
  6274.         fi;
  6275.         return isLess;
  6276.     end; |
  6277.  
  6278. The next operation that  we must implement  is  the multiplication  '\*'.
  6279. This function  is quite complex because it must handle several  different
  6280. tasks.  To  make its implementation  easier to understand we  will  start
  6281. with a very  simple--minded  one, which only multiplies residue  classes,
  6282. and extend it in the following paragraphs.
  6283.  
  6284. |    ResidueClassOps.'*' := function ( l, r )
  6285.         local   prd;        # product of <l> and <r>, result
  6286.         if IsResidueClass( l )  then
  6287.             if IsResidueClass( r )  then
  6288.                 if l.modulus <> r.modulus  then
  6289.                     Error("<l> and <r> must have the same modulus");
  6290.                 fi;
  6291.                 prd := ResidueClass(
  6292.                             l.representative * r.representative,
  6293.                             l.modulus );
  6294.             else
  6295.                 Error("product of <l> and <r> must be defined");
  6296.             fi;
  6297.         else
  6298.             if IsResidueClass( r )  then
  6299.                 Error("product of <l> and <r> must be defined");
  6300.             else
  6301.                 Error("panic, neither <l> nor <r> is a residue class");
  6302.             fi;
  6303.         fi;
  6304.         return prd;
  6305.     end; |
  6306.  
  6307. This function correctly  multiplies residue classes,  but there are other
  6308. products that must be   implemented.  First every  group element   can be
  6309. multiplied with a  list of group elements,  and  the result shall  be the
  6310. list of products (see "Operations for Group Elements" and "Operations for
  6311. Lists").  In such  a case the above  function would only signal an error,
  6312. which is not acceptable.  Therefore we must extend this definition.
  6313.  
  6314. |    ResidueClassOps.'*' := function ( l, r )
  6315.         local   prd;        # product of <l> and <r>, result
  6316.         if IsResidueClass( l )  then
  6317.             if IsResidueClass( r )  then
  6318.                 if l.modulus <> r.modulus  then
  6319.                     Error( "<l> and <r> must have the same modulus" );
  6320.                 fi;
  6321.                 prd := ResidueClass(
  6322.                             l.representative * r.representative,
  6323.                             l.modulus );
  6324.             elif IsList( r )  then
  6325.                 prd := List( r, x -> l * x );
  6326.             else
  6327.                 Error("product of <l> and <r> must be defined");
  6328.             fi;
  6329.         elif IsList( l )  then
  6330.             if IsResidueClass( r )  then
  6331.                 prd := List( l, x -> x * r );
  6332.             else
  6333.                 Error("panic: neither <l> nor <r> is a residue class");
  6334.             fi;
  6335.         else
  6336.             if IsResidueClass( r )  then
  6337.                 Error( "product of <l> and <r> must be defined" );
  6338.             else
  6339.                 Error("panic, neither <l> nor <r> is a residue class");
  6340.             fi;
  6341.         fi;
  6342.         return prd;
  6343.     end; |
  6344.  
  6345. This function is almost complete.  However it is also allowed to multiply
  6346. a group element  with a subgroup  and the result shall  be  a coset  (see
  6347. "RightCoset").  The operations  record  of subgroups, which are of course
  6348. also represented by records  (see "Group Records"),  contains  a function
  6349. that constructs such a coset.  The problem is that in  an expression like
  6350. '<subgroup> \*\ <residue-class>', this  function is not  called.  This is
  6351. because  the  multiplication function in   the  operations record  of the
  6352. *right* operand is   called if both   operands have such a function  (see
  6353. "Operations for Records").  Now in the above case both operands have such
  6354. a  function.   The   left operand   <subgroup> has  the operations record
  6355. 'GroupOps'     (or   some    refinement    thereof),  the   right operand
  6356. <residue-class>   has the  operations   record 'ResidueClassOps'.    Thus
  6357. 'ResidueClassOps.\*' is called.  But it does not and also should not know
  6358. how to construct a  coset.  The solution  is simple.   The multiplication
  6359. function for  residue classes detects this special  case and simply calls
  6360. the multiplication function of the left operand.
  6361.  
  6362. |    ResidueClassOps.'*' := function ( l, r )
  6363.         local   prd;        # product of <l> and <r>, result
  6364.         if IsResidueClass( l )  then
  6365.             if IsResidueClass( r )  then
  6366.                 if l.modulus <> r.modulus  then
  6367.                     Error( "<l> and <r> must have the same modulus" );
  6368.                 fi;
  6369.                 prd := ResidueClass(
  6370.                             l.representative * r.representative,
  6371.                             l.modulus );
  6372.             elif IsList( r )  then
  6373.                 prd := List( r, x -> l * x );
  6374.             else
  6375.                 Error("product of <l> and <r> must be defined");
  6376.             fi;
  6377.         elif IsList( l )  then
  6378.             if IsResidueClass( r )  then
  6379.                 prd := List( l, x -> x * r );
  6380.             else
  6381.                 Error("panic: neither <l> nor <r> is a residue class");
  6382.             fi;
  6383.         else
  6384.             if IsResidueClass( r )  then
  6385.                 if IsRec( l )  and IsBound( l.operations )
  6386.                     and IsBound( l.operations.'*' )
  6387.                     and l.operations.'*' <> ResidueClassOps.'*'
  6388.                 then
  6389.                     prd := l.operations.'*'( l, r );
  6390.                 else
  6391.                     Error("product of <l> and <r> must be defined");
  6392.                 fi;
  6393.             else
  6394.                 Error("panic, neither <l> nor <r> is a residue class");
  6395.             fi;
  6396.         fi;
  6397.         return prd;
  6398.     end; |
  6399.  
  6400. Now we are done with the multiplication.
  6401.  
  6402. Next is the  powering operation '\^'.  It is not very  complicated.   The
  6403. 'PowerMod'  function  (see  "PowerMod")  does   most  of  what  we  need,
  6404. especially the  inversion of elements with  the Euclidean  algorithm when
  6405. the  exponent  is   negative.   Note  however,  that  the  definition  of
  6406. operations (see  "Operations  for  Group  Elements")  requires  that  the
  6407. conjugation  is  available as power of a residue class by another residue
  6408. class.  This is of course very easy since residue classes form an abelian
  6409. group.
  6410.  
  6411. |    ResidueClassOps.'^' := function ( l, r )
  6412.         local    pow;
  6413.         if IsResidueClass( l )  then
  6414.             if IsResidueClass( r )  then
  6415.                 if l.modulus <> r.modulus  then
  6416.                     Error("<l> and <r> must have the same modulus");
  6417.                 fi;
  6418.                 if GcdInt( r.representative, r.modulus ) <> 1  then
  6419.                     Error("<r> must be invertable");
  6420.                 fi;
  6421.                 pow := l;
  6422.             elif IsInt( r )  then
  6423.                 pow := ResidueClass(
  6424.                             PowerMod( l.representative, r, l.modulus ),
  6425.                             l.modulus );
  6426.             else
  6427.                 Error("power of <l> and <r> must be defined");
  6428.             fi;
  6429.         else
  6430.             if IsResidueClass( r )  then
  6431.                 Error("power of <l> and <r> must be defined");
  6432.             else
  6433.                 Error("panic, neither <l> nor <r> is a residue class");
  6434.             fi;
  6435.         fi;
  6436.         return pow;
  6437.     end; |
  6438.  
  6439. The last function that we  have to write is  the printing function.  This
  6440. is called  to print a residue class.   It prints the residue class in the
  6441. form 'ResidueClass( <representative>, <modulus> )'.  It is fairly typical
  6442. to print objects in such a form.  This form has the advantage that it can
  6443. be read back,  resulting in exactly  the  same  element, yet  it is  very
  6444. concise.
  6445.  
  6446. |    ResidueClassOps.Print := function ( r )
  6447.         Print("ResidueClass( ",r.representative,", ",r.modulus," )");
  6448.     end; |
  6449.  
  6450. Now we are done with the definition of residue classes as group elements.
  6451. Try them.  We can at this point actually create  groups of such elements,
  6452. and compute in them.
  6453.  
  6454. However, we are not yet satisfied.  There  are two problems with the code
  6455. we  have implemented  so far.  Different   people have different opinions
  6456. about which of those problems is the graver one,  but hopefully all agree
  6457. that we should try to attack those problems.
  6458.  
  6459. The first  problem is that   it is still  possible to  define objects via
  6460. 'Group' (see "Group") that are not actually groups.
  6461.  
  6462. |    gap> G := Group( ResidueClass(13,43), ResidueClass(13,41) );
  6463.     Group( ResidueClass(13,43), ResidueClass(13,41) ) |
  6464.  
  6465. The other problem is that  groups of residue classes constructed with the
  6466. code  we have  implemented so far are not handled very efficiently.  This
  6467. is  because the generic group algorithms are  used,  since  we  have  not
  6468. implemented anything else.  For example to test whether  a  residue class
  6469. lies in  a residue class group, all elements of  the residue  class group
  6470. are computed by  a  Dimino  algorithm, and  then it is tested whether the
  6471. residue class is an element of this proper set.
  6472.  
  6473. To solve the first problem we must first understand what happens with the
  6474. above code if we create   a  group with 'Group(  <res1>, <res2>...    )'.
  6475. 'Group' tries  to find a  domain that contains  all  the elements <res1>,
  6476. <res2>,  etc.  It first calls 'Domain(  [ <res1>, <res2>...    ] )'  (see
  6477. "Domain").  'Domain' looks at the residue classes  and sees that they all
  6478. are records  and that they all have  a component with  the name 'domain'.
  6479. This is understood to be a domain in which the elements lie.  And in fact
  6480. '<res1> in GroupElements' is 'true', because  'GroupElements' accepts all
  6481. records with tag 'isGroupElement'.  So 'Domain'  returns 'GroupElements'.
  6482. 'Group' then calls\\
  6483. 'GroupElements.operations.Group(GroupElements,[<res1>,<res2>...],<id>)',
  6484. where <id> is the identity residue class, obtained by '<res1> \^\ 0', and
  6485. returns the result.
  6486.  
  6487. 'GroupElementsOps.Group' is the function that actually creates the group.
  6488. It does   this by simply creating  a  record with its  second argument as
  6489. generators  list,  its  third  argument  as   identity, and  the  generic
  6490. 'GroupOps' as operations record.  It ignores the first argument, which is
  6491. passed  only because convention  dictates that  a  dispatcher passes  the
  6492. domain as first argument.
  6493.  
  6494. So  to solve  the first problem   we must achieve  that another  function
  6495. instead of the generic function 'GroupElementsOps.Group' is called.  This
  6496. can  be  done by persuading 'Domain' to  return a different  domain.  And
  6497. this will happen if the residue  classes hold this  other domain in their
  6498. 'domain' component.
  6499.  
  6500. The obvious choice for such a  domain is  the (yet to be written)  domain
  6501. 'ResidueClasses'.  So 'ResidueClass' must be slightly changed.
  6502.  
  6503. |    ResidueClass := function ( representative, modulus )
  6504.         local res;
  6505.         res := rec();
  6506.         res.isGroupElement  := true;
  6507.         res.isResidueClass  := true;
  6508.         res.representative  := representative mod modulus;
  6509.         res.modulus         := modulus;
  6510.         res.domain          := ResidueClasses;
  6511.         res.operations      := ResidueClassOps;
  6512.         return res;
  6513.     end; |
  6514.  
  6515. The main  purpose of the domain 'ResidueClasses'  is to construct groups,
  6516. so there is very little we have to do.  And  in fact most  of that can be
  6517. inherited from 'GroupElements'.
  6518.  
  6519. |    ResidueClasses := Copy( GroupElements );
  6520.     ResidueClasses.name := "ResidueClasses";
  6521.     ResidueClassesOps := Copy( GroupElementsOps );
  6522.     ResidueClasses.operations := ResidueClassesOps; |
  6523.  
  6524. So now  we must implement  'ResidueClassesOps.Group',  which should check
  6525. whether the passed elements  do in fact form a  group.  After checking it
  6526. simply delegates   to the  generic  function 'GroupElementsOps.Group'  to
  6527. create the group as before.
  6528.  
  6529. |    ResidueClassesOps.Group := function ( ResidueClasses, gens, id )
  6530.         local   g;          # one generator from <gens>
  6531.         for g  in gens  do
  6532.             if g.modulus <> id.modulus  then
  6533.                 Error("the generators must all have the same modulus");
  6534.             fi;
  6535.             if GcdInt( g.representative, g.modulus ) <> 1  then
  6536.               Error("the generators must all be prime residue classes");
  6537.             fi;
  6538.         od;
  6539.         return GroupElementOps.Group( ResidueClasses, gens, id );
  6540.     end; |
  6541.  
  6542. This solves  the first problem.   To solve the second problem,   i.e., to
  6543. make operations with residue class  groups more efficient, we must extend
  6544. the function  'ResidueClassesOps.Group'.  It now  enters a new operations
  6545. record into the group.  It  also puts the  modulus into the group record,
  6546. so that it is easier to access.
  6547.  
  6548. |    ResidueClassesOps.Group := function ( ResidueClasses, gens, id )
  6549.         local   G,          # group <G>, result
  6550.                 gen;        # one generator from <gens>
  6551.         for gen  in gens  do
  6552.             if gen.modulus <> id.modulus  then
  6553.                 Error("the generators must all have the same modulus");
  6554.             fi;
  6555.             if GcdInt( gen.representative, gen.modulus ) <> 1  then
  6556.               Error("the generators must all be prime residue classes");
  6557.             fi;
  6558.         od;
  6559.         G := GroupElementsOps.Group( ResidueClasses, gens, id );
  6560.         G.modulus    := id.modulus;
  6561.         G.operations := ResidueClassGroupOps;
  6562.         return G;
  6563.     end; |
  6564.  
  6565. Of course now we must build such an operations record.  Luckily we do not
  6566. have to  implement  all  functions,  because  we can inherit   a  lot  of
  6567. functions from 'GroupOps'.  This is done by copying 'GroupOps' as we have
  6568. done before for 'ResidueClassOps' and 'ResidueClassesOps'.
  6569.  
  6570. |    ResidueClassGroupOps := Copy( GroupOps ); |
  6571.  
  6572. Now the first function that we must write is  the  'Subgroup' function to
  6573. ensure  that  not only groups  constructed  by  'Group'  have the correct
  6574. operations  record, but  also  subgroups  of those  groups    created  by
  6575. 'Subgroup'.  As in 'Group' we only check the arguments and then leave the
  6576. work to 'GroupOps.Subgroup'.
  6577.  
  6578. |    ResidueClassGroupOps.Subgroup := function ( G, gens )
  6579.         local   S,          # subgroup of <G>, result
  6580.                 gen;        # one generator from <gens>
  6581.         for gen  in gens  do
  6582.             if gen.modulus <> G.modulus  then
  6583.                 Error("the generators must all have the same modulus");
  6584.             fi;
  6585.             if GcdInt( gen.representative, gen.modulus ) <> 1  then
  6586.               Error("the generators must all be prime residue classes");
  6587.             fi;
  6588.         od;
  6589.         S := GroupOps.Subgroup( G, gens );
  6590.         S.modulus    := G.modulus;
  6591.         S.operations := ResidueClassGroupOps;
  6592.         return S;
  6593.     end; |
  6594.  
  6595. The first function  that we write especially for residue  class groups is
  6596. 'SylowSubgroup'.  Since residue class groups are abelian we can compute a
  6597. Sylow subgroup of such a group by simply taking appropriate powers of the
  6598. generators.
  6599.  
  6600. |    ResidueClassGroupOps.SylowSubgroup := function ( G, p )
  6601.         local   S,          # Sylow subgroup of <G>, result
  6602.                 gen,        # one generator of <G>
  6603.                 ord,        # order of <gen>
  6604.                 gens;       # generators of <S>
  6605.         gens := [];
  6606.         for gen  in G.generators  do
  6607.             ord := OrderMod( gen.representative, G.modulus );
  6608.             while ord mod p = 0  do ord := ord / p;  od;
  6609.             Add( gens, gen ^ ord );
  6610.         od;
  6611.         S := Subgroup( Parent( G ), gens );
  6612.         return S;
  6613.     end; |
  6614.  
  6615. To allow the other functions that are applicable  to residue class groups
  6616. to  work efficiently we  now want to make  use of the  fact  that residue
  6617. class groups are direct  products of cyclic groups and  that we know what
  6618. those factors are and how we can project onto those factors.
  6619.  
  6620. To do  this  we write 'ResidueClassGroupOps.MakeFactors'  that   adds the
  6621. components 'facts', 'roots', 'sizes', and 'sgs' to  the group record <G>.
  6622. This  information,  detailed below, will enable  other  functions to work
  6623. efficiently  with such groups.  Creating   such information   is a fairly
  6624. typical thing,  for  example  for  permutation  groups the  corresponding
  6625. information is the stabilizer chain computed by 'MakeStabChain'.
  6626.  
  6627. '<G>.facts'  will be the list  of prime power factors  of  '<G>.modulus'.
  6628. Actually this is a little bit more complicated, because the residue class
  6629. group modulo the largest power  <q> of 2 that  divides '<G>.modulus' need
  6630. not be  cyclic.  So if <q>  is a multiple of 4, '<G>.facts[1]' will be 4,
  6631. corresponding to the  projection of <G> into $(Z / 4 Z)^\*$ (of  size 2),
  6632. furthermore  if  <q>  is  a multiple  of  8,  '<G>.facts[2]' will be <q>,
  6633. corresponding to the projection of <G> into the  subgroup  generated by 5
  6634. in $(Z / q Z)^\*$ (of size $q/4$).
  6635.  
  6636. '<G>.roots' will be a list of primitive roots, i.e., of generators of the
  6637. corresponding factors in '<G>.facts'.  '<G>.sizes' will be  a list of the
  6638. sizes of the corresponding factors  in '<G>.facts', i.e., '<G>.sizes[<i>]
  6639. = Phi(  <G>.facts[<i>]   )'.   (If  '<G>.modulus'  is a  multiple  of  8,
  6640. '<G>.roots[2]' will be 5, and '<G>.sizes[2]' will be <q>/4.)
  6641.  
  6642. Now we can  represent each element <g> of  the group <G>  by a list  <e>,
  6643. called  the exponent   vector,  of   the  length of  '<G>.facts',   where
  6644. '<e>[<i>]' is the  logarithm of  '<g>.representative  mod <G>.facts[<i>]'
  6645. with respect to '<G>.roots[<i>]'.  The  multiplication of elements of <G>
  6646. corresponds to the  componentwise  addition  of their  exponent  vectors,
  6647. where we add  modulo  '<G>.sizes[<i>]' in the  <i>-th component.   (Again
  6648. special consideration are necessary if '<G>.modulus' is divisible by 8.)
  6649.  
  6650. Next we compute  the  exponent  vectors of  all  generators of  <G>,  and
  6651. represent this information as a matrix.  Then we  bring this  matrix into
  6652. upper  triangular  form, with an algorithm that  is  very  much  like the
  6653. ordinary Gaussian  elimination,  modified  to  account for the  different
  6654. sizes  of  the  components.   This  upper triangular  matrix  of exponent
  6655. vectors  is  the component '<G>.sgs'.   This new  matrix  obviously still
  6656. contains the exponent vectors of a  generating  system of <G>, but a much
  6657. nicer one, which allows us to tackle problems  one component at  a  time.
  6658. (It is not necessary that you  fully check this, the important thing here
  6659. is not the mathematical side.)
  6660.  
  6661. |    ResidueClassGroupOps.MakeFactors := function ( G )
  6662.         local   p, q,       # prime factor of modulus and largest power
  6663.                 r, s,       # two rows of the standard generating system
  6664.                 g,          # extended gcd of leading entries in <r>, <s>
  6665.                 x, y,       # two entries in <r> and <s>
  6666.                 i, k, l;    # loop variables
  6667.  
  6668.         # find the factors of the direct product
  6669.         G.facts := [];
  6670.         G.roots := [];
  6671.         G.sizes := [];
  6672.         for p  in Set( Factors( G.modulus ) )  do
  6673.             q := p;
  6674.             while G.modulus mod (p*q) = 0  do q := p*q;  od;
  6675.             if q mod 4 = 0  then
  6676.                 Add( G.facts, 4 );
  6677.                 Add( G.roots, 3 );
  6678.                 Add( G.sizes, 2 );
  6679.             fi;
  6680.             if q mod 8 = 0  then
  6681.                 Add( G.facts, q );
  6682.                 Add( G.roots, 5 );
  6683.                 Add( G.sizes, q/4 );
  6684.             fi;
  6685.             if p <> 2  then
  6686.                 Add( G.facts, q );
  6687.                 Add( G.roots, PrimitiveRootMod( q ) );
  6688.                 Add( G.sizes, (p-1)*q/p );
  6689.             fi;
  6690.         od;
  6691.  
  6692.         # represent each generator in this factorization
  6693.         G.sgs := [];
  6694.         for k  in [ 1 .. Length( G.generators ) ]  do
  6695.             G.sgs[k] := [];
  6696.             for i  in [ 1 .. Length( G.facts ) ]  do
  6697.                 if G.facts[i] mod 8 = 0  then
  6698.                     if G.generators[k].representative mod 4 = 1  then
  6699.                         G.sgs[k][i] := LogMod(
  6700.                             G.generators[k].representative,
  6701.                             G.roots[i], G.facts[i] );
  6702.                     else
  6703.                         G.sgs[k][i] := LogMod(
  6704.                             -G.generators[k].representative,
  6705.                             G.roots[i], G.facts[i] );
  6706.                     fi;
  6707.                 else
  6708.                     G.sgs[k][i] := LogMod(
  6709.                             G.generators[k].representative,
  6710.                             G.roots[i], G.facts[i] );
  6711.                 fi;
  6712.             od;
  6713.         od;
  6714.         for i  in [ Length( G.sgs ) + 1 .. Length( G.facts ) ]  do
  6715.             G.sgs[i] := 0 * G.facts;
  6716.         od;
  6717.  
  6718.         # bring this matrix to diagonal form
  6719.         for i  in [ 1 .. Length( G.facts ) ]  do
  6720.             r := G.sgs[i];
  6721.             for k  in [ i+1 .. Length( G.sgs ) ]  do
  6722.                 s := G.sgs[k];
  6723.                 g := Gcdex( r[i], s[i] );
  6724.                 for l  in [ i .. Length( r ) ]  do
  6725.                     x := r[l];  y := s[l];
  6726.                     r[l] := (g.coeff1 * x + g.coeff2 * y) mod G.sizes[l];
  6727.                     s[l] := (g.coeff3 * x + g.coeff4 * y) mod G.sizes[l];
  6728.                 od;
  6729.             od;
  6730.             s := [];
  6731.             x := G.sizes[i] / GcdInt( G.sizes[i], r[i] );
  6732.             for l  in [ 1 .. Length( r ) ]  do
  6733.                 s[l] := (x * r[l]) mod G.sizes[l];
  6734.             od;
  6735.             Add( G.sgs, s );
  6736.         od;
  6737.  
  6738.     end; |
  6739.  
  6740. With the information computed by  'MakeFactors' it  is now of course very
  6741. easy to compute the size of  a residue class group.  We  just look at the
  6742. '<G>.sgs',  and  multiply  the orders  of  the  leading exponents  of the
  6743. nonzero exponent vectors.
  6744.  
  6745. |    ResidueClassGroupOps.Size := function ( G )
  6746.         local   s,          # size of <G>, result
  6747.                 i;          # loop variable
  6748.         if not IsBound( G.facts )  then
  6749.             G.operations.MakeFactors( G );
  6750.         fi;
  6751.         s := 1;
  6752.         for i  in [ 1 .. Length( G.facts ) ]  do
  6753.             s := s * G.sizes[i] / GcdInt( G.sizes[i], G.sgs[i][i] );
  6754.         od;
  6755.         return s;
  6756.     end; |
  6757.  
  6758. The membership test is a little bit more complicated.  First we test that
  6759. the first argument is really  a residue  class with the  correct modulus.
  6760. Then we compute the exponent vector of this residue class and reduce this
  6761. exponent vector using the upper triangular matrix '<G>.sgs'.
  6762.  
  6763. |    ResidueClassGroupOps.'in' := function ( res, G )
  6764.         local   s,          # exponent vector of <res>
  6765.                 g,          # extended gcd
  6766.                 x, y,       # two entries in <s> and '<G>.sgs[i]'
  6767.                 i, l;       # loop variables
  6768.         if not IsResidueClass( res )
  6769.             or res.modulus <> G.modulus
  6770.             or GcdInt( res.representative, res.modulus ) <> 1
  6771.         then
  6772.             return false;
  6773.         fi;
  6774.         if not IsBound( G.facts )  then
  6775.             G.operations.MakeFactors( G );
  6776.         fi;
  6777.         s := [];
  6778.         for i  in [ 1 .. Length( G.facts ) ]  do
  6779.             if G.facts[i] mod 8 = 0  then
  6780.                 if res.representative mod 4 = 1  then
  6781.                     s[i] := LogMod( res.representative,
  6782.                                     G.roots[i], G.facts[i] );
  6783.                 else
  6784.                     s[i] := LogMod( -res.representative,
  6785.                                     G.roots[i], G.facts[i] );
  6786.                 fi;
  6787.             else
  6788.                 s[i] := LogMod( res.representative,
  6789.                                 G.roots[i], G.facts[i] );
  6790.             fi;
  6791.         od;
  6792.         for i  in [ 1 .. Length( G.facts ) ]  do
  6793.             if s[i] mod GcdInt( G.sizes[i], G.sgs[i][i] ) <> 0  then
  6794.                 return false;
  6795.             fi;
  6796.             g := Gcdex( s[i], G.sgs[i][i] );
  6797.             for l  in [ i .. Length( G.facts ) ]  do
  6798.                 x := s[l];  y := G.sgs[i][l];
  6799.                 s[l] := (g.coeff3 * x + g.coeff4 * y) mod G.sizes[l];
  6800.             od;
  6801.         od;
  6802.         return true;
  6803.     end; |
  6804.  
  6805. We also add a function 'Random' that works by creating a random  exponent
  6806. as a random  linear combination of the exponent vectors in '<G>.sgs', and
  6807. converts this exponent vector to  a  residue class.  (The main purpose of
  6808. this function  is  to allow you to create random test  examples  for  the
  6809. other functions.)
  6810.  
  6811. |    ResidueClassGroupOps.Random := function ( G )
  6812.         local   s,          # exponent vector of random element
  6813.                 r,          # vector of remainders in each factor
  6814.                 i, k, l;    # loop variables
  6815.         if not IsBound( G.facts )  then
  6816.             G.operations.MakeFactors( G );
  6817.         fi;
  6818.         s := 0 * G.facts;
  6819.         for i  in [ 1 .. Length( G.facts ) ]  do
  6820.             l := G.sizes[i] / GcdInt( G.sizes[i], G.sgs[i][i] );
  6821.             k := Random( [ 0 .. l-1 ] );
  6822.             for l  in [ i .. Length( s ) ]  do
  6823.                 s[l] := (s[l] + k * G.sgs[i][l]) mod G.sizes[l];
  6824.             od;
  6825.         od;
  6826.         r := [];
  6827.         for l  in [ 1 .. Length( s ) ]  do
  6828.             r[l] := PowerModInt( G.roots[l], s[l], G.facts[l] );
  6829.             if G.facts[l] mod 8 = 0  and r[1] = 3  then
  6830.                 r[l] := G.facts[l] - r[l];
  6831.             fi;
  6832.         od;
  6833.         return ResidueClass( ChineseRem( G.facts, r ), G.modulus );
  6834.     end; |
  6835.  
  6836. There are  a lot more functions that would benefit from being implemented
  6837. especially for residue class groups.  We do not  show them  here, because
  6838. the above functions already displayed how such functions can be written.
  6839.  
  6840. To round things  up, we finally add a function  that  constructs the full
  6841. residue class  group given a  modulus  <m>.   This  function  is  totally
  6842. independent of  the implementation  of residue classes and residue  class
  6843. groups.  It only has to find a (minimal) system of generators of the full
  6844. prime residue classes group, and to call 'Group' to construct this group.
  6845. It also adds the information entry 'size' to the group record,  of course
  6846. with the value $\phi(n)$.
  6847.  
  6848. |    PrimeResidueClassGroup := function ( m )
  6849.         local   G,          # group $Z/mZ$, result
  6850.                 gens,       # generators of <G>
  6851.                 p, q,       # prime and prime power dividing <m>
  6852.                 r,          # primitive root modulo <q>
  6853.                 g;          # is = <r> mod <q> and = 1 mod <m> / <q>
  6854.  
  6855.         # add generators for each prime power factor <q> of <m>
  6856.         gens := [];
  6857.         for p  in Set( Factors( m ) )  do
  6858.             q := p;
  6859.             while m mod (q * p) = 0  do q := q * p;  od;
  6860.  
  6861.             # $(Z / 4Z)^\* = \< 3 > $
  6862.             if   q = 4  then
  6863.                 r := 3;
  6864.                 g := r + q * (((1/q mod (m/q)) * (1 - r)) mod (m/q));
  6865.                 Add( gens, ResidueClass( g, m ) );
  6866.  
  6867.             # $(Z / 8nZ)^\* = \< 5, -1 > $ is *not* cyclic
  6868.             elif q mod 8 = 0  then
  6869.                 r := q-1;
  6870.                 g := r + q * (((1/q mod (m/q)) * (1 - r)) mod (m/q));
  6871.                 Add( gens, ResidueClass( g, m ) );
  6872.                 r := 5;
  6873.                 g := r + q * (((1/q mod (m/q)) * (1 - r)) mod (m/q));
  6874.                 Add( gens, ResidueClass( g, m ) );
  6875.  
  6876.             # for odd <q> $(Z / qZ)^\*$ is cyclic
  6877.             elif q <> 2  then
  6878.                 r :=  PrimitiveRootMod( q );
  6879.                 g := r + q * (((1/q mod (m/q)) * (1 - r)) mod (m/q));
  6880.                 Add( gens, ResidueClass( g, m ) );
  6881.             fi;
  6882.  
  6883.         od;
  6884.  
  6885.         # return the group generated by <gens>
  6886.         G := Group( gens, ResidueClass( 1, m ) );
  6887.         G.size := Phi( n );
  6888.         return G;
  6889.     end; |
  6890.  
  6891. There   is  one  more   thing  that we   can   learn  from this  example.
  6892. Mathematically a residue class is not only a group  element, but a set as
  6893. well.  We can  reflect  this in {\GAP}  by  turning residue classes  into
  6894. domains  (see "Domains").  Section "About Defining  New Domains" gives an
  6895. example of how to implement a  new domain, so  we will here only show the
  6896. code with few comments.
  6897.  
  6898. First we must  change the function  that  constructs a residue class,  so
  6899. that it enters the necessary fields to tag  this record as  a domain.  It
  6900. also adds the information that residue classes are infinite.
  6901.  
  6902. |    ResidueClass := function ( representative, modulus )
  6903.         local res;
  6904.         res := rec();
  6905.         res.isGroupElement  := true;
  6906.         res.isDomain        := true;
  6907.         res.isResidueClass  := true;
  6908.         res.representative  := representative mod modulus;
  6909.         res.modulus         := modulus;
  6910.         res.isFinite        := false;
  6911.         res.size            := "infinity";
  6912.         res.domain          := ResidueClasses;
  6913.         res.operations      := ResidueClassOps;
  6914.         return res;
  6915.     end; |
  6916.  
  6917. The  initialization of the  'ResidueClassOps' record must be changed too,
  6918. because now   we  want  to   inherit  both  from  'GroupElementsOps'  and
  6919. 'DomainOps'.  This is  done by the function 'MergedRecord',  which  takes
  6920. two records and  returns a new record  that contains all components  from
  6921. either record.
  6922.  
  6923. Note  that the  record returned  by  'MergedRecord' does not  have  those
  6924. components that appear in both arguments.  This forces  us  to explicitly
  6925. write down from which  record we  want to inherit those functions, or  to
  6926. define   them   anew.    In  our  example   the   components   common  to
  6927. 'GroupElementOps'  and 'DomainOps' are  only  the  equality and  ordering
  6928. functions, which  we  have  to  define  anyhow.   (This  solution for the
  6929. problem of which definition to choose in the case of multiple inheritance
  6930. is also taken by C++.)
  6931.  
  6932. With this function definition we can now initialize 'ResidueClassOps'.
  6933.  
  6934. |    ResidueClassOps := MergedRecord( GroupElementOps, DomainOps ); |
  6935.  
  6936. Now we add all functions to this record as described above.
  6937.  
  6938. Next  we add a  function  to the operations record  that tests  whether a
  6939. certain object is in a residue class.
  6940.  
  6941. |    ResidueClassOps.'in' := function ( element, class )
  6942.         if IsInt( element )  then
  6943.             return (element mod class.modulus = class.representative);
  6944.         else
  6945.             return false;
  6946.         fi;
  6947.     end; |
  6948.  
  6949. Finally we add   a function to  compute  the intersection of two  residue
  6950. classes.
  6951.  
  6952. |    ResidueClassOps.Intersection := function ( R, S )
  6953.         local   I,          # intersection of <R> and <S>, result
  6954.                 gcd;        # gcd of the moduli
  6955.         if IsResidueClass( R )  then
  6956.             if IsResidueClass( S )  then
  6957.                 gcd := GcdInt( R.modulus, S.modulus );
  6958.                 if     R.representative mod gcd
  6959.                     <> S.representative mod gcd
  6960.                 then
  6961.                     I := [];
  6962.                 else
  6963.                     I := ResidueClass(
  6964.                             ChineseRem(
  6965.                                 [ R.representative, S.representative ],
  6966.                                 [ R.modulus,        S.modulus ] ),
  6967.                             Lcm(  R.modulus,        S.modulus ) );
  6968.                 fi;
  6969.             else
  6970.                 I := DomainOps.Intersection( R, S );
  6971.             fi;
  6972.         else
  6973.             I := DomainOps.Intersection( R, S );
  6974.         fi;
  6975.         return I;
  6976.     end; |
  6977.  
  6978. There is  one further thing that we  have to do.  When 'Group' is  called
  6979. with a  single  argument  that is a domain, it  assumes that you  want to
  6980. create a new  group such that  there is a bijection between  the original
  6981. domain and the  new group.  This  is not what we want here.  We want that
  6982. in this case  we  get the  cyclic  group that is generated by the  single
  6983. residue class.  (This overloading of 'Group'  is probably  a mistake, but
  6984. so is the  overloading of residue classes, which  are both group elements
  6985. and domains.)  The following definition solves this problem.
  6986.  
  6987. |    ResidueClassOps.Group := function ( R )
  6988.         return ResidueClassesOps.Group( ResidueClasses, [R], R^0 );
  6989.     end; |
  6990.  
  6991. This  concludes our example.   There  are however  several further things
  6992. that  you could do.   One  is  to  add  functions  for  the quotient, the
  6993. modulus, etc.  Another is to  fix the functions so that  they do not hang
  6994. if asked  for the  residue class group  mod  1.   Also you might  try  to
  6995. implement residue class rings analogous to residue class groups.  Finally
  6996. it  might be worthwhile  to  improve the speed  of the multiplication  of
  6997. prime residue classes.   This can be done by doing some precomputation in
  6998. 'ResidueClass' and adding  some  information  to the residue class record
  6999. for prime residue classes (\cite{Mon85}).
  7000.  
  7001. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  7002. %%
  7003. %E  Emacs . . . . . . . . . . . . . . . . . . . . . local Emacs variables
  7004. %%
  7005. %%  Local Variables:
  7006. %%  mode:               outline
  7007. %%  outline-regexp:     "\\\\Chapter\\|\\\\Section"
  7008. %%  fill-column:        73
  7009. %%  eval:               (hide-body)
  7010. %%  End:
  7011. %%
  7012.