Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/abelian_gps/values.py
8815 views
1
"""
2
Multiplicative Abelian Groups With Values
3
4
Often, one ends up with a set that forms an Abelian group. It would be
5
nice if one could return an Abelian group class to encapsulate the
6
data. However,
7
:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` is an
8
abstract Abelian group defined by generators and relations. This
9
module implements :class:`AbelianGroupWithValues` that allows the
10
group elements to be decorated with values.
11
12
An example where this module is used is the unit group of a number
13
field, see :mod:`sage.rings.number_field.unit_group`. The units form a
14
finitely generated Abelian group. We can think of the elements either
15
as abstract Abelian group elements or as particular numbers in the
16
number field. The :func:`AbelianGroupWithValues` keeps track of these
17
associated values.
18
19
.. warning::
20
21
Really, this requires a group homomorphism from the abstract
22
Abelian group to the set of values. This is only checked if you
23
pass the ``check=True`` option to :func:`AbelianGroupWithValues`.
24
25
EXAMPLES:
26
27
Here is `\ZZ_6` with value `-1` assigned to the generator::
28
29
sage: Z6 = AbelianGroupWithValues([-1], [6], names='g')
30
sage: g = Z6.gen(0)
31
sage: g.value()
32
-1
33
sage: g*g
34
g^2
35
sage: (g*g).value()
36
1
37
sage: for i in range(7):
38
... print i, g^i, (g^i).value()
39
0 1 1
40
1 g -1
41
2 g^2 1
42
3 g^3 -1
43
4 g^4 1
44
5 g^5 -1
45
6 1 1
46
47
The elements come with a coercion embedding into the
48
:meth:`~AbelianGroupWithValues_class.values_group`, so you can use the
49
group elements instead of the values::
50
51
sage: CF3.<zeta> = CyclotomicField(3)
52
sage: Z3.<g> = AbelianGroupWithValues([zeta], [3])
53
sage: Z3.values_group()
54
Cyclotomic Field of order 3 and degree 2
55
sage: g.value()
56
zeta
57
sage: CF3(g)
58
zeta
59
sage: g + zeta
60
2*zeta
61
sage: zeta + g
62
2*zeta
63
"""
64
65
##########################################################################
66
# Copyright (C) 2012 Volker Braun <[email protected]>
67
#
68
# Distributed under the terms of the GNU General Public License (GPL):
69
#
70
# http://www.gnu.org/licenses/
71
##########################################################################
72
73
74
from sage.misc.misc import prod
75
from sage.rings.integer import Integer
76
from sage.categories.morphism import Morphism
77
from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize
78
from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
79
80
81
82
def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, values_group=None):
83
"""
84
Construct an Abelian group with values associated to the generators.
85
86
INPUT:
87
88
- ``values`` -- a list/tuple/iterable of values that you want to
89
associate to the generators.
90
91
- ``n`` -- integer (optional). If not specified, will be derived
92
from ``gens_orders``.
93
94
- ``gens_orders`` -- a list of non-negative integers in the form
95
`[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing
96
order. This list is padded with zeros if it has length less
97
than n. The orders of the commuting generators, with `0`
98
denoting an infinite cyclic factor.
99
100
- ``names`` -- (optional) names of generators
101
102
- ``values_group`` -- a parent or ``None`` (default). The common
103
parent of the values. This might be a group, but can also just
104
contain the values. For example, if the values are units in a
105
ring then the ``values_group`` would be the whole ring. If
106
``None`` it will be derived from the values.
107
108
EXAMPLES::
109
110
sage: G = AbelianGroupWithValues([-1], [6])
111
sage: g = G.gen(0)
112
sage: for i in range(7):
113
... print i, g^i, (g^i).value()
114
0 1 1
115
1 f -1
116
2 f^2 1
117
3 f^3 -1
118
4 f^4 1
119
5 f^5 -1
120
6 1 1
121
sage: G.values_group()
122
Integer Ring
123
124
The group elements come with a coercion embedding into the
125
:meth:`values_group`, so you can use them like their
126
:meth:`~sage.groups.abelian_gps.value.AbelianGroupWithValuesElement.value`
127
::
128
129
sage: G.values_embedding()
130
Generic morphism:
131
From: Multiplicative Abelian group isomorphic to C6
132
To: Integer Ring
133
sage: g.value()
134
-1
135
sage: 0 + g
136
-1
137
sage: 1 + 2*g
138
-1
139
"""
140
if check:
141
raise NotImplementedError('checking that the values are a homomorphism is not implemented')
142
gens_orders, names = _normalize(n, gens_orders, names)
143
if values_group is None:
144
from sage.structure.sequence import Sequence
145
values_group = Sequence(values).universe()
146
values = tuple( values_group(val) for val in values )
147
M = AbelianGroupWithValues_class(gens_orders, names, values, values_group)
148
return M
149
150
151
class AbelianGroupWithValuesEmbedding(Morphism):
152
"""
153
The morphism embedding the Abelian group with values in its values group.
154
155
INPUT:
156
157
- ``domain`` -- a :class:`AbelianGroupWithValues_class`
158
159
- ``codomain`` -- the values group (need not be in the cateory of
160
groups, e.g. symbolic ring).
161
162
EXAMPLES::
163
164
sage: Z4.<g> = AbelianGroupWithValues([I], [4])
165
sage: embedding = Z4.values_embedding(); embedding
166
Generic morphism:
167
From: Multiplicative Abelian group isomorphic to C4
168
To: Symbolic Ring
169
sage: embedding(1)
170
1
171
sage: embedding(g)
172
I
173
sage: embedding(g^2)
174
-1
175
"""
176
177
def __init__(self, domain, codomain):
178
"""
179
Construct the morphism
180
181
TESTS::
182
183
sage: Z4 = AbelianGroupWithValues([I], [4])
184
sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding
185
sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group())
186
Generic morphism:
187
From: Multiplicative Abelian group isomorphic to C4
188
To: Symbolic Ring
189
"""
190
assert domain.values_group() is codomain
191
from sage.categories.homset import Hom
192
Morphism.__init__(self, Hom(domain, codomain))
193
194
def _call_(self, x):
195
"""
196
Return the value associated to ``x``
197
198
INPUT:
199
200
- ``x`` -- a group element
201
202
OUTPUT:
203
204
Its value.
205
206
EXAMPLES::
207
208
sage: Z4.<g> = AbelianGroupWithValues([I], [4])
209
sage: embedding = Z4.values_embedding()
210
sage: embedding(g)
211
I
212
sage: embedding._call_(g)
213
I
214
"""
215
return x.value()
216
217
218
class AbelianGroupWithValuesElement(AbelianGroupElement):
219
"""
220
An element of an Abelian group with values assigned to generators.
221
222
INPUT:
223
224
- ``exponents`` -- tuple of integers. The exponent vector defining
225
the group element.
226
227
- ``parent`` -- the parent.
228
229
- ``value`` -- the value assigned to the group element or ``None``
230
(default). In the latter case, the value is computed as needed.
231
232
EXAMPLES::
233
234
sage: F = AbelianGroupWithValues([1,-1], [2,4])
235
sage: a,b = F.gens()
236
sage: TestSuite(a*b).run()
237
"""
238
239
def __init__(self, parent, exponents, value=None):
240
"""
241
Create an element
242
243
EXAMPLES::
244
245
sage: F = AbelianGroupWithValues([1,-1], [2,4])
246
sage: a,b = F.gens()
247
sage: a*b^-1 in F
248
True
249
sage: (a*b^-1).value()
250
-1
251
"""
252
self._value = value
253
AbelianGroupElement.__init__(self, parent, exponents)
254
255
def value(self):
256
"""
257
Return the value of the group element.
258
259
OUTPUT:
260
261
The value according to the values for generators, see
262
:meth:`~AbelianGroupWithValues.gens_values`.
263
264
EXAMPLES::
265
266
sage: G = AbelianGroupWithValues([5], 1)
267
sage: G.0.value()
268
5
269
"""
270
if self._value is None:
271
values = self.parent().gens_values()
272
self._value = prod( v**e for v,e in zip(values, self.exponents()) )
273
return self._value
274
275
def _div_(left, right):
276
"""
277
Divide ``left`` by ``right``
278
279
TESTS::
280
281
sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
282
sage: a._div_(b)
283
a*b^-1
284
sage: a/b
285
a*b^-1
286
sage: (a/b).value()
287
5/2
288
"""
289
m = AbelianGroupElement._div_(left, right)
290
m._value = left.value() / right.value()
291
return m
292
293
def _mul_(left, right):
294
"""
295
Multiply ``left`` and ``right``
296
297
TESTS::
298
299
sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
300
sage: a._mul_(b)
301
a*b
302
sage: a*b
303
a*b
304
sage: (a*b).value()
305
10
306
"""
307
m = AbelianGroupElement._mul_(left, right)
308
m._value = left.value() * right.value()
309
return m
310
311
def __pow__(self, n):
312
"""
313
Exponentiate ``self``
314
315
INPUT:
316
317
- ``n`` -- integer. The exponent.
318
319
TESTS::
320
321
sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
322
sage: a^3
323
a^3
324
sage: (a^3).value()
325
125
326
"""
327
m = Integer(n)
328
if n != m:
329
raise TypeError('argument n (= '+str(n)+') must be an integer.')
330
pow_self = AbelianGroupElement.__pow__(self, m)
331
pow_self._value = pow(self.value(), m)
332
return pow_self
333
334
def inverse(self):
335
"""
336
Return the inverse element.
337
338
EXAMPLE::
339
340
sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
341
sage: a.inverse()
342
a^-1
343
sage: a.inverse().value()
344
1/2
345
sage: a.__invert__().value()
346
1/2
347
sage: (~a).value()
348
1/2
349
sage: (a*b).value()
350
-2
351
sage: (a*b).inverse().value()
352
-1/2
353
"""
354
m = AbelianGroupElement.inverse(self)
355
m._value = ~self.value()
356
return m
357
358
__invert__ = inverse
359
360
361
362
class AbelianGroupWithValues_class(AbelianGroup_class):
363
"""
364
The class of an Abelian group with values associated to the generator.
365
366
INPUT:
367
368
- ``generator_orders`` -- tuple of integers. The orders of the
369
generators.
370
371
- ``names`` -- string or list of strings. The names for the generators.
372
373
- ``values`` -- Tuple the same length as the number of
374
generators. The values assigned to the generators.
375
376
- ``values_group`` -- the common parent of the values.
377
378
EXAMPLES::
379
380
sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
381
sage: TestSuite(G).run()
382
"""
383
Element = AbelianGroupWithValuesElement
384
385
def __init__(self, generator_orders, names, values, values_group):
386
"""
387
The Python constructor
388
389
TESTS::
390
391
sage: G = AbelianGroupWithValues([2,-1], [0,4]); G
392
Multiplicative Abelian group isomorphic to Z x C4
393
394
sage: cm = sage.structure.element.get_coercion_model()
395
sage: cm.explain(G, ZZ, operator.add)
396
Coercion on left operand via
397
Generic morphism:
398
From: Multiplicative Abelian group isomorphic to Z x C4
399
To: Integer Ring
400
Arithmetic performed after coercions.
401
Result lives in Integer Ring
402
Integer Ring
403
"""
404
self._values = values
405
self._values_group = values_group
406
AbelianGroup_class.__init__(self, generator_orders, names)
407
self._populate_coercion_lists_(embedding=self.values_embedding())
408
if self.ngens() != len(self._values):
409
raise ValueError('need one value per generator')
410
411
def gen(self, i=0):
412
"""
413
The `i`-th generator of the abelian group.
414
415
INPUT:
416
417
- ``i`` -- integer (default: 0). The index of the generator.
418
419
OUTPUT:
420
421
A group element.
422
423
EXAMPLES::
424
425
sage: F = AbelianGroupWithValues([1,2,3,4,5], 5,[],names='a')
426
sage: F.0
427
a0
428
sage: F.0.value()
429
1
430
sage: F.2
431
a2
432
sage: F.2.value()
433
3
434
435
sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
436
sage: G.gens()
437
(f0, 1, f2)
438
"""
439
g = AbelianGroup_class.gen(self, i)
440
g._value = self._values[i]
441
return g
442
443
def gens_values(self):
444
"""
445
Return the values associated to the generators.
446
447
OUTPUT:
448
449
A tuple.
450
451
EXAMPLES::
452
453
sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
454
sage: G.gens()
455
(f0, 1, f2)
456
sage: G.gens_values()
457
(-1, 0, 1)
458
"""
459
return self._values
460
461
def values_group(self):
462
"""
463
The common parent of the values.
464
465
The values need to form a multiplicative group, but can be
466
embedded in a larger structure. For example, if the values are
467
units in a ring then the :meth:`values_group` would be the
468
whole ring.
469
470
OUTPUT:
471
472
The common parent of the values, containing the group
473
generated by all values.
474
475
EXAMPLES::
476
477
sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
478
sage: G.values_group()
479
Integer Ring
480
481
sage: Z4 = AbelianGroupWithValues([I], [4])
482
sage: Z4.values_group()
483
Symbolic Ring
484
"""
485
return self._values_group
486
487
def values_embedding(self):
488
"""
489
Return the embedding of ``self`` in :meth:`values_group`.
490
491
OUTPUT:
492
493
A morphism.
494
495
EXAMPLES::
496
497
sage: Z4 = AbelianGroupWithValues([I], [4])
498
sage: Z4.values_embedding()
499
Generic morphism:
500
From: Multiplicative Abelian group isomorphic to C4
501
To: Symbolic Ring
502
"""
503
return AbelianGroupWithValuesEmbedding(self, self.values_group())
504
505