Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/libs/gap/element.pyx
8815 views
1
"""
2
libGAP element wrapper
3
4
This document describes the individual wrappers for various GAP
5
elements. For general information about libGAP, you should read the
6
:mod:`~sage.libs.gap.libgap` module documentation.
7
"""
8
9
###############################################################################
10
# Copyright (C) 2012, Volker Braun <[email protected]>
11
#
12
# Distributed under the terms of the GNU General Public License (GPL)
13
# as published by the Free Software Foundation; either version 2 of
14
# the License, or (at your option) any later version.
15
# http://www.gnu.org/licenses/
16
###############################################################################
17
18
from cpython.object cimport *
19
20
from sage.structure.sage_object cimport SageObject
21
from sage.structure.parent import Parent
22
from sage.rings.all import ZZ
23
24
decode_type_number = {
25
libGAP_T_INT: 'T_INT (integer)',
26
libGAP_T_INTPOS: 'T_INTPOS (positive integer)',
27
libGAP_T_INTNEG: 'T_INTNEG (negative integer)',
28
libGAP_T_RAT: 'T_RAT (rational number)',
29
libGAP_T_CYC: 'T_CYC (universal cylotomic)',
30
libGAP_T_FFE: 'T_FFE (finite field element)',
31
libGAP_T_PERM2: 'T_PERM2',
32
libGAP_T_PERM4: 'T_PERM4',
33
libGAP_T_BOOL: 'T_BOOL',
34
libGAP_T_CHAR: 'T_CHAR',
35
libGAP_T_FUNCTION: 'T_FUNCTION',
36
libGAP_T_PLIST: 'T_PLIST',
37
libGAP_T_PLIST_CYC: 'T_PLIST_CYC',
38
libGAP_T_BLIST: 'T_BLIST',
39
libGAP_T_STRING: 'T_STRING',
40
libGAP_T_MACFLOAT: 'T_MACFLOAT (hardware floating point number)',
41
libGAP_T_COMOBJ: 'T_COMOBJ (component object)',
42
libGAP_T_POSOBJ: 'T_POSOBJ (positional object)',
43
libGAP_T_DATOBJ: 'T_DATOBJ (data object)',
44
libGAP_T_WPOBJ: 'T_WPOBJ (weak pointer object)',
45
}
46
47
############################################################################
48
### helper functions to construct lists and records ########################
49
############################################################################
50
51
cdef libGAP_Obj make_gap_list(sage_list):
52
"""
53
Convert Sage lists into Gap lists
54
55
INPUT:
56
57
- ``a`` -- list of :class:`GapElement`.
58
59
OUTPUT:
60
61
The list of the elements in ``a`` as a Gap ``Obj``.
62
"""
63
# FIXME slow -- to make fast directly use ADD_LIST in Gap's C code.
64
from sage.libs.gap.libgap import libgap
65
cdef GapElement l = libgap.eval('[]')
66
for x in sage_list:
67
l.Add(x)
68
return l.value
69
70
71
cdef libGAP_Obj make_gap_record(sage_dict):
72
"""
73
Convert Sage lists into Gap lists
74
75
INPUT:
76
77
- ``a`` -- list of :class:`GapElement`.
78
79
OUTPUT:
80
81
The list of the elements in ``a`` as a Gap ``Obj``.
82
83
TESTS::
84
85
sage: libgap({'a': 1, 'b':123}) # indirect doctest
86
rec( a := 1, b := 123 )
87
"""
88
from sage.libs.gap.libgap import libgap
89
data = [ (str(key), libgap(value)) for key, value in sage_dict.iteritems() ]
90
91
libgap_enter()
92
cdef libGAP_Obj rec = libGAP_NEW_PREC(len(data))
93
cdef GapElement val
94
cdef libGAP_UInt rnam
95
for d in data:
96
key, val = d
97
rnam = libGAP_RNamName(key)
98
libGAP_AssPRec(rec, rnam, val.value)
99
libgap_exit()
100
return rec
101
102
103
cdef libGAP_Obj make_gap_integer(sage_int):
104
"""
105
Convert Sage integer into Gap integer
106
107
INPUT:
108
109
- ``sage_int`` -- a Sage integer.
110
111
OUTPUT
112
113
The integer as a GAP ``Obj``.
114
115
TESTS::
116
117
sage: libgap(1) # indirect doctest
118
1
119
"""
120
libgap_enter()
121
cdef libGAP_Obj result = libGAP_INTOBJ_INT(<int>sage_int)
122
libgap_exit()
123
return result
124
125
126
cdef libGAP_Obj make_gap_string(sage_string):
127
"""
128
Convert a Sage string to a Gap string
129
130
INPUT:
131
132
- ``sage_string`` -- a Sage integer.
133
134
OUTPUT
135
136
The string as a GAP ``Obj``.
137
138
TESTS::
139
140
sage: libgap('string') # indirect doctest
141
"string"
142
"""
143
libgap_enter()
144
cdef libGAP_Obj result
145
libGAP_C_NEW_STRING(result, len(sage_string), <char*>sage_string)
146
libgap_exit()
147
return result
148
149
150
############################################################################
151
### generic construction of GapElements ####################################
152
############################################################################
153
154
cdef GapElement make_any_gap_element(parent, libGAP_Obj obj):
155
"""
156
Return the libGAP element wrapper of ``obj``
157
158
The most suitable subclass of GapElement is determined
159
automatically. Use this function to wrap GAP objects unless you
160
know exactly which type it is (then you can use the specialized
161
``make_GapElement_...``)
162
"""
163
if obj is NULL:
164
return make_GapElement(parent, obj)
165
cdef int num = libGAP_TNUM_OBJ(obj)
166
if num == libGAP_T_INT or num == libGAP_T_INTPOS or num == libGAP_T_INTNEG:
167
return make_GapElement_Integer(parent, obj)
168
elif num == libGAP_T_CYC:
169
return make_GapElement_Cyclotomic(parent, obj)
170
elif num == libGAP_T_FFE:
171
return make_GapElement_FiniteField(parent, obj)
172
elif num == libGAP_T_RAT:
173
return make_GapElement_Rational(parent, obj)
174
elif num == libGAP_T_BOOL:
175
return make_GapElement_Boolean(parent, obj)
176
elif num == libGAP_T_FUNCTION:
177
return make_GapElement_Function(parent, obj)
178
elif num == libGAP_T_PERM2 or num == libGAP_T_PERM4:
179
return make_GapElement_Permutation(parent, obj)
180
elif num >= libGAP_FIRST_RECORD_TNUM and num <= libGAP_LAST_RECORD_TNUM:
181
return make_GapElement_Record(parent, obj)
182
elif num >= libGAP_T_STRING and num <= libGAP_T_STRING_SSORT + libGAP_IMMUTABLE:
183
# GAP strings are lists, too. Make sure this comes before make_GapElement_List
184
return make_GapElement_String(parent, obj)
185
elif num >= libGAP_FIRST_LIST_TNUM and num <= libGAP_LAST_LIST_TNUM:
186
return make_GapElement_List(parent, obj)
187
result = make_GapElement(parent, obj)
188
if num == libGAP_T_POSOBJ:
189
if result.IsZmodnZObj():
190
return make_GapElement_IntegerMod(parent, obj)
191
if num == libGAP_T_COMOBJ:
192
if result.IsRing():
193
return make_GapElement_Ring(parent, obj)
194
return result
195
196
197
198
199
############################################################################
200
### GapElement #############################################################
201
############################################################################
202
203
cdef GapElement make_GapElement(parent, libGAP_Obj obj):
204
r"""
205
Turn a Gap C object (of type ``Obj``) into a Cython ``GapElement``.
206
207
INPUT:
208
209
- ``parent`` -- the parent of the new :class:`GapElement`
210
211
- ``obj`` -- a GAP object.
212
213
OUTPUT:
214
215
A :class:`GapElement_Function` instance, or one of its derived
216
classes if it is a better fit for the GAP object.
217
218
EXAMPLES::
219
220
sage: libgap(0)
221
0
222
sage: type(_)
223
<type 'sage.libs.gap.element.GapElement_Integer'>
224
225
sage: libgap.eval('')
226
NULL
227
228
sage: libgap(None)
229
Traceback (most recent call last):
230
...
231
AttributeError: 'NoneType' object has no attribute '_gap_init_'
232
"""
233
cdef GapElement r = GapElement.__new__(GapElement)
234
r._initialize(parent, obj)
235
return r
236
237
238
cdef class GapElement(RingElement):
239
r"""
240
Wrapper for all Gap objects.
241
242
.. NOTE::
243
244
In order to create ``GapElements`` you should use the
245
``libgap`` instance (the parent of all Gap elements) to
246
convert things into ``GapElement``. You must not create
247
``GapElement`` instances manually.
248
249
EXAMPLES::
250
251
sage: libgap(0)
252
0
253
254
If Gap finds an error while evaluating, a corresponding assertion is raised::
255
256
sage: libgap.eval('1/0')
257
Traceback (most recent call last):
258
...
259
ValueError: libGAP: Error, Rational operations: <divisor> must not be zero
260
261
Also, a ``ValueError`` is raised if the input is not a simple expression::
262
263
sage: libgap.eval('1; 2; 3')
264
Traceback (most recent call last):
265
...
266
ValueError: can only evaluate a single statement
267
"""
268
269
def __cinit__(self):
270
"""
271
The Cython constructor.
272
273
EXAMPLES::
274
275
sage: libgap.eval('1')
276
1
277
"""
278
self.value = NULL
279
self._compare_by_id = False
280
281
282
def __init__(self):
283
"""
284
The ``GapElement`` constructor
285
286
Users must use the ``libgap`` instance to construct instances
287
of :class:`GapElement`. Cython programmers must use
288
:funct:`make_GapElement` factory function.
289
290
TESTS::
291
292
sage: from sage.libs.gap.element import GapElement
293
sage: GapElement()
294
Traceback (most recent call last):
295
...
296
TypeError: this class cannot be instantiated from Python
297
"""
298
raise TypeError('this class cannot be instantiated from Python')
299
300
301
cdef _initialize(self, parent, libGAP_Obj obj):
302
r"""
303
Initialize the GapElement.
304
305
This Cython method is called from :func:`make_GapElement` to
306
initialize the newly-constructed object. You must never call
307
it manually.
308
309
TESTS::
310
311
sage: n_before = libgap.count_GAP_objects()
312
sage: a = libgap.eval('123')
313
sage: b = libgap.eval('456')
314
sage: c = libgap.eval('CyclicGroup(3)')
315
sage: d = libgap.eval('"a string"')
316
sage: libgap.collect()
317
sage: del c
318
sage: libgap.collect()
319
sage: n_after = libgap.count_GAP_objects()
320
sage: n_after - n_before
321
3
322
"""
323
assert self.value is NULL
324
self._parent = parent
325
self.value = obj
326
if obj is NULL:
327
return
328
reference_obj(obj)
329
330
331
def __dealloc__(self):
332
r"""
333
The Cython destructor
334
335
TESTS::
336
337
sage: pre_refcount = libgap.count_GAP_objects()
338
sage: def f():
339
... local_variable = libgap.eval('"This is a new string"')
340
sage: f()
341
sage: f()
342
sage: f()
343
sage: post_refcount = libgap.count_GAP_objects()
344
sage: post_refcount - pre_refcount
345
0
346
"""
347
if self.value is NULL:
348
return
349
dereference_obj(self.value)
350
351
352
cpdef _type_number(self):
353
"""
354
Return the GAP internal type number.
355
356
This is only useful for libgap development purposes.
357
358
OUTPUT:
359
360
Integer.
361
362
EXAMPLES::
363
364
sage: x = libgap(1)
365
sage: x._type_number()
366
(0L, 'T_INT (integer)')
367
"""
368
n = libGAP_TNUM_OBJ(self.value)
369
global decode_type_number
370
name = decode_type_number.get(n, 'unknown')
371
return (n, name)
372
373
374
def trait_names(self):
375
"""
376
Return all Gap function names.
377
378
OUTPUT:
379
380
A list of strings.
381
382
EXAMPLES::
383
384
sage: x = libgap(1)
385
sage: len(x.trait_names()) > 1000
386
True
387
"""
388
import gap_functions
389
return gap_functions.common_gap_functions
390
391
392
def __getattr__(self, name):
393
r"""
394
Return functionoid implementing the function ``name``.
395
396
EXAMPLES::
397
398
sage: lst = libgap([])
399
sage: lst.Add(1) # this is the syntactic sugar
400
sage: lst
401
[ 1 ]
402
403
The above is equivalent to the following calls::
404
405
sage: lst = libgap.eval('[]')
406
sage: libgap.eval('Add') (lst, 1)
407
sage: lst
408
[ 1 ]
409
410
TESTS::
411
412
sage: lst.Adddddd(1)
413
Traceback (most recent call last):
414
...
415
AttributeError: name "Adddddd" is not defined in GAP.
416
417
sage: libgap.eval('some_name := 1')
418
1
419
sage: lst.some_name
420
Traceback (most recent call last):
421
...
422
AttributeError: name "some_name" does not define a GAP function.
423
"""
424
# print '__getattr__', name
425
if name in ('__dict__', '_getAttributeNames', '__custom_name', 'keys'):
426
raise AttributeError('Python special name, not a GAP function.')
427
try:
428
proxy = make_GapElement_MethodProxy\
429
(self.parent(), gap_eval(name), self)
430
except ValueError:
431
raise AttributeError('name "'+str(name)+'" is not defined in GAP.')
432
if not proxy.is_function():
433
raise AttributeError('name "'+str(name)+'" does not define a GAP function.')
434
return proxy
435
436
437
def _repr_(self):
438
r"""
439
Return a string representation of ``self``.
440
441
EXAMPLES::
442
443
sage: libgap(0)
444
0
445
sage: libgap.eval('')
446
NULL
447
sage: libgap(0)
448
0
449
sage: libgap(0)._repr_()
450
'0'
451
"""
452
if self.value == NULL:
453
return 'NULL'
454
try:
455
libgap_enter()
456
libgap_start_interaction('')
457
libGAP_ViewObjHandler(self.value)
458
s = libgap_get_output()
459
return s.strip()
460
finally:
461
libgap_finish_interaction()
462
libgap_exit()
463
464
465
cpdef _set_compare_by_id(self):
466
"""
467
Set comparison to compare by ``id``
468
469
By default, GAP is used to compare libGAP objects. However,
470
this is not defined for all GAP objects. To have libGAP play
471
nice with ``UniqueRepresentation``, comparison must always
472
work. This method allows one to override the comparison to
473
sort by the (unique) Python ``id``.
474
475
Obviously it is a bad idea to change the comparison of objects
476
after you have inserted them into a set/dict. You also must
477
not mix libGAP objects with different sort methods in the same
478
container.
479
480
EXAMPLES::
481
482
sage: F1 = libgap.FreeGroup(['a'])
483
sage: F2 = libgap.FreeGroup(['a'])
484
sage: F1 < F2
485
Traceback (most recent call last):
486
...
487
ValueError: libGAP: cannot compare less than: Error, no method found!
488
Error, no 1st choice method found for `<' on 2 arguments
489
490
sage: F1._set_compare_by_id()
491
sage: F1 != F2
492
Traceback (most recent call last):
493
...
494
ValueError: comparison style must be the same for both operands
495
496
sage: F1._set_compare_by_id()
497
sage: F2._set_compare_by_id()
498
sage: F1 != F2
499
True
500
"""
501
self._compare_by_id = True
502
503
504
cpdef _assert_compare_by_id(self):
505
"""
506
Ensure that comparison is by ``id``
507
508
See :meth:`_set_compare_by_id`.
509
510
OUTPUT:
511
512
This method returns nothing. A ``ValueError`` is raised if
513
:meth:`_set_compare_by_id` has not been called on this libgap
514
object.
515
516
EXAMPLES::
517
518
sage: x = libgap.FreeGroup(1)
519
sage: x._assert_compare_by_id()
520
Traceback (most recent call last):
521
...
522
ValueError: requires a libGAP objects whose comparison is by "id"
523
524
sage: x._set_compare_by_id()
525
sage: x._assert_compare_by_id()
526
"""
527
if not self._compare_by_id:
528
raise ValueError('requires a libGAP objects whose comparison is by "id"')
529
530
531
def __richcmp__(left, right, int op):
532
"""
533
Boilerplate for Cython class comparison.
534
535
EXAMPLES::
536
537
sage: a = libgap(123)
538
sage: a == a
539
True
540
"""
541
return (<Element>left)._richcmp(right, op)
542
543
def __hash__(self):
544
"""
545
Make hashable.
546
547
EXAMPLES::
548
549
sage: hash(libgap(123)) # random output
550
163512108404620371
551
"""
552
return hash(str(self))
553
554
cdef _richcmp_c_impl(self, Element other, int op):
555
"""
556
Compare ``self`` with ``other``.
557
558
Uses the GAP comparison by default, or the Python ``id`` if
559
:meth:`_set_compare_by_id` was called.
560
561
OUTPUT:
562
563
Boolean, depending on the comparison of ``self`` and
564
``other``. Raises a ``ValueError`` if GAP does not support
565
comparison of ``self`` and ``other``, unless
566
:meth:`_set_compare_by_id` was called on both ``self`` and
567
``other``.
568
569
EXAMPLES::
570
571
sage: a = libgap(123)
572
sage: b = libgap('string')
573
sage: a._richcmp_(b, 0)
574
1
575
sage: (a < b) or (a > b)
576
True
577
sage: a._richcmp_(libgap(123), 2)
578
True
579
580
GAP does not have a comparison function for two ``FreeGroup``
581
objects. LibGAP signals this by raising a ``ValueError`` ::
582
583
sage: F1 = libgap.FreeGroup(['a'])
584
sage: F2 = libgap.FreeGroup(['a'])
585
sage: F1 < F2
586
Traceback (most recent call last):
587
...
588
ValueError: libGAP: cannot compare less than: Error, no method found!
589
Error, no 1st choice method found for `<' on 2 arguments
590
591
sage: F1._set_compare_by_id()
592
sage: F1 < F2
593
Traceback (most recent call last):
594
...
595
ValueError: comparison style must be the same for both operands
596
597
sage: F1._set_compare_by_id()
598
sage: F2._set_compare_by_id()
599
sage: F1 < F2 or F1 > F2
600
True
601
"""
602
if self._compare_by_id != (<GapElement>other)._compare_by_id:
603
raise ValueError('comparison style must be the same for both operands')
604
if op==Py_LT:
605
return self._compare_less(other)
606
elif op==Py_LE:
607
return self._compare_equal(other) or self._compare_less(other)
608
elif op == Py_EQ:
609
return self._compare_equal(other)
610
elif op == Py_GT:
611
return not self._compare_less(other)
612
elif op == Py_GE:
613
return self._compare_equal(other) or not self._compare_less(other)
614
elif op == Py_NE:
615
return not self._compare_equal(other)
616
else:
617
assert False # unreachable
618
619
cdef bint _compare_equal(self, Element other) except -2:
620
"""
621
Compare ``self`` with ``other``.
622
623
Helper for :meth:`_richcmp_c_impl`
624
625
EXAMPLES::
626
627
sage: libgap(1) == libgap(1) # indirect doctest
628
True
629
"""
630
if self._compare_by_id:
631
return id(self) == id(other)
632
cdef GapElement c_other = <GapElement>other
633
cdef bint result
634
libgap_enter()
635
try:
636
sig_on()
637
result = libGAP_EQ(self.value, c_other.value)
638
sig_off()
639
except RuntimeError, msg:
640
raise ValueError('libGAP: cannot compare equality: '+str(msg))
641
finally:
642
libgap_exit()
643
return result
644
645
cdef bint _compare_less(self, Element other) except -2:
646
"""
647
Compare ``self`` with ``other``.
648
649
Helper for :meth:`_richcmp_c_impl`
650
651
EXAMPLES::
652
653
sage: libgap(1) < libgap(2) # indirect doctest
654
True
655
"""
656
if self._compare_by_id:
657
return id(self) < id(other)
658
cdef bint result
659
cdef GapElement c_other = <GapElement>other
660
libgap_enter()
661
try:
662
sig_on()
663
result = libGAP_LT(self.value, c_other.value)
664
sig_off()
665
except RuntimeError, msg:
666
raise ValueError('libGAP: cannot compare less than: '+str(msg))
667
finally:
668
libgap_exit()
669
return result
670
671
cpdef ModuleElement _add_(self, ModuleElement right):
672
r"""
673
Add two GapElement objects.
674
675
EXAMPLES::
676
677
sage: g1 = libgap(1)
678
sage: g2 = libgap(2)
679
sage: g1._add_(g2)
680
3
681
sage: g1 + g2 # indirect doctest
682
3
683
684
sage: libgap(1) + libgap.CyclicGroup(2)
685
Traceback (most recent call last):
686
...
687
ValueError: libGAP: Error, no method found!
688
Error, no 1st choice method found for `+' on 2 arguments
689
"""
690
cdef libGAP_Obj result
691
try:
692
libgap_enter()
693
sig_on()
694
result = libGAP_SUM(self.value, (<GapElement>right).value)
695
sig_off()
696
except RuntimeError, msg:
697
libGAP_ClearError()
698
raise ValueError('libGAP: '+str(msg))
699
finally:
700
libgap_exit()
701
return make_any_gap_element(self.parent(), result)
702
703
704
cpdef ModuleElement _sub_(self, ModuleElement right):
705
r"""
706
Subtract two GapElement objects.
707
708
EXAMPLES::
709
710
sage: g1 = libgap(1)
711
sage: g2 = libgap(2)
712
sage: g1._sub_(g2)
713
-1
714
sage: g1 - g2 # indirect doctest
715
-1
716
717
sage: libgap(1) - libgap.CyclicGroup(2)
718
Traceback (most recent call last):
719
...
720
ValueError: libGAP: Error, no method found!
721
Error, no 1st choice method found for `-' on 2 arguments
722
"""
723
cdef libGAP_Obj result
724
try:
725
libgap_enter()
726
sig_on()
727
result = libGAP_DIFF(self.value, (<GapElement>right).value)
728
sig_off()
729
except RuntimeError, msg:
730
libGAP_ClearError()
731
raise ValueError, 'libGAP: '+str(msg)
732
finally:
733
libgap_exit()
734
return make_any_gap_element(self.parent(), result)
735
736
737
cpdef RingElement _mul_(self, RingElement right):
738
r"""
739
Multiply two GapElement objects.
740
741
EXAMPLES::
742
743
sage: g1 = libgap(3)
744
sage: g2 = libgap(5)
745
sage: g1._mul_(g2)
746
15
747
sage: g1 * g2 # indirect doctest
748
15
749
750
sage: libgap(1) * libgap.CyclicGroup(2)
751
Traceback (most recent call last):
752
...
753
ValueError: libGAP: Error, no method found!
754
Error, no 1st choice method found for `*' on 2 arguments
755
"""
756
cdef libGAP_Obj result
757
try:
758
libgap_enter()
759
sig_on()
760
result = libGAP_PROD(self.value, (<GapElement>right).value)
761
sig_off()
762
except RuntimeError, msg:
763
libGAP_ClearError()
764
raise ValueError, 'libGAP: '+str(msg)
765
finally:
766
libgap_exit()
767
return make_any_gap_element(self.parent(), result)
768
769
770
cpdef RingElement _div_(self, RingElement right):
771
r"""
772
Divide two GapElement objects.
773
774
EXAMPLES::
775
776
sage: g1 = libgap(3)
777
sage: g2 = libgap(5)
778
sage: g1._div_(g2)
779
3/5
780
sage: g1 / g2 # indirect doctest
781
3/5
782
783
sage: libgap(1) / libgap.CyclicGroup(2)
784
Traceback (most recent call last):
785
...
786
ValueError: libGAP: Error, no method found!
787
Error, no 1st choice method found for `/' on 2 arguments
788
789
sage: libgap(1) / libgap(0)
790
Traceback (most recent call last):
791
...
792
ValueError: libGAP: Error, Rational operations: <divisor> must not be zero
793
"""
794
cdef libGAP_Obj result
795
try:
796
libgap_enter()
797
sig_on()
798
result = libGAP_QUO(self.value, (<GapElement>right).value)
799
sig_off()
800
except RuntimeError, msg:
801
libGAP_ClearError()
802
raise ValueError, 'libGAP: '+str(msg)
803
finally:
804
libgap_exit()
805
return make_any_gap_element(self.parent(), result)
806
807
808
def __mod__(GapElement self, GapElement right):
809
r"""
810
Modulus of two GapElement objects.
811
812
EXAMPLES::
813
814
sage: g1 = libgap(5)
815
sage: g2 = libgap(2)
816
sage: g1 % g2
817
1
818
819
sage: libgap(1) % libgap.CyclicGroup(2)
820
Traceback (most recent call last):
821
...
822
ValueError: libGAP: Error, no method found!
823
Error, no 1st choice method found for `mod' on 2 arguments
824
"""
825
cdef libGAP_Obj result
826
try:
827
libgap_enter()
828
sig_on()
829
result = libGAP_MOD(self.value, right.value)
830
sig_off()
831
except RuntimeError, msg:
832
libGAP_ClearError()
833
raise ValueError, 'libGAP: '+str(msg)
834
finally:
835
libgap_exit()
836
return make_any_gap_element(self.parent(), result)
837
838
839
def __pow__(GapElement self, right, dummy):
840
r"""
841
Exponentiation of two GapElement objects.
842
843
EXAMPLES::
844
845
sage: g1 = libgap(5)
846
sage: g2 = libgap(2)
847
sage: g1 ^ g2
848
25
849
850
sage: libgap.CyclicGroup(2) ^ 2
851
Traceback (most recent call last):
852
...
853
ValueError: libGAP: Error, no method found!
854
Error, no 1st choice method found for `^' on 2 arguments
855
856
sage: libgap(3) ^ Infinity
857
Traceback (most recent call last):
858
...
859
ValueError: libGAP: Error, Variable: 'Infinity' must have a value
860
"""
861
if not PY_TYPE_CHECK(right, GapElement):
862
libgap = self.parent()
863
right = libgap(right)
864
cdef libGAP_Obj result
865
try:
866
libgap_enter()
867
sig_on()
868
result = libGAP_POW(self.value, (<GapElement>right).value)
869
sig_off()
870
except RuntimeError, msg:
871
libGAP_ClearError()
872
raise ValueError, 'libGAP: '+str(msg)
873
finally:
874
libgap_exit()
875
return make_any_gap_element(self.parent(), result)
876
877
878
def is_function(self):
879
"""
880
Return whether the wrapped GAP object is a function.
881
882
OUTPUT:
883
884
Boolean.
885
886
EXAMPLES::
887
888
sage: a = libgap.eval("NormalSubgroups")
889
sage: a.is_function()
890
True
891
sage: a = libgap(2/3)
892
sage: a.is_function()
893
False
894
"""
895
return libGAP_IS_FUNC(self.value)
896
897
898
def is_list(self):
899
r"""
900
Return whether the wrapped GAP object is a GAP List.
901
902
OUTPUT:
903
904
Boolean.
905
906
EXAMPLES::
907
908
sage: libgap.eval('[1, 2,,,, 5]').is_list()
909
True
910
sage: libgap.eval('3/2').is_list()
911
False
912
"""
913
return libGAP_IS_PLIST(self.value)
914
915
916
def is_record(self):
917
r"""
918
Return whether the wrapped GAP object is a GAP record.
919
920
OUTPUT:
921
922
Boolean.
923
924
EXAMPLES::
925
926
sage: libgap.eval('[1, 2,,,, 5]').is_record()
927
False
928
sage: libgap.eval('rec(a:=1, b:=3)').is_record()
929
True
930
"""
931
return libGAP_IS_REC(self.value)
932
933
934
cpdef is_bool(self):
935
r"""
936
Return whether the wrapped GAP object is a GAP boolean.
937
938
OUTPUT:
939
940
Boolean.
941
942
EXAMPLES::
943
944
sage: libgap(True).is_bool()
945
True
946
"""
947
libgap = self.parent()
948
cdef GapElement r_sage = libgap.IsBool(self)
949
cdef libGAP_Obj r_gap = r_sage.value
950
return r_gap == libGAP_True
951
952
953
def is_string(self):
954
r"""
955
Return whether the wrapped GAP object is a GAP string.
956
957
OUTPUT:
958
959
Boolean.
960
961
EXAMPLES::
962
963
sage: libgap('this is a string').is_string()
964
True
965
"""
966
return libGAP_IS_STRING(self.value)
967
968
969
def is_permutation(self):
970
r"""
971
Return whether the wrapped GAP object is a GAP permutation.
972
973
OUTPUT:
974
975
Boolean.
976
977
EXAMPLES::
978
979
sage: perm = libgap.PermList( libgap([1,5,2,3,4]) ); perm
980
(2,5,4,3)
981
sage: perm.is_permutation()
982
True
983
sage: libgap('this is a string').is_permutation()
984
False
985
"""
986
return (libGAP_TNUM_OBJ(self.value) == libGAP_T_PERM2 or
987
libGAP_TNUM_OBJ(self.value) == libGAP_T_PERM4)
988
989
990
def sage(self):
991
r"""
992
Return the Sage equivalent of the :class:`GapElement`
993
994
EXAMPLES::
995
996
sage: libgap(1).sage()
997
1
998
sage: type(_)
999
<type 'sage.rings.integer.Integer'>
1000
1001
sage: libgap(3/7).sage()
1002
3/7
1003
sage: type(_)
1004
<type 'sage.rings.rational.Rational'>
1005
1006
sage: libgap.eval('5 + 7*E(3)').sage()
1007
7*zeta3 + 5
1008
1009
sage: libgap(True).sage()
1010
True
1011
sage: libgap(False).sage()
1012
False
1013
sage: type(_)
1014
<type 'bool'>
1015
1016
sage: libgap('this is a string').sage()
1017
'this is a string'
1018
sage: type(_)
1019
<type 'str'>
1020
"""
1021
if self.value is NULL:
1022
return None
1023
libgap = self.parent()
1024
raise NotImplementedError('cannot construct equivalent Sage object')
1025
1026
1027
def matrix(self, ring=None):
1028
"""
1029
Return the list as a matrix.
1030
1031
GAP does not have a special matrix data type, they are just
1032
lists of lists. This function converts a GAP list of lists to
1033
a Sage matrix.
1034
1035
OUTPUT:
1036
1037
A Sage matrix.
1038
1039
EXAMPLES::
1040
1041
sage: m = libgap.eval('[[Z(2^2), Z(2)^0],[0*Z(2), Z(2^2)^2]]'); m
1042
[ [ Z(2^2), Z(2)^0 ],
1043
[ 0*Z(2), Z(2^2)^2 ] ]
1044
sage: m.IsMatrix()
1045
true
1046
sage: matrix(m)
1047
[ a 1]
1048
[ 0 a + 1]
1049
sage: matrix(GF(4,'B'), m)
1050
[ B 1]
1051
[ 0 B + 1]
1052
1053
GAP is also starting to introduce a specialized matrix
1054
type. Currently, you need to use ``Unpack`` to convert it back
1055
to a list-of-lists::
1056
1057
sage: M = libgap.eval('SL(2,GF(5))').GeneratorsOfGroup()[1]
1058
sage: type(M) # not a GAP list
1059
<type 'sage.libs.gap.element.GapElement'>
1060
sage: M.IsMatrix()
1061
true
1062
sage: M.matrix()
1063
[4 1]
1064
[4 0]
1065
"""
1066
if not self.IsMatrix():
1067
raise ValueError('not a GAP matrix')
1068
entries = self.Flat()
1069
n = self.Length().sage()
1070
m = len(entries) // n
1071
if len(entries) % n != 0:
1072
raise ValueError('not a rectangular list of lists')
1073
from sage.matrix.constructor import matrix
1074
if ring is None:
1075
ring = entries.DefaultRing().sage()
1076
return matrix(ring, n, m, [ x.sage(ring=ring) for x in entries ])
1077
1078
_matrix_ = matrix
1079
1080
def vector(self, ring=None):
1081
"""
1082
Return the list as a vector.
1083
1084
GAP does not have a special vetor data type, they are just
1085
lists. This function converts a GAP list to a Sage vector.
1086
1087
OUTPUT:
1088
1089
A Sage vector.
1090
1091
EXAMPLES::
1092
1093
sage: m = libgap.eval('[0*Z(2), Z(2^2), Z(2)^0, Z(2^2)^2]'); m
1094
[ 0*Z(2), Z(2^2), Z(2)^0, Z(2^2)^2 ]
1095
sage: vector(m)
1096
(0, a, 1, a + 1)
1097
sage: vector(GF(4,'B'), m)
1098
(0, B, 1, B + 1)
1099
"""
1100
if not self.IsVector():
1101
raise ValueError('not a GAP vector')
1102
from sage.modules.all import vector
1103
entries = self.Flat()
1104
n = self.Length().sage()
1105
if ring is None:
1106
ring = entries.DefaultRing().sage()
1107
return vector(ring, n, self.sage(ring=ring))
1108
1109
_vector_ = vector
1110
1111
1112
1113
############################################################################
1114
### GapElement_Integer #####################################################
1115
############################################################################
1116
1117
cdef GapElement_Integer make_GapElement_Integer(parent, libGAP_Obj obj):
1118
r"""
1119
Turn a Gap integer object into a GapElement_Integer Sage object
1120
1121
EXAMPLES::
1122
1123
sage: libgap(123)
1124
123
1125
sage: type(_)
1126
<type 'sage.libs.gap.element.GapElement_Integer'>
1127
"""
1128
cdef GapElement_Integer r = GapElement_Integer.__new__(GapElement_Integer)
1129
r._initialize(parent, obj)
1130
return r
1131
1132
1133
cdef class GapElement_Integer(GapElement):
1134
r"""
1135
Derived class of GapElement for GAP rational numbers.
1136
1137
EXAMPLES::
1138
1139
sage: i = libgap(123)
1140
sage: type(i)
1141
<type 'sage.libs.gap.element.GapElement_Integer'>
1142
"""
1143
1144
def is_C_int(self):
1145
r"""
1146
Return whether the wrapped GAP object is a immediate GAP integer.
1147
1148
An immediate integer is one that is stored as a C integer, and
1149
is subject to the usual size limits. Larger integers are
1150
stored in GAP as GMP integers.
1151
1152
OUTPUT:
1153
1154
Boolean.
1155
1156
EXAMPLES::
1157
1158
sage: n = libgap(1)
1159
sage: type(n)
1160
<type 'sage.libs.gap.element.GapElement_Integer'>
1161
sage: n.is_C_int()
1162
True
1163
sage: n.IsInt()
1164
true
1165
1166
sage: N = libgap(2^130)
1167
sage: type(N)
1168
<type 'sage.libs.gap.element.GapElement_Integer'>
1169
sage: N.is_C_int()
1170
False
1171
sage: N.IsInt()
1172
true
1173
"""
1174
return libGAP_IS_INTOBJ(self.value)
1175
1176
1177
def sage(self, ring=None):
1178
r"""
1179
Return the Sage equivalent of the :class:`GapElement_Integer`
1180
1181
- ``ring`` -- Integer ring or ``None`` (default). If not
1182
specified, a the default Sage integer ring is used.
1183
1184
OUTPUT:
1185
1186
A Sage integer
1187
1188
EXAMPLES::
1189
1190
sage: libgap([ 1, 3, 4 ]).sage()
1191
[1, 3, 4]
1192
sage: all( x in ZZ for x in _ )
1193
True
1194
1195
sage: libgap(132).sage(ring=IntegerModRing(13))
1196
2
1197
sage: parent(_)
1198
Ring of integers modulo 13
1199
1200
TESTS::
1201
1202
sage: large = libgap.eval('2^130'); large
1203
1361129467683753853853498429727072845824
1204
sage: large.sage()
1205
1361129467683753853853498429727072845824
1206
"""
1207
if ring is None:
1208
ring = ZZ
1209
if self.is_C_int():
1210
return ring(libGAP_INT_INTOBJ(self.value))
1211
else:
1212
return ring(str(self))
1213
1214
1215
############################################################################
1216
### GapElement_IntegerMod #####################################################
1217
############################################################################
1218
1219
cdef GapElement_IntegerMod make_GapElement_IntegerMod(parent, libGAP_Obj obj):
1220
r"""
1221
Turn a Gap integer object into a :class:`GapElement_IntegerMod` Sage object
1222
1223
EXAMPLES::
1224
1225
sage: n = IntegerModRing(123)(13)
1226
sage: libgap(n)
1227
ZmodnZObj( 13, 123 )
1228
sage: type(_)
1229
<type 'sage.libs.gap.element.GapElement_IntegerMod'>
1230
"""
1231
cdef GapElement_IntegerMod r = GapElement_IntegerMod.__new__(GapElement_IntegerMod)
1232
r._initialize(parent, obj)
1233
return r
1234
1235
cdef class GapElement_IntegerMod(GapElement):
1236
r"""
1237
Derived class of GapElement for GAP integers modulo an integer.
1238
1239
EXAMPLES::
1240
1241
sage: n = IntegerModRing(123)(13)
1242
sage: i = libgap(n)
1243
sage: type(i)
1244
<type 'sage.libs.gap.element.GapElement_IntegerMod'>
1245
"""
1246
1247
cpdef GapElement_Integer lift(self):
1248
"""
1249
Return an integer lift.
1250
1251
OUTPUT:
1252
1253
A :class:`GapElement_Integer` that equals ``self`` in the
1254
integer mod ring.
1255
1256
EXAMPLES::
1257
1258
sage: n = libgap.eval('One(ZmodnZ(123)) * 13')
1259
sage: n.lift()
1260
13
1261
sage: type(_)
1262
<type 'sage.libs.gap.element.GapElement_Integer'>
1263
"""
1264
return self.Int()
1265
1266
1267
def sage(self, ring=None):
1268
r"""
1269
Return the Sage equivalent of the :class:`GapElement_IntegerMod`
1270
1271
INPUT:
1272
1273
- ``ring`` -- Sage integer mod ring or ``None`` (default). If
1274
not specified, a suitable integer mod ringa is used
1275
automatically.
1276
1277
OUTPUT:
1278
1279
A Sage integer modulo another integer.
1280
1281
EXAMPLES::
1282
1283
sage: n = libgap.eval('One(ZmodnZ(123)) * 13')
1284
sage: n.sage()
1285
13
1286
sage: parent(_)
1287
Ring of integers modulo 123
1288
"""
1289
if ring is None:
1290
# ring = self.DefaultRing().sage()
1291
characteristic = self.Characteristic().sage()
1292
ring = ZZ.quotient_ring(characteristic)
1293
return self.lift().sage(ring=ring)
1294
1295
1296
############################################################################
1297
### GapElement_FiniteField #####################################################
1298
############################################################################
1299
1300
cdef GapElement_FiniteField make_GapElement_FiniteField(parent, libGAP_Obj obj):
1301
r"""
1302
Turn a GAP finite field object into a :class:`GapElement_FiniteField` Sage object
1303
1304
EXAMPLES::
1305
1306
sage: libgap.eval('Z(5)^2')
1307
Z(5)^2
1308
sage: type(_)
1309
<type 'sage.libs.gap.element.GapElement_FiniteField'>
1310
"""
1311
cdef GapElement_FiniteField r = GapElement_FiniteField.__new__(GapElement_FiniteField)
1312
r._initialize(parent, obj)
1313
return r
1314
1315
1316
cdef class GapElement_FiniteField(GapElement):
1317
r"""
1318
Derived class of GapElement for GAP finite field elements.
1319
1320
EXAMPLES::
1321
1322
sage: libgap.eval('Z(5)^2')
1323
Z(5)^2
1324
sage: type(_)
1325
<type 'sage.libs.gap.element.GapElement_FiniteField'>
1326
"""
1327
1328
cpdef GapElement_Integer lift(self):
1329
"""
1330
Return an integer lift.
1331
1332
OUTPUT:
1333
1334
The smallest positive :class:`GapElement_Integer` that equals
1335
``self`` in the prime finite field.
1336
1337
EXAMPLES::
1338
1339
sage: n = libgap.eval('Z(5)^2')
1340
sage: n.lift()
1341
4
1342
sage: type(_)
1343
<type 'sage.libs.gap.element.GapElement_Integer'>
1344
1345
sage: n = libgap.eval('Z(25)')
1346
sage: n.lift()
1347
Traceback (most recent call last):
1348
TypeError: not in prime subfield
1349
"""
1350
degree = self.DegreeFFE().sage()
1351
if degree == 1:
1352
return self.IntFFE()
1353
else:
1354
raise TypeError('not in prime subfield')
1355
1356
1357
def sage(self, ring=None, var='a'):
1358
r"""
1359
Return the Sage equivalent of the :class:`GapElement_FiniteField`.
1360
1361
INPUT:
1362
1363
- ``ring`` -- a Sage finite field or ``None`` (default). The
1364
field to return ``self`` in. If not specified, a suitable
1365
finite field will be constructed.
1366
1367
OUTPUT:
1368
1369
An Sage finite field element. The isomorphism is chosen such
1370
that the Gap ``PrimitiveRoot()`` maps to the Sage
1371
:meth:`~sage.rings.finite_rings.finite_field_prime_modn.multiplicative_generator`.
1372
1373
EXAMPLES::
1374
1375
sage: n = libgap.eval('Z(25)^2')
1376
sage: n.sage()
1377
a + 3
1378
sage: parent(_)
1379
Finite Field in a of size 5^2
1380
1381
sage: n.sage(ring=GF(5))
1382
Traceback (most recent call last):
1383
...
1384
ValueError: the given finite field has incompatible size
1385
"""
1386
deg = self.DegreeFFE().sage()
1387
char = self.Characteristic().sage()
1388
if ring is None:
1389
from sage.rings.finite_rings.constructor import GF
1390
ring = GF(char**deg, name=var)
1391
1392
if self.IsOne():
1393
return ring.one()
1394
if deg == 1 and char == ring.characteristic():
1395
return ring(self.lift().sage())
1396
else:
1397
field = self.DefaultField()
1398
if field.Size().sage() != ring.cardinality():
1399
raise ValueError('the given finite field has incompatible size')
1400
root = self.DefaultField().PrimitiveRoot()
1401
exp = self.LogFFE(root)
1402
return ring.multiplicative_generator() ** exp.sage()
1403
1404
1405
############################################################################
1406
### GapElement_Cyclotomic #####################################################
1407
############################################################################
1408
1409
cdef GapElement_Cyclotomic make_GapElement_Cyclotomic(parent, libGAP_Obj obj):
1410
r"""
1411
Turn a Gap cyclotomic object into a :class:`GapElement_Cyclotomic` Sage
1412
object.
1413
1414
EXAMPLES::
1415
1416
sage: libgap.eval('E(3)')
1417
E(3)
1418
sage: type(_)
1419
<type 'sage.libs.gap.element.GapElement_Cyclotomic'>
1420
"""
1421
cdef GapElement_Cyclotomic r = GapElement_Cyclotomic.__new__(GapElement_Cyclotomic)
1422
r._initialize(parent, obj)
1423
return r
1424
1425
1426
cdef class GapElement_Cyclotomic(GapElement):
1427
r"""
1428
Derived class of GapElement for GAP universal cyclotomics.
1429
1430
EXAMPLES::
1431
1432
sage: libgap.eval('E(3)')
1433
E(3)
1434
sage: type(_)
1435
<type 'sage.libs.gap.element.GapElement_Cyclotomic'>
1436
"""
1437
1438
def sage(self, ring=None):
1439
r"""
1440
Return the Sage equivalent of the :class:`GapElement_Cyclotomic`.
1441
1442
INPUT:
1443
1444
- ``ring`` -- a Sage cyclotomic field or ``None``
1445
(default). If not specified, a suitable minimal cyclotomic
1446
field will be constructed.
1447
1448
OUTPUT:
1449
1450
A Sage cyclotomic field element.
1451
1452
EXAMPLES::
1453
1454
sage: n = libgap.eval('E(3)')
1455
sage: n.sage()
1456
zeta3
1457
sage: parent(_)
1458
Cyclotomic Field of order 3 and degree 2
1459
1460
sage: n.sage(ring=CyclotomicField(6))
1461
zeta6 - 1
1462
1463
sage: libgap.E(3).sage(ring=CyclotomicField(3))
1464
zeta3
1465
sage: libgap.E(3).sage(ring=CyclotomicField(6))
1466
zeta6 - 1
1467
1468
TESTS:
1469
1470
Check that :trac:`15204` is fixed::
1471
1472
sage: libgap.E(3).sage(ring=UniversalCyclotomicField())
1473
E(3)
1474
sage: libgap.E(3).sage(ring=CC)
1475
-0.500000000000000 + 0.866025403784439*I
1476
"""
1477
if ring is None:
1478
conductor = self.Conductor()
1479
from sage.rings.number_field.number_field import CyclotomicField
1480
ring = CyclotomicField(conductor.sage())
1481
else:
1482
try:
1483
conductor = ring._n()
1484
except AttributeError:
1485
from sage.rings.number_field.number_field import CyclotomicField
1486
conductor = self.Conductor()
1487
cf = CyclotomicField(conductor.sage())
1488
return ring(cf(self.CoeffsCyc(conductor).sage()))
1489
coeff = self.CoeffsCyc(conductor).sage()
1490
return ring(coeff)
1491
1492
1493
############################################################################
1494
### GapElement_Rational ####################################################
1495
############################################################################
1496
1497
cdef GapElement_Rational make_GapElement_Rational(parent, libGAP_Obj obj):
1498
r"""
1499
Turn a Gap Rational number (of type ``Obj``) into a Cython ``GapElement_Rational``.
1500
1501
EXAMPLES::
1502
1503
sage: libgap(123/456)
1504
41/152
1505
sage: type(_)
1506
<type 'sage.libs.gap.element.GapElement_Rational'>
1507
"""
1508
cdef GapElement_Rational r = GapElement_Rational.__new__(GapElement_Rational)
1509
r._initialize(parent, obj)
1510
return r
1511
1512
1513
cdef class GapElement_Rational(GapElement):
1514
r"""
1515
Derived class of GapElement for GAP rational numbers.
1516
1517
EXAMPLES::
1518
1519
sage: r = libgap(123/456)
1520
sage: type(r)
1521
<type 'sage.libs.gap.element.GapElement_Rational'>
1522
"""
1523
1524
def sage(self, ring=None):
1525
r"""
1526
Return the Sage equivalent of the :class:`GapElement`.
1527
1528
INPUT:
1529
1530
- ``ring`` -- the Sage rational ring or ``None`` (default). If
1531
not specified, the rational ring is used automatically.
1532
1533
OUTPUT:
1534
1535
A Sage rational number.
1536
1537
EXAMPLES::
1538
1539
sage: r = libgap(123/456); r
1540
41/152
1541
sage: type(_)
1542
<type 'sage.libs.gap.element.GapElement_Rational'>
1543
sage: r.sage()
1544
41/152
1545
sage: type(_)
1546
<type 'sage.rings.rational.Rational'>
1547
"""
1548
if ring is None:
1549
ring = ZZ
1550
libgap = self.parent()
1551
return libgap.NumeratorRat(self).sage(ring=ring) / libgap.DenominatorRat(self).sage(ring=ring)
1552
1553
1554
############################################################################
1555
### GapElement_Ring #####################################################
1556
############################################################################
1557
1558
cdef GapElement_Ring make_GapElement_Ring(parent, libGAP_Obj obj):
1559
r"""
1560
Turn a Gap integer object into a :class:`GapElement_Ring` Sage
1561
object.
1562
1563
EXAMPLES::
1564
1565
sage: libgap(GF(5))
1566
GF(5)
1567
sage: type(_)
1568
<type 'sage.libs.gap.element.GapElement_Ring'>
1569
"""
1570
cdef GapElement_Ring r = GapElement_Ring.__new__(GapElement_Ring)
1571
r._initialize(parent, obj)
1572
return r
1573
1574
1575
cdef class GapElement_Ring(GapElement):
1576
r"""
1577
Derived class of GapElement for GAP rings (parents of ring elements).
1578
1579
EXAMPLES::
1580
1581
sage: i = libgap(ZZ)
1582
sage: type(i)
1583
<type 'sage.libs.gap.element.GapElement_Ring'>
1584
"""
1585
1586
def ring_integer(self):
1587
"""
1588
Construct the Sage integers.
1589
1590
EXAMPLES::
1591
1592
sage: libgap.eval('Integers').ring_integer()
1593
Integer Ring
1594
"""
1595
return ZZ
1596
1597
1598
def ring_rational(self):
1599
"""
1600
Construct the Sage rationals.
1601
1602
EXAMPLES::
1603
1604
sage: libgap.eval('Rationals').ring_rational()
1605
Rational Field
1606
"""
1607
return ZZ.fraction_field()
1608
1609
1610
def ring_integer_mod(self):
1611
"""
1612
Construct a Sage integer mod ring.
1613
1614
EXAMPLES::
1615
1616
sage: libgap.eval('ZmodnZ(15)').ring_integer_mod()
1617
Ring of integers modulo 15
1618
"""
1619
characteristic = self.Characteristic().sage()
1620
return ZZ.quotient_ring(characteristic)
1621
1622
1623
def ring_finite_field(self, var='a'):
1624
"""
1625
Construct an integer ring.
1626
1627
EXAMPLES::
1628
1629
sage: libgap.GF(3,2).ring_finite_field(var='A')
1630
Finite Field in A of size 3^2
1631
"""
1632
size = self.Size().sage()
1633
from sage.rings.finite_rings.constructor import GF
1634
return GF(size, name=var)
1635
1636
1637
def ring_cyclotomic(self):
1638
"""
1639
Construct an integer ring.
1640
1641
EXAMPLES::
1642
1643
sage: libgap.CyclotomicField(6).ring_cyclotomic()
1644
Cyclotomic Field of order 3 and degree 2
1645
"""
1646
conductor = self.Conductor()
1647
from sage.rings.number_field.number_field import CyclotomicField
1648
return CyclotomicField(conductor.sage())
1649
1650
1651
def sage(self, **kwds):
1652
r"""
1653
Return the Sage equivalent of the :class:`GapElement_Ring`.
1654
1655
INPUT:
1656
1657
- ``**kwds`` -- keywords that are passed on to the ``ring_``
1658
method.
1659
1660
OUTPUT:
1661
1662
A Sage ring.
1663
1664
EXAMPLES::
1665
1666
sage: libgap.eval('Integers').sage()
1667
Integer Ring
1668
1669
sage: libgap.eval('Rationals').sage()
1670
Rational Field
1671
1672
sage: libgap.eval('ZmodnZ(15)').sage()
1673
Ring of integers modulo 15
1674
1675
sage: libgap.GF(3,2).sage(var='A')
1676
Finite Field in A of size 3^2
1677
1678
sage: libgap.CyclotomicField(6).sage()
1679
Cyclotomic Field of order 3 and degree 2
1680
"""
1681
if self.IsField():
1682
if self.IsRationals():
1683
return self.ring_rational(**kwds)
1684
if self.IsCyclotomicField():
1685
return self.ring_cyclotomic(**kwds)
1686
if self.IsFinite():
1687
return self.ring_finite_field(**kwds)
1688
else:
1689
if self.IsIntegers():
1690
return self.ring_integer(**kwds)
1691
if self.IsFinite():
1692
return self.ring_integer_mod(**kwds)
1693
raise NotImplementedError('cannot convert GAP ring to Sage')
1694
1695
1696
############################################################################
1697
### GapElement_Boolean #####################################################
1698
############################################################################
1699
1700
cdef GapElement_Boolean make_GapElement_Boolean(parent, libGAP_Obj obj):
1701
r"""
1702
Turn a Gap Boolean number (of type ``Obj``) into a Cython ``GapElement_Boolean``.
1703
1704
EXAMPLES::
1705
1706
sage: libgap(True)
1707
true
1708
sage: type(_)
1709
<type 'sage.libs.gap.element.GapElement_Boolean'>
1710
"""
1711
cdef GapElement_Boolean r = GapElement_Boolean.__new__(GapElement_Boolean)
1712
r._initialize(parent, obj)
1713
return r
1714
1715
1716
cdef class GapElement_Boolean(GapElement):
1717
r"""
1718
Derived class of GapElement for GAP boolean values.
1719
1720
EXAMPLES::
1721
1722
sage: b = libgap(True)
1723
sage: type(b)
1724
<type 'sage.libs.gap.element.GapElement_Boolean'>
1725
"""
1726
1727
def sage(self):
1728
r"""
1729
Return the Sage equivalent of the :class:`GapElement`
1730
1731
OUTPUT:
1732
1733
A Python boolean if the values is either true or false. GAP
1734
booleans can have the third value ``Fail``, in which case a
1735
``ValueError`` is raised.
1736
1737
EXAMPLES::
1738
1739
sage: b = libgap.eval('true'); b
1740
true
1741
sage: type(_)
1742
<type 'sage.libs.gap.element.GapElement_Boolean'>
1743
sage: b.sage()
1744
True
1745
sage: type(_)
1746
<type 'bool'>
1747
1748
sage: libgap.eval('fail')
1749
fail
1750
sage: _.sage()
1751
Traceback (most recent call last):
1752
...
1753
ValueError: the GAP boolean value "fail" cannot be represented in Sage
1754
"""
1755
if self.value == libGAP_True: return True
1756
if self.value == libGAP_False: return False
1757
raise ValueError('the GAP boolean value "fail" cannot be represented in Sage')
1758
1759
1760
def __nonzero__(self):
1761
"""
1762
Check that the boolean is "true".
1763
1764
This is syntactic sugar for using libgap. See the examples below.
1765
1766
OUTPUT:
1767
1768
Boolean.
1769
1770
EXAMPLES::
1771
1772
sage: gap_bool = [libgap.eval('true'), libgap.eval('false'), libgap.eval('fail')]
1773
sage: for x in gap_bool:
1774
... if x: # this calls __nonzero__
1775
... print x, type(x)
1776
true <type 'sage.libs.gap.element.GapElement_Boolean'>
1777
1778
sage: for x in gap_bool:
1779
... if not x: # this calls __nonzero__
1780
... print x, type(x)
1781
false <type 'sage.libs.gap.element.GapElement_Boolean'>
1782
fail <type 'sage.libs.gap.element.GapElement_Boolean'>
1783
"""
1784
return self.value == libGAP_True
1785
1786
1787
############################################################################
1788
### GapElement_String ####################################################
1789
############################################################################
1790
1791
cdef GapElement_String make_GapElement_String(parent, libGAP_Obj obj):
1792
r"""
1793
Turn a Gap String (of type ``Obj``) into a Cython ``GapElement_String``.
1794
1795
EXAMPLES::
1796
1797
sage: libgap('this is a string')
1798
"this is a string"
1799
sage: type(_)
1800
<type 'sage.libs.gap.element.GapElement_String'>
1801
"""
1802
cdef GapElement_String r = GapElement_String.__new__(GapElement_String)
1803
r._initialize(parent, obj)
1804
return r
1805
1806
1807
cdef class GapElement_String(GapElement):
1808
r"""
1809
Derived class of GapElement for GAP strings.
1810
1811
EXAMPLES::
1812
1813
sage: s = libgap('string')
1814
sage: type(s)
1815
<type 'sage.libs.gap.element.GapElement_String'>
1816
"""
1817
1818
def sage(self):
1819
r"""
1820
Return the Sage equivalent of the :class:`GapElement`
1821
1822
OUTPUT:
1823
1824
A Python list.
1825
1826
EXAMPLES::
1827
1828
sage: s = libgap.eval(' "string" '); s
1829
"string"
1830
sage: type(_)
1831
<type 'sage.libs.gap.element.GapElement_String'>
1832
sage: s.sage()
1833
'string'
1834
sage: type(_)
1835
<type 'str'>
1836
"""
1837
libgap_enter()
1838
s = libGAP_CSTR_STRING(self.value)
1839
libgap_exit()
1840
return s
1841
1842
1843
1844
############################################################################
1845
### GapElement_Function ####################################################
1846
############################################################################
1847
1848
cdef GapElement_Function make_GapElement_Function(parent, libGAP_Obj obj):
1849
r"""
1850
Turn a Gap C function object (of type ``Obj``) into a Cython ``GapElement_Function``.
1851
1852
INPUT:
1853
1854
- ``parent`` -- the parent of the new :class:`GapElement`
1855
1856
- ``obj`` -- a GAP function object.
1857
1858
OUTPUT:
1859
1860
A :class:`GapElement_Function` instance.
1861
1862
EXAMPLES::
1863
1864
sage: libgap.CycleLength
1865
<Gap function "CycleLength">
1866
sage: type(_)
1867
<type 'sage.libs.gap.element.GapElement_Function'>
1868
"""
1869
cdef GapElement_Function r = GapElement_Function.__new__(GapElement_Function)
1870
r._initialize(parent, obj)
1871
return r
1872
1873
1874
cdef class GapElement_Function(GapElement):
1875
r"""
1876
Derived class of GapElement for GAP functions.
1877
1878
EXAMPLES::
1879
1880
sage: f = libgap.Cycles
1881
sage: type(f)
1882
<type 'sage.libs.gap.element.GapElement_Function'>
1883
"""
1884
1885
1886
def __repr__(self):
1887
r"""
1888
Return a string representation
1889
1890
OUTPUT:
1891
1892
String.
1893
1894
EXAMPLES::
1895
1896
sage: libgap.Orbits
1897
<Gap function "Orbits">
1898
"""
1899
libgap = self.parent()
1900
name = libgap.NameFunction(self)
1901
s = '<Gap function "'+name.sage()+'">'
1902
return s
1903
1904
1905
def __call__(self, *args):
1906
"""
1907
Call syntax for functions.
1908
1909
INPUT:
1910
1911
- ``*args`` -- arguments. Will be converted to `GapElement` if
1912
they are not already of this type.
1913
1914
OUTPUT:
1915
1916
A :class:`GapElement` encapsulating the functions return
1917
value, or ``None`` if it does not return anything.
1918
1919
EXAMPLES::
1920
1921
sage: a = libgap.NormalSubgroups
1922
sage: b = libgap.SymmetricGroup(4)
1923
sage: libgap.collect()
1924
sage: a
1925
<Gap function "NormalSubgroups">
1926
sage: b
1927
Sym( [ 1 .. 4 ] )
1928
sage: a(b)
1929
[ Group(()),
1930
Group([ (1,4)(2,3), (1,3)(2,4) ]),
1931
Group([ (2,4,3), (1,4)(2,3), (1,3)(2,4) ]),
1932
Sym( [ 1 .. 4 ] ) ]
1933
1934
sage: libgap.eval("a := NormalSubgroups")
1935
<Gap function "NormalSubgroups">
1936
sage: libgap.eval("b := SymmetricGroup(4)")
1937
Sym( [ 1 .. 4 ] )
1938
sage: libgap.collect()
1939
sage: libgap.eval('a') (libgap.eval('b'))
1940
[ Group(()),
1941
Group([ (1,4)(2,3), (1,3)(2,4) ]),
1942
Group([ (2,4,3), (1,4)(2,3), (1,3)(2,4) ]),
1943
Sym( [ 1 .. 4 ] ) ]
1944
sage: a = libgap.eval('a')
1945
sage: b = libgap.eval('b')
1946
sage: libgap.collect()
1947
sage: a(b)
1948
[ Group(()),
1949
Group([ (1,4)(2,3), (1,3)(2,4) ]),
1950
Group([ (2,4,3), (1,4)(2,3), (1,3)(2,4) ]),
1951
Sym( [ 1 .. 4 ] ) ]
1952
1953
Not every ``GapElement`` is callable::
1954
1955
sage: f = libgap(3)
1956
sage: f()
1957
Traceback (most recent call last):
1958
...
1959
TypeError: 'sage.libs.gap.element.GapElement_Integer' object is not callable
1960
1961
We illustrate appending to a list which returns None::
1962
1963
sage: a = libgap([]); a
1964
[ ]
1965
sage: a.Add(5); a
1966
[ 5 ]
1967
sage: a.Add(10); a
1968
[ 5, 10 ]
1969
1970
TESTS::
1971
1972
sage: s = libgap.Sum
1973
sage: s(libgap([1,2]))
1974
3
1975
sage: s(libgap(1), libgap(2))
1976
Traceback (most recent call last):
1977
...
1978
ValueError: libGAP: Error, no method found!
1979
Error, no 1st choice method found for `SumOp' on 2 arguments
1980
1981
sage: for i in range(0,100):
1982
... rnd = [ randint(-10,10) for i in range(0,randint(0,7)) ]
1983
... # compute the sum in GAP
1984
... _ = libgap.Sum(rnd)
1985
... try:
1986
... libgap.Sum(*rnd)
1987
... print 'This should have triggered a ValueError'
1988
... print 'because Sum needs a list as argument'
1989
... except ValueError:
1990
... pass
1991
1992
sage: libgap_exec = libgap.eval("Exec")
1993
sage: libgap_exec('echo hello from the shell > /dev/null')
1994
"""
1995
cdef libGAP_Obj result = NULL
1996
cdef libGAP_Obj arg_list
1997
cdef int i, n = len(args)
1998
1999
if n > 0:
2000
libgap = self.parent()
2001
a = [x if isinstance(x,GapElement) else libgap(x) for x in args]
2002
2003
try:
2004
libgap_enter()
2005
sig_on()
2006
if n == 0:
2007
result = libGAP_CALL_0ARGS(self.value)
2008
elif n == 1:
2009
result = libGAP_CALL_1ARGS(self.value,
2010
(<GapElement>a[0]).value)
2011
elif n == 2:
2012
result = libGAP_CALL_2ARGS(self.value,
2013
(<GapElement>a[0]).value,
2014
(<GapElement>a[1]).value)
2015
elif n == 3:
2016
result = libGAP_CALL_3ARGS(self.value,
2017
(<GapElement>a[0]).value,
2018
(<GapElement>a[1]).value,
2019
(<GapElement>a[2]).value)
2020
elif n == 4:
2021
result = libGAP_CALL_4ARGS(self.value,
2022
(<GapElement>a[0]).value,
2023
(<GapElement>a[1]).value,
2024
(<GapElement>a[2]).value,
2025
(<GapElement>a[3]).value)
2026
elif n == 5:
2027
result = libGAP_CALL_5ARGS(self.value,
2028
(<GapElement>a[0]).value,
2029
(<GapElement>a[1]).value,
2030
(<GapElement>a[2]).value,
2031
(<GapElement>a[3]).value,
2032
(<GapElement>a[4]).value)
2033
elif n == 6:
2034
result = libGAP_CALL_6ARGS(self.value,
2035
(<GapElement>a[0]).value,
2036
(<GapElement>a[1]).value,
2037
(<GapElement>a[2]).value,
2038
(<GapElement>a[3]).value,
2039
(<GapElement>a[4]).value,
2040
(<GapElement>a[5]).value)
2041
elif n >= 7:
2042
libgap_exit()
2043
arg_list = make_gap_list(args)
2044
libgap_enter()
2045
result = libGAP_CALL_XARGS(self.value, arg_list)
2046
sig_off()
2047
except RuntimeError, msg:
2048
raise ValueError('libGAP: '+str(msg))
2049
finally:
2050
libgap_exit()
2051
2052
if result == NULL:
2053
# We called a procedure that does not return anything
2054
return None
2055
2056
return make_any_gap_element(self.parent(), result)
2057
2058
2059
def _sage_doc_(self):
2060
r"""
2061
Return the help string
2062
2063
EXAMPLES::
2064
2065
sage: f = libgap.CyclicGroup
2066
sage: 'constructs the cyclic group' in f._sage_doc_()
2067
True
2068
2069
You would get the full help by typing ``f?`` in the command line.
2070
"""
2071
libgap = self.parent()
2072
from sage.interfaces.gap import gap
2073
return gap.help(libgap.NameFunction(self).sage(), pager=False)
2074
2075
2076
2077
2078
############################################################################
2079
### GapElement_MethodProxy #################################################
2080
############################################################################
2081
2082
cdef GapElement_MethodProxy make_GapElement_MethodProxy(parent, libGAP_Obj function, GapElement base_object):
2083
r"""
2084
Turn a Gap C rec object (of type ``Obj``) into a Cython ``GapElement_Record``.
2085
2086
This class implement syntactic sugar so that you can write
2087
``gapelement.f()`` instead of ``libgap.f(gapelement)`` for any GAP
2088
function ``f``.
2089
2090
INPUT:
2091
2092
- ``parent`` -- the parent of the new :class:`GapElement`
2093
2094
- ``obj`` -- a GAP function object.
2095
2096
- ``base_object`` -- The first argument to be inserted into the function.
2097
2098
OUTPUT:
2099
2100
A :class:`GapElement_MethodProxy` instance.
2101
2102
EXAMPLES::
2103
2104
sage: lst = libgap([])
2105
sage: type( lst.Add )
2106
<type 'sage.libs.gap.element.GapElement_MethodProxy'>
2107
"""
2108
cdef GapElement_MethodProxy r = GapElement_MethodProxy.__new__(GapElement_MethodProxy)
2109
r._initialize(parent, function)
2110
r.first_argument = base_object
2111
return r
2112
2113
2114
cdef class GapElement_MethodProxy(GapElement_Function):
2115
r"""
2116
Helper class returned by ``GapElement.__getattr__``.
2117
2118
Derived class of GapElement for GAP functions. Like its parent,
2119
you can call instances to implement function call syntax. The only
2120
difference is that a fixed first argument is prepended to the
2121
argument list.
2122
2123
EXAMPLES::
2124
2125
sage: lst = libgap([])
2126
sage: lst.Add
2127
<Gap function "Add">
2128
sage: type(_)
2129
<type 'sage.libs.gap.element.GapElement_MethodProxy'>
2130
sage: lst.Add(1)
2131
sage: lst
2132
[ 1 ]
2133
"""
2134
2135
def __call__(self, *args):
2136
"""
2137
Call syntax for methods.
2138
2139
This method is analogous to
2140
:meth:`GapElement_Function.__call__`, except that it inserts a
2141
fixed :class:`GapElement` in the first slot of the function.
2142
2143
INPUT:
2144
2145
- ``*args`` -- arguments. Will be converted to `GapElement` if
2146
they are not already of this type.
2147
2148
OUTPUT:
2149
2150
A :class:`GapElement` encapsulating the functions return
2151
value, or ``None`` if it does not return anything.
2152
2153
EXAMPLES::
2154
2155
sage: lst = libgap.eval('[1,,3]')
2156
sage: lst.Add.__call__(4)
2157
sage: lst.Add(5)
2158
sage: lst
2159
[ 1,, 3, 4, 5 ]
2160
"""
2161
if len(args) > 0:
2162
return GapElement_Function.__call__(self, * ([self.first_argument] + list(args)))
2163
else:
2164
return GapElement_Function.__call__(self, self.first_argument)
2165
2166
2167
2168
############################################################################
2169
### GapElement_List ########################################################
2170
############################################################################
2171
2172
cdef GapElement_List make_GapElement_List(parent, libGAP_Obj obj):
2173
r"""
2174
Turn a Gap C List object (of type ``Obj``) into a Cython ``GapElement_List``.
2175
2176
EXAMPLES::
2177
2178
sage: libgap([0, 2, 3])
2179
[ 0, 2, 3 ]
2180
sage: type(_)
2181
<type 'sage.libs.gap.element.GapElement_List'>
2182
"""
2183
cdef GapElement_List r = GapElement_List.__new__(GapElement_List)
2184
r._initialize(parent, obj)
2185
return r
2186
2187
2188
cdef class GapElement_List(GapElement):
2189
r"""
2190
Derived class of GapElement for GAP Lists.
2191
2192
.. NOTE::
2193
2194
Lists are indexed by `0..len(l)-1`, as expected from
2195
Python. This differs from the GAP convention where lists start
2196
at `1`.
2197
2198
EXAMPLES::
2199
2200
sage: lst = libgap.SymmetricGroup(3).List(); lst
2201
[ (), (1,3), (1,2,3), (2,3), (1,3,2), (1,2) ]
2202
sage: type(lst)
2203
<type 'sage.libs.gap.element.GapElement_List'>
2204
sage: len(lst)
2205
6
2206
sage: lst[3]
2207
(2,3)
2208
2209
We can easily convert a Gap ``List`` object into a Python ``list``::
2210
2211
sage: list(lst)
2212
[(), (1,3), (1,2,3), (2,3), (1,3,2), (1,2)]
2213
sage: type(_)
2214
<type 'list'>
2215
2216
Range checking is performed::
2217
2218
sage: lst[10]
2219
Traceback (most recent call last):
2220
...
2221
IndexError: index out of range.
2222
"""
2223
2224
def __len__(self):
2225
r"""
2226
Return the length of the list.
2227
2228
OUTPUT:
2229
2230
Integer.
2231
2232
EXAMPLES::
2233
2234
sage: lst = libgap.eval('[1,,,4]') # a sparse list
2235
sage: len(lst)
2236
4
2237
"""
2238
return libGAP_LEN_PLIST(self.value)
2239
2240
2241
def __getitem__(self, i):
2242
r"""
2243
Return the ``i``-th element of the list.
2244
2245
As usual in Python, indexing starts at `0` and not at `1` (as
2246
in GAP).
2247
2248
INPUT:
2249
2250
- ``i`` -- integer.
2251
2252
OUTPUT:
2253
2254
The ``i``-th element as a :class:`GapElement`.
2255
2256
EXAMPLES::
2257
2258
sage: lst = libgap.eval('["first",,,"last"]') # a sparse list
2259
sage: lst[0]
2260
"first"
2261
"""
2262
if i<0 or i>=len(self):
2263
raise IndexError('index out of range.')
2264
return make_any_gap_element(self.parent(),
2265
libGAP_ELM_PLIST(self.value, i+1))
2266
2267
2268
def sage(self, **kwds):
2269
r"""
2270
Return the Sage equivalent of the :class:`GapElement`
2271
2272
OUTPUT:
2273
2274
A Python list.
2275
2276
EXAMPLES::
2277
2278
sage: libgap([ 1, 3, 4 ]).sage()
2279
[1, 3, 4]
2280
sage: all( x in ZZ for x in _ )
2281
True
2282
"""
2283
return [ x.sage(**kwds) for x in self ]
2284
2285
2286
2287
############################################################################
2288
### GapElement_Permutation #################################################
2289
############################################################################
2290
2291
2292
cdef GapElement_Permutation make_GapElement_Permutation(parent, libGAP_Obj obj):
2293
r"""
2294
Turn a Gap C permutation object (of type ``Obj``) into a Cython ``GapElement_Permutation``.
2295
2296
EXAMPLES::
2297
2298
sage: libgap.eval('(1,3,2)(4,5,8)')
2299
(1,3,2)(4,5,8)
2300
sage: type(_)
2301
<type 'sage.libs.gap.element.GapElement_Permutation'>
2302
"""
2303
cdef GapElement_Permutation r = GapElement_Permutation.__new__(GapElement_Permutation)
2304
r._initialize(parent, obj)
2305
return r
2306
2307
2308
cdef class GapElement_Permutation(GapElement):
2309
r"""
2310
Derived class of GapElement for GAP permutations.
2311
2312
.. NOTE::
2313
2314
Permutations in GAP act on the numbers starting with 1.
2315
2316
EXAMPLES::
2317
2318
sage: perm = libgap.eval('(1,5,2)(4,3,8)')
2319
sage: type(perm)
2320
<type 'sage.libs.gap.element.GapElement_Permutation'>
2321
"""
2322
2323
def sage(self):
2324
r"""
2325
Return the Sage equivalent of the :class:`GapElement`
2326
2327
EXAMPLES::
2328
2329
sage: perm_gap = libgap.eval('(1,5,2)(4,3,8)'); perm_gap
2330
(1,5,2)(3,8,4)
2331
sage: perm_gap.sage()
2332
(1,5,2)(3,8,4)
2333
sage: type(_)
2334
<type 'sage.groups.perm_gps.permgroup_element.PermutationGroupElement'>
2335
"""
2336
from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
2337
libgap = self.parent()
2338
return PermutationGroupElement(libgap.ListPerm(self).sage())
2339
2340
2341
2342
############################################################################
2343
### GapElement_Record ######################################################
2344
############################################################################
2345
2346
cdef GapElement_Record make_GapElement_Record(parent, libGAP_Obj obj):
2347
r"""
2348
Turn a Gap C rec object (of type ``Obj``) into a Cython ``GapElement_Record``.
2349
2350
EXAMPLES::
2351
2352
sage: libgap.eval('rec(a:=0, b:=2, c:=3)')
2353
rec( a := 0, b := 2, c := 3 )
2354
sage: type(_)
2355
<type 'sage.libs.gap.element.GapElement_Record'>
2356
"""
2357
cdef GapElement_Record r = GapElement_Record.__new__(GapElement_Record)
2358
r._initialize(parent, obj)
2359
return r
2360
2361
2362
cdef class GapElement_Record(GapElement):
2363
r"""
2364
Derived class of GapElement for GAP records.
2365
2366
EXAMPLES::
2367
2368
sage: rec = libgap.eval('rec(a:=123, b:=456)')
2369
sage: type(rec)
2370
<type 'sage.libs.gap.element.GapElement_Record'>
2371
sage: len(rec)
2372
2
2373
sage: rec['a']
2374
123
2375
2376
We can easily convert a Gap ``rec`` object into a Python ``dict``::
2377
2378
sage: dict(rec)
2379
{'a': 123, 'b': 456}
2380
sage: type(_)
2381
<type 'dict'>
2382
2383
Range checking is performed::
2384
2385
sage: rec['no_such_element']
2386
Traceback (most recent call last):
2387
...
2388
IndexError: libGAP: Error, Record: '<rec>.no_such_element' must have an assigned value
2389
"""
2390
2391
def __len__(self):
2392
r"""
2393
Return the length of the record.
2394
2395
OUTPUT:
2396
2397
Integer. The number of entries in the record.
2398
2399
EXAMPLES::
2400
2401
sage: rec = libgap.eval('rec(a:=123, b:=456, S3:=SymmetricGroup(3))')
2402
sage: len(rec)
2403
3
2404
"""
2405
return libGAP_LEN_PREC(self.value)
2406
2407
2408
def __iter__(self):
2409
r"""
2410
Iterate over the elements of the record.
2411
2412
OUTPUT:
2413
2414
A :class:`GapElement_RecordIterator`.
2415
2416
EXAMPLES::
2417
2418
sage: rec = libgap.eval('rec(a:=123, b:=456)')
2419
sage: iter = rec.__iter__()
2420
sage: type(iter)
2421
<type 'sage.libs.gap.element.GapElement_RecordIterator'>
2422
sage: list(rec)
2423
[('a', 123), ('b', 456)]
2424
"""
2425
return GapElement_RecordIterator(self)
2426
2427
2428
cpdef libGAP_UInt record_name_to_index(self, bytes py_name):
2429
r"""
2430
Convert string to GAP record index.
2431
2432
INPUT:
2433
2434
- ``py_name`` -- a python string.
2435
2436
OUTPUT:
2437
2438
A ``UInt``, which is a GAP hash of the string. If this is the
2439
first time the string is encountered, a new integer is
2440
returned(!)
2441
2442
EXAMPLE::
2443
2444
sage: rec = libgap.eval('rec(first:=123, second:=456)')
2445
sage: rec.record_name_to_index('first') # random output
2446
1812L
2447
sage: rec.record_name_to_index('no_such_name') # random output
2448
3776L
2449
"""
2450
cdef char* c_name = py_name
2451
try:
2452
libgap_enter()
2453
return libGAP_RNamName(c_name)
2454
finally:
2455
libgap_exit()
2456
2457
def __getitem__(self, name):
2458
r"""
2459
Return the ``name``-th element of the GAP record.
2460
2461
INPUT:
2462
2463
- ``name`` -- string.
2464
2465
OUTPUT:
2466
2467
The record element labelled by ``name`` as a :class:`GapElement`.
2468
2469
EXAMPLES::
2470
2471
sage: rec = libgap.eval('rec(first:=123, second:=456)')
2472
sage: rec['first']
2473
123
2474
"""
2475
cdef libGAP_UInt i = self.record_name_to_index(name)
2476
cdef libGAP_Obj result
2477
try:
2478
sig_on()
2479
result = libGAP_ELM_REC(self.value, i)
2480
sig_off()
2481
except RuntimeError, msg:
2482
raise IndexError('libGAP: '+str(msg))
2483
return make_any_gap_element(self.parent(), result)
2484
2485
2486
def sage(self):
2487
r"""
2488
Return the Sage equivalent of the :class:`GapElement`
2489
2490
EXAMPLES::
2491
2492
sage: libgap.eval('rec(a:=1, b:=2)').sage()
2493
{'a': 1, 'b': 2}
2494
sage: all( isinstance(key,str) and val in ZZ for key,val in _.items() )
2495
True
2496
2497
sage: rec = libgap.eval('rec(a:=123, b:=456, Sym3:=SymmetricGroup(3))')
2498
sage: rec.sage()
2499
{'a': 123,
2500
'Sym3': NotImplementedError('cannot construct equivalent Sage object',),
2501
'b': 456}
2502
"""
2503
result = dict()
2504
for key, val in self:
2505
try:
2506
val = val.sage()
2507
except Exception as ex:
2508
val = ex
2509
result[key] = val
2510
return result
2511
2512
2513
cdef class GapElement_RecordIterator(object):
2514
r"""
2515
Iterator for :class:`GapElement_Record`
2516
2517
Since Cython does not support generators yet, we implement the
2518
older iterator specification with this auxiliary class.
2519
2520
INPUT:
2521
2522
- ``rec`` -- the :class:`GapElement_Record` to iterate over.
2523
2524
EXAMPLES::
2525
2526
sage: rec = libgap.eval('rec(a:=123, b:=456)')
2527
sage: list(rec)
2528
[('a', 123), ('b', 456)]
2529
sage: dict(rec)
2530
{'a': 123, 'b': 456}
2531
"""
2532
2533
def __cinit__(self, rec):
2534
r"""
2535
The Cython constructor.
2536
2537
INPUT:
2538
2539
- ``rec`` -- the :class:`GapElement_Record` to iterate over.
2540
2541
EXAMPLES::
2542
2543
sage: libgap.eval('rec(a:=123, b:=456)')
2544
rec( a := 123, b := 456 )
2545
"""
2546
self.rec = rec
2547
self.i = 1
2548
2549
2550
def __next__(self):
2551
r"""
2552
The next elemnt in the record.
2553
2554
OUTPUT:
2555
2556
A tuple ``(key, value)`` where ``key`` is a string and
2557
``value`` is the corresponding :class:`GapElement`.
2558
2559
EXAMPLES::
2560
2561
sage: rec = libgap.eval('rec(a:=123, b:=456)')
2562
sage: iter = rec.__iter__()
2563
sage: iter.__next__()
2564
('a', 123)
2565
sage: iter.next()
2566
('b', 456)
2567
"""
2568
cdef libGAP_UInt i = self.i
2569
if i>len(self.rec):
2570
raise StopIteration
2571
# note the abs: negative values mean the rec keys are not sorted
2572
libgap_enter()
2573
key_index = abs(libGAP_GET_RNAM_PREC(self.rec.value, i))
2574
key = libGAP_NAME_RNAM(key_index)
2575
cdef libGAP_Obj result = libGAP_GET_ELM_PREC(self.rec.value,i)
2576
libgap_exit()
2577
val = make_any_gap_element(self.rec.parent(), result)
2578
self.i += 1
2579
return (key, val)
2580
2581