  
  [1X8 [33X[0;0YOperations and Methods[133X[101X
  
  
  [1X8.1 [33X[0;0YAttributes[133X[101X
  
  [33X[0;0YIn  the  preceding  chapters,  we  have seen how to obtain information about
  mathematical  objects in [5XGAP[105X: We have to pass the object as an argument to a
  function.  For  example,  if  [3XG[103X  is  a group one can call [10XSize( [3XG[103X[10X )[110X, and the
  function will return a value, in our example an integer which is the size of
  [3XG[103X.  Computing the size of a group generally requires a substantial amount of
  work,  therefore  it seems desirable to store the size somewhere once it has
  been  calculated.  You should imagine that [5XGAP[105X stores the size in some place
  associated  with the object [3XG[103X when [10XSize( [3XG[103X[10X )[110X is executed for the first time,
  and if this function call is executed again later, the size is simply looked
  up and returned, without further computation.[133X
  
  [33X[0;0YThis  means  that the behavior of the function [2XSize[102X ([14XReference: Size[114X) has to
  depend  on whether the size for the argument [3XG[103X is already known, and if not,
  that  the  size must be stored after it has been calculated. These two extra
  tasks  are  done by two other functions that accompany [10XSize( [3XG[103X[10X )[110X, namely the
  [13Xtester[113X  [10XHasSize(  [3XG[103X[10X  )[110X and the [13Xsetter[113X [10XSetSize( [3XG[103X[10X, [3Xsize[103X[10X )[110X. The tester returns
  [9Xtrue[109X  or  [9Xfalse[109X  according to whether [3XG[103X has already stored its size, and the
  setter  puts  [3Xsize[103X  into  a  place from where [3XG[103X can directly look it up. The
  function  [2XSize[102X  ([14XReference:  Size[114X) itself is called the [13Xgetter[113X, and from the
  preceding  discussion  we see that there must really be at least two [13Xmethods[113X
  for  the getter: One method is used when the tester returns [9Xfalse[109X; it is the
  method  which  first  does the real computation and then executes the setter
  with  the  computed  value.  A second method is used when the tester returns
  [9Xtrue[109X;  it simply returns the stored value. This second method is also called
  the  [13Xsystem getter[113X. [5XGAP[105X functions for which several methods can be available
  are  called  [13Xoperations[113X,  so  [2XSize[102X  ([14XReference:  Size[114X)  is  an example of an
  operation.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27XG := Group(List([1..3], i-> Random(SymmetricGroup(53))));;[127X[104X
    [4X[25Xgap>[125X [27XSize( G ); time > 0; # the time may of course vary on your machine[127X[104X
    [4X[28X4274883284060025564298013753389399649690343788366813724672000000000000[128X[104X
    [4X[28Xtrue[128X[104X
    [4X[25Xgap>[125X [27XSize( G ); time;[127X[104X
    [4X[28X4274883284060025564298013753389399649690343788366813724672000000000000[128X[104X
    [4X[28X0[128X[104X
  [4X[32X[104X
  
  [33X[0;0YThe  convenient  thing  for  the  user is that [5XGAP[105X automatically chooses the
  right  method for the getter, i.e., it calls a real-work getter at most once
  and  the  system  getter in all subsequent occurrences. [13XAt most once[113X because
  the value of a function call like [10XSize( [3XG[103X[10X )[110X can also be set for [3XG[103X before the
  getter  is  called  at all; for example, one can call the setter directly if
  one knows the size.[133X
  
  [33X[0;0YThe  size  of  a  group  is an example of a class of things which in [5XGAP[105X are
  called  [13Xattributes[113X.  Every  attribute in [5XGAP[105X is represented by a triple of a
  getter,  a  setter and a tester. When a new attribute is declared, all three
  functions  are  created  together  and the getter contains references to the
  other  two.  This  is  necessary  because when the getter is called, it must
  first  consult  the  tester,  and  perhaps  execute  the  setter in the end.
  Therefore the getter could be implemented as follows:[133X
  
  [4X[32X  Example  [32X[104X
    [4X[28Xgetter := function( obj )[128X[104X
    [4X[28Xlocal   value;[128X[104X
    [4X[28X    if tester( obj )  then[128X[104X
    [4X[28X        value := system_getter( obj );[128X[104X
    [4X[28X    else[128X[104X
    [4X[28X        value := real_work_getter( obj );[128X[104X
    [4X[28X        setter( obj, value );[128X[104X
    [4X[28X    fi;[128X[104X
    [4X[28X    return value;[128X[104X
    [4X[28Xend;[128X[104X
  [4X[32X[104X
  
  [33X[0;0YThe  only function which depends on the mathematical nature of the attribute
  is  the  real-work  getter,  and this is of course what the programmer of an
  attribute  has to install. In both cases, the getter returns the same value,
  which  we  also  call the value of the attribute (properly: the value of the
  attribute  for  the object [10Xobj[110X). By the way: The names for setter and tester
  of  an  attribute  are always composed from the prefix [10XSet[110X resp. [10XHas[110X and the
  name of the getter.[133X
  
  [33X[0;0YAs  a  (not  typical) example, note that the [5XGAP[105X function [2XRandom[102X ([14XReference:
  Random[114X), although it takes only one argument, is of course [13Xnot[113X an attribute,
  because otherwise the first random element of a group would be stored by the
  setter  and  returned  over  and  over again by the system getter every time
  [2XRandom[102X ([14XReference: Random[114X) is called in the sequel.[133X
  
  [33X[0;0YThere  is  a  general  important rule about attributes: [13XOnce the value of an
  attribute for an object has been set, it cannot be reset, i.e., it cannot be
  changed  any  more.[113X  This is achieved by having two methods not only for the
  getter  but also for the setter: If an object already has an attribute value
  stored, i.e., if the tester returns [9Xtrue[109X, the setter simply does nothing.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27XG := SymmetricGroup(8);; Size(G);[127X[104X
    [4X[28X40320[128X[104X
    [4X[25Xgap>[125X [27XSetSize( G, 0 ); Size( G );[127X[104X
    [4X[28X40320[128X[104X
  [4X[32X[104X
  
  [33X[0;0Y[13XSummary.[113X In this section we have introduced attributes as triples of getter,
  setter  and  tester  and  we  have  explained how these three functions work
  together behind the scene to provide automatic storage and look-up of values
  that  have  once  been  calculated.  We  have seen that there can be several
  methods  for  the  same  function  among  which [5XGAP[105X automatically selects an
  appropriate one.[133X
  
  
  [1X8.2 [33X[0;0YProperties and Filters[133X[101X
  
  [33X[0;0YCertain    attributes,    like   [2XIsAbelian[102X   ([14XReference:   IsAbelian[114X),   are
  boolean-valued.  Such  attributes  are  known  to [5XGAP[105X as [13Xproperties[113X, because
  their  values  are stored in a slightly different way. A property also has a
  getter,  a  setter and a tester, but in this case, the getter as well as the
  tester returns a boolean value. Therefore [5XGAP[105X stores both values in the same
  way, namely as bits in a boolean list, thereby treating property getters and
  all  testers  (of  attributes or properties) uniformly. These boolean-valued
  functions  are called [13Xfilters[113X. You can imagine a filter as a switch which is
  set either to [9Xtrue[109X or to [9Xfalse[109X. For every [5XGAP[105X object there is a boolean list
  which  has  reserved  a  bit  for  every  filter  [5XGAP[105X  knows about. Strictly
  speaking, there is one bit for every [13Xsimple filter[113X, and these simple filters
  can  be  combined with [10Xand[110X to form other filters (which are then [9Xtrue[109X if and
  only if all the corresponding bits are set to [9Xtrue[109X). For example, the filter
  [10XIsPermGroup and IsSolvableGroup[110X is made up from several simple filters.[133X
  
  [33X[0;0YSince  they  allow  only two values, the bits which represent filters can be
  compared very quickly, and the scheme by which [5XGAP[105X chooses the method, e.g.,
  for  a  getter  or  a  setter  (as we have seen in the previous section), is
  mostly  based on the examination of filters, not on the examination of other
  attribute  values.  Details  of  this  [13Xmethod  selection[113X  are  described  in
  chapter [14X'Reference: Method Selection'[114X.[133X
  
  [33X[0;0YWe  only present the following rule of thumb here: Each installed method for
  an  attribute,  say  [2XSize[102X ([14XReference: Size[114X), has a [21Xrequired filter[121X, which is
  made  up  from certain simple filters which must yield [9Xtrue[109X for the argument
  [3Xobj[103X  for this method to be applicable. To execute a call of [10XSize( [3Xobj[103X[10X )[110X, [5XGAP[105X
  selects  among all applicable methods the one whose required filter combines
  the  most  simple  filters;  the  idea  behind is that the more an algorithm
  requires  of  [3Xobj[103X,  the more efficient it is expected to be. For example, if
  [3Xobj[103X is a permutation group that is not (known to be) solvable, a method with
  required filter [10XIsPermGroup and IsSolvableGroup[110X is not applicable, whereas a
  method  with  required  filter  [2XIsPermGroup[102X  ([14XReference: IsPermGroup[114X) can be
  chosen.  On the other hand, if [3Xobj[103X was known to be solvable, the method with
  required  filter  [10XIsPermGroup  and IsSolvableGroup[110X would be preferred to the
  one with required filter [2XIsPermGroup[102X ([14XReference: IsPermGroup[114X).[133X
  
  [33X[0;0YIt  may  happen  that a method is applicable for a given argument but cannot
  compute  the  desired  value.  In  such  cases,  the method will execute the
  statement  [10XTryNextMethod();[110X,  and  [5XGAP[105X calls the next applicable method. For
  example,  [Sim90]  describes  an algorithm to compute the size of a solvable
  permutation  group,  which  can  be  used  also  to  decide whether or not a
  permutation  group  is  solvable.  Suppose  that  the function [10Xsize_solvable[110X
  implements  this algorithm, and that is returns the order of the group if it
  is solvable and [9Xfail[109X otherwise. Then we can install the following method for
  [2XSize[102X   ([14XReference:   Size[114X)  with  required  filter  [2XIsPermGroup[102X  ([14XReference:
  IsPermGroup[114X).[133X
  
  [4X[32X  Example  [32X[104X
    [4X[28Xfunction( G )[128X[104X
    [4X[28Xlocal  value;[128X[104X
    [4X[28X    value := size_solvable( G );[128X[104X
    [4X[28X    if value <> fail  then  return value;[128X[104X
    [4X[28X                      else  TryNextMethod();  fi;[128X[104X
    [4X[28Xend;[128X[104X
  [4X[32X[104X
  
  [33X[0;0YThis  method  can then be tried on every permutation group (whether known to
  be solvable or not), and it would include a mandatory solvability test.[133X
  
  [33X[0;0YIf  no  applicable method (or no next applicable method) is found, [5XGAP[105X stops
  with an error message of the form[133X
  
  [4X[32X  Example  [32X[104X
    [4X[28XError, no method found! For debugging hints type ?Recovery from NoMethodFound[128X[104X
    [4X[28XError, no 1st choice method found for `Size' on 1 arguments called from[128X[104X
    [4X[28X... lines deleted here ...[128X[104X
  [4X[32X[104X
  
  [33X[0;0YYou  would  get  an  error  message as above if you asked for [10XSize( 1 )[110X. The
  message  simply  says  that there is no method installed for calculating the
  size  of [10X1[110X. Section [14X'Reference: Recovery from NoMethodFound-Errors'[114X contains
  more information on how to deal with these messages.[133X
  
  [33X[0;0Y[13XSummary.[113X   In   this  section  we  have  introduced  properties  as  special
  attributes,  and  filters as the general concept behind property getters and
  attribute  testers.  The  values  of the filters of an object govern how the
  object is treated in the selection of methods for operations.[133X
  
  
  [1X8.3 [33X[0;0YImmediate and True Methods[133X[101X
  
  [33X[0;0YIn  the  example  in  Section [14X8.2[114X, we have mentioned that the operation [2XSize[102X
  ([14XReference:  Size[114X)  has  a method for solvable permutation groups that is so
  far  superior  to  the  method  for general permutation groups that it seems
  worthwhile to try it even if nothing is known about solvability of the group
  of  which  the  [2XSize[102X  ([14XReference: Size[114X) is to be calculated. There are other
  examples  where certain methods are even [21Xcheaper[121X to execute. For example, if
  the  size  of a group is known it is easy to check whether it is odd, and if
  so,  the  Feit-Thompson theorem allows us to set [2XIsSolvableGroup[102X ([14XReference:
  IsSolvableGroup[114X)  to  [9Xtrue[109X  for  this  group.  [5XGAP[105X  utilizes this celebrated
  theorem  by  having  an  [13Ximmediate  method[113X  for  [2XIsSolvableGroup[102X ([14XReference:
  IsSolvableGroup[114X)  with  required  filter  [10XHasSize[110X which checks parity of the
  size  and  either  sets [2XIsSolvableGroup[102X ([14XReference: IsSolvableGroup[114X) or does
  nothing,  i.e.,  calls [10XTryNextMethod()[110X. These immediate methods are executed
  automatically  for  an  object  whenever  the  value of a filter changes, so
  solvability  of  a group will automatically be detected when an odd size has
  been  calculated  for  it (and therefore the value of [10XHasSize[110X for that group
  has changed to [9Xtrue[109X).[133X
  
  [33X[0;0YSome  methods  are  even  more  immediate,  because  they do not require any
  calculation  at all: They allow a filter to be set if another filter is also
  set.  In other words, they model a mathematical implication like [10XIsGroup and
  IsCyclic[110X  implies  [10XIsSolvableGroup[110X and such implications can be installed in
  [5XGAP[105X  as  [13Xtrue  methods[113X.  To  execute true methods, [5XGAP[105X only needs to do some
  bookkeeping  with  its  filters, therefore true methods are much faster than
  immediate methods.[133X
  
  [33X[0;0YHow  immediate  and  true  methods are installed is described in [14X'Reference:
  Immediate Methods'[114X and [14X'Reference: Logical Implications'[114X.[133X
  
  
  [1X8.4 [33X[0;0YOperations and Method Selection[133X[101X
  
  [33X[0;0YThe  method  selection  is  not  only  used  to select methods for attribute
  getters  but  also  for  arbitrary  [13Xoperations[113X, which can have more than one
  argument.  In this case, there is a required filter for each argument (which
  must yield [9Xtrue[109X for the corresponding arguments).[133X
  
  [33X[0;0YAdditionally,  a  method  with  at least two arguments may require a certain
  relation  between the arguments, which is expressed in terms of the [13Xfamilies[113X
  of  the  arguments.  For example, the methods for [10XConjugateGroup( [3Xgrp[103X[10X, [3Xelm[103X[10X )[110X
  require  that  [3Xelm[103X  lies  in  the family of elements from which [3Xgrp[103X is made,
  i.e., that the family of [3Xelm[103X equals the [21Xelements family[121X of [3Xgrp[103X.[133X
  
  [33X[0;0YFor  permutation  groups, the situation is quite easy: all permutations form
  one  family,  [2XPermutationsFamily[102X  ([14XReference:  PermutationsFamily[114X), and each
  collection  of  permutations, for example each permutation group, each coset
  of  a  permutation  group,  or  each  dense  list  of  permutations, lies in
  [10XCollectionsFamily( PermutationsFamily )[110X.[133X
  
  [33X[0;0YFor  other  kinds  of  group elements, the situation can be different. Every
  call  of  [2XFreeGroup[102X  ([14XReference:  FreeGroup[114X) constructs a new family of free
  group  elements.  [5XGAP[105X  refuses  to  compute  [10XOne(  FreeGroup(  1  ) ) * One(
  FreeGroup(  1  )  )[110X  because  the  two operands of the multiplication lie in
  different families and no method is installed for this case.[133X
  
  [33X[0;0YFor further information on family relations, see [14X'Reference: Families'[114X.[133X
  
  [33X[0;0YIf you want to know which properties are already known for an object [3Xobj[103X, or
  which   properties  are  known  to  be  true,  you  can  use  the  functions
  [10XKnownPropertiesOfObject(  [3Xobj[103X[10X  )[110X  resp.  [10XKnownTruePropertiesOfObject( [3Xobj[103X[10X )[110X.
  This  will  print  a  list  of names of properties. These names are also the
  identifiers  of the property getters, by which you can retrieve the value of
  the  properties  (and confirm that they are really [9Xtrue[109X). Analogously, there
  is the function [2XKnownAttributesOfObject[102X ([14XReference: KnownAttributesOfObject[114X)
  which lists the names of the known attributes, leaving out the properties.[133X
  
  [33X[0;0YSince  [5XGAP[105X  lets  you know what it already knows about an object, it is only
  natural  that it also lets you know what methods it considers applicable for
  a   certain   method,   and  in  what  order  it  will  try  them  (in  case
  [10XTryNextMethod()[110X  occurs).  [10XApplicableMethod(  [3Xopr[103X[10X,  [  arg_1, arg_2, ... ] )[110X
  returns  the  first applicable method for the call [10X[3Xopr[103X[10X( arg_1, arg_2, ... )[110X.
  More  generally,  [10XApplicableMethod(  [3Xopr[103X[10X,  [ ... ], 0, [3Xnr[103X[10X )[110X returns the [3Xnr[103Xth
  applicable  method  (i.e.,  the one that would be chosen after [22X[3Xnr[103X-1[122X calls of
  [10XTryNextMethod[110X)  and if [3Xnr[103X[10X = "all"[110X, the sorted list of all applicable methods
  is  returned.  For  details,  see  [14X'Reference: Applicable Methods and Method
  Selection'[114X.[133X
  
  [33X[0;0YIf you want to see which methods are chosen for certain operations while [5XGAP[105X
  code  is  being executed, you can call the function [2XTraceMethods[102X ([14XReference:
  TraceMethods  (for a list of operations)[114X) with a list of these operations as
  arguments.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27XTraceMethods( [ Size ] );[127X[104X
    [4X[25Xgap>[125X [27Xg:= Group( (1,2,3), (1,2) );;  Size( g );[127X[104X
    [4X[28X#I  Size: for a permutation group[128X[104X
    [4X[28X#I  Setter(Size): system setter[128X[104X
    [4X[28X#I  Size: system getter[128X[104X
    [4X[28X#I  Size: system getter[128X[104X
    [4X[28X6[128X[104X
  [4X[32X[104X
  
  [33X[0;0YThe  system  getter  is  called once to fetch the freshly computed value for
  returning  to the user. The second call is triggered by an immediate method.
  To  find  out  by  which,  we  can  trace  the  immediate  methods by saying
  [10XTraceImmediateMethods( true )[110X.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27XTraceImmediateMethods( true );[127X[104X
    [4X[25Xgap>[125X [27Xg:= Group( (1,2,3), (1,2) );;[127X[104X
    [4X[28X#I  immediate: Size[128X[104X
    [4X[28X#I  immediate: IsCyclic[128X[104X
    [4X[28X#I  immediate: IsCommutative[128X[104X
    [4X[28X#I  immediate: IsTrivial[128X[104X
    [4X[25Xgap>[125X [27XSize( g );[127X[104X
    [4X[28X#I  Size: for a permutation group[128X[104X
    [4X[28X#I  immediate: IsNonTrivial[128X[104X
    [4X[28X#I  immediate: Size[128X[104X
    [4X[28X#I  immediate: IsFreeAbelian[128X[104X
    [4X[28X#I  immediate: IsTorsionFree[128X[104X
    [4X[28X#I  immediate: IsNonTrivial[128X[104X
    [4X[28X#I  immediate: GeneralizedPcgs[128X[104X
    [4X[28X#I  Setter(Size): system setter[128X[104X
    [4X[28X#I  Size: system getter[128X[104X
    [4X[28X#I  immediate: IsPerfectGroup[128X[104X
    [4X[28X#I  Size: system getter[128X[104X
    [4X[28X#I  immediate: IsEmpty[128X[104X
    [4X[28X6[128X[104X
    [4X[25Xgap>[125X [27XTraceImmediateMethods( false );[127X[104X
    [4X[25Xgap>[125X [27XUntraceMethods( [ Size ] );[127X[104X
  [4X[32X[104X
  
  [33X[0;0YThe  last  two  lines  switch  off tracing again. We now see that the system
  getter  was  called  by  the immediate method for [2XIsPerfectGroup[102X ([14XReference:
  IsPerfectGroup[114X).    Also    the   above-mentioned   immediate   method   for
  [2XIsSolvableGroup[102X  ([14XReference:  IsSolvableGroup[114X)  was  not  used  because  the
  solvability  of [10Xg[110X was already found out during the size calculation (cf. the
  example in Section [14X8.2[114X).[133X
  
  [33X[0;0Y[13XSummary.[113X  In  this  section and the last we have looked some more behind the
  scenes  and  seen that [5XGAP[105X automatically executes immediate and true methods
  to  deduce information about objects that is cheaply available. We have seen
  how this can be supervised by tracing the methods.[133X
  
