Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/structure/category_object.pyx
4045 views
1
r"""
2
Base class for objects of a category
3
4
CLASS HIERARCHY:
5
6
- :class:`~sage.structure.sage_object.SageObject`
7
8
- **CategoryObject**
9
10
- :class:`~sage.structure.parent.Parent`
11
12
Many category objects in Sage are equipped with generators, which are
13
usually special elements of the object. For example, the polynomial ring
14
`\ZZ[x,y,z]` is generated by `x`, `y`, and `z`. In Sage the ``i`` th
15
generator of an object ``X`` is obtained using the notation
16
``X.gen(i)``. From the Sage interactive prompt, the shorthand
17
notation ``X.i`` is also allowed.
18
19
The following examples illustrate these functions in the context of
20
multivariate polynomial rings and free modules.
21
22
EXAMPLES::
23
24
sage: R = PolynomialRing(ZZ, 3, 'x')
25
sage: R.ngens()
26
3
27
sage: R.gen(0)
28
x0
29
sage: R.gens()
30
(x0, x1, x2)
31
sage: R.variable_names()
32
('x0', 'x1', 'x2')
33
34
This example illustrates generators for a free module over `\ZZ`.
35
36
::
37
38
sage: M = FreeModule(ZZ, 4)
39
sage: M
40
Ambient free module of rank 4 over the principal ideal domain Integer Ring
41
sage: M.ngens()
42
4
43
sage: M.gen(0)
44
(1, 0, 0, 0)
45
sage: M.gens()
46
((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
47
"""
48
49
cdef int bad_parent_warnings = 0
50
51
import generators
52
import sage_object
53
from sage.categories.category import Category, JoinCategory
54
55
def guess_category(obj):
56
# this should be obsolete if things declare their categories
57
try:
58
if obj.is_field():
59
from sage.categories.all import Fields
60
return Fields()
61
except:
62
pass
63
try:
64
if obj.is_ring():
65
from sage.categories.all import CommutativeAlgebras, Algebras, CommutativeRings, Rings
66
if obj.is_commutative():
67
if obj._base is not obj:
68
return CommutativeAlgebras(obj._base)
69
else:
70
return CommutativeRings()
71
else:
72
if obj._base is not obj:
73
return Algebras(obj._base)
74
else:
75
return Rings()
76
except:
77
pass
78
from sage.structure.parent import Parent
79
#if isinstance(obj, Parent):
80
# import sys
81
# sys.stderr.write("bla: %s"%obj)
82
# from sage.categories.all import Sets
83
# return Sets()
84
return None # don't want to risk importing stuff...
85
86
cpdef inline check_default_category(default_category, category):
87
"""
88
89
"""
90
## The resulting category is guaranteed to be
91
## a sub-category of the default.
92
if category is None:
93
return default_category
94
return default_category.join([default_category,category])
95
96
cdef class CategoryObject(sage_object.SageObject):
97
"""
98
An object in some category.
99
"""
100
def __init__(self, category = None, base = None):
101
"""
102
Initializes an object in a category
103
104
INPUT:
105
106
- ``category`` - The category this object belongs to. If this object
107
belongs to multiple categories, those can be passed as a tuple
108
- ``base`` - If this object has another object that should be
109
considered a base in its primary category, you can include that base
110
here.
111
112
EXAMPLES::
113
114
sage: from sage.structure.category_object import CategoryObject
115
sage: A = CategoryObject()
116
sage: A.category()
117
Category of objects
118
sage: A.base()
119
120
sage: A = CategoryObject(category = Rings(), base = QQ)
121
sage: A.category()
122
Category of rings
123
sage: A.base()
124
Rational Field
125
126
sage: A = CategoryObject(category = (Semigroups(), CommutativeAdditiveSemigroups()))
127
sage: A.category()
128
Join of Category of semigroups and Category of commutative additive semigroups
129
130
FIXME: the base and generators attributes have nothing to do with categories, do they?
131
"""
132
if base is not None:
133
self._base = base
134
self._generators = {}
135
if category is not None:
136
self._init_category_(category)
137
138
def __cinit__(self):
139
self._hash_value = -1
140
141
def _init_category_(self, category):
142
"""
143
Sets the category or categories of this object.
144
145
EXAMPLES::
146
147
sage: A = sage.structure.category_object.CategoryObject()
148
sage: A._init_category_(Rings())
149
sage: A.category()
150
Category of rings
151
sage: A._init_category_((Semigroups(), CommutativeAdditiveSemigroups()))
152
sage: A.category()
153
Join of Category of semigroups and Category of commutative additive semigroups
154
"""
155
if category is None:
156
if bad_parent_warnings:
157
print "No category for %s" % type(self)
158
category = guess_category(self) # so generators don't crash
159
elif (type(category) == tuple or type(category) == list):
160
assert(len(category)>0) # or we should decide of the semantic for an empty category
161
if len(category) == 1:
162
category = category[0]
163
else:
164
category = JoinCategory(category)
165
self._category = category
166
167
def _refine_category_(self, category):
168
"""
169
Changes the category of ``self`` into a subcategory.
170
171
INPUT:
172
173
- ``category`` -- a category or list or tuple thereof
174
175
The new category is obtained by adjoining ``category`` to the
176
current one.
177
178
.. seealso:: :function:`Category.join`
179
180
EXAMPLES::
181
182
sage: P = Parent()
183
sage: P.category()
184
Category of sets
185
sage: P._refine_category_(Magmas())
186
sage: P.category()
187
Category of magmas
188
sage: P._refine_category_(Magmas())
189
sage: P.category()
190
Category of magmas
191
sage: P._refine_category_(EnumeratedSets())
192
sage: P.category()
193
Join of Category of magmas and Category of enumerated sets
194
sage: P._refine_category_([Semigroups(), CommutativeAdditiveSemigroups()])
195
sage: P.category()
196
Join of Category of enumerated sets and Category of semigroups and Category of commutative additive semigroups
197
sage: P._refine_category_((CommutativeAdditiveMonoids(), Monoids()))
198
sage: P.category()
199
Join of Category of enumerated sets and Category of commutative additive monoids and Category of monoids
200
201
"""
202
if self._category is None:
203
self._init_category_(category)
204
return
205
if not (type(category) == tuple or type(category) == list):
206
category = [category]
207
self._category = self._category.join([self._category]+list(category))
208
209
def _is_category_initialized(self):
210
return self._category is not None
211
212
def category(self):
213
if self._category is None:
214
# COERCE TODO: we shouldn't need this
215
from sage.categories.objects import Objects
216
self._category = Objects()
217
return self._category
218
219
def categories(self):
220
"""
221
EXAMPLES::
222
223
sage: ZZ.categories()
224
[Category of euclidean domains,
225
Category of principal ideal domains,
226
Category of unique factorization domains,
227
Category of gcd domains,
228
Category of integral domains,
229
Category of commutative rings,
230
Category of domains,
231
Category of rings,
232
Category of rngs,
233
Category of commutative additive groups,
234
Category of semirings,
235
Category of commutative additive monoids,
236
Category of commutative additive semigroups,
237
Category of additive magmas,
238
Category of monoids,
239
Category of semigroups,
240
Category of magmas,
241
Category of sets,
242
Category of sets with partial maps,
243
Category of objects]
244
"""
245
return self.category().all_super_categories()
246
247
##############################################################################
248
# Generators
249
##############################################################################
250
251
def _populate_generators_(self, gens=None, names=None, normalize = True, category=None):
252
if self._generators.has_key(category):
253
raise ValueError, "Generators cannot be changed after object creation."
254
if category is None:
255
category = self._category
256
from sage.structure.sequence import Sequence
257
if gens is None:
258
n = self._ngens_()
259
from sage.rings.infinity import infinity
260
if n is infinity:
261
gens = generators.Generators_naturals(self, category)
262
else:
263
gens = generators.Generators_finite(self, self._ngens_(), None, category)
264
elif isinstance(gens, Generators):
265
pass
266
elif isinstance(gens, (list, tuple, Sequence)):
267
if names is None:
268
names = tuple([str(x) for x in gens])
269
gens = generators.Generators_list(self, list(gens), category)
270
else:
271
gens = generators.Generators_list(self, [gens], category)
272
self._generators[category] = gens
273
if category == self._category:
274
if names is not None and self._names is None:
275
self._assign_names(names, ngens=gens.count(), normalize=normalize)
276
self._generators[category] = gens
277
278
# cpdef Generators gens(self, category=None):
279
# if category is None:
280
# category = self._categories[0]
281
# try:
282
# return self._generators[category]
283
# except KeyError:
284
# if category == self._categories[0]:
285
# n = self._ngens_()
286
# from sage.rings.infinity import infinity
287
# if n is infinity:
288
# gens = generators.Generators_naturals(self, category)
289
# else:
290
# gens = generators.Generators_finite(self, self._ngens_(), None, category)
291
# else:
292
# gens = self._compute_generators_(category)
293
# self._generators[category] = gens
294
# return gens
295
#
296
# cpdef gen(self, index=0, category=None):
297
# return self.gens(category)[index]
298
#
299
# cpdef ngens(self, category=None):
300
# return self.gens(category).count()
301
302
def _ngens_(self):
303
return 0
304
305
def gens_dict(self):
306
r"""
307
Return a dictionary whose entries are ``{var_name:variable,...}``.
308
"""
309
if HAS_DICTIONARY(self):
310
try:
311
if self._gens_dict is not None:
312
return self._gens_dict
313
except AttributeError:
314
pass
315
v = {}
316
for x in self.gens():
317
v[str(x)] = x
318
if HAS_DICTIONARY(self):
319
self._gens_dict = v
320
return v
321
322
def objgens(self):
323
"""
324
Return the tuple ``(self, self.gens())``.
325
326
EXAMPLES::
327
328
sage: R = PolynomialRing(QQ, 3, 'x'); R
329
Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
330
sage: R.objgens()
331
(Multivariate Polynomial Ring in x0, x1, x2 over Rational Field, (x0, x1, x2))
332
"""
333
return self, self.gens()
334
335
def objgen(self):
336
"""
337
Return the tuple ``(self, self.gen())``.
338
339
EXAMPLES::
340
341
sage: R, x = PolynomialRing(QQ,'x').objgen()
342
sage: R
343
Univariate Polynomial Ring in x over Rational Field
344
sage: x
345
x
346
"""
347
return self, self.gen()
348
349
def _first_ngens(self, n):
350
"""
351
Used by the preparser for R.<x> = ...
352
"""
353
return self.gens()[:n]
354
355
#################################################################################################
356
# Names and Printers
357
#################################################################################################
358
359
def _assign_names(self, names=None, normalize=True, ngens=None):
360
"""
361
Set the names of the generator of this object.
362
363
This can only be done once because objects with generators
364
are immutable, and is typically done during creation of the object.
365
366
367
EXAMPLES:
368
When we create this polynomial ring, self._assign_names is called by the constructor::
369
370
sage: R = QQ['x,y,abc']; R
371
Multivariate Polynomial Ring in x, y, abc over Rational Field
372
sage: R.2
373
abc
374
375
We can't rename the variables::
376
377
sage: R._assign_names(['a','b','c'])
378
Traceback (most recent call last):
379
...
380
ValueError: variable names cannot be changed after object creation.
381
"""
382
# this will eventually all be handled by the printer
383
if names is None: return
384
if normalize:
385
if ngens is None:
386
if self._generators is None or len(self._generators) == 0:
387
# not defined yet
388
if isinstance(names, (tuple, list)) and names is not None:
389
ngens = len(names)
390
else:
391
ngens = 1
392
else:
393
ngens = self.ngens()
394
names = self.normalize_names(ngens, names)
395
if self._names is not None and names != self._names:
396
raise ValueError, 'variable names cannot be changed after object creation.'
397
if PY_TYPE_CHECK(names, str):
398
names = (names, ) # make it a tuple
399
elif PY_TYPE_CHECK(names, list):
400
names = tuple(names)
401
elif not PY_TYPE_CHECK(names, tuple):
402
raise TypeError, "names must be a tuple of strings"
403
self._names = names
404
405
def normalize_names(self, int ngens, names=None):
406
if names is None:
407
return None
408
if ngens == 0:
409
return ()
410
if isinstance(names, str) and names.find(',') != -1:
411
names = names.split(',')
412
if isinstance(names, str) and ngens > 1 and len(names) == ngens:
413
names = tuple(names)
414
if isinstance(names, str):
415
name = names
416
import sage.misc.defaults
417
names = sage.misc.defaults.variable_names(ngens, name)
418
names = self._certify_names(names)
419
else:
420
names = self._certify_names(names)
421
if not isinstance(names, (list, tuple)):
422
raise TypeError, "names must be a list or tuple of strings"
423
for x in names:
424
if not isinstance(x,str):
425
raise TypeError, "names must consist of strings"
426
if len(names) != ngens:
427
raise IndexError, "the number of names must equal the number of generators"
428
return names
429
430
def _certify_names(self, names):
431
v = []
432
try:
433
names = tuple(names)
434
except TypeError:
435
names = [str(names)]
436
for N in names:
437
if not isinstance(N, str):
438
N = str(N)
439
N = N.strip().strip("'")
440
if len(N) == 0:
441
raise ValueError, "variable name must be nonempty"
442
if not N.isalnum() and not N.replace("_","").isalnum():
443
# We must be alphanumeric, but we make an exception for non-leading '_' characters.
444
raise ValueError, "variable names must be alphanumeric, but one is '%s' which is not."%N
445
if not N[0].isalpha():
446
raise ValueError, "first letter of variable name must be a letter: %s" % N
447
v.append(N)
448
return tuple(v)
449
450
def variable_names(self):
451
if self._names != None:
452
return self._names
453
raise ValueError, "variable names have not yet been set using self._assign_names(...)"
454
455
def variable_name(self):
456
return self.variable_names()[0]
457
458
def __temporarily_change_names(self, names, latex_names):
459
"""
460
This is used by the variable names context manager.
461
462
TEST:
463
464
In an old version, it was impossible to temporarily change
465
the names if no names were previously assigned. But if one
466
wants to print elements of the quotient of such an "unnamed"
467
ring, an error resulted. That was fixed in trac ticket
468
#11068.
469
::
470
471
sage: MS = MatrixSpace(GF(5),2,2)
472
sage: I = MS*[MS.0*MS.1,MS.2+MS.3]*MS
473
sage: Q.<a,b,c,d> = MS.quo(I)
474
sage: a #indirect doctest
475
[1 0]
476
[0 0]
477
478
"""
479
#old = self._names, self._latex_names
480
# We can not assume that self *has* _latex_variable_names.
481
# But there is a method that returns them and sets
482
# the attribute at the same time, if needed.
483
# Simon King: It is not necessarily the case that variable
484
# names are assigned. In that case, self._names is None,
485
# and self.variable_names() raises a ValueError
486
try:
487
old = self.variable_names(), self.latex_variable_names()
488
except ValueError:
489
old = None, None
490
self._names, self._latex_names = names, latex_names
491
return old
492
493
def inject_variables(self, scope=None, verbose=True):
494
"""
495
Inject the generators of self with their names into the
496
namespace of the Python code from which this function is
497
called. Thus, e.g., if the generators of self are labeled
498
'a', 'b', and 'c', then after calling this method the
499
variables a, b, and c in the current scope will be set
500
equal to the generators of self.
501
502
NOTE: If Foo is a constructor for a Sage object with generators, and
503
Foo is defined in Cython, then it would typically call
504
``inject_variables()`` on the object it creates. E.g.,
505
``PolynomialRing(QQ, 'y')`` does this so that the variable y is the
506
generator of the polynomial ring.
507
"""
508
vs = self.variable_names()
509
gs = self.gens()
510
if scope is None:
511
scope = globals()
512
if verbose:
513
print "Defining %s"%(', '.join(vs))
514
for v, g in zip(vs, gs):
515
scope[v] = g
516
517
def injvar(self, scope=None, verbose=True):
518
"""
519
This is a deprecated synonym for :meth:`.inject_variables`.
520
"""
521
from sage.misc.misc import deprecation
522
deprecation('injvar is deprecated; use inject_variables instead.')
523
return self.inject_variables(scope=scope, verbose=verbose)
524
525
#################################################################################################
526
# Bases
527
#################################################################################################
528
529
# cpdef base(self, category=None):
530
# if category is None:
531
# return self._base
532
# else:
533
# return category._obj_base(self)
534
535
def has_base(self, category=None):
536
if category is None:
537
return self._base is not None
538
else:
539
return category._obj_base(self) is not None
540
541
# cpdef base_extend(self, other, category=None):
542
# """
543
# EXAMPLES:
544
# sage: QQ.base_extend(GF(7))
545
# Traceback (most recent call last):
546
# ...
547
# TypeError: base extension not defined for Rational Field
548
# sage: ZZ.base_extend(GF(7))
549
# Finite Field of size 7
550
# """
551
# try:
552
# if category is None:
553
# method = self._category.get_object_method("base_extend") # , self._categories[1:])
554
# else:
555
# method = category.get_object_method("base_extend")
556
# return method(self)
557
# except AttributeError:
558
# raise TypeError, "base extension not defined for %s" % self
559
560
# COERCE TODO: When everything has a category, move let it be an optional arg.
561
def base_ring(self): # This should be in a category or elsewhere, but not here
562
return self._base
563
564
def base(self):
565
return self._base
566
567
#################################################################################################
568
# Automatic lookup of methods on the category.
569
#################################################################################################
570
571
# def __getattr__(self, name):
572
# """
573
# Overriding the __getattr__ method allows one to define methods for objects in a particular
574
# category by writing a corresponding method on the category.
575
#
576
# In order to write a method called FOO that's automatically attached to a category object,
577
# write a method object_FOO on one of that object's categories.
578
#
579
# EXAMPLES:
580
# sage: G = DirichletGroup(18); G
581
# Group of Dirichlet characters of modulus 18 over Cyclotomic Field of order 6 and degree 2
582
# sage: G.generator_orders()
583
# [1, 6]
584
# sage: G.category().object_generator_orders(G)
585
# [1, 6]
586
# """
587
# if self._category is not None:
588
# attr = self._category.get_object_method(name)
589
# if attr is not None:
590
# if callable(attr):
591
# return FillFirstArg(attr, self)
592
# else:
593
# return attr
594
# return object.__getattribute__(self, name)
595
596
############################################################################
597
# Homomorphism --
598
############################################################################
599
def Hom(self, codomain, cat=None):
600
r"""
601
Return the homspace ``Hom(self, codomain, cat)`` of all
602
homomorphisms from self to codomain in the category cat. The
603
default category is determined by ``self.category()`` and
604
``codomain.category()``.
605
606
EXAMPLES::
607
608
sage: R.<x,y> = PolynomialRing(QQ, 2)
609
sage: R.Hom(QQ)
610
Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
611
612
Homspaces are defined for very general Sage objects, even elements of familiar rings.
613
614
::
615
616
sage: n = 5; Hom(n,7)
617
Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
618
sage: z=(2/3); Hom(z,8/1)
619
Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
620
621
This example illustrates the optional third argument::
622
623
sage: QQ.Hom(ZZ, Sets())
624
Set of Morphisms from Rational Field to Integer Ring in Category of sets
625
"""
626
try:
627
return self._Hom_(codomain, cat)
628
except (AttributeError, TypeError):
629
pass
630
from sage.categories.all import Hom
631
return Hom(self, codomain, cat)
632
633
def latex_variable_names(self):
634
"""
635
Returns the list of variable names suitable for latex output.
636
637
All ``_SOMETHING`` substrings are replaced by ``_{SOMETHING}``
638
recursively so that subscripts of subscripts work.
639
640
EXAMPLES::
641
642
sage: R, x = PolynomialRing(QQ,'x',12).objgens()
643
sage: x
644
(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
645
sage: print R.latex_variable_names ()
646
['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}']
647
sage: f = x[0]^3 + 15/3 * x[1]^10
648
sage: print latex(f)
649
5 x_{1}^{10} + x_{0}^{3}
650
"""
651
from sage.misc.latex import latex, latex_variable_name
652
try:
653
names = self._latex_names
654
if names is not None:
655
return names
656
except AttributeError:
657
pass
658
# Compute the latex versions of the variable names.
659
self._latex_names = [latex_variable_name(x) for x in self.variable_names()]
660
return self._latex_names
661
662
def latex_name(self):
663
return self.latex_variable_names()[0]
664
665
def _temporarily_change_names(self, names):
666
self._names = names
667
668
#################################################################################
669
# Give all objects with generators a dictionary, so that attribute setting
670
# works. It would be nice if this functionality were standard in Cython,
671
# i.e., just define __dict__ as an attribute and all this code gets generated.
672
#################################################################################
673
def __getstate__(self):
674
d = []
675
try:
676
d = list(self.__dict__.copy().iteritems()) # so we can add elements
677
except AttributeError:
678
pass
679
d = dict(d)
680
d['_generators'] = self._generators
681
d['_category'] = self._category
682
d['_base'] = self._base
683
d['_cdata'] = self._cdata
684
d['_names'] = self._names
685
###########
686
# The _pickle_version ensures that the unpickling for objects created
687
# in different versions of sage works across versions.
688
# Update this integer if you change any of these attributes
689
###########
690
d['_pickle_version'] = 1
691
try:
692
d['_generator_orders'] = self._generator_orders
693
except AttributeError:
694
pass
695
696
return d
697
698
def __setstate__(self,d):
699
try:
700
version = d['_pickle_version']
701
except KeyError:
702
version = 0
703
try:
704
if version == 1:
705
self._generators = d['_generators']
706
if d['_category'] is not None:
707
# We must not erase the category information of
708
# self. Otherwise, pickles break (e.g., QQ should
709
# be a commutative ring, but when QQ._category is
710
# None then it only knows that it is a ring!
711
if self._category is None:
712
self._category = d['_category']
713
else:
714
self._category = self._category.join([self._category,d['_category']])
715
self._base = d['_base']
716
self._cdata = d['_cdata']
717
self._names = d['_names']
718
try:
719
self._generator_orders = d['_generator_orders']
720
except (AttributeError, KeyError):
721
pass
722
elif version == 0:
723
# In the old code, this functionality was in parent_gens,
724
# but there were parents that didn't inherit from parent_gens.
725
# If we have such, then we only need to deal with the dictionary.
726
try:
727
self._base = d['_base']
728
self._names = d['_names']
729
from sage.categories.all import Objects
730
if d['_gens'] is None:
731
from sage.structure.generators import Generators
732
self._generators = Generators(self, None, Objects())
733
else:
734
from sage.structure.generators import Generator_list
735
self._generators = Generator_list(self, d['_gens'], Objects())
736
self._generator_orders = d['_generator_orders'] # this may raise a KeyError, but that's okay.
737
# We throw away d['_latex_names'] and d['_list'] and d['_gens_dict']
738
except (AttributeError, KeyError):
739
pass
740
try:
741
self.__dict__ = d
742
except AttributeError:
743
pass
744
except (AttributeError, KeyError):
745
raise
746
#raise RuntimeError, "If you change the pickling code in parent or category_object, you need to update the _pickle_version field"
747
748
def __hash__(self):
749
"""
750
A default hash is provide based on the string representation of the
751
self. It is cached to remain consistent throughout a session, even
752
if the representation changes.
753
754
EXAMPLES::
755
756
sage: bla = PolynomialRing(ZZ,"x")
757
sage: hash(bla)
758
-5279516879544852222 # 64-bit
759
-1056120574 # 32-bit
760
sage: bla.rename("toto")
761
sage: hash(bla)
762
-5279516879544852222 # 64-bit
763
-1056120574 # 32-bit
764
"""
765
if self._hash_value == -1:
766
self._hash_value = hash(repr(self))
767
return self._hash_value
768
769
# #################################################################################
770
# # Morphisms of objects with generators
771
# #################################################################################
772
773
774
## COERCE TODO: see categories.MultiplicativeAbelianGroups
775
776
# cdef class ParentWithMultiplicativeAbelianGens(Parent):
777
# def generator_orders(self):
778
# if self._generator_orders != None:
779
# return self._generator_orders
780
# else:
781
# g = []
782
# for x in self.gens():
783
# g.append(x.multiplicative_order())
784
# self._generator_orders = g
785
# return g
786
787
# def __iter__(self):
788
# """
789
# Return an iterator over the elements in this object.
790
# """
791
# return gens_py.multiplicative_iterator(self)
792
793
794
795
# cdef class ParentWithAdditiveAbelianGens(Parent):
796
# def generator_orders(self):
797
# if self._generator_orders != None:
798
# return self._generator_orders
799
# else:
800
# g = []
801
# for x in self.gens():
802
# g.append(x.additive_order())
803
# self._generator_orders = g
804
# return g
805
806
# def __iter__(self):
807
# """
808
# Return an iterator over the elements in this object.
809
# """
810
# return gens_py.abelian_iterator(self)
811
812
813
814
815
class localvars:
816
r"""
817
Context manager for safely temporarily changing the variables
818
names of an object with generators.
819
820
Objects with named generators are globally unique in Sage.
821
Sometimes, though, it is very useful to be able to temporarily
822
display the generators differently. The new Python ``with``
823
statement and the localvars context manager make this easy and
824
safe (and fun!)
825
826
Suppose X is any object with generators. Write
827
828
::
829
830
with localvars(X, names[, latex_names] [,normalize=False]):
831
some code
832
...
833
834
and the indented code will be run as if the names in ``X`` are changed to
835
the new names. If you give ``normalize=True``, then the names are assumed
836
to be a tuple of the correct number of strings.
837
838
If you're writing Python library code, you currently have to put ``from
839
__future__ import with_statement`` in your file in order to use the
840
``with`` statement. This restriction will disappear in Python 2.6.
841
842
EXAMPLES::
843
844
sage: R.<x,y> = PolynomialRing(QQ,2)
845
sage: with localvars(R, 'z,w'):
846
... print x^3 + y^3 - x*y
847
...
848
z^3 + w^3 - z*w
849
850
NOTES: I wrote this because it was needed to print elements of the quotient
851
of a ring `R` by an ideal `I` using the print function for elements of `R`.
852
See the code in :mod:`sage.rings.quotient_ring_element`.
853
854
AUTHOR: William Stein (2006-10-31)
855
"""
856
# fix this so that it handles latex names with the printer framework.
857
def __init__(self, obj, names, latex_names=None, normalize=True):
858
self._obj = obj
859
if normalize:
860
self._names = obj.normalize_names(obj.ngens(), names)
861
else:
862
self._names = names
863
864
def __enter__(self):
865
self._orig_names = (<CategoryObject?>self._obj)._names
866
self._obj._temporarily_change_names(self._names)
867
868
def __exit__(self, type, value, traceback):
869
self._obj._temporarily_change_names(self._orig_names)
870
871
872
# This Cython class confuses the hell out of the Sphinx documentation parser
873
# (because __doc__ is defined but not set). And the only code that refers to it
874
# is commented out. So I'm commenting it out too. -- David Loeffler 2009-07-06
875
#cdef class FillFirstArg:
876
# cdef object arg, f
877
# cdef public __doc__
878
# def __init__(self, f, arg):
879
# self.arg = arg
880
# self.f = f
881
# self.__doc__ = f.__doc__
882
# def __call__(self, *args, **kwds):
883
# return self.f(self.arg, *args, **kwds)
884
885