Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/additive_abelian/additive_abelian_wrapper.py
4094 views
1
r"""
2
Wrapper class for abelian groups
3
4
This class is intended as a template for anything in Sage that needs the
5
functionality of abelian groups. One can create an AdditiveAbelianGroupWrapper
6
object from any given set of elements in some given parent, as long as an
7
``_add_`` method has been defined.
8
9
10
EXAMPLES:
11
12
We create a toy example based on the Mordell-Weil group of an elliptic curve over `\QQ`::
13
14
sage: E = EllipticCurve('30a2')
15
sage: pts = [E(4,-7,1), E(7/4, -11/8, 1), E(3, -2, 1)]
16
sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [3, 2, 2])
17
sage: M
18
Additive abelian group isomorphic to Z/2 + Z/6 embedded in Abelian group of
19
points on Elliptic Curve defined by y^2 + x*y + y = x^3 - 19*x + 26 over
20
Rational Field
21
sage: M.gens()
22
((4 : -7 : 1), (7/4 : -11/8 : 1), (3 : -2 : 1))
23
sage: 3*M.0
24
(0 : 1 : 0)
25
sage: 3000000000000001 * M.0
26
(4 : -7 : 1)
27
sage: M == loads(dumps(M)) # optional - pickling http://trac.sagemath.org/sage_trac/ticket/11599
28
True
29
30
We check that ridiculous operations are being avoided::
31
32
sage: set_verbose(2, 'additive_abelian_wrapper.py')
33
sage: 300001 * M.0
34
verbose 1 (...: additive_abelian_wrapper.py, _discrete_exp) Calling discrete exp on (1, 0, 0)
35
(4 : -7 : 1)
36
sage: set_verbose(0, 'additive_abelian_wrapper.py')
37
38
39
TODO:
40
41
- Implement proper black-box discrete logarithm (using baby-step giant-step).
42
The discrete_exp function can also potentially be speeded up substantially
43
via caching.
44
45
- Think about subgroups and quotients, which probably won't work in the current
46
implementation -- some fiddly adjustments will be needed in order to be able
47
to pass extra arguments to the subquotient's init method.
48
"""
49
50
import additive_abelian_group as addgp
51
from sage.rings.all import ZZ
52
from sage.misc.misc import verbose
53
from sage.categories.morphism import Morphism
54
55
class UnwrappingMorphism(Morphism):
56
r"""
57
The embedding into the ambient group. Used by the coercion framework.
58
"""
59
def __init__(self, domain):
60
r"""
61
EXAMPLE::
62
63
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])
64
sage: F = QQbar.coerce_map_from(G); F
65
Generic morphism:
66
From: Additive abelian group isomorphic to Z + Z embedded in Algebraic Field
67
To: Algebraic Field
68
sage: type(F)
69
<class 'sage.groups.additive_abelian.additive_abelian_wrapper.UnwrappingMorphism'>
70
"""
71
Morphism.__init__(self, domain.Hom(domain.universe()))
72
73
def _call_(self, x):
74
r"""
75
TEST::
76
77
sage: E = EllipticCurve("65a1")
78
sage: G = E.torsion_subgroup()
79
sage: isinstance(G, sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper)
80
True
81
sage: P1 = E([1,-1,1])
82
sage: P2 = E([0,1,0])
83
sage: P1 in G # indirect doctest
84
False
85
sage: P2 in G
86
True
87
sage: (G(P2) + P1) in G
88
False
89
sage: (G(P2) + P1).parent()
90
Abelian group of points on Elliptic Curve defined by y^2 + x*y = x^3 - x over Rational Field
91
"""
92
return self.codomain()(x.element())
93
94
95
class AdditiveAbelianGroupWrapperElement(addgp.AdditiveAbelianGroupElement):
96
"""
97
An element of an :class:`AdditiveAbelianGroupWrapper`.
98
"""
99
100
def __init__(self, parent, vector, element=None, check=False):
101
r"""
102
EXAMPLE:
103
104
sage: from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper
105
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])
106
sage: G.0 # indirect doctest
107
1.414213562373095?
108
"""
109
addgp.AdditiveAbelianGroupElement.__init__(self, parent, vector, check)
110
if element is not None:
111
element = self.parent().universe()(element)
112
self._element = element
113
114
def element(self):
115
r"""
116
Return the underlying object that this element wraps.
117
118
EXAMPLE::
119
120
sage: T = EllipticCurve('65a').torsion_subgroup().gen(0)
121
sage: T; type(T)
122
(0 : 0 : 1)
123
<class 'sage.groups.additive_abelian.additive_abelian_wrapper.EllipticCurveTorsionSubgroup_with_category.element_class'>
124
sage: T.element(); type(T.element())
125
(0 : 0 : 1)
126
<class 'sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_number_field'>
127
"""
128
if self._element is None:
129
self._element = self.parent()._discrete_exp(self._hermite_lift())
130
return self._element
131
132
def _repr_(self):
133
r"""
134
String representation of self.
135
136
EXAMPLE::
137
138
sage: T = EllipticCurve('65a').torsion_subgroup().gen(0)
139
sage: repr(T) # indirect doctest
140
'(0 : 0 : 1)'
141
"""
142
return repr(self.element())
143
144
145
class AdditiveAbelianGroupWrapper(addgp.AdditiveAbelianGroup_fixed_gens):
146
"""
147
The parent of :class:`AdditiveAbelianGroupWrapperElement`
148
"""
149
150
Element = AdditiveAbelianGroupWrapperElement
151
152
def __init__(self, universe, gens, invariants):
153
r"""
154
EXAMPLE::
155
156
sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) # indirect doctest
157
Additive abelian group isomorphic to Z + Z embedded in Algebraic Field
158
"""
159
self._universe = universe
160
self._gen_elements = tuple(universe(x) for x in gens)
161
self._gen_orders = invariants
162
cover,rels = addgp.cover_and_relations_from_invariants(invariants)
163
addgp.AdditiveAbelianGroup_fixed_gens.__init__(self, cover, rels, cover.gens())
164
self._unset_coercions_used()
165
self.register_embedding(UnwrappingMorphism(self))
166
167
def universe(self):
168
r"""
169
The ambient group in which this abelian group lives.
170
171
EXAMPLE::
172
173
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])
174
sage: G.universe()
175
Algebraic Field
176
"""
177
return self._universe
178
179
def generator_orders(self):
180
r"""
181
The orders of the generators with which this group was initialised.
182
(Note that these are not necessarily a minimal set of generators.)
183
Generators of infinite order are returned as 0. Compare
184
``self.invariants()``, which returns the orders of a minimal set of
185
generators.
186
187
EXAMPLE::
188
189
sage: V = Zmod(6)**2
190
sage: G = AdditiveAbelianGroupWrapper(V, [2*V.0, 3*V.1], [3, 2])
191
sage: G.generator_orders()
192
(3, 2)
193
sage: G.invariants()
194
(6,)
195
"""
196
return tuple(self._gen_orders)
197
198
def _repr_(self):
199
r"""
200
EXAMPLE::
201
202
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])
203
sage: repr(G) # indirect doctest
204
'Additive abelian group isomorphic to Z + Z embedded in Algebraic Field'
205
"""
206
return addgp.AdditiveAbelianGroup_fixed_gens._repr_(self) + " embedded in " + self.universe()._repr_()
207
208
def _discrete_exp(self, v):
209
r"""
210
Given a list (or other iterable) of length equal to the number of
211
generators of this group, compute the element of the ambient group with
212
those exponents in terms of the generators of self.
213
214
EXAMPLE::
215
216
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), -1], [0, 0])
217
sage: v = G._discrete_exp([3, 5]); v
218
-0.7573593128807148?
219
sage: v.parent() is QQbar
220
True
221
"""
222
v = self.V()(v)
223
verbose("Calling discrete exp on %s" % v)
224
# DUMB IMPLEMENTATION!
225
return sum([self._gen_elements[i] * ZZ(v[i]) for i in xrange(len(v))], self.universe()(0))
226
227
def _discrete_log(self,x):
228
r"""
229
Given an element of the ambient group, attempt to express it in terms of the
230
generators of self.
231
232
EXAMPLE::
233
234
sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2])
235
sage: G._discrete_log(V([6, 2]))
236
(1, 1)
237
sage: G._discrete_log(V([6, 4]))
238
Traceback (most recent call last):
239
...
240
TypeError: Not in group
241
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(2)], [0])
242
sage: G._discrete_log(QQbar(2*sqrt(2)))
243
Traceback (most recent call last):
244
...
245
NotImplementedError: No black-box discrete log for infinite abelian groups
246
"""
247
# EVEN DUMBER IMPLEMENTATION!
248
from sage.rings.infinity import Infinity
249
if self.order() == Infinity:
250
raise NotImplementedError, "No black-box discrete log for infinite abelian groups"
251
u = [y for y in self.list() if y.element() == x]
252
if len(u) == 0: raise TypeError, "Not in group"
253
if len(u) > 1: raise NotImplementedError
254
return u[0].vector()
255
256
def _element_constructor_(self, x, check=False):
257
r"""
258
Create an element from x. This may be either an element of self, an element of the
259
ambient group, or an iterable (in which case the result is the corresponding
260
product of the generators of self).
261
262
EXAMPLES::
263
264
sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2])
265
sage: G(V([6,2]))
266
(6, 2)
267
sage: G([1,1])
268
(6, 2)
269
sage: G(G([1,1]))
270
(6, 2)
271
"""
272
if hasattr(x,"parent"):
273
if x.parent() is self.universe():
274
return self.element_class(self, self._discrete_log(x), element = x)
275
return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_(self, x, check)
276
277
278