The easiest case is the addition of a new algorithm as a method for an existing operation for the existing structures.
For example, assume we wanted to implement a better method for computing the exponent of a nilpotent group (it is the product of the exponents of the sylow subgroups).
The first task is to find which operation is used by GAP (it is Exponent)
and how it is declared. We can find this in the reference manual (in our
particular case in section Numerical Group Attributes) and the
declaration in the library file lib/grp.gd (The easiest way to find the
place of the declaration is usually to grep over all .gd and .g files,
see section Library Files of ``Extending Gap''.)
In our example the declaration in the library is:
DeclareAttribute("Exponent",IsGroup);
Similarly we find that the filter IsNilpotentGroup
represents the concept of being nilpotent.
We then write a function that implements the new algorithm which takes the right set of arguments and install it as a method. In our example this installation would be:
InstallMethod(Exponent,"for nilpotent groups", [IsGroup and IsNilpotent], function(G) [function body omitted] end);
We have left out the optional rank argument of InstallMethod,
which normally is a wise choice -- GAP
automatically uses an internal ranking based on the filters that is only
offset by the given rank. So our method will certainly be ``better'' than
a method that has been installed for mere groups or for solvable groups but
will be ranked lower than the library method for abelian groups.
That's all. Using ApplicableMethod (see ApplicableMethod) we can
check for an nilpotent group that indeed our new method will be used.
When testing, remember that the method selection will not check for
properties that are not known. (This is done internally by checking the
property tester first.) Therefore the method would not be applicable
for the group g in the following definition but only for the --
mathematically identical but endowed with more knowledge by GAP -- group
h. (Section Enforcing Property Tests shows a way around this.)
gap> g:=Group((1,2),(1,3)(2,4));; gap> h:=Group((1,2),(1,3)(2,4));; gap> IsNilpotentGroup(h); # enforce test true gap> HasIsNilpotentGroup(g); false gap> HasIsNilpotentGroup(h); true
Lets now look at a slightly more complicated example: We want to implement a better method for computing normalizers in a nilpotent permutation group. (Such an algorithm can be found for example in luksrakocziwright97.)
We already know IsNilpotentGroup, the filter IsPermGroup
represent the concepts of being a group of permutations.
GAP uses Normalizer to compute normalizers, however the declaration is
a bit more complicated. In the library we find
InParentFOA( "Normalizer", IsGroup, IsObject, NewAttribute );
The full mechanism of InParentFOA is described in
chapter Function-Operation-Attribute Triples of ``Extending GAP'',
however for our purposes it is sufficient to know that for such a function
the actual work is done by an operation NormalizerOp (and all the
complications are just there to be able to remember certain results) and that
the declaration of this operation is given by the first arguments, it would
be:
DeclareOperation( "NormalizerOp", [IsGroup, IsObject] );
This time we decide to enter a non-default family predicate in the call to
InstallMethod.
We could just leave it out as in the previous call;
this would yield the default value, the function ReturnTrue of arbitrary
many arguments which always returns true.
However, then the method might be called in some cases of inconsistent input
(for example matrix groups in different characteristics) that ought to fall
through the method selection to raise an error.
In our situation, we want the second group to be a subgroup of the first, so
necessarily both must have the same family and we can use IsIdenticalObj
as family predicate.
Now we can install the method. Again this manual is lazy and does not show you the actual code:
InstallMethod(NormalizerOp,"for nilpotent permutation groups",IsIdenticalObj, [IsPermGroup and IsNilpotentGroup, IsPermGroup and IsNilpotentGroup], function(G,U) [ function body omitted ] end);
GAP 4 manual