Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/elliptic_curves/weierstrass_morphism.py
4126 views
1
r"""
2
Isomorphisms between Weierstrass models of elliptic curves
3
4
AUTHORS:
5
6
- Robert Bradshaw (2007): initial version
7
- John Cremona (Jan 2008): isomorphisms, automorphisms and twists
8
in all characteristics
9
"""
10
11
#*****************************************************************************
12
# Copyright (C) 2007 Robert Bradshaw <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
#
16
# This code is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
# General Public License for more details.
20
#
21
# The full text of the GPL is available at:
22
#
23
# http://www.gnu.org/licenses/
24
#*****************************************************************************
25
26
27
from sage.categories.morphism import Morphism
28
from constructor import EllipticCurve
29
from sage.categories.homset import Hom
30
31
class baseWI:
32
r"""
33
This class implements the basic arithmetic of isomorphisms between
34
Weierstrass models of elliptic curves. These are specified by
35
lists of the form `[u,r,s,t]` (with `u\not=0`) which specifies a
36
transformation `(x,y) \mapsto (x',y')` where
37
38
`(x,y) = (u^2x'+r , u^3y' + su^2x' + t).`
39
40
INPUT:
41
42
- ``u,r,s,t`` (default (1,0,0,0)) -- standard parameters of an isomorphism between Weierstrass models.
43
44
EXAMPLES::
45
46
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
47
sage: baseWI()
48
(1, 0, 0, 0)
49
sage: baseWI(2,3,4,5)
50
(2, 3, 4, 5)
51
sage: R.<u,r,s,t>=QQ[]; baseWI(u,r,s,t)
52
(u, r, s, t)
53
"""
54
55
def __init__(self, u=1, r=0, s=0, t=0):
56
r"""
57
Constructor: check for valid parameters (defaults to identity)
58
59
INPUT:
60
61
- ``u,r,s,t`` (default (1,0,0,0)) -- standard parameters of an isomorphism between Weierstrass models.
62
63
EXAMPLES::
64
65
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
66
sage: baseWI()
67
(1, 0, 0, 0)
68
sage: baseWI(2,3,4,5)
69
(2, 3, 4, 5)
70
sage: R.<u,r,s,t>=QQ[]; baseWI(u,r,s,t)
71
(u, r, s, t)
72
"""
73
if u==0:
74
raise ValueError, "u!=0 required for baseWI"
75
self.u=u; self.r=r; self.s=s; self.t=t
76
77
def __cmp__(self, other):
78
"""
79
Standard comparison function.
80
81
The ordering is just lexicographic on the tuple `(u,r,s,t)`.
82
83
.. note::
84
85
In a list of automorphisms, there is no guarantee that the
86
identity will be first!
87
88
EXAMPLE::
89
90
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
91
sage: baseWI(1,2,3,4)==baseWI(1,2,3,4)
92
True
93
sage: baseWI(1,2,3,4)<baseWI(1,2,3,5)
94
True
95
sage: baseWI(1,2,3,4)>baseWI(1,2,3,4)
96
False
97
98
::
99
100
It will never return equality if other is of another type:
101
sage: baseWI() == 1
102
False
103
104
"""
105
if not isinstance(other, baseWI):
106
return cmp(type(self), type(other))
107
return cmp(self.tuple(), other.tuple())
108
109
def tuple(self):
110
r"""
111
Returns the parameters `u,r,s,t` as a tuple.
112
113
EXAMPLES::
114
115
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
116
sage: u,r,s,t=baseWI(2,3,4,5).tuple()
117
sage: w=baseWI(2,3,4,5)
118
sage: u,r,s,t=w.tuple()
119
sage: u
120
2
121
"""
122
return (self.u,self.r,self.s,self.t)
123
124
def __mul__(self, other):
125
r"""
126
Returns the Composition of this isomorphism and another.
127
128
EXAMPLES::
129
130
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
131
sage: baseWI(1,2,3,4)*baseWI(5,6,7,8)
132
(5, 56, 22, 858)
133
sage: baseWI()*baseWI(1,2,3,4)*baseWI()
134
(1, 2, 3, 4)
135
"""
136
u1,r1,s1,t1=other.tuple()
137
u2,r2,s2,t2=self.tuple()
138
return baseWI(u1*u2,(u1**2)*r2+r1,u1*s2+s1,(u1**3)*t2+s1*(u1**2)*r2+t1)
139
140
def __invert__(self):
141
r"""
142
Returns the inverse of this isomorphism.
143
144
EXAMPLES::
145
146
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
147
sage: w=baseWI(2,3,4,5)
148
sage: ~w
149
(1/2, -3/4, -2, 7/8)
150
sage: w*~w
151
(1, 0, 0, 0)
152
sage: ~w*w
153
(1, 0, 0, 0)
154
sage: R.<u,r,s,t>=QQ[]; w=baseWI(u,r,s,t)
155
sage: ~w
156
(1/u, (-r)/u^2, (-s)/u, (r*s - t)/u^3)
157
sage: ~w*w
158
(1, 0, 0, 0)
159
"""
160
u,r,s,t=self.tuple()
161
return baseWI(1/u,-r/(u**2),-s/u,(r*s-t)/(u**3))
162
163
def __repr__(self):
164
r"""
165
Returns the string representation of this isomorphism.
166
167
EXAMPLES::
168
169
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
170
sage: baseWI(2,3,4,5)
171
(2, 3, 4, 5)
172
"""
173
return self.tuple().__repr__()
174
175
def is_identity(self):
176
r"""
177
Returns True if this is the identity isomorphism.
178
179
EXAMPLES::
180
181
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
182
sage: w=baseWI(); w.is_identity()
183
True
184
sage: w=baseWI(2,3,4,5); w.is_identity()
185
False
186
"""
187
return self.tuple()==(1,0,0,0)
188
189
def __call__(self, EorP):
190
r"""
191
Base application of isomorphisms to curves and points: a
192
baseWI `w` may be applied to a list `[a1,a2,a3,a4,a6]`
193
representing the `a`-invariants of an elliptic curve `E`,
194
returning the `a`-invariants of `w(E)`; or to `P=[x,y]` or
195
`P=[x,y,z]` representing a point in `\mathbb{A}^2` or
196
`\mathbb{P}^2`, returning the transformed point.
197
198
INPUT:
199
200
- ``EorP`` -- either an elliptic curve, or a point on an elliptic curve.
201
202
OUTPUT:
203
204
The transformed curve or point.
205
206
EXAMPLES::
207
208
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
209
sage: E=EllipticCurve([0,0,1,-7,6])
210
sage: w=baseWI(2,3,4,5);
211
sage: w(E.ainvs())
212
[4, -7/4, 11/8, -3/2, -9/32]
213
sage: P=E(-2,3)
214
sage: w(P.xy())
215
[-5/4, 9/4]
216
sage: EllipticCurve(w(E.ainvs()))(w(P.xy()))
217
(-5/4 : 9/4 : 1)
218
"""
219
u,r,s,t=self.tuple()
220
if len(EorP)==5:
221
a1,a2,a3,a4,a6=EorP
222
a6 += r*(a4 + r*(a2 + r)) - t*(a3 + r*a1 + t);
223
a4 += -s*a3 + 2*r*a2 - (t + r*s)*a1 + 3*r*r - 2*s*t;
224
a3 += r*a1 +t+t;
225
a2 += -s*a1 + 3*r - s*s;
226
a1 += 2*s;
227
return [a1/u,a2/u**2,a3/u**3,a4/u**4,a6/u**6]
228
if len(EorP)==2:
229
x,y=EorP
230
x-=r
231
y-=(s*x+t)
232
return [x/u**2,y/u**3]
233
if len(EorP)==3:
234
x,y,z=EorP
235
x-=r*z
236
y-=(s*x+t*z)
237
return [x/u**2,y/u**3,z]
238
raise ValueError, "baseWI(a) only for a=(x,y), (x:y:z) or (a1,a2,a3,a4,a6)"
239
240
def isomorphisms(E,F,JustOne=False):
241
r"""
242
Returns one or all isomorphisms between two elliptic curves.
243
244
INPUT:
245
246
- ``E``, ``F`` (EllipticCurve) -- Two elliptic curves.
247
248
- ``JustOne`` (bool) If True, returns one isomorphism, or None if
249
the curves are not isomorphic. If False, returns a (possibly
250
empty) list of isomorphisms.
251
252
OUTPUT:
253
254
Either None, or a 4-tuple `(u,r,s,t)` representing an isomorphism,
255
or a list of these.
256
257
.. note::
258
259
This function is not intended for users, who should use the
260
interface provided by ``ell_generic``.
261
262
EXAMPLES::
263
264
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
265
sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'))
266
[(-1, 0, 0, -1), (1, 0, 0, 0)]
267
sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a3'),JustOne=True)
268
(1, 0, 0, 0)
269
sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'))
270
[]
271
sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'),JustOne=True)
272
"""
273
from ell_generic import is_EllipticCurve
274
if not is_EllipticCurve(E) or not is_EllipticCurve(F):
275
raise ValueError, "arguments are not elliptic curves"
276
K = E.base_ring()
277
# if not K == F.base_ring(): return []
278
j=E.j_invariant()
279
if j != F.j_invariant():
280
if JustOne: return None
281
return []
282
283
from sage.rings.all import PolynomialRing
284
x=PolynomialRing(K,'x').gen()
285
286
a1E, a2E, a3E, a4E, a6E = E.ainvs()
287
a1F, a2F, a3F, a4F, a6F = F.ainvs()
288
289
char=K.characteristic()
290
291
if char==2:
292
if j==0:
293
ulist=(x**3-(a3E/a3F)).roots(multiplicities=False)
294
ans=[]
295
for u in ulist:
296
slist=(x**4+a3E*x+(a2F**2+a4F)*u**4+a2E**2+a4E).roots(multiplicities=False)
297
for s in slist:
298
r=s**2+a2E+a2F*u**2
299
tlist= (x**2 + a3E*x + r**3 + a2E*r**2 + a4E*r + a6E + a6F*u**6).roots(multiplicities=False)
300
for t in tlist:
301
if JustOne: return (u,r,s,t)
302
ans.append((u,r,s,t))
303
if JustOne: return None
304
ans.sort()
305
return ans
306
else:
307
ans=[]
308
u=a1E/a1F
309
r=(a3E+a3F*u**3)/a1E
310
slist=[s[0] for s in (x**2+a1E*x+(r+a2E+a2F*u**2)).roots()]
311
for s in slist:
312
t = (a4E+a4F*u**4 + s*a3E + r*s*a1E + r**2)
313
if JustOne: return (u,r,s,t)
314
ans.append((u,r,s,t))
315
if JustOne: return None
316
ans.sort()
317
return ans
318
319
b2E, b4E, b6E, b8E = E.b_invariants()
320
b2F, b4F, b6F, b8F = F.b_invariants()
321
322
if char==3:
323
if j==0:
324
ulist=(x**4-(b4E/b4F)).roots(multiplicities=False)
325
ans=[]
326
for u in ulist:
327
s=a1E-a1F*u
328
t=a3E-a3F*u**3
329
rlist=(x**3-b4E*x+(b6E-b6F*u**6)).roots(multiplicities=False)
330
for r in rlist:
331
if JustOne: return (u,r,s,t+r*a1E)
332
ans.append((u,r,s,t+r*a1E))
333
if JustOne: return None
334
ans.sort()
335
return ans
336
else:
337
ulist=(x**2-(b2E/b2F)).roots(multiplicities=False)
338
ans=[]
339
for u in ulist:
340
r = (b4F*u**4 -b4E)/b2E
341
s = (a1E-a1F*u)
342
t = (a3E-a3F*u**3 + a1E*r)
343
if JustOne: return (u,r,s,t)
344
ans.append((u,r,s,t))
345
if JustOne: return None
346
ans.sort()
347
return ans
348
349
# now char!=2,3:
350
c4E,c6E = E.c_invariants()
351
c4F,c6F = F.c_invariants()
352
353
if j==0:
354
m,um = 6,c6E/c6F
355
elif j==1728:
356
m,um=4,c4E/c4F
357
else:
358
m,um=2,(c6E*c4F)/(c6F*c4E)
359
ulist=(x**m-um).roots(multiplicities=False)
360
ans=[]
361
for u in ulist:
362
s = (a1F*u - a1E)/2
363
r = (a2F*u**2 + a1E*s + s**2 - a2E)/3
364
t = (a3F*u**3 - a1E*r - a3E)/2
365
if JustOne: return (u,r,s,t)
366
ans.append((u,r,s,t))
367
if JustOne: return None
368
ans.sort()
369
return ans
370
371
class WeierstrassIsomorphism(baseWI,Morphism):
372
r"""
373
Class representing a Weierstrass isomorphism between two elliptic curves.
374
"""
375
def __init__(self, E=None, urst=None, F=None):
376
r"""
377
Constructor for WeierstrassIsomorphism class,
378
379
INPUT:
380
381
- ``E`` -- an EllipticCurve, or None (see below).
382
383
- ``urst`` -- a 4-tuple `(u,r,s,t)`, or None (see below).
384
385
- ``F`` -- an EllipticCurve, or None (see below).
386
387
Given two Elliptic Curves ``E`` and ``F`` (represented by
388
Weierstrass models as usual), and a transformation ``urst``
389
from ``E`` to ``F``, construct an isomorphism from ``E`` to
390
``F``. An exception is raised if ``urst(E)!=F``. At most one
391
of ``E``, ``F``, ``urst`` can be None. If ``F==None`` then
392
``F`` is constructed as ``urst(E)``. If ``E==None`` then
393
``E`` is constructed as ``urst^-1(F)``. If ``urst==None``
394
then an isomorphism from ``E`` to ``F`` is constructed if
395
possible, and an exception is raised if they are not
396
isomorphic. Otherwise ``urst`` can be a tuple of length 4 or
397
a object of type ``baseWI``.
398
399
Users will not usually need to use this class directly, but instead use
400
methods such as ``isomorphism`` of elliptic curves.
401
402
EXAMPLES::
403
404
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
405
sage: WeierstrassIsomorphism(EllipticCurve([0,1,2,3,4]),(-1,2,3,4))
406
Generic morphism:
407
From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field
408
To: Abelian group of points on Elliptic Curve defined by y^2 - 6*x*y - 10*y = x^3 - 2*x^2 - 11*x - 2 over Rational Field
409
Via: (u,r,s,t) = (-1, 2, 3, 4)
410
sage: E=EllipticCurve([0,1,2,3,4])
411
sage: F=EllipticCurve(E.cremona_label())
412
sage: WeierstrassIsomorphism(E,None,F)
413
Generic morphism:
414
From: Abelian group of points on Elliptic Curve defined by y^2 + 2*y = x^3 + x^2 + 3*x + 4 over Rational Field
415
To: Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 5 over Rational Field
416
Via: (u,r,s,t) = (1, 0, 0, -1)
417
sage: w=WeierstrassIsomorphism(None,(1,0,0,-1),F)
418
sage: w._domain_curve==E
419
True
420
"""
421
from ell_generic import is_EllipticCurve
422
423
if E!=None:
424
if not is_EllipticCurve(E):
425
raise ValueError, "First argument must be an elliptic curve or None"
426
if F!=None:
427
if not is_EllipticCurve(F):
428
raise ValueError, "Third argument must be an elliptic curve or None"
429
if urst!=None:
430
if len(urst)!=4:
431
raise ValueError, "Second argument must be [u,r,s,t] or None"
432
if len([par for par in [E,urst,F] if par!=None])<2:
433
raise ValueError, "At most 1 argument can be None"
434
435
if F==None: # easy case
436
baseWI.__init__(self,*urst)
437
F=EllipticCurve(baseWI.__call__(self,list(E.a_invariants())))
438
Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))
439
self._domain_curve = E
440
self._codomain_curve = F
441
return
442
443
if E==None: # easy case in reverse
444
baseWI.__init__(self,*urst)
445
inv_urst=baseWI.__invert__(self)
446
E=EllipticCurve(baseWI.__call__(inv_urst,list(F.a_invariants())))
447
Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))
448
self._domain_curve = E
449
self._codomain_curve = F
450
return
451
452
if urst==None: # try to construct the morphism
453
urst=isomorphisms(E,F,True)
454
if urst==None:
455
raise ValueError, "Elliptic curves not isomorphic."
456
baseWI.__init__(self, *urst)
457
Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))
458
self._domain_curve = E
459
self._codomain_curve = F
460
return
461
462
463
# none of the parameters is None:
464
baseWI.__init__(self,*urst)
465
if F!=EllipticCurve(baseWI.__call__(self,list(E.a_invariants()))):
466
raise ValueError, "second argument is not an isomorphism from first argument to third argument"
467
else:
468
Morphism.__init__(self, Hom(E(0).parent(), F(0).parent()))
469
self._domain_curve = E
470
self._codomain_curve = F
471
return
472
473
def __cmp__(self, other):
474
r"""
475
Standard comparison function for the WeierstrassIsomorphism class.
476
477
EXAMPLE::
478
479
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
480
sage: E=EllipticCurve('389a1')
481
sage: F=E.change_weierstrass_model(1,2,3,4)
482
sage: w1=E.isomorphism_to(F)
483
sage: w1==w1
484
True
485
sage: w2 = F.automorphisms()[0] *w1
486
sage: w1==w2
487
False
488
489
::
490
491
sage: E=EllipticCurve_from_j(GF(7)(0))
492
sage: F=E.change_weierstrass_model(2,3,4,5)
493
sage: a=E.isomorphisms(F)
494
sage: b=[w*a[0] for w in F.automorphisms()]
495
sage: b.sort()
496
sage: a==b
497
True
498
sage: c=[a[0]*w for w in E.automorphisms()]
499
sage: c.sort()
500
sage: a==c
501
True
502
"""
503
if not isinstance(other, WeierstrassIsomorphism):
504
return cmp(type(self), type(other))
505
t = cmp(self._domain_curve, other._domain_curve)
506
if t: return t
507
t = cmp(self._codomain_curve, other._codomain_curve)
508
if t: return t
509
return baseWI.__cmp__(self,other)
510
511
def __call__(self, P):
512
r"""
513
Call function for WeierstrassIsomorphism class.
514
515
INPUT:
516
517
- ``P`` (Point) -- a point on the domain curve.
518
519
OUTPUT:
520
521
(Point) the transformed point on the codomain curve.
522
523
EXAMPLES::
524
525
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import *
526
sage: E=EllipticCurve('37a1')
527
sage: w=WeierstrassIsomorphism(E,(2,3,4,5))
528
sage: P=E(0,-1)
529
sage: w(P)
530
(-3/4 : 3/4 : 1)
531
sage: w(P).curve()==E.change_weierstrass_model((2,3,4,5))
532
True
533
"""
534
if P[2] == 0:
535
return self._codomain_curve(0)
536
else:
537
return self._codomain_curve.point(baseWI.__call__(self,tuple(P._coords)), check=False)
538
539
def __invert__(self):
540
r"""
541
Returns the inverse of this WeierstrassIsomorphism.
542
543
EXAMPLES::
544
545
sage: E = EllipticCurve('5077')
546
sage: F = E.change_weierstrass_model([2,3,4,5]); F
547
Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field
548
sage: w = E.isomorphism_to(F)
549
sage: P = E(-2,3,1)
550
sage: w(P)
551
(-5/4 : 9/4 : 1)
552
sage: ~w
553
Generic morphism:
554
From: Abelian group of points on Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field
555
To: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
556
Via: (u,r,s,t) = (1/2, -3/4, -2, 7/8)
557
sage: Q = w(P); Q
558
(-5/4 : 9/4 : 1)
559
sage: (~w)(Q)
560
(-2 : 3 : 1)
561
"""
562
winv=baseWI.__invert__(self).tuple()
563
return WeierstrassIsomorphism(self._codomain_curve, winv, self._domain_curve)
564
565
def __mul__(self,other):
566
r"""
567
Returns the composition of this WeierstrassIsomorphism and the other,
568
569
WeierstrassMorphisms can be composed using ``*`` if the
570
codomain & domain match: `(w1*w2)(X)=w1(w2(X))`, so we require
571
``w1.domain()==w2.codomain()``.
572
573
EXAMPLES::
574
575
sage: E1 = EllipticCurve('5077')
576
sage: E2 = E1.change_weierstrass_model([2,3,4,5])
577
sage: w1 = E1.isomorphism_to(E2)
578
sage: E3 = E2.change_weierstrass_model([6,7,8,9])
579
sage: w2 = E2.isomorphism_to(E3)
580
sage: P = E1(-2,3,1)
581
sage: (w2*w1)(P)==w2(w1(P))
582
True
583
"""
584
if self._domain_curve==other._codomain_curve:
585
w=baseWI.__mul__(self,other)
586
return WeierstrassIsomorphism(other._domain_curve, w.tuple(), self._codomain_curve)
587
else:
588
raise ValueError, "Domain of first argument must equal codomain of second"
589
590
def __repr__(self):
591
r"""
592
Returns the string representation of this WeierstrassIsomorphism.
593
594
OUTPUT:
595
596
(string) The underlying morphism, together with an extra line
597
showing the `(u,r,s,t)` parameters.
598
599
EXAMPLES::
600
601
sage: E1 = EllipticCurve('5077')
602
sage: E2 = E1.change_weierstrass_model([2,3,4,5])
603
sage: E1.isomorphism_to(E2)
604
Generic morphism:
605
From: Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
606
To: Abelian group of points on Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 7/4*x^2 - 3/2*x - 9/32 over Rational Field
607
Via: (u,r,s,t) = (2, 3, 4, 5)
608
"""
609
return Morphism.__repr__(self)+"\n Via: (u,r,s,t) = "+baseWI.__repr__(self)
610
611
612
613