1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%W foa.tex GAP documentation Heiko Thei\3en
%%
%H @(#)$Id: foa.tex,v 4.20 2002/10/09 12:32:13 gap Exp $
%%
%Y Copyright 1997, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
%%
\Chapter{Function-Operation-Attribute Triples}
{\GAP} is eager to maintain information that it has gathered about an
object, possibly by lengthy calculations. The most important mechanism
for information maintenance is the automatic storage and look-up that
takes place for *attributes*; and this was already mentioned in
section~"tut:Attributes" in the tutorial. In this chapter we will
describe further mechanisms that allow storage of results that are not
values of attributes.
\index{FOA triples}
The idea which is common to all sections is that certain operations,
which are not themselves attributes, have an attribute associated with
them. To automatically delegate tasks to the attribute, {\GAP} knows, in
addition to the *operation* and the *attributes* also a
*function*, which is ``wrapped around'' the other two. This ``wrapper
function'' is called by the user and decides whether to call the
operation or the attribute or possibly both. The whole
*f*unction-*o*peration-*a*ttribute triple (or *FOA triple*) is set up by
a single {\GAP} command which writes the wrapper function and already
installs some methods, e.g., for the attribute to fall back on the
operation. The idea is then that subsequent methods, which perform the
actual computation, are installed only for the operation, whereas the
wrapper function remains unaltered, and in general no additional methods
for the attribute are required either.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Key Dependent Operations}
% see the text in the declaration of `KeyDependentOperation';
% eventually one would like to use the manual builder also for the `ext'
% manual
There are several functions that require as first argument a domain,
e.g., a group, and as second argument something much simpler, e.g., a
prime. `SylowSubgroup' is an example.
Since its value depends on two arguments, it cannot be an attribute,
yet one would like to store Sylow subgroups once they have been computed.
The idea is to provide an attribute of the group,
called `ComputedSylowSubgroups', and to store the groups in this list.
The name implies that the value of this attribute may change in the course
of a {\GAP} session,
whenever a newly-computed Sylow subgroup is put into the list.
Therefore, this is a *mutable attribute*
(see~"prg:Creating Attributes and Properties" in ``Programming in GAP'').
The list contains primes in each bound odd position and a corresponding
Sylow subgroup in the following even position.
More precisely, if `<p> = ComputedSylowSubgroups( <G> )[ <even> - 1 ]'
then `ComputedSylowSubgroups( <G> )[ <even> ]' holds the value
of `SylowSubgroup( <G>, <p> )'.
The pairs are sorted in increasing order of <p>,
in particular at most one Sylow <p> subgroup of <G> is stored for each
prime <p>.
This attribute value is maintained by the operation `SylowSubgroup',
which calls the operation `SylowSubgroupOp( <G>, <p> )' to do the real
work, if the prime <p> cannot be found in the list.
So methods that do the real work should be installed for `SylowSubgroupOp'
and not for `SylowSubgroup'.
The same mechanism works for other functions as well, e.g., for `PCore',
but also for `HallSubgroup',
where the second argument is not a prime but a set of primes.
\>KeyDependentOperation( <name>, <dom-req>, <key-req>, <key-test> )
declares at the same time all three: two operations with names <name>
and `<name>Op', respectively, and an attribute with name
and the attribute as described above,
with names <name>, `<name>Op', and `Computed<name>s'.
<dom-req> and <key-req> specify the required filters for the first and
second argument of the operation `<name>Op',
which are needed to create this operation with `NewOperation'
(see~"prg:NewOperation").
<dom-req> is also the required filter for the corresponding attribute
`Computed<name>s'.
The fourth argument <key-test> is in general a function to which the second
argument <info> of `<name>( <D>, <info> )' will be passed.
This function can perform tests on <info>,
and raise an error if appropriate.
For example, to set up the three objects `SylowSubgroup', `SylowSubgroupOp',
and `ComputedSylowSubgroups' together,
the declaration file ``lib/grp.gd'' contains the following line of code.
\begintt
KeyDependentOperation( "SylowSubgroup", IsGroup, IsPosInt, "prime" );
\endtt
In this example, <key-test> has the value `"prime"',
which is silently replaced by a function that tests whether its argument
is a prime.
\beginexample
gap> s4 := Group((1,2,3,4),(1,2));;
gap> SylowSubgroup( s4, 5 );; ComputedSylowSubgroups( s4 );
[ 5, Group(()) ]
gap> SylowSubgroup( s4, 2 );; ComputedSylowSubgroups( s4 );
[ 2, Group([ (3,4), (1,4)(2,3), (1,3)(2,4) ]), 5, Group(()) ]
\endexample
%notest
\beginexample
gap> SylowSubgroup( s4, 6 );
Error, SylowSubgroup: <p> must be a prime called from
<compiled or corrupted call value> called from
<function>( <arguments> ) called from read-eval-loop
Entering break read-eval-print loop ...
you can 'quit;' to quit to outer loop, or
you can 'return;' to continue
brk> quit;
\endexample
Thus the prime test need not be repeated in the methods for the operation
`SylowSubgroupOp' (which are installed to do the real work).
Note that no methods need be installed for `SylowSubgroup' and
`ComputedSylowSubgroups'.
If a method is installed with `InstallMethod' for a wrapper operation
such as `SylowSubgroup' then a warning is signalled
provided the `InfoWarning' level is at least 1.
(Use `InstallOtherMethod' in order to suppress the warning.)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{In Parent Attributes}
This section describes how you can add new ``in parent attributes''
(see~"ref:Constructing Subdomains" and "ref:Parents" in the Reference Manual).
As an example, we describe how `Index' and its related functions
are implemented.
There are two operations `Index' and `IndexOp',
and an attribute `IndexInParent'.
They are created together as shown below,
and after they have been created,
methods need be installed only for `IndexOp'.
In the creation process, `IndexInParent' already gets one default method
installed
(in addition to the usual system getter of each attribute,
see~"ref:Attributes" in the Reference Manual),
namely `D -> IndexOp( Parent( D ), D )'.
The operation `Index' proceeds as follows.
\beginlist%unordered
\item{$\bullet$}
If it is called with the two arguments <super> and <sub>, and if
`HasParent( <sub> )' and `IsIdenticalObj( <super>, Parent( <sub> ) )'
are `true', `IndexInParent' is called with argument <sub>,
and the result is returned.
\item{$\bullet$}
Otherwise, `IndexOp' is called with the same arguments that `Index' was
called with, and the result is returned.
\endlist
(Note that it is in principle possible to install even `Index' and
`IndexOp' methods for a number of arguments different from two,
with `InstallOtherMethod',
see~"prg:Creating Attributes and Properties" in ``Programming in GAP'').
\>InParentFOA( <name>, <super-req>, <sub-req>, DeclareAttribute )
\>InParentFOA( <name>, <super-req>, <sub-req>, DeclareProperty )
declares the operations and the attribute as described above,
with names <name>, `<name>Op', and `<name>InParent'.
<super-req> and <sub-req> specify the required filters for the first and
second argument of the operation `<name>Op',
which are needed to create this operation with `NewOperation'
(see~"prg:NewOperation").
<sub-req> is also the required filter for the corresponding attribute
`<name>InParent';
note that `HasParent' is *not* required for the argument <U> of
`<name>InParent', because even without a parent stored,
`Parent( <U> )' is legal, meaning <U> itself
(see~"ref:Parents" in the Reference Manual).
The fourth argument is `DeclareProperty' if `<name>InParent' takes only
boolean values (for example in the case `IsNormalInParent'),
and `DeclareAttribute' otherwise.
For example, to set up the three objects `Index', `IndexOp',
and `IndexInParent' together,
the declaration file ``lib/domain.gd'' contains the following line of code.
\begintt
InParentFOA( "Index", IsGroup, IsGroup, DeclareAttribute );
\endtt
Note that no methods need be installed for `Index' and `IndexInParent'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Operation Functions}
\indextt{ExternalSet}\atindex{G-sets}{@$G$-sets}\indextt{Orbits}
Chapter~"ref:Group Actions" of the Reference Manual
and, in particular, the Section~"ref:About Group Actions"
% currently in `abattoir/group.tex', `abattoir/permgrp.tex',
% `abattoir/solvgrp.tex' ...
explain that certain operations such as `Orbits' (see~"ref:Orbits"),
besides their usual usage with arguments <G>, <D>, and <opr>,
can also be applied to an external set ($G$-set),
in which case they can be interpreted as attributes.
Moreover, they can also be interpreted as attributes for permutation
group, meaning the natural action on the set of its moved points.
The definition of `Orbits' says that a method should be a function
with arguments <G>, <D>, <gens>, <oprs>, and <opr>,
as in the case of the operation `ExternalSet' when specified via <gens>
and <oprs> (see~"ref:External Sets" in the Reference Manual).
All other syntax variants allowed for `Orbits' (e.g., leaving
out <gens> and <oprs>) are handled by default methods.
The default methods for `Orbits' support the following behaviour.
\beginlist%ordered
\item{1.}
If the only argument is an external set <xset> and the attribute
tester `HasOrbits( <xset> )' returns `true',
the stored value of that attribute is returned.
\item{2.}
If the only argument is an external set <xset> and the attribute
value is not known,
the default arguments are obtained from the data of <xset>.
\item{3.}
If <gens> and <oprs> are not specified,
<gens> is set to `Pcgs( <G> )' if `CanEasilyComputePcgs( <G> )'
is `true', and to `GeneratorsOfGroup( <G> )' otherwise;
<oprs> is set to <gens>.
\item{4.}
The default value of <opr> is `OnPoints'.
\item{5.}
In the case of an operation of a permutation group <G>
on `MovedPoints( <G> )' via `OnPoints',
if the attribute tester `HasOrbits( <G> )' returns `true',
the stored attribute value is returned.
\item{6.}
The operation is called as `<result>:= Orbits( <G>, <D>, <gens>,
<oprs>, <opr> )'.
\item{7.}
In the case of an external set <xset> or a permutation group <G> in its
natural action, the attribute setter is called to store <result>.
\item{8.}
<result> is returned.
\endlist
The declaration of operations that match the above pattern is done
as follows.
\>OrbitsishOperation( <name>, <reqs>, <usetype>, NewAttribute ) F
\>OrbitsishOperation( <name>, <reqs>, <usetype>, NewProperty ) F
declares an attribute <op> as described above, with name <name>.
The second argument <reqs> specifies the list of required filters
for the usual (five-argument) methods that do the real work.
If the third argument <usetype> is `true',
the function call `<op>( <xset> )' will
--- if the value of <op> for <xset> is not yet known ---
delegate to the five-argument call of <op> with second argument <xset>
rather than with <D> (cf.~step~6 above).
This allows certain methods for <op> to make use of the type of <xset>,
in which the types of the external subsets of <xset>
and of the external orbits in <xset> are stored.
(This is used to avoid repeated calls of `NewType' in functions like
`ExternalOrbits( <xset> )',
which call `ExternalOrbit( <xset>, <pnt> )' for several values of~<pnt>.)
For property testing functions such as `IsTransitive',
the fourth argument is `NewProperty',
otherwise it is `NewAttribute'.
For example, to set up the operation `Orbits',
the declaration file ``lib/oprt.gd'' contains the following line of code:
\begintt
OrbitsishOperation( "Orbits", OrbitsishReq, false, NewAttribute );
\endtt
The variable `OrbitsishReq' contains the standard requirements
\begintt
OrbitsishReq := [ IsGroup, IsList,
IsList,
IsList,
IsFunction ];
\endtt
which are usually entered in calls to `OrbitsishOperation'.
A similar mechanism is provided for operations such as `Orbit' that do
not have an associated attribute but still need a wrapper function to
standardize the arguments for the associated operation.
\>OrbitishFO( <name>, <reqs>, <famrel>, <usetype> ) F
declares a wrapper function and its operation,
with names <name> and `<name>Op'.
The second argument <reqs> specifies the list of required filters for the
operation `<name>Op'.
The third argument <famrel> is used to test the family relation between
the second and third argument of `<name>( <G>, <D>, <elm> )'.
For example, in the call `Orbit( <G>, <D>, <pnt> )',
<pnt> must be an element of <D>, so `<famrel> = IsCollsElms' is
appropriate, and in the call `Blocks( <G>, <D>, <seed> )',
<seed> must be a subset of <D>,
and the family relation is `IsIdenticalObj'.
The fourth argument <usetype> serves the same purpose as in the case of
`OrbitsishOperation'.
For example, to setup the function `Orbit' and its operation `OrbitOp',
the declaration file ``lib/oprt.gd'' contains the following line of code:
\begintt
OrbitishFO( "Orbit", OrbitishReq, IsCollsElms, false );
\endtt
The variable `OrbitishReq' contains the standard requirements
\begintt
OrbitishReq := [ IsGroup, IsList, IsObject,
IsList,
IsList,
IsFunction ];
\endtt
which are usually entered in calls to `OrbitishFO'.
The relation test via <famrel> is used to provide a uniform construction
of the wrapper functions created by `OrbitishFO',
in spite of the different syntax of the specific functions.
For example, `Orbit' admits the calls `Orbit( <G>, <D>, <pnt>, <opr> )'
and `Orbit( <G>, <pnt>, <opr> )', i.e., the second argument <D> may be
omitted;
`Blocks' admits the calls `Blocks( <G>, <D>, <seed>, <opr> )' and
`Blocks( <G>, <D>, <opr> )', i.e., the third argument may be omitted.
The translation to the appropriate call of `OrbitOp' or `BlocksOp',
for either operation with five or six arguments,
is handled via <famrel>.
As a consequence, there must not only be methods for `OrbitOp' with
the six arguments corresponding to `OrbitishReq',
but also methods for only five arguments (i.e., without <D>).
Plenty of examples are contained in the implementation file ``lib/oprt.gi''.
In order to handle a few special cases
(currently `Blocks' and `MaximalBlocks'),
also the following form is supported.
\)OrbitishFO( <name>, <reqs>, <famrel>, <attr> ) F
The functions in question depend upon an argument <seed>,
so they cannot be regarded as attributes.
However, they are most often called without giving <seed>,
meaning ``choose any minimal resp.\ maximal block system''.
In this case, the result can be stored as the value of the attribute
<attr> that was entered as fourth argument of `OrbitishFO'.
This attribute is considered by a call `Blocks( <G>, <D>, <opr> )'
(i.e., without <seed>) in the same way as `Orbits' considers `OrbitsAttr'.
To set this up, the declaration file ``lib/oprt.gd'' contains the following
lines:
\begintt
DeclareAttribute( "BlocksAttr", IsExternalSet );
OrbitishFO( "Blocks",
[ IsGroup, IsList, IsList,
IsList,
IsList,
IsFunction ], IsIdenticalObj, BlocksAttr );
\endtt
And this extraordinary FOA triple works as follows:
\beginexample
gap> s4 := Group((1,2,3,4),(1,2));; Blocks( s4, MovedPoints(s4), [1,2] );
[ [ 1, 2, 3, 4 ] ]
gap> Tester( BlocksAttr )( s4 );
false
\endexample
\beginexample
gap> Blocks( s4, MovedPoints(s4) );
[ [ 1, 2, 3, 4 ] ]
gap> Tester( BlocksAttr )( s4 ); BlocksAttr( s4 );
true
[ [ 1, 2, 3, 4 ] ]
\endexample
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%E
|