CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Path: gap4r8 / doc / ref / arith.xml
Views: 418346
1
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
2
<!-- %% -->
3
<!-- %W arith.tex GAP manual Thomas Breuer -->
4
<!-- %% -->
5
<!-- %H @(#)<M>Id: arith.tex,v 4.4 2000/01/21 13:21:28 gap Exp </M> -->
6
<!-- %% -->
7
8
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
9
<Chapter Label="An Example -- Designing Arithmetic Operations">
10
<Heading>An Example &ndash; Designing Arithmetic Operations</Heading>
11
12
In this chapter, we give a &ndash;hopefully typical&ndash;
13
example of extending &GAP; by new objects with prescribed
14
arithmetic operations (for a simple approach that may be useful
15
to get started though does not permit to exploit all potential
16
features, see also <Ref Func="ArithmeticElementCreator"/>).
17
18
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
19
<Section Label="New Arithmetic Operations vs. New Objects">
20
<Heading>New Arithmetic Operations vs. New Objects</Heading>
21
22
A usual procedure in mathematics is the definition of new operations for
23
given objects;
24
here are a few typical examples.
25
The Lie bracket defines an interesting new multiplicative
26
structure on a given (associative) algebra.
27
Forming a group ring can be viewed as defining a new addition for the
28
elements of the given group, and extending the multiplication to sums
29
of group elements in a natural way.
30
Forming the exterior algebra of a given vector space can be viewed as
31
defining a new multiplication for the vectors in a natural way.
32
<P/>
33
&GAP; does <E>not</E> support such a procedure.
34
The main reason for this is that in &GAP;, the multiplication in a group,
35
a ring etc.&nbsp;is always written as <C>*</C>,
36
and the addition in a vector space, a ring etc.&nbsp; is always written as <C>+</C>.
37
Therefore it is not possible to define the Lie bracket as a
38
<Q>second multiplication</Q> for the elements of a given algebra;
39
in fact, the multiplication in Lie algebras in &GAP; is denoted by <C>*</C>.
40
Analogously, constructing the group ring as sketched above is impossible
41
if an addition is already defined for the elements;
42
note the difference between the usual addition of matrices and the
43
addition in the group ring of a matrix group!
44
(See Chapter&nbsp;<Ref Chap="Magma Rings"/> for an example.)
45
Similarly, there is already a multiplication defined for row vectors
46
(yielding the standard scalar product), hence these vectors cannot be
47
regarded as elements of the exterior algebra of the space.
48
<P/>
49
In situations such as the ones mentioned above,
50
&GAP;'s way to deal with the structures in question is the following.
51
Instead of defining <E>new</E> operations for the <E>given</E> objects,
52
<E>new</E> objects are created to which the <E>given</E> arithmetic operations
53
<C>*</C> and <C>+</C> are then made applicable.
54
<P/>
55
With this construction, matrix Lie algebras consist of matrices that are
56
different from the matrices with associative multiplication;
57
technically, the type of a matrix determines how it is multiplied with
58
other matrices (see&nbsp;<Ref Func="IsMatrix"/>).
59
A matrix with the Lie bracket as its multiplication can be created with
60
the function <Ref Func="LieObject"/>
61
from a matrix with the usual associative multiplication.
62
<P/>
63
Group rings (more general: magma rings,
64
see Chapter&nbsp;<Ref Chap="Magma Rings"/>)
65
can be constructed with <Ref Func="FreeMagmaRing"/>
66
from a coefficient ring and a group.
67
The elements of the group are not contained in such a group ring,
68
one has to use an embedding map for creating a group ring element that
69
corresponds to a given group element.
70
<P/>
71
It should be noted that the &GAP; approach to the construction of
72
Lie algebras from associative algebras is generic in the sense
73
that all objects in the filter <Ref Filt="IsLieObject"/> use the
74
same methods for their addition, multiplication etc.,
75
by delegating to the <Q>underlying</Q> objects of the associative algebra,
76
no matter what these objects actually are.
77
Analogously, also the construction of group rings is generic.
78
79
</Section>
80
81
82
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
83
<Section Label="Designing new Multiplicative Objects">
84
<Heading>Designing new Multiplicative Objects</Heading>
85
86
The goal of this section is to implement objects with a prescribed
87
multiplication.
88
Let us assume that we are given a field <M>F</M>,
89
and that we want to define a new multiplication <M>*</M> on <M>F</M>
90
that is given by <M>a * b = a b - a - b + 2</M>;
91
here <M>a b</M> denotes the ordinary product in <M>F</M>.
92
<P/>
93
By the discussion in Section&nbsp;<Ref Sect="New Arithmetic Operations vs. New Objects"/>,
94
we know that we cannot define a new multiplication on <M>F</M> itself
95
but have to create new objects.
96
<P/>
97
We want to distinguish these new objects from all other &GAP; objects,
98
in order to describe for example the situation that two of our objects
99
shall be multiplied.
100
This distinction is made via the <E>type</E> of the objects.
101
More precisely, we declare a new <E>filter</E>, a function that will return
102
<K>true</K> for our new objects, and <K>false</K> for all other &GAP; objects.
103
This can be done by calling <Ref Func="DeclareFilter"/>,
104
but since our objects will know about the value already when they are
105
constructed, the filter can be created with
106
<Ref Func="DeclareCategory"/> or <Ref Func="NewCategory"/>.
107
<P/>
108
<Log><![CDATA[
109
DeclareCategory( "IsMyObject", IsObject );
110
]]></Log>
111
<P/>
112
The idea is that the new multiplication will be installed only
113
for objects that <Q>lie in the category <C>IsMyObject</C></Q>.
114
<P/>
115
The next question is what internal data our new objects store,
116
and how they are accessed.
117
The easiest solution is to store the <Q>underlying</Q> object from the
118
field <M>F</M>.
119
&GAP; provides two general possibilities how to store this,
120
namely record-like and list-like structures
121
(for examples, see&nbsp;<Ref Sect="Component Objects"/> and&nbsp;<Ref Sect="Positional Objects"/>).
122
We decide to store the data in a list-like structure, at position 1.
123
This <E>representation</E> is declared as follows.
124
<P/>
125
<Log><![CDATA[
126
DeclareRepresentation( "IsMyObjectListRep", IsPositionalObjectRep, [ 1 ] );
127
]]></Log>
128
<P/>
129
Of course we can argue that this declaration is superfluous
130
because <E>all</E> objects in the category <C>IsMyObject</C> will be represented
131
this way;
132
it is possible to proceed like that,
133
but often (in more complicated situations) it turns out to be useful
134
that several representations are available for <Q>the same element</Q>.
135
<P/>
136
For creating the type of our objects, we need to specify to which <E>family</E>
137
(see&nbsp;<Ref Sect="Families"/>) the objects shall belong.
138
For the moment, we need not say anything about relations to other &GAP;
139
objects,
140
thus the only requirement is that all new objects lie in the <E>same</E> family;
141
therefore we create a <E>new</E> family.
142
Also we are not interested in properties that some of our objects have
143
and others do not have,
144
thus we need only one type,
145
and store it in a global variable.
146
<P/>
147
<Log><![CDATA[
148
MyType:= NewType( NewFamily( "MyFamily" ),
149
IsMyObject and IsMyObjectListRep );
150
]]></Log>
151
<P/>
152
The next step is to write a function that creates a new object.
153
It may look as follows.
154
<Log><![CDATA[
155
MyObject:= val -> Objectify( MyType, [ Immutable( val ) ] );
156
]]></Log>
157
Note that we store an <E>immutable copy</E> of the argument in the returned
158
object;
159
without doing so, for example if the argument would be a mutable matrix
160
then the corresponding new object would be changed whenever the matrix
161
is changed
162
(see&nbsp;<Ref Sect="Mutability and Copyability"/> for more
163
details about mutability).
164
<P/>
165
Having entered the above &GAP; code, we can create some of our objects.
166
<Log><![CDATA[
167
gap> a:= MyObject( 3 ); b:= MyObject( 5 );
168
<object>
169
<object>
170
gap> a![1]; b![1];
171
3
172
5
173
]]></Log>
174
But clearly a lot is missing.
175
Besides the fact that the desired multiplication is not yet installed,
176
we see that also the way how the objects are printed is not satisfactory.
177
<P/>
178
Let us improve the latter first.
179
There are two &GAP; functions <Ref Func="View"/> and
180
<Ref Func="Print"/> for showing objects
181
on the screen.
182
<Ref Func="View"/> is thought to show a short and human
183
readable form of the object,
184
and <Ref Func="Print"/> is thought to show a not necessarily
185
short form that is &GAP; readable whenever this makes sense.
186
We decide to show <C>a</C> as <C><A>3</A></C> by
187
<Ref Func="View"/>, and to show the construction
188
<C>MyObject( 3 )</C> by <Ref Func="Print"/>;
189
the methods are installed for the underlying operations
190
<Ref Func="ViewObj"/> and
191
<Ref Func="PrintObj"/>.
192
<Log><![CDATA[
193
InstallMethod( ViewObj,
194
"for object in `IsMyObject'",
195
[ IsMyObject and IsMyObjectListRep ],
196
function( obj )
197
Print( "<", obj![1], ">" );
198
end );
199
200
InstallMethod( PrintObj,
201
"for object in `IsMyObject'",
202
[ IsMyObject and IsMyObjectListRep ],
203
function( obj )
204
Print( "MyObject( ", obj![1], " )" );
205
end );
206
]]></Log>
207
<P/>
208
This is the result of the above installations.
209
<Log><![CDATA[
210
gap> a; Print( a, "\n" );
211
<3>
212
MyObject( 3 )
213
]]></Log>
214
<P/>
215
And now we try to install the multiplication.
216
<P/>
217
<Log><![CDATA[
218
InstallMethod( \*,
219
"for two objects in `IsMyObject'",
220
[ IsMyObject and IsMyObjectListRep,
221
IsMyObject and IsMyObjectListRep ],
222
function( a, b )
223
return MyObject( a![1] * b![1] - a![1] - b![1] + 2 );
224
end );
225
]]></Log>
226
<P/>
227
When we enter the above code, &GAP; runs into an error.
228
This is due to the fact that the operation <Ref Func="\*"/>
229
is declared for two arguments that lie in the category
230
<Ref Func="IsMultiplicativeElement"/>.
231
One could circumvent the check whether the method matches the
232
declaration of the operation, by calling <Ref Func="InstallOtherMethod"/>
233
instead of <Ref Func="InstallMethod"/>.
234
But it would make sense if our objects would lie in
235
<Ref Func="IsMultiplicativeElement"/>,
236
for example because some generic methods
237
for objects with multiplication would be available then,
238
such as powering by positive integers via repeated squaring.
239
So we want that <C>IsMyObject</C> implies
240
<Ref Func="IsMultiplicativeElement"/>.
241
The easiest way to achieve such implications is to use the
242
implied filter as second argument of the <Ref Func="DeclareCategory"/> call;
243
but since we do not want to start anew,
244
we can also install the implication afterwards.
245
<P/>
246
<Log><![CDATA[
247
InstallTrueMethod( IsMultiplicativeElement, IsMyObject );
248
]]></Log>
249
<P/>
250
Afterwards, installing the multiplication works without problems.
251
Note that <C>MyType</C> and therefore also <C>a</C> and <C>b</C> are <E>not</E>
252
affected by this implication, so we construct them anew.
253
<P/>
254
<Log><![CDATA[
255
gap> MyType:= NewType( NewFamily( "MyFamily" ),
256
> IsMyObject and IsMyObjectListRep );;
257
gap> a:= MyObject( 3 );; b:= MyObject( 5 );;
258
gap> a*b; a^27;
259
<9>
260
<134217729>
261
]]></Log>
262
<P/>
263
Powering the new objects by negative integers is not possible yet,
264
because &GAP; does not know how to compute the inverse of an element <M>a</M>,
265
say, which is defined as the unique element <M>a'</M> such that both
266
<M>a a'</M> and <M>a' a</M> are <Q>the unique multiplicative neutral
267
element that belongs to <M>a</M></Q>.
268
<P/>
269
And also this neutral element, if it exists,
270
cannot be computed by &GAP; in our current situation.
271
It does, however, make sense to ask for the multiplicative neutral
272
element of a given magma, and for inverses of elements in the magma.
273
<P/>
274
But before we can form domains of our objects,
275
we must define when two objects are regarded as equal;
276
note that this is necessary in order to decide about the uniqueness
277
of neutral and inverse elements.
278
In our situation, equality is defined in the obvious way.
279
For being able to form sets of our objects,
280
also an ordering via <Ref Func="\&lt;"/> is defined for them.
281
<P/>
282
<Log><![CDATA[
283
InstallMethod( \=,
284
"for two objects in `IsMyObject'",
285
[ IsMyObject and IsMyObjectListRep,
286
IsMyObject and IsMyObjectListRep ],
287
function( a, b )
288
return a![1] = b![1];
289
end );
290
291
InstallMethod( \<,
292
"for two objects in `IsMyObject'",
293
[ IsMyObject and IsMyObjectListRep,
294
IsMyObject and IsMyObjectListRep ],
295
function( a, b )
296
return a![1] < b![1];
297
end );
298
]]></Log>
299
<P/>
300
Let us look at an example.
301
We start with finite field elements because then the domains are finite,
302
hence the generic methods for such domains will have a chance to succeed.
303
<P/>
304
<Log><![CDATA[
305
gap> a:= MyObject( Z(7) );
306
<Z(7)>
307
gap> m:= Magma( a );
308
<magma with 1 generators>
309
gap> e:= MultiplicativeNeutralElement( m );
310
<Z(7)^2>
311
gap> elms:= AsList( m );
312
[ <Z(7)>, <Z(7)^2>, <Z(7)^5> ]
313
gap> ForAll( elms, x -> ForAny( elms, y -> x*y = e and y*x = e ) );
314
true
315
gap> List( elms, x -> First( elms, y -> x*y = e and y*x = e ) );
316
[ <Z(7)^5>, <Z(7)^2>, <Z(7)> ]
317
]]></Log>
318
<P/>
319
So a multiplicative neutral element exists,
320
in fact all elements in the magma <C>m</C> are invertible.
321
But what about the following.
322
<P/>
323
<Log><![CDATA[
324
gap> b:= MyObject( Z(7)^0 ); m:= Magma( a, b );
325
<Z(7)^0>
326
<magma with 2 generators>
327
gap> elms:= AsList( m );
328
[ <Z(7)^0>, <Z(7)>, <Z(7)^2>, <Z(7)^5> ]
329
gap> e:= MultiplicativeNeutralElement( m );
330
<Z(7)^2>
331
gap> ForAll( elms, x -> ForAny( elms, y -> x*y = e and y*x = e ) );
332
false
333
gap> List( elms, x -> b * x );
334
[ <Z(7)^0>, <Z(7)^0>, <Z(7)^0>, <Z(7)^0> ]
335
]]></Log>
336
<P/>
337
Here we found a multiplicative neutral element,
338
but the element <C>b</C> does not have an inverse.
339
If an addition would be defined for our elements then we would say
340
that <C>b</C> behaves like a zero element.
341
<P/>
342
When we started to implement the new objects,
343
we said that we wanted to define the new multiplication for elements
344
of a given field <M>F</M>.
345
In principle, the current implementation would admit also something
346
like <C>MyObject( 2 ) * MyObject( Z(7) )</C>.
347
But if we decide that our initial assumption holds,
348
we may define the identity and the inverse of the object <C>&lt;a></C> as
349
<C>&lt;2*e></C> and <C>&lt;a/(a-e)></C>, respectively,
350
where <C>e</C> is the identity element in <M>F</M> and <C>/</C> denotes the division
351
in <M>F</M>;
352
note that the element <C>&lt;e></C> is not invertible,
353
and that the above definitions are determined by the multiplication
354
defined for our objects.
355
Further note that after the installations shown below,
356
also <C>One( MyObject( 1 ) )</C> is defined.
357
<P/>
358
(For technical reasons, we do not install the intended methods for
359
the attributes <Ref Func="One"/> and
360
<Ref Func="Inverse"/> but for the operations
361
<Ref Func="OneOp"/>
362
and <Ref Func="InverseOp"/>.
363
This is because for certain kinds of objects &ndash;mainly matrices&ndash;
364
one wants to support a method to compute a <E>mutable</E> identity or
365
inverse, and the attribute needs only a method that takes this
366
object, makes it immutable, and then returns this object.
367
As stated above, we only want to deal with immutable objects,
368
so this distinction is not really interesting for us.)
369
<P/>
370
A more interesting point to note is that we should mark our objects
371
as likely to be invertible,
372
since we add the possibility to invert them.
373
Again, this could have been part of the declaration of <C>IsMyObject</C>,
374
but we may also formulate an implication for the existing category.
375
<P/>
376
<Log><![CDATA[
377
InstallTrueMethod( IsMultiplicativeElementWithInverse, IsMyObject );
378
379
InstallMethod( OneOp,
380
"for an object in `IsMyObject'",
381
[ IsMyObject and IsMyObjectListRep ],
382
a -> MyObject( 2 * One( a![1] ) ) );
383
384
InstallMethod( InverseOp,
385
"for an object in `IsMyObject'",
386
[ IsMyObject and IsMyObjectListRep ],
387
a -> MyObject( a![1] / ( a![1] - One( a![1] ) ) ) );
388
]]></Log>
389
Now we can form groups of our (nonzero) elements.
390
<Log><![CDATA[
391
gap> MyType:= NewType( NewFamily( "MyFamily" ),
392
> IsMyObject and IsMyObjectListRep );;
393
gap>
394
gap> a:= MyObject( Z(7) );
395
<Z(7)>
396
gap> b:= MyObject( 0*Z(7) ); g:= Group( a, b );
397
<0*Z(7)>
398
<group with 2 generators>
399
gap> Size( g );
400
6
401
]]></Log>
402
<P/>
403
We are completely free to define an <E>addition</E> for our elements,
404
a natural one is given by <C>&lt;a> + &lt;b> = &lt;a+b-1></C>.
405
As we did for the multiplication, we first change <C>IsMyObject</C>
406
such that the additive structure is also known.
407
<Log><![CDATA[
408
InstallTrueMethod( IsAdditiveElementWithInverse, IsMyObject );
409
]]></Log>
410
Next we install the methods for the addition,
411
and those to compute the additive neutral element
412
and the additive inverse.
413
<P/>
414
<Log><![CDATA[
415
InstallMethod( \+,
416
"for two objects in `IsMyObject'",
417
[ IsMyObject and IsMyObjectListRep,
418
IsMyObject and IsMyObjectListRep ],
419
function( a, b )
420
return MyObject( a![1] + b![1] - 1 );
421
end );
422
423
InstallMethod( ZeroOp,
424
"for an object in `IsMyObject'",
425
[ IsMyObject and IsMyObjectListRep ],
426
a -> MyObject( One( a![1] ) ) );
427
428
InstallMethod( AdditiveInverseOp,
429
"for an object in `IsMyObject'",
430
[ IsMyObject and IsMyObjectListRep ],
431
a -> MyObject( a![1] / ( a![1] - One( a![1] ) ) ) );
432
]]></Log>
433
<P/>
434
Let us try whether the addition works.
435
<P/>
436
<Log><![CDATA[
437
gap> MyType:= NewType( NewFamily( "MyFamily" ),
438
> IsMyObject and IsMyObjectListRep );;
439
gap> a:= MyObject( Z(7) );; b:= MyObject( 0*Z(7) );;
440
gap> m:= AdditiveMagma( a, b );
441
<additive magma with 2 generators>
442
gap> Size( m );
443
7
444
]]></Log>
445
<P/>
446
Similar as installing a multiplication automatically makes
447
powering by integers available,
448
multiplication with integers becomes available with the addition.
449
<P/>
450
<Log><![CDATA[
451
gap> 2 * a;
452
<Z(7)^5>
453
gap> a+a;
454
<Z(7)^5>
455
gap> MyObject( 2*Z(7)^0 ) * a;
456
<Z(7)>
457
]]></Log>
458
<P/>
459
In particular we see that this multiplication does <E>not</E> coincide
460
with the multiplication of two of our objects,
461
that is, an integer <E>cannot</E> be used as a shorthand for one of the
462
new objects in a multiplication.
463
<P/>
464
(It should be possible to create a <E>field</E> with the new multiplication
465
and addition.
466
Currently this fails, due to missing methods for computing
467
several kinds of generators from field generators,
468
for computing the characteristic in the case that the family does not
469
know this in advance,
470
for checking with <Ref Func="AsField"/> whether a domain
471
is in fact a field, for computing the closure as a field.)
472
<P/>
473
It should be emphasized that the mechanism described above may be not
474
suitable for the situation that one wants to consider many different
475
multiplications <Q>on the same set of objects</Q>,
476
since the installation of a new multiplication requires the declaration
477
of at least one new filter and the installation of several methods.
478
But the design of &GAP; is not suitable for such dynamic method
479
installations.
480
<P/>
481
Turning this argument the other way round,
482
the implementation of the new arithmetics defined by the above
483
multiplication and addition is available for any field <M>F</M>,
484
one need not repeat it for each field one is interested in.
485
<P/>
486
Similar to the above situation,
487
the construction of a magma ring <M>RM</M> from a coefficient ring <M>R</M>
488
and a magma <M>M</M> is implemented only once,
489
since the definition of the arithmetic operations depends only on the
490
given multiplication of <M>M</M> and not on <M>M</M> itself.
491
So the addition is not implemented for the elements in <M>M</M> or
492
&ndash;more precisely&ndash; for an isomorphic copy.
493
In some sense, the addition is installed <Q>for the multiplication</Q>,
494
and as mentioned in Section&nbsp;<Ref Sect="New Arithmetic Operations vs. New Objects"/>,
495
there is only one multiplication <Ref Func="\*"/> in &GAP;.
496
497
</Section>
498
</Chapter>
499
500
501
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
502
<!-- %% -->
503
<!-- %E -->
504
505
506