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 - hyperell.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 30802-b11b770002) Lines: 1232 1313 93.8 %
Date: 2026-04-11 09:26:21 Functions: 109 112 97.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2014  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             : /**                     HYPERELLIPTIC CURVES                       **/
      18             : /**                                                                **/
      19             : /********************************************************************/
      20             : #include "pari.h"
      21             : #include "paripriv.h"
      22             : 
      23             : #define DEBUGLEVEL DEBUGLEVEL_hyperell
      24             : 
      25             : /* Implementation of Kedlaya Algorithm for counting point on hyperelliptic
      26             : curves by Bill Allombert based on a GP script by Bernadette Perrin-Riou.
      27             : 
      28             : References:
      29             : Pierrick Gaudry and Nicolas G\"urel
      30             : Counting Points in Medium Characteristic Using Kedlaya's Algorithm
      31             : Experiment. Math.  Volume 12, Number 4 (2003), 395-402.
      32             :    http://projecteuclid.org/euclid.em/1087568016
      33             : 
      34             : Harrison, M. An extension of Kedlaya's algorithm for hyperelliptic
      35             :   curves. Journal of Symbolic Computation, 47 (1) (2012), 89-101.
      36             :   http://arxiv.org/pdf/1006.4206v3.pdf
      37             : */
      38             : 
      39             : /* We use the basis of differentials (x^i*dx/y^k) (i=1 to 2*g-1),
      40             :    with k either 1 or 3, depending on p and d, see Harrison paper */
      41             : 
      42             : static long
      43        1764 : get_basis(long p, long d)
      44             : {
      45        1764 :   if (odd(d))
      46         868 :     return p < d-1 ? 3 : 1;
      47             :   else
      48         896 :     return 2*p <= d-2 ? 3 : 1;
      49             : }
      50             : 
      51             : static GEN
      52       20265 : FpXXQ_red(GEN S, GEN T, GEN p)
      53             : {
      54       20265 :   pari_sp av = avma;
      55       20265 :   long i, dS = degpol(S);
      56             :   GEN A, C;
      57       20265 :   if (signe(S)==0) return pol_0(varn(T));
      58       20265 :   A = cgetg(dS+3, t_POL);
      59       20265 :   C = pol_0(varn(T));
      60     1520393 :   for(i=dS; i>0; i--)
      61             :   {
      62     1500128 :     GEN Si = FpX_add(C, gel(S,i+2), p);
      63     1500128 :     GEN R, Q = FpX_divrem(Si, T, p, &R);
      64     1500128 :     gel(A,i+2) = R;
      65     1500128 :     C = Q;
      66             :   }
      67       20265 :   gel(A,2) = FpX_add(C, gel(S,2), p);
      68       20265 :   A[1] = S[1];
      69       20265 :   return gc_GEN(av, FpXX_renormalize(A,dS+3));
      70             : }
      71             : 
      72             : static GEN
      73        3402 : FpXXQ_sqr(GEN x, GEN T, GEN p)
      74             : {
      75        3402 :   pari_sp av = avma;
      76        3402 :   long n = degpol(T);
      77        3402 :   GEN z = FpX_red(ZXX_sqr_Kronecker(x, n), p);
      78        3402 :   z = Kronecker_to_ZXX(z, n, varn(T));
      79        3402 :   return gc_upto(av, FpXXQ_red(z, T, p));
      80             : }
      81             : 
      82             : static GEN
      83       16863 : FpXXQ_mul(GEN x, GEN y, GEN T, GEN p)
      84             : {
      85       16863 :   pari_sp av = avma;
      86       16863 :   long n = degpol(T);
      87       16863 :   GEN z = FpX_red(ZXX_mul_Kronecker(x, y, n), p);
      88       16863 :   z = Kronecker_to_ZXX(z, n, varn(T));
      89       16863 :   return gc_upto(av, FpXXQ_red(z, T, p));
      90             : }
      91             : 
      92             : static GEN
      93        1309 : ZpXXQ_invsqrt(GEN S, GEN T, ulong p, long e)
      94             : {
      95        1309 :   pari_sp av = avma, av2;
      96             :   ulong mask;
      97        1309 :   long v = varn(S), n=1;
      98        1309 :   GEN a = pol_1(v);
      99        1309 :   if (e <= 1) return gc_GEN(av, a);
     100        1309 :   mask = quadratic_prec_mask(e);
     101        1309 :   av2 = avma;
     102        4676 :   for (;mask>1;)
     103             :   {
     104             :     GEN q, q2, q22, f, fq, afq;
     105        3367 :     long n2 = n;
     106        3367 :     n<<=1; if (mask & 1) n--;
     107        3367 :     mask >>= 1;
     108        3367 :     q = powuu(p,n); q2 = powuu(p,n2);
     109        3367 :     f = RgX_sub(FpXXQ_mul(FpXX_red(S, q), FpXXQ_sqr(a, T, q), T, q), pol_1(v));
     110        3367 :     fq = ZXX_Z_divexact(f, q2);
     111        3367 :     q22 = shifti(addiu(q2,1),-1);
     112        3367 :     afq = FpXX_Fp_mul(FpXXQ_mul(a, fq, T, q2), q22, q2);
     113        3367 :     a = RgX_sub(a, ZXX_Z_mul(afq, q2));
     114        3367 :     if (gc_needed(av2,1))
     115             :     {
     116           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_invsqrt, e = %ld", n);
     117           0 :       a = gc_upto(av2, a);
     118             :     }
     119             :   }
     120        1309 :   return gc_upto(av, a);
     121             : }
     122             : 
     123             : static GEN
     124     1029007 : to_ZX(GEN a, long v) { return typ(a)==t_INT? scalarpol(a,v): a; }
     125             : 
     126             : static void
     127          14 : is_sing(GEN H, ulong p)
     128             : {
     129          14 :   pari_err_DOMAIN("hyperellpadicfrobenius","H","is singular at",utoi(p),H);
     130           0 : }
     131             : 
     132             : static void
     133        1309 : get_UV(GEN *U, GEN *V, GEN T, ulong p, long e)
     134             : {
     135        1309 :   GEN q = powuu(p,e), d;
     136        1309 :   GEN dT = FpX_deriv(T, q);
     137        1309 :   GEN R = polresultantext(T, dT);
     138        1309 :   long v = varn(T);
     139        1309 :   if (dvdiu(gel(R,3),p)) is_sing(T, p);
     140        1309 :   d = Zp_inv(gel(R,3), utoi(p), e);
     141        1309 :   *U = FpX_Fp_mul(FpX_red(to_ZX(gel(R,1),v),q),d,q);
     142        1309 :   *V = FpX_Fp_mul(FpX_red(to_ZX(gel(R,2),v),q),d,q);
     143        1309 : }
     144             : 
     145             : static GEN
     146      133847 : frac_to_Fp(GEN a, GEN b, GEN p)
     147             : {
     148      133847 :   GEN d = gcdii(a, b);
     149      133847 :   return Fp_div(diviiexact(a, d), diviiexact(b, d), p);
     150             : }
     151             : 
     152             : static GEN
     153       10094 : ZpXXQ_frob(GEN S, GEN U, GEN V, long k, GEN T, ulong p, long e)
     154             : {
     155       10094 :   pari_sp av = avma, av2;
     156       10094 :   long i, pr = degpol(S), dT = degpol(T), vT = varn(T);
     157       10094 :   GEN q = powuu(p,e);
     158       10094 :   GEN Tp = FpX_deriv(T, q), Tp1 = RgX_shift_shallow(Tp, 1);
     159       10094 :   GEN M = to_ZX(gel(S,pr+2),vT), R;
     160       10094 :   av2 = avma;
     161      987868 :   for(i = pr-1; i>=k; i--)
     162             :   {
     163             :     GEN A, B, H, Bc;
     164             :     ulong v, r;
     165      977774 :     H = FpX_divrem(FpX_mul(V,M,q), T, q, &B);
     166      977774 :     A = FpX_add(FpX_mul(U,M,q), FpX_mul(H, Tp, q),q);
     167      977774 :     v = u_lvalrem(2*i+1,p,&r);
     168      977774 :     Bc = ZX_deriv(B);
     169      977774 :     Bc = FpX_Fp_mul(ZX_divuexact(Bc,upowuu(p,v)),Fp_divu(gen_2, r, q), q);
     170      977774 :     M = FpX_add(to_ZX(gel(S,i+2),vT), FpX_add(A, Bc, q), q);
     171      977774 :     if (gc_needed(av2,1))
     172             :     {
     173           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 1, i = %ld", i);
     174           0 :       M = gc_upto(av2, M);
     175             :     }
     176             :   }
     177       10094 :   if (degpol(M)<dT-1)
     178        5488 :     return gc_upto(av, M);
     179        4606 :   R = RgX_shift_shallow(M,dT-degpol(M)-2);
     180        4606 :   av2 = avma;
     181      237629 :   for(i = degpol(M)-dT+2; i>=1; i--)
     182             :   {
     183             :     GEN B, c;
     184      233023 :     R = RgX_shift_shallow(R, 1);
     185      233023 :     gel(R,2) = gel(M, i+1);
     186      233023 :     if (degpol(R) < dT) continue;
     187      130935 :     B = FpX_add(FpX_mulu(T, 2*i, q), Tp1, q);
     188      130935 :     c = frac_to_Fp(leading_coeff(R), leading_coeff(B), q);
     189      130935 :     R = FpX_sub(R, FpX_Fp_mul(B, c, q), q);
     190      130935 :     if (gc_needed(av2,1))
     191             :     {
     192           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 2, i = %ld", i);
     193           0 :       R = gc_upto(av2, R);
     194             :     }
     195             :   }
     196        4606 :   if (degpol(R)==dT-1)
     197             :   {
     198        2912 :     GEN c = frac_to_Fp(leading_coeff(R), leading_coeff(Tp), q);
     199        2912 :     R = FpX_sub(R, FpX_Fp_mul(Tp, c, q), q);
     200        2912 :     return gc_upto(av, R);
     201             :   } else
     202        1694 :     return gc_GEN(av, R);
     203             : }
     204             : 
     205             : static GEN
     206       12026 : revdigits(GEN v)
     207             : {
     208       12026 :   long i, n = lg(v)-1;
     209       12026 :   GEN w = cgetg(n+2, t_POL);
     210       12026 :   w[1] = evalsigne(1)|evalvarn(0);
     211      168784 :   for (i=0; i<n; i++)
     212      156758 :     gel(w,i+2) = gel(v,n-i);
     213       12026 :   return FpXX_renormalize(w, n+2);
     214             : }
     215             : 
     216             : static GEN
     217       10094 : diff_red(GEN s, GEN A, long m, GEN T, GEN p)
     218             : {
     219       10094 :   long v, n, vT = varn(T);
     220             :   GEN Q, sQ, qS;
     221             :   pari_timer ti;
     222       10094 :   if (DEBUGLEVEL>1) timer_start(&ti);
     223       10094 :   Q = revdigits(FpX_digits(A,T,p));
     224       10094 :   n = degpol(Q);
     225       10094 :   if (DEBUGLEVEL>1) timer_printf(&ti,"reddigits");
     226       10094 :   sQ = FpXXQ_mul(s,Q,T,p);
     227       10094 :   if (DEBUGLEVEL>1) timer_printf(&ti,"redmul");
     228       10094 :   qS = RgX_shift_shallow(sQ,m-n);
     229       10094 :   v = ZX_val(sQ);
     230       10094 :   if (n > m + v)
     231             :   {
     232        4564 :     long i, l = n-m-v;
     233        4564 :     GEN rS = cgetg(l+1,t_VEC);
     234       29190 :     for (i = l-1; i >=0 ; i--)
     235       24626 :       gel(rS,i+1) = to_ZX(gel(sQ, 1+v+l-i), vT);
     236        4564 :     rS = FpXV_FpX_fromdigits(rS,T,p);
     237        4564 :     gel(qS,2) = FpX_add(FpX_mul(rS, T, p), gel(qS, 2), p);
     238        4564 :     if (DEBUGLEVEL>1) timer_printf(&ti,"redadd");
     239             :   }
     240       10094 :   return qS;
     241             : }
     242             : 
     243             : static GEN
     244       10094 : ZC_to_padic(GEN C, GEN q)
     245             : {
     246       10094 :   long i, l = lg(C);
     247       10094 :   GEN V = cgetg(l,t_COL);
     248      102914 :   for(i = 1; i < l; i++)
     249       92820 :     gel(V, i) = gadd(gel(C, i), q);
     250       10094 :   return V;
     251             : }
     252             : 
     253             : static GEN
     254        1309 : ZM_to_padic(GEN M, GEN q)
     255             : {
     256        1309 :   long i, l = lg(M);
     257        1309 :   GEN V = cgetg(l,t_MAT);
     258       11403 :   for(i = 1; i < l; i++)
     259       10094 :     gel(V, i) = ZC_to_padic(gel(M, i), q);
     260        1309 :   return V;
     261             : }
     262             : 
     263             : static GEN
     264        1743 : ZX_to_padic(GEN P, GEN q)
     265             : {
     266        1743 :   long i, l = lg(P);
     267        1743 :   GEN Q = cgetg(l, t_POL);
     268        1743 :   Q[1] = P[1];
     269        5978 :   for (i=2; i<l ;i++)
     270        4235 :     gel(Q,i) = gadd(gel(P,i), q);
     271        1743 :   return normalizepol(Q);
     272             : }
     273             : 
     274             : static GEN
     275         469 : ZXC_to_padic(GEN x, GEN q)
     276        2212 : { pari_APPLY_type(t_COL, ZX_to_padic(gel(x, i), q)) }
     277             : 
     278             : static GEN
     279         147 : ZXM_to_padic(GEN x, GEN q)
     280         616 : { pari_APPLY_same(ZXC_to_padic(gel(x, i), q)) }
     281             : 
     282             : static GEN
     283        1309 : ZlX_hyperellpadicfrobenius(GEN H, ulong p, long n)
     284             : {
     285        1309 :   pari_sp av = avma;
     286             :   long k, N, i, d;
     287             :   GEN F, s, Q, pN1, U, V;
     288             :   pari_timer ti;
     289        1309 :   if (typ(H) != t_POL) pari_err_TYPE("hyperellpadicfrobenius",H);
     290        1309 :   if (p == 2) is_sing(H, 2);
     291        1309 :   d = degpol(H);
     292        1309 :   if (d <= 0)
     293           0 :     pari_err_CONSTPOL("hyperellpadicfrobenius");
     294        1309 :   if (n < 1)
     295           0 :     pari_err_DOMAIN("hyperellpadicfrobenius","n","<", gen_1, utoi(n));
     296        1309 :   k = get_basis(p, d);
     297        1309 :   N = n + ulogint(2*n, p) + 1;
     298        1309 :   pN1 = powuu(p,N+1);
     299        1309 :   Q = RgX_to_FpX(H, pN1);
     300        1309 :   if (dvdiu(leading_coeff(Q),p)) is_sing(H, p);
     301        1309 :   setvarn(Q,1);
     302        1309 :   if (DEBUGLEVEL>1) timer_start(&ti);
     303        1309 :   s = revdigits(FpX_digits(RgX_inflate(Q, p), Q, pN1));
     304        1309 :   if (DEBUGLEVEL>1) timer_printf(&ti,"s1");
     305        1309 :   s = ZpXXQ_invsqrt(s, Q, p, N);
     306        1309 :   if (k==3)
     307          35 :     s = FpXXQ_mul(s, FpXXQ_sqr(s, Q, pN1), Q, pN1);
     308        1309 :   if (DEBUGLEVEL>1) timer_printf(&ti,"invsqrt");
     309        1309 :   get_UV(&U, &V, Q, p, N+1);
     310        1309 :   F = cgetg(d, t_MAT);
     311       11403 :   for (i = 1; i < d; i++)
     312             :   {
     313       10094 :     pari_sp av2 = avma;
     314             :     GEN M, D;
     315       10094 :     D = diff_red(s, monomial(utoipos(p),p*i-1,1),(k*p-1)>>1, Q, pN1);
     316       10094 :     if (DEBUGLEVEL>1) timer_printf(&ti,"red");
     317       10094 :     M = ZpXXQ_frob(D, U, V, (k-1)>>1, Q, p, N + 1);
     318       10094 :     if (DEBUGLEVEL>1) timer_printf(&ti,"frob");
     319       10094 :     gel(F, i) = gc_GEN(av2, RgX_to_RgC(M, d-1));
     320             :   }
     321        1309 :   return gc_upto(av, F);
     322             : }
     323             : 
     324             : GEN
     325        1309 : hyperellpadicfrobenius(GEN H, ulong p, long n)
     326             : {
     327        1309 :   pari_sp av = avma;
     328        1309 :   GEN M = ZlX_hyperellpadicfrobenius(H, p, n);
     329        1309 :   GEN q = zeropadic_shallow(utoipos(p),n);
     330        1309 :   return gc_upto(av, ZM_to_padic(M, q));
     331             : }
     332             : 
     333             : INLINE GEN
     334        2247 : FpXXX_renormalize(GEN x, long lx)  { return ZXX_renormalize(x,lx); }
     335             : 
     336             : static GEN
     337        1806 : ZpXQXXQ_red(GEN F, GEN S, GEN T, GEN q, GEN p, long e)
     338             : {
     339        1806 :   pari_sp av = avma;
     340        1806 :   long i, dF = degpol(F);
     341             :   GEN A, C;
     342        1806 :   if (signe(F)==0) return pol_0(varn(S));
     343        1806 :   A = cgetg(dF+3, t_POL);
     344        1806 :   C = pol_0(varn(S));
     345       96404 :   for(i=dF; i>0; i--)
     346             :   {
     347       94598 :     GEN Fi = FpXX_add(C, gel(F,i+2), q);
     348       94598 :     GEN R, Q = ZpXQX_divrem(Fi, S, T, q, p, e, &R);
     349       94598 :     gel(A,i+2) = R;
     350       94598 :     C = Q;
     351             :   }
     352        1806 :   gel(A,2) = FpXX_add(C, gel(F,2), q);
     353        1806 :   A[1] = F[1];
     354        1806 :   return gc_GEN(av, FpXXX_renormalize(A,dF+3));
     355             : }
     356             : 
     357             : static GEN
     358         448 : ZpXQXXQ_sqr(GEN x, GEN S, GEN T, GEN q, GEN p, long e)
     359             : {
     360         448 :   pari_sp av = avma;
     361             :   GEN z, kx;
     362         448 :   long n = degpol(S), vx = varn(S);
     363         448 :   kx = RgXX_to_Kronecker_var(x, n, vx);
     364         448 :   z = Kronecker_to_ZXX(FpXQX_sqr(kx, T, q), n, vx);
     365         448 :   setvarn(z, varn(x));
     366         448 :   return gc_upto(av, ZpXQXXQ_red(z, S, T, q, p, e));
     367             : }
     368             : 
     369             : static GEN
     370        1358 : ZpXQXXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN q, GEN p, long e)
     371             : {
     372        1358 :   pari_sp av = avma;
     373             :   GEN z, kx, ky;
     374        1358 :   long n = degpol(S), vx = varn(S);
     375        1358 :   kx = RgXX_to_Kronecker_var(x, n, vx);
     376        1358 :   ky = RgXX_to_Kronecker_var(y, n, vx);
     377        1358 :   z = Kronecker_to_ZXX(FpXQX_mul(ky, kx, T, q), n, vx);
     378        1358 :   setvarn(z, varn(x));
     379        1358 :   return gc_upto(av, ZpXQXXQ_red(z, S, T, q, p, e));
     380             : }
     381             : 
     382             : static GEN
     383         441 : FpXXX_red(GEN z, GEN p)
     384             : {
     385             :   GEN res;
     386         441 :   long i, l = lg(z);
     387         441 :   res = cgetg(l,t_POL); res[1] = z[1];
     388       17388 :   for (i=2; i<l; i++)
     389             :   {
     390       16947 :     GEN zi = gel(z,i);
     391       16947 :     if (typ(zi)==t_INT)
     392         287 :       gel(res,i) = modii(zi,p);
     393             :     else
     394       16660 :      gel(res,i) = FpXX_red(zi,p);
     395             :   }
     396         441 :   return FpXXX_renormalize(res,lg(res));
     397             : }
     398             : 
     399             : static GEN
     400         441 : FpXXX_Fp_mul(GEN z, GEN a, GEN p)
     401             : {
     402         441 :   return FpXXX_red(RgX_Rg_mul(z, a), p);
     403             : }
     404             : 
     405             : static GEN
     406         154 : ZpXQXXQ_invsqrt(GEN F, GEN S, GEN T, ulong p, long e)
     407             : {
     408         154 :   pari_sp av = avma, av2, av3;
     409             :   ulong mask;
     410         154 :   long v = varn(F), n=1;
     411             :   pari_timer ti;
     412         154 :   GEN a = pol_1(v), pp = utoipos(p);
     413         154 :   if (DEBUGLEVEL>1) timer_start(&ti);
     414         154 :   if (e <= 1) return gc_GEN(av, a);
     415         154 :   mask = quadratic_prec_mask(e);
     416         154 :   av2 = avma;
     417         595 :   for (;mask>1;)
     418             :   {
     419             :     GEN q, q2, q22, f, fq, afq;
     420         441 :     long n2 = n;
     421         441 :     n<<=1; if (mask & 1) n--;
     422         441 :     mask >>= 1;
     423         441 :     q = powuu(p,n); q2 = powuu(p,n2);
     424         441 :     av3 = avma;
     425         441 :     f = RgX_sub(ZpXQXXQ_mul(F, ZpXQXXQ_sqr(a, S, T, q, pp, n), S, T, q, pp, n), pol_1(v));
     426         441 :     fq = gc_upto(av3, RgX_Rg_divexact(f, q2));
     427         441 :     q22 = shifti(addiu(q2,1),-1);
     428         441 :     afq = FpXXX_Fp_mul(ZpXQXXQ_mul(a, fq, S, T, q2, pp, n2), q22, q2);
     429         441 :     a = RgX_sub(a, RgX_Rg_mul(afq, q2));
     430         441 :     if (gc_needed(av2,1))
     431             :     {
     432           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_invsqrt, e = %ld", n);
     433           0 :       a = gc_upto(av2, a);
     434             :     }
     435             :   }
     436         154 :   return gc_upto(av, a);
     437             : }
     438             : 
     439             : static GEN
     440        6573 : frac_to_Fq(GEN a, GEN b, GEN T, GEN q, GEN p, long e)
     441             : {
     442        6573 :   GEN d = gcdii(ZX_content(a), ZX_content(b));
     443        6573 :   return ZpXQ_div(ZX_Z_divexact(a, d), ZX_Z_divexact(b, d), T, q, p, e);
     444             : }
     445             : 
     446             : static GEN
     447         469 : ZpXQXXQ_frob(GEN F, GEN U, GEN V, long k, GEN S, GEN T, ulong p, long e)
     448             : {
     449         469 :   pari_sp av = avma, av2;
     450         469 :   long i, pr = degpol(F), dS = degpol(S), v = varn(T);
     451         469 :   GEN q = powuu(p,e), pp = utoipos(p);
     452         469 :   GEN Sp = RgX_deriv(S), Sp1 = RgX_shift_shallow(Sp, 1);
     453         469 :   GEN M = gel(F,pr+2), R;
     454         469 :   av2 = avma;
     455       52311 :   for(i = pr-1; i>=k; i--)
     456             :   {
     457             :     GEN A, B, H, Bc;
     458             :     ulong v, r;
     459       51842 :     H = ZpXQX_divrem(FpXQX_mul(V, M, T, q), S, T, q, utoipos(p), e, &B);
     460       51842 :     A = FpXX_add(FpXQX_mul(U, M, T, q), FpXQX_mul(H, Sp, T, q),q);
     461       51842 :     v = u_lvalrem(2*i+1,p,&r);
     462       51842 :     Bc = RgX_deriv(B);
     463       51842 :     Bc = FpXX_Fp_mul(ZXX_Z_divexact(Bc,powuu(p,v)), Fp_divu(gen_2, r, q), q);
     464       51842 :     M = FpXX_add(gel(F,i+2), FpXX_add(A, Bc, q), q);
     465       51842 :     if (gc_needed(av2,1))
     466             :     {
     467           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_frob, step 1, i = %ld", i);
     468           0 :       M = gc_upto(av2, M);
     469             :     }
     470             :   }
     471         469 :   if (degpol(M)<dS-1)
     472         266 :     return gc_upto(av, M);
     473         203 :   R = RgX_shift_shallow(M,dS-degpol(M)-2);
     474         203 :   av2 = avma;
     475        7175 :   for(i = degpol(M)-dS+2; i>=1; i--)
     476             :   {
     477             :     GEN B, c;
     478        6972 :     R = RgX_shift_shallow(R, 1);
     479        6972 :     gel(R,2) = gel(M, i+1);
     480        6972 :     if (degpol(R) < dS) continue;
     481        6412 :     B = FpXX_add(FpXX_mulu(S, 2*i, q), Sp1, q);
     482        6412 :     c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(B),v), T, q, pp, e);
     483        6412 :     R = FpXX_sub(R, FpXQX_FpXQ_mul(B, c, T, q), q);
     484        6412 :     if (gc_needed(av2,1))
     485             :     {
     486           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 2, i = %ld", i);
     487           0 :       R = gc_upto(av2, R);
     488             :     }
     489             :   }
     490         203 :   if (degpol(R)==dS-1)
     491             :   {
     492         161 :     GEN c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(Sp),v), T, q, pp, e);
     493         161 :     R = FpXX_sub(R, FpXQX_FpXQ_mul(Sp, c, T, q), q);
     494         161 :     return gc_upto(av, R);
     495             :   } else
     496          42 :     return gc_GEN(av, R);
     497             : }
     498             : 
     499             : static GEN
     500         469 : Fq_diff_red(GEN s, GEN A, long m, GEN S, GEN T, GEN q, GEN p, long e)
     501             : {
     502             :   long v, n;
     503             :   GEN Q, sQ, qS;
     504             :   pari_timer ti;
     505         469 :   if (DEBUGLEVEL>1) timer_start(&ti);
     506         469 :   Q = revdigits(ZpXQX_digits(A, S, T, q, p, e));
     507         469 :   n = degpol(Q);
     508         469 :   if (DEBUGLEVEL>1) timer_printf(&ti,"reddigits");
     509         469 :   sQ = ZpXQXXQ_mul(s, Q, S, T, q, p, e);
     510         469 :   if (DEBUGLEVEL>1) timer_printf(&ti,"redmul");
     511         469 :   qS = RgX_shift_shallow(sQ,m-n);
     512         469 :   v = ZX_val(sQ);
     513         469 :   if (n > m + v)
     514             :   {
     515         189 :     long i, l = n-m-v;
     516         189 :     GEN rS = cgetg(l+1,t_VEC);
     517        1547 :     for (i = l-1; i >=0 ; i--)
     518        1358 :       gel(rS,i+1) = gel(sQ, 1+v+l-i);
     519         189 :     rS = FpXQXV_FpXQX_fromdigits(rS, S, T, q);
     520         189 :     gel(qS,2) = FpXX_add(FpXQX_mul(rS, S, T, q), gel(qS, 2), q);
     521         189 :     if (DEBUGLEVEL>1) timer_printf(&ti,"redadd");
     522             :   }
     523         469 :   return qS;
     524             : }
     525             : 
     526             : static void
     527         154 : Fq_get_UV(GEN *U, GEN *V, GEN S, GEN T, ulong p, long e)
     528             : {
     529         154 :   GEN q = powuu(p, e), pp = utoipos(p), d;
     530         154 :   GEN dS = RgX_deriv(S), R  = polresultantext(S, dS), C;
     531         154 :   long v = varn(S);
     532         154 :   if (signe(FpX_red(to_ZX(gel(R,3),v), pp))==0) is_sing(S, p);
     533         147 :   C = FpXQ_red(to_ZX(gel(R, 3),v), T, q);
     534         147 :   d = ZpXQ_inv(C, T, pp, e);
     535         147 :   *U = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,1),v),T,q),d,T,q);
     536         147 :   *V = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,2),v),T,q),d,T,q);
     537         147 : }
     538             : 
     539             : static GEN
     540         469 : ZXX_to_FpXC(GEN x, long N, GEN p, long v)
     541             : {
     542             :   long i, l;
     543             :   GEN z;
     544         469 :   l = lg(x)-1; x++;
     545         469 :   if (l > N+1) l = N+1; /* truncate higher degree terms */
     546         469 :   z = cgetg(N+1,t_COL);
     547        2170 :   for (i=1; i<l ; i++)
     548             :   {
     549        1701 :     GEN xi = gel(x, i);
     550        1701 :     gel(z,i) = typ(xi)==t_INT? scalarpol(Fp_red(xi, p), v): FpX_red(xi, p);
     551             :   }
     552         511 :   for (   ; i<=N ; i++)
     553          42 :     gel(z,i) = pol_0(v);
     554         469 :   return z;
     555             : }
     556             : 
     557             : GEN
     558         154 : ZlXQX_hyperellpadicfrobenius(GEN H, GEN T, ulong p, long n)
     559             : {
     560         154 :   pari_sp av = avma;
     561             :   long k, N, i, d, N1, v0;
     562             :   GEN xp, F, s, q, Q, pN1, U, V, pp;
     563             :   pari_timer ti;
     564         154 :   if (typ(H) != t_POL) pari_err_TYPE("hyperellpadicfrobenius",H);
     565         154 :   if (p == 2) is_sing(H, 2);
     566         154 :   d = degpol(H);
     567         154 :   if (d <= 0) pari_err_CONSTPOL("hyperellpadicfrobenius");
     568         154 :   if (n < 1) pari_err_DOMAIN("hyperellpadicfrobenius","n","<", gen_1, utoi(n));
     569         154 :   k = get_basis(p, d); pp = utoipos(p);
     570         154 :   N = n + ulogint(2*n, p) + 1;
     571         154 :   q = powuu(p,n); N1 = N+1;
     572         154 :   pN1 = powuu(p,N1); T = FpX_get_red(T, pN1);
     573         154 :   Q = RgX_to_FqX(H, T, pN1);
     574         154 :   if (signe(FpX_red(to_ZX(leading_coeff(Q),varn(Q)),pp))==0) is_sing(H, p);
     575         154 :   if (DEBUGLEVEL>1) timer_start(&ti);
     576         154 :   xp = ZpX_Frobenius(T, pp, N1);
     577         154 :   s = RgX_inflate(FpXY_FpXQ_evalx(Q, xp, T, pN1), p);
     578         154 :   v0 = fetch_var_higher();
     579         154 :   s = revdigits(ZpXQX_digits(s, Q, T, pN1, pp, N1));
     580         154 :   setvarn(s, v0);
     581         154 :   if (DEBUGLEVEL>1) timer_printf(&ti,"s1");
     582         154 :   s = ZpXQXXQ_invsqrt(s, Q, T, p, N);
     583         154 :   if (k==3)
     584           7 :     s = ZpXQXXQ_mul(s, ZpXQXXQ_sqr(s, Q, T, pN1, pp, N1), Q, T, pN1, pp, N1);
     585         154 :   if (DEBUGLEVEL>1) timer_printf(&ti,"invsqrt");
     586         154 :   Fq_get_UV(&U, &V, Q, T, p, N+1);
     587         147 :   if (DEBUGLEVEL>1) timer_printf(&ti,"get_UV");
     588         147 :   F = cgetg(d, t_MAT);
     589         616 :   for (i = 1; i < d; i++)
     590             :   {
     591         469 :     pari_sp av2 = avma;
     592             :     GEN M, D;
     593         469 :     D = Fq_diff_red(s, monomial(pp,p*i-1,0),(k*p-1)>>1, Q, T, pN1, pp, N1);
     594         469 :     if (DEBUGLEVEL>1) timer_printf(&ti,"red");
     595         469 :     M = ZpXQXXQ_frob(D, U, V, (k - 1)>>1, Q, T, p, N1);
     596         469 :     if (DEBUGLEVEL>1) timer_printf(&ti,"frob");
     597         469 :     gel(F, i) = gc_upto(av2, ZXX_to_FpXC(M, d-1, q, varn(T)));
     598             :   }
     599         147 :   delete_var();
     600         147 :   return gc_upto(av, F);
     601             : }
     602             : 
     603             : GEN
     604         154 : nfhyperellpadicfrobenius(GEN H, GEN T, ulong p, long n)
     605             : {
     606         154 :   pari_sp av = avma;
     607         154 :   GEN pp = utoipos(p), q = zeropadic_shallow(pp, n);
     608         154 :   GEN M = ZlXQX_hyperellpadicfrobenius(lift_shallow(H),T,p,n);
     609         147 :   GEN MM = ZpXQM_prodFrobenius(M, T, pp, n);
     610         147 :   GEN m = gmul(ZXM_to_padic(MM, q), gmodulo(gen_1, T));
     611         147 :   return gc_upto(av, m);
     612             : }
     613             : 
     614             : GEN
     615         595 : hyperellpadicfrobenius0(GEN H, GEN Tp, long n)
     616             : {
     617             :   GEN T, p;
     618         595 :   if (!ff_parse_Tp(Tp, &T,&p,0)) pari_err_TYPE("hyperellpadicfrobenius", Tp);
     619         595 :   if (lgefint(p) > 3) pari_err_IMPL("large prime in hyperellpadicfrobenius");
     620           7 :   return T? nfhyperellpadicfrobenius(H, T, itou(p), n)
     621         602 :           : hyperellpadicfrobenius(H, itou(p), n);
     622             : }
     623             : 
     624             : static GEN
     625         392 : F2x_genus2charpoly_naive(GEN P, GEN Q)
     626             : {
     627         392 :   long a, b = 1, c = 0;
     628         392 :   GEN T = mkvecsmall2(P[1], 7);
     629         392 :   GEN PT = F2x_rem(P, T), QT = F2x_rem(Q, T);
     630         392 :   long q0 = F2x_eval(Q, 0), q1 = F2x_eval(Q, 1);
     631         392 :   long dP = F2x_degree(P), dQ = F2x_degree(Q);
     632         392 :   a= dQ<3 ? 0: dP<=5 ? 1: -1;
     633         392 :   a += (q0? F2x_eval(P, 0)? -1: 1: 0) + (q1? F2x_eval(P, 1)? -1: 1: 0);
     634         392 :   b += q0 + q1;
     635         392 :   if (lgpol(QT))
     636         308 :     c = (F2xq_trace(F2xq_div(PT, F2xq_sqr(QT, T), T), T)==0 ? 1: -1);
     637         392 :   return mkvecsmalln(6, 0UL, 4UL, 2*a, (b+2*c+a*a)>>1, a, 1UL);
     638             : }
     639             : 
     640             : static GEN
     641       19544 : Flx_difftable(GEN P, ulong p)
     642             : {
     643       19544 :   long i, n = degpol(P);
     644       19544 :   GEN V = cgetg(n+2, t_VEC);
     645       19544 :   gel(V, n+1) = P;
     646      132832 :   for(i = n; i >= 1; i--)
     647      113288 :     gel(V, i) = Flx_diff1(gel(V, i+1), p);
     648       19544 :   return V;
     649             : }
     650             : 
     651             : static GEN
     652      766955 : FlxV_Fl2_eval_pre(GEN V, GEN x, ulong D, ulong p, ulong pi)
     653             : {
     654      766955 :   long i, n = lg(V)-1;
     655      766955 :   GEN r = cgetg(n+1, t_VEC);
     656     5981661 :   for (i = 1; i <= n; i++)
     657     5214706 :     gel(r, i) = Flx_Fl2_eval_pre(gel(V, i), x, D, p, pi);
     658      766955 :   return r;
     659             : }
     660             : 
     661             : static GEN
     662    97965182 : Fl2V_next(GEN V, ulong p)
     663             : {
     664    97965182 :   long i, n = lg(V)-1;
     665    97965182 :   GEN r = cgetg(n+1, t_VEC);
     666    97965182 :   gel(r, 1) = gel(V, 1);
     667   666067388 :   for (i = 2; i <= n; i++)
     668   568102206 :     gel(r, i) = Flv_add(gel(V, i), gel(V, i-1), p);
     669    97965182 :   return r;
     670             : }
     671             : 
     672             : static GEN
     673       19544 : FlxV_constant(GEN x)
     674      152376 : { pari_APPLY_long(Flx_constant(gel(x,i))) }
     675             : 
     676             : static GEN
     677       19544 : Flx_genus2charpoly_naive(GEN H, ulong p)
     678             : {
     679       19544 :   pari_sp av = avma, av2;
     680       19544 :   ulong pi = get_Fl_red(p);
     681       19544 :   ulong i, j, p2 = p>>1, D = 2, e = ((p&2UL) == 0) ? -1 : 1;
     682       19544 :   long a, b, c = 0, n = degpol(H);
     683       19544 :   GEN t, d, k = const_vecsmall(p, -1);
     684       19544 :   k[1] = 0;
     685      786499 :   for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p)) k[j+1] = 1;
     686       35679 :   while (k[1+D] >= 0) D++;
     687       19544 :   b = n == 5 ? 0 : 1;
     688       19544 :   a = b ? k[1+Flx_lead(H)]: 0;
     689       19544 :   t = Flx_difftable(H, p);
     690       19544 :   d = FlxV_constant(t);
     691       19544 :   av2 = avma;
     692     1572998 :   for (i=0; i < p; i++)
     693             :   {
     694     1553454 :     ulong v = uel(d,n+1);
     695     1553454 :     a += k[1+v];
     696     1553454 :     b += !!v;
     697     1553454 :     if (n==6)
     698     1241520 :       uel(d,7) = Fl_add(uel(d,7), uel(d,6), p);
     699     1553454 :     uel(d,6) = Fl_add(uel(d,6), uel(d,5), p);
     700     1553454 :     uel(d,5) = Fl_add(uel(d,5), uel(d,4), p);
     701     1553454 :     uel(d,4) = Fl_add(uel(d,4), uel(d,3), p);
     702     1553454 :     uel(d,3) = Fl_add(uel(d,3), uel(d,2), p);
     703     1553454 :     uel(d,2) = Fl_add(uel(d,2), uel(d,1), p);
     704             :   }
     705      786499 :   for (j=1; j <= p2; j++)
     706             :   {
     707      766955 :     GEN V = FlxV_Fl2_eval_pre(t, mkvecsmall2(0, j), D, p, pi);
     708      766955 :     for (i=0;; i++)
     709    97965182 :     {
     710    98732137 :       GEN r2 = gel(V, n+1);
     711   197464274 :       c += uel(r2,2) ?
     712    97786633 :         (uel(r2,1) ? uel(k,1+Fl2_norm_pre(r2, D, p, pi)): e)
     713   196518770 :          : !!uel(r2,1);
     714    98732137 :       if (i == p-1) break;
     715    97965182 :       V = Fl2V_next(V, p);
     716             :     }
     717      766955 :     set_avma(av2);
     718             :   }
     719       19544 :   set_avma(av);
     720       19544 :   return mkvecsmalln(6, 0UL, p*p, a*p, (b+2*c+a*a)>>1, a, 1UL);
     721             : }
     722             : 
     723             : static GEN
     724         679 : charpoly_funceq(GEN P, GEN q)
     725             : {
     726         679 :   long i, l, g = degpol(P)>>1;
     727         679 :   GEN R, Q = gpowers0(q, g-1, q); /* Q[i] = q^i, i <= g */
     728         679 :   R = cgetg_copy(P, &l); R[1] = P[1];
     729        3164 :   for (i=0; i<g; i++) gel(R, i+2) = mulii(gel(P, 2*g-i+2), gel(Q, g-i));
     730        3843 :   for (; i<=2*g; i++) gel(R, i+2) = icopy(gel(P, i+2));
     731         679 :   return R;
     732             : }
     733             : 
     734             : static long
     735         686 : hyperell_Weil_bound(GEN q, ulong g, GEN p)
     736             : {
     737         686 :   pari_sp av = avma;
     738         686 :   GEN w = mulii(binomialuu(2*g,g),sqrtint(shifti(powiu(q, g),2)));
     739         686 :   return gc_long(av, logint(w,p) + 1);
     740             : }
     741             : 
     742             : /* return 4P + Q^2 */
     743             : static GEN
     744      401783 : check_hyperell(GEN PQ)
     745             : {
     746             :   GEN H;
     747      401783 :   if (is_vec_t(typ(PQ)) && lg(PQ)==3)
     748      332114 :     H = gadd(gsqr(gel(PQ, 2)), gmul2n(gel(PQ, 1), 2));
     749             :   else
     750       69669 :     H = gmul2n(PQ, 2);
     751      401783 :   return typ(H) == t_POL? H: NULL;
     752             : }
     753             : 
     754             : static long
     755      535427 : hyperellgenus(GEN H)
     756      535427 : { long d = degpol(H); return ((d+1)>>1)-1; }
     757             : 
     758             : static void
     759      152922 : check_hyperell_Rg(const char *fun, GEN *pW, GEN *pF)
     760             : {
     761      152922 :   GEN W = *pW, F = check_hyperell(W);
     762             :   long v;
     763      152922 :   if (!F)
     764           7 :     pari_err_TYPE(fun, W);
     765      152915 :   if (degpol(F) <= 0) pari_err_CONSTPOL(fun);
     766      152908 :   v = varn(F);
     767      152908 :   if (typ(W)==t_POL) W = mkvec2(W, pol_0(v));
     768             :   else
     769             :   {
     770      152880 :     GEN P = gel(W, 1), Q = gel(W, 2);
     771      152880 :     long g = hyperellgenus(F);
     772      152880 :     if( typ(P)!=t_POL) P = scalarpol(P, v);
     773      152880 :     if( typ(Q)!=t_POL) Q = scalarpol(Q, v);
     774      152880 :     if (degpol(P) > 2*g+2)
     775           0 :       pari_err_DOMAIN(fun, "poldegree(P)", ">", utoi(2*g+2), P);
     776      152880 :     if (degpol(Q) > g+1)
     777           0 :       pari_err_DOMAIN(fun, "poldegree(Q)", ">", utoi(g+1), Q);
     778             : 
     779      152880 :     W = mkvec2(P, Q);
     780             :   }
     781      152908 :   if (pF) *pF = F;
     782      152908 :   *pW = W;
     783      152908 : }
     784             : 
     785             : GEN
     786       20629 : hyperellcharpoly(GEN PQ)
     787             : {
     788       20629 :   pari_sp av = avma;
     789       20629 :   GEN M, R, T=NULL, pp=NULL, q;
     790       20629 :   long d, n, eps = 0;
     791             :   ulong p;
     792       20629 :   GEN H = check_hyperell(PQ);
     793       20629 :   if (!H || !RgX_is_FpXQX(H, &T, &pp) || !pp)
     794           0 :     pari_err_TYPE("hyperellcharpoly", PQ);
     795       20629 :   p = itou(pp);
     796       20629 :   if (!T)
     797             :   {
     798       20482 :     if (p==2 && is_vec_t(typ(PQ)))
     799             :     {
     800         392 :       long dP, dQ, v = varn(H);
     801         392 :       GEN P = gel(PQ,1), Q = gel(PQ,2);
     802         392 :       if (typ(P)!=t_POL)  P = scalarpol(P, v);
     803         392 :       if (typ(Q)!=t_POL)  Q = scalarpol(Q, v);
     804         392 :       dP = degpol(P); dQ = degpol(Q);
     805         392 :       if (dP<=6 && dQ <=3 && (dQ==3 || dP>=5))
     806             :       {
     807         392 :         GEN P2 = RgX_to_F2x(P), Q2 = RgX_to_F2x(Q);
     808         392 :         GEN D = F2x_add(F2x_mul(P2, F2x_sqr(F2x_deriv(Q2))), F2x_sqr(F2x_deriv(P2)));
     809         392 :         if (F2x_degree(F2x_gcd(D, Q2))) is_sing(PQ, 2);
     810         392 :         if (dP==6 && dQ<3 && F2x_coeff(P2,5)==F2x_coeff(Q2,2))
     811           0 :           is_sing(PQ, 2); /* The curve is singular at infinity */
     812         392 :         R = zx_to_ZX(F2x_genus2charpoly_naive(P2, Q2));
     813         392 :         return gc_upto(av, R);
     814             :       }
     815             :     }
     816       20090 :     H = RgX_to_FpX(H, pp);
     817       20090 :     d = degpol(H);
     818       20090 :     if (d <= 0) is_sing(H, p);
     819       20090 :     if (p > 2 && ((d == 5 && p < 17500) || (d == 6 && p < 24500)))
     820             :     {
     821       19551 :       GEN Hp = ZX_to_Flx(H, p);
     822       19551 :       if (!Flx_is_squarefree(Hp, p)) is_sing(H, p);
     823       19544 :       R = zx_to_ZX(Flx_genus2charpoly_naive(Hp, p));
     824       19544 :       return gc_upto(av, R);
     825             :     }
     826         539 :     n = hyperell_Weil_bound(pp, (d-1)>>1, pp);
     827         539 :     eps = odd(d)? 0: Fp_issquare(leading_coeff(H), pp);
     828         539 :     M = hyperellpadicfrobenius(H, p, n);
     829         539 :     R = centerlift(carberkowitz(M, 0));
     830         539 :     q = pp;
     831             :   }
     832             :   else
     833             :   {
     834             :     int fixvar;
     835         147 :     T = typ(T)==t_FFELT? FF_mod(T): RgX_to_FpX(T, pp);
     836         147 :     q = powuu(p, degpol(T));
     837         147 :     fixvar = (varncmp(varn(T),varn(H)) <= 0);
     838         147 :     if (fixvar) setvarn(T, fetch_var());
     839         147 :     H = RgX_to_FpXQX(H, T, pp);
     840         147 :     d = degpol(H);
     841         147 :     if (d <= 0) is_sing(H, p);
     842         147 :     eps = odd(d)? 0: Fq_issquare(leading_coeff(H), T, pp);
     843         147 :     n = hyperell_Weil_bound(q, (d-1)>>1, pp);
     844         147 :     M = nfhyperellpadicfrobenius(H, T, p, n);
     845         140 :     R = simplify_shallow(centerlift(liftpol_shallow(carberkowitz(M, 0))));
     846         140 :     if (fixvar) (void)delete_var();
     847             :   }
     848         679 :   if (!odd(d))
     849             :   {
     850         301 :     GEN b = get_basis(p, d) == 3 ? gen_1 : q;
     851         301 :     GEN pn = powuu(p, n);
     852         301 :     R = FpX_div_by_X_x(R, eps? b: negi(b), pn, NULL);
     853         301 :     R = FpX_center_i(R, pn, shifti(pn,-1));
     854             :   }
     855         679 :   return gc_upto(av, charpoly_funceq(R, q));
     856             : }
     857             : 
     858             : GEN
     859          70 : hyperellordinate(GEN W, GEN x)
     860             : {
     861          70 :   pari_sp av = avma;
     862          70 :   if (typ(W)==t_POL)
     863             :   {
     864             :     GEN d, y;
     865          42 :     if (typ(x)==t_INFINITY)
     866             :     {
     867          14 :       long dW = degpol(W);
     868          14 :       d = odd(dW) ? gen_0: gel(W,dW+2);
     869             :     } else
     870          28 :       d = poleval(W,x);
     871          42 :     if (gequal0(d)) { return gc_GEN(av, mkvec(d)); }
     872          35 :     if (!issquareall(d, &y)) retgc_const(av, cgetg(1, t_VEC));
     873          14 :     return gc_GEN(av, mkvec2(y, gneg(y)));
     874             :   }
     875             :   else
     876             :   {
     877             :     GEN b, c, d, rd, y, P, Q, F;
     878          28 :     check_hyperell_Rg("hyperellordinate", &W, &F);
     879          28 :     P = gel(W,1); Q = gel(W,2);
     880          28 :     if (typ(x)==t_INFINITY)
     881             :     {
     882           7 :       long dP = degpol(P), dQ = degpol(Q), g = hyperellgenus(F);
     883           7 :       c = dP < 2*g+2 ? gen_0: gel(P,dP+2);
     884           7 :       b = dQ < g+1   ? gen_0: gel(Q,dQ+2);
     885             :     } else
     886          21 :     { b = poleval(Q, x); c = poleval(P, x); }
     887          28 :     d = gadd(gsqr(b), gmul2n(c, 2));
     888          28 :     if (gequal0(d)) { return gc_GEN(av, mkvec(gmul2n(gneg(b),-1))); }
     889          21 :     if (!issquareall(d, &rd)) retgc_const(av, cgetg(1, t_VEC));
     890          14 :     y = gmul2n(gsub(rd, b), -1);
     891          14 :     return gc_GEN(av, mkvec2(y, gsub(y,rd)));
     892             :   }
     893             : }
     894             : 
     895             : GEN
     896      120721 : hyperelldisc(GEN PQ)
     897             : {
     898      120721 :   pari_sp av = avma;
     899      120721 :   GEN D, H = check_hyperell(PQ);
     900             :   long g;
     901      120721 :   if (!H || signe(H)==0) pari_err_TYPE("hyperelldisc",PQ);
     902      120721 :   g = hyperellgenus(H);
     903      120721 :   D = gmul2n(RgX_disc(H),-4*(g+1));
     904      120721 :   if (odd(degpol(H))) D = gmul(D, gsqr(leading_coeff(H)));
     905      120721 :   return gc_upto(av, D);
     906             : }
     907             : 
     908             : static long
     909      130093 : get_ep(GEN W)
     910             : {
     911      130093 :   GEN P = gel(W,1), Q = gel(W,2);
     912      130093 :   if (signe(Q)==0) return ZX_lval(P,2);
     913       89814 :   return minss(ZX_lval(P,2), ZX_lval(Q,2));
     914             : }
     915             : 
     916             : static GEN
     917       52534 : algo51(GEN W, GEN M)
     918             : {
     919       52534 :   GEN P = gel(W,1), Q = gel(W,2);
     920             :   for(;;)
     921       10647 :   {
     922       63181 :     long vP = ZX_lval(P,2);
     923       63181 :     long vQ = signe(Q) ? ZX_lval(Q,2): vP+1;
     924             :     long r;
     925             :     /* 1 */
     926       63181 :     if (vQ==0) break;
     927             :     /* 2 */
     928       36302 :     if (vP==0)
     929             :     {
     930             :       GEN H, H1;
     931             :       /* a */
     932       29714 :       RgX_even_odd(FpX_red(P,gen_2),&H, &H1);
     933       29714 :       if (signe(H1)) break;
     934             :       /* b */
     935       15035 :       P = ZX_add(P, ZX_mul(H, ZX_sub(Q, H)));
     936       15035 :       Q = ZX_sub(Q, ZX_shifti(H, 1));
     937       15035 :       vP = ZX_lval(P,2);
     938       15035 :       vQ = signe(Q) ? ZX_lval(Q,2): vP+1;
     939             :     }
     940             :     /* 2c */
     941       21623 :     if (vP==1) break;
     942             :     /* 2d */
     943       10647 :     r = minss(2*vQ, vP)>>1;
     944       10647 :     if (M) gel(M,1) = shifti(gel(M,1), r);
     945       10647 :     P = ZX_shifti(P, -2*r);
     946       10647 :     Q = ZX_shifti(Q, -r);
     947             :   }
     948       52534 :   return mkvec2(P,Q);
     949             : }
     950             : 
     951             : static GEN
     952      105506 : algo52(GEN W, GEN c, long *pt_lambda)
     953             : {
     954             :   long lambda;
     955      105506 :   GEN P = gel(W,1), Q = gel(W,2);
     956             :   for(;;)
     957      118338 :   {
     958             :     GEN H, H1;
     959             :     /* 1 */
     960      223844 :     GEN Pc = ZX_affine(P,gen_2,c), Qc = ZX_affine(Q,gen_2,c);
     961      223844 :     long mP = ZX_lval(Pc,2), mQ = signe(Qc) ? ZX_lval(Qc,2): mP+1;
     962             :     /* 2 */
     963      223844 :     if (2*mQ <= mP) { lambda = 2*mQ; break; }
     964             :     /* 3 */
     965      191223 :     if (odd(mP)) { lambda = mP; break; }
     966             :     /* 4 */
     967      129265 :     RgX_even_odd(FpX_red(ZX_shifti(Pc, -mP),gen_2),&H, &H1);
     968      129265 :     if (signe(H1)) { lambda = mP; break; }
     969             :     /* 5 */
     970      118338 :     P = ZX_add(P, ZX_mul(H, ZX_sub(Q, H)));
     971      118338 :     Q = ZX_sub(Q, ZX_shifti(H, 1));
     972             :   }
     973      105506 :   *pt_lambda = lambda;
     974      105506 :   return mkvec2(P,Q);
     975             : }
     976             : 
     977             : static long
     978      149115 : test53(long lambda, long ep, long g)
     979             : {
     980      149115 :   return (lambda <= g+1) || (odd(g) && lambda<g+3 && ep==1);
     981             : }
     982             : 
     983             : static long
     984      194492 : test55(GEN W, long ep, long g)
     985             : {
     986      194492 :   GEN P = gel(W,1), Q = gel(W,2);
     987      194492 :   GEN Pe = FpX_red(ep ? ZX_shifti(P,-1): P, gen_2);
     988      194492 :   GEN Qe = FpX_red(ep ? ZX_shifti(Q,-1): Q, gen_2);
     989      194492 :   if (ep==0)
     990             :   {
     991      153833 :     if (signe(Qe)!=0) return ZX_val(Qe) >= (g + 3)>>1;
     992       92620 :     else return ZX_val(FpX_deriv(Pe, gen_2)) >= g+1;
     993             :   }
     994             :   else
     995       40659 :     return ZX_val(Qe) >= (g+1)>>1 && ZX_val(Pe) >= g + 1;
     996             : }
     997             : 
     998             : static GEN
     999       52436 : hyperell_reverse(GEN W, long g)
    1000             : {
    1001       52436 :   return mkvec2(RgXn_recip_shallow(gel(W,1),2*g+3),
    1002       52436 :                 RgXn_recip_shallow(gel(W,2),g+2));
    1003             : }
    1004             : 
    1005             : /* [P,Q] -> [P(2x)/4^r, Q(2x)/2^r] */
    1006             : static GEN
    1007      173246 : ZX2_unscale(GEN W, long r)
    1008             : {
    1009      173246 :   GEN P = ZX_unscale2n(gel(W,1), 1);
    1010      173246 :   GEN Q = ZX_unscale2n(gel(W,2), 1);
    1011      173246 :   if (r)
    1012             :   {
    1013       30959 :     P = ZX_shifti(P, -2*r);
    1014       30959 :     Q = ZX_shifti(Q, -r);
    1015             :   }
    1016      173246 :   return mkvec2(P,Q);
    1017             : }
    1018             : /* [P,Q] -> [P(2x+c)/4^r, Q(2x+c)/2^r] */
    1019             : static GEN
    1020      167032 : ZX2_affine_unscale(GEN W, long c, long r)
    1021             : {
    1022      243807 :   if (c) W = mkvec2(ZX_Z_translate(gel(W,1), gen_1),
    1023       76775 :                     ZX_Z_translate(gel(W,2), gen_1));
    1024      167032 :   return ZX2_unscale(W, r);
    1025             : }
    1026             : 
    1027             : static GEN
    1028       52205 : algo56(GEN W, long g)
    1029             : {
    1030             :   long ep;
    1031       52205 :   GEN M = mkvec2(gen_1, matid(2)), Woo;
    1032       52205 :   W = algo51(W, M);
    1033       52205 :   Woo = hyperell_reverse(W, g);
    1034       52205 :   ep = get_ep(Woo);
    1035       52205 :   if (test55(Woo,ep,g))
    1036             :   {
    1037             :     long lambda;
    1038       11940 :     Woo = algo52(Woo, gen_0, &lambda);
    1039       11940 :     if (!test53(lambda,ep,g))
    1040             :     {
    1041        5969 :       long r = lambda>>1;
    1042        5969 :       gel(M,1) = shifti(gel(M,1), r);
    1043        5969 :       gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_0, gen_1, gen_2, gen_0));
    1044        5969 :       W = ZX2_unscale(Woo, r);
    1045             :     }
    1046             :   }
    1047             :   for(;;)
    1048       24892 :   {
    1049       77097 :     long j, ep = get_ep(W);
    1050      193603 :     for (j = 0; j < 2; j++)
    1051      141398 :       if (test55(ZX2_affine_unscale(W, j, 0), ep, g))
    1052             :       {
    1053             :         long lambda;
    1054       93090 :         GEN c = utoi(j), Wc = algo52(W, c, &lambda);
    1055       93090 :         if (!test53(lambda,ep,g))
    1056             :         {
    1057       24892 :           long r = lambda>>1;
    1058       24892 :           gel(M,1) = shifti(gel(M,1), r);
    1059       24892 :           gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_2, c, gen_0, gen_1));
    1060       24892 :           W = ZX2_affine_unscale(Wc, j, r);
    1061       24892 :           break;
    1062             :         }
    1063             :       }
    1064       77097 :     if (j==2) break;
    1065             :   }
    1066       52205 :   return mkvec2(W, M);
    1067             : }
    1068             : 
    1069             : static GEN
    1070         329 : algo56bis(GEN W, long g, long inf, long thr)
    1071             : {
    1072         329 :   pari_sp av = avma;
    1073         329 :   GEN vl = cgetg(3,t_VEC);
    1074         329 :   long nl = 1;
    1075         329 :   W = algo51(W, NULL);
    1076         329 :   if (inf)
    1077             :   {
    1078         231 :     GEN Woo = hyperell_reverse(W, g);
    1079         231 :     long ep = get_ep(Woo);
    1080         231 :     if (test55(ZX2_unscale(Woo, 0), ep, g))
    1081             :     {
    1082             :       long lambda;
    1083          70 :       Woo = algo52(Woo, gen_0, &lambda);
    1084          70 :       if (lambda == thr) gel(vl,nl++) = ZX2_unscale(Woo, lambda>>1);
    1085             :     }
    1086             :   }
    1087             :   {
    1088         329 :     long j, ep = get_ep(W);
    1089         987 :     for (j = 0; j < 2; j++)
    1090         658 :       if (test55(ZX2_affine_unscale(W, j, 0), ep, g))
    1091             :       {
    1092             :         long lambda;
    1093         406 :         GEN Wc = algo52(W, utoi(j), &lambda);
    1094         406 :         if (lambda == thr) gel(vl,nl++) = ZX2_affine_unscale(Wc, j, lambda>>1);
    1095             :       }
    1096             :   }
    1097         329 :   setlg(vl, nl);
    1098         329 :   return gc_GEN(av,vl);
    1099             : }
    1100             : 
    1101             : /* return the (degree 2) apolar invariant (the nth transvectant of P and P) */
    1102             : static GEN
    1103        1491 : ZX_apolar(GEN P, long n)
    1104             : {
    1105        1491 :   pari_sp av = avma;
    1106        1491 :   long d = degpol(P), i;
    1107        1491 :   GEN s = gen_0, g = cgetg(n+2,t_VEC);
    1108        1491 :   gel(g,1) = gen_1;
    1109       10437 :   for (i = 1; i <= n; i++) gel(g,i+1) = muliu(gel(g,i),i); /* g[i+1] = i! */
    1110       11354 :   for (i = n-d; i <= d; i++)
    1111             :   {
    1112        9863 :      GEN a = mulii(mulii(gel(g,i+1),gel(g,n-i+1)),
    1113        9863 :                    mulii(gel(P,i+2),gel(P,n-i+2)));
    1114        9863 :      s = odd(i)? subii(s, a): addii(s, a);
    1115             :   }
    1116        1491 :   return gc_INT(av,s);
    1117             : }
    1118             : 
    1119             : static GEN
    1120       54438 : algo57(GEN F, long g, GEN pr)
    1121             : {
    1122             :   long i, l;
    1123       54438 :   GEN D, C = content(F);
    1124       54438 :   GEN e = gel(core2(shifti(C,-vali(C))),2);
    1125       54438 :   GEN M = mkvec2(e, matid(2));
    1126       54438 :   long minvd = (2*g+1)>>(odd(g) ? 4:2);
    1127       54438 :   F = ZX_Z_divexact(F, sqri(e));
    1128       54438 :   D = absi(hyperelldisc(F));
    1129       54438 :   if (!pr)
    1130             :   {
    1131        1491 :     GEN A = gcdii(D, ZX_apolar(F, 2*g+2));
    1132        1491 :     pr = gel(factor(shifti(A, -vali(A))),1);
    1133             :   }
    1134       54438 :   l = lg(pr);
    1135      314809 :   for (i = 1; i < l; i++)
    1136             :   {
    1137             :     long ep;
    1138      260371 :     GEN p = gel(pr, i), ps2 = shifti(p,-1), Fe;
    1139      260371 :     if (equaliu(p,2) || Z_pval(D,p) < minvd) continue;
    1140      198135 :     ep = ZX_pvalrem(F,p, &Fe); Fe = FpX_red(Fe, p);
    1141      198135 :     if (degpol(Fe) < g+1+ep)
    1142             :     {
    1143        6406 :       GEN Fi = ZX_unscale(RgXn_recip_shallow(F,2*g+3), p);
    1144        6406 :       long lambda = ZX_pval(Fi,p);
    1145        6406 :       if (!test53(lambda,ep,g))
    1146             :       {
    1147        3815 :         GEN ppr = powiu(p,lambda>>1);
    1148        3815 :         F = ZX_Z_divexact(Fi,sqri(ppr));
    1149        3815 :         gel(M,1) = mulii(gel(M,1), ppr);
    1150        3815 :         gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_0,gen_1,p,gen_0));
    1151             :       }
    1152             :     }
    1153             :     for(;;)
    1154       25186 :     {
    1155             :       GEN Fe, R;
    1156      223321 :       long j, lR, ep = ZX_pvalrem(F,p, &Fe);
    1157      223321 :       R = FpX_roots_mult(FpX_red(Fe, p), g+2-ep, p); lR = lg(R);
    1158      235814 :       for (j = 1; j<lR; j++)
    1159             :       {
    1160       37679 :         GEN c = Fp_center(gel(R,j), p, ps2);
    1161       37679 :         GEN Fi = ZX_affine(F,p,c);
    1162       37679 :         long lambda = ZX_pval(Fi,p);
    1163       37679 :         if (!test53(lambda,ep,g))
    1164             :         {
    1165       25186 :           GEN ppr = powiu(p,lambda>>1);
    1166       25186 :           F = ZX_Z_divexact(Fi, sqri(ppr));
    1167       25186 :           gel(M,1) = mulii(gel(M,1), ppr);
    1168       25186 :           gel(M,2) = ZM2_mul(gel(M,2), mkmat22(p,c,gen_0,gen_1));
    1169       25186 :           break;
    1170             :         }
    1171             :       }
    1172      223321 :       if (j==lR) break;
    1173             :     }
    1174             :   }
    1175       54438 :   return mkvec2(F, M);
    1176             : }
    1177             : 
    1178             : /* if inf=0, ignore point at infinity */
    1179             : static GEN
    1180        3563 : algo57bis(GEN F, long g, GEN p, long inf, long thr)
    1181             : {
    1182        3563 :   pari_sp av = avma;
    1183        3563 :   GEN vl = cgetg(3,t_VEC), Fe;
    1184        3563 :   long nl = 1, ep = ZX_pvalrem(F,p, &Fe);
    1185        3563 :   Fe = FpX_red(Fe, p);
    1186             :   {
    1187        3563 :     GEN R = FpX_roots_mult(Fe, thr-ep, p);
    1188        3563 :     long j, lR = lg(R);
    1189        6496 :     for (j = 1; j<lR; j++)
    1190             :     {
    1191        2933 :       GEN Fj = ZX_affine(F, p, gel(R,j));
    1192        2933 :       long lambda = ZX_pvalrem(Fj, p, &Fj);
    1193        2933 :       if (lambda == thr) gel(vl,nl++) = odd(lambda)? ZX_Z_mul(Fj, p): Fj;
    1194             :     }
    1195             :   }
    1196        3563 :   if (inf==1 && 2*g+2-degpol(Fe) >= thr-ep)
    1197             :   {
    1198           0 :     GEN Fj = ZX_unscale(RgXn_recip_shallow(F,2*g+3), p);
    1199           0 :     long lambda = ZX_pvalrem(Fj, p, &Fj);
    1200           0 :     if (lambda == thr) gel(vl,nl++) = odd(lambda)? ZX_Z_mul(Fj, p): Fj;
    1201             :   }
    1202        3563 :   setlg(vl, nl);
    1203        3563 :   return gc_GEN(av,vl);
    1204             : }
    1205             : 
    1206             : static GEN
    1207        3892 : next_model(GEN G, long g, GEN p, long inf, long thr)
    1208             : {
    1209        4221 :   return equaliu(p,2) ? algo56bis(G, g,    inf, thr)
    1210        4221 :                       : algo57bis(G, g, p, inf, thr);
    1211             : }
    1212             : 
    1213             : static GEN
    1214        1526 : get_extremal_even(GEN F, GEN G, long g, GEN p, long *nb)
    1215             : {
    1216             :   while (1)
    1217        1274 :   {
    1218        1526 :     GEN Wi = next_model(G, g, p, 0, g+2);
    1219        1526 :     if (lg(Wi)==1) return F;
    1220        1365 :     F = gel(Wi,1); ++*nb;
    1221        1365 :     if (DEBUGLEVEL>1) err_printf("model %ld: %Ps\n", *nb, F);
    1222        1365 :     Wi = next_model(F, g, p, 0, g+1);
    1223        1365 :     if (lg(Wi)==1) return F;
    1224        1274 :     G = gel(Wi,1);
    1225             :   }
    1226             : }
    1227             : 
    1228             : static GEN
    1229           0 : get_extremal_odd(GEN F, long g, GEN p, long *nb)
    1230             : {
    1231             :   while (1)
    1232           0 :   {
    1233           0 :     GEN Wi = next_model(F, g, p, 0, g+2);
    1234           0 :     if (lg(Wi)==1) return F;
    1235           0 :     F = gel(Wi,1); ++*nb;
    1236           0 :     if (DEBUGLEVEL>1) err_printf("model %ld: %Ps\n", *nb, F);
    1237             :   }
    1238             : }
    1239             : 
    1240             : static GEN
    1241        1036 : hyperellextremalmodels_nb(GEN F, long g, GEN p, long *nb)
    1242             : {
    1243        1036 :   pari_sp av = avma;
    1244             :   GEN W, A, B;
    1245             :   long l;
    1246             : 
    1247        1036 :   *nb = 1;
    1248        1036 :   if (equaliu(p,2))
    1249             :   {
    1250         231 :     if (get_ep(F) > 0) retmkvec(gcopy(F));
    1251             :   } else
    1252             :   {
    1253         805 :     F = check_hyperell(F);
    1254         805 :     if (ZX_pval(F, p) > 0) return gc_GEN(av, mkvec(F));
    1255             :   }
    1256        1001 :   if (DEBUGLEVEL>1) err_printf("model %ld: %Ps\n", *nb, F);
    1257        1001 :   W = next_model(F, g, p, 1, odd(g)? g+2: g+1);
    1258        1001 :   l = lg(W); if (l==1) return gc_GEN(av, mkvec(F));
    1259         238 :   if (odd(g))
    1260             :   {
    1261           0 :     *nb = l-1;
    1262           0 :     A = get_extremal_odd(gel(W,1), g, p, nb);
    1263           0 :     B = l==3 ? get_extremal_odd(gel(W,2), g, p, nb) : F;
    1264             :   }
    1265             :   else
    1266             :   {
    1267         238 :     A = get_extremal_even(F, gel(W,1), g, p, nb);
    1268         238 :     B = l==3 ? get_extremal_even(F, gel(W,2), g, p, nb) : F;
    1269             :   }
    1270         238 :   return gc_GEN(av, A == B? mkvec(A): mkvec2(A, B));
    1271             : }
    1272             : 
    1273             : static GEN
    1274        1029 : hyperellextremalmodels_i(GEN F, long g, GEN p)
    1275             : {
    1276             :   long nb;
    1277        1029 :   return hyperellextremalmodels_nb(F, g, p, &nb);
    1278             : }
    1279             : 
    1280             : GEN
    1281           7 : hyperellextremalmodels(GEN PQ, GEN p)
    1282             : {
    1283           7 :   pari_sp av = avma;
    1284           7 :   GEN H = check_hyperell(PQ), W, v;
    1285             :   long g, nb;
    1286           7 :   if (!H || signe(H)==0) pari_err_TYPE("hyperellextremalmodels",PQ);
    1287           7 :   if (typ(p)!=t_INT || signe(p)<=0) pari_err_TYPE("hyperellextremalmodels",p);
    1288           7 :   g = hyperellgenus(H);
    1289           7 :   W = hyperellminimalmodel(H,NULL,mkvec(p));
    1290           7 :   v = cgetg(3, t_VEC);
    1291           7 :   gel(v, 2) = hyperellextremalmodels_nb(W, g, p, &nb);
    1292           7 :   gel(v, 1) = stoi(nb);
    1293           7 :   return gc_upto(av, v);
    1294             : }
    1295             : 
    1296             : static GEN
    1297       54452 : minimalmodel_merge(GEN W2, GEN Modd, long g, long v)
    1298             : {
    1299       54452 :   GEN P = gel(W2,1), Q = gel(W2,2);
    1300       54452 :   GEN e = gel(Modd,1), M = gel(Modd,2);
    1301       54452 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1302       54452 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1303       54452 :   GEN Bp = gpowers(B, 2*g+2);
    1304       54452 :   long f = mod4(e)==1 ? 1: -1;
    1305       54452 :   GEN m = shifti(f > 0 ? subui(1,e): addui(1,e), -2);
    1306       54452 :   GEN  m24 = subii(shifti(m,1), shifti(sqri(m),2));
    1307       54452 :   P = RgX_homogenous_evalpow(P, A, Bp, 2*g+2);
    1308       54452 :   Q = RgX_homogenous_evalpow(Q, A, Bp, g+1);
    1309       54452 :   P = ZX_Z_divexact(ZX_add(P, ZX_Z_mul(ZX_sqr(Q), m24)),sqri(e));
    1310       54452 :   if (f < 0) Q = ZX_neg(Q);
    1311       54452 :   return mkvec2(P,Q);
    1312             : }
    1313             : 
    1314             : static GEN
    1315      108890 : hyperell_redQ(GEN W)
    1316             : {
    1317      108890 :   GEN P = gel(W,1), Q = gel(W,2);
    1318      108890 :   GEN Pr, Qr = FpX_red(Q, gen_2);
    1319      108890 :   Pr = ZX_add(P, ZX_shifti(ZX_mul(ZX_sub(Q, Qr),ZX_add(Q, Qr)),-2));
    1320      108890 :   return mkvec2(Pr, Qr);
    1321             : }
    1322             : 
    1323             : static GEN
    1324       50735 : hyperellisom_finalize(GEN W1, GEN W2, GEN e, GEN M, long g, long v)
    1325             : {
    1326       50735 :   GEN Q1 = gel(W1,2), Q2 = gel(W2,2);
    1327       50735 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1328       50735 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1329       50735 :   GEN Bp = gpowers(B, g+1);
    1330       50735 :   GEN Hp = RgX_homogenous_evalpow(Q1, A, Bp, g+1);
    1331       50735 :   GEN H = RgX_mul2n(RgX_sub(RgX_Rg_mul(Q2,e), Hp),-1);
    1332       50735 :   return mkvec3(e, M, H);
    1333             : }
    1334             : 
    1335             : static void
    1336       54494 : check_hyperell_Q(const char *fun, GEN *pW, GEN *pF)
    1337             : {
    1338       54494 :   GEN W = *pW, F = check_hyperell(W);
    1339             :   long v, g;
    1340       54494 :   if (!F || !signe(F) || !RgX_is_ZX(F)) pari_err_TYPE(fun, W);
    1341       54487 :   if (!signe(ZX_disc(F))) pari_err_DOMAIN(fun,"disc(W)","==",gen_0,W);
    1342       54480 :   v = varn(F); g = hyperellgenus(F);
    1343       54480 :   if (g == 0) pari_err_DOMAIN(fun, "genus", "=", gen_0, gen_0);
    1344       54466 :   if (typ(W)==t_POL) W = mkvec2(W, pol_0(v));
    1345             :   else
    1346             :   {
    1347       45010 :     GEN P = gel(W, 1), Q = gel(W, 2);
    1348       45010 :     if (typ(P)!=t_POL) P = scalarpol_shallow(P, v);
    1349       45010 :     if (typ(Q)!=t_POL) Q = scalarpol_shallow(Q, v);
    1350       45010 :     if (!RgX_is_ZX(P) || !RgX_is_ZX(Q)) pari_err_TYPE(fun,W);
    1351       45010 :     if (degpol(P) > 2*g+2) pari_err_DOMAIN(fun, "deg(P)", ">", utoi(2*g+2), P);
    1352       45010 :     if (degpol(Q) > g+1) pari_err_DOMAIN(fun, "deg(Q)", ">", utoi(g+1), Q);
    1353       45010 :     W = mkvec2(P, Q);
    1354             :   }
    1355       54466 :   *pW = W; *pF = F;
    1356       54466 : }
    1357             : 
    1358             : GEN
    1359       54452 : hyperellminimalmodel(GEN W, GEN *pM, GEN pr)
    1360             : {
    1361       54452 :   pari_sp av = avma;
    1362             :   GEN Wr, F, WM2, F2, W2, M2, Modd, Wf, ef, Mf;
    1363             :   long g, v;
    1364       54452 :   check_hyperell_Q("hyperellminimalmodel",&W, &F);
    1365       54452 :   if (pr && (!is_vec_t(typ(pr)) || !RgV_is_ZV(pr)))
    1366          14 :     pari_err_TYPE("hyperellminimalmodel",pr);
    1367       54438 :   g = hyperellgenus(F); v = varn(F);
    1368       54438 :   Wr = hyperell_redQ(W);
    1369       54438 :   if (!pr || RgV_isin(pr, gen_2))
    1370             :   {
    1371       52205 :     WM2 = algo56(Wr,g); W2 = gel(WM2, 1); M2 = gel(WM2, 2);
    1372       52205 :     F2 = check_hyperell(W2);
    1373             :   }
    1374             :   else
    1375             :   {
    1376        2233 :     W2 = Wr; F2 = F; M2 = mkvec2(gen_1, matid(2));
    1377             :   }
    1378       54438 :   Modd = gel(algo57(F2, g, pr), 2);
    1379       54438 :   Wf = hyperell_redQ(minimalmodel_merge(W2, Modd, g, v));
    1380       54438 :   if (!pM) return gc_GEN(av, Wf);
    1381       50721 :   ef = mulii(gel(M2,1), gel(Modd,1));
    1382       50721 :   Mf = ZM2_mul(gel(M2,2), gel(Modd,2));
    1383       50721 :   *pM = hyperellisom_finalize(W, Wf, ef, Mf, g, v);
    1384       50721 :   return gc_all(av, 2, &Wf, pM);
    1385             : }
    1386             : 
    1387             : GEN
    1388          14 : hyperellminimaldisc(GEN W, GEN pr)
    1389             : {
    1390          14 :   pari_sp av = avma;
    1391          14 :   GEN C = hyperellminimalmodel(W, NULL, pr);
    1392          14 :   return gc_INT(av, hyperelldisc(C));
    1393             : }
    1394             : 
    1395             : static GEN
    1396          35 : redqfbsplit(GEN a, GEN b, GEN c, GEN d)
    1397             : {
    1398          35 :   GEN p = subii(d,b), q = shifti(a,1);
    1399          35 :   GEN U, Q, u, v, w = bezout(p, q, &u, &v);
    1400             : 
    1401          35 :   if (!equali1(w)) { p = diviiexact(p, w); q = diviiexact(q, w); }
    1402          35 :   U = mkmat22(p, negi(v), q, u);
    1403          35 :   Q = qfb3_SL2_apply(mkvec3(a,b,c), U);
    1404          35 :   b = gel(Q, 2); c = gel(Q,3);
    1405          35 :   if (signe(b) < 0) gel(U,2) = mkcol2(v, negi(u));
    1406          35 :   gel(U,2) = ZC_lincomb(gen_1, truedivii(negi(c), d), gel(U,2), gel(U,1));
    1407          35 :   return U;
    1408             : }
    1409             : 
    1410             : static GEN
    1411       16386 : polreduce(GEN P, GEN M)
    1412             : {
    1413       16386 :   long v = varn(P), dP = degpol(P), d = odd(dP) ? dP+1: dP;
    1414       16386 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1415       16386 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1416       16386 :   return RgX_homogenous_evalpow(P, A, gpowers(B, d), d);
    1417             : }
    1418             : 
    1419             : /* assume deg(P) > 2 */
    1420             : static GEN
    1421        8193 : red_Cremona_Stoll(GEN P, GEN *pM)
    1422             : {
    1423             :   GEN q1, q2, q3, M, R;
    1424        8193 :   long i, prec = nbits2prec(2*gexpo(P)) + EXTRAPRECWORD, d = degpol(P);
    1425        8193 :   GEN dP = ZX_deriv(P);
    1426             :   for (;;)
    1427           0 :   {
    1428        8193 :     GEN r = QX_complex_roots(P, prec);
    1429        8193 :     q1 = gen_0; q2 = gen_0; q3 = gen_0;
    1430       41000 :     for (i = 1; i <= d; i++)
    1431             :     {
    1432       32807 :       GEN ri = gel(r,i);
    1433       32807 :       GEN s = ginv(gabs(RgX_cxeval(dP,ri,NULL), prec));
    1434       32807 :       if (d!=4) s = gpow(s, gdivgs(gen_2,d-2), prec);
    1435       32807 :       q1 = gadd(q1, s);
    1436       32807 :       q2 = gsub(q2, gmul(real_i(ri), s));
    1437       32807 :       q3 = gadd(q3, gmul(gnorm(ri), s));
    1438             :     }
    1439        8193 :     M = lllgram(mkmat22(q1,q2,q2,q3));
    1440        8193 :     if (M && lg(M) == 3) break;
    1441           0 :     prec = precdbl(prec);
    1442             :   }
    1443        8193 :   R = polreduce(P, M);
    1444        8193 :   *pM = M;
    1445        8193 :   return R;
    1446             : }
    1447             : 
    1448             : /* assume deg(P) > 2 */
    1449             : GEN
    1450        8193 : ZX_hyperellred(GEN P, GEN *pM)
    1451             : {
    1452        8193 :   pari_sp av = avma;
    1453        8193 :   long d = degpol(P);
    1454             :   GEN q1, q2, q3, D, vD;
    1455        8193 :   GEN a = gel(P,d+2), b = gel(P,d+1), c = gel(P, d);
    1456             :   GEN M, R, M2;
    1457             : 
    1458        8193 :   q1 = muliu(sqri(a), d);
    1459        8193 :   q2 = shifti(mulii(a,b), 1);
    1460        8193 :   q3 = subii(sqri(b), shifti(mulii(a,c), 1));
    1461        8193 :   D = gcdii(gcdii(q1, q2), q3);
    1462        8193 :   if (!equali1(D))
    1463             :   {
    1464        8172 :     q1 = diviiexact(q1, D);
    1465        8172 :     q2 = diviiexact(q2, D);
    1466        8172 :     q3 = diviiexact(q3, D);
    1467             :   }
    1468        8193 :   D = qfb_disc3(q1, q2, q3);
    1469        8193 :   if (!signe(D))
    1470          49 :     M = mkmat22(gen_1, truedivii(negi(q2),shifti(q1,1)), gen_0, gen_1);
    1471        8144 :   else if (issquareall(D,&vD))
    1472          35 :     M = redqfbsplit(q1, q2, q3, vD);
    1473             :   else
    1474        8109 :     M = gel(qfbredsl2(mkqfb(q1,q2,q3,D), NULL), 2);
    1475        8193 :   R = red_Cremona_Stoll(polreduce(P, M), &M2);
    1476        8193 :   if (pM) *pM = gmul(M, M2);
    1477        8193 :   return gc_all(av, pM ? 2: 1, &R, pM);
    1478             : }
    1479             : 
    1480             : GEN
    1481          42 : hyperellred(GEN W, GEN *pM)
    1482             : {
    1483          42 :   pari_sp av = avma;
    1484             :   long g, v;
    1485             :   GEN F, M, Wf;
    1486          42 :   check_hyperell_Q("hyperellred", &W, &F);
    1487          14 :   g = hyperellgenus(F); v = varn(F);
    1488          14 :   (void) ZX_hyperellred(F, &M);
    1489          14 :   Wf = hyperell_redQ(minimalmodel_merge(W, mkvec2(gen_1, M), g, v));
    1490          14 :   if (pM) *pM = hyperellisom_finalize(W, Wf, gen_1, M, g, v);
    1491          14 :   return gc_all(av, pM ? 2: 1, &Wf, pM);
    1492             : }
    1493             : 
    1494             : static void
    1495      152859 : check_hyperell_vc(const char *fun, GEN C, long v, GEN *e, GEN *M, GEN *H)
    1496             : {
    1497      152859 :   if (typ(C) != t_VEC || lg(C) != 4) pari_err_TYPE(fun,C);
    1498      152852 :   *e = gel(C,1); *M = gel(C,2); *H = gel(C,3);
    1499      152852 :   if (typ(*M) != t_MAT || lg(*M) != 3 || lgcols(*M) != 3) pari_err_TYPE(fun,C);
    1500      152845 :   if (typ(*H) != t_POL || varncmp(varn(*H),v) > 0) *H = scalarpol_shallow(*H,v);
    1501      152845 :   if (varncmp(gvar(*M),v) <= 0) pari_err_PRIORITY(fun,*M,"<=",v);
    1502      152845 : }
    1503             : 
    1504             : GEN
    1505      108857 : hyperellchangecurve(GEN W, GEN C)
    1506             : {
    1507      108857 :   pari_sp av = avma;
    1508             :   GEN F, P, Q, A, B, Bp, e, M, H;
    1509             :   long g, v;
    1510             : 
    1511      108857 :   check_hyperell_Rg("hyperellchangecurve",&W,&F);
    1512      108843 :   P = gel(W,1); Q = gel(W,2);
    1513      108843 :   g = hyperellgenus(F); v = varn(F);
    1514      108843 :   check_hyperell_vc("hyperellchangecurve", C, v, &e, &M, &H);
    1515      108829 :   A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1516      108829 :   B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1517      108829 :   Bp = gpowers(B, 2*g+2);
    1518      108829 :   P = RgX_homogenous_evalpow(P, A, Bp, 2*g+2);
    1519      108829 :   Q = RgX_homogenous_evalpow(Q, A, Bp, g+1);
    1520      108829 :   P = RgX_Rg_div(RgX_sub(P, RgX_mul(H,RgX_add(Q,H))), gsqr(e));
    1521      108829 :   Q = RgX_Rg_div(RgX_add(Q, RgX_mul2n(H,1)), e);
    1522      108829 :   return gc_GEN(av, mkvec2(P,Q));
    1523             : }
    1524             : 
    1525             : static int
    1526         413 : checkhyperellpt_i(GEN pt, GEN *x, GEN *y, GEN *z)
    1527             : {
    1528         413 :   if (typ(pt) != t_VEC || lg(pt)<2 || lg(pt)>4)
    1529           0 :     { *x=NULL; *y=NULL; *z=NULL; return 0; }
    1530         413 :   if (lg(pt) == 2)
    1531             :   {
    1532           0 :     *x = gen_1; *y = gel(pt,1); *z = gen_0;
    1533             :   } else
    1534             :   {
    1535         413 :     *x = gel(pt,1); *y = gel(pt,2);
    1536         413 :     *z = lg(pt)==3 ? gen_1: gel(pt, 3);
    1537             :   }
    1538         413 :   return 1;
    1539             : }
    1540             : 
    1541             : static GEN
    1542         329 : wprojtoaff(GEN X, GEN Y, GEN Z, GEN pt, long g)
    1543             : {
    1544         329 :   if (lg(pt)==4) return mkvec3(X,Y,Z);
    1545         329 :   return gequal0(Z) ? mkvec(gequal0(Y) ? gen_0: gdiv(Y,gpowgs(X,g+1)))
    1546         329 :          : mkvec2(gdiv(X,Z),gequal0(Y) ? gen_0: gdiv(Y, gpowgs(Z,g+1)));
    1547             : }
    1548             : 
    1549             : GEN
    1550          70 : hyperellchangepointinv(GEN W, GEN pt, GEN C)
    1551             : {
    1552          70 :   pari_sp av = avma;
    1553             :   GEN F, e, M, H, x, y, z, X, Y,Z;
    1554             :   long g, v;
    1555             : 
    1556          70 :   check_hyperell_Rg("hyperellchangepointinv",&W,&F);
    1557          70 :   g = hyperellgenus(F); v = varn(F);
    1558          70 :   check_hyperell_vc("hyperellchangepointinv", C, v, &e, &M, &H);
    1559          70 :   if (!checkhyperellpt_i(pt,&x,&y,&z))
    1560           0 :     pari_err_TYPE("hyperellchangepointinv",pt);
    1561          70 :   X = gadd(gmul(gcoeff(M,1,1), x), gmul(gcoeff(M,1,2),z));
    1562          70 :   Z = gadd(gmul(gcoeff(M,2,1), x), gmul(gcoeff(M,2,2),z));
    1563          70 :   Y = gadd(gmul(e, y), RgX_homogenous_eval(H, x, z, g+1));
    1564          70 :   return gc_GEN(av, wprojtoaff(X,Y,Z,pt,g));
    1565             : }
    1566             : 
    1567             : GEN
    1568         259 : hyperellchangepoint(GEN W, GEN pt, GEN C)
    1569             : {
    1570         259 :   pari_sp av = avma;
    1571             :   GEN F, e, M, H, x, y, z, X, Y, Z;
    1572             :   GEN a, b, c, d, D;
    1573             :   long g, v;
    1574             : 
    1575         259 :   check_hyperell_Rg("hyperellchangepoint",&W,&F);
    1576         259 :   g = hyperellgenus(F); v = varn(F);
    1577         259 :   check_hyperell_vc("hyperellchangepoint", C, v, &e, &M, &H);
    1578         259 :   if (!checkhyperellpt_i(pt,&x,&y,&z))
    1579           0 :     pari_err_TYPE("hyperellchangepoint",pt);
    1580         259 :   a = gcoeff(M,1,1); b =  gcoeff(M,1,2);
    1581         259 :   c = gcoeff(M,2,1); d =  gcoeff(M,2,2);
    1582         259 :   Z = gsub(gmul(a, z), gmul(c, x));
    1583         259 :   X = gsub(gmul(d, x), gmul(b, z));
    1584         259 :   D = gsub(gmul(a, d), gmul(b, c));
    1585         259 :   Y = gdiv(gsub(gmul(y, gpowgs(D, g+1)), RgX_homogenous_eval(H,X,Z,g+1)), e);
    1586         259 :   return gc_GEN(av, wprojtoaff(X,Y,Z,pt,g));
    1587             : }
    1588             : 
    1589             : GEN
    1590       43561 : hyperellchangeinvert(GEN W, GEN C)
    1591             : {
    1592       43561 :   pari_sp av = avma;
    1593             :   GEN F, e, M, H, ei, Mi, Hi, X, Z, Zp;
    1594             :   long g, v;
    1595       43561 :   check_hyperell_Rg("hyperellchangeinvert",&W,&F);
    1596       43561 :   g = hyperellgenus(F); v = varn(F);
    1597       43561 :   check_hyperell_vc("hyperellchangeinvert", C, v, &e, &M, &H);
    1598       43561 :   ei = ginv(e);
    1599       43561 :   Mi = RgM_inv(M);
    1600       43561 :   X = deg1pol_shallow(gcoeff(Mi,1,1), gcoeff(Mi,1,2), v);
    1601       43561 :   Z = deg1pol_shallow(gcoeff(Mi,2,1), gcoeff(Mi,2,2), v);
    1602       43561 :   Zp = gpowers(Z, g+1);
    1603       43561 :   Hi = gmul(ei, gneg(RgX_homogenous_evalpow(H, X, Zp, g+1)));
    1604       43561 :   return gc_GEN(av, mkvec3(ei, Mi, Hi));
    1605             : }
    1606             : 
    1607             : GEN
    1608          63 : hyperellchangecompose(GEN W, GEN C1, GEN C2)
    1609             : {
    1610          63 :   pari_sp av = avma;
    1611             :   GEN F, e1, M1, H1, e2, M2, H2, H, X, Z, Zp;
    1612             :   long g, v;
    1613          63 :   check_hyperell_Rg("hyperellchangecompose",&W,&F);
    1614          63 :   g = hyperellgenus(F); v = varn(F);
    1615          63 :   check_hyperell_vc("hyperellchangecompose", C1, v, &e1, &M1, &H1);
    1616          63 :   check_hyperell_vc("hyperellchangecompose", C2, v, &e2, &M2, &H2);
    1617          63 :   X = deg1pol_shallow(gcoeff(M2,1,1), gcoeff(M2,1,2), v);
    1618          63 :   Z = deg1pol_shallow(gcoeff(M2,2,1), gcoeff(M2,2,2), v);
    1619          63 :   Zp = gpowers(Z, g+1);
    1620          63 :   H = gadd(gmul(e1,H2),RgX_homogenous_evalpow(H1, X, Zp, g+1));
    1621          63 :   return gc_GEN(av, mkvec3(gmul(e1,e2), gmul(M1, M2), H));
    1622             : }
    1623             : 
    1624             : int
    1625          84 : hyperellisoncurve(GEN W, GEN P)
    1626             : {
    1627          84 :   pari_sp av = avma;
    1628             :   GEN x, y, z, F;
    1629             :   long g;
    1630             :   int res;
    1631          84 :   check_hyperell_Rg("hyperellisoncurve",&W,&F);
    1632          84 :   g = hyperellgenus(F);
    1633          84 :   if (!checkhyperellpt_i(P,&x,&y,&z)) pari_err_TYPE("hyperellisoncurve",P);
    1634          84 :   if (typ(W)==t_POL)
    1635           0 :     res = gequal(gsqr(y), RgX_homogenous_eval(W,x,z,2*g+2));
    1636             :   else
    1637             :   {
    1638             :     GEN zp;
    1639          84 :     if (typ(W)!=t_VEC || lg(W)!=3) pari_err_TYPE("hyperellisoncurve",W);
    1640          84 :     zp = gpowers(z, 2*g+2);
    1641          84 :     res = gequal(gmul(y, gadd(y,RgX_homogenous_evalpow(gel(W,2), x,zp,g+1))),
    1642          84 :           RgX_homogenous_evalpow(gel(W,1),x,zp,2*(g+1)));
    1643             :   }
    1644          84 :   return gc_int(av, res);
    1645             : }
    1646             : 
    1647             : /****************************************************************************/
    1648             : /***                                                                      ***/
    1649             : /***                        genus2charpoly                                ***/
    1650             : /***                                                                      ***/
    1651             : /****************************************************************************/
    1652             : 
    1653             : /* Half stable reduction */
    1654             : 
    1655             : static long
    1656         588 : Zst_val(GEN P, GEN f, GEN p, long vt, GEN *pR)
    1657             : {
    1658         588 :   pari_sp av = avma;
    1659         588 :   long v = varn(P);
    1660             :   while(1)
    1661        1260 :   {
    1662        1848 :     long i, j, dm = LONG_MAX;
    1663        1848 :     GEN Pm = NULL;
    1664        1848 :     long dP = degpol(P);
    1665        7532 :     for (i = 0; i <= minss(dP, dm); i++)
    1666             :     {
    1667        5684 :       GEN Py = gel(P, i+2);
    1668        5684 :       if (signe(Py))
    1669             :       {
    1670        4186 :         if (typ(Py)==t_POL)
    1671             :         {
    1672        3864 :           long dPy = degpol(Py);
    1673       12502 :           for (j = 0; j <= minss(dPy, dm-i); j++)
    1674             :           {
    1675        8638 :             GEN c = gel(Py, j+2);
    1676        8638 :             if (signe(c))
    1677             :             {
    1678        3556 :                 if (i+j < dm)
    1679             :                 {
    1680        1848 :                   dm = i+j;
    1681        1848 :                   Pm = monomial(gen_1, dm, v);
    1682        1848 :                   gel(Pm,dm+2) = gen_0;
    1683             :                 }
    1684        3556 :                 gel(Pm,i+2) = c;
    1685             :             }
    1686             :           }
    1687             :         } else
    1688             :         {
    1689         322 :           if (i < dm)
    1690             :           {
    1691          77 :             dm = i;
    1692          77 :             Pm = monomial(Py, dm, v);
    1693             :           }
    1694             :           else
    1695         245 :             gel(Pm, i+2) = Py;
    1696             :         }
    1697             :       }
    1698             :     }
    1699        1848 :     Pm = RgX_renormalize(Pm);
    1700        1848 :     if (ZX_pval(Pm,p)==0)
    1701             :     {
    1702         588 :       *pR = gc_GEN(av, P);
    1703         588 :       return dm;
    1704             :     }
    1705        1260 :     Pm = RgX_homogenize_deg(Pm, dm, vt);
    1706        1260 :     P = gadd(gsub(P, Pm), gmul(f, ZXX_Z_divexact(Pm, p)));
    1707             :   }
    1708             : }
    1709             : 
    1710             : static long
    1711         588 : Zst_normval(GEN P, GEN f, GEN p, long vt, GEN *pR)
    1712             : {
    1713         588 :   long v = Zst_val(P, f, p, vt, pR);
    1714         588 :   long e = RgX_val(*pR)>>1;
    1715         588 :   if (e > 0)
    1716             :   {
    1717           0 :     v -= 2*e;
    1718           0 :     *pR = RgX_shift(*pR, -2*e);
    1719             :   }
    1720         588 :   return v;
    1721             : }
    1722             : 
    1723             : static GEN
    1724        1176 : RgXY_swapsafe(GEN P, long v1, long v2)
    1725             : {
    1726        1176 :   if (varn(P)==v2)
    1727             :   {
    1728          77 :     P = shallowcopy(P); setvarn(P,v1); return P;
    1729             :   } else
    1730        1099 :     return RgXY_swap(P, RgXY_degreex(P), v2);
    1731             : }
    1732             : 
    1733             : static GEN
    1734         588 : Zst_red1(GEN P, GEN f, GEN p, long vt)
    1735             : {
    1736         588 :   pari_sp av = avma;
    1737             :   GEN r, f1, f2, P1, P2;
    1738         588 :   long vs = varn(P);
    1739         588 :   long w = Zst_normval(P, f, p, vt, &r), ww = w-odd(w);
    1740         588 :   GEN st = monomial(pol_x(vt), 1, vs);
    1741         588 :   f1 = gsubst(f, vt, st);
    1742         588 :   P1 = gsubst(gdiv(r, monomial(gen_1,ww,vs)),vt,st);
    1743         588 :   f2 = gsubst(f, vs, st);
    1744         588 :   P2 = gsubst(gdiv(r, monomial(gen_1,ww,vt)),vs,st);
    1745         588 :   f2 = RgXY_swapsafe(f2, vs, vt);
    1746         588 :   P2 = RgXY_swapsafe(P2, vs, vt);
    1747         588 :   return gc_GEN(av, mkvec4(P1, f1, P2, f2));
    1748             : }
    1749             : 
    1750             : static GEN
    1751        1176 : Zst_reduce(GEN P, GEN p, long vt, long *pv)
    1752             : {
    1753             :   GEN C;
    1754        1176 :   long v = RgX_val(P);
    1755        1176 :   *pv = v + ZXX_pvalrem(RgX_shift(P, -v), p, &P);
    1756        1176 :   C = constant_coeff(P);
    1757        1176 :   C = typ(C) == t_POL ? C: scalarpol_shallow(C, vt);
    1758        1176 :   return FpX_red(C, p);
    1759             : }
    1760             : 
    1761             : static GEN
    1762         588 : Zst_red3(GEN C, GEN p, long vt)
    1763             : {
    1764             :   while(1)
    1765         511 :   {
    1766         588 :     GEN P1 = gel(C,1), f1 = gel(C,2), Poo = gel(C,3), foo= gel(C,4);
    1767             :     long e;
    1768         588 :     GEN Qoop = Zst_reduce(Poo, p, vt, &e), Qp, R;
    1769         588 :     if (RgX_val(Qoop) >= 3-e)
    1770             :     {
    1771           0 :       C = Zst_red1(Poo, foo, p, vt);
    1772         511 :       continue;
    1773             :     }
    1774         588 :     Qp = Zst_reduce(P1, p, vt, &e);
    1775         588 :     R = FpX_roots_mult(Qp, 3-e, p);
    1776         588 :     if (lg(R) > 1)
    1777         511 :     {
    1778         511 :       GEN xz = deg1pol_shallow(gen_1, gel(R,1), vt);
    1779         511 :       C = Zst_red1(gsubst(P1, vt, xz), gsubst(f1, vt, xz), p, vt);
    1780         511 :       continue;
    1781             :     }
    1782          77 :     return Qp;
    1783             :   }
    1784             : }
    1785             : 
    1786             : static GEN
    1787          77 : genus2_halfstablemodel_i(GEN P, GEN p, long vt)
    1788             : {
    1789             :   GEN Qp, R, Poo, Qoop;
    1790          77 :   long e = ZX_pvalrem(P, p, &Qp);
    1791          77 :   R = FpX_roots_mult(FpX_red(Qp,p), 4-e, p);
    1792          77 :   if (lg(R) > 1)
    1793             :   {
    1794          77 :     GEN C = Zst_red1(ZX_Z_translate(P, gel(R,1)), pol_x(vt), p, vt);
    1795          77 :     return Zst_red3(C, p, vt);
    1796             :   }
    1797           0 :   Poo = RgXn_recip_shallow(P, 7);
    1798           0 :   e = ZX_pvalrem(Poo, p, &Qoop);
    1799           0 :   Qoop = FpX_red(Qoop,p);
    1800           0 :   if (RgX_val(Qoop)>=4-e)
    1801             :   {
    1802           0 :     GEN C = Zst_red1(Poo, pol_x(vt), p, vt);
    1803           0 :     return Zst_red3(C, p, vt);
    1804             :   }
    1805           0 :   return gcopy(P);
    1806             : }
    1807             : 
    1808             : static GEN
    1809          77 : genus2_halfstablemodel(GEN P, GEN p)
    1810             : {
    1811          77 :   pari_sp av = avma;
    1812          77 :   long vt = fetch_var(), vs = varn(P);
    1813          77 :   GEN S = genus2_halfstablemodel_i(P, p, vt);
    1814          77 :   setvarn(S, vs); delete_var();
    1815          77 :   return gc_GEN(av, S);
    1816             : }
    1817             : 
    1818             : /* semi-stable reduction */
    1819             : 
    1820             : static GEN
    1821        1015 : genus2_redmodel(GEN P, GEN p)
    1822             : {
    1823             :   GEN LP, U, F;
    1824             :   long i, k, r;
    1825        1015 :   if (degpol(P) < 0) return mkvec2(cgetg(1, t_COL), P);
    1826         980 :   F = FpX_factor_squarefree(P, p);
    1827         980 :   r = lg(F); U = NULL;
    1828        3416 :   for (i = k = 1; i < r; i++)
    1829             :   {
    1830        2436 :     GEN f = gel(F,i);
    1831        2436 :     long df = degpol(f);
    1832        2436 :     if (!df) continue;
    1833        1687 :     if (odd(i)) U = U? FpX_mul(U, f, p): f;
    1834        1687 :     if (i > 1) gel(F,k++) = df == 1? mkcol(f): gel(FpX_factor(f, p), 1);
    1835             :   }
    1836         980 :   LP = leading_coeff(P);
    1837         980 :   if (!U)
    1838         154 :     U = scalarpol_shallow(LP, varn(P));
    1839             :   else
    1840             :   {
    1841         826 :     GEN LU = leading_coeff(U);
    1842         826 :     if (!equalii(LU, LP)) U = FpX_Fp_mul(U, Fp_div(LP, LU, p), p);
    1843             :   }
    1844         980 :   setlg(F,k); if (k > 1) F = shallowconcat1(F);
    1845         980 :   return mkvec2(F, U);
    1846             : }
    1847             : 
    1848             : static GEN
    1849        5852 : xdminusone(long d)
    1850             : {
    1851        5852 :   return gsub(pol_xn(d, 0),gen_1);
    1852             : }
    1853             : 
    1854             : static GEN
    1855         623 : ellfromeqncharpoly(GEN P, GEN Q, GEN p)
    1856             : {
    1857             :   long v;
    1858             :   GEN E, F, t, y;
    1859         623 :   v = fetch_var();
    1860         623 :   y = pol_x(v);
    1861         623 :   F = gsub(gadd(ZX_sqr(y), gmul(y, Q)), P);
    1862         623 :   E = ellinit(ellfromeqn(F), p, DEFAULTPREC);
    1863         623 :   delete_var();
    1864         623 :   t = ellcharpoly(E, p);
    1865         623 :   obj_free(E);
    1866         623 :   return t;
    1867             : }
    1868             : 
    1869             : static GEN
    1870           0 : nfellcharpoly(GEN e, GEN T, GEN p)
    1871             : {
    1872             :   GEN nf, E, t;
    1873           0 :   e = shallowcopy(e);
    1874           0 :   nf = nfinit(mkvec2(T, mkvec(p)), DEFAULTPREC);
    1875             :   while(1)
    1876             :   {
    1877           0 :     E = ellinit(e, nf, DEFAULTPREC);
    1878           0 :     if (lg(E)!=1) break;
    1879           0 :     gel(e,5) = gadd(gel(e,5), p);
    1880             :   }
    1881           0 :   t = elleulerf(E, p);
    1882           0 :   obj_free(E);
    1883           0 :   return RgX_recip(ginv(t));
    1884             : }
    1885             : 
    1886             : static GEN
    1887           0 : genus2_red5(GEN P, GEN T, GEN p)
    1888             : {
    1889           0 :   long vx = varn(P), vy = varn(T);
    1890           0 :   GEN f = shallowcopy(T), pi = shifti(p,-1);
    1891           0 :   setvarn(f, vx);
    1892             :   while(1)
    1893           0 :   {
    1894             :     GEN Pr, R, r, Rs;
    1895           0 :     long v = ZXX_pvalrem(P, p, &Pr);
    1896           0 :     R = FpXQX_roots_mult(Pr, 2-v, T, p);
    1897           0 :     if (lg(R)==1) return P;
    1898           0 :     r = FpX_center(gel(R,1), p, pi);
    1899           0 :     Pr = RgX_affine(P, p, r);
    1900           0 :     setvarn(r, vx);
    1901           0 :     f = RgX_Rg_div(gsub(f, r), p);
    1902           0 :     Rs = RgX_rem(RgXY_swap(Pr, 3, vy), gsub(f, pol_x(vy)));
    1903           0 :     Pr = RgXY_swap(Rs, 3, vy);
    1904           0 :     if (ZXX_pvalrem(Pr, sqri(p), &Pr)==0) return P;
    1905           0 :     P = Pr;
    1906             :   }
    1907             : }
    1908             : 
    1909             : static GEN
    1910        1029 : genus2_type5(GEN P, GEN p)
    1911             : {
    1912             :   GEN E, F, T, a, a2, Q;
    1913             :   long v;
    1914        1029 :   if (equaliu(p, 2))
    1915         224 :     (void) ZXX_pvalrem(P, sqri(p), &P);
    1916        1029 :   (void) ZX_pvalrem(P, p, &F);
    1917        1029 :   F = FpX_red(F, p);
    1918        1029 :   if (degpol(F) < 1) return NULL;
    1919        1015 :   F = FpX_factor(F, p);
    1920        1015 :   if (mael(F,2,1) != 3 || degpol(gmael(F,1,1)) != 2) return NULL;
    1921           0 :   T = gmael(F, 1, 1);
    1922           0 :   v = fetch_var_higher();
    1923           0 :   Q = RgV_to_RgX(ZX_digits(P, T), v);
    1924           0 :   Q = genus2_red5(Q, T, p);
    1925           0 :   a = gel(Q,5); a2 = ZX_sqr(a);
    1926           0 :   E = mkvec5(gen_0, gel(Q,4), gen_0, ZX_mul(gel(Q,3),a), ZX_mul(gel(Q,2),a2));
    1927           0 :   delete_var();
    1928           0 :   return nfellcharpoly(E, T, p);
    1929             : }
    1930             : 
    1931             : /* Assume P has semistable reduction at p */
    1932             : static GEN
    1933        1015 : genus2_eulerfact_semistable(GEN P, GEN p)
    1934             : {
    1935        1015 :   GEN Pp = FpX_red(P, p);
    1936        1015 :   GEN GU = genus2_redmodel(Pp, p);
    1937        1015 :   long d = 6-degpol(Pp), v = d/2, w = odd(d);
    1938             :   GEN abe, tor;
    1939        1015 :   GEN ki, kp = pol_1(0), kq = pol_1(0);
    1940        1015 :   GEN F = gel(GU,1), Q = gel(GU,2);
    1941        1015 :   long dQ = degpol(Q), lF = lg(F)-1;
    1942             : 
    1943           7 :   abe = dQ >= 5 ? hyperellcharpoly(gmul(Q,gmodulo(gen_1,p)))
    1944        2023 :       : dQ >= 3 ? ellfromeqncharpoly(Q,gen_0,p)
    1945        1008 :                 : pol_1(0);
    1946         861 :   ki = dQ != 0 ? xdminusone(1)
    1947        1169 :               : Fp_issquare(gel(Q,2),p) ? ZX_sqr(xdminusone(1))
    1948         154 :                                         : xdminusone(2);
    1949        1015 :   if (lF)
    1950             :   {
    1951             :     long i;
    1952        2100 :     for(i=1; i <= lF; i++)
    1953             :     {
    1954        1183 :       GEN Fi = gel(F, i);
    1955        1183 :       long d = degpol(Fi);
    1956        1183 :       GEN e = FpX_rem(Q, Fi, p);
    1957        2100 :       GEN kqf = lgpol(e)==0 ? xdminusone(d):
    1958        1561 :                 FpXQ_issquare(e, Fi, p) ? ZX_sqr(xdminusone(d))
    1959         917 :                                         : xdminusone(2*d);
    1960        1183 :       kp = gmul(kp, xdminusone(d));
    1961        1183 :       kq = gmul(kq, kqf);
    1962             :     }
    1963             :   }
    1964        1015 :   if (v)
    1965             :   {
    1966         273 :     GEN kqoo = w==1 ? xdminusone(1):
    1967          21 :                Fp_issquare(leading_coeff(Q), p)? ZX_sqr(xdminusone(1))
    1968          14 :                                               : xdminusone(2);
    1969         259 :     kp = gmul(kp, xdminusone(1));
    1970         259 :     kq = gmul(kq, kqoo);
    1971             :   }
    1972        1015 :   tor = RgX_div(ZX_mul(xdminusone(1), kq), ZX_mul(ki, kp));
    1973        1015 :   return ZX_mul(abe, tor);
    1974             : }
    1975             : 
    1976             : GEN
    1977        1428 : genus2_eulerfact(GEN P, GEN p, long ra, long rt)
    1978             : {
    1979        1428 :   pari_sp av = avma;
    1980             :   GEN W, R, E;
    1981        1428 :   long d = 2*ra+rt;
    1982        1428 :   if (d == 0) return pol_1(0);
    1983         805 :   R = genus2_type5(P, p);
    1984         805 :   if (R) return R;
    1985         805 :   W = hyperellextremalmodels_i(P, 2, p);
    1986         805 :   if (lg(W) < 3)
    1987             :   {
    1988         672 :     GEN F = genus2_eulerfact_semistable(P,p);
    1989         672 :     if (degpol(F)!=d)
    1990             :     {
    1991          77 :       GEN S = genus2_halfstablemodel(P, p);
    1992          77 :       F = genus2_eulerfact_semistable(S, p);
    1993          77 :       if (degpol(F)!=d) pari_err_BUG("genus2charpoly");
    1994             :     }
    1995         672 :     return F;
    1996             :   }
    1997         133 :   E =  gmul(genus2_eulerfact_semistable(gel(W,1),p),
    1998         133 :             genus2_eulerfact_semistable(gel(W,2),p));
    1999         133 :   return gc_upto(av, E);
    2000             : }
    2001             : 
    2002             : /*   p = 2  */
    2003             : 
    2004             : static GEN
    2005         238 : F2x_genus2_find_trans(GEN P, GEN Q, GEN F)
    2006             : {
    2007         238 :   pari_sp av = avma;
    2008         238 :   long i, d = F2x_degree(F), v = P[1];
    2009             :   GEN M, C, V;
    2010         238 :   M = cgetg(d+1, t_MAT);
    2011         798 :   for (i=1; i<=d; i++)
    2012             :   {
    2013         560 :     GEN Mi = F2x_rem(F2x_add(F2x_shift(Q,i-1), monomial_F2x(2*i-2,v)), F);
    2014         560 :     gel(M,i) = F2x_to_F2v(Mi, d);
    2015             :   }
    2016         238 :   C = F2x_to_F2v(F2x_rem(P, F), d);
    2017         238 :   V = F2m_F2c_invimage(M, C);
    2018         238 :   return gc_leaf(av, F2v_to_F2x(V, v));
    2019             : }
    2020             : 
    2021             : static GEN
    2022         280 : F2x_genus2_trans(GEN P, GEN Q, GEN H)
    2023             : {
    2024         280 :   return F2x_add(P,F2x_add(F2x_mul(H,Q), F2x_sqr(H)));
    2025             : }
    2026             : 
    2027             : static GEN
    2028         693 : F2x_genus_redoo(GEN P, GEN Q, long k)
    2029             : {
    2030         693 :   if (F2x_degree(P)==2*k)
    2031             :   {
    2032         126 :     long c = F2x_coeff(P,2*k-1), dQ = F2x_degree(Q);
    2033         126 :     if ((dQ==k-1 && c==1) || (dQ<k-1 && c==0))
    2034          42 :      return F2x_genus2_trans(P, Q, monomial_F2x(k, P[1]));
    2035             :   }
    2036         651 :   return P;
    2037             : }
    2038             : 
    2039             : static GEN
    2040         434 : F2x_pseudodisc(GEN P, GEN Q)
    2041             : {
    2042         434 :   GEN dP = F2x_deriv(P), dQ = F2x_deriv(Q);
    2043         434 :   return F2x_gcd(Q, F2x_add(F2x_mul(P, F2x_sqr(dQ)), F2x_sqr(dP)));
    2044             : }
    2045             : 
    2046             : static GEN
    2047         231 : F2x_genus_red(GEN P, GEN Q)
    2048             : {
    2049             :   long dP, dQ;
    2050             :   GEN F, FF;
    2051         231 :   P = F2x_genus_redoo(P, Q, 3);
    2052         231 :   P = F2x_genus_redoo(P, Q, 2);
    2053         231 :   P = F2x_genus_redoo(P, Q, 1);
    2054         231 :   dP = F2x_degree(P);
    2055         231 :   dQ = F2x_degree(Q);
    2056         231 :   FF = F = F2x_pseudodisc(P,Q);
    2057         434 :   while(F2x_degree(F)>0)
    2058             :   {
    2059         203 :     GEN M = gel(F2x_factor(F),1);
    2060         203 :     long i, l = lg(M);
    2061         441 :     for(i=1; i<l; i++)
    2062             :     {
    2063         238 :       GEN R = F2x_sqr(gel(M,i));
    2064         238 :       GEN H = F2x_genus2_find_trans(P, Q, R);
    2065         238 :       P = F2x_div(F2x_genus2_trans(P, Q, H), R);
    2066         238 :       Q = F2x_div(Q, gel(M,i));
    2067             :     }
    2068         203 :     F = F2x_pseudodisc(P, Q);
    2069             :   }
    2070         231 :   return mkvec4(P,Q,FF,mkvecsmall2(dP,dQ));
    2071             : }
    2072             : 
    2073             : /* Number of solutions of x^2+b*x+c */
    2074             : static long
    2075         210 : F2xqX_quad_nbroots(GEN b, GEN c, GEN T)
    2076             : {
    2077         210 :   if (lgpol(b) > 0)
    2078             :   {
    2079         147 :     GEN d = F2xq_div(c, F2xq_sqr(b, T), T);
    2080         147 :     return F2xq_trace(d, T)? 0: 2;
    2081             :   }
    2082             :   else
    2083          63 :     return 1;
    2084             : }
    2085             : 
    2086             : static GEN
    2087         231 : genus2_eulerfact2_semistable(GEN PQ)
    2088             : {
    2089         231 :   GEN V = F2x_genus_red(ZX_to_F2x(gel(PQ, 1)), ZX_to_F2x(gel(PQ, 2)));
    2090         231 :   GEN P = gel(V, 1), Q = gel(V, 2);
    2091         231 :   GEN F = gel(V, 3), v = gel(V, 4);
    2092             :   GEN abe, tor;
    2093         231 :   GEN ki, kp = pol_1(0), kq = pol_1(0);
    2094         231 :   long dP = F2x_degree(P), dQ = F2x_degree(Q), d = maxss(dP, 2*dQ);
    2095         231 :   if (!lgpol(F)) return pol_1(0);
    2096         259 :   ki = dQ!=0 || dP>0 ? xdminusone(1):
    2097          49 :       dP==-1 ? ZX_sqr(xdminusone(1)): xdminusone(2);
    2098         420 :   abe = d>=5? hyperellcharpoly(gmul(PQ,gmodulss(1,2))):
    2099         210 :         d>=3? ellfromeqncharpoly(F2x_to_ZX(P), F2x_to_ZX(Q), gen_2):
    2100          70 :         pol_1(0);
    2101         210 :   if (lgpol(F))
    2102             :   {
    2103         210 :     GEN M = gel(F2x_factor(F), 1);
    2104         210 :     long i, lF = lg(M)-1;
    2105         420 :     for(i=1; i <= lF; i++)
    2106             :     {
    2107         210 :       GEN Fi = gel(M, i);
    2108         210 :       long d = F2x_degree(Fi);
    2109         210 :       long nb  = F2xqX_quad_nbroots(F2x_rem(Q, Fi), F2x_rem(P, Fi), Fi);
    2110         357 :       GEN kqf = nb==1 ? xdminusone(d):
    2111          63 :                 nb==2 ? ZX_sqr(xdminusone(d))
    2112         147 :                       : xdminusone(2*d);
    2113         210 :       kp = gmul(kp, xdminusone(d));
    2114         210 :       kq = gmul(kq, kqf);
    2115             :     }
    2116             :   }
    2117         210 :   if (maxss(v[1],2*v[2])<5)
    2118             :   {
    2119          70 :     GEN kqoo = v[1]>2*v[2] ? xdminusone(1):
    2120           7 :                v[1]<2*v[2] ? ZX_sqr(xdminusone(1))
    2121          21 :                            : xdminusone(2);
    2122          49 :     kp = gmul(kp, xdminusone(1));
    2123          49 :     kq = gmul(kq, kqoo);
    2124             :   }
    2125         210 :   tor = RgX_div(ZX_mul(xdminusone(1),kq), ZX_mul(ki, kp));
    2126         210 :   return ZX_mul(abe, tor);
    2127             : }
    2128             : 
    2129             : GEN
    2130         224 : genus2_eulerfact2(GEN F, GEN PQ)
    2131             : {
    2132         224 :   pari_sp av = avma;
    2133         224 :   GEN W, R = genus2_type5(F, gen_2), E;
    2134         224 :   if (R) return R;
    2135         224 :   W = hyperellextremalmodels_i(PQ, 2, gen_2);
    2136         224 :   if (lg(W) < 3) return genus2_eulerfact2_semistable(PQ);
    2137           7 :   E = gmul(genus2_eulerfact2_semistable(gel(W,1)),
    2138           7 :            genus2_eulerfact2_semistable(gel(W,2)));
    2139           7 :   return gc_upto(av, E);
    2140             : }
    2141             : 
    2142             : GEN
    2143         889 : genus2charpoly(GEN G, GEN p)
    2144             : {
    2145         889 :   pari_sp av = avma;
    2146         889 :   GEN gr = genus2red(G, p), F;
    2147         889 :   GEN PQ = gel(gr, 3), L = gel(gr, 4), r = gel(L, 4);
    2148         889 :   GEN P = gadd(gsqr(gel(PQ, 2)), gmul2n(gel(PQ, 1), 2));
    2149         889 :   if (equaliu(p,2))
    2150           7 :     F = genus2_eulerfact2(P, PQ);
    2151             :   else
    2152         882 :     F = genus2_eulerfact(P,p, r[1],r[2]);
    2153         889 :   return gc_upto(av, F);
    2154             : }

Generated by: LCOV version 1.16