home *** CD-ROM | disk | FTP | other *** search
/ Math Solutions 1995 October / Math_Solutions_CD-ROM_Walnut_Creek_October_1995.iso / pc / mac / discrete / lib / grpcoset.g < prev    next >
Encoding:
Text File  |  1993-05-05  |  50.3 KB  |  1,816 lines

  1. #############################################################################
  2. ##
  3. #A  grpcoset.g                  GAP library                  Martin Schoenert
  4. ##
  5. #A  @(#)$Id: grpcoset.g,v 3.10 1993/01/18 18:55:57 martin Rel $
  6. ##
  7. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  8. ##
  9. ##  This file contains dispatcher and default functions for coset  functions.
  10. ##
  11. #H  $Log: grpcoset.g,v $
  12. #H  Revision 3.10  1993/01/18  18:55:57  martin
  13. #H  added double coset functions
  14. #H
  15. #H  Revision 3.9  1992/12/16  19:47:27  martin
  16. #H  replaced quoted record names with escaped ones
  17. #H
  18. #H  Revision 3.8  1992/06/01  12:04:10  martin
  19. #H  fixed a minor problem in 'FactorGroupElementsOps.Order'
  20. #H
  21. #H  Revision 3.7  1992/05/08  16:20:25  martin
  22. #H  changed 'FactorGroupOps.*' to avoid 'FactorGroupElement' dispatcher
  23. #H
  24. #H  Revision 3.6  1992/03/27  11:14:51  martin
  25. #H  changed mapping to general mapping and function to mapping
  26. #H
  27. #H  Revision 3.5  1992/03/25  08:31:06  martin
  28. #H  fixed a few problems for natural homomorphisms
  29. #H
  30. #H  Revision 3.4  1992/02/10  15:14:35  martin
  31. #H  added the domain 'Mappings'
  32. #H
  33. #H  Revision 3.3  1992/01/30  10:38:20  martin
  34. #H  changed 'NaturalHomomorphism', not every is surjective
  35. #H
  36. #H  Revision 3.2  1992/01/29  09:09:38  martin
  37. #H  changed 'Order' to take two arguments, group and element
  38. #H
  39. #H  Revision 3.1  1992/01/07  12:31:47  martin
  40. #H  initial revision under RCS
  41. #H
  42. ##
  43.  
  44.  
  45. #############################################################################
  46. ##
  47. #F  GroupOps.\*(<G>,<H>) . . . . . . . . . . . . . . . . . product of groups
  48. ##
  49. GroupOps.\* := function ( G, H )
  50.     local   P;          # product of <G> and <H>, result
  51.     if IsGroup( G )  and H in Parent( G )  then
  52.         P := RightCoset( G, H );
  53.     elif IsGroup( H )  and G in Parent( H )  then
  54.         P := LeftCoset( H, G );
  55.     elif IsGroup( G )  then
  56.         P := Elements( G ) * H;
  57.     elif IsGroup( H )  then
  58.         P := G * Elements( H );
  59.     else
  60.         Error("panic, neither <G> nor <H> is a group");
  61.     fi;
  62.     return P;
  63. end;
  64.  
  65.  
  66. #############################################################################
  67. ##
  68. #F  IsRightCoset(<C>) . . . . . . . . . .  test if an object is a right coset
  69. ##
  70. IsRightCoset := function ( C )
  71.     return IsRec( C )
  72.        and IsBound( C.isRightCoset )
  73.        and C.isRightCoset;
  74. end;
  75.  
  76. IsCoset := function ( C )
  77.     return IsRightCoset( C );
  78. end;
  79.  
  80.  
  81. #############################################################################
  82. ##
  83. #F  RightCoset(<U>,<g>) . . . . . . . . . . . . . . . .  create a right coset
  84. ##
  85. RightCoset := function ( arg )
  86.     local   C;
  87.     if Length( arg ) = 1  and IsGroup( arg[1] )  then
  88.         C := arg[1].operations.RightCoset( arg[1], arg[1].identity );
  89.     elif Length( arg ) = 2  and IsGroup( arg[1] )  then
  90.         if not arg[2] in Parent( arg[1] )  then
  91.             Error("<g> must be in the parent group of <U>");
  92.         fi;
  93.         C := arg[1].operations.RightCoset( arg[1], arg[2] );
  94.     else
  95.         Error("usage: RightCoset( <U> [, <g>] )");
  96.     fi;
  97.     return C;
  98. end;
  99.  
  100. Coset := function ( arg )
  101.     if Length( arg ) = 1  then
  102.         return RightCoset( arg[1] );
  103.     elif Length( arg ) = 2  then
  104.         return RightCoset( arg[1], arg[2] );
  105.     else
  106.         Error("usage: Coset( <U> [, <g>] )");
  107.     fi;
  108. end;
  109.  
  110.  
  111. #############################################################################
  112. ##
  113. #F  GroupOps.RightCoset(<U>,<g>)  . . . . . . . . . . .  create a right coset
  114. #V  RightCosetGroupOps  . . . . . . .  operations record of cosets in a group
  115. ##
  116. ##  'GroupOps.RightCoset'  is the   default   function   to create a    right
  117. ##  coset.   It only  stuffs <U>   and  <g>  in  a  record  and  enters   the
  118. ##  operations record 'RightCosetGroupOps'.
  119. ##
  120. ##  'RightCosetGroupOps'  is the operations  record  of  right  cosets  in  a
  121. ##  generic  group.  Thus 'RightCosetGroupOps'  is the operations  record  of
  122. ##  default functions  for right  cosets.   Right cosets in special  types of
  123. ##  groups, e.g.,  permutation  groups,  inherit  the   default  functions by
  124. ##  making  a  copy   of  'RightCosetGroupOps' and  overlaying   the  default
  125. ##  functions with more efficient ones.
  126. ##
  127. GroupOps.RightCoset := function ( U, g )
  128.     local   C;          # right coset of <U> and <g>, result
  129.  
  130.     # make the domain
  131.     C := rec( );
  132.     C.isDomain          := true;
  133.     C.isRightCoset      := true;
  134.  
  135.     # enter the identifying information
  136.     C.group             := U;
  137.     C.representative    := g;
  138.  
  139.     # enter knowledge
  140.     if IsBound( U.isFinite )  then
  141.         C.isFinite      := U.isFinite;
  142.     fi;
  143.     if IsBound( U.size )  then
  144.         C.size          := U.size;
  145.     fi;
  146.  
  147.     # enter the operations record
  148.     C.operations        := RightCosetGroupOps;
  149.  
  150.     # return the coset
  151.     return C;
  152. end;
  153.  
  154. RightCosetGroupOps := Copy( DomainOps );
  155.  
  156. RightCosetGroupOps.Elements := function ( C )
  157.     local   elms;       # elements of the coset <C>, result
  158.  
  159.     # compute the set of elements
  160.     elms := Set( Elements( C.group ) * C.representative );
  161.  
  162.     # return the set of elements
  163.     return elms;
  164. end;
  165.  
  166. RightCosetGroupOps.IsFinite := function ( C )
  167.     return IsFinite( C.group );
  168. end;
  169.  
  170. RightCosetGroupOps.Size := function ( C )
  171.     return Size( C.group );
  172. end;
  173.  
  174. RightCosetGroupOps.\= := function( C, D )
  175.     local   isEql;
  176.  
  177.     # compare a right coset
  178.     if IsRightCoset( C )  then
  179.  
  180.         # with another right coset
  181.         if IsRightCoset( D )  then
  182.             isEql := C.group = D.group
  183.                      and C.representative / D.representative in C.group;
  184.  
  185.         # with a subgroup, which is a special right coset
  186.         elif IsGroup( D )  then
  187.             isEql := C.group = D  and C.representative in C.group;
  188.  
  189.         # with something else
  190.         else
  191.             isEql := DomainOps.\=( C, D );
  192.         fi;
  193.  
  194.     # compare a subgroup, which is a special right coset
  195.     elif IsGroup( C )  then
  196.  
  197.         # with a right coset
  198.         if IsRightCoset( D )  then
  199.             isEql := C = D.group  and D.representative in C;
  200.  
  201.         # with something else
  202.         else
  203.             Error("panic, neither <C> nor <D> is a right coset");
  204.         fi;
  205.  
  206.     # compare something else
  207.     else
  208.  
  209.         # with a right coset
  210.         if IsRightCoset( D )  then
  211.             isEql := DomainOps.\=( C, D );
  212.  
  213.         # with another something else
  214.         else
  215.             Error("panic, neither <C> nor <D> is a right coset");
  216.         fi;
  217.  
  218.     fi;
  219.  
  220.     # return the result
  221.     return isEql;
  222. end;
  223.  
  224. RightCosetGroupOps.\in := function ( g, C )
  225.  
  226.     # use the list of elements of the subgroup if they are known
  227.     if IsBound( C.group.elements )  then
  228.         return g/C.representative in C.group.elements;
  229.  
  230.     # otherwise leave it to the subgroup to sort things out
  231.     else
  232.         return g/C.representative in C.group;
  233.     fi;
  234.  
  235. end;
  236.  
  237. RightCosetGroupOps.Intersection := function ( C, D )
  238.     local   I;          # intersection of <C> and <D>, result
  239.  
  240.     # special case of intersection of two right cosets
  241.     if IsRightCoset( C )  and IsRightCoset( D )  and C.group = D.group  then
  242.  
  243.         # its either the whole coset
  244.         if C.representative/D.representative in C.group  then
  245.             I := ShallowCopy( C );
  246.  
  247.         # or it is empty
  248.         else
  249.             I := [];
  250.         fi;
  251.  
  252.     # intersection of a right coset with something else
  253.     else
  254.         I := DomainOps.Intersection( C, D );
  255.     fi;
  256.  
  257.     # return the intersection
  258.     return I;
  259. end;
  260.  
  261. RightCosetGroupOps.Union := function ( C, D )
  262.     local   U;          # union of <C> and <D>, result
  263.  
  264.     # special case of intersection of two right cosets
  265.     if IsRightCoset( C )  and IsRightCoset( D )  and C.group = D.group  then
  266.  
  267.         # its either the whole coset
  268.         if C.representative/D.representative in C.group  then
  269.             U := ShallowCopy( C );
  270.  
  271.         # or the union
  272.         else
  273.             U := DomainOps.Union( C, D );
  274.         fi;
  275.  
  276.     # union of  a right coset and something else
  277.     else
  278.         U := DomainOps.Union( C, D );
  279.     fi;
  280.  
  281.     # return the union
  282.     return U;
  283. end;
  284.  
  285. RightCosetGroupOps.Random := function ( C )
  286.     return Random( C.group ) * C.representative;
  287. end;
  288.  
  289. RightCosetGroupOps.Print := function( C )
  290.     if IsBound( C.name )  then
  291.         Print( C.name );
  292.     else
  293.         Print( "(", C.group, "*", C.representative, ")" );
  294.     fi;
  295. end;
  296.  
  297. RightCosetGroupOps.\* := function ( C, D )
  298.     local   E;          # product of <C> and <D>, result
  299.     if IsRightCoset( C )  and D in Parent( C.group )  then
  300.         E := RightCoset( C.group, C.representative * D );
  301.     elif IsRightCoset( C )  then
  302.         E := Elements( C ) * D;
  303.     elif IsRightCoset( D )  then
  304.         E := C * Elements( D );
  305.     else
  306.         Error("product of <C> and <D> is not defined");
  307.     fi;
  308.     return E;
  309. end;
  310.  
  311.  
  312. #############################################################################
  313. ##
  314. #F  RightCosets(<G>,<U>)  . . . . . . . right cosets of a subgroup in a group
  315. ##
  316. RightCosets := function ( G, U )
  317.     local   C;          # right cosets of <U> in <G>, result
  318.  
  319.     # check the arguments
  320.     if not IsGroup( G )  then
  321.         Error("<G> must be a group");
  322.     fi;
  323.     if not IsSubgroup( G, U )  then
  324.         Error("<U> must be a subgroup of <G>");
  325.     fi;
  326.  
  327.     # compute the right cosets
  328.     if IsParent( G )  then
  329.         if not IsBound( U.rightCosets )  then
  330.             U.rightCosets := G.operations.RightCosets( G, U );
  331.         fi;
  332.         C := U.rightCosets;
  333.     else
  334.         C := G.operations.RightCosets( G, U );
  335.     fi;
  336.  
  337.     # return the right cosets
  338.     return C;
  339. end;
  340.  
  341. Cosets := function ( G, U )
  342.     return RightCosets( G, U );
  343. end;
  344.  
  345.  
  346. #############################################################################
  347. ##
  348. #F  GroupOps.RightCosets(<G>,<U>) . . . right cosets of a subgroup in a group
  349. ## 
  350. GroupOps.RightCosets := function ( G, U )
  351.     return Orbit( G, RightCoset( U ), OnRight );
  352. end;
  353.  
  354.  
  355. #############################################################################
  356. ##
  357. #F  IsLeftCoset(<C>)  . . . . . . . . . . . test if an object is a left coset
  358. ##
  359. IsLeftCoset := function ( C )
  360.     return IsRec( C )
  361.        and IsBound( C.isLeftCoset )
  362.        and C.isLeftCoset;
  363. end;
  364.  
  365.  
  366. #############################################################################
  367. ##
  368. #F  LeftCoset(<U>,<g>)  . . . . . . . . . . . . . . . . . create a left coset
  369. ##
  370. LeftCoset := function ( arg )
  371.     local   C;
  372.     if Length( arg ) = 1  and IsGroup( arg[1] )  then
  373.         C := arg[1].operations.LeftCoset( arg[1], arg[1].identity );
  374.     elif Length( arg ) = 2  and IsGroup( arg[1] )  then
  375.         if not arg[2] in Parent( arg[1] )  then
  376.             Error("<g> must be in the parent group of <U>");
  377.         fi;
  378.         C := arg[1].operations.LeftCoset( arg[1], arg[2] );
  379.     else
  380.         Error("usage: LeftCoset( <U> [, <g>] )");
  381.     fi;
  382.     return C;
  383. end;
  384.  
  385.  
  386. #############################################################################
  387. ##
  388. #F  GroupOps.LeftCoset(<U>,<g>) . . . . . . . . . . . . . create a left coset
  389. #V  LeftCosetGroupOps . . . . . . . .  operations record of cosets in a group
  390. ##
  391. ##  'GroupOps.LeftCoset' is the default  function  to  create a  left  coset.
  392. ##  It only   stuffs <U> and <g>  in  a  record  and  enters   the operations
  393. ##  record 'LeftCosetGroupOps'.
  394. ##
  395. ##  'LeftCosetGroupOps'   is the  operations  record of  left   cosets   in a
  396. ##  generic group.    Thus  'LeftCosetGroupOps' is the  operations  record of
  397. ##  default functions  for left  cosets.    Left cosets in special   types of
  398. ##  groups,   e.g.,  permutation groups,   inherit the   default functions by
  399. ##  making  a   copy  of 'LeftCosetGroupOps'   and  overlaying   the  default
  400. ##  functions with more efficient ones.
  401. ##
  402. GroupOps.LeftCoset := function ( U, g )
  403.     local   C;          # left coset of <U> and <g>, result
  404.  
  405.     # make the domain
  406.     C := rec( );
  407.     C.isDomain          := true;
  408.     C.isLeftCoset      := true;
  409.  
  410.     # enter the identifying information
  411.     C.group             := U;
  412.     C.representative    := g;
  413.  
  414.     # enter knowledge
  415.     if IsBound( U.isFinite )  then
  416.         C.isFinite      := U.isFinite;
  417.     fi;
  418.     if IsBound( U.size )  then
  419.         C.size          := U.size;
  420.     fi;
  421.  
  422.     # enter the operations record
  423.     C.operations        := LeftCosetGroupOps;
  424.  
  425.     # return the coset
  426.     return C;
  427. end;
  428.  
  429. LeftCosetGroupOps := Copy( DomainOps );
  430.  
  431. LeftCosetGroupOps.Elements := function ( C )
  432.     local   elms;       # elements of the coset <C>, result
  433.  
  434.     # compute the set of elements
  435.     elms := Set( C.representative * Elements( C.group ) );
  436.  
  437.     # return the set of elements
  438.     return elms;
  439. end;
  440.  
  441. LeftCosetGroupOps.IsFinite := function ( C )
  442.     return IsFinite( C.group );
  443. end;
  444.  
  445. LeftCosetGroupOps.Size := function ( C )
  446.     return Size( C.group );
  447. end;
  448.  
  449. LeftCosetGroupOps.\= := function( C, D )
  450.     local   isEql;
  451.  
  452.     # compare a left coset
  453.     if IsLeftCoset( C )  then
  454.  
  455.         # with another left coset
  456.         if IsLeftCoset( D )  then
  457.             isEql := C.group = D.group
  458.               and LeftQuotient(C.representative,D.representative) in C.group;
  459.  
  460.         # with a subgroup, which is a special left coset
  461.         elif IsGroup( D )  then
  462.             isEql := C.group = D  and C.representative in C.group;
  463.  
  464.         # with something else
  465.         else
  466.             isEql := DomainOps.\=( C, D );
  467.         fi;
  468.  
  469.     # compare a subgroup, which is a special left coset
  470.     elif IsGroup( C )  then
  471.  
  472.         # with a left coset
  473.         if IsLeftCoset( D )  then
  474.             isEql := C = D.group  and D.representative in C;
  475.  
  476.         # with something else
  477.         else
  478.             Error("panic, neither <C> nor <D> is a left coset");
  479.         fi;
  480.  
  481.     # compare something else
  482.     else
  483.  
  484.         # with a left coset
  485.         if IsLeftCoset( D )  then
  486.             isEql := DomainOps.\=( C, D );
  487.  
  488.         # with another something else
  489.         else
  490.             Error("panic, neither <C> nor <D> is a left coset");
  491.         fi;
  492.  
  493.     fi;
  494.  
  495.     # return the result
  496.     return isEql;
  497. end;
  498.  
  499. LeftCosetGroupOps.\in := function ( g, C )
  500.  
  501.     # use the list of elements of the subgroup if they are known
  502.     if IsBound( C.group.elements )  then
  503.         return LeftQuotient( g, C.representative ) in C.group.elements;
  504.  
  505.     # otherwise leave it to the subgroup to sort things out
  506.     else
  507.         return LeftQuotient( g, C.representative ) in C.group;
  508.     fi;
  509.  
  510. end;
  511.  
  512. LeftCosetGroupOps.Intersection := function ( C, D )
  513.     local   I;          # intersection of <C> and <D>, result
  514.  
  515.     # special case of intersection of two left cosets
  516.     if IsLeftCoset( C )  and IsLeftCoset( D )  and C.group = D.group  then
  517.  
  518.         # its either the whole coset
  519.         if LeftQuotient(C.representative,D.representative) in C.group  then
  520.             I := ShallowCopy( C );
  521.  
  522.         # or it is empty
  523.         else
  524.             I := [];
  525.         fi;
  526.  
  527.     # intersection of a left coset with something else
  528.     else
  529.         I := DomainOps.Intersection( C, D );
  530.     fi;
  531.  
  532.     # return the intersection
  533.     return I;
  534. end;
  535.  
  536. LeftCosetGroupOps.Union := function ( C, D )
  537.     local   U;          # union of <C> and <D>, result
  538.  
  539.     # special case of intersection of two left cosets
  540.     if IsLeftCoset( C )  and IsLeftCoset( D )  and C.group = D.group  then
  541.  
  542.         # its either the whole coset
  543.         if LeftQuotient(C.representative,D.representative) in C.group  then
  544.             U := ShallowCopy( C );
  545.  
  546.         # or the union
  547.         else
  548.             U := DomainOps.Union( C, D );
  549.         fi;
  550.  
  551.     # union of  a left coset and something else
  552.     else
  553.         U := DomainOps.Union( C, D );
  554.     fi;
  555.  
  556.     # return the union
  557.     return U;
  558. end;
  559.  
  560. LeftCosetGroupOps.Random := function ( C )
  561.     return C.representative * Random( C.group );
  562. end;
  563.  
  564. LeftCosetGroupOps.Print := function( C )
  565.     if IsBound( C.name )  then
  566.         Print( C.name );
  567.     else
  568.         Print( "(", C.representative, "*", C.group, ")" );
  569.     fi;
  570. end;
  571.  
  572. LeftCosetGroupOps.\* := function ( C, D )
  573.     local   E;          # product of <C> and <D>, result
  574.     if IsLeftCoset( D )  and C in Parent( D.group )  then
  575.         E := LeftCoset( D.group, C * D.representative );
  576.     elif IsLeftCoset( D )  then
  577.         E := C * Elements( D );
  578.     elif IsLeftCoset( C )  then
  579.         E := Elements( C ) * D;
  580.     else
  581.         Error("product of <C> and <D> is not defined");
  582.     fi;
  583.     return E;
  584. end;
  585.  
  586.  
  587. #############################################################################
  588. ##
  589. #F  LeftCosets(<G>,<U>) . . . . . . . .  left cosets of a subgroup in a group
  590. ##
  591. LeftCosets := function ( G, U )
  592.     local   C;          # left cosets of <U> in <G>, result
  593.  
  594.     # check the arguments
  595.     if not IsGroup( G )  then
  596.         Error("<G> must be a group");
  597.     fi;
  598.     if not IsSubgroup( G, U )  then
  599.         Error("<U> must be a subgroup of <G>");
  600.     fi;
  601.  
  602.     # compute the left cosets
  603.     if IsParent( G )  then
  604.         if not IsBound( U.leftCosets )  then
  605.             U.leftCosets := G.operations.LeftCosets( G, U );
  606.         fi;
  607.         C := U.leftCosets;
  608.     else
  609.         C := G.operations.LeftCosets( G, U );
  610.     fi;
  611.  
  612.     # return the left cosets
  613.     return C;
  614. end;
  615.  
  616.  
  617. #############################################################################
  618. ##
  619. #F  GroupOps.LeftCosets(<G>,<U>)  . . .  left cosets of a subgroup in a group
  620. ## 
  621. GroupOps.LeftCosets := function ( G, U )
  622.     return List( RightCosets( G, U ), C -> LeftCoset( U, Random(C)^-1 ) );
  623. end;
  624.  
  625.  
  626. #############################################################################
  627. ##
  628. #F  IsDoubleCoset( <C> )  . . . . . . . . test if an object is a double coset
  629. ##
  630. IsDoubleCoset := function ( C )
  631.     return IsRec( C )
  632.        and IsBound( C.isDoubleCoset )
  633.        and C.isDoubleCoset;
  634. end;
  635.  
  636.  
  637. #############################################################################
  638. ##
  639. #F  DoubleCoset(<U>,<g>,<V>)  . . . . . . . . . . . . . create a double coset
  640. ##
  641. DoubleCoset := function ( U, g, V )
  642.  
  643.     # check that the arguments lie in a common parent
  644.     if not IsGroup( U )  then
  645.         Error("<U> must be a group");
  646.     fi;
  647.     if not IsGroup( V )  then
  648.         Error("<V> must be a group");
  649.     fi;
  650.     if not g in Parent( U, V )  then
  651.         Error("<g> must lie in the common parent group of <U> and <V>");
  652.     fi;
  653.  
  654.     # dispatch
  655.     return U.operations.DoubleCoset( U, g, V );
  656. end;
  657.  
  658.  
  659. #############################################################################
  660. ##
  661. #F  GroupOps.DoubleCoset(<U>,<g>,<V>) . . . . . . . . . create a double coset
  662. #V  DoubleCosetGroupOps . . . . operations record of double cosets in a group
  663. ##
  664. ##  'GroupOps.DoubleCoset' is the default function to create a double  coset.
  665. ##  It only stuffs <U>, <g>, and <V> in a record and  enters  the  operations
  666. ##  record 'DoubleCosetGroupOps'.
  667. ##
  668. ##  'DoubleCosetGroupOps' is   the operations record  of double   cosets in a
  669. ##  generic group.  Thus 'DoubleCosetGroupOps'   is the operations record  of
  670. ##  default functions for  double cosets.  Double cosets  in special types of
  671. ##  groups, e.g., permutation groups, inherit the default functions by making
  672. ##  a copy of 'DoubleCosetGroupOps' and overlaying the default functions with
  673. ##  more efficient ones.
  674. ##
  675. ##  The  default  functions for double    cosets deal with double  cosets  by
  676. ##  computing  the list of   right cosets of   <U> whose union is  the double
  677. ##  coset.  This list is  simply the orbit  of the right  coset '<U> \*\ <g>'
  678. ##  under <V>.   This list  is  only computed  on  demand,  i.e., it is   not
  679. ##  automatically  computed  by  'GroupOps.DoubleCoset'.  This   allows other
  680. ##  double coset creation functions to fall back on 'GroupOps.DoubleCoset'.
  681. ##
  682. GroupOps.DoubleCoset := function ( U, g, V )
  683.     local   C;          # double coset, result
  684.  
  685.     # create the domain
  686.     C := rec( );
  687.     C.isDomain          := true;
  688.     C.isDoubleCoset     := true;
  689.  
  690.     # enter the identification
  691.     C.leftGroup         := U;
  692.     C.representative    := g;
  693.     C.rightGroup        := V;
  694.  
  695.     # enter knowledge
  696.     if IsBound( U.isFinite )  and IsBound( V.isFinite )  then
  697.         C.isFinite      := U.isFinite and V.isFinite;
  698.     fi;
  699.  
  700.     # enter the operations record
  701.     C.operations        := DoubleCosetGroupOps;
  702.  
  703.     # return the double coset
  704.     return C;
  705. end;
  706.  
  707. DoubleCosetGroupOps := Copy( DomainOps );
  708.  
  709. DoubleCosetGroupOps.Elements := function ( C )
  710.  
  711.     # make sure that the double coset is finite
  712.     if not IsFinite( C )  then
  713.         Error("the double coset <C> must be finite to compute its elements");
  714.     fi;
  715.  
  716.     # get the list of right cosets
  717.     if not IsBound( C.rightCosets )  then
  718.         C.rightCosets := Orbit( C.rightGroup,
  719.                                 Coset( C.leftGroup, C.representative ),
  720.                                 OnRight );
  721.     fi;
  722.  
  723.     # return the set of Elements
  724.     return Union( List( C.rightCosets, Elements ) );
  725. end;
  726.  
  727. DoubleCosetGroupOps.IsFinite := function ( C )
  728.     return IsFinite( C.leftGroup ) and IsFinite( C.rightGroup );
  729. end;
  730.  
  731. DoubleCosetGroupOps.Size := function ( C )
  732.  
  733.     # make sure that the double coset is finite
  734.     if not IsFinite( C )  then
  735.         return "infinity";
  736.     fi;
  737.  
  738.     # get the list of right cosets
  739.     if not IsBound( C.rightCosets )  then
  740.         C.rightCosets := Orbit( C.rightGroup,
  741.                                 Coset( C.leftGroup, C.representative ),
  742.                                 OnRight );
  743.     fi;
  744.  
  745.     # return the size
  746.     return Size( C.leftGroup ) * Length( C.rightCosets );
  747. end;
  748.  
  749. DoubleCosetGroupOps.\= := function ( C, D )
  750.     local   isEql;
  751.  
  752.     # compare a double coset
  753.     if IsDoubleCoset( C )  then
  754.  
  755.         # with another double coset
  756.         if IsDoubleCoset( D )  then
  757.  
  758.             # over the same subgroups
  759.             if C.leftGroup = D.leftGroup and C.rightGroup = D.rightGroup then
  760.                 isEql := C.representative in D;
  761.  
  762.             # over different subgroups
  763.             else
  764.                 isEql := DomainOps.\=( C, D );
  765.             fi;
  766.  
  767.         # with something else
  768.         else
  769.             isEql := DomainOps.\=( C, D );
  770.         fi;
  771.  
  772.     # compare something else
  773.     else
  774.  
  775.         # with a double coset
  776.         if IsDoubleCoset( D )  then
  777.             isEql := DomainOps.\=( C, D );
  778.  
  779.         # with another something else
  780.         else
  781.             Error("panic, neither <C> nor <D> is a double coset");
  782.         fi;
  783.  
  784.     fi;
  785.  
  786.     # return the result
  787.     return isEql;
  788. end;
  789.  
  790. DoubleCosetGroupOps.\in := function ( g, C )
  791.  
  792.     # make sure that the double coset is finite
  793.     if not IsFinite( C )  then
  794.         Error(
  795.            "sorry, can not test if <g> lies in the infinite double coset <C>"
  796.         );
  797.     fi;
  798.  
  799.     # get the list of right cosets
  800.     if not IsBound( C.rightCosets )  then
  801.         C.rightCosets := Orbit( C.rightGroup,
  802.                                 Coset( C.leftGroup, C.representative ),
  803.                                 OnRight );
  804.     fi;
  805.  
  806.     # return the result
  807.     return ForAny( C.rightCosets, cos -> g in cos );
  808. end;
  809.  
  810. DoubleCosetGroupOps.Intersection := function ( C, D )
  811.     local   I;          # intersection of <C> and <D>, result
  812.  
  813.     # special case for the intersection of two double cosets
  814.     if      IsDoubleCoset( C )
  815.         and IsDoubleCoset( D )
  816.         and C.leftGroup  = D.leftGroup
  817.         and C.rightGroup = D.rightGroup
  818.     then
  819.  
  820.         # its either the whole double coset
  821.         if C.representative in D  then
  822.             I := C;
  823.  
  824.         # or its empty
  825.         else
  826.             I := [];
  827.         fi;
  828.  
  829.     # intersection of a double coset with something else
  830.     else
  831.         I := DomainOps.Intersection( C, D );
  832.     fi;
  833.  
  834.     # return the intersection
  835.     return I;
  836. end;
  837.  
  838. DoubleCosetGroupOps.Union := function ( C, D )
  839.     local   U;          # union of <C> and <D>, result
  840.  
  841.     # special case for the union of two double cosets
  842.     if      IsDoubleCoset( C )
  843.         and IsDoubleCoset( E )
  844.         and C.leftGroup  = D.leftGroup
  845.         and C.rightGroup = D.rightGroup
  846.     then
  847.  
  848.         # its either the whole double coset
  849.         if C.representative in D  then
  850.             U := C;
  851.  
  852.         # or the union
  853.         else
  854.             U := DomainOps.Union( C, D );
  855.         fi;
  856.  
  857.     # union of a double coset with something else
  858.     else
  859.         U := DomainOps.Union( C, D );
  860.     fi;
  861.  
  862.     # return the union
  863.     return U;
  864. end;
  865.  
  866. DoubleCosetGroupOps.Random := function ( C )
  867.  
  868.     # make sure that the double coset is finite
  869.     if not IsFinite( C )  then
  870.       Error(
  871.        "sorry, can not find a random elment in the infinite double coset <C>"
  872.       );
  873.     fi;
  874.  
  875.     # get the list of right cosets
  876.     if not IsBound( C.rightCosets )  then
  877.         C.rightCosets := Orbit( C.rightGroup,
  878.                                 Coset( C.leftGroup, C.representative ),
  879.                                 OnRight );
  880.     fi;
  881.  
  882.     # get a random right coset and a random element of this coset
  883.     return Random( Random( C.rightCosets ) );
  884. end;
  885.  
  886. DoubleCosetGroupOps.\Print := function ( C )
  887.     if IsBound( C.name )  then
  888.         Print( C.name );
  889.     else
  890.         Print("DoubleCoset( ",C.leftGroup,", ",C.representative,", ",
  891.               C.rightGroup," )");
  892.     fi;
  893. end;
  894.  
  895. DoubleCosetGroupOps.\* := function ( C, D )
  896.     local   E;
  897.     if IsDoubleCoset( C )  then
  898.         E := Elements( C ) * D;
  899.     elif IsDoubleCoset( D )  then
  900.         E := C * Elements( D );
  901.     else
  902.         Error("panic, neither <C> nor <D> is a double coset");
  903.     fi;
  904.     return E;
  905. end;
  906.  
  907.  
  908. #############################################################################
  909. ##
  910. #F  DoubleCosets(<G>,<U>,<V>) . . . . . . .  list of double cosets in a group
  911. ##
  912. DoubleCosets := function ( G, U, V )
  913.  
  914.     # check that the arguments lie in a common parent group
  915.     if not IsGroup( G )  then
  916.         Error("<G> must be a group");
  917.     fi;
  918.     if not IsSubgroup( G, U )  then
  919.         Error("<U> must be a subgroup of <G>");
  920.     fi;
  921.     if not IsSubgroup( G, V )  then
  922.         Error("<V> must be a subgroup of <G>");
  923.     fi;
  924.  
  925.     # dispatch
  926.     return G.operations.DoubleCosets( G, U, V );
  927. end;
  928.  
  929.  
  930. #############################################################################
  931. ##
  932. #F  GroupOps.DoubleCosets(<G>,<U>,<V>)  . .  list of double cosets in a group
  933. ##
  934. GroupOps.DoubleCosets := function ( G, U, V )
  935.     local   C,          # list of double cosets, result
  936.             elm;        # one element of <G>
  937.  
  938.     # initialize the list of double cosets
  939.     C := [ DoubleCoset( U, G.identity, V ) ];
  940.     while Sum( List( C, Size ) ) <> Size( G )  do
  941.         elm := Random( G );
  942.         if ForAll( C, c -> not elm in c )  then
  943.             Add( C, DoubleCoset( U, elm, V ) );
  944.         fi;
  945.     od;
  946.  
  947.     # return the list of double cosets
  948.     return C;
  949. end;
  950.  
  951.  
  952. #############################################################################
  953. ##
  954. #F  InfoCoset1  . . . . . . . . . . . . . . . information for coset functions
  955. ##
  956. if not IsBound(InfoCoset1)  then InfoCoset1:=Ignore;  fi;
  957.  
  958.  
  959. #############################################################################
  960. ##
  961.  
  962. #F  CalcDoubleCosets( <G>, <A>, <B> ) . . . . . . . . .  double cosets: A\G/B
  963. ## 
  964. ##  special DoubleCosets routine for PermGroups and small AgGroups, using an
  965. ##  ascending chain of subgroups from A to G, using the fact, that a
  966. ##  double coset is an union of right cosets
  967. ##
  968. CalcDoubleCosets := function(G,a,b)
  969.   local CCE,c,a1,a2,r,s,t,rg,st,i,j,q,nr,o,nu,step,p,set,img,k,sch,rep,sifa,
  970.         stabs,nstab,lst,compst,e,cnt,rt,flip,dcs,unten,pg;
  971.  
  972.   pg:=IsBound(G.isPermGroup) and  G.isPermGroup;
  973.   # if a is small and b large, compute cosets b\G/a and take inverses of the
  974.   # representatives: Since we compute stabilizers in b and a chain down to
  975.   # a, this is remarkable faster
  976.  
  977.   if 3*Size(a)<2*Size(b) then
  978.     c:=b;
  979.     b:=a;
  980.     a:=c;
  981.     flip:=true;
  982.     InfoCoset1("#I DoubleCosetFlip\n");
  983.   else
  984.     flip:=false;
  985.   fi;
  986.  
  987.   CCE:=G.operations.MainEntryCCE;
  988.   if not(pg) then
  989.     AgGroupOps.GenRelOrdersAgGroup(G);
  990.   fi;
  991.   c:=AscendingChain(G,a);
  992.   r:=[G.identity];
  993.   stabs:=[b];
  994.   dcs:=[];
  995.   for step in [1..Length(c)-1] do
  996.     a1:=c[Length(c)-step+1];
  997.     a2:=c[Length(c)-step];
  998.     InfoCoset1("#I Step :",Size(a1)/Size(a2),"\n");
  999.  
  1000.     # is this the last step?
  1001.     unten:=step=Length(c)-1;
  1002.  
  1003.     # shall we compute stabilizers?
  1004.     compst:=not(unten) or a2.normalStep;
  1005.  
  1006.     if pg then
  1007.       # prepare special base for CCE
  1008.       if not IsBound( a2.smallestBase )  or a2.smallestBase <> Base( a2)  then
  1009.       MakeStabChain( a2, a2.operations.MovedPoints( a2 ) );
  1010.       a2.smallestBase := Base( a2 );
  1011.       fi;
  1012.     else
  1013.       # force computation of a Cgs
  1014.       Cgs(a2);
  1015.     fi;
  1016.  
  1017.     t:=RightTransversal(a1,a2);
  1018.     s:=[];
  1019.     nr:=[];
  1020.     nstab:=[];
  1021.     for nu in [1..Length(r)] do
  1022.       lst:=stabs[nu];
  1023.       sifa:=Size(a2)*Size(b)/Size(lst); 
  1024.       p:=r[nu];
  1025.  
  1026.       rg:=Set(List(t,i->CCE(G,a2,i*p)));
  1027.  
  1028.       # if a2 is normal in a1, the stabilizer is the same for all Orbits of
  1029.       # right cosets. Thus we need to compute only one, and will receive all
  1030.       # others by simple calculations afterwards
  1031.  
  1032.       if a2.normalStep then
  1033.     cnt:=1;
  1034.       else
  1035.     cnt:=Length(rg);
  1036.       fi;
  1037.  
  1038.       while rg<>[] and cnt>0 do
  1039.     cnt:=cnt-1;
  1040.  
  1041.     # compute orbit and stabilizers for the next step
  1042.         # own Orbitalgorithm and stabilizer computation
  1043.     
  1044.     e:=rg[1];
  1045.     Add(nr,e);
  1046.  
  1047.     # note: e is canonic representative
  1048.     o   := [ e ];
  1049.     set := [ e ];
  1050.     rep := [ b.identity ];
  1051.     st := Subgroup(Parent(G), [] );
  1052.     for i  in o  do
  1053.       for j  in lst.generators  do
  1054.         img:=CCE(G,a2,i*j);
  1055.         if not img in set  then
  1056.           Add( o, img );
  1057.           AddSet( set, img );
  1058.           Add( rep, rep[Position(o,i)]*j );
  1059.         elif compst then
  1060.           sch := rep[Position(o,i)]*j
  1061.              / rep[Position(o,img)];
  1062.           if not sch in st  then
  1063.         st := G.operations.Subgroup(Parent(G),Union(st.generators,[sch]));
  1064.           fi;
  1065.         fi;
  1066.       od;
  1067.     od;
  1068.  
  1069.         if unten then
  1070.       if flip then
  1071.         p:=a.operations.DoubleCoset(a,e^(-1),b);
  1072.       else
  1073.         p:=a.operations.DoubleCoset(a,e,b);
  1074.       fi;
  1075.       p.size:=sifa*Length(set);
  1076.       Add(dcs,p);
  1077.     fi;
  1078.  
  1079.     SubtractSet(rg,set);
  1080.  
  1081.     Add(nstab,st);
  1082.  
  1083.       od;
  1084.  
  1085.       if a2.normalStep then
  1086.     # in the normal case, we can obtain the other orbits easily via
  1087.     # the orbit theorem (same stabilizer)
  1088.     rt:=RightTransversal(lst,st);
  1089.     o:=sifa*Length(set); #order
  1090.     while rg<>[] do
  1091.       e:=rg[1];
  1092.       Add(nr,e);
  1093.  
  1094.       if unten then
  1095.         if flip then
  1096.           p:=a.operations.DoubleCoset(a,e^(-1),b);
  1097.         else
  1098.           p:=a.operations.DoubleCoset(a,e,b);
  1099.         fi;
  1100.         p.size:=o;
  1101.         Add(dcs,p);
  1102.       fi;
  1103.  
  1104.       SubtractSet(rg,set);
  1105.       Add(nstab,st);
  1106.       SubtractSet(rg,List(rt,i->CCE(G,a2,e*i)));
  1107.     od;
  1108.       fi;
  1109.  
  1110.     od;
  1111.     stabs:=nstab;
  1112.     r:=nr;
  1113.   od;
  1114.  
  1115.   return dcs;
  1116. end;
  1117.  
  1118.  
  1119. #############################################################################
  1120. ##
  1121. #F  AscendingChain(<G>,<U>) . . . . . . .  chain of subgroups G=G_1>...>G_n=U
  1122. ##
  1123. ##  Dispatcher for the AscendingChain routines.  Additionally, the normalStep
  1124. ##  entry is forced.
  1125. ##
  1126. AscendingChain := function(G,U)
  1127.   local c,i;
  1128.   if not IsBound(U.ascendingChain) then
  1129.     c:=G.operations.AscendingChain(G,U);
  1130.     U.ascendingChain:=c;
  1131.     for i in [1..Length(c)-1] do
  1132.       if not IsBound(c[i].normalStep) then
  1133.     c[i].normalStep:=IsNormal(c[i+1],c[i]);
  1134.       fi;
  1135.     od;
  1136.   fi;
  1137.   return U.ascendingChain;
  1138. end;
  1139.  
  1140. GroupOps.AscendingChain := function(G,U)
  1141.   return RefinedChain(G,[U,G]);
  1142. end;
  1143.  
  1144.  
  1145. #############################################################################
  1146. ##
  1147. #F  RefinedChain(<G>,<c>) . . . . . . . . . . . . . . . .  refine chain links
  1148. ##
  1149. ##  <c> is an ascending chain in the Group <G>. The task of this routine is
  1150. ##  to refine c, i.e. if there is a "link" U>L in c with [U:L] too big,
  1151. ##  this procedure tries to find Subgroups G_0,...,G_n of G; such that 
  1152. ##  U=G_0>...>G_n=L. This is done by extending L inductively: Since normal
  1153. ##  steps can help in further calculations, the routine first tries to
  1154. ##  extend to the normalizer in U. If the subgroup is self-normalizing,
  1155. ##  the group is extended via a random element. If this results in a step
  1156. ##  too big, it is repeated several times to find hopefully a small
  1157. ##  extension!
  1158. ##
  1159. RefinedChain := function(G,cc)
  1160.   local bound,a,b,c,cnt,r,i,j,bb;
  1161.   bound:=10*LogInt(Size(G),10)*Maximum(Factors(Size(G)));
  1162.   c:=[];  
  1163.   for i in [2..Length(cc)] do  
  1164.     Add(c,cc[i-1]);
  1165.     if Index(cc[i],cc[i-1]) > bound then
  1166.       # c:=Concatenation(c,RefinedChainLink(G,cc[i],cc[i-1]));
  1167.       a:=cc[i-1];
  1168.       while Index(cc[i],a)>bound do
  1169.     # try extension via normalizer
  1170.     b:=Normalizer(cc[i],a);
  1171.     if b<>a then
  1172.      # extension by normalizer surely is a normal step
  1173.       a.normalStep:=true;
  1174.       bb:=b;
  1175.         else
  1176.       bb:=cc[i];
  1177.       a.normalStep:=false;
  1178.         fi;
  1179.     if b=a then
  1180.       b:=Centralizer(cc[i],Centre(a));
  1181.     fi;
  1182.     if b=a or Index(b,a)>bound then
  1183.       cnt:=8+2^(LogInt(Index(bb,a),5)+2);
  1184.       repeat
  1185.         if Index(bb,a)<3000 then
  1186.           b:=Extension(bb,a);
  1187.           if b=false then
  1188.         b:=bb;
  1189.           fi;
  1190.           cnt:=0;
  1191.         else
  1192.         # larger indices may take more tests...
  1193.           InfoCoset1("#W Random\n");
  1194.           repeat
  1195.         r:=Random(bb);
  1196.           until not(r in a);
  1197.           if a.normalStep then
  1198.         b:=Closure(a,r);
  1199.               else
  1200.         # self normalizing subgroup: thus every element not in <a>
  1201.              # will surely map one generator out
  1202.             j:=0;
  1203.         repeat
  1204.           j:=j+1;
  1205.                 until not(a.generators[j]^r in a);
  1206.         r:=a.generators[j]^r;
  1207.  
  1208.         b:=Closure(a,r);
  1209.           fi;
  1210.           if Size(b)<Size(bb) then
  1211.         bb:=b;
  1212.         InfoCoset1("#I improvement found\n");
  1213.           fi;
  1214.           cnt:=cnt-1;
  1215.         fi;
  1216.       until Index(bb,a)<=bound or cnt<1;
  1217.     fi;
  1218.     a:=b;
  1219.     if a<>cc[i] then #not upper level
  1220.       Add(c,a);
  1221.     fi;
  1222.       od;
  1223.     fi;
  1224.   od;
  1225.   Add(c,cc[Length(cc)]);
  1226.   return c;
  1227. end;
  1228.  
  1229.  
  1230. #############################################################################
  1231. ##
  1232. ##  Extension(<G>,<U>)  . . . . . . . . . . . . . . . . subgroup, extending U
  1233. ##
  1234. ##  This routine tries to find a subgroup E of G, such that G>E>U. If U is
  1235. ##  maximal, it returns false. This is done by finding minimal blocks for
  1236. ##  the operation of G on the Right Cosets of U.
  1237. ##
  1238. Extension := function(G,U)
  1239.   local t,o,b,p,bl,q;
  1240.  
  1241.   t:=CanonicalRightTransversal(G,U);
  1242.   o:=Operation(G,t,OnCanonicalCosetElements(G,U));
  1243.   b:=Blocks(o,PermGroupOps.MovedPoints(o));
  1244.   if Length(b)=1 then
  1245.     return false;
  1246.   else
  1247.     p:=Position(t,G.identity);
  1248.     bl:=Filtered(b,i->p in i)[1];
  1249.     if bl[1]=p then
  1250.       q:=bl[2];
  1251.     else
  1252.       q:=bl[1];
  1253.     fi;
  1254.     return Closure(U,t[p] mod t[q]);
  1255.   fi;
  1256. end;
  1257.  
  1258.  
  1259. #############################################################################
  1260. ##
  1261. #F  CanonicalRightTransversal(<G>,<U>) .  RightTransversal for U\G containing
  1262. #F                                                  canonical representatives
  1263. ##
  1264. CanonicalRightTransversal := function(G,U)
  1265.   local c,i;
  1266.   #c:=List(RightTransversal(G,U),i->U.operations.CanonicalCosetElement(U,i));
  1267.   # don't use bound traverse-> we'll modify it
  1268.   c:=G.operations.RightTransversal(G,U);
  1269.   for i in [1..Length(c)] do
  1270.     c[i]:=U.operations.CanonicalCosetElement(U,c[i]);
  1271.   od;
  1272.   Sort(c);
  1273.   return c;
  1274. end;
  1275.  
  1276.  
  1277. #############################################################################
  1278. ##
  1279. #F CanonicalCosetElement( <U>, <g> )  . . . . compute canonical coset element
  1280. ##
  1281. CanonicalCosetElement := function(arg)
  1282.   local C;
  1283.   if Length(arg)=2 then
  1284.     # subgroup, representative
  1285.     return arg[1].operations.CanonicalCosetElement(arg[1],arg[2]);
  1286.   else
  1287.     C:=arg[1];
  1288.     if IsRightCoset(C) then
  1289.       return C.group.operations.CanonicalCosetElement(C.group,C.representative);
  1290.     elif IsGroup(C) then
  1291.       return C.identity;
  1292.     else 
  1293.       Error("usage: CanonicalCosetElement(<G>,<r>) or C.C.E.(<Coset>)");
  1294.     fi;
  1295.   fi; 
  1296. end;
  1297.  
  1298. GroupOps.CanonicalCosetElement := function(U,g)
  1299.   return Set(Elements(U*g))[1];
  1300. end;
  1301.  
  1302.  
  1303. #############################################################################
  1304. ##
  1305. #F  OnCanonicalCosetElements(<G>,<U>) . .  create operation function for CCEs
  1306. ##
  1307. ##  This function returns another function that can be used like 'OnPoints'
  1308. ##  to operate on canonical coset elements.
  1309. ##
  1310. OnCanonicalCosetElements := function(G,U)
  1311.   return G.operations.OnCanonicalCosetElements(G,U);
  1312. end;
  1313.  
  1314. GroupOps.OnCanonicalCosetElements := function(G,U)
  1315.   return function(a,b)
  1316.        return U.operations.CanonicalCosetElement(U,a*b);
  1317.      end;
  1318. end;
  1319.  
  1320.  
  1321. #############################################################################
  1322. ##
  1323. #F  PermutationCharacter(<G>,<U>) . permutation character of G on cosets of U
  1324. #F  PermutationCharacter(<P>) . . . . .  permutation character of PermGroup P 
  1325. ##
  1326. PermutationCharacter := function(arg)
  1327.   local G,U,i,c,cl,s;
  1328.   if Length(arg)=2 then
  1329.     G:=arg[1];
  1330.     U:=arg[2];
  1331.     s:=Size(U);
  1332.     c:=[Index(G,U)];
  1333.     cl:=ConjugacyClasses(G);
  1334.     for i in [2..Length(cl)] do
  1335.       Add(c,Number(DoubleCosets(G,U,Subgroup(Parent(G),[cl[i].representative])),
  1336.            i->Size(i)=s) );
  1337.     od;
  1338.   elif IsBound(arg[1].isPermGroup) and arg[1].isPermGroup then
  1339.     s:=PermGroupOps.MovedPoints(arg[1]);
  1340.     c:=[Length(s)];
  1341.     cl:=ConjugacyClasses(arg[1]);
  1342.     for i in [2..Length(cl)] do
  1343.       Add(c,Length(Difference(s,
  1344.       PermGroupOps.MovedPoints(Subgroup(arg[1],[cl[i].representative])))));
  1345.     od;
  1346.   else
  1347.     Error("dont't know, how to compute permutation character");
  1348.   fi;
  1349.   return c;
  1350. end;
  1351.  
  1352.  
  1353. #############################################################################
  1354. ##
  1355. #F  IsFactorGroupElement(<C>) . . test if an object is a factor group element
  1356. ##
  1357. IsFactorGroupElement := function ( C )
  1358.     return IsRec( C )
  1359.        and IsBound( C.isFactorGroupElement )
  1360.        and C.isFactorGroupElement;
  1361. end;
  1362.  
  1363.  
  1364. #############################################################################
  1365. ##
  1366. #F  FactorGroupElement(<N>,<g>) . . . . . . . . . make a factor group element
  1367. ##
  1368. FactorGroupElement := function ( arg )
  1369.     local   C;
  1370.     if Length( arg ) = 1  and IsGroup( arg[1] )  then
  1371.         C := arg[1].operations.FactorGroupElement( arg[1], arg[1].identity );
  1372.     elif Length( arg ) = 2  and IsGroup( arg[1] )  then
  1373.         if not arg[2] in Parent( arg[1] )  then
  1374.             Error("<g> must be in the parent group of <U>");
  1375.         fi;
  1376.         C := arg[1].operations.FactorGroupElement( arg[1], arg[2] );
  1377.     else
  1378.         Error("usage: FactorGroupElement( <N> [, <g>] )");
  1379.     fi;
  1380.     return C;
  1381. end;
  1382.  
  1383. GroupOps.FactorGroupElement := function ( N, g )
  1384.     local   C;          # factor group element of <N> and <g>, result
  1385.  
  1386.     # make the factor group element
  1387.     C := rec( );
  1388.     C.isGroupElement       := true;
  1389.     C.isFactorGroupElement := true;
  1390.     C.domain               := FactorGroupElements;
  1391.  
  1392.     # enter the identifying information
  1393.     C.element              := N.operations.RightCoset( N, g );
  1394.  
  1395.     # enter the operations record
  1396.     C.operations           := FactorGroupElementOps;
  1397.  
  1398.     # return the coset
  1399.     return C;
  1400. end;
  1401.  
  1402.  
  1403. #############################################################################
  1404. ##
  1405. #V  FactorGroupElementOps . . . .  operations record of factor group elements
  1406. ##
  1407. FactorGroupElementOps := Copy( GroupElementOps );
  1408.  
  1409. FactorGroupElementOps.\* := function ( c, d )
  1410.     local   prd;        # product of <c> and <d>, result
  1411.     if      IsFactorGroupElement(c)
  1412.         and IsFactorGroupElement(d)
  1413.         and c.element.group = d.element.group
  1414.     then
  1415.         prd := c.element.group.operations.FactorGroupElement(
  1416.                                    c.element.group,
  1417.                                      c.element.representative
  1418.                                    * d.element.representative );
  1419.     elif IsList( c )  then
  1420.         prd := List( c, x -> x * d );
  1421.     elif IsList( d )  then
  1422.         prd := List( d, x -> c * x );
  1423.     else
  1424.         Error("product of <c> and <d> is not defined");
  1425.     fi;
  1426.     return prd;
  1427. end;
  1428.  
  1429. FactorGroupElementOps.\/ := function ( c, d )
  1430.     local   quo;        # quotient of <c> and <d>, result
  1431.     if      IsFactorGroupElement(c)
  1432.         and IsFactorGroupElement(d)
  1433.         and c.element.group = d.element.group
  1434.     then
  1435.         quo := c.element.group.operations.FactorGroupElement(
  1436.                                    c.element.group,
  1437.                                      c.element.representative
  1438.                                    / d.element.representative );
  1439.     elif IsList( c )  then
  1440.         quo := List( c, x -> x / d );
  1441.     elif IsList( d )  then
  1442.         quo := List( d, x -> c / x );
  1443.     else
  1444.         Error("quotient of <c> and <d> is not defined");
  1445.     fi;
  1446.     return quo;
  1447. end;
  1448.  
  1449. FactorGroupElementOps.\mod := function ( c, d )
  1450.     local   quo;        # left quotient of <c> and <d>, result
  1451.     if      IsFactorGroupElement(c)
  1452.         and IsFactorGroupElement(d)
  1453.         and c.element.group = d.element.group
  1454.     then
  1455.         quo := c.element.group.operations.FactorGroupElement(
  1456.                                    c.element.group,
  1457.                                        c.element.representative
  1458.                                    mod d.element.representative );
  1459.     elif IsList( c )  then
  1460.         quo := List( c, x -> x mod d );
  1461.     elif IsList( d )  then
  1462.         quo := List( d, x -> c mod x );
  1463.     else
  1464.         Error("left quotient of <c> and <d> is not defined");
  1465.     fi;
  1466.     return quo;
  1467. end;
  1468.  
  1469. FactorGroupElementOps.\^ := function ( c, d )
  1470.     local   pow;        # power of <c> and <d>, result
  1471.     if      IsFactorGroupElement(c)
  1472.         and IsFactorGroupElement(d)
  1473.         and c.element.group = d.element.group
  1474.     then
  1475.         pow := c.element.group.operations.FactorGroupElement(
  1476.                                    c.element.group,
  1477.                                      c.element.representative
  1478.                                    ^ d.element.representative );
  1479.     elif IsInt( d )  then
  1480.         pow := c.element.group.operations.FactorGroupElement(
  1481.                                    c.element.group,
  1482.                                    c.element.representative ^ d );
  1483.     else
  1484.         Error("power of <c> and <d> is not defined");
  1485.     fi;
  1486.     return pow;
  1487. end;
  1488.  
  1489. FactorGroupElementOps.Comm := function ( c, d )
  1490.     local   comm;       # commutator of <c> and <d>, result
  1491.     if      IsFactorGroupElement(c)
  1492.         and IsFactorGroupElement(d)
  1493.         and c.element.group = d.element.group
  1494.     then
  1495.         comm := c.element.group.operations.FactorGroupElement(
  1496.                                     c.element.group,
  1497.                                     Comm( c.element.representative,
  1498.                                           d.element.representative ) );
  1499.     else
  1500.         Error("commutator of <c> and <d> is not defined");
  1501.     fi;
  1502.     return comm;
  1503. end;
  1504.  
  1505. FactorGroupElementOps.Print := function ( c )
  1506.     Print("FactorGroupElement( ",c.element.group,", ",
  1507.           c.element.representative," )");
  1508. end;
  1509.  
  1510.  
  1511. #############################################################################
  1512. ##
  1513. #F  FactorGroupElements . . . . . . . . . domain of all factor group elements
  1514. #F  FactorGroupElementsOps  . . . . operations record for FactorGroupElements
  1515. ##
  1516. FactorGroupElements             := rec();
  1517. FactorGroupElements.isDomain    := true;
  1518.  
  1519. FactorGroupElements.name        := "FactorGroupElements";
  1520.  
  1521. FactorGroupElements.isFinite    := false;
  1522. FactorGroupElements.size        := "infinity";
  1523.  
  1524. FactorGroupElements.operations  := Copy( GroupElementsOps );
  1525. FactorGroupElementsOps          := FactorGroupElements.operations;
  1526.  
  1527. FactorGroupElementsOps.Order := function ( G, c )
  1528.     local   ord,        # order of the coset <c>, result
  1529.             rep,        # representative of the coset <c>
  1530.             grp,        # group of the coset <c>
  1531.             div;        # prime divisor of the order of <rep>
  1532.  
  1533.     # compute the order
  1534.     rep := c.element.representative;
  1535.     grp := c.element.group;
  1536.     ord := Order( Parent(grp), rep );
  1537.     for div in Set( Factors( ord ) )  do
  1538.         while ord <> 1  and ord mod div = 0  and rep^(ord/div) in grp  do
  1539.             ord := ord / div;
  1540.         od;
  1541.     od;
  1542.  
  1543.     # return the order
  1544.     return ord;
  1545. end;
  1546.  
  1547. FactorGroupElementsOps.\in     := function ( g, FactorGroupElements )
  1548.     return IsFactorGroupElement( g );
  1549. end;
  1550.  
  1551.  
  1552. #############################################################################
  1553. ##
  1554. #F  FactorGroup(<G>,<N>)  . . . . . . . . . . . . . . factor group of a group
  1555. ##
  1556. FactorGroup := function ( G, N )
  1557.     local   F;          # factor of <G> over <N>, result
  1558.  
  1559.     # check the arguments
  1560.     if not IsGroup( G )  then
  1561.         Error("<G> must be a group");
  1562.     fi;
  1563.     if not IsSubgroup( G, N )  or not IsNormal( G, N )  then
  1564.         Error("<N> must be a normal subgroup of <G>");
  1565.     fi;
  1566.  
  1567.     # make the factor group
  1568.     if IsParent( G )  then
  1569.         if not IsBound( N.factorGroup )  then
  1570.             N.factorGroup := G.operations.FactorGroup( G, N );
  1571.         fi;
  1572.         F := N.factorGroup;
  1573.     else
  1574.         F := G.operations.FactorGroup( G, N );
  1575.     fi;
  1576.  
  1577.     # return the factor group
  1578.     F.factorNum := G;
  1579.     F.factorDen := N;
  1580.     return F;
  1581. end;
  1582.  
  1583. GroupOps.\/ := function ( G, N )
  1584.     return FactorGroup( G, N );
  1585. end;
  1586.  
  1587. GroupOps.FactorGroup := function ( G, N )
  1588.     local   F;          # factor of <G> over <N>, result
  1589.  
  1590.     # make the factor group
  1591.     F := Group( List( G.generators, gen -> FactorGroupElement(N,gen) ),
  1592.                 FactorGroupElement(N,G.identity) );
  1593.  
  1594.     # return the factor group
  1595.     return F;
  1596. end;
  1597.  
  1598.  
  1599. #############################################################################
  1600. ##
  1601. #F  FactorGroupElementsOps.Group(<D>,<gens>,<id>) . . . create a factor group
  1602. ##
  1603. FactorGroupElementsOps.Group := function ( FactorGroupElements, gens, id )
  1604.     local   G;          # permutation group <G>, result
  1605.  
  1606.     # check the arguments
  1607.     if not ForAll( gens, gen->gen.element.group
  1608.                          =gens[1].element.group )  then
  1609.         Error("the factor group elements must have the same subgroup");
  1610.     fi;
  1611.  
  1612.     # let the default function do the main work
  1613.     G := GroupElementsOps.Group( FactorGroupElements, gens, id );
  1614.  
  1615.     # add the permutation group tag
  1616.     G.isFactorGroup     := true;
  1617.  
  1618.     # add the operations record
  1619.     G.operations        := FactorGroupOps;
  1620.  
  1621.     # return the factor group
  1622.     return G;
  1623. end;
  1624.  
  1625.  
  1626. #############################################################################
  1627. ##
  1628. #F  NaturalHomomorphism(<G>,<F>)  .  natural homomorphism onto a factor group
  1629. ##
  1630. NaturalHomomorphism := function ( G, F )
  1631.     local   hom;        # natural homomorphism of <G> onto <F>, result
  1632.  
  1633.     # check the arguments
  1634.     if not IsGroup( F )  or not IsBound( F.factorNum )  then
  1635.         Error("<F> must be a factor group");
  1636.     fi;
  1637.     if not IsGroup( G )  or not IsSubgroup( F.factorNum, G )  then
  1638.         Error("<G> must be a subgroup of the numerator of <F>");
  1639.     fi;
  1640.  
  1641.     # compute the homomorphism
  1642.     if G = F.factorNum  then
  1643.         if not IsBound( F.naturalHomomorphism )  then
  1644.             F.naturalHomomorphism := F.operations.NaturalHomomorphism(G,F);
  1645.         fi;
  1646.         hom := F.naturalHomomorphism;
  1647.     else
  1648.         hom := F.operations.NaturalHomomorphism( G, F );
  1649.     fi;
  1650.  
  1651.     # return the homomorphism
  1652.     return hom;
  1653. end;
  1654.  
  1655. GroupOps.NaturalHomomorphism := function ( G, F )
  1656.     local   hom;        # natural homomorphism from <G> onto <F>, result
  1657.  
  1658.     # make the homomorphism
  1659.     hom := rec();
  1660.     hom.isGeneralMapping := true;
  1661.     hom.domain          := Mappings;
  1662.     hom.source          := G;
  1663.     hom.range           := F;
  1664.  
  1665.     # enter usefull information
  1666.     hom.isMapping       := true;
  1667.     hom.isHomomorphism  := true;
  1668.     hom.isEndomorphism  := false;
  1669.     hom.isAutomorphism  := false;
  1670.     hom.preImage        := hom.source;
  1671.     if G = F.factorNum  then
  1672.         hom.isInjective     := IsTrivial( F.factorDen );
  1673.         hom.isSurjective    := true;
  1674.         hom.isBijection     := hom.isInjective;
  1675.         hom.isMonomorphism  := hom.isInjective;
  1676.         hom.isEpimorphism   := true;
  1677.         hom.isIsomorphism   := hom.isInjective;
  1678.         hom.image           := hom.range;
  1679.         hom.kernel          := F.factorDen;
  1680.     fi;
  1681.  
  1682.     # enter the operations record
  1683.     hom.operations      := NaturalHomomorphismOps;
  1684.  
  1685.     # return the homomorphism
  1686.     return hom;
  1687. end;
  1688.  
  1689. NaturalHomomorphismOps := Copy( GroupHomomorphismOps );
  1690.  
  1691. NaturalHomomorphismOps.ImageElm := function ( hom, elm )
  1692.     return FactorGroupElement( hom.range.factorDen, elm );
  1693. end;
  1694.  
  1695. NaturalHomomorphismOps.ImagesElm := function ( hom, elm )
  1696.     return [ FactorGroupElement( hom.range.factorDen, elm ) ];
  1697. end;
  1698.  
  1699. NaturalHomomorphismOps.ImagesRepresentative := function ( hom, elm )
  1700.     return FactorGroupElement( hom.range.factorDen, elm );
  1701. end;
  1702.  
  1703. NaturalHomomorphismOps.PreImagesElm := function ( hom, elm )
  1704.     if hom.source = hom.range.factorNum  then
  1705.         return elm.element;
  1706.     else
  1707.         return Coset( Kernel( hom ), PreImagesRepresentative( hom, elm ) );
  1708.     fi;
  1709. end;
  1710.  
  1711. NaturalHomomorphismOps.PreImagesRepresentative := function ( hom, elm )
  1712.     if hom.source = hom.range.factorNum  then
  1713.         return elm.element.representative;
  1714.     else
  1715.         return Elements( Intersection( hom.source, elm.element ) )[1];
  1716.     fi;
  1717. end;
  1718.  
  1719. NaturalHomomorphismOps.KernelGroupHomomorphism := function ( hom )
  1720.     return Intersection( hom.source, hom.range.factorDen );
  1721. end;
  1722.  
  1723. NaturalHomomorphismOps.Print := function ( hom )
  1724.     Print("NaturalHomomorphism( ",hom.source,", ",hom.range," )");
  1725. end;
  1726.  
  1727.  
  1728. #############################################################################
  1729. ##
  1730. #F  FactorGroupOps  . . . . . . . . . . . operations record for factor groups
  1731. ##
  1732. ##  This  comes so late, because  we first wanted to  make all assignments to
  1733. ##  'GroupOps', of which we take a copy now.
  1734. ##
  1735. FactorGroupOps  := Copy( GroupOps );
  1736.  
  1737. FactorGroupOps.\in := function ( elm, F )
  1738.     return IsFactorGroupElement( elm )
  1739.        and elm.element.group = F.factorDen
  1740.        and elm.element.representative in F.factorNum;
  1741. end;
  1742.  
  1743. FactorGroupOps.Elements := function ( F )
  1744.     local   elms,       # elements of <F>, result
  1745.             cos,        # coset of normal subgroup in whole group
  1746.             elm;        # factor group element for <cos>
  1747.  
  1748.     # make the set of elements
  1749.     elms := [];
  1750.     for cos  in Set( RightCosets( F.factorNum, F.factorDen ) )  do
  1751.         elm := rec();
  1752.         elm.isGroupElement       := true;
  1753.         elm.isFactorGroupElement := true;
  1754.         elm.domain               := FactorGroupElements;
  1755.         elm.element              := cos;
  1756.         elm.operations           := FactorGroupElementOps;
  1757.         Add( elms, elm );
  1758.     od;
  1759.  
  1760.     # return the set of elements
  1761.     return elms;
  1762. end;
  1763.  
  1764. FactorGroupOps.Size := function ( F )
  1765.     return Index( F.factorNum, F.factorDen );
  1766. end;
  1767.  
  1768. FactorGroupOps.Random := function ( F )
  1769.     if IsBound( F.elements )  then
  1770.         return Random( F.elements );
  1771.     else
  1772.         return FactorGroupElement( F.factorDen, Random(F.factorNum) );
  1773.     fi;
  1774. end;
  1775.  
  1776. FactorGroupOps.Order := function ( G, c )
  1777.     local   ord,        # order of the coset <c>, result
  1778.             rep,        # representative of the coset <c>
  1779.             grp,        # group of the coset <c>
  1780.             div;        # prime divisor of the order of <rep>
  1781.  
  1782.     # compute the order
  1783.     rep := c.element.representative;
  1784.     grp := c.element.group;
  1785.     ord := Order( Parent(grp), rep );
  1786.     for div in Set( Factors( ord ) )  do
  1787.         while ord <> 1  and ord mod div = 0  and rep^(ord/div) in grp  do
  1788.             ord := ord / div;
  1789.         od;
  1790.     od;
  1791.  
  1792.     # return the order
  1793.     return ord;
  1794. end;
  1795.  
  1796. FactorGroupOps.Print := function ( F )
  1797.     Print("(",F.factorNum," / ",F.factorDen,")");
  1798. end;
  1799.  
  1800.  
  1801. #############################################################################
  1802. ##
  1803. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1804. ##
  1805. ##  Local Variables:
  1806. ##  mode:               outline
  1807. ##  outline-regexp:     "#F\\|#V\\|#E"
  1808. ##  fill-column:        77
  1809. ##  fill-prefix:        "##  "
  1810. ##  eval:               (hide-body)
  1811. ##  End:
  1812. ##
  1813.  
  1814.  
  1815.  
  1816.