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 - elltrans.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.19.0 lcov report (development 31057-89c4d54ba6) Lines: 93.1 % 1484 1381
Test Date: 2026-07-25 17:02:42 Functions: 97.4 % 117 114
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : /********************************************************************/
      16              : /**                                                                **/
      17              : /**               ELLIPTIC and MODULAR FUNCTIONS                   **/
      18              : /**              (as complex or p-adic functions)                   **/
      19              : /**                                                                **/
      20              : /********************************************************************/
      21              : #include "pari.h"
      22              : #include "paripriv.h"
      23              : 
      24              : #define DEBUGLEVEL DEBUGLEVEL_ell
      25              : 
      26              : /* add3, add4, mul3, mul4 and these 2 should be exported as convenience
      27              :  * functions (cf dirichlet.c, lfunlarge.c, hypergeom.c) */
      28              : static GEN
      29          406 : gadd3(GEN a, GEN b, GEN c) { return gadd(gadd(a, b), c); }
      30              : static GEN
      31       182574 : gmul3(GEN a, GEN b, GEN c) { return gmul(gmul(a, b), c); }
      32              : static GEN
      33       181909 : gmul4(GEN a, GEN b, GEN c, GEN d) { return gmul(gmul(a, b), gmul(c,d)); }
      34              : 
      35              : /********************************************************************/
      36              : /**        exp(I*Pi*x) with attention to rational arguments        **/
      37              : /********************************************************************/
      38              : 
      39              : /* sqrt(3)/2 */
      40              : static GEN
      41         2079 : sqrt32(long prec) { GEN z = sqrtr_abs(utor(3,prec)); setexpo(z, -1); return z; }
      42              : /* exp(i k pi/12)  */
      43              : static GEN
      44        91155 : e12(ulong k, long prec)
      45              : {
      46              :   int s, sPi, sPiov2;
      47              :   GEN z, t;
      48        91155 :   k %= 24;
      49        91155 :   if (!k) return gen_1;
      50        91148 :   if (k == 12) return gen_m1;
      51        91148 :   if (k >12) { s = 1; k = 24 - k; } else s = 0; /* x -> 2pi - x */
      52        91148 :   if (k > 6) { sPi = 1; k = 12 - k; } else sPi = 0; /* x -> pi  - x */
      53        91148 :   if (k > 3) { sPiov2 = 1; k = 6 - k; } else sPiov2 = 0; /* x -> pi/2 - x */
      54        91148 :   z = cgetg(3, t_COMPLEX);
      55        91148 :   switch(k)
      56              :   {
      57        88195 :     case 0: gel(z,1) = icopy(gen_1); gel(z,2) = gen_0; break;
      58          777 :     case 1: t = gmul2n(addrs(sqrt32(prec), 1), -1);
      59          777 :       gel(z,1) = sqrtr(t);
      60          777 :       gel(z,2) = gmul2n(invr(gel(z,1)), -2); break;
      61              : 
      62         1302 :     case 2: gel(z,1) = sqrt32(prec);
      63         1302 :             gel(z,2) = real2n(-1, prec); break;
      64              : 
      65          874 :     case 3: gel(z,1) = sqrtr_abs(real2n(-1,prec));
      66          874 :             gel(z,2) = rcopy(gel(z,1)); break;
      67              :   }
      68        91148 :   if (sPiov2) swap(gel(z,1), gel(z,2));
      69        91148 :   if (sPi) togglesign(gel(z,1));
      70        91148 :   if (s)   togglesign(gel(z,2));
      71        91148 :   return z;
      72              : }
      73              : /* z a t_FRAC */
      74              : static GEN
      75       128098 : expIPifrac(GEN z, long prec)
      76              : {
      77       128098 :   GEN n = gel(z,1), d = gel(z,2);
      78       128098 :   ulong r, q = uabsdivui_rem(12, d, &r);
      79       128098 :   if (!r) return e12(q * umodiu(n, 24), prec); /* d | 12 */
      80        36992 :   n = centermodii(n, shifti(d,1), d);
      81        36992 :   return expIr(divri(mulri(mppi(prec), n), d));
      82              : }
      83              : /* exp(i Pi z), z a t_INT or t_FRAC */
      84              : GEN
      85         2170 : expIPiQ(GEN z, long prec)
      86              : {
      87         2170 :   if (typ(z) == t_INT) return mpodd(z)? gen_m1: gen_1;
      88         1974 :   return expIPifrac(z, prec);
      89              : }
      90              : 
      91              : /* convert power of 2 t_REAL to rational */
      92              : static GEN
      93       160560 : real2nQ(GEN x)
      94              : {
      95       160560 :   long e = expo(x);
      96              :   GEN z;
      97       160560 :   if (e < 0)
      98       113867 :     z = mkfrac(signe(x) < 0? gen_m1: gen_1, int2n(-e));
      99              :   else
     100              :   {
     101        46693 :     z = int2n(e);
     102        46693 :     if (signe(x) < 0) togglesign_safe(&z);
     103              :   }
     104       160560 :   return z;
     105              : }
     106              : 
     107              : /* round t_REAL x to 0 or 2^n if close to such a value */
     108              : static GEN
     109       754842 : mayberound(GEN x, long prec)
     110              : {
     111       754842 :   if (!signe(x))
     112              :   {
     113       262075 :     if (expo(x) <= -prec) x = gen_0;
     114              :   }
     115              :   else
     116       492767 :     if (absrnz_equal2n(x)) x = real2nQ(x);
     117       754842 :   return x;
     118              : }
     119              : /* x a real number */
     120              : GEN
     121       192067 : expIPiR(GEN x, long prec)
     122              : {
     123       192067 :   if (typ(x) == t_REAL) x = mayberound(x, prec);
     124       192067 :   switch(typ(x))
     125              :   {
     126         3929 :     case t_INT:  return mpodd(x)? gen_m1: gen_1;
     127         1763 :     case t_FRAC: return expIPifrac(x, prec);
     128              :   }
     129       186375 :   return expIr(mulrr(mppi(prec), x));
     130              : }
     131              : /* z a t_COMPLEX */
     132              : GEN
     133       783654 : expIPiC(GEN z, long prec)
     134              : {
     135              :   GEN pi, r, x, y;
     136       783654 :   if (typ(z) != t_COMPLEX) return expIPiR(z, prec);
     137       592631 :   x = gel(z,1);
     138       592631 :   y = gel(z,2); if (gequal0(y)) return expIPiR(x, prec);
     139       591587 :   pi = mppi(prec);
     140       591587 :   r = gmul(pi, y); togglesign(r); r = mpexp(r); /* exp(-pi y) */
     141       591587 :   if (typ(x) == t_REAL) x = mayberound(x, prec);
     142       591587 :   switch(typ(x))
     143              :   {
     144       315751 :     case t_INT: if (mpodd(x)) togglesign(r);
     145       315751 :                 return r;
     146       124361 :     case t_FRAC: return gmul(r, expIPifrac(x, prec));
     147              :   }
     148       151475 :   return gmul(r, expIr(mulrr(pi, x)));
     149              : }
     150              : /* exp(I x y), more efficient for x in R, y pure imaginary */
     151              : GEN
     152          147 : expIxy(GEN x, GEN y, long prec) { return gexp(gmul(x, mulcxI(y)), prec); }
     153              : 
     154              : /********************************************************************/
     155              : /**                       PERIODS                                  **/
     156              : /********************************************************************/
     157              : /* The complex AGM, periods of elliptic curves over C and complex elliptic
     158              :  * logarithms; John E. Cremona, Thotsaphon Thongjunthug, arXiv:1011.0914 */
     159              : 
     160              : static GEN
     161        52577 : ellomega_agm(GEN a, GEN b, GEN c, long prec)
     162              : {
     163        52577 :   GEN pi = mppi(prec), mIpi = mkcomplex(gen_0, negr(pi));
     164        52577 :   GEN Mac = agm(a,c,prec), Mbc = agm(b,c,prec);
     165        52577 :   retmkvec2(gdiv(pi, Mac), gdiv(mIpi, Mbc));
     166              : }
     167              : 
     168              : static GEN
     169        42864 : ellomega_cx(GEN E, long prec)
     170              : {
     171        42864 :   pari_sp av = avma;
     172        42864 :   GEN roots = ellR_roots(E, prec + EXTRAPREC64);
     173        42864 :   GEN d1=gel(roots,4), d2=gel(roots,5), d3=gel(roots,6);
     174        42864 :   GEN a = gsqrt(d3,prec), b = gsqrt(d1,prec), c = gsqrt(d2,prec);
     175        42864 :   return gc_upto(av, ellomega_agm(a,b,c,prec));
     176              : }
     177              : 
     178              : /* return [w1,w2] for E / R; w1 > 0 is real.
     179              :  * If e.disc > 0, w2 = -I r; else w2 = w1/2 - I r, for some real r > 0.
     180              :  * => tau = w1/w2 is in upper half plane */
     181              : static GEN
     182        52577 : doellR_omega(GEN E, long prec)
     183              : {
     184        52577 :   pari_sp av = avma;
     185              :   GEN roots, d2, z, a, b, c;
     186        52577 :   if (ellR_get_sign(E) >= 0) return ellomega_cx(E,prec);
     187         9713 :   roots = ellR_roots(E,prec + EXTRAPREC64);
     188         9713 :   d2 = gel(roots,5);
     189         9713 :   z = gsqrt(d2,prec); /* imag(e1-e3) > 0, so that b > 0*/
     190         9713 :   a = gel(z,1); /* >= 0 */
     191         9713 :   b = gel(z,2);
     192         9713 :   c = gabs(z, prec);
     193         9713 :   z = ellomega_agm(a,b,c,prec);
     194         9713 :   return gc_GEN(av, mkvec2(gel(z,1),gmul2n(gadd(gel(z,1),gel(z,2)),-1)));
     195              : }
     196              : static GEN
     197           70 : doellR_eta(GEN E, long prec)
     198           70 : { GEN w = ellR_omega(E, prec + EXTRAPREC64); return elleta(w, prec); }
     199              : 
     200              : GEN
     201       273833 : ellR_omega(GEN E, long prec)
     202       273833 : { return obj_checkbuild_realprec(E, R_PERIODS, &doellR_omega, prec); }
     203              : GEN
     204           98 : ellR_eta(GEN E, long prec)
     205           98 : { return obj_checkbuild_realprec(E, R_ETA, &doellR_eta, prec); }
     206              : 
     207              : /* P = [x,0] is 2-torsion on y^2 = g(x). Return w1/2, (w1+w2)/2, or w2/2
     208              :  * depending on whether x is closest to e1,e2, or e3, the 3 complex root of g */
     209              : static GEN
     210           56 : zell_closest_0(GEN om, GEN x, GEN ro)
     211              : {
     212           56 :   GEN e1 = gel(ro,1), e2 = gel(ro,2), e3 = gel(ro,3);
     213           56 :   GEN d1 = gnorm(gsub(x,e1));
     214           56 :   GEN d2 = gnorm(gsub(x,e2));
     215           56 :   GEN d3 = gnorm(gsub(x,e3));
     216           56 :   GEN z = gel(om,2);
     217           56 :   if (gcmp(d1, d2) <= 0)
     218            0 :   { if (gcmp(d1, d3) <= 0) z = gel(om,1); }
     219              :   else
     220           56 :   { if (gcmp(d2, d3)<=0) z = gadd(gel(om,1),gel(om,2)); }
     221           56 :   return gmul2n(z, -1);
     222              : }
     223              : 
     224              : static GEN
     225        28735 : zellcx(GEN E, GEN P, long prec)
     226              : {
     227        28735 :   GEN R = ellR_roots(E, prec+EXTRAPREC64);
     228        28735 :   GEN x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P);
     229        28735 :   if (gequal0(y0))
     230            0 :     return zell_closest_0(ellomega_cx(E,prec),x0,R);
     231              :   else
     232              :   {
     233        28735 :     GEN e2 = gel(R,2), e3 = gel(R,3), d2 = gel(R,5), d3 = gel(R,6);
     234        28735 :     GEN a = gsqrt(d2,prec), b = gsqrt(d3,prec);
     235        28735 :     GEN r = gsqrt(gdiv(gsub(x0,e3), gsub(x0,e2)),prec);
     236        28735 :     GEN t = gdiv(gneg(y0), gmul2n(gmul(r,gsub(x0,e2)),1));
     237        28735 :     GEN ar = real_i(a), br = real_i(b), ai = imag_i(a), bi = imag_i(b);
     238              :     /* |a+b| < |a-b| */
     239        28735 :     if (gcmp(gmul(ar,br), gneg(gmul(ai,bi))) < 0) b = gneg(b);
     240        28735 :     return zellagmcx(a,b,r,t,prec);
     241              :   }
     242              : }
     243              : 
     244              : /* Assume E/R, disc E < 0, and P \in E(R) ==> z \in R */
     245              : static GEN
     246           28 : zellrealneg(GEN E, GEN P, long prec)
     247              : {
     248           28 :   GEN x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P);
     249           28 :   if (gequal0(y0)) return gmul2n(gel(ellR_omega(E,prec),1),-1);
     250              :   else
     251              :   {
     252            0 :     GEN R = ellR_roots(E, prec+EXTRAPREC64);
     253            0 :     GEN d2 = gel(R,5), e3 = gel(R,3);
     254            0 :     GEN a = gsqrt(d2,prec);
     255            0 :     GEN z = gsqrt(gsub(x0,e3), prec);
     256            0 :     GEN ar = real_i(a), zr = real_i(z), ai = imag_i(a), zi = imag_i(z);
     257            0 :     GEN t = gdiv(gneg(y0), gmul2n(gnorm(z),1));
     258            0 :     GEN r2 = ginv(gsqrt(gaddsg(1,gdiv(gmul(ai,zi),gmul(ar,zr))),prec));
     259            0 :     return zellagmcx(ar,gabs(a,prec),r2,gmul(t,r2),prec);
     260              :   }
     261              : }
     262              : 
     263              : /* Assume E/R, disc E > 0, and P \in E(R) */
     264              : static GEN
     265           70 : zellrealpos(GEN E, GEN P, long prec)
     266              : {
     267           70 :   GEN R = ellR_roots(E, prec+EXTRAPREC64);
     268           70 :   GEN d2,d3,e1,e2,e3, a,b, x0 = gel(P,1), y0 = ec_dmFdy_evalQ(E,P);
     269           70 :   if (gequal0(y0)) return zell_closest_0(ellR_omega(E,prec), x0,R);
     270           14 :   e1 = gel(R,1);
     271           14 :   e2 = gel(R,2);
     272           14 :   e3 = gel(R,3);
     273           14 :   d2 = gel(R,5);
     274           14 :   d3 = gel(R,6);
     275           14 :   a = gsqrt(d2,prec);
     276           14 :   b = gsqrt(d3,prec);
     277           14 :   if (gcmp(x0,e1)>0) {
     278            7 :     GEN r = gsqrt(gdiv(gsub(x0,e3), gsub(x0,e2)),prec);
     279            7 :     GEN t = gdiv(gneg(y0), gmul2n(gmul(r,gsub(x0,e2)),1));
     280            7 :     return zellagmcx(a,b,r,t,prec);
     281              :   } else {
     282            7 :     GEN om = ellR_omega(E,prec);
     283            7 :     GEN r = gdiv(a,gsqrt(gsub(e1,x0),prec));
     284            7 :     GEN t = gdiv(gmul(r,y0),gmul2n(gsub(x0,e3),1));
     285            7 :     return gsub(zellagmcx(a,b,r,t,prec),gmul2n(gel(om,2),-1));
     286              :   }
     287              : }
     288              : 
     289              : static void
     290           21 : ellQp_P2t_err(GEN E, GEN z)
     291              : {
     292           21 :   if (typ(ellQp_u(E,1)) == t_POLMOD)
     293           21 :     pari_err_IMPL("ellpointtoz when u not in Qp");
     294            0 :   pari_err_DOMAIN("ellpointtoz", "point", "not on", strtoGENstr("E"),z);
     295            0 : }
     296              : static GEN
     297          182 : get_r0(GEN E, long prec)
     298              : {
     299          182 :   GEN b2 = ell_get_b2(E), e1 = ellQp_root(E, prec);
     300          182 :   return gadd(e1,gmul2n(b2,-2));
     301              : }
     302              : static GEN
     303          133 : ellQp_P2t(GEN E, GEN P, long prec)
     304              : {
     305          133 :   pari_sp av = avma;
     306              :   GEN a, b, ab, c0, r0, ar, r, x, delta, x1, y1, t, u, q;
     307              :   long vq, vt, Q, R;
     308          133 :   if (ell_is_inf(P)) return gen_1;
     309          126 :   ab = ellQp_ab(E, prec); a = gel(ab,1); b = gel(ab,2);
     310          126 :   u = ellQp_u(E, prec);
     311          126 :   q = ellQp_q(E, prec);
     312          126 :   x = gel(P,1);
     313          126 :   r0 = get_r0(E, prec);
     314          126 :   c0 = gadd(x, gmul2n(r0,-1));
     315          126 :   if (typ(c0) != t_PADIC || !is_scalar_t(typ(gel(P,2))))
     316            7 :     pari_err_TYPE("ellpointtoz",P);
     317          119 :   r = gsub(a,b);
     318          119 :   ar = gmul(a, r);
     319          119 :   if (gequal0(c0))
     320              :   {
     321            7 :     x1 = Qp_sqrt(gneg(ar));
     322            7 :     if (!x1) ellQp_P2t_err(E,P);
     323              :   }
     324              :   else
     325              :   {
     326          112 :     delta = gdiv(ar, gsqr(c0));
     327          112 :     t = Qp_sqrt(gsubsg(1,gmul2n(delta,2)));
     328          112 :     if (!t) ellQp_P2t_err(E,P);
     329          105 :     x1 = gmul(gmul2n(c0,-1), gaddsg(1,t));
     330              :   }
     331          112 :   y1 = gsubsg(1, gdiv(ar, gsqr(x1)));
     332          112 :   if (gequal0(y1))
     333              :   {
     334           14 :     y1 = Qp_sqrt(gmul(x1, gmul(gadd(x1, a), gadd(x1, r))));
     335           14 :     if (!y1) ellQp_P2t_err(E,P);
     336              :   }
     337              :   else
     338           98 :     y1 = gdiv(gmul2n(ec_dmFdy_evalQ(E,P), -1), y1);
     339           98 :   Qp_descending_Landen(ellQp_AGM(E,prec), &x1,&y1);
     340              : 
     341           98 :   t = gmul(u, gmul2n(y1,1)); /* 2u y_oo */
     342           98 :   t = gdiv(gsub(t, x1), gadd(t, x1));
     343              :   /* Reduce mod q^Z: we want 0 <= v(t) < v(q) */
     344           98 :   if (typ(t) == t_PADIC)
     345           56 :     vt = valp(t);
     346              :   else
     347           42 :     vt = valp(gnorm(t)) / 2; /* v(t) = v(Nt) / (e*f) */
     348           98 :   vq = valp(q); /* > 0 */
     349           98 :   Q = vt / vq; R = vt % vq; if (R < 0) Q--;
     350           98 :   if (Q) t = gdiv(t, gpowgs(q,Q));
     351           98 :   if (padicprec_relative(t) > prec) t = gprec(t, prec);
     352           98 :   return gc_upto(av, t);
     353              : }
     354              : 
     355              : static GEN
     356           56 : ellQp_t2P(GEN E, GEN t, long prec)
     357              : {
     358           56 :   pari_sp av = avma;
     359              :   GEN AB, A, R, x0,x1, y0,y1, u, u2, r0, s0, ar;
     360              :   long v;
     361           56 :   if (gequal1(t)) return ellinf();
     362              : 
     363           56 :   AB = ellQp_AGM(E,prec); A = gel(AB,1); R = gel(AB,3); v = itos(gel(AB,4));
     364           56 :   u = ellQp_u(E,prec);
     365           56 :   u2= ellQp_u2(E,prec);
     366           56 :   x1 = gdiv(t, gmul(u2, gsqr(gsubsg(1,t))));
     367           56 :   y1 = gdiv(gmul(x1,gaddsg(1,t)), gmul(gmul2n(u,1),gsubsg(1,t)));
     368           56 :   Qp_ascending_Landen(AB, &x1,&y1);
     369           56 :   r0 = get_r0(E, prec);
     370              : 
     371           56 :   ar = gmul(gel(A,1), gel(R,1)); setvalp(ar, valp(ar)+v);
     372           56 :   x0 = gsub(gadd(x1, gdiv(ar, x1)), gmul2n(r0,-1));
     373           56 :   s0 = gmul2n(ec_h_evalx(E, x0), -1);
     374           56 :   y0 = gsub(gmul(y1, gsubsg(1, gdiv(ar,gsqr(x1)))), s0);
     375           56 :   return gc_GEN(av, mkvec2(x0,y0));
     376              : }
     377              : 
     378              : static GEN
     379        28833 : zell_i(GEN e, GEN z, long prec)
     380              : {
     381              :   GEN t;
     382              :   long s;
     383        28833 :   (void)ellR_omega(e, prec); /* type checking */
     384        28833 :   if (ell_is_inf(z)) return gen_0;
     385        28833 :   s = ellR_get_sign(e);
     386        28833 :   if (s && typ(gel(z,1))!=t_COMPLEX && typ(gel(z,2))!=t_COMPLEX)
     387           98 :     t = (s < 0)? zellrealneg(e,z,prec): zellrealpos(e,z,prec);
     388              :   else
     389        28735 :     t = zellcx(e,z,prec);
     390        28833 :   return t;
     391              : }
     392              : 
     393              : GEN
     394        28973 : zell(GEN E, GEN P, long prec)
     395              : {
     396        28973 :   pari_sp av = avma;
     397        28973 :   checkell(E);
     398        28973 :   if (!checkellpt_i(P)) pari_err_TYPE("ellpointtoz", P);
     399        28959 :   switch(ell_get_type(E))
     400              :   {
     401          133 :     case t_ELL_Qp:
     402          133 :       prec = minss(ellQp_get_prec(E), padicprec_relative(P));
     403          133 :       return ellQp_P2t(E, P, prec);
     404            7 :     case t_ELL_NF:
     405              :     {
     406            7 :       GEN Ee = ellnfembed(E, prec), Pe = ellpointnfembed(E, P, prec);
     407            7 :       long i, l = lg(Pe);
     408           21 :       for (i = 1; i < l; i++) gel(Pe,i) = zell_i(gel(Ee,i), gel(Pe,i), prec);
     409            7 :       ellnfembed_free(Ee); return gc_GEN(av, Pe);
     410              :     }
     411           84 :     case t_ELL_Q: break;
     412        28735 :     case t_ELL_Rg: break;
     413            0 :     default: pari_err_TYPE("ellpointtoz", E);
     414              :   }
     415        28819 :   return gc_upto(av, zell_i(E, P, prec));
     416              : }
     417              : 
     418              : /********************************************************************/
     419              : /**                COMPLEX ELLIPTIC FUNCTIONS                      **/
     420              : /********************************************************************/
     421              : 
     422              : enum period_type { t_PER_W, t_PER_WETA, t_PER_ELL };
     423              : /* normalization / argument reduction for elliptic functions */
     424              : typedef struct {
     425              :   enum period_type type;
     426              :   GEN in; /* original input */
     427              :   GEN w1,w2,tau; /* original basis for L = <w1,w2> = w2 <1,tau> */
     428              :   GEN W1,W2,Tau; /* new basis for L = <W1,W2> = W2 <1,tau> */
     429              :   GEN ETA; /* quasi-periods for [W1,W2] or NULL */
     430              :   GEN a,b,c,d; /* t_INT; tau in F = h/Sl2, tau = g.t, g=[a,b;c,d] in SL(2,Z) */
     431              :   GEN z,Z; /* z/w2 defined mod <1,tau>, Z = z/w2 + x*tau+y reduced mod <1,tau>*/
     432              :   GEN x,y; /* t_INT */
     433              :   int swap; /* 1 if we swapped w1 and w2 */
     434              :   int some_q_is_real; /* exp(2iPi g.tau) for some g \in SL(2,Z) */
     435              :   int some_z_is_real; /* z + xw1 + yw2 is real for some x,y \in Z */
     436              :   int some_z_is_pure_imag; /* z + xw1 + yw2 in i*R */
     437              :   int q_is_real; /* exp(2iPi tau) \in R */
     438              :   int abs_u_is_1; /* |exp(2iPi Z)| = 1 */
     439              :   long prec; /* precision(Z) */
     440              :   long prec0; /* required precision for result */
     441              : } ellred_t;
     442              : 
     443              : /* compute g in SL_2(Z), g.t is in the usual
     444              :    fundamental domain. Internal function no check, no garbage. */
     445              : static void
     446       224742 : set_gamma(GEN *pt, GEN *pa, GEN *pb, GEN *pc, GEN *pd)
     447              : {
     448       224742 :   GEN a, b, c, d, t, t0 = *pt, run = dbltor(1. - 1e-8);
     449       224742 :   long e = gexpo(gel(t0,2));
     450       224742 :   if (e < 0) t0 = gprec_wensure(t0, precision(t0)+nbits2extraprec(-e));
     451       224742 :   t = t0;
     452       224742 :   a = d = gen_1;
     453       224742 :   b = c = gen_0;
     454              :   for(;;)
     455        44240 :   {
     456       268982 :     GEN m, n = ground(gel(t,1));
     457       268982 :     if (signe(n))
     458              :     { /* apply T^n */
     459        44829 :       t = gsub(t,n);
     460        44829 :       a = subii(a, mulii(n,c));
     461        44829 :       b = subii(b, mulii(n,d));
     462              :     }
     463       268982 :     m = cxnorm(t); if (gcmp(m,run) > 0) break;
     464        44240 :     t = gneg_i(gdiv(conj_i(t), m)); /* apply S */
     465        44240 :     togglesign_safe(&c); swap(a,c);
     466        44240 :     togglesign_safe(&d); swap(b,d);
     467              :   }
     468       224742 :   if (e < 0 && (signe(b) || signe(c))) *pt = t0;
     469       224742 :   *pa = a; *pb = b; *pc = c; *pd = d;
     470       224742 : }
     471              : /* Im z > 0. Return U.z in PSl2(Z)'s standard fundamental domain.
     472              :  * Set *pU to U. */
     473              : GEN
     474          336 : cxredsl2_i(GEN z, GEN *pU, GEN *czd)
     475              : {
     476              :   GEN a,b,c,d;
     477          336 :   set_gamma(&z, &a, &b, &c, &d);
     478          336 :   *pU = mkmat2(mkcol2(a,c), mkcol2(b,d));
     479          336 :   *czd = gadd(gmul(c,z), d);
     480          336 :   return gdiv(gadd(gmul(a,z), b), *czd);
     481              : }
     482              : GEN
     483          294 : cxredsl2(GEN t, GEN *pU)
     484              : {
     485          294 :   pari_sp av = avma;
     486              :   GEN czd;
     487          294 :   t = cxredsl2_i(t, pU, &czd);
     488          294 :   return gc_all(av, 2, &t, pU);
     489              : }
     490              : 
     491              : /* swap w1, w2 so that Im(t := w1/w2) > 0. Set tau = representative of t in
     492              :  * the standard fundamental domain, and g in Sl_2, such that tau = g.t */
     493              : static void
     494       253288 : red_modSL2(ellred_t *T, long prec)
     495              : {
     496              :   long s, p;
     497       253288 :   T->tau = gdiv(T->w1,T->w2);
     498       253288 :   if (isintzero(real_i(T->tau))) T->some_q_is_real = 1;
     499       253288 :   s = gsigne(imag_i(T->tau));
     500       253288 :   if (!s) pari_err_DOMAIN("elliptic function", "det(w1,w2)", "=", gen_0,
     501              :                           mkvec2(T->w1,T->w2));
     502       253288 :   T->swap = (s < 0);
     503       253288 :   if (T->swap) { swap(T->w1, T->w2); T->tau = ginv(T->tau); }
     504       253288 :   p = precision(T->tau); T->prec0 = p? p: prec;
     505       253288 :   if (T->type == t_PER_WETA)
     506              :   {
     507        28882 :     T->a = T->d = gen_1; T->W1 = T->w1;
     508        28882 :     T->b = T->c = gen_0; T->W2 = T->w2; T->Tau = T->tau;
     509              :   }
     510              :   else
     511              :   {
     512       224406 :     set_gamma(&T->tau, &T->a, &T->b, &T->c, &T->d);
     513              :     /* update lattice */
     514       224406 :     p = precision(T->tau);
     515       224406 :     if (p)
     516              :     {
     517       223874 :       T->w1 = gprec_wensure(T->w1, p);
     518       223874 :       T->w2 = gprec_wensure(T->w2, p);
     519              :     }
     520       224406 :     T->W1 = gadd(gmul(T->a,T->w1), gmul(T->b,T->w2));
     521       224406 :     T->W2 = gadd(gmul(T->c,T->w1), gmul(T->d,T->w2));
     522       224406 :     T->Tau = gdiv(T->W1, T->W2);
     523              :   }
     524       253288 :   if (isintzero(real_i(T->Tau))) T->some_q_is_real = T->q_is_real = 1;
     525       253288 :   p = precision(T->Tau); T->prec = p? p: prec;
     526       253288 : }
     527              : /* is z real or pure imaginary ? */
     528              : static void
     529       525588 : check_complex(GEN z, int *real, int *imag)
     530              : {
     531       525588 :   if (typ(z) != t_COMPLEX)      { *real = 1; *imag = 0; }
     532       461594 :   else if (isintzero(gel(z,1))) { *real = 0; *imag = 1; }
     533       325780 :   else *real = *imag = 0;
     534       525588 : }
     535              : static void
     536       219639 : reduce_z(GEN z, ellred_t *T)
     537              : {
     538              :   GEN x, Z;
     539              :   long p, e;
     540       219639 :   switch(typ(z))
     541              :   {
     542       219639 :     case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX: break;
     543            0 :     case t_QUAD:
     544            0 :       z = isexactzero(gel(z,2))? gel(z,1): quadtofp(z, T->prec);
     545            0 :       break;
     546            0 :     default: pari_err_TYPE("reduction mod 2-dim lattice (reduce_z)", z);
     547              :   }
     548       219639 :   Z = gdiv(z, T->W2);
     549       219639 :   T->z = z;
     550       219639 :   x = gdiv(imag_i(Z), imag_i(T->Tau));
     551       219639 :   T->x = grndtoi(x, &e); /* |Im(Z - x*Tau)| <= Im(Tau)/2 */
     552              :   /* Avoid Im(Z) << 0; take 0 <= Im(Z - x*Tau) < Im(Tau) instead.
     553              :    * Leave round when Im(Z - x*Tau) ~ 0 to allow detecting Z in <1,Tau>
     554              :    * at the end */
     555       219639 :   if (e > -10) T->x = gfloor(x);
     556       219639 :   if (signe(T->x)) Z = gsub(Z, gmul(T->x,T->Tau));
     557       219639 :   T->y = ground(real_i(Z));/* |Re(Z - y)| <= 1/2 */
     558       219639 :   if (signe(T->y)) Z = gsub(Z, T->y);
     559       219639 :   T->abs_u_is_1 = (typ(Z) != t_COMPLEX);
     560              :   /* Z = - y - x tau + z/W2, x,y integers */
     561       219639 :   check_complex(z, &(T->some_z_is_real), &(T->some_z_is_pure_imag));
     562       219639 :   if (!T->some_z_is_real && !T->some_z_is_pure_imag)
     563              :   {
     564              :     int W2real, W2imag;
     565       162883 :     check_complex(T->W2,&W2real,&W2imag);
     566       162883 :     if (W2real)
     567         7301 :       check_complex(Z, &(T->some_z_is_real), &(T->some_z_is_pure_imag));
     568       155582 :     else if (W2imag)
     569       135695 :       check_complex(Z, &(T->some_z_is_pure_imag), &(T->some_z_is_real));
     570              :   }
     571       219639 :   p = precision(Z);
     572       219639 :   if (gequal0(Z) || (p && gexpo(Z) < 5 - p)) Z = NULL; /*z in L*/
     573       219639 :   if (p && p < T->prec) T->prec = p;
     574       219639 :   T->Z = Z;
     575       219639 : }
     576              : /* return x.eta1 + y.eta2 */
     577              : static GEN
     578        75208 : _period(ellred_t *T, GEN eta)
     579              : {
     580        75208 :   GEN y1 = NULL, y2 = NULL;
     581        75208 :   if (signe(T->x)) y1 = gmul(T->x, gel(eta,1));
     582        75208 :   if (signe(T->y)) y2 = gmul(T->y, gel(eta,2));
     583        75208 :   if (!y1) return y2? y2: gen_0;
     584        28167 :   return y2? gadd(y1, y2): y1;
     585              : }
     586              : /* e is either
     587              :  * - [w1,w2]
     588              :  * - [[w1,w2],[eta1,eta2]]
     589              :  * - an ellinit structure */
     590              : static void
     591       253288 : compute_periods(ellred_t *T, GEN z, long prec)
     592              : {
     593              :   GEN w, e;
     594       253288 :   T->ETA = NULL;
     595       253288 :   T->q_is_real = 0;
     596       253288 :   T->some_q_is_real = 0;
     597       253288 :   switch(T->type)
     598              :   {
     599       210735 :     case t_PER_ELL:
     600              :     {
     601       210735 :       long pr, p = prec;
     602       210735 :       if (z && (pr = precision(z))) p = pr;
     603       210735 :       e = T->in;
     604       210735 :       w = ellR_omega(e, p);
     605       210735 :       T->some_q_is_real = T->q_is_real = 1;
     606       210735 :       break;
     607              :     }
     608        13671 :     case t_PER_W:
     609        13671 :       w = T->in; break;
     610        28882 :     default: /*t_PER_WETA*/
     611        28882 :       w = gel(T->in,1);
     612        28882 :       T->ETA = gel(T->in, 2); break;
     613              :   }
     614       253288 :   T->w1 = gel(w,1);
     615       253288 :   T->w2 = gel(w,2);
     616       253288 :   red_modSL2(T, prec);
     617       253288 :   if (z) reduce_z(z, T);
     618       253288 : }
     619              : static int
     620        71435 : ispair(GEN w) { return typ(w) == t_VEC && lg(w) == 3; }
     621              : static int
     622       253295 : check_periods(GEN e, ellred_t *T)
     623              : {
     624       253295 :   if (typ(e) != t_VEC) return 0;
     625       253295 :   T->in = e;
     626       253295 :   switch(lg(e))
     627              :   {
     628       210742 :     case 17:
     629       210742 :       T->type = t_PER_ELL;
     630       210742 :       break;
     631        42553 :     case 3:
     632        42553 :       if (!ispair(gel(e,1)))
     633        13671 :         T->type = t_PER_W;
     634              :       else
     635              :       {
     636        28882 :         if (!ispair(gel(e,2))) return 0;
     637        28882 :         T->type = t_PER_WETA;
     638              :       }
     639        42553 :       break;
     640            0 :     default: return 0;
     641              :   }
     642       253295 :   return 1;
     643              : }
     644              : static int
     645       253211 : get_periods(GEN e, GEN z, ellred_t *T, long prec)
     646              : {
     647       253211 :   if (!check_periods(e, T)) return 0;
     648       253211 :   compute_periods(T, z, prec); return 1;
     649              : }
     650              : 
     651              : /* pi^2/3 */
     652              : static GEN
     653       219646 : pi23(long prec) { return divru(sqrr(mppi(prec)), 3); }
     654              : /* 2iPi/x, more efficient when x pure imaginary (rectangular lattice) */
     655              : static GEN
     656        41685 : PiI2div(GEN x, long prec) { return gdiv(Pi2n(1, prec), mulcxmI(x)); }
     657              : /* 2iPi/x)^2 = -4pi^2 / x */
     658              : static GEN
     659         4725 : PiI2div_sqr(GEN x, long prec)
     660              : {
     661         4725 :   GEN p = sqrr(Pi2n(1, prec)); setsigne(p, -1);
     662         4725 :   return gdiv(p, gsqr(x));
     663              : }
     664              : 
     665              : static void
     666         5222 : elleisnum_testk(long k)
     667              : {
     668         5222 :   if (k<=0) pari_err_DOMAIN("elleisnum", "k", "<=", gen_0, stoi(k));
     669         5215 :   if (k&1) pari_err_DOMAIN("elleisnum", "k % 2", "!=", gen_0, stoi(k));
     670         5201 : }
     671              : 
     672              : /* quasi-periods eta1, eta2 attached to [W1,W2] = W2 [Tau, 1] */
     673              : static GEN
     674        66374 : elleta_W(ellred_t *T)
     675              : {
     676              :   long prec;
     677              :   GEN e, E2;
     678              : 
     679        66374 :   if (T->ETA) return T->ETA;
     680        37583 :   prec = precision(T->W2)? T->prec: T->prec + EXTRAPREC64;
     681        37583 :   E2 = cxEk(T->Tau, 2, prec);
     682        37583 :   e = cxtoreal(gdiv(gmul(E2, pi23(prec)), gsqr(T->W2)));
     683              :   /* y2 Tau - y1 = 2i pi/W2 => y2 W1 - y1 W2 = 2i pi */
     684        37583 :   return mkvec2(gsub(gmul(T->W1, e), PiI2div(T->W2, prec)), gmul(T->W2, e));
     685              : }
     686              : 
     687              : GEN
     688        28756 : ellperiods(GEN w, long flag, long prec)
     689              : {
     690        28756 :   pari_sp av = avma;
     691              :   ellred_t T;
     692              :   GEN W;
     693        28756 :   if (!get_periods(w, NULL, &T, prec)) pari_err_TYPE("ellperiods",w);
     694        28756 :   W = mkvec2(T.W1, T.W2);
     695        28756 :   switch(flag)
     696              :   {
     697        28735 :     case 1: W = mkvec2(W, elleta_W(&T)); /* fall through */
     698        28756 :     case 0: break;
     699            0 :     default: pari_err_FLAG("ellperiods");
     700              :   }
     701        28756 :   return gc_GEN(av, W);
     702              : }
     703              : 
     704              : /* quasi-periods eta1, eta2 attached to [w1, w2] = w2 [tau, 1] */
     705              : /* warning: w1*eta2 - w2*eta1 = sign(imag(tau))*2*Pi*I */
     706              : 
     707              : GEN
     708           84 : elleta(GEN om, long prec)
     709              : {
     710           84 :   pari_sp av = avma;
     711              :   GEN y1, y2, E2, pi;
     712              :   ellred_t T;
     713              : 
     714           84 :   if (!check_periods(om, &T))
     715              :   {
     716            0 :     pari_err_TYPE("elleta",om);
     717              :     return NULL;/*LCOV_EXCL_LINE*/
     718              :   }
     719           84 :   if (T.type == t_PER_ELL) return ellR_eta(om, prec);
     720              : 
     721           77 :   compute_periods(&T, NULL, prec);
     722           77 :   prec = T.prec;
     723           77 :   pi = mppi(prec);
     724           77 :   E2 = cxEk(T.Tau, 2, prec); /* E_2(Tau) */
     725           77 :   if (signe(T.c))
     726              :   {
     727           21 :     GEN u = gdiv(T.w2, T.W2);
     728              :     /* E2 := u^2 E2 + 6iuc/pi = E_2(tau) */
     729           21 :     E2 = gadd(gmul(gsqr(u), E2), mulcxI(gdiv(gmul(mului(6,T.c), u), pi)));
     730              :   }
     731           77 :   y2 = gdiv(gmul(E2, sqrr(pi)), gmulsg(3, T.w2));
     732           77 :   if (T.swap)
     733              :   {
     734            7 :     y1 = y2;
     735            7 :     y2 = gsub(gmul(T.tau,y1), PiI2div(T.w2, prec));
     736              :   }
     737              :   else
     738           70 :     y1 = gsub(gmul(T.tau,y2), PiI2div(T.w2, prec));
     739           77 :   if (is_real_t(typ(T.w1))) y1 = real_i(y1);
     740           77 :   return gc_GEN(av, mkvec2(y1,y2));
     741              : }
     742              : 
     743              : /********************************************************************/
     744              : /**                     Jacobi sine theta                          **/
     745              : /********************************************************************/
     746              : 
     747              : /* check |q| < 1 */
     748              : static GEN
     749           21 : check_unit_disc(const char *fun, GEN q, long prec)
     750              : {
     751           21 :   GEN Q = gtofp(q, prec), Qlow;
     752           21 :   Qlow = (prec > LOWDEFAULTPREC)? gtofp(Q,LOWDEFAULTPREC): Q;
     753           21 :   if (gcmp(gnorm(Qlow), gen_1) >= 0)
     754            0 :     pari_err_DOMAIN(fun, "abs(q)", ">=", gen_1, q);
     755           21 :   return Q;
     756              : }
     757              : 
     758              : GEN
     759            7 : thetanullk(GEN q, long k, long prec)
     760              : {
     761              :   long l, n;
     762            7 :   pari_sp av = avma;
     763              :   GEN p1, ps, qn, y, ps2;
     764              : 
     765            7 :   if (k < 0)
     766            0 :     pari_err_DOMAIN("thetanullk", "k", "<", gen_0, stoi(k));
     767            7 :   l = precision(q);
     768            7 :   if (l) prec = l;
     769            7 :   q = check_unit_disc("thetanullk", q, prec);
     770              : 
     771            7 :   if (!odd(k)) { set_avma(av); return gen_0; }
     772            7 :   qn = gen_1;
     773            7 :   ps2 = gsqr(q);
     774            7 :   ps = gneg_i(ps2);
     775            7 :   y = gen_1;
     776            7 :   for (n = 3;; n += 2)
     777          280 :   {
     778              :     GEN t;
     779          287 :     qn = gmul(qn,ps);
     780          287 :     ps = gmul(ps,ps2);
     781          287 :     t = gmul(qn, powuu(n, k)); y = gadd(y, t);
     782          287 :     if (gexpo(t) < -prec2nbits(prec)) break;
     783              :   }
     784            7 :   p1 = gmul2n(gsqrt(gsqrt(q,prec),prec),1);
     785            7 :   if (k&2) y = gneg_i(y);
     786            7 :   return gc_upto(av, gmul(p1, y));
     787              : }
     788              : 
     789              : /* q2 = q^2 */
     790              : static GEN
     791        42039 : vecthetanullk_loop(GEN q2, long k, long prec)
     792              : {
     793        42039 :   GEN ps, qn = gen_1, y = const_vec(k, gen_1);
     794        42039 :   pari_sp av = avma;
     795        42039 :   const long bit = prec2nbits(prec);
     796              :   long i, n;
     797              : 
     798        42039 :   if (gexpo(q2) < -2*bit) return y;
     799        42039 :   ps = gneg_i(q2);
     800        42039 :   for (n = 3;; n += 2)
     801       227409 :   {
     802       269448 :     GEN t = NULL/*-Wall*/, P = utoipos(n), N2 = sqru(n);
     803       269448 :     qn = gmul(qn,ps);
     804       269448 :     ps = gmul(ps,q2);
     805       808344 :     for (i = 1; i <= k; i++)
     806              :     {
     807       538896 :       t = gmul(qn, P); gel(y,i) = gadd(gel(y,i), t);
     808       538896 :       P = mulii(P, N2);
     809              :     }
     810       269448 :     if (gexpo(t) < -bit) return y;
     811       227409 :     if (gc_needed(av,2))
     812              :     {
     813            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"vecthetanullk_loop, n = %ld",n);
     814            0 :       (void)gc_all(av, 3, &qn, &ps, &y);
     815              :     }
     816              :   }
     817              : }
     818              : /* [d^i theta/dz^i(q, 0), i = 1, 3, .., 2*k - 1] */
     819              : GEN
     820            0 : vecthetanullk(GEN q, long k, long prec)
     821              : {
     822            0 :   long i, l = precision(q);
     823            0 :   pari_sp av = avma;
     824              :   GEN p1, y;
     825              : 
     826            0 :   if (l) prec = l;
     827            0 :   q = check_unit_disc("vecthetanullk", q, prec);
     828            0 :   y = vecthetanullk_loop(gsqr(q), k, prec);
     829            0 :   p1 = gmul2n(gsqrt(gsqrt(q,prec),prec),1);
     830            0 :   for (i = 2; i <= k; i += 2) gel(y,i) = gneg_i(gel(y,i));
     831            0 :   return gc_upto(av, gmul(p1, y));
     832              : }
     833              : 
     834              : /* [d^i theta/dz^i(q, 0), i = 1, 3, .., 2*k - 1], q = exp(2iPi tau) */
     835              : GEN
     836            0 : vecthetanullk_tau(GEN tau, long k, long prec)
     837              : {
     838            0 :   long i, l = precision(tau);
     839            0 :   pari_sp av = avma;
     840              :   GEN q4, y;
     841              : 
     842            0 :   if (l) prec = l;
     843            0 :   if (typ(tau) != t_COMPLEX || gsigne(gel(tau,2)) <= 0)
     844            0 :     pari_err_DOMAIN("vecthetanullk_tau", "imag(tau)", "<=", gen_0, tau);
     845            0 :   q4 = expIPiC(gmul2n(tau,-1), prec); /* q^(1/4) */
     846            0 :   y = vecthetanullk_loop(gpowgs(q4,8), k, prec);
     847            0 :   for (i = 2; i <= k; i += 2) gel(y,i) = gneg_i(gel(y,i));
     848            0 :   return gc_upto(av, gmul(gmul2n(q4,1), y));
     849              : }
     850              : 
     851              : /********************************************************************/
     852              : /*   Riemann-Jacobi 1-variable theta functions, does not use AGM    */
     853              : /********************************************************************/
     854              : /* theta(z,tau,0) should be identical to riemann_theta([z]~, Mat(tau))
     855              :  * from Jean Kieffer. */
     856              : 
     857              : static long
     858          112 : equali01(GEN x)
     859              : {
     860          112 :   if (!signe(x)) return 0;
     861           84 :   if (!equali1(x)) pari_err_FLAG("theta");
     862           84 :   return 1;
     863              : }
     864              : 
     865              : static long
     866          182 : thetaflag(GEN v)
     867              : {
     868              :   long v1, v2;
     869          182 :   if (!v) return 0;
     870          182 :   switch(typ(v))
     871              :   {
     872          126 :     case t_INT:
     873          126 :       if (signe(v) < 0 || cmpis(v, 4) > 0) pari_err_FLAG("theta");
     874          126 :       return itou(v);
     875           56 :     case t_VEC:
     876           56 :       if (RgV_is_ZV(v) && lg(v) == 3) break;
     877            0 :     default: pari_err_FLAG("theta");
     878              :   }
     879           56 :   v1 = equali01(gel(v,1));
     880           56 :   v2 = equali01(gel(v,2)); return v1? (v2? -1: 2): (v2? 4: 3);
     881              : }
     882              : 
     883              : /* Automorphy factor for bringing tau towards standard fundamental domain
     884              :  * (we stop when im(tau) >= 1/2, no need to go all the way to sqrt(3)/2).
     885              :  * At z = 0 if NULL */
     886              : static GEN
     887       220192 : autojtau(GEN *pz, GEN *ptau, long *psumr, long *pct, long prec)
     888              : {
     889       220192 :   GEN S = gen_1, z = *pz, tau = *ptau;
     890       220192 :   long ct = 0, sumr = 0;
     891       220192 :   if (z && gequal0(z)) z = NULL;
     892       220367 :   while (gexpo(imag_i(tau)) < -1)
     893              :   {
     894          175 :     GEN r = ground(real_i(tau)), taup;
     895          175 :     tau = gsub(tau, r); taup = gneg(ginv(tau));
     896          175 :     S = gdiv(S, gsqrt(mulcxmI(tau), prec));
     897          175 :     if (z)
     898              :     {
     899          119 :       S = gmul(S, expIPiC(gmul(taup, gsqr(z)), prec));
     900          119 :       z = gneg(gmul(z, taup));
     901              :     }
     902          175 :     ct++; tau = taup; sumr = (sumr + Mod8(r)) & 7;
     903              :   }
     904       220192 :   if (pct) *pct = ct;
     905       220192 :   *psumr = sumr; *pz = z; *ptau = tau; return S;
     906              : }
     907              : 
     908              : /* At 0 if z = NULL. Real(tau) = n is an integer; 4 | n if fl = 1 or 2 */
     909              : static void
     910      1510544 : clearim(GEN *v, GEN z, long fl)
     911              : {
     912      1510544 :   if (!z || gequal0(imag_i(z)) || (fl != 1 && gequal0(real_i(z))))
     913       905555 :     *v = real_i(*v);
     914      1510544 : }
     915              : 
     916              : static GEN
     917       377636 : clearimall(GEN z, GEN n, GEN VS)
     918              : {
     919       377636 :   long nmod4 = Mod4(n);
     920       377636 :   clearim(&gel(VS,1), z, 3);
     921       377636 :   clearim(&gel(VS,2), z, 4);
     922       377636 :   if (!nmod4)
     923              :   {
     924       377636 :     clearim(&gel(VS,3), z, 2);
     925       377636 :     clearim(&gel(VS,4), z, 1);
     926              :   }
     927       377636 :   return VS;
     928              : }
     929              : 
     930              : /* Implementation of all 4 theta functions */
     931              : 
     932              : /* If z = NULL, we are at 0 */
     933              : static long
     934       220269 : thetaprec(GEN z, GEN tau, long prec)
     935              : {
     936       220269 :   long l = precision(tau);
     937       220269 :   if (z)
     938              :   {
     939       219814 :     long n = precision(z);
     940       219814 :     if (n && n < l) l = n;
     941              :   }
     942       220269 :   return l? l: prec;
     943              : }
     944              : 
     945              : static GEN
     946       219807 : redmod2Z(GEN z)
     947              : {
     948       219807 :   GEN k = ground(gmul2n(real_i(z), -1));
     949       219807 :   if (typ(k) != t_INT) pari_err_TYPE("theta", z);
     950       219800 :   if (signe(k)) z = gsub(z, shifti(k, 1));
     951       219800 :   return z;
     952              : }
     953              : 
     954              : /* Return theta[0,0], theta[0,1], theta[1,0] and theta[1,1] at (z,tau).
     955              :  * If pT0 != NULL, assume z != NULL and set *pT0 to
     956              :  *  theta[0,0], theta[0,1], theta[1,0] and theta[1,1]' at (0,tau).
     957              :  * Note that theta[1,1](0, tau) is identically 0, hence the derivative.
     958              :  * If z = NULL, return theta[1,1]'(0) */
     959              : static GEN
     960       220192 : thetaall(GEN z, GEN tau, GEN *pT0, long prec)
     961              : {
     962              :   pari_sp av;
     963              :   GEN zold, tauold, k, u, un, q, q2, qd, qn;
     964              :   GEN S, Skeep, S00, S01, S10, S11, u2, ui2, uin;
     965       220192 :   GEN Z00 = gen_1, Z01 = gen_1, Z10 = gen_0, Z11 = gen_0;
     966       220192 :   long n, ct, eS, B, sumr, precold = prec;
     967       220192 :   int theta1p = !z;
     968              : 
     969       220192 :   if (z) z = redmod2Z(z);
     970       220185 :   tau = upper_to_cx(tau, &prec);
     971       220185 :   prec = thetaprec(z, tau, prec);
     972       220185 :   z = zold = z? gtofp(z, prec): NULL;
     973       220185 :   tau = tauold = gtofp(tau, prec);
     974       220185 :   S = autojtau(&z, &tau, &sumr, &ct, prec);
     975       220185 :   Skeep = S;
     976       220185 :   k = gen_0; S00 = S01 = gen_1; S10 = S11 = gen_0;
     977       220185 :   if (z)
     978              :   {
     979       219702 :     GEN y = imag_i(z);
     980       219702 :     if (!gequal0(y)) k = roundr(divrr(y, gneg(imag_i(tau))));
     981       219702 :     if (signe(k))
     982              :     {
     983       105511 :       GEN Sz = expIPiC(gadd(gmul(sqri(k), tau), gmul(shifti(k,1), z)), prec);
     984       105511 :       S = gmul(S, Sz);
     985       105511 :       z = gadd(z, gmul(tau, k));
     986              :     }
     987              :   }
     988       220185 :   if ((eS = gexpo(S)) > 0)
     989              :   {
     990        81989 :     prec = nbits2prec(eS + prec2nbits(prec));
     991        81989 :     if (z) z = gprec_w(z, prec);
     992        81989 :     tau = gprec_w(tau, prec);
     993              :   }
     994       220185 :   q = expIPiC(gmul2n(tau,-2), prec); q2 = gsqr(q); qn = gen_1;
     995       220185 :   if (!z) u = u2 = ui2 = un = uin = NULL; /* constant, equal to 1 */
     996              :   else
     997              :   {
     998       219702 :     u = expIPiC(z, prec); u2 = gsqr(u); ui2 = ginv(u2);
     999       219702 :     un = uin = gen_1;
    1000              :   }
    1001       220185 :   qd = q; B = prec2nbits(prec);
    1002       220185 :   av = avma;
    1003       220185 :   for (n = 1;; n++)
    1004      1226131 :   { /* qd = q^(4n-3), qn = q^(4(n-1)^2), un = u^(2n-2), uin = 1/un */
    1005      1446316 :     long e = 0, eqn, prec2;
    1006              :     GEN tmp;
    1007      1446316 :     if (u) uin = gmul(uin, ui2);
    1008      1446316 :     qn = gmul(qn, qd); /* q^((2n-1)^2) */
    1009      1446316 :     tmp = u? gmul(qn, gadd(un, uin)): gmul2n(qn, 1);
    1010      1446316 :     S10 = gadd(S10, tmp);
    1011      1446316 :     if (pT0) Z10 = gadd(Z10, gmul2n(qn, 1));
    1012      1446316 :     if (z)
    1013              :     {
    1014      1444503 :       tmp = gmul(qn, gsub(un, uin));
    1015      1444503 :       S11 = odd(n)? gsub(S11, tmp): gadd(S11, tmp);
    1016      1444503 :       e = maxss(0, gexpo(un)); un = gmul(un, u2);
    1017      1444503 :       e = maxss(e, gexpo(un));
    1018              :     }
    1019         1813 :     else if (theta1p) /* theta'[1,1] at 0 */
    1020              :     {
    1021         1624 :       tmp = gmulsg(2*n-1, tmp);
    1022         1624 :       S11 = odd(n)? gsub(S11, tmp): gadd(S11, tmp);
    1023              :     }
    1024      1446316 :     if (pT0)
    1025              :     {
    1026      1443759 :       tmp = gmulsg(4*n-2, qn);
    1027      1443759 :       Z11 = odd(n)? gsub(Z11, tmp): gadd(Z11, tmp);
    1028              :     }
    1029      1446316 :     qd = gmul(qd, q2); qn = gmul(qn, qd); /* q^(4n^2) */
    1030      1446316 :     tmp = u? gmul(qn, gadd(un, uin)): gmul2n(qn, 1);
    1031      1446316 :     S00 = gadd(S00, tmp);
    1032      1446316 :     S01 = odd(n)? gsub(S01, tmp): gadd(S01, tmp);
    1033      1446316 :     if (pT0)
    1034              :     {
    1035      1443759 :       tmp = gmul2n(qn, 1); Z00 = gadd(Z00, tmp);
    1036      1443759 :       Z01 = odd(n)? gsub(Z01, tmp): gadd(Z01, tmp);
    1037              :     }
    1038      1446316 :     eqn = gexpo(qn) + e; if (eqn < -B) break;
    1039      1226131 :     qd = gmul(qd, q2);
    1040      1226131 :     prec2 = minss(prec, nbits2prec(eqn + B + 64));
    1041      1226131 :     qn = gprec_w(qn, prec2); qd = gprec_w(qd, prec2);
    1042      1226131 :     if (u) { un = gprec_w(un, prec2); uin = gprec_w(uin, prec2); }
    1043      1226131 :     if (gc_needed(av, 1))
    1044              :     {
    1045            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"theta");
    1046            0 :       gc_all(av, pT0? 12: (u? 8: 6), &qd, &qn, &S00,&S01,&S10,&S11, &un,&uin,
    1047              :              &Z00,&Z01,&Z10,&Z11);
    1048              :     }
    1049              :   }
    1050       220185 :   if (u)
    1051              :   {
    1052       219702 :     S10 = gmul(u, S10);
    1053       219702 :     S11 = gmul(u, S11);
    1054              :   }
    1055              :   /* automorphic factor
    1056              :    *   theta[1,1]: I^ct
    1057              :    *   theta[1,0]: exp(-I*Pi/4*sumr)
    1058              :    *   theta[0,1]: (-1)^k
    1059              :    *   theta[1,1]: (-1)^k exp(-I*Pi/4*sumr) */
    1060       220185 :   if (!theta1p && mpodd(k)) { S01 = gneg(S01); S11 = gneg(S11); }
    1061       220185 :   S11 = z? mulcxpowIs(S11, ct + 3): gmul(mppi(prec), S11);
    1062       220185 :   if (pT0) Z11 = gmul(mppi(prec), Z11);
    1063       220185 :   if (ct&1L) { swap(S10, S01); if (pT0) swap(Z10, Z01); }
    1064       220185 :   if (sumr & 7)
    1065              :   {
    1066           42 :     GEN zet = e12(sumr * 3, prec); /* exp(I Pi sumr / 4) */
    1067           42 :     if (odd(sumr)) { swap(S01, S00); if (pT0) swap(Z01, Z00); }
    1068           42 :     S10 = gmul(S10, zet); S11 = gmul(S11, zet);
    1069           42 :     if (pT0) { Z10 = gmul(Z10, zet); Z11 = gmul(Z11, zet); }
    1070              :   }
    1071       220185 :   if (theta1p) S11 = gmul(gsqr(S), S11);
    1072       220185 :   if (pT0) Z11 = gmul(gsqr(Skeep), Z11);
    1073       220185 :   S = gmul(S, mkvec4(S00, S01, S10, S11));
    1074       220185 :   if (precold < prec) S = gprec_wtrunc(S, precold);
    1075       220185 :   if (pT0)
    1076              :   {
    1077       219583 :     *pT0 = gmul(Skeep, mkvec4(Z00, Z01, Z10, Z11));
    1078       219583 :     if (precold < prec) *pT0 = gprec_wtrunc(*pT0, precold);
    1079              :   }
    1080       220185 :   if (isint(real_i(tauold), &k))
    1081              :   {
    1082       189042 :     S = clearimall(zold, k, S);
    1083       189042 :     if (pT0) *pT0 = clearimall(NULL, k, *pT0);
    1084              :   }
    1085       220185 :   return S;
    1086              : }
    1087              : 
    1088              : static GEN
    1089          455 : thetanull_i(GEN tau, long prec) { return thetaall(NULL, tau, NULL, prec); }
    1090              : 
    1091              : GEN
    1092          154 : theta(GEN z, GEN tau, GEN flag, long prec)
    1093              : {
    1094          154 :   pari_sp av = avma;
    1095              :   GEN T;
    1096          154 :   if (!flag)
    1097              :   { /* backward compatibility: sine theta */
    1098           14 :     GEN pi = mppi(prec), q = z; z = tau; /* input (q = exp(i pi tau), Pi*z) */
    1099           14 :     prec = thetaprec(z, tau, prec);
    1100           14 :     q = check_unit_disc("theta", q, prec);
    1101           14 :     z = gdiv(gtofp(z, prec), pi);
    1102           14 :     tau = gdiv(mulcxmI(glog(q, prec)), pi);
    1103           14 :     flag = gen_1;
    1104              :   }
    1105          154 :   T = thetaall(z, tau, NULL, prec);
    1106          147 :   switch (thetaflag(flag))
    1107              :   {
    1108           28 :     case -1: T = gel(T,4); break;
    1109           63 :     case 0: break;
    1110           14 :     case 1: T = gneg(gel(T,4)); break;
    1111           14 :     case 2: T = gel(T,3); break;
    1112           14 :     case 3: T = gel(T,1); break;
    1113           14 :     case 4: T = gel(T,2); break;
    1114            0 :     default: pari_err_FLAG("theta");
    1115              :   }
    1116          147 :   return gc_GEN(av, T);
    1117              : }
    1118              : 
    1119              : /* Same as 2*Pi*eta(tau,1)^3 = - thetanull_i(tau)[4], faster than both. */
    1120              : static GEN
    1121            7 : thetanull11(GEN tau, long prec)
    1122              : {
    1123            7 :   GEN z = NULL, tauold, q, q8, qd, qn, S, S11;
    1124            7 :   long n, eS, B, sumr, precold = prec;
    1125              : 
    1126            7 :   tau = upper_to_cx(tau, &prec);
    1127            7 :   tau = tauold = gtofp(tau, prec);
    1128            7 :   S = autojtau(&z, &tau, &sumr, NULL, prec);
    1129            7 :   S11 = gen_1; ;
    1130            7 :   if ((eS = gexpo(S)) > 0)
    1131              :   {
    1132            0 :     prec += nbits2extraprec(eS);
    1133            0 :     tau = gprec_w(tau, prec);
    1134              :   }
    1135            7 :   q8 = expIPiC(gmul2n(tau,-2), prec); q = gpowgs(q8, 8);
    1136            7 :   qn = gen_1; qd = q; B = prec2nbits(prec);
    1137            7 :   for (n = 1;; n++)
    1138           42 :   { /* qd = q^n, qn = q^((n^2-n)/2) */
    1139              :     long eqn, prec2;
    1140              :     GEN tmp;
    1141           49 :     qn = gmul(qn, qd); tmp = gmulsg(2*n+1, qn); eqn = gexpo(tmp);
    1142           49 :     S11 = odd(n)? gsub(S11, tmp): gadd(S11, tmp);
    1143           49 :     if (eqn < -B) break;
    1144           42 :     qd = gmul(qd, q);
    1145           42 :     prec2 = minss(prec, nbits2prec(eqn + B + 32));
    1146           42 :     qn = gprec_w(qn, prec2); qd = gprec_w(qd, prec2);
    1147              :   }
    1148            7 :   if (precold < prec) prec = precold;
    1149            7 :   S11 = gmul3(S11, q8, e12(3*sumr, prec));
    1150            7 :   S11 = gmul3(Pi2n(1, prec), gpowgs(S, 3), S11);
    1151            7 :   if (isint(real_i(tauold), &q) && !Mod4(q)) clearim(&S11, z, 1);
    1152            7 :   return S11;
    1153              : }
    1154              : 
    1155              : GEN
    1156           35 : thetanull(GEN tau, GEN flag, long prec)
    1157              : {
    1158           35 :   pari_sp av = avma;
    1159           35 :   long fl = thetaflag(flag);
    1160              :   GEN T0;
    1161           35 :   if (fl == 1) T0 = thetanull11(tau, prec);
    1162           35 :   else if (fl == -1) T0 = gneg(thetanull11(tau, prec));
    1163              :   else
    1164              :   {
    1165           28 :     T0 = thetanull_i(tau, prec);
    1166           28 :     switch (fl)
    1167              :     {
    1168            7 :       case 0: break;
    1169            7 :       case 2: T0 = gel(T0,3); break;
    1170            7 :       case 3: T0 = gel(T0,1); break;
    1171            7 :       case 4: T0 = gel(T0,2); break;
    1172            0 :       default: pari_err_FLAG("thetanull");
    1173              :     }
    1174              :   }
    1175           35 :   return gc_GEN(av, T0);
    1176              : }
    1177              : 
    1178              : static GEN
    1179           70 : autojtauprime(GEN *pz, GEN *ptau, GEN *pmat, long *psumr, long *pct, long prec)
    1180              : {
    1181           70 :   GEN S = gen_1, z = *pz, tau = *ptau, M = matid(2);
    1182           70 :   long ct = 0, sumr = 0;
    1183           70 :   while (gexpo(imag_i(tau)) < -1)
    1184              :   {
    1185            0 :     GEN r = ground(real_i(tau)), taup;
    1186            0 :     tau = gsub(tau, r); taup = gneg(ginv(tau));
    1187            0 :     S = gdiv(S, gsqrt(mulcxmI(tau), prec));
    1188            0 :     S = gmul(S, expIPiC(gmul(taup, gsqr(z)), prec));
    1189            0 :     M = gmul(mkmat22(gen_1, gen_0, gmul(z, PiI2n(1, prec)), tau), M);
    1190            0 :     z = gneg(gmul(z, taup));
    1191            0 :     ct++; tau = taup; sumr = (sumr + Mod8(r)) & 7;
    1192              :   }
    1193           70 :   if (pct) *pct = ct;
    1194           70 :   *pmat = M; *psumr = sumr; *pz = z; *ptau = tau; return S;
    1195              : }
    1196              : 
    1197              : /* computes theta_{1,1} and theta'_{1,1} together */
    1198              : 
    1199              : static GEN
    1200           70 : theta11prime(GEN z, GEN tau, long prec)
    1201              : {
    1202           70 :   pari_sp av = avma;
    1203              :   GEN zold, tauold, k, u, un, q, q2, qd, qn;
    1204              :   GEN S, S11, S11prime, S11all, u2, ui2, uin;
    1205              :   GEN y, mat;
    1206           70 :   long n, ct, eS, B, sumr, precold = prec;
    1207              : 
    1208           70 :   if (z) z = redmod2Z(z);
    1209           70 :   if (!z || gequal0(z)) pari_err(e_MISC, "z even integer in theta11prime");
    1210           70 :   tau = upper_to_cx(tau, &prec);
    1211           70 :   prec = thetaprec(z, tau, prec);
    1212           70 :   z = zold = z? gtofp(z, prec): NULL;
    1213           70 :   tau = tauold = gtofp(tau, prec);
    1214           70 :   S = autojtauprime(&z, &tau, &mat, &sumr, &ct, prec);
    1215           70 :   k = gen_0; S11 = gen_0; S11prime = gen_0;
    1216           70 :   y = imag_i(z);
    1217           70 :   if (!gequal0(y)) k = roundr(divrr(y, gneg(imag_i(tau))));
    1218           70 :   if (signe(k))
    1219              :   {
    1220           28 :     GEN Sz = expIPiC(gadd(gmul(sqri(k), tau), gmul(shifti(k,1), z)), prec);
    1221           28 :     mat = gmul(mkmat22(gen_1, gen_0, gneg(gmul(k, PiI2n(1, prec))), gen_1), mat);
    1222           28 :     S = gmul(S, Sz);
    1223           28 :     z = gadd(z, gmul(tau, k));
    1224              :   }
    1225           70 :   if ((eS = gexpo(S)) > 0)
    1226              :   {
    1227           28 :     prec = nbits2prec(eS + prec2nbits(prec));
    1228           28 :     z = gprec_w(z, prec);
    1229           28 :     tau = gprec_w(tau, prec);
    1230              :   }
    1231           70 :   q = expIPiC(gmul2n(tau,-2), prec); q2 = gsqr(q); qn = gen_1;
    1232           70 :   u = expIPiC(z, prec); u2 = gsqr(u); ui2 = ginv(u2);
    1233           70 :   un = uin = gen_1;
    1234           70 :   qd = q; B = prec2nbits(prec);
    1235           70 :   for (n = 1;; n++)
    1236          315 :   { /* qd = q^(4n-3), qn = q^(4(n-1)^2), un = u^(2n-2), uin = 1/un */
    1237          385 :     long e = 0, eqn, prec2;
    1238              :     GEN tmp, tmpprime;
    1239          385 :     uin = gmul(uin, ui2);
    1240          385 :     qn = gmul(qn, qd); /* q^((2n-1)^2) */
    1241          385 :     tmp = gmul(qn, gsub(un, uin));
    1242          385 :     tmpprime = gmulsg(2*n - 1, gmul(qn, gadd(un, uin)));
    1243          385 :     S11 = odd(n)? gsub(S11, tmp): gadd(S11, tmp);
    1244          385 :     S11prime = odd(n)? gsub(S11prime, tmpprime): gadd(S11prime, tmpprime);
    1245          385 :     e = maxss(0, gexpo(un)); un = gmul(un, u2); e = maxss(e, gexpo(un));
    1246          385 :     qd = gmul(qd, q2); qn = gmul(qn, qd); /* q^(4n^2) */
    1247          385 :     eqn = gexpo(qn) + e; if (eqn < -B) break;
    1248          315 :     qd = gmul(qd, q2);
    1249          315 :     prec2 = minss(prec, nbits2prec(eqn + B + 64));
    1250          315 :     qn = gprec_w(qn, prec2); qd = gprec_w(qd, prec2);
    1251          315 :     un = gprec_w(un, prec2); uin = gprec_w(uin, prec2);
    1252              :   }
    1253           70 :   S11prime = gmul(S11prime, PiI2n(0, prec));
    1254           70 :   S11all = gmul(u, mkcol2(S11, S11prime));
    1255           70 :   S11all = mulcxpowIs(S11all, ct + 3);
    1256           70 :   if (sumr & 7) S11all = gmul(e12(sumr * 3, prec), S11all);
    1257           70 :   if (mpodd(k)) S11all = gneg(S11all);
    1258           70 :   if (precold < prec) S11all = gprec_w(S11all, precold);
    1259           70 :   return gc_upto(av, gmul(S, gmul(ginv(mat), S11all)));
    1260              : }
    1261              : 
    1262              : /* is q = exp(2ipi tau) a real number ? */
    1263              : static int
    1264          427 : isqreal(GEN tau) { return gequal0(gfrac(gmul2n(real_i(tau), 1))); }
    1265              : static void
    1266          427 : cxE4E6(GEN tau, GEN *pE4, GEN *pE6, long prec)
    1267              : {
    1268          427 :   GEN z2, z3, z4, T0 = thetanull_i(tau, prec);
    1269          427 :   int fl = isqreal(tau);
    1270          427 :   z3 = gpowgs(gel(T0, 1), 4);
    1271          427 :   z4 = gpowgs(gel(T0, 2), 4);
    1272          427 :   z2 = gpowgs(gel(T0, 3), 4);
    1273          427 :   if (pE4)
    1274              :   {
    1275          406 :     GEN e = gadd3(gsqr(z2), gsqr(z3), gsqr(z4));
    1276          406 :     *pE4 = gmul2n(fl? real_i(e): e, -1); /* N.B. g2 = (2ipi)^4 E4 / 12 */
    1277              :   }
    1278          427 :   if (pE6)
    1279              :   { /* the roots (e1,e2,e3) of 4x^3 - g2x - g3 are z3+z4, -(z2+z3), z2-z4 */
    1280          392 :     GEN e = gmul3(gadd(z3, z4), gadd(z2, z3), gsub(z4, z2));
    1281          392 :     *pE6 = gmul2n(fl? real_i(e): e, -1); /* N.B. g3 = (2ipi)^6 E6 / -216 */
    1282              :   }
    1283          427 : }
    1284              : 
    1285              : /* Weierstrass elliptic data in terms of thetas */
    1286              : /* tau,z reduced */
    1287              : static GEN
    1288       181972 : ellwp_cx(GEN tau, GEN z, GEN *pyp, long prec)
    1289              : {
    1290       181972 :   GEN P, T0, T = thetaall(z, tau, &T0, prec);
    1291       181972 :   GEN z1 = gel(T0, 1), z3 = gel(T0, 3), t2 = gel(T, 2), t4 = gel(T, 4);
    1292       181972 :   P = gmul(pi23(prec), gsub(gmulgs(gsqr(gdiv(gmul3(z1, z3, t2), t4)), 3),
    1293              :                             gadd(gpowgs(z1, 4), gpowgs(z3, 4))));
    1294       181972 :   if (pyp)
    1295              :   {
    1296       181909 :     GEN t1 = gel(T, 1), t3 = gel(T, 3);
    1297       181909 :     GEN c = gmul(Pi2n(1, prec), gsqr(gel(T0, 4)));
    1298       181909 :     *pyp = gdiv(gmul4(c, t1, t2, t3), gpowgs(t4, 3));
    1299              :   }
    1300       181972 :   return P;
    1301              : }
    1302              : 
    1303              : /* computes the numerical value of wp(z | L), L = om1 Z + om2 Z
    1304              :  * return NULL if z in L.  If flall=1, compute also wp' */
    1305              : static GEN
    1306       181993 : ellwpnum_all(GEN e, GEN z, long flall, long prec)
    1307              : {
    1308       181993 :   pari_sp av = avma;
    1309       181993 :   GEN yp = NULL, y, u1;
    1310              :   ellred_t T;
    1311              : 
    1312       181993 :   if (!get_periods(e, z, &T, prec)) pari_err_TYPE("ellwp",e);
    1313       181993 :   if (!T.Z) return NULL;
    1314       181972 :   prec = T.prec;
    1315              : 
    1316              :   /* Now L,Z normalized to <1,tau>. Z in fund. domain of <1, tau> */
    1317       181972 :   y = ellwp_cx(T.Tau, T.Z, flall? &yp: NULL, prec);
    1318       181972 :   u1 = gsqr(T.W2); y = gdiv(y, u1);
    1319       181972 :   if (yp) yp = gdiv(yp, gmul(u1, T.W2));
    1320       181972 :   if (T.some_q_is_real && (T.some_z_is_real || T.some_z_is_pure_imag))
    1321        47866 :     y = real_i(y);
    1322       181972 :   if (yp)
    1323              :   {
    1324       181909 :     if (T.some_q_is_real)
    1325              :     {
    1326       181909 :       if (T.some_z_is_real) yp = real_i(yp);
    1327       134092 :       else if (T.some_z_is_pure_imag) yp = mkcomplex(gen_0, imag_i(yp));
    1328              :     }
    1329       181909 :     y = mkvec2(y, yp);
    1330              :   }
    1331       181972 :   return gc_GEN(av, gprec_wtrunc(y, T.prec0));
    1332              : }
    1333              : static GEN
    1334          553 : ellwpseries_aux(GEN c4, GEN c6, long v, long PRECDL)
    1335              : {
    1336              :   long i, k, l;
    1337              :   pari_sp av;
    1338          553 :   GEN _1, t, res = cgetg(PRECDL+2,t_SER), *P = (GEN*)(res + 2);
    1339              : 
    1340          553 :   res[1] = evalsigne(1) | _evalvalser(-2) | evalvarn(v);
    1341          553 :   if (!PRECDL) { setsigne(res,0); return res; }
    1342              : 
    1343         7245 :   for (i=1; i<PRECDL; i+=2) P[i]= gen_0;
    1344          553 :   _1 = Rg_get_1(c4);
    1345          553 :   switch(PRECDL)
    1346              :   {
    1347          553 :     default:P[6] = gdivgu(c6,6048);
    1348          553 :     case 6:
    1349          553 :     case 5: P[4] = gdivgu(c4, 240);
    1350          553 :     case 4:
    1351          553 :     case 3: P[2] = gmul(_1,gen_0);
    1352          553 :     case 2:
    1353          553 :     case 1: P[0] = _1;
    1354              :   }
    1355          553 :   if (PRECDL <= 8) return res;
    1356          546 :   av = avma;
    1357          546 :   P[8] = gc_upto(av, gdivgu(gsqr(P[4]), 3));
    1358         4550 :   for (k=5; (k<<1) < PRECDL; k++)
    1359              :   {
    1360         4004 :     av = avma;
    1361         4004 :     t = gmul(P[4], P[(k-2)<<1]);
    1362        16940 :     for (l=3; (l<<1) < k; l++) t = gadd(t, gmul(P[l<<1], P[(k-l)<<1]));
    1363         4004 :     t = gmul2n(t, 1);
    1364         4004 :     if ((k & 1) == 0) t = gadd(gsqr(P[k]), t);
    1365         4004 :     if (k % 3 == 2)
    1366         1435 :       t = gdivgu(gmulsg(3, t), (k-3)*(2*k+1));
    1367              :     else /* same value, more efficient */
    1368         2569 :       t = gdivgu(t, ((k-3)*(2*k+1)) / 3);
    1369         4004 :     P[k<<1] = gc_upto(av, t);
    1370              :   }
    1371          546 :   return res;
    1372              : }
    1373              : 
    1374              : static int
    1375          294 : get_c4c6(GEN w, GEN *c4, GEN *c6, long prec)
    1376              : {
    1377          294 :   if (typ(w) == t_VEC) switch(lg(w))
    1378              :   {
    1379          203 :     case 17:
    1380          203 :       *c4 = ell_get_c4(w);
    1381          203 :       *c6 = ell_get_c6(w); return 1;
    1382           91 :     case 3:
    1383              :     {
    1384              :       GEN E4, E6, a2, a;
    1385              :       ellred_t T;
    1386           91 :       if (!get_periods(w,NULL,&T, prec)) break;
    1387           91 :       a = gdiv(pi23(T.prec + EXTRAPREC64), gsqr(T.W2));
    1388           91 :       cxE4E6(T.Tau, &E4, &E6, prec); a2 = gsqr(a);
    1389           91 :       *c4 = gmul(gmulgs(E4, 144), a2);
    1390           91 :       *c6 = gmul(gmulgs(E6, 1728), gmul(a2,a)); return 1;
    1391              :     }
    1392              :   }
    1393            0 :   *c4 = *c6 = NULL;
    1394            0 :   return 0;
    1395              : }
    1396              : 
    1397              : GEN
    1398           42 : ellwpseries(GEN e, long v, long PRECDL)
    1399              : {
    1400              :   GEN c4, c6;
    1401           42 :   checkell(e);
    1402           42 :   c4 = ell_get_c4(e);
    1403           42 :   c6 = ell_get_c6(e); return ellwpseries_aux(c4,c6,v,PRECDL);
    1404              : }
    1405              : 
    1406              : GEN
    1407            0 : ellwp(GEN w, GEN z, long prec)
    1408            0 : { return ellwp0(w,z,0,prec); }
    1409              : 
    1410              : GEN
    1411          182 : ellwp0(GEN w, GEN z, long flag, long prec)
    1412              : {
    1413          182 :   pari_sp av = avma;
    1414              :   GEN y;
    1415              : 
    1416          182 :   if (flag && flag != 1) pari_err_FLAG("ellwp");
    1417          182 :   if (!z) z = pol_x(0);
    1418          182 :   y = toser_i(z);
    1419          182 :   if (y)
    1420              :   {
    1421          105 :     long vy = varn(y), v = valser(y);
    1422              :     GEN P, Q, c4,c6;
    1423          105 :     if (!get_c4c6(w,&c4,&c6,prec)) pari_err_TYPE("ellwp",w);
    1424          105 :     if (v <= 0) pari_err(e_IMPL,"ellwp(t_SER) away from 0");
    1425          105 :     if (gequal0(y)) {
    1426            0 :       set_avma(av);
    1427            0 :       if (!flag) return zeroser(vy, -2*v);
    1428            0 :       retmkvec2(zeroser(vy, -2*v), zeroser(vy, -3*v));
    1429              :     }
    1430          105 :     P = ellwpseries_aux(c4,c6, vy, lg(y)-2);
    1431          105 :     Q = gsubst(P, varn(P), y);
    1432          105 :     if (!flag)
    1433          105 :       return gc_upto(av, Q);
    1434              :     else
    1435              :     {
    1436            0 :       GEN R = mkvec2(Q, gdiv(derivser(Q), derivser(y)));
    1437            0 :       return gc_GEN(av, R);
    1438              :     }
    1439              :   }
    1440           77 :   y = ellwpnum_all(w,z,flag,prec);
    1441           77 :   if (!y) pari_err_DOMAIN("ellwp", "argument","=", gen_0,z);
    1442           70 :   return gc_upto(av, y);
    1443              : }
    1444              : 
    1445              : static GEN
    1446           70 : ellzeta_cx(ellred_t *T)
    1447              : {
    1448           70 :   GEN e, y, TALL = theta11prime(T->Z, T->Tau, T->prec), ETA = elleta_W(T);
    1449           70 :   y = gadd(gmul(T->Z, gel(ETA,2)),
    1450           70 :            gdiv(gel(TALL,2), gmul(gel(TALL,1), T->W2)));
    1451           70 :   e = _period(T, ETA);
    1452           70 :   if (T->some_q_is_real)
    1453              :   {
    1454           70 :     if (T->some_z_is_real)
    1455              :     {
    1456           28 :       if (e == gen_0 || typ(e) != t_COMPLEX) y = real_i(y);
    1457              :     }
    1458           42 :     else if (T->some_z_is_pure_imag)
    1459              :     {
    1460           21 :       if (e == gen_0 || (typ(e) == t_COMPLEX && isintzero(gel(e,1))))
    1461           21 :         gel(y,1) = gen_0;
    1462              :     }
    1463              :   }
    1464           70 :   return gprec_wtrunc(e != gen_0? gadd(y, e): y, T->prec0);
    1465              : }
    1466              : GEN
    1467          161 : ellzeta(GEN w, GEN z, long prec0)
    1468              : {
    1469          161 :   pari_sp av = avma;
    1470              :   ellred_t T;
    1471              :   GEN y;
    1472              : 
    1473          161 :   if (!z) z = pol_x(0);
    1474          161 :   y = toser_i(z);
    1475          161 :   if (y)
    1476              :   {
    1477           91 :     long vy = varn(y), v = valser(y);
    1478              :     GEN P, Q, c4,c6;
    1479           91 :     if (!get_c4c6(w,&c4,&c6,prec0)) pari_err_TYPE("ellzeta",w);
    1480           91 :     if (v <= 0) pari_err(e_IMPL,"ellzeta(t_SER) away from 0");
    1481           91 :     if (gequal0(y)) { set_avma(av); return zeroser(vy, -v); }
    1482           91 :     P = ellwpseries_aux(c4,c6, vy, lg(y)-2);
    1483           91 :     P = integser(gneg(P)); /* \zeta' = - \wp*/
    1484           91 :     Q = gsubst(P, varn(P), y);
    1485           91 :     return gc_upto(av, Q);
    1486              :   }
    1487           70 :   if (!get_periods(w, z, &T, prec0)) pari_err_TYPE("ellzeta", w);
    1488           70 :   if (!T.Z) pari_err_DOMAIN("ellzeta", "z", "=", gen_0, z);
    1489           70 :   return gc_GEN(av, ellzeta_cx(&T));
    1490              : }
    1491              : 
    1492              : static GEN
    1493        37569 : ellsigma_cx(ellred_t *T, long flag)
    1494              : {
    1495        37569 :   long prec = T->prec;
    1496        37569 :   GEN t0, t = thetaall(T->Z, T->Tau, &t0, prec), ETA = elleta_W(T);
    1497        37569 :   GEN y1, y = gmul(T->W2, gdiv(gel(t, 4), gel(t0, 4)));
    1498              : 
    1499              :   /* y = W2 theta_1(q, Z) / theta_1'(q, 0)
    1500              :    *   = sigma([W1, W2], W2 Z) * exp(-eta2 W2 Z^2/2)
    1501              :    * We have z/W2 = Z + x Tau + y, so
    1502              :    * sigma([W1,W2], z) = (-1)^(x+y+xy) sigma([W1,W2], W2 Z) exp(W2 y1) where
    1503              :    *   y1 = eta2 Z^2/2 + (x eta1 + y eta2)(Z + (x Tau + y)/2) */
    1504              : 
    1505        37569 :   y1 = gadd(T->Z, gmul2n(_period(T, mkvec2(T->Tau,gen_1)), -1));
    1506        37569 :   y1 = gadd(gmul(_period(T, ETA), y1),
    1507        37569 :             gmul2n(gmul(gsqr(T->Z),gel(ETA,2)), -1));
    1508        37569 :   if (flag)
    1509              :   {
    1510        37499 :     y = gadd(gmul(T->W2,y1), glog(y,prec));
    1511        37499 :     if (mpodd(T->x) || mpodd(T->y)) y = gadd(y, PiI2n(0, prec));
    1512              :     /* log(real number): im(y) = 0 or Pi */
    1513        37499 :     if (T->some_q_is_real && isintzero(imag_i(T->z)) && gexpo(imag_i(y)) < 1)
    1514            7 :       y = real_i(y);
    1515              :   }
    1516              :   else
    1517              :   {
    1518           70 :     y = gmul(y, gexp(gmul(T->W2, y1), prec));
    1519           70 :     if (mpodd(T->x) || mpodd(T->y)) y = gneg_i(y);
    1520           70 :     if (T->some_q_is_real)
    1521              :     {
    1522              :       int re, cx;
    1523           70 :       check_complex(T->z,&re,&cx);
    1524           70 :       if (re) y = real_i(y);
    1525           49 :       else if (cx && typ(y) == t_COMPLEX) gel(y,1) = gen_0;
    1526              :     }
    1527              :   }
    1528        37569 :   return gprec_wtrunc(y, T->prec0);
    1529              : }
    1530              : /* if flag=0, return ellsigma, otherwise return log(ellsigma) */
    1531              : GEN
    1532        37674 : ellsigma(GEN w, GEN z, long flag, long prec0)
    1533              : {
    1534        37674 :   pari_sp av = avma;
    1535              :   ellred_t T;
    1536              :   GEN y;
    1537              : 
    1538        37674 :   if (flag < 0 || flag > 1) pari_err_FLAG("ellsigma");
    1539        37674 :   if (!z) z = pol_x(0);
    1540        37674 :   y = toser_i(z);
    1541        37674 :   if (y)
    1542              :   {
    1543           98 :     long vy = varn(y), v = valser(y);
    1544              :     GEN P, Q, c4,c6;
    1545           98 :     if (!get_c4c6(w,&c4,&c6,prec0)) pari_err_TYPE("ellsigma",w);
    1546           98 :     if (v <= 0) pari_err_IMPL("ellsigma(t_SER) away from 0");
    1547           98 :     if (flag) pari_err_TYPE("log(ellsigma)",y);
    1548           91 :     if (gequal0(y)) { set_avma(av); return zeroser(vy, -v); }
    1549           91 :     P = ellwpseries_aux(c4,c6, vy, lg(y)-2);
    1550           91 :     P = integser(gneg(P)); /* \zeta' = - \wp*/
    1551              :     /* (log \sigma)' = \zeta; remove log-singularity first */
    1552           91 :     P = integser(serchop0(P));
    1553           91 :     P = gexp(P, prec0);
    1554           91 :     setvalser(P, valser(P)+1);
    1555           91 :     Q = gsubst(P, varn(P), y);
    1556           91 :     return gc_upto(av, Q);
    1557              :   }
    1558        37576 :   if (!get_periods(w, z, &T, prec0)) pari_err_TYPE("ellsigma",w);
    1559        37576 :   if (!T.Z)
    1560              :   {
    1561            7 :     if (!flag) return gen_0;
    1562            7 :     pari_err_DOMAIN("log(ellsigma)", "argument","=",gen_0,z);
    1563              :   }
    1564        37569 :   return gc_GEN(av, ellsigma_cx(&T, flag));
    1565              : }
    1566              : 
    1567              : GEN
    1568       181972 : pointell(GEN e, GEN z, long prec)
    1569              : {
    1570       181972 :   pari_sp av = avma;
    1571              :   GEN v;
    1572              : 
    1573       181972 :   checkell(e);
    1574       181972 :   if (ell_get_type(e) == t_ELL_Qp)
    1575              :   {
    1576           56 :     prec = minss(ellQp_get_prec(e), padicprec_relative(z));
    1577           56 :     return ellQp_t2P(e, z, prec);
    1578              :   }
    1579       181916 :   v = ellwpnum_all(e,z,1,prec);
    1580       181916 :   if (!v) { set_avma(av); return ellinf(); }
    1581       181902 :   gel(v,1) = gsub(gel(v,1), gdivgu(ell_get_b2(e),12));
    1582       181902 :   gel(v,2) = gmul2n(gsub(gel(v,2), ec_h_evalx(e,gel(v,1))),-1);
    1583       181902 :   return gc_GEN(av, v);
    1584              : }
    1585              : 
    1586              : /********************************************************************/
    1587              : /**              Eisenstein series of level 1                      **/
    1588              : /********************************************************************/
    1589              : 
    1590              : GEN
    1591       262413 : upper_to_cx(GEN x, long *prec)
    1592              : {
    1593       262413 :   long tx = typ(x), l;
    1594       262413 :   if (tx == t_QUAD) { x = quadtofp(x, *prec); tx = typ(x); }
    1595       262413 :   switch(tx)
    1596              :   {
    1597       262392 :     case t_COMPLEX:
    1598       262392 :       if (gsigne(gel(x,2)) > 0) break; /*fall through*/
    1599              :     case t_REAL: case t_INT: case t_FRAC:
    1600           14 :       pari_err_DOMAIN("modular function", "Im(argument)", "<=", gen_0, x);
    1601            7 :     default:
    1602            7 :       pari_err_TYPE("modular function", x);
    1603              :   }
    1604       262392 :   l = precision(x); if (l) *prec = l;
    1605       262392 :   return x;
    1606              : }
    1607              : 
    1608              : static GEN
    1609        42116 : qq(GEN x, long prec)
    1610              : {
    1611        42116 :   long tx = typ(x);
    1612              :   GEN y;
    1613              : 
    1614        42116 :   if (is_scalar_t(tx))
    1615              :   {
    1616        42074 :     if (tx == t_PADIC) return x;
    1617        42060 :     x = upper_to_cx(x, &prec);
    1618        42046 :     return cxtoreal(expIPiC(gmul2n(x,1), prec)); /* e(x) */
    1619              :   }
    1620           42 :   if (! ( y = toser_i(x)) ) pari_err_TYPE("modular function", x);
    1621           42 :   return y;
    1622              : }
    1623              : 
    1624              : /* P = ellwpseries_aux(E4, E6, 0, kmax), where kmax >= k+2. Beware we use
    1625              :  * E4,E6 instead of c4,c6: coeffs rescale to (k-1) G_k / (2pi)^k */
    1626              : static GEN
    1627          392 : Ek_from_wp(GEN P, long k)
    1628              : { /* P[k+2] = Ek * (k-1) * 2 zeta(k) / (2pi)^k = Ek * (k-1) * |B_k| / k! */
    1629          392 :   return gdiv(gmul(gel(P, k + 2), muliu(mpfact(k-2), k)),
    1630              :               absfrac_shallow(bernfrac(k)));
    1631              : }
    1632              : /* P = ellwpseries(e, kmax), where kmax >= k+2 */
    1633              : static GEN
    1634          231 : elleis_from_wp(GEN P, long k)
    1635          231 : { return gneg(gmul(gel(P, k + 2), gdiv(muliu(mpfact(k-2), k), bernfrac(k)))); }
    1636              : 
    1637              : /* k > 0 even, tau reduced (in particular Im tau > 0). Return
    1638              :  * E_k(tau) = 1 + 2/zeta(1-k) * sum_n n^(k-1) q^n/(1-q^n) */
    1639              : GEN
    1640        42385 : cxEk(GEN tau, long k, long prec)
    1641              : {
    1642        42385 :   pari_sp av = avma;
    1643        42385 :   GEN P, y, E4 = NULL, E6 = NULL;
    1644              :   long b;
    1645              : 
    1646        42385 :   if ((b = precision(tau))) prec = b;
    1647        42385 :   if (gcmpgs(imag_i(tau), (M_LN2 / (2*M_PI)) * (prec2nbits(prec)+1+10)) > 0)
    1648           17 :     return real_1(prec);
    1649        42368 :   if (k == 2)
    1650              :   { /* -theta^(3)(tau/2) / theta^(1)(tau/2) */
    1651        42039 :     y = vecthetanullk_loop(qq(tau,prec), 2, prec);
    1652        42039 :     return gdiv(gel(y,2), gel(y,1));
    1653              :   }
    1654          329 :   if (k > 8) cxE4E6(tau, &E4, &E6, k < 16? prec: prec + EXTRAPREC64);
    1655          329 :   switch (k)
    1656              :   {
    1657           21 :     case 4:  cxE4E6(tau, &E4, NULL, prec); return gc_GEN(av, E4);
    1658           21 :     case 6:  cxE4E6(tau, NULL, &E6, prec); return gc_GEN(av, E6);
    1659           14 :     case 8:  cxE4E6(tau, &E4, NULL, prec); return gc_upto(av, gsqr(E4));
    1660           28 :     case 10: return gc_upto(av, gmul(E4, E6));
    1661           14 :     case 12:
    1662              :     {
    1663           14 :       GEN e = gadd(gmulsg(441, gpowgs(E4,3)), gmulsg(250, gsqr(E6)));
    1664           14 :       return gc_upto(av, gdivgs(e, 691));
    1665              :     }
    1666           14 :     case 14: return gc_upto(av, gmul(gsqr(E4), E6));
    1667              :   }
    1668          217 :   P = ellwpseries_aux(E4, E6, 0, k + 2);
    1669          217 :   return gc_GEN(av, gprec_wtrunc(Ek_from_wp(P, k), prec));
    1670              : }
    1671              : 
    1672              : static GEN
    1673         4025 : E2_correction(ellred_t *T)
    1674         4025 : { return gmul(mului(12, T->c), PiI2div(gmul(T->W2,T->w2), T->prec)); }
    1675              : 
    1676              : /* Return y = (2iPi)^k E_k(L) = (2iPi/w2)^k E_k(tau), L = <w1,w2>, k > 0 even.
    1677              :  * Let G_k(L) = sum' 1/l^k = 2 zeta(k) E_k(L) =  - y * B_k / k! then
    1678              :  *   z^2 wp(L,z) = 1 + sum_{k > 1} (k-1)G_k z^k */
    1679              : GEN
    1680         4781 : elleisnum(GEN om, long k, long prec)
    1681              : {
    1682         4781 :   pari_sp av = avma;
    1683              :   GEN y, w, Ek;
    1684              :   ellred_t T;
    1685              : 
    1686         4781 :   elleisnum_testk(k);
    1687         4767 :   if (checkell_i(om)) switch(k)
    1688              :   {
    1689           14 :     case 2:
    1690           14 :       y = ellR_eta(om, prec);
    1691           14 :       w = ellR_omega(om, prec);
    1692           14 :       return gc_upto(av, gdiv(gmulgs(gel(y,2), -12), gel(w,2)));
    1693           14 :     case 4: return gcopy(ell_get_c4(om));
    1694            7 :     case 6: return gneg(ell_get_c6(om));
    1695           14 :     default:
    1696           14 :       y = ellwpseries(om, 0, k + 2);
    1697           14 :       return gc_upto(av, elleis_from_wp(y, k));
    1698              :   }
    1699         4718 :   if (!get_periods(om, NULL, &T, prec)) pari_err_TYPE("elleisnum",om);
    1700         4718 :   Ek = cxEk(T.Tau, k, T.prec);
    1701         4718 :   y = cxtoreal( gmul(Ek, gpowgs(PiI2div_sqr(T.W2, T.prec), k/2)));
    1702         4718 :   if (k==2 && signe(T.c)) y = gsub(y, E2_correction(&T));
    1703         4718 :   return gc_GEN(av, gprec_wtrunc(y, T.prec0));
    1704              : }
    1705              : 
    1706              : GEN
    1707          448 : elleisnum0(GEN om, GEN k, long prec)
    1708              : {
    1709          448 :   pari_sp av = avma;
    1710          448 :   GEN iW2, W, E4, E6, vG, P = NULL;
    1711              :   long i, l, kmax;
    1712              :   ellred_t T;
    1713              : 
    1714          448 :   if (typ(k) == t_INT) return elleisnum(om, itos(k), prec);
    1715           28 :   if (typ(k) != t_VEC || !RgV_is_ZV(k)) pari_err_TYPE("elleisnum",k);
    1716           28 :   l = lg(k); if (l == 2) retmkvec(elleisnum(om, itos(gel(k,1)), prec));
    1717           28 :   k = ZV_to_zv(k); kmax = 0;
    1718          462 :   for (i = 1; i < l; i++)
    1719              :   {
    1720          441 :     elleisnum_testk(k[i]);
    1721          434 :     if (k[i] > kmax) kmax = k[i];
    1722              :   }
    1723           21 :   if (checkell_i(om))
    1724              :   {
    1725           14 :     if (l == 1) { set_avma(av); return cgetg(1, t_VEC); }
    1726           14 :     P = ellwpseries(om, 0, kmax + 2);
    1727           14 :     vG = cgetg(l, t_VEC);
    1728          238 :     for (i = 1; i < l; i++)
    1729              :     {
    1730          224 :       long ki = k[i];
    1731          224 :       gel(vG, i) = (ki == 2)? elleisnum(om, 2, prec) : elleis_from_wp(P, ki);
    1732              :     }
    1733           14 :     return gc_GEN(av, vG);
    1734              :   }
    1735            7 :   if (!get_periods(om, NULL, &T, prec)) pari_err_TYPE("elleisnum",om);
    1736            7 :   if (l == 1) { set_avma(av); return cgetg(1, t_VEC); }
    1737            7 :   cxE4E6(T.tau, &E4, &E6, kmax < 16? prec: prec + EXTRAPREC64);
    1738            7 :   if (kmax > 10) P = ellwpseries_aux(E4, E6, 0, kmax+2);
    1739            7 :   iW2 = PiI2div_sqr(T.W2, prec); /* (2iPi / W2)^2 */
    1740            7 :   W = gpowers0(iW2, kmax/2, iW2); /* .[k] = (2ipi/W2)^(2k) */
    1741            7 :   vG = cgetg(l, t_VEC);
    1742          217 :   for (i = 1; i < l; i++)
    1743              :   {
    1744          210 :     long ki = k[i];
    1745              :     GEN e, G;
    1746          210 :     switch(ki)
    1747              :     {
    1748            7 :       case 2: e = cxEk(T.Tau, 2, prec); break;
    1749            7 :       case 4: e = E4; break;
    1750            7 :       case 6: e = E6; break;
    1751            7 :       case 8: e = gsqr(E4); break;
    1752            7 :       case 10:e = gmul(E4, E6); break;
    1753          175 :       default: e = Ek_from_wp(P, ki);
    1754              :     }
    1755          210 :     G = cxtoreal( gmul(e, gel(W, ki/2)) ); /* (2iPi/W2)^ki E_k(W1/W2) */
    1756          210 :     if (ki == 2 && signe(T.c)) G = gsub(G, E2_correction(&T));
    1757          210 :     gel(vG, i) = gprec_wtrunc(G, T.prec0);
    1758              :   }
    1759            7 :   return gc_GEN(av, vG);
    1760              : }
    1761              : 
    1762              : /********************************************************************/
    1763              : /**                 Eta function(s) and j-invariant                **/
    1764              : /********************************************************************/
    1765              : 
    1766              : /* return (y * X^d) + x. Assume d > 0, x != 0, valser(x) = 0 */
    1767              : static GEN
    1768           21 : ser_addmulXn(GEN y, GEN x, long d)
    1769              : {
    1770           21 :   long i, lx, ly, l = valser(y) + d; /* > 0 */
    1771              :   GEN z;
    1772              : 
    1773           21 :   lx = lg(x);
    1774           21 :   ly = lg(y) + l; if (lx < ly) ly = lx;
    1775           21 :   if (l > lx-2) return gcopy(x);
    1776           21 :   z = cgetg(ly,t_SER);
    1777           77 :   for (i=2; i<=l+1; i++) gel(z,i) = gel(x,i);
    1778           70 :   for (   ; i < ly; i++) gel(z,i) = gadd(gel(x,i),gel(y,i-l));
    1779           21 :   z[1] = x[1]; return z;
    1780              : }
    1781              : 
    1782              : /* q a t_POL s.t. q(0) != 0, v > 0, Q = x^v*q; return \prod_i (1-Q^i) */
    1783              : static GEN
    1784           28 : RgXn_eta(GEN q, long v, long lim)
    1785              : {
    1786           28 :   pari_sp av = avma;
    1787              :   GEN qn, ps, y;
    1788              :   ulong vps, vqn, n;
    1789              : 
    1790           28 :   if (!degpol(q) && isint1(gel(q,2))) return eta_ZXn(v, lim+v);
    1791            7 :   y = qn = ps = pol_1(0);
    1792            7 :   vps = vqn = 0;
    1793            7 :   for(n = 0;; n++)
    1794            7 :   { /* qn = q^n,  ps = (-1)^n q^(n(3n+1)/2),
    1795              :      * vps, vqn valuation of ps, qn HERE */
    1796           14 :     pari_sp av2 = avma;
    1797           14 :     ulong vt = vps + 2*vqn + v; /* valuation of t at END of loop body */
    1798              :     long k1, k2;
    1799              :     GEN t;
    1800           14 :     vqn += v; vps = vt + vqn; /* valuation of qn, ps at END of body */
    1801           14 :     k1 = lim + v - vt + 1;
    1802           14 :     k2 = k1 - vqn; /* = lim + v - vps + 1 */
    1803           14 :     if (k1 <= 0) break;
    1804           14 :     t = RgX_mul(q, RgX_sqr(qn));
    1805           14 :     t = RgXn_red_shallow(t, k1);
    1806           14 :     t = RgX_mul(ps,t);
    1807           14 :     t = RgXn_red_shallow(t, k1);
    1808           14 :     t = RgX_neg(t); /* t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */
    1809           14 :     t = gc_upto(av2, t);
    1810           14 :     y = RgX_addmulXn_shallow(t, y, vt);
    1811           14 :     if (k2 <= 0) break;
    1812              : 
    1813            7 :     qn = RgX_mul(qn,q);
    1814            7 :     ps = RgX_mul(t,qn);
    1815            7 :     ps = RgXn_red_shallow(ps, k2);
    1816            7 :     y = RgX_addmulXn_shallow(ps, y, vps);
    1817              : 
    1818            7 :     if (gc_needed(av,1))
    1819              :     {
    1820            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"eta, n = %ld", n);
    1821            0 :       (void)gc_all(av, 3, &y, &qn, &ps);
    1822              :     }
    1823              :   }
    1824            7 :   return y;
    1825              : }
    1826              : 
    1827              : static GEN
    1828         7639 : inteta(GEN q)
    1829              : {
    1830         7639 :   long tx = typ(q);
    1831              :   GEN ps, qn, y;
    1832              : 
    1833         7639 :   y = gen_1; qn = gen_1; ps = gen_1;
    1834         7639 :   if (tx==t_PADIC)
    1835              :   {
    1836           28 :     if (valp(q) <= 0) pari_err_DOMAIN("eta", "v_p(q)", "<=",gen_0,q);
    1837              :     for(;;)
    1838           56 :     {
    1839           77 :       GEN t = gneg_i(gmul(ps,gmul(q,gsqr(qn))));
    1840           77 :       y = gadd(y,t); qn = gmul(qn,q); ps = gmul(t,qn);
    1841           77 :       t = y;
    1842           77 :       y = gadd(y,ps); if (gequal(t,y)) return y;
    1843              :     }
    1844              :   }
    1845              : 
    1846         7611 :   if (tx == t_SER)
    1847              :   {
    1848              :     ulong vps, vqn;
    1849           42 :     long l = lg(q), v, n;
    1850              :     pari_sp av;
    1851              : 
    1852           42 :     v = valser(q); /* handle valuation separately to avoid overflow */
    1853           42 :     if (v <= 0) pari_err_DOMAIN("eta", "v_p(q)", "<=",gen_0,q);
    1854           35 :     y = ser2pol_i(q, l); /* t_SER inefficient when input has low degree */
    1855           35 :     n = degpol(y);
    1856           35 :     if (n <= (l>>2))
    1857              :     {
    1858           28 :       GEN z = RgXn_eta(y, v, l-2);
    1859           28 :       setvarn(z, varn(y)); return RgX_to_ser(z, l+v);
    1860              :     }
    1861            7 :     q = leafcopy(q); av = avma;
    1862            7 :     setvalser(q, 0);
    1863            7 :     y = scalarser(gen_1, varn(q), l+v);
    1864            7 :     vps = vqn = 0;
    1865            7 :     for(n = 0;; n++)
    1866            7 :     { /* qn = q^n,  ps = (-1)^n q^(n(3n+1)/2) */
    1867           14 :       ulong vt = vps + 2*vqn + v;
    1868              :       long k;
    1869              :       GEN t;
    1870           14 :       t = gneg_i(gmul(ps,gmul(q,gsqr(qn))));
    1871              :       /* t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */
    1872           14 :       y = ser_addmulXn(t, y, vt);
    1873           14 :       vqn += v; vps = vt + vqn;
    1874           14 :       k = l+v - vps; if (k <= 2) return y;
    1875              : 
    1876            7 :       qn = gmul(qn,q); ps = gmul(t,qn);
    1877            7 :       y = ser_addmulXn(ps, y, vps);
    1878            7 :       setlg(q, k);
    1879            7 :       setlg(qn, k);
    1880            7 :       setlg(ps, k);
    1881            7 :       if (gc_needed(av,3))
    1882              :       {
    1883            0 :         if(DEBUGMEM>1) pari_warn(warnmem,"eta");
    1884            0 :         (void)gc_all(av, 3, &y, &qn, &ps);
    1885              :       }
    1886              :     }
    1887              :   }
    1888              :   {
    1889         7569 :     long l = -prec2nbits(precision(q));
    1890         7569 :     pari_sp av = avma;
    1891              : 
    1892              :     for(;;)
    1893        20750 :     {
    1894        28319 :       GEN t = gneg_i(gmul(ps,gmul(q,gsqr(qn))));
    1895              :       /* qn = q^n
    1896              :        * ps = (-1)^n q^(n(3n+1)/2)
    1897              :        * t = (-1)^(n+1) q^(n(3n+1)/2 + 2n+1) */
    1898        28319 :       y = gadd(y,t); qn = gmul(qn,q); ps = gmul(t,qn);
    1899        28319 :       y = gadd(y,ps);
    1900        28319 :       if (gexpo(ps)-gexpo(y) < l) return y;
    1901        20750 :       if (gc_needed(av,3))
    1902              :       {
    1903            0 :         if(DEBUGMEM>1) pari_warn(warnmem,"eta");
    1904            0 :         (void)gc_all(av, 3, &y, &qn, &ps);
    1905              :       }
    1906              :     }
    1907              :   }
    1908              : }
    1909              : 
    1910              : GEN
    1911           77 : eta(GEN x, long prec)
    1912              : {
    1913           77 :   pari_sp av = avma;
    1914           77 :   GEN z = inteta( qq(x,prec) );
    1915           49 :   if (typ(z) == t_SER) return gc_GEN(av, z);
    1916           14 :   return gc_upto(av, z);
    1917              : }
    1918              : 
    1919              : /* s(h,k) = sum(n = 1, k-1, (n/k)*(frac(h*n/k) - 1/2))
    1920              :  * Knuth's algorithm. h integer, k integer > 0, (h,k) = 1 */
    1921              : GEN
    1922         6300 : sumdedekind_coprime(GEN h, GEN k)
    1923              : {
    1924         6300 :   pari_sp av = avma;
    1925              :   GEN s2, s1, p, pp;
    1926              :   long s;
    1927         6300 :   if (lgefint(k) == 3 && uel(k,2) <= (2*(ulong)LONG_MAX) / 3)
    1928              :   {
    1929         6293 :     ulong kk = k[2], hh = umodiu(h, kk);
    1930              :     long s1, s2;
    1931              :     GEN v;
    1932         6293 :     if (signe(k) < 0) { k = negi(k); hh = Fl_neg(hh, kk); }
    1933         6293 :     v = u_sumdedekind_coprime(hh, kk);
    1934         6293 :     s1 = v[1]; s2 = v[2];
    1935         6293 :     return gc_upto(av, gdiv(addis(mulis(k,s1), s2), muluu(12, kk)));
    1936              :   }
    1937            7 :   s = 1;
    1938            7 :   s1 = gen_0; p = gen_1; pp = gen_0;
    1939            7 :   s2 = h = modii(h, k);
    1940           35 :   while (signe(h)) {
    1941           28 :     GEN r, nexth, a = dvmdii(k, h, &nexth);
    1942           28 :     if (is_pm1(h)) s2 = s == 1? addii(s2, p): subii(s2, p);
    1943           28 :     s1 = s == 1? addii(s1, a): subii(s1, a);
    1944           28 :     s = -s;
    1945           28 :     k = h; h = nexth;
    1946           28 :     r = addii(mulii(a,p), pp); pp = p; p = r;
    1947              :   }
    1948              :   /* at this point p = original k */
    1949            7 :   if (s == -1) s1 = subiu(s1, 3);
    1950            7 :   return gc_upto(av, gdiv(addii(mulii(p,s1), s2), muliu(p,12)));
    1951              : }
    1952              : /* as above, for ulong arguments.
    1953              :  * k integer > 0, 0 <= h < k, (h,k) = 1. Returns [s1,s2] such that
    1954              :  * s(h,k) = (s2 + k s1) / (12k). Requires max(h + k/2, k) < LONG_MAX
    1955              :  * to avoid overflow, in particular k <= LONG_MAX * 2/3 is fine */
    1956              : GEN
    1957         6293 : u_sumdedekind_coprime(long h, long k)
    1958              : {
    1959         6293 :   long s = 1, s1 = 0, s2 = h, p = 1, pp = 0;
    1960        11466 :   while (h) {
    1961         5173 :     long r, nexth = k % h, a = k / h; /* a >= 1, a >= 2 if h = 1 */
    1962         5173 :     if (h == 1) s2 += p * s; /* occurs exactly once, last step */
    1963         5173 :     s1 += a * s;
    1964         5173 :     s = -s;
    1965         5173 :     k = h; h = nexth;
    1966         5173 :     r = a*p + pp; pp = p; p = r; /* p >= pp >= 0 */
    1967              :   }
    1968              :   /* in the above computation, p increases from 1 to original k,
    1969              :    * -k/2 <= s2 <= h + k/2, and |s1| <= k */
    1970         6293 :   if (s < 0) s1 -= 3; /* |s1| <= k+3 ? */
    1971              :   /* But in fact, |s2 + p s1| <= k^2 + 1/2 - 3k; if (s < 0), we have
    1972              :    * |s2| <= k/2 and it follows that |s1| < k here as well */
    1973              :   /* p = k; s(h,k) = (s2 + p s1)/12p. */
    1974         6293 :   return mkvecsmall2(s1, s2);
    1975              : }
    1976              : GEN
    1977           28 : sumdedekind(GEN h, GEN k)
    1978              : {
    1979           28 :   pari_sp av = avma;
    1980              :   GEN d;
    1981           28 :   if (typ(h) != t_INT) pari_err_TYPE("sumdedekind",h);
    1982           28 :   if (typ(k) != t_INT) pari_err_TYPE("sumdedekind",k);
    1983           28 :   d = gcdii(h,k);
    1984           28 :   if (!is_pm1(d))
    1985              :   {
    1986            7 :     h = diviiexact(h, d);
    1987            7 :     k = diviiexact(k, d);
    1988              :   }
    1989           28 :   return gc_upto(av, sumdedekind_coprime(h,k));
    1990              : }
    1991              : 
    1992              : /* eta(x); assume Im x >> 0 (e.g. x in SL2's standard fundamental domain) */
    1993              : static GEN
    1994         8477 : eta_reduced(GEN x, long prec)
    1995              : {
    1996         8477 :   GEN z = expIPiC(gdivgu(x, 12), prec); /* e(x/24) */
    1997         8477 :   if (24 * gexpo(z) >= -prec2nbits(prec))
    1998         7548 :     z = gmul(z, inteta( gpowgs(z,24) ));
    1999         8477 :   return z;
    2000              : }
    2001              : 
    2002              : /* x = U.z (flag = 1), or x = U^(-1).z (flag = 0)
    2003              :  * Return [s,t] such that eta(z) = eta(x) * sqrt(s) * exp(I Pi t) */
    2004              : static GEN
    2005         8491 : eta_correction(GEN x, GEN U, long flag)
    2006              : {
    2007              :   GEN a,b,c,d, s,t;
    2008              :   long sc;
    2009         8491 :   a = gcoeff(U,1,1);
    2010         8491 :   b = gcoeff(U,1,2);
    2011         8491 :   c = gcoeff(U,2,1);
    2012         8491 :   d = gcoeff(U,2,2);
    2013              :   /* replace U by U^(-1) */
    2014         8491 :   if (flag) {
    2015          119 :     swap(a,d);
    2016          119 :     togglesign_safe(&b);
    2017          119 :     togglesign_safe(&c);
    2018              :   }
    2019         8491 :   sc = signe(c);
    2020         8491 :   if (!sc) {
    2021         2219 :     if (signe(d) < 0) togglesign_safe(&b);
    2022         2219 :     s = gen_1;
    2023         2219 :     t = uutoQ(umodiu(b, 24), 12);
    2024              :   } else {
    2025         6272 :     if (sc < 0) {
    2026         1764 :       togglesign_safe(&a);
    2027         1764 :       togglesign_safe(&b);
    2028         1764 :       togglesign_safe(&c);
    2029         1764 :       togglesign_safe(&d);
    2030              :     } /* now c > 0 */
    2031         6272 :     s = mulcxmI(gadd(gmul(c,x), d));
    2032         6272 :     t = gadd(gdiv(addii(a,d),muliu(c,12)), sumdedekind_coprime(negi(d),c));
    2033              :     /* correction : exp(I Pi (((a+d)/12c) + s(-d,c)) ) sqrt(-i(cx+d))  */
    2034              :   }
    2035         8491 :   return mkvec2(s, t);
    2036              : }
    2037              : 
    2038              : /* returns the true value of eta(x) for Im(x) > 0, using reduction to
    2039              :  * standard fundamental domain */
    2040              : GEN
    2041           35 : trueeta(GEN x, long prec)
    2042              : {
    2043           35 :   pari_sp av = avma;
    2044              :   GEN U, st, s, t;
    2045              : 
    2046           35 :   if (!is_scalar_t(typ(x))) pari_err_TYPE("trueeta",x);
    2047           35 :   x = upper_to_cx(x, &prec);
    2048           35 :   x = cxredsl2(x, &U);
    2049           35 :   st = eta_correction(x, U, 1);
    2050           35 :   x = eta_reduced(x, prec);
    2051           35 :   s = gel(st, 1);
    2052           35 :   t = gel(st, 2);
    2053           35 :   x = gmul(x, expIPiQ(t, prec));
    2054           35 :   if (s != gen_1) x = gmul(x, gsqrt(s, prec));
    2055           35 :   return gc_upto(av, x);
    2056              : }
    2057              : 
    2058              : GEN
    2059          112 : eta0(GEN x, long flag,long prec)
    2060          112 : { return flag? trueeta(x,prec): eta(x,prec); }
    2061              : 
    2062              : /* eta(q) = 1 + \sum_{n>0} (-1)^n * (q^(n(3n-1)/2) + q^(n(3n+1)/2)) */
    2063              : static GEN
    2064            7 : ser_eta(long prec)
    2065              : {
    2066            7 :   GEN e = cgetg(prec+2, t_SER), ed = e+2;
    2067              :   long n, j;
    2068            7 :   e[1] = evalsigne(1)|_evalvalser(0)|evalvarn(0);
    2069            7 :   gel(ed,0) = gen_1;
    2070          483 :   for (n = 1; n < prec; n++) gel(ed,n) = gen_0;
    2071           49 :   for (n = 1, j = 0; n < prec; n++)
    2072              :   {
    2073              :     GEN s;
    2074           49 :     j += 3*n-2; /* = n*(3*n-1) / 2 */;
    2075           49 :     if (j >= prec) break;
    2076           42 :     s = odd(n)? gen_m1: gen_1;
    2077           42 :     gel(ed, j) = s;
    2078           42 :     if (j+n >= prec) break;
    2079           42 :     gel(ed, j+n) = s;
    2080              :   }
    2081            7 :   return e;
    2082              : }
    2083              : 
    2084              : static GEN
    2085          476 : coeffEu(GEN fa)
    2086              : {
    2087          476 :   pari_sp av = avma;
    2088          476 :   return gc_INT(av, mului(65520, usumdivk_fact(fa,11)));
    2089              : }
    2090              : /* E12 = 1 + q*E/691 */
    2091              : static GEN
    2092            7 : ser_E(long prec)
    2093              : {
    2094            7 :   GEN e = cgetg(prec+2, t_SER), ed = e+2;
    2095            7 :   GEN F = vecfactoru_i(2, prec); /* F[n] = factoru(n+1) */
    2096              :   long n;
    2097            7 :   e[1] = evalsigne(1)|_evalvalser(0)|evalvarn(0);
    2098            7 :   gel(ed,0) = utoipos(65520);
    2099          483 :   for (n = 1; n < prec; n++) gel(ed,n) = coeffEu(gel(F,n));
    2100            7 :   return e;
    2101              : }
    2102              : /* j = E12/Delta + 432000/691, E12 = 1 + q*E/691 */
    2103              : static GEN
    2104            7 : ser_j2(long prec, long v)
    2105              : {
    2106            7 :   pari_sp av = avma;
    2107            7 :   GEN iD = gpowgs(ginv(ser_eta(prec)), 24); /* q/Delta */
    2108            7 :   GEN J = gmul(ser_E(prec), iD);
    2109            7 :   setvalser(iD,-1); /* now 1/Delta */
    2110            7 :   J = gadd(gdivgu(J, 691), iD);
    2111            7 :   J = gc_upto(av, J);
    2112            7 :   if (prec > 1) gel(J,3) = utoipos(744);
    2113            7 :   setvarn(J,v); return J;
    2114              : }
    2115              : 
    2116              : /* j(q) = \sum_{n >= -1} c(n)q^n,
    2117              :  * \sum_{n = -1}^{N-1} c(n) (-10n \sigma_3(N-n) + 21 \sigma_5(N-n))
    2118              :  * = c(N) (N+1)/24 */
    2119              : static GEN
    2120           14 : ser_j(long prec, long v)
    2121              : {
    2122              :   GEN j, J, S3, S5, F;
    2123              :   long i, n;
    2124           14 :   if (prec > 64) return ser_j2(prec, v);
    2125            7 :   S3 = cgetg(prec+1, t_VEC);
    2126            7 :   S5 = cgetg(prec+1,t_VEC);
    2127            7 :   F = vecfactoru_i(1, prec);
    2128           35 :   for (n = 1; n <= prec; n++)
    2129              :   {
    2130           28 :     GEN fa = gel(F,n);
    2131           28 :     gel(S3,n) = mului(10, usumdivk_fact(fa,3));
    2132           28 :     gel(S5,n) = mului(21, usumdivk_fact(fa,5));
    2133              :   }
    2134            7 :   J = cgetg(prec+2, t_SER),
    2135            7 :   J[1] = evalvarn(v)|evalsigne(1)|evalvalser(-1);
    2136            7 :   j = J+3;
    2137            7 :   gel(j,-1) = gen_1;
    2138            7 :   gel(j,0) = utoipos(744);
    2139            7 :   gel(j,1) = utoipos(196884);
    2140           21 :   for (n = 2; n < prec; n++)
    2141              :   {
    2142           14 :     pari_sp av = avma;
    2143           14 :     GEN c, s3 = gel(S3,n+1), s5 = gel(S5,n+1);
    2144           14 :     c = addii(s3, s5);
    2145           49 :     for (i = 0; i < n; i++)
    2146              :     {
    2147           35 :       s3 = gel(S3,n-i); s5 = gel(S5,n-i);
    2148           35 :       c = addii(c, mulii(gel(j,i), subii(s5, mului(i,s3))));
    2149              :     }
    2150           14 :     gel(j,n) = gc_INT(av, diviuexact(muliu(c,24), n+1));
    2151              :   }
    2152            7 :   return J;
    2153              : }
    2154              : 
    2155              : GEN
    2156           42 : jell(GEN x, long prec)
    2157              : {
    2158           42 :   long tx = typ(x);
    2159           42 :   pari_sp av = avma;
    2160              :   GEN q, h, U;
    2161              : 
    2162           42 :   if (!is_scalar_t(tx))
    2163              :   {
    2164              :     long v;
    2165           21 :     if (gequalX(x)) return ser_j(precdl, varn(x));
    2166           21 :     q = toser_i(x); if (!q) pari_err_TYPE("ellj",x);
    2167           14 :     v = fetch_var_higher();
    2168           14 :     h = ser_j(lg(q)-2, v);
    2169           14 :     h = gsubst(h, v, q);
    2170           14 :     delete_var(); return gc_upto(av, h);
    2171              :   }
    2172           21 :   if (tx == t_PADIC)
    2173              :   {
    2174            7 :     GEN p2, p1 = gdiv(inteta(gsqr(x)), inteta(x));
    2175            7 :     p1 = gmul2n(gsqr(p1),1);
    2176            7 :     p1 = gmul(x,gpowgs(p1,12));
    2177            7 :     p2 = gaddsg(768,gadd(gsqr(p1),gdivsg(4096,p1)));
    2178            7 :     p1 = gmulsg(48,p1);
    2179            7 :     return gc_upto(av, gadd(p2,p1));
    2180              :   }
    2181              :   /* Let h = Delta(2x) / Delta(x), then j(x) = (1 + 256h)^3 / h */
    2182           14 :   x = upper_to_cx(x, &prec);
    2183            7 :   x = cxredsl2(x, &U); /* forget about Ua : j has weight 0 */
    2184              :   { /* cf eta_reduced, raised to power 24
    2185              :      * Compute
    2186              :      *   t = (inteta(q(2x)) / inteta(q(x))) ^ 24;
    2187              :      * then
    2188              :      *   h = t * (q(2x) / q(x) = t * q(x);
    2189              :      * but inteta(q) costly and useless if expo(q) << 1  => inteta(q) = 1.
    2190              :      * log_2 ( exp(-2Pi Im tau) ) < -prec2nbits(prec)
    2191              :      * <=> Im tau > prec2nbits(prec) * log(2) / 2Pi */
    2192            7 :     long C = (long)prec2nbits_mul(prec, M_LN2/(2*M_PI));
    2193            7 :     q = expIPiC(gmul2n(x,1), prec); /* e(x) */
    2194            7 :     if (gcmpgs(gel(x,2), C) > 0) /* eta(q(x)) = 1 : no need to compute q(2x) */
    2195            0 :       h = q;
    2196              :     else
    2197              :     {
    2198            7 :       GEN t = gdiv(inteta(gsqr(q)), inteta(q));
    2199            7 :       h = gmul(q, gpowgs(t, 24));
    2200              :     }
    2201              :   }
    2202              :   /* real_1 important ! gaddgs(, 1) could increase the accuracy ! */
    2203            7 :   return gc_upto(av, gdiv(gpowgs(gadd(gmul2n(h,8), real_1(prec)), 3), h));
    2204              : }
    2205              : 
    2206              : static GEN
    2207         8372 : to_form(GEN a, GEN w, GEN C, GEN D)
    2208         8372 : { return mkqfb(a, w, diviiexact(C, a), D); }
    2209              : static GEN
    2210         8372 : form_to_quad(GEN f, GEN sqrtD)
    2211              : {
    2212         8372 :   long a = itos(gel(f,1)), a2 = a << 1;
    2213         8372 :   GEN b = gel(f,2);
    2214         8372 :   return mkcomplex(gdivgs(b, -a2), gdivgs(sqrtD, a2));
    2215              : }
    2216              : static GEN
    2217         8372 : eta_form(GEN f, GEN sqrtD, GEN *s_t, long prec)
    2218              : {
    2219         8372 :   GEN U, t = form_to_quad(redimagsl2(f, &U), sqrtD);
    2220         8372 :   *s_t = eta_correction(t, U, 0);
    2221         8372 :   return eta_reduced(t, prec);
    2222              : }
    2223              : 
    2224              : /* eta(t/p)eta(t/q) / (eta(t)eta(t/pq)), t = (-w + sqrt(D)) / 2a */
    2225              : GEN
    2226         2093 : double_eta_quotient(GEN a, GEN w, GEN D, long p, long q, GEN pq, GEN sqrtD)
    2227              : {
    2228         2093 :   GEN C = shifti(subii(sqri(w), D), -2);
    2229              :   GEN d, t, z, zp, zq, zpq, s_t, s_tp, s_tpq, s, sp, spq;
    2230         2093 :   long prec = realprec(sqrtD);
    2231              : 
    2232         2093 :   z = eta_form(to_form(a, w, C, D), sqrtD, &s_t, prec);
    2233         2093 :   s = gel(s_t, 1);
    2234         2093 :   zp = eta_form(to_form(mului(p, a), w, C, D), sqrtD, &s_tp, prec);
    2235         2093 :   sp = gel(s_tp, 1);
    2236         2093 :   zpq = eta_form(to_form(mulii(pq, a), w, C, D), sqrtD, &s_tpq, prec);
    2237         2093 :   spq = gel(s_tpq, 1);
    2238         2093 :   if (p == q) {
    2239            0 :     z = gdiv(gsqr(zp), gmul(z, zpq));
    2240            0 :     t = gsub(gmul2n(gel(s_tp,2), 1),
    2241            0 :              gadd(gel(s_t,2), gel(s_tpq,2)));
    2242            0 :     if (sp != gen_1) z = gmul(z, sp);
    2243              :   } else {
    2244              :     GEN s_tq, sq;
    2245         2093 :     zq = eta_form(to_form(mului(q, a), w, C, D), sqrtD, &s_tq, prec);
    2246         2093 :     sq = gel(s_tq, 1);
    2247         2093 :     z = gdiv(gmul(zp, zq), gmul(z, zpq));
    2248         2093 :     t = gsub(gadd(gel(s_tp,2), gel(s_tq,2)),
    2249         2093 :              gadd(gel(s_t,2), gel(s_tpq,2)));
    2250         2093 :     if (sp != gen_1) z = gmul(z, gsqrt(sp, prec));
    2251         2093 :     if (sq != gen_1) z = gmul(z, gsqrt(sq, prec));
    2252              :   }
    2253         2093 :   d = NULL;
    2254         2093 :   if (s != gen_1) d = gsqrt(s, prec);
    2255         2093 :   if (spq != gen_1) {
    2256         2065 :     GEN x = gsqrt(spq, prec);
    2257         2065 :     d = d? gmul(d, x): x;
    2258              :   }
    2259         2093 :   if (d) z = gdiv(z, d);
    2260         2093 :   return gmul(z, expIPiQ(t, prec));
    2261              : }
    2262              : 
    2263              : typedef struct { GEN u; long v, t; } cxanalyze_t;
    2264              : 
    2265              : /* Check whether a t_COMPLEX, t_REAL or t_INT z != 0 can be written as
    2266              :  * z = u * 2^(v/2) * exp(I Pi/4 t), u > 0, v = 0,1 and -3 <= t <= 4.
    2267              :  * Allow z t_INT/t_REAL to simplify handling of eta_correction() output */
    2268              : static int
    2269           84 : cxanalyze(cxanalyze_t *T, GEN z)
    2270              : {
    2271              :   GEN a, b;
    2272              :   long ta, tb;
    2273              : 
    2274           84 :   T->u = z;
    2275           84 :   T->v = 0;
    2276           84 :   if (is_intreal_t(typ(z)))
    2277              :   {
    2278           70 :     T->u = mpabs_shallow(z);
    2279           70 :     T->t = signe(z) < 0? 4: 0;
    2280           70 :     return 1;
    2281              :   }
    2282           14 :   a = gel(z,1); ta = typ(a);
    2283           14 :   b = gel(z,2); tb = typ(b);
    2284              : 
    2285           14 :   T->t = 0;
    2286           14 :   if (ta == t_INT && !signe(a))
    2287              :   {
    2288            0 :     T->u = R_abs_shallow(b);
    2289            0 :     T->t = gsigne(b) < 0? -2: 2;
    2290            0 :     return 1;
    2291              :   }
    2292           14 :   if (tb == t_INT && !signe(b))
    2293              :   {
    2294            0 :     T->u = R_abs_shallow(a);
    2295            0 :     T->t = gsigne(a) < 0? 4: 0;
    2296            0 :     return 1;
    2297              :   }
    2298           14 :   if (ta != tb || ta == t_REAL) return 0;
    2299              :   /* a,b both non zero, both t_INT or t_FRAC */
    2300           14 :   if (ta == t_INT)
    2301              :   {
    2302            7 :     if (!absequalii(a, b)) return 0;
    2303            7 :     T->u = absi_shallow(a);
    2304            7 :     T->v = 1;
    2305            7 :     if (signe(a) == signe(b))
    2306            0 :     { T->t = signe(a) < 0? -3: 1; }
    2307              :     else
    2308            7 :     { T->t = signe(a) < 0? 3: -1; }
    2309              :   }
    2310              :   else
    2311              :   {
    2312            7 :     if (!absequalii(gel(a,2), gel(b,2)) || !absequalii(gel(a,1),gel(b,1)))
    2313            7 :       return 0;
    2314            0 :     T->u = absfrac_shallow(a);
    2315            0 :     T->v = 1;
    2316            0 :     a = gel(a,1);
    2317            0 :     b = gel(b,1);
    2318            0 :     if (signe(a) == signe(b))
    2319            0 :     { T->t = signe(a) < 0? -3: 1; }
    2320              :     else
    2321            0 :     { T->t = signe(a) < 0? 3: -1; }
    2322              :   }
    2323            7 :   return 1;
    2324              : }
    2325              : 
    2326              : /* z * sqrt(st_b) / sqrt(st_a) exp(I Pi (t + t0)). Assume that
    2327              :  * sqrt2 = gsqrt(gen_2, prec) or NULL */
    2328              : static GEN
    2329           42 : apply_eta_correction(GEN z, GEN st_a, GEN st_b, GEN t0, GEN sqrt2, long prec)
    2330              : {
    2331           42 :   GEN t, s_a = gel(st_a, 1), s_b = gel(st_b, 1);
    2332              :   cxanalyze_t Ta, Tb;
    2333              :   int ca, cb;
    2334              : 
    2335           42 :   t = gsub(gel(st_b,2), gel(st_a,2));
    2336           42 :   if (t0 != gen_0) t = gadd(t, t0);
    2337           42 :   ca = cxanalyze(&Ta, s_a);
    2338           42 :   cb = cxanalyze(&Tb, s_b);
    2339           42 :   if (ca || cb)
    2340           42 :   { /* compute sqrt(s_b) / sqrt(s_a) in a more efficient way:
    2341              :      * sb = ub sqrt(2)^vb exp(i Pi/4 tb) */
    2342           42 :     GEN u = gdiv(Tb.u,Ta.u);
    2343           42 :     switch(Tb.v - Ta.v)
    2344              :     {
    2345            0 :       case -1: u = gmul2n(u,-1); /* fall through: write 1/sqrt2 = sqrt2/2 */
    2346            7 :       case 1: u = gmul(u, sqrt2? sqrt2: sqrtr_abs(real2n(1, prec)));
    2347              :     }
    2348           42 :     if (!isint1(u)) z = gmul(z, gsqrt(u, prec));
    2349           42 :     t = gadd(t, gmul2n(stoi(Tb.t - Ta.t), -3));
    2350              :   }
    2351              :   else
    2352              :   {
    2353            0 :     z = gmul(z, gsqrt(s_b, prec));
    2354            0 :     z = gdiv(z, gsqrt(s_a, prec));
    2355              :   }
    2356           42 :   return gmul(z, expIPiQ(t, prec));
    2357              : }
    2358              : 
    2359              : /* sqrt(2) eta(2x) / eta(x) */
    2360              : GEN
    2361           14 : weberf2(GEN x, long prec)
    2362              : {
    2363           14 :   pari_sp av = avma;
    2364              :   GEN z, sqrt2, a,b, Ua,Ub, st_a,st_b;
    2365              : 
    2366           14 :   x = upper_to_cx(x, &prec);
    2367           14 :   a = cxredsl2(x, &Ua);
    2368           14 :   b = cxredsl2(gmul2n(x,1), &Ub);
    2369           14 :   if (gequal(a,b)) /* not infrequent */
    2370            0 :     z = gen_1;
    2371              :   else
    2372           14 :     z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec));
    2373           14 :   st_a = eta_correction(a, Ua, 1);
    2374           14 :   st_b = eta_correction(b, Ub, 1);
    2375           14 :   sqrt2 = sqrtr_abs(real2n(1, prec));
    2376           14 :   z = apply_eta_correction(z, st_a, st_b, gen_0, sqrt2, prec);
    2377           14 :   return gc_upto(av, gmul(z, sqrt2));
    2378              : }
    2379              : 
    2380              : /* eta(x/2) / eta(x) */
    2381              : GEN
    2382           14 : weberf1(GEN x, long prec)
    2383              : {
    2384           14 :   pari_sp av = avma;
    2385              :   GEN z, a,b, Ua,Ub, st_a,st_b;
    2386              : 
    2387           14 :   x = upper_to_cx(x, &prec);
    2388           14 :   a = cxredsl2(x, &Ua);
    2389           14 :   b = cxredsl2(gmul2n(x,-1), &Ub);
    2390           14 :   if (gequal(a,b)) /* not infrequent */
    2391            0 :     z = gen_1;
    2392              :   else
    2393           14 :     z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec));
    2394           14 :   st_a = eta_correction(a, Ua, 1);
    2395           14 :   st_b = eta_correction(b, Ub, 1);
    2396           14 :   z = apply_eta_correction(z, st_a, st_b, gen_0, NULL, prec);
    2397           14 :   return gc_upto(av, z);
    2398              : }
    2399              : /* exp(-I*Pi/24) * eta((x+1)/2) / eta(x) */
    2400              : GEN
    2401           14 : weberf(GEN x, long prec)
    2402              : {
    2403           14 :   pari_sp av = avma;
    2404              :   GEN z, t0, a,b, Ua,Ub, st_a,st_b;
    2405           14 :   x = upper_to_cx(x, &prec);
    2406           14 :   a = cxredsl2(x, &Ua);
    2407           14 :   b = cxredsl2(gmul2n(gaddgs(x,1),-1), &Ub);
    2408           14 :   if (gequal(a,b)) /* not infrequent */
    2409            7 :     z = gen_1;
    2410              :   else
    2411            7 :     z = gdiv(eta_reduced(b,prec), eta_reduced(a,prec));
    2412           14 :   st_a = eta_correction(a, Ua, 1);
    2413           14 :   st_b = eta_correction(b, Ub, 1);
    2414           14 :   t0 = mkfrac(gen_m1, utoipos(24));
    2415           14 :   z = apply_eta_correction(z, st_a, st_b, t0, NULL, prec);
    2416           14 :   if (typ(z) == t_COMPLEX && isexactzero(real_i(x)))
    2417            0 :     z = gc_GEN(av, gel(z,1));
    2418              :   else
    2419           14 :     z = gc_upto(av, z);
    2420           14 :   return z;
    2421              : }
    2422              : GEN
    2423           42 : weber0(GEN x, long flag,long prec)
    2424              : {
    2425           42 :   switch(flag)
    2426              :   {
    2427           14 :     case 0: return weberf(x,prec);
    2428           14 :     case 1: return weberf1(x,prec);
    2429           14 :     case 2: return weberf2(x,prec);
    2430            0 :     default: pari_err_FLAG("weber");
    2431              :   }
    2432              :   return NULL; /* LCOV_EXCL_LINE */
    2433              : }
    2434              : 
    2435              : /********************************************************************/
    2436              : /**                     Jacobi sn, cn, dn                          **/
    2437              : /********************************************************************/
    2438              : 
    2439              : static GEN
    2440           42 : elljacobi_cx(GEN z, GEN k, long prec)
    2441              : {
    2442           42 :   GEN K = ellK(k, prec), Kp = ellK(gsqrt(gsubsg(1, gsqr(k)), prec), prec);
    2443           42 :   GEN zet = gdiv(gmul2n(z, -1), K), tau = mulcxI(gdiv(Kp, K));
    2444           42 :   GEN T0, T = thetaall(zet, tau, &T0, prec);
    2445           42 :   GEN t1 = gneg(gel(T,4)), t2 = gel(T,3), t3 = gel(T,1), t4 = gel(T,2);
    2446           42 :   GEN z2 = gel(T0,3), z3 = gel(T0,1), z4 = gel(T0,2), z2t4 = gmul(z2, t4);
    2447              :   GEN SN, CN, DN;
    2448           42 :   SN = gdiv(gmul(z3, t1), z2t4);
    2449           42 :   CN = gdiv(gmul(z4, t2), z2t4);
    2450           42 :   DN = gdiv(gmul(z4, t3), gmul(z3, t4));
    2451           42 :   return mkvec3(SN, CN, DN);
    2452              : }
    2453              : 
    2454              : /* N >= 1 */
    2455              : static GEN
    2456           14 : elljacobi_pol(long N, GEN k)
    2457              : {
    2458           14 :   GEN S = cgetg(N, t_VEC), C = cgetg(N+1, t_VEC), D = cgetg(N+1, t_VEC);
    2459           14 :   GEN SS, SC, SD, F, P, k2 = gsqr(k);
    2460              :   long n, j;
    2461           14 :   if (N == 1)
    2462              :   {
    2463            7 :     SS = cgetg(2, t_SER); SS[1] = evalsigne(0) | _evalvalser(1);
    2464            7 :     SC = cgetg(4, t_SER); SC[1] = evalsigne(1) | _evalvalser(0);
    2465            7 :     SD = cgetg(4, t_SER); SD[1] = evalsigne(1) | _evalvalser(0);
    2466            7 :     gel(SC, 2) = gel(SD, 2) = gen_1;
    2467            7 :     gel(SC, 3) = gel(SD, 3) = gen_0; return mkvec3(SS, SC, SD);
    2468              :   }
    2469              :   /* N > 1 */
    2470            7 :   gel(C,1) = gel(D,1) = gel(S,1) = gen_1;
    2471            7 :   P = matqpascal(2*N-1, NULL);
    2472           63 :   for (n = 1; n < N; n++)
    2473              :   {
    2474              :     GEN TD, TC, TS;
    2475           63 :     TC = gmulgs(gel(D, n), 2*n-1);
    2476           63 :     TD = gmulgs(gel(C, n), 2*n-1); /* j = 0 */
    2477          315 :     for (j = 1; j < n; j++)
    2478              :     {
    2479          252 :       GEN a  = gmul(gcoeff(P, 1 + 2*n-1, 1 + 2*j+1), gel(S, j+1));
    2480          252 :       TC = gadd(TC, gmul(a, gel(D, n-j)));
    2481          252 :       TD = gadd(TD, gmul(a, gel(C, n-j)));
    2482              :     }
    2483           63 :     gel(C, n+1) = TC;
    2484           63 :     gel(D, n+1) = gmul(TD, k2);
    2485           63 :     if (n+1 == N) break;
    2486           56 :     TS = gadd(gel(C, n+1), gel(D, n+1)); /* j = 0 and n */
    2487          252 :     for (j = 1; j < n; j++)
    2488          196 :       TS = gadd(TS, gmul3(gcoeff(P, 1+2*n, 1+2*j), gel(C,j+1), gel(D,n+1-j)));
    2489           56 :     gel(S, n+1) = TS;
    2490              :   }
    2491            7 :   F = cgetg(2*N, t_VEC); gel(F,1) = gen_1;
    2492          133 :   for (j = 2; j < 2*N; j++) gel(F,j) = mulis(gel(F,j-1), odd(j)? j: -j);
    2493            7 :   SS = cgetg(2*N, t_SER);   SS[1] = evalsigne(1) | _evalvalser(1);
    2494            7 :   SC = cgetg(2*N+2, t_SER); SC[1] = evalsigne(1) | _evalvalser(0);
    2495            7 :   SD = cgetg(2*N+2, t_SER); SD[1] = evalsigne(1) | _evalvalser(0);
    2496            7 :   gel(SC, 2) = gel(SD, 2) = gel(SS, 2) = gen_1;
    2497            7 :   gel(SC, 3) = gel(SD, 3) = gel(SS, 3) = gen_0;
    2498           70 :   for (j = 2; j <= N; j++)
    2499              :   {
    2500           63 :     GEN q = gel(F, 2*j-2); /* (-1)^(j-1) (2j-2)! */
    2501           63 :     gel(SC, 2*j) = gdiv(gel(C,j), q);
    2502           63 :     gel(SD, 2*j) = gdiv(gel(D,j), q);
    2503           63 :     gel(SC, 2*j+1) = gen_0;
    2504           63 :     gel(SD, 2*j+1) = gen_0;
    2505           63 :     if (j < N)
    2506              :     {
    2507           56 :       q = gel(F, 2*j-1); /* (-1)^(j-1) (2j-1)! */
    2508           56 :       gel(SS, 2*j) = gdiv(gel(S,j), q);
    2509           56 :       gel(SS, 2*j+1) = gen_0;
    2510              :     }
    2511              :   }
    2512            7 :   return mkvec3(SS, SC, SD);
    2513              : }
    2514              : 
    2515              : GEN
    2516           70 : elljacobi(GEN z, GEN k, long prec)
    2517              : {
    2518           70 :   pari_sp av = avma;
    2519           70 :   long N = (precdl + 3) >> 1;
    2520           70 :   if (!z) z = pol_x(0);
    2521           70 :   switch (typ(z))
    2522              :   {
    2523            0 :     case t_QUAD: z = gtofp(z, prec); /* fall through */
    2524           42 :     case t_INT: case t_REAL: case t_FRAC: case t_COMPLEX:
    2525           42 :       return gc_GEN(av, elljacobi_cx(z, k, prec)); break;
    2526            7 :     case t_POL:
    2527            7 :       if (lg(z) > 2 && !gequal0(gel(z,2)))
    2528            7 :         pari_err(e_IMPL, "elljacobi(t_SER) away from 0");
    2529            0 :       break;
    2530            7 :     case t_RFRAC:
    2531              :     {
    2532            7 :       GEN b = gel(z,2);
    2533            7 :       if (gequal0(gel(b,2)) || !gequal0(gsubst(gel(z,1), varn(b), gen_0)))
    2534            7 :         pari_err(e_IMPL, "elljacobi(t_SER) away from 0");
    2535            0 :       break;
    2536              :     }
    2537           14 :     case t_SER:
    2538           14 :       if (valser(z) <= 0)
    2539            0 :         pari_err(e_IMPL, "elljacobi(t_SER) away from 0");
    2540           14 :       N = lg(z) - 1; break;
    2541            0 :     default: pari_err_TYPE("elljacobi", z);
    2542              :       return NULL; /* LCOV_EXCL_LINE */
    2543              :   }
    2544           14 :   return gc_upto(av, gsubst(elljacobi_pol(N, k), 0, z));
    2545              : }
        

Generated by: LCOV version 2.0-1