Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - elltors.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.12.1 lcov report (development 25406-bf255ab81b) Lines: 404 429 94.2 %
Date: 2020-06-04 05:59:24 Functions: 23 26 88.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : /********************************************************************/
      15             : /**                                                                **/
      16             : /**         TORSION OF ELLIPTIC CURVES over NUMBER FIELDS          **/
      17             : /**                                                                **/
      18             : /********************************************************************/
      19             : #include "pari.h"
      20             : #include "paripriv.h"
      21             : static int
      22         196 : smaller_x(GEN p, GEN q)
      23             : {
      24         196 :   int s = abscmpii(denom_i(p), denom_i(q));
      25         196 :   return (s<0 || (s==0 && abscmpii(numer_i(p),numer_i(q)) < 0));
      26             : }
      27             : 
      28             : /* best generator in cycle of length k */
      29             : static GEN
      30         175 : best_in_cycle(GEN e, GEN p, long k)
      31             : {
      32         175 :   GEN p0 = p,q = p;
      33             :   long i;
      34             : 
      35         343 :   for (i=2; i+i<k; i++)
      36             :   {
      37         168 :     q = elladd(e,q,p0);
      38         168 :     if (ugcd(i,k)==1 && smaller_x(gel(q,1), gel(p,1))) p = q;
      39             :   }
      40         175 :   return (gsigne(ec_dmFdy_evalQ(e,p)) < 0)? ellneg(e,p): p;
      41             : }
      42             : 
      43             : /* <p,q> = E_tors, possibly NULL (= oo), p,q independent unless NULL
      44             :  * order p = k, order q = 2 unless NULL */
      45             : static GEN
      46         231 : tors(GEN e, long k, GEN p, GEN q, GEN v)
      47             : {
      48             :   GEN r;
      49         231 :   if (q)
      50             :   {
      51          70 :     long n = k>>1;
      52          70 :     GEN p1, best = q, np = ellmul(e,p,utoipos(n));
      53          70 :     if (n % 2 && smaller_x(gel(np,1), gel(best,1))) best = np;
      54          70 :     p1 = elladd(e,q,np);
      55          70 :     if (smaller_x(gel(p1,1), gel(best,1))) q = p1;
      56          49 :     else if (best == np) { p = elladd(e,p,q); q = np; }
      57          70 :     p = best_in_cycle(e,p,k);
      58          70 :     if (v)
      59             :     {
      60           0 :       p = ellchangepointinv(p,v);
      61           0 :       q = ellchangepointinv(q,v);
      62             :     }
      63          70 :     r = cgetg(4,t_VEC);
      64          70 :     gel(r,1) = utoipos(2*k);
      65          70 :     gel(r,2) = mkvec2(utoipos(k), gen_2);
      66          70 :     gel(r,3) = mkvec2copy(p, q);
      67             :   }
      68             :   else
      69             :   {
      70         161 :     if (p)
      71             :     {
      72         105 :       p = best_in_cycle(e,p,k);
      73         105 :       if (v) p = ellchangepointinv(p,v);
      74         105 :       r = cgetg(4,t_VEC);
      75         105 :       gel(r,1) = utoipos(k);
      76         105 :       gel(r,2) = mkvec( gel(r,1) );
      77         105 :       gel(r,3) = mkvec( gcopy(p) );
      78             :     }
      79             :     else
      80             :     {
      81          56 :       r = cgetg(4,t_VEC);
      82          56 :       gel(r,1) = gen_1;
      83          56 :       gel(r,2) = cgetg(1,t_VEC);
      84          56 :       gel(r,3) = cgetg(1,t_VEC);
      85             :     }
      86             :   }
      87         231 :   return r;
      88             : }
      89             : 
      90             : /* Finds a multiplicative upper bound for #E_tor; assume integral model */
      91             : static long
      92         231 : torsbound(GEN e, ulong p)
      93             : {
      94         231 :   GEN D = ell_get_disc(e);
      95         231 :   pari_sp av = avma, av2;
      96             :   long m, b, bold, nb;
      97             :   forprime_t S;
      98         231 :   long CM = ellQ_get_CM(e);
      99         231 :   nb = expi(D) >> 3;
     100             :   /* nb = number of primes to try ~ 1 prime every 8 bits in D */
     101         231 :   switch (p)
     102             :   {
     103         231 :     case 0: b = 5040; break;
     104           0 :     case 2: b = 16;   break;
     105           0 :     case 3: b = 9;    break;
     106           0 :     case 5: case 7: b = p; break;
     107           0 :     default: return 1;
     108             :   }
     109         231 :   bold = b;
     110         231 :   m = 0;
     111             :   /* p > 2 has good reduction => E(Q) injects in E(Fp) */
     112         231 :   (void)u_forprime_init(&S, 3, ULONG_MAX);
     113         231 :   av2 = avma;
     114        2226 :   while (m < nb || (b > 12 && b != 16))
     115             :   {
     116        2023 :     ulong p = u_forprime_next(&S);
     117        2023 :     if (!p) pari_err_BUG("torsbound [ran out of primes]");
     118        2023 :     if (!umodiu(D, p)) continue;
     119             : 
     120        1610 :     b = ugcd(b, p+1 - ellap_CM_fast(e,p,CM));
     121        1610 :     set_avma(av2);
     122        1610 :     if (b == 1) break;
     123        1582 :     if (b == bold) m++; else { bold = b; m = 0; }
     124             :   }
     125         231 :   return gc_long(av,b);
     126             : }
     127             : 
     128             : /* return a rational point of order pk = p^k on E, or NULL if E(Q)[k] = O.
     129             :  * *fk is either NULL (pk = 4 or prime) or elldivpol(p^(k-1)).
     130             :  * Set *fk to elldivpol(p^k) */
     131             : static GEN
     132         203 : tpoint(GEN E, long pk, GEN *fk)
     133             : {
     134         203 :   GEN f = elldivpol(E,pk,0), g = *fk, v;
     135             :   long i, l;
     136         203 :   *fk = f;
     137         203 :   if (g) f = RgX_div(f, g);
     138         203 :   v = nfrootsQ(f); l = lg(v);
     139         280 :   for (i = 1; i < l; i++)
     140             :   {
     141         231 :     GEN x = gel(v,i);
     142         231 :     GEN y = ellordinate(E,x,0);
     143         231 :     if (lg(y) != 1) return mkvec2(x,gel(y,1));
     144             :   }
     145          49 :   return NULL;
     146             : }
     147             : /* return E(Q)[2] */
     148             : static GEN
     149         140 : t2points(GEN E, GEN *f2)
     150             : {
     151             :   long i, l;
     152             :   GEN v;
     153         140 :   *f2 = ec_bmodel(E);
     154         140 :   v = nfrootsQ(*f2); l = lg(v);
     155         413 :   for (i = 1; i < l; i++)
     156             :   {
     157         273 :     GEN x = gel(v,i);
     158         273 :     GEN y = ellordinate(E,x,0);
     159         273 :     if (lg(y) != 1) gel(v,i) = mkvec2(x,gel(y,1));
     160             :   }
     161         140 :   return v;
     162             : }
     163             : 
     164             : static GEN
     165         231 : elltors_divpol(GEN E, long psylow)
     166             : {
     167         231 :   GEN T2 = NULL, p, P, Q, v;
     168             :   long v2, r2, B;
     169             : 
     170         231 :   E = ellintegralmodel_i(E, &v);
     171         231 :   B = torsbound(E, psylow); /* #E_tor | B */
     172         231 :   if (B == 1) return tors(E,1,NULL,NULL, v);
     173         203 :   v2 = vals(B); /* bound for v_2(point order) */
     174         203 :   B >>= v2;
     175         203 :   p = const_vec(9, NULL);
     176         203 :   r2 = 0;
     177         203 :   if (v2) {
     178             :     GEN f;
     179         140 :     T2 = t2points(E, &f);
     180         140 :     switch(lg(T2)-1)
     181             :     {
     182           7 :       case 0:  v2 = 0; break;
     183          63 :       case 1:  r2 = 1; if (v2 == 4) v2 = 3; break;
     184          70 :       default: r2 = 2; v2--; break; /* 3 */
     185             :     }
     186         140 :     if (v2) gel(p,2) = gel(T2,1);
     187             :     /* f = f_2 */
     188         140 :     if (v2 > 1) { gel(p,4) = tpoint(E,4, &f); if (!gel(p,4)) v2 = 1; }
     189             :     /* if (v2>1) now f = f4 */
     190         140 :     if (v2 > 2) { gel(p,8) = tpoint(E,8, &f); if (!gel(p,8)) v2 = 2; }
     191             :   }
     192         203 :   B <<= v2;
     193         203 :   if (B % 3 == 0) {
     194          70 :     GEN f3 = NULL;
     195          70 :     gel(p,3) = tpoint(E,3,&f3);
     196          70 :     if (!gel(p,3)) B /= (B%9)? 3: 9;
     197          70 :     if (gel(p,3) && B % 9 == 0)
     198             :     {
     199           7 :       gel(p,9) = tpoint(E,9,&f3);
     200           7 :       if (!gel(p,9)) B /= 3;
     201             :     }
     202             :   }
     203         203 :   if (B % 5 == 0) {
     204          28 :     GEN junk = NULL;
     205          28 :     gel(p,5) = tpoint(E,5,&junk);
     206          28 :     if (!gel(p,5)) B /= 5;
     207             :   }
     208         203 :   if (B % 7 == 0) {
     209          21 :     GEN junk = NULL;
     210          21 :     gel(p,7) = tpoint(E,7,&junk);
     211          21 :     if (!gel(p,7)) B /= 7;
     212             :   }
     213             :   /* B is the exponent of E_tors(Q), r2 is the rank of its 2-Sylow,
     214             :    * for i > 1, p[i] is a point of order i if one exists and i is a prime power
     215             :    * and NULL otherwise */
     216         203 :   if (r2 == 2) /* 2 cyclic factors */
     217             :   { /* C2 x C2 */
     218          70 :     if (B == 2) return tors(E,2, gel(T2,1), gel(T2,2), v);
     219          35 :     else if (B == 6)
     220             :     { /* C2 x C6 */
     221          14 :       P = elladd(E, gel(p,3), gel(T2,1));
     222          14 :       Q = gel(T2,2);
     223             :     }
     224             :     else
     225             :     { /* C2 x C4 or C2 x C8 */
     226          21 :       P = gel(p, B);
     227          21 :       Q = gel(T2,2);
     228          21 :       if (gequal(Q, ellmul(E, P, utoipos(B>>1)))) Q = gel(T2,1);
     229             :     }
     230             :   }
     231             :   else /* cyclic */
     232             :   {
     233         133 :     Q = NULL;
     234         133 :     if (v2)
     235             :     {
     236          63 :       if (B>>v2 == 1)
     237          35 :         P = gel(p, B);
     238             :       else
     239          28 :         P = elladd(E, gel(p, B>>v2), gel(p,1<<v2));
     240             :     }
     241          70 :     else P = gel(p, B);
     242             :   }
     243         168 :   return tors(E,B, P, Q, v);
     244             : }
     245             : 
     246             : /* either return one prime of degree 1 above p or NULL (none or expensive) */
     247             : static GEN
     248        6405 : primedec_deg1(GEN K, GEN p)
     249             : {
     250        6405 :   GEN r, T, f = nf_get_index(K);
     251        6405 :   if (dvdii(f,p)) return NULL;
     252        6328 :   T = nf_get_pol(K);
     253        6328 :   r = FpX_oneroot(T, p); if (!r) return NULL;
     254        1211 :   r = deg1pol_shallow(gen_1, Fp_neg(r,p), varn(T));
     255        1211 :   return idealprimedec_kummer(K, r, 1, p);
     256             : }
     257             : 
     258             : /* Bound for the elementary divisors of the torsion group of elliptic curve
     259             :  * Reduce the curve modulo some small good primes */
     260             : static GEN
     261         427 : nftorsbound(GEN E, ulong psylow)
     262             : {
     263             :   pari_sp av;
     264         427 :   long k = 0, g;
     265         427 :   GEN B1 = gen_0, B2 = gen_0, K = ellnf_get_nf(E);
     266         427 :   GEN D = ell_get_disc(E), ND = idealnorm(K,D);
     267             :   forprime_t S;
     268         427 :   if (typ(ND) == t_FRAC) ND = gel(ND,1);
     269         427 :   ND = mulii(ND, Q_denom(vecslice(E,1,5)));
     270         427 :   g = maxss(5, expi(ND) >> 3);
     271         427 :   if (g > 20) g = 20;
     272             :   /* P | p such that e(P/p) < p-1 => E(K) injects in E(k(P)) [otherwise
     273             :    * we may lose some p-torsion]*/
     274         427 :   (void)u_forprime_init(&S, 3, ULONG_MAX);
     275         427 :   av = avma;
     276        9492 :   while (k < g) /* k = number of good primes already used */
     277             :   {
     278        9226 :     ulong p = u_forprime_next(&S);
     279             :     GEN P, gp;
     280             :     long j, l;
     281        9226 :     if (!umodiu(ND,p)) continue;
     282        8358 :     gp = utoipos(p);
     283             :     /* primes of degree 1 are easier and give smaller bounds */
     284        8358 :     if (typ(D) != t_POLMOD) /* E/Q */
     285             :     {
     286        5796 :       P = primedec_deg1(K, gp); /* single P|p has all the information */
     287        5796 :       if (!P) continue;
     288         973 :       P = mkvec(P);
     289             :     }
     290             :     else
     291        2562 :       P = idealprimedec_limit_f(K, utoipos(p), 1);
     292        3535 :     l = lg(P);
     293        6146 :     for (j = 1; j < l; j++,k++)
     294             :     {
     295        2772 :       GEN Q = gel(P,j), EQ, cyc;
     296             :       long n;
     297        2772 :       if ((ulong)pr_get_e(Q) >= p-1) continue;
     298        2772 :       EQ = ellinit(E,zkmodprinit(K,Q),0);
     299        2772 :       cyc = ellgroup(EQ, NULL);
     300        2772 :       n = lg(cyc)-1;
     301        2772 :       if (n == 0) return mkvec2(gen_1,gen_1);
     302        2765 :       B1 = gcdii(B1,gel(cyc,1));
     303        2765 :       B2 = (n == 1)? gen_1: gcdii(B2,gel(cyc,2));
     304        2765 :       obj_free(EQ);
     305             :       /* division by 2 is cheap when it fails, no need to have a sharp bound */
     306        2765 :       if (psylow==0 && Z_ispow2(B1)) return mkvec2(B1,B2);
     307             :     }
     308        3374 :     if ((g & 15) == 0) gerepileall(av, 2, &B1, &B2);
     309             :   }
     310         266 :   if (abscmpiu(B2, 2) > 0)
     311             :   { /* if E(K) has full n-torsion then K contains the n-th roots of 1 */
     312          91 :     GEN n = gel(nfrootsof1(K), 1);
     313          91 :     B2 = gcdii(B2,n);
     314             :   }
     315         266 :   if (psylow)
     316             :   {
     317           0 :     B1 = powuu(psylow, Z_lval(B1, psylow));
     318           0 :     B2 = powuu(psylow, Z_lval(B1, psylow));
     319             :   }
     320         266 :   return mkvec2(B1,B2);
     321             : }
     322             : 
     323             : /* Checks whether the point P is divisible by n in E(K), where xn is
     324             :  * [phi_n, psi_n^2]
     325             :  * If true, returns a point Q such that nQ = P or -P. Else, returns NULL */
     326             : static GEN
     327         189 : ellnfis_divisible_by(GEN E, GEN K, GEN P, GEN xn)
     328             : {
     329         189 :   GEN r, x = gel(P,1);
     330             :   long i, l;
     331         189 :   if (ell_is_inf(P)) return P;
     332         189 :   r = nfroots(K, RgX_sub(RgX_Rg_mul(gel(xn,2), x), gel(xn,1)));
     333         189 :   l = lg(r);
     334         189 :   for(i=1; i<l; i++)
     335             :   {
     336         112 :     GEN a = gel(r,i), y = ellordinate(E,a,0);
     337         112 :     if (lg(y) != 1) return mkvec2(a, gel(y,1));
     338             :   }
     339          77 :   return NULL;
     340             : }
     341             : 
     342             : /* w a variable number of highest priority */
     343             : static long
     344         161 : ellisdivisible_i(GEN E, GEN P, GEN n, long w, GEN *pQ)
     345             : {
     346         161 :   GEN xP, R, K = NULL, N = NULL;
     347             :   long i, l;
     348         161 :   checkell(E);
     349         161 :   switch(ell_get_type(E))
     350             :   {
     351         140 :     case t_ELL_Q: break;
     352          21 :     case t_ELL_NF: K = ellnf_get_nf(E); break;
     353           0 :     default: pari_err_TYPE("ellisdivisible",E);
     354             :   }
     355         161 :   checkellpt(P);
     356         161 :   switch(typ(n))
     357             :   {
     358          84 :     case t_INT:
     359          84 :       N = n;
     360          84 :       if (!isprime(absi_shallow(n)))
     361             :       {
     362          42 :         GEN f = absZ_factor(n), LP = gel(f,1), LE = gel(f,2);
     363          42 :         l = lg(LP);
     364          84 :         for (i = 1; i < l; i++)
     365             :         {
     366          56 :           long j, e = itos(gel(LE,i));
     367          56 :           GEN xp = ellxn(E,itos(gel(LP,i)), w);
     368         112 :           for (j = 1; j <= e; j++)
     369          70 :             if (!ellisdivisible(E, P, xp, &P)) return 0;
     370             :         }
     371          28 :         if (pQ) *pQ = signe(n) < 0? ellneg(E, P): P;
     372          28 :         return 1;
     373             :       }
     374          42 :       n = ellxn(E, itou(n), w);
     375          42 :       break;
     376          77 :     case t_VEC:
     377          77 :       if (lg(n) == 3 && typ(gel(n,1)) == t_POL && typ(gel(n,2)) == t_POL) break;
     378             :     default:
     379           0 :       pari_err_TYPE("ellisdivisible",n);
     380           0 :       break;
     381             :   }
     382         119 :   if (ell_is_inf(P)) { if (pQ) *pQ = ellinf(); return 1; }
     383         112 :   if (!N)
     384             :   {
     385          70 :     long d, d2 = degpol(gel(n,1));
     386          70 :     if (d2 < 0)
     387           7 :       N = gen_0;
     388             :     else
     389             :     {
     390          63 :       if (!uissquareall(d2,(ulong*)&d)) pari_err_TYPE("ellisdivisible",n);
     391          63 :       N = stoi(d);
     392             :     }
     393             :   }
     394         112 :   if (!signe(N)) return 0;
     395         105 :   xP = gel(P,1);
     396         105 :   R = nfroots(K, RgX_sub(RgX_Rg_mul(gel(n,2), xP), gel(n,1)));
     397         105 :   l = lg(R);
     398         105 :   for(i = 1; i < l; i++)
     399             :   {
     400          84 :     GEN Q,y, x = gel(R,i), a = ellordinate(E,x,0);
     401          84 :     if (lg(a) == 1) continue;
     402          84 :     y = gel(a,1);
     403          84 :     Q = mkvec2(x,y);
     404          84 :     if (!gequal(P,ellmul(E,Q,N))) Q = ellneg(E,Q); /* nQ = -P */
     405          84 :     if (pQ) *pQ = Q;
     406          84 :     return 1;
     407             :   }
     408          21 :   return 0;
     409             : }
     410             : long
     411         161 : ellisdivisible(GEN E, GEN P, GEN n, GEN *pQ)
     412             : {
     413         161 :   pari_sp av = avma;
     414         161 :   long w = fetch_var_higher(), t = ellisdivisible_i(E, P, n, w, pQ);
     415         161 :   delete_var();
     416         161 :   if (!t) return gc_long(av, 0);
     417         119 :   if (pQ) *pQ = gerepilecopy(av, *pQ); else set_avma(av);
     418         119 :   return 1;
     419             : }
     420             : /* 2-torsion point of abscissa x */
     421             : static GEN
     422         126 : tor2(GEN E, GEN x) { return mkvec2(x, gmul2n(gneg(ec_h_evalx(E,x)), -1)); }
     423             : 
     424             : static GEN
     425          35 : ptor0(void)
     426          35 : { return mkvec2(mkvec(gen_1),cgetg(1,t_VEC)); }
     427             : static GEN
     428         126 : ptor1(long p, long n, GEN P)
     429         126 : { return mkvec2(mkvec(powuu(p,n)), mkvec(P)); }
     430             : static GEN
     431          98 : ptor2(long p, long n1, long n2, GEN P1, GEN P2)
     432          98 : { return mkvec2(mkvec2(powuu(p,n1), powuu(p,n2)), mkvec2(P1,P2)); }
     433             : 
     434             : /* Computes the p-primary torsion in E(K). Assume that p is small, should use
     435             :  * Weil pairing otherwise.
     436             :  * N1, N2 = upper bounds on the integers n1 >= n2 such that
     437             :  * E(K)[p^oo] = Z/p^n1 x Z/p^n2
     438             :  * Returns [cyc,gen], where E(K)[p^oo] = sum Z/cyc[i] gen[i] */
     439             : static GEN
     440         259 : ellnftorsprimary(GEN E, long p, long N1, long N2, long v)
     441             : {
     442         259 :   GEN X, P1, P2, Q1, Q2, xp, K = ellnf_get_nf(E);
     443             :   long n1, n2;
     444             : 
     445             :   /* compute E[p] = < P1 > or < P1, P2 > */
     446         259 :   P1 = P2 = ellinf();
     447         259 :   X = nfroots(K, elldivpol(E,p,v));
     448         259 :   if(lg(X) == 1) return ptor0();
     449         231 :   if (p==2)
     450             :   {
     451          77 :     P1 = tor2(E, gel(X,1));
     452          77 :     if (lg(X) > 2) P2 = tor2(E, gel(X,2)); /* E[2] = (Z/2Z)^2 */
     453             :   }
     454             :   else
     455             :   {
     456         154 :     long j, l = lg(X), nT, a;
     457         154 :     GEN T = vectrunc_init(l);
     458         539 :     for(j=1; j < l; j++)
     459             :     {
     460         385 :       GEN a = gel(X,j), Y = ellordinate(E,a,0);
     461         385 :       if (lg(Y) != 1) vectrunc_append(T, mkvec2(a,gel(Y,1)));
     462             :     }
     463         154 :     nT = lg(T)-1;
     464         154 :     if (!nT) return ptor0();
     465         147 :     P1 = gel(T,1);
     466         147 :     a = (p-1)/2;
     467         147 :     if (nT != a)
     468             :     { /* E[p] = (Z/pZ)^2 */
     469          49 :       GEN Z = cgetg(a+1,t_VEC), Q1 = P1;
     470             :       long k;
     471          49 :       gel(Z,1) = Q1;
     472          49 :       for (k=2; k <= a; k++) gel(Z,k) = elladd(E,Q1,P1);
     473          49 :       gen_sort_inplace(Z, (void*)&cmp_universal, &cmp_nodata, NULL);
     474          49 :       while (tablesearch(Z, gel(T,k), &cmp_universal)) k++;
     475          49 :       P2 = gel(T,k);
     476             :     }
     477             :   }
     478         224 :   xp = ellxn(E, p, v);
     479             : 
     480         224 :   if (ell_is_inf(P2))
     481             :   { /* E[p^oo] is cyclic, start from P1 and divide by p while possible */
     482         140 :     for (n1 = 1; n1 < N1; n1++)
     483             :     {
     484          14 :       GEN Q = ellnfis_divisible_by(E,K,P1,xp);
     485          14 :       if (!Q) break;
     486          14 :       P1 = Q;
     487             :     }
     488         126 :     return ptor1(p, n1, P1);
     489             :   }
     490             : 
     491             :   /* E[p] = (Z/pZ)^2, compute n2 and E[p^n2] */
     492          98 :   Q1 = NULL;
     493         119 :   for (n2 = 1; n2 < N2; n2++)
     494             :   {
     495          21 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     496          21 :     Q2 = ellnfis_divisible_by(E,K,P2,xp);
     497          21 :     if (!Q1 || !Q2) break;
     498          21 :     P1 = Q1;
     499          21 :     P2 = Q2;
     500             :   }
     501             : 
     502             :   /* compute E[p^oo] = < P1, P2 > */
     503          98 :   n1 = n2;
     504          98 :   if (n2 == N2)
     505             :   {
     506          98 :     if (N1 == N2) return ptor2(p, n2,n2, P1,P2);
     507          42 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     508             :   }
     509          42 :   if (Q1) { P1 = Q1; n1++; }
     510             :   else
     511             :   {
     512          28 :     Q2 = ellnfis_divisible_by(E,K,P2,xp);
     513          28 :     if (Q2) { P2 = P1; P1 = Q2; n1++; }
     514             :     else
     515             :     {
     516             :       long k;
     517          35 :       for (k = 1; k < p; k++)
     518             :       {
     519          28 :         P1 = elladd(E,P1,P2);
     520          28 :         Q1 = ellnfis_divisible_by(E,K,P1,xp);
     521          28 :         if (Q1) { P1 = Q1; n1++; break; }
     522             :       }
     523          28 :       if (k == p) return ptor2(p, n2,n2, P1,P2);
     524             :     }
     525             :   }
     526             :   /* P1,P2 of order p^n1,p^n2 with n1=n2+1.
     527             :    * Keep trying to divide P1 + k P2 with 0 <= k < p by p */
     528          56 :   while (n1 < N1)
     529             :   {
     530          21 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     531          21 :     if (Q1) { P1 = Q1; n1++; }
     532             :     else
     533             :     {
     534             :       long k;
     535          14 :       for (k = 1; k < p; k++)
     536             :       {
     537          14 :         P1 = elladd(E,P1,P2);
     538          14 :         Q1 = ellnfis_divisible_by(E,K,P1,xp);
     539          14 :         if (Q1) { P1 = Q1; n1++; break; }
     540             :       }
     541          14 :       if (k == p) break;
     542             :     }
     543             :   }
     544          35 :   return ptor2(p, n1,n2, P1,P2);
     545             : }
     546             : 
     547             : /* P affine point */
     548             : static GEN
     549         259 : nfpt(GEN e, GEN P)
     550             : {
     551         259 :   GEN T = nf_get_pol(ellnf_get_nf(e));
     552         259 :   GEN x = gel(P,1), y = gel(P,2);
     553         259 :   long tx = typ(x), ty = typ(y);
     554         259 :   if (tx == ty) return P;
     555          98 :   if (tx != t_POLMOD) x = mkpolmod(x,T); else y = mkpolmod(y,T);
     556          98 :   return mkvec2(x,y);
     557             : }
     558             : /* Computes the torsion subgroup of E(K), as [order, cyc, gen] */
     559             : static GEN
     560         189 : ellnftors(GEN e, ulong psylow)
     561             : {
     562         189 :   GEN B = nftorsbound(e, psylow), B1 = gel(B,1), B2 = gel(B,2), d1,d2, P1,P2;
     563         189 :   GEN f = Z_factor(B1), P = gel(f,1), E = gel(f,2);
     564         189 :   long i, l = lg(P), v = fetch_var_higher();
     565             : 
     566         189 :   d1 = d2 = gen_1; P1 = P2 = ellinf();
     567         448 :   for (i=1; i<l; i++)
     568             :   {
     569         259 :     long p = itos(gel(P,i)); /* Compute p-primary torsion */
     570         259 :     long N1 = itos(gel(E,i)); /* >= n1 */
     571         259 :     long N2 = Z_lval(B2,p); /* >= n2 */
     572         259 :     GEN T = ellnftorsprimary(e, p, N1, N2, v), cyc = gel(T,1), gen = gel(T,2);
     573         259 :     if (is_pm1(gel(cyc,1))) continue;
     574             :     /* update generators P1,P2 and their respective orders d1,d2 */
     575         224 :     P1 = elladd(e, P1, gel(gen,1)); d1 = mulii(d1, gel(cyc,1));
     576         224 :     if (lg(cyc) > 2)
     577          98 :     { P2 = elladd(e, P2, gel(gen,2)); d2 = mulii(d2, gel(cyc,2)); }
     578             :   }
     579         189 :   (void)delete_var();
     580         189 :   if (is_pm1(d1)) return mkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC));
     581         168 :   if (is_pm1(d2)) return mkvec3(d1, mkvec(d1), mkvec(nfpt(e,P1)));
     582          91 :   return mkvec3(mulii(d1,d2), mkvec2(d1,d2), mkvec2(nfpt(e,P1),nfpt(e,P2)));
     583             : }
     584             : 
     585             : GEN
     586         420 : elltors(GEN e)
     587             : {
     588         420 :   pari_sp av = avma;
     589         420 :   GEN t = NULL;
     590         420 :   checkell(e);
     591         420 :   switch(ell_get_type(e))
     592             :   {
     593         231 :     case t_ELL_Q:  t = elltors_divpol(e, 0); break;
     594         189 :     case t_ELL_NF: t = ellnftors(e, 0); break;
     595           0 :     case t_ELL_Fp:
     596           0 :     case t_ELL_Fq: return ellgroup0(e,NULL,1);
     597           0 :     default: pari_err_TYPE("elltors",e);
     598             :   }
     599         420 :   return gerepilecopy(av, t);
     600             : }
     601             : 
     602             : GEN
     603           0 : elltors0(GEN e, long flag) { (void)flag; return elltors(e); }
     604             : 
     605             : GEN
     606           0 : elltors_psylow(GEN e, ulong p)
     607             : {
     608           0 :   pari_sp av = avma;
     609           0 :   GEN t = NULL;
     610           0 :   checkell(e);
     611           0 :   switch(ell_get_type(e))
     612             :   {
     613           0 :     case t_ELL_Q:  t = elltors_divpol(e, p); break;
     614           0 :     case t_ELL_NF: t = ellnftors(e, p); break;
     615           0 :     default: pari_err_TYPE("elltorspsylow",e);
     616             :   }
     617           0 :   return gerepilecopy(av, t);
     618             : }
     619             : 
     620             : /********************************************************************/
     621             : /**                                                                **/
     622             : /**                ORDER OF POINTS over NUMBER FIELDS              **/
     623             : /**                                                                **/
     624             : /********************************************************************/
     625             : /* E a t_ELL_Q (use Mazur's theorem) */
     626             : long
     627         350 : ellorder_Q(GEN E, GEN P)
     628             : {
     629         350 :   pari_sp av = avma;
     630             :   GEN dx, dy, d4, d6, D, Pp, Q;
     631             :   forprime_t S;
     632             :   ulong a4, p;
     633             :   long k;
     634         350 :   if (ell_is_inf(P)) return 1;
     635         350 :   if (gequal(P, ellneg(E,P))) return 2;
     636             : 
     637         315 :   dx = Q_denom(gel(P,1));
     638         315 :   dy = Q_denom(gel(P,2));
     639         315 :   if (ell_is_integral(E)) /* integral model, try Nagell Lutz */
     640         259 :     if (abscmpiu(dx, 4) > 0 || abscmpiu(dy, 8) > 0) return 0;
     641             : 
     642         231 :   d4 = Q_denom(ell_get_c4(E));
     643         231 :   d6 = Q_denom(ell_get_c6(E));
     644         231 :   D = ell_get_disc (E);
     645             :   /* choose not too small prime p dividing neither a coefficient of the
     646             :      short Weierstrass form nor of P and leading to good reduction */
     647         231 :   u_forprime_init(&S, 100003, ULONG_MAX);
     648         231 :   while ( (p = u_forprime_next(&S)) )
     649         231 :     if (umodiu(d4, p) && umodiu(d6, p) && Rg_to_Fl(D, p)
     650         231 :      && umodiu(dx, p) && umodiu(dy, p)) break;
     651             : 
     652             :   /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep,
     653             :    * check whether the order of Pp on Ep is <= 12 */
     654         231 :   Pp = point_to_a4a6_Fl(E, P, p, &a4);
     655        2555 :   for (Q = Fle_dbl(Pp, a4, p), k = 2;
     656        4585 :        !ell_is_inf(Q) && k <= 12;
     657        2093 :        Q = Fle_add(Q, Pp, a4, p), k++) /* empty */;
     658             : 
     659         231 :   if (k == 13) k = 0;
     660             :   else
     661             :   { /* check whether [k]P = O over Q. Save potentially costly last elladd */
     662             :     GEN R;
     663          63 :     Q = ellmul(E, P, utoipos(k>>1));
     664          63 :     R = odd(k)? elladd(E, P,Q): Q;
     665          63 :     if (!gequal(Q, ellneg(E,R))) k = 0;
     666             :   }
     667         231 :   return gc_long(av,k);
     668             : }
     669             : /* E a t_ELL_NF */
     670             : static GEN
     671         273 : ellorder_nf(GEN E, GEN P)
     672             : {
     673         273 :   GEN K = ellnf_get_nf(E), B;
     674         273 :   pari_sp av = avma;
     675             :   GEN dx, dy, d4, d6, D, ND, Ep, Pp, Q, gp, modpr, pr, T, k;
     676             :   forprime_t S;
     677             :   ulong a4, p;
     678         273 :   if (ell_is_inf(P)) return gen_1;
     679         273 :   if (gequal(P, ellneg(E,P))) return gen_2;
     680             : 
     681         238 :   B = gel(nftorsbound(E, 0), 1);
     682         238 :   dx = Q_denom(gel(P,1));
     683         238 :   dy = Q_denom(gel(P,2));
     684         238 :   d4 = Q_denom(ell_get_c4(E));
     685         238 :   d6 = Q_denom(ell_get_c6(E));
     686         238 :   D = ell_get_disc(E);
     687         238 :   ND = idealnorm(K,D);
     688         238 :   if (typ(ND) == t_FRAC) ND = gel(ND,1);
     689             : 
     690             :   /* choose not too small prime p of degree 1 dividing neither a coefficient of
     691             :    * the short Weierstrass form nor of P and leading to good reduction */
     692         238 :   u_forprime_init(&S, 100003, ULONG_MAX);
     693         609 :   while ( (p = u_forprime_next(&S)) )
     694             :   {
     695         609 :     if (!umodiu(d4, p) || !umodiu(d6, p) || !umodiu(ND, p)
     696         609 :      || !umodiu(dx, p) || !umodiu(dy, p)) continue;
     697         609 :     gp = utoipos(p);
     698         609 :     pr = primedec_deg1(K, gp);
     699         609 :     if (pr) break;
     700             :   }
     701             : 
     702         238 :   modpr = nf_to_Fq_init(K, &pr,&T,&gp);
     703         238 :   Ep = ellinit(E, pr, 0);
     704         238 :   Pp = nfV_to_FqV(P, K, modpr);
     705             : 
     706             :   /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep,
     707             :    * check whether the order of Pp on Ep divides B */
     708         238 :   Pp = point_to_a4a6_Fl(Ep, Pp, p, &a4);
     709         238 :   if (!ell_is_inf(Fle_mul(Pp, B, a4, p))) { set_avma(av); return gen_0; }
     710         147 :   k = Fle_order(Pp, B, a4, p);
     711             :   { /* check whether [k]P = O over K. Save potentially costly last elladd */
     712             :     GEN R;
     713         147 :     Q = ellmul(E, P, shifti(k,-1));
     714         147 :     R = mod2(k)? elladd(E, P,Q): Q;
     715         147 :     if (!gequal(Q, ellneg(E,R))) k = gen_0;
     716             :   }
     717         147 :   return gerepileuptoint(av, k);
     718             : }
     719             : 
     720             : GEN
     721        2793 : ellorder(GEN E, GEN P, GEN o)
     722             : {
     723        2793 :   pari_sp av = avma;
     724        2793 :   GEN fg, r, E0 = E;
     725        2793 :   checkell(E); checkellpt(P);
     726        2793 :   if (ell_is_inf(P)) return gen_1;
     727        2779 :   if (ell_get_type(E)==t_ELL_Q)
     728             :   {
     729        1869 :     long tx = typ(gel(P,1)), ty = typ(gel(P,2));
     730        1869 :     GEN p = NULL;
     731        1869 :     if (is_rational_t(tx) && is_rational_t(ty)) return utoi(ellorder_Q(E, P));
     732        1778 :     if (tx == t_INTMOD || tx == t_FFELT) p = gel(P,1);
     733        1778 :     if (!p && (ty == t_INTMOD || ty == t_FFELT)) p = gel(P,2);
     734        1778 :     if (p)
     735             :     {
     736        1778 :       E = ellinit(E,p,0);
     737        1778 :       if (lg(E)==1) pari_err_IMPL("ellorder for curve with singular reduction");
     738             :     }
     739             :   }
     740        2681 :   if (ell_get_type(E)==t_ELL_NF) return ellorder_nf(E, P);
     741        2408 :   checkell_Fq(E);
     742        2408 :   fg = ellff_get_field(E);
     743        2408 :   if (!o) o = ellff_get_o(E);
     744        2408 :   if (typ(fg)==t_FFELT)
     745        1750 :     r = FF_ellorder(E, P, o);
     746             :   else
     747             :   {
     748         658 :     GEN p = fg, e = ellff_get_a4a6(E);
     749         658 :     GEN Pp = FpE_changepointinv(RgE_to_FpE(P,p), gel(e,3), p);
     750         658 :     r = FpE_order(Pp, o, gel(e,1), p);
     751             :   }
     752        2408 :   if (E != E0) obj_free(E);
     753        2408 :   return gerepileuptoint(av, r);
     754             : }
     755             : 
     756             : GEN
     757           0 : orderell(GEN e, GEN z) { return ellorder(e,z,NULL); }

Generated by: LCOV version 1.13