Path: blob/master/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx
8820 views
"""1Descent on elliptic curves over QQ with a 2-isogeny.2"""34#*****************************************************************************5# Copyright (C) 2009 Robert L. Miller <[email protected]>6#7# Distributed under the terms of the GNU General Public License (GPL)8# http://www.gnu.org/licenses/9#*****************************************************************************1011from sage.rings.all import ZZ12from sage.rings.polynomial.polynomial_ring import polygen13cdef object x_ZZ = polygen(ZZ)14from sage.rings.polynomial.real_roots import real_roots15from sage.rings.arith import prime_divisors16from sage.misc.all import walltime, cputime17from sage.all import ntl1819from sage.rings.integer cimport Integer2021include "sage/ext/cdefs.pxi"22include "sage/ext/interrupt.pxi"23include "sage/libs/flint/fmpz_poly.pxi"2425from sage.libs.flint.nmod_poly cimport *, nmod_poly_t26from sage.libs.flint.ulong_extras cimport *, n_factor_t27from sage.libs.ratpoints cimport ratpoints_mpz_exists_only2829cdef int N_RES_CLASSES_BSD = 103031cdef unsigned long ui0 = <unsigned long>032cdef unsigned long ui1 = <unsigned long>133cdef unsigned long ui2 = <unsigned long>234cdef unsigned long ui3 = <unsigned long>335cdef unsigned long ui4 = <unsigned long>436cdef unsigned long ui8 = <unsigned long>83738cdef unsigned long valuation(mpz_t a, mpz_t p):39"""40Return the number of times p divides a.41"""42cdef mpz_t aa43cdef unsigned long v44mpz_init(aa)45v = mpz_remove(aa,a,p)46mpz_clear(aa)47return v4849def test_valuation(a, p):50"""51Doctest function for cdef long valuation(mpz_t, mpz_t).5253EXAMPLE::5455sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_valuation as tv56sage: for i in [1..20]:57... print '%10s'%factor(i), tv(i,2), tv(i,3), tv(i,5)581 0 0 0592 1 0 0603 0 1 0612^2 2 0 0625 0 0 1632 * 3 1 1 0647 0 0 0652^3 3 0 0663^2 0 2 0672 * 5 1 0 16811 0 0 0692^2 * 3 2 1 07013 0 0 0712 * 7 1 0 0723 * 5 0 1 1732^4 4 0 07417 0 0 0752 * 3^2 1 2 07619 0 0 0772^2 * 5 2 0 17879"""80cdef Integer A = Integer(a)81cdef Integer P = Integer(p)82return valuation(A.value, P.value)8384cdef int padic_square(mpz_t a, mpz_t p):85"""86Test if a is a p-adic square.87"""88cdef unsigned long v89cdef mpz_t aa90cdef int result9192if mpz_sgn(a) == 0: return 19394v = valuation(a,p)95if v&(ui1): return 09697mpz_init_set(aa,a)98while v:99v -= 1100mpz_divexact(aa, aa, p)101if mpz_cmp_ui(p, ui2)==0:102result = ( mpz_fdiv_ui(aa,ui8)==ui1 )103else:104result = ( mpz_legendre(aa,p)==1 )105mpz_clear(aa)106return result107108def test_padic_square(a, p):109"""110Doctest function for cdef int padic_square(mpz_t, unsigned long).111112EXAMPLE::113114sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps115sage: for i in [1..300]:116... for p in prime_range(100):117... if not Qp(p)(i).is_square()==bool(ps(i,p)):118... print i, p119120"""121cdef Integer A = Integer(a)122cdef Integer P = Integer(p)123return padic_square(A.value, P.value)124125cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,126mpz_t x, mpz_t p, unsigned long nu):127"""128Implements Lemma 6 of BSD's "Notes on elliptic curves, I" for odd p.129130Returns -1 for insoluble, 0 for undecided, +1 for soluble.131"""132cdef mpz_t g_of_x, g_prime_of_x133cdef unsigned long lambd, mu134cdef int result = -1135136mpz_init(g_of_x)137mpz_mul(g_of_x, a, x)138mpz_add(g_of_x, g_of_x, b)139mpz_mul(g_of_x, g_of_x, x)140mpz_add(g_of_x, g_of_x, c)141mpz_mul(g_of_x, g_of_x, x)142mpz_add(g_of_x, g_of_x, d)143mpz_mul(g_of_x, g_of_x, x)144mpz_add(g_of_x, g_of_x, e)145146if padic_square(g_of_x, p):147mpz_clear(g_of_x)148return +1 # soluble149150mpz_init_set(g_prime_of_x, x)151mpz_mul(g_prime_of_x, a, x)152mpz_mul_ui(g_prime_of_x, g_prime_of_x, ui4)153mpz_addmul_ui(g_prime_of_x, b, ui3)154mpz_mul(g_prime_of_x, g_prime_of_x, x)155mpz_addmul_ui(g_prime_of_x, c, ui2)156mpz_mul(g_prime_of_x, g_prime_of_x, x)157mpz_add(g_prime_of_x, g_prime_of_x, d)158159lambd = valuation(g_of_x, p)160if mpz_sgn(g_prime_of_x)==0:161if lambd >= 2*nu: result = 0 # undecided162else:163mu = valuation(g_prime_of_x, p)164if lambd > 2*mu: result = +1 # soluble165elif lambd >= 2*nu and mu >= nu: result = 0 # undecided166167mpz_clear(g_prime_of_x)168mpz_clear(g_of_x)169return result170171cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,172mpz_t x, mpz_t p, unsigned long nu):173"""174Implements Lemma 7 of BSD's "Notes on elliptic curves, I" for p=2.175176Returns -1 for insoluble, 0 for undecided, +1 for soluble.177"""178cdef mpz_t g_of_x, g_prime_of_x, g_of_x_odd_part179cdef unsigned long lambd, mu, g_of_x_odd_part_mod_4180cdef int result = -1181182mpz_init(g_of_x)183mpz_mul(g_of_x, a, x)184mpz_add(g_of_x, g_of_x, b)185mpz_mul(g_of_x, g_of_x, x)186mpz_add(g_of_x, g_of_x, c)187mpz_mul(g_of_x, g_of_x, x)188mpz_add(g_of_x, g_of_x, d)189mpz_mul(g_of_x, g_of_x, x)190mpz_add(g_of_x, g_of_x, e)191192if padic_square(g_of_x, p):193mpz_clear(g_of_x)194return +1 # soluble195196mpz_init_set(g_prime_of_x, x)197mpz_mul(g_prime_of_x, a, x)198mpz_mul_ui(g_prime_of_x, g_prime_of_x, ui4)199mpz_addmul_ui(g_prime_of_x, b, ui3)200mpz_mul(g_prime_of_x, g_prime_of_x, x)201mpz_addmul_ui(g_prime_of_x, c, ui2)202mpz_mul(g_prime_of_x, g_prime_of_x, x)203mpz_add(g_prime_of_x, g_prime_of_x, d)204205lambd = valuation(g_of_x, p)206mpz_init_set(g_of_x_odd_part, g_of_x)207while mpz_even_p(g_of_x_odd_part):208mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, ui2)209g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, ui4)210if mpz_sgn(g_prime_of_x)==0:211if lambd >= 2*nu: result = 0 # undecided212elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1:213result = 0 # undecided214else:215mu = valuation(g_prime_of_x, p)216if lambd > 2*mu: result = +1 # soluble217elif nu > mu:218if lambd >= mu+nu: result = +1 # soluble219elif lambd+1 == mu+nu and lambd&ui1==0:220result = +1 # soluble221elif lambd+2 == mu+nu and lambd&ui1==0 and g_of_x_odd_part_mod_4==1:222result = +1 # soluble223else: # nu <= mu224if lambd >= 2*nu: result = 0 # undecided225elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1:226result = 0 # undecided227228mpz_clear(g_prime_of_x)229mpz_clear(g_of_x)230return result231232cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,233mpz_t x_k, mpz_t p, unsigned long k):234"""235Uses the approach of BSD's "Notes on elliptic curves, I" to test for236solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp, with237x=x_k (mod p^k).238"""239# returns solubility of y^2 = ax^4 + bx^3 + cx^2 + dx + e240# in Zp with x=x_k (mod p^k)241cdef int code242cdef unsigned long t243cdef mpz_t s244245if mpz_cmp_ui(p, ui2)==0:246code = lemma7(a,b,c,d,e,x_k,p,k)247else:248code = lemma6(a,b,c,d,e,x_k,p,k)249if code == 1:250return 1251if code == -1:252return 0253254# now code == 0255t = 0256mpz_init(s)257while code == 0 and mpz_cmp_ui(p, t) > 0 and t < N_RES_CLASSES_BSD:258mpz_pow_ui(s, p, k)259mpz_mul_ui(s, s, t)260mpz_add(s, s, x_k)261code = Zp_soluble_BSD(a,b,c,d,e,s,p,k+1)262t += 1263mpz_clear(s)264return code265266cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,267mpz_t pp, unsigned long pp_ui,268nmod_poly_factor_t f_factzn, nmod_poly_t f,269fmpz_poly_t f1, fmpz_poly_t linear):270"""271Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for272solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.273"""274cdef unsigned long v_min, v275cdef unsigned long roots[4]276cdef int i, j, has_roots, has_single_roots277cdef bint result278279cdef mpz_t aa, bb, cc, dd, ee280cdef mpz_t aaa, bbb, ccc, ddd, eee281cdef unsigned long qq282cdef unsigned long rr, ss283cdef mpz_t tt284285# Step 0: divide out all common p from the quartic286v_min = valuation(a, pp)287if mpz_cmp_ui(b, ui0) != 0:288v = valuation(b, pp)289if v < v_min: v_min = v290if mpz_cmp_ui(c, ui0) != 0:291v = valuation(c, pp)292if v < v_min: v_min = v293if mpz_cmp_ui(d, ui0) != 0:294v = valuation(d, pp)295if v < v_min: v_min = v296if mpz_cmp_ui(e, ui0) != 0:297v = valuation(e, pp)298if v < v_min: v_min = v299for 0 <= v < v_min:300mpz_divexact(a, a, pp)301mpz_divexact(b, b, pp)302mpz_divexact(c, c, pp)303mpz_divexact(d, d, pp)304mpz_divexact(e, e, pp)305306if not v_min%2:307# Step I in Alg. 5.3.1 of Siksek's thesis308nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))309nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))310nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))311nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))312nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))313314result = 0315(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct316qq = nmod_poly_factor(f_factzn, f)317for i from 0 <= i < f_factzn.num:318if f_factzn.exp[i]&1:319result = 1320break321if result == 0 and n_jacobi(qq, pp_ui) == 1:322result = 1323if result:324return 1325326nmod_poly_zero(f)327nmod_poly_set_coeff_ui(f, 0, ui1)328for i from 0 <= i < f_factzn.num:329for j from 0 <= j < (f_factzn.exp[i]>>1):330nmod_poly_mul(f, f, &f_factzn.p[i])331332(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct333nmod_poly_factor(f_factzn, f)334has_roots = 0335j = 0336for i from 0 <= i < f_factzn.num:337if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):338has_roots = 1339roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)340j += 1341if not has_roots:342return 0343344i = nmod_poly_degree(f)345mpz_init(aaa)346mpz_init(bbb)347mpz_init(ccc)348mpz_init(ddd)349mpz_init(eee)350351if i == 0: # g == 1352mpz_set(aaa, a)353mpz_set(bbb, b)354mpz_set(ccc, c)355mpz_set(ddd, d)356mpz_sub_ui(eee, e, qq)357elif i == 1: # g == x + rr358mpz_set(aaa, a)359mpz_set(bbb, b)360mpz_sub_ui(ccc, c, qq)361rr = nmod_poly_get_coeff_ui(f, 0)362ss = rr*qq363mpz_set(ddd,d)364mpz_sub_ui(ddd, ddd, ss*ui2)365mpz_set(eee,e)366mpz_sub_ui(eee, eee, ss*rr)367elif i == 2: # g == x^2 + rr*x + ss368mpz_sub_ui(aaa, a, qq)369rr = nmod_poly_get_coeff_ui(f, 1)370mpz_init(tt)371mpz_set_ui(tt, rr*qq)372mpz_set(bbb,b)373mpz_submul_ui(bbb, tt, ui2)374mpz_set(ccc,c)375mpz_submul_ui(ccc, tt, rr)376ss = nmod_poly_get_coeff_ui(f, 0)377mpz_set_ui(tt, ss*qq)378mpz_set(eee,e)379mpz_submul_ui(eee, tt, ss)380mpz_mul_ui(tt, tt, ui2)381mpz_sub(ccc, ccc, tt)382mpz_set(ddd,d)383mpz_submul_ui(ddd, tt, rr)384mpz_clear(tt)385mpz_divexact(aaa, aaa, pp)386mpz_divexact(bbb, bbb, pp)387mpz_divexact(ccc, ccc, pp)388mpz_divexact(ddd, ddd, pp)389mpz_divexact(eee, eee, pp)390# now aaa,bbb,ccc,ddd,eee represents h(x)391392result = 0393mpz_init(tt)394for i from 0 <= i < j:395mpz_mul_ui(tt, aaa, roots[i])396mpz_add(tt, tt, bbb)397mpz_mul_ui(tt, tt, roots[i])398mpz_add(tt, tt, ccc)399mpz_mul_ui(tt, tt, roots[i])400mpz_add(tt, tt, ddd)401mpz_mul_ui(tt, tt, roots[i])402mpz_add(tt, tt, eee)403# tt == h(r) mod p404mpz_mod(tt, tt, pp)405if mpz_sgn(tt) == 0:406fmpz_poly_zero(f1)407fmpz_poly_zero(linear)408fmpz_poly_set_coeff_mpz(f1, 0, e)409fmpz_poly_set_coeff_mpz(f1, 1, d)410fmpz_poly_set_coeff_mpz(f1, 2, c)411fmpz_poly_set_coeff_mpz(f1, 3, b)412fmpz_poly_set_coeff_mpz(f1, 4, a)413fmpz_poly_set_coeff_ui(linear, 0, roots[i])414fmpz_poly_set_coeff_mpz(linear, 1, pp)415fmpz_poly_compose(f1, f1, linear)416fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)417fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)418mpz_init(aa)419mpz_init(bb)420mpz_init(cc)421mpz_init(dd)422mpz_init(ee)423fmpz_poly_get_coeff_mpz(aa, f1, 4)424fmpz_poly_get_coeff_mpz(bb, f1, 3)425fmpz_poly_get_coeff_mpz(cc, f1, 2)426fmpz_poly_get_coeff_mpz(dd, f1, 1)427fmpz_poly_get_coeff_mpz(ee, f1, 0)428result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)429mpz_clear(aa)430mpz_clear(bb)431mpz_clear(cc)432mpz_clear(dd)433mpz_clear(ee)434if result == 1:435break436mpz_clear(aaa)437mpz_clear(bbb)438mpz_clear(ccc)439mpz_clear(ddd)440mpz_clear(eee)441mpz_clear(tt)442return result443else:444# Step II in Alg. 5.3.1 of Siksek's thesis445nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))446nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))447nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))448nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))449nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))450(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct451nmod_poly_factor(f_factzn, f)452has_roots = 0453has_single_roots = 0454j = 0455for i from 0 <= i < f_factzn.num:456if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):457has_roots = 1458if f_factzn.exp[i] == 1:459has_single_roots = 1460break461roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)462j += 1463464if not has_roots: return 0465if has_single_roots: return 1466467result = 0468if j > 0:469mpz_init(aa)470mpz_init(bb)471mpz_init(cc)472mpz_init(dd)473mpz_init(ee)474for i from 0 <= i < j:475fmpz_poly_zero(f1)476fmpz_poly_zero(linear)477fmpz_poly_set_coeff_mpz(f1, 0, e)478fmpz_poly_set_coeff_mpz(f1, 1, d)479fmpz_poly_set_coeff_mpz(f1, 2, c)480fmpz_poly_set_coeff_mpz(f1, 3, b)481fmpz_poly_set_coeff_mpz(f1, 4, a)482fmpz_poly_set_coeff_ui(linear, 0, roots[i])483fmpz_poly_set_coeff_mpz(linear, 1, pp)484fmpz_poly_compose(f1, f1, linear)485fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)486fmpz_poly_get_coeff_mpz(aa, f1, 4)487fmpz_poly_get_coeff_mpz(bb, f1, 3)488fmpz_poly_get_coeff_mpz(cc, f1, 2)489fmpz_poly_get_coeff_mpz(dd, f1, 1)490fmpz_poly_get_coeff_mpz(ee, f1, 0)491result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)492if result == 1:493break494if j > 0:495mpz_clear(aa)496mpz_clear(bb)497mpz_clear(cc)498mpz_clear(dd)499mpz_clear(ee)500return result501502cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp,503fmpz_poly_t f1, fmpz_poly_t linear):504"""505Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for506solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.507"""508cdef unsigned long v_min, v509cdef mpz_t roots[4]510cdef int i, j, has_roots, has_single_roots511cdef bint result512513cdef mpz_t aa, bb, cc, dd, ee514cdef mpz_t aaa, bbb, ccc, ddd, eee515cdef mpz_t qq, rr, ss, tt516cdef Integer A,B,C,D,E,P517518# Step 0: divide out all common p from the quartic519v_min = valuation(a, pp)520if mpz_cmp_ui(b, ui0) != 0:521v = valuation(b, pp)522if v < v_min: v_min = v523if mpz_cmp_ui(c, ui0) != 0:524v = valuation(c, pp)525if v < v_min: v_min = v526if mpz_cmp_ui(d, ui0) != 0:527v = valuation(d, pp)528if v < v_min: v_min = v529if mpz_cmp_ui(e, ui0) != 0:530v = valuation(e, pp)531if v < v_min: v_min = v532for 0 <= v < v_min:533mpz_divexact(a, a, pp)534mpz_divexact(b, b, pp)535mpz_divexact(c, c, pp)536mpz_divexact(d, d, pp)537mpz_divexact(e, e, pp)538539if not v_min%2:540# Step I in Alg. 5.3.1 of Siksek's thesis541A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0)542mpz_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)543f = ntl.ZZ_pX([E,D,C,B,A], P)544f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E545mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial546f_factzn = f.factor()547result = 0548for factor, exponent in f_factzn:549if exponent&1:550result = 1551break552if result == 0 and mpz_legendre(qq, pp) == 1:553result = 1554if result:555return 1556557f = ntl.ZZ_pX([1], P)558for factor, exponent in f_factzn:559for j from 0 <= j < (exponent/2):560f *= factor561562f /= f.leading_coefficient()563f_factzn = f.factor()564565has_roots = 0566j = 0567for factor, exponent in f_factzn:568if factor.degree() == 1:569has_roots = 1570A = P - Integer(factor[0])571mpz_set(roots[j], A.value)572j += 1573if not has_roots:574return 0575576i = f.degree()577mpz_init(aaa)578mpz_init(bbb)579mpz_init(ccc)580mpz_init(ddd)581mpz_init(eee)582583if i == 0: # g == 1584mpz_set(aaa, a)585mpz_set(bbb, b)586mpz_set(ccc, c)587mpz_set(ddd, d)588mpz_sub(eee, e, qq)589elif i == 1: # g == x + rr590mpz_set(aaa, a)591mpz_set(bbb, b)592mpz_sub(ccc, c, qq)593A = Integer(f[0])594mpz_set(rr, A.value)595mpz_mul(ss, rr, qq)596mpz_set(ddd,d)597mpz_sub(ddd, ddd, ss)598mpz_sub(ddd, ddd, ss)599mpz_set(eee,e)600mpz_mul(ss, ss, rr)601mpz_sub(eee, eee, ss)602mpz_divexact(ss, ss, rr)603elif i == 2: # g == x^2 + rr*x + ss604mpz_sub(aaa, a, qq)605A = Integer(f[1])606mpz_set(rr, A.value)607mpz_init(tt)608mpz_mul(tt, rr, qq)609mpz_set(bbb,b)610mpz_submul_ui(bbb, tt, ui2)611mpz_set(ccc,c)612mpz_submul(ccc, tt, rr)613A = Integer(f[0])614mpz_set(ss, A.value)615mpz_mul(tt, ss, qq)616mpz_set(eee,e)617mpz_submul(eee, tt, ss)618mpz_mul_ui(tt, tt, ui2)619mpz_sub(ccc, ccc, tt)620mpz_set(ddd,d)621mpz_submul(ddd, tt, rr)622mpz_clear(tt)623mpz_divexact(aaa, aaa, pp)624mpz_divexact(bbb, bbb, pp)625mpz_divexact(ccc, ccc, pp)626mpz_divexact(ddd, ddd, pp)627mpz_divexact(eee, eee, pp)628# now aaa,bbb,ccc,ddd,eee represents h(x)629630result = 0631mpz_init(tt)632for i from 0 <= i < j:633mpz_mul(tt, aaa, roots[i])634mpz_add(tt, tt, bbb)635mpz_mul(tt, tt, roots[i])636mpz_add(tt, tt, ccc)637mpz_mul(tt, tt, roots[i])638mpz_add(tt, tt, ddd)639mpz_mul(tt, tt, roots[i])640mpz_add(tt, tt, eee)641# tt == h(r) mod p642mpz_mod(tt, tt, pp)643if mpz_sgn(tt) == 0:644fmpz_poly_zero(f1)645fmpz_poly_zero(linear)646fmpz_poly_set_coeff_mpz(f1, 0, e)647fmpz_poly_set_coeff_mpz(f1, 1, d)648fmpz_poly_set_coeff_mpz(f1, 2, c)649fmpz_poly_set_coeff_mpz(f1, 3, b)650fmpz_poly_set_coeff_mpz(f1, 4, a)651fmpz_poly_set_coeff_mpz(linear, 0, roots[i])652fmpz_poly_set_coeff_mpz(linear, 1, pp)653fmpz_poly_compose(f1, f1, linear)654fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)655fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)656657mpz_init(aa)658mpz_init(bb)659mpz_init(cc)660mpz_init(dd)661mpz_init(ee)662fmpz_poly_get_coeff_mpz(aa, f1, 4)663fmpz_poly_get_coeff_mpz(bb, f1, 3)664fmpz_poly_get_coeff_mpz(cc, f1, 2)665fmpz_poly_get_coeff_mpz(dd, f1, 1)666fmpz_poly_get_coeff_mpz(ee, f1, 0)667result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)668mpz_clear(aa)669mpz_clear(bb)670mpz_clear(cc)671mpz_clear(dd)672mpz_clear(ee)673if result == 1:674break675mpz_clear(aaa)676mpz_clear(bbb)677mpz_clear(ccc)678mpz_clear(ddd)679mpz_clear(eee)680mpz_clear(tt)681return result682else:683# Step II in Alg. 5.3.1 of Siksek's thesis684A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0)685mpz_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)686f = ntl.ZZ_pX([E,D,C,B,A], P)687f /= ntl.ZZ_pX([A], P) # now f is monic688f_factzn = f.factor()689690has_roots = 0691has_single_roots = 0692j = 0693for factor, exponent in f_factzn:694if factor.degree() == 1:695has_roots = 1696if exponent == 1:697has_single_roots = 1698break699A = P - Integer(factor[0])700mpz_set(roots[j], A.value)701j += 1702703if not has_roots: return 0704if has_single_roots: return 1705706result = 0707if j > 0:708mpz_init(aa)709mpz_init(bb)710mpz_init(cc)711mpz_init(dd)712mpz_init(ee)713for i from 0 <= i < j:714fmpz_poly_zero(f1)715fmpz_poly_zero(linear)716fmpz_poly_set_coeff_mpz(f1, 0, e)717fmpz_poly_set_coeff_mpz(f1, 1, d)718fmpz_poly_set_coeff_mpz(f1, 2, c)719fmpz_poly_set_coeff_mpz(f1, 3, b)720fmpz_poly_set_coeff_mpz(f1, 4, a)721fmpz_poly_set_coeff_mpz(linear, 0, roots[i])722fmpz_poly_set_coeff_mpz(linear, 1, pp)723fmpz_poly_compose(f1, f1, linear)724fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)725fmpz_poly_get_coeff_mpz(aa, f1, 4)726fmpz_poly_get_coeff_mpz(bb, f1, 3)727fmpz_poly_get_coeff_mpz(cc, f1, 2)728fmpz_poly_get_coeff_mpz(dd, f1, 1)729fmpz_poly_get_coeff_mpz(ee, f1, 0)730result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)731if result == 1:732break733if j > 0:734mpz_clear(aa)735mpz_clear(bb)736mpz_clear(cc)737mpz_clear(dd)738mpz_clear(ee)739return result740741cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,742mpz_t p, unsigned long P,743nmod_poly_factor_t f_factzn, fmpz_poly_t f1,744fmpz_poly_t linear):745"""746Uses Samir Siksek's thesis results to determine whether the quartic is747locally soluble at p.748"""749cdef int result = 0750cdef mpz_t a,b,c,d,e751cdef nmod_poly_t f752nmod_poly_init(f, P)753754mpz_init_set(a,A)755mpz_init_set(b,B)756mpz_init_set(c,C)757mpz_init_set(d,D)758mpz_init_set(e,E)759760if Zp_soluble_siksek(a,b,c,d,e,p,P,f_factzn, f, f1, linear):761result = 1762else:763mpz_set(a,A)764mpz_set(b,B)765mpz_set(c,C)766mpz_set(d,D)767mpz_set(e,E)768if Zp_soluble_siksek(e,d,c,b,a,p,P,f_factzn, f, f1, linear):769result = 1770771mpz_clear(a)772mpz_clear(b)773mpz_clear(c)774mpz_clear(d)775mpz_clear(e)776nmod_poly_clear(f)777return result778779cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,780mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear):781"""782Uses Samir Siksek's thesis results to determine whether the quartic is783locally soluble at p, when p is bigger than wordsize, and we can't use784FLINT.785"""786cdef int result = 0787cdef mpz_t a,b,c,d,e788789mpz_init_set(a,A)790mpz_init_set(b,B)791mpz_init_set(c,C)792mpz_init_set(d,D)793mpz_init_set(e,E)794795if Zp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear):796result = 1797else:798mpz_set(a,A)799mpz_set(b,B)800mpz_set(c,C)801mpz_set(d,D)802mpz_set(e,E)803if Zp_soluble_siksek_large_p(e,d,c,b,a,p,f1,linear):804result = 1805806mpz_clear(a)807mpz_clear(b)808mpz_clear(c)809mpz_clear(d)810mpz_clear(e)811return result812813cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p):814"""815Uses the original test of Birch and Swinnerton-Dyer to test for local816solubility of the quartic at p.817"""818cdef mpz_t zero819cdef int result = 0820mpz_init_set_ui(zero, ui0)821if Zp_soluble_BSD(a,b,c,d,e,zero,p,0):822result = 1823elif Zp_soluble_BSD(e,d,c,b,a,zero,p,1):824result = 1825mpz_clear(zero)826return result827828cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p):829"""830Try the BSD approach for a few residue classes and if no solution is found,831switch to Siksek to try to prove insolubility.832"""833cdef int bsd_sol, sik_sol834cdef unsigned long pp835cdef fmpz_poly_t f1, linear836cdef nmod_poly_factor_t f_factzn837bsd_sol = Qp_soluble_BSD(a, b, c, d, e, p)838if mpz_cmp_ui(p,N_RES_CLASSES_BSD)>0 and not bsd_sol:839fmpz_poly_init(f1)840fmpz_poly_init(linear)841if mpz_fits_ulong_p(p):842nmod_poly_factor_init(f_factzn)843pp = mpz_get_ui(p)844sik_sol = Qp_soluble_siksek(a,b,c,d,e,p,pp,f_factzn,f1,linear)845nmod_poly_factor_clear(f_factzn)846else:847sik_sol = Qp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear)848fmpz_poly_clear(f1)849fmpz_poly_clear(linear)850else:851sik_sol = bsd_sol852return sik_sol853854def test_qpls(a,b,c,d,e,p):855"""856Testing function for Qp_soluble.857858EXAMPLE:859sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_qpls as tq860sage: tq(1,2,3,4,5,7)8611862863"""864cdef Integer A,B,C,D,E,P865cdef int i, result866cdef mpz_t aa,bb,cc,dd,ee,pp867A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e); P=Integer(p)868mpz_init_set(aa, A.value)869mpz_init_set(bb, B.value)870mpz_init_set(cc, C.value)871mpz_init_set(dd, D.value)872mpz_init_set(ee, E.value)873mpz_init_set(pp, P.value)874result = Qp_soluble(aa, bb, cc, dd, ee, pp)875mpz_clear(aa)876mpz_clear(bb)877mpz_clear(cc)878mpz_clear(dd)879mpz_clear(ee)880mpz_clear(pp)881return result882883cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1:884"""885Returns whether the quartic has local solutions at all primes p.886"""887cdef Integer A,B,C,D,E,Delta,p888cdef mpz_t mpz_2889A=Integer(0); B=Integer(0); C=Integer(0); D=Integer(0); E=Integer(0)890mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e);891f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E892893# RR soluble:894if mpz_sgn(a)!=1:895if len(real_roots(f)) == 0:896return 0897898# Q2 soluble:899mpz_init_set_ui(mpz_2, ui2)900if not Qp_soluble(a,b,c,d,e,mpz_2):901mpz_clear(mpz_2)902return 0903mpz_clear(mpz_2)904905# Odd finite primes906Delta = f.discriminant()907for p in prime_divisors(Delta):908if p == 2: continue909if not Qp_soluble(a,b,c,d,e,p.value): return 0910911return 1912913def test_els(a,b,c,d,e):914"""915Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t).916917EXAMPLE::918919sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_els920sage: from sage.libs.ratpoints import ratpoints921sage: for _ in range(1000):922... a,b,c,d,e = randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000)923... if len(ratpoints([e,d,c,b,a], 1000)) > 0:924... try:925... if not test_els(a,b,c,d,e):926... print "This never happened", a,b,c,d,e927... except ValueError:928... continue929930"""931cdef Integer A,B,C,D,E,Delta932A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e)933return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value)934935cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len,936int global_limit_small, int global_limit_large,937int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1:938"""939Count the number of els/gls quartic 2-covers of E.940"""941cdef unsigned long n_primes, i942cdef bint found_global_points, els, check_negs, verbose = (verbosity > 4)943cdef Integer a_Int, c_Int, e_Int944cdef mpz_t c_sq_mpz, d_prime_mpz945cdef mpz_t n_divisors, j946cdef mpz_t *coeffs_ratp947948949mpz_init(c_sq_mpz)950mpz_mul(c_sq_mpz, c_mpz, c_mpz)951mpz_init_set(d_prime_mpz, c_sq_mpz)952mpz_submul_ui(d_prime_mpz, d_mpz, ui4)953check_negs = 0954if mpz_sgn(d_prime_mpz) > 0:955if mpz_sgn(c_mpz) >= 0 or mpz_cmp(c_sq_mpz, d_prime_mpz) <= 0:956check_negs = 1957mpz_clear(c_sq_mpz)958mpz_clear(d_prime_mpz)959960961# Set up coefficient array, and static variables962cdef mpz_t *coeffs = <mpz_t *> sage_malloc(5 * sizeof(mpz_t))963for i from 0 <= i <= 4:964mpz_init(coeffs[i])965mpz_set_ui(coeffs[1], ui0) #966mpz_set(coeffs[2], c_mpz) # These never change967mpz_set_ui(coeffs[3], ui0) #968969if not selmer_only:970# allocate space for ratpoints971coeffs_ratp = <mpz_t *> sage_malloc(5 * sizeof(mpz_t))972for i from 0 <= i <= 4:973mpz_init(coeffs_ratp[i])974975# Get prime divisors, and put them in an mpz_t array976# (this block, by setting check_negs, takes care of977# local solubility over RR)978cdef mpz_t *p_div_d_mpz = <mpz_t *> sage_malloc((p_list_len+1) * sizeof(mpz_t))979n_primes = 0980for i from 0 <= i < p_list_len:981if mpz_divisible_p(d_mpz, p_list[i]):982mpz_init(p_div_d_mpz[n_primes])983mpz_set(p_div_d_mpz[n_primes], p_list[i])984n_primes += 1985if check_negs:986mpz_init(p_div_d_mpz[n_primes])987mpz_set_si(p_div_d_mpz[n_primes], -1)988n_primes += 1989mpz_init_set_ui(n_divisors, ui1)990mpz_mul_2exp(n_divisors, n_divisors, n_primes)991# if verbosity > 3:992# print '\nDivisors of d which may lead to RR-soluble quartics:', p_div_d993994mpz_init_set_ui(j, ui0)995if not selmer_only:996mpz_set_ui(n1, ui0)997mpz_set_ui(n2, ui0)998while mpz_cmp(j, n_divisors) < 0:999mpz_set_ui(coeffs[4], ui1)1000for i from 0 <= i < n_primes:1001if mpz_tstbit(j, i):1002mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i])1003if verbosity > 3:1004a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])1005print '\nSquarefree divisor:', a_Int1006mpz_divexact(coeffs[0], d_mpz, coeffs[4])1007found_global_points = 01008if not selmer_only:1009if verbose:1010print "\nCalling ratpoints for small point search"1011for i from 0 <= i <= 4:1012mpz_set(coeffs_ratp[i], coeffs[i])1013sig_on()1014found_global_points = ratpoints_mpz_exists_only(coeffs_ratp, global_limit_small, 4, verbose)1015sig_off()1016if found_global_points:1017if verbosity > 2:1018a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])1019c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2])1020e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0])1021print 'Found small global point, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)1022mpz_add_ui(n1, n1, ui1)1023mpz_add_ui(n2, n2, ui1)1024if verbose:1025print "\nDone calling ratpoints for small point search"1026if not found_global_points:1027# Test whether the quartic is everywhere locally soluble:1028els = 11029for i from 0 <= i < p_list_len:1030if not Qp_soluble(coeffs[4], coeffs[3], coeffs[2], coeffs[1], coeffs[0], p_list[i]):1031els = 01032break1033if els:1034if verbosity > 2:1035a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4])1036c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2])1037e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0])1038print 'ELS without small global points, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)1039mpz_add_ui(n2, n2, ui1)1040if not selmer_only:1041if verbose:1042print "\nCalling ratpoints for large point search"1043for i from 0 <= i <= 4:1044mpz_set(coeffs_ratp[i], coeffs[i])1045sig_on()1046found_global_points = ratpoints_mpz_exists_only(coeffs_ratp, global_limit_large, 4, verbose)1047sig_off()1048if found_global_points:1049if verbosity > 2:1050print ' -- Found large global point.'1051mpz_add_ui(n1, n1, ui1)1052if verbose:1053print "\nDone calling ratpoints for large point search"1054mpz_add_ui(j, j, ui1)1055if not selmer_only:1056for i from 0 <= i <= 4:1057mpz_clear(coeffs_ratp[i])1058sage_free(coeffs_ratp)1059mpz_clear(j)1060for i from 0 <= i < n_primes:1061mpz_clear(p_div_d_mpz[i])1062sage_free(p_div_d_mpz)1063mpz_clear(n_divisors)1064for i from 0 <= i <= 4:1065mpz_clear(coeffs[i])1066sage_free(coeffs)1067return 010681069def two_descent_by_two_isogeny(E,1070int global_limit_small = 10,1071int global_limit_large = 10000,1072int verbosity = 0,1073bint selmer_only = 0, bint proof = 1):1074"""1075Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny1076phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here1077n1 is the number of quartic covers found with a rational point, and n2 is1078the number which are ELS.10791080EXAMPLES::10811082sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny1083sage: E = EllipticCurve('14a')1084sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)1085sage: log(n1,2) + log(n1_prime,2) - 2 # the rank108601087sage: E = EllipticCurve('65a')1088sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)1089sage: log(n1,2) + log(n1_prime,2) - 2 # the rank109011091sage: x,y = var('x,y')1092sage: E = EllipticCurve(y^2 == x^3 + x^2 - 25*x + 39)1093sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)1094sage: log(n1,2) + log(n1_prime,2) - 2 # the rank109521096sage: E = EllipticCurve(y^2 + x*y + y == x^3 - 131*x + 558)1097sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)1098sage: log(n1,2) + log(n1_prime,2) - 2 # the rank1099311001101Using the verbosity option::11021103sage: E = EllipticCurve('14a')1104sage: two_descent_by_two_isogeny(E, verbosity=1)11052-isogeny1106Results:11072 <= #E(Q)/phi'(E'(Q)) <= 211082 <= #E'(Q)/phi(E(Q)) <= 21109#Sel^(phi')(E'/Q) = 21110#Sel^(phi)(E/Q) = 211111 <= #Sha(E'/Q)[phi'] <= 111121 <= #Sha(E/Q)[phi] <= 111131 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <= 111140 <= rank of E(Q) = rank of E'(Q) <= 01115(2, 2, 2, 2)11161117Handling curves whose discriminants involve larger than wordsize primes::11181119sage: E = EllipticCurve('14a')1120sage: E = E.quadratic_twist(next_prime(10^20))1121sage: E1122Elliptic Curve defined by y^2 = x^3 + x^2 + 716666666666666667225666666666666666775672*x - 391925925925925926384240370370370370549019837037037037060249356 over Rational Field1123sage: E.discriminant().factor()1124-1 * 2^18 * 7^3 * 100000000000000000039^61125sage: log(100000000000000000039.0, 2.0)112666.438...1127sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)1128sage: log(n1,2) + log(n1_prime,2) - 2 # the rank1129011301131TESTS:11321133Here we contrive an example to demonstrate that a keyboard interrupt1134is caught. Here we let `E` be the smallest optimal curve with two-torsion1135and nontrivial `Sha[2]`. This ensures that the two-descent will be looking1136for rational points which do not exist, and by setting global_limit_large1137to a very high bound, it will still be working when we simulate a ``CTRL-C``::11381139sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny1140sage: import sage.tests.interrupt1141sage: E = EllipticCurve('960d'); E1142Elliptic Curve defined by y^2 = x^3 - x^2 - 900*x - 10098 over Rational Field1143sage: E.sha().an()114441145sage: try:1146... sage.tests.interrupt.interrupt_after_delay(1000)1147... two_descent_by_two_isogeny(E, global_limit_large=10^8)1148... except KeyboardInterrupt:1149... print "Caught!"1150Caught!1151"""1152cdef Integer a1, a2, a3, a4, a6, s2, s4, s61153cdef Integer c, d, x01154cdef list x_list1155assert E.torsion_order()%2==0, 'Need rational two-torsion for isogeny descent.'1156if verbosity > 0:1157print '\n2-isogeny'1158if verbosity > 1:1159print '\nchanging coordinates'1160a1 = Integer(E.a1())1161a2 = Integer(E.a2())1162a3 = Integer(E.a3())1163a4 = Integer(E.a4())1164a6 = Integer(E.a6())1165if a1==0 and a3==0:1166s2=a2; s4=a4; s6=a61167else:1168s2=a1*a1+4*a2; s4=8*(a1*a3+2*a4); s6=16*(a3*a3+4*a6)1169f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s61170x_list = f.roots() # over ZZ -- use FLINT directly?1171x0 = x_list[0][0]1172c = 3*x0+s2; d = (c+s2)*x0+s41173return two_descent_by_two_isogeny_work(c, d,1174global_limit_small, global_limit_large, verbosity, selmer_only, proof)11751176def two_descent_by_two_isogeny_work(Integer c, Integer d,1177int global_limit_small = 10, int global_limit_large = 10000,1178int verbosity = 0, bint selmer_only = 0, bint proof = 1):1179"""1180Do all the work in doing a two-isogeny descent.11811182EXAMPLES::11831184sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny_work1185sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(13,128)1186sage: log(n1,2) + log(n1_prime,2) - 2 # the rank118701188sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(1,-16)1189sage: log(n1,2) + log(n1_prime,2) - 2 # the rank119011191sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(10,8)1192sage: log(n1,2) + log(n1_prime,2) - 2 # the rank119321194sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(85,320)1195sage: log(n1,2) + log(n1_prime,2) - 2 # the rank1196311971198"""1199cdef mpz_t c_mpz, d_mpz, c_prime_mpz, d_prime_mpz1200cdef mpz_t *p_list_mpz1201cdef unsigned long i, j, p, p_list_len1202cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime1203cdef object PO1204cdef bint found, too_big, d_neg, d_prime_neg1205cdef n_factor_t fact1206cdef list primes1207mpz_init_set(c_mpz, c.value) #1208mpz_init_set(d_mpz, d.value) #1209mpz_init(c_prime_mpz) #1210mpz_init(d_prime_mpz) #1211mpz_mul_si(c_prime_mpz, c_mpz, -2)1212mpz_mul(d_prime_mpz, c_mpz, c_mpz)1213mpz_submul_ui(d_prime_mpz, d_mpz, ui4)12141215d_neg = 01216d_prime_neg = 01217if mpz_sgn(d_mpz) < 0:1218d_neg = 11219mpz_neg(d_mpz, d_mpz)1220if mpz_sgn(d_prime_mpz) < 0:1221d_prime_neg = 11222mpz_neg(d_prime_mpz, d_prime_mpz)1223if mpz_fits_ulong_p(d_mpz) and mpz_fits_ulong_p(d_prime_mpz):1224# Factor very quickly using FLINT.1225p_list_mpz = <mpz_t *> sage_malloc(20 * sizeof(mpz_t))1226mpz_init_set_ui(p_list_mpz[0], ui2)1227p_list_len = 11228n_factor_init(&fact)1229n_factor(&fact, mpz_get_ui(d_mpz), proof)1230for i from 0 <= i < fact.num:1231p = fact.p[i]1232if p != ui2:1233mpz_init_set_ui(p_list_mpz[p_list_len], p)1234p_list_len += 11235n_factor(&fact, mpz_get_ui(d_prime_mpz), proof)1236for i from 0 <= i < fact.num:1237p = fact.p[i]1238found = 01239for j from 0 <= j < p_list_len:1240if mpz_cmp_ui(p_list_mpz[j], p)==0:1241found = 11242break1243if not found:1244mpz_init_set_ui(p_list_mpz[p_list_len], p)1245p_list_len += 11246else:1247# Factor more slowly using Pari via Python.1248from sage.libs.pari.all import pari1249d = Integer(0)1250mpz_set(d.value, d_mpz)1251primes = list(pari(d).factor()[0])1252d_prime = Integer(0)1253mpz_set(d_prime.value, d_prime_mpz)1254for PO in pari(d_prime).factor()[0]:1255if PO not in primes:1256primes.append(PO)1257P = Integer(2)1258if P not in primes: primes.append(P)1259p_list_len = len(primes)1260p_list_mpz = <mpz_t *> sage_malloc(p_list_len * sizeof(mpz_t))1261for i from 0 <= i < p_list_len:1262P = Integer(primes[i])1263mpz_init_set(p_list_mpz[i], P.value)1264if d_neg:1265mpz_neg(d_mpz, d_mpz)1266if d_prime_neg:1267mpz_neg(d_prime_mpz, d_prime_mpz)12681269if verbosity > 1:1270c_prime = -2*c1271d_prime = c*c-4*d1272print '\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )'%(int(c),int(d))1273print 'new isogenous curve is' + \1274' y^2 == x( x^2 + (%d)x + (%d) )'%(int(c_prime),int(d_prime))12751276n1 = Integer(0); n2 = Integer(0)1277n1_prime = Integer(0); n2_prime = Integer(0)1278count(c.value, d.value, p_list_mpz, p_list_len,1279global_limit_small, global_limit_large, verbosity, selmer_only,1280n1.value, n2.value)1281count(c_prime_mpz, d_prime_mpz, p_list_mpz, p_list_len,1282global_limit_small, global_limit_large, verbosity, selmer_only,1283n1_prime.value, n2_prime.value)12841285for i from 0 <= i < p_list_len:1286mpz_clear(p_list_mpz[i])1287sage_free(p_list_mpz)12881289if verbosity > 0:1290print "\nResults:"1291print n1, "<= #E(Q)/phi'(E'(Q)) <=", n21292print n1_prime, "<= #E'(Q)/phi(E(Q)) <=", n2_prime1293print "#Sel^(phi')(E'/Q) =", n21294print "#Sel^(phi)(E/Q) =", n2_prime1295print "1 <= #Sha(E'/Q)[phi'] <=", n2/n11296print "1 <= #Sha(E/Q)[phi] <=", n2_prime/n1_prime1297print "1 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <=", (n2_prime/n1_prime)*(n2/n1)1298a = Integer(n1*n1_prime).log(Integer(2))1299e = Integer(n2*n2_prime).log(Integer(2))1300print a - 2, "<= rank of E(Q) = rank of E'(Q) <=", e - 213011302return n1, n2, n1_prime, n2_prime13031304130513061307