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

Generated by: LCOV version 1.16