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 - lfunutils.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.0 lcov report (development 29806-4d001396c7) Lines: 1805 1991 90.7 %
Date: 2024-12-21 09:08:57 Functions: 180 192 93.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2015  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : /********************************************************************/
      16             : /**                                                                **/
      17             : /**                 L-functions: Applications                      **/
      18             : /**                                                                **/
      19             : /********************************************************************/
      20             : 
      21             : #include "pari.h"
      22             : #include "paripriv.h"
      23             : 
      24             : #define DEBUGLEVEL DEBUGLEVEL_lfun
      25             : 
      26             : static GEN
      27       26047 : tag(GEN x, long t) { return mkvec2(mkvecsmall(t), x); }
      28             : 
      29             : /* v a t_VEC of length > 1 */
      30             : static int
      31      104971 : is_tagged(GEN v)
      32             : {
      33      104971 :   GEN T = gel(v,1);
      34      104971 :   return (typ(T)==t_VEC && lg(T)==3 && typ(gel(T,1))==t_VECSMALL);
      35             : }
      36             : /* rough check */
      37             : static long
      38      126440 : is_ldata(GEN L)
      39             : {
      40      126440 :   long l = lg(L);
      41      126440 :   return typ(L) == t_VEC && (l == 7 || l == 8);
      42             : }
      43             : /* thorough check */
      44             : static void
      45      104859 : checkldata(GEN ldata)
      46             : {
      47             :   GEN vga, w, N;
      48             : #if 0 /* assumed already checked and true */
      49             :   if (!is_ldata(ldata) || !is_tagged(ldata)) pari_err_TYPE("checkldata", ldata);
      50             : #endif
      51      104859 :   vga = ldata_get_gammavec(ldata);
      52      104859 :   if (typ(vga) != t_VEC) pari_err_TYPE("checkldata [gammavec]",vga);
      53      104859 :   w = gel(ldata, 4); /* FIXME */
      54      104859 :   switch(typ(w))
      55             :   {
      56      102829 :     case t_INT: case t_FRAC: break;
      57        2030 :     case t_VEC: if (lg(w) == 3 && is_rational_t(typ(gel(w,1)))) break;
      58           0 :     default: pari_err_TYPE("checkldata [weight]",w);
      59             :   }
      60      104859 :   N = ldata_get_conductor(ldata);
      61      104859 :   if (typ(N) != t_INT) pari_err_TYPE("checkldata [conductor]",N);
      62      104859 : }
      63             : 
      64             : /* tag as t_LFUN_GENERIC */
      65             : static void
      66         609 : lfuncreate_tag(GEN L)
      67             : {
      68         609 :   if (is_tagged(L)) return;
      69         448 :   gel(L,1) = tag(gel(L,1), t_LFUN_GENERIC);
      70         448 :   if (typ(gel(L,2)) != t_INT) gel(L,2) = tag(gel(L,2), t_LFUN_GENERIC);
      71             : }
      72             : 
      73             : /* shallow */
      74             : static GEN
      75         168 : closure2ldata(GEN C, long prec)
      76             : {
      77         168 :   GEN L = closure_callgen0prec(C, prec);
      78         168 :   if (is_ldata(L)) { checkldata(L); lfuncreate_tag(L); }
      79          56 :   else L = lfunmisc_to_ldata_shallow(L);
      80         168 :   return L;
      81             : }
      82             : 
      83             : /* data may be either an object (polynomial, elliptic curve, etc...)
      84             :  * or a description vector [an,sd,Vga,k,conductor,rootno,{poles}]. */
      85             : GEN
      86        4025 : lfuncreate(GEN data)
      87             : {
      88        4025 :   if (is_ldata(data))
      89             :   {
      90         497 :     GEN L = gcopy(data);
      91         497 :     lfuncreate_tag(L); checkldata(L); return L;
      92             :   }
      93        3528 :   if (typ(data) == t_CLOSURE && closure_arity(data)==0)
      94             :   {
      95          14 :     pari_sp av = avma;
      96          14 :     GEN L = closure2ldata(data, DEFAULTPREC);
      97          14 :     gel(L,1) = tag(data, t_LFUN_CLOSURE0); return gerepilecopy(av, L);
      98             :   }
      99        3514 :   return lfunmisc_to_ldata(data);
     100             : }
     101             : 
     102             : GEN
     103         133 : lfunparams(GEN L, long prec)
     104             : {
     105         133 :   pari_sp av = avma;
     106             :   GEN k, N, v;
     107             :   long p;
     108             : 
     109         133 :   if (!is_ldata(L) || !is_tagged(L)) L = lfunmisc_to_ldata_shallow(L);
     110         133 :   N = ldata_get_conductor(L);
     111         133 :   k = ldata_get_k(L);
     112         133 :   v = ldata_get_gammavec(L);
     113         133 :   p = gprecision(v);
     114         133 :   if (p > prec) v = gprec_wtrunc(v, prec);
     115         133 :   else if (p < prec)
     116             :   {
     117         133 :     GEN van = ldata_get_an(L), an = gel(van,2);
     118         133 :     long t = mael(van,1,1);
     119         133 :     if (t == t_LFUN_CLOSURE0) L = closure2ldata(an, prec);
     120             :   }
     121         133 :   return gerepilecopy(av, mkvec3(N, k, v));
     122             : }
     123             : 
     124             : /********************************************************************/
     125             : /**                     Simple constructors                        **/
     126             : /********************************************************************/
     127             : static GEN ldata_eulerf(GEN van, GEN p, long prec);
     128             : 
     129             : static GEN
     130         126 : vecan_conj(GEN an, long n, long prec)
     131             : {
     132         126 :   GEN p1 = ldata_vecan(gel(an,1), n, prec);
     133         126 :   return typ(p1) == t_VEC? conj_i(p1): p1;
     134             : }
     135             : 
     136             : static GEN
     137           0 : eulerf_conj(GEN an, GEN p, long prec)
     138             : {
     139           0 :   GEN p1 = ldata_eulerf(gel(an,1), p, prec);
     140           0 :   return conj_i(p1);
     141             : }
     142             : 
     143             : static GEN
     144         308 : vecan_mul(GEN an, long n, long prec)
     145             : {
     146         308 :   GEN p1 = ldata_vecan(gel(an,1), n, prec);
     147         308 :   GEN p2 = ldata_vecan(gel(an,2), n, prec);
     148         308 :   if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1);
     149         308 :   if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2);
     150         308 :   return dirmul(p1, p2);
     151             : }
     152             : 
     153             : static GEN
     154          28 : eulerf_mul(GEN an, GEN p, long prec)
     155             : {
     156          28 :   GEN p1 = ldata_eulerf(gel(an,1), p, prec);
     157          28 :   GEN p2 = ldata_eulerf(gel(an,2), p, prec);
     158          28 :   return gmul(p1, p2);
     159             : }
     160             : 
     161             : static GEN
     162          77 : lfunconvol(GEN a1, GEN a2)
     163          77 : { return tag(mkvec2(a1, a2), t_LFUN_MUL); }
     164             : 
     165             : static GEN
     166         630 : vecan_div(GEN an, long n, long prec)
     167             : {
     168         630 :   GEN p1 = ldata_vecan(gel(an,1), n, prec);
     169         630 :   GEN p2 = ldata_vecan(gel(an,2), n, prec);
     170         630 :   if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1);
     171         630 :   if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2);
     172         630 :   return dirdiv(p1, p2);
     173             : }
     174             : 
     175             : static GEN
     176          14 : eulerf_div(GEN an, GEN p, long prec)
     177             : {
     178          14 :   GEN p1 = ldata_eulerf(gel(an,1), p, prec);
     179          14 :   GEN p2 = ldata_eulerf(gel(an,2), p, prec);
     180          14 :   return gdiv(p1, p2);
     181             : }
     182             : 
     183             : static GEN
     184          56 : lfunconvolinv(GEN a1, GEN a2)
     185          56 : { return tag(mkvec2(a1,a2), t_LFUN_DIV); }
     186             : 
     187             : static GEN
     188          84 : lfunconj(GEN a1)
     189          84 : { return tag(mkvec(a1), t_LFUN_CONJ); }
     190             : 
     191             : static GEN
     192         133 : lfuncombdual(GEN (*fun)(GEN, GEN), GEN ldata1, GEN ldata2)
     193             : {
     194         133 :   GEN a1 = ldata_get_an(ldata1), a2 = ldata_get_an(ldata2);
     195         133 :   GEN b1 = ldata_get_dual(ldata1), b2 = ldata_get_dual(ldata2);
     196         133 :   if (typ(b1)==t_INT && typ(b2)==t_INT)
     197         133 :     return utoi(signe(b1) || signe(b2));
     198             :   else
     199             :   {
     200           0 :     if (typ(b1)==t_INT) b1 = signe(b1) ? lfunconj(a1): a1;
     201           0 :     if (typ(b2)==t_INT) b2 = signe(b2) ? lfunconj(a2): a2;
     202           0 :     return fun(b1, b2);
     203             :   }
     204             : }
     205             : 
     206             : static GEN
     207        2877 : vecan_twist(GEN an, long n, long prec)
     208             : {
     209        2877 :   GEN p1 = ldata_vecan(gel(an,1), n, prec);
     210        2877 :   GEN p2 = ldata_vecan(gel(an,2), n, prec);
     211             :   long i;
     212             :   GEN V;
     213        2877 :   if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1);
     214        2877 :   if (typ(p2) == t_VECSMALL) p2 = vecsmall_to_vec(p2);
     215        2877 :   V = cgetg(n+1, t_VEC);
     216     1424479 :   for(i = 1; i <= n ; i++)
     217     1421602 :     gel(V, i) = gmul(gel(p1, i), gel(p2, i));
     218        2877 :   return V;
     219             : }
     220             : 
     221             : static GEN
     222          14 : eulerf_twist(GEN an, GEN p, long prec)
     223             : {
     224          14 :   GEN p1 = ldata_eulerf(gel(an,1), p, prec);
     225          14 :   GEN p2 = ginv(ldata_eulerf(gel(an,2), p, prec));
     226          14 :   if (typ(p2)!=t_POL || degpol(p2)==0)
     227           0 :     return poleval(p1,pol_0(0));
     228          14 :   if (degpol(p2)!=1) pari_err_IMPL("lfuneuler");
     229          14 :   return poleval(p1,monomial(gneg(gel(p2,3)),1,0));
     230             : }
     231             : 
     232             : static GEN
     233         637 : vecan_shift(GEN an, long n, long prec)
     234             : {
     235         637 :   GEN p1 = ldata_vecan(gel(an,1), n, prec);
     236         637 :   GEN s = gel(an,2);
     237             :   long i;
     238             :   GEN V;
     239         637 :   if (typ(p1) == t_VECSMALL) p1 = vecsmall_to_vec(p1);
     240         637 :   V = cgetg(n+1, t_VEC);
     241         637 :   if (typ(s)==t_INT)
     242             :   {
     243         448 :     if (equali1(s))
     244       31850 :       for(i = 1; i <= n ; i++)
     245             :       {
     246       31500 :         GEN gi = gel(p1, i);
     247       31500 :         gel(V, i) = gequal0(gi)? gi: gmulgu(gi, i);
     248             :       }
     249             :     else
     250        1848 :       for(i = 1; i <= n ; i++)
     251             :       {
     252        1750 :         GEN gi = gel(p1, i);
     253        1750 :         gel(V, i) = gequal0(gi)? gi: gmul(gi, powgi(utoi(i), s));
     254             :       }
     255             :   }
     256             :   else
     257             :   {
     258         189 :     GEN D = dirpowers(n, s, prec);
     259        7049 :     for(i = 1; i <= n ; i++)
     260        6860 :       gel(V, i) = gmul(gel(p1,i), gel(D,i));
     261             :   }
     262         637 :   return V;
     263             : }
     264             : 
     265             : static GEN
     266          42 : eulerf_shift(GEN an, GEN p, long prec)
     267             : {
     268          42 :   GEN p1 = ldata_eulerf(gel(an,1), p, prec);
     269          42 :   GEN s = gel(an,2);
     270          42 :   return gsubst(p1, 0, monomial(gpow(p, s, prec), 1, 0));
     271             : }
     272             : 
     273             : static GEN
     274          84 : eulerf_hgm(GEN an, GEN p)
     275             : {
     276          84 :   GEN H = gel(an,1), t = gel(an,2);
     277          84 :   if (typ(t)==t_VEC && lg(t)==3)
     278             :   {
     279          28 :     GEN L = gel(t,2);
     280          28 :     long i, l = lg(L);
     281          28 :     t = gel(t,1);
     282          49 :     for (i = 1; i < l; i++) /* wild primes */
     283          35 :       if (equalii(p, gmael(L, i, 1))) break;
     284          28 :     if (i<l) return gmael(L,i,2);
     285             :   }
     286          70 :   return ginv(hgmeulerfactor(H, t, itos(p), NULL));
     287             : }
     288             : 
     289             : static GEN
     290         315 : deg1ser_shallow(GEN a1, GEN a0, long e)
     291         315 : { return RgX_to_ser(deg1pol_shallow(a1, a0, 0), e+2); }
     292             : /* lfunrtopoles without sort */
     293             : static GEN
     294         168 : rtopoles(GEN r)
     295             : {
     296         168 :   long j, l = lg(r);
     297         168 :   GEN v = cgetg(l, t_VEC);
     298         350 :   for (j = 1; j < l; j++)
     299             :   {
     300         182 :     GEN rj = gel(r,j), a = gel(rj,1);
     301         182 :     gel(v,j) = a;
     302             :   }
     303         168 :   return v;
     304             : }
     305             : /* re = polar part; overestimate when re = gen_0 (unknown) */
     306             : static long
     307         266 : orderpole(GEN re) { return typ(re) == t_SER? -valser(re): 1; }
     308             : static GEN
     309          77 : lfunmulpoles(GEN ldata1, GEN ldata2, long bitprec)
     310             : {
     311          77 :   GEN r, k = ldata_get_k(ldata1), b1 = NULL, b2 = NULL;
     312          77 :   GEN r1 = ldata_get_residue(ldata1);
     313          77 :   GEN r2 = ldata_get_residue(ldata2);
     314          77 :   long i, j, l, L = 0;
     315             : 
     316          77 :   if (!r1 && !r2) return NULL;
     317          70 :   if (r1 && !is_vec_t(typ(r1))) r1 = mkvec(mkvec2(k, r1));
     318          70 :   if (r2 && !is_vec_t(typ(r2))) r2 = mkvec(mkvec2(k, r2));
     319          70 :   if (r1) { b1 = rtopoles(r1); L += lg(b1); }
     320          70 :   if (r2) { b2 = rtopoles(r2); L += lg(b2); }
     321          70 :   r = cgetg(L, t_VEC); j = 1;
     322          70 :   if (b1)
     323             :   {
     324          63 :     l = lg(b1);
     325         133 :     for (i = 1; i < l; i++)
     326             :     {
     327          70 :       GEN z, z1, z2, be = gmael(r1,i,1);
     328          70 :       long n, v = orderpole(gmael(r1,i,2));
     329          70 :       if (b2 && (n = RgV_isin(b2, be))) v += orderpole(gmael(r2,n,2));
     330          70 :       z = deg1ser_shallow(gen_1, be, 2 + v);
     331          70 :       z1 = lfun(ldata1,z,bitprec);
     332          70 :       z2 = lfun(ldata2,z,bitprec);
     333          70 :       gel(r,j++) = mkvec2(be, gmul(z1, z2));
     334             :     }
     335             :   }
     336          70 :   if (b2)
     337             :   {
     338          63 :     long l = lg(b2);
     339         133 :     for (i = 1; i < l; i++)
     340             :     {
     341          70 :       GEN z, z1, z2, be = gmael(r2,i,1);
     342          70 :       long n, v = orderpole(gmael(r2,i,2));
     343          70 :       if (b1 && (n = RgV_isin(b1, be))) continue; /* done already */
     344          28 :       z = deg1ser_shallow(gen_1, be, 2 + v);
     345          28 :       z1 = lfun(ldata1,z,bitprec);
     346          28 :       z2 = lfun(ldata2,z,bitprec);
     347          28 :       gel(r,j++) = mkvec2(be, gmul(z1, z2));
     348             :     }
     349             :   }
     350          70 :   setlg(r, j); return r;
     351             : }
     352             : 
     353             : static GEN
     354          77 : lfunmul_k(GEN ldata1, GEN ldata2, GEN k, long bitprec)
     355             : {
     356             :   GEN r, N, Vga, eno, a1a2, b1b2;
     357          77 :   r = lfunmulpoles(ldata1, ldata2, bitprec);
     358          77 :   N = gmul(ldata_get_conductor(ldata1), ldata_get_conductor(ldata2));
     359          77 :   Vga = shallowconcat(ldata_get_gammavec(ldata1), ldata_get_gammavec(ldata2));
     360          77 :   Vga = sort(Vga);
     361          77 :   eno = gmul(ldata_get_rootno(ldata1), ldata_get_rootno(ldata2));
     362          77 :   a1a2 = lfunconvol(ldata_get_an(ldata1), ldata_get_an(ldata2));
     363          77 :   b1b2 = lfuncombdual(lfunconvol, ldata1, ldata2);
     364          77 :   return mkvecn(r? 7: 6, a1a2, b1b2, Vga, k, N, eno, r);
     365             : }
     366             : 
     367             : GEN
     368          63 : lfunmul(GEN ldata1, GEN ldata2, long bitprec)
     369             : {
     370          63 :   pari_sp ltop = avma;
     371             :   GEN k;
     372          63 :   long prec = nbits2prec(bitprec);
     373          63 :   ldata1 = ldata_newprec(lfunmisc_to_ldata_shallow(ldata1), prec);
     374          63 :   ldata2 = ldata_newprec(lfunmisc_to_ldata_shallow(ldata2), prec);
     375          63 :   k = ldata_get_k(ldata1);
     376          63 :   if (!gequal(ldata_get_k(ldata2),k))
     377           0 :     pari_err_OP("lfunmul [weight]",ldata1, ldata2);
     378          63 :   return gerepilecopy(ltop, lfunmul_k(ldata1, ldata2, k, bitprec));
     379             : }
     380             : 
     381             : static GEN
     382          56 : lfundivpoles(GEN ldata1, GEN ldata2, long bitprec)
     383             : {
     384             :   long i, j, l;
     385          56 :   GEN be2, k  = ldata_get_k(ldata1);
     386          56 :   GEN r1 = ldata_get_residue(ldata1);
     387          56 :   GEN r2 = ldata_get_residue(ldata2), r;
     388             : 
     389          56 :   if (r1 && !is_vec_t(typ(r1))) r1 = mkvec(mkvec2(k, r1));
     390          56 :   if (r2 && !is_vec_t(typ(r2))) r2 = mkvec(mkvec2(k, r2));
     391          56 :   if (!r1) return NULL;
     392          56 :   l = lg(r1); r = cgetg(l, t_VEC);
     393          56 :   be2 = r2? rtopoles(r2): NULL;
     394         112 :   for (i = j = 1; j < l; j++)
     395             :   {
     396          56 :     GEN z, v = gel(r1,j), be = gel(v,1), s1 = gel(v,2);
     397             :     long n;
     398          56 :     if (be2 && (n = RgV_isin(be2, be)))
     399             :     {
     400          42 :       GEN s2 = gmael(r2,n,2); /* s1,s2: polar parts */
     401          42 :       if (orderpole(s1) == orderpole(s2)) continue;
     402             :     }
     403          14 :     z = gdiv(lfun(ldata1,be,bitprec), lfun(ldata2,be,bitprec));
     404          14 :     if (valser(z) < 0) gel(r,i++) = mkvec2(be, z);
     405             :   }
     406          56 :   if (i == 1) return NULL;
     407          14 :   setlg(r, i); return r;
     408             : }
     409             : 
     410             : static GEN
     411          56 : lfunvgasub(GEN v01, GEN v2)
     412             : {
     413          56 :   GEN v1 = shallowcopy(v01), v;
     414          56 :   long l1 = lg(v1), l2 = lg(v2), j1, j2, j;
     415         119 :   for (j2 = 1; j2 < l2; j2++)
     416             :   {
     417          91 :     for (j1 = 1; j1 < l1; j1++)
     418          91 :       if (gel(v1,j1) && gequal(gel(v1,j1), gel(v2,j2)))
     419             :       {
     420          63 :         gel(v1,j1) = NULL; break;
     421             :       }
     422          63 :     if (j1 == l1) pari_err_OP("lfunvgasub", v1, v2);
     423             :   }
     424          56 :   v = cgetg(l1-l2+1, t_VEC);
     425         259 :   for (j1 = j = 1; j1 < l1; j1++)
     426         203 :     if (gel(v1, j1)) gel(v,j++) = gel(v1,j1);
     427          56 :   return v;
     428             : }
     429             : 
     430             : GEN
     431          56 : lfundiv(GEN ldata1, GEN ldata2, long bitprec)
     432             : {
     433          56 :   pari_sp ltop = avma;
     434             :   GEN k, r, N, v, eno, a1a2, b1b2, eno2;
     435          56 :   long prec = nbits2prec(bitprec);
     436          56 :   ldata1 = ldata_newprec(lfunmisc_to_ldata_shallow(ldata1), prec);
     437          56 :   ldata2 = ldata_newprec(lfunmisc_to_ldata_shallow(ldata2), prec);
     438          56 :   k = ldata_get_k(ldata1);
     439          56 :   if (!gequal(ldata_get_k(ldata2),k))
     440           0 :     pari_err_OP("lfundiv [weight]",ldata1, ldata2);
     441          56 :   N = gdiv(ldata_get_conductor(ldata1), ldata_get_conductor(ldata2));
     442          56 :   if (typ(N) != t_INT) pari_err_OP("lfundiv [conductor]",ldata1, ldata2);
     443          56 :   r = lfundivpoles(ldata1, ldata2, bitprec);
     444          56 :   a1a2 = lfunconvolinv(ldata_get_an(ldata1), ldata_get_an(ldata2));
     445          56 :   b1b2 = lfuncombdual(lfunconvolinv, ldata1, ldata2);
     446          56 :   eno2 = ldata_get_rootno(ldata2);
     447          56 :   eno = isintzero(eno2)? gen_0: gdiv(ldata_get_rootno(ldata1), eno2);
     448          56 :   v = lfunvgasub(ldata_get_gammavec(ldata1), ldata_get_gammavec(ldata2));
     449          56 :   return gerepilecopy(ltop,  mkvecn(r? 7: 6, a1a2, b1b2, v, k, N, eno, r));
     450             : }
     451             : 
     452             : static GEN
     453        2387 : gamma_imagchi(GEN gam, GEN w)
     454             : {
     455        2387 :   long i, j, k=1, l;
     456        2387 :   GEN g = cgetg_copy(gam, &l);
     457        2387 :   gam = shallowcopy(gam);
     458        7161 :   for (i = l-1; i>=1; i--)
     459             :   {
     460        4774 :     GEN al = gel(gam, i);
     461        4774 :     if (al)
     462             :     {
     463        2394 :       GEN N = gadd(w,gmul2n(real_i(al),1));
     464        2394 :       if (gcmpgs(N,2) > 0)
     465             :       {
     466        2380 :         GEN bl = gsubgs(al, 1);
     467        2380 :         for (j=1; j < i; j++)
     468        2380 :           if (gel(gam,j) && gequal(gel(gam,j), bl))
     469        2380 :           { gel(gam,j) = NULL; break; }
     470        2380 :         if (j==i) return NULL;
     471        2380 :         gel(g, k++) = al;
     472        2380 :         gel(g, k++) = bl;
     473          14 :       } else if (gequal0(N))
     474          14 :         gel(g, k++) = gaddgs(al, 1);
     475           0 :       else if (gequal1(N))
     476           0 :         gel(g, k++) = gsubgs(al, 1);
     477           0 :       else return NULL;
     478             :     }
     479             :   }
     480        2387 :   return sort(g);
     481             : }
     482             : 
     483             : GEN
     484        5173 : lfuntwist(GEN ldata1, GEN chi, long bitprec)
     485             : {
     486        5173 :   pari_sp ltop = avma;
     487             :   GEN k, L, N, N1, N2, a, a1, a2, b, b1, b2, gam, gam1, gam2;
     488             :   GEN ldata2;
     489             :   long d1, t;
     490        5173 :   long prec = nbits2prec(bitprec);
     491        5173 :   ldata1 = ldata_newprec(lfunmisc_to_ldata_shallow(ldata1), prec);
     492        5173 :   ldata2 = lfunmisc_to_ldata_shallow(chi);
     493        5173 :   t = ldata_get_type(ldata2);
     494        5173 :   a1 = ldata_get_an(ldata1);
     495        5173 :   a2 = ldata_get_an(ldata2);
     496        5173 :   if (t == t_LFUN_ZETA)
     497        2415 :     return gerepilecopy(ltop, ldata1);
     498        2758 :   if (t != t_LFUN_CHIZ && t != t_LFUN_KRONECKER &&
     499           7 :     ( t != t_LFUN_CHIGEN || nf_get_degree(bnr_get_nf(gmael(a2,2,1))) != 1))
     500           0 :     pari_err_TYPE("lfuntwist", chi);
     501        2758 :   N1 = ldata_get_conductor(ldata1);
     502        2758 :   N2 = ldata_get_conductor(ldata2);
     503        2758 :   if (!gequal1(gcdii(N1, N2)))
     504           0 :     pari_err_IMPL("lfuntwist (conductors not coprime)");
     505        2758 :   k = ldata_get_k(ldata1);
     506        2758 :   d1 = ldata_get_degree(ldata1);
     507        2758 :   N = gmul(N1, gpowgs(N2, d1));
     508        2758 :   gam1 = ldata_get_gammavec(ldata1);
     509        2758 :   gam2 = ldata_get_gammavec(ldata2);
     510        2758 :   if (gequal0(gel(gam2, 1)))
     511         371 :     gam = gam1;
     512             :   else
     513        2387 :     gam = gamma_imagchi(ldata_get_gammavec(ldata1), gaddgs(k,-1));
     514        2758 :   if (!gam) pari_err_IMPL("lfuntwist (gammafactors)");
     515        2758 :   b1 = ldata_get_dual(ldata1);
     516        2758 :   b2 = ldata_get_dual(ldata2);
     517        2758 :   a = tag(mkvec2(a1, a2), t_LFUN_TWIST);
     518        2758 :   if (typ(b1)==t_INT)
     519        2758 :     b = signe(b1) && signe(b2) ? gen_0: gen_1;
     520             :   else
     521           0 :     b = tag(mkvec2(b1,lfunconj(a2)), t_LFUN_TWIST);
     522        2758 :   L = mkvecn(6, a, b, gam, k, N, gen_0);
     523        2758 :   return gerepilecopy(ltop, L);
     524             : }
     525             : 
     526             : static GEN
     527         280 : lfundualpoles(GEN ldata, GEN reno)
     528             : {
     529             :   long l, j;
     530         280 :   GEN k = ldata_get_k(ldata);
     531         280 :   GEN r = gel(reno,2), eno = gel(reno,3), R;
     532         280 :   R = cgetg_copy(r, &l);
     533         854 :   for (j = 1; j < l; j++)
     534             :   {
     535         574 :     GEN b = gmael(r,j,1), e = gmael(r,j,2);
     536         574 :     long v = varn(e);
     537         574 :     GEN E = gsubst(gdiv(e, eno), v, gneg(pol_x(v)));
     538         574 :     gel(R,l-j) = mkvec2(gsub(k,b), E);
     539             :   }
     540         280 :   return R;
     541             : }
     542             : 
     543             : static GEN
     544         567 : ginvvec(GEN x)
     545             : {
     546         567 :   if (is_vec_t(typ(x)))
     547          42 :     pari_APPLY_same(ginv(gel(x,i)))
     548             :   else
     549         553 :     return ginv(x);
     550             : }
     551             : 
     552             : GEN
     553         630 : lfundual(GEN L, long bitprec)
     554             : {
     555         630 :   pari_sp av = avma;
     556         630 :   long prec = nbits2prec(bitprec);
     557         630 :   GEN ldata = ldata_newprec(lfunmisc_to_ldata_shallow(L), prec);
     558         630 :   GEN a = ldata_get_an(ldata), b = ldata_get_dual(ldata);
     559         630 :   GEN e = ldata_get_rootno(ldata);
     560         630 :   GEN ldual, ad, bd, ed, Rd = NULL;
     561         630 :   if (typ(b) == t_INT)
     562             :   {
     563         602 :     ad = equali1(b) ? lfunconj(a): a;
     564         602 :     bd = b;
     565             :   }
     566          28 :   else { ad = b; bd = a; }
     567         630 :   if (lg(ldata)==8)
     568             :   {
     569         280 :     GEN reno = lfunrootres(ldata, bitprec);
     570         280 :     e = gel(reno,3);
     571         280 :     Rd = lfundualpoles(ldata, reno);
     572             :   }
     573         630 :   ed = isintzero(e) ? e: ginvvec(e);
     574         630 :   ldual = mkvecn(Rd ? 7:6, ad, bd, gel(ldata,3), gel(ldata,4), gel(ldata,5), ed, Rd);
     575         630 :   return gerepilecopy(av, ldual);
     576             : }
     577             : 
     578             : static GEN
     579          98 : RgV_Rg_translate(GEN x, GEN s)
     580         259 : { pari_APPLY_same(gadd(gel(x,i),s)) }
     581             : 
     582             : static GEN
     583          28 : pole_translate(GEN x, GEN s, GEN Ns)
     584             : {
     585          28 :   x = shallowcopy(x);
     586          28 :   gel(x,1) = gadd(gel(x,1), s);
     587          28 :   if (Ns)
     588          28 :     gel(x,2) = gmul(gel(x,2), Ns);
     589          28 :   return x;
     590             : }
     591             : 
     592             : static GEN
     593          14 : poles_translate(GEN x, GEN s, GEN Ns)
     594          42 : { pari_APPLY_same(pole_translate(gel(x,i), s, Ns)) }
     595             : 
     596             : /* r / x + O(1) */
     597             : static GEN
     598         266 : simple_pole(GEN r)
     599             : {
     600             :   GEN S;
     601         266 :   if (isintzero(r)) return gen_0;
     602         217 :   S = deg1ser_shallow(gen_0, r, 1);
     603         217 :   setvalser(S, -1); return S;
     604             : }
     605             : 
     606             : GEN
     607          98 : lfunshift(GEN ldata, GEN s, long flag, long bitprec)
     608             : {
     609          98 :   pari_sp ltop = avma;
     610             :   GEN k, k1, L, N, a, b, gam, eps, res;
     611          98 :   long prec = nbits2prec(bitprec);
     612          98 :   if (!is_rational_t(typ(s))) pari_err_TYPE("lfunshift",s);
     613          98 :   ldata = ldata_newprec(lfunmisc_to_ldata_shallow(ldata), prec);
     614          98 :   a = ldata_get_an(ldata);
     615          98 :   b = ldata_get_dual(ldata);
     616          98 :   gam = RgV_Rg_translate(ldata_get_gammavec(ldata), gneg(s));
     617          98 :   k = gadd(ldata_get_k(ldata), gmul2n(s, 1));
     618          98 :   k1 = gadd(ldata_get_k1(ldata), s);
     619          98 :   N = ldata_get_conductor(ldata);
     620          98 :   eps = ldata_get_rootno(ldata);
     621          98 :   res = ldata_get_residue(ldata);
     622          98 :   a = tag(mkvec2(a, s), t_LFUN_SHIFT);
     623          98 :   if (typ(b) != t_INT)
     624           0 :     b = tag(mkvec2(b, s), t_LFUN_SHIFT);
     625          98 :   if (res)
     626          98 :     switch(typ(res))
     627             :     {
     628           0 :     case t_VEC:
     629           0 :       res = poles_translate(res, s, NULL);
     630           0 :       break;
     631          14 :     case t_COL:
     632          14 :       res = poles_translate(res, s, gpow(N, gmul2n(s, -1), prec));
     633          14 :       break;
     634          84 :     default:
     635          84 :       res = mkvec(mkvec2(gsub(k, s), simple_pole(res)));
     636             :     }
     637          98 :   L = mkvecn(res ? 7: 6, a, b, gam, mkvec2(k, k1), N, eps, res);
     638          98 :   if (flag) L = lfunmul_k(ldata, L, gsub(k, s), bitprec);
     639          98 :   return gerepilecopy(ltop, L);
     640             : }
     641             : 
     642             : /*****************************************************************/
     643             : /*  L-series from closure                                        */
     644             : /*****************************************************************/
     645             : static GEN
     646       58954 : localfactor(void *E, GEN p, long n)
     647             : {
     648       58954 :   GEN s = closure_callgen2((GEN)E, p, utoi(n));
     649       58954 :   return direuler_factor(s, n);
     650             : }
     651             : static GEN
     652        1932 : vecan_closure(GEN a, long L, long prec)
     653             : {
     654        1932 :   long ta = typ(a);
     655        1932 :   GEN gL, Sbad = NULL;
     656             : 
     657        1932 :   if (!L) return cgetg(1,t_VEC);
     658        1932 :   if (ta == t_VEC)
     659             :   {
     660        1015 :     long l = lg(a);
     661        1015 :     if (l == 1) pari_err_TYPE("vecan_closure", a);
     662        1015 :     ta = typ(gel(a,1));
     663             :     /* regular vector, return it */
     664        1015 :     if (ta != t_CLOSURE) return vecslice(a, 1, minss(L,l-1));
     665         119 :     if (l != 3) pari_err_TYPE("vecan_closure", a);
     666         119 :     Sbad = gel(a,2);
     667         119 :     if (typ(Sbad) != t_VEC) pari_err_TYPE("vecan_closure", a);
     668         112 :     a = gel(a,1);
     669             :   }
     670         917 :   else if (ta != t_CLOSURE) pari_err_TYPE("vecan_closure", a);
     671        1015 :   push_localprec(prec);
     672        1015 :   gL = stoi(L);
     673        1015 :   switch(closure_arity(a))
     674             :   {
     675         371 :     case 2:
     676         371 :       a = direuler_bad((void*)a, localfactor, gen_2, gL,gL, Sbad);
     677         336 :       break;
     678         637 :     case 1:
     679         637 :       a = closure_callgen1(a, gL);
     680         637 :       if (typ(a) != t_VEC) pari_err_TYPE("vecan_closure", a);
     681         630 :       break;
     682           7 :     default: pari_err_TYPE("vecan_closure [wrong arity]", a);
     683             :       a = NULL; /*LCOV_EXCL_LINE*/
     684             :   }
     685         966 :   pop_localprec(); return a;
     686             : }
     687             : 
     688             : static GEN
     689          70 : eulerf_closure(GEN a, GEN p, long prec)
     690             : {
     691          70 :   long ta = typ(a);
     692          70 :   GEN Sbad = NULL, f;
     693             : 
     694          70 :   if (ta == t_VEC)
     695             :   {
     696           0 :     long l = lg(a);
     697           0 :     if (l == 1) pari_err_TYPE("vecan_closure", a);
     698           0 :     ta = typ(gel(a,1));
     699             :     /* regular vector, return it */
     700           0 :     if (ta != t_CLOSURE) return NULL;
     701           0 :     if (l != 3) pari_err_TYPE("vecan_closure", a);
     702           0 :     Sbad = gel(a,2);
     703           0 :     if (typ(Sbad) != t_VEC) pari_err_TYPE("vecan_closure", a);
     704           0 :     a = gel(a,1);
     705             :   }
     706          70 :   else if (ta != t_CLOSURE) pari_err_TYPE("vecan_closure", a);
     707          70 :   push_localprec(prec);
     708          70 :   switch(closure_arity(a))
     709             :   {
     710          14 :     case 2:
     711          14 :       f = closure_callgen2(a, p, mkoo()); break;
     712          56 :     case 1:
     713          56 :       f = NULL; break;
     714           0 :     default:
     715           0 :       f = NULL; pari_err_TYPE("vecan_closure", a);
     716             :   }
     717          70 :   pop_localprec(); return f;
     718             : }
     719             : 
     720             : /*****************************************************************/
     721             : /*  L-series of Dirichlet characters.                            */
     722             : /*****************************************************************/
     723             : 
     724             : static GEN
     725        4074 : lfunzeta(void)
     726             : {
     727        4074 :   GEN zet = mkvecn(7, NULL, gen_0, NULL, gen_1, gen_1, gen_1, gen_1);
     728        4074 :   gel(zet,1) = tag(gen_1, t_LFUN_ZETA);
     729        4074 :   gel(zet,3) = mkvec(gen_0);
     730        4074 :   return zet;
     731             : }
     732             : 
     733             : static GEN
     734        3654 : vecan_Kronecker(GEN D, long n)
     735             : {
     736        3654 :   GEN v = cgetg(n+1, t_VECSMALL);
     737        3654 :   ulong Du = itou_or_0(D);
     738        3654 :   long i, id, d = Du ? minuu(Du, n): n;
     739       42483 :   for (i = 1; i <= d; i++) v[i] = krois(D,i);
     740      553630 :   for (id = i; i <= n; i++,id++) /* periodic mod d */
     741             :   {
     742      549976 :     if (id > d) id = 1;
     743      549976 :     gel(v, i) = gel(v, id);
     744             :   }
     745        3654 :   return v;
     746             : }
     747             : 
     748             : static GEN
     749        6881 : lfunchiquad(GEN D)
     750             : {
     751             :   GEN r;
     752        6881 :   D = coredisc(D);
     753        6881 :   if (equali1(D)) return lfunzeta();
     754        6055 :   if (!isfundamental(D)) pari_err_TYPE("lfunchiquad [not primitive]", D);
     755        6055 :   r = mkvecn(6, NULL, gen_0, NULL, gen_1, NULL, gen_1);
     756        6055 :   gel(r,1) = tag(icopy(D), t_LFUN_KRONECKER);
     757        6055 :   gel(r,3) = mkvec(signe(D) < 0? gen_1: gen_0);
     758        6055 :   gel(r,5) = mpabs(D);
     759        6055 :   return r;
     760             : }
     761             : 
     762             : /* Begin Hecke characters. Here a character is assumed to be given by a
     763             :    vector on the generators of the ray class group clgp of CL_m(K).
     764             :    If clgp = [h,[d1,...,dk],[g1,...,gk]] with dk|...|d2|d1, a character chi
     765             :    is given by [a1,a2,...,ak] such that chi(gi)=\zeta_di^ai. */
     766             : 
     767             : /* Value of CHI on x, coprime to bnr.mod */
     768             : static GEN
     769       97293 : chigeneval_i(GEN logx, GEN d, GEN nchi, GEN z, long prec)
     770             : {
     771       97293 :   pari_sp av = avma;
     772       97293 :   GEN e = FpV_dotproduct(nchi, logx, d);
     773       97293 :   if (!is_vec_t(typ(z)))
     774        1225 :     return gerepileupto(av, gpow(z, e, prec));
     775             :   else
     776             :   {
     777       96068 :     ulong i = itou(e);
     778       96068 :     set_avma(av); return gel(z, i+1);
     779             :   }
     780             : }
     781             : 
     782             : static GEN
     783       85050 : chigenevalvec(GEN logx, GEN nchi, GEN z, long prec, long multi)
     784             : {
     785       85050 :   GEN d = gel(nchi,1), x = gel(nchi, 2);
     786       85050 :   if (multi)
     787       35511 :     pari_APPLY_same(chigeneval_i(logx, d, gel(x,i), z, prec))
     788             :   else
     789       73416 :     return chigeneval_i(logx, d, x, z, prec);
     790             : }
     791             : 
     792             : /* return x + yz; y != 0; z = 0,1 "often"; x = 0 "often" */
     793             : static GEN
     794     1887018 : gaddmul(GEN x, GEN y, GEN z)
     795             : {
     796             :   pari_sp av;
     797     1887018 :   if (typ(z) == t_INT)
     798             :   {
     799     1684025 :     if (!signe(z)) return x;
     800       28350 :     if (equali1(z)) return gadd(x,y);
     801             :   }
     802      222943 :   if (isintzero(x)) return gmul(y,z);
     803      119931 :   av = avma;
     804      119931 :   return gerepileupto(av, gadd(x, gmul(y,z)));
     805             : }
     806             : 
     807             : static GEN
     808     1805916 : gaddmulvec(GEN x, GEN y, GEN z, long multi)
     809             : {
     810     1805916 :   if (multi)
     811      244916 :     pari_APPLY_same(gaddmul(gel(x,i),gel(y,i),gel(z,i)))
     812             :   else
     813     1724009 :     return gaddmul(x,y,z);
     814             : }
     815             : 
     816             : static GEN
     817        4991 : mkvchi(GEN chi, long n)
     818             : {
     819             :   GEN v;
     820        4991 :   if (lg(chi) > 1 && is_vec_t(typ(gel(chi,1))))
     821         483 :   {
     822         483 :     long d = lg(chi)-1;
     823         483 :     v = const_vec(n, zerovec(d));
     824         483 :     gel(v,1) = const_vec(d, gen_1);
     825             :   }
     826             :   else
     827        4508 :     v = vec_ei(n, 1);
     828        4991 :   return v;
     829             : }
     830             : 
     831             : static GEN
     832        3647 : vecan_chiZ(GEN an, long n, long prec)
     833             : {
     834             :   forprime_t iter;
     835        3647 :   GEN G = gel(an,1);
     836        3647 :   GEN nchi = gel(an,2), gord = gel(nchi,1), chi = gel(nchi,2), z;
     837        3647 :   GEN gp = cgetipos(3), v = mkvchi(chi, n);
     838        3647 :   GEN N = znstar_get_N(G);
     839        3647 :   long ord = itos_or_0(gord);
     840        3647 :   ulong Nu = itou_or_0(N);
     841        3647 :   long i, id, d = Nu ? minuu(Nu, n): n;
     842        3647 :   long multichi= (lg(chi) > 1 && is_vec_t(typ(gel(chi,1))));
     843             :   ulong p;
     844        3647 :   if (!multichi && ord && n > (ord>>4))
     845        3521 :   {
     846        3521 :     GEN w = ncharvecexpo(G, nchi);
     847        3521 :     z = grootsof1(ord, prec);
     848       37926 :     for (i = 1; i <= d; i++)
     849       34405 :       if (w[i] >= 0) gel(v, i) = gel(z, w[i]+1);
     850             :   }
     851             :   else
     852             :   {
     853         126 :     z = rootsof1_cx(gord, prec);
     854         126 :     u_forprime_init(&iter, 2, d);
     855         805 :     while ((p = u_forprime_next(&iter)))
     856             :     {
     857             :       GEN ch;
     858             :       ulong k;
     859         679 :       if (!umodiu(N,p)) continue;
     860         560 :       gp[2] = p;
     861         560 :       ch = chigenevalvec(znconreylog(G, gp), nchi, z, prec, multichi);
     862         560 :       gel(v, p)  = ch;
     863        1582 :       for (k = 2*p; k <= (ulong)d; k += p)
     864        1022 :         gel(v, k) = gaddmulvec(gel(v, k), ch, gel(v, k/p), multichi);
     865             :     }
     866             :   }
     867      898765 :   for (id = i = d+1; i <= n; i++,id++) /* periodic mod d */
     868             :   {
     869      895118 :     if (id > d) id = 1;
     870      895118 :     gel(v, i) = gel(v, id);
     871             :   }
     872        3647 :   return v;
     873             : }
     874             : 
     875             : static GEN
     876          42 : eulerf_chiZ(GEN an, GEN p, long prec)
     877             : {
     878          42 :   GEN G = gel(an,1);
     879          42 :   GEN nchi = gel(an,2), gord = gel(nchi,1), chi = gel(nchi,2);
     880          42 :   long multichi= (lg(chi) > 1 && is_vec_t(typ(gel(chi,1))));
     881          42 :   GEN z = rootsof1_cx(gord, prec);
     882          42 :   GEN N = znstar_get_N(G);
     883          42 :   GEN ch = dvdii(N,p) ? gen_0: chigenevalvec(znconreylog(G, p), nchi, z, prec, multichi);
     884          42 :   return mkrfrac(gen_1, deg1pol_shallow(gneg(ch), gen_1,0));
     885             : }
     886             : 
     887             : static GEN
     888        1344 : vecan_chigen(GEN an, long n, long prec)
     889             : {
     890             :   forprime_t iter;
     891        1344 :   GEN bnr = gel(an,1), nf = bnr_get_nf(bnr);
     892        1344 :   GEN nchi = gel(an,2), gord = gel(nchi,1), chi = gel(nchi,2), z;
     893        1344 :   GEN gp = cgetipos(3), v = mkvchi(chi, n);
     894        1344 :   GEN N = gel(bnr_get_mod(bnr), 1), NZ = gcoeff(N,1,1);
     895        1344 :   long ord = itos_or_0(gord);
     896        1344 :   long multichi= (lg(chi) > 1 && is_vec_t(typ(gel(chi,1))));
     897             :   ulong p;
     898             : 
     899        1344 :   if (ord && n > (ord>>4))
     900        1344 :     z = grootsof1(ord, prec);
     901             :   else
     902           0 :     z = rootsof1_cx(gord, prec);
     903             : 
     904        1344 :   if (nf_get_degree(nf) == 1)
     905             :   {
     906         945 :     ulong Nu = itou_or_0(NZ);
     907         945 :     long i, id, d = Nu ? minuu(Nu, n): n;
     908         945 :     u_forprime_init(&iter, 2, d);
     909        4711 :     while ((p = u_forprime_next(&iter)))
     910             :     {
     911             :       GEN ch;
     912             :       ulong k;
     913        3766 :       if (!umodiu(NZ,p)) continue;
     914        2800 :       gp[2] = p;
     915        2800 :       ch = chigenevalvec(isprincipalray(bnr,gp), nchi, z, prec, multichi);
     916        2800 :       gel(v, p)  = ch;
     917        7987 :       for (k = 2*p; k <= (ulong)d; k += p)
     918        5187 :         gel(v, k) = gaddmulvec(gel(v, k), ch, gel(v, k/p), multichi);
     919             :     }
     920       11543 :     for (id = i = d+1; i <= n; i++,id++) /* periodic mod d */
     921             :     {
     922       10598 :       if (id > d) id = 1;
     923       10598 :       gel(v, i) = gel(v, id);
     924             :     }
     925             :   }
     926             :   else
     927             :   {
     928         399 :     GEN BOUND = stoi(n);
     929         399 :     u_forprime_init(&iter, 2, n);
     930       82369 :     while ((p = u_forprime_next(&iter)))
     931             :     {
     932             :       GEN L;
     933             :       long j;
     934       81970 :       int check = !umodiu(NZ,p);
     935       81970 :       gp[2] = p;
     936       81970 :       L = idealprimedec_limit_norm(nf, gp, BOUND);
     937      163828 :       for (j = 1; j < lg(L); j++)
     938             :       {
     939       81858 :         GEN pr = gel(L, j), ch;
     940             :         ulong k, q;
     941       81858 :         if (check && idealval(nf, N, pr)) continue;
     942       81613 :         ch = chigenevalvec(isprincipalray(bnr,pr), nchi, z, prec, multichi);
     943       81613 :         q = upr_norm(pr);
     944       81613 :         gel(v, q) = gadd(gel(v, q), ch);
     945     1881320 :         for (k = 2*q; k <= (ulong)n; k += q)
     946     1799707 :           gel(v, k) = gaddmulvec(gel(v, k), ch, gel(v, k/q), multichi);
     947             :       }
     948             :     }
     949             :   }
     950        1344 :   return v;
     951             : }
     952             : 
     953             : static GEN
     954          28 : eulerf_chigen(GEN an, GEN p, long prec)
     955             : {
     956          28 :   GEN bnr = gel(an,1), nf = bnr_get_nf(bnr);
     957          28 :   GEN nchi = gel(an,2), gord = gel(nchi,1), chi = gel(nchi,2), z;
     958          28 :   GEN N = gel(bnr_get_mod(bnr), 1), NZ = gcoeff(N,1,1), f;
     959          28 :   long multichi= (lg(chi) > 1 && is_vec_t(typ(gel(chi,1))));
     960             : 
     961          28 :   z = rootsof1_cx(gord, prec);
     962          28 :   if (nf_get_degree(nf) == 1)
     963             :   {
     964             :     GEN ch;
     965           0 :     if (dvdii(NZ,p)) ch = gen_0;
     966             :     else
     967             :     {
     968           0 :       ch = chigenevalvec(isprincipalray(bnr,p), nchi, z, prec, multichi);
     969           0 :       if (typ(ch)==t_VEC) return NULL;
     970             :     }
     971           0 :     f = deg1pol_shallow(gneg(ch), gen_1, 0);
     972             :   }
     973             :   else
     974             :   {
     975          28 :     int check = dvdii(NZ,p);
     976          28 :     GEN L = idealprimedec(nf, p);
     977          28 :     long j, lL = lg(L);
     978          28 :     f = pol_1(0);
     979          49 :     for (j = 1; j < lL; j++)
     980             :     {
     981          35 :       GEN pr = gel(L, j), ch;
     982          35 :       if (check && idealval(nf, N, pr)) ch = gen_0;
     983             :       else
     984          35 :       ch = chigenevalvec(isprincipalray(bnr,pr), nchi, z, prec, multichi);
     985          35 :       if (typ(ch)==t_VEC) return NULL;
     986          21 :       f = gmul(f, gsub(gen_1, monomial(ch, pr_get_f(pr), 0)));
     987             :     }
     988             :   }
     989          14 :   return mkrfrac(gen_1,f);
     990             : }
     991             : 
     992             : static GEN
     993        4480 : vec01(long r1, long r2)
     994             : {
     995        4480 :   long d = r1+r2, i;
     996        4480 :   GEN v = cgetg(d+1,t_VEC);
     997       12649 :   for (i = 1; i <= r1; i++) gel(v,i) = gen_0;
     998        7203 :   for (     ; i <= d;  i++) gel(v,i) = gen_1;
     999        4480 :   return v;
    1000             : }
    1001             : 
    1002             : /* true nf or t_POL */
    1003             : static GEN
    1004        1246 : lfunzetak_i(GEN T)
    1005             : {
    1006             :   GEN Vga, N;
    1007             :   long r1, r2;
    1008        1246 :   if (typ(T) == t_POL)
    1009             :   {
    1010         651 :     T = nfinit0(T, nf_NOLLL, DEFAULTPREC);
    1011         651 :     if (lg(T) == 3) T = gel(T,1); /* [nf,change of var] */
    1012             :   }
    1013        1246 :   if (nf_get_degree(T) == 1) return lfunzeta();
    1014        1246 :   nf_get_sign(T,&r1,&r2); Vga = vec01(r1+r2,r2);
    1015        1246 :   N = absi_shallow(nf_get_disc(T));
    1016        1246 :   return mkvecn(7, tag(T,t_LFUN_NF), gen_0, Vga, gen_1, N, gen_1, gen_0);
    1017             : }
    1018             : /* truen nf or t_POL */
    1019             : static GEN
    1020         819 : lfunzetak(GEN T)
    1021         819 : { pari_sp av = avma; return gerepilecopy(av, lfunzetak_i(T)); }
    1022             : 
    1023             : /* C = normalized character of order dividing o; renormalize so that it has
    1024             :  * apparent order o */
    1025             : static GEN
    1026         609 : char_renormalize(GEN C, GEN o)
    1027             : {
    1028         609 :   GEN oc = gel(C,1), c = gel(C,2);
    1029         609 :   if (!equalii(o, oc)) c = ZC_Z_mul(c, diviiexact(o, oc));
    1030         609 :   return c;
    1031             : }
    1032             : static GEN
    1033         224 : vecchar_renormalize(GEN x, GEN o)
    1034         833 : { pari_APPLY_same(char_renormalize(gel(x,i), o)); }
    1035             : 
    1036             : /* G is a bid of nftyp typ_BIDZ */
    1037             : static GEN
    1038        8421 : lfunchiZ(GEN G, GEN CHI)
    1039             : {
    1040        8421 :   pari_sp av = avma;
    1041        8421 :   GEN sig = NULL, N = bid_get_ideal(G), nchi, r;
    1042             :   int real;
    1043             :   long s;
    1044             : 
    1045        8421 :   if (typ(N) != t_INT) pari_err_TYPE("lfunchiZ", G);
    1046        8421 :   if (typ(CHI) == t_VEC && !RgV_is_ZV(CHI))
    1047          21 :   {
    1048          42 :     GEN C, G0 = G, o = gen_1;
    1049          42 :     long i, l = lg(CHI);
    1050          42 :     nchi = cgetg(l, t_VEC);
    1051          42 :     N = znconreyconductor(G, gel(CHI,1), &C);
    1052          35 :     if (typ(N) != t_INT) G = znstar0(N, 1);
    1053          35 :     s = zncharisodd(G, C);
    1054          91 :     for (i = 1; i < l; i++)
    1055             :     {
    1056          70 :       if (i > 1)
    1057             :       {
    1058          35 :         if (!gequal(N, znconreyconductor(G0, gel(CHI,i), &C))
    1059          28 :             || zncharisodd(G, C) != s)
    1060          14 :           pari_err_TYPE("lfuncreate [different conductors]", CHI);
    1061             :       }
    1062          56 :       C = znconreylog_normalize(G, C);
    1063          56 :       o = lcmii(o, gel(C,1)); /* lcm with charorder */
    1064          56 :       gel(nchi,i) = C;
    1065             :     }
    1066          21 :     nchi = mkvec2(o, vecchar_renormalize(nchi, o));
    1067          21 :     if (typ(N) != t_INT) N = gel(N,1);
    1068             :   }
    1069             :   else
    1070             :   {
    1071        8379 :     N = znconreyconductor(G, CHI, &CHI);
    1072        8379 :     if (typ(N) != t_INT)
    1073             :     {
    1074           7 :       if (equali1(gel(N,1))) { set_avma(av); return lfunzeta(); }
    1075           0 :       G = znstar0(N, 1);
    1076           0 :       N = gel(N,1);
    1077             :     }
    1078             :     /* CHI now primitive on G */
    1079        8372 :     switch(itou_or_0(zncharorder(G, CHI)))
    1080             :     {
    1081        2415 :       case 1: set_avma(av); return lfunzeta();
    1082        2982 :       case 2: if (zncharisodd(G,CHI)) N = negi(N);
    1083        2982 :               return gerepileupto(av, lfunchiquad(N));
    1084             :     }
    1085        2975 :     nchi = znconreylog_normalize(G, CHI);
    1086        2975 :     s = zncharisodd(G, CHI);
    1087             :   }
    1088        2996 :   sig = mkvec(s? gen_1: gen_0);
    1089        2996 :   real = abscmpiu(gel(nchi,1), 2) <= 0;
    1090        2996 :   r = mkvecn(6, tag(mkvec2(G,nchi), t_LFUN_CHIZ),
    1091             :                 real? gen_0: gen_1, sig, gen_1, N, gen_0);
    1092        2996 :   return gerepilecopy(av, r);
    1093             : }
    1094             : 
    1095             : static GEN
    1096        1309 : lfunchigen(GEN bnr, GEN CHI)
    1097             : {
    1098        1309 :   pari_sp av = avma;
    1099             :   GEN N, sig, Ldchi, nf, nchi, NN;
    1100             :   long r1, r2, n1;
    1101             :   int real;
    1102             : 
    1103        1309 :   if (typ(CHI) == t_VEC && !RgV_is_ZV(CHI))
    1104         203 :   {
    1105         210 :     long map, i, l = lg(CHI);
    1106         210 :     GEN bnr0 = bnr, D, chi = gel(CHI,1), o = gen_1;
    1107         210 :     nchi = cgetg(l, t_VEC);
    1108         210 :     bnr_char_sanitize(&bnr, &chi);
    1109         210 :     D = cyc_normalize(bnr_get_cyc(bnr));
    1110         210 :     N = bnr_get_mod(bnr);
    1111         210 :     map = (bnr != bnr0);
    1112         784 :     for (i = 1; i < l; i++)
    1113             :     {
    1114         581 :       if (i > 1)
    1115             :       {
    1116         371 :         chi = gel(CHI,i);
    1117         371 :         if (!map)
    1118             :         {
    1119         350 :           if (!bnrisconductor(bnr, chi))
    1120           7 :             pari_err_TYPE("lfuncreate [different conductors]", CHI);
    1121             :         }
    1122             :         else
    1123             :         {
    1124          21 :           if (!gequal(bnrconductor_raw(bnr0, chi), N))
    1125           0 :             pari_err_TYPE("lfuncreate [different conductors]", CHI);
    1126          21 :           chi = bnrchar_primitive_raw(bnr0, bnr, chi);
    1127             :         }
    1128             :       }
    1129         574 :       chi = char_normalize(chi, D);
    1130         574 :       o = lcmii(o, gel(chi,1)); /* lcm with charorder */
    1131         574 :       gel(nchi,i) = chi;
    1132             :     }
    1133         203 :     nchi = mkvec2(o, vecchar_renormalize(nchi, o));
    1134             :   }
    1135             :   else
    1136             :   {
    1137        1099 :     bnr_char_sanitize(&bnr, &CHI);
    1138        1099 :     nchi = NULL; /* now CHI is primitive wrt bnr */
    1139             :   }
    1140             : 
    1141        1302 :   N = bnr_get_mod(bnr);
    1142        1302 :   nf = bnr_get_nf(bnr);
    1143        1302 :   n1 = lg(vec01_to_indices(gel(N,2))) - 1; /* vecsum(N[2]) */
    1144        1302 :   N = gel(N,1);
    1145        1302 :   NN = mulii(idealnorm(nf, N), absi_shallow(nf_get_disc(nf)));
    1146        1302 :   if (!nchi)
    1147             :   {
    1148        1099 :     if (equali1(NN)) { set_avma(av); return lfunzeta(); }
    1149         658 :     if (ZV_equal0(CHI)) return gerepilecopy(av, lfunzetak_i(bnr_get_nf(bnr)));
    1150         581 :     nchi = char_normalize(CHI, cyc_normalize(bnr_get_cyc(bnr)));
    1151             :   }
    1152         784 :   real = abscmpiu(gel(nchi,1), 2) <= 0;
    1153         784 :   nf_get_sign(nf, &r1, &r2);
    1154         784 :   sig = vec01(r1+r2-n1, r2+n1);
    1155         784 :   Ldchi = mkvecn(6, tag(mkvec2(bnr, nchi), t_LFUN_CHIGEN),
    1156             :                     real? gen_0: gen_1, sig, gen_1, NN, gen_0);
    1157         784 :   return gerepilecopy(av, Ldchi);
    1158             : }
    1159             : 
    1160             : /* Find all characters of clgp whose kernel contain group given by HNF H.
    1161             :  * Set *pcnj[i] to the conductor */
    1162             : static GEN
    1163         518 : chigenkerfind(GEN bnr, GEN H, GEN *pcnj)
    1164             : {
    1165         518 :   GEN res, cnj, L = bnrchar(bnr, H, NULL);
    1166         518 :   long i, k, l = lg(L);
    1167             : 
    1168         518 :   res = cgetg(l, t_VEC);
    1169         518 :   *pcnj = cnj = cgetg(l, t_VEC);
    1170        1911 :   for (i = k = 1; i < l; i++)
    1171             :   {
    1172        1393 :     GEN chi = gel(L,i);
    1173        1393 :     gel(res, k) = chi;
    1174        1393 :     gel(cnj, k) = ZV_equal0(chi)? gen_0: bnrconductor_raw(bnr, chi);
    1175        1393 :     k++;
    1176             :   }
    1177         518 :   setlg(cnj, k);
    1178         518 :   setlg(res, k); return res;
    1179             : }
    1180             : 
    1181             : static GEN
    1182         518 : vec_classes(GEN A, GEN F)
    1183             : {
    1184         518 :   GEN w = vec_equiv(F);
    1185         518 :   long i, l = lg(w);
    1186         518 :   GEN V = cgetg(l, t_VEC);
    1187        1575 :   for (i = 1; i < l; i++) gel(V,i) = vecpermute(A,gel(w,i));
    1188         518 :   return V;
    1189             : }
    1190             : 
    1191             : static GEN
    1192      990451 : abelrel_pfactor(GEN bnr, GEN pr, GEN U, GEN D, GEN h)
    1193             : {
    1194      990451 :   GEN v = bnrisprincipalmod(bnr, pr, h, 0);
    1195      990451 :   GEN E = ZV_ZV_mod(ZM_ZC_mul(U, v), D);
    1196      990451 :   ulong o = itou(charorder(D, E)), f = pr_get_f(pr);
    1197      990451 :   return gpowgs(gsub(gen_1, monomial(gen_1, f * o, 0)), itou(h) / o);
    1198             : }
    1199             : 
    1200             : static GEN
    1201      687925 : abelrel_factor(GEN bnr, GEN C, GEN p, GEN mod, GEN U, GEN D, GEN h)
    1202             : {
    1203      687925 :   GEN nf = bnr_get_nf(bnr), F = pol_1(0), prid = idealprimedec(nf,p);
    1204      687925 :   GEN mod2 = shallowcopy(mod);
    1205      687925 :   long i, l = lg(prid);
    1206     1678376 :   for (i = 1; i < l; i++)
    1207             :   {
    1208      990451 :     GEN pr = gel(prid, i), Fpr;
    1209      990451 :     long v = idealval(nf,mod,pr);
    1210      990451 :     if (v > 0)
    1211             :     {
    1212             :       GEN bnr2, C2, U2, D2, h2;
    1213         161 :       gel(mod2, 1) = idealdivpowprime(nf, gel(mod, 1), pr, utoi(v));
    1214         161 :       bnr2 = bnrinitmod(bnr, mod2, 0, h);
    1215         161 :       C2 = bnrmap(bnrmap(bnr, bnr2), C);
    1216         161 :       D2 = ZM_snfall_i(C2, &U2, NULL, 1);
    1217         161 :       h2 = ZV_prod(D2);
    1218         161 :       Fpr = abelrel_pfactor(bnr2, pr, U2, D2, h2);
    1219             :     }
    1220             :     else
    1221      990290 :       Fpr = abelrel_pfactor(bnr, pr, U, D, h);
    1222      990451 :     F = ZX_mul(F, Fpr);
    1223             :   }
    1224      687925 :   return gcopy(mkrfrac(gen_1, F));
    1225             : }
    1226             : 
    1227             : static GEN
    1228          42 : eulerf_abelrel(GEN an, GEN p)
    1229             : {
    1230          42 :   GEN bnr = gel(an,1), C = gel(an,2), mod = gel(an,3);
    1231          42 :   GEN U, D = ZM_snfall_i(C, &U, NULL, 1), h = ZV_prod(D);
    1232          42 :   return abelrel_factor(bnr, C, p, mod, U, D, h);
    1233             : }
    1234             : 
    1235             : struct direuler_abelrel
    1236             : {
    1237             :   GEN bnr, C, mod, U, D, h;
    1238             : };
    1239             : 
    1240             : static GEN
    1241      687883 : _direuler_abelrel(void *E, GEN p)
    1242             : {
    1243      687883 :   struct direuler_abelrel *s = (struct direuler_abelrel*) E;
    1244      687883 :   return abelrel_factor(s->bnr, s->C, p, s->mod, s->U, s->D, s->h);
    1245             : }
    1246             : 
    1247             : static GEN
    1248         168 : vecan_abelrel(GEN an, long N)
    1249             : {
    1250             :   struct direuler_abelrel s;
    1251         168 :   s.bnr = gel(an,1);
    1252         168 :   s.C   = gel(an,2);
    1253         168 :   s.mod = gel(an,3);
    1254         168 :   s.D = ZM_snfall_i(s.C, &s.U, NULL, 1);
    1255         168 :   s.h = ZV_prod(s.D);
    1256         168 :   return direuler((void*)&s, _direuler_abelrel, gen_1, stoi(N), NULL);
    1257             : }
    1258             : 
    1259             : static GEN
    1260         539 : lfunabelrel_i(GEN bnr, GEN H, GEN mod)
    1261             : {
    1262         539 :   GEN NrD = bnrdisc(bnr, H, 0), N = absi_shallow(gel(NrD,3));
    1263         539 :   long n = itos(gel(NrD,1)), r1 = itos(gel(NrD,2)), r2 = (n-r1)>>1;
    1264         539 :   if (!mod) mod = bnrconductor(bnr, H, 0);
    1265         539 :   return mkvecn(7, tag(mkvec3(bnr,H,mod),t_LFUN_ABELREL),
    1266             :                    gen_0, vec01(r1+r2, r2), gen_1, N, gen_1, gen_0);
    1267             : }
    1268             : static GEN
    1269          21 : lfunabelrel(GEN bnr, GEN H, GEN mod)
    1270          21 : { pari_sp av = avma; return gerepilecopy(av, lfunabelrel_i(bnr, H, mod)); }
    1271             : 
    1272             : 
    1273             : static GEN
    1274        1057 : lfunchiinit(GEN bnr, GEN chi, GEN dom, long der, long bitprec)
    1275             : {
    1276        1057 :   GEN L = lfunchigen(bnr, lg(chi)==2 ? gel(chi,1): chi);
    1277        1057 :   return lfuninit(L, dom, der, bitprec);
    1278             : }
    1279             : static GEN
    1280         518 : veclfunchiinit(GEN bnr, GEN x, GEN dom, long der, long bitprec)
    1281        1575 : { pari_APPLY_same(lfunchiinit(bnr, gel(x,i), dom, der, bitprec)); }
    1282             : GEN
    1283         518 : lfunabelianrelinit(GEN bnr, GEN H, GEN dom, long der, long bitprec)
    1284             : {
    1285         518 :   GEN cnj, M, D, C = chigenkerfind(bnr, H, &cnj);
    1286             :   long l;
    1287         518 :   C = vec_classes(C, cnj); l = lg(C);
    1288         518 :   M = mkvec3(veclfunchiinit(bnr, C, dom, der, bitprec),
    1289             :              const_vecsmall(l-1, 1), const_vecsmall(l-1, 0));
    1290         518 :   D = mkvec2(dom, mkvecsmall2(der, bitprec));
    1291         518 :   return lfuninit_make(t_LDESC_PRODUCT, lfunabelrel_i(bnr, H, NULL), M, D);
    1292             : }
    1293             : 
    1294             : /*****************************************************************/
    1295             : /*                 Dedekind zeta functions                       */
    1296             : /*****************************************************************/
    1297             : /* true nf */
    1298             : static GEN
    1299        2107 : dirzetak0(GEN nf, ulong N)
    1300             : {
    1301        2107 :   GEN vect, c, c2, T = nf_get_pol(nf), index = nf_get_index(nf);
    1302        2107 :   pari_sp av = avma, av2;
    1303        2107 :   const ulong SQRTN = usqrt(N);
    1304             :   ulong i, p, lx;
    1305        2107 :   long court[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3),0};
    1306             :   forprime_t S;
    1307             : 
    1308        2107 :   c  = cgetalloc(N+1, t_VECSMALL);
    1309        2107 :   c2 = cgetalloc(N+1, t_VECSMALL);
    1310     2671991 :   c2[1] = c[1] = 1; for (i=2; i<=N; i++) c[i] = 0;
    1311        2107 :   u_forprime_init(&S, 2, N); av2 = avma;
    1312      348579 :   while ( (p = u_forprime_next(&S)) )
    1313             :   {
    1314      346472 :     set_avma(av2);
    1315      346472 :     if (umodiu(index, p)) /* p does not divide index */
    1316      346108 :       vect = gel(Flx_degfact(ZX_to_Flx(T,p), p),1);
    1317             :     else
    1318             :     {
    1319         364 :       court[2] = p;
    1320         364 :       vect = idealprimedec_degrees(nf,court);
    1321             :     }
    1322      346472 :     lx = lg(vect);
    1323      346472 :     if (p <= SQRTN)
    1324       35245 :       for (i=1; i<lx; i++)
    1325             :       {
    1326       23548 :         ulong qn, q = upowuu(p, vect[i]); /* Norm P[i] */
    1327       23548 :         if (!q || q > N) break;
    1328       20797 :         memcpy(c2 + 2, c + 2, (N-1)*sizeof(long));
    1329             :         /* c2[i] <- c[i] + sum_{k = 1}^{v_q(i)} c[i/q^k] for all i <= N */
    1330       42889 :         for (qn = q; qn <= N; qn *= q)
    1331             :         {
    1332       42889 :           ulong k0 = N/qn, k, k2; /* k2 = k*qn */
    1333     3760050 :           for (k = k0, k2 = k*qn; k > 0; k--, k2 -=qn) c2[k2] += c[k];
    1334       42889 :           if (q > k0) break; /* <=> q*qn > N */
    1335             :         }
    1336       20797 :         swap(c, c2);
    1337             :       }
    1338             :     else /* p > sqrt(N): simpler */
    1339      656292 :       for (i=1; i<lx; i++)
    1340             :       {
    1341             :         ulong k, k2; /* k2 = k*p */
    1342      581798 :         if (vect[i] > 1) break;
    1343             :         /* c2[i] <- c[i] + sum_{k = 1}^{v_q(i)} c[i/q^k] for all i <= N */
    1344     1906723 :         for (k = N/p, k2 = k*p; k > 0; k--, k2 -= p) c[k2] += c[k];
    1345             :       }
    1346             :   }
    1347        2107 :   set_avma(av);
    1348        2107 :   pari_free(c2); return c;
    1349             : }
    1350             : 
    1351             : static GEN
    1352         168 : eulerf_zetak(GEN nf, GEN p)
    1353             : {
    1354         168 :   GEN v, f = pol_1(0);
    1355             :   long i, l;
    1356         168 :   if (dvdii(nf_get_index(nf), p)) /* p does not divide index */
    1357           7 :     v = idealprimedec_degrees(nf,p);
    1358             :   else
    1359         161 :     v = gel(FpX_degfact(nf_get_pol(nf), p), 1);
    1360         168 :   l = lg(v);
    1361         406 :   for (i = 1; i < l; i++) f = ZX_sub(f, RgX_shift_shallow(f, v[i]));
    1362         168 :   retmkrfrac(gen_1, ZX_copy(f));
    1363             : }
    1364             : 
    1365             : GEN
    1366        2107 : dirzetak(GEN nf, GEN b)
    1367             : {
    1368             :   GEN z, c;
    1369             :   long n;
    1370             : 
    1371        2107 :   if (typ(b) != t_INT) pari_err_TYPE("dirzetak",b);
    1372        2107 :   if (signe(b) <= 0) return cgetg(1,t_VEC);
    1373        2107 :   nf = checknf(nf);
    1374        2107 :   n = itou_or_0(b); if (!n) pari_err_OVERFLOW("dirzetak");
    1375        2107 :   c = dirzetak0(nf, n);
    1376        2107 :   z = vecsmall_to_vec(c); pari_free(c); return z;
    1377             : }
    1378             : 
    1379             : static GEN
    1380         658 : linit_get_mat(GEN linit)
    1381             : {
    1382         658 :   if (linit_get_type(linit)==t_LDESC_PRODUCT)
    1383         161 :     return lfunprod_get_fact(linit_get_tech(linit));
    1384             :   else
    1385         497 :     return mkvec3(mkvec(linit), mkvecsmall(1), mkvecsmall(0));
    1386             : }
    1387             : 
    1388             : static GEN
    1389         329 : lfunproduct(GEN ldata, GEN linit1, GEN linit2, GEN domain)
    1390             : {
    1391         329 :   GEN M1 = linit_get_mat(linit1);
    1392         329 :   GEN M2 = linit_get_mat(linit2);
    1393         329 :   GEN M3 = mkvec3(shallowconcat(gel(M1, 1), gel(M2, 1)),
    1394         329 :                   vecsmall_concat(gel(M1, 2), gel(M2, 2)),
    1395         329 :                   vecsmall_concat(gel(M1, 3), gel(M2, 3)));
    1396         329 :   return lfuninit_make(t_LDESC_PRODUCT, ldata, M3, domain);
    1397             : }
    1398             : static GEN lfunzetakinit_artin(GEN nf, GEN gal, GEN dom, long der, long bit);
    1399             : /* true nf */
    1400             : static GEN
    1401         329 : lfunzetakinit_quotient(GEN nf, GEN polk, GEN dom, long der, long bitprec)
    1402             : {
    1403             :   GEN ak, an, nfk, Vga, ldata, N, Lk, LKk, domain;
    1404             :   long r1k, r2k, r1, r2;
    1405             : 
    1406         329 :   nf_get_sign(nf,&r1,&r2);
    1407         329 :   nfk = nfinit(polk, nbits2prec(bitprec));
    1408         329 :   Lk = lfunzetakinit(nfk, dom, der, bitprec); /* zeta_k */
    1409         329 :   nf_get_sign(nfk,&r1k,&r2k);
    1410         329 :   Vga = vec01((r1+r2) - (r1k+r2k), r2-r2k);
    1411         329 :   N = absi_shallow(diviiexact(nf_get_disc(nf), nf_get_disc(nfk)));
    1412         329 :   ak = nf_get_degree(nf)==1 ? tag(gen_1, t_LFUN_ZETA): tag(nfk, t_LFUN_NF);
    1413         329 :   an = tag(mkvec2(tag(nf,t_LFUN_NF), ak), t_LFUN_DIV);
    1414         329 :   ldata = mkvecn(6, an, gen_0, Vga, gen_1, N, gen_1);
    1415         329 :   LKk = lfuninit(ldata, dom, der, bitprec); /* zeta_K/zeta_k */
    1416         329 :   domain = mkvec2(dom, mkvecsmall2(der, bitprec));
    1417         329 :   return lfunproduct(lfunzetak_i(nf), Lk, LKk, domain);
    1418             : }
    1419             : /* true nf */
    1420             : GEN
    1421         945 : lfunzetakinit(GEN nf, GEN dom, long der, long bitprec)
    1422             : {
    1423         945 :   long n, d = nf_get_degree(nf);
    1424         945 :   GEN L, Q, R, T = nf_get_pol(nf);
    1425         945 :   if (d == 1) return lfuninit(lfunzeta(), dom, der, bitprec);
    1426         777 :   if (d > 2)
    1427             :   {
    1428         441 :     GEN G = galoisinit(nf, NULL);
    1429         441 :     if (isintzero(G))
    1430             :     { /* not Galois */
    1431         329 :       GEN S = nfsubfields(nf, 0); n = lg(S)-1;
    1432         329 :       return lfunzetakinit_quotient(nf, gmael(S,n-1,1), dom, der, bitprec);
    1433             :     }
    1434         112 :     if (!group_isabelian(galois_group(G))) /* Galois, not Abelian */
    1435          21 :       return lfunzetakinit_artin(nf, G, dom, der, bitprec);
    1436             :   }
    1437             :   /* Abelian over Q */
    1438         427 :   Q = Buchall(pol_x(1), 0, nbits2prec(bitprec));
    1439         427 :   T = shallowcopy(T); setvarn(T,0);
    1440         427 :   R = rnfconductor0(Q, T, 1);
    1441         427 :   L = lfunabelianrelinit(gel(R,2), gel(R,3), dom, der, bitprec);
    1442         427 :   delete_var(); return L;
    1443             : }
    1444             : 
    1445             : /***************************************************************/
    1446             : /*             Elliptic Curves and Modular Forms               */
    1447             : /***************************************************************/
    1448             : 
    1449             : static GEN
    1450         203 : lfunellnf(GEN e)
    1451             : {
    1452         203 :   pari_sp av = avma;
    1453         203 :   GEN ldata = cgetg(7, t_VEC), nf = ellnf_get_nf(e);
    1454         203 :   GEN N = gel(ellglobalred(e), 1);
    1455         203 :   long n = nf_get_degree(nf);
    1456         203 :   gel(ldata, 1) = tag(e, t_LFUN_ELL);
    1457         203 :   gel(ldata, 2) = gen_0;
    1458         203 :   gel(ldata, 3) = vec01(n, n);
    1459         203 :   gel(ldata, 4) = gen_2;
    1460         203 :   gel(ldata, 5) = mulii(idealnorm(nf,N), sqri(nf_get_disc(nf)));
    1461         203 :   gel(ldata, 6) = stoi(ellrootno_global(e));
    1462         203 :   return gerepilecopy(av, ldata);
    1463             : }
    1464             : 
    1465             : static GEN
    1466        3850 : lfunellQ(GEN e)
    1467             : {
    1468        3850 :   pari_sp av = avma;
    1469        3850 :   GEN ldata = cgetg(7, t_VEC);
    1470        3850 :   gel(ldata, 1) = tag(ellanal_globalred(e, NULL), t_LFUN_ELL);
    1471        3850 :   gel(ldata, 2) = gen_0;
    1472        3850 :   gel(ldata, 3) = mkvec2(gen_0, gen_1);
    1473        3850 :   gel(ldata, 4) = gen_2;
    1474        3850 :   gel(ldata, 5) = ellQ_get_N(e);
    1475        3850 :   gel(ldata, 6) = stoi(ellrootno_global(e));
    1476        3850 :   return gerepilecopy(av, ldata); /* ellanal_globalred not gerepile-safe */
    1477             : }
    1478             : 
    1479             : static GEN
    1480        4053 : lfunell(GEN e)
    1481             : {
    1482        4053 :   long t = ell_get_type(e);
    1483        4053 :   switch(t)
    1484             :   {
    1485        3850 :     case t_ELL_Q: return lfunellQ(e);
    1486         203 :     case t_ELL_NF:return lfunellnf(e);
    1487             :   }
    1488           0 :   pari_err_TYPE("lfun",e);
    1489             :   return NULL; /*LCOV_EXCL_LINE*/
    1490             : }
    1491             : 
    1492             : static GEN
    1493         140 : ellsympow_gamma(long m)
    1494             : {
    1495         140 :   GEN V = cgetg(m+2, t_VEC);
    1496         140 :   long i = 1, j;
    1497         140 :   if (!odd(m)) gel(V, i++) = stoi(-2*(m>>2));
    1498         364 :   for (j = (m+1)>>1; j > 0; i+=2, j--)
    1499             :   {
    1500         224 :     gel(V,i)   = stoi(1-j);
    1501         224 :     gel(V,i+1) = stoi(1-j+1);
    1502             :   }
    1503         140 :   return V;
    1504             : }
    1505             : 
    1506             : static GEN
    1507       86591 : ellsympow_trace(GEN p, GEN t, long m)
    1508             : {
    1509       86591 :   long k, n = m >> 1;
    1510       86591 :   GEN tp = gpowers0(sqri(t), n, odd(m)? t: NULL);
    1511       86866 :   GEN pp = gen_1, b = gen_1, r = gel(tp,n+1);
    1512      245264 :   for(k=1; k<=n; k++)
    1513             :   {
    1514             :     GEN s;
    1515      158853 :     pp = mulii(pp, p);
    1516      158510 :     b  = diviuexact(muliu(b, (m-(2*k-1))*(m-(2*k-2))), k*(m-(k-1)));
    1517      157737 :     s = mulii(mulii(b, gel(tp,1+n-k)), pp);
    1518      158152 :     r = odd(k) ? subii(r, s): addii(r, s);
    1519             :   }
    1520       86411 :   return r;
    1521             : }
    1522             : 
    1523             : static GEN
    1524        3129 : ellsympow_abelian(GEN p, GEN ap, long m, long o)
    1525             : {
    1526        3129 :   pari_sp av = avma;
    1527        3129 :   long i, M, n = (m+1)>>1;
    1528             :   GEN pk, tv, pn, pm, F, v;
    1529        3129 :   if (!odd(o))
    1530             :   {
    1531           0 :     if (odd(m)) return pol_1(0);
    1532           0 :     M = m >> 1; o >>= 1;
    1533             :   }
    1534             :   else
    1535        3129 :     M = m * ((o+1) >> 1);
    1536        3129 :   pk = gpowers(p,n); pn = gel(pk,n+1);
    1537        3129 :   tv = cgetg(m+2,t_VEC);
    1538        3129 :   gel(tv, 1) = gen_2;
    1539        3129 :   gel(tv, 2) = ap;
    1540       10668 :   for (i = 3; i <= m+1; i++)
    1541        7539 :     gel(tv,i) = subii(mulii(ap,gel(tv,i-1)), mulii(p,gel(tv,i-2)));
    1542        3129 :   pm = odd(m)? mulii(gel(pk,n), pn): sqri(pn); /* cheap p^m */
    1543        3129 :   F = deg2pol_shallow(pm, gen_0, gen_1, 0);
    1544        3129 :   v = odd(m) ? pol_1(0): deg1pol_shallow(negi(pn), gen_1, 0);
    1545        9450 :   for (i = M % o; i < n; i += o) /* o | m-2*i */
    1546             :   {
    1547        6321 :     gel(F,3) = negi(mulii(gel(tv,m-2*i+1), gel(pk,i+1)));
    1548        6321 :     v = ZX_mul(v, F);
    1549             :   }
    1550        3129 :   return gerepilecopy(av, v);
    1551             : }
    1552             : 
    1553             : static GEN
    1554       89811 : ellsympow(GEN E, ulong m, GEN p, long n)
    1555             : {
    1556       89811 :   pari_sp av = avma;
    1557       89811 :   GEN ap = ellap(E, p);
    1558       89633 :   if (n <= 2)
    1559             :   {
    1560       86534 :     GEN t = ellsympow_trace(p, ap, m);
    1561       86414 :     return deg1pol_shallow(t, gen_1, 0);
    1562             :   }
    1563             :   else
    1564        3099 :     return gerepileupto(av, RgXn_inv_i(ellsympow_abelian(p, ap, m, 1), n));
    1565             : }
    1566             : 
    1567             : GEN
    1568        5656 : direllsympow_worker(GEN P, ulong X, GEN E, ulong m)
    1569             : {
    1570        5656 :   pari_sp av = avma;
    1571        5656 :   long i, l = lg(P);
    1572        5656 :   GEN W = cgetg(l, t_VEC);
    1573       95454 :   for(i = 1; i < l; i++)
    1574             :   {
    1575       89798 :     ulong p = uel(P,i);
    1576       89798 :     long d = ulogint(X, p) + 1; /* minimal d such that p^d > X */
    1577       89809 :     gel(W,i) = ellsympow(E, m, utoi(uel(P,i)), d);
    1578             :   }
    1579        5656 :   return gerepilecopy(av, mkvec2(P,W));
    1580             : }
    1581             : 
    1582             : static GEN
    1583          56 : eulerf_bad(GEN bad, GEN p)
    1584             : {
    1585          56 :   long i, l = lg(bad);
    1586         112 :   for (i = 1; i < l; i++)
    1587          56 :     if (equalii(gmael(bad,i,1), p))
    1588           0 :       return gmael(bad,i,2);
    1589          56 :   return NULL;
    1590             : }
    1591             : 
    1592             : static GEN
    1593         343 : vecan_ellsympow(GEN an, long n)
    1594             : {
    1595         343 :   GEN nn = utoi(n), crvm = gel(an,1), bad = gel(an,2);
    1596         343 :   GEN worker = snm_closure(is_entry("_direllsympow_worker"), crvm);
    1597         343 :   return pardireuler(worker, gen_2, nn, nn, bad);
    1598             : }
    1599             : 
    1600             : static GEN
    1601          28 : eulerf_ellsympow(GEN an, GEN p)
    1602             : {
    1603          28 :   GEN crvm = gel(an,1), bad = gel(an,2), E = gel(crvm,1);
    1604          28 :   GEN f = eulerf_bad(bad, p);
    1605          28 :   if (f) return f;
    1606          28 :   retmkrfrac(gen_1,ellsympow_abelian(p, ellap(E, p), itos(gel(crvm,2)), 1));
    1607             : }
    1608             : 
    1609             : static long
    1610         196 : ellsympow_betam(long o, long m)
    1611             : {
    1612         196 :   const long c3[]={3, -1, 1};
    1613         196 :   const long c12[]={6, -2, 2, 0, 4, -4};
    1614         196 :   const long c24[]={12, -2, -4, 6, 4, -10};
    1615         196 :   if (!odd(o) && odd(m)) return 0;
    1616         161 :   switch(o)
    1617             :   {
    1618           0 :     case 1:  return m+1;
    1619          14 :     case 2:  return m+1;
    1620          84 :     case 3:  case 6: return (m+c3[m%3])/3;
    1621           0 :     case 4:  return m%4 == 0 ? (m+2)/2: m/2;
    1622          21 :     case 8:  return m%4 == 0 ? (m+4)/4: (m-2)/4;
    1623          35 :     case 12: return (m+c12[(m%12)/2])/6;
    1624           7 :     case 24: return (m+c24[(m%12)/2])/12;
    1625             :   }
    1626           0 :   return 0;
    1627             : }
    1628             : 
    1629             : static long
    1630          98 : ellsympow_epsm(long o, long m) { return m + 1 - ellsympow_betam(o, m); }
    1631             : 
    1632             : static GEN
    1633          98 : ellsympow_multred(GEN E, GEN p, long m, long vN, long *cnd, long *w)
    1634             : {
    1635          98 :   if (vN == 1 || !odd(m))
    1636             :   {
    1637          98 :     GEN s = (odd(m) && signe(ellap(E,p)) < 0)? gen_1: gen_m1;
    1638          98 :     *cnd = m;
    1639          98 :     *w = odd(m)? ellrootno(E, p): 1;
    1640          98 :     return deg1pol_shallow(s, gen_1, 0);
    1641             :   }
    1642             :   else
    1643             :   {
    1644           0 :     *cnd = equaliu(p,2)? ((m+1)>>1) * vN: m+1;
    1645           0 :     *w = (m & 3) == 1? ellrootno(E, p): 1;
    1646           0 :     return pol_1(0);
    1647             :   }
    1648             : }
    1649             : 
    1650             : static GEN
    1651          98 : ellsympow_nonabelian(GEN p, long m, long bet)
    1652             : {
    1653          98 :  GEN q = powiu(p, m >> 1), q2 = sqri(q), F;
    1654          98 :  if (odd(m))
    1655             :  {
    1656          35 :    q2 = mulii(q2, p); /* p^m */
    1657          35 :    return gpowgs(deg2pol_shallow(q2, gen_0, gen_1, 0), bet>>1);
    1658             :  }
    1659          63 :  togglesign_safe(&q2);
    1660          63 :  F = gpowgs(deg2pol_shallow(q2, gen_0, gen_1, 0), bet>>1);
    1661          63 :  if (!odd(bet)) return F;
    1662          28 :  if (m%4 != 2) togglesign_safe(&q);
    1663          28 :  return gmul(F, deg1pol_shallow(q, gen_1, 0));
    1664             : }
    1665             : 
    1666             : static long
    1667           0 : safe_Z_pvalrem(GEN n, GEN p, GEN *pr)
    1668           0 : { return signe(n)==0? -1: Z_pvalrem(n, p, pr); }
    1669             : 
    1670             : static GEN
    1671           0 : c4c6_ap(GEN c4, GEN c6, GEN p)
    1672             : {
    1673           0 :   GEN N = Fp_ellcard(Fp_muls(c4, -27, p), Fp_muls(c6, -54, p), p);
    1674           0 :   return subii(addiu(p, 1), N);
    1675             : }
    1676             : 
    1677             : static GEN
    1678           0 : ellsympow_abelian_twist(GEN E, GEN p, long m, long o)
    1679             : {
    1680           0 :   GEN ap, c4t, c6t, c4 = ell_get_c4(E), c6 = ell_get_c6(E);
    1681           0 :   long v4 = safe_Z_pvalrem(c4, p, &c4t);
    1682           0 :   long v6 = safe_Z_pvalrem(c6, p, &c6t);
    1683           0 :   if (v6>=0 && (v4==-1 || 3*v4>=2*v6)) c6 = c6t;
    1684           0 :   if (v4>=0 && (v6==-1 || 3*v4<=2*v6)) c4 = c4t;
    1685           0 :   ap = c4c6_ap(c4, c6, p);
    1686           0 :   return ellsympow_abelian(p, ap, m, o);
    1687             : }
    1688             : 
    1689             : static GEN
    1690           0 : ellsympow_goodred(GEN E, GEN p, long m, long *cnd, long *w)
    1691             : {
    1692           0 :   long o = 12/cgcd(12, Z_pval(ell_get_disc(E), p));
    1693           0 :   long bet = ellsympow_betam(o, m);
    1694           0 :   long eps = m + 1 - bet;
    1695           0 :   *w = odd(m) && odd(eps>>1) ? ellrootno(E,p): 1;
    1696           0 :   *cnd = eps;
    1697           0 :   if (umodiu(p, o) == 1)
    1698           0 :     return ellsympow_abelian_twist(E, p, m, o);
    1699             :   else
    1700           0 :     return ellsympow_nonabelian(p, m, bet);
    1701             : }
    1702             : 
    1703             : static long
    1704          70 : ellsympow_inertia3(GEN E, long vN)
    1705             : {
    1706          70 :   long vD = Z_lval(ell_get_disc(E), 3);
    1707          70 :   if (vN==2) return vD%2==0 ? 2: 4;
    1708          70 :   if (vN==4) return vD%4==0 ? 3: 6;
    1709          70 :   if (vN==3 || vN==5) return 12;
    1710           0 :   return 0;
    1711             : }
    1712             : 
    1713             : static long
    1714          70 : ellsympow_deltam3(long o, long m, long vN)
    1715             : {
    1716          70 :   if (o==3 || o==6) return ellsympow_epsm(3, m);
    1717          70 :   if (o==12 && vN ==3) return (ellsympow_epsm(3, m))/2;
    1718           0 :   if (o==12 && vN ==5) return (ellsympow_epsm(3, m))*3/2;
    1719           0 :   return 0;
    1720             : }
    1721             : 
    1722             : static long
    1723           0 : ellsympow_isabelian3(GEN E)
    1724             : {
    1725           0 :   ulong c4 = umodiu(ell_get_c4(E),81), c6 = umodiu(ell_get_c6(E), 243);
    1726           0 :   return (c4 == 27 || (c4%27==9 && (c6==108 || c6==135)));
    1727             : }
    1728             : 
    1729             : static long
    1730          35 : ellsympow_rootno3(GEN E, GEN p, long o, long m)
    1731             : {
    1732          35 :   const long  w6p[]={1,-1,-1,-1,1,1};
    1733          35 :   const long  w6n[]={-1,1,-1,1,-1,1};
    1734          35 :   const long w12p[]={1,1,-1,1,1,1};
    1735          35 :   const long w12n[]={-1,-1,-1,-1,-1,1};
    1736          35 :   long w = ellrootno(E, p), mm = (m%12)>>1;
    1737          35 :   switch(o)
    1738             :   {
    1739           0 :     case 2: return m%4== 1 ? -1: 1;
    1740           0 :     case 6:  return w == 1 ? w6p[mm]: w6n[mm];
    1741          35 :     case 12: return w == 1 ? w12p[mm]: w12n[mm];
    1742           0 :     default: return 1;
    1743             :   }
    1744             : }
    1745             : 
    1746             : static GEN
    1747          70 : ellsympow_goodred3(GEN E, GEN F, GEN p, long m, long vN, long *cnd, long *w)
    1748             : {
    1749          70 :   long o = ellsympow_inertia3(E, vN);
    1750          70 :   long bet = ellsympow_betam(o, m);
    1751          70 :   *cnd = m + 1 - bet + ellsympow_deltam3(o, m, vN);
    1752          70 :   *w = odd(m)? ellsympow_rootno3(E, p, o, m): 1;
    1753          70 :   if (o==1 || o==2)
    1754           0 :     return ellsympow_abelian(p, ellap(F, p), m, o);
    1755          70 :   if ((o==3 || o==6) && ellsympow_isabelian3(F))
    1756           0 :     return ellsympow_abelian(p, p, m, o);
    1757             :   else
    1758          70 :     return ellsympow_nonabelian(p, m, bet);
    1759             : }
    1760             : 
    1761             : static long
    1762          28 : ellsympow_inertia2(GEN F, long vN)
    1763             : {
    1764          28 :   long vM = itos(gel(elllocalred(F, gen_2),1));
    1765          28 :   GEN c6 = ell_get_c6(F);
    1766          28 :   long v6 = signe(c6) ? vali(c6): 24;
    1767          28 :   if (vM==0) return vN==0 ? 1: 2;
    1768          28 :   if (vM==2) return vN==2 ? 3: 6;
    1769          14 :   if (vM==5) return 8;
    1770           7 :   if (vM==8) return v6>=9? 8: 4;
    1771           7 :   if (vM==3 || vN==7) return 24;
    1772           0 :   return 0;
    1773             : }
    1774             : 
    1775             : static long
    1776          28 : ellsympow_deltam2(long o, long m, long vN)
    1777             : {
    1778          28 :   if ((o==2 || o==6) && vN==4) return ellsympow_epsm(2, m);
    1779          28 :   if ((o==2 || o==6) && vN==6) return 2*ellsympow_epsm(2, m);
    1780          28 :   if (o==4) return 2*ellsympow_epsm(4, m)+ellsympow_epsm(2, m);
    1781          28 :   if (o==8 && vN==5) return ellsympow_epsm(8, m)+ellsympow_epsm(2, m)/2;
    1782          21 :   if (o==8 && vN==6) return ellsympow_epsm(8, m)+ellsympow_epsm(2, m);
    1783          21 :   if (o==8 && vN==8) return ellsympow_epsm(8, m)+ellsympow_epsm(4, m)+ellsympow_epsm(2, m);
    1784          21 :   if (o==24 && vN==3) return (2*ellsympow_epsm(8, m)+ellsympow_epsm(2, m))/6;
    1785          14 :   if (o==24 && vN==4) return (ellsympow_epsm(8, m)+ellsympow_epsm(2, m)*2)/3;
    1786          14 :   if (o==24 && vN==6) return (ellsympow_epsm(8, m)+ellsympow_epsm(2, m)*5)/3;
    1787          14 :   if (o==24 && vN==7) return (ellsympow_epsm(8, m)*10+ellsympow_epsm(2, m)*5)/6;
    1788          14 :   return 0;
    1789             : }
    1790             : 
    1791             : static long
    1792           0 : ellsympow_isabelian2(GEN F)
    1793           0 : { return umodi2n(ell_get_c4(F),7) == 96; }
    1794             : 
    1795             : static long
    1796           0 : ellsympow_rootno2(GEN E, long vN, long m, long bet)
    1797             : {
    1798           0 :   long eps2 = (m + 1 - bet)>>1;
    1799           0 :   long eta = odd(vN) && m%8==3 ? -1 : 1;
    1800           0 :   long w2 = odd(eps2) ? ellrootno(E, gen_2): 1;
    1801           0 :   return eta == w2 ? 1 : -1;
    1802             : }
    1803             : 
    1804             : static GEN
    1805          28 : ellsympow_goodred2(GEN E, GEN F, GEN p, long m, long vN, long *cnd, long *w)
    1806             : {
    1807          28 :   long o = ellsympow_inertia2(F, vN);
    1808          28 :   long bet = ellsympow_betam(o, m);
    1809          28 :   *cnd = m + 1 - bet + ellsympow_deltam2(o, m, vN);
    1810          28 :   *w = odd(m) ? ellsympow_rootno2(E, vN, m, bet): 1;
    1811          28 :   if (o==1 || o==2)
    1812           0 :     return ellsympow_abelian(p, ellap(F, p), m, o);
    1813          28 :   if (o==4 && ellsympow_isabelian2(F))
    1814           0 :     return ellsympow_abelian(p, p, m, o);
    1815             :   else
    1816          28 :     return ellsympow_nonabelian(p, m, bet);
    1817             : }
    1818             : 
    1819             : static GEN
    1820         189 : ellminimaldotwist(GEN E, GEN *pD)
    1821             : {
    1822         189 :   GEN D = ellminimaltwistcond(E), Et = elltwist(E, D), Etmin;
    1823         189 :   if (pD) *pD = D;
    1824         189 :   Etmin = ellminimalmodel(Et, NULL);
    1825         189 :   obj_free(Et); return Etmin;
    1826             : }
    1827             : 
    1828             : /* Based on
    1829             : Symmetric powers of elliptic curve L-functions,
    1830             : Phil Martin and Mark Watkins, ANTS VII
    1831             : <http://magma.maths.usyd.edu.au/users/watkins/papers/antsVII.pdf>
    1832             : with thanks to Mark Watkins. BA20180402
    1833             : */
    1834             : static GEN
    1835         140 : lfunellsympow(GEN e, ulong m)
    1836             : {
    1837         140 :   pari_sp av = avma;
    1838             :   GEN B, N, Nfa, pr, ex, ld, bad, ejd, et, pole;
    1839         140 :   long i, l, mero, w = (m&7)==1 || (m&7)==3 ? -1: 1;
    1840         140 :   checkell_Q(e);
    1841         140 :   e = ellminimalmodel(e, NULL);
    1842         140 :   ejd = Q_denom(ell_get_j(e));
    1843         140 :   mero = m==0 || (m%4==0 && ellQ_get_CM(e)<0);
    1844         140 :   ellQ_get_Nfa(e, &N, &Nfa);
    1845         140 :   pr = gel(Nfa,1);
    1846         140 :   ex = gel(Nfa,2); l = lg(pr);
    1847         140 :   if (ugcd(umodiu(N,6), 6) == 1)
    1848          21 :     et = NULL;
    1849             :   else
    1850         119 :     et = ellminimaldotwist(e, NULL);
    1851         140 :   B = gen_1;
    1852         140 :   bad = cgetg(l, t_VEC);
    1853         336 :   for (i=1; i<l; i++)
    1854             :   {
    1855         196 :     long vN = itos(gel(ex,i));
    1856         196 :     GEN p = gel(pr,i), eul;
    1857             :     long cnd, wp;
    1858         196 :     if (dvdii(ejd, p))
    1859          98 :       eul = ellsympow_multred(e, p, m, vN, &cnd, &wp);
    1860          98 :     else if (equaliu(p, 2))
    1861          28 :       eul = ellsympow_goodred2(e, et, p, m, vN, &cnd, &wp);
    1862          70 :     else if (equaliu(p, 3))
    1863          70 :       eul = ellsympow_goodred3(e, et, p, m, vN, &cnd, &wp);
    1864             :     else
    1865           0 :       eul = ellsympow_goodred(e, p, m, &cnd, &wp);
    1866         196 :     gel(bad, i) = mkvec2(p, ginv(eul));
    1867         196 :     B = mulii(B, powiu(p,cnd));
    1868         196 :     w *= wp;
    1869             :   }
    1870         140 :   pole = mero ? mkvec(mkvec2(stoi(1+(m>>1)),gen_0)): NULL;
    1871         280 :   ld = mkvecn(mero? 7: 6, tag(mkvec2(mkvec2(e,utoi(m)),bad), t_LFUN_SYMPOW_ELL),
    1872         140 :         gen_0, ellsympow_gamma(m), stoi(m+1), B, stoi(w), pole);
    1873         140 :   if (et) obj_free(et);
    1874         140 :   return gerepilecopy(av, ld);
    1875             : }
    1876             : 
    1877             : GEN
    1878          70 : lfunsympow(GEN ldata, ulong m)
    1879             : {
    1880          70 :   ldata = lfunmisc_to_ldata_shallow(ldata);
    1881          70 :   if (ldata_get_type(ldata) != t_LFUN_ELL)
    1882           0 :     pari_err_IMPL("lfunsympow");
    1883          70 :   return lfunellsympow(gel(ldata_get_an(ldata), 2), m);
    1884             : }
    1885             : 
    1886             : static GEN
    1887          28 : lfunmfspec_i(GEN lmisc, long bit)
    1888             : {
    1889             :   GEN linit, ldataf, v, ve, vo, om, op, B, dom;
    1890             :   long k, k2, j;
    1891             : 
    1892          28 :   ldataf = lfunmisc_to_ldata_shallow(lmisc);
    1893          28 :   if (!gequal(ldata_get_gammavec(ldataf), mkvec2(gen_0,gen_1)))
    1894           0 :     pari_err_TYPE("lfunmfspec", lmisc);
    1895          28 :   k = gtos(ldata_get_k(ldataf));
    1896          28 :   if (k == 1) return mkvec2(cgetg(1, t_VEC), gen_1);
    1897          21 :   dom = mkvec3(dbltor(k/2.), dbltor((k-2)/2.), gen_0);
    1898          21 :   if (is_linit(lmisc) && linit_get_type(lmisc) == t_LDESC_INIT
    1899           0 :       && sdomain_isincl((double)k, dom, lfun_get_dom(linit_get_tech(lmisc))))
    1900           0 :     linit = lmisc;
    1901             :   else
    1902          21 :     linit = lfuninit(ldataf, dom, 0, bit);
    1903          21 :   B = int2n(bit/4);
    1904          21 :   v = cgetg(k, t_VEC);
    1905         168 :   for (j = 1; j < k; j++) gel(v,j) = lfunlambda(linit, utoi(j), bit);
    1906          21 :   om = gel(v,1);
    1907          21 :   if (odd(k)) return mkvec2(bestappr(gdiv(v, om), B), om);
    1908             : 
    1909           7 :   k2 = k/2;
    1910           7 :   ve = cgetg(k2, t_VEC);
    1911           7 :   vo = cgetg(k2+1, t_VEC);
    1912           7 :   gel(vo,1) = om;
    1913          42 :   for (j = 1; j < k2; j++)
    1914             :   {
    1915          35 :     gel(ve,j) = gel(v,2*j);
    1916          35 :     gel(vo,j+1) = gel(v,2*j+1);
    1917             :   }
    1918           7 :   if (k2 == 1) { om = gen_1;    op = gel(v,1); }
    1919           7 :   else         { om = gel(v,2); op = gel(v,3); }
    1920           7 :   if (maxss(gexpo(imag_i(om)), gexpo(imag_i(op))) > -bit/2)
    1921           0 :     pari_err_TYPE("lfunmfspec", lmisc);
    1922           7 :   ve = gdiv(ve, om);
    1923           7 :   vo = gdiv(vo, op);
    1924           7 :   return mkvec4(bestappr(ve,B), bestappr(vo,B), om, op);
    1925             : }
    1926             : GEN
    1927          28 : lfunmfspec(GEN lmisc, long bit)
    1928             : {
    1929          28 :   pari_sp av = avma;
    1930          28 :   return gerepilecopy(av, lfunmfspec_i(lmisc, bit));
    1931             : }
    1932             : 
    1933             : static long
    1934          28 : ellsymsq_bad2(GEN c4, GEN c6, long e)
    1935             : {
    1936          28 :   switch (e)
    1937             :   {
    1938          14 :     case 2: return 1;
    1939           7 :     case 3: return 0;
    1940           7 :     case 5: return 0;
    1941           0 :     case 7: return 0;
    1942           0 :     case 8:
    1943           0 :       if (!umodi2n(c6,9)) return 0;
    1944           0 :       return umodi2n(c4,7)==32 ? 1 : -1;
    1945           0 :     default: return 0;
    1946             :   }
    1947             : }
    1948             : static long
    1949          14 : ellsymsq_bad3(GEN c4, GEN c6, long e)
    1950             : {
    1951             :   long c6_243, c4_81;
    1952          14 :   switch (e)
    1953             :   {
    1954           0 :     case 2: return 1;
    1955          14 :     case 3: return 0;
    1956           0 :     case 5: return 0;
    1957           0 :     case 4:
    1958           0 :       c4_81 = umodiu(c4,81);
    1959           0 :       if (c4_81 == 27) return -1;
    1960           0 :       if (c4_81%27 != 9) return 1;
    1961           0 :       c6_243 = umodiu(c6,243);
    1962           0 :       return (c6_243==108 || c6_243==135)? -1: 1;
    1963           0 :     default: return 0;
    1964             :   }
    1965             : }
    1966             : static int
    1967           0 : c4c6_testp(GEN c4, GEN c6, GEN p)
    1968           0 : { GEN p2 = sqri(p); return (dvdii(c6,p2) && !dvdii(c4,p2)); }
    1969             : /* assume e = v_p(N) >= 2 */
    1970             : static long
    1971          42 : ellsymsq_badp(GEN c4, GEN c6, GEN p, long e)
    1972             : {
    1973          42 :   if (absequaliu(p, 2)) return ellsymsq_bad2(c4, c6, e);
    1974          14 :   if (absequaliu(p, 3)) return ellsymsq_bad3(c4, c6, e);
    1975           0 :   switch(umodiu(p, 12UL))
    1976             :   {
    1977           0 :     case 1: return -1;
    1978           0 :     case 5: return c4c6_testp(c4,c6,p)? -1: 1;
    1979           0 :     case 7: return c4c6_testp(c4,c6,p)?  1:-1;
    1980           0 :     default:return 1; /* p%12 = 11 */
    1981             :   }
    1982             : }
    1983             : static GEN
    1984          70 : lfunellsymsqmintwist(GEN e)
    1985             : {
    1986          70 :   pari_sp av = avma;
    1987             :   GEN N, Nfa, P, E, V, c4, c6, ld;
    1988             :   long i, l, k;
    1989          70 :   checkell_Q(e);
    1990          70 :   e = ellminimalmodel(e, NULL);
    1991          70 :   ellQ_get_Nfa(e, &N, &Nfa);
    1992          70 :   c4 = ell_get_c4(e);
    1993          70 :   c6 = ell_get_c6(e);
    1994          70 :   P = gel(Nfa,1); l = lg(P);
    1995          70 :   E = gel(Nfa,2);
    1996          70 :   V = cgetg(l, t_VEC);
    1997         196 :   for (i=k=1; i<l; i++)
    1998             :   {
    1999         126 :     GEN p = gel(P,i);
    2000         126 :     long a, e = itos(gel(E,i));
    2001         126 :     if (e == 1) continue;
    2002          42 :     a = ellsymsq_badp(c4, c6, p, e);
    2003          42 :     gel(V,k++) = mkvec2(p, stoi(a));
    2004             :   }
    2005          70 :   setlg(V, k);
    2006          70 :   ld = lfunellsympow(e, 2);
    2007          70 :   return gerepilecopy(av, mkvec2(ld, V));
    2008             : }
    2009             : 
    2010             : static GEN
    2011          70 : mfpeters(GEN ldata2, GEN fudge, GEN N, long k, long bitprec)
    2012             : {
    2013          70 :   GEN t, L = real_i(lfun(ldata2, stoi(k), bitprec));
    2014          70 :   long prec = nbits2prec(bitprec);
    2015          70 :   t = powrs(mppi(prec), k+1); shiftr_inplace(t, 2*k-1); /* Pi/2 * (4Pi)^k */
    2016          70 :   return gmul(gdiv(gmul(mulii(N,mpfact(k-1)), fudge), t), L);
    2017             : }
    2018             : 
    2019             : /* Assume E to be twist-minimal */
    2020             : static GEN
    2021          70 : lfunellmfpetersmintwist(GEN E, long bitprec)
    2022             : {
    2023          70 :   pari_sp av = avma;
    2024          70 :   GEN symsq, veceuler, N = ellQ_get_N(E), fudge = gen_1;
    2025          70 :   long j, k = 2;
    2026          70 :   symsq = lfunellsymsqmintwist(E);
    2027          70 :   veceuler = gel(symsq,2);
    2028         112 :   for (j = 1; j < lg(veceuler); j++)
    2029             :   {
    2030          42 :     GEN v = gel(veceuler,j), p = gel(v,1), q = powis(p,1-k);
    2031          42 :     long s = signe(gel(v,2));
    2032          42 :     if (s) fudge = gmul(fudge, s==1 ? gaddsg(1, q): gsubsg(1, q));
    2033             :   }
    2034          70 :   return gerepileupto(av, mfpeters(gel(symsq,1),fudge,N,k,bitprec));
    2035             : }
    2036             : 
    2037             : /* From Christophe Delaunay, http://delaunay.perso.math.cnrs.fr/these.pdf */
    2038             : static GEN
    2039          70 : elldiscfix(GEN E, GEN Et, GEN D)
    2040             : {
    2041          70 :   GEN N = ellQ_get_N(E), Nt = ellQ_get_N(Et);
    2042          70 :   GEN P = gel(absZ_factor(D), 1);
    2043          70 :   GEN f = gen_1;
    2044          70 :   long i, l = lg(P);
    2045         133 :   for (i=1; i < l; i++)
    2046             :   {
    2047          63 :     GEN r, p = gel(P,i);
    2048          63 :     long v = Z_pval(N, p), vt = Z_pval(Nt, p);
    2049          63 :     if (v <= vt) continue;
    2050             :     /* v > vt */
    2051          49 :     if (absequaliu(p, 2))
    2052             :     {
    2053          28 :       if (vt == 0 && v >= 4)
    2054           0 :         r = shifti(subsi(9, sqri(ellap(Et, p))), v-3);  /* 9=(2+1)^2 */
    2055          28 :       else if (vt == 1)
    2056           7 :         r = gmul2n(utoipos(3), v-3);  /* not in Z if v=2 */
    2057          21 :       else if (vt >= 2)
    2058          21 :         r = int2n(v-vt);
    2059             :       else
    2060           0 :         r = gen_1; /* vt = 0, 1 <= v <= 3 */
    2061             :     }
    2062          21 :     else if (vt >= 1)
    2063          14 :       r = gdiv(subiu(sqri(p), 1), p);
    2064             :     else
    2065           7 :       r = gdiv(mulii(subiu(p, 1), subii(sqri(addiu(p, 1)), sqri(ellap(Et, p)))), p);
    2066          49 :     f = gmul(f, r);
    2067             :   }
    2068          70 :   return f;
    2069             : }
    2070             : 
    2071             : GEN
    2072          70 : lfunellmfpeters(GEN E, long bitprec)
    2073             : {
    2074          70 :   pari_sp ltop = avma;
    2075          70 :   GEN D, Et = ellminimaldotwist(E, &D);
    2076          70 :   GEN nor = lfunellmfpetersmintwist(Et, bitprec);
    2077          70 :   GEN nor2 = gmul(nor, elldiscfix(E, Et, D));
    2078          70 :   obj_free(Et); return gerepileupto(ltop, nor2);
    2079             : }
    2080             : 
    2081             : /*************************************************************/
    2082             : /*               Genus 2 curves                              */
    2083             : /*************************************************************/
    2084             : 
    2085             : static void
    2086      233611 : Flv_diffnext(GEN d, ulong p)
    2087             : {
    2088      233611 :   long j, n = lg(d)-1;
    2089     1635277 :   for(j = n; j>=2; j--)
    2090     1401666 :     uel(d,j) = Fl_add(uel(d,j), uel(d,j-1), p);
    2091      233611 : }
    2092             : 
    2093             : static GEN
    2094        1995 : Flx_difftable(GEN P, ulong p)
    2095             : {
    2096        1995 :   long i, n = degpol(P);
    2097        1995 :   GEN V = cgetg(n+2, t_VECSMALL);
    2098        1995 :   uel(V, n+1) = Flx_constant(P);
    2099       13965 :   for(i = n; i >= 1; i--)
    2100             :   {
    2101       11970 :     P = Flx_diff1(P, p);
    2102       11970 :     uel(V, i) = Flx_constant(P);
    2103             :   }
    2104        1995 :   return V;
    2105             : }
    2106             : 
    2107             : static long
    2108        1995 : Flx_genus2trace_naive(GEN H, ulong p)
    2109             : {
    2110        1995 :   pari_sp av = avma;
    2111             :   ulong i, j;
    2112        1995 :   long a, n = degpol(H);
    2113        1995 :   GEN k = const_vecsmall(p, -1), d;
    2114        1995 :   k[1] = 0;
    2115      117803 :   for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p))
    2116      115808 :     k[j+1] = 1;
    2117        1995 :   a = n == 5 ? 0: k[1+Flx_lead(H)];
    2118        1995 :   d = Flx_difftable(H, p);
    2119      235606 :   for (i=0; i < p; i++)
    2120             :   {
    2121      233611 :     a += k[1+uel(d,n+1)];
    2122      233611 :     Flv_diffnext(d, p);
    2123             :   }
    2124        1995 :   set_avma(av);
    2125        1995 :   return a;
    2126             : }
    2127             : 
    2128             : static GEN
    2129        2156 : dirgenus2(GEN Q, GEN p, long n)
    2130             : {
    2131        2156 :   pari_sp av = avma;
    2132             :   GEN f;
    2133        2156 :   if (n > 2)
    2134         161 :     f = RgX_recip(hyperellcharpoly(gmul(Q,gmodulo(gen_1, p))));
    2135             :   else
    2136             :   {
    2137        1995 :     ulong pp = itou(p);
    2138        1995 :     GEN Qp = ZX_to_Flx(Q, pp);
    2139        1995 :     long t = Flx_genus2trace_naive(Qp, pp);
    2140        1995 :     f = deg1pol_shallow(stoi(t), gen_1, 0);
    2141             :   }
    2142        2156 :   return gerepileupto(av, RgXn_inv_i(f, n));
    2143             : }
    2144             : 
    2145             : GEN
    2146         875 : dirgenus2_worker(GEN P, ulong X, GEN Q)
    2147             : {
    2148         875 :   pari_sp av = avma;
    2149         875 :   long i, l = lg(P);
    2150         875 :   GEN V = cgetg(l, t_VEC);
    2151        3031 :   for(i = 1; i < l; i++)
    2152             :   {
    2153        2156 :     ulong p = uel(P,i);
    2154        2156 :     long d = ulogint(X, p) + 1; /* minimal d such that p^d > X */
    2155        2156 :     gel(V,i) = dirgenus2(Q, utoi(uel(P,i)), d);
    2156             :   }
    2157         875 :   return gerepilecopy(av, mkvec2(P,V));
    2158             : }
    2159             : 
    2160             : static GEN
    2161         196 : vecan_genus2(GEN an, long L)
    2162             : {
    2163         196 :   GEN Q = gel(an,1), bad = gel(an, 2);
    2164         196 :   GEN worker = snm_closure(is_entry("_dirgenus2_worker"), mkvec(Q));
    2165         196 :   return pardireuler(worker, gen_2, stoi(L), NULL, bad);
    2166             : }
    2167             : 
    2168             : static GEN
    2169           0 : eulerf_genus2(GEN an, GEN p)
    2170             : {
    2171           0 :   GEN Q = gel(an,1), bad = gel(an, 2);
    2172           0 :   GEN f = eulerf_bad(bad, p);
    2173           0 :   if (f) return f;
    2174           0 :   f = RgX_recip(hyperellcharpoly(gmul(Q,gmodulo(gen_1, p))));
    2175           0 :   return mkrfrac(gen_1,f);
    2176             : }
    2177             : 
    2178             : static GEN
    2179          49 : genus2_redmodel(GEN P, GEN p)
    2180             : {
    2181          49 :   GEN M = FpX_factor(P, p);
    2182          49 :   GEN F = gel(M,1), E = gel(M,2);
    2183          49 :   long i, k, r = lg(F);
    2184          49 :   GEN U = scalarpol(leading_coeff(P), varn(P));
    2185          49 :   GEN G = cgetg(r, t_COL);
    2186         161 :   for (i=1, k=0; i<r; i++)
    2187             :   {
    2188         112 :     if (E[i]>1)
    2189          56 :       gel(G,++k) = gel(F,i);
    2190         112 :     if (odd(E[i]))
    2191          77 :       U = FpX_mul(U, gel(F,i), p);
    2192             :   }
    2193          49 :   setlg(G,++k);
    2194          49 :   return mkvec2(G,U);
    2195             : }
    2196             : 
    2197             : static GEN
    2198         308 : oneminusxd(long d)
    2199             : {
    2200         308 :   return gsub(gen_1, pol_xn(d, 0));
    2201             : }
    2202             : 
    2203             : static GEN
    2204          21 : ellfromeqncharpoly(GEN P, GEN Q, GEN p)
    2205             : {
    2206             :   long v;
    2207             :   GEN E, F, t, y;
    2208          21 :   v = fetch_var();
    2209          21 :   y = pol_x(v);
    2210          21 :   F = gsub(gadd(ZX_sqr(y), gmul(y, Q)), P);
    2211          21 :   E = ellinit(ellfromeqn(F), p, DEFAULTPREC);
    2212          21 :   delete_var();
    2213          21 :   t = ellap(E, p);
    2214          21 :   obj_free(E);
    2215          21 :   return mkpoln(3, gen_1, negi(t), p);
    2216             : }
    2217             : 
    2218             : static GEN
    2219           0 : nfellcharpoly(GEN e, GEN T, GEN p)
    2220             : {
    2221             :   GEN nf, E, t;
    2222           0 :   nf = nfinit(mkvec2(T, mkvec(p)), DEFAULTPREC);
    2223           0 :   E = ellinit(e, nf, DEFAULTPREC);
    2224           0 :   if (lg(E)==1) return NULL;
    2225           0 :   t = elleulerf(E, p);
    2226           0 :   obj_free(E);
    2227           0 :   return t;
    2228             : }
    2229             : 
    2230             : static GEN
    2231           0 : genus2_red5(GEN P, GEN T, GEN p)
    2232             : {
    2233           0 :   long vx = varn(P), vy = varn(T);
    2234           0 :   GEN f = shallowcopy(T);
    2235           0 :   setvarn(f, vx);
    2236             :   while(1)
    2237           0 :   {
    2238             :     GEN Pr, R, r, Rs;
    2239           0 :     (void) ZXX_pvalrem(P, p, &Pr);
    2240           0 :     R = FpXQX_roots_mult(Pr, 3, T, p);
    2241           0 :     if (lg(R)==1) return P;
    2242           0 :     r = FpX_center(gel(R,1), p, shifti(p,-1));
    2243           0 :     r = gel(R,1);
    2244           0 :     P = RgX_affine(P, p, r);
    2245           0 :     setvarn(r, vx);
    2246           0 :     f = RgX_Rg_div(gsub(f, r), p);
    2247           0 :     Rs = RgX_rem(RgXY_swap(P, 3, vy), gsub(f, pol_x(vy)));
    2248           0 :     P = RgXY_swap(Rs, 3, vy);
    2249           0 :     (void) ZXX_pvalrem(P, sqri(p), &P);
    2250             :   }
    2251             : }
    2252             : 
    2253             : static GEN
    2254          63 : genus2_type5(GEN P, GEN p)
    2255             : {
    2256             :   GEN E, F, T, a, a2, Q;
    2257             :   long v;
    2258          63 :   (void) ZX_pvalrem(P, p, &F);
    2259          63 :   F = FpX_red(F, p);
    2260          63 :   if (degpol(F) < 1) return NULL;
    2261          63 :   F = FpX_factor(F, p);
    2262          63 :   if (mael(F,2,1) != 3 || degpol(gmael(F,1,1)) != 2) return NULL;
    2263           0 :   T = gmael(F, 1, 1);
    2264           0 :   v = fetch_var_higher();
    2265           0 :   Q = RgV_to_RgX(ZX_digits(P, T), v);
    2266           0 :   Q = genus2_red5(Q, T, p);
    2267           0 :   a = gel(Q,5); a2 = ZX_sqr(a);
    2268           0 :   E = mkvec5(gen_0, gel(Q,4), gen_0, ZX_mul(gel(Q,3),a), ZX_mul(gel(Q,2),a2));
    2269           0 :   delete_var();
    2270           0 :   return nfellcharpoly(E, T, p);
    2271             : }
    2272             : 
    2273             : /* Assume P has semistable reduction at p */
    2274             : static GEN
    2275          49 : genus2_eulerfact_semistable(GEN P, GEN p)
    2276             : {
    2277          49 :   GEN Pp = FpX_red(P, p);
    2278          49 :   GEN GU = genus2_redmodel(Pp, p);
    2279          49 :   long d = 6-degpol(Pp), v = d/2, w = odd(d);
    2280             :   GEN abe, tor;
    2281          49 :   GEN ki, kp = pol_1(0), kq = pol_1(0);
    2282          49 :   GEN F = gel(GU,1), Q = gel(GU,2);
    2283          49 :   long dQ = degpol(Q), lF = lg(F)-1;
    2284             : 
    2285           0 :   abe = dQ >= 5 ? RgX_recip(hyperellcharpoly(gmul(Q,gmodulo(gen_1,p))))
    2286          98 :       : dQ >= 3 ? RgX_recip(ellfromeqncharpoly(Q,gen_0,p))
    2287          49 :                 : pol_1(0);
    2288          42 :   ki = dQ != 0 ? oneminusxd(1)
    2289          56 :               : Fp_issquare(gel(Q,2),p) ? ZX_sqr(oneminusxd(1))
    2290           7 :                                         : oneminusxd(2);
    2291          49 :   if (lF)
    2292             :   {
    2293             :     long i;
    2294          98 :     for(i=1; i <= lF; i++)
    2295             :     {
    2296          56 :       GEN Fi = gel(F, i);
    2297          56 :       long d = degpol(Fi);
    2298          56 :       GEN e = FpX_rem(Q, Fi, p);
    2299          91 :       GEN kqf = lgpol(e)==0 ? oneminusxd(d):
    2300          70 :                 FpXQ_issquare(e, Fi, p) ? ZX_sqr(oneminusxd(d))
    2301          35 :                                         : oneminusxd(2*d);
    2302          56 :       kp = gmul(kp, oneminusxd(d));
    2303          56 :       kq = gmul(kq, kqf);
    2304             :     }
    2305             :   }
    2306          49 :   if (v)
    2307             :   {
    2308           7 :     GEN kqoo = w==1 ? oneminusxd(1):
    2309           0 :                Fp_issquare(leading_coeff(Q), p)? ZX_sqr(oneminusxd(1))
    2310           0 :                                               : oneminusxd(2);
    2311           7 :     kp = gmul(kp, oneminusxd(1));
    2312           7 :     kq = gmul(kq, kqoo);
    2313             :   }
    2314          49 :   tor = RgX_div(ZX_mul(oneminusxd(1), kq), ZX_mul(ki, kp));
    2315          49 :   return ginv( ZX_mul(abe, tor) );
    2316             : }
    2317             : 
    2318             : static GEN
    2319          49 : genus2_eulerfact(GEN P, GEN p)
    2320             : {
    2321          49 :   pari_sp av = avma;
    2322          49 :   GEN W, R = genus2_type5(P, p), E;
    2323          49 :   if (R) return R;
    2324          49 :   W = hyperellextremalmodels(P, 2, p);
    2325          49 :   if (lg(W) < 3) return genus2_eulerfact_semistable(P,p);
    2326           0 :   E =  gmul(genus2_eulerfact_semistable(gel(W,1),p),
    2327           0 :             genus2_eulerfact_semistable(gel(W,2),p));
    2328           0 :   return gerepileupto(av, E);
    2329             : }
    2330             : 
    2331             : static GEN
    2332          28 : F2x_genus2_find_trans(GEN P, GEN Q, GEN F)
    2333             : {
    2334          28 :   pari_sp av = avma;
    2335          28 :   long i, d = F2x_degree(F), v = P[1];
    2336             :   GEN M, C, V;
    2337          28 :   M = cgetg(d+1, t_MAT);
    2338          84 :   for (i=1; i<=d; i++)
    2339             :   {
    2340          56 :     GEN Mi = F2x_rem(F2x_add(F2x_shift(Q,i-1), monomial_F2x(2*i-2,v)), F);
    2341          56 :     gel(M,i) = F2x_to_F2v(Mi, d);
    2342             :   }
    2343          28 :   C = F2x_to_F2v(F2x_rem(P, F), d);
    2344          28 :   V = F2m_F2c_invimage(M, C);
    2345          28 :   return gerepileuptoleaf(av, F2v_to_F2x(V, v));
    2346             : }
    2347             : 
    2348             : static GEN
    2349          35 : F2x_genus2_trans(GEN P, GEN Q, GEN H)
    2350             : {
    2351          35 :   return F2x_add(P,F2x_add(F2x_mul(H,Q), F2x_sqr(H)));
    2352             : }
    2353             : 
    2354             : static GEN
    2355          42 : F2x_genus_redoo(GEN P, GEN Q, long k)
    2356             : {
    2357          42 :   if (F2x_degree(P)==2*k)
    2358             :   {
    2359          14 :     long c = F2x_coeff(P,2*k-1), dQ = F2x_degree(Q);
    2360          14 :     if ((dQ==k-1 && c==1) || (dQ<k-1 && c==0))
    2361           7 :      return F2x_genus2_trans(P, Q, monomial_F2x(k, P[1]));
    2362             :   }
    2363          35 :   return P;
    2364             : }
    2365             : 
    2366             : static GEN
    2367          35 : F2x_pseudodisc(GEN P, GEN Q)
    2368             : {
    2369          35 :   GEN dP = F2x_deriv(P), dQ = F2x_deriv(Q);
    2370          35 :   return F2x_gcd(Q, F2x_add(F2x_mul(P, F2x_sqr(dQ)), F2x_sqr(dP)));
    2371             : }
    2372             : 
    2373             : static GEN
    2374          14 : F2x_genus_red(GEN P, GEN Q)
    2375             : {
    2376             :   long dP, dQ;
    2377             :   GEN F, FF;
    2378          14 :   P = F2x_genus_redoo(P, Q, 3);
    2379          14 :   P = F2x_genus_redoo(P, Q, 2);
    2380          14 :   P = F2x_genus_redoo(P, Q, 1);
    2381          14 :   dP = F2x_degree(P);
    2382          14 :   dQ = F2x_degree(Q);
    2383          14 :   FF = F = F2x_pseudodisc(P,Q);
    2384          35 :   while(F2x_degree(F)>0)
    2385             :   {
    2386          21 :     GEN M = gel(F2x_factor(F),1);
    2387          21 :     long i, l = lg(M);
    2388          49 :     for(i=1; i<l; i++)
    2389             :     {
    2390          28 :       GEN R = F2x_sqr(gel(M,i));
    2391          28 :       GEN H = F2x_genus2_find_trans(P, Q, R);
    2392          28 :       P = F2x_div(F2x_genus2_trans(P, Q, H), R);
    2393          28 :       Q = F2x_div(Q, gel(M,i));
    2394             :     }
    2395          21 :     F = F2x_pseudodisc(P, Q);
    2396             :   }
    2397          14 :   return mkvec4(P,Q,FF,mkvecsmall2(dP,dQ));
    2398             : }
    2399             : 
    2400             : /* Number of solutions of x^2+b*x+c */
    2401             : static long
    2402          21 : F2xqX_quad_nbroots(GEN b, GEN c, GEN T)
    2403             : {
    2404          21 :   if (lgpol(b) > 0)
    2405             :   {
    2406          14 :     GEN d = F2xq_div(c, F2xq_sqr(b, T), T);
    2407          14 :     return F2xq_trace(d, T)? 0: 2;
    2408             :   }
    2409             :   else
    2410           7 :     return 1;
    2411             : }
    2412             : 
    2413             : static GEN
    2414          14 : genus2_eulerfact2_semistable(GEN PQ)
    2415             : {
    2416          14 :   GEN V = F2x_genus_red(ZX_to_F2x(gel(PQ, 1)), ZX_to_F2x(gel(PQ, 2)));
    2417          14 :   GEN P = gel(V, 1), Q = gel(V, 2);
    2418          14 :   GEN F = gel(V, 3), v = gel(V, 4);
    2419             :   GEN abe, tor;
    2420          14 :   GEN ki, kp = pol_1(0), kq = pol_1(0);
    2421          14 :   long dP = F2x_degree(P), dQ = F2x_degree(Q), d = maxss(dP, 2*dQ);
    2422          14 :   if (!lgpol(F)) return pol_1(0);
    2423          21 :   ki = dQ!=0 || dP>0 ? oneminusxd(1):
    2424           7 :       dP==-1 ? ZX_sqr(oneminusxd(1)): oneminusxd(2);
    2425          28 :   abe = d>=5? RgX_recip(hyperellcharpoly(gmul(PQ,gmodulss(1,2)))):
    2426          14 :         d>=3? RgX_recip(ellfromeqncharpoly(F2x_to_ZX(P), F2x_to_ZX(Q), gen_2)):
    2427          14 :         pol_1(0);
    2428          14 :   if (lgpol(F))
    2429             :   {
    2430          14 :     GEN M = gel(F2x_factor(F), 1);
    2431          14 :     long i, lF = lg(M)-1;
    2432          35 :     for(i=1; i <= lF; i++)
    2433             :     {
    2434          21 :       GEN Fi = gel(M, i);
    2435          21 :       long d = F2x_degree(Fi);
    2436          21 :       long nb  = F2xqX_quad_nbroots(F2x_rem(Q, Fi), F2x_rem(P, Fi), Fi);
    2437          35 :       GEN kqf = nb==1 ? oneminusxd(d):
    2438           0 :                 nb==2 ? ZX_sqr(oneminusxd(d))
    2439          14 :                       : oneminusxd(2*d);
    2440          21 :       kp = gmul(kp, oneminusxd(d));
    2441          21 :       kq = gmul(kq, kqf);
    2442             :     }
    2443             :   }
    2444          14 :   if (maxss(v[1],2*v[2])<5)
    2445             :   {
    2446          14 :     GEN kqoo = v[1]>2*v[2] ? oneminusxd(1):
    2447           0 :                v[1]<2*v[2] ? ZX_sqr(oneminusxd(1))
    2448           7 :                            : oneminusxd(2);
    2449           7 :     kp = gmul(kp, oneminusxd(1));
    2450           7 :     kq = gmul(kq, kqoo);
    2451             :   }
    2452          14 :   tor = RgX_div(ZX_mul(oneminusxd(1),kq), ZX_mul(ki, kp));
    2453          14 :   return ginv( ZX_mul(abe, tor) );
    2454             : }
    2455             : 
    2456             : static GEN
    2457          14 : genus2_eulerfact2(GEN F, GEN PQ)
    2458             : {
    2459          14 :   pari_sp av = avma;
    2460          14 :   GEN W, R = genus2_type5(F, gen_2), E;
    2461          14 :   if (R) return R;
    2462          14 :   W = hyperellextremalmodels(PQ, 2, gen_2);
    2463          14 :   if (lg(W) < 3) return genus2_eulerfact2_semistable(PQ);
    2464           0 :   E = gmul(genus2_eulerfact2_semistable(gel(W,1)),
    2465           0 :            genus2_eulerfact2_semistable(gel(W,2)));
    2466           0 :   return gerepileupto(av, E);
    2467             : }
    2468             : 
    2469             : GEN
    2470          35 : lfungenus2(GEN G)
    2471             : {
    2472          35 :   pari_sp ltop = avma;
    2473             :   GEN Ldata;
    2474          35 :   GEN gr = genus2red(G, NULL);
    2475          35 :   GEN N  = gel(gr, 1), M = gel(gr, 2), PQ = gel(gr, 3), L = gel(gr, 4);
    2476          35 :   GEN e, F = gadd(gsqr(gel(PQ, 2)), gmul2n(gel(PQ, 1), 2));
    2477          35 :   long i, lL = lg(L), ram2;
    2478          35 :   ram2 = absequaliu(gmael(M,1,1),2);
    2479          35 :   if (ram2 && equalis(gmael(M,2,1),-1))
    2480          14 :     pari_warn(warner,"unknown valuation of conductor at 2");
    2481          35 :   e = cgetg(lL+(ram2?0:1), t_VEC);
    2482          56 :   gel(e,1) = mkvec2(gen_2, ram2 ? genus2_eulerfact2(F, PQ)
    2483          21 :            : ginv( RgX_recip(hyperellcharpoly(gmul(PQ,gmodulss(1,2))))) );
    2484          84 :   for(i = ram2? 2: 1; i < lL; i++)
    2485             :   {
    2486          49 :     GEN Li = gel(L, i);
    2487          49 :     GEN p = gel(Li, 1);
    2488          49 :     gel(e, ram2 ? i: i+1) = mkvec2(p, genus2_eulerfact(F,p));
    2489             :   }
    2490          35 :   Ldata = mkvecn(6, tag(mkvec2(F,e), t_LFUN_GENUS2),
    2491             :       gen_0, mkvec4(gen_0, gen_0, gen_1, gen_1), gen_2, N, gen_0);
    2492          35 :   return gerepilecopy(ltop, Ldata);
    2493             : }
    2494             : 
    2495             : /*************************************************************/
    2496             : /*                        ETA QUOTIENTS                      */
    2497             : /* An eta quotient is a matrix with 2 columns [m, r_m] with  */
    2498             : /* m >= 1 representing f(\tau)=\prod_m\eta(m\tau)^{r_m}.     */
    2499             : /*************************************************************/
    2500             : 
    2501             : /* eta(x^v) + O(x^L) */
    2502             : GEN
    2503        1222 : eta_ZXn(long v, long L)
    2504             : {
    2505        1222 :   long n, k = 0, v2 = 2*v, bn = v, cn = 0;
    2506             :   GEN P;
    2507        1222 :   if (!L) return zeropol(0);
    2508        1222 :   P = cgetg(L+2,t_POL); P[1] = evalsigne(1);
    2509       72543 :   for(n = 0; n < L; n++) gel(P,n+2) = gen_0;
    2510        1222 :   for(n = 0;; n++, bn += v2, cn += v)
    2511        3000 :   { /* k = v * (3*n-1) * n / 2; bn = v * (2*n+1); cn = v * n */
    2512             :     long k2;
    2513        4222 :     gel(P, k+2) = odd(n)? gen_m1: gen_1;
    2514        4222 :     k2 = k+cn; if (k2 >= L) break;
    2515        3770 :     k = k2;
    2516             :     /* k = v * (3*n+1) * n / 2 */;
    2517        3770 :     gel(P, k+2) = odd(n)? gen_m1: gen_1;
    2518        3770 :     k2 = k+bn; if (k2 >= L) break;
    2519        3000 :     k = k2;
    2520             :   }
    2521        1222 :   setlg(P, k+3); return P;
    2522             : }
    2523             : GEN
    2524         322 : eta_product_ZXn(GEN eta, long L)
    2525             : {
    2526         322 :   pari_sp av = avma;
    2527         322 :   GEN P = NULL, D = gel(eta,1), R = gel(eta,2);
    2528         322 :   long i, l = lg(D);
    2529        1148 :   for (i = 1; i < l; ++i)
    2530             :   {
    2531         826 :     GEN Q = eta_ZXn(D[i], L);
    2532         826 :     long r = R[i];
    2533         826 :     if (r < 0) { Q = RgXn_inv_i(Q, L); r = -r; }
    2534         826 :     if (r != 1) Q = RgXn_powu_i(Q, r, L);
    2535         826 :     P = P? ZXn_mul(P, Q, L): Q;
    2536         826 :     if (gc_needed(av,1) && i > 1)
    2537             :     {
    2538           0 :       if (DEBUGMEM>1) pari_warn(warnmem,"eta_product_ZXn");
    2539           0 :       P = gerepilecopy(av, P);
    2540             :     }
    2541             :   }
    2542         322 :   return P;
    2543             : }
    2544             : static GEN
    2545         147 : vecan_eta(GEN an, long L)
    2546             : {
    2547         147 :   long v = itos(gel(an, 3));
    2548             :   GEN t;
    2549         147 :   if (v > L) return zerovec(L);
    2550         140 :   t = eta_product_ZXn(an, L - v);
    2551         140 :   if (v) t = RgX_shift_shallow(t, v);
    2552         140 :   return RgX_to_RgV(t, L);
    2553             : }
    2554             : /* return 1 if cuspidal, 0 if holomorphic, -1 otherwise */
    2555             : static int
    2556         231 : etacuspidal(GEN N, GEN k, GEN B, GEN R, GEN NB)
    2557             : {
    2558         231 :   long i, j, lD, l, cusp = 1;
    2559         231 :   pari_sp av = avma;
    2560             :   GEN D;
    2561         231 :   if (gsigne(k) < 0) return -1;
    2562         224 :   D = divisors(N); lD = lg(D); l = lg(B);
    2563        1505 :   for (i = 1; i < lD; i++)
    2564             :   {
    2565        1281 :     GEN t = gen_0, d = gel(D,i);
    2566             :     long s;
    2567        3997 :     for (j = 1; j < l; j++)
    2568        2716 :       t = addii(t, mulii(gel(NB,j), mulii(gel(R,j), sqri(gcdii(d, gel(B,j))))));
    2569        1281 :     s = signe(t);
    2570        1281 :     if (s < 0) return -1;
    2571        1281 :     if (!s) cusp = 0;
    2572             :   }
    2573         224 :   return gc_bool(av, cusp);
    2574             : }
    2575             : /* u | 24, level N = u*N0, N0 = lcm(B), NB[i] = N0/B[i] */
    2576             : static int
    2577          49 : etaselfdual(GEN B, GEN R, GEN NB, ulong u)
    2578             : {
    2579          49 :   pari_sp av = avma;
    2580          49 :   long i, l = lg(B);
    2581         161 :   for (i = 1; i < l; i++)
    2582             :   {
    2583         112 :     long j = ZV_search(B, muliu(gel(NB,i), u)); /* search for N / B[i] */
    2584         112 :     set_avma(av); if (!j || !equalii(gel(R,i),gel(R,j))) return 0;
    2585             :   }
    2586          49 :   return 1;
    2587             : }
    2588             : /* return Nebentypus of eta quotient, k2 = 2*k integral */
    2589             : static GEN
    2590         203 : etachar(GEN B, GEN R, GEN k2)
    2591             : {
    2592         203 :   long i, l = lg(B);
    2593         203 :   GEN P = gen_1;
    2594         546 :   for (i = 1; i < l; ++i) if (mpodd(gel(R,i))) P = mulii(P, gel(B,i));
    2595         203 :   switch(Mod4(k2))
    2596             :   {
    2597         133 :     case 0: break;
    2598          42 :     case 2:  P = negi(P); break;
    2599          28 :     default: P = shifti(P, 1); break;
    2600             :   }
    2601         203 :   return coredisc(P);
    2602             : }
    2603             : /* Return 0 if not on gamma_0(N). Sets conductor, modular weight, character,
    2604             :  * canonical matrix, v_q(eta), sd = 1 iff self-dual, cusp = 1 iff cuspidal
    2605             :  * [0 if holomorphic at all cusps, else -1] */
    2606             : long
    2607         259 : etaquotype(GEN *peta, GEN *pN, GEN *pk, GEN *CHI, long *pv, long *sd,
    2608             :            long *cusp)
    2609             : {
    2610         259 :   GEN B, R, S, T, N, NB, eta = *peta;
    2611             :   long l, i, u, S24;
    2612             : 
    2613         259 :   if (lg(eta) != 3) pari_err_TYPE("lfunetaquo", eta);
    2614         259 :   switch(typ(eta))
    2615             :   {
    2616          77 :     case t_VEC: eta = mkmat2(mkcol(gel(eta,1)), mkcol(gel(eta,2))); break;
    2617         182 :     case t_MAT: break;
    2618           0 :     default: pari_err_TYPE("lfunetaquo", eta);
    2619             :   }
    2620         259 :   if (!RgV_is_ZVpos(gel(eta,1)) || !RgV_is_ZV(gel(eta,2)))
    2621           0 :     pari_err_TYPE("lfunetaquo", eta);
    2622         259 :   *peta = eta = famat_reduce(eta);
    2623         259 :   B = gel(eta,1); l = lg(B); /* sorted in increasing order */
    2624         259 :   R = gel(eta,2);
    2625         259 :   N = ZV_lcm(B); NB = cgetg(l, t_VEC);
    2626         721 :   for (i = 1; i < l; i++) gel(NB,i) = diviiexact(N, gel(B,i));
    2627         259 :   S = gen_0; T = gen_0; u = 0;
    2628         721 :   for (i = 1; i < l; ++i)
    2629             :   {
    2630         462 :     GEN b = gel(B,i), r = gel(R,i);
    2631         462 :     S = addii(S, mulii(b, r));
    2632         462 :     T = addii(T, r);
    2633         462 :     u += umodiu(r,24) * umodiu(gel(NB,i), 24);
    2634             :   }
    2635         259 :   S = divis_rem(S, 24, &S24);
    2636         259 :   if (S24) return 0; /* nonintegral valuation at oo */
    2637         252 :   u = 24 / ugcd(24, u % 24);
    2638         252 :   *pN = muliu(N, u); /* level */
    2639         252 :   *pk = gmul2n(T,-1); /* weight */
    2640         252 :   *pv = itos(S); /* valuation */
    2641         252 :   if (cusp) *cusp = etacuspidal(*pN, *pk, B, R, NB);
    2642         252 :   if (sd) *sd = etaselfdual(B, R, NB, u);
    2643         252 :   if (CHI) *CHI = etachar(B, R, T);
    2644         252 :   return 1;
    2645             : }
    2646             : 
    2647             : GEN
    2648          49 : lfunetaquo(GEN eta0)
    2649             : {
    2650          49 :   pari_sp ltop = avma;
    2651          49 :   GEN Ldata, N, BR, k, eta = eta0;
    2652             :   long v, sd, cusp;
    2653          49 :   if (!etaquotype(&eta, &N, &k, NULL, &v, &sd, &cusp))
    2654           0 :     pari_err_TYPE("lfunetaquo", eta0);
    2655          49 :   if (!cusp) pari_err_IMPL("noncuspidal eta quotient");
    2656          49 :   if (!sd) pari_err_IMPL("non self-dual eta quotient");
    2657          49 :   if (typ(k) != t_INT) pari_err_TYPE("lfunetaquo [nonintegral weight]", eta0);
    2658          49 :   BR = mkvec3(ZV_to_zv(gel(eta,1)), ZV_to_zv(gel(eta,2)), stoi(v - 1));
    2659          49 :   Ldata = mkvecn(6, tag(BR,t_LFUN_ETA), gen_0, mkvec2(gen_0,gen_1), k,N, gen_1);
    2660          49 :   return gerepilecopy(ltop, Ldata);
    2661             : }
    2662             : 
    2663             : static GEN
    2664         399 : vecan_qf(GEN Q, long L)
    2665             : {
    2666         399 :   GEN v, w = qfrep0(Q, utoi(L), 1);
    2667             :   long i;
    2668         399 :   v = cgetg(L+1, t_VEC);
    2669       26698 :   for (i = 1; i <= L; i++) gel(v,i) = utoi(2 * w[i]);
    2670         399 :   return v;
    2671             : }
    2672             : 
    2673             : long
    2674         336 : qfiseven(GEN M)
    2675             : {
    2676         336 :   long i, l = lg(M);
    2677         784 :   for (i=1; i<l; i++)
    2678         679 :     if (mpodd(gcoeff(M,i,i))) return 0;
    2679         105 :   return 1;
    2680             : }
    2681             : 
    2682             : GEN
    2683          91 : lfunqf(GEN M, long prec)
    2684             : {
    2685          91 :   pari_sp ltop = avma;
    2686             :   long n;
    2687             :   GEN k, D, d, Mi, Ldata, poles, eno, dual;
    2688             : 
    2689          91 :   if (typ(M) != t_MAT) pari_err_TYPE("lfunqf", M);
    2690          91 :   if (!RgM_is_ZM(M))   pari_err_TYPE("lfunqf [not integral]", M);
    2691          91 :   n = lg(M)-1;
    2692          91 :   k = uutoQ(n,2);
    2693          91 :   M = Q_primpart(M);
    2694          91 :   Mi = ZM_inv(M, &d); /* d M^(-1) */
    2695          91 :   if (!qfiseven(M)) { M = gmul2n(M, 1); d = shifti(d,1); }
    2696          91 :   if (!qfiseven(Mi)){ Mi= gmul2n(Mi,1); d = shifti(d,1); }
    2697             :   /* det(Mi) = d^n/det(M), D^2 = det(Mi)/det(M) */
    2698          91 :   D = gdiv(gpow(d,k,prec), ZM_det(M));
    2699          91 :   if (!issquareall(D, &eno)) eno = gsqrt(D, prec);
    2700          91 :   dual = gequal1(D) ? gen_0: tag(Mi, t_LFUN_QF);
    2701          91 :   poles = mkcol2(mkvec2(k, simple_pole(gmul2n(eno,1))),
    2702             :                  mkvec2(gen_0, simple_pole(gen_m2)));
    2703          91 :   Ldata = mkvecn(7, tag(M, t_LFUN_QF), dual,
    2704             :        mkvec2(gen_0, gen_1), k, d, eno, poles);
    2705          91 :   return gerepilecopy(ltop, Ldata);
    2706             : }
    2707             : 
    2708             : /********************************************************************/
    2709             : /**  Artin L function, based on a GP script by Charlotte Euvrard   **/
    2710             : /********************************************************************/
    2711             : 
    2712             : static GEN
    2713         119 : artin_charfromgens(GEN G, GEN M)
    2714             : {
    2715         119 :   GEN R, V, ord = gal_get_orders(G), grp = gal_get_group(G);
    2716         119 :   long i, j, k, n = lg(ord)-1, m = lg(grp)-1;
    2717             : 
    2718         119 :   if (lg(M)-1 != n) pari_err_DIM("lfunartin");
    2719         119 :   R = cgetg(m+1, t_VEC);
    2720         119 :   gel(R, 1) = matid(lg(gel(M, 1))-1);
    2721         357 :   for (i = 1, k = 1; i <= n; ++i)
    2722             :   {
    2723         238 :     long c = k*(ord[i] - 1);
    2724         238 :     gel(R, ++k) = gel(M, i);
    2725        1043 :     for (j = 2; j <= c; ++j) gel(R, ++k) = gmul(gel(R,j), gel(M,i));
    2726             :   }
    2727         119 :   V = cgetg(m+1, t_VEC);
    2728        1281 :   for (i = 1; i <= m; i++) gel(V, gel(grp,i)[1]) = gtrace(gel(R,i));
    2729         119 :   return V;
    2730             : }
    2731             : 
    2732             : /* TODO move somewhere else? */
    2733             : GEN
    2734         280 : galois_get_conj(GEN G)
    2735             : {
    2736         280 :   GEN grp = gal_get_group(G);
    2737         280 :   long i, k, r = lg(grp)-1;
    2738         280 :   GEN b = zero_F2v(r);
    2739         959 :   for (k = 2; k <= r; ++k)
    2740             :   {
    2741         959 :     GEN g = gel(grp,k);
    2742         959 :     if (!F2v_coeff(b,g[1]) && g[g[1]]==1)
    2743             :     {
    2744         392 :       pari_sp av = avma;
    2745         392 :       GEN F = galoisfixedfield(G, g, 1, -1);
    2746         392 :       if (ZX_sturmpart(F, NULL) > 0) { set_avma(av); return g; }
    2747        1456 :       for (i = 1; i<=r; i++)
    2748             :       {
    2749        1344 :         GEN h = gel(grp, i);
    2750        1344 :         long t = h[1];
    2751        5264 :         while (h[t]!=1) t = h[t];
    2752        1344 :         F2v_set(b, h[g[t]]);
    2753             :       }
    2754         112 :       set_avma(av);
    2755             :     }
    2756             :   }
    2757           0 :   pari_err_BUG("galois_get_conj");
    2758             :   return NULL;/*LCOV_EXCL_LINE*/
    2759             : }
    2760             : 
    2761        7700 : static GEN  cyclotoi(GEN v) { return simplify_shallow(lift_shallow(v)); }
    2762        2891 : static long cyclotos(GEN v) { return gtos(cyclotoi(v)); }
    2763        2821 : static long char_dim(GEN ch) { return cyclotos(gel(ch,1)); }
    2764             : 
    2765             : static GEN
    2766        1379 : artin_gamma(GEN N, GEN G, GEN ch)
    2767             : {
    2768        1379 :   long a, t, d = char_dim(ch);
    2769        1379 :   if (nf_get_r2(N) == 0) return vec01(d, 0);
    2770          70 :   a = galois_get_conj(G)[1];
    2771          70 :   t = cyclotos(gel(ch,a));
    2772          70 :   return vec01((d+t) / 2, (d-t) / 2);
    2773             : }
    2774             : 
    2775             : static long
    2776        3213 : artin_dim(GEN ind, GEN ch)
    2777             : {
    2778        3213 :   long n = lg(ch)-1;
    2779        3213 :   GEN elts = group_elts(ind, n);
    2780        3213 :   long i, d = lg(elts)-1;
    2781        3213 :   GEN s = gen_0;
    2782       18123 :   for(i=1; i<=d; i++)
    2783       14910 :     s = gadd(s, gel(ch, gel(elts,i)[1]));
    2784        3213 :   return gtos(gdivgu(cyclotoi(s), d));
    2785             : }
    2786             : 
    2787             : static GEN
    2788         623 : artin_ind(GEN elts, GEN ch, GEN p)
    2789             : {
    2790         623 :   long i, d = lg(elts)-1;
    2791         623 :   GEN s = gen_0;
    2792        2149 :   for(i=1; i<=d; i++)
    2793        1526 :     s = gadd(s, gel(ch, gmul(gel(elts,i),p)[1]));
    2794         623 :   return gdivgu(s, d);
    2795             : }
    2796             : 
    2797             : static GEN
    2798        2282 : artin_ram(GEN nf, GEN gal, GEN aut, GEN pr, GEN ramg, GEN ch, long d)
    2799             : {
    2800        2282 :   pari_sp av = avma;
    2801             :   long i, v, n;
    2802             :   GEN p, q, V, elts;
    2803        2282 :   if (d==0) return pol_1(0);
    2804         616 :   n = degpol(gal_get_pol(gal));
    2805         616 :   q = p = idealramfrobenius_aut(nf, gal, pr, ramg, aut);
    2806         616 :   elts = group_elts(gel(ramg,2), n);
    2807         616 :   v = fetch_var_higher();
    2808         616 :   V = cgetg(d+2, t_POL);
    2809         616 :   V[1] = evalsigne(1)|evalvarn(v);
    2810        1239 :   for(i=1; i<=d; i++)
    2811             :   {
    2812         623 :     gel(V,i+1) = artin_ind(elts, ch, q);
    2813         623 :     q = gmul(q, p);
    2814             :   }
    2815         616 :   delete_var();
    2816         616 :   V = RgXn_expint(RgX_neg(V),d+1);
    2817         616 :   setvarn(V,0); return gerepileupto(av, ginv(V));
    2818             : }
    2819             : 
    2820             : /* N true nf; [Artin conductor, vec of [p, Lp]] */
    2821             : static GEN
    2822        1379 : artin_badprimes(GEN N, GEN G, GEN aut, GEN ch)
    2823             : {
    2824        1379 :   pari_sp av = avma;
    2825        1379 :   long i, d = char_dim(ch);
    2826        1379 :   GEN P = gel(absZ_factor(nf_get_disc(N)), 1);
    2827        1379 :   long lP = lg(P);
    2828        1379 :   GEN B = cgetg(lP, t_VEC), C = cgetg(lP, t_VEC);
    2829             : 
    2830        3661 :   for (i = 1; i < lP; ++i)
    2831             :   {
    2832        2282 :     GEN p = gel(P, i), pr = idealprimedec_galois(N, p);
    2833        2282 :     GEN J = idealramgroups_aut(N, G, pr, aut);
    2834        2282 :     GEN G0 = gel(J,2); /* inertia group */
    2835        2282 :     long lJ = lg(J);
    2836        2282 :     long sdec = artin_dim(G0, ch);
    2837        2282 :     long ndec = group_order(G0);
    2838        2282 :     long j, v = ndec * (d - sdec);
    2839        3213 :     for (j = 3; j < lJ; ++j)
    2840             :     {
    2841         931 :       GEN Jj = gel(J, j);
    2842         931 :       long s = artin_dim(Jj, ch);
    2843         931 :       v += group_order(Jj) * (d - s);
    2844             :     }
    2845        2282 :     gel(C, i) = powiu(p, v/ndec);
    2846        2282 :     gel(B, i) = mkvec2(p, artin_ram(N, G, aut, pr, J, ch, sdec));
    2847             :   }
    2848        1379 :   return gerepilecopy(av, mkvec2(ZV_prod(C), B));
    2849             : }
    2850             : 
    2851             : /* p does not divide nf.index */
    2852             : static GEN
    2853       52401 : idealfrobenius_easy(GEN nf, GEN gal, GEN aut, GEN T, GEN p)
    2854             : {
    2855       52401 :   long i, l = lg(aut), f = degpol(T);
    2856       52400 :   GEN D, Dzk, DzkT, DXp, grp = gal_get_group(gal);
    2857       52401 :   pari_sp av = avma;
    2858       52401 :   if (f==1) return gel(grp,1);
    2859       50595 :   Dzk = nf_get_zkprimpart(nf);
    2860       50595 :   D = modii(nf_get_zkden(nf), p);
    2861       50592 :   DzkT = RgV_to_RgM(FqV_red(Dzk, T, p), f);
    2862       50595 :   DXp = RgX_to_RgC(FpX_Frobenius(T, p), f);
    2863       50596 :   if (!equali1(D)) DXp = FpC_Fp_mul(DXp, D, p);
    2864      332160 :   for(i=1; i < l; i++)
    2865             :   {
    2866      332151 :     GEN g = gel(grp,i);
    2867      332151 :     if (perm_orderu(g) == (ulong)f)
    2868             :     {
    2869      170269 :       GEN A = FpM_FpC_mul(DzkT, gel(aut,g[1]), p);
    2870      170257 :       if (ZV_equal(A, DXp)) {set_avma(av); return g; }
    2871             :     }
    2872             :   }
    2873             :   return NULL; /* LCOV_EXCL_LINE */
    2874             : }
    2875             : /* true nf; p divides nf.index, pr/p unramified */
    2876             : static GEN
    2877        1596 : idealfrobenius_hard(GEN nf, GEN gal, GEN aut, GEN pr)
    2878             : {
    2879        1596 :   long i, l = lg(aut), f = pr_get_f(pr);
    2880        1596 :   GEN modpr, p, T, X, Xp, pi, grp = gal_get_group(gal);
    2881        1596 :   pari_sp av = avma;
    2882        1596 :   if (f==1) return gel(grp,1);
    2883        1344 :   pi = pr_get_gen(pr);
    2884        1344 :   modpr = zkmodprinit(nf, pr);
    2885        1344 :   p = modpr_get_p(modpr);
    2886        1344 :   T = modpr_get_T(modpr);
    2887        1344 :   X = modpr_genFq(modpr);
    2888        1344 :   Xp = FpX_Frobenius(T, p);
    2889        9188 :   for (i = 1; i < l; i++)
    2890             :   {
    2891        9188 :     GEN g = gel(grp,i);
    2892        9188 :     if (perm_orderu(g) == (ulong)f)
    2893             :     {
    2894        4372 :       GEN S = gel(aut,g[1]);
    2895        4372 :       GEN A = nf_to_Fq(nf, zk_galoisapplymod(nf,X,S,p), modpr);
    2896             :       /* sigma(X) = X^p (mod pr) and sigma(pi) in pr */
    2897        5828 :       if (ZX_equal(A, Xp) && (f == nf_get_degree(nf) ||
    2898        2800 :           ZC_prdvd(zk_galoisapplymod(nf,pi,S,p),pr))) { set_avma(av); return g; }
    2899             :     }
    2900             :   }
    2901             :   return NULL; /* LCOV_EXCL_LINE */
    2902             : }
    2903             : 
    2904             : /* true nf */
    2905             : static GEN
    2906       53993 : dirartin(GEN nf, GEN G, GEN V, GEN aut, GEN p, long n)
    2907             : {
    2908       53993 :   pari_sp av = avma;
    2909             :   GEN pr, frob;
    2910             :   /* pick one maximal ideal in the conjugacy class above p */
    2911       53993 :   GEN T = nf_get_pol(nf);
    2912       53993 :   if (!dvdii(nf_get_index(nf), p))
    2913             :   { /* simple case */
    2914       52396 :     GEN F = FpX_factor(T, p), P = gmael(F,1,1);
    2915       52402 :     frob = idealfrobenius_easy(nf, G, aut, P, p);
    2916             :   }
    2917             :   else
    2918             :   {
    2919        1596 :     pr = idealprimedec_galois(nf,p);
    2920        1596 :     frob = idealfrobenius_hard(nf, G, aut, pr);
    2921             :   }
    2922       53997 :   set_avma(av); return n ? RgXn_inv(gel(V, frob[1]), n): gel(V, frob[1]);
    2923             : }
    2924             : 
    2925             : GEN
    2926       15666 : dirartin_worker(GEN P, ulong X, GEN nf, GEN G, GEN V, GEN aut)
    2927             : {
    2928       15666 :   pari_sp av = avma;
    2929       15666 :   long i, l = lg(P);
    2930       15666 :   GEN W = cgetg(l, t_VEC);
    2931       69629 :   for(i = 1; i < l; i++)
    2932             :   {
    2933       53963 :     ulong p = uel(P,i);
    2934       53963 :     long d = ulogint(X, p) + 1; /* minimal d such that p^d > X */
    2935       53965 :     gel(W,i) = dirartin(nf, G, V, aut, utoi(uel(P,i)), d);
    2936             :   }
    2937       15666 :   return gerepilecopy(av, mkvec2(P,W));
    2938             : }
    2939             : 
    2940             : static GEN
    2941        2947 : vecan_artin(GEN an, long L, long prec)
    2942             : {
    2943        2947 :   GEN A, Sbad = gel(an,5);
    2944        2947 :   long n = itos(gel(an,6)), isreal = lg(an)<8 ? 0: !itos(gel(an,7));
    2945        2947 :   GEN worker = snm_closure(is_entry("_dirartin_worker"), vecslice(an,1,4));
    2946        2947 :   A = lift_shallow(pardireuler(worker, gen_2, stoi(L), NULL, Sbad));
    2947        2947 :   A = RgXV_RgV_eval(A, grootsof1(n, prec));
    2948        2947 :   if (isreal) A = real_i(A);
    2949        2947 :   return A;
    2950             : }
    2951             : 
    2952             : static GEN
    2953          28 : eulerf_artin(GEN an, GEN p, long prec)
    2954             : {
    2955          28 :   GEN nf = gel(an,1), G = gel(an,2), V = gel(an,3), aut = gel(an,4);
    2956          28 :   GEN Sbad = gel(an,5);
    2957          28 :   long n = itos(gel(an,6)), isreal = lg(an)<8 ? 0: !itos(gel(an,7));
    2958          28 :   GEN f = eulerf_bad(Sbad, p);
    2959          28 :   if (!f) f = mkrfrac(gen_1,dirartin(nf, G, V, aut, p, 0));
    2960          28 :   f = gsubst(liftpol(f),1, rootsof1u_cx(n, prec));
    2961          28 :   if (isreal) f = real_i(f);
    2962          28 :   return f;
    2963             : }
    2964             : 
    2965             : static GEN
    2966        2856 : char_expand(GEN conj, GEN ch)
    2967             : {
    2968        2856 :   long i, l = lg(conj);
    2969        2856 :   GEN V = cgetg(l, t_COL);
    2970       31409 :   for (i=1; i<l; i++) gel(V,i) = gel(ch, conj[i]);
    2971        2856 :   return V;
    2972             : }
    2973             : 
    2974             : static GEN
    2975        1596 : handle_zeta(long n, GEN ch, long *m)
    2976             : {
    2977             :   GEN c;
    2978        1596 :   long t, i, l = lg(ch);
    2979        1596 :   GEN dim = cyclotoi(vecsum(ch));
    2980        1596 :   if (typ(dim) != t_INT)
    2981           0 :     pari_err_DOMAIN("lfunartin","chi","is not a", strtoGENstr("character"), ch);
    2982        1596 :   t = itos(dim);
    2983        1596 :   if (t < 0 || t % n)
    2984           0 :     pari_err_DOMAIN("lfunartin","chi","is not a", strtoGENstr("character"), ch);
    2985        1596 :   if (t == 0) { *m = 0; return ch; }
    2986         224 :   *m = t / n;
    2987         224 :   c = cgetg(l, t_COL);
    2988        2065 :   for (i=1; i<l; i++)
    2989        1841 :     gel(c,i) = gsubgs(gel(ch,i), *m);
    2990         224 :   return c;
    2991             : }
    2992             : 
    2993             : static int
    2994        6496 : cyclo_is_real(GEN v, GEN ix)
    2995             : {
    2996        6496 :   pari_sp av = avma;
    2997        6496 :   GEN w = poleval(lift_shallow(v), ix);
    2998        6496 :   return gc_bool(av, gequal(w, v));
    2999             : }
    3000             : 
    3001             : static int
    3002        1379 : char_is_real(GEN ch, GEN mod)
    3003             : {
    3004        1379 :   long i, l = lg(ch);
    3005        1379 :   GEN ix = QXQ_inv(pol_x(varn(mod)), mod);
    3006        7014 :   for (i=1; i<l; i++)
    3007        6496 :     if (!cyclo_is_real(gel(ch,i), ix)) return 0;
    3008         518 :   return 1;
    3009             : }
    3010             : 
    3011             : GEN
    3012        1610 : lfunartin(GEN nf, GEN gal, GEN ch, long o, long bitprec)
    3013             : {
    3014        1610 :   pari_sp av = avma;
    3015        1610 :   GEN bc, V, aut, mod, Ldata = NULL, chx, cc, conj, repr;
    3016             :   long tmult, var;
    3017        1610 :   nf = checknf(nf);
    3018        1610 :   checkgal(gal);
    3019        1610 :   var = gvar(ch);
    3020        1610 :   if (var == 0) pari_err_PRIORITY("lfunartin",ch,"=",0);
    3021        1610 :   if (var < 0) var = 1;
    3022        1610 :   if (!is_vec_t(typ(ch))) pari_err_TYPE("lfunartin", ch);
    3023        1610 :   cc = group_to_cc(gal);
    3024        1610 :   conj = gel(cc,2);
    3025        1610 :   repr = gel(cc,3);
    3026        1610 :   mod = mkpolmod(gen_1, polcyclo(o, var));
    3027        1610 :   if (lg(ch)>1 && typ(gel(ch,1))==t_MAT)
    3028         119 :     chx = artin_charfromgens(gal, gmul(ch,mod));
    3029             :   else
    3030             :   {
    3031        1491 :     if (lg(repr) != lg(ch)) pari_err_DIM("lfunartin");
    3032        1477 :     chx = char_expand(conj, gmul(ch,mod));
    3033             :   }
    3034        1596 :   chx = handle_zeta(nf_get_degree(nf), chx, &tmult);
    3035        1596 :   ch = shallowextract(chx, repr);
    3036        1596 :   if (!gequal0(chx))
    3037             :   {
    3038        1379 :     GEN real = char_is_real(chx, gel(mod,1))? gen_0: gen_1;
    3039        1379 :     aut = nfgaloispermtobasis(nf, gal);
    3040        1379 :     V = gmul(char_expand(conj, galoischarpoly(gal, ch, o)), mod);
    3041        1379 :     bc = artin_badprimes(nf, gal, aut, chx);
    3042        2758 :     Ldata = mkvecn(6,
    3043        1379 :       tag(mkcoln(7, nf, gal, V, aut, gel(bc, 2), stoi(o), real), t_LFUN_ARTIN),
    3044        1379 :       real, artin_gamma(nf, gal, chx), gen_1, gel(bc,1), gen_0);
    3045             :   }
    3046        1596 :   if (tmult==0 && Ldata==NULL) pari_err_TYPE("lfunartin",ch);
    3047        1596 :   if (tmult)
    3048             :   {
    3049             :     long i;
    3050         224 :     if (Ldata==NULL) { Ldata = lfunzeta(); tmult--; }
    3051         231 :     for(i=1; i<=tmult; i++)
    3052           7 :       Ldata = lfunmul(Ldata, gen_1, bitprec);
    3053             :   }
    3054        1596 :   return gerepilecopy(av, Ldata);
    3055             : }
    3056             : 
    3057             : /* true nf */
    3058             : static GEN
    3059          21 : lfunzetakinit_artin(GEN nf, GEN gal, GEN dom, long der, long bitprec)
    3060             : {
    3061          21 :   GEN F, E, M, domain, To = galoischartable(gal), T = gel(To, 1);
    3062          21 :   long i, o = itos(gel(To, 2)), l = lg(T);
    3063          21 :   F = cgetg(l, t_VEC);
    3064          21 :   E = cgetg(l, t_VECSMALL);
    3065          84 :   for (i = 1; i < l; ++i)
    3066             :   {
    3067          63 :     GEN L = lfunartin(nf, gal, gel(T,i), o, bitprec);
    3068          63 :     gel(F, i) = lfuninit(L, dom, der, bitprec);
    3069          63 :     E[i] = char_dim(gel(T,i));
    3070             :   }
    3071          21 :   domain = mkvec2(dom, mkvecsmall2(der, bitprec));
    3072          21 :   M = mkvec3(F, E, zero_zv(l-1));
    3073          21 :   return lfuninit_make(t_LDESC_PRODUCT, lfunzetak_i(nf), M, domain);
    3074             : }
    3075             : 
    3076             : /********************************************************************/
    3077             : /**                    High-level Constructors                     **/
    3078             : /********************************************************************/
    3079             : enum { t_LFUNMISC_POL, t_LFUNMISC_CHIQUAD, t_LFUNMISC_CHICONREY,
    3080             :        t_LFUNMISC_CHIGEN, t_LFUNMISC_ELLINIT, t_LFUNMISC_ETAQUO,
    3081             :        t_LFUNMISC_GCHAR, t_LFUNMISC_ABELREL };
    3082             : static long
    3083       17696 : lfundatatype(GEN data)
    3084             : {
    3085       17696 :   switch(typ(data))
    3086             :   {
    3087        3899 :     case t_INT: return t_LFUNMISC_CHIQUAD;
    3088         217 :     case t_INTMOD: return t_LFUNMISC_CHICONREY;
    3089         651 :     case t_POL: return t_LFUNMISC_POL;
    3090       12929 :     case t_VEC:
    3091       12929 :       switch(lg(data))
    3092             :       {
    3093        4053 :         case 17: return t_LFUNMISC_ELLINIT;
    3094           0 :         case 10: return t_LFUNMISC_POL;
    3095        8876 :         case 3:
    3096        8876 :           if (typ(gel(data,1)) != t_VEC) break;
    3097        8876 :           return is_gchar_group(gel(data,1))  ? t_LFUNMISC_GCHAR
    3098        8876 :                     : typ(gel(data,2))==t_MAT ? t_LFUNMISC_ABELREL
    3099             :                                               : t_LFUNMISC_CHIGEN;
    3100             :       }
    3101           0 :       break;
    3102             :   }
    3103           0 :   return -1;
    3104             : }
    3105             : static GEN
    3106      122114 : lfunmisc_to_ldata_i(GEN ldata, long shallow)
    3107             : {
    3108             :   GEN x;
    3109      122114 :   if (is_linit(ldata)) ldata = linit_get_ldata(ldata);
    3110      122114 :   if (is_ldata(ldata) && is_tagged(ldata))
    3111             :   {
    3112      104250 :     if (!shallow) ldata = gcopy(ldata);
    3113      104250 :     checkldata(ldata); return ldata;
    3114             :   }
    3115       17864 :   x = checknf_i(ldata); if (x) return lfunzetak(x);
    3116       17696 :   switch (lfundatatype(ldata))
    3117             :   {
    3118         651 :     case t_LFUNMISC_POL: return lfunzetak(ldata);
    3119        3899 :     case t_LFUNMISC_CHIQUAD: return lfunchiquad(ldata);
    3120         217 :     case t_LFUNMISC_CHICONREY:
    3121             :     {
    3122         217 :       GEN G = znstar0(gel(ldata,1), 1);
    3123         217 :       return lfunchiZ(G, gel(ldata,2));
    3124             :     }
    3125        8463 :     case t_LFUNMISC_CHIGEN:
    3126             :     {
    3127        8463 :       GEN G = gel(ldata,1), chi = gel(ldata,2);
    3128        8463 :       switch(nftyp(G))
    3129             :       {
    3130        8204 :         case typ_BIDZ: return lfunchiZ(G, chi);
    3131         252 :         case typ_BNR: return lfunchigen(G, chi);
    3132             :       }
    3133             :     }
    3134           7 :     break;
    3135         392 :     case t_LFUNMISC_GCHAR: return lfungchar(gel(ldata,1), gel(ldata,2));
    3136          21 :     case t_LFUNMISC_ABELREL:
    3137          21 :       return lfunabelrel(gel(ldata,1), gel(ldata,2),
    3138          21 :                          lg(ldata)==3? NULL: gel(ldata,3));
    3139        4053 :     case t_LFUNMISC_ELLINIT: return lfunell(ldata);
    3140             :   }
    3141           7 :   if (shallow != 2) pari_err_TYPE("lfunmisc_to_ldata",ldata);
    3142           0 :   return NULL;
    3143             : }
    3144             : 
    3145             : GEN
    3146        3514 : lfunmisc_to_ldata(GEN ldata)
    3147        3514 : { return lfunmisc_to_ldata_i(ldata, 0); }
    3148             : 
    3149             : GEN
    3150       97803 : lfunmisc_to_ldata_shallow(GEN ldata)
    3151       97803 : { return lfunmisc_to_ldata_i(ldata, 1); }
    3152             : 
    3153             : GEN
    3154       20797 : lfunmisc_to_ldata_shallow_i(GEN ldata)
    3155       20797 : { return lfunmisc_to_ldata_i(ldata, 2); }
    3156             : 
    3157             : /********************************************************************/
    3158             : /**                    High-level an expansion                     **/
    3159             : /********************************************************************/
    3160             : /* van is the output of ldata_get_an: return a_1,...a_L at precision prec */
    3161             : GEN
    3162       31878 : ldata_vecan(GEN van, long L, long prec)
    3163             : {
    3164       31878 :   GEN an = gel(van, 2);
    3165       31878 :   long t = mael(van,1,1);
    3166             :   pari_timer ti;
    3167       31878 :   if (DEBUGLEVEL >= 1)
    3168           0 :     err_printf("Lfun: computing %ld coeffs, prec %ld, type %ld\n", L, prec, t);
    3169       31878 :   if (DEBUGLEVEL >= 2) timer_start(&ti);
    3170       31878 :   if (L < 0) L = 0;
    3171       31878 :   switch (t)
    3172             :   {
    3173             :     long n;
    3174        1932 :     case t_LFUN_GENERIC:
    3175        1932 :       an = vecan_closure(an, L, prec);
    3176        1862 :       n = lg(an)-1;
    3177        1862 :       if (n < L)
    3178             :       {
    3179          14 :         pari_warn(warner, "#an = %ld < %ld, results may be imprecise", n, L);
    3180          14 :         an = shallowconcat(an, zerovec(L-n));
    3181             :       }
    3182        1862 :       break;
    3183           0 :     case t_LFUN_CLOSURE0:
    3184             :       pari_err_BUG("ldata_vecan: please call ldata_newprec");/*LCOV_EXCL_LINE*/
    3185        2898 :     case t_LFUN_ZETA: an = const_vecsmall(L, 1); break;
    3186        2100 :     case t_LFUN_NF:  an = dirzetak(an, stoi(L)); break;
    3187        6258 :     case t_LFUN_ELL:
    3188        6258 :       an = (ell_get_type(an) == t_ELL_Q) ? ellanQ_zv(an, L): ellan(an, L);
    3189        6258 :       break;
    3190        3654 :     case t_LFUN_KRONECKER: an = vecan_Kronecker(an, L); break;
    3191         168 :     case t_LFUN_ABELREL: an = vecan_abelrel(an, L); break;
    3192        3647 :     case t_LFUN_CHIZ: an = vecan_chiZ(an, L, prec); break;
    3193        1344 :     case t_LFUN_CHIGEN: an = vecan_chigen(an, L, prec); break;
    3194         693 :     case t_LFUN_HECKE: an = vecan_gchar(an, L, prec); break;
    3195        2947 :     case t_LFUN_ARTIN: an = vecan_artin(an, L, prec); break;
    3196         147 :     case t_LFUN_ETA: an = vecan_eta(an, L); break;
    3197         399 :     case t_LFUN_QF: an = vecan_qf(an, L); break;
    3198         630 :     case t_LFUN_DIV: an = vecan_div(an, L, prec); break;
    3199         308 :     case t_LFUN_MUL: an = vecan_mul(an, L, prec); break;
    3200         126 :     case t_LFUN_CONJ: an = vecan_conj(an, L, prec); break;
    3201         343 :     case t_LFUN_SYMPOW_ELL: an = vecan_ellsympow(an, L); break;
    3202         196 :     case t_LFUN_GENUS2: an = vecan_genus2(an, L); break;
    3203         168 :     case t_LFUN_HGM:
    3204         168 :       an = hgmcoefs(gel(an,1), gel(an,2), L); break;
    3205         406 :     case t_LFUN_MFCLOS:
    3206             :     {
    3207         406 :       GEN F = gel(an,1), E = gel(an,2), c = gel(an,3);
    3208         406 :       an = mfcoefs(F,L,1) + 1; /* skip a_0 */
    3209         406 :       an[0] = evaltyp(t_VEC)|_evallg(L+1);
    3210         406 :       an = mfvecembed(E, an);
    3211         406 :       if (!isint1(c)) an = RgV_Rg_mul(an,c);
    3212         406 :       break;
    3213             :     }
    3214        2877 :     case t_LFUN_TWIST: an = vecan_twist(an, L, prec); break;
    3215         637 :     case t_LFUN_SHIFT: an = vecan_shift(an, L, prec); break;
    3216           0 :     default: pari_err_TYPE("ldata_vecan", van);
    3217             :   }
    3218       31808 :   if (DEBUGLEVEL >= 2) timer_printf(&ti, "ldata_vecan");
    3219       31808 :   return an;
    3220             : }
    3221             : 
    3222             : /* shallow */
    3223             : GEN
    3224       32613 : ldata_newprec(GEN ldata, long prec)
    3225             : {
    3226       32613 :   GEN van = ldata_get_an(ldata), an = gel(van, 2);
    3227       32613 :   long t = mael(van,1,1);
    3228       32613 :   switch (t)
    3229             :   {
    3230         154 :     case t_LFUN_CLOSURE0: return closure2ldata(an, prec);
    3231         994 :     case t_LFUN_HECKE:
    3232             :     {
    3233         994 :       GEN gc = gel(an, 1), chiw = gel(an, 2);
    3234         994 :       gc = gcharnewprec(gc, prec);
    3235         994 :       return gchari_lfun(gc, chiw, gen_0); /* chi in internal format */
    3236             :     }
    3237         329 :     case t_LFUN_QF:
    3238             :     {
    3239         329 :       GEN eno = ldata_get_rootno(ldata);
    3240         329 :       if (typ(eno)==t_REAL && realprec(eno) < prec) return lfunqf(an, prec);
    3241         273 :       break;
    3242             :     }
    3243             :   }
    3244       31409 :   return ldata;
    3245             : }
    3246             : 
    3247             : GEN
    3248         854 : ldata_eulerf(GEN van, GEN p, long prec)
    3249             : {
    3250         854 :   GEN an = gel(van, 2), f = gen_0;
    3251         854 :   long t = mael(van,1,1);
    3252         854 :   switch (t)
    3253             :   {
    3254          70 :     case t_LFUN_GENERIC:
    3255          70 :       f = eulerf_closure(an, p, prec); break;
    3256           0 :     case t_LFUN_CLOSURE0:
    3257             :       pari_err_BUG("ldata_vecan: please call ldata_newprec");/*LCOV_EXCL_LINE*/
    3258          70 :     case t_LFUN_ZETA: f = mkrfrac(gen_1,deg1pol(gen_m1, gen_1,0)); break;
    3259         168 :     case t_LFUN_NF:  f = eulerf_zetak(an, p); break;
    3260          70 :     case t_LFUN_ELL: f = elleulerf(an, p); break;
    3261          70 :     case t_LFUN_KRONECKER:
    3262          70 :       f = mkrfrac(gen_1, deg1pol_shallow(stoi(-kronecker(an, p)), gen_1, 0)); break;
    3263          42 :     case t_LFUN_ABELREL: f = eulerf_abelrel(an, p); break;
    3264          42 :     case t_LFUN_CHIZ: f = eulerf_chiZ(an, p, prec); break;
    3265          28 :     case t_LFUN_CHIGEN: f = eulerf_chigen(an, p, prec); break;
    3266          14 :     case t_LFUN_HECKE: f = eulerf_gchar(an, p, prec); break;
    3267          28 :     case t_LFUN_ARTIN: f = eulerf_artin(an, p, prec); break;
    3268          14 :     case t_LFUN_DIV: f = eulerf_div(an, p, prec); break;
    3269          28 :     case t_LFUN_MUL: f = eulerf_mul(an, p, prec); break;
    3270           0 :     case t_LFUN_CONJ: f = eulerf_conj(an, p, prec); break;
    3271          28 :     case t_LFUN_SYMPOW_ELL: f = eulerf_ellsympow(an, p); break;
    3272           0 :     case t_LFUN_GENUS2: f = eulerf_genus2(an, p); break;
    3273          14 :     case t_LFUN_TWIST: f = eulerf_twist(an, p, prec); break;
    3274          42 :     case t_LFUN_SHIFT: f = eulerf_shift(an, p, prec); break;
    3275          84 :     case t_LFUN_HGM: f = eulerf_hgm(an, p); break;
    3276          42 :     default: f = NULL; break;
    3277             :   }
    3278         854 :   if (!f) pari_err_DOMAIN("lfuneuler", "L", "Euler product", strtoGENstr("unknown"), an);
    3279         742 :   return f;
    3280             : }
    3281             : 
    3282             : GEN
    3283         707 : lfuneuler(GEN ldata, GEN p, long prec)
    3284             : {
    3285         707 :   pari_sp av = avma;
    3286         707 :   if (typ(p)!=t_INT || signe(p)<=0) pari_err_TYPE("lfuneuler", p);
    3287         700 :   ldata = ldata_newprec(lfunmisc_to_ldata_shallow(ldata), prec);
    3288         700 :   return gerepilecopy(av, ldata_eulerf(ldata_get_an(ldata), p, prec));
    3289             : }

Generated by: LCOV version 1.16