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

Views: 418346
1
<Chapter Label="Objects">
2
<Heading>Implementing circle objects</Heading>
3
4
In this chapter we explain how the &GAP; system may be extended
5
with new objects using the circle multiplication as an example.
6
We follow the guidelines given in the &GAP; Reference Manual
7
(see <Ref Chap="Creating New Objects" BookName="ref"/> and subsequent
8
chapters), to which we refer for more details.
9
10
<Section Label="ObjectsFirst">
11
<Heading>First attempts</Heading>
12
13
Of course, having two ring elements, you can straightforwardly compute
14
their circle product defined as <M> r \cdot s = r + s + rs </M>. You can
15
do this in a command line, and it is a trivial task to write a simplest
16
function of two arguments that will do this:
17
18
<Example>
19
<![CDATA[
20
gap> CircleMultiplication := function(a,b)
21
> return a+b+a*b;
22
> end;
23
function( a, b ) ... end
24
gap> CircleMultiplication(2,3);
25
11
26
gap> CircleMultiplication( ZmodnZObj(2,8), ZmodnZObj(5,8) );
27
ZmodnZObj( 1, 8 )
28
]]>
29
</Example>
30
31
However, there is no check whether both arguments belong to the
32
same ring and whether they are ring elements at all, so it is easy
33
to obtain some meaningless results:
34
35
<Example>
36
<![CDATA[
37
gap> CircleMultiplication( 3, ZmodnZObj(3,8) );
38
ZmodnZObj( 7, 8 )
39
gap> CircleMultiplication( [1], [2,3] );
40
[ 5, 5 ]
41
]]>
42
</Example>
43
44
You can include some tests for arguments, and maybe the best way of
45
doing this would be declaring a new operation for two ring elements,
46
and installing the previous function as a method for this operation.
47
This will check automatically if the arguments are ring elements from
48
the common ring:
49
50
<Example>
51
<![CDATA[
52
gap> DeclareOperation( "BetterCircleMultiplication",
53
> [IsRingElement,IsRingElement] );
54
gap> InstallMethod( BetterCircleMultiplication,
55
> IsIdenticalObj,
56
> [IsRingElement,IsRingElement],
57
> CircleMultiplication );
58
gap> BetterCircleMultiplication(2,3);
59
11
60
gap> BetterCircleMultiplication( ZmodnZObj(2,8), ZmodnZObj(5,8) );
61
ZmodnZObj( 1, 8 )
62
]]>
63
</Example>
64
65
Nevertheless, the functionality gained from such operation would be rather
66
limited. You will not be able to compute circle product via the infix
67
operator <C>*</C>, and, moreover, you will not be able to create higher
68
level objects such as semigroups and groups with respect to the circle
69
multiplication.<P/>
70
71
In order to "integrate" the circle multiplication into the &GAP; library
72
properly, instead of defining <E>new</E> operations for existing objects,
73
we should define <E>new</E> objects for which the infix operator <C>*</C>
74
will perform the circle multiplication. This approach is explained in the
75
next two sections.
76
77
</Section>
78
79
<Section Label="ObjectsDefining">
80
<Heading>Defining circle objects</Heading>
81
82
Thus, we are going to implement <E>circle objects</E>,
83
for which we can envisage the following functionality:
84
85
<Example>
86
<![CDATA[
87
gap> CircleObject( 2 ) * CircleObject( 3 );
88
CircleObject( 11 )
89
]]>
90
</Example>
91
92
First we need to distinguish these new objects from other &GAP; objects.
93
This is done via the <E>type</E> of the objects, that is mainly determined
94
by their <E>category</E>, <E>representation</E> and <E>family</E>.
95
<P/>
96
97
We start with declaring the category <C>IsCircleObject</C> as a subcategory
98
of <C>IsAssociativeElement></C> and <C>IsMultiplicativeElementWithInverse</C>.
99
Thus, each circle object will "know" that it is <C>IsAssociativeElement</C>
100
and <C>IsMultiplicativeElementWithInverse</C>, and this will make it possible
101
to apply to circle objects such operations as <C>One</C> and <C>Inverse</C>
102
(the latter is allowed to return <K>fail</K> for a given circle object), and
103
construct semigroups generated by circle objects.
104
<P/>
105
106
<Example>
107
<![CDATA[
108
gap> DeclareCategory( "IsMyCircleObject",
109
> IsAssociativeElement and IsMultiplicativeElementWithInverse );
110
]]>
111
</Example>
112
113
Further we would like to create semigroups and groups generated by circle
114
objects. Such structures will be <E>collections</E> of circle objects, so
115
they will be in the category <C>CategoryCollections( IsCircleObject )</C>.
116
This is why immediately after we declare the underlying category of circle
117
objects, we need also to declare the category of their collections:
118
119
<Example>
120
<![CDATA[
121
gap> DeclareCategoryCollections( "IsMyCircleObject" );
122
]]>
123
</Example>
124
125
On the next step we should think about the internal representation of
126
circle objects. A natural way would be to store the underlying ring element
127
in a list-like structure at its first position. We do not foresee any other
128
data that we need to store internally in the circle object. This is quite
129
common situation, so we may define first <C>IsPositionalObjectOneSlotRep</C>
130
that is the list-like representation with only one position in the list, and
131
then declare a synonym <C>IsDefaultCircleObject</C> that means that we are
132
dealing with a circle object in one-slot representation:
133
134
<Example>
135
<![CDATA[
136
gap> DeclareRepresentation( "IsMyPositionalObjectOneSlotRep",
137
> IsPositionalObjectRep, [ 1 ] );
138
gap> DeclareSynonym( "IsMyDefaultCircleObject",
139
> IsMyCircleObject and IsMyPositionalObjectOneSlotRep );
140
]]>
141
</Example>
142
143
Until now we are still unable to create circle objects, because we did not
144
specify to which family they will belong. Naturally, having a ring, we want
145
to have all circle objects for elements of this ring in the same family to
146
be able to multiply them, and we expect circle objects for elements of
147
different rings to be placed in different families. Thus, it would be nice
148
to establish one-to-one correspondence between the family of ring elements
149
and a family of circle elements for this ring. We can store the corresponding
150
circle family as an attribute of the ring elements family. To do this first
151
we declare an attribute <C>CircleFamily</C> for families:
152
153
<Example>
154
<![CDATA[
155
gap> DeclareAttribute( "MyCircleFamily", IsFamily );
156
]]>
157
</Example>
158
159
Now we install the method that stores the corresponding
160
circle family in this attribute:
161
162
<Example>
163
<![CDATA[
164
gap> InstallMethod( MyCircleFamily,
165
> "for a family",
166
> [ IsFamily ],
167
> function( Fam )
168
> local F;
169
> # create the family of circle elements
170
> F:= NewFamily( "MyCircleFamily(...)", IsMyCircleObject );
171
> if HasCharacteristic( Fam ) then
172
> SetCharacteristic( F, Characteristic( Fam ) );
173
> fi;
174
> # store the type of objects in the output
175
> F!.MyCircleType:= NewType( F, IsMyDefaultCircleObject );
176
> # Return the circle family
177
> return F;
178
> end );
179
]]>
180
</Example>
181
182
Similarly, we want one-to-one correspondence between
183
circle elements and underlying ring elements. We declare
184
an attribute <C>CircleObject</C> for a ring element,
185
and then install the method to create new circle object from
186
the ring element. This method takes the family of the
187
ring element, finds corresponding circle family, extracts
188
from it the type of circle objects and finally creates the
189
new circle object of that type:
190
191
<Example>
192
<![CDATA[
193
gap> DeclareAttribute( "MyCircleObject", IsRingElement );
194
gap> InstallMethod( MyCircleObject,
195
> "for a ring element",
196
> [ IsRingElement ],
197
> obj -> Objectify( MyCircleFamily( FamilyObj( obj ) )!.MyCircleType,
198
> [ Immutable( obj ) ] ) );
199
]]>
200
</Example>
201
202
Only after entering all code above we are able to create some circle object.
203
However, it is displayed just as <C>&lt;object&gt;</C>, though we can get
204
the underlying ring element using the "!" operator:
205
206
<Example>
207
<![CDATA[
208
gap> a:=MyCircleObject(2);
209
<object>
210
gap> a![1];
211
2
212
]]>
213
</Example>
214
215
We can check that the intended relation between families holds:
216
<P/>
217
218
<Example>
219
<![CDATA[
220
gap> FamilyObj( MyCircleObject ( 2 ) ) = MyCircleFamily( FamilyObj( 2 ) );
221
true
222
]]>
223
</Example>
224
225
We can not multiply circle objects yet. But before implementing this,
226
first let us improve the output by installing the method for <C>PrintObj</C>:
227
228
<Example>
229
<![CDATA[
230
gap> InstallMethod( PrintObj,
231
> "for object in `IsMyCircleObject'",
232
> [ IsMyDefaultCircleObject ],
233
> function( obj )
234
> Print( "MyCircleObject( ", obj![1], " )" );
235
> end );
236
]]>
237
</Example>
238
239
This method will be used by <C>Print</C> function, and also
240
by <C>View</C>, since we did not install special method for
241
<C>ViewObj</C> for circle objects. As a result of this installation,
242
the output became more meaningful:
243
244
<Example>
245
<![CDATA[
246
gap> a;
247
MyCircleObject( 2 )
248
]]>
249
</Example>
250
251
We need to avoid the usage of "!" operator, which, in general, is not
252
recommended to the user (for example, if &GAP; developers will
253
change the internal representation of some object, all &GAP; functions
254
that deal with it must be adjusted appropriately, while if the user's code
255
had direct access to that representation via "!", an error may occur).
256
To do this, we wrap getting the first component of a circle object
257
in the following operation:
258
259
<Example>
260
<![CDATA[
261
gap> DeclareAttribute("UnderlyingRingElement", IsMyCircleObject );
262
gap> InstallMethod( UnderlyingRingElement,
263
> "for a circle object",
264
> [ IsMyCircleObject],
265
> obj -> obj![1] );
266
gap> UnderlyingRingElement(a);
267
2
268
]]>
269
</Example>
270
271
</Section>
272
273
<Section Label="ObjectsOperations">
274
<Heading>Installing operations for circle objects</Heading>
275
276
Now we are finally able to install circle multiplication as a default
277
method for the multiplication of circle objects, and perform the
278
computation that we envisaged in the beginning:
279
280
<Example>
281
<![CDATA[
282
gap> InstallMethod( \*,
283
> "for two objects in `IsMyCircleObject'",
284
> IsIdenticalObj,
285
> [ IsMyDefaultCircleObject, IsMyDefaultCircleObject ],
286
> function( a, b )
287
> return MyCircleObject( a![1] + b![1] + a![1]*b![1] );
288
> end );
289
gap> MyCircleObject(2)*MyCircleObject(3);
290
MyCircleObject( 11 )
291
]]>
292
</Example>
293
294
However, this functionality is not enough to form semigroups or groups
295
generated by circle elements. We need to be able to check whether two
296
circle objects are equal, and we need to define ordering for them (for
297
example, to be able to form sets of circle elements). Since we already
298
have both operations for underlying ring elements, this can be implemented
299
in a straightforward way:
300
301
<Example>
302
<![CDATA[
303
gap> InstallMethod( \=,
304
> "for two objects in `IsMyCircleObject'",
305
> IsIdenticalObj,
306
> [ IsMyDefaultCircleObject, IsMyDefaultCircleObject ],
307
> function( a, b )
308
> return a![1] = b![1];
309
> end );
310
gap> InstallMethod( \<,
311
> "for two objects in `IsMyCircleObject'",
312
> IsIdenticalObj,
313
> [ IsMyDefaultCircleObject, IsMyDefaultCircleObject ],
314
> function( a, b )
315
> return a![1] < b![1];
316
> end );
317
]]>
318
</Example>
319
320
Further, zero element of the ring plays a role of the neutral element
321
for the circle multiplication, and we add this knowledge to our code
322
in a form of a method for <C>OneOp</C> that returns circle object
323
for the corresponding zero object:
324
325
<Example>
326
<![CDATA[
327
gap> InstallMethod( OneOp,
328
> "for an object in `IsMyCircleObject'",
329
> [ IsMyDefaultCircleObject ],
330
> a -> MyCircleObject( Zero( a![1] ) ) );
331
gap> One(a);
332
MyCircleObject( 0 )
333
]]>
334
</Example>
335
336
Now we are already able to create monoids generated by circle objects:
337
338
<Example>
339
<![CDATA[
340
gap> S:=Monoid(a);
341
<commutative monoid with 1 generator>
342
gap> One(S);
343
MyCircleObject( 0 )
344
gap> S:=Monoid( MyCircleObject( ZmodnZObj( 2,8) ) );
345
<commutative monoid with 1 generator>
346
gap> Size(S);
347
2
348
gap> AsList(S);
349
[ MyCircleObject( ZmodnZObj( 0, 8 ) ), MyCircleObject( ZmodnZObj( 2, 8 ) ) ]
350
]]>
351
</Example>
352
353
Finally, to generate groups using circle objects, we need to add a method
354
for the <C>InverseOp</C>. In our implementation we will assume that the
355
underlying ring is a subring of the ring with one, thus, if the circle
356
inverse for an element <M>x</M> exists, than it can be computed as
357
<M>-x(1+x)^{-1}</M>:
358
359
<Example>
360
<![CDATA[
361
gap> InstallMethod( InverseOp,
362
> "for an object in `IsMyCircleObject'",
363
> [ IsMyDefaultCircleObject ],
364
> function( a )
365
> local x;
366
> x := Inverse( One( a![1] ) + a![1] );
367
> if x = fail then
368
> return fail;
369
> else
370
> return MyCircleObject( -a![1] * x );
371
> fi;
372
> end );
373
gap> MyCircleObject(-2)^-1;
374
MyCircleObject( -2 )
375
gap> MyCircleObject(2)^-1;
376
MyCircleObject( -2/3 )
377
]]>
378
</Example>
379
380
The last method already makes it possible to create groups generated by
381
circle objects (the warning may be ignored):
382
383
<Example>
384
<![CDATA[
385
gap> Group( MyCircleObject(2) );
386
#I default `IsGeneratorsOfMagmaWithInverses' method returns `true' for
387
[ MyCircleObject( 2 ) ]
388
<group with 1 generators>
389
gap> G:=Group( [MyCircleObject( ZmodnZObj( 2,8 ) ) ]);
390
#I default `IsGeneratorsOfMagmaWithInverses' method returns `true' for
391
[ MyCircleObject( ZmodnZObj( 2, 8 ) ) ]
392
<group with 1 generators>
393
gap> Size(G);
394
2
395
gap> AsList(G);
396
[ MyCircleObject( ZmodnZObj( 0, 8 ) ), MyCircleObject( ZmodnZObj( 2, 8 ) ) ]
397
]]>
398
</Example>
399
400
The &GAP; code used in this Chapter, is contained in the files
401
<File>circle/lib/circle.gd</File> and <File>circle/lib/circle.gi</File>
402
(without <C>My</C> in identifiers).
403
For more examples of implementing new &GAP; objects and further details
404
see <Ref Chap="Creating New Objects" BookName="ref"/> and subsequent
405
chapters in the &GAP; Reference Manual.
406
407
</Section>
408
409
</Chapter>
410