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.14.0 lcov report (development 27775-aca467eab2) Lines: 806 835 96.5 %
Date: 2022-07-03 07:33:15 Functions: 70 70 100.0 %
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 gerepilecopy(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 gerepileupto(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 gerepileupto(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 gerepilecopy(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 = gerepileupto(av2, a);
     118             :     }
     119             :   }
     120        1309 :   return gerepileupto(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 = gerepileupto(av2, M);
     175             :     }
     176             :   }
     177       10094 :   if (degpol(M)<dT-1)
     178        5488 :     return gerepileupto(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 = gerepileupto(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 gerepileupto(av, R);
     201             :   } else
     202        1694 :     return gerepilecopy(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) = gerepilecopy(av2, RgX_to_RgC(M, d-1));
     320             :   }
     321        1309 :   return gerepileupto(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(utoipos(p),n);
     330        1309 :   return gerepileupto(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 gerepilecopy(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);
     363         448 :   kx = RgXX_to_Kronecker(x, n);
     364         448 :   z = Kronecker_to_ZXX(FpXQX_sqr(kx, T, q), n, varn(S));
     365         448 :   return gerepileupto(av, ZpXQXXQ_red(z, S, T, q, p, e));
     366             : }
     367             : 
     368             : static GEN
     369        1358 : ZpXQXXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN q, GEN p, long e)
     370             : {
     371        1358 :   pari_sp av = avma;
     372             :   GEN z, kx, ky;
     373        1358 :   long n = degpol(S);
     374        1358 :   kx = RgXX_to_Kronecker(x, n);
     375        1358 :   ky = RgXX_to_Kronecker(y, n);
     376        1358 :   z = Kronecker_to_ZXX(FpXQX_mul(ky, kx, T, q), n, varn(S));
     377        1358 :   return gerepileupto(av, ZpXQXXQ_red(z, S, T, q, p, e));
     378             : }
     379             : 
     380             : static GEN
     381         441 : FpXXX_red(GEN z, GEN p)
     382             : {
     383             :   GEN res;
     384         441 :   long i, l = lg(z);
     385         441 :   res = cgetg(l,t_POL); res[1] = z[1];
     386       17388 :   for (i=2; i<l; i++)
     387             :   {
     388       16947 :     GEN zi = gel(z,i);
     389       16947 :     if (typ(zi)==t_INT)
     390           0 :       gel(res,i) = modii(zi,p);
     391             :     else
     392       16947 :      gel(res,i) = FpXX_red(zi,p);
     393             :   }
     394         441 :   return FpXXX_renormalize(res,lg(res));
     395             : }
     396             : 
     397             : static GEN
     398         441 : FpXXX_Fp_mul(GEN z, GEN a, GEN p)
     399             : {
     400         441 :   return FpXXX_red(RgX_Rg_mul(z, a), p);
     401             : }
     402             : 
     403             : static GEN
     404         154 : ZpXQXXQ_invsqrt(GEN F, GEN S, GEN T, ulong p, long e)
     405             : {
     406         154 :   pari_sp av = avma, av2, av3;
     407             :   ulong mask;
     408         154 :   long v = varn(F), n=1;
     409             :   pari_timer ti;
     410         154 :   GEN a = pol_1(v), pp = utoipos(p);
     411         154 :   if (DEBUGLEVEL>1) timer_start(&ti);
     412         154 :   if (e <= 1) return gerepilecopy(av, a);
     413         154 :   mask = quadratic_prec_mask(e);
     414         154 :   av2 = avma;
     415         595 :   for (;mask>1;)
     416             :   {
     417             :     GEN q, q2, q22, f, fq, afq;
     418         441 :     long n2 = n;
     419         441 :     n<<=1; if (mask & 1) n--;
     420         441 :     mask >>= 1;
     421         441 :     q = powuu(p,n); q2 = powuu(p,n2);
     422         441 :     av3 = avma;
     423         441 :     f = RgX_sub(ZpXQXXQ_mul(F, ZpXQXXQ_sqr(a, S, T, q, pp, n), S, T, q, pp, n), pol_1(v));
     424         441 :     fq = gerepileupto(av3, RgX_Rg_divexact(f, q2));
     425         441 :     q22 = shifti(addiu(q2,1),-1);
     426         441 :     afq = FpXXX_Fp_mul(ZpXQXXQ_mul(a, fq, S, T, q2, pp, n2), q22, q2);
     427         441 :     a = RgX_sub(a, RgX_Rg_mul(afq, q2));
     428         441 :     if (gc_needed(av2,1))
     429             :     {
     430           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_invsqrt, e = %ld", n);
     431           0 :       a = gerepileupto(av2, a);
     432             :     }
     433             :   }
     434         154 :   return gerepileupto(av, a);
     435             : }
     436             : 
     437             : static GEN
     438        6573 : frac_to_Fq(GEN a, GEN b, GEN T, GEN q, GEN p, long e)
     439             : {
     440        6573 :   GEN d = gcdii(ZX_content(a), ZX_content(b));
     441        6573 :   return ZpXQ_div(ZX_Z_divexact(a, d), ZX_Z_divexact(b, d), T, q, p, e);
     442             : }
     443             : 
     444             : static GEN
     445         469 : ZpXQXXQ_frob(GEN F, GEN U, GEN V, long k, GEN S, GEN T, ulong p, long e)
     446             : {
     447         469 :   pari_sp av = avma, av2;
     448         469 :   long i, pr = degpol(F), dS = degpol(S), v = varn(T);
     449         469 :   GEN q = powuu(p,e), pp = utoipos(p);
     450         469 :   GEN Sp = RgX_deriv(S), Sp1 = RgX_shift_shallow(Sp, 1);
     451         469 :   GEN M = gel(F,pr+2), R;
     452         469 :   av2 = avma;
     453       52311 :   for(i = pr-1; i>=k; i--)
     454             :   {
     455             :     GEN A, B, H, Bc;
     456             :     ulong v, r;
     457       51842 :     H = ZpXQX_divrem(FpXQX_mul(V, M, T, q), S, T, q, utoipos(p), e, &B);
     458       51842 :     A = FpXX_add(FpXQX_mul(U, M, T, q), FpXQX_mul(H, Sp, T, q),q);
     459       51842 :     v = u_lvalrem(2*i+1,p,&r);
     460       51842 :     Bc = RgX_deriv(B);
     461       51842 :     Bc = FpXX_Fp_mul(ZXX_Z_divexact(Bc,powuu(p,v)), Fp_divu(gen_2, r, q), q);
     462       51842 :     M = FpXX_add(gel(F,i+2), FpXX_add(A, Bc, q), q);
     463       51842 :     if (gc_needed(av2,1))
     464             :     {
     465           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXQXXQ_frob, step 1, i = %ld", i);
     466           0 :       M = gerepileupto(av2, M);
     467             :     }
     468             :   }
     469         469 :   if (degpol(M)<dS-1)
     470         266 :     return gerepileupto(av, M);
     471         203 :   R = RgX_shift_shallow(M,dS-degpol(M)-2);
     472         203 :   av2 = avma;
     473        7175 :   for(i = degpol(M)-dS+2; i>=1; i--)
     474             :   {
     475             :     GEN B, c;
     476        6972 :     R = RgX_shift_shallow(R, 1);
     477        6972 :     gel(R,2) = gel(M, i+1);
     478        6972 :     if (degpol(R) < dS) continue;
     479        6412 :     B = FpXX_add(FpXX_mulu(S, 2*i, q), Sp1, q);
     480        6412 :     c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(B),v), T, q, pp, e);
     481        6412 :     R = FpXX_sub(R, FpXQX_FpXQ_mul(B, c, T, q), q);
     482        6412 :     if (gc_needed(av2,1))
     483             :     {
     484           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"ZpXXQ_frob, step 2, i = %ld", i);
     485           0 :       R = gerepileupto(av2, R);
     486             :     }
     487             :   }
     488         203 :   if (degpol(R)==dS-1)
     489             :   {
     490         161 :     GEN c = frac_to_Fq(to_ZX(leading_coeff(R),v), to_ZX(leading_coeff(Sp),v), T, q, pp, e);
     491         161 :     R = FpXX_sub(R, FpXQX_FpXQ_mul(Sp, c, T, q), q);
     492         161 :     return gerepileupto(av, R);
     493             :   } else
     494          42 :     return gerepilecopy(av, R);
     495             : }
     496             : 
     497             : static GEN
     498         469 : Fq_diff_red(GEN s, GEN A, long m, GEN S, GEN T, GEN q, GEN p, long e)
     499             : {
     500             :   long v, n;
     501             :   GEN Q, sQ, qS;
     502             :   pari_timer ti;
     503         469 :   if (DEBUGLEVEL>1) timer_start(&ti);
     504         469 :   Q = revdigits(ZpXQX_digits(A, S, T, q, p, e));
     505         469 :   n = degpol(Q);
     506         469 :   if (DEBUGLEVEL>1) timer_printf(&ti,"reddigits");
     507         469 :   sQ = ZpXQXXQ_mul(s, Q, S, T, q, p, e);
     508         469 :   if (DEBUGLEVEL>1) timer_printf(&ti,"redmul");
     509         469 :   qS = RgX_shift_shallow(sQ,m-n);
     510         469 :   v = ZX_val(sQ);
     511         469 :   if (n > m + v)
     512             :   {
     513         189 :     long i, l = n-m-v;
     514         189 :     GEN rS = cgetg(l+1,t_VEC);
     515        1547 :     for (i = l-1; i >=0 ; i--)
     516        1358 :       gel(rS,i+1) = gel(sQ, 1+v+l-i);
     517         189 :     rS = FpXQXV_FpXQX_fromdigits(rS, S, T, q);
     518         189 :     gel(qS,2) = FpXX_add(FpXQX_mul(rS, S, T, q), gel(qS, 2), q);
     519         189 :     if (DEBUGLEVEL>1) timer_printf(&ti,"redadd");
     520             :   }
     521         469 :   return qS;
     522             : }
     523             : 
     524             : static void
     525         154 : Fq_get_UV(GEN *U, GEN *V, GEN S, GEN T, ulong p, long e)
     526             : {
     527         154 :   GEN q = powuu(p, e), pp = utoipos(p), d;
     528         154 :   GEN dS = RgX_deriv(S), R  = polresultantext(S, dS), C;
     529         154 :   long v = varn(S);
     530         154 :   if (signe(FpX_red(to_ZX(gel(R,3),v), pp))==0) is_sing(S, p);
     531         147 :   C = FpXQ_red(to_ZX(gel(R, 3),v), T, q);
     532         147 :   d = ZpXQ_inv(C, T, pp, e);
     533         147 :   *U = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,1),v),T,q),d,T,q);
     534         147 :   *V = FpXQX_FpXQ_mul(FpXQX_red(to_ZX(gel(R,2),v),T,q),d,T,q);
     535         147 : }
     536             : 
     537             : static GEN
     538         469 : ZXX_to_FpXC(GEN x, long N, GEN p, long v)
     539             : {
     540             :   long i, l;
     541             :   GEN z;
     542         469 :   l = lg(x)-1; x++;
     543         469 :   if (l > N+1) l = N+1; /* truncate higher degree terms */
     544         469 :   z = cgetg(N+1,t_COL);
     545        2170 :   for (i=1; i<l ; i++)
     546             :   {
     547        1701 :     GEN xi = gel(x, i);
     548        1701 :     gel(z,i) = typ(xi)==t_INT? scalarpol(Fp_red(xi, p), v): FpX_red(xi, p);
     549             :   }
     550         511 :   for (   ; i<=N ; i++)
     551          42 :     gel(z,i) = pol_0(v);
     552         469 :   return z;
     553             : }
     554             : 
     555             : GEN
     556         154 : ZlXQX_hyperellpadicfrobenius(GEN H, GEN T, ulong p, long n)
     557             : {
     558         154 :   pari_sp av = avma;
     559             :   long k, N, i, d, N1;
     560             :   GEN xp, F, s, q, Q, pN1, U, V, pp;
     561             :   pari_timer ti;
     562         154 :   if (typ(H) != t_POL) pari_err_TYPE("hyperellpadicfrobenius",H);
     563         154 :   if (p == 2) is_sing(H, 2);
     564         154 :   d = degpol(H);
     565         154 :   if (d <= 0) pari_err_CONSTPOL("hyperellpadicfrobenius");
     566         154 :   if (n < 1) pari_err_DOMAIN("hyperellpadicfrobenius","n","<", gen_1, utoi(n));
     567         154 :   k = get_basis(p, d); pp = utoipos(p);
     568         154 :   N = n + ulogint(2*n, p) + 1;
     569         154 :   q = powuu(p,n); N1 = N+1;
     570         154 :   pN1 = powuu(p,N1); T = FpX_get_red(T, pN1);
     571         154 :   Q = RgX_to_FqX(H, T, pN1);
     572         154 :   if (signe(FpX_red(to_ZX(leading_coeff(Q),varn(Q)),pp))==0) is_sing(H, p);
     573         154 :   if (DEBUGLEVEL>1) timer_start(&ti);
     574         154 :   xp = ZpX_Frobenius(T, pp, N1);
     575         154 :   s = RgX_inflate(FpXY_FpXQ_evalx(Q, xp, T, pN1), p);
     576         154 :   s = revdigits(ZpXQX_digits(s, Q, T, pN1, pp, N1));
     577         154 :   if (DEBUGLEVEL>1) timer_printf(&ti,"s1");
     578         154 :   s = ZpXQXXQ_invsqrt(s, Q, T, p, N);
     579         154 :   if (k==3)
     580           7 :     s = ZpXQXXQ_mul(s, ZpXQXXQ_sqr(s, Q, T, pN1, pp, N1), Q, T, pN1, pp, N1);
     581         154 :   if (DEBUGLEVEL>1) timer_printf(&ti,"invsqrt");
     582         154 :   Fq_get_UV(&U, &V, Q, T, p, N+1);
     583         147 :   if (DEBUGLEVEL>1) timer_printf(&ti,"get_UV");
     584         147 :   F = cgetg(d, t_MAT);
     585         616 :   for (i = 1; i < d; i++)
     586             :   {
     587         469 :     pari_sp av2 = avma;
     588             :     GEN M, D;
     589         469 :     D = Fq_diff_red(s, monomial(pp,p*i-1,1),(k*p-1)>>1, Q, T, pN1, pp, N1);
     590         469 :     if (DEBUGLEVEL>1) timer_printf(&ti,"red");
     591         469 :     M = ZpXQXXQ_frob(D, U, V, (k - 1)>>1, Q, T, p, N1);
     592         469 :     if (DEBUGLEVEL>1) timer_printf(&ti,"frob");
     593         469 :     gel(F, i) = gerepileupto(av2, ZXX_to_FpXC(M, d-1, q, varn(T)));
     594             :   }
     595         147 :   return gerepileupto(av, F);
     596             : }
     597             : 
     598             : GEN
     599         154 : nfhyperellpadicfrobenius(GEN H, GEN T, ulong p, long n)
     600             : {
     601         154 :   pari_sp av = avma;
     602         154 :   GEN pp = utoipos(p), q = zeropadic(pp, n);
     603         154 :   GEN M = ZlXQX_hyperellpadicfrobenius(lift_shallow(H),T,p,n);
     604         147 :   GEN MM = ZpXQM_prodFrobenius(M, T, pp, n);
     605         147 :   GEN m = gmul(ZXM_to_padic(MM, q), gmodulo(gen_1, T));
     606         147 :   return gerepileupto(av, m);
     607             : }
     608             : 
     609             : GEN
     610         595 : hyperellpadicfrobenius0(GEN H, GEN Tp, long n)
     611             : {
     612             :   GEN T, p;
     613         595 :   if (!ff_parse_Tp(Tp, &T,&p,0)) pari_err_TYPE("hyperellpadicfrobenius", Tp);
     614         595 :   if (lgefint(p) > 3) pari_err_IMPL("large prime in hyperellpadicfrobenius");
     615           7 :   return T? nfhyperellpadicfrobenius(H, T, itou(p), n)
     616         602 :           : hyperellpadicfrobenius(H, itou(p), n);
     617             : }
     618             : 
     619             : static GEN
     620          77 : F2x_genus2charpoly_naive(GEN P, GEN Q)
     621             : {
     622          77 :   long a, b = 1, c = 0;
     623          77 :   GEN T = mkvecsmall2(P[1], 7);
     624          77 :   GEN PT = F2x_rem(P, T), QT = F2x_rem(Q, T);
     625          77 :   long q0 = F2x_eval(Q, 0), q1 = F2x_eval(Q, 1);
     626          77 :   long dP = F2x_degree(P), dQ = F2x_degree(Q);
     627          77 :   a= dQ<3 ? 0: dP<=5 ? 1: -1;
     628          77 :   a += (q0? F2x_eval(P, 0)? -1: 1: 0) + (q1? F2x_eval(P, 1)? -1: 1: 0);
     629          77 :   b += q0 + q1;
     630          77 :   if (lgpol(QT))
     631          63 :     c = (F2xq_trace(F2xq_div(PT, F2xq_sqr(QT, T), T), T)==0 ? 1: -1);
     632          77 :   return mkvecsmalln(6, 0UL, 4UL, 2*a, (b+2*c+a*a)>>1, a, 1UL);
     633             : }
     634             : 
     635             : static GEN
     636         217 : Flx_difftable(GEN P, ulong p)
     637             : {
     638         217 :   long i, n = degpol(P);
     639         217 :   GEN V = cgetg(n+2, t_VEC);
     640         217 :   gel(V, n+1) = P;
     641        1484 :   for(i = n; i >= 1; i--)
     642        1267 :     gel(V, i) = Flx_diff1(gel(V, i+1), p);
     643         217 :   return V;
     644             : }
     645             : 
     646             : static GEN
     647        1519 : FlxV_Fl2_eval_pre(GEN V, GEN x, ulong D, ulong p, ulong pi)
     648             : {
     649        1519 :   long i, n = lg(V)-1;
     650        1519 :   GEN r = cgetg(n+1, t_VEC);
     651       11627 :   for (i = 1; i <= n; i++)
     652       10108 :     gel(r, i) = Flx_Fl2_eval_pre(gel(V, i), x, D, p, pi);
     653        1519 :   return r;
     654             : }
     655             : 
     656             : static GEN
     657       44478 : Fl2V_next(GEN V, ulong p)
     658             : {
     659       44478 :   long i, n = lg(V)-1;
     660       44478 :   GEN r = cgetg(n+1, t_VEC);
     661       44478 :   gel(r, 1) = gel(V, 1);
     662      285516 :   for (i = 2; i <= n; i++)
     663      241038 :     gel(r, i) = Flv_add(gel(V, i), gel(V, i-1), p);
     664       44478 :   return r;
     665             : }
     666             : 
     667             : static GEN
     668         217 : Flx_genus2charpoly_naive(GEN H, ulong p)
     669             : {
     670         217 :   pari_sp av = avma, av2;
     671         217 :   ulong pi = get_Fl_red(p);
     672         217 :   ulong i, j, p2 = p>>1, D = 2, e = ((p&2UL) == 0) ? -1 : 1;
     673         217 :   long a, b, c = 0, n = degpol(H);
     674         217 :   GEN t, k = const_vecsmall(p, -1);
     675         217 :   k[1] = 0;
     676        1736 :   for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p)) k[j+1] = 1;
     677         259 :   while (k[1+D] >= 0) D++;
     678         217 :   b = n == 5 ? 0 : 1;
     679         217 :   a = b ? k[1+Flx_lead(H)]: 0;
     680         217 :   t = Flx_difftable(H, p);
     681         217 :   av2 = avma;
     682        3472 :   for (i=0; i < p; i++)
     683             :   {
     684        3255 :     ulong v = Flx_eval(H, i, p);
     685        3255 :     a += k[1+v];
     686        3255 :     b += !!v;
     687             :   }
     688        1736 :   for (j=1; j <= p2; j++)
     689             :   {
     690        1519 :     GEN V = FlxV_Fl2_eval_pre(t, mkvecsmall2(0, j), D, p, pi);
     691        1519 :     for (i=0;; i++)
     692       44478 :     {
     693       45997 :       GEN r2 = gel(V, n+1);
     694       91994 :       c += uel(r2,2) ?
     695       43764 :         (uel(r2,1) ? uel(k,1+Fl2_norm_pre(r2, D, p, pi)): e)
     696       89761 :          : !!uel(r2,1);
     697       45997 :       if (i == p-1) break;
     698       44478 :       V = Fl2V_next(V, p);
     699             :     }
     700        1519 :     set_avma(av2);
     701             :   }
     702         217 :   set_avma(av);
     703         217 :   return mkvecsmalln(6, 0UL, p*p, a*p, (b+2*c+a*a)>>1, a, 1UL);
     704             : }
     705             : 
     706             : static GEN
     707         679 : charpoly_funceq(GEN P, GEN q)
     708             : {
     709         679 :   long i, l, g = degpol(P)>>1;
     710         679 :   GEN Q = cgetg_copy(P, &l);
     711         679 :   Q[1] = P[1];
     712        3843 :   for (i=0; i<=g; i++)
     713        3164 :     gel(Q, i+2) = mulii(gel(P, 2*g-i+2), powiu(q, g-i));
     714        3164 :   for (; i<=2*g; i++)
     715        2485 :     gel(Q, i+2) = icopy(gel(P, i+2));
     716         679 :   return Q;
     717             : }
     718             : 
     719             : static long
     720         686 : hyperell_Weil_bound(GEN q, ulong g, GEN p)
     721             : {
     722         686 :   pari_sp av = avma;
     723         686 :   GEN w = mulii(binomialuu(2*g,g),sqrtint(shifti(powiu(q, g),2)));
     724         686 :   return gc_long(av, logint(w,p) + 1);
     725             : }
     726             : 
     727             : static GEN
     728      286468 : check_hyperell(GEN PQ)
     729             : {
     730             :   GEN H;
     731      286468 :   if (is_vec_t(typ(PQ)) && lg(PQ)==3)
     732      225379 :     H = gadd(gsqr(gel(PQ, 2)), gmul2n(gel(PQ, 1), 2));
     733             :   else
     734       61089 :     H = gmul2n(PQ, 2);
     735      286468 :   if (typ(H)!=t_POL)
     736           0 :     return NULL;
     737      286468 :   return H;
     738             : }
     739             : 
     740             : GEN
     741         987 : hyperellcharpoly(GEN PQ)
     742             : {
     743         987 :   pari_sp av = avma;
     744         987 :   GEN M, R, T=NULL, pp=NULL, q;
     745         987 :   long d, n, eps = 0;
     746             :   ulong p;
     747         987 :   GEN H = check_hyperell(PQ);
     748         987 :   if (!H || !RgX_is_FpXQX(H, &T, &pp) || !pp)
     749           0 :     pari_err_TYPE("hyperellcharpoly", PQ);
     750         987 :   p = itou(pp);
     751         987 :   if (!T)
     752             :   {
     753         840 :     if (p==2 && is_vec_t(typ(PQ)))
     754             :     {
     755          77 :       long dP, dQ, v = varn(H);
     756          77 :       GEN P = gel(PQ,1), Q = gel(PQ,2);
     757          77 :       if (typ(P)!=t_POL)  P = scalarpol(P, v);
     758          77 :       if (typ(Q)!=t_POL)  Q = scalarpol(Q, v);
     759          77 :       dP = degpol(P); dQ = degpol(Q);
     760          77 :       if (dP<=6 && dQ <=3 && (dQ==3 || dP>=5))
     761             :       {
     762          77 :         GEN P2 = RgX_to_F2x(P), Q2 = RgX_to_F2x(Q);
     763          77 :         GEN D = F2x_add(F2x_mul(P2, F2x_sqr(F2x_deriv(Q2))), F2x_sqr(F2x_deriv(P2)));
     764          77 :         if (F2x_degree(F2x_gcd(D, Q2))) is_sing(PQ, 2);
     765          77 :         if (dP==6 && dQ<3 && F2x_coeff(P2,5)==F2x_coeff(Q2,2))
     766           0 :           is_sing(PQ, 2); /* The curve is singular at infinity */
     767          77 :         R = zx_to_ZX(F2x_genus2charpoly_naive(P2, Q2));
     768          77 :         return gerepileupto(av, R);
     769             :       }
     770             :     }
     771         763 :     H = RgX_to_FpX(H, pp);
     772         763 :     d = degpol(H);
     773         763 :     if (d <= 0) is_sing(H, p);
     774         763 :     if (p > 2 && ((d == 5 && p < 17500) || (d == 6 && p < 24500)))
     775             :     {
     776         224 :       GEN Hp = ZX_to_Flx(H, p);
     777         224 :       if (!Flx_is_squarefree(Hp, p)) is_sing(H, p);
     778         217 :       R = zx_to_ZX(Flx_genus2charpoly_naive(Hp, p));
     779         217 :       return gerepileupto(av, R);
     780             :     }
     781         539 :     n = hyperell_Weil_bound(pp, (d-1)>>1, pp);
     782         539 :     eps = odd(d)? 0: Fp_issquare(leading_coeff(H), pp);
     783         539 :     M = hyperellpadicfrobenius(H, p, n);
     784         539 :     R = centerlift(carberkowitz(M, 0));
     785         539 :     q = pp;
     786             :   }
     787             :   else
     788             :   {
     789             :     int fixvar;
     790         147 :     T = typ(T)==t_FFELT? FF_mod(T): RgX_to_FpX(T, pp);
     791         147 :     q = powuu(p, degpol(T));
     792         147 :     fixvar = (varncmp(varn(T),varn(H)) <= 0);
     793         147 :     if (fixvar) setvarn(T, fetch_var());
     794         147 :     H = RgX_to_FpXQX(H, T, pp);
     795         147 :     d = degpol(H);
     796         147 :     if (d <= 0) is_sing(H, p);
     797         147 :     eps = odd(d)? 0: Fq_issquare(leading_coeff(H), T, pp);
     798         147 :     n = hyperell_Weil_bound(q, (d-1)>>1, pp);
     799         147 :     M = nfhyperellpadicfrobenius(H, T, p, n);
     800         140 :     R = simplify_shallow(centerlift(liftpol_shallow(carberkowitz(M, 0))));
     801         140 :     if (fixvar) (void)delete_var();
     802             :   }
     803         679 :   if (!odd(d))
     804             :   {
     805         301 :     GEN b = get_basis(p, d) == 3 ? gen_1 : q;
     806         301 :     GEN pn = powuu(p, n);
     807         301 :     R = FpX_div_by_X_x(R, eps? b: negi(b), pn, NULL);
     808         301 :     R = FpX_center_i(R, pn, shifti(pn,-1));
     809             :   }
     810         679 :   R = charpoly_funceq(R, q);
     811         679 :   return gerepilecopy(av, R);
     812             : }
     813             : 
     814             : int
     815        3493 : hyperellisoncurve(GEN W, GEN P)
     816             : {
     817        3493 :   pari_sp av = avma;
     818             :   long res;
     819             :   GEN x, y;
     820        3493 :   if (typ(P)!=t_VEC || lg(P)!=3) pari_err_TYPE("hyperellisoncurve",P);
     821        3493 :   x = gel(P,1); y = gel(P,2);
     822        3493 :   if (typ(W)==t_POL)
     823           0 :     res = gequal(gsqr(y), poleval(W,x));
     824             :   else
     825             :   {
     826        3493 :     if (typ(W)!=t_VEC || lg(W)!=3) pari_err_TYPE("hyperellisoncurve",W);
     827        3493 :     res = gequal(gmul(y, gadd(y,poleval(gel(W,2), x))), poleval(gel(W,1), x));
     828             :   }
     829        3493 :   return gc_int(av, res);
     830             : }
     831             : 
     832             : GEN
     833      117810 : hyperelldisc(GEN PQ)
     834             : {
     835      117810 :   pari_sp av = avma;
     836      117810 :   GEN D, H = check_hyperell(PQ);
     837             :   long d, g;
     838      117810 :   if (!H || signe(H)==0) pari_err_TYPE("hyperelldisc",PQ);
     839      117810 :   d = degpol(H); g = ((d+1)>>1)-1;
     840      117810 :   D = gmul2n(RgX_disc(H),-4*(g+1));
     841      117810 :   if (odd(d)) D = gmul(D, gsqr(leading_coeff(H)));
     842      117810 :   return gerepileupto(av, D);
     843             : }
     844             : 
     845             : static long
     846      125406 : get_ep(GEN W)
     847             : {
     848      125406 :   GEN P = gel(W,1), Q = gel(W,2);
     849      125406 :   if (signe(Q)==0) return ZX_lval(P,2);
     850       85456 :   return minss(ZX_lval(P,2), ZX_lval(Q,2));
     851             : }
     852             : 
     853             : static GEN
     854       50526 : algo51(GEN W, GEN M)
     855             : {
     856       50526 :   GEN P = gel(W,1), Q = gel(W,2);
     857             :   for(;;)
     858       10430 :   {
     859       60956 :     long vP = ZX_lval(P,2);
     860       60956 :     long vQ = signe(Q) ? ZX_lval(Q,2): vP+1;
     861             :     long r;
     862             :     /* 1 */
     863       60956 :     if (vQ==0) break;
     864             :     /* 2 */
     865       35777 :     if (vP==0)
     866             :     {
     867             :       GEN H, H1;
     868             :       /* a */
     869       29407 :       RgX_even_odd(FpX_red(P,gen_2),&H, &H1);
     870       29407 :       if (signe(H1)) break;
     871             :       /* b */
     872       14798 :       P = ZX_add(P, ZX_mul(H, ZX_sub(Q, H)));
     873       14798 :       Q = ZX_sub(Q, ZX_mulu(H, 2));
     874       14798 :       vP = ZX_lval(P,2);
     875       14798 :       vQ = signe(Q) ? ZX_lval(Q,2): vP+1;
     876             :     }
     877             :     /* 2c */
     878       21168 :     if (vP==1) break;
     879             :     /* 2d */
     880       10430 :     r = minss(2*vQ, vP)>>1;
     881       10430 :     gel(M,1) = shifti(gel(M,1), r);
     882       10430 :     P = ZX_shifti(P, -2*r);
     883       10430 :     Q = ZX_shifti(Q, -r);
     884             :   }
     885       50526 :   return mkvec2(P,Q);
     886             : }
     887             : 
     888             : static GEN
     889      102767 : algo52(GEN W, GEN c, long *pt_lambda)
     890             : {
     891             :   long lambda;
     892      102767 :   GEN P = gel(W,1), Q = gel(W,2);
     893             :   for(;;)
     894      116234 :   {
     895             :     GEN H, H1;
     896             :     /* 1 */
     897      219001 :     GEN Pc = ZX_affine(P,gen_2,c), Qc = ZX_affine(Q,gen_2,c);
     898      219001 :     long mP = ZX_lval(Pc,2), mQ = signe(Qc) ? ZX_lval(Qc,2): mP+1;
     899             :     /* 2 */
     900      219001 :     if (2*mQ <= mP) { lambda = 2*mQ; break; }
     901             :     /* 3 */
     902      186990 :     if (mP%2 == 1) { lambda = mP; break; }
     903             :     /* 4 */
     904      127028 :     RgX_even_odd(FpX_red(ZX_shifti(Pc, -mP),gen_2),&H, &H1);
     905      127028 :     if (signe(H1)) { lambda = mP; break; }
     906             :     /* 5 */
     907      116234 :      P = ZX_add(P, ZX_mul(H, ZX_sub(Q, H)));
     908      116234 :      Q = ZX_sub(Q, ZX_mulu(H, 2));
     909             :   }
     910      102767 :   *pt_lambda = lambda;
     911      102767 :   return mkvec2(P,Q);
     912             : }
     913             : 
     914             : static GEN
     915      218470 : algo541(GEN F, GEN p, long ep, long g)
     916             : {
     917      218470 :   GEN Fe = FpX_red(ep ? ZX_Z_divexact(F,p): F, p);
     918      218470 :   return FpX_roots_mult(Fe, g+2-ep, p);
     919             : }
     920             : 
     921             : static long
     922      144984 : test53(long lambda, long ep, long g)
     923             : {
     924      144984 :   return (lambda <= g+1) || (g%2 && lambda<g+3 && ep==1);
     925             : }
     926             : 
     927             : static long
     928      187891 : test55(GEN W, long ep, long g)
     929             : {
     930      187891 :   GEN P = gel(W,1), Q = gel(W,2);
     931      187891 :   GEN Pe = FpX_red(ep ? ZX_shifti(P,-1): P, gen_2);
     932      187891 :   GEN Qe = FpX_red(ep ? ZX_shifti(Q,-1): Q, gen_2);
     933      187891 :   if (ep==0)
     934             :   {
     935      148052 :     if (signe(Qe)!=0) return ZX_val(Qe) >= (g + 3)>>1;
     936       90237 :     else return ZX_val(FpX_deriv(Pe, gen_2)) >= g+1;
     937             :   }
     938             :   else
     939       39839 :     return ZX_val(Qe) >= (g+1)>>1 && ZX_val(Pe) >= g + 1;
     940             : }
     941             : 
     942             : static GEN
     943       50526 : hyperell_reverse(GEN W, long g)
     944             : {
     945       50526 :   return mkvec2(RgXn_recip_shallow(gel(W,1),2*g+3),
     946       50526 :                 RgXn_recip_shallow(gel(W,2),g+2));
     947             : }
     948             : 
     949             : static GEN
     950       50526 : algo56(GEN W, long g)
     951             : {
     952             :   long ep;
     953       50526 :   GEN M = mkvec2(gen_1, matid(2)), Woo;
     954       50526 :   W = algo51(W, M);
     955       50526 :   Woo = hyperell_reverse(W, g);
     956       50526 :   ep = get_ep(Woo);
     957       50526 :   if (test55(Woo,ep,g))
     958             :   {
     959             :     long lambda;
     960       11885 :     Woo = algo52(Woo, gen_0, &lambda);
     961       11885 :     if (!test53(lambda,ep,g))
     962             :     {
     963        6054 :       long r = lambda>>1;
     964        6054 :       gel(M,1) = shifti(gel(M,1), r);
     965        6054 :       gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_0, gen_1, gen_2, gen_0));
     966        6054 :       W = mkvec2(ZX_shifti(ZX_unscale(gel(Woo,1), gen_2), -2*r),
     967        6054 :                  ZX_shifti(ZX_unscale(gel(Woo,2), gen_2), -r));
     968             :     }
     969             :   }
     970             :   for(;;)
     971       24354 :   {
     972       74880 :     long j, ep = get_ep(W);
     973      187891 :     for (j = 0; j < 2; j++)
     974             :     {
     975             :       long lambda;
     976      137365 :       GEN c = utoi(j);
     977      137365 :       GEN Pc = ZX_affine(gel(W,1), gen_2, c);
     978      137365 :       GEN Qc = ZX_affine(gel(W,2), gen_2, c);
     979      137365 :       if (test55(mkvec2(Pc, Qc), ep, g))
     980             :       {
     981       90882 :         GEN Wc = algo52(W, c, &lambda);
     982       90882 :         if (!test53(lambda,ep,g))
     983             :         {
     984       24354 :           long r = lambda>>1;
     985       24354 :           gel(M,1) = shifti(gel(M,1), r);
     986       24354 :           gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_2, c, gen_0, gen_1));
     987       24354 :           W = mkvec2(ZX_shifti(ZX_affine(gel(Wc,1), gen_2,c), -2*r),
     988       24354 :                      ZX_shifti(ZX_affine(gel(Wc,2), gen_2,c), -r));
     989       24354 :           break;
     990             :         }
     991             :       }
     992             :     }
     993       74880 :     if (j==2) break;
     994             :   }
     995       50526 :   return mkvec2(W, M);
     996             : }
     997             : 
     998             : /* return the (degree 2) apolar invariant (the nth transvectant of P and P) */
     999             : static GEN
    1000          77 : ZX_apolar(GEN P, long n)
    1001             : {
    1002          77 :   pari_sp av = avma;
    1003          77 :   long d = degpol(P), i;
    1004          77 :   GEN s = gen_0, g = cgetg(n+2,t_VEC);
    1005          77 :   gel(g,1) = gen_1;
    1006         539 :   for (i = 1; i <= n; i++) gel(g,i+1) = muliu(gel(g,i),i); /* g[i+1] = i! */
    1007         602 :   for (i = n-d; i <= d; i++)
    1008             :   {
    1009         525 :      GEN a = mulii(mulii(gel(g,i+1),gel(g,n-i+1)),
    1010         525 :                    mulii(gel(P,i+2),gel(P,n-i+2)));
    1011         525 :      s = odd(i)? subii(s, a): addii(s, a);
    1012             :   }
    1013          77 :   return gerepileuptoint(av,s);
    1014             : }
    1015             : 
    1016             : static GEN
    1017       51877 : algo57(GEN F, long g, GEN pr)
    1018             : {
    1019             :   long i, l;
    1020       51877 :   GEN D, C = content(F);
    1021       51877 :   GEN e = gel(core2(shifti(C,-vali(C))),2);
    1022       51877 :   GEN M = mkvec2(e, matid(2));
    1023       51877 :   long minvd = (2*g+1)>>(odd(g) ? 4:2);
    1024       51877 :   F = ZX_Z_divexact(F, sqri(e));
    1025       51877 :   D = absi(hyperelldisc(F));
    1026       51877 :   if (!pr)
    1027             :   {
    1028          77 :     GEN A = gcdii(D, ZX_apolar(F, 2*g+2));
    1029          77 :     pr = gel(factor(shifti(A, -vali(A))),1);
    1030             :   }
    1031       51877 :   l = lg(pr);
    1032      307230 :   for (i = 1; i < l; i++)
    1033             :   {
    1034             :     long ep;
    1035      255353 :     GEN p = gel(pr, i), ps2 = shifti(p,-1), Fe;
    1036      255353 :     if (equaliu(p,2) || Z_pval(D,p) < minvd) continue;
    1037      193389 :     ep = ZX_pval(F,p);
    1038      193389 :     Fe = FpX_red(ep ? ZX_Z_divexact(F,p): F, p);
    1039      193389 :     if (degpol(Fe) < g+1+ep)
    1040             :     {
    1041        6461 :       GEN Fi = ZX_unscale(RgXn_recip_shallow(F,2*g+3), p);
    1042        6461 :       long lambda = ZX_pval(Fi,p);
    1043        6461 :       if (!test53(lambda,ep,g))
    1044             :       {
    1045        3822 :         GEN ppr = powiu(p,lambda>>1);
    1046        3822 :         F = ZX_Z_divexact(Fi,sqri(ppr));
    1047        3822 :         gel(M,1) = mulii(gel(M,1), ppr);
    1048        3822 :         gel(M,2) = ZM2_mul(gel(M,2), mkmat22(gen_0,gen_1,p,gen_0));
    1049             :       }
    1050             :     }
    1051             :     for(;;)
    1052       25081 :     {
    1053      218470 :       long ep = ZX_pval(F,p);
    1054      218470 :       GEN R = algo541(F, p, ep, g);
    1055      218470 :       long j, lR = lg(R);
    1056      229145 :       for (j = 1; j<lR; j++)
    1057             :       {
    1058       35756 :         GEN c = Fp_center(gel(R,j), p, ps2);
    1059       35756 :         GEN Fi = ZX_affine(F,p,c);
    1060       35756 :         long lambda = ZX_pval(Fi,p);
    1061       35756 :         if (!test53(lambda,ep,g))
    1062             :         {
    1063       25081 :           GEN ppr = powiu(p,lambda>>1);
    1064       25081 :           F = ZX_Z_divexact(Fi, sqri(ppr));
    1065       25081 :           gel(M,1) = mulii(gel(M,1), ppr);
    1066       25081 :           gel(M,2) = ZM2_mul(gel(M,2), mkmat22(p,c,gen_0,gen_1));
    1067       25081 :           break;
    1068             :         }
    1069             :       }
    1070      218470 :       if (j==lR) break;
    1071             :     }
    1072             :   }
    1073       51877 :   return mkvec2(F, M);
    1074             : }
    1075             : 
    1076             : static GEN
    1077      300503 : RgX_RgM2_eval(GEN P, GEN A, GEN Bp, long d)
    1078             : {
    1079      300503 :   if (signe(P)==0)
    1080       78680 :     return P;
    1081             :   else
    1082             :   {
    1083      221823 :     long dP = degpol(P);
    1084      221823 :     GEN R = RgX_homogenous_evalpow(P, A, Bp);
    1085      221823 :     if (d > dP)
    1086       16891 :       R = gmul(R, gel(Bp,1+d-dP));
    1087      221823 :     return R;
    1088             :   }
    1089             : }
    1090             : 
    1091             : static GEN
    1092       51884 : minimalmodel_merge(GEN W2, GEN Modd, long g, long v)
    1093             : {
    1094       51884 :   GEN P = gel(W2,1), Q = gel(W2,2);
    1095       51884 :   GEN e = gel(Modd,1), M = gel(Modd,2);
    1096       51884 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1097       51884 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1098       51884 :   GEN Bp = gpowers(B, 2*g+2);
    1099       51884 :   long f = mod4(e)==1 ? 1: -1;
    1100       51884 :   GEN m = shifti(f > 0 ? subui(1,e): addui(1,e), -2);
    1101       51884 :   GEN  m24 = subii(shifti(m,1), shifti(sqri(m),2));
    1102       51884 :   P = RgX_RgM2_eval(P, A, Bp, 2*g+2);
    1103       51884 :   Q = RgX_RgM2_eval(Q, A, Bp, g+1);
    1104       51884 :   P = ZX_Z_divexact(ZX_add(P, ZX_Z_mul(ZX_sqr(Q), m24)),sqri(e));
    1105       51884 :   if (f < 0) Q = ZX_neg(Q);
    1106       51884 :   return mkvec2(P,Q);
    1107             : }
    1108             : 
    1109             : static GEN
    1110      103761 : hyperell_redQ(GEN W)
    1111             : {
    1112      103761 :   GEN P = gel(W,1), Q = gel(W,2);
    1113      103761 :   GEN Pr, Qr = FpX_red(Q, gen_2);
    1114      103761 :   Pr = ZX_add(P, ZX_shifti(ZX_mul(ZX_sub(Q, Qr),ZX_add(Q, Qr)),-2));
    1115      103761 :   return mkvec2(Pr, Qr);
    1116             : }
    1117             : 
    1118             : static GEN
    1119       50477 : minimalmodel_getH(GEN W, GEN Qn, GEN e, GEN M, long g, long v)
    1120             : {
    1121       50477 :   GEN Q = gel(W,2);
    1122       50477 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1123       50477 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1124       50477 :   GEN Bp = gpowers(B, g+1);
    1125       50477 :   return ZX_shifti(ZX_sub(ZX_Z_mul(Qn,e),RgX_RgM2_eval(Q, A, Bp, g+1)), -1);
    1126             : }
    1127             : 
    1128             : static void
    1129       51884 : check_hyperell_Q(const char *fun, GEN *pW, GEN *pF)
    1130             : {
    1131       51884 :   GEN W = *pW, F = check_hyperell(W);
    1132       51884 :   long v = varn(F);
    1133       51884 :   if (!F || signe(F)==0 || !RgX_is_ZX(F))
    1134           0 :     pari_err_TYPE(fun, W);
    1135       51884 :   if (signe(ZX_disc(F))==0)
    1136           0 :     pari_err_DOMAIN(fun,"disc(W)","==",gen_0,W);
    1137       51884 :   if (typ(W)==t_POL) W = mkvec2(W, pol_0(v));
    1138             :   else
    1139             :   {
    1140       43596 :     GEN P = gel(W, 1), Q = gel(W, 2);
    1141       43596 :     long g = ((degpol(F)+1)>>1)-1;
    1142       43596 :     if( typ(P)!=t_POL) P = scalarpol(P, v);
    1143       43596 :     if( typ(Q)!=t_POL) Q = scalarpol(Q, v);
    1144       43596 :     if (!RgX_is_ZX(P) || !RgX_is_ZX(Q))
    1145           0 :       pari_err_TYPE(fun,W);
    1146       43596 :     if (degpol(P) > 2*g+2)
    1147           0 :       pari_err_DOMAIN(fun, "poldegree(P)", ">", utoi(2*g+2), P);
    1148       43596 :     if (degpol(Q) > g+1)
    1149           0 :       pari_err_DOMAIN(fun, "poldegree(Q)", ">", utoi(g+1), Q);
    1150       43596 :     W = mkvec2(P, Q);
    1151             :   }
    1152       51884 :   *pW = W; *pF = F;
    1153       51884 : }
    1154             : 
    1155             : GEN
    1156       51877 : hyperellminimalmodel(GEN W, GEN *pM, GEN pr)
    1157             : {
    1158       51877 :   pari_sp av = avma;
    1159             :   GEN Wr, F, WM2, F2, W2, M2, Modd, Wf, ef, Mf, Hf;
    1160             :   long d, g, v;
    1161       51877 :   check_hyperell_Q("hyperellminimalmodel",&W, &F);
    1162       51877 :   d = degpol(F); g = ((d+1)>>1)-1; v = varn(F);
    1163       51877 :   Wr = hyperell_redQ(W);
    1164       51877 :   if (!pr || RgV_isin(pr, gen_2))
    1165             :   {
    1166       50526 :     WM2 = algo56(Wr,g); W2 = gel(WM2, 1); M2 = gel(WM2, 2);
    1167       50526 :     F2 = check_hyperell(W2);
    1168             :   }
    1169             :   else
    1170             :   {
    1171        1351 :     W2 = Wr; F2 = F; M2 = mkvec2(gen_1, matid(2));
    1172             :   }
    1173       51877 :   Modd = gel(algo57(F2, g, pr), 2);
    1174       51877 :   Wf = hyperell_redQ(minimalmodel_merge(W2, Modd, g, v));
    1175       51877 :   if (!pM) return gerepilecopy(av, Wf);
    1176       50470 :   ef = mulii(gel(M2,1), gel(Modd,1));
    1177       50470 :   Mf = ZM2_mul(gel(M2,2), gel(Modd,2));
    1178       50470 :   Hf = minimalmodel_getH(W, gel(Wf,2), ef, Mf, g, v);
    1179       50470 :   *pM =  mkvec3(ef, Mf, Hf);
    1180       50470 :   return gc_all(av, 2, &Wf, pM);
    1181             : }
    1182             : 
    1183             : GEN
    1184          14 : hyperellminimaldisc(GEN W, GEN pr)
    1185             : {
    1186          14 :   pari_sp av = avma;
    1187          14 :   GEN C = hyperellminimalmodel(W, NULL, pr);
    1188          14 :   return gerepileuptoint(av, hyperelldisc(C));
    1189             : }
    1190             : 
    1191             : static GEN
    1192          35 : redqfbsplit(GEN a, GEN b, GEN c, GEN d)
    1193             : {
    1194          35 :   GEN p = subii(d,b), q = shifti(a,1);
    1195          35 :   GEN U, Q, u, v, w = bezout(p, q, &u, &v);
    1196             : 
    1197          35 :   if (!equali1(w)) { p = diviiexact(p, w); q = diviiexact(q, w); }
    1198          35 :   U = mkmat22(p, negi(v), q, u);
    1199          35 :   Q = qfb_apply_ZM(mkvec3(a,b,c), U);
    1200          35 :   b = gel(Q, 2); c = gel(Q,3);
    1201          35 :   if (signe(b) < 0) gel(U,2) = mkcol2(v, negi(u));
    1202          35 :   gel(U,2) = ZC_lincomb(gen_1, truedivii(negi(c), d), gel(U,2), gel(U,1));
    1203          35 :   return U;
    1204             : }
    1205             : 
    1206             : static GEN
    1207       15736 : polreduce(GEN P, GEN M)
    1208             : {
    1209       15736 :   long v = varn(P), dP = degpol(P), d = odd(dP) ? dP+1: dP;
    1210       15736 :   GEN A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1211       15736 :   GEN B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1212       15736 :   return RgX_RgM2_eval(P, A, gpowers(B, d), d);
    1213             : }
    1214             : 
    1215             : static GEN
    1216        7868 : red_Cremona_Stoll(GEN P, GEN *pM)
    1217             : {
    1218             :   GEN q1, q2, q3, M, R;
    1219        7868 :   long i, prec = nbits2prec(2*gexpo(P)) + 1, d = degpol(P);
    1220        7868 :   GEN dP = ZX_deriv(P), r = QX_complex_roots(P, prec);
    1221        7868 :   q1 = gen_0; q2 = gen_0; q3 = gen_0;
    1222       39382 :   for (i = 1; i <= d; i++)
    1223             :   {
    1224       31514 :     GEN ri = gel(r,i);
    1225       31514 :     GEN s = ginv(gabs(RgX_cxeval(dP,ri,NULL), prec));
    1226       31514 :     if (d!=4) s = gpow(s, gdivgs(gen_2,d-2), prec);
    1227       31514 :     q1 = gadd(q1, s);
    1228       31514 :     q2 = gsub(q2, gmul(real_i(ri), s));
    1229       31514 :     q3 = gadd(q3, gmul(gnorm(ri), s));
    1230             :   }
    1231        7868 :   M = lllgram(mkmat22(q1,q2,q2,q3));
    1232        7868 :   if (lg(M) != 3) M = matid(2);
    1233        7868 :   R = polreduce(P, M);
    1234        7868 :   *pM = M;
    1235        7868 :   return R;
    1236             : }
    1237             : 
    1238             : GEN
    1239        7868 : ZX_hyperellred(GEN P, GEN *pM)
    1240             : {
    1241        7868 :   pari_sp av = avma;
    1242        7868 :   long d = degpol(P);
    1243             :   GEN q1, q2, q3, D, vD;
    1244        7868 :   GEN a = gel(P,d+2), b = gel(P,d+1), c = gel(P, d);
    1245             :   GEN M, R, M2;
    1246             : 
    1247        7868 :   q1 = muliu(sqri(a), d);
    1248        7868 :   q2 = shifti(mulii(a,b), 1);
    1249        7868 :   q3 = subii(sqri(b), shifti(mulii(a,c), 1));
    1250        7868 :   D = gcdii(gcdii(q1, q2), q3);
    1251        7868 :   if (!equali1(D))
    1252             :   {
    1253        7847 :     q1 = diviiexact(q1, D);
    1254        7847 :     q2 = diviiexact(q2, D);
    1255        7847 :     q3 = diviiexact(q3, D);
    1256             :   }
    1257        7868 :   D = qfb_disc3(q1, q2, q3);
    1258        7868 :   if (!signe(D))
    1259          49 :     M = mkmat22(gen_1, truedivii(negi(q2),shifti(q1,1)), gen_0, gen_1);
    1260        7819 :   else if (issquareall(D,&vD))
    1261          35 :     M = redqfbsplit(q1, q2, q3, vD);
    1262             :   else
    1263        7784 :     M = gel(qfbredsl2(mkqfb(q1,q2,q3,D), NULL), 2);
    1264        7868 :   R = red_Cremona_Stoll(polreduce(P, M), &M2);
    1265        7868 :   if (pM) *pM = gmul(M, M2);
    1266        7868 :   return gc_all(av, pM ? 2: 1, &R, pM);
    1267             : }
    1268             : 
    1269             : GEN
    1270           7 : hyperellred(GEN W, GEN *pM)
    1271             : {
    1272           7 :   pari_sp av = avma;
    1273             :   long g, d, v;
    1274             :   GEN F, M, Wf, Hf;
    1275           7 :   check_hyperell_Q("hyperellred", &W, &F);
    1276           7 :   d = degpol(F); g = ((d+1)>>1)-1; v = varn(F);
    1277           7 :   (void) ZX_hyperellred(F, &M);
    1278           7 :   Wf = hyperell_redQ(minimalmodel_merge(W, mkvec2(gen_1, M), g, v));
    1279           7 :   Hf = minimalmodel_getH(W, gel(Wf,2), gen_1, M, g, v);
    1280           7 :   if (pM) *pM = mkvec3(gen_1, M, Hf);
    1281           7 :   return gc_all(av, pM ? 2: 1, &Wf, pM);
    1282             : }
    1283             : 
    1284             : static void
    1285       65261 : check_hyperell_Rg(const char *fun, GEN *pW, GEN *pF)
    1286             : {
    1287       65261 :   GEN W = *pW, F = check_hyperell(W);
    1288       65261 :   long v = varn(F);
    1289       65261 :   if (!F || signe(F)==0)
    1290           0 :     pari_err_TYPE(fun, W);
    1291       65261 :   if (typ(W)==t_POL) W = mkvec2(W, pol_0(v));
    1292             :   else
    1293             :   {
    1294       65254 :     GEN P = gel(W, 1), Q = gel(W, 2);
    1295       65254 :     long g = ((degpol(F)+1)>>1)-1;
    1296       65254 :     if( typ(P)!=t_POL) P = scalarpol(P, v);
    1297       65254 :     if( typ(Q)!=t_POL) Q = scalarpol(Q, v);
    1298       65254 :     if (degpol(P) > 2*g+2)
    1299           0 :       pari_err_DOMAIN(fun, "poldegree(P)", ">", utoi(2*g+2), P);
    1300       65254 :     if (degpol(Q) > g+1)
    1301           0 :       pari_err_DOMAIN(fun, "poldegree(Q)", ">", utoi(g+1), Q);
    1302             : 
    1303       65254 :     W = mkvec2(P, Q);
    1304             :   }
    1305       65261 :   if (pF) *pF = F;
    1306       65261 :   *pW = W;
    1307       65261 : }
    1308             : 
    1309             : static void
    1310       65261 : check_hyperell_vc(const char *fun, GEN C, long v, GEN *e, GEN *M, GEN *H)
    1311             : {
    1312       65261 :   if (lg(C)!=4 || typ(gel(C,2))!=t_MAT)
    1313           0 :     pari_err_TYPE(fun,C);
    1314       65261 :   *e = gel(C,1); *M = gel(C,2);
    1315       65261 :   *H = typ(gel(C,3))!=t_POL || varn(gel(C,3))!=v ? scalarpol(gel(C,3), v): gel(C,3);
    1316       65261 : }
    1317             : 
    1318             : GEN
    1319       65261 : hyperellchangecurve(GEN W, GEN C)
    1320             : {
    1321       65261 :   pari_sp av = avma;
    1322             :   GEN F, P, Q, A, B, Bp, e, M, H;
    1323             :   long d, g, v;
    1324       65261 :   check_hyperell_Rg("hyperellchangecurve",&W,&F);
    1325       65261 :   P = gel(W,1); Q = gel(W,2);
    1326       65261 :   d = degpol(F); g = ((d+1)>>1)-1; v = varn(F);
    1327       65261 :   check_hyperell_vc("hyperellchangecurve", C, v, &e, &M, &H);
    1328       65261 :   A = deg1pol_shallow(gcoeff(M,1,1), gcoeff(M,1,2), v);
    1329       65261 :   B = deg1pol_shallow(gcoeff(M,2,1), gcoeff(M,2,2), v);
    1330       65261 :   Bp = gpowers(B, 2*g+2);
    1331       65261 :   P = RgX_RgM2_eval(P, A, Bp, 2*g+2);
    1332       65261 :   Q = RgX_RgM2_eval(Q, A, Bp, g+1);
    1333       65261 :   P = RgX_Rg_div(RgX_sub(P, RgX_mul(H,RgX_add(Q,H))), gsqr(e));
    1334       65261 :   Q = RgX_Rg_div(RgX_add(Q, RgX_mul2n(H,1)), e);
    1335       65261 :   return gerepilecopy(av, mkvec2(P,Q));
    1336             : }

Generated by: LCOV version 1.13