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) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 88.7 % 986 875
Test Date: 2026-07-22 22:45:42 Functions: 92.0 % 87 80
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      3431482 : gen_BG_add(void *E, bg_fun *fun, struct bg_data *bg, GEN n, long i, GEN a, GEN lasta)
      50              : {
      51      3431482 :   pari_sp av = avma;
      52              :   long j;
      53      3431482 :   ulong nn = itou_or_0(n);
      54      3431482 :   if (nn && nn <= bg->rootbnd) bg->an[nn] = itos(a);
      55              : 
      56      3431482 :   if (signe(a))
      57              :   {
      58       867121 :     fun(E, n, a);
      59       867121 :     j = 1;
      60              :   }
      61              :   else
      62      2564361 :     j = i;
      63      6857939 :   for(; j <= i; j++)
      64              :   {
      65      5484935 :     ulong p = bg->p[j];
      66      5484935 :     GEN nexta, pn = mului(p, n);
      67      5484935 :     if (cmpii(pn, bg->bnd) > 0) return;
      68      3426457 :     nexta = mulis(a, bg->an[p]);
      69      3426457 :     if (i == j && umodiu(bg->N, p)) nexta = subii(nexta, mului(p, lasta));
      70      3426457 :     gen_BG_add(E, fun, bg, pn, j, nexta, a);
      71      3426457 :     set_avma(av);
      72              :   }
      73              : }
      74              : 
      75              : static void
      76           42 : gen_BG_init(struct bg_data *bg, GEN E, GEN N, GEN bnd)
      77              : {
      78           42 :   bg->E = E;
      79           42 :   bg->N = N;
      80           42 :   bg->bnd = bnd;
      81           42 :   bg->rootbnd = itou(sqrtint(bnd));
      82           42 :   bg->p = primes_upto_zv(bg->rootbnd);
      83           42 :   bg->an = ellanQ_zv(E, bg->rootbnd);
      84           42 : }
      85              : 
      86              : static void
      87           42 : gen_BG_rec(void *E, bg_fun *fun, struct bg_data *bg)
      88              : {
      89           42 :   long i, j, lp = lg(bg->p)-1;
      90           42 :   GEN bndov2 = shifti(bg->bnd, -1);
      91           42 :   pari_sp av = avma, av2;
      92              :   GEN p;
      93              :   forprime_t S;
      94           42 :   (void)forprime_init(&S, utoipos(bg->p[lp]+1), bg->bnd);
      95           42 :   av2 = avma;
      96           42 :   if (DEBUGLEVEL)
      97            0 :     err_printf("1st stage, using recursion for p <= %ld\n", bg->p[lp]);
      98         5067 :   for (i = 1; i <= lp; i++)
      99              :   {
     100         5025 :     ulong pp = bg->p[i];
     101         5025 :     long ap = bg->an[pp];
     102         5025 :     gen_BG_add(E, fun, bg, utoipos(pp), i, stoi(ap), gen_1);
     103         5025 :     set_avma(av2);
     104              :   }
     105           42 :   if (DEBUGLEVEL) err_printf("2nd stage, looping for p <= %Ps\n", bndov2);
     106      2393586 :   while ( (p = forprime_next(&S)) )
     107              :   {
     108              :     long jmax;
     109      2393586 :     GEN ap = ellap(bg->E, p);
     110      2393586 :     pari_sp av3 = avma;
     111      2393586 :     if (!signe(ap)) continue;
     112              : 
     113      1196490 :     jmax = itou( divii(bg->bnd, p) ); /* 2 <= jmax <= el->rootbound */
     114      1196490 :     fun(E, p, ap);
     115     20342791 :     for (j = 2;  j <= jmax; j++)
     116              :     {
     117     19146301 :       long aj = bg->an[j];
     118              :       GEN a, n;
     119     19146301 :       if (!aj) continue;
     120      2942771 :       a = mulis(ap, aj);
     121      2942771 :       n = muliu(p, j);
     122      2942771 :       fun(E, n, a);
     123      2942771 :       set_avma(av3);
     124              :     }
     125      1196490 :     set_avma(av2);
     126      1196490 :     if (abscmpii(p, bndov2) >= 0) break;
     127              :   }
     128           42 :   if (DEBUGLEVEL) err_printf("3nd stage, looping for p <= %Ps\n", bg->bnd);
     129      2164631 :   while ( (p = forprime_next(&S)) )
     130              :   {
     131      2164589 :     GEN ap = ellap(bg->E, p);
     132      2164589 :     if (!signe(ap)) continue;
     133      1082114 :     fun(E, p, ap);
     134      1082114 :     set_avma(av2);
     135              :   }
     136           42 :   set_avma(av);
     137           42 : }
     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          245 : logboundG0(long e, double aY)
     157              : {
     158              :   double cla, loggam;
     159          245 :   cla = 1 + 1/sqrt(aY);
     160          245 :   if (e) cla = ( cla + 1/(2*aY) ) / (2*sqrt(aY));
     161          245 :   loggam = (e) ? M_LN2-aY : -aY + log( log( 1+1/aY) );
     162          245 :   return log(cla) + loggam;
     163              : }
     164              : 
     165              : static void
     166          245 : 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          245 :   long d = 2, w = 1;
     171          245 :   tmax *= d;
     172          245 :   D = bprec * M_LN2 + M_PI/4*tmax + 2;
     173          245 :   *cprec = nbits2prec(ceil(D / M_LN2) + 5);
     174          245 :   a = 2 * M_PI / sqrt(gtodouble(N));
     175          245 :   aY = a * cos(M_PI/2*Y);
     176          245 :   logM = 2*M_LN2 + logboundG0(w+1, aY) + tmax * Y * M_PI/2;
     177          245 :   *h = ( 2 * M_PI * M_PI / 2 * Y ) / ( D + logM );
     178          245 :   X = log( D / a);
     179          245 :   *L = ceil( X / *h);
     180          245 :   *K = ceil_safe(dbltor( D / a ));
     181          245 : }
     182              : 
     183              : static GEN
     184          245 : vecF2_lk(GEN E, GEN K, GEN rbnd, GEN Q, GEN sleh, long prec)
     185              : {
     186              :   pari_sp av;
     187          245 :   long l, L  = lg(K)-1;
     188          245 :   GEN a = ellanQ_zv(E, itos(gel(K,1)));
     189          245 :   GEN S = cgetg(L+1, t_VEC);
     190              : 
     191        13776 :   for (l = 1; l <= L; l++) gel(S,l) = cgetr(prec);
     192          245 :   av = avma;
     193        13776 :   for (l = 1; l <= L; l++)
     194              :   {
     195              :     GEN e1, Sl, z, zB;
     196        13531 :     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        13531 :     e1 = gel(Q, l);
     200        13531 :     Sl = real_0(prec);;
     201              :     /* baby-step giant step */
     202        13531 :     B = A = rbnd[l];
     203        13531 :     z = powersr(e1, B); zB = gel(z, B+1);
     204        13531 :     av2 = avma;
     205       314174 :     for (aB = A*B; aB >= 0; aB -= B)
     206              :     {
     207       300643 :       GEN s = real_0(prec); /* could change also prec here */
     208     38032519 :       for (b = B; b > 0; --b)
     209              :       {
     210     37731876 :         long k = aB+b;
     211     37731876 :         if (k <= Kl && a[k]) s = addrr(s, mulsr(a[k], gel(z, b+1)));
     212     37731876 :         if (gc_needed(av2, 1)) (void)gc_all(av2, 2, &s, &Sl);
     213              :       }
     214       300643 :       Sl = addrr(mulrr(Sl, zB), s);
     215              :     }
     216        13531 :     affrr(mulrr(Sl, gel(sleh,l)), gel(S, l)); /* to avoid copying all S */
     217        13531 :     set_avma(av);
     218              :   }
     219          245 :   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          245 : baby_size(GEN rbnd, long Ks, long prec)
     243              : {
     244          245 :   long i, s, m, l = lg(rbnd);
     245        13776 :   for (s = 0, i = 1; i < l; ++i)
     246        13531 :     s += rbnd[i];
     247          245 :   m = 2*s*prec + 3*l + s;
     248          245 :   if (DEBUGLEVEL)
     249            0 :     err_printf("ellL1: BG_add: %ld words, ellan: %ld words\n", m, Ks);
     250          245 :   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        13531 : _sqrt(GEN x) { pari_sp av = avma; return gc_long(av, itou(sqrtint(x))); }
     293              : 
     294              : static GEN
     295          245 : vecF(struct lcritical *C, GEN E)
     296              : {
     297          245 :   pari_sp av = avma;
     298          245 :   long prec = C->cprec, Ks = itos_or_0(C->K), L = C->L, l;
     299          245 :   GEN N = ellQ_get_N(E), PiN;
     300          245 :   GEN e = mpexp(C->h), elh = powersr(e, L-1), Q, bnd, rbnd, vec;
     301              : 
     302          245 :   PiN = divrr(Pi2n(1,prec), sqrtr_abs(itor(N, prec)));
     303          245 :   setsigne(PiN, -1); /* - 2Pi/sqrt(N) */
     304          245 :   bnd = gpowers0(invr(e), L-1, C->K); /* bnd[i] = K exp(-(i-1)h) */
     305          245 :   rbnd = cgetg(L+1, t_VECSMALL);
     306          245 :   Q  = cgetg(L+1, t_VEC);
     307        13776 :   for (l = 1; l <= L; l++)
     308              :   {
     309        13531 :     gel(bnd,l) = ceil_safe(gel(bnd,l));
     310        13531 :     rbnd[l] = _sqrt(gel(bnd,l)) + 1;
     311        13531 :     gel(Q, l) = mpexp(mulrr(PiN, gel(elh, l)));
     312              :   }
     313          245 :   if (Ks && baby_size(rbnd, Ks, prec) > (Ks>>1))
     314          245 :     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          245 :   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          273 : glambda(GEN t, GEN vec, GEN h, long real, long prec)
     323              : {
     324          273 :   GEN z, r, e = gexp(gmul(mkcomplex(gen_0,h), t), prec);
     325          273 :   long n = lg(vec)-1, i;
     326              : 
     327          273 :   r = real == 1? gmul2n(real_i(gel(vec, 1)), -1): gen_0;
     328          273 :   z = real == 1? e: gmul(powIs(3), e);
     329              :   /* FIXME: summing backward may be more stable */
     330        16268 :   for (i = 2; i <= n; i++)
     331              :   {
     332        15995 :     r = gadd(r, real_i(gmul(gel(vec,i), z)));
     333        15995 :     if (i < n) z = gmul(z, e);
     334              :   }
     335          273 :   return gmul(mulsr(4, h), r);
     336              : }
     337              : 
     338              : static GEN
     339          245 : Lpoints(struct lcritical *C, GEN e, double tmax, long bprec)
     340              : {
     341          245 :   double h = 0, Y = .97;
     342          245 :   GEN N = ellQ_get_N(e);
     343          245 :   param_points(N, Y, tmax, bprec, &C->cprec, &C->L, &C->K, &h);
     344          245 :   C->real = ellrootno_global(e);
     345          245 :   C->h = rtor(dbltor(h), C->cprec);
     346          245 :   return vecF(C, e);
     347              : }
     348              : 
     349              : static GEN
     350          273 : Llambda(GEN vec, struct lcritical *C, GEN t, long prec)
     351              : {
     352          273 :   GEN lambda = glambda(gprec_w(t, C->cprec), vec, C->h, C->real, C->cprec);
     353          273 :   return gprec_w(lambda, prec);
     354              : }
     355              : 
     356              : /* 2*(2*Pi)^(-s)*gamma(s)*N^(s/2); */
     357              : static GEN
     358          273 : ellgammafactor(GEN N, GEN s, long prec)
     359              : {
     360          273 :   GEN c = gpow(divrr(gsqrt(N,prec), Pi2n(1,prec)), s, prec);
     361          273 :   return gmul(gmul2n(c,1), ggamma(s, prec));
     362              : }
     363              : 
     364              : static GEN
     365          273 : ellL1_eval(GEN e, GEN vec, struct lcritical *C, GEN t, long prec)
     366              : {
     367          273 :   GEN g = ellgammafactor(ellQ_get_N(e), gaddgs(gmul(gen_I(),t), 1), prec);
     368          273 :   return gdiv(Llambda(vec, C, t, prec), g);
     369              : }
     370              : 
     371              : static GEN
     372          273 : ellL1_der(GEN e, GEN vec, struct lcritical *C, GEN t, long der, long prec)
     373              : {
     374          273 :   GEN r = polcoef_i(ellL1_eval(e, vec, C, t, prec), der, 0);
     375          273 :   r = gmul(r,powIs(C->real == 1 ? -der: 1-der));
     376          273 :   return gmul(real_i(r), mpfact(der));
     377              : }
     378              : 
     379              : GEN
     380          231 : ellL1(GEN E, long r, long bitprec)
     381              : {
     382          231 :   pari_sp av = avma;
     383              :   struct lcritical C;
     384          231 :   long prec = nbits2prec(bitprec);
     385              :   GEN e, vec, t;
     386          231 :   if (r < 0)
     387            7 :     pari_err_DOMAIN("ellL1", "derivative order", "<", gen_0, stoi(r));
     388          224 :   e = ellanal_globalred(E, NULL);
     389          224 :   if (r == 0 && ellrootno_global(e) < 0) { set_avma(av); return gen_0; }
     390          210 :   vec = Lpoints(&C, e, 0., bitprec);
     391          210 :   t = r ? scalarser(gen_1, 0, r):  zeroser(0, 0);
     392          210 :   setvalser(t, 1);
     393          210 :   return gc_upto(av, ellL1_der(e, vec, &C, t, r, prec));
     394              : }
     395              : 
     396              : GEN
     397           35 : ellanalyticrank(GEN E, GEN eps, long bitprec)
     398              : {
     399           35 :   pari_sp av = avma, av2;
     400           35 :   long prec = nbits2prec(bitprec);
     401              :   struct lcritical C;
     402              :   pari_timer ti;
     403              :   GEN e, vec;
     404              :   long rk;
     405           35 :   if (DEBUGLEVEL) timer_start(&ti);
     406           35 :   if (!eps)
     407           35 :     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           35 :   e = ellanal_globalred(E, NULL);
     414           35 :   vec = Lpoints(&C, e, 0., bitprec);
     415           35 :   if (DEBUGLEVEL) timer_printf(&ti, "init L");
     416           35 :   av2 = avma;
     417           35 :   for (rk = C.real>0 ? 0: 1;  ; rk += 2)
     418           28 :   {
     419              :     GEN Lrk;
     420           63 :     GEN t = rk ? scalarser(gen_1, 0, rk):  zeroser(0, 0);
     421           63 :     setvalser(t, 1);
     422           63 :     Lrk = ellL1_der(e, vec, &C, t, rk, prec);
     423           63 :     if (DEBUGLEVEL) timer_printf(&ti, "L^(%ld)=%Ps", rk, Lrk);
     424           63 :     if (abscmprr(Lrk, eps) > 0)
     425           35 :       return gc_GEN(av, mkvec2(stoi(rk), Lrk));
     426           28 :     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      6088496 : heegner_L1(void*E, GEN n, GEN a)
     454              : {
     455      6088496 :   struct baby_giant *bb = (struct baby_giant*) E;
     456      6088496 :   long j, l = lg(bb->giant);
     457     36228875 :   for (j = 1; j < l; j++)
     458     30140379 :     if (cmpii(n, gel(bb->bnd,j)) <= 0)
     459              :     {
     460     25949953 :       ulong r, q = uabsdiviu_rem(n, bb->rbnd[j], &r);
     461     25949953 :       GEN giant = gel(bb->giant, j), baby = gel(bb->baby, j);
     462     25949953 :       GEN ex = mulreal(gel(baby, r+1), gel(giant, q+1));
     463     25949953 :       affrr(addrr(gel(bb->sum, j), divri(mulri(ex, a), n)),
     464     25949953 :             gel(bb->sum, j));
     465              :     }
     466      6088496 : }
     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           42 : RgV_zv_powers(GEN x, GEN n)
     475          189 : { 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           42 : baby_init3(struct baby_giant *bb, GEN Q, GEN bnd, GEN rbnd, long prec)
     496              : {
     497           42 :   long i, l = lg(Q);
     498           42 :   GEN S, C = RgV_zv_powers(Q, rbnd), R = cgetg(l,t_VEC);
     499          189 :   for (i = 1; i < l; ++i)
     500          147 :     gel(R, i) = gpowers(gmael(C, i, 1+rbnd[i]), rbnd[i]);
     501           42 :   S = cgetg(l,t_VEC);
     502          189 :   for (i = 1; i < l; ++i) gel(S, i) = rtor(real_i(gmael(C, i, 2)), prec);
     503           42 :   bb->baby = C; bb->giant = R; bb->sum = S;
     504           42 :   bb->bnd = bnd; bb->rbnd = rbnd;
     505           42 : }
     506              : 
     507              : /* ymin a t_REAL */
     508              : static GEN
     509           42 : heegner_psi(GEN E, GEN N, GEN points, long bitprec)
     510              : {
     511           42 :   pari_sp av = avma, av2;
     512              :   struct baby_giant bb;
     513              :   struct bg_data bg;
     514           42 :   long l, k, L = lg(points)-1, prec = nbits2prec(bitprec)+EXTRAPREC64;
     515           42 :   GEN Q, pi2 = Pi2n(1, prec), bnd, rbnd, bndmax;
     516           42 :   GEN B = divrr(mulur(bitprec,mplog2(DEFAULTPREC)), pi2);
     517              : 
     518           42 :   rbnd = cgetg(L+1, t_VECSMALL); av2 = avma;
     519           42 :   bnd = cgetg(L+1, t_VEC);
     520           42 :   Q  = cgetg(L+1, t_VEC);
     521          189 :   for (l = 1; l <= L; ++l)
     522              :   {
     523          147 :     gel(bnd,l) = ceil_safe(divrr(B,imag_i(gel(points, l))));
     524          147 :     rbnd[l] = itou(sqrtint(gel(bnd,l)))+1;
     525          147 :     gel(Q, l) = expIxy(pi2, gel(points, l), prec);
     526              :   }
     527           42 :   (void)gc_all(av2, 2, &bnd, &Q);
     528           42 :   bndmax = gel(bnd,vecindexmax(bnd));
     529           42 :   gen_BG_init(&bg, E, N, bndmax);
     530           42 :   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           42 :     baby_init3(&bb, Q, bnd, rbnd, prec);
     548           42 :     gen_BG_rec((void*)&bb, heegner_L1, &bg);
     549           42 :     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           91 : lambda1(GEN E, GEN nv, GEN p, long prec)
     556              : {
     557              :   GEN res, lp;
     558           91 :   long kod = itos(gel(nv, 2));
     559           91 :   if (kod == 2 || kod == -2) return NULL;
     560           91 :   lp = glog(p, prec);
     561           91 :   if (kod > 4)
     562              :   { /* I_m */
     563           14 :     long n = Z_pval(ell_get_disc(E), p);
     564           14 :     long j, m = kod - 4, nl = 1 + (m >> 1L);
     565           14 :     res = cgetg(nl, t_VEC);
     566           35 :     for (j = 1; j < nl; j++) /* log(p) (j/n) (j - n) */
     567           21 :       gel(res, j) = divru(mulri(lp, mulss(j, j-n)), n);
     568              :   }
     569           77 :   else if (kod < -4) /* I^*_m */
     570           14 :     res = mkvec2(negr(lp), shiftr(mulrs(lp, kod), -2));
     571              :   else
     572              :   {
     573           63 :     const long lam[] = {8,9,0,6,0,0,0,3,4};
     574           63 :     long m = -lam[kod+4];
     575           63 :     res = mkvec(divru(mulrs(lp, m), 6));
     576              :   }
     577           91 :   return res;
     578              : }
     579              : 
     580              : /* lambda[1] = gen_0, other components are t_REAL */
     581              : static GEN
     582           42 : lambdalist(GEN E, long prec)
     583              : {
     584           42 :   pari_sp ltop = avma;
     585           42 :   GEN glob = ellglobalred(E), P = gmael(glob,4,1), L = gel(glob,5);
     586           42 :   GEN res, v, D = ell_get_disc(E);
     587           42 :   long i, j, k, l, m, n, lv = lg(P), lr = 1;
     588           42 :   v = cgetg(lv, t_VEC);
     589          147 :   for (j = 1, i = 1 ; j < lv; j++)
     590              :   {
     591          105 :     GEN p = gel(P, j);
     592          105 :     if (dvdii(D, sqri(p)))
     593              :     {
     594           91 :       GEN la = lambda1(E, gel(L,j), p, prec);
     595           91 :       if (la) { gel(v, i++) = la; lr *= lg(la); }
     596              :     }
     597              :   }
     598           42 :   lv = i;
     599           42 :   res = cgetg(lr+1, t_VEC); gel(res, 1) = gen_0;
     600          133 :   for (j = n = 1; j < lv; j++)
     601              :   {
     602           91 :     GEN w = gel(v, j); /* vector of t_REAL */
     603           91 :     long lw = lg(w);
     604              :     /* k = 1 */
     605          203 :     for (l = 1, m = n; l < lw; l++, m+=n)
     606          112 :       gel(res, 1 + m) = gel(w, l);
     607          217 :     for (k = 2; k <= n; k++)
     608              :     {
     609          126 :       GEN t = gel(res, k);
     610          252 :       for (l = 1, m = n; l < lw; l++, m+=n)
     611          126 :         gel(res, k + m) = addrr(t, gel(w, l));
     612              :     }
     613           91 :     n = m;
     614              :   }
     615           42 :   return gc_GEN(ltop, res);
     616              : }
     617              : 
     618              : /* P a t_INT or t_FRAC, return its logarithmic height */
     619              : static GEN
     620           98 : heightQ(GEN P, long prec)
     621              : {
     622              :   long s;
     623           98 :   if (typ(P) == t_FRAC)
     624              :   {
     625           56 :     GEN a = gel(P,1), b = gel(P,2);
     626           56 :     P = abscmpii(a,b) > 0 ? a: b;
     627              :   }
     628           98 :   s = signe(P);
     629           98 :   if (!s) return real_0(prec);
     630           84 :   if (s < 0) P = negi(P);
     631           84 :   return glog(P, prec);
     632              : }
     633              : 
     634              : /* t a t_INT or t_FRAC, returns max(1, log |t|), returns a t_REAL */
     635              : static GEN
     636          147 : logplusQ(GEN t, long prec)
     637              : {
     638          147 :   if (typ(t) == t_INT)
     639              :   {
     640           42 :     if (!signe(t)) return real_1(prec);
     641           28 :     t = absi_shallow(t);
     642              :   }
     643              :   else
     644              :   {
     645          105 :     GEN a = gel(t,1), b = gel(t,2);
     646          105 :     if (abscmpii(a, b) < 0) return real_1(prec);
     647           56 :     if (signe(a) < 0) t = gneg(t);
     648              :   }
     649           84 :   return glog(t, prec);
     650              : }
     651              : 
     652              : /* See GTM239, p532, Th 8.1.18
     653              :  * Return M such that h_naive <= M */
     654              : GEN
     655           98 : hnaive_max(GEN ell, GEN ht)
     656              : {
     657           98 :   const long prec = LOWDEFAULTPREC; /* minimal accuracy */
     658           98 :   GEN b2     = ell_get_b2(ell), j = ell_get_j(ell);
     659           98 :   GEN logd   = glog(absi_shallow(ell_get_disc(ell)), prec);
     660           98 :   GEN logj   = logplusQ(j, prec);
     661           98 :   GEN hj     = heightQ(j, prec);
     662           49 :   GEN logb2p = signe(b2)? addrr(logplusQ(gdivgu(b2, 12),prec), mplog2(prec))
     663           98 :                         : real_1(prec);
     664           98 :   GEN mu     = addrr(divru(addrr(logd, logj),6), logb2p);
     665           98 :   return addrs(addrr(addrr(ht, divru(hj,12)), mu), 2);
     666              : }
     667              : 
     668              : static GEN
     669          147 : qfb_root(GEN Q, GEN vDi)
     670              : {
     671          147 :   GEN a2 = shifti(gel(Q, 1),1), b = gel(Q, 2);
     672          147 :   return mkcomplex(gdiv(negi(b),a2),divri(vDi,a2));
     673              : }
     674              : 
     675              : static GEN
     676        24668 : qimag2(GEN Q)
     677              : {
     678        24668 :   pari_sp av = avma;
     679        24668 :   GEN z = gdiv(negi(qfb_disc(Q)), shifti(sqri(gel(Q, 1)),2));
     680        24668 :   return gc_upto(av, z);
     681              : }
     682              : 
     683              : /***************************************************/
     684              : /*Routines for increasing the imaginary parts using*/
     685              : /*Atkin-Lehner operators                           */
     686              : /***************************************************/
     687              : 
     688              : static GEN
     689        24668 : qfb_mult(GEN Q, GEN a, GEN b, GEN c, GEN d)
     690              : {
     691        24668 :   GEN A = gel(Q, 1), B = gel(Q, 2), C = gel(Q, 3), D = qfb_disc(Q);
     692        24668 :   GEN a2 = sqri(a), b2 = sqri(b), c2 = sqri(c), d2 = sqri(d);
     693        24668 :   GEN ad = mulii(d, a), bc = mulii(b, c), e = subii(ad, bc);
     694        24668 :   GEN W1 = addii(addii(mulii(a2, A), mulii(mulii(c, a), B)), mulii(c2, C));
     695        24668 :   GEN W3 = addii(addii(mulii(b2, A), mulii(mulii(d, b), B)), mulii(d2, C));
     696        24668 :   GEN W2 = addii(addii(mulii(mulii(shifti(b,1), a), A),
     697              :                        mulii(addii(ad, bc), B)),
     698              :                  mulii(mulii(shifti(d,1), c), C));
     699        24668 :   if (!equali1(e)) {
     700        22190 :     W1 = diviiexact(W1,e);
     701        22190 :     W2 = diviiexact(W2,e);
     702        22190 :     W3 = diviiexact(W3,e);
     703              :   }
     704        24668 :   return mkqfb(W1, W2, W3, D);
     705              : }
     706              : 
     707              : #ifdef DEBUG
     708              : static void
     709              : best_point_old(GEN Q, GEN NQ, GEN f, GEN *u, GEN *v)
     710              : {
     711              :   long n, k;
     712              :   GEN U, c, d, A = gel(f,1), B = gel(f,2), C = gel(f,3), D = qfb_disc(f);
     713              :   GEN q = mkqfb(mulii(NQ, C), negi(B), diviiexact(A, NQ), D);
     714              :   redimagsl2(q, &U);
     715              :   *u = c = gcoeff(U, 1, 1);
     716              :   *v = d = gcoeff(U, 2, 1);
     717              :   if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return;
     718              :   for (n = 1;; n++)
     719              :   {
     720              :     for (k = -n; k <= n; k++)
     721              :     {
     722              :       *u = addis(c, k); *v = addiu(d, n);
     723              :       if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return;
     724              :       *v = subiu(d, n);
     725              :       if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return;
     726              :       *u = addiu(c, n); *v = addis(d, k);
     727              :       if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return;
     728              :       *u = subiu(c, n);
     729              :       if (equali1(gcdii(mulii(*u, NQ), mulii(*v, Q)))) return;
     730              :     }
     731              :   }
     732              : }
     733              : /* q(x,y) = ax^2 + bxy + cy^2 */
     734              : static GEN
     735              : qfb_eval(GEN q, GEN x, GEN y)
     736              : {
     737              :   GEN a = gel(q,1), b = gel(q,2), c = gel(q,3);
     738              :   GEN x2 = sqri(x), y2 = sqri(y), xy = mulii(x,y);
     739              :   return addii(addii(mulii(a, x2), mulii(b,xy)), mulii(c, y2));
     740              : }
     741              : #endif
     742              : 
     743              : static long
     744         6594 : nexti(long i) { return i>0 ? -i : 1-i; }
     745              : 
     746              : /* q0 + i q1 + i^2 q2 */
     747              : static GEN
     748        12334 : qfmin_eval(GEN q0, GEN q1, GEN q2, long i)
     749        12334 : { return addii(mulis(addii(mulis(q2, i), q1), i), q0); }
     750              : 
     751              : /* assume a > 0, return gcd(a,b,c) */
     752              : static ulong
     753        16443 : gcduii(ulong a, GEN b, GEN c)
     754              : {
     755        16443 :   a = ugcdiu(b, a);
     756        16443 :   return a == 1? 1: ugcdiu(c, a);
     757              : }
     758              : 
     759              : static void
     760        24668 : best_point(GEN Q, GEN NQ, GEN f, GEN *pu, GEN *pv)
     761              : {
     762        24668 :   GEN a = mulii(NQ, gel(f,3)), b = negi(gel(f,2)), c = diviiexact(gel(f,1), NQ);
     763        24668 :   GEN D = qfb_disc(f);
     764        24668 :   GEN U, qr = redimagsl2(mkqfb(a, b, c, D), &U);
     765        24668 :   GEN A = gel(qr,1), B = gel(qr,2), A2 = shifti(A,1), AA4 = sqri(A2);
     766              :   GEN V, best;
     767              :   long y;
     768              : 
     769        24668 :   D = absi_shallow(D);
     770              :   /* 4A qr(x,y) = (2A x + By)^2 + D y^2
     771              :    * Write x = x0(y) + i, where x0 is an integer minimum
     772              :    * (the smallest in case of tie) of x-> qr(x,y), for given y.
     773              :    * 4A qr(x,y) = ((2A x0 + By)^2 + Dy^2) + 4A i (2A x0 + By) + 4A^2 i^2
     774              :    *            = q0(y) + q1(y) i + q2 i^2
     775              :    * Loop through (x,y), y>0 by (roughly) increasing values of qr(x,y) */
     776              : 
     777              :   /* We must test whether [X,Y]~ := U * [x,y]~ satisfy (X NQ, Y Q) = 1
     778              :    * This is equivalent to (X,Y) = 1 (note that (X,Y) = (x,y)), and
     779              :    * (X, Q) = (Y, NQ) = 1.
     780              :    * We have U * [x0+i, y]~ = U * [x0,y]~ + i U[,1] =: V0 + i U[,1] */
     781              : 
     782              :   /* try [1,0]~ = first minimum */
     783        24668 :   V = gel(U,1); /* U *[1,0]~ */
     784        24668 :   *pu = gel(V,1);
     785        24668 :   *pv = gel(V,2);
     786        30947 :   if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return;
     787              : 
     788              :   /* try [0,1]~ = second minimum */
     789        11935 :   V = gel(U,2); /* U *[0,1]~ */
     790        11935 :   *pu = gel(V,1);
     791        11935 :   *pv = gel(V,2);
     792        11935 :   if (is_pm1(gcdii(*pu, Q)) && is_pm1(gcdii(*pv, NQ))) return;
     793              : 
     794              :   /* (X,Y) = (1, \pm1) always works. Try to do better now */
     795         5656 :   best = subii(addii(a, c), absi_shallow(b));
     796         5656 :   *pu = gen_1;
     797         5656 :   *pv = signe(b) < 0? gen_1: gen_m1;
     798              : 
     799         5656 :   for (y = 1;; y++)
     800         9135 :   {
     801              :     GEN Dy2, r, By, x0, q0, q1, V0;
     802              :     long i;
     803        14791 :     if (y > 1)
     804              :     {
     805        10703 :       if (gcduii(y, gcoeff(U,1,1),  Q) != 1) continue;
     806         7308 :       if (gcduii(y, gcoeff(U,2,1), NQ) != 1) continue;
     807              :     }
     808        11403 :     Dy2 = mulii(D, sqru(y));
     809        11403 :     if (cmpii(Dy2, best) >= 0) break; /* we won't improve. STOP */
     810         5747 :     By = muliu(B,y), x0 = truedvmdii(negi(By), A2, &r);
     811         5747 :     if (cmpii(r, A) >= 0) { x0 = subiu(x0,1); r = subii(r, A2); }
     812              :     /* (2A x + By)^2 + Dy^2, minimal at x = x0. Assume A2 > 0 */
     813              :     /* r = 2A x0 + By */
     814         5747 :     q0 = addii(sqri(r), Dy2); /* minimal value for this y, at x0 */
     815         5747 :     if (cmpii(q0, best) >= 0) continue; /* we won't improve for this y */
     816         5740 :     q1 = shifti(mulii(A2, r), 1);
     817              : 
     818         5740 :     V0 = ZM_ZC_mul(U, mkcol2(x0, utoipos(y)));
     819        12334 :     for (i = 0;; i = nexti(i))
     820         6594 :     {
     821        12334 :       pari_sp av2 = avma;
     822        12334 :       GEN x, N = qfmin_eval(q0, q1, AA4, i);
     823        12334 :       if (cmpii(N, best) >= 0) break;
     824        12299 :       x = addis(x0, i);
     825        12299 :       if (ugcdiu(x, y) == 1)
     826              :       {
     827              :         GEN u, v;
     828        12257 :         V = ZC_add(V0, ZC_z_mul(gel(U,1), i)); /* [X, Y] */
     829        12257 :         u = gel(V,1);
     830        12257 :         v = gel(V,2);
     831        12257 :         if (is_pm1(gcdii(u, Q)) && is_pm1(gcdii(v, NQ)))
     832              :         {
     833         5705 :           *pu = u;
     834         5705 :           *pv = v;
     835         5705 :           best = N; break;
     836              :         }
     837              :       }
     838         6594 :       set_avma(av2);
     839              :     }
     840              :   }
     841              : #ifdef DEBUG
     842              :   {
     843              :     GEN oldu, oldv, F = mkqfb(a, b, c, qfb_disc(f));
     844              :     best_point_old(Q, NQ, f, &oldu, &oldv);
     845              :     if (!equalii(oldu, *pu) || !equalii(oldv, *pv))
     846              :     {
     847              :       if (!equali1(gcdii(mulii(*pu, NQ), mulii(*pv, Q))))
     848              :         pari_err_BUG("best_point (gcd)");
     849              :       if (cmpii(qfb_eval(F, *pu,*pv), qfb_eval(F, oldu, oldv)) > 0)
     850              :       {
     851              :         pari_warn(warner, "%Ps,%Ps,%Ps, %Ps > %Ps",
     852              :                           Q,NQ,f, mkvec2(*pu,*pv), mkvec2(oldu,oldv));
     853              :         pari_err_BUG("best_point (too large)");
     854              :       }
     855              :     }
     856              :   }
     857              : #endif
     858              : }
     859              : 
     860              : static GEN
     861        24668 : best_lift(GEN Q, GEN NQ, GEN f)
     862              : {
     863              :   GEN a, b, c, d, dQ, cNQ;
     864        24668 :   best_point(Q, NQ, f, &c, &d);
     865        24668 :   dQ = mulii(d, Q); cNQ = mulii(NQ, c);
     866        24668 :   (void)bezout(dQ, cNQ, &a, &b);
     867        24668 :   return qfb_mult(f, dQ, b, mulii(negi(Q),cNQ), mulii(a,Q));
     868              : }
     869              : 
     870              : static GEN
     871         2478 : lift_points(GEN listQ, GEN f, GEN *pt, GEN *pQ)
     872              : {
     873         2478 :   pari_sp av = avma;
     874         2478 :   GEN yf = gen_0, tf = NULL, Qf = NULL;
     875         2478 :   long k, l = lg(listQ);
     876        27146 :   for (k = 1; k < l; ++k)
     877              :   {
     878        24668 :     GEN c = gel(listQ, k), Q = gel(c,1), NQ = gel(c,2);
     879        24668 :     GEN t = best_lift(Q, NQ, f), y = qimag2(t);
     880        24668 :     if (gcmp(y, yf) > 0) { yf = y; Qf = Q; tf = t; }
     881              :   }
     882         2478 :   *pt = tf; *pQ = Qf; return gc_all(av, 3, &yf, pt, pQ);
     883              : }
     884              : 
     885              : /***************************/
     886              : /*         Twists          */
     887              : /***************************/
     888              : 
     889              : static GEN
     890           56 : ltwist1(GEN E, GEN d, long bitprec)
     891              : {
     892           56 :   pari_sp av = avma;
     893           56 :   GEN Ed = elltwist(E, d), z = ellL1(Ed, 0, bitprec);
     894           56 :   obj_free(Ed); return gc_leaf(av, z);
     895              : }
     896              : 
     897              : /* omega(gcd(D, N)), given faN = factor(N) */
     898              : static long
     899          168 : omega_N_D(GEN faN, ulong D)
     900              : {
     901          168 :   GEN P = gel(faN, 1);
     902          168 :   long i, l = lg(P), w = 0;
     903          658 :   for (i = 1; i < l; i++)
     904          490 :     if (dvdui(D, gel(P,i))) w++;
     905          168 :   return w;
     906              : }
     907              : 
     908              : static long
     909          112 : get_w(long D)
     910              : {
     911          112 :   switch(D)
     912              :   {
     913            0 :     case -3: return 3; break;
     914            0 :     case -4: return 2; break;
     915          112 :     default: return 1;
     916              :   }
     917              : }
     918              : 
     919              : static GEN
     920           56 : heegner_indexmultD(GEN faN, GEN a, long D, GEN sqrtD)
     921              : {
     922           56 :   pari_sp av = avma;
     923              :   GEN c;
     924              :   long w;
     925           56 :   switch(D)
     926              :   {
     927            0 :     case -3: w = 9; break;
     928            0 :     case -4: w = 4; break;
     929           56 :     default: w = 1;
     930              :   }
     931           56 :   c = shifti(stoi(w), omega_N_D(faN,-D)); /* (w(D)/2)^2 * 2^omega(gcd(D,N)) */
     932           56 :   return gc_upto(av, mulri(mulrr(a, sqrtD), c));
     933              : }
     934              : 
     935              : static GEN
     936          399 : nf_to_basis(GEN nf, GEN x)
     937              : {
     938          399 :   x = nf_to_scalar_or_basis(nf, x);
     939          399 :   if (typ(x)!=t_COL)
     940          301 :     x = scalarcol(x, nf_get_degree(nf));
     941          399 :   return x;
     942              : }
     943              : 
     944              : static GEN
     945          196 : etnf_to_basis(GEN et, GEN x)
     946              : {
     947          196 :   long i, l = lg(et);
     948          196 :   GEN V = cgetg(l, t_VEC);
     949          595 :   for (i = 1; i < l; i++)
     950          399 :     gel(V,i) = nf_to_basis(gel(et,i), x);
     951          196 :   return shallowconcat1(V);
     952              : }
     953              : 
     954              : static long
     955           42 : etnf_get_varn(GEN et)
     956              : {
     957           42 :   return nf_get_varn(gel(et,1));
     958              : }
     959              : 
     960              : static GEN
     961           98 : heegner_descent_try_point(GEN nfA, GEN z, GEN den, long prec)
     962              : {
     963           98 :   pari_sp av = avma;
     964           98 :   GEN etal = gel(nfA,1), A = gel(nfA,2), cb = gel(nfA,3);
     965           98 :   GEN u2 = gsqr(gel(cb,1)), r = gel(cb,2), zz = gdiv(gsub(z,r), u2);
     966           98 :   GEN al = gel(nfA,4), th = gel(nfA, 5), M = gel(nfA,6);
     967           98 :   GEN zk = gel(etal, 2), T = gel(etal,3), den2 = sqri(den);
     968           98 :   long i, j, n = lg(th)-1, l = lg(al);
     969           98 :   GEN be = cgetg(n+1, t_COL);
     970              : 
     971          154 :   for (j = 1; j < l; j++)
     972              :   {
     973           98 :     GEN aj = gel(al, j), Aj = gel(A,j);
     974          371 :     for (i = 1; i <= n; i++)
     975              :     {
     976          273 :       GEN b = gsqrt(gmul(gsub(zz, gel(th,i)), gel(aj,i)), prec);
     977          273 :       gel(be,i) = gmul(b, den);
     978              :     }
     979          336 :     for (i = 0; i < (1<<(n-1)); i++)
     980              :     { /* n <= 3, by altering be[1] and be[2] we try all sign choices */
     981          280 :       GEN V, S = RgM_solve_realimag(M, be);
     982              :       long eps;
     983          280 :       gel(be,1+odd(i)) = gneg(gel(be,1+odd(i)));
     984          280 :       S = grndtoi(S, &eps); if (eps > -7) continue;
     985           42 :       V = QXQ_mul(Aj, QXQ_sqr(RgV_RgC_mul(zk, S), T), T);
     986           42 :       if (typ(V) != t_POL || degpol(V) != 1) continue;
     987           42 :       if (gequal0(gadd(gel(V,3), den2)))
     988              :       {
     989           42 :         GEN x = gdiv(gel(V,2), den2);
     990           42 :         return gc_upto(av, gadd(gmul(x, u2), r));
     991              :       }
     992              :     }
     993              :   }
     994           56 :   return gc_NULL(av);
     995              : }
     996              : 
     997              : /* lambdas[1] = gen_0, the others are t_REAL */
     998              : static GEN
     999         1785 : heegner_try_point(GEN E, GEN nfA, GEN lambdas, GEN ht, GEN z, long prec)
    1000              : {
    1001         1785 :   long l = lg(lambdas), i, eps;
    1002         1785 :   GEN P = real_i(pointell(E, z, prec)), x = gel(P,1);
    1003         1785 :   GEN rh = subrr(ht, shiftr(ellheightoo(E, P, prec),1));
    1004        26572 :   for (i = 1; i < l; ++i)
    1005              :   {
    1006        24829 :     GEN logd = shiftr(i == 1? rh: subrr(rh, gel(lambdas, i)), -1);
    1007        24829 :     GEN approxd = gexp(logd, prec), d = grndtoi(approxd, &eps);
    1008        24829 :     if (signe(d) > 0 && eps < -10)
    1009              :     {
    1010              :       GEN X, ylist;
    1011           98 :       if (DEBUGLEVEL > 2)
    1012            0 :         err_printf("\nTrying lambda number %ld, logd=%Ps, approxd=%Ps\n",
    1013              :                    i, logd, approxd);
    1014           98 :       X = heegner_descent_try_point(nfA, x, d, prec);
    1015           98 :       if (X)
    1016              :       {
    1017           42 :         ylist = ellordinate(E, X, prec);
    1018           42 :         if (lg(ylist) > 1)
    1019              :         {
    1020           42 :           GEN P = mkvec2(X, gel(ylist, 1));
    1021           42 :           GEN hp = ellheight(E,P,prec);
    1022           42 :           if (signe(hp) && cmprr(hp, shiftr(ht,1)) < 0
    1023           42 :                         && cmprr(hp, shiftr(ht,-1)) > 0)
    1024           42 :             return P;
    1025            0 :           if (DEBUGLEVEL)
    1026            0 :             err_printf("found non-Heegner point %Ps\n", P);
    1027              :         }
    1028              :       }
    1029              :     }
    1030              :   }
    1031         1743 :   return NULL;
    1032              : }
    1033              : 
    1034              : static GEN
    1035           42 : heegner_find_point(GEN e, GEN nfA, GEN om, GEN ht, GEN z1, long k, long prec)
    1036              : {
    1037           42 :   GEN lambdas = lambdalist(e, prec);
    1038           42 :   pari_sp av = avma;
    1039              :   long m;
    1040           42 :   GEN Ore = gel(om, 1), Oim = gel(om, 2);
    1041           42 :   if (DEBUGLEVEL)
    1042            0 :     err_printf("%ld*%ld multipliers to test: ",k,lg(lambdas)-1);
    1043          966 :   for (m = 0; m < k; m++)
    1044              :   {
    1045          966 :     GEN P, z2 = divru(addrr(z1, mulsr(m, Ore)), k);
    1046          966 :     if (DEBUGLEVEL > 2)
    1047            0 :       err_printf("%ld ",m);
    1048          966 :     P = heegner_try_point(e, nfA, lambdas, ht, z2, prec);
    1049          966 :     if (P) return P;
    1050          931 :     if (signe(ell_get_disc(e)) > 0)
    1051              :     {
    1052          819 :       z2 = gadd(z2, gmul2n(Oim, -1));
    1053          819 :       P = heegner_try_point(e, nfA, lambdas, ht, z2, prec);
    1054          819 :       if (P) return P;
    1055              :     }
    1056          924 :     set_avma(av);
    1057              :   }
    1058            0 :   pari_err_BUG("ellheegner, point not found");
    1059              :   return NULL; /* LCOV_EXCL_LINE */
    1060              : }
    1061              : 
    1062              : /* N > 1, fa = factor(N), return factor(4*N) */
    1063              : static GEN
    1064           42 : fa_shift2(GEN fa)
    1065              : {
    1066           42 :   GEN P = gel(fa,1), E = gel(fa,2);
    1067           42 :   if (absequaliu(gcoeff(fa,1,1), 2))
    1068              :   {
    1069           21 :     E = shallowcopy(E);
    1070           21 :     gel(E,1) = addiu(gel(E,1), 2);
    1071              :   }
    1072              :   else
    1073              :   {
    1074           21 :     P = shallowconcat(gen_2, P);
    1075           21 :     E = shallowconcat(gen_2, E);
    1076              :   }
    1077           42 :   return mkmat2(P, E);
    1078              : }
    1079              : 
    1080              : /* P = prime divisors of N(E). Return the product of primes p in P, a_p != -1
    1081              :  * HACK: restrict to small primes since large ones won't divide our C-long
    1082              :  * discriminants */
    1083              : static GEN
    1084           70 : get_bad(GEN E, GEN F)
    1085              : {
    1086           70 :   GEN P = gel(F,1), e = gel(F,2);
    1087           70 :   long k, l = lg(P), ibad = 1;
    1088           70 :   GEN B = cgetg(l, t_VECSMALL);
    1089          224 :   for (k = 1; k < l; k++)
    1090          154 :     if (is_pm1(gel(e,k)))
    1091              :     {
    1092           63 :       GEN p = gel(P,k);
    1093           63 :       long pp = itos_or_0(p);
    1094           63 :       if (!pp) break;
    1095           63 :       if (! equalim1(ellap(E,p))) B[ibad++] = pp;
    1096              :     }
    1097           70 :   setlg(B, ibad); return ibad == 1? NULL: zv_prod_Z(B);
    1098              : }
    1099              : 
    1100              : /* factorization into primary factors */
    1101              : static GEN
    1102           42 : to_primary(GEN fa)
    1103              : {
    1104           42 :   GEN Q, P = gel(fa,1), E = gel(fa,2);
    1105           42 :   long i, l = lg(P);
    1106           42 :   Q = cgetg(l, t_COL);
    1107          147 :   for (i = 1; i < l; i++) gel(Q,i) = powii(gel(P,i), gel(E,i));
    1108           42 :   return mkmat2(Q, const_col(l-1, gen_1));
    1109              : }
    1110              : 
    1111              : /* list of pairs [Q,N/Q], where Q || N, sorted by increasing Q. */
    1112              : static GEN
    1113           42 : find_div(GEN faN)
    1114              : {
    1115           42 :   GEN L, Q = divisors(to_primary(faN));
    1116           42 :   long k, l = lg(Q);
    1117           42 :   L = cgetg(l, t_VEC);
    1118          322 :   for (k = 1; k < l; k++) gel(L, k) = mkvec2(gel(Q,k), gel(Q,l-k));
    1119           42 :   return L;
    1120              : }
    1121              : 
    1122              : static long
    1123         8736 : testDisc(GEN bad, long d) { return !bad || ugcdiu(bad, -d) == 1; }
    1124              : /* bad = product of bad primes. Return the NDISC largest fundamental
    1125              :  * discriminants D < d such that (D,bad) = 1 and d is a square mod 4N */
    1126              : static GEN
    1127           42 : listDisc(GEN fa4N, GEN bad, long d, long ndisc)
    1128              : {
    1129           42 :   GEN v = cgetg(ndisc+1, t_VECSMALL);
    1130           42 :   pari_sp av = avma;
    1131           42 :   long j = 1;
    1132              :   for(;;)
    1133              :   {
    1134         8652 :     d -= odd(d)? 1: 3;
    1135         8652 :     if (testDisc(bad,d) && unegisfundamental(-d) && Zn_issquare(stoi(d), fa4N))
    1136              :     {
    1137          420 :       v[j++] = d;
    1138          420 :       if (j > ndisc) break;
    1139              :     }
    1140         8610 :     set_avma(av);
    1141              :   }
    1142           42 :   set_avma(av); return v;
    1143              : }
    1144              : 
    1145              : /* as normforms, but only return solution so that b = beta [mod Q] */
    1146              : static GEN
    1147       112483 : normformsbeta(GEN D, GEN fa, GEN beta, GEN Q)
    1148              : {
    1149       112483 :   pari_sp av = avma;
    1150              :   long i, j, k, lB, aN, sa;
    1151              :   GEN a, L, V, B, N, N2;
    1152       112483 :   int D_odd = mpodd(D);
    1153       112483 :   a = typ(fa) == t_INT ? fa: typ(fa) == t_VEC? gel(fa,1): factorback(fa);
    1154       112483 :   sa = signe(a);
    1155       112483 :   if (sa==0 || (signe(D)<0 && sa<0)) return NULL;
    1156         5530 :   V = D_odd? Zn_quad_roots(fa, gen_1, shifti(subsi(1, D), -2))
    1157       112483 :            : Zn_quad_roots(fa, gen_0, negi(shifti(D, -2)));
    1158       112483 :   if (!V) return NULL;
    1159        32403 :   N = gel(V,1); B = gel(V,2); lB = lg(B);
    1160        32403 :   N2 = shifti(N,1);
    1161        32403 :   aN = itou(diviiexact(a, N)); /* |a|/N */
    1162        32403 :   L = cgetg((lB-1)*aN+1, t_VEC);
    1163       188657 :   for (k = 1, i = 1; i < lB; i++)
    1164              :   {
    1165       156254 :     GEN b = shifti(gel(B,i), 1), c, C;
    1166       156254 :     if (D_odd) b = addiu(b, 1);
    1167       156254 :     c = diviiexact(shifti(subii(sqri(b), D), -2), a);
    1168       156254 :     for (j = 0;; b = addii(b, N2))
    1169              :     {
    1170       172382 :       if (dvdii(subii(b,beta),Q))
    1171       105833 :         gel(L, k++) = mkqfb(a, b, c, D);
    1172       172382 :       if (++j == aN) break;
    1173        16128 :       C = addii(b, N); if (aN > 1) C = diviuexact(C, aN);
    1174        16128 :       c = sa > 0? addii(c, C): subii(c, C);
    1175              :     }
    1176              :   }
    1177        32403 :   setlg(L, k); return gc_GEN(av, L);
    1178              : }
    1179              : 
    1180              : /* faN4 = factor(4*N) */
    1181              : static GEN
    1182          420 : listheegner(GEN N, GEN faN4, GEN listQ, GEN D)
    1183              : {
    1184          420 :   pari_sp av = avma;
    1185              :   hashtable H;
    1186          420 :   ulong h = itou(quadclassno(D));
    1187          420 :   GEN ymin, beta = Zn_sqrt(D, faN4), N2 = shifti(N, 1), L, V;
    1188              :   long l, k, n;
    1189          420 :   hash_init_GEN(&H, h, gequal, 1);
    1190         5740 :   for (k = 1; H.nb < h ; k++)
    1191              :   {
    1192         5320 :     GEN LF = normformsbeta(D, mulis(N, k), beta, N2);
    1193         5320 :     if (LF)
    1194              :     {
    1195         3990 :       long i, l = lg(LF);
    1196         8953 :       for (i = 1; i < l && H.nb < h; i++)
    1197              :       {
    1198         4963 :         GEN F = gel(LF, i), f = qfi_red(F), k = hash_haskey_GEN(&H, f);
    1199         4963 :         if (!k)
    1200              :         {
    1201         2478 :           GEN a = gel(F,1), b = gel(F,2), c = gel(F,3);
    1202         2478 :           GEN F2 = mkqfb(diviiexact(a,N), negi(b), mulii(c,N), D);
    1203         2478 :           GEN f2 = qfi_red(F2);
    1204         2478 :           if (gequal(f, f2))
    1205          322 :             hash_insert(&H, f, mkvec(F));
    1206              :           else
    1207              :           {
    1208         2156 :             hash_insert(&H, f, mkvec2(F, F2));
    1209         2156 :             hash_insert(&H, f2, cgetg(1,t_VEC));
    1210              :           }
    1211              :         }
    1212              :       }
    1213              :     }
    1214              :   }
    1215          420 :   ymin = NULL;
    1216          420 :   V = hash_values_GEN(&H); l = lg(V);
    1217          420 :   L = cgetg(H.nb+1, t_VEC);
    1218         5054 :   for (k = n = 1; k < l; k++)
    1219              :   {
    1220         4634 :     GEN t, Q, Vk = gel(V,k), y;
    1221         4634 :     long nk = lg(Vk) - 1;
    1222         4634 :     if (nk)
    1223              :     {
    1224         2478 :       y = lift_points(listQ, gel(Vk,1), &t, &Q);
    1225         2478 :       gel(L, n++) = mkvec3(t, stoi(nk), Q);
    1226         2478 :       if (!ymin || gcmp(y, ymin) < 0) ymin = y;
    1227              :     }
    1228              :   }
    1229          420 :   setlg(L, n); /* H.nb/2 <= n-1 <= H.nb */
    1230          420 :   if (DEBUGLEVEL > 1)
    1231            0 :     err_printf("Disc %Ps : N*ymin = %Pg\n", D,
    1232              :                            gmul(gsqrt(ymin, DEFAULTPREC),N));
    1233          420 :   return gc_GEN(av, mkvec3(ymin, L, D));
    1234              : }
    1235              : 
    1236              : /* Q | N, P = prime divisors of N, R[i] = local epsilon-factor at P[i].
    1237              :  * Return \prod_{p | Q} R[i] */
    1238              : static long
    1239          147 : rootno(GEN Q, GEN P, GEN R)
    1240              : {
    1241          147 :   long s = 1, i, l = lg(P);
    1242          581 :   for (i = 1; i < l; i++)
    1243          434 :     if (dvdii(Q, gel(P,i))) s *= R[i];
    1244          147 :   return s;
    1245              : }
    1246              : 
    1247              : static void
    1248           42 : heegner_find_disc(GEN *points, GEN *coefs, long *pind, GEN E,
    1249              :                   GEN indmult, long ndisc, long prec)
    1250              : {
    1251           42 :   long d = 0;
    1252              :   GEN faN4, bad, N, faN, listQ, listR;
    1253              : 
    1254           42 :   ellQ_get_Nfa(E, &N, &faN);
    1255           42 :   faN4 = fa_shift2(faN);
    1256           42 :   listQ = find_div(faN);
    1257           42 :   bad = get_bad(E, faN);
    1258           42 :   listR = gel(obj_check(E, Q_ROOTNO), 2);
    1259              :   for(;;)
    1260            0 :   {
    1261           42 :     pari_sp av = avma;
    1262           42 :     GEN list, listD = listDisc(faN4, bad, d, ndisc);
    1263           42 :     long k, l = lg(listD);
    1264           42 :     list = cgetg(l, t_VEC);
    1265          462 :     for (k = 1; k < l; ++k)
    1266          420 :       gel(list, k) = listheegner(N, faN4, listQ, stoi(listD[k]));
    1267           42 :     list = vecsort0(list, gen_1, 0);
    1268           56 :     for (k = l-1; k > 0; --k)
    1269              :     {
    1270           56 :       long bprec = 8;
    1271           56 :       GEN Lk = gel(list,k), D = gel(Lk,3);
    1272           56 :       GEN sqrtD = sqrtr_abs(itor(D, prec)); /* sqrt(|D|) */
    1273           56 :       GEN indmultD = heegner_indexmultD(faN, indmult, itos(D), sqrtD);
    1274              :       do
    1275              :       {
    1276              :         GEN mulf, indr;
    1277              :         pari_timer ti;
    1278           56 :         if (DEBUGLEVEL) timer_start(&ti);
    1279           56 :         mulf = ltwist1(E, D, bprec+expo(indmultD));
    1280           56 :         if (DEBUGLEVEL) timer_printf(&ti,"ellL1twist");
    1281           56 :         indr = mulrr(indmultD, mulf);
    1282           56 :         if (DEBUGLEVEL) err_printf("Disc = %Ps, Index^2 = %Ps\n", D, indr);
    1283           56 :         if (signe(indr)>0 && expo(indr) >= -1) /* indr >=.5 */
    1284              :         {
    1285              :           long e, i, l;
    1286           42 :           GEN pts, cfs, L, indi = grndtoi(sqrtr_abs(indr), &e);
    1287           42 :           if (e > expi(indi)-7)
    1288              :           {
    1289            0 :             bprec++;
    1290            0 :             pari_warn(warnprec, "ellL1",bprec);
    1291            0 :             continue;
    1292              :           }
    1293           42 :           *pind = itos(indi);
    1294           42 :           L = gel(Lk, 2); l = lg(L);
    1295           42 :           pts = cgetg(l, t_VEC);
    1296           42 :           cfs = cgetg(l, t_VECSMALL);
    1297          189 :           for (i = 1; i < l; ++i)
    1298              :           {
    1299          147 :             GEN P = gel(L,i), z = gel(P,2), Q = gel(P,3); /* [1 or 2, Q] */
    1300              :             long c;
    1301          147 :             gel(pts, i) = qfb_root(gel(P,1), sqrtD);
    1302          147 :             c = rootno(Q, gel(faN,1), listR);
    1303          147 :             if (!equali1(z)) c *= 2;
    1304          147 :             cfs[i] = c;
    1305              :           }
    1306           42 :           if (DEBUGLEVEL)
    1307            0 :             err_printf("N = %Ps, ymin*N = %Ps\n",N,
    1308            0 :                        gmul(gsqrt(gel(Lk, 1), prec),N));
    1309           42 :           *coefs = cfs; *points = pts; return;
    1310              :         }
    1311              :       } while(0);
    1312              :     }
    1313            0 :     d = listD[l-1]; set_avma(av);
    1314              :   }
    1315              : }
    1316              : 
    1317              : GEN
    1318          224 : ellanal_globalred_all(GEN e, GEN *cb, GEN *N, GEN *tam)
    1319              : {
    1320          224 :   GEN E = ellanal_globalred(e, cb), red = obj_check(E, Q_GLOBALRED);
    1321          224 :   *N = gel(red, 1);
    1322          224 :   if (tam)
    1323              :   {
    1324          154 :     *tam = gel(red,2);
    1325          154 :     if (signe(ell_get_disc(E))>0) *tam = shifti(*tam,1);
    1326              :   }
    1327          224 :   return E;
    1328              : }
    1329              : 
    1330              : static GEN
    1331           42 : vecelnfembed(GEN x, GEN M, GEN et)
    1332           91 : { pari_APPLY_same(gmul(M, etnf_to_basis(et, gel(x,i)))) }
    1333              : 
    1334              : static GEN
    1335           42 : QXQV_inv(GEN x, GEN T)
    1336           91 : { pari_APPLY_same(QXQ_inv(gel(x,i), T)) }
    1337              : 
    1338              : static GEN
    1339           42 : etnfnewprec(GEN x, long prec)
    1340          126 : { pari_APPLY_same(nfnewprec(gel(x,i),prec)) }
    1341              : 
    1342              : static GEN
    1343           49 : vec_etnf_to_basis(GEN et, GEN x)
    1344          154 : { pari_APPLY_same(etnf_to_basis(et,gel(x,i))) }
    1345              : 
    1346              : static GEN
    1347           42 : etnf_M(GEN et)
    1348              : {
    1349           42 :   long i, l = lg(et);
    1350           42 :   GEN V = cgetg(l, t_VEC);
    1351          126 :   for (i = 1; i < l; i++) gel(V,i) = nf_get_M(gel(et,i));
    1352           42 :   return shallowmatconcat(diagonal_shallow(V));
    1353              : }
    1354              : 
    1355              : static GEN
    1356           42 : makenfA(GEN sel, GEN A, GEN cb)
    1357              : {
    1358           42 :   GEN etal = gel(sel,1), T = gel(etal,3);
    1359           42 :   GEN et = gel(etal,1), M = etnf_M(et);
    1360           42 :   GEN al = vecelnfembed(A, M, et);
    1361           42 :   GEN th = gmul(M, etnf_to_basis(et, pol_x(etnf_get_varn(et))));
    1362           42 :   return mkvec6(etal,QXQV_inv(A, T),cb,al,th,M);
    1363              : }
    1364              : 
    1365              : static GEN
    1366           42 : ellheegner_z_i(GEN E, double ht, long *pindx,
    1367              :                GEN N, GEN tam, long wtor, long etor, long prec)
    1368              : {
    1369           42 :   GEN om = ellR_omega(E,prec), w1 = gel(om,1), w2 = gel(om,2);
    1370              :   GEN pts, cfs, s, z, indmult;
    1371           42 :   long ndisc = maxss(10, (long)(ht? ht: prec*M_LN2) / 10), ind, lint, k, l;
    1372              :   pari_timer ti;
    1373              : 
    1374              :   /* O_re*c(E) / (4*O_vol*|E_t|^2) */
    1375           42 :   indmult = divir(tam, mulru(gel(w2,2), 4*wtor*wtor)); setsigne(indmult,1);
    1376           42 :   heegner_find_disc(&pts, &cfs, &ind, E, indmult, ndisc, prec);
    1377              : 
    1378           42 :   if (DEBUGLEVEL) timer_start(&ti);
    1379           42 :   s = heegner_psi(E, N, pts, prec);
    1380           42 :   if (DEBUGLEVEL) timer_printf(&ti,"heegner_psi");
    1381              : 
    1382           42 :   l = lg(pts); z = mulsr(cfs[1], gel(s, 1));
    1383          147 :   for (k = 2; k < l; k++) z = addrr(z, mulsr(cfs[k], gel(s, k)));
    1384           42 :   z = subrr(z, mulri(w1, roundr(divrr(z, w1))));
    1385           42 :   if (DEBUGLEVEL) err_printf("z=%.*Pg\n", nbits2ndec(prec), z);
    1386              : 
    1387           42 :   lint = etor > 1 ? ugcd(ind, etor): 1;
    1388           42 :   *pindx = 2*lint*ind; return gmulsg(2*lint, z);
    1389              : }
    1390              : 
    1391              : /* set cb,N,tam from globalred, w cardinal of E(Q)_tor and e its exponent */
    1392              : static GEN
    1393           56 : ellheegner_init(GEN E, GEN *pcb, GEN *pN, GEN *ptam, long *pw, long *pe)
    1394              : {
    1395              :   GEN T;
    1396              :   long w;
    1397              : 
    1398           56 :   E = ellanal_globalred_all(E, pcb, pN, ptam);
    1399           56 :   if (ellrootno_global(E) == 1)
    1400            7 :     pari_err_DOMAIN("ellheegner", "(analytic rank)%2", "=", gen_0, E);
    1401           49 :   T = elltors(E); w = itou(abgrp_get_no(T));
    1402           49 :   *pe = lg(abgrp_get_cyc(T)) == 2? w: (w >> 1);
    1403           49 :   *pw = w; return E;
    1404              : }
    1405              : 
    1406              : GEN
    1407            0 : ellheegner_z(GEN E, long prec)
    1408              : {
    1409            0 :   pari_sp av = avma;
    1410              :   long indx, etor, wtor;
    1411              :   GEN N, tam, z;
    1412              : 
    1413            0 :   E = ellheegner_init(E, NULL, &N, &tam, &wtor, &etor);
    1414            0 :   z = ellheegner_z_i(E, 0., &indx, N, tam, wtor, etor, prec);
    1415            0 :   return gerepilecopy(av, mkvec2(z, utoi(indx)));
    1416              : }
    1417              : 
    1418              : GEN
    1419           56 : ellheegner(GEN E)
    1420              : {
    1421           56 :   pari_sp av = avma;
    1422              :   GEN N, tam, z, cb, P, ht, om, nfA, sel, etal, et, cbb, sbase, dAi, T, A, Ag;
    1423           56 :   long bitprec = 16, prec = nbits2prec(bitprec) + EXTRAPRECWORD;
    1424              :   long indx, wtor, etor, selrank;
    1425              :   pari_timer ti;
    1426              : 
    1427           56 :   E = ellheegner_init(E, &cb, &N, &tam, &wtor, &etor);
    1428           49 :   sel = ell2selmer_basis(E, &cbb, prec);
    1429           49 :   etal = gel(sel,1); sbase = gel(sel,2); et = gel(etal,1); T = gel(etal,3);
    1430           49 :   dAi = gsupnorm(vec_etnf_to_basis(et,sbase),prec);
    1431              :   while (1)
    1432           42 :   {
    1433              :     GEN hnaive, l1;
    1434              :     long bitneeded;
    1435           91 :     if (DEBUGLEVEL) timer_start(&ti);
    1436           91 :     l1 = ellL1(E, 1, bitprec);
    1437           91 :     if (DEBUGLEVEL) timer_printf(&ti,"ellL1");
    1438           91 :     if (expo(l1) < 1 - bitprec/2)
    1439            7 :       pari_err_DOMAIN("ellheegner", "analytic rank",">",gen_1,E);
    1440           84 :     om = ellR_omega(E,prec);
    1441           84 :     ht = divrr(mulru(l1, wtor * wtor), mulri(gel(om,1), tam));
    1442           84 :     if (DEBUGLEVEL) err_printf("Expected height=%Ps\n", ht);
    1443           84 :     hnaive = hnaive_max(E, ht);
    1444           84 :     if (DEBUGLEVEL) err_printf("Naive height <= %Ps\n", hnaive);
    1445           84 :     hnaive = gadd(shiftr(hnaive,-1), glog(dAi,prec));
    1446           84 :     bitneeded = itos(gceil(divrr(hnaive, mplog2(prec)))) + 32;
    1447           84 :     if (DEBUGLEVEL) err_printf("precision = %ld\n", bitneeded);
    1448           84 :     if (bitprec >= bitneeded) break;
    1449           42 :     bitprec = bitneeded;
    1450           42 :     prec = nbits2prec(bitprec) + EXTRAPRECWORD;
    1451              :   }
    1452           42 :   z = ellheegner_z_i(E, rtodbl(ht), &indx, N, tam, wtor, etor, prec);
    1453              : 
    1454           42 :   selrank = lg(sbase)-1;
    1455           42 :   Ag = selrank > lg(et)-1 ? pol_1(etnf_get_varn(et)): gel(sbase,selrank);
    1456           42 :   if (vals(indx) >= vals(etor))
    1457           35 :     A = mkvec(Ag);
    1458              :   else
    1459            7 :     A = mkvec2(Ag, QXQ_mul(Ag, gel(sbase,1), T));
    1460           42 :   gmael(sel,1,1) = etnfnewprec(et, prec);
    1461           42 :   nfA = makenfA(sel, A, cbb);
    1462           42 :   if (DEBUGLEVEL) timer_start(&ti);
    1463           42 :   P = heegner_find_point(E, nfA, om, ht, z, indx, prec);
    1464           42 :   if (DEBUGLEVEL) timer_printf(&ti,"heegner_find_point");
    1465           42 :   if (cb) P = ellchangepointinv(P, cb);
    1466           42 :   return gc_GEN(av, P);
    1467              : }
    1468              : 
    1469              : /* ellheegnertwist */
    1470              : 
    1471              : static GEN
    1472          105 : listheegnertwist(GEN Q, GEN D, GEN P, GEN Dt, long *kmax)
    1473              : {
    1474          105 :   pari_sp av = avma;
    1475              :   hashtable H;
    1476          105 :   GEN beta = Zn_sqrt(D, shifti(Q, 2)), Q2 = shifti(Q, 1);
    1477          105 :   GEN P2 = sqri(P), DP2 = mulii(D, P2);
    1478          105 :   long h = itos(quadclassno(DP2));
    1479          105 :   long k, s = 0;
    1480          105 :   hash_init_GEN(&H, h, gequal, 1);
    1481       107268 :   for (k = 1; s < h ; k++)
    1482              :   {
    1483       107163 :     GEN LF = normformsbeta(D, mulis(Q, k), beta, Q2);
    1484       107163 :     if (LF)
    1485              :     {
    1486        28413 :       long i, l = lg(LF);
    1487       129066 :       for (i = 1; i < l && s < h; i++)
    1488              :       {
    1489       100653 :         GEN F = gel(LF, i), a = gel(F,1), b = gel(F,2), c = gel(F,3);
    1490       100653 :         GEN bi = mulii(P,b), ci = mulii(P2, c);
    1491       100653 :         if (is_pm1(gcdii(gcdii(a, bi), ci)))
    1492              :         {
    1493        65730 :           GEN f = qfi_red(mkqfb(a,bi,ci,DP2)), k = hash_haskey_GEN(&H, f);
    1494        65730 :           long e = kronecker(Dt,a);
    1495        65730 :           if (!k)
    1496              :           {
    1497         2667 :             hash_insert(&H, f, mkvec2(mkvec3(a,b,c),stoi(e)));
    1498         2667 :             s += !!e;
    1499        63063 :           } else if (e && signe(gel(k,2))==0)
    1500              :           {
    1501          700 :             gel(k,2) = stoi(e); s++;
    1502              :           }
    1503              :         }
    1504              :       }
    1505              :     }
    1506              :   }
    1507          105 :   *kmax = k-1;
    1508          105 :   return gc_GEN(av, hash_values_GEN(&H));
    1509              : }
    1510              : 
    1511              : static GEN
    1512           35 : findtwist(GEN E, GEN *pt_D)
    1513              : {
    1514           35 :   GEN d = ellminimaltwistcond(E), N, F, P, Ex, D = *pt_D;
    1515              :   long i, l;
    1516           35 :   D = coredisc(mulii(D,d));
    1517           35 :   E = elltwist(E, d);
    1518           35 :   ellanal_globalred_all(E, NULL, &N, NULL);
    1519           35 :   F = Z_factor(gcdii(absi(D),N));
    1520           35 :   P = gel(F,1); Ex = gel(F,2); l = lg(P);
    1521           42 :   for (i = 1; i < l; i++)
    1522              :   {
    1523            7 :     GEN p = gel(P,i), e = gel(Ex,i), q = powii(p, e);
    1524            7 :     if (is_pm1(gcdii(q,diviiexact(N,q)))) continue;
    1525            0 :     d = cmpiu(p,2)>0 ? mod4(p)== 1 ? p : negi(p) : shifti( Mod8(D)==4 ? gen_m1: Mod32(D)==8 ? gen_1:gen_m1,vali(D));
    1526            0 :     E = elltwist(E, d); D = coredisc(mulii(D,d));
    1527              :   }
    1528           35 :   *pt_D = D;
    1529           35 :   return ellminimalmodel(E,NULL);
    1530              : }
    1531              : 
    1532              : /* ellheegnertwist */
    1533              : 
    1534              : static GEN
    1535          770 : finddivis(GEN E, GEN T, GEN z, long n, long prec)
    1536              : {
    1537          770 :   pari_sp av = avma;
    1538          770 :   long i, j, k, l = lg(T);
    1539          770 :   GEN om = ellR_omega(E, prec);
    1540          770 :   GEN om1 = gdivgs(gel(om,1),n), om2 = gmul2n(gel(om,2),-1);
    1541          770 :   z = gdivgs(z, n); T = gdivgs(T,n);
    1542        46249 :   for (i = 0; i < n; i++)
    1543              :   {
    1544       135709 :     for (j = 1; j < l; j++)
    1545              :     {
    1546        90230 :       GEN w = gadd(z,gel(T,j));
    1547       270277 :       for(k = 0; k < (odd(n)?1:2); k++)
    1548              :       {
    1549       180082 :         GEN x2, y2, P = pointell(E,w,prec);
    1550       180082 :         if (ell_is_inf(P)) return P;
    1551       180082 :         x2 = bestappr(real_i(gel(P,1)), int2n((prec>>1)-1));
    1552       180082 :         if (lg(x2)==1) continue;
    1553       180082 :         y2 = ellordinate(E, x2, prec);
    1554       180082 :         if (lg(y2)>1) return gc_GEN(av, mkvec2(x2, gel(y2,1)));
    1555       180047 :         w = gadd(z, om2);
    1556              :       }
    1557              :     }
    1558        45479 :     z = gadd(z, om1);
    1559              :   }
    1560          735 :   return gc_NULL(av);
    1561              : }
    1562              : 
    1563              : static GEN
    1564          147 : listpointstwist(GEN D, GEN L, long prec)
    1565              : {
    1566          147 :   GEN vDi = gsqrt(D, prec);
    1567              :   long k, l;
    1568          147 :   GEN V = cgetg_copy(L, &l);
    1569         3360 :   for (k = 1; k < l; k++)
    1570              :   {
    1571         3213 :     GEN Lk = gel(L,k), v = gel(Lk, 1);
    1572         3213 :     gel(V,k) = mkvec2(gdiv(gsub(vDi,gel(v,2)),shifti(gel(v,1),1)),gel(Lk,2));
    1573              :   }
    1574          147 :   return V;
    1575              : }
    1576              : 
    1577              : static GEN
    1578      5836413 : _gen_cmul(void *E, GEN an, long i, GEN x)
    1579              : {
    1580      5836413 :   (void) E; return i ? gdivgs(gmulgs(x, an[i]), i): gen_0;
    1581              : }
    1582              : 
    1583              : static GEN
    1584         2505 : heegnersum(GEN an, long nb, GEN z, long r)
    1585              : {
    1586         2505 :   GEN q = gen_bkeval(an, nb, z, 1, NULL, get_Rg_algebra(), _gen_cmul);
    1587         2506 :   return r>0 ? real_i(q) : imag_i(q);
    1588              : }
    1589              : 
    1590              : GEN
    1591         2503 : heegnersum_worker(GEN l, GEN an, long r, long prec)
    1592              : {
    1593         2503 :   pari_sp av = avma;
    1594         2503 :   long nb = ceil(prec*M_LN2/(2*M_PI*rtodbl(imag_i(gel(l,1)))));
    1595         2502 :   return gc_upto(av, gmul(gel(l,2), heegnersum(an, nb, expIPiC(gmul2n(gel(l,1),1), prec), r)));
    1596              : }
    1597              : 
    1598              : static GEN
    1599          112 : sumheegner(GEN an, GEN L, long r, long prec)
    1600              : {
    1601          112 :   pari_sp av = avma;
    1602          112 :   GEN worker = snm_closure(is_entry("_heegnersum_worker"),mkvec3(an,stoi(r),stoi(prec)));
    1603              :   GEN V;
    1604          112 :   if (DEBUGLEVEL>1) err_printf("ellheegnertwist: Computing sum with prec %ld: ",prec);
    1605          112 :   V = gen_parapply_percent(worker, L, DEBUGLEVEL>1);
    1606          112 :   if (DEBUGLEVEL>1) err_printf(" done.\n");
    1607          112 :   return gc_upto(av, vecsum(V));
    1608              : }
    1609              : 
    1610              : static GEN
    1611          112 : torstoz(GEN E, GEN ET, long prec)
    1612              : {
    1613          112 :   long n = itos(abgrp_get_no(ET));
    1614              :   GEN cyc, gen, g1, g2;
    1615              :   long o1, i;
    1616          112 :   GEN V = cgetg(n+1, t_VEC);
    1617          112 :   gel(V,1) = gen_0;
    1618          112 :   if (n == 1) return V;
    1619           63 :   cyc  = abgrp_get_cyc(ET);
    1620           63 :   gen  = abgrp_get_gen(ET);
    1621           63 :   g1 = zell(E, gel(gen,1), prec);
    1622           63 :   o1 = itos(gel(cyc,1));
    1623          126 :   for (i = 2; i <= o1; i++)
    1624           63 :     gel(V,i) = gmulgs(g1,i-1);
    1625           63 :   if (lg(cyc)==2) return V;
    1626            7 :   g2 = zell(E, gel(gen,2), prec);
    1627           21 :   for (i = o1+1; i <=n; i++)
    1628           14 :     gel(V,i) = gadd(g2, gel(V,i-o1));
    1629            7 :   return V;
    1630              : }
    1631              : 
    1632              : static GEN
    1633           35 : findpoint(GEN E, GEN N, GEN D, GEN d, GEN f, long manin, GEN s, long prec)
    1634              : {
    1635              :   long kmax, m;
    1636              :   GEN AL, LH, Ed, ET, tam, faN, R;
    1637              :   double mR;
    1638           35 :   AL = diviiexact(N,f);
    1639           35 :   if (!Zn_issquare(D,shifti(AL,2))) pari_err_BUG("findpoint");
    1640           35 :   LH = listheegnertwist(AL, D, f, d, &kmax);
    1641           35 :   Ed = elltwist(E, d); ET= elltors(Ed);
    1642           35 :   m = ellmanintable_heuristic(Ed);
    1643           35 :   tam = elltamagawa(Ed); faN = Z_factor(mulii(N,sqri(d)));
    1644           35 :   R = imag_i(row(listpointstwist(D, LH, MEDDEFAULTPREC),1));
    1645           35 :   mR = M_LN2/(2*M_PI*rtodbl(vecmin(R)));
    1646           35 :   if (DEBUGLEVEL > 2)
    1647            0 :      err_printf("Heegnertwist: min imag: %.9g, h = %ld\n",mR, lg(LH)-1);
    1648           77 :   for (;;prec*=2)
    1649           77 :   {
    1650              :     long i, lD;
    1651          112 :     GEN T = torstoz(Ed, ET, prec), dv, M, z;
    1652          112 :     GEN L = listpointstwist(D, LH, prec+EXTRAPREC64);
    1653          112 :     long nb = ceil(prec*mR);
    1654          112 :     if (DEBUGLEVEL > 2) err_printf("Heegnertwist: nb = %ld, prec = %ld\n",nb, prec);
    1655          112 :     z = sumheegner(ellanQ_zv(E, nb), L, signe(d), prec);
    1656          112 :     z = gmulgs(gdiv(z, gsqrt(absi(d), prec)), 2*manin);
    1657          112 :     M = mulii(shifti(tam, omega_N_D(faN,-itos(D))), mulsi(m,s));
    1658          112 :     M = mulis(M, get_w(itos_or_0(d)));
    1659          112 :     dv = divisors(M); lD = lg(dv);
    1660          847 :     for (i = 1; i < lD; i++)
    1661              :     {
    1662          770 :       ulong di = itou_or_0(gel(dv,i));
    1663          770 :       if (di)
    1664              :       {
    1665          770 :         GEN P = finddivis(Ed, T, z, di, prec);
    1666          770 :         if (!P) continue;
    1667           35 :         if (!signe(ellorder(Ed, P, NULL)))
    1668           35 :           return P;
    1669            0 :         else if (i==1) return NULL;
    1670              :       }
    1671              :     }
    1672              :   }
    1673              : }
    1674              : 
    1675              : static GEN
    1676           35 : heegnertwistdisc(GEN *ptD, GEN N, GEN d, GEN f, GEN g, GEN F, GEN bad, long n)
    1677              : {
    1678           35 :   GEN D = *ptD, p, f2  = sqri(f), AL = diviiexact(N,f);
    1679           35 :   GEN L = cgetg(n+1, t_VEC);
    1680           35 :   GEN h = cgetg(n+1, t_VEC);
    1681           35 :   GEN lh = cgetg(n+1, t_VEC);
    1682              :   long i, kmax;
    1683          105 :   for (i = 1; i <= n; i++)
    1684              :   {
    1685              :     for (;;)
    1686              :     {
    1687          224 :       D = subii(D, g);
    1688          224 :       if (Mod4(D)<=1 && Zn_issquare(D, F) && testDisc(bad, itos(D)))
    1689              :       {
    1690           84 :         GEN r, q = dvmdii(mulii(D, f2), d, &r);
    1691           84 :         if (signe(r)==0 && Mod4(q)<=1) break;
    1692              :       }
    1693              :     }
    1694           70 :     gel(L,i) = D;
    1695           70 :     gel(lh,i)= listheegnertwist(AL, D, f, d, &kmax);
    1696           70 :     gel(h,i) = gdiv(gdivgs(D,kmax),gsqr(quadclassno(D)));
    1697              :   }
    1698           35 :   *ptD = D;
    1699           35 :   p = indexsort(h);
    1700           35 :   return vecpermute(L, p);
    1701              : }
    1702              : 
    1703              : /* Algorithm by BA inspired by
    1704              : Mock Heegner Points and Congruent Numbers
    1705              : Paul Monsky
    1706              : Mathematische Zeitschrift (1990) Volume: 204, Issue: 1, page 45-68
    1707              : ISSN: 0025-5874; 1432-1823
    1708              : https://gdz.sub.uni-goettingen.de/id/PPN266833020_0204
    1709              : https://link.springer.com/article/10.1007/BF02570859
    1710              : 
    1711              : Regulators of rank one quadratic twists
    1712              : Christophe Delaunay, Xavier-Francois Roblot
    1713              : Journal de theorie des nombres de Bordeaux, Tome 20 (2008) no. 3, pp. 601-624
    1714              : https://jtnb.centre-mersenne.org/item/10.5802/jtnb.643.pdf
    1715              : */
    1716              : 
    1717              : GEN
    1718           35 : ellheegnertwist(GEN E, GEN d, GEN s)
    1719              : {
    1720           35 :   pari_sp av = avma;
    1721           35 :   GEN Et, Ed, iso, N, D1 = gen_0, P, f, f2, g, F, bad, F2;
    1722           35 :   long m, prec = DEFAULTPREC;
    1723           35 :   checkell(E);
    1724           35 :   if (!s) s = gen_1;
    1725            7 :   else if (typ(s)!=t_INT || signe(s)<=0)
    1726            0 :     pari_err_TYPE("ellheegnertwist",s);
    1727           35 :   if (d)
    1728              :   {
    1729           21 :     if (typ(d) != t_INT)
    1730            0 :       pari_err_TYPE("ellheegnertwist",d);
    1731           21 :     Et = elltwist(E,d);
    1732              :   }
    1733           14 :   else { d = gen_1; Et = E; }
    1734           35 :   if (ellrootno_global(Et) == 1)
    1735            0 :     pari_err_DOMAIN("ellheegnertwist", "(analytic rank)%2","=",gen_0,E);
    1736           35 :   E = findtwist(E, &d);
    1737           35 :   if (DEBUGLEVEL>1) err_printf("ellheegnertwist: using disc. %Ps\n",d);
    1738           35 :   m = ellmanintable_heuristic(E);
    1739           35 :   Ed = elltwist(E, d);
    1740           35 :   ellanal_globalred_all(E, NULL, &N, NULL);
    1741           35 :   iso = ellisisom(Et, Ed);
    1742           35 :   f = gcdii(N,d); f2 = sqri(f);
    1743           35 :   g = diviiexact(absi(d), gcdii(d, f2));
    1744           35 :   F = Z_factor(diviiexact(N, f));
    1745           35 :   F2 = famat_reduce(famat_mul(mkmat2(mkcol(gen_2), mkcol(gen_2)),F));
    1746           35 :   bad = equalii(N,f) ? NULL: get_bad(Ed, F);
    1747              :   for(;;)
    1748            0 :   {
    1749           35 :     const long n = 2;
    1750           35 :     GEN L =  heegnertwistdisc(&D1, N, d, f, g, F2, bad, n);
    1751              :     long i;
    1752           35 :     for(i = 1; i <= n; i++)
    1753              :     {
    1754           35 :       GEN Di = gel(L,i);
    1755           35 :       if (DEBUGLEVEL > 1)
    1756            0 :         err_printf("ellheegnertwist: using secondary disc. %Ps\n", Di);
    1757           35 :       P = findpoint(E, N, Di, d, f, m, s, prec);
    1758           35 :       if (P) return gc_GEN(av, ellchangepointinv(P, iso));
    1759            0 :       if (DEBUGLEVEL)
    1760            0 :         err_printf("ellheegnertwist: point is torsion for D=%Ps\n", Di);
    1761              :     }
    1762              :   }
    1763              : }
    1764              : 
    1765              : /* Modular degree */
    1766              : 
    1767              : static GEN
    1768           70 : ellisobound(GEN e)
    1769              : {
    1770           70 :   GEN M = gel(ellisomat(e,0,1),2);
    1771           70 :   return vecmax(gel(M,1));
    1772              : }
    1773              : /* 4Pi^2 / E.area */
    1774              : static GEN
    1775          140 : getA(GEN E, long prec) { return divrr(sqrr(Pi2n(1,prec)), ellR_area(E, prec)); }
    1776              : 
    1777              : /* Modular degree of elliptic curve e over Q, assuming Manin constant = 1
    1778              :  * (otherwise multiply by square of Manin constant). */
    1779              : GEN
    1780           70 : ellmoddegree(GEN E)
    1781              : {
    1782           70 :   pari_sp av = avma;
    1783              :   GEN N, tam, mc2, d;
    1784              :   long b;
    1785           70 :   E = ellanal_globalred_all(E, NULL, &N, &tam);
    1786           70 :   mc2 = sqri(ellisobound(E));
    1787           70 :   b = expi(mulii(N, mc2)) + maxss(0, expo(getA(E, LOWDEFAULTPREC))) + 16;
    1788              :   for(;;)
    1789            0 :   {
    1790           70 :     long prec = nbits2prec(b), e, s;
    1791           70 :     GEN deg = mulri(mulrr(lfunellmfpeters(E, b), getA(E, prec)), mc2);
    1792           70 :     d = grndtoi(deg, &e);
    1793           70 :     if (DEBUGLEVEL) err_printf("ellmoddegree: %Ps, bit=%ld, err=%ld\n",deg,b,e);
    1794           70 :     s = expo(deg);
    1795           70 :     if (e <= -8 && s <= b-8) return gc_upto(av, gdiv(d,mc2));
    1796            0 :     b = maxss(s, b+e) + 16;
    1797              :   }
    1798              : }
        

Generated by: LCOV version 2.0-1