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

Generated by: LCOV version 1.16