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 - ellpadic.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30702-bddb8d6928) Lines: 588 611 96.2 %
Date: 2026-02-23 02:23:56 Functions: 47 47 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2011  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
      14             : 
      15             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : 
      18             : static GEN
      19         228 : precp_fix(GEN h, long v)
      20         228 : { return (precp(h) > v)? cvtop(h,padic_p(h),v): h; }
      21             : 
      22             : /* TATE CURVE */
      23             : 
      24             : /* a1, b1 are t_PADICs, a1/b1 = 1 (mod p) if p odd, (mod 2^4) otherwise.
      25             :  * Let (A_n, B_n) be defined by A_1 = a1/p^v, B_1 = b1/p^v, v=v(a1)=v(a2);
      26             :  *   A_{n+1} = (A_n + B_n + 2 B_{n+1}) / 4
      27             :  *   B_{n+1} = B_n sqrt(A_n / B_n) = square root of A_n B_n congruent to B_n
      28             :  *   R_n = p^v( A_n - B_n ) = r_{n+1}
      29             :  * Return [An,Bn,Rn]. N.B. lim An = M2(a1,b1) = M(sqrt(a1),sqrt(b1))^2 */
      30             : GEN
      31         222 : Qp_agm2_sequence(GEN a1, GEN b1)
      32             : {
      33         222 :   GEN bp, pmod, p = padic_p(a1), q = padic_pd(a1), An, Bn, Rn;
      34         222 :   long pp = precp(a1), v = valp(a1), i;
      35         222 :   int pis2 = absequaliu(p,2);
      36         222 :   a1 = padic_u(a1);
      37         222 :   b1 = padic_u(b1);
      38         222 :   if (pis2)
      39         132 :     pmod = utoipos(8);
      40             :   else
      41          90 :     pmod = p;
      42         222 :   bp = modii(b1, pmod);
      43         222 :   An = cgetg(pp+1, t_VEC); /* overestimate: rather log_2(pp) */
      44         222 :   Bn = cgetg(pp+1, t_VEC);
      45         222 :   Rn = cgetg(pp+1, t_VEC);
      46         222 :   for(i = 1;; i++)
      47         558 :   {
      48         780 :     GEN a = a1, b = b1, r;
      49             :     long vr;
      50         780 :     gel(An, i) = a;
      51         780 :     gel(Bn, i) = b;
      52         780 :     r = subii(a,b);
      53         780 :     if (!signe(r)) break;
      54         582 :     vr = Z_pvalrem(r,p,&r);
      55         582 :     if (vr >= pp) break;
      56         558 :     r = cvtop(r, p, pp - vr); setvalp(r, vr+v);
      57         558 :     gel(Rn, i) = r;
      58             : 
      59         558 :     b1 = Zp_sqrt(Fp_mul(a,b,q), p, pp);
      60         558 :     if (!b1) pari_err_PREC("p-adic AGM");
      61         558 :     if (!equalii(modii(b1,pmod), bp)) b1 = Fp_neg(b1, q);
      62             :     /* a1 = (a+b+2sqrt(ab))/4 */
      63         558 :     if (pis2)
      64             :     {
      65         294 :       b1 = remi2n(b1, pp-1);
      66         294 :       a1 = shifti(addii(addii(a,b), shifti(b1,1)),-2);
      67         294 :       a1 = remi2n(a1, pp-2);
      68         294 :       pp -= 2;
      69             :     }
      70             :     else
      71         264 :       a1 = modii(Fp_halve(addii(Fp_halve(addii(a,b),q), b1), q), q);
      72             :   }
      73         222 :   setlg(An,i+1);
      74         222 :   setlg(Bn,i+1);
      75         222 :   setlg(Rn,i); return mkvec4(An, Bn, Rn, stoi(v));
      76             : }
      77             : void
      78         306 : Qp_descending_Landen(GEN AB, GEN *ptx, GEN *pty)
      79             : {
      80         306 :   GEN R = gel(AB,3);
      81         306 :   long i, n = lg(R)-1;
      82         306 :   GEN x = *ptx;
      83         306 :   if (isintzero(x))
      84             :   {
      85         222 :     i = 2;
      86         222 :     x = gmul2n(gel(R,1),-2);
      87         222 :     if (pty)
      88             :     {
      89           0 :       GEN A = gel(AB,1);
      90           0 :       if (n == 1)
      91           0 :         *pty = gmul(x, Qp_sqrt(gadd(x,gel(A,2))));
      92             :       else
      93           0 :         *pty = Qp_sqrt(gmul(gmul(x, gadd(x,gel(A,2))), gadd(x,gel(R,2))));
      94           0 :       if (!*pty) pari_err_PREC("Qp_descending_Landen");
      95             :     }
      96             :   }
      97             :   else
      98          84 :     i = 1;
      99         864 :   for (; i <= n; i++)
     100             :   {
     101         558 :     GEN r = gel(R,i), t;
     102         558 :     if (gequal0(x)) pari_err_PREC("Qp_descending_Landen");
     103         558 :     t = Qp_sqrt(gaddsg(1, gdiv(r,x))); /* = 1 (mod p) */
     104         558 :     if (!t) pari_err_PREC("Qp_descending_Landen");
     105         558 :     if (i == n)
     106             :     {
     107         264 :       GEN p = padic_p(r);
     108         264 :       long v, vx = valp(x), vr = valp(r);
     109         264 :       if (vx >= vr) pari_err_PREC("Qp_descending_Landen");
     110             :       /* last loop, take into account loss of accuracy from multiplication
     111             :        * by \prod_{j > n} sqrt(1+r_j/x_j); since vx < vr, j = n+1 is enough */
     112         264 :       v = 2*vr - vx;
     113             :       /* |r_{n+1}| <= |(r_n)^2 / 8| + 1 bit for sqrt loss */
     114         264 :       if (absequaliu(p,2)) v -= 4;
     115             :       /* tail is 1 + O(p^v) */
     116         264 :       if (v < precp(x)) x = cvtop(x,p,v);
     117             :     }
     118             :     /* x_{n+1} = x_n  ((1 + sqrt(1 + r_n/x_n)) / 2)^2 */
     119         558 :     x = gmul(x, gsqr(gmul2n(gaddsg(1,t),-1)));
     120             :     /* y_{n+1} = y_n / (1 - (r_n/4x_{n+1})^2) */
     121         558 :     if (pty) *pty = gdiv(*pty, gsubsg(1, gsqr(gdiv(r,gmul2n(x,2)))));
     122             :   }
     123         306 :   *ptx = x;
     124         306 : }
     125             : void
     126          48 : Qp_ascending_Landen(GEN AB, GEN *ptx, GEN *pty)
     127             : {
     128          48 :   GEN A = gel(AB,1), R = gel(AB,3), x = *ptx, p, r;
     129          48 :   long n = lg(R)-1, va = itos(gel(AB,4)), v, i;
     130             : 
     131          48 :   r = gel(R,n);
     132          48 :   v = 2*valp(r) + va;
     133          48 :   if (typ(x) == t_PADIC)
     134          30 :     v -= 2*valp(x);
     135             :   else
     136          18 :     v -= valp(gnorm(x)); /* v(x) = v(Nx) / (e*f), here ef = 2 */
     137          48 :   p = padic_p(r);
     138          48 :   if (absequaliu(p,2)) v -= 3; /* |r_{n+1}| <= |(r_n)^2 / 8| */
     139             :   /* v = v(A[n+1] R[n+1] / x_{n+1}^2) */
     140          48 :   if (v <= 0) pari_err_PREC("Qp_ascending_Landen");
     141             :   /* v > 0 => v = v(x_oo) = ... = v(x_{n+1}) */
     142          48 :   x = gsub(x, gmul2n(r,-1));
     143          48 :   if (padicprec_relative(x) > v) x = gcvtop(x, p, v);
     144             :   /* x = x_n */
     145         132 :   for (i = n; i > 1; i--)
     146             :   {
     147          84 :     GEN ar = gmul(gel(A,i),gel(R,i)), xp;
     148          84 :     setvalp(ar, valp(ar)+va); /* A_i = A[i] * p^va */
     149             :     /* x_{i-1} = x_i + a_i r_i / x_i - r_{i-1}/2 */
     150          84 :     xp = gsub(gadd(x, gdiv(ar, x)), gmul2n(gel(R,i-1),-1));
     151             :     /* y_{i-1} = y_i (1 - a_i r_i / x^2) */
     152          84 :     if (pty) *pty = gmul(*pty, gsubsg(1, gdiv(ar,gsqr(x))));
     153          84 :     x = xp;
     154             :   }
     155          48 :   *ptx = x;
     156          48 : }
     157             : 
     158             : /* Let T = 4x^3 + b2 x^2 + 2b4 x + b6, where T has a unique p-adic root 'a'.
     159             :  * Return a lift of a to padic accuracy prec. We have
     160             :  * 216 T = 864 X^3 - 18 c4X - c6, where X = x + b2/12 */
     161             : static GEN
     162         246 : doellQp_root(GEN E, long prec)
     163             : {
     164         246 :   GEN c4=ell_get_c4(E), c6=ell_get_c6(E), j=ell_get_j(E), p=ellQp_get_p(E);
     165             :   GEN c6p, T, a;
     166             :   long alpha;
     167         246 :   int pis2 = absequaliu(p, 2);
     168         246 :   if (Q_pval(j, p) >= 0) pari_err_DOMAIN(".root", "v_p(j)", ">=", gen_0, j);
     169             :   /* v(j) < 0 => v(c4^3) = v(c6^2) = 2 alpha */
     170         246 :   alpha = Q_pvalrem(ell_get_c4(E), p, &c4) >> 1;
     171         246 :   if (alpha) (void)Q_pvalrem(ell_get_c6(E), p, &c6);
     172             :   /* Renormalized so that v(c4) = v(c6) = 0; multiply by p^alpha at the end */
     173         246 :   if (prec < 4 && pis2) prec = 4;
     174         246 :   c6p = modii(c6,p);
     175         246 :   if (pis2)
     176             :   { /* Use 432T(X/4) = 27X^3 - 9c4 X - 2c6 to have integral root; a=0 mod 2 */
     177         120 :     T = mkpoln(4, utoipos(27), gen_0, mulis(c4,-9), mulis(c6, -2));
     178             :     /* v_2(root a) = 1, i.e. will lose one bit of accuracy: prec+1 */
     179         120 :     a = ZpX_liftroot(T, gen_0, p, prec+1);
     180         120 :     alpha -= 2;
     181             :   }
     182         126 :   else if (absequaliu(p, 3))
     183             :   { /* Use 216T(X/3) = 32X^3 - 6c4 X - c6 to have integral root; a=-c6 mod 3 */
     184          66 :     a = Fp_neg(c6p, p);
     185          66 :     T = mkpoln(4, utoipos(32), gen_0, mulis(c4, -6), negi(c6));
     186          66 :     a = ZX_Zp_root(T, a, p, prec);
     187          66 :     switch(lg(a)-1)
     188             :     {
     189          24 :       case 1: /* single root */
     190          24 :         a = gel(a,1); break;
     191          42 :       case 3: /* three roots, e.g. "15a1", choose the right one */
     192             :       {
     193          42 :         GEN a1 = gel(a,1), a2 = gel(a,2), a3 = gel(a,3);
     194          42 :         long v1 = Z_lval(subii(a2, a3), 3);
     195          42 :         long v2 = Z_lval(subii(a1, a3), 3);
     196          42 :         long v3 = Z_lval(subii(a1, a2), 3);
     197          42 :         if      (v1 == v2) a = a3;
     198          18 :         else if (v1 == v3) a = a2;
     199          18 :         else a = a1;
     200             :       }
     201          42 :       break;
     202             :     }
     203          66 :     alpha--;
     204             :   }
     205             :   else
     206             :   { /* p != 2,3: T = 4(x-a)(x-b)^2 = 4x^3 - 3a^2 x - a^3 when b = -a/2
     207             :      * (so that the trace coefficient vanishes) => a = c6/6c4 (mod p)*/
     208          60 :     GEN c4p = modii(c4,p);
     209          60 :     a = Fp_div(c6p, Fp_mulu(c4p, 6, p), p);
     210          60 :     T = mkpoln(4, utoipos(864), gen_0, mulis(c4, -18), negi(c6));
     211          60 :     a = ZpX_liftroot(T, a, p, prec);
     212             :   }
     213         246 :   a = cvtop(a, p, prec);
     214         246 :   if (alpha) setvalp(a, valp(a)+alpha);
     215         246 :   return gsub(a, gdivgu(ell_get_b2(E), 12));
     216             : }
     217             : GEN
     218         462 : ellQp_root(GEN E, long prec)
     219         462 : { return obj_checkbuild_padicprec(E, Qp_ROOT, &doellQp_root, prec); }
     220             : 
     221             : /* compute a,b such that E1: y^2 = x(x-a)(x+a-b) ~ E */
     222             : static void
     223         288 : doellQp_ab(GEN E, GEN *pta, GEN *ptb, long prec)
     224             : {
     225         288 :   GEN b2 = ell_get_b2(E), b4 = ell_get_b4(E), e1 = ellQp_root(E, prec);
     226         288 :   GEN w, u, t = gadd(gdivgu(b2,4), gmulsg(3,e1)), p = ellQp_get_p(E);
     227         288 :   w = Qp_sqrt(gmul2n(gadd(b4,gmul(e1,gadd(b2,gmulsg(6,e1)))),1));
     228         288 :   u = gadd(t,w);
     229             :   /* Decide between w and -w: we want v(a-b) > v(b) */
     230         288 :   if (absequaliu(p,2))
     231         174 :   { if (valp(u)-1 <= valp(w)) w = gneg_i(w); }
     232             :   else
     233         114 :   { if (valp(u) <= valp(w)) w = gneg_i(w); }
     234             : 
     235             :   /* w^2 = 2b4 + 2b2 e1 + 12 e1^2 = 4(e1-e2)(e1-e3) */
     236         288 :   *pta = gmul2n(gsub(w,t),-2);
     237         288 :   *ptb = gmul2n(w,-1);
     238         288 : }
     239             : 
     240             : static GEN
     241         102 : doellQp_Tate(GEN E, long prec0)
     242             : {
     243         102 :   GEN p = ellQp_get_p(E), j = ell_get_j(E);
     244             :   GEN L, u, u2, q, x1, a, b, d, s, t, AB, A, M2;
     245         102 :   long v, n, pp, prec = prec0+3;
     246         102 :   int split = -1; /* unknown */
     247         102 :   int pis2 = equaliu(p,2);
     248             : 
     249         102 :   if (Q_pval(j, p) >= 0) pari_err_DOMAIN(".tate", "v_p(j)", ">=", gen_0, j);
     250         102 : START:
     251         288 :   doellQp_ab(E, &a, &b, prec);
     252         288 :   d = gsub(a,b);
     253         288 :   v = prec0 - precp(d);
     254         288 :   if (v > 0) { prec += v; goto START; }
     255         222 :   AB = Qp_agm2_sequence(a,b);
     256         222 :   A = gel(AB,1);
     257         222 :   n = lg(A)-1; /* AGM iterations */
     258         222 :   pp = minss(precp(a),precp(b));
     259         222 :   M2 = cvtop(gel(A,n), p, pis2? pp-2*n: pp);
     260         222 :   setvalp(M2, valp(a));
     261         222 :   u2 = ginv(gmul2n(M2, 2));
     262         222 :   if (split < 0) split = issquare(u2);
     263         222 :   x1 = gen_0;
     264         222 :   Qp_descending_Landen(AB,&x1,NULL);
     265             : 
     266         222 :   t = gaddsg(1, ginv(gmul2n(gmul(u2,x1),1)));
     267         222 :   s = Qp_sqrt(gsubgs(gsqr(t), 1));
     268         222 :   q = gadd(t,s);
     269         222 :   if (gequal0(q)) q = gsub(t,s);
     270         222 :   v = prec0 - precp(q);
     271         222 :   if (split)
     272             :   { /* we want log q at precision prec0 */
     273          84 :     GEN q0 = leafcopy(q); setvalp(q0, 0);
     274          84 :     v +=  valp(gsubgs(q0,1));
     275             :   }
     276         222 :   if (v > 0) { prec += v; goto START; }
     277         102 :   if (valp(q) < 0) q = ginv(q);
     278         102 :   if (split)
     279             :   {
     280          48 :     u = Qp_sqrt(u2);
     281          48 :     L = gdivgs(Qp_log(q), valp(q));
     282             :   }
     283             :   else
     284             :   {
     285          54 :     GEN T = mkpoln(3, gen_1, gen_0, gneg(u2));
     286          54 :     u = mkpolmod(pol_x(0), T);
     287          54 :     L = gen_1;
     288             :   }
     289         102 :   return mkvecn(6, u2, u, q, mkvec2(a, b), L, AB);
     290             : }
     291             : static long
     292         588 : Tate_prec(GEN T) { return padicprec_relative(gel(T,3)); }
     293             : GEN
     294         684 : ellQp_Tate_uniformization(GEN E, long prec)
     295         684 : { return obj_checkbuild_prec(E,Qp_TATE,&doellQp_Tate, &Tate_prec,prec); }
     296             : GEN
     297         174 : ellQp_u(GEN E, long prec)
     298         174 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,2); }
     299             : GEN
     300          66 : ellQp_u2(GEN E, long prec)
     301          66 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,1); }
     302             : GEN
     303         126 : ellQp_q(GEN E, long prec)
     304         126 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,3); }
     305             : GEN
     306         108 : ellQp_ab(GEN E, long prec)
     307         108 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,4); }
     308             : GEN
     309           6 : ellQp_L(GEN E, long prec)
     310           6 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,5); }
     311             : GEN
     312         132 : ellQp_AGM(GEN E, long prec)
     313         132 : { GEN T = ellQp_Tate_uniformization(E, prec); return gel(T,6); }
     314             : 
     315             : /* FORMAL GROUP */
     316             : 
     317             : /* t to w := -1/y */
     318             : GEN
     319         426 : ellformalw(GEN e, long n, long v)
     320             : {
     321         426 :   pari_sp av = avma, av2;
     322             :   GEN a1,a2,a3,a4,a6, a63;
     323         426 :   GEN w = cgetg(3, t_SER), t, U, V, W, U2;
     324         426 :   ulong mask, nold = 1;
     325         426 :   if (v < 0) v = 0;
     326         426 :   if (n <= 0) pari_err_DOMAIN("ellformalw","precision","<=",gen_0,stoi(n));
     327         414 :   mask = quadratic_prec_mask(n);
     328         414 :   t = pol_x(v);
     329         414 :   checkell(e);
     330         414 :   a1 = ell_get_a1(e); a2 = ell_get_a2(e); a3 = ell_get_a3(e);
     331         414 :   a4 = ell_get_a4(e); a6 = ell_get_a6(e); a63 = gmulgu(a6,3);
     332         414 :   w[1] = evalsigne(1)|evalvarn(v)|evalvalser(3);
     333         414 :   gel(w,2) = gen_1; /* t^3 + O(t^4) */
     334             :   /* use Newton iteration, doubling accuracy at each step
     335             :    *
     336             :    *            w^3 a6 + w^2(a4 t + a3) + w (a2 t^2 + a1 t - 1) + t^3
     337             :    * w  <-  w - -----------------------------------------------------
     338             :    *              w^2 (3a6) + w (2a4 t + 2a3) + (a2 t^2 + a1 t - 1)
     339             :    *
     340             :    *              w^3 a6 + w^2 U + w V + W
     341             :    *      =: w -  -----------------------
     342             :    *                w^2 (3a6) + 2w U + V
     343             :    */
     344         414 :   U = gadd(gmul(a4,t), a3);
     345         414 :   U2 = gmul2n(U,1);
     346         414 :   V = gsubgs(gadd(gmul(a2,gsqr(t)), gmul(a1,t)), 1);
     347         414 :   W = gpowgs(t,3);
     348         414 :   av2 = avma;
     349        1938 :   while (mask > 1)
     350             :   { /* nold correct terms in w */
     351        1524 :     ulong i, nnew = nold << 1;
     352             :     GEN num, den, wnew, w2, w3;
     353        1524 :     if (mask & 1) nnew--;
     354        1524 :     mask >>= 1;
     355        1524 :     wnew = cgetg(nnew+2, t_SER);
     356        1524 :     wnew[1] = w[1];
     357        6492 :     for (i = 2; i < nold+2; i++) gel(wnew,i) = gel(w,i);
     358        6180 :     for (     ; i < nnew+2; i++) gel(wnew,i) = gen_0;
     359        1524 :     w = wnew;
     360        1524 :     w2 = gsqr(w); w3 = gmul(w2,w);
     361        1524 :     num = gadd(gmul(a6,w3), gadd(gmul(U,w2), gadd(gmul(V,w), W)));
     362        1524 :     den = gadd(gmul(a63,w2), gadd(gmul(w,U2), V));
     363             : 
     364        1524 :     w = gc_upto(av2, gsub(w, gdiv(num, den)));
     365        1524 :     nold = nnew;
     366             :   }
     367         414 :   return gc_GEN(av, w);
     368             : }
     369             : 
     370             : static GEN
     371         228 : ellformalpoint_i(GEN w, GEN wi)
     372         228 : { return mkvec2(gmul(pol_x(varn(w)),wi), gneg(wi)); }
     373             : 
     374             : /* t to [x,y] */
     375             : GEN
     376          60 : ellformalpoint(GEN e, long n, long v)
     377             : {
     378          60 :   pari_sp av = avma;
     379          60 :   GEN w = ellformalw(e, n, v), wi = ser_inv(w);
     380          60 :   return gc_GEN(av, ellformalpoint_i(w, wi));
     381             : }
     382             : 
     383             : static GEN
     384         294 : ellformaldifferential_i(GEN e, GEN w, GEN wi, GEN *px)
     385             : {
     386             :   GEN x, w1;
     387         294 :   if (gequal0(ell_get_a1(e)) && gequal0(ell_get_a3(e)))
     388             :   { /* dx/2y = dx * -w/2, avoid division */
     389         126 :     x = gmul(pol_x(varn(w)), wi);
     390         126 :     w1 = gmul(derivser(x), gneg(gmul2n(w,-1)));
     391             :   }
     392             :   else
     393             :   {
     394         168 :     GEN P = ellformalpoint_i(w, wi);
     395         168 :     x = gel(P,1);
     396         168 :     w1 = gdiv(derivser(x), ec_dmFdy_evalQ(e, P));
     397             :   }
     398         294 :   *px = x; return w1;
     399             : }
     400             : /* t to [ dx / (2y + a1 x + a3), x * ... ]*/
     401             : GEN
     402          60 : ellformaldifferential(GEN e, long n, long v)
     403             : {
     404          60 :   pari_sp av = avma;
     405          60 :   GEN w = ellformalw(e, n, v), wi = ser_inv(w), x;
     406          60 :   GEN w1 = ellformaldifferential_i(e, w, wi, &x);
     407          60 :   return gc_GEN(av, mkvec2(w1,gmul(x,w1)));
     408             : }
     409             : 
     410             : /* t to z, dz = w1 dt */
     411             : GEN
     412         126 : ellformallog(GEN e, long n, long v)
     413             : {
     414         126 :   pari_sp av = avma;
     415         126 :   GEN w = ellformalw(e, n, v), wi = ser_inv(w), x;
     416         126 :   GEN w1 = ellformaldifferential_i(e, w, wi, &x);
     417         126 :   return gc_upto(av, integser(w1));
     418             : }
     419             : /* z to t */
     420             : GEN
     421          60 : ellformalexp(GEN e, long n, long v)
     422             : {
     423          60 :   pari_sp av = avma;
     424          60 :   return gc_upto(av, serreverse(ellformallog(e,n,v)));
     425             : }
     426             : /* [log_p (sigma(t) / t), log_E t], as power series, d (log_E t) := w1 dt;
     427             :  * As a fonction of z: odd, = e.b2/12 * z + O(z^3).
     428             :  *   sigma(z) = ellsigma(e) exp(e.b2/24*z^2)
     429             :  * log_p(sigma(t)/t)=log(subst(sigma(z), x, ellformallog(e))/x) */
     430             : static GEN
     431         108 : ellformallogsigma_t(GEN e, long n)
     432             : {
     433         108 :   pari_sp av = avma;
     434         108 :   GEN w = ellformalw(e, n, 0), wi = ser_inv(w), t = pol_x(0);
     435         108 :   GEN x, s = ellformaldifferential_i(e, w, wi, &x);
     436         108 :   GEN f = gmul(s, gadd(integser(gmul(x,s)), gmul2n(ell_get_a1(e),-1)));
     437         108 :   return gc_GEN(av, mkvec2(integser( gsub(ginv(gneg(t)), f) ),
     438             :                                  integser(s)));
     439             : }
     440             : 
     441             : /* P-ADIC HEIGHTS */
     442             : 
     443             : /* m >= 0, T = b6^2, g4 = b6^2 - b4 b8, return g_m(xP) mod N, in Mazur-Tate's
     444             :  * notation (Duke 1991)*/
     445             : static GEN
     446        3516 : rellg(hashtable *H, GEN m, GEN T, GEN g4, GEN b8, GEN N)
     447             : {
     448             :   hashentry *h;
     449             :   GEN n, z, np2, np1, nm2, nm1, fp2, fp1, fm2, fm1, f;
     450             :   ulong m4;
     451        3516 :   if (abscmpiu(m, 4) <= 0) switch(itou(m))
     452             :   {
     453         168 :     case 0: return gen_0;
     454         456 :     case 1: return gen_1;
     455         540 :     case 2: return subiu(N,1);
     456         624 :     case 3: return b8;
     457         648 :     case 4: return g4;
     458             :   }
     459        1080 :   if ((h = hash_search(H, (void*)m))) return (GEN)h->val;
     460         588 :   m4 = mod4(m);
     461         588 :   n = shifti(m, -1); f   = rellg(H,n,T,g4,b8,N);
     462         588 :   np2 = addiu(n, 2); fp2 = rellg(H,np2,T,g4,b8,N);
     463         588 :   np1 = addiu(n, 1); fp1 = rellg(H,np1,T,g4,b8,N);
     464         588 :   nm2 = subiu(n, 2); fm2 = rellg(H,nm2,T,g4,b8,N);
     465         588 :   nm1 = subiu(n, 1); fm1 = rellg(H,nm1,T,g4,b8,N);
     466         588 :   if (odd(m4))
     467             :   {
     468         348 :     GEN t1 = Fp_mul(fp2, Fp_powu(f,3,N), N);
     469         348 :     GEN t2 = Fp_mul(fm1, Fp_powu(fp1,3,N), N);
     470         348 :     if (mpodd(n)) t2 = Fp_mul(T,t2,N); else t1 = Fp_mul(T,t1,N);
     471         348 :     z = Fp_sub(t1, t2, N);
     472             :   }
     473             :   else
     474             :   {
     475         240 :     GEN t1 = Fp_mul(fm2, Fp_sqr(fp1,N), N);
     476         240 :     GEN t2 = Fp_mul(fp2, Fp_sqr(fm1,N), N);
     477         240 :     z = Fp_mul(f, Fp_sub(t1, t2, N), N);
     478             :   }
     479         588 :   hash_insert(H, (void*)m, (void*)z);
     480         588 :   return z;
     481             : }
     482             : 
     483             : static GEN
     484         576 : addii3(GEN x, GEN y, GEN z) { return addii(x,addii(y,z)); }
     485             : static GEN
     486         384 : addii4(GEN x, GEN y, GEN z, GEN t) { return addii(x,addii3(y,z,t)); }
     487             : static GEN
     488         192 : addii5(GEN x, GEN y, GEN z, GEN t, GEN u) { return addii(x,addii4(y,z,t,u)); }
     489             : 
     490             : /* xP = [n,d] (corr. to n/d, coprime), such that the reduction of the point
     491             :  * P = [xP,yP] is non singular at all places. Return x([m] P) mod N as
     492             :  * [num,den] (coprime) */
     493             : static GEN
     494         192 : xmP(GEN e, GEN xP, GEN m, GEN N)
     495             : {
     496         192 :   pari_sp av = avma;
     497         192 :   ulong k = expi(m);
     498         192 :   hashtable *H = hash_create_GEN((5+k)*k, 1);
     499         192 :   GEN b2 = ell_get_b2(e), b4 = ell_get_b4(e), n = gel(xP,1), d = gel(xP,2);
     500         192 :   GEN b6 = ell_get_b6(e), b8 = ell_get_b8(e);
     501             :   GEN B4, B6, B8, T, g4;
     502         192 :   GEN d2 = Fp_sqr(d,N), d3 = Fp_mul(d2,d,N), d4 = Fp_sqr(d2,N);
     503         192 :   GEN n2 = Fp_sqr(n,N), n3 = Fp_mul(n2,n,N), n4 = Fp_sqr(n2,N);
     504         192 :   GEN nd = Fp_mul(n,d,N), n2d2 = Fp_sqr(nd,N);
     505         192 :   GEN b2nd = Fp_mul(b2,nd, N), b2n2d = Fp_mul(b2nd,n,N);
     506         192 :   GEN b6d3 = Fp_mul(b6,d3,N), g,gp1,gm1, C,D;
     507         192 :   B8 = addii5(muliu(n4,3), mulii(b2n2d,n), mulii(muliu(b4,3), n2d2),
     508             :               mulii(muliu(b6d3,3), n), mulii(b8,d4));
     509         192 :   B6 = addii4(muliu(n3,4), mulii(b2nd,n),
     510             :               shifti(mulii(b4,Fp_mul(n,d2,N)), 1), b6d3);
     511         192 :   B4 = addii3(muliu(n2,6), b2nd,  mulii(b4,d2));
     512         192 :   B4 = modii(B4,N);
     513         192 :   B6 = modii(B6,N);
     514         192 :   B8 = modii(B8,N);
     515         192 :   g4 = Fp_sub(sqri(B6), mulii(B4,B8), N);
     516         192 :   T = Fp_sqr(B6,N);
     517             : 
     518         192 :   g = rellg(H, m, T,g4,B8, N);
     519         192 :   gp1 = rellg(H, addiu(m,1), T,g4,B8, N);
     520         192 :   gm1 = rellg(H, subiu(m,1), T,g4,B8, N);
     521         192 :   C = Fp_sqr(g, N);
     522         192 :   D = Fp_mul(gp1,gm1, N);
     523         192 :   if (mpodd(m))
     524             :   {
     525          96 :     n = Fp_sub(mulii(C,n), mulii(D,B6), N);
     526          96 :     d = Fp_mul(C,d, N);
     527             :   }
     528             :   else
     529             :   {
     530          96 :     n = Fp_sub(Fp_mul(Fp_mul(B6,C,N), n, N), D, N);
     531          96 :     d = Fp_mul(Fp_mul(C,d,N), B6, N);
     532             :   }
     533         192 :   return gc_GEN(av, mkvec2(n,d));
     534             : }
     535             : /* given [n,d2], x = n/d2 (coprime, d2 = d^2), p | den,
     536             :  * return t = -x/y + O(p^v) */
     537             : static GEN
     538         108 : tfromx(GEN e, GEN x, GEN p, long v, GEN N, GEN *pd)
     539             : {
     540         108 :   GEN n = gel(x,1), d2 = gel(x,2), d;
     541             :   GEN a1, a3, b2, b4, b6, B, C, d4, d6, Y;
     542         108 :   if (!signe(n)) { *pd = gen_1; return zeropadic_shallow(p, v); }
     543         108 :   a1 = ell_get_a1(e);
     544         108 :   b2 = ell_get_b2(e);
     545         108 :   a3 = ell_get_a3(e);
     546         108 :   b4 = ell_get_b4(e);
     547         108 :   b6 = ell_get_b6(e);
     548         108 :   d = Qp_sqrt(cvtop(d2, p, v - Z_pval(d2,p)));
     549         108 :   if (!d) pari_err_BUG("ellpadicheight");
     550             :   /* Solve Y^2 = 4n^3 + b2 n^2 d2+ 2b4 n d2^2 + b6 d2^3,
     551             :    * Y = 2y + a1 n d + a3 d^3 */
     552         108 :   d4 = Fp_sqr(d2, N);
     553         108 :   d6 = Fp_mul(d4, d2, N);
     554         108 :   B = gmul(d, Fp_add(mulii(a1,n), mulii(a3,d2), N));
     555         108 :   C = mkpoln(4, utoipos(4), Fp_mul(b2, d2, N),
     556             :                 Fp_mul(shifti(b4,1), d4, N),
     557             :                 Fp_mul(b6,d6,N));
     558         108 :   C = FpX_eval(C, n, N);
     559         108 :   if (!signe(C))
     560           0 :     Y = zeropadic_shallow(p, v >> 1);
     561             :   else
     562         108 :     Y = Qp_sqrt(cvtop(C, p, v - Z_pval(C,p)));
     563         108 :   if (!Y) pari_err_BUG("ellpadicheight");
     564         108 :   *pd = d;
     565         108 :   return gdiv(gmulgs(gmul(n,d), -2), gsub(Y,B));
     566             : }
     567             : 
     568             : /* return minimal i s.t. -v_p(j+1) - log_p(j-1) + (j+1)*t >= v for all j>=i */
     569             : static long
     570         108 : logsigma_prec(GEN p, long v, long t)
     571             : {
     572         108 :   double log2p = dbllog2(p);
     573         108 :   long j, i = ceil((v - t) / (t - 2*M_LN2/(3*log2p)) + 0.01);
     574         108 :   if (absequaliu(p,2) && i < 5) i = 5;
     575             :   /* guaranteed to work, now optimize */
     576         156 :   for (j = i-1; j >= 2; j--)
     577             :   {
     578         156 :     if (- u_pval(j+1,p) - log2(j-1)/log2p + (j+1)*t + 0.01 < v) break;
     579          48 :     i = j;
     580             :   }
     581         108 :   if (j == 1)
     582             :   {
     583           0 :     if (- absequaliu(p,2) + 2*t + 0.01 >= v) i = 1;
     584             :   }
     585         108 :   return i;
     586             : }
     587             : /* return minimal i s.t. -v_p(j+1) + (j+1)*t >= v for all j>=i */
     588             : static long
     589           6 : log_prec(GEN p, long v, long t)
     590             : {
     591           6 :   double log2p = dbllog2(p);
     592           6 :   long j, i = ceil(v / (t - M_LN2/(2*log2p)) + 0.01);
     593             :   /* guaranteed to work, now optimize */
     594          24 :   for (j = i-1; j >= 1; j--)
     595             :   {
     596          24 :     if (- u_pval(j+1,p) + (j+1)*t + 0.01 < v) break;
     597          18 :     i = j;
     598             :   }
     599           6 :   return i;
     600             : }
     601             : 
     602             : /* P = rational point of exact denominator d. Is Q singular on E(Fp) ? */
     603             : static int
     604         156 : FpE_issingular(GEN E, GEN P, GEN d, GEN p)
     605             : {
     606         156 :   pari_sp av = avma;
     607             :   GEN t, x, y, a1, a2, a3, a4;
     608         156 :   if (ell_is_inf(E) || dvdii(d,p)) return 0; /* 0_E is smooth */
     609         150 :   P = Q_muli_to_int(P,d);
     610         150 :   x = gel(P,1);
     611         150 :   y = gel(P,2);
     612         150 :   a1 = ell_get_a1(E);
     613         150 :   a3 = ell_get_a3(E);
     614         150 :   t = addii(shifti(y,1), addii(mulii(a1,x), mulii(a3,d)));
     615         150 :   if (!dvdii(t,p)) return gc_bool(av, 0);
     616          30 :   a2 = ell_get_a2(E);
     617          30 :   a4 = ell_get_a4(E);
     618          30 :   d = Fp_inv(d, p);
     619          30 :   x = Fp_mul(x,d,p);
     620          30 :   y = Fp_mul(y,d,p);
     621          30 :   t = subii(mulii(a1,y), addii(a4, mulii(x, addii(gmul2n(a2,1), muliu(x,3)))));
     622          30 :   return gc_bool(av, dvdii(t,p));
     623             : }
     624             : /* E/Q, P on E(Q). Let g > 0 minimal such that the image of R = [g]P in a
     625             :  * minimal model is everywhere nonsingular; return [R,g] */
     626             : GEN
     627         120 : ellnonsingularmultiple(GEN e, GEN P)
     628             : {
     629         120 :   pari_sp av = avma;
     630         120 :   GEN ch, E = ellanal_globalred(e, &ch), NP, L, S, d, g = gen_1;
     631             :   long i, l;
     632         120 :   if (!checkellpt_i(P)) pari_err_TYPE("ellnonsingularmultiple",P);
     633         120 :   if (ell_is_inf(P)) retmkvec2(gcopy(P), gen_1);
     634         120 :   if (E != e) P = ellchangepoint(P, ch);
     635         120 :   S = obj_check(E, Q_GLOBALRED);
     636         120 :   NP = gmael(S,3,1);
     637         120 :   L = gel(S,4);
     638         120 :   l = lg(NP);
     639         120 :   d = Q_denom(P);
     640         270 :   for (i = 1; i < l; i++)
     641             :   {
     642         150 :     GEN G = gel(L,i), p = gel(NP,i);/* prime of bad reduction */
     643             :     long kod;
     644         150 :     if (!FpE_issingular(E, P, d, p)) continue;
     645          18 :     kod = itos(gel(G,2)); /* Kodaira type */
     646          18 :     if (kod >= 5) /* I_nu */
     647             :     {
     648           6 :       long nu = kod - 4;
     649           6 :       long n = minss(Q_pval(ec_dmFdy_evalQ(E,P), p), nu/2);
     650           6 :       nu /= ugcd(nu, n);
     651           6 :       g = muliu(g, nu);
     652           6 :       P = ellmul(E, P, utoipos(nu)); d = Q_denom(P);
     653          12 :     } else if (kod <= -5) /* I^*_nu */
     654             :     { /* either 2 or 4 */
     655           6 :       long nu = - kod - 4;
     656           6 :       P = elladd(E, P,P); d = Q_denom(P);
     657           6 :       g = shifti(g,1);
     658           6 :       if (odd(nu) && FpE_issingular(E, P, d, p))
     659             :       { /* it's 4 */
     660           6 :         P = elladd(E, P,P); d = Q_denom(P);
     661           6 :         g = shifti(g,1);
     662             :       }
     663             :     } else {
     664           6 :       GEN c = gel(G, 4); /* Tamagawa number at p */
     665           6 :       if (absequaliu(c, 4)) c = gen_2;
     666           6 :       P = ellmul(E, P, c); d = Q_denom(P);
     667           6 :       g = mulii(g, c);
     668             :     }
     669             :   }
     670         120 :   if (E != e) P = ellchangepointinv(P, ch);
     671         120 :   return gc_GEN(av, mkvec2(P,g));
     672             : }
     673             : 
     674             : GEN
     675         120 : ellpadicheight(GEN e, GEN p, long v0, GEN P)
     676             : {
     677         120 :   pari_sp av = avma;
     678             :   GEN N, H, h, t, ch, g, E, x, D, ls, lt, S, a,b;
     679             :   long v, vd;
     680             :   int is2;
     681         120 :   if (!checkellpt_i(P)) pari_err_TYPE("ellpadicheight",P);
     682         120 :   if (v0<=0) pari_err_DOMAIN("ellpadicheight","precision","<=",gen_0,stoi(v0));
     683         114 :   checkell_Q(e);
     684         114 :   if (typ(p) != t_INT) pari_err_TYPE("ellpadicheight",p);
     685         114 :   if (cmpiu(p,2) < 0) pari_err_PRIME("ellpadicheight",p);
     686         114 :   if (ellorder_Q(e,P)) return mkvec2(gen_0,gen_0);
     687         108 :   E = ellanal_globalred(e, &ch);
     688         108 :   if (E != e) P = ellchangepoint(P, ch);
     689         108 :   S = ellnonsingularmultiple(E, P);
     690         108 :   P = gel(S,1);
     691         108 :   g = gel(S,2);
     692         108 :   v = v0 + 2*Z_pval(g, p);
     693         108 :   is2 = absequaliu(p,2); if (is2) v += 2;
     694         108 :   x = Q_remove_denom(gel(P,1), &b);
     695         108 :   x = mkvec2(x, b? b: gen_1);
     696         108 :   vd = Z_pval(gel(x,2), p);
     697         108 :   if (!vd)
     698             :   { /* P not in kernel of reduction mod p */
     699          96 :     GEN d, m, X, Pp, Ep = ellinit(E, mkintmod(gen_0,p), 0);
     700          96 :     long w = v+2;
     701          96 :     Pp = RgV_to_FpV(P, p);
     702          96 :     if (lg(Ep) != 1)
     703          90 :       m = ellorder(Ep, Pp, NULL);
     704             :     else
     705             :     { /* E has bad reduction at p */
     706           6 :       m = ellcard(E, p);
     707           6 :       if (equalii(m, p)) pari_err_TYPE("ellpadicheight: additive reduction", E);
     708             :     }
     709          96 :     g = mulii(g,m);
     710             :     for(;;)
     711             :     {
     712         192 :       N = powiu(p, w);
     713         192 :       X = xmP(E, x, m, N);
     714         192 :       d = gel(X,2);
     715         192 :       if (!signe(d)) w <<= 1;
     716             :       else
     717             :       {
     718         192 :         vd = Z_pval(d, p);
     719         192 :         if (w >= v+2*vd + is2) break;
     720          96 :         w = v+2*vd + is2;
     721             :       }
     722             :     }
     723          96 :     x = X;
     724             :   }
     725             :   /* we will want t mod p^(v+vd) because of t/D in H later, and
     726             :    * we lose p^vd in tfromx because of sqrt(d) (p^(vd+1) if p=2)*/
     727         108 :   v += 2*vd + is2;
     728         108 :   N = powiu(p,v);
     729         108 :   t = tfromx(E, x, p, v, N, &D); /* D^2=denom(x)=x[2] */
     730         108 :   S = ellformallogsigma_t(E, logsigma_prec(p, v-vd, valp(t)) + 1);
     731         108 :   ls = ser2rfrac_i(gel(S,1)); /* log_p (sigma(T)/T) */
     732         108 :   lt = ser2rfrac_i(gel(S,2)); /* log_E (T) */
     733             :   /* evaluate our formal power series at t */
     734         108 :   H = gadd(poleval(ls, t), glog(gdiv(t, D), 0));
     735         108 :   h = gsqr(poleval(lt, t));
     736         108 :   g = sqri(g);
     737         108 :   a = gdiv(gmulgs(H,-2), g);
     738         108 :   b = gdiv(gneg(h), g);
     739         108 :   if (E != e)
     740             :   {
     741          18 :     GEN u = gel(ch,1), r = gel(ch,2);
     742          18 :     a = gdiv(gadd(a, gmul(r,b)), u);
     743          18 :     b = gmul(u,b);
     744             :   }
     745         108 :   H = mkvec2(a,b);
     746         108 :   gel(H,1) = precp_fix(gel(H,1),v0);
     747         108 :   gel(H,2) = precp_fix(gel(H,2),v0);
     748         108 :   return gc_GEN(av, H);
     749             : }
     750             : 
     751             : GEN
     752          12 : ellpadiclog(GEN E, GEN p, long n, GEN P)
     753             : {
     754          12 :   pari_sp av = avma;
     755             :   long vt;
     756             :   GEN t, x, y, L;
     757          12 :   if (!checkellpt_i(P)) pari_err_TYPE("ellpadiclog",P);
     758          12 :   if (ell_is_inf(P)) return gen_0;
     759          12 :   x = gel(P,1);
     760          12 :   y = gel(P,2); t = gneg(gdiv(x,y));
     761          12 :   vt = gvaluation(t, p); /* can be a t_INT, t_FRAC or t_PADIC */
     762          12 :   if (vt <= 0)
     763           6 :     pari_err_DOMAIN("ellpadiclog","P","not in the kernel of reduction at",p,P);
     764           6 :   L = ser2rfrac_i(ellformallog(E, log_prec(p, n, vt) + 1, 0));
     765           6 :   return gc_upto(av, poleval(L, cvtop(t, p, n)));
     766             : }
     767             : 
     768             : /* E/Qp has multiplicative reduction, Tate curve */
     769             : static GEN
     770          12 : ellpadics2_tate(GEN Ep, long n)
     771             : {
     772             :   pari_sp av;
     773          12 :   GEN u2 = ellQp_u2(Ep, n), q = ellQp_q(Ep, n), pn = padic_pd(q);
     774          12 :   GEN qm, s, b2 = ell_get_b2(Ep), v = vecfactoru_i(1, n);
     775             :   long m;
     776          12 :   qm = Fp_powers(padic_to_Fp(q, pn), n, pn);
     777          12 :   s = gel(qm, 2); av = avma;
     778          60 :   for (m = 2; m <= n; m++) /* sum sigma(m) q^m */
     779             :   {
     780          48 :     s = addii(s, mulii(gel(qm,m+1), usumdiv_fact(gel(v,m))));
     781          48 :     if ((m & 31) == 0) s = gc_INT(av, s);
     782             :   }
     783          12 :   s = subui(1, muliu(s,24));
     784          12 :   s = gdivgu(gsub(b2, gdiv(s,u2)), 12);
     785          12 :   return precp_fix(s,n);
     786             : }
     787             : 
     788             : GEN
     789         162 : ellpadicfrobenius(GEN E, ulong p, long n)
     790             : {
     791         162 :   checkell(E);
     792         162 :   if (p < 2) pari_err_DOMAIN("ellpadicfrobenius","p", "<", gen_2, utoipos(p));
     793         162 :   switch(ell_get_type(E))
     794             :   {
     795         150 :     case t_ELL_Q: break;
     796          12 :     case t_ELL_Qp: if (equaliu(ellQp_get_p(E), p)) break;
     797           6 :     default: pari_err_TYPE("ellpadicfrobenius", E);
     798             :   }
     799         156 :   return hyperellpadicfrobenius(ec_bmodel(E,0), p, n);
     800             : }
     801             : 
     802             : /* s2 = (b_2-E_2)/12 */
     803             : GEN
     804          30 : ellpadics2(GEN E, GEN p, long n)
     805             : {
     806          30 :   pari_sp av = avma;
     807             :   GEN l, F, a,b,d, ap;
     808             :   ulong pp;
     809          30 :   if (typ(p) != t_INT) pari_err_TYPE("ellpadics2",p);
     810          30 :   if (cmpis(p,2) < 0) pari_err_PRIME("ellpadics2",p);
     811          30 :   checkell(E);
     812          30 :   if (Q_pval(ell_get_j(E), p) < 0)
     813             :   {
     814             :     GEN Ep;
     815           6 :     if (ell_get_type(E) == t_ELL_Qp) Ep = E;
     816           0 :     else Ep = ellinit(E, zeropadic_shallow(p,n), 0);
     817           6 :     l = ellpadics2_tate(Ep, n);
     818           6 :     if (Ep != E) obj_free(Ep);
     819           6 :     return gc_GEN(av, l);
     820             :   }
     821          24 :   pp = itou(p);
     822          24 :   F = ellpadicfrobenius(E, pp, n);
     823          18 :   a = gcoeff(F,1,1);
     824          18 :   b = gcoeff(F,1,2);
     825          18 :   d = gcoeff(F,2,2); ap = gadd(a,d);
     826          18 :   if (valp(ap) > 0) pari_err_DOMAIN("ellpadics2","E","is supersingular at",p,E);
     827          18 :   if (pp == 2 || (pp <= 13 && n == 1)) /* 2sqrt(p) > p/2: ambiguity */
     828           0 :     ap = ellap(E,p);
     829             :   else
     830             :   { /* either 2sqrt(p) < p/2 or n > 1 and 2sqrt(p) < p^2/2 (since p!=2) */
     831          18 :     GEN q = pp <= 13? utoipos(pp * pp): p;
     832          18 :     ap = padic_to_Fp(ap, q);
     833          18 :     ap = Fp_center_i(ap, q, shifti(q,-1));
     834             :   }
     835          18 :   l = mspadic_unit_eigenvalue(ap, 2, p, n);
     836          18 :   return gc_upto(av, gdiv(b, gsub(l, a))); /* slope of eigenvector */
     837             : }
     838             : 
     839             : /* symbol and modular symbol space attached to E to later compute
     840             :  * ellpadicL(E,p,, s,,D) */
     841             : static GEN
     842          78 : ellpadicL_symbol(GEN E, GEN p, GEN s, GEN D)
     843             : {
     844             :   GEN s1, s2, ap;
     845             :   long sign;
     846          78 :   checkell(E);
     847          78 :   if (ell_get_type(E) != t_ELL_Q) pari_err_TYPE("ellpadicL",E);
     848          78 :   ap = ellap(E,p);
     849          78 :   if (D && typ(D) != t_INT) pari_err_TYPE("ellpadicL",D);
     850          78 :   if (D && !Z_isfundamental(D))
     851           0 :     pari_err_DOMAIN("ellpadicL", "isfundamental(D)", "=", gen_0, D);
     852          78 :   if (!D) D = gen_1;
     853          78 :   if (Z_pval(ellQ_get_N(E), p) >= 2)
     854           0 :     pari_err_IMPL("additive reduction in ellpadicL");
     855          78 :   mspadic_parse_chi(s, &s1,&s2);
     856          78 :   sign = signe(D); if (mpodd(s2)) sign = -sign;
     857          78 :   return shallowconcat(msfromell(E, sign), mkvec4(ap, p, s, D));
     858             : }
     859             : /* W an ellpadicL_symbol, initialize for ellpadicL(E,p,n,s,,D) */
     860             : static GEN
     861          78 : ellpadicL_init(GEN W, long n)
     862             : {
     863          78 :   GEN Wp, den, M = gel(W,1), xpm = gel(W,2), ap = gel(W,3), s = gel(W,5);
     864          78 :   long p = itos(gel(W,4)), D = itos(gel(W,6));
     865             : 
     866          78 :   xpm = Q_remove_denom(xpm,&den); if (!den) den = gen_1;
     867          78 :   n += Z_lval(den,p);
     868          78 :   Wp = mspadicinit(M, p, n, Z_lval(ap,p));
     869          78 :   return mkvec3(mspadicmoments(Wp,xpm,D), den, s);
     870             : }
     871             : /* v from ellpadicL_init, compute ellpadicL(E,p,n,s,r,D) */
     872             : static GEN
     873         108 : ellpadic_i(GEN v, long r)
     874             : {
     875         108 :   GEN oms = gel(v,1), den = gel(v,2), s = gel(v,3);
     876         108 :   return gdiv(mspadicL(oms,s,r), den);
     877             : }
     878             : GEN
     879          54 : ellpadicL(GEN E, GEN p, long n, GEN s, long r, GEN D)
     880             : {
     881          54 :   pari_sp av = avma;
     882             :   GEN W, v;
     883          54 :   if (r < 0) pari_err_DOMAIN("ellpadicL","r","<",gen_0,stoi(r));
     884          54 :   if (n <= 0) pari_err_DOMAIN("ellpadicL","precision","<=",gen_0,stoi(n));
     885          54 :   W = ellpadicL_symbol(E, p, s, D);
     886          54 :   v = ellpadicL_init(W, n);
     887          54 :   return gc_upto(av, ellpadic_i(v, r));
     888             : }
     889             : 
     890             : static long
     891          24 : torsion_order(GEN E) { GEN T = elltors(E); return itos(gel(T,1)); }
     892             : 
     893             : /* E given by a minimal model; D != 0. Compare Euler factor of L(E,(D/.),1)
     894             :  * with L(E^D,1). Return
     895             :  *   \prod_{p|D} (p-a_p(E)+eps_{E}(p)) / p,
     896             :  * where eps(p) = 0 if p | N_E and 1 otherwise */
     897             : static GEN
     898           6 : get_Euler(GEN E, GEN D)
     899             : {
     900           6 :   GEN a = gen_1, b = gen_1, P = gel(absZ_factor(D), 1);
     901           6 :   long i, l = lg(P);
     902          12 :   for (i = 1; i < l; i++)
     903             :   {
     904           6 :     GEN p = gel(P,i);
     905           6 :     a = mulii(a, ellcard(E, p));
     906           6 :     b = mulii(b, p);
     907             :   }
     908           6 :   return Qdivii(a, b);
     909             : }
     910             : GEN
     911          24 : ellpadicbsd(GEN E, GEN p, long n, GEN D)
     912             : {
     913          24 :   const long MAXR = 30;
     914          24 :   pari_sp av = avma;
     915          24 :   GEN D0, W, ED, tam, ND, C, apD, U = NULL;/*-Wall*/
     916             :   long r, vN;
     917          24 :   checkell(E);
     918          24 :   if (D && isint1(D)) D = NULL;
     919          24 :   D0 = ellminimaltwistcond(E); if (isint1(D0)) D0 = NULL;
     920          24 :   if (D0) { E = elltwist(E, D0); D = D? coredisc(mulii(D, D0)): D0; }
     921          24 :   W = ellpadicL_symbol(E, p, gen_0, D);
     922          24 :   ED = D? elltwist(E, D): E;
     923          24 :   ED = ellanal_globalred_all(ED, NULL, &ND, &tam);
     924          24 :   vN = Z_pval(ND, p); /* additive reduction ? */
     925          24 :   if (vN >= 2) pari_err_DOMAIN("ellpadicbsd","v_p(N(E_D))",">",gen_1,stoi(vN));
     926          24 :   if (n < 5) n = 5;
     927           0 :   for(;; n <<= 1)
     928           0 :   {
     929          24 :     pari_sp av2 = avma;
     930          24 :     GEN v = ellpadicL_init(W, n);
     931          54 :     for (r = 0; r < MAXR; r++)
     932             :     {
     933          54 :       U = ellpadic_i(v, r);
     934          54 :       if (!gequal0(U)) break;
     935             :     }
     936          24 :     if (r < MAXR) break;
     937           0 :     set_avma(av2);
     938             :   }
     939          24 :   apD = ellap(ED, p);
     940          24 :   if (typ(U) == t_COL)
     941             :   { /* p | a_p(E_D), frobenius on E_D */
     942           0 :     GEN F = mkmat22(gen_0, negi(p), gen_1, apD);
     943           0 :     U = RgM_RgC_mul(gpowgs(gsubsg(1, gdiv(F,p)), -2), U);
     944           0 :     settyp(U, t_VEC);
     945             :   }
     946          24 :   else if (dvdii(ND,p))
     947             :   {
     948          18 :     if (equalim1(apD)) /* divide by 1-1/a_p */
     949          12 :       U = gdivgu(U, 2);
     950             :     else
     951             :     { /* ap = 1 */
     952           6 :       GEN EDp = ellinit(ED, zeropadic_shallow(p,n), 0);
     953           6 :       U = gdiv(U, ellQp_L(EDp,n));
     954           6 :       obj_free(EDp);
     955             :     }
     956             :   }
     957             :   else
     958             :   {
     959           6 :     GEN a = mspadic_unit_eigenvalue(apD, 2, p, n);
     960           6 :     U = gmul(U, gpowgs(gsubsg(1, ginv(a)), -2));
     961             :   }
     962          24 :   C = mulii(tam, mpfact(r));
     963          24 :   if (D) C = gmul(C, get_Euler(ED, D));
     964          24 :   C = gdiv(sqru(torsion_order(ED)), C);
     965          24 :   if (D) obj_free(ED);
     966          24 :   return gc_GEN(av, mkvec2(utoi(r), gmul(U, C)));
     967             : }
     968             : 
     969             : GEN
     970           6 : ellpadicregulator(GEN E, GEN p, long n, GEN S)
     971             : {
     972           6 :   pari_sp av = avma;
     973           6 :   GEN FG = ellpadicheightmatrix(E,p,n,S); /* forbids additive reduction */
     974             :   /* [F,G]: height in basis [omega, eta] */
     975           6 :   GEN R, F = gel(FG,1), G = gel(FG,2), ap = ellap(E,p);
     976           6 :   if (dvdii(ap, p))
     977             :   { /* supersingular */
     978           0 :     GEN f = ellpadicfrobenius(E, itou(p), n);
     979           0 :     GEN x = gcoeff(f,1,1), y = gcoeff(f,2,1);
     980             :     /* [A,B]: regulator height in basis [omega, eta] */
     981           0 :     GEN A = det(F), B = det(gadd(F,G)), C;
     982           0 :     C = gdiv(gsub(B,A), y);
     983             :     /* R: regulator height in basis [omega, F.omega] */
     984           0 :     R = mkvec2(gsub(A, gmul(x,C)), C);
     985             :   }
     986             :   else
     987             :   {
     988             :     GEN s2;
     989           6 :     if (equali1(ap) && dvdii(ell_get_disc(E),p))
     990           6 :     { /* split multiplicative reduction */
     991           6 :       GEN Ep = ellinit(E, zeropadic_shallow(p,n), 0);
     992           6 :       GEN q = ellQp_q(Ep,n), u2 = ellQp_u2(Ep,n);
     993           6 :       s2 = ellpadics2_tate(Ep, n);
     994           6 :       s2 = gsub(s2, ginv(gmul(Qp_log(q), u2))); /*extended MW group contrib*/
     995           6 :       obj_free(Ep);
     996             :     }
     997             :     else
     998           0 :       s2 = ellpadics2(E,p,n);
     999           6 :     R = det( RgM_sub(F, RgM_Rg_mul(G,s2)) );
    1000             :   }
    1001           6 :   return gc_GEN(av, R);
    1002             : }

Generated by: LCOV version 1.16