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

Generated by: LCOV version 1.16