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 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 - ellanal.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.10.0 lcov report (development 20459-9710128) Lines: 667 727 91.7 %
Date: 2017-04-27 05:33:52 Functions: 55 58 94.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2010  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation. It is distributed in the hope that it will be useful, but WITHOUT
       8             : ANY WARRANTY WHATSOEVER.
       9             : 
      10             : Check the License for details. You should have received a copy of it, along
      11             : with the package; see the file 'COPYING'. If not, write to the Free Software
      12             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      13             : 
      14             : /********************************************************************/
      15             : /**                                                                **/
      16             : /**                  L functions of elliptic curves                **/
      17             : /**                                                                **/
      18             : /********************************************************************/
      19             : #include "pari.h"
      20             : #include "paripriv.h"
      21             : 
      22             : struct baby_giant
      23             : {
      24             :   GEN baby, giant, sum;
      25             :   GEN bnd, rbnd;
      26             : };
      27             : 
      28             : /* Generic Buhler-Gross algorithm */
      29             : 
      30             : struct bg_data
      31             : {
      32             :   GEN E, N; /* ell, conductor */
      33             :   GEN bnd; /* t_INT; will need all an for n <= bnd */
      34             :   ulong rootbnd; /* sqrt(bnd) */
      35             :   GEN an; /* t_VECSMALL: cache of an, n <= rootbnd */
      36             :   GEN p;  /* t_VECSMALL: primes <= rootbnd */
      37             : };
      38             : 
      39             : typedef void bg_fun(void*el, GEN n, GEN a);
      40             : 
      41             : /* a = a_n, where p = bg->pp[i] divides n, and lasta = a_{n/p}.
      42             :  * Call fun(E, N, a_N), for all N, n | N, P^+(N) <= p, a_N != 0,
      43             :  * i.e. assumes that fun accumulates a_N * w(N) */
      44             : 
      45             : static void
      46     1670922 : gen_BG_add(void *E, bg_fun *fun, struct bg_data *bg, GEN n, long i, GEN a, GEN lasta)
      47             : {
      48     1670922 :   pari_sp av = avma;
      49             :   long j;
      50     1670922 :   ulong nn = itou_or_0(n);
      51     1670922 :   if (nn && nn <= bg->rootbnd) bg->an[nn] = itos(a);
      52             : 
      53     1670922 :   if (signe(a))
      54             :   {
      55      412440 :     fun(E, n, a);
      56      412440 :     j = 1;
      57             :   }
      58             :   else
      59     1258482 :     j = i;
      60     3337038 :   for(; j <= i; j++)
      61             :   {
      62     2649942 :     ulong p = bg->p[j];
      63     2649942 :     GEN nexta, pn = mului(p, n);
      64     4320864 :     if (cmpii(pn, bg->bnd) > 0) return;
      65     1666116 :     nexta = mulis(a, bg->an[p]);
      66     1666116 :     if (i == j && umodiu(bg->N, p)) nexta = subii(nexta, mului(p, lasta));
      67     1666116 :     gen_BG_add(E, fun, bg, pn, j, nexta, a);
      68     1666116 :     avma = av;
      69             :   }
      70             : }
      71             : 
      72             : static void
      73          60 : gen_BG_init(struct bg_data *bg, GEN E, GEN N, GEN bnd)
      74             : {
      75          60 :   bg->E = E;
      76          60 :   bg->N = N;
      77          60 :   bg->bnd = bnd;
      78          60 :   bg->rootbnd = itou(sqrtint(bnd));
      79          60 :   bg->p = primes_upto_zv(bg->rootbnd);
      80          60 :   bg->an = ellanQ_zv(E, bg->rootbnd);
      81          60 : }
      82             : 
      83             : static void
      84          60 : gen_BG_rec(void *E, bg_fun *fun, struct bg_data *bg)
      85             : {
      86          60 :   long i, j, lp = lg(bg->p)-1;
      87          60 :   GEN bndov2 = shifti(bg->bnd, -1);
      88          60 :   pari_sp av = avma, av2;
      89             :   GEN p;
      90             :   forprime_t S;
      91          60 :   (void)forprime_init(&S, utoipos(bg->p[lp]+1), bg->bnd);
      92          60 :   av2 = avma;
      93          60 :   if (DEBUGLEVEL)
      94           0 :     err_printf("1st stage, using recursion for p <= %ld\n", bg->p[lp]);
      95        4866 :   for (i = 1; i <= lp; i++)
      96             :   {
      97        4806 :     ulong pp = bg->p[i];
      98        4806 :     long ap = bg->an[pp];
      99        4806 :     gen_BG_add(E, fun, bg, utoipos(pp), i, stoi(ap), gen_1);
     100        4806 :     avma = av2;
     101             :   }
     102          60 :   if (DEBUGLEVEL) err_printf("2nd stage, looping for p <= %Ps\n", bndov2);
     103     1202364 :   while ( (p = forprime_next(&S)) )
     104             :   {
     105             :     long jmax;
     106     1202304 :     GEN ap = ellap(bg->E, p);
     107     1202304 :     pari_sp av3 = avma;
     108     1202304 :     if (!signe(ap)) continue;
     109             : 
     110      600612 :     jmax = itou( divii(bg->bnd, p) ); /* 2 <= jmax <= el->rootbound */
     111      600612 :     fun(E, p, ap);
     112     9392124 :     for (j = 2;  j <= jmax; j++)
     113             :     {
     114     8791512 :       long aj = bg->an[j];
     115             :       GEN a, n;
     116     8791512 :       if (!aj) continue;
     117     1324830 :       a = mulis(ap, aj);
     118     1324830 :       n = muliu(p, j);
     119     1324830 :       fun(E, n, a);
     120     1324830 :       avma = av3;
     121             :     }
     122      600612 :     avma = av2;
     123      600612 :     if (abscmpii(p, bndov2) >= 0) break;
     124             :   }
     125          60 :   if (DEBUGLEVEL) err_printf("3nd stage, looping for p <= %Ps\n", bg->bnd);
     126     1080018 :   while ( (p = forprime_next(&S)) )
     127             :   {
     128     1079898 :     GEN ap = ellap(bg->E, p);
     129     1079898 :     if (!signe(ap)) continue;
     130      539448 :     fun(E, p, ap);
     131      539448 :     avma = av2;
     132             :   }
     133          60 :   avma = av;
     134          60 : }
     135             : 
     136             : /******************************************************************
     137             :  *
     138             :  * L functions of elliptic curves
     139             :  * Pascal Molin (molin.maths@gmail.com) 2014
     140             :  *
     141             :  ******************************************************************/
     142             : 
     143             : struct lcritical
     144             : {
     145             :   GEN h;    /* real */
     146             :   long cprec; /* computation prec */
     147             :   long L; /* number of points */
     148             :   GEN  K; /* length of series */
     149             :   long real;
     150             : };
     151             : 
     152             : static double
     153         522 : logboundG0(long e, double aY)
     154             : {
     155             :   double cla, loggam;
     156         522 :   cla = 1 + 1/sqrt(aY);
     157         522 :   if (e) cla = ( cla + 1/(2*aY) ) / (2*sqrt(aY));
     158         522 :   loggam = (e) ? LOG2-aY : -aY + log( log( 1+1/aY) );
     159         522 :   return log(cla) + loggam;
     160             : }
     161             : 
     162             : static void
     163         522 : param_points(GEN N, double Y, double tmax, long bprec, long *cprec, long *L,
     164             :              GEN *K, double *h)
     165             : {
     166             :   double D, a, aY, X, logM;
     167         522 :   long d = 2, w = 1;
     168         522 :   tmax *= d;
     169         522 :   D = bprec * LOG2 + M_PI/4*tmax + 2;
     170         522 :   *cprec = nbits2prec(ceil(D / LOG2) + 5);
     171         522 :   a = 2 * M_PI / sqrt(gtodouble(N));
     172         522 :   aY = a * cos(M_PI/2*Y);
     173         522 :   logM = 2*LOG2 + logboundG0(w+1, aY) + tmax * Y * M_PI/2;
     174         522 :   *h = ( 2 * M_PI * M_PI / 2 * Y ) / ( D + logM );
     175         522 :   X = log( D / a);
     176         522 :   *L = ceil( X / *h);
     177         522 :   *K = ceil_safe(dbltor( D / a ));
     178         522 : }
     179             : 
     180             : static GEN
     181         492 : vecF2_lk(GEN E, GEN K, GEN rbnd, GEN Q, GEN sleh, long prec)
     182             : {
     183         492 :   pari_sp av = avma, av2;
     184         492 :   long l, L  = lg(K)-1;
     185         492 :   GEN a = ellanQ_zv(E, itos(gel(K,1)));
     186         492 :   GEN S = cgetg(L+1, t_VEC);
     187       18522 :   for (l = 1; l <= L; l++)
     188       18030 :     gel(S,l) = cgetr(prec);
     189         492 :   av2 = avma;
     190       18522 :   for (l = 1; l <= L; ++l)
     191             :   {
     192             :     GEN e1, Sl;
     193             :     long aB, b, A, B;
     194             :     GEN z, zB;
     195             :     pari_sp av3;
     196       18030 :     long Kl = itou(gel(K,l));
     197             :     /* FIXME: could reduce prec here (useful for large prec) */
     198       18030 :     e1 = gel(Q, l);
     199       18030 :     Sl = real_0(prec);;
     200             :     /* baby-step giant step */
     201       18030 :     A = rbnd[l]; B = A;
     202       18030 :     z = powersr(e1, B); zB = gel(z, B+1);
     203       18030 :     av3 = avma;
     204      250296 :     for (aB = A*B; aB >= 0; aB -= B)
     205             :     {
     206      232266 :       GEN s = real_0(prec); /* could change also prec here */
     207    13477170 :       for (b = B; b > 0; --b)
     208             :       {
     209    13244904 :         long k = aB+b;
     210    13244904 :         if (k <= Kl && a[k]) s = addrr(s, mulsr(a[k], gel(z, b+1)));
     211    13244904 :         if (gc_needed(av3, 1))
     212          60 :           gerepileall(av3, 2, &s, &Sl);
     213             :       }
     214      232266 :       Sl = addrr(mulrr(Sl, zB), s);
     215             :     }
     216       18030 :     affrr(mulrr(Sl, gel(sleh,l)), gel(S, l)); /* to avoid copying all S */
     217       18030 :     avma = av2;
     218             :   }
     219         492 :   return gerepilecopy(av, S);
     220             : }
     221             : 
     222             : /* Return C, C[i][j] = Q[j]^i, i = 1..nb */
     223             : static void
     224          30 : baby_init(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec)
     225             : {
     226          30 :   long i, j, l = lg(Q);
     227             :   GEN R, C, r0;
     228          30 :   C = cgetg(l,t_VEC);
     229        1044 :   for (i = 1; i < l; ++i)
     230        1014 :     gel(C, i) = powersr(gel(Q, i), rbnd[i]);
     231          30 :   R = cgetg(l,t_VEC);
     232          30 :   r0 = real_0(prec);
     233        1044 :   for (i = 1; i < l; ++i)
     234             :   {
     235        1014 :     gel(R, i) = cgetg(rbnd[i]+1, t_VEC);
     236        1014 :     gmael(R, i, 1) = cgetr(prec);
     237        1014 :     affrr(gmael(C, i, 2),gmael(R, i, 1));
     238       68772 :     for (j = 2; j <= rbnd[i]; j++)
     239             :     {
     240       67758 :       gmael(R, i, j) = cgetr(prec);
     241       67758 :       affrr(r0, gmael(R, i, j));
     242             :     }
     243             :   }
     244          30 :   bb->baby = C; bb->giant = R;
     245          30 :   bb->bnd = bnd; bb->rbnd = rbnd;
     246          30 : }
     247             : 
     248             : static long
     249         522 : baby_size(GEN rbnd, long Ks, long prec)
     250             : {
     251         522 :   long i, s, m, l = lg(rbnd);
     252       19566 :   for (s = 0, i = 1; i < l; ++i)
     253       19044 :     s += rbnd[i];
     254         522 :   m = 2*s*prec + 3*l + s;
     255         522 :   if (DEBUGLEVEL)
     256           0 :     err_printf("ellL1: BG_add: %ld words, ellan: %ld words\n", m, Ks);
     257         522 :   return m;
     258             : }
     259             : 
     260             : static void
     261      389976 : ellL1_add(void *E, GEN n, GEN a)
     262             : {
     263      389976 :   pari_sp av = avma;
     264      389976 :   struct baby_giant *bb = (struct baby_giant*) E;
     265      389976 :   long j, l = lg(bb->giant);
     266     1965312 :   for (j = 1; j < l; j++)
     267     1965312 :     if (cmpii(n, gel(bb->bnd,j)) <= 0)
     268             :     {
     269     1575336 :       ulong r, q = udiviu_rem(n, bb->rbnd[j], &r);
     270     1575336 :       GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j);
     271     1575336 :       affrr(addrr(gel(giant, q+1), mulri(gel(baby, r+1), a)), gel(giant, q+1));
     272     1575336 :       avma = av;
     273      389976 :     } else break;
     274      389976 : }
     275             : 
     276             : static GEN
     277          30 : vecF2_lk_bsgs(GEN E, GEN bnd, GEN rbnd, GEN Q, GEN sleh, GEN N, long prec)
     278             : {
     279          30 :   pari_sp av = avma;
     280             :   struct bg_data bg;
     281             :   struct baby_giant bb;
     282          30 :   long k, L = lg(bnd)-1;
     283             :   GEN S;
     284          30 :   baby_init(&bb, Q, bnd, rbnd, prec);
     285          30 :   gen_BG_init(&bg, E, N, gel(bnd,1));
     286          30 :   gen_BG_rec((void*) &bb, ellL1_add, &bg);
     287          30 :   S = cgetg(L+1, t_VEC);
     288        1044 :   for (k = 1; k <= L; ++k)
     289             :   {
     290        1014 :     pari_sp av2 = avma;
     291        1014 :     long j, g = rbnd[k];
     292        1014 :     GEN giant = gmael(bb.baby, k, g+1);
     293        1014 :     GEN Sl = real_0(prec);
     294       69786 :     for (j = g; j >=1; j--)
     295       68772 :       Sl = addrr(mulrr(Sl, giant), gmael(bb.giant,k,j));
     296        1014 :     gel(S, k) = gerepileupto(av2, mulrr(gel(sleh,k), Sl));
     297             :   }
     298          30 :   return gerepileupto(av, S);
     299             : }
     300             : 
     301             : static GEN
     302         522 : vecF(struct lcritical *C, GEN E)
     303             : {
     304         522 :   pari_sp av = avma, av2;
     305         522 :   long prec = C->cprec, Ks = itos_or_0(C->K), l, L = C->L;
     306         522 :   GEN N = ellQ_get_N(E);
     307         522 :   GEN PiN = shiftr(divrr(mppi(prec), gsqrt(N, prec)), 1);
     308         522 :   GEN eh = mpexp(C->h), elh = powersr(eh, L-1), sleh = elh;
     309             :   GEN Q, bnd, rbnd, vec;
     310         522 :   rbnd = cgetg(L+1, t_VECSMALL);
     311         522 :   av2 = avma;
     312         522 :   bnd = cgetg(L+1, t_VEC);
     313         522 :   Q  = cgetg(L+1, t_VEC);
     314       19566 :   for (l = 1; l <= L; ++l)
     315             :   {
     316       19044 :     gel(bnd,l) = l==1 ? C->K: ceil_safe(divir(C->K, gel(elh, l)));
     317       19044 :     rbnd[l] = itou(sqrtint(gel(bnd,l)))+1;
     318       19044 :     gel(Q, l) = mpexp(mulrr(negr(PiN), gel(elh, l)));
     319             :   }
     320         522 :   gerepileall(av2, 2, &bnd, &Q);
     321         522 :   if (Ks && baby_size(rbnd, Ks, prec) > (Ks>>1))
     322         492 :     vec = vecF2_lk(E, bnd, rbnd, Q, sleh, prec);
     323             :   else
     324          30 :     vec = vecF2_lk_bsgs(E, bnd, rbnd, Q, sleh, N, prec);
     325         522 :   return gerepileupto(av, vec);
     326             : }
     327             : 
     328             : /* ************************************************************************
     329             :  *
     330             :  * Compute Lambda function by Fourier inversion
     331             :  *
     332             :  */
     333             : 
     334             : static GEN
     335         546 : glambda(GEN t, GEN vec, GEN h, long real, long prec)
     336             : {
     337             :   GEN ehs, elhs;
     338             :   GEN r;
     339         546 :   long L = lg(vec)-1, l;
     340             :   /* assume vec is a grid */
     341         546 :   ehs = gexp(gmul(gen_I(),gmul(h, t)), prec);
     342         546 :   elhs = (real == 1) ? gen_1 : mkcomplex(gen_0, gen_m1);
     343         546 :   r = gmul2n(greal(gmul(greal(gel(vec, 1)), elhs)), -1);
     344             :   /* FIXME: summing backward may be more stable */
     345       21390 :   for (l = 2; l <= L; ++l)
     346             :   {
     347       20844 :     elhs = gmul(elhs, ehs);
     348       20844 :     r = gadd(r, greal(gmul(gel(vec, l), elhs)));
     349             :   }
     350         546 :   return gmul(mulsr(4, h), r);
     351             : }
     352             : 
     353             : static GEN
     354         522 : Lpoints(struct lcritical *C, GEN e, GEN tmax, long bprec)
     355             : {
     356         522 :   double h = 0, Y = .97;
     357         522 :   GEN N = ellQ_get_N(e);
     358         522 :   param_points(N, Y, gtodouble(tmax), bprec, &C->cprec, &C->L, &C->K, &h);
     359         522 :   C->real = ellrootno_global(e);
     360         522 :   C->h = rtor(dbltor(h), C->cprec);
     361         522 :   return vecF(C, e);
     362             : }
     363             : 
     364             : static GEN
     365         546 : Llambda(GEN vec, struct lcritical *C, GEN t, long prec)
     366             : {
     367         546 :   GEN lambda = glambda(gprec_w(t, C->cprec), vec, C->h, C->real, C->cprec);
     368         546 :   return gprec_w(lambda, prec);
     369             : }
     370             : 
     371             : /* 2*(2*Pi)^(-s)*gamma(s)*N^(s/2); */
     372             : static GEN
     373         546 : ellgammafactor(GEN N, GEN s, long prec)
     374             : {
     375         546 :   GEN Ns2 = gpow(N, gdivgs(s, 2), prec);
     376         546 :   Ns2 = gmul(Ns2, gmulsg(2, gpow(shiftr(mppi(prec), 1), gneg(s), prec)));
     377         546 :   return gmul(Ns2, ggamma(s, prec));
     378             : }
     379             : 
     380             : static GEN
     381         546 : ellL1_eval(GEN e, GEN vec, struct lcritical *C, GEN t, long prec)
     382             : {
     383         546 :   GEN gam = ellgammafactor(ellQ_get_N(e), gaddgs(gmul(gen_I(),t), 1), prec);
     384         546 :   return gdiv(Llambda(vec, C, t, prec), gam);
     385             : }
     386             : 
     387             : static GEN
     388         546 : ellL1_der(GEN e, GEN vec, struct lcritical *C, GEN t, long der, long prec)
     389             : {
     390         546 :   GEN r = polcoeff0(ellL1_eval(e, vec, C, t, prec), der, 0);
     391         546 :   r = gdiv(r,gpowgs(gen_I(), C->real == 1 ? der: der-1));
     392         546 :   return gmul(r, mpfact(der));
     393             : }
     394             : 
     395             : GEN
     396         510 : ellL1_bitprec(GEN E, long r, long bitprec)
     397             : {
     398         510 :   pari_sp av = avma;
     399             :   struct lcritical C;
     400         510 :   long prec = nbits2prec(bitprec);
     401             :   GEN e, vec, t;
     402         510 :   if (r < 0)
     403           6 :     pari_err_DOMAIN("ellL1", "derivative order", "<", gen_0, stoi(r));
     404         504 :   e = ellanal_globalred(E, NULL);
     405         504 :   if (r == 0 && ellrootno_global(e) < 0) { avma = av; return gen_0; }
     406         492 :   vec = Lpoints(&C, e, gen_0, bitprec);
     407         492 :   t = r ? scalarser(gen_1, 0, r):  zeroser(0, 0);
     408         492 :   setvalp(t, 1);
     409         492 :   return gerepileupto(av, ellL1_der(e, vec, &C, t, r, prec));
     410             : }
     411             : 
     412             : GEN
     413         330 : ellL1(GEN E, long r, long prec) { return ellL1_bitprec(E, r, prec2nbits(prec)); }
     414             : 
     415             : GEN
     416          30 : ellanalyticrank_bitprec(GEN E, GEN eps, long bitprec)
     417             : {
     418          30 :   pari_sp av = avma, av2;
     419          30 :   long prec = nbits2prec(bitprec);
     420             :   struct lcritical C;
     421             :   pari_timer ti;
     422             :   GEN e, vec;
     423             :   long rk;
     424          30 :   if (DEBUGLEVEL) timer_start(&ti);
     425          30 :   if (!eps)
     426          30 :     eps = real2n(-bitprec/2+1, DEFAULTPREC);
     427             :   else
     428           0 :     if (typ(eps) != t_REAL) {
     429           0 :       eps = gtofp(eps, DEFAULTPREC);
     430           0 :       if (typ(eps) != t_REAL) pari_err_TYPE("ellanalyticrank", eps);
     431             :     }
     432          30 :   e = ellanal_globalred(E, NULL);
     433          30 :   vec = Lpoints(&C, e, gen_0, bitprec);
     434          30 :   if (DEBUGLEVEL) timer_printf(&ti, "init L");
     435          30 :   av2 = avma;
     436          54 :   for (rk = C.real>0 ? 0: 1;  ; rk += 2)
     437             :   {
     438             :     GEN Lrk;
     439          54 :     GEN t = rk ? scalarser(gen_1, 0, rk):  zeroser(0, 0);
     440          54 :     setvalp(t, 1);
     441          54 :     Lrk = ellL1_der(e, vec, &C, t, rk, prec);
     442          54 :     if (DEBUGLEVEL) timer_printf(&ti, "L^(%ld)=%Ps", rk, Lrk);
     443          54 :     if (abscmprr(Lrk, eps) > 0)
     444          60 :       return gerepilecopy(av, mkvec2(stoi(rk), Lrk));
     445          24 :     avma = av2;
     446          24 :   }
     447             : }
     448             : 
     449             : GEN
     450           0 : ellanalyticrank(GEN E, GEN eps, long prec)
     451             : {
     452           0 :   return ellanalyticrank_bitprec(E, eps, prec2nbits(prec));
     453             : }
     454             : 
     455             : /*        Heegner point computation
     456             : 
     457             :    This section is a C version by Bill Allombert of a GP script by
     458             :    Christophe Delaunay which was based on a GP script by John Cremona.
     459             :    Reference: Henri Cohen's book GTM 239.
     460             : */
     461             : 
     462             : static void
     463           0 : heegner_L1_bg(void*E, GEN n, GEN a)
     464             : {
     465           0 :   struct baby_giant *bb = (struct baby_giant*) E;
     466           0 :   long j, l = lg(bb->giant);
     467           0 :   for (j = 1; j < l; j++)
     468           0 :     if (cmpii(n, gel(bb->bnd,j)) <= 0)
     469             :     {
     470           0 :       ulong r, q = udiviu_rem(n, bb->rbnd[j], &r);
     471           0 :       GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j);
     472           0 :       gaffect(gadd(gel(giant, q+1), gdiv(gmul(gel(baby, r+1), a), n)), gel(giant, q+1));
     473             :     }
     474           0 : }
     475             : 
     476             : static void
     477     2487354 : heegner_L1(void*E, GEN n, GEN a)
     478             : {
     479     2487354 :   struct baby_giant *bb = (struct baby_giant*) E;
     480     2487354 :   long j, l = lg(bb->giant);
     481    13665282 :   for (j = 1; j < l; j++)
     482    11177928 :     if (cmpii(n, gel(bb->bnd,j)) <= 0)
     483             :     {
     484     9122214 :       ulong r, q = udiviu_rem(n, bb->rbnd[j], &r);
     485     9122214 :       GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j);
     486     9122214 :       GEN ex = mulreal(gel(baby, r+1), gel(giant, q+1));
     487     9122214 :       affrr(addrr(gel(bb->sum, j), divri(mulri(ex, a), n)), gel(bb->sum, j));
     488             :     }
     489     2487354 : }
     490             : /* Return C, C[i][j] = Q[j]^i, i = 1..nb */
     491             : static void
     492           0 : baby_init2(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec)
     493             : {
     494           0 :   long i, j, l = lg(Q);
     495             :   GEN R, C, r0;
     496           0 :   C = cgetg(l,t_VEC);
     497           0 :   for (i = 1; i < l; ++i)
     498           0 :     gel(C, i) = gpowers(gel(Q, i), rbnd[i]);
     499           0 :   R = cgetg(l,t_VEC);
     500           0 :   r0 = mkcomplex(real_0(prec),real_0(prec));
     501           0 :   for (i = 1; i < l; ++i)
     502             :   {
     503           0 :     gel(R, i) = cgetg(rbnd[i]+1, t_VEC);
     504           0 :     gmael(R, i, 1) = cgetc(prec);
     505           0 :     gaffect(gmael(C, i, 2),gmael(R, i, 1));
     506           0 :     for (j = 2; j <= rbnd[i]; j++)
     507             :     {
     508           0 :       gmael(R, i, j) = cgetc(prec);
     509           0 :       gaffect(r0, gmael(R, i, j));
     510             :     }
     511             :   }
     512           0 :   bb->baby = C; bb->giant = R;
     513           0 :   bb->bnd = bnd; bb->rbnd = rbnd;
     514           0 : }
     515             : 
     516             : /* Return C, C[i][j] = Q[j]^i, i = 1..nb */
     517             : static void
     518          30 : baby_init3(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec)
     519             : {
     520          30 :   long i, l = lg(Q);
     521             :   GEN R, C, S;
     522          30 :   C = cgetg(l,t_VEC);
     523         144 :   for (i = 1; i < l; ++i)
     524         114 :     gel(C, i) = gpowers(gel(Q, i), rbnd[i]);
     525          30 :   R = cgetg(l,t_VEC);
     526         144 :   for (i = 1; i < l; ++i)
     527         114 :     gel(R, i) = gpowers(gmael(C, i, 1+rbnd[i]), rbnd[i]);
     528          30 :   S = cgetg(l,t_VEC);
     529         144 :   for (i = 1; i < l; ++i)
     530             :   {
     531         114 :     gel(S, i) = cgetr(prec);
     532         114 :     affrr(real_i(gmael(C, i, 2)), gel(S, i));
     533             :   }
     534          30 :   bb->baby = C; bb->giant = R; bb->sum = S;
     535          30 :   bb->bnd = bnd; bb->rbnd = rbnd;
     536          30 : }
     537             : 
     538             : /* ymin a t_REAL */
     539             : static GEN
     540          30 : heegner_psi(GEN E, GEN N, GEN points, long bitprec)
     541             : {
     542          30 :   pari_sp av = avma, av2;
     543             :   struct baby_giant bb;
     544             :   struct bg_data bg;
     545          30 :   long k, L = lg(points)-1, prec = nbits2prec(bitprec)+EXTRAPRECWORD;
     546          30 :   GEN  Q, pi2 = Pi2n(1, prec), bnd, rbnd;
     547             :   long l;
     548          30 :   GEN B = divrr(mulur(bitprec,mplog2(DEFAULTPREC)), pi2);
     549             :   GEN bndmax;
     550          30 :   rbnd = cgetg(L+1, t_VECSMALL);
     551          30 :   av2 = avma;
     552          30 :   bnd = cgetg(L+1, t_VEC);
     553          30 :   Q  = cgetg(L+1, t_VEC);
     554         144 :   for (l = 1; l <= L; ++l)
     555             :   {
     556         114 :     gel(bnd,l) = ceil_safe(divrr(B,gimag(gel(points, l))));
     557         114 :     rbnd[l] = itou(sqrtint(gel(bnd,l)))+1;
     558         114 :     gel(Q, l) = expIxy(pi2, gel(points, l), prec);
     559             :   }
     560          30 :   gerepileall(av2, 2, &bnd, &Q);
     561          30 :   bndmax = gel(bnd,vecindexmax(bnd));
     562          30 :   gen_BG_init(&bg, E, N, bndmax);
     563          30 :   if (bitprec >= 1900)
     564             :   {
     565             :     GEN S;
     566           0 :     baby_init2(&bb, Q, bnd, rbnd, prec);
     567           0 :     gen_BG_rec((void*)&bb, heegner_L1_bg, &bg);
     568           0 :     S = cgetg(L+1, t_VEC);
     569           0 :     for (k = 1; k <= L; ++k)
     570             :     {
     571           0 :       pari_sp av2 = avma;
     572           0 :       long j, g = rbnd[k];
     573           0 :       GEN giant = gmael(bb.baby, k, g+1);
     574           0 :       GEN Sl = real_0(prec);
     575           0 :       for (j = g; j >=1; j--)
     576           0 :         Sl = gadd(gmul(Sl, giant), gmael(bb.giant,k,j));
     577           0 :       gel(S, k) = gerepileupto(av2, real_i(Sl));
     578             :     }
     579           0 :     return gerepileupto(av, S);
     580             :   }
     581             :   else
     582             :   {
     583          30 :     baby_init3(&bb, Q, bnd, rbnd, prec);
     584          30 :     gen_BG_rec((void*)&bb, heegner_L1, &bg);
     585          30 :     return gerepilecopy(av, bb.sum);
     586             :   }
     587             : }
     588             : 
     589             : /*Returns lambda_bad list for one prime p, nv = localred(E, p) */
     590             : static GEN
     591          72 : lambda1(GEN E, GEN nv, GEN p, long prec)
     592             : {
     593             :   pari_sp av;
     594             :   GEN res, lp;
     595          72 :   long kod = itos(gel(nv, 2));
     596          72 :   if (kod==2 || kod ==-2) return cgetg(1,t_VEC);
     597          72 :   av = avma; lp = glog(p, prec);
     598          72 :   if (kod > 4)
     599             :   {
     600          12 :     long n = Z_pval(ell_get_disc(E), p);
     601          12 :     long j, m = kod - 4, nl = 1 + (m >> 1L);
     602          12 :     res = cgetg(nl, t_VEC);
     603          30 :     for (j = 1; j < nl; j++)
     604          18 :       gel(res, j) = gmul(lp, gsubgs(gdivgs(sqru(j), n), j)); /* j^2/n - j */
     605             :   }
     606          60 :   else if (kod < -4)
     607           6 :     res = mkvec2(negr(lp), shiftr(mulrs(lp, kod), -2));
     608             :   else
     609             :   {
     610          54 :     const long lam[] = {8,9,0,6,0,0,0,3,4};
     611          54 :     long m = -lam[kod+4];
     612          54 :     res = mkvec(divru(mulrs(lp, m), 6));
     613             :   }
     614          72 :   return gerepilecopy(av, res);
     615             : }
     616             : 
     617             : static GEN
     618          30 : lambdalist(GEN E, long prec)
     619             : {
     620          30 :   pari_sp ltop = avma;
     621          30 :   GEN glob = ellglobalred(E), plist = gmael(glob,4,1), L = gel(glob,5);
     622          30 :   GEN res, v, D = ell_get_disc(E);
     623          30 :   long i, j, k, l, m, n, np = lg(plist), lr = 1;
     624          30 :   v = cgetg(np, t_VEC);
     625         108 :   for (j = 1, i = 1 ; j < np; ++j)
     626             :   {
     627          78 :     GEN p = gel(plist, j);
     628          78 :     if (dvdii(D, sqri(p)))
     629             :     {
     630          72 :       GEN la = lambda1(E, gel(L,j), p, prec);
     631          72 :       gel(v, i++) = la;
     632          72 :       lr *= lg(la);
     633             :     }
     634             :   }
     635          30 :   np = i;
     636          30 :   res = cgetg(lr+1, t_VEC);
     637          30 :   gel(res, 1) = gen_0; n = 1; m = 1;
     638         102 :   for (j = 1; j < np; ++j)
     639             :   {
     640          72 :     GEN w = gel(v, j);
     641          72 :     long lw = lg(w);
     642         252 :     for (k = 1; k <= n; k++)
     643             :     {
     644         180 :       GEN t = gel(res, k);
     645         372 :       for (l = 1, m = n; l < lw; l++, m+=n)
     646         192 :         gel(res, k + m) = mpadd(t, gel(w, l));
     647             :     }
     648          72 :     n = m;
     649             :   }
     650          30 :   return gerepilecopy(ltop, res);
     651             : }
     652             : 
     653             : /* P a t_INT or t_FRAC, return its logarithmic height */
     654             : static GEN
     655          60 : heightQ(GEN P, long prec)
     656             : {
     657             :   long s;
     658          60 :   if (typ(P) == t_FRAC)
     659             :   {
     660          24 :     GEN a = gel(P,1), b = gel(P,2);
     661          24 :     P = abscmpii(a,b) > 0 ? a: b;
     662             :   }
     663          60 :   s = signe(P);
     664          60 :   if (!s) return real_0(prec);
     665          48 :   if (s < 0) P = absi(P);
     666          48 :   return glog(P, prec);
     667             : }
     668             : 
     669             : /* t a t_INT or t_FRAC, returns max(1, log |t|), returns a t_REAL */
     670             : static GEN
     671          84 : logplusQ(GEN t, long prec)
     672             : {
     673          84 :   if (typ(t) == t_INT)
     674             :   {
     675          36 :     if (!signe(t)) return real_1(prec);
     676          24 :     if (signe(t) < 0) t = absi(t);
     677             :   }
     678             :   else
     679             :   {
     680          48 :     GEN a = gel(t,1), b = gel(t,2);
     681          48 :     if (abscmpii(a, b) < 0) return real_1(prec);
     682          24 :     if (signe(a) < 0) t = gneg(t);
     683             :   }
     684          48 :   return glog(t, prec);
     685             : }
     686             : 
     687             : /* See GTM239, p532, Th 8.1.18
     688             :  * Return M such that h_naive <= M */
     689             : static GEN
     690          60 : hnaive_max(GEN ell, GEN ht)
     691             : {
     692          60 :   const long prec = LOWDEFAULTPREC; /* minimal accuracy */
     693          60 :   GEN b2     = ell_get_b2(ell), j = ell_get_j(ell);
     694          60 :   GEN logd   = glog(absi(ell_get_disc(ell)), prec);
     695          60 :   GEN logj   = logplusQ(j, prec);
     696          60 :   GEN hj     = heightQ(j, prec);
     697         144 :   GEN logb2p = signe(b2)? addrr(logplusQ(gdivgs(b2, 12),prec), mplog2(prec))
     698          84 :                         : real_1(prec);
     699          60 :   GEN mu     = addrr(divru(addrr(logd, logj),6), logb2p);
     700          60 :   return addrs(addrr(addrr(ht, divru(hj,12)), mu), 2);
     701             : }
     702             : 
     703             : static GEN
     704         114 : qfb_root(GEN Q, GEN vDi)
     705             : {
     706         114 :   GEN a2 = shifti(gel(Q, 1),1), b = gel(Q, 2);
     707         114 :   return mkcomplex(gdiv(negi(b),a2),divri(vDi,a2));
     708             : }
     709             : 
     710             : static GEN
     711       20520 : qimag2(GEN Q)
     712             : {
     713       20520 :   pari_sp av = avma;
     714       20520 :   GEN z = gdiv(negi(qfb_disc(Q)), shifti(sqri(gel(Q, 1)),2));
     715       20520 :   return gerepileupto(av, z);
     716             : }
     717             : 
     718             : /***************************************************/
     719             : /*Routines for increasing the imaginary parts using*/
     720             : /*Atkin-Lehner operators                           */
     721             : /***************************************************/
     722             : 
     723             : static GEN
     724       20520 : qfb_mult(GEN Q, GEN M)
     725             : {
     726       20520 :   GEN A = gel(Q, 1) , B = gel(Q, 2) , C = gel(Q, 3);
     727       20520 :   GEN a = gcoeff(M, 1, 1), b = gcoeff(M, 1, 2);
     728       20520 :   GEN c = gcoeff(M, 2, 1), d = gcoeff(M, 2, 2);
     729       20520 :   GEN W1 = addii(addii(mulii(sqri(a), A), mulii(mulii(c, a), B)), mulii(sqri(c), C));
     730       20520 :   GEN W2 = addii(addii(mulii(mulii(shifti(b,1), a), A),
     731             :                        mulii(addii(mulii(d, a), mulii(c, b)), B)),
     732             :                  mulii(mulii(shifti(d,1), c), C));
     733       20520 :   GEN W3 = addii(addii(mulii(sqri(b), A), mulii(mulii(d, b), B)), mulii(sqri(d), C));
     734       20520 :   GEN D = gcdii(W1, gcdii(W2, W3));
     735       20520 :   if (!equali1(D)) {
     736       18552 :     W1 = diviiexact(W1,D);
     737       18552 :     W2 = diviiexact(W2,D);
     738       18552 :     W3 = diviiexact(W3,D);
     739             :   }
     740       20520 :   return qfi(W1, W2, W3);
     741             : }
     742             : 
     743             : #ifdef DEBUG
     744             : static void
     745             : best_point_old(GEN Q, GEN NQ, GEN f, GEN *u, GEN *v)
     746             : {
     747             :   long n, k;
     748             :   GEN U, c, d;
     749             :   GEN A = gel(f, 1);
     750             :   GEN B = gel(f, 2);
     751             :   GEN C = gel(f, 3);
     752             :   GEN q = qfi(mulii(NQ, C), negi(B), diviiexact(A, NQ));
     753             :   redimagsl2(q, &U);
     754             :   *u = c = gcoeff(U, 1, 1);
     755             :   *v = d = gcoeff(U, 2, 1);
     756             :   if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q))))
     757             :     return;
     758             :   for (n = 1; ; n++)
     759             :   {
     760             :     for (k = -n; k<=n; k++)
     761             :     {
     762             :       *u = addis(c, k); *v = addiu(d, n);
     763             :       if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q))))
     764             :         return;
     765             :       *v= subiu(d, n);
     766             :       if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q))))
     767             :         return;
     768             :       *u = addiu(c, n); *v = addis(d, k);
     769             :       if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q))))
     770             :         return;
     771             :       *u = subiu(c, n);
     772             :       if (equali1(ggcd(mulii(*u, NQ), mulii(*v, Q))))
     773             :         return;
     774             :     }
     775             :   }
     776             : }
     777             : /* q(x,y) = ax^2 + bxy + cy^2 */
     778             : static GEN
     779             : qfb_eval(GEN q, GEN x, GEN y)
     780             : {
     781             :   GEN a = gel(q,1), b = gel(q,2), c = gel(q,3);
     782             :   GEN x2 = sqri(x), y2 = sqri(y), xy = mulii(x,y);
     783             :   return addii(addii(mulii(a, x2), mulii(b,xy)), mulii(c, y2));
     784             : }
     785             : #endif
     786             : 
     787             : static long
     788        5634 : nexti(long i) { return i>0 ? -i : 1-i; }
     789             : 
     790             : /* q0 + i q1 + i^2 q2 */
     791             : static GEN
     792       10542 : qfmin_eval(GEN q0, GEN q1, GEN q2, long i)
     793       10542 : { return addii(mulis(addii(mulis(q2, i), q1), i), q0); }
     794             : 
     795             : /* assume a > 0, return gcd(a,b,c) */
     796             : static ulong
     797       14076 : gcduii(ulong a, GEN b, GEN c)
     798             : {
     799       14076 :   ulong d = a;
     800       14076 :   d = ugcd(umodiu(b, d), d );
     801       14076 :   if (d == 1) return 1;
     802        4926 :   d = ugcd(umodiu(c, d), d );
     803        4926 :   return d;
     804             : }
     805             : 
     806             : static void
     807       20520 : best_point(GEN Q, GEN NQ, GEN f, GEN *pu, GEN *pv)
     808             : {
     809       20520 :   GEN a = mulii(NQ, gel(f,3)), b = negi(gel(f,2)), c = diviiexact(gel(f,1), NQ);
     810       20520 :   GEN D = absi( qfb_disc(f) );
     811       20520 :   GEN U, qr = redimagsl2(qfi(a,b,c), &U);
     812       20520 :   GEN A = gel(qr,1), B = gel(qr,2), A2 = shifti(A,1), AA4 = sqri(A2);
     813             :   GEN V, best;
     814             :   long y;
     815             : 
     816             :   /* 4A qr(x,y) = (2A x + By)^2 + D y^2
     817             :    * Write x = x0(y) + i, where x0 is an integer minimum
     818             :    * (the smallest in case of tie) of x-> qr(x,y), for given y.
     819             :    * 4A qr(x,y) = ((2A x0 + By)^2 + Dy^2) + 4A i (2A x0 + By) + 4A^2 i^2
     820             :    *            = q0(y) + q1(y) i + q2 i^2
     821             :    * Loop through (x,y), y>0 by (roughly) increasing values of qr(x,y) */
     822             : 
     823             :   /* We must test whether [X,Y]~ := U * [x,y]~ satisfy (X NQ, Y Q) = 1
     824             :    * This is equivalent to (X,Y) = 1 (note that (X,Y) = (x,y)), and
     825             :    * (X, Q) = (Y, NQ) = 1.
     826             :    * We have U * [x0+i, y]~ = U * [x0,y]~ + i U[,1] =: V0 + i U[,1] */
     827             : 
     828             :   /* try [1,0]~ = first minimum */
     829       20520 :   V = gel(U,1); /* U *[1,0]~ */
     830       20520 :   *pu = gel(V,1);
     831       20520 :   *pv = gel(V,2);
     832       36204 :   if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return;
     833             : 
     834             :   /* try [0,1]~ = second minimum */
     835       10116 :   V = gel(U,2); /* U *[0,1]~ */
     836       10116 :   *pu = gel(V,1);
     837       10116 :   *pv = gel(V,2);
     838       10116 :   if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return;
     839             : 
     840             :   /* (X,Y) = (1, \pm1) always works. Try to do better now */
     841        4836 :   best = subii(addii(a, c), absi(b));
     842        4836 :   *pu = gen_1;
     843        4836 :   *pv = signe(b) < 0? gen_1: gen_m1;
     844             : 
     845       12654 :   for (y = 1;; y++)
     846             :   {
     847             :     GEN Dy2, r, By, x0, q0, q1, V0;
     848             :     long i;
     849       12654 :     if (y > 1)
     850             :     {
     851       10728 :       if (gcduii(y, gcoeff(U,1,1),  Q) != 1) continue;
     852        6258 :       if (gcduii(y, gcoeff(U,2,1), NQ) != 1) continue;
     853             :     }
     854        9750 :     Dy2 = mulii(D, sqru(y));
     855        9750 :     if (cmpii(Dy2, best) >= 0) break; /* we won't improve. STOP */
     856        4914 :     By = muliu(B,y), x0 = truedvmdii(negi(By), A2, &r);
     857        4914 :     if (cmpii(r, A) >= 0) { x0 = subiu(x0,1); r = subii(r, A2); }
     858             :     /* (2A x + By)^2 + Dy^2, minimal at x = x0. Assume A2 > 0 */
     859             :     /* r = 2A x0 + By */
     860        4914 :     q0 = addii(sqri(r), Dy2); /* minimal value for this y, at x0 */
     861        4914 :     if (cmpii(q0, best) >= 0) continue; /* we won't improve for this y */
     862        4908 :     q1 = shifti(mulii(A2, r), 1);
     863             : 
     864        4908 :     V0 = ZM_ZC_mul(U, mkcol2(x0, utoipos(y)));
     865       10542 :     for (i = 0;; i = nexti(i))
     866             :     {
     867       10542 :       pari_sp av2 = avma;
     868       10542 :       GEN x, N = qfmin_eval(q0, q1, AA4, i);
     869       10542 :       if (cmpii(N , best) >= 0) break;
     870       10506 :       x = addis(x0, i);
     871       10506 :       if (ugcd(umodiu(x, y), y) == 1)
     872             :       {
     873             :         GEN u, v;
     874       10470 :         V = ZC_add(V0, ZC_z_mul(gel(U,1), i)); /* [X, Y] */
     875       10470 :         u = gel(V,1);
     876       10470 :         v = gel(V,2);
     877       10470 :         if (is_pm1(gcdii(u, Q)) && is_pm1(gcdii(v, NQ)))
     878             :         {
     879        4872 :           *pu = u;
     880        4872 :           *pv = v;
     881        4872 :           best = N; break;
     882             :         }
     883             :       }
     884        5634 :       avma = av2;
     885        5634 :     }
     886        7818 :   }
     887             : #ifdef DEBUG
     888             :   {
     889             :     GEN oldu, oldv, F = qfi(a,b,c);
     890             :     best_point_old(Q, NQ, f, &oldu, &oldv);
     891             :     if (!equalii(oldu, *pu) || !equalii(oldv, *pv))
     892             :     {
     893             :       if (!equali1(gcdii(mulii(*pu, NQ), mulii(*pv, Q))))
     894             :         pari_err_BUG("best_point (gcd)");
     895             :       if (cmpii(qfb_eval(F, *pu,*pv), qfb_eval(F, oldu, oldv)) > 0)
     896             :       {
     897             :         pari_warn(warner, "%Ps,%Ps,%Ps, %Ps > %Ps",
     898             :                           Q,NQ,f, mkvec2(*pu,*pv), mkvec2(oldu,oldv));
     899             :         pari_err_BUG("best_point (too large)");
     900             :       }
     901             :     }
     902             :   }
     903             : #endif
     904             : }
     905             : 
     906             : static GEN
     907       20520 : best_lift(GEN N, GEN Q, GEN NQ, GEN f)
     908             : {
     909             :   GEN a,b,c,d,M;
     910       20520 :   best_point(Q, NQ, f, &c, &d);
     911       20520 :   (void)bezout(mulii(d, Q), mulii(NQ, c), &a, &b);
     912       20520 :   M = mkmat2( mkcol2(mulii(d, Q), mulii(negi(N), c)),
     913             :               mkcol2(b, mulii(a, Q)));
     914       20520 :   return qfb_mult(f, M);
     915             : }
     916             : 
     917             : static GEN
     918        1968 : lift_points(GEN N, GEN listQ, GEN f, GEN *pt, GEN *pQ)
     919             : {
     920        1968 :   pari_sp av = avma;
     921        1968 :   GEN yf = gen_0, tf = NULL, Qf = NULL;
     922        1968 :   long k, l = lg(listQ);
     923       22488 :   for (k = 1; k < l; ++k)
     924             :   {
     925       20520 :     GEN c = gel(listQ, k), Q = gel(c,1), NQ = gel(c,2);
     926       20520 :     GEN t = best_lift(N, Q, NQ, f), y = qimag2(t);
     927       20520 :     if (gcmp(y, yf) > 0) { yf = y; Qf = Q; tf = t; }
     928             :   }
     929        1968 :   gerepileall(av, 3, &tf, &Qf, &yf);
     930        1968 :   *pt = tf; *pQ = Qf; return yf;
     931             : }
     932             : 
     933             : /***************************/
     934             : /*         Twists          */
     935             : /***************************/
     936             : 
     937             : static GEN
     938          42 : ltwist1(GEN E, GEN d, long bitprec)
     939             : {
     940          42 :   pari_sp av = avma;
     941          42 :   GEN Ed = ellinit(elltwist(E, d), NULL, DEFAULTPREC);
     942          42 :   GEN z = ellL1_bitprec(Ed, 0, bitprec);
     943          42 :   obj_free(Ed); return gerepileuptoleaf(av, z);
     944             : }
     945             : 
     946             : /* Return O_re*c(E)/(4*O_vol*|E_t|^2) */
     947             : 
     948             : static GEN
     949          30 : heegner_indexmult(GEN om, long t, GEN tam, long prec)
     950             : {
     951          30 :   pari_sp av = avma;
     952          30 :   GEN Ovr = gabs(gimag(gel(om, 2)), prec); /* O_vol/O_re, t_REAL */
     953          30 :   return gerepileupto(av, divru(divir(tam, Ovr), 4*t*t));
     954             : }
     955             : 
     956             : 
     957             : /* omega(gcd(D, N)), given faN = factor(N) */
     958             : static long
     959          42 : omega_N_D(GEN faN, ulong D)
     960             : {
     961          42 :   GEN P = gel(faN, 1);
     962          42 :   long i, l = lg(P), w = 0;
     963         150 :   for (i = 1; i < l; i++)
     964         108 :     if (dvdui(D, gel(P,i))) w++;
     965          42 :   return w;
     966             : }
     967             : 
     968             : static GEN
     969          42 : heegner_indexmultD(GEN faN, GEN a, long D, GEN sqrtD)
     970             : {
     971          42 :   pari_sp av = avma;
     972             :   GEN c;
     973             :   long w;
     974          42 :   switch(D)
     975             :   {
     976           0 :     case -3: w = 9; break;
     977           0 :     case -4: w = 4; break;
     978          42 :     default: w = 1;
     979             :   }
     980          42 :   c = shifti(stoi(w), omega_N_D(faN,-D)); /* (w(D)/2)^2 * 2^omega(gcd(D,N)) */
     981          42 :   return gerepileupto(av, mulri(mulrr(a, sqrtD), c));
     982             : }
     983             : 
     984             : static GEN
     985         744 : heegner_try_point(GEN E, GEN lambdas, GEN ht, GEN z, long prec)
     986             : {
     987         744 :   long l = lg(lambdas);
     988             :   long i, eps;
     989         744 :   GEN P = greal(pointell(E, z, prec)), x = gel(P,1);
     990         744 :   GEN rh = subrr(ht, shiftr(ellheightoo(E, P, prec),1));
     991        9636 :   for (i = 1; i < l; ++i)
     992             :   {
     993        8922 :     GEN logd = shiftr(gsub(rh, gel(lambdas, i)), -1);
     994        8922 :     GEN d, approxd = gexp(logd, prec);
     995        8922 :     if (DEBUGLEVEL > 2)
     996           0 :       err_printf("Trying lambda number %ld, logd=%Ps, approxd=%Ps\n", i, logd, approxd);
     997        8922 :     d = grndtoi(approxd, &eps);
     998        8922 :     if (signe(d) > 0 && eps<-10)
     999             :     {
    1000          48 :       GEN X, ylist, d2 = sqri(d), approxn = mulir(d2, x);
    1001          48 :       if (DEBUGLEVEL > 2) err_printf("approxn=%Ps  eps=%ld\n", approxn,eps);
    1002          48 :       X = gdiv(ground(approxn), d2);
    1003          48 :       ylist = ellordinate(E, X, prec);
    1004          48 :       if (lg(ylist) > 1)
    1005             :       {
    1006          42 :         GEN P = mkvec2(X, gel(ylist, 1));
    1007          42 :         GEN hp = ghell(E,P,prec);
    1008          42 :         if (cmprr(hp, shiftr(ht,1)) < 0 && cmprr(hp, shiftr(ht,-1)) > 0)
    1009          30 :           return P;
    1010          12 :         if (DEBUGLEVEL)
    1011           0 :           err_printf("found non-Heegner point %Ps\n", P);
    1012             :       }
    1013             :     }
    1014             :   }
    1015         714 :   return NULL;
    1016             : }
    1017             : 
    1018             : static GEN
    1019          30 : heegner_find_point(GEN e, GEN om, GEN ht, GEN z1, long k, long prec)
    1020             : {
    1021          30 :   GEN lambdas = lambdalist(e, prec);
    1022          30 :   pari_sp av = avma;
    1023             :   long m;
    1024          30 :   GEN Ore = gel(om, 1), Oim = gel(om, 2);
    1025          30 :   if (DEBUGLEVEL)
    1026           0 :     err_printf("%ld*%ld multipliers to test\n",k,lg(lambdas)-1);
    1027         432 :   for (m = 0; m < k; m++)
    1028             :   {
    1029         432 :     GEN P, z2 = divru(addrr(z1, mulsr(m, Ore)), k);
    1030         432 :     if (DEBUGLEVEL > 2)
    1031           0 :       err_printf("Trying multiplier %ld\n",m);
    1032         432 :     P = heegner_try_point(e, lambdas, ht, z2, prec);
    1033         432 :     if (P) return P;
    1034         408 :     if (signe(ell_get_disc(e)) > 0)
    1035             :     {
    1036         312 :       z2 = gadd(z2, gmul2n(Oim, -1));
    1037         312 :       P = heegner_try_point(e, lambdas, ht, z2, prec);
    1038         312 :       if (P) return P;
    1039             :     }
    1040         402 :     avma = av;
    1041             :   }
    1042           0 :   pari_err_BUG("ellheegner, point not found");
    1043             :   return NULL; /* LCOV_EXCL_LINE */
    1044             : }
    1045             : 
    1046             : /* N > 1, fa = factor(N), return factor(4*N) */
    1047             : static GEN
    1048          30 : fa_shift2(GEN fa)
    1049             : {
    1050          30 :   GEN P = gel(fa,1), E = gel(fa,2);
    1051          30 :   if (absequaliu(gcoeff(fa,1,1), 2))
    1052             :   {
    1053          18 :     E = shallowcopy(E);
    1054          18 :     gel(E,1) = addiu(gel(E,1), 2);
    1055             :   }
    1056             :   else
    1057             :   {
    1058          12 :     P = shallowconcat(gen_2, P);
    1059          12 :     E = shallowconcat(gen_2, E);
    1060             :   }
    1061          30 :   return mkmat2(P, E);
    1062             : }
    1063             : 
    1064             : /* P = prime divisors of N(E). Return the product of primes p in P, a_p != -1
    1065             :  * HACK: restrict to small primes since large ones won't divide our C-long
    1066             :  * discriminants */
    1067             : static GEN
    1068          30 : get_bad(GEN E, GEN P)
    1069             : {
    1070          30 :   long k, l = lg(P), ibad = 1;
    1071          30 :   GEN B = cgetg(l, t_VECSMALL);
    1072         108 :   for (k = 1; k < l; k++)
    1073             :   {
    1074          78 :     GEN p = gel(P,k);
    1075          78 :     long pp = itos_or_0(p);
    1076          78 :     if (!pp) break;
    1077          78 :     if (! equalim1(ellap(E,p))) B[ibad++] = pp;
    1078             :   }
    1079          30 :   setlg(B, ibad); return ibad == 1? NULL: zv_prod_Z(B);
    1080             : }
    1081             : 
    1082             : /* list of pairs [Q,N/Q], where Q | N and gcd(Q,N/Q) = 1 */
    1083             : static GEN
    1084          30 : find_div(GEN N, GEN faN)
    1085             : {
    1086          30 :   GEN listQ = divisors(faN);
    1087          30 :   long j, k, l = lg(listQ);
    1088             : 
    1089          30 :   gel(listQ, 1) = mkvec2(gen_1, N);
    1090        1356 :   for (j = k = 2; k < l; ++k)
    1091             :   {
    1092        1326 :     GEN Q = gel(listQ, k), NQ = diviiexact(N, Q);
    1093        1326 :     if (is_pm1(gcdii(Q,NQ))) gel(listQ, j++) = mkvec2(Q,NQ);
    1094             :   }
    1095          30 :   setlg(listQ, j); return listQ;
    1096             : }
    1097             : 
    1098             : static long
    1099        6954 : testDisc(GEN bad, long d)
    1100        6954 : { return !bad || ugcd(umodiu(bad, -d), -d) == 1; }
    1101             : /* bad = product of bad primes. Return the NDISC largest fundamental
    1102             :  * discriminants D < d such that (D,bad) = 1 and d is a square mod 4N */
    1103             : static GEN
    1104          30 : listDisc(GEN fa4N, GEN bad, long d)
    1105             : {
    1106          30 :   const long NDISC = 10;
    1107          30 :   GEN v = cgetg(NDISC+1, t_VECSMALL);
    1108          30 :   pari_sp av = avma;
    1109          30 :   long j = 1;
    1110             :   for(;;)
    1111             :   {
    1112        6954 :     d -= odd(d)? 1: 3;
    1113        6954 :     if (testDisc(bad,d) && unegisfundamental(-d) && Zn_issquare(stoi(d), fa4N))
    1114             :     {
    1115         300 :       v[j++] = d;
    1116         300 :       if (j > NDISC) break;
    1117             :     }
    1118        6924 :     avma = av;
    1119        6924 :   }
    1120          30 :   avma = av; return v;
    1121             : }
    1122             : /* L = vector of [q1,q2] or [q1,q2,q2']
    1123             :  * cd = (b^2 - D)/(4N) */
    1124             : static void
    1125      127656 : listfill(GEN N, GEN b, GEN c, GEN d, GEN L, long *s)
    1126             : {
    1127      127656 :   long k, l = lg(L);
    1128      127656 :   GEN add, frm2, a = mulii(d, N), V = mkqfi(a,b,c), frm = redimag(V);
    1129      487074 :   for (k = 1; k < l; ++k)
    1130             :   { /* Lk = [v,frm] or [v,frm,frm2] */
    1131      485106 :     GEN Lk = gel(L,k);
    1132             :     long i;
    1133     1240488 :     for (i = 2; i < lg(Lk); i++) /* 1 or 2 elements */
    1134      881070 :       if (gequal(frm, gel(Lk,i)))
    1135             :       {
    1136      125688 :         GEN v = gel(Lk, 1);
    1137      125688 :         if (cmpii(a, gel(v,1)) < 0) gel(Lk,1) = V;
    1138      253344 :         return;
    1139             :       }
    1140             :   }
    1141        1968 :   frm2 = redimag( mkqfi(d, negi(b), mulii(c,N)) );
    1142        1968 :   add = gequal(frm, frm2)? mkvec2(V,frm): mkvec3(V,frm,frm2);
    1143        1968 :   vectrunc_append(L, add);
    1144        1968 :   *s += lg(add) - 2;
    1145             : }
    1146             : /* faN4 = factor(4*N) */
    1147             : static GEN
    1148         300 : listheegner(GEN N, GEN faN4, GEN listQ, GEN D)
    1149             : {
    1150         300 :   pari_sp av = avma;
    1151         300 :   const long kmin = 30;
    1152         300 :   long h = itos(gel(quadclassunit0(D, 0, NULL, DEFAULTPREC), 1));
    1153         300 :   GEN ymin, b = Zn_sqrt(D, faN4), L = vectrunc_init(h+1);
    1154         300 :   long l, k, s = 0;
    1155        9300 :   for (k = 0; k < kmin || s < h; k++)
    1156             :   {
    1157        9000 :     GEN bk = addii(b, mulsi(2*k, N));
    1158        9000 :     GEN C = diviiexact(shifti(subii(sqri(bk), D), -2), N);
    1159        9000 :     GEN div = divisors(C);
    1160        9000 :     long i, l = lg(div);
    1161      136656 :     for (i = 1; i < l; i++)
    1162             :     {
    1163      127656 :       GEN d = gel(div, i), c = gel(div, l-i); /* cd = C */
    1164      127656 :       listfill(N, bk, c, d, L, &s);
    1165             :     }
    1166             :   }
    1167         300 :   l = lg(L); ymin = NULL;
    1168        2268 :   for (k = 1; k < l; k++)
    1169             :   {
    1170        1968 :     GEN t, Q, Lk = gel(L,k), f = gel(Lk,1);
    1171        1968 :     GEN y = lift_points(N, listQ, f, &t, &Q);
    1172        1968 :     gel(L, k) = mkvec3(t, stoi(lg(Lk) - 2), Q);
    1173        1968 :     if (!ymin || gcmp(y, ymin) < 0) ymin = y;
    1174             :   }
    1175         300 :   if (DEBUGLEVEL > 1)
    1176           0 :     err_printf("Disc %Ps : N*ymin = %Pg\n", D,
    1177             :                            gmul(gsqrt(ymin, DEFAULTPREC),N));
    1178         300 :   return gerepilecopy(av, mkvec3(ymin, L, D));
    1179             : }
    1180             : 
    1181             : /* Q | N, P = prime divisors of N, R[i] = local epsilon-factor at P[i].
    1182             :  * Return \prod_{p | Q} R[i] */
    1183             : static long
    1184         114 : rootno(GEN Q, GEN P, GEN R)
    1185             : {
    1186         114 :   long s = 1, i, l = lg(P);
    1187         462 :   for (i = 1; i < l; i++)
    1188         348 :     if (dvdii(Q, gel(P,i))) s *= R[i];
    1189         114 :   return s;
    1190             : }
    1191             : 
    1192             : static void
    1193          30 : heegner_find_disc(GEN *points, GEN *coefs, long *pind, GEN E,
    1194             :                   GEN indmult, long prec)
    1195             : {
    1196          30 :   long d = 0;
    1197             :   GEN faN4, bad, N, faN, listQ, listR;
    1198             : 
    1199          30 :   ellQ_get_Nfa(E, &N, &faN);
    1200          30 :   faN4 = fa_shift2(faN);
    1201          30 :   listQ = find_div(N, faN);
    1202          30 :   bad = get_bad(E, gel(faN, 1));
    1203          30 :   listR = gel(obj_check(E, Q_ROOTNO), 2);
    1204             :   for(;;)
    1205             :   {
    1206          30 :     pari_sp av = avma;
    1207          30 :     GEN list, listD = listDisc(faN4, bad, d);
    1208          30 :     long k, l = lg(listD);
    1209          30 :     list = cgetg(l, t_VEC);
    1210         330 :     for (k = 1; k < l; ++k)
    1211         300 :       gel(list, k) = listheegner(N, faN4, listQ, stoi(listD[k]));
    1212          30 :     list = vecsort0(list, gen_1, 0);
    1213          42 :     for (k = l-1; k > 0; --k)
    1214             :     {
    1215          42 :       long bprec = 8;
    1216          42 :       GEN Lk = gel(list,k), D = gel(Lk,3);
    1217          42 :       GEN sqrtD = sqrtr_abs(itor(D, prec)); /* sqrt(|D|) */
    1218          42 :       GEN indmultD = heegner_indexmultD(faN, indmult, itos(D), sqrtD);
    1219             :       do
    1220             :       {
    1221             :         GEN mulf, indr;
    1222             :         pari_timer ti;
    1223          42 :         if (DEBUGLEVEL) timer_start(&ti);
    1224          42 :         mulf = ltwist1(E, D, bprec+expo(indmultD));
    1225          42 :         if (DEBUGLEVEL) timer_printf(&ti,"ellL1twist");
    1226          42 :         indr = mulrr(indmultD, mulf);
    1227          42 :         if (DEBUGLEVEL) err_printf("Disc = %Ps, Index^2 = %Ps\n", D, indr);
    1228          42 :         if (signe(indr)>0 && expo(indr) >= -1) /* indr >=.5 */
    1229             :         {
    1230             :           long e, i, l;
    1231          30 :           GEN pts, cfs, L, indi = grndtoi(sqrtr_abs(indr), &e);
    1232          30 :           if (e > expi(indi)-7)
    1233             :           {
    1234           0 :             bprec++;
    1235           0 :             pari_warn(warnprec, "ellL1",bprec);
    1236           0 :             continue;
    1237             :           }
    1238          30 :           *pind = itos(indi);
    1239          30 :           L = gel(Lk, 2); l = lg(L);
    1240          30 :           pts = cgetg(l, t_VEC);
    1241          30 :           cfs = cgetg(l, t_VECSMALL);
    1242         144 :           for (i = 1; i < l; ++i)
    1243             :           {
    1244         114 :             GEN P = gel(L,i), z = gel(P,2), Q = gel(P,3); /* [1 or 2, Q] */
    1245             :             long c;
    1246         114 :             gel(pts, i) = qfb_root(gel(P,1), sqrtD);
    1247         114 :             c = rootno(Q, gel(faN,1), listR);
    1248         114 :             if (!equali1(z)) c *= 2;
    1249         114 :             cfs[i] = c;
    1250             :           }
    1251          30 :           if (DEBUGLEVEL)
    1252           0 :             err_printf("N = %Ps, ymin*N = %Ps\n",N,
    1253           0 :                        gmul(gsqrt(gel(Lk, 1), prec),N));
    1254          60 :           *coefs = cfs; *points = pts; return;
    1255             :         }
    1256             :       } while(0);
    1257             :     }
    1258           0 :     d = listD[l-1]; avma = av;
    1259           0 :   }
    1260             : }
    1261             : 
    1262             : GEN
    1263         372 : ellanal_globalred_all(GEN e, GEN *cb, GEN *N, GEN *tam)
    1264             : {
    1265         372 :   GEN E = ellanal_globalred(e, cb), red = obj_check(E, Q_GLOBALRED);
    1266         372 :   *N = gel(red, 1);
    1267         372 :   *tam = gel(red,2);
    1268         372 :   if (signe(ell_get_disc(E))>0) *tam = shifti(*tam,1);
    1269         372 :   return E;
    1270             : }
    1271             : 
    1272             : GEN
    1273          42 : ellheegner(GEN E)
    1274             : {
    1275          42 :   pari_sp av = avma;
    1276             :   GEN z, P, ht, points, coefs, s, om, indmult;
    1277             :   long ind, lint, k, l, wtor, etor;
    1278          42 :   long bitprec = 16, prec = nbits2prec(bitprec)+1;
    1279             :   pari_timer ti;
    1280             :   GEN N, cb, tam, torsion;
    1281             : 
    1282          42 :   E = ellanal_globalred_all(E, &cb, &N, &tam);
    1283          42 :   if (ellrootno_global(E) == 1)
    1284           6 :     pari_err_DOMAIN("ellheegner", "(analytic rank)%2","=",gen_0,E);
    1285          36 :   torsion = elltors(E);
    1286          36 :   wtor = itos( gel(torsion,1) ); /* #E(Q)_tor */
    1287          36 :   etor = wtor > 1? itos(gmael(torsion, 2, 1)): 1; /* exponent of E(Q)_tor */
    1288             :   while (1)
    1289             :   {
    1290             :     GEN hnaive, l1;
    1291             :     long bitneeded;
    1292          66 :     if (DEBUGLEVEL) timer_start(&ti);
    1293          66 :     l1 = ellL1_bitprec(E, 1, bitprec);
    1294          66 :     if (DEBUGLEVEL) timer_printf(&ti,"ellL1");
    1295          66 :     if (expo(l1) < 1 - bitprec/2)
    1296           6 :       pari_err_DOMAIN("ellheegner", "analytic rank",">",gen_1,E);
    1297          60 :     om = ellR_omega(E,prec);
    1298          60 :     ht = divrr(mulru(l1, wtor * wtor), mulri(gel(om,1), tam));
    1299          60 :     if (DEBUGLEVEL) err_printf("Expected height=%Ps\n", ht);
    1300          60 :     hnaive = hnaive_max(E, ht);
    1301          60 :     if (DEBUGLEVEL) err_printf("Naive height <= %Ps\n", hnaive);
    1302          60 :     bitneeded = itos(gceil(divrr(hnaive, mplog2(prec)))) + 10;
    1303          60 :     if (DEBUGLEVEL) err_printf("precision = %ld\n", bitneeded);
    1304          60 :     if (bitprec>=bitneeded) break;
    1305          30 :     bitprec = bitneeded;
    1306          30 :     prec = nbits2prec(bitprec)+1;
    1307          30 :   }
    1308          30 :   indmult = heegner_indexmult(om, wtor, tam, prec);
    1309          30 :   heegner_find_disc(&points, &coefs, &ind, E, indmult, prec);
    1310          30 :   if (DEBUGLEVEL) timer_start(&ti);
    1311          30 :   s = heegner_psi(E, N, points, bitprec);
    1312          30 :   if (DEBUGLEVEL) timer_printf(&ti,"heegner_psi");
    1313          30 :   l = lg(points);
    1314          30 :   z = mulsr(coefs[1], gel(s, 1));
    1315          30 :   for (k = 2; k < l; ++k) z = addrr(z, mulsr(coefs[k], gel(s, k)));
    1316          30 :   if (DEBUGLEVEL) err_printf("z=%Ps\n", z);
    1317          30 :   z = gsub(z, gmul(gel(om,1), ground(gdiv(z, gel(om,1)))));
    1318          30 :   lint = wtor > 1 ? cgcd(ind, etor): 1;
    1319          30 :   P = heegner_find_point(E, om, ht, gmulsg(2*lint, z), lint*2*ind, prec);
    1320          30 :   if (DEBUGLEVEL) timer_printf(&ti,"heegner_find_point");
    1321          30 :   if (cb) P = ellchangepointinv(P, cb);
    1322          30 :   return gerepilecopy(av, P);
    1323             : }
    1324             : 
    1325             : /* Modular degree */
    1326             : 
    1327             : /* Modular degree of elliptic curve e over Q, assuming Manin constant = 1
    1328             :    (otherwise multiply by square of Manin constant). */
    1329             : GEN
    1330          48 : ellmoddegree(GEN e, long bitprec)
    1331             : {
    1332          48 :   pari_sp ltop = avma;
    1333          48 :   long prec = nbits2prec(bitprec);
    1334          48 :   GEN E = ellminimalmodel(e, NULL);
    1335          48 :   GEN nor = lfunellmfpeters(E, bitprec);
    1336          48 :   GEN deg = gdiv(gmul(nor, sqrr(Pi2n(1, prec))), member_area(E));
    1337          48 :   GEN degr = bestappr(deg, int2n(bitprec>>1));
    1338          48 :   long err = gexpo(gsub(gen_1, gdiv(deg,degr)));
    1339          48 :   obj_free(E);
    1340          48 :   return gerepilecopy(ltop, mkvec2(degr, stoi(err)));
    1341             : }

Generated by: LCOV version 1.11