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