Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx
8820 views
1
"""
2
Descent on elliptic curves over QQ with a 2-isogeny.
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2009 Robert L. Miller <[email protected]>
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
# http://www.gnu.org/licenses/
10
#*****************************************************************************
11
12
from sage.rings.all import ZZ
13
from sage.rings.polynomial.polynomial_ring import polygen
14
cdef object x_ZZ = polygen(ZZ)
15
from sage.rings.polynomial.real_roots import real_roots
16
from sage.rings.arith import prime_divisors
17
from sage.misc.all import walltime, cputime
18
from sage.all import ntl
19
20
from sage.rings.integer cimport Integer
21
22
include "sage/ext/cdefs.pxi"
23
include "sage/ext/interrupt.pxi"
24
include "sage/libs/flint/fmpz_poly.pxi"
25
26
from sage.libs.flint.nmod_poly cimport *, nmod_poly_t
27
from sage.libs.flint.ulong_extras cimport *, n_factor_t
28
from sage.libs.ratpoints cimport ratpoints_mpz_exists_only
29
30
cdef int N_RES_CLASSES_BSD = 10
31
32
cdef unsigned long ui0 = <unsigned long>0
33
cdef unsigned long ui1 = <unsigned long>1
34
cdef unsigned long ui2 = <unsigned long>2
35
cdef unsigned long ui3 = <unsigned long>3
36
cdef unsigned long ui4 = <unsigned long>4
37
cdef unsigned long ui8 = <unsigned long>8
38
39
cdef unsigned long valuation(mpz_t a, mpz_t p):
40
"""
41
Return the number of times p divides a.
42
"""
43
cdef mpz_t aa
44
cdef unsigned long v
45
mpz_init(aa)
46
v = mpz_remove(aa,a,p)
47
mpz_clear(aa)
48
return v
49
50
def test_valuation(a, p):
51
"""
52
Doctest function for cdef long valuation(mpz_t, mpz_t).
53
54
EXAMPLE::
55
56
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_valuation as tv
57
sage: for i in [1..20]:
58
... print '%10s'%factor(i), tv(i,2), tv(i,3), tv(i,5)
59
1 0 0 0
60
2 1 0 0
61
3 0 1 0
62
2^2 2 0 0
63
5 0 0 1
64
2 * 3 1 1 0
65
7 0 0 0
66
2^3 3 0 0
67
3^2 0 2 0
68
2 * 5 1 0 1
69
11 0 0 0
70
2^2 * 3 2 1 0
71
13 0 0 0
72
2 * 7 1 0 0
73
3 * 5 0 1 1
74
2^4 4 0 0
75
17 0 0 0
76
2 * 3^2 1 2 0
77
19 0 0 0
78
2^2 * 5 2 0 1
79
80
"""
81
cdef Integer A = Integer(a)
82
cdef Integer P = Integer(p)
83
return valuation(A.value, P.value)
84
85
cdef int padic_square(mpz_t a, mpz_t p):
86
"""
87
Test if a is a p-adic square.
88
"""
89
cdef unsigned long v
90
cdef mpz_t aa
91
cdef int result
92
93
if mpz_sgn(a) == 0: return 1
94
95
v = valuation(a,p)
96
if v&(ui1): return 0
97
98
mpz_init_set(aa,a)
99
while v:
100
v -= 1
101
mpz_divexact(aa, aa, p)
102
if mpz_cmp_ui(p, ui2)==0:
103
result = ( mpz_fdiv_ui(aa,ui8)==ui1 )
104
else:
105
result = ( mpz_legendre(aa,p)==1 )
106
mpz_clear(aa)
107
return result
108
109
def test_padic_square(a, p):
110
"""
111
Doctest function for cdef int padic_square(mpz_t, unsigned long).
112
113
EXAMPLE::
114
115
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps
116
sage: for i in [1..300]:
117
... for p in prime_range(100):
118
... if not Qp(p)(i).is_square()==bool(ps(i,p)):
119
... print i, p
120
121
"""
122
cdef Integer A = Integer(a)
123
cdef Integer P = Integer(p)
124
return padic_square(A.value, P.value)
125
126
cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
127
mpz_t x, mpz_t p, unsigned long nu):
128
"""
129
Implements Lemma 6 of BSD's "Notes on elliptic curves, I" for odd p.
130
131
Returns -1 for insoluble, 0 for undecided, +1 for soluble.
132
"""
133
cdef mpz_t g_of_x, g_prime_of_x
134
cdef unsigned long lambd, mu
135
cdef int result = -1
136
137
mpz_init(g_of_x)
138
mpz_mul(g_of_x, a, x)
139
mpz_add(g_of_x, g_of_x, b)
140
mpz_mul(g_of_x, g_of_x, x)
141
mpz_add(g_of_x, g_of_x, c)
142
mpz_mul(g_of_x, g_of_x, x)
143
mpz_add(g_of_x, g_of_x, d)
144
mpz_mul(g_of_x, g_of_x, x)
145
mpz_add(g_of_x, g_of_x, e)
146
147
if padic_square(g_of_x, p):
148
mpz_clear(g_of_x)
149
return +1 # soluble
150
151
mpz_init_set(g_prime_of_x, x)
152
mpz_mul(g_prime_of_x, a, x)
153
mpz_mul_ui(g_prime_of_x, g_prime_of_x, ui4)
154
mpz_addmul_ui(g_prime_of_x, b, ui3)
155
mpz_mul(g_prime_of_x, g_prime_of_x, x)
156
mpz_addmul_ui(g_prime_of_x, c, ui2)
157
mpz_mul(g_prime_of_x, g_prime_of_x, x)
158
mpz_add(g_prime_of_x, g_prime_of_x, d)
159
160
lambd = valuation(g_of_x, p)
161
if mpz_sgn(g_prime_of_x)==0:
162
if lambd >= 2*nu: result = 0 # undecided
163
else:
164
mu = valuation(g_prime_of_x, p)
165
if lambd > 2*mu: result = +1 # soluble
166
elif lambd >= 2*nu and mu >= nu: result = 0 # undecided
167
168
mpz_clear(g_prime_of_x)
169
mpz_clear(g_of_x)
170
return result
171
172
cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
173
mpz_t x, mpz_t p, unsigned long nu):
174
"""
175
Implements Lemma 7 of BSD's "Notes on elliptic curves, I" for p=2.
176
177
Returns -1 for insoluble, 0 for undecided, +1 for soluble.
178
"""
179
cdef mpz_t g_of_x, g_prime_of_x, g_of_x_odd_part
180
cdef unsigned long lambd, mu, g_of_x_odd_part_mod_4
181
cdef int result = -1
182
183
mpz_init(g_of_x)
184
mpz_mul(g_of_x, a, x)
185
mpz_add(g_of_x, g_of_x, b)
186
mpz_mul(g_of_x, g_of_x, x)
187
mpz_add(g_of_x, g_of_x, c)
188
mpz_mul(g_of_x, g_of_x, x)
189
mpz_add(g_of_x, g_of_x, d)
190
mpz_mul(g_of_x, g_of_x, x)
191
mpz_add(g_of_x, g_of_x, e)
192
193
if padic_square(g_of_x, p):
194
mpz_clear(g_of_x)
195
return +1 # soluble
196
197
mpz_init_set(g_prime_of_x, x)
198
mpz_mul(g_prime_of_x, a, x)
199
mpz_mul_ui(g_prime_of_x, g_prime_of_x, ui4)
200
mpz_addmul_ui(g_prime_of_x, b, ui3)
201
mpz_mul(g_prime_of_x, g_prime_of_x, x)
202
mpz_addmul_ui(g_prime_of_x, c, ui2)
203
mpz_mul(g_prime_of_x, g_prime_of_x, x)
204
mpz_add(g_prime_of_x, g_prime_of_x, d)
205
206
lambd = valuation(g_of_x, p)
207
mpz_init_set(g_of_x_odd_part, g_of_x)
208
while mpz_even_p(g_of_x_odd_part):
209
mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, ui2)
210
g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, ui4)
211
if mpz_sgn(g_prime_of_x)==0:
212
if lambd >= 2*nu: result = 0 # undecided
213
elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1:
214
result = 0 # undecided
215
else:
216
mu = valuation(g_prime_of_x, p)
217
if lambd > 2*mu: result = +1 # soluble
218
elif nu > mu:
219
if lambd >= mu+nu: result = +1 # soluble
220
elif lambd+1 == mu+nu and lambd&ui1==0:
221
result = +1 # soluble
222
elif lambd+2 == mu+nu and lambd&ui1==0 and g_of_x_odd_part_mod_4==1:
223
result = +1 # soluble
224
else: # nu <= mu
225
if lambd >= 2*nu: result = 0 # undecided
226
elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1:
227
result = 0 # undecided
228
229
mpz_clear(g_prime_of_x)
230
mpz_clear(g_of_x)
231
return result
232
233
cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
234
mpz_t x_k, mpz_t p, unsigned long k):
235
"""
236
Uses the approach of BSD's "Notes on elliptic curves, I" to test for
237
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp, with
238
x=x_k (mod p^k).
239
"""
240
# returns solubility of y^2 = ax^4 + bx^3 + cx^2 + dx + e
241
# in Zp with x=x_k (mod p^k)
242
cdef int code
243
cdef unsigned long t
244
cdef mpz_t s
245
246
if mpz_cmp_ui(p, ui2)==0:
247
code = lemma7(a,b,c,d,e,x_k,p,k)
248
else:
249
code = lemma6(a,b,c,d,e,x_k,p,k)
250
if code == 1:
251
return 1
252
if code == -1:
253
return 0
254
255
# now code == 0
256
t = 0
257
mpz_init(s)
258
while code == 0 and mpz_cmp_ui(p, t) > 0 and t < N_RES_CLASSES_BSD:
259
mpz_pow_ui(s, p, k)
260
mpz_mul_ui(s, s, t)
261
mpz_add(s, s, x_k)
262
code = Zp_soluble_BSD(a,b,c,d,e,s,p,k+1)
263
t += 1
264
mpz_clear(s)
265
return code
266
267
cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
268
mpz_t pp, unsigned long pp_ui,
269
nmod_poly_factor_t f_factzn, nmod_poly_t f,
270
fmpz_poly_t f1, fmpz_poly_t linear):
271
"""
272
Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for
273
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.
274
"""
275
cdef unsigned long v_min, v
276
cdef unsigned long roots[4]
277
cdef int i, j, has_roots, has_single_roots
278
cdef bint result
279
280
cdef mpz_t aa, bb, cc, dd, ee
281
cdef mpz_t aaa, bbb, ccc, ddd, eee
282
cdef unsigned long qq
283
cdef unsigned long rr, ss
284
cdef mpz_t tt
285
286
# Step 0: divide out all common p from the quartic
287
v_min = valuation(a, pp)
288
if mpz_cmp_ui(b, ui0) != 0:
289
v = valuation(b, pp)
290
if v < v_min: v_min = v
291
if mpz_cmp_ui(c, ui0) != 0:
292
v = valuation(c, pp)
293
if v < v_min: v_min = v
294
if mpz_cmp_ui(d, ui0) != 0:
295
v = valuation(d, pp)
296
if v < v_min: v_min = v
297
if mpz_cmp_ui(e, ui0) != 0:
298
v = valuation(e, pp)
299
if v < v_min: v_min = v
300
for 0 <= v < v_min:
301
mpz_divexact(a, a, pp)
302
mpz_divexact(b, b, pp)
303
mpz_divexact(c, c, pp)
304
mpz_divexact(d, d, pp)
305
mpz_divexact(e, e, pp)
306
307
if not v_min%2:
308
# Step I in Alg. 5.3.1 of Siksek's thesis
309
nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))
310
nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))
311
nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))
312
nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))
313
nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))
314
315
result = 0
316
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
317
qq = nmod_poly_factor(f_factzn, f)
318
for i from 0 <= i < f_factzn.num:
319
if f_factzn.exp[i]&1:
320
result = 1
321
break
322
if result == 0 and n_jacobi(qq, pp_ui) == 1:
323
result = 1
324
if result:
325
return 1
326
327
nmod_poly_zero(f)
328
nmod_poly_set_coeff_ui(f, 0, ui1)
329
for i from 0 <= i < f_factzn.num:
330
for j from 0 <= j < (f_factzn.exp[i]>>1):
331
nmod_poly_mul(f, f, &f_factzn.p[i])
332
333
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
334
nmod_poly_factor(f_factzn, f)
335
has_roots = 0
336
j = 0
337
for i from 0 <= i < f_factzn.num:
338
if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):
339
has_roots = 1
340
roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)
341
j += 1
342
if not has_roots:
343
return 0
344
345
i = nmod_poly_degree(f)
346
mpz_init(aaa)
347
mpz_init(bbb)
348
mpz_init(ccc)
349
mpz_init(ddd)
350
mpz_init(eee)
351
352
if i == 0: # g == 1
353
mpz_set(aaa, a)
354
mpz_set(bbb, b)
355
mpz_set(ccc, c)
356
mpz_set(ddd, d)
357
mpz_sub_ui(eee, e, qq)
358
elif i == 1: # g == x + rr
359
mpz_set(aaa, a)
360
mpz_set(bbb, b)
361
mpz_sub_ui(ccc, c, qq)
362
rr = nmod_poly_get_coeff_ui(f, 0)
363
ss = rr*qq
364
mpz_set(ddd,d)
365
mpz_sub_ui(ddd, ddd, ss*ui2)
366
mpz_set(eee,e)
367
mpz_sub_ui(eee, eee, ss*rr)
368
elif i == 2: # g == x^2 + rr*x + ss
369
mpz_sub_ui(aaa, a, qq)
370
rr = nmod_poly_get_coeff_ui(f, 1)
371
mpz_init(tt)
372
mpz_set_ui(tt, rr*qq)
373
mpz_set(bbb,b)
374
mpz_submul_ui(bbb, tt, ui2)
375
mpz_set(ccc,c)
376
mpz_submul_ui(ccc, tt, rr)
377
ss = nmod_poly_get_coeff_ui(f, 0)
378
mpz_set_ui(tt, ss*qq)
379
mpz_set(eee,e)
380
mpz_submul_ui(eee, tt, ss)
381
mpz_mul_ui(tt, tt, ui2)
382
mpz_sub(ccc, ccc, tt)
383
mpz_set(ddd,d)
384
mpz_submul_ui(ddd, tt, rr)
385
mpz_clear(tt)
386
mpz_divexact(aaa, aaa, pp)
387
mpz_divexact(bbb, bbb, pp)
388
mpz_divexact(ccc, ccc, pp)
389
mpz_divexact(ddd, ddd, pp)
390
mpz_divexact(eee, eee, pp)
391
# now aaa,bbb,ccc,ddd,eee represents h(x)
392
393
result = 0
394
mpz_init(tt)
395
for i from 0 <= i < j:
396
mpz_mul_ui(tt, aaa, roots[i])
397
mpz_add(tt, tt, bbb)
398
mpz_mul_ui(tt, tt, roots[i])
399
mpz_add(tt, tt, ccc)
400
mpz_mul_ui(tt, tt, roots[i])
401
mpz_add(tt, tt, ddd)
402
mpz_mul_ui(tt, tt, roots[i])
403
mpz_add(tt, tt, eee)
404
# tt == h(r) mod p
405
mpz_mod(tt, tt, pp)
406
if mpz_sgn(tt) == 0:
407
fmpz_poly_zero(f1)
408
fmpz_poly_zero(linear)
409
fmpz_poly_set_coeff_mpz(f1, 0, e)
410
fmpz_poly_set_coeff_mpz(f1, 1, d)
411
fmpz_poly_set_coeff_mpz(f1, 2, c)
412
fmpz_poly_set_coeff_mpz(f1, 3, b)
413
fmpz_poly_set_coeff_mpz(f1, 4, a)
414
fmpz_poly_set_coeff_ui(linear, 0, roots[i])
415
fmpz_poly_set_coeff_mpz(linear, 1, pp)
416
fmpz_poly_compose(f1, f1, linear)
417
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
418
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
419
mpz_init(aa)
420
mpz_init(bb)
421
mpz_init(cc)
422
mpz_init(dd)
423
mpz_init(ee)
424
fmpz_poly_get_coeff_mpz(aa, f1, 4)
425
fmpz_poly_get_coeff_mpz(bb, f1, 3)
426
fmpz_poly_get_coeff_mpz(cc, f1, 2)
427
fmpz_poly_get_coeff_mpz(dd, f1, 1)
428
fmpz_poly_get_coeff_mpz(ee, f1, 0)
429
result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)
430
mpz_clear(aa)
431
mpz_clear(bb)
432
mpz_clear(cc)
433
mpz_clear(dd)
434
mpz_clear(ee)
435
if result == 1:
436
break
437
mpz_clear(aaa)
438
mpz_clear(bbb)
439
mpz_clear(ccc)
440
mpz_clear(ddd)
441
mpz_clear(eee)
442
mpz_clear(tt)
443
return result
444
else:
445
# Step II in Alg. 5.3.1 of Siksek's thesis
446
nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))
447
nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))
448
nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))
449
nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))
450
nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))
451
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
452
nmod_poly_factor(f_factzn, f)
453
has_roots = 0
454
has_single_roots = 0
455
j = 0
456
for i from 0 <= i < f_factzn.num:
457
if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):
458
has_roots = 1
459
if f_factzn.exp[i] == 1:
460
has_single_roots = 1
461
break
462
roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)
463
j += 1
464
465
if not has_roots: return 0
466
if has_single_roots: return 1
467
468
result = 0
469
if j > 0:
470
mpz_init(aa)
471
mpz_init(bb)
472
mpz_init(cc)
473
mpz_init(dd)
474
mpz_init(ee)
475
for i from 0 <= i < j:
476
fmpz_poly_zero(f1)
477
fmpz_poly_zero(linear)
478
fmpz_poly_set_coeff_mpz(f1, 0, e)
479
fmpz_poly_set_coeff_mpz(f1, 1, d)
480
fmpz_poly_set_coeff_mpz(f1, 2, c)
481
fmpz_poly_set_coeff_mpz(f1, 3, b)
482
fmpz_poly_set_coeff_mpz(f1, 4, a)
483
fmpz_poly_set_coeff_ui(linear, 0, roots[i])
484
fmpz_poly_set_coeff_mpz(linear, 1, pp)
485
fmpz_poly_compose(f1, f1, linear)
486
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
487
fmpz_poly_get_coeff_mpz(aa, f1, 4)
488
fmpz_poly_get_coeff_mpz(bb, f1, 3)
489
fmpz_poly_get_coeff_mpz(cc, f1, 2)
490
fmpz_poly_get_coeff_mpz(dd, f1, 1)
491
fmpz_poly_get_coeff_mpz(ee, f1, 0)
492
result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)
493
if result == 1:
494
break
495
if j > 0:
496
mpz_clear(aa)
497
mpz_clear(bb)
498
mpz_clear(cc)
499
mpz_clear(dd)
500
mpz_clear(ee)
501
return result
502
503
cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp,
504
fmpz_poly_t f1, fmpz_poly_t linear):
505
"""
506
Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for
507
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.
508
"""
509
cdef unsigned long v_min, v
510
cdef mpz_t roots[4]
511
cdef int i, j, has_roots, has_single_roots
512
cdef bint result
513
514
cdef mpz_t aa, bb, cc, dd, ee
515
cdef mpz_t aaa, bbb, ccc, ddd, eee
516
cdef mpz_t qq, rr, ss, tt
517
cdef Integer A,B,C,D,E,P
518
519
# Step 0: divide out all common p from the quartic
520
v_min = valuation(a, pp)
521
if mpz_cmp_ui(b, ui0) != 0:
522
v = valuation(b, pp)
523
if v < v_min: v_min = v
524
if mpz_cmp_ui(c, ui0) != 0:
525
v = valuation(c, pp)
526
if v < v_min: v_min = v
527
if mpz_cmp_ui(d, ui0) != 0:
528
v = valuation(d, pp)
529
if v < v_min: v_min = v
530
if mpz_cmp_ui(e, ui0) != 0:
531
v = valuation(e, pp)
532
if v < v_min: v_min = v
533
for 0 <= v < v_min:
534
mpz_divexact(a, a, pp)
535
mpz_divexact(b, b, pp)
536
mpz_divexact(c, c, pp)
537
mpz_divexact(d, d, pp)
538
mpz_divexact(e, e, pp)
539
540
if not v_min%2:
541
# Step I in Alg. 5.3.1 of Siksek's thesis
542
A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0)
543
mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp)
544
f = ntl.ZZ_pX([E,D,C,B,A], P)
545
f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E
546
mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial
547
f_factzn = f.factor()
548
result = 0
549
for factor, exponent in f_factzn:
550
if exponent&1:
551
result = 1
552
break
553
if result == 0 and mpz_legendre(qq, pp) == 1:
554
result = 1
555
if result:
556
return 1
557
558
f = ntl.ZZ_pX([1], P)
559
for factor, exponent in f_factzn:
560
for j from 0 <= j < (exponent/2):
561
f *= factor
562
563
f /= f.leading_coefficient()
564
f_factzn = f.factor()
565
566
has_roots = 0
567
j = 0
568
for factor, exponent in f_factzn:
569
if factor.degree() == 1:
570
has_roots = 1
571
A = P - Integer(factor[0])
572
mpz_set(roots[j], A.value)
573
j += 1
574
if not has_roots:
575
return 0
576
577
i = f.degree()
578
mpz_init(aaa)
579
mpz_init(bbb)
580
mpz_init(ccc)
581
mpz_init(ddd)
582
mpz_init(eee)
583
584
if i == 0: # g == 1
585
mpz_set(aaa, a)
586
mpz_set(bbb, b)
587
mpz_set(ccc, c)
588
mpz_set(ddd, d)
589
mpz_sub(eee, e, qq)
590
elif i == 1: # g == x + rr
591
mpz_set(aaa, a)
592
mpz_set(bbb, b)
593
mpz_sub(ccc, c, qq)
594
A = Integer(f[0])
595
mpz_set(rr, A.value)
596
mpz_mul(ss, rr, qq)
597
mpz_set(ddd,d)
598
mpz_sub(ddd, ddd, ss)
599
mpz_sub(ddd, ddd, ss)
600
mpz_set(eee,e)
601
mpz_mul(ss, ss, rr)
602
mpz_sub(eee, eee, ss)
603
mpz_divexact(ss, ss, rr)
604
elif i == 2: # g == x^2 + rr*x + ss
605
mpz_sub(aaa, a, qq)
606
A = Integer(f[1])
607
mpz_set(rr, A.value)
608
mpz_init(tt)
609
mpz_mul(tt, rr, qq)
610
mpz_set(bbb,b)
611
mpz_submul_ui(bbb, tt, ui2)
612
mpz_set(ccc,c)
613
mpz_submul(ccc, tt, rr)
614
A = Integer(f[0])
615
mpz_set(ss, A.value)
616
mpz_mul(tt, ss, qq)
617
mpz_set(eee,e)
618
mpz_submul(eee, tt, ss)
619
mpz_mul_ui(tt, tt, ui2)
620
mpz_sub(ccc, ccc, tt)
621
mpz_set(ddd,d)
622
mpz_submul(ddd, tt, rr)
623
mpz_clear(tt)
624
mpz_divexact(aaa, aaa, pp)
625
mpz_divexact(bbb, bbb, pp)
626
mpz_divexact(ccc, ccc, pp)
627
mpz_divexact(ddd, ddd, pp)
628
mpz_divexact(eee, eee, pp)
629
# now aaa,bbb,ccc,ddd,eee represents h(x)
630
631
result = 0
632
mpz_init(tt)
633
for i from 0 <= i < j:
634
mpz_mul(tt, aaa, roots[i])
635
mpz_add(tt, tt, bbb)
636
mpz_mul(tt, tt, roots[i])
637
mpz_add(tt, tt, ccc)
638
mpz_mul(tt, tt, roots[i])
639
mpz_add(tt, tt, ddd)
640
mpz_mul(tt, tt, roots[i])
641
mpz_add(tt, tt, eee)
642
# tt == h(r) mod p
643
mpz_mod(tt, tt, pp)
644
if mpz_sgn(tt) == 0:
645
fmpz_poly_zero(f1)
646
fmpz_poly_zero(linear)
647
fmpz_poly_set_coeff_mpz(f1, 0, e)
648
fmpz_poly_set_coeff_mpz(f1, 1, d)
649
fmpz_poly_set_coeff_mpz(f1, 2, c)
650
fmpz_poly_set_coeff_mpz(f1, 3, b)
651
fmpz_poly_set_coeff_mpz(f1, 4, a)
652
fmpz_poly_set_coeff_mpz(linear, 0, roots[i])
653
fmpz_poly_set_coeff_mpz(linear, 1, pp)
654
fmpz_poly_compose(f1, f1, linear)
655
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
656
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
657
658
mpz_init(aa)
659
mpz_init(bb)
660
mpz_init(cc)
661
mpz_init(dd)
662
mpz_init(ee)
663
fmpz_poly_get_coeff_mpz(aa, f1, 4)
664
fmpz_poly_get_coeff_mpz(bb, f1, 3)
665
fmpz_poly_get_coeff_mpz(cc, f1, 2)
666
fmpz_poly_get_coeff_mpz(dd, f1, 1)
667
fmpz_poly_get_coeff_mpz(ee, f1, 0)
668
result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)
669
mpz_clear(aa)
670
mpz_clear(bb)
671
mpz_clear(cc)
672
mpz_clear(dd)
673
mpz_clear(ee)
674
if result == 1:
675
break
676
mpz_clear(aaa)
677
mpz_clear(bbb)
678
mpz_clear(ccc)
679
mpz_clear(ddd)
680
mpz_clear(eee)
681
mpz_clear(tt)
682
return result
683
else:
684
# Step II in Alg. 5.3.1 of Siksek's thesis
685
A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0)
686
mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp)
687
f = ntl.ZZ_pX([E,D,C,B,A], P)
688
f /= ntl.ZZ_pX([A], P) # now f is monic
689
f_factzn = f.factor()
690
691
has_roots = 0
692
has_single_roots = 0
693
j = 0
694
for factor, exponent in f_factzn:
695
if factor.degree() == 1:
696
has_roots = 1
697
if exponent == 1:
698
has_single_roots = 1
699
break
700
A = P - Integer(factor[0])
701
mpz_set(roots[j], A.value)
702
j += 1
703
704
if not has_roots: return 0
705
if has_single_roots: return 1
706
707
result = 0
708
if j > 0:
709
mpz_init(aa)
710
mpz_init(bb)
711
mpz_init(cc)
712
mpz_init(dd)
713
mpz_init(ee)
714
for i from 0 <= i < j:
715
fmpz_poly_zero(f1)
716
fmpz_poly_zero(linear)
717
fmpz_poly_set_coeff_mpz(f1, 0, e)
718
fmpz_poly_set_coeff_mpz(f1, 1, d)
719
fmpz_poly_set_coeff_mpz(f1, 2, c)
720
fmpz_poly_set_coeff_mpz(f1, 3, b)
721
fmpz_poly_set_coeff_mpz(f1, 4, a)
722
fmpz_poly_set_coeff_mpz(linear, 0, roots[i])
723
fmpz_poly_set_coeff_mpz(linear, 1, pp)
724
fmpz_poly_compose(f1, f1, linear)
725
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
726
fmpz_poly_get_coeff_mpz(aa, f1, 4)
727
fmpz_poly_get_coeff_mpz(bb, f1, 3)
728
fmpz_poly_get_coeff_mpz(cc, f1, 2)
729
fmpz_poly_get_coeff_mpz(dd, f1, 1)
730
fmpz_poly_get_coeff_mpz(ee, f1, 0)
731
result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)
732
if result == 1:
733
break
734
if j > 0:
735
mpz_clear(aa)
736
mpz_clear(bb)
737
mpz_clear(cc)
738
mpz_clear(dd)
739
mpz_clear(ee)
740
return result
741
742
cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,
743
mpz_t p, unsigned long P,
744
nmod_poly_factor_t f_factzn, fmpz_poly_t f1,
745
fmpz_poly_t linear):
746
"""
747
Uses Samir Siksek's thesis results to determine whether the quartic is
748
locally soluble at p.
749
"""
750
cdef int result = 0
751
cdef mpz_t a,b,c,d,e
752
cdef nmod_poly_t f
753
nmod_poly_init(f, P)
754
755
mpz_init_set(a,A)
756
mpz_init_set(b,B)
757
mpz_init_set(c,C)
758
mpz_init_set(d,D)
759
mpz_init_set(e,E)
760
761
if Zp_soluble_siksek(a,b,c,d,e,p,P,f_factzn, f, f1, linear):
762
result = 1
763
else:
764
mpz_set(a,A)
765
mpz_set(b,B)
766
mpz_set(c,C)
767
mpz_set(d,D)
768
mpz_set(e,E)
769
if Zp_soluble_siksek(e,d,c,b,a,p,P,f_factzn, f, f1, linear):
770
result = 1
771
772
mpz_clear(a)
773
mpz_clear(b)
774
mpz_clear(c)
775
mpz_clear(d)
776
mpz_clear(e)
777
nmod_poly_clear(f)
778
return result
779
780
cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,
781
mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear):
782
"""
783
Uses Samir Siksek's thesis results to determine whether the quartic is
784
locally soluble at p, when p is bigger than wordsize, and we can't use
785
FLINT.
786
"""
787
cdef int result = 0
788
cdef mpz_t a,b,c,d,e
789
790
mpz_init_set(a,A)
791
mpz_init_set(b,B)
792
mpz_init_set(c,C)
793
mpz_init_set(d,D)
794
mpz_init_set(e,E)
795
796
if Zp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear):
797
result = 1
798
else:
799
mpz_set(a,A)
800
mpz_set(b,B)
801
mpz_set(c,C)
802
mpz_set(d,D)
803
mpz_set(e,E)
804
if Zp_soluble_siksek_large_p(e,d,c,b,a,p,f1,linear):
805
result = 1
806
807
mpz_clear(a)
808
mpz_clear(b)
809
mpz_clear(c)
810
mpz_clear(d)
811
mpz_clear(e)
812
return result
813
814
cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p):
815
"""
816
Uses the original test of Birch and Swinnerton-Dyer to test for local
817
solubility of the quartic at p.
818
"""
819
cdef mpz_t zero
820
cdef int result = 0
821
mpz_init_set_ui(zero, ui0)
822
if Zp_soluble_BSD(a,b,c,d,e,zero,p,0):
823
result = 1
824
elif Zp_soluble_BSD(e,d,c,b,a,zero,p,1):
825
result = 1
826
mpz_clear(zero)
827
return result
828
829
cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p):
830
"""
831
Try the BSD approach for a few residue classes and if no solution is found,
832
switch to Siksek to try to prove insolubility.
833
"""
834
cdef int bsd_sol, sik_sol
835
cdef unsigned long pp
836
cdef fmpz_poly_t f1, linear
837
cdef nmod_poly_factor_t f_factzn
838
bsd_sol = Qp_soluble_BSD(a, b, c, d, e, p)
839
if mpz_cmp_ui(p,N_RES_CLASSES_BSD)>0 and not bsd_sol:
840
fmpz_poly_init(f1)
841
fmpz_poly_init(linear)
842
if mpz_fits_ulong_p(p):
843
nmod_poly_factor_init(f_factzn)
844
pp = mpz_get_ui(p)
845
sik_sol = Qp_soluble_siksek(a,b,c,d,e,p,pp,f_factzn,f1,linear)
846
nmod_poly_factor_clear(f_factzn)
847
else:
848
sik_sol = Qp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear)
849
fmpz_poly_clear(f1)
850
fmpz_poly_clear(linear)
851
else:
852
sik_sol = bsd_sol
853
return sik_sol
854
855
def test_qpls(a,b,c,d,e,p):
856
"""
857
Testing function for Qp_soluble.
858
859
EXAMPLE:
860
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_qpls as tq
861
sage: tq(1,2,3,4,5,7)
862
1
863
864
"""
865
cdef Integer A,B,C,D,E,P
866
cdef int i, result
867
cdef mpz_t aa,bb,cc,dd,ee,pp
868
A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e); P=Integer(p)
869
mpz_init_set(aa, A.value)
870
mpz_init_set(bb, B.value)
871
mpz_init_set(cc, C.value)
872
mpz_init_set(dd, D.value)
873
mpz_init_set(ee, E.value)
874
mpz_init_set(pp, P.value)
875
result = Qp_soluble(aa, bb, cc, dd, ee, pp)
876
mpz_clear(aa)
877
mpz_clear(bb)
878
mpz_clear(cc)
879
mpz_clear(dd)
880
mpz_clear(ee)
881
mpz_clear(pp)
882
return result
883
884
cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1:
885
"""
886
Returns whether the quartic has local solutions at all primes p.
887
"""
888
cdef Integer A,B,C,D,E,Delta,p
889
cdef mpz_t mpz_2
890
A=Integer(0); B=Integer(0); C=Integer(0); D=Integer(0); E=Integer(0)
891
mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e);
892
f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E
893
894
# RR soluble:
895
if mpz_sgn(a)!=1:
896
if len(real_roots(f)) == 0:
897
return 0
898
899
# Q2 soluble:
900
mpz_init_set_ui(mpz_2, ui2)
901
if not Qp_soluble(a,b,c,d,e,mpz_2):
902
mpz_clear(mpz_2)
903
return 0
904
mpz_clear(mpz_2)
905
906
# Odd finite primes
907
Delta = f.discriminant()
908
for p in prime_divisors(Delta):
909
if p == 2: continue
910
if not Qp_soluble(a,b,c,d,e,p.value): return 0
911
912
return 1
913
914
def test_els(a,b,c,d,e):
915
"""
916
Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t).
917
918
EXAMPLE::
919
920
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_els
921
sage: from sage.libs.ratpoints import ratpoints
922
sage: for _ in range(1000):
923
... a,b,c,d,e = randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000)
924
... if len(ratpoints([e,d,c,b,a], 1000)) > 0:
925
... try:
926
... if not test_els(a,b,c,d,e):
927
... print "This never happened", a,b,c,d,e
928
... except ValueError:
929
... continue
930
931
"""
932
cdef Integer A,B,C,D,E,Delta
933
A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e)
934
return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value)
935
936
cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len,
937
int global_limit_small, int global_limit_large,
938
int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1:
939
"""
940
Count the number of els/gls quartic 2-covers of E.
941
"""
942
cdef unsigned long n_primes, i
943
cdef bint found_global_points, els, check_negs, verbose = (verbosity > 4)
944
cdef Integer a_Int, c_Int, e_Int
945
cdef mpz_t c_sq_mpz, d_prime_mpz
946
cdef mpz_t n_divisors, j
947
cdef mpz_t *coeffs_ratp
948
949
950
mpz_init(c_sq_mpz)
951
mpz_mul(c_sq_mpz, c_mpz, c_mpz)
952
mpz_init_set(d_prime_mpz, c_sq_mpz)
953
mpz_submul_ui(d_prime_mpz, d_mpz, ui4)
954
check_negs = 0
955
if mpz_sgn(d_prime_mpz) > 0:
956
if mpz_sgn(c_mpz) >= 0 or mpz_cmp(c_sq_mpz, d_prime_mpz) <= 0:
957
check_negs = 1
958
mpz_clear(c_sq_mpz)
959
mpz_clear(d_prime_mpz)
960
961
962
# Set up coefficient array, and static variables
963
cdef mpz_t *coeffs = <mpz_t *> sage_malloc(5 * sizeof(mpz_t))
964
for i from 0 <= i <= 4:
965
mpz_init(coeffs[i])
966
mpz_set_ui(coeffs[1], ui0) #
967
mpz_set(coeffs[2], c_mpz) # These never change
968
mpz_set_ui(coeffs[3], ui0) #
969
970
if not selmer_only:
971
# allocate space for ratpoints
972
coeffs_ratp = <mpz_t *> sage_malloc(5 * sizeof(mpz_t))
973
for i from 0 <= i <= 4:
974
mpz_init(coeffs_ratp[i])
975
976
# Get prime divisors, and put them in an mpz_t array
977
# (this block, by setting check_negs, takes care of
978
# local solubility over RR)
979
cdef mpz_t *p_div_d_mpz = <mpz_t *> sage_malloc((p_list_len+1) * sizeof(mpz_t))
980
n_primes = 0
981
for i from 0 <= i < p_list_len:
982
if mpz_divisible_p(d_mpz, p_list[i]):
983
mpz_init(p_div_d_mpz[n_primes])
984
mpz_set(p_div_d_mpz[n_primes], p_list[i])
985
n_primes += 1
986
if check_negs:
987
mpz_init(p_div_d_mpz[n_primes])
988
mpz_set_si(p_div_d_mpz[n_primes], -1)
989
n_primes += 1
990
mpz_init_set_ui(n_divisors, ui1)
991
mpz_mul_2exp(n_divisors, n_divisors, n_primes)
992
# if verbosity > 3:
993
# print '\nDivisors of d which may lead to RR-soluble quartics:', p_div_d
994
995
mpz_init_set_ui(j, ui0)
996
if not selmer_only:
997
mpz_set_ui(n1, ui0)
998
mpz_set_ui(n2, ui0)
999
while mpz_cmp(j, n_divisors) < 0:
1000
mpz_set_ui(coeffs[4], ui1)
1001
for i from 0 <= i < n_primes:
1002
if mpz_tstbit(j, i):
1003
mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i])
1004
if verbosity > 3:
1005
a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])
1006
print '\nSquarefree divisor:', a_Int
1007
mpz_divexact(coeffs[0], d_mpz, coeffs[4])
1008
found_global_points = 0
1009
if not selmer_only:
1010
if verbose:
1011
print "\nCalling ratpoints for small point search"
1012
for i from 0 <= i <= 4:
1013
mpz_set(coeffs_ratp[i], coeffs[i])
1014
sig_on()
1015
found_global_points = ratpoints_mpz_exists_only(coeffs_ratp, global_limit_small, 4, verbose)
1016
sig_off()
1017
if found_global_points:
1018
if verbosity > 2:
1019
a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])
1020
c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2])
1021
e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0])
1022
print 'Found small global point, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)
1023
mpz_add_ui(n1, n1, ui1)
1024
mpz_add_ui(n2, n2, ui1)
1025
if verbose:
1026
print "\nDone calling ratpoints for small point search"
1027
if not found_global_points:
1028
# Test whether the quartic is everywhere locally soluble:
1029
els = 1
1030
for i from 0 <= i < p_list_len:
1031
if not Qp_soluble(coeffs[4], coeffs[3], coeffs[2], coeffs[1], coeffs[0], p_list[i]):
1032
els = 0
1033
break
1034
if els:
1035
if verbosity > 2:
1036
a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])
1037
c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2])
1038
e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0])
1039
print 'ELS without small global points, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)
1040
mpz_add_ui(n2, n2, ui1)
1041
if not selmer_only:
1042
if verbose:
1043
print "\nCalling ratpoints for large point search"
1044
for i from 0 <= i <= 4:
1045
mpz_set(coeffs_ratp[i], coeffs[i])
1046
sig_on()
1047
found_global_points = ratpoints_mpz_exists_only(coeffs_ratp, global_limit_large, 4, verbose)
1048
sig_off()
1049
if found_global_points:
1050
if verbosity > 2:
1051
print ' -- Found large global point.'
1052
mpz_add_ui(n1, n1, ui1)
1053
if verbose:
1054
print "\nDone calling ratpoints for large point search"
1055
mpz_add_ui(j, j, ui1)
1056
if not selmer_only:
1057
for i from 0 <= i <= 4:
1058
mpz_clear(coeffs_ratp[i])
1059
sage_free(coeffs_ratp)
1060
mpz_clear(j)
1061
for i from 0 <= i < n_primes:
1062
mpz_clear(p_div_d_mpz[i])
1063
sage_free(p_div_d_mpz)
1064
mpz_clear(n_divisors)
1065
for i from 0 <= i <= 4:
1066
mpz_clear(coeffs[i])
1067
sage_free(coeffs)
1068
return 0
1069
1070
def two_descent_by_two_isogeny(E,
1071
int global_limit_small = 10,
1072
int global_limit_large = 10000,
1073
int verbosity = 0,
1074
bint selmer_only = 0, bint proof = 1):
1075
"""
1076
Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny
1077
phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here
1078
n1 is the number of quartic covers found with a rational point, and n2 is
1079
the number which are ELS.
1080
1081
EXAMPLES::
1082
1083
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny
1084
sage: E = EllipticCurve('14a')
1085
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
1086
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1087
0
1088
sage: E = EllipticCurve('65a')
1089
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
1090
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1091
1
1092
sage: x,y = var('x,y')
1093
sage: E = EllipticCurve(y^2 == x^3 + x^2 - 25*x + 39)
1094
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
1095
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1096
2
1097
sage: E = EllipticCurve(y^2 + x*y + y == x^3 - 131*x + 558)
1098
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
1099
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1100
3
1101
1102
Using the verbosity option::
1103
1104
sage: E = EllipticCurve('14a')
1105
sage: two_descent_by_two_isogeny(E, verbosity=1)
1106
2-isogeny
1107
Results:
1108
2 <= #E(Q)/phi'(E'(Q)) <= 2
1109
2 <= #E'(Q)/phi(E(Q)) <= 2
1110
#Sel^(phi')(E'/Q) = 2
1111
#Sel^(phi)(E/Q) = 2
1112
1 <= #Sha(E'/Q)[phi'] <= 1
1113
1 <= #Sha(E/Q)[phi] <= 1
1114
1 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <= 1
1115
0 <= rank of E(Q) = rank of E'(Q) <= 0
1116
(2, 2, 2, 2)
1117
1118
Handling curves whose discriminants involve larger than wordsize primes::
1119
1120
sage: E = EllipticCurve('14a')
1121
sage: E = E.quadratic_twist(next_prime(10^20))
1122
sage: E
1123
Elliptic Curve defined by y^2 = x^3 + x^2 + 716666666666666667225666666666666666775672*x - 391925925925925926384240370370370370549019837037037037060249356 over Rational Field
1124
sage: E.discriminant().factor()
1125
-1 * 2^18 * 7^3 * 100000000000000000039^6
1126
sage: log(100000000000000000039.0, 2.0)
1127
66.438...
1128
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
1129
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1130
0
1131
1132
TESTS:
1133
1134
Here we contrive an example to demonstrate that a keyboard interrupt
1135
is caught. Here we let `E` be the smallest optimal curve with two-torsion
1136
and nontrivial `Sha[2]`. This ensures that the two-descent will be looking
1137
for rational points which do not exist, and by setting global_limit_large
1138
to a very high bound, it will still be working when we simulate a ``CTRL-C``::
1139
1140
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny
1141
sage: import sage.tests.interrupt
1142
sage: E = EllipticCurve('960d'); E
1143
Elliptic Curve defined by y^2 = x^3 - x^2 - 900*x - 10098 over Rational Field
1144
sage: E.sha().an()
1145
4
1146
sage: try:
1147
... sage.tests.interrupt.interrupt_after_delay(1000)
1148
... two_descent_by_two_isogeny(E, global_limit_large=10^8)
1149
... except KeyboardInterrupt:
1150
... print "Caught!"
1151
Caught!
1152
"""
1153
cdef Integer a1, a2, a3, a4, a6, s2, s4, s6
1154
cdef Integer c, d, x0
1155
cdef list x_list
1156
assert E.torsion_order()%2==0, 'Need rational two-torsion for isogeny descent.'
1157
if verbosity > 0:
1158
print '\n2-isogeny'
1159
if verbosity > 1:
1160
print '\nchanging coordinates'
1161
a1 = Integer(E.a1())
1162
a2 = Integer(E.a2())
1163
a3 = Integer(E.a3())
1164
a4 = Integer(E.a4())
1165
a6 = Integer(E.a6())
1166
if a1==0 and a3==0:
1167
s2=a2; s4=a4; s6=a6
1168
else:
1169
s2=a1*a1+4*a2; s4=8*(a1*a3+2*a4); s6=16*(a3*a3+4*a6)
1170
f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s6
1171
x_list = f.roots() # over ZZ -- use FLINT directly?
1172
x0 = x_list[0][0]
1173
c = 3*x0+s2; d = (c+s2)*x0+s4
1174
return two_descent_by_two_isogeny_work(c, d,
1175
global_limit_small, global_limit_large, verbosity, selmer_only, proof)
1176
1177
def two_descent_by_two_isogeny_work(Integer c, Integer d,
1178
int global_limit_small = 10, int global_limit_large = 10000,
1179
int verbosity = 0, bint selmer_only = 0, bint proof = 1):
1180
"""
1181
Do all the work in doing a two-isogeny descent.
1182
1183
EXAMPLES::
1184
1185
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny_work
1186
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(13,128)
1187
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1188
0
1189
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(1,-16)
1190
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1191
1
1192
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(10,8)
1193
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1194
2
1195
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(85,320)
1196
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
1197
3
1198
1199
"""
1200
cdef mpz_t c_mpz, d_mpz, c_prime_mpz, d_prime_mpz
1201
cdef mpz_t *p_list_mpz
1202
cdef unsigned long i, j, p, p_list_len
1203
cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime
1204
cdef object PO
1205
cdef bint found, too_big, d_neg, d_prime_neg
1206
cdef n_factor_t fact
1207
cdef list primes
1208
mpz_init_set(c_mpz, c.value) #
1209
mpz_init_set(d_mpz, d.value) #
1210
mpz_init(c_prime_mpz) #
1211
mpz_init(d_prime_mpz) #
1212
mpz_mul_si(c_prime_mpz, c_mpz, -2)
1213
mpz_mul(d_prime_mpz, c_mpz, c_mpz)
1214
mpz_submul_ui(d_prime_mpz, d_mpz, ui4)
1215
1216
d_neg = 0
1217
d_prime_neg = 0
1218
if mpz_sgn(d_mpz) < 0:
1219
d_neg = 1
1220
mpz_neg(d_mpz, d_mpz)
1221
if mpz_sgn(d_prime_mpz) < 0:
1222
d_prime_neg = 1
1223
mpz_neg(d_prime_mpz, d_prime_mpz)
1224
if mpz_fits_ulong_p(d_mpz) and mpz_fits_ulong_p(d_prime_mpz):
1225
# Factor very quickly using FLINT.
1226
p_list_mpz = <mpz_t *> sage_malloc(20 * sizeof(mpz_t))
1227
mpz_init_set_ui(p_list_mpz[0], ui2)
1228
p_list_len = 1
1229
n_factor_init(&fact)
1230
n_factor(&fact, mpz_get_ui(d_mpz), proof)
1231
for i from 0 <= i < fact.num:
1232
p = fact.p[i]
1233
if p != ui2:
1234
mpz_init_set_ui(p_list_mpz[p_list_len], p)
1235
p_list_len += 1
1236
n_factor(&fact, mpz_get_ui(d_prime_mpz), proof)
1237
for i from 0 <= i < fact.num:
1238
p = fact.p[i]
1239
found = 0
1240
for j from 0 <= j < p_list_len:
1241
if mpz_cmp_ui(p_list_mpz[j], p)==0:
1242
found = 1
1243
break
1244
if not found:
1245
mpz_init_set_ui(p_list_mpz[p_list_len], p)
1246
p_list_len += 1
1247
else:
1248
# Factor more slowly using Pari via Python.
1249
from sage.libs.pari.all import pari
1250
d = Integer(0)
1251
mpz_set(d.value, d_mpz)
1252
primes = list(pari(d).factor()[0])
1253
d_prime = Integer(0)
1254
mpz_set(d_prime.value, d_prime_mpz)
1255
for PO in pari(d_prime).factor()[0]:
1256
if PO not in primes:
1257
primes.append(PO)
1258
P = Integer(2)
1259
if P not in primes: primes.append(P)
1260
p_list_len = len(primes)
1261
p_list_mpz = <mpz_t *> sage_malloc(p_list_len * sizeof(mpz_t))
1262
for i from 0 <= i < p_list_len:
1263
P = Integer(primes[i])
1264
mpz_init_set(p_list_mpz[i], P.value)
1265
if d_neg:
1266
mpz_neg(d_mpz, d_mpz)
1267
if d_prime_neg:
1268
mpz_neg(d_prime_mpz, d_prime_mpz)
1269
1270
if verbosity > 1:
1271
c_prime = -2*c
1272
d_prime = c*c-4*d
1273
print '\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )'%(int(c),int(d))
1274
print 'new isogenous curve is' + \
1275
' y^2 == x( x^2 + (%d)x + (%d) )'%(int(c_prime),int(d_prime))
1276
1277
n1 = Integer(0); n2 = Integer(0)
1278
n1_prime = Integer(0); n2_prime = Integer(0)
1279
count(c.value, d.value, p_list_mpz, p_list_len,
1280
global_limit_small, global_limit_large, verbosity, selmer_only,
1281
n1.value, n2.value)
1282
count(c_prime_mpz, d_prime_mpz, p_list_mpz, p_list_len,
1283
global_limit_small, global_limit_large, verbosity, selmer_only,
1284
n1_prime.value, n2_prime.value)
1285
1286
for i from 0 <= i < p_list_len:
1287
mpz_clear(p_list_mpz[i])
1288
sage_free(p_list_mpz)
1289
1290
if verbosity > 0:
1291
print "\nResults:"
1292
print n1, "<= #E(Q)/phi'(E'(Q)) <=", n2
1293
print n1_prime, "<= #E'(Q)/phi(E(Q)) <=", n2_prime
1294
print "#Sel^(phi')(E'/Q) =", n2
1295
print "#Sel^(phi)(E/Q) =", n2_prime
1296
print "1 <= #Sha(E'/Q)[phi'] <=", n2/n1
1297
print "1 <= #Sha(E/Q)[phi] <=", n2_prime/n1_prime
1298
print "1 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <=", (n2_prime/n1_prime)*(n2/n1)
1299
a = Integer(n1*n1_prime).log(Integer(2))
1300
e = Integer(n2*n2_prime).log(Integer(2))
1301
print a - 2, "<= rank of E(Q) = rank of E'(Q) <=", e - 2
1302
1303
return n1, n2, n1_prime, n2_prime
1304
1305
1306
1307