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

  1. #############################################################################
  2. ##
  3. #A  mapping.g                   GAP library                  Martin Schoenert
  4. #A                                                             & Frank Celler
  5. ##
  6. #A  @(#)$Id: mapping.g,v 3.10 1993/02/08 15:44:50 martin Rel $
  7. ##
  8. #Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
  9. ##
  10. ##  This  file  contains  the  functions  that  mainly  deal  with  mappings.
  11. ##
  12. #H  $Log: mapping.g,v $
  13. #H  Revision 3.10  1993/02/08  15:44:50  martin
  14. #H  fixed 'IsInjective' for generic inverse mappings
  15. #H
  16. #H  Revision 3.9  1992/12/16  19:47:27  martin
  17. #H  replaced quoted record names with escaped ones
  18. #H
  19. #H  Revision 3.8  1992/04/29  14:36:08  martin
  20. #H  fixed 'Image' etc. from incorrect case testing
  21. #H
  22. #H  Revision 3.7  1992/04/02  16:59:22  martin
  23. #H  hacked mappings operations records
  24. #H
  25. #H  Revision 3.6  1992/03/27  10:48:22  martin
  26. #H  added 'MappingByFunction'
  27. #H
  28. #H  Revision 3.5  1992/03/27  10:45:54  martin
  29. #H  changed mapping to general mapping and function to mapping
  30. #H
  31. #H  Revision 3.4  1992/02/10  15:14:35  martin
  32. #H  added the domain 'Mappings'
  33. #H
  34. #H  Revision 3.3  1992/02/07  12:04:48  martin
  35. #H  fixed another stupid mistake in 'PowerMapping'
  36. #H
  37. #H  Revision 3.2  1992/02/07  11:49:47  martin
  38. #H  fixed a stupied mistake in 'PowerMapping'
  39. #H
  40. #H  Revision 3.1  1992/01/07  12:02:07  martin
  41. #H  initial revision under RCS
  42. #H
  43. ##
  44.  
  45.  
  46. #############################################################################
  47. ##
  48. #F  IsGeneralMapping(<obj>) . . . . .  test if an object is a general mapping
  49. ##
  50. IsGeneralMapping := function ( obj )
  51.     return IsRec( obj )
  52.        and IsBound( obj.isGeneralMapping )  and obj.isGeneralMapping;
  53. end;
  54.  
  55.  
  56. #############################################################################
  57. ##
  58. #F  IsMapping(<map>)  . . . . . . . . . .  test if a mapping is single valued
  59. ##
  60. IsMapping := function ( map )
  61.     if not IsBound( map.isMapping )  then
  62.         map.isMapping := map.operations.IsMapping( map );
  63.     fi;
  64.     return map.isMapping;
  65. end;
  66.  
  67.  
  68. #############################################################################
  69. ##
  70. #F  IsInjective(<map>)  . . . . . . . . . . .  test if a mapping is injective
  71. ##
  72. IsInjective := function ( map )
  73.     if not IsBound( map.isInjective )  then
  74.         map.isInjective := map.operations.IsInjective( map );
  75.     fi;
  76.     return map.isInjective;
  77. end;
  78.  
  79.  
  80. #############################################################################
  81. ##
  82. #F  IsSurjective(<map>) . . . . . . . . . . . test if a mapping is surjective
  83. ##
  84. IsSurjective := function ( map )
  85.     if not IsBound( map.isSurjective )  then
  86.         map.isSurjective := map.operations.IsSurjective( map );
  87.     fi;
  88.     return map.isSurjective;
  89. end;
  90.  
  91.  
  92. #############################################################################
  93. ##
  94. #F  IsBijection(<map>)  . . . . . . . . . .  test if a mapping is a bijection
  95. ##
  96. IsBijection := function ( map )
  97.     if not IsBound( map.isBijection )  then
  98.         map.isBijection := map.operations.IsBijection( map );
  99.     fi;
  100.     return map.isBijection;
  101. end;
  102.  
  103. IsBijective := IsBijection;
  104.  
  105.  
  106. #############################################################################
  107. ##
  108. #F  IsHomomorphism(<map>) . . . . . . . . test if a mapping is a homomorphism
  109. ##
  110. IsHomomorphism := function ( map )
  111.     if not IsBound( map.isHomomorphism )  then
  112.         map.isHomomorphism := map.source.operations.IsHomomorphism( map );
  113.     fi;
  114.     return map.isHomomorphism;
  115. end;
  116.  
  117.  
  118. #############################################################################
  119. ##
  120. #F  IsMonomorphism(<map>) . . . . . . .  test if a mapping is an monomorphism
  121. ##
  122. IsMonomorphism := function ( map )
  123.     if not IsBound( map.isMonomorphism )  then
  124.         map.isMonomorphism := map.operations.IsMonomorphism( map );
  125.     fi;
  126.     return map.isMonomorphism;
  127. end;
  128.  
  129.  
  130. #############################################################################
  131. ##
  132. #F  IsEpimorphism(<map>)  . . . . . . . . test if a mapping is an epimorphism
  133. ##
  134. IsEpimorphism := function ( map )
  135.     if not IsBound( map.isEpimorphism )  then
  136.         map.isEpimorphism := map.operations.IsEpimorphism( map );
  137.     fi;
  138.     return map.isEpimorphism;
  139. end;
  140.  
  141.  
  142. #############################################################################
  143. ##
  144. #F  IsIsomorphism(<map>)  . . . . . . . . test if a mapping is an isomorphism
  145. ##
  146. IsIsomorphism := function ( map )
  147.     if not IsBound( map.isIsomorphism )  then
  148.         map.isIsomorphism := map.operations.IsIsomorphism( map );
  149.     fi;
  150.     return map.isIsomorphism;
  151. end;
  152.  
  153.  
  154. #############################################################################
  155. ##
  156. #F  IsEndomorphism(<map>) . . . . . . .  test if a mapping is an endomorphism
  157. ##
  158. IsEndomorphism := function ( map )
  159.     if not IsBound( map.isEndomorphism )  then
  160.         map.isEndomorphism := map.operations.IsEndomorphism( map );
  161.     fi;
  162.     return map.isEndomorphism;
  163. end;
  164.  
  165.  
  166. #############################################################################
  167. ##
  168. #F  IsAutomorphism(<map>) . . . . . . .  test if a mapping is an automorphism
  169. ##
  170. IsAutomorphism := function ( map )
  171.     if not IsBound( map.isAutomorphism )  then
  172.         map.isAutomorphism := map.operations.IsAutomorphism( map );
  173.     fi;
  174.     return map.isAutomorphism;
  175. end;
  176.  
  177.  
  178. #############################################################################
  179. ##
  180. #F  Image(<map>[,<elm>])  . . . . . . . . image of an element under a mapping
  181. ##
  182. Image := function ( arg )
  183.     local   map,        # mapping <map>, first argument
  184.             elm,        # element <elm>, second argument
  185.             img;        # image of <elm> under <map>, result
  186.  
  187.     # image of the source under <map>, which may be multi valued in this case
  188.     if Length( arg ) = 1  then
  189.         map := arg[1];
  190.         if not IsBound( map.image )  then
  191.             map.image := map.operations.ImagesSource( map );
  192.         fi;
  193.         img := map.image;
  194.  
  195.     # image of a set of elments <elm> under the mapping <map>
  196.     elif Length( arg ) = 2
  197.         and ((IsDomain( arg[2] ) and IsSubset( arg[1].source, arg[2] ))
  198.           or (IsSet( arg[2] )    and IsSubset( arg[1].source, arg[2] ))
  199.           or (IsList( arg[2] )   and IsSubset( arg[1].source, Set(arg[2]) )))
  200.     then
  201.         map := arg[1];
  202.         elm := arg[2];
  203.         img := map.operations.ImagesSet( map, elm );
  204.  
  205.     # image of a single element <elm> under the mapping <map>
  206.     elif Length( arg ) = 2  and arg[2] in arg[1].source  then
  207.         map := arg[1];
  208.         elm := arg[2];
  209.         img := map.operations.ImageElm( map, elm );
  210.  
  211.     # otherwise signal an error
  212.     elif Length( arg ) = 2  then
  213.         Error("<elm> must be an element or a subset of '<map>.source'");
  214.     else
  215.         Error("usage: Image( <map> ) or Image( <map>, <elm> )");
  216.     fi;
  217.  
  218.     # return the image
  219.     return img;
  220. end;
  221.  
  222.  
  223. #############################################################################
  224. ##
  225. #F  Images(<map>,<elm>) . . . . . . . .  images of an element under a mapping
  226. ##
  227. Images := function ( arg )
  228.     local   map,        # mapping <map>, fist argument
  229.             elm,        # element <elm>, second argument
  230.             imgs;       # images of <elm> under <map>, result
  231.  
  232.     # image of the source under <map>
  233.     if Length( arg ) = 1  then
  234.         map := arg[1];
  235.         if not IsBound( map.image )  then
  236.            map.image := map.operations.ImagesSource( map );
  237.         fi;
  238.         imgs := map.image;
  239.  
  240.     # image of a set of elments <elm> under the mapping <map>
  241.     elif Length( arg ) = 2
  242.         and ((IsDomain( arg[2] ) and IsSubset( arg[1].source, arg[2] ))
  243.           or (IsSet( arg[2] )    and IsSubset( arg[1].source, arg[2] ))
  244.           or (IsList( arg[2] )   and IsSubset( arg[1].source, Set(arg[2]) )))
  245.     then
  246.         map := arg[1];
  247.         elm := arg[2];
  248.         imgs := map.operations.ImagesSet( map, elm );
  249.  
  250.     # image of a single element <elm> under the mapping <map>
  251.     elif Length( arg ) = 2  and arg[2] in arg[1].source  then
  252.         map := arg[1];
  253.         elm := arg[2];
  254.         imgs := map.operations.ImagesElm( map, elm );
  255.  
  256.     # otherwise signal an error
  257.     elif Length( arg ) = 2  then
  258.         Error("<elm> must be an element or a subset of '<map>.source'");
  259.     else
  260.         Error("usage: Images( <map> ) or Images( <map>, <elm> )");
  261.     fi;
  262.  
  263.     # return the images
  264.     return imgs;
  265. end;
  266.  
  267.  
  268. #############################################################################
  269. ##
  270. #F  ImagesRepresentative(<map>,<elm>) one image of an element under a mapping
  271. ##
  272. ImagesRepresentative := function ( map, elm )
  273.     return map.operations.ImagesRepresentative( map, elm );
  274. end;
  275.  
  276.  
  277. #############################################################################
  278. ##
  279. #F  PreImage(<bij>[,<img>]) . . . .  preimage of an element under a bijection
  280. ##
  281. PreImage := function ( arg )
  282.     local   bij,        # bijection <bij>, first argument
  283.             img,        # element <img>, second argument
  284.             pre;        # image of <img> under <bij>, result
  285.  
  286.     # preimage of the range under <bij>, which may be a multi valued mapping
  287.     if Length( arg ) = 1  then
  288.         bij := arg[1];
  289.         if not IsBound( bij.preImage )  then
  290.            bij.preImage := bij.operations.PreImagesRange( bij );
  291.         fi;
  292.         pre := bij.preImage;
  293.  
  294.     # image of a set of elments <img> under the bijection <bij>
  295.     elif Length( arg ) = 2
  296.         and ((IsDomain( arg[2] ) and IsSubset( arg[1].range, arg[2] ))
  297.           or (IsSet( arg[2] )    and IsSubset( arg[1].range, arg[2] ))
  298.           or (IsList( arg[2] )   and IsSubset( arg[1].range, Set(arg[2]) )))
  299.     then
  300.         bij := arg[1];
  301.         img := arg[2];
  302.         pre := bij.operations.PreImagesSet( bij, img );
  303.  
  304.     # preimage of a single element <img> under the bijection <bij>
  305.     elif Length( arg ) = 2  and arg[2] in arg[1].range  then
  306.         bij := arg[1];
  307.         img := arg[2];
  308.         pre := bij.operations.PreImageElm( bij, img );
  309.  
  310.     # otherwise signal an error
  311.     elif Length( arg ) = 2  then
  312.         Error("<img> must be an element or a subset of '<bij>.range'");
  313.     else
  314.         Error("usage: PreImage( <bij> ) or PreImage( <bij>, <img> )");
  315.     fi;
  316.  
  317.     # return the preimage
  318.     return pre;
  319. end;
  320.  
  321.  
  322. #############################################################################
  323. ##
  324. #F  PreImages(<map>,<img>)  . . . . . preimages of an element under a mapping
  325. ##
  326. PreImages := function ( arg )
  327.     local   map,        # mapping <map>, first argument
  328.             img,        # element <img>, second argument
  329.             pres;       # preimages of <img> under <map>, result
  330.  
  331.     # preimage of the range under <map>
  332.     if Length( arg ) = 1  then
  333.         map := arg[1];
  334.         if not IsBound( map.preImage )  then
  335.            map.preImage := map.operations.PreImagesRange( map );
  336.         fi;
  337.         pres := map.preImage;
  338.  
  339.     # image of a set of elements <img> under the mapping <map>
  340.     elif Length( arg ) = 2
  341.         and ((IsDomain( arg[2] ) and IsSubset( arg[1].range, arg[2] ))
  342.           or (IsSet( arg[2] )    and IsSubset( arg[1].range, arg[2] ))
  343.           or (IsList( arg[2] )   and IsSubset( arg[1].range, Set(arg[2]) )))
  344.     then
  345.         map := arg[1];
  346.         img := arg[2];
  347.         pres := map.operations.PreImagesSet( map, img );
  348.  
  349.     # preimage of a single element <img> under the mapping <map>
  350.     elif Length( arg ) = 2  and arg[2] in arg[1].range  then
  351.         map := arg[1];
  352.         img := arg[2];
  353.         pres := map.operations.PreImagesElm( map, img );
  354.  
  355.     # otherwise signal an error
  356.     elif Length( arg ) = 2  then
  357.         Error("<img> must be an element or a subset of '<map>.range'");
  358.     else
  359.         Error("usage: PreImages( <map> ) or PreImages( <map>, <img> )");
  360.     fi;
  361.  
  362.     # return the preimages
  363.     return pres;
  364. end;
  365.  
  366.  
  367. #############################################################################
  368. ##
  369. #F  PreImagesRepresentative(<map>,<img>)  . . . .  one preimage of an element
  370. #F                                                            under a mapping
  371. ##
  372. PreImagesRepresentative := function ( map, img )
  373.     return map.operations.PreImagesRepresentative( map, img );
  374. end;
  375.  
  376.  
  377. #############################################################################
  378. ##
  379. #F  CompositionMapping(<map1>,<map2>) . . . . . . . . composition of mappings
  380. ##
  381. CompositionMapping := function ( arg )
  382.     local   com,        # composition of the arguments, result
  383.             i;          # loop variable
  384.  
  385.     # check the arguments
  386.     if Length( arg ) = 0  then
  387.         Error("usage: CompositionMapping(<map1>..)");
  388.     fi;
  389.  
  390.     # unravel the argument list
  391.     if Length( arg ) = 1  and IsList( arg[1] )  then
  392.         arg := arg[1];
  393.     fi;
  394.  
  395.     # compute the composition
  396.     com := arg[ Length( arg ) ];
  397.     for i  in Reversed( [1..Length( arg )-1] )  do
  398.         if not IsSubset( arg[i].source, com.range )  then
  399.             Error("the range of <com> must be a subset of <map>");
  400.         fi;
  401.         com := com.operations.CompositionMapping( arg[i], com );
  402.     od;
  403.  
  404.     # return the composition
  405.     return com;
  406. end;
  407.  
  408.  
  409. #############################################################################
  410. ##
  411. #F  IdentityMapping(<dom>)  . . . . . . . . . .  identity mapping of a domain
  412. ##
  413. IdentityMapping := function ( dom )
  414.     if not IsBound( dom.identityMapping )  then
  415.         dom.identityMapping := dom.operations.IdentityMapping( dom );
  416.     fi;
  417.     return dom.identityMapping;
  418. end;
  419.  
  420.  
  421. #############################################################################
  422. ##
  423. #F  InverseMapping(<map>) . . . . . . . . . . .  inverse mapping of a mapping
  424. ##
  425. InverseMapping := function ( map )
  426.  
  427.     # compute the inverse mapping
  428.     if not IsBound( map.inverseMapping )  then
  429.         map.inverseMapping := map.operations.InverseMapping( map );
  430.     fi;
  431.  
  432.     # return the inverse mapping
  433.     return map.inverseMapping;
  434. end;
  435.  
  436.  
  437. #############################################################################
  438. ##
  439. #F  PowerMapping(<map>,<n>) . . . . . . . . . . . . . . .  power of a mapping
  440. ##
  441. PowerMapping := function ( map, n )
  442.     local   pow;        # <map> raised to the <n>th power, result
  443.  
  444.     # check the arguments
  445.     if not IsSubset( map.source, map.range )  then
  446.         Error("'<map>.range' must be a subset of '<map>.source'");
  447.     fi;
  448.     if not IsInt( n )  or n < 0  then
  449.         Error("<n> must be a nonnegative integer");
  450.     fi;
  451.  
  452.     # compute the power
  453.     pow := map.operations.PowerMapping( map, n );
  454.  
  455.     # return the power
  456.     return pow;
  457. end;
  458.  
  459.  
  460. #############################################################################
  461. ##
  462. #F  Kernel(<hom>) . . . . . . . . . . . . . . . . .  kernel of a homomorphism
  463. ##
  464. Kernel := function ( hom )
  465.     if not IsBound( hom.kernel )  then
  466.         hom.kernel := hom.source.operations.Kernel( hom );
  467.     fi;
  468.     return hom.kernel;
  469. end;
  470.  
  471.  
  472. #############################################################################
  473. ##
  474. #V  MappingOps  . . . . . . . . . . . . . . . . operation record for mappings
  475. ##
  476. ##  'MappingOps'  is the operation record of  mappings.  It  contains all the
  477. ##  default functions for mappings.
  478. ##
  479. ##  Most mappings  have operations records that  are created by making a copy
  480. ##  of 'MappingOps'  and overlaying the default  functions with more specific
  481. ##  ones.
  482. ##
  483. MappingOps := rec( );
  484.  
  485. MappingOps.IsMapping := function ( map )
  486.     local   isMap;      # 'true' if <map> is a mapping, result
  487.  
  488.     # test that each element of the source has exactely one image
  489.     if IsFinite( map.source )  then
  490.         isMap := ForAll( Elements( map.source ),
  491.                          elm -> Size( Images( map, elm ) ) = 1 );
  492.  
  493.     # give up if <map> has an infinite source
  494.     else
  495.         Error("sorry, can not test if <map> is a mapping, infinite source");
  496.     fi;
  497.  
  498.     # return the result
  499.     return isMap;
  500. end;
  501.  
  502. MappingOps.IsInjective := function ( map )
  503.     local   isInj;      # 'true' if <map> is injective, result
  504.  
  505.     # check that <map> is a mapping
  506.     if not IsMapping( map )  then
  507.         Error("<map> must be a single valued mapping");
  508.     fi;
  509.  
  510.     # if the source is larger than the range, <map> can not be injective
  511.     if Size( map.source ) > Size( map.range )  then
  512.         isInj := false;
  513.  
  514.     # compare the size of the source with the size of the image
  515.     elif IsFinite( map.source )  then
  516.         isInj := Size( map.source ) = Size( Image( map ) );
  517.  
  518.     # give up if <map> has an infinite source
  519.     else
  520.         Error("sorry, can not test if <map> is injective, infinite source");
  521.     fi;
  522.  
  523.     # return the result
  524.     return isInj;
  525. end;
  526.  
  527. MappingOps.IsSurjective := function ( map )
  528.     local   isSur;      # 'true' if <map> is surjective, result
  529.  
  530.     # check that <map> is a mapping
  531.     if not IsMapping( map )  then
  532.         Error("<map> must be a single valued mapping");
  533.     fi;
  534.  
  535.     # if the source is smaller than the range, <map> can not be surjective
  536.     if Size( map.source ) < Size( map.range )  then
  537.         isSur := false;
  538.  
  539.     # otherwise compare the size of the range with the size of the image
  540.     elif IsFinite( map.range )  then
  541.         isSur := Size( map.range ) = Size( Image( map ) );
  542.  
  543.     # give up if <map> has an infinite range
  544.     else
  545.         Error("sorry, can not test if <map> is surjective, infinite range");
  546.     fi;
  547.  
  548.     # return the result
  549.     return isSur;
  550. end;
  551.  
  552. MappingOps.IsBijection := function ( map )
  553.     return IsInjective( map )
  554.        and IsSurjective( map );
  555. end;
  556.  
  557. MappingOps.IsMonomorphism := function ( map )
  558.     return IsHomomorphism( map )
  559.        and IsInjective( map );
  560. end;
  561.  
  562. MappingOps.IsEpimorphism := function ( map )
  563.     return IsHomomorphism( map )
  564.        and IsSurjective( map );
  565. end;
  566.  
  567. MappingOps.IsIsomorphism := function ( map )
  568.     return IsHomomorphism( map )
  569.        and IsBijection( map );
  570. end;
  571.  
  572. MappingOps.IsEndomorphism := function ( map )
  573.     return IsHomomorphism( map )
  574.        and IsSubset( map.source, map.range );
  575. end;
  576.  
  577. MappingOps.IsAutomorphism := function ( map )
  578.     return IsEndomorphism( map )
  579.        and IsBijective( map );
  580. end;
  581.  
  582. MappingOps.\= := function ( map1, map2 )
  583.     local   isEql;      # 'true' if <map1> and <map2> are equal, result
  584.  
  585.     # if <map1> is a mapping
  586.     if IsGeneralMapping( map1 )  then
  587.  
  588.         # and if <map2> is also a mapping
  589.         if IsGeneralMapping( map2 )  then
  590.  
  591.             # maybe the properties we already know determine the result
  592.             if (IsBound(map1.isMapping) and IsBound(map2.isMapping)
  593.                 and map1.isMapping <> map2.isMapping)
  594.             or (IsBound(map1.isInjective) and IsBound(map2.isInjective)
  595.                 and map1.isInjective <> map2.isInjective)
  596.             or (IsBound(map1.isSurjective) and IsBound(map2.isSurjective)
  597.                 and map1.isSurjective <> map2.isSurjective)
  598.             or (IsBound(map1.isHomomorphism) and IsBound(map2.isHomomorphism)
  599.                 and map1.isHomomorphism <> map2.isHomomorphism)
  600.             then
  601.                 isEql := false;
  602.  
  603.             # otherwise we must really test the equality
  604.             else
  605.                 isEql := map1.source = map2.source
  606.                     and map1.range  = map2.range
  607.                     and ForAll( Elements( map1.source ),
  608.                            elm -> map1.operations.ImagesElm( map1, elm )
  609.                                 = map2.operations.ImagesElm( map2, elm ) );
  610.             fi;
  611.  
  612.         # a mapping and an object of another type are never equal
  613.         else
  614.             isEql := false;
  615.         fi;
  616.  
  617.     # if <map1> is not a mapping
  618.     else
  619.  
  620.         # a mapping and an object of another type are never equal
  621.         if IsGeneralMapping( map2 )  then
  622.             isEql := false;
  623.  
  624.         # at least one argument must be a mapping
  625.         else
  626.             Error("panic, either <map1> or <map2> must be a mapping");
  627.         fi;
  628.  
  629.     fi;
  630.  
  631.     # return the result
  632.     return isEql;
  633. end;
  634.  
  635. MappingOps.\< := function ( map1, map2 )
  636.     local   isLess,     # 'true' if <map1> is less than <map2>, result
  637.             elms,       # elements of the source of <map1> and <map2>
  638.             i;          # loop variable
  639.  
  640.     # if <map1> is not a mapping
  641.     if IsGeneralMapping( map1 )  then
  642.  
  643.         # and if <map2> is also a mapping
  644.         if IsGeneralMapping( map2 )  then
  645.  
  646.             # compare the sources and the ranges
  647.             if map1.source <> map2.source  then
  648.                 isLess := map1.source < map2.source;
  649.             elif map1.range <> map2.range  then
  650.                 isLess := map1.range < map2.range;
  651.  
  652.             # otherwise compare the images lexicographically
  653.             else
  654.  
  655.                 # find the first element where the images differ
  656.                 elms := Elements( map1.source );
  657.                 i := 1;
  658.                 while i <= Length( elms )
  659.                   and map1.operations.ImagesElm( map1, elms[i] )
  660.                     = map2.operations.ImagesElm( map2, elms[i] )  do
  661.                     i := i + 1;
  662.                 od;
  663.  
  664.                 # compare the image sets
  665.                 if i <= Length( elms )  then
  666.                     isLess := map1.operations.ImagesElm( map1, elms[i] )
  667.                             < map2.operations.ImagesElm( map2, elms[i] );
  668.                 else
  669.                     isLess := false;
  670.                 fi;
  671.  
  672.             fi;
  673.  
  674.         # a mapping and an object of another type are never equal
  675.         else
  676.             isLess := IsBool( map2 ) or IsString( map2 )
  677.                    or IsList( map2 ) or IsRec( map2 );
  678.         fi;
  679.  
  680.     # if <map1> is not a mapping
  681.     else
  682.  
  683.         # a mapping and an object of another type are never equal
  684.         if IsGeneralMapping( map2 )  then
  685.             isLess := not (IsBool( map1 ) or IsString( map1 )
  686.                         or IsList( map1 ) or IsRec( map1 ));
  687.  
  688.         # at least one argument must be a mapping
  689.         else
  690.             Error("panic, either <map1> or <map2> must be a mapping");
  691.         fi;
  692.  
  693.     fi;
  694.  
  695.     # return the result
  696.     return isLess;
  697. end;
  698.  
  699. MappingOps.\* := function ( map1, map2 )
  700.     local   prd;
  701.  
  702.     # product of two mappings
  703.     if      IsGeneralMapping( map1 )  and IsMapping( map1 )
  704.         and IsGeneralMapping( map2 )  and IsMapping( map2 )
  705.         and IsSubset( map1.range, map2.source )
  706.     then
  707.         prd := map1.operations.CompositionMapping( map2, map1 );
  708.  
  709.     # product of a mapping with a list, distribute
  710.     elif    IsGeneralMapping( map1 )  and IsMapping( map1 )
  711.         and IsList( map2 )
  712.     then
  713.         return List( map2, elm -> map1 * elm );
  714.     elif IsList( map1 )
  715.         and IsGeneralMapping( map2 )  and IsMapping( map2 )
  716.     then
  717.         return List( map1, elm -> elm * map2 );
  718.  
  719.     # if this function is the operations function of the right operand
  720.     # and the left operand has a different operations function, try that
  721.     elif    IsRec( map2 )
  722.         and IsBound( map2.operations )
  723.         and IsBound( map2.operations.\* )
  724.         and map2.operations.\* = MappingOps.\*
  725.         and IsRec( map1 )
  726.         and IsBound( map1.operations )
  727.         and IsBound( map1.operations.\* )
  728.         and map1.operations.\* <> MappingOps.\*
  729.     then
  730.         prd := map1.operations.\*( map1, map2 );
  731.  
  732.     # no other product involving a mapping is defined
  733.     else
  734.         Error("product of <map1> and <map2> is not defined");
  735.     fi;
  736.  
  737.     # return the product
  738.     return prd;
  739. end;
  740.  
  741. MappingOps.\/ := function ( map1, map2 )
  742.     return map1 * map2 ^ -1;
  743. end;
  744.  
  745. MappingOps.\mod := function ( map1, map2 )
  746.     return map1 ^ -1 * map2;
  747. end;
  748.  
  749. MappingOps.Comm := function ( map1, map2 )
  750.     return map1 ^ -1 * map2 ^ -1 * map1 * map2;
  751. end;
  752.  
  753. MappingOps.\^ := function ( lft, rgt )
  754.     local   pow;        # power of <lft> with <rgt>, result
  755.  
  756.     # conjugate of a mapping
  757.     if IsGeneralMapping( lft )  and IsMapping( lft )
  758.      and IsGeneralMapping( rgt )  and IsMapping( rgt )  then
  759.         if not IsBijection( rgt )  then
  760.             Error("<rgt> must be a bijection");
  761.         fi;
  762.         pow := rgt^-1 * lft * rgt;
  763.  
  764.     # image of an element under a mapping
  765.     elif IsGeneralMapping( rgt )  and IsMapping( rgt )
  766.         and lft in rgt.source
  767.     then
  768.         pow := rgt.operations.ImageElm( rgt, lft );
  769.  
  770.     # power of a mapping
  771.     elif IsGeneralMapping( lft )  and IsMapping( lft )
  772.         and IsInt( rgt )
  773.     then
  774.         if rgt < 0  then
  775.             if not IsBijection( lft )  then
  776.                 Error("<lft> must be a bijection");
  777.             fi;
  778.             lft := lft.operations.InverseMapping( lft );
  779.             lft.isMapping := true;
  780.             rgt := - rgt;
  781.         fi;
  782.         if rgt <> 1  then
  783.             if not IsSubset( lft.source, lft.range )  then
  784.                 Error("'<lft>.range' must be a subset of '<lft>.source'");
  785.             fi;
  786.             pow := lft.operations.PowerMapping( lft, rgt );
  787.         else
  788.             pow := lft;
  789.         fi;
  790.  
  791.     # otherwise the power is not defined
  792.     else
  793.         Error("power of <lft> by <rgt> must be defined");
  794.     fi;
  795.  
  796.     # return the power
  797.     return pow;
  798. end;
  799.  
  800. MappingOps.ImageElm := function ( map, elm )
  801.     local   img;        # image of <elm> under <map>, result
  802.  
  803.     # check that <map> is a mapping
  804.     if not IsMapping( map )  then
  805.         Error("<map> must be a single valued mapping");
  806.     fi;
  807.  
  808.     # take the first and only image of <elm> under <map>
  809.     img := Elements( Images( map, elm ) )[1];
  810.  
  811.     # return the image
  812.     return img;
  813. end;
  814.  
  815. MappingOps.ImagesElm := function ( map, elm )
  816.     Error("no default function to find images of <elm> under <map>");
  817. end;
  818.  
  819. MappingOps.ImagesSet := function ( map, elms )
  820.     local   imgs;       # images of <elms> under <map>, result
  821.  
  822.     # unite the images of the elements in <elm> under <map>
  823.     imgs := Union( List( Elements( elms ), elm -> Images( map, elm ) ) );
  824.  
  825.     # return the images
  826.     return imgs;
  827. end;
  828.  
  829. MappingOps.ImagesSource := function ( map )
  830.     return map.operations.ImagesSet( map, map.source );
  831. end;
  832.  
  833. MappingOps.ImagesRepresentative := function ( map, elm )
  834.     local   rep,        # representative, result
  835.             imgs;       # all images of <elm> under <map>
  836.  
  837.     # get all images of <elm> under <map>
  838.     imgs := Images( map, elm );
  839.  
  840.     # check that <elm> has at least one image under <map>
  841.     if Size( imgs ) = 0  then
  842.         Error("<elm> must have at least one image under <map>");
  843.     fi;
  844.  
  845.     # pick one image from the source, which is probably a proper set
  846.     #N  03-Nov-91 martin this should be
  847.     #N  rep := Representative( imgs );
  848.     rep := Elements( imgs )[1];
  849.  
  850.     # and return it
  851.     return rep;
  852. end;
  853.  
  854. MappingOps.PreImageElm := function ( bij, elm )
  855.     local   pre;        # preimage of <elm> under <bij>, result
  856.  
  857.     # check that <bij> is a bijection
  858.     if not IsBijection( bij )  then
  859.         Error("<bij> must be a bijection, not an arbitrary mapping");
  860.     fi;
  861.  
  862.     # take the first and only preimage of <elm> under <bij>
  863.     pre := Elements( PreImages( bij, elm ) )[1];
  864.  
  865.     # return the preimage
  866.     return pre;
  867. end;
  868.  
  869. MappingOps.PreImagesElm := function ( map, elm )
  870.     local   pres;       # preimages of <elm> under <map>, result
  871.  
  872.     # for a finite source simply run over the elements of the source
  873.     if IsFinite( map.source )  then
  874.         pres := Filtered( Elements( map.source ),
  875.                           pre -> elm in Images( map, pre ) );
  876.  
  877.     # give up if <map> has an infinite source
  878.     else
  879.       Error("sorry, can not compute preimages under <map>, infinite source");
  880.     fi;
  881.  
  882.     # return the result
  883.     return pres;
  884. end;
  885.  
  886. MappingOps.PreImagesSet := function ( map, elms )
  887.     local   pres;       # preimages of <elms> under <map>, result
  888.  
  889.     # unite the preimages of the elements in <elm> under <map>
  890.     pres := Union( List( Elements( elms ), elm -> PreImages( map, elm ) ) );
  891.  
  892.     # return the preimages
  893.     return pres;
  894. end;
  895.  
  896. MappingOps.PreImagesRange := function ( map )
  897.     return map.operations.PreImagesSet( map, map.range );
  898. end;
  899.  
  900. MappingOps.PreImagesRepresentative := function ( map, elm )
  901.     local   rep,        # representative, result
  902.             pres;       # all preimages of <elm> under <map>
  903.  
  904.     # get all preimages of <elm> under <map>
  905.     pres := PreImages( map, elm );
  906.  
  907.     # check that <elm> has at least one preimage under <map>
  908.     if Size( pres ) = 0  then
  909.         Error("<elm> must have at least one preimage under <map>");
  910.     fi;
  911.  
  912.     # pick one preimage from the source, which is probably a proper set
  913.     #N  03-Nov-91 martin this should be
  914.     #N  rep := Representative( imgs );
  915.     rep := Elements( pres )[1];
  916.  
  917.     # and return it
  918.     return rep;
  919. end;
  920.  
  921. MappingOps.CompositionMapping := function ( map1, map2 )
  922.     local   com;        # composition of <map1> and <map2>, result
  923.  
  924.     # make the mapping record
  925.     com := rec();
  926.     com.isGeneralMapping := true;
  927.     com.domain          := Mappings;
  928.  
  929.     # enter the source and the range
  930.     com.source          := map2.source;
  931.     com.range           := map1.range;
  932.  
  933.     # maybe we know that the mapping is single valued
  934.     if      IsBound( map1.isMapping )  and map1.isMapping
  935.         and IsBound( map2.isMapping )  and map2.isMapping
  936.     then
  937.         com.isMapping   := true;
  938.     fi;
  939.  
  940.     # enter the identifying information
  941.     com.map1            := map1;
  942.     com.map2            := map2;
  943.  
  944.     # enter the operations record
  945.     com.operations      := CompositionMappingOps;
  946.  
  947.     # return the composition
  948.     return com;
  949. end;
  950.  
  951. MappingOps.PowerMapping := function ( map, n )
  952.     local   pow,        # <map> raised to the <n>th power, result
  953.             i;          # loop variable
  954.  
  955.     # compute the power
  956.     pow := IdentityMapping( map.source );
  957.     if n = 0  then
  958.         return pow;
  959.     fi;
  960.     i := 2 ^ (LogInt( n, 2 ) + 1);
  961.     while 1 < i  do
  962.         pow := pow.operations.CompositionMapping( pow, pow );
  963.         i := QuoInt( i, 2 );
  964.         if i <= n  then
  965.             pow := map.operations.CompositionMapping( pow, map );
  966.             n := n - i;
  967.         fi;
  968.     od;
  969.  
  970.     # return the power
  971.     return pow;
  972. end;
  973.  
  974. MappingOps.InverseMapping := function ( map )
  975.     local   inv;
  976.  
  977.     # make the mapping record
  978.     inv := rec();
  979.     inv.isGeneralMapping := true;
  980.     inv.domain          := Mappings;
  981.  
  982.     # enter source and range, and, if possible, preimage and image
  983.     inv.source          := map.range;
  984.     inv.range           := map.source;
  985.     if IsBound( map.image )  then
  986.         inv.preimge     := map.image;
  987.     fi;
  988.     if IsBound( map.preimage )  then
  989.         inv.image       := map.preimage;
  990.     fi;
  991.  
  992.     # maybe we know that this mapping is single valued
  993.     if IsBound( map.isBijection )  and map.isBijection  then
  994.         inv.isMapping   := true;
  995.         inv.isInjective := true;
  996.         inv.isSurjective:= true;
  997.         inv.isBijection := true;
  998.     fi;
  999.  
  1000.     # we know the inverse mapping of the inverse mapping ;-)
  1001.     inv.inverseMapping  := map;
  1002.  
  1003.     # enter the operations record
  1004.     inv.operations      := InverseMappingOps;
  1005.  
  1006.     # return the inverse mapping
  1007.     return inv;
  1008. end;
  1009.  
  1010. CompositionMappingOps := Copy( MappingOps );
  1011.  
  1012. CompositionMappingOps.IsMapping := function ( com )
  1013.     if     IsMapping( com.map1 )
  1014.        and IsMapping( com.map2 )
  1015.     then
  1016.         return true;
  1017.     else
  1018.         return MappingOps.IsMapping( com );
  1019.     fi;
  1020. end;
  1021.  
  1022. CompositionMappingOps.IsInjective := function ( com )
  1023.     if      IsMapping( com.map1 )  and IsInjective( com.map1 )
  1024.         and IsMapping( com.map2 )  and IsInjective( com.map2 )
  1025.     then
  1026.         return true;
  1027.     else
  1028.         return MappingOps.IsInjective( com );
  1029.     fi;
  1030. end;
  1031.  
  1032. CompositionMappingOps.IsSurjective := function ( com )
  1033.     if      IsMapping( com.map1 )  and IsSurjective( com.map1 )
  1034.         and IsMapping( com.map2 )  and IsSurjective( com.map2 )
  1035.     then
  1036.         return true;
  1037.     else
  1038.         return MappingOps.IsInjective( com );
  1039.     fi;
  1040. end;
  1041.  
  1042. CompositionMappingOps.IsHomomorphism := function ( com )
  1043.     if      IsMapping( com.map1 )  and IsHomomorphism( com.map1 )
  1044.         and IsMapping( com.map2 )  and IsHomomorphism( com.map2 )  then
  1045.         return true;
  1046.     else
  1047.         return MappingOps.IsHomomorphism( com );
  1048.     fi;
  1049. end;
  1050.  
  1051. CompositionMappingOps.ImagesElm := function ( com, elm )
  1052.     return com.map1.operations.ImagesSet( com.map1,
  1053.                com.map2.operations.ImagesElm( com.map2,
  1054.                    elm ) );
  1055. end;
  1056.  
  1057. CompositionMappingOps.ImagesSet := function ( com, elms )
  1058.     return com.map1.operations.ImagesSet( com.map1,
  1059.                com.map2.operations.ImagesSet( com.map2,
  1060.                    elms ) );
  1061. end;
  1062.  
  1063. CompositionMappingOps.ImagesRepresentative := function ( com, elm )
  1064.     return com.map1.operations.ImagesRepresentative( com.map1,
  1065.                com.map2.operations.ImagesRepresentative( com.map2,
  1066.                    elm ) );
  1067. end;
  1068.  
  1069. CompositionMappingOps.PreImagesElm := function ( com, elm )
  1070.     return com.map2.operations.PreImagesSet( com.map2,
  1071.                com.map1.operations.PreImagesElm( com.map1,
  1072.                    elm ) );
  1073. end;
  1074.  
  1075. CompositionMappingOps.PreImagesSet := function ( com, elms )
  1076.     return com.map2.operations.PreImagesSet( com.map2,
  1077.                com.map1.operations.PreImagesSet( com.map1,
  1078.                    elms ) );
  1079. end;
  1080.  
  1081. CompositionMappingOps.PreImagesRepresentative := function ( com, elm )
  1082.     return com.map2.operations.PreImagesRepresentative( com.map2,
  1083.                com.map1.operations.PreImagesRepresentative( com.map1,
  1084.                    elm ) );
  1085. end;
  1086.  
  1087. CompositionMappingOps.Print := function ( com )
  1088.     Print( "CompositionMapping( ", com.map1, ", ", com.map2, " )" );
  1089. end;
  1090.  
  1091. CompositionMappingOps.IsGroupHomomorphism := function ( com )
  1092.     return MappingOps.IsGroupHomomorphism( com );
  1093. end;
  1094.  
  1095. CompositionMappingOps.KernelGroupHomomorphism := function ( com )
  1096.     return MappingOps.KernelGroupHomomorphism( com );
  1097. end;
  1098.  
  1099. CompositionMappingOps.IsFieldHomomorphism := function ( com )
  1100.     return MappingOps.IsFieldHomomorphism( com );
  1101. end;
  1102.  
  1103. CompositionMappingOps.KernelFieldHomomorphism := function ( com )
  1104.     return MappingOps.KernelFieldHomomorphism( com );
  1105. end;
  1106.  
  1107. InverseMappingOps := Copy( MappingOps );
  1108.  
  1109. InverseMappingOps.IsMapping := function ( inv )
  1110.     if IsMapping( inv.inverseMapping )  then
  1111.         return IsBijection( inv.inverseMapping );
  1112.     else
  1113.         return MappingOps.IsMapping( inv );
  1114.     fi;
  1115. end;
  1116.  
  1117. InverseMappingOps.IsInjective := function ( inv )
  1118.     if not IsMapping( inv )  then
  1119.         Error("<map> must be a single valued mapping");
  1120.     fi;
  1121.     if IsMapping( inv.inverseMapping )  then
  1122.         return IsBijection( inv.inverseMapping );
  1123.     else
  1124.         return MappingOps.IsInjective( inv );
  1125.     fi;
  1126. end;
  1127.  
  1128. InverseMappingOps.IsSurjective := function ( inv )
  1129.     if not IsMapping( inv )  then
  1130.         Error("<map> must be a single valued mapping");
  1131.     fi;
  1132.     if IsMapping( inv.inverseMapping )  then
  1133.         return IsBijection( inv.inverseMapping );
  1134.     else
  1135.         return MappingOps.IsSurjective( inv );
  1136.     fi;
  1137. end;
  1138.  
  1139. InverseMappingOps.IsHomomorphism := function ( inv )
  1140.     if not IsMapping( inv )  then
  1141.         Error("<map> must be a single valued mapping");
  1142.     fi;
  1143.     if IsMapping( inv.inverseMapping )
  1144.         and IsHomomorphism( inv.inverseMapping )
  1145.     then
  1146.         return IsBijection( inv.inverseMapping );
  1147.     else
  1148.         return MappingOps.IsHomomorphism( inv );
  1149.     fi;
  1150. end;
  1151.  
  1152. InverseMappingOps.ImageElm := function ( inv, elm )
  1153.     return inv.inverseMapping.operations.PreImageElm(
  1154.                 inv.inverseMapping, elm );
  1155. end;
  1156.  
  1157. InverseMappingOps.ImagesElm := function ( inv, elm )
  1158.     return inv.inverseMapping.operations.PreImagesElm(
  1159.                 inv.inverseMapping, elm );
  1160. end;
  1161.  
  1162. InverseMappingOps.ImagesSet := function ( inv, elms )
  1163.     return inv.inverseMapping.operations.PreImagesSet(
  1164.                 inv.inverseMapping, elms );
  1165. end;
  1166.  
  1167. InverseMappingOps.ImagesRepresentative := function ( inv, elm )
  1168.     return inv.inverseMapping.operations.PreImagesRepresentative(
  1169.                 inv.inverseMapping, elm );
  1170. end;
  1171.  
  1172. InverseMappingOps.PreImageElm := function ( inv, elm )
  1173.     return inv.inverseMapping.operations.ImageElm(
  1174.                 inv.inverseMapping, elm );
  1175. end;
  1176.  
  1177. InverseMappingOps.PreImagesElm := function ( inv, elm )
  1178.     return inv.inverseMapping.operations.ImagesElm(
  1179.                 inv.inverseMapping, elm );
  1180. end;
  1181.  
  1182. InverseMappingOps.PreImagesSet := function ( inv, elms )
  1183.     return inv.inverseMapping.operations.Images(
  1184.                 inv.inverseMapping, elms );
  1185. end;
  1186.  
  1187. InverseMappingOps.PreImagesRepresentative := function ( inv, elm )
  1188.     return inv.inverseMapping.operations.ImagesRepresentative(
  1189.                 inv.inverseMapping, elm );
  1190. end;
  1191.  
  1192. InverseMappingOps.Print := function ( inv )
  1193.     Print("InverseMapping( ",inv.inverseMapping," )");
  1194. end;
  1195.  
  1196. InverseMappingOps.IsGroupHomomorphism := function ( inv )
  1197.     return MappingOps.IsGroupHomomorphism( inv );
  1198. end;
  1199.  
  1200. InverseMappingOps.KernelGroupHomomorphism := function ( inv )
  1201.     return MappingOps.KernelGroupHomomorphism( inv );
  1202. end;
  1203.  
  1204. InverseMappingOps.IsFieldHomomorphism := function ( inv )
  1205.     return MappingOps.IsFieldHomomorphism( inv );
  1206. end;
  1207.  
  1208. InverseMappingOps.KernelFieldHomomorphism := function ( inv )
  1209.     return MappingOps.KernelFieldHomomorphism( inv );
  1210. end;
  1211.  
  1212.  
  1213. #############################################################################
  1214. ##
  1215. #F  MappingByFunction(<D>,<E>,<fun>)  . . .  create a mapping from a function
  1216. ##
  1217. MappingByFunction := function ( D, E, fun )
  1218.     local   map;        # mapping <map>, result
  1219.  
  1220.     # make the mapping
  1221.     map := rec(
  1222.  
  1223.         # enter the tag components
  1224.         isGeneralMapping        := true,
  1225.         domain                  := Mappings,
  1226.         isMapping               := true,
  1227.         isMappingByFunction     := true,
  1228.  
  1229.         # enter the source and the range
  1230.         source                  := D,
  1231.         range                   := E,
  1232.         fun                     := fun,
  1233.  
  1234.         # enter the operations record
  1235.         operations              := MappingByFunctionOps
  1236.  
  1237.     );
  1238.  
  1239.     # return the mapping
  1240.     return map;
  1241. end;
  1242.  
  1243. MappingByFunctionOps := Copy( MappingOps );
  1244.  
  1245. MappingByFunctionOps.ImageElm := function ( map, elm )
  1246.     return map.fun( elm );
  1247. end;
  1248.  
  1249. MappingByFunctionOps.ImagesElm := function ( map, elm )
  1250.     return [ map.fun( elm ) ];
  1251. end;
  1252.  
  1253. MappingByFunctionOps.ImagesRepresentative := function ( map, elm )
  1254.     return map.fun( elm );
  1255. end;
  1256.  
  1257. MappingByFunctionOps.Print := function ( map )
  1258.     Print( "MappingByFunction( ", map.source, ", ", map.range, ", ",
  1259.            map.fun, " )" );
  1260. end;
  1261.  
  1262. MappingByFunctionOps.IsGroupHomomorphism := function ( map )
  1263.     return MappingOps.IsGroupHomomorphism( map );
  1264. end;
  1265.  
  1266. MappingByFunctionOps.KernelGroupHomomorphism := function ( map )
  1267.     return MappingOps.KernelGroupHomomorphism( map );
  1268. end;
  1269.  
  1270. MappingByFunctionOps.IsFieldHomomorphism := function ( map )
  1271.     return MappingOps.IsFieldHomomorphism( map );
  1272. end;
  1273.  
  1274. MappingByFunctionOps.KernelFieldHomomorphism := function ( map )
  1275.     return MappingOps.KernelFieldHomomorphism( map );
  1276. end;
  1277.  
  1278.  
  1279. #############################################################################
  1280. ##
  1281. #F  Embedding(<S>,<T>)  . . . . . . . .  embedding of one domain into another
  1282. ##
  1283. Embedding := function ( arg )
  1284.     if Length(arg) = 2  then
  1285.         return arg[2].operations.Embedding( arg[1], arg[2] );
  1286.     elif Length(arg) = 3  then
  1287.         return arg[2].operations.Embedding( arg[1], arg[2], arg[3] );
  1288.     else
  1289.         Error("usage: Embedding(<S>,<T>) or Embedding(<S>,<T>,<i>)");
  1290.     fi;
  1291. end;
  1292.  
  1293.  
  1294. #############################################################################
  1295. ##
  1296. #F  Projection(<S>,<T>) . . . . . . . . projection of one domain onto another
  1297. ##
  1298. Projection := function ( arg )
  1299.     if Length(arg) = 2  then
  1300.         return arg[1].operations.Projection( arg[1], arg[2] );
  1301.     elif Length(arg) = 3  then
  1302.         return arg[1].operations.Projection( arg[1], arg[2], arg[3] );
  1303.     else
  1304.         Error("usage: Projection(<S>,<T>) or Projection(<S>,<T>,<i>)");
  1305.     fi;
  1306. end;
  1307.  
  1308.  
  1309. #############################################################################
  1310. ##
  1311. #V  Mappings  . . . . . . . . . . . . . . . . . . . .  domain of all mappings
  1312. #V  MappingsOps . . . . . .  operations record for the domain of all mappings
  1313. ##
  1314. Mappings                := rec();
  1315.  
  1316. Mappings.isDomain       := true;
  1317.  
  1318. Mappings.name           := "Mappings";
  1319.  
  1320. Mappings.isFinite       := false;
  1321. Mappings.size           := "infinity";
  1322.  
  1323. Mappings.operations     := Copy( DomainOps );
  1324. MappingsOps             := Mappings.operations;
  1325.  
  1326. MappingsOps.\in        := function ( obj, Mappings )
  1327.     return IsMapping( obj );
  1328. end;
  1329.  
  1330. MappingsOps.Order       := GroupElementsOps.Order;
  1331.  
  1332. MappingsOps.Group       := function ( Mappings, gens, id )
  1333.     local   gen;
  1334.  
  1335.     # check the arguments
  1336.     if not IsMapping( id )  or not IsBijection( id )  then
  1337.         Error("<id> must be a bijection");
  1338.     fi;
  1339.     if id.source <> id.range  then
  1340.         Error("the source and range of <id> must be equal");
  1341.     fi;
  1342.     for gen  in gens  do
  1343.         if not IsMapping( gen )  or not IsBijection( gen )  then
  1344.             Error("<gen> must be a bijection");
  1345.         fi;
  1346.         if gen.source <> id.source  or gen.range <> id.range  then
  1347.             Error("<gen> must permute the source of <id>");
  1348.         fi;
  1349.     od;
  1350.  
  1351.     # delegate the work
  1352.     return GroupElementsOps.Group( Mappings, gens, id );
  1353. end;
  1354.  
  1355.  
  1356. #############################################################################
  1357. ##
  1358. #E  Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
  1359. ##
  1360. ##  Local Variables:
  1361. ##  mode:               outline
  1362. ##  outline-regexp:     "#F\\|#V\\|#E"
  1363. ##  fill-column:        73
  1364. ##  fill-prefix:        "##  "
  1365. ##  eval:               (hide-body)
  1366. ##  End:
  1367. ##
  1368.  
  1369.  
  1370.  
  1371.