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 - modules - thue.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 95.1 % 989 941
Test Date: 2026-07-23 17:04:59 Functions: 98.5 % 65 64
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : #include "pari.h"
      16              : #include "paripriv.h"
      17              : 
      18              : #define DEBUGLEVEL DEBUGLEVEL_thue
      19              : 
      20              : /********************************************************************/
      21              : /**                                                                **/
      22              : /**             THUE EQUATION SOLVER (G. Hanrot)                   **/
      23              : /**                                                                **/
      24              : /********************************************************************/
      25              : /* In all the forthcoming remarks, "paper" designs the paper "Thue Equations of
      26              :  * High Degree", by Yu. Bilu and G. Hanrot, J. Number Theory (1996). The
      27              :  * numbering of the constants corresponds to Hanrot's thesis rather than to the
      28              :  * paper. See also
      29              :  * "Solving Thue equations without the full unit group", Math. Comp. (2000) */
      30              : 
      31              : /* Check whether tnf is a valid structure */
      32              : static int
      33          805 : checktnf(GEN tnf)
      34              : {
      35          805 :   long l = lg(tnf);
      36              :   GEN v;
      37          805 :   if (typ(tnf)!=t_VEC || (l!=8 && l!=4)) return 0;
      38          392 :   v = gel(tnf,1);
      39          392 :   if (typ(v) != t_VEC || lg(v) != 4) return 0;
      40          392 :   if (l == 4) return 1; /* s=0 */
      41              : 
      42          189 :   (void)checkbnf(gel(tnf,2));
      43          189 :   return (typ(gel(tnf,3)) == t_COL
      44          189 :        && typ(gel(tnf,4)) == t_COL
      45          189 :        && typ(gel(tnf,5)) == t_MAT
      46          189 :        && typ(gel(tnf,6)) == t_MAT
      47          378 :        && typ(gel(tnf,7)) == t_VEC);
      48              : }
      49              : 
      50              : /* Compensates rounding errors for computation/display of the constants.
      51              :  * Round up if dir > 0, down otherwise */
      52              : static GEN
      53         8547 : myround(GEN x, long dir)
      54              : {
      55         8547 :   GEN eps = powis(stoi(dir > 0? 10: -10), -10);
      56         8547 :   return gmul(x, gadd(gen_1, eps));
      57              : }
      58              : 
      59              : /* v a t_VEC/t_VEC */
      60              : static GEN
      61         4097 : vecmax_shallow(GEN v) { return gel(v, vecindexmax(v)); }
      62              : 
      63              : static GEN
      64          241 : tnf_get_roots(GEN poly, long prec, long S, long T)
      65              : {
      66          241 :   GEN R0 = QX_complex_roots(poly, prec), R = cgetg(lg(R0), t_COL);
      67              :   long k;
      68              : 
      69          689 :   for (k=1; k<=S; k++) gel(R,k) = gel(R0,k);
      70              :   /* swap roots to get the usual order */
      71          424 :   for (k=1; k<=T; k++)
      72              :   {
      73          183 :     gel(R,k+S)  = gel(R0,2*k+S-1);
      74          183 :     gel(R,k+S+T)= gel(R0,2*k+S);
      75              :   }
      76          241 :   return R;
      77              : }
      78              : 
      79              : /* Computation of the logarithmic height of x (given by embeddings) */
      80              : static GEN
      81         4412 : LogHeight(GEN x, long prec)
      82              : {
      83         4412 :   pari_sp av = avma;
      84         4412 :   long i, n = lg(x)-1;
      85         4412 :   GEN LH = gen_1;
      86        18768 :   for (i=1; i<=n; i++)
      87              :   {
      88        14356 :     GEN t = gabs(gel(x,i), prec);
      89        14356 :     if (gcmpgs(t,1) > 0) LH = gmul(LH, t);
      90              :   }
      91         4412 :   return gc_upto(av, gdivgu(glog(LH,prec), n));
      92              : }
      93              : 
      94              : /* |x|^(1/n), x t_INT */
      95              : static GEN
      96          113 : absisqrtn(GEN x, long n, long prec)
      97          113 : { GEN r = itor(x,prec); setabssign(r); return sqrtnr(r, n); }
      98              : 
      99              : static GEN
     100         4225 : get_emb(GEN x, GEN r)
     101              : {
     102         4225 :   long l = lg(r), i;
     103              :   GEN y;
     104              : 
     105         4225 :   if (typ(x) == t_INT) return const_col(l-1, x);
     106         4183 :   y = cgetg(l, t_COL);
     107        17693 :   for (i=1; i<l; i++)
     108              :   {
     109        13537 :     GEN e = poleval(x, gel(r,i));
     110        13537 :     if (gequal0(e) || (typ(e) != t_INT && precision(e) <= LOWDEFAULTPREC ))
     111           27 :       return NULL;
     112        13510 :     gel(y,i) = e;
     113              :   }
     114         4156 :   return y;
     115              : }
     116              : 
     117              : /* Computation of the conjugates (sigma_i(v_j)), and log. heights, of elts of v */
     118              : static GEN
     119          630 : Conj_LH(GEN v, GEN *H, GEN r, long prec)
     120              : {
     121          630 :   long j, l = lg(v);
     122          630 :   GEN e, M = cgetg(l,t_MAT);
     123              : 
     124          630 :   (*H) = cgetg(l,t_COL);
     125         4828 :   for (j = 1; j < l; j++)
     126              :   {
     127         4225 :     if (! (e = get_emb(gel(v,j), r)) ) return NULL; /* FAIL */
     128         4198 :     gel(M,j) = e;
     129         4198 :     gel(*H,j) = LogHeight(e, prec);
     130              :   }
     131          603 :   return M;
     132              : }
     133              : 
     134              : /* Computation of M, its inverse A and precision check (see paper) */
     135              : static GEN
     136          214 : T_A_Matrices(GEN MatFU, long r, GEN *eps5, long prec)
     137              : {
     138              :   GEN A, p1, m1, IntM, nia, eps3, eps2;
     139              : 
     140          214 :   m1 = matslice(MatFU, 1,r, 1,r); /* minor order r */
     141          214 :   m1 = glog(gabs(m1, prec), prec); /* HIGH accuracy */
     142          214 :   A = RgM_inv(m1); if (!A) pari_err_PREC("thue");
     143          214 :   IntM = RgM_Rg_add_shallow(RgM_mul(A,m1), gen_m1);
     144          214 :   IntM = gabs(IntM, 0);
     145              : 
     146          214 :   eps2 = gadd(vecmax(IntM), real2n(-prec, LOWDEFAULTPREC)); /* t_REAL */
     147          214 :   nia = vecmax(gabs(A, 0));
     148              : 
     149              :   /* Check for the precision in matrix inversion. See paper, Lemma 2.4.2. */
     150          214 :   p1 = addrr(mulur(r, gmul2n(nia, prec)), eps2); /* t_REAL */
     151          214 :   if (expo(p1) < -2*r) pari_err_PREC("thue");
     152              : 
     153          214 :   p1 = addrr(mulur(r, gmul2n(nia,-prec)), eps2);
     154          214 :   eps3 = mulrr(mulur(2*r*r,nia), p1);
     155          214 :   if (!signe(eps3))
     156           24 :     eps3 = real2n(expo(eps3), LOWDEFAULTPREC);
     157              :   else
     158          190 :     eps3 = myround(eps3, 1);
     159              : 
     160          214 :   if (DEBUGLEVEL>1) err_printf("epsilon_3 -> %Ps\n",eps3);
     161          214 :   *eps5 = mulur(r, eps3); return A;
     162              : }
     163              : 
     164              : /* find a few large primes such that p Z_K = P1 P2 P3 Q, with f(Pi/p) = 1
     165              :  * From x - \alpha y = \prod u_i^b_i we will deduce 3 equations in F_p
     166              :  * in check_prinfo. Eliminating x,y we get a stringent condition on (b_i). */
     167              : static GEN
     168          214 : get_prime_info(GEN bnf)
     169              : {
     170          214 :   long n = 1, e = gexpo(bnf_get_reg(bnf)), nbp = e < 20? 1: 2;
     171          214 :   GEN L = cgetg(nbp+1, t_VEC), nf = bnf_get_nf(bnf), fu = bnf_get_fu(bnf);
     172          214 :   GEN X = pol_x(nf_get_varn(nf));
     173              :   ulong p;
     174         3424 :   for(p = 2147483659UL; n <= nbp; p = unextprime(p+1))
     175              :   {
     176         3210 :     GEN PR, A, U, LP = idealprimedec_limit_f(bnf, utoipos(p), 1);
     177              :     long i;
     178         3210 :     if (lg(LP) < 4) continue;
     179          228 :     A = cgetg(5, t_VECSMALL);
     180          228 :     U = cgetg(4, t_VEC);
     181          228 :     PR = cgetg(4, t_VEC);
     182          912 :     for (i = 1; i <= 3; i++)
     183              :     {
     184          684 :       GEN modpr = zkmodprinit(nf, gel(LP,i));
     185          684 :       GEN a = nf_to_Fq(nf, X, modpr);
     186          684 :       GEN u = nfV_to_FqV(fu, nf, modpr);
     187          684 :       A[i] = itou(a);
     188          684 :       gel(U,i) = ZV_to_Flv(u,p);
     189          684 :       gel(PR,i) = modpr;
     190              :     }
     191          228 :     A[4] = p;
     192          228 :     gel(L,n++) = mkvec3(A,U,PR);
     193              :   }
     194          214 :   return L;
     195              : }
     196              : 
     197              : /* Performs basic computations concerning the equation.
     198              :  * Returns a "tnf" structure containing
     199              :  *  1) the polynomial
     200              :  *  2) the bnf (used to solve the norm equation)
     201              :  *  3) roots, with presumably enough precision
     202              :  *  4) The logarithmic heights of units
     203              :  *  5) The matrix of conjugates of units
     204              :  *  6) its inverse
     205              :  *  7) a few technical constants */
     206              : static GEN
     207          214 : inithue(GEN P, GEN bnf, long flag, long prec)
     208              : {
     209              :   GEN fu, MatFU, x0, tnf, tmp, gpmin, dP, csts, ALH, eps5, ro, c1, c2;
     210          214 :   GEN Ind = gen_1;
     211          214 :   long s,t, k,j, prec_roots, n = degpol(P);
     212              : 
     213          214 :   if (!bnf)
     214              :   {
     215          196 :     bnf = Buchall(P, nf_FORCE, maxss(prec, DEFAULTPREC));
     216          196 :     if (flag) (void)bnfcertify(bnf);
     217              :     else
     218          161 :       Ind = floorr(mulru(bnf_get_reg(bnf), 5));
     219              :   }
     220              : 
     221          214 :   nf_get_sign(bnf_get_nf(bnf), &s, &t);
     222          214 :   fu = bnf_get_fu(bnf);
     223          214 :   prec_roots = prec + nbits2extraprec(gexpo(Q_primpart(fu)));
     224              :   for(;;)
     225              :   {
     226          241 :     ro = tnf_get_roots(P, prec_roots, s, t);
     227          241 :     MatFU = Conj_LH(fu, &ALH, ro, prec);
     228          241 :     if (MatFU) break;
     229           27 :     prec_roots = precdbl(prec_roots);
     230           27 :     if (DEBUGLEVEL>1) pari_warn(warnprec, "inithue", prec_roots);
     231              :   }
     232              : 
     233          214 :   dP = ZX_deriv(P);
     234          214 :   c1 = NULL; /* min |P'(r_i)|, i <= s */
     235          623 :   for (k=1; k<=s; k++)
     236              :   {
     237          409 :     tmp = gabs(poleval(dP,gel(ro,k)),prec);
     238          409 :     if (!c1 || gcmp(tmp,c1) < 0) c1 = tmp;
     239              :   }
     240          214 :   c1 = gdiv(int2n(n-1), c1);
     241          214 :   c1 = gprec_w(myround(c1, 1), DEFAULTPREC);
     242              : 
     243          214 :   c2 = NULL; /* max |r_i - r_j|, i!=j */
     244          947 :   for (k=1; k<=n; k++)
     245         1753 :     for (j=k+1; j<=n; j++)
     246              :     {
     247         1020 :       tmp = gabs(gsub(gel(ro,j),gel(ro,k)), prec);
     248         1020 :       if (!c2 || gcmp(c2,tmp) > 0) c2 = tmp;
     249              :     }
     250          214 :   c2 = gprec_w(myround(c2, -1), DEFAULTPREC);
     251              : 
     252          214 :   if (t==0)
     253           87 :     x0 = real_1(DEFAULTPREC);
     254              :   else
     255              :   {
     256          127 :     gpmin = NULL; /* min |P'(r_i)|, i > s */
     257          289 :     for (k=1; k<=t; k++)
     258              :     {
     259          162 :       tmp = gabs(poleval(dP,gel(ro,s+k)), prec);
     260          162 :       if (!gpmin || gcmp(tmp,gpmin) < 0) gpmin = tmp;
     261              :     }
     262          127 :     gpmin = gprec_w(gpmin, DEFAULTPREC);
     263              : 
     264              :     /* Compute x0. See paper, Prop. 2.2.1 */
     265          127 :     x0 = gmul(gpmin, vecmax_shallow(gabs(imag_i(ro), prec)));
     266          127 :     x0 = sqrtnr(gdiv(int2n(n-1), x0), n);
     267              :   }
     268          214 :   if (DEBUGLEVEL>1)
     269            0 :     err_printf("c1 = %Ps\nc2 = %Ps\nIndice <= %Ps\n", c1, c2, Ind);
     270              : 
     271          214 :   ALH = gmul2n(ALH, 1);
     272          214 :   tnf = cgetg(8,t_VEC); csts = cgetg(9,t_VEC);
     273          214 :   gel(tnf,1) = P;
     274          214 :   gel(tnf,2) = bnf;
     275          214 :   gel(tnf,3) = ro;
     276          214 :   gel(tnf,4) = ALH;
     277          214 :   gel(tnf,5) = MatFU;
     278          214 :   gel(tnf,6) = T_A_Matrices(MatFU, s+t-1, &eps5, prec);
     279          214 :   gel(tnf,7) = csts;
     280          214 :   gel(csts,1) = c1; gel(csts,2) = c2;   gel(csts,3) = LogHeight(ro, prec);
     281          214 :   gel(csts,4) = x0; gel(csts,5) = eps5; gel(csts,6) = utoipos(prec);
     282          214 :   gel(csts,7) = Ind;
     283          214 :   gel(csts,8) = get_prime_info(bnf);
     284          214 :   return tnf;
     285              : }
     286              : 
     287              : typedef struct {
     288              :   GEN c10, c11, c13, c15, c91, bak, NE, Ind, hal, MatFU, divro, Hmu;
     289              :   GEN delta, lambda, inverrdelta, ro, Pi, Pi2;
     290              :   long r, iroot, deg;
     291              : } baker_s;
     292              : 
     293              : static void
     294         4159 : other_roots(long iroot, long *i1, long *i2)
     295              : {
     296         4159 :   switch (iroot) {
     297         1632 :     case 1: *i1=2; *i2=3; break;
     298         1190 :     case 2: *i1=1; *i2=3; break;
     299         1337 :    default: *i1=1; *i2=2; break;
     300              :   }
     301         4159 : }
     302              : /* low precision */
     303              : static GEN
     304         4540 : abslog(GEN x) { return gabs(glog(gtofp(x,DEFAULTPREC),0), 0); }
     305              : 
     306              : /* Compute Baker's bound c9 and B_0, the bound for the b_i's. See Thm 2.3.1 */
     307              : static GEN
     308         3770 : Baker(baker_s *BS)
     309              : {
     310              :   GEN tmp, B0, hb0, c9, Indc11;
     311              :   long i1, i2;
     312              : 
     313         3770 :   other_roots(BS->iroot, &i1,&i2);
     314              :   /* Compute a bound for the h_0 */
     315         3770 :   hb0 = gadd(gmul2n(BS->hal,2), gmul2n(gadd(BS->Hmu,mplog2(DEFAULTPREC)), 1));
     316         3770 :   tmp = gmul(BS->divro, gdiv(gel(BS->NE,i1), gel(BS->NE,i2)));
     317         3770 :   tmp = gmax_shallow(gen_1, abslog(tmp));
     318         3770 :   hb0 = gmax_shallow(hb0, gdiv(tmp, BS->bak));
     319         3770 :   c9 = gmul(BS->c91,hb0);
     320         3770 :   c9 = gprec_w(myround(c9, 1), DEFAULTPREC);
     321         3770 :   Indc11 = rtor(mulir(BS->Ind,BS->c11), DEFAULTPREC);
     322              :   /* Compute B0 according to Lemma 2.3.3 */
     323         3770 :   B0 = mulir(shifti(BS->Ind,1),
     324              :              divrr(addrr(mulrr(c9,mplog(divrr(mulir(BS->Ind, c9),BS->c10))),
     325              :                          mplog(Indc11)), BS->c10));
     326         3770 :   B0 = gmax_shallow(B0, dbltor(2.71828183));
     327         3770 :   B0 = gmax_shallow(B0, mulrr(divir(BS->Ind, BS->c10),
     328              :                               mplog(divrr(Indc11, BS->Pi2))));
     329         3770 :   if (DEBUGLEVEL>1) {
     330            0 :     err_printf("  B0  = %Ps\n",B0);
     331            0 :     err_printf("  Baker = %Ps\n",c9);
     332              :   }
     333         3770 :   return B0;
     334              : }
     335              : 
     336              : /* || x d ||, x t_REAL, d t_INT */
     337              : static GEN
     338         8519 : errnum(GEN x, GEN d)
     339              : {
     340         8519 :   GEN dx = mulir(d, x), D = subri(dx, roundr(dx));
     341         8519 :   setabssign(D); return D;
     342              : }
     343              : 
     344              : /* Try to reduce the bound through continued fractions. *B0 t_REAL. */
     345              : static int
     346         4177 : CF_1stPass(GEN *B0, GEN kappa, baker_s *BS)
     347              : {
     348         4177 :   GEN a, b, q, ql, qd, l0, denbound = mulri(*B0, kappa);
     349              : 
     350         4177 :   if (cmprr(mulrr(dbltor(0.1),sqrr(denbound)), BS->inverrdelta) > 0)
     351            9 :     return -1;
     352              : 
     353         4168 :   q = denom_i( bestappr(BS->delta, denbound) );
     354         4168 :   qd = errnum(BS->delta, q);
     355         4168 :   ql = errnum(BS->lambda,q);
     356              : 
     357         4168 :   l0 = subrr(ql, addrr(mulrr(qd, *B0), divri(dbltor(0.1),kappa)));
     358         4168 :   if (signe(l0) <= 0) return 0;
     359              : 
     360         3488 :   if (BS->r > 1) {
     361         2732 :     a = BS->c15; b = BS->c13;
     362              :   }
     363              :   else {
     364          756 :     a = BS->c11; b = BS->c10;
     365          756 :     l0 = mulrr(l0, Pi2n(1, DEFAULTPREC));
     366              :   }
     367         3488 :   *B0 = divrr(mplog(divrr(mulir(q,a), l0)), b);
     368         3488 :   if (DEBUGLEVEL>1) err_printf("    B0 -> %Ps\n",*B0);
     369         3488 :   return 1;
     370              : }
     371              : 
     372              : static void
     373        10832 : get_B0Bx(baker_s *BS, GEN l0, GEN *B0, GEN *Bx)
     374              : {
     375        10832 :   GEN t = divrr(mulir(BS->Ind, BS->c15), l0);
     376        10832 :   *B0 = divrr(mulir(BS->Ind, mplog(t)), BS->c13);
     377        10832 :   *Bx = sqrtnr(shiftr(t,1), BS->deg);
     378        10832 : }
     379              : 
     380              : static int
     381        20178 : LLL_1stPass(GEN *pB0, GEN kappa, baker_s *BS, GEN *pBx)
     382              : {
     383        20178 :   GEN B0 = *pB0, Bx = *pBx, lllmat, C, l0, l1, triv;
     384              :   long e;
     385              : 
     386        20178 :   C = grndtoi(mulir(mulii(BS->Ind, kappa),
     387              :                     gpow(B0, dbltor(2.2), DEFAULTPREC)), NULL);
     388              : 
     389        20178 :   if (DEBUGLEVEL > 1) err_printf("C (bitsize) : %d\n", expi(C));
     390        20178 :   lllmat = matid(3);
     391        20178 :   if (cmpri(B0, BS->Ind) > 0)
     392              :   {
     393        14324 :     gcoeff(lllmat, 1, 1) = grndtoi(divri(B0, BS->Ind), NULL);
     394        14324 :     triv = shiftr(sqrr(B0), 1);
     395              :   }
     396              :   else
     397         5854 :     triv = addir(sqri(BS->Ind), sqrr(B0));
     398              : 
     399        20178 :   gcoeff(lllmat, 3, 1) = grndtoi(negr(mulir(C, BS->lambda)), &e);
     400        20178 :   if (e >= 0) return -1;
     401        20169 :   gcoeff(lllmat, 3, 2) = grndtoi(negr(mulir(C, BS->delta)), &e);
     402        20169 :   if (e >= 0) return -1;
     403        20169 :   gcoeff(lllmat, 3, 3) = C;
     404        20169 :   lllmat = ZM_lll(lllmat, 0.99, LLL_IM|LLL_INPLACE);
     405              : 
     406        20169 :   l0 = gnorml2(gel(lllmat,1));
     407        20169 :   l0 = subrr(divir(l0, dbltor(1.8262)), triv); /* delta = 0.99 */
     408        20169 :   if (signe(l0) <= 0) return 0;
     409              : 
     410        13667 :   l1 = shiftr(addri(shiftr(B0,1), BS->Ind), -1);
     411        13667 :   l0 = divri(subrr(sqrtr(l0), l1), C);
     412              : 
     413        13667 :   if (signe(l0) <= 0) return 0;
     414              : 
     415        10649 :   get_B0Bx(BS, l0, &B0, &Bx);
     416        10649 :   if (DEBUGLEVEL>=2)
     417              :   {
     418            0 :     err_printf("LLL_First_Pass successful\n");
     419            0 :     err_printf("B0 -> %Ps\n", B0);
     420            0 :     err_printf("x <= %Ps\n", Bx);
     421              :   }
     422        10649 :   *pB0 = B0; *pBx = Bx; return 1;
     423              : }
     424              : 
     425              : /* add solution (x,y) if not already known */
     426              : static void
     427          693 : add_sol(GEN *pS, GEN x, GEN y) { *pS = vec_append(*pS, mkvec2(x,y)); }
     428              : /* z = P(p,q), d = deg P, |z| = |rhs|. Check signs and (possibly)
     429              :  * add solutions (p,q), (-p,-q) */
     430              : static void
     431          182 : add_pm(GEN *pS, GEN p, GEN q, GEN z, long d, GEN rhs)
     432              : {
     433          182 :   if (signe(z) == signe(rhs))
     434              :   {
     435           98 :     add_sol(pS, p, q);
     436           98 :     if (!odd(d)) add_sol(pS, negi(p), negi(q));
     437              :   }
     438              :   else
     439           84 :     if (odd(d))  add_sol(pS, negi(p), negi(q));
     440          182 : }
     441              : 
     442              : /* Check whether a potential solution is a true solution. Return 0 if
     443              :  * truncation error (increase precision) */
     444              : static int
     445           77 : CheckSol(GEN *pS, GEN z1, GEN z2, GEN P, GEN rhs, GEN ro)
     446              : {
     447           77 :   GEN x, y, ro1 = gel(ro,1), ro2 = gel(ro,2);
     448              :   long e;
     449              : 
     450           77 :   y = grndtoi(real_i(gdiv(gsub(z2,z1), gsub(ro1,ro2))), &e);
     451           77 :   if (e > 0) return 0;
     452           77 :   if (!signe(y)) return 1; /* y = 0 taken care of in SmallSols */
     453           70 :   x = gadd(z1, gmul(ro1, y));
     454           70 :   x = grndtoi(real_i(x), &e);
     455           70 :   if (e > 0) return 0;
     456           70 :   if (e <= -13)
     457              :   { /* y != 0 and rhs != 0; check whether P(x,y) = rhs or P(-x,-y) = rhs */
     458           70 :     GEN z = ZX_Z_eval(ZX_rescale(P,y),x);
     459           70 :     if (absequalii(z, rhs)) add_pm(pS, x,y, z, degpol(P), rhs);
     460              :   }
     461           70 :   return 1;
     462              : }
     463              : 
     464              : static const long EXPO1 = 7;
     465              : static int
     466        29476 : round_to_b(GEN v, long B, long b, GEN Delta2, long i1, GEN L)
     467              : {
     468        29476 :   long i, l = lg(v);
     469        29476 :   if (!b)
     470              :   {
     471         2212 :     for (i = 1; i < l; i++)
     472              :     {
     473              :       long c;
     474         1929 :       if (i == i1)
     475         1065 :         c = 0;
     476              :       else
     477              :       {
     478          864 :         GEN d = gneg(gel(L,i));
     479              :         long e;
     480          864 :         d = grndtoi(d,&e);
     481          864 :         if (e > -EXPO1 || is_bigint(d)) return 0;
     482           45 :         c = itos(d); if (labs(c) > B) return 0;
     483              :       }
     484         1110 :       v[i] = c;
     485              :     }
     486              :   }
     487              :   else
     488              :   {
     489        56727 :     for (i = 1; i < l; i++)
     490              :     {
     491              :       long c;
     492        36197 :       if (i == i1)
     493        28207 :         c = b;
     494              :       else
     495              :       {
     496         7990 :         GEN d = gsub(gmulgs(gel(Delta2,i), b), gel(L,i));
     497              :         long e;
     498         7990 :         d = grndtoi(d,&e);
     499         7990 :         if (e > -EXPO1 || is_bigint(d)) return 0;
     500          146 :         c = itos(d); if (labs(c) > B) return 0;
     501              :       }
     502        28353 :       v[i] = c;
     503              :     }
     504              :   }
     505        20813 :   return 1;
     506              : }
     507              : 
     508              : /* mu \prod U[i]^b[i] */
     509              : static ulong
     510        62439 : Fl_factorback(ulong mu, GEN U, GEN b, ulong p)
     511              : {
     512        62439 :   long i, l = lg(U);
     513        62439 :   ulong r = mu;
     514       125451 :   for (i = 1; i < l; i++)
     515              :   {
     516        63012 :     long c = b[i];
     517        63012 :     ulong u = U[i];
     518        63012 :     if (!c) continue;
     519        61761 :     if (c < 0) { u = Fl_inv(u,p); c = -c; }
     520        61761 :     r = Fl_mul(r, Fl_powu(u,c,p), p);
     521              :   }
     522        62439 :   return r;
     523              : }
     524              : 
     525              : /* x - alpha y = \pm mu \prod \mu_i^{b_i}. Reduce mod 3 distinct primes of
     526              :  * degree 1 above the same p, and eliminate x,y => drastic conditions on b_i */
     527              : static int
     528        20813 : check_pr(GEN bi, GEN Lmu, GEN L)
     529              : {
     530        20813 :   GEN A = gel(L,1), U = gel(L,2);
     531        20813 :   ulong a = A[1], b = A[2], c = A[3], p = A[4];
     532        20813 :   ulong r = Fl_mul(Fl_sub(c,b,p), Fl_factorback(Lmu[1],gel(U,1),bi, p), p);
     533        20813 :   ulong s = Fl_mul(Fl_sub(a,c,p), Fl_factorback(Lmu[2],gel(U,2),bi, p), p);
     534        20813 :   ulong t = Fl_mul(Fl_sub(b,a,p), Fl_factorback(Lmu[3],gel(U,3),bi, p), p);
     535        20813 :   return Fl_add(Fl_add(r,s,p),t,p) == 0;
     536              : }
     537              : static int
     538        20813 : check_prinfo(GEN b, GEN Lmu, GEN prinfo)
     539              : {
     540              :   long i;
     541        20890 :   for (i = 1; i < lg(prinfo); i++)
     542        20813 :     if (!check_pr(b, gel(Lmu,i), gel(prinfo,i))) return 0;
     543           77 :   return 1;
     544              : }
     545              : /* For each possible value of b_i1, compute the b_i's
     546              : * and 2 conjugates of z = x - alpha y. Then check. */
     547              : static int
     548         1102 : TrySol(GEN *pS, GEN B0, long i1, GEN Delta2, GEN Lambda, GEN ro,
     549              :        GEN Lmu, GEN NE, GEN MatFU, GEN prinfo, GEN P, GEN rhs)
     550              : {
     551         1102 :   long bi1, i, B = itos(gceil(B0)), l = lg(Delta2);
     552         1102 :   GEN b = cgetg(l,t_VECSMALL), L = cgetg(l,t_VEC);
     553              : 
     554         3075 :   for (i = 1; i < l; i++)
     555              :   {
     556         1973 :     if (i == i1)
     557         1102 :       gel(L,i) = gen_0;
     558              :     else
     559              :     {
     560          871 :       GEN delta = gel(Delta2,i);
     561          871 :       gel(L, i) = gsub(gmul(delta,gel(Lambda,i1)), gel(Lambda,i));
     562              :     }
     563              :   }
     564        30578 :   for (bi1 = -B; bi1 <= B; bi1++)
     565              :   {
     566              :     GEN z1, z2;
     567        29476 :     if (!round_to_b(b, B, bi1, Delta2, i1, L)) continue;
     568        20813 :     if (!check_prinfo(b, Lmu, prinfo)) continue;
     569           77 :     z1 = gel(NE,1);
     570           77 :     z2 = gel(NE,2);
     571          182 :     for (i = 1; i < l; i++)
     572              :     {
     573          105 :       z1 = gmul(z1, gpowgs(gcoeff(MatFU,1,i), b[i]));
     574          105 :       z2 = gmul(z2, gpowgs(gcoeff(MatFU,2,i), b[i]));
     575              :     }
     576           77 :     if (!CheckSol(pS, z1,z2,P,rhs,ro)) return 0;
     577              :   }
     578         1102 :   return 1;
     579              : }
     580              : 
     581              : /* b and c t_REAL; find q1,q2,q3 st q1 b + q2 c + q3 ~ 0 */
     582              : static GEN
     583          183 : GuessQi(GEN b, GEN c, GEN *eps)
     584              : {
     585          183 :   const long shift = 65;
     586              :   GEN Q, L;
     587              : 
     588          183 :   L = matid(3);
     589          183 :   gcoeff(L,3,1) = roundr(shiftr(b, shift));
     590          183 :   gcoeff(L,3,2) = roundr(shiftr(c, shift));
     591          183 :   gcoeff(L,3,3) = int2n(shift);
     592              : 
     593          183 :   Q = gel(lllint(L),1);
     594          183 :   if (!signe(gel(Q,2))) return NULL; /* FAIL */
     595              : 
     596          183 :   *eps = addrr(addir(gel(Q,3), mulir(gel(Q,1),b)), mulir(gel(Q,2),c));
     597          183 :   setabssign(*eps); return Q;
     598              : }
     599              : 
     600              : /* x a t_REAL */
     601              : static GEN
     602          362 : myfloor(GEN x) { return expo(x) > 30 ? ceil_safe(x): floorr(x); }
     603              : 
     604              : /* Check for not-so-small solutions. Return a t_REAL or NULL */
     605              : static GEN
     606          182 : MiddleSols(GEN *pS, GEN bound, GEN roo, GEN P, GEN rhs, long s, GEN c1)
     607              : {
     608              :   long j, k, nmax, d;
     609              :   GEN bndcf;
     610              : 
     611          182 :   if (expo(bound) < 0) return bound;
     612          168 :   d = degpol(P);
     613          168 :   bndcf = sqrtnr(shiftr(c1,1), d - 2);
     614          168 :   if (cmprr(bound, bndcf) < 0) return bound;
     615              :   /* divide by log2((1+sqrt(5))/2)
     616              :    * 1 + ==> ceil
     617              :    * 2 + ==> continued fraction is normalized if last entry is 1
     618              :    * 3 + ==> start at a0, not a1 */
     619          152 :   nmax = 3 + (long)(dbllog2(bound) * 1.44042009041256);
     620          152 :   bound = myfloor(bound);
     621              : 
     622          481 :   for (k = 1; k <= s; k++)
     623              :   {
     624          329 :     GEN ro = real_i(gel(roo,k)), t = gboundcf(ro, nmax);
     625              :     GEN pm1, qm1, p0, q0;
     626              : 
     627          329 :     pm1 = gen_0; p0 = gen_1;
     628          329 :     qm1 = gen_1; q0 = gen_0;
     629              : 
     630        13947 :     for (j = 1; j < lg(t); j++)
     631              :     {
     632              :       GEN p, q, z, Q, R;
     633              :       pari_sp av;
     634        13941 :       p = addii(mulii(p0, gel(t,j)), pm1); pm1 = p0; p0 = p;
     635        13941 :       q = addii(mulii(q0, gel(t,j)), qm1); qm1 = q0; q0 = q;
     636        13941 :       if (cmpii(q, bound) > 0) break;
     637        13618 :       if (DEBUGLEVEL >= 2) err_printf("Checking (+/- %Ps, +/- %Ps)\n",p, q);
     638        13618 :       av = avma;
     639        13618 :       z = ZX_Z_eval(ZX_rescale(P,q), p); /* = P(p/q) q^dep(P) */
     640        13618 :       Q = dvmdii(rhs, z, &R);
     641        13618 :       if (R != gen_0) { set_avma(av); continue; }
     642          252 :       setabssign(Q);
     643          252 :       if (Z_ispowerall(Q, d, &Q))
     644              :       {
     645          112 :         if (!is_pm1(Q)) { p = mulii(p, Q); q = mulii(q, Q); }
     646          112 :         add_pm(pS, p, q, z, d, rhs);
     647              :       }
     648              :     }
     649          329 :     if (j == lg(t))
     650              :     {
     651              :       long prec;
     652            6 :       if (j > nmax) pari_err_BUG("thue [short continued fraction]");
     653              :       /* the theoretical value is bit_prec = gexpo(ro)+1+log2(bound) */
     654            6 :       prec = precdbl(precision(ro));
     655            6 :       if (DEBUGLEVEL>1) pari_warn(warnprec,"thue",prec);
     656            6 :       roo = ZX_realroots_irred(P, prec);
     657            6 :       if (lg(roo)-1 != s) pari_err_BUG("thue [realroots]");
     658            6 :       k--;
     659              :     }
     660              :   }
     661          152 :   return bndcf;
     662              : }
     663              : 
     664              : static void
     665       672700 : check_y_root(GEN *pS, GEN P, GEN Y)
     666              : {
     667       672700 :   GEN r = nfrootsQ(P);
     668              :   long j;
     669       673134 :   for (j = 1; j < lg(r); j++)
     670          434 :     if (typ(gel(r,j)) == t_INT) add_sol(pS, gel(r,j), Y);
     671       672700 : }
     672              : 
     673              : static void
     674       336406 : check_y(GEN *pS, GEN P, GEN poly, GEN Y, GEN rhs)
     675              : {
     676       336406 :   long j, l = lg(poly);
     677       336406 :   GEN Yn = Y;
     678       336406 :   gel(P, l-1) = gel(poly, l-1);
     679      1345582 :   for (j = l-2; j >= 2; j--)
     680              :   {
     681      1009176 :     gel(P,j) = mulii(Yn, gel(poly,j));
     682      1009176 :     if (j > 2) Yn = mulii(Yn, Y);
     683              :   }
     684       336406 :   gel(P,2) = subii(gel(P,2), rhs); /* P = poly(Y/y)*y^deg(poly) - rhs */
     685       336406 :   check_y_root(pS, P, Y);
     686       336406 : }
     687              : 
     688              : /* Check for solutions under a small bound (see paper) */
     689              : static GEN
     690          210 : SmallSols(GEN S, GEN x3, GEN poly, GEN rhs)
     691              : {
     692          210 :   pari_sp av = avma;
     693              :   GEN X, P, rhs2;
     694          210 :   long j, l = lg(poly), n = degpol(poly);
     695              :   ulong y, By;
     696              : 
     697          210 :   x3 = myfloor(x3);
     698              : 
     699          210 :   if (DEBUGLEVEL>1) err_printf("* Checking for small solutions <= %Ps\n", x3);
     700          210 :   if (lgefint(x3) > 3)
     701            0 :     pari_err_OVERFLOW(stack_sprintf("thue (SmallSols): y <= %Ps", x3));
     702          210 :   By = itou(x3);
     703              :   /* y = 0 first: solve X^n = rhs */
     704          210 :   if (odd(n))
     705              :   {
     706          161 :     if (Z_ispowerall(absi_shallow(rhs), n, &X))
     707           28 :       add_sol(&S, signe(rhs) > 0? X: negi(X), gen_0);
     708              :   }
     709           49 :   else if (signe(rhs) > 0 && Z_ispowerall(rhs, n, &X))
     710              :   {
     711           21 :     add_sol(&S, X, gen_0);
     712           21 :     add_sol(&S, negi(X), gen_0);
     713              :   }
     714          210 :   rhs2 = shifti(rhs,1);
     715              :   /* y != 0 */
     716          210 :   P = cgetg(l, t_POL); P[1] = poly[1];
     717       336504 :   for (y = 1; y <= By; y++)
     718              :   {
     719       336294 :     pari_sp av2 = avma;
     720       336294 :     long lS = lg(S);
     721       336294 :     GEN Y = utoipos(y);
     722              :     /* try y */
     723       336294 :     check_y(&S, P, poly, Y, rhs);
     724              :     /* try -y */
     725      1008224 :     for (j = l-2; j >= 2; j -= 2) togglesign( gel(P,j) );
     726       336294 :     if (j == 0) gel(P,2) = subii(gel(P,2), rhs2);
     727       336294 :     check_y_root(&S, P, utoineg(y));
     728       336294 :     if (lS == lg(S)) { set_avma(av2); continue; } /* no solution found */
     729              : 
     730          154 :     if (gc_needed(av,1))
     731              :     {
     732            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"SmallSols");
     733            0 :       (void)gc_all(av, 2, &S, &rhs2);
     734            0 :       P = cgetg(l, t_POL); P[1] = poly[1];
     735              :     }
     736              :   }
     737          210 :   return S;
     738              : }
     739              : 
     740              : /* Computes [x]! */
     741              : static double
     742          196 : fact(double x)
     743              : {
     744          196 :   double ft = 1.0;
     745          910 :   x = floor(x); while (x>1) { ft *= x; x--; }
     746          196 :   return ft ;
     747              : }
     748              : 
     749              : /* Compute all relevant constants needed to solve the equation P(x,y)=a given
     750              :  * the solutions of N_{K/Q}(x)=a (see inithue). */
     751              : GEN
     752          413 : thueinit(GEN pol, long flag, long prec)
     753              : {
     754          413 :   GEN POL, C, L, fa, tnf, bnf = NULL;
     755          413 :   pari_sp av = avma;
     756              :   long s, lfa, dpol;
     757              : 
     758          413 :   if (checktnf(pol)) { bnf = checkbnf(gel(pol,2)); pol = gel(pol,1); }
     759          413 :   if (typ(pol)!=t_POL) pari_err_TYPE("thueinit",pol);
     760          413 :   dpol = degpol(pol);
     761          413 :   if (dpol <= 0) pari_err_CONSTPOL("thueinit");
     762          406 :   RgX_check_ZX(pol, "thueinit");
     763          406 :   if (varn(pol)) { pol = leafcopy(pol); setvarn(pol, 0); }
     764              : 
     765          406 :   POL = Q_primitive_part(pol, &C);
     766          406 :   L = gen_1;
     767          406 :   fa = ZX_factor(POL); lfa = lgcols(fa);
     768          406 :   if (lfa > 2 || itos(gcoeff(fa,1,2)) > 1)
     769              :   { /* reducible polynomial, no need to reduce to the monic case */
     770           91 :     GEN P, Q, R, g, f = gcoeff(fa,1,1), E = gcoeff(fa,1,2);
     771           91 :     long e = itos(E);
     772           91 :     long vy = fetch_var();
     773           91 :     long va = fetch_var();
     774           91 :     long vb = fetch_var();
     775           91 :     C = C? ginv(C): gen_1;
     776           91 :     if (e != 1)
     777              :     {
     778           63 :       if (lfa == 2) {
     779           42 :         tnf = mkvec3(mkvec3(POL,C,L), thueinit(f, flag, prec), E);
     780           42 :         delete_var(); delete_var(); delete_var();
     781           42 :         return gc_GEN(av, tnf);
     782              :       }
     783           21 :       P = gpowgs(f,e);
     784              :     }
     785              :     else
     786           28 :       P = f;
     787           49 :     g = RgX_div(POL, P);
     788           49 :     P = RgX_Rg_sub(RgX_homogenize(f, vy), pol_x(va));
     789           49 :     Q = RgX_Rg_sub(RgX_homogenize(g, vy), pol_x(vb));
     790           49 :     R = polresultant0(P, Q, -1, 0);
     791           49 :     tnf = mkvec3(mkvec3(POL,C,L), mkvecsmall4(degpol(f), e, va,vb),  R);
     792           49 :     delete_var(); delete_var(); delete_var();
     793           49 :     return gc_GEN(av, tnf);
     794              :   }
     795              :   /* POL monic irreducible: POL(x) = C pol(x/L), L integer */
     796          315 :   POL = ZX_primitive_to_monic(POL, &L);
     797          315 :   C = gdiv(powiu(L, dpol), gel(pol, dpol+2));
     798          315 :   pol = POL;
     799              : 
     800          315 :   s = ZX_sturm_irred(pol);
     801          315 :   if (s)
     802              :   {
     803          196 :     long PREC, n = degpol(pol);
     804          196 :     double d, dr, dn = (double)n;
     805              : 
     806          196 :     if (dpol <= 2) pari_err_DOMAIN("thueinit", "P","=",pol,pol);
     807          196 :     dr = (double)((s+n-2)>>1); /* s+t-1 */
     808          196 :     d = dn*(dn-1)*(dn-2);
     809              :     /* Guess precision by approximating Baker's bound. The guess is most of
     810              :      * the time not sharp, ie 10 to 30 decimal digits above what is _really_
     811              :      * necessary. Note that the limiting step is the reduction. See paper. */
     812          196 :     PREC = nbits2prec((long)((5.83 + (dr+4)*5 + log(fact(dr+3)) + (dr+3)*log(dr+2) +
     813          196 :                      (dr+3)*log(d) + log(log(2*d*(dr+2))) + (dr+1))
     814          196 :                      /10.)*32+32);
     815              : 
     816          196 :     if (flag == 0) PREC = (long)(2.2 * PREC); /* Lazy, to be improved */
     817          196 :     if (PREC < prec) PREC = prec;
     818          196 :     if (DEBUGLEVEL >=2) err_printf("prec = %d\n", PREC);
     819              : 
     820              :     for (;;)
     821              :     {
     822          196 :       if (( tnf = inithue(pol, bnf, flag, PREC) )) break;
     823            0 :       PREC = precdbl(PREC);
     824            0 :       if (DEBUGLEVEL>1) pari_warn(warnprec,"thueinit",PREC);
     825            0 :       bnf = NULL; set_avma(av);
     826              :     }
     827              :   }
     828              :   else
     829              :   {
     830              :     GEN ro, c0;
     831              :     long k,l;
     832          119 :     if (!bnf)
     833              :     {
     834          119 :       bnf = gen_0;
     835          119 :       if (expi(ZX_disc(pol)) <= 50)
     836              :       {
     837           91 :         bnf = Buchall(pol, nf_FORCE, DEFAULTPREC);
     838           91 :         if (flag) (void)bnfcertify(bnf);
     839              :       }
     840              :     }
     841           91 :     ro = typ(bnf)==t_VEC? nf_get_roots(bnf_get_nf(bnf))
     842          119 :                         : QX_complex_roots(pol, DEFAULTPREC);
     843          119 :     l = lg(ro); c0 = imag_i(gel(ro,1));
     844          875 :     for (k = 2; k < l; k++) c0 = mulrr(c0, imag_i(gel(ro,k)));
     845          119 :     setsigne(c0,1); c0 = invr(c0); tnf = mkvec3(pol, bnf, c0);
     846              :   }
     847          315 :   gel(tnf,1) = mkvec3(gel(tnf,1), C, L);
     848          315 :   return gc_GEN(av,tnf);
     849              : }
     850              : 
     851              : /* arg(t^2) / 2Pi; arg(t^2) = arg(t/conj(t)) */
     852              : static GEN
     853          632 : argsqr(GEN t, GEN Pi)
     854              : {
     855          632 :   GEN v, u = divrr(garg(t,0), Pi); /* in -1 < u <= 1 */
     856              :   /* reduce mod Z to -1/2 < u <= 1/2 */
     857          632 :   if (signe(u) > 0)
     858              :   {
     859          359 :     v = subrs(u,1); /* ]-1,0] */
     860          359 :     if (abscmprr(v,u) < 0) u = v;
     861              :   }
     862              :   else
     863              :   {
     864          273 :     v = addrs(u,1);/* ]0,1] */
     865          273 :     if (abscmprr(v,u) <= 0) u = v;
     866              :   }
     867          632 :   return u;
     868              : }
     869              : /* i1 != i2 */
     870              : static void
     871         3770 : init_get_B(long i1, long i2, GEN Delta2, GEN Lambda, GEN Deps5, baker_s *BS,
     872              :            long prec)
     873              : {
     874              :   GEN delta, lambda;
     875         3770 :   if (BS->r > 1)
     876              :   {
     877         3454 :     delta = gel(Delta2,i2);
     878         3454 :     lambda = gsub(gmul(delta,gel(Lambda,i1)), gel(Lambda,i2));
     879         3454 :     if (Deps5) BS->inverrdelta = divrr(Deps5, addsr(1,delta));
     880              :   }
     881              :   else
     882              :   { /* r == 1: i1 = s = t = 1; i2 = 2 */
     883          316 :     GEN fu = gel(BS->MatFU,1), ro = BS->ro, t;
     884              : 
     885          316 :     t = gel(fu,2);
     886          316 :     delta = argsqr(t, BS->Pi);
     887          316 :     if (Deps5) BS->inverrdelta = shiftr(gabs(t,prec), prec-1);
     888              : 
     889          316 :     t = gmul(gsub(gel(ro,1), gel(ro,2)), gel(BS->NE,3));
     890          316 :     lambda = argsqr(t, BS->Pi);
     891              :   }
     892         3770 :   BS->delta = delta;
     893         3770 :   BS->lambda = lambda;
     894         3770 : }
     895              : 
     896              : static GEN
     897         1111 : get_B0(long i1, GEN Delta2, GEN Lambda, GEN Deps5, long prec, baker_s *BS)
     898              : {
     899         1111 :   GEN B0 = Baker(BS); /* t_REAL */
     900         1111 :   long step = 0, i2 = (i1 == 1)? 2: 1;
     901              :   for(;;) /* i2 from 1 to r unless r = 1 [then i2 = 2] */
     902              :   {
     903         1111 :     init_get_B(i1,i2, Delta2,Lambda,Deps5, BS, prec);
     904              :     /* Reduce B0 as long as we make progress: newB0 < oldB0 - 0.1 */
     905              :     for (;;)
     906         2393 :     {
     907         3504 :       GEN oldB0 = B0, kappa = utoipos(10);
     908              :       long cf;
     909              : 
     910         4184 :       for (cf = 0; cf < 10; cf++, kappa = muliu(kappa,10))
     911              :       {
     912         4177 :         int res = CF_1stPass(&B0, kappa, BS);
     913         4177 :         if (res < 0) return NULL; /* prec problem */
     914         4168 :         if (res) break;
     915          680 :         if (DEBUGLEVEL>1) err_printf("CF failed. Increasing kappa\n");
     916              :       }
     917         3495 :       if (!step && cf == 10)
     918              :       { /* Semirational or totally rational case */
     919              :         GEN Q, ep, q, l0, denbound;
     920              : 
     921            0 :         if (! (Q = GuessQi(BS->delta, BS->lambda, &ep)) ) break;
     922              : 
     923            0 :         denbound = addii(floorr(B0), absi_shallow(gel(Q,1)));
     924            0 :         q = denom_i( bestappr(BS->delta, denbound) );
     925            0 :         l0 = subrr(errnum(BS->delta, q), ep);
     926            0 :         if (signe(l0) <= 0) break;
     927              : 
     928            0 :         B0 = divrr(logr_abs(divrr(mulir(gel(Q,2), BS->c15), l0)),  BS->c13);
     929            0 :         if (DEBUGLEVEL>1) err_printf("Semirat. reduction: B0 -> %Ps\n",B0);
     930              :       }
     931              :       /* if no progress, stop */
     932         3495 :       if (gcmp(oldB0, addrr(B0, dbltor(0.1))) <= 0)
     933         1102 :         return gmin_shallow(oldB0, B0);
     934         2393 :       else step++;
     935              :     }
     936            0 :     i2++; if (i2 == i1) i2++;
     937            0 :     if (i2 > BS->r) break;
     938              :   }
     939            0 :   pari_err_BUG("thue (totally rational case)");
     940              :   return NULL; /* LCOV_EXCL_LINE */
     941              : }
     942              : 
     943              : static GEN
     944         2659 : get_Bx_LLL(long i1, GEN Delta2, GEN Lambda, long prec, baker_s *BS)
     945              : {
     946         2659 :   GEN B0 = Baker(BS), Bx = NULL;
     947         2659 :   long step = 0, i2 = (i1 == 1)? 2: 1;
     948              :   for(;;) /* i2 from 1 to r unless r = 1 [then i2 = 2] */
     949              :   {
     950         2659 :     init_get_B(i1,i2, Delta2,Lambda,NULL, BS, prec);
     951         2659 :     if (DEBUGLEVEL>1) err_printf("  Entering LLL...\n");
     952              :     /* Reduce B0 as long as we make progress: newB0 < oldB0 - 0.1 */
     953              :     for (;;)
     954         8386 :     {
     955        11045 :       GEN oldBx = Bx, kappa = utoipos(10);
     956        11045 :       const long cfMAX = 10;
     957              :       long cf;
     958              : 
     959        20565 :       for (cf = 0; cf < cfMAX; cf++, kappa = muliu(kappa,10))
     960              :       {
     961        20178 :         int res = LLL_1stPass(&B0, kappa, BS, &Bx);
     962        20178 :         if (res < 0) return NULL;
     963        20169 :         if (res) break;
     964         9520 :         if (DEBUGLEVEL>1) err_printf("LLL failed. Increasing kappa\n");
     965              :       }
     966              : 
     967              :       /* FIXME: TO BE COMPLETED */
     968        11036 :       if (!step && cf == cfMAX)
     969              :       { /* Semirational or totally rational case */
     970              :         GEN Q, Q1, Q2, ep, q, l0, denbound;
     971              : 
     972          183 :         if (! (Q = GuessQi(BS->delta, BS->lambda, &ep)) ) break;
     973              : 
     974              :         /* Q[2] != 0 */
     975          183 :         Q1 = absi_shallow(gel(Q,1));
     976          183 :         Q2 = absi_shallow(gel(Q,2));
     977          183 :         denbound = gadd(mulri(B0, Q1), mulii(BS->Ind, Q2));
     978          183 :         q = denom_i( bestappr(BS->delta, denbound) );
     979          183 :         l0 = divri(subrr(errnum(BS->delta, q), ep), Q2);
     980          183 :         if (signe(l0) <= 0) break;
     981              : 
     982          183 :         get_B0Bx(BS, l0, &B0, &Bx);
     983          183 :         if (DEBUGLEVEL>1)
     984            0 :           err_printf("Semirat. reduction: B0 -> %Ps x <= %Ps\n",B0, Bx);
     985              :       }
     986              :       /* if no progress, stop */
     987        11036 :       if (oldBx && gcmp(oldBx, Bx) <= 0) return oldBx; else step++;
     988              :     }
     989            0 :     i2++; if (i2 == i1) i2++;
     990            0 :     if (i2 > BS->r) break;
     991              :   }
     992            0 :   pari_err_BUG("thue (totally rational case)");
     993              :   return NULL; /* LCOV_EXCL_LINE */
     994              : }
     995              : 
     996              : static GEN
     997          182 : LargeSols(GEN P, GEN tnf, GEN rhs, GEN ne)
     998              : {
     999          182 :   GEN S = NULL, Delta0, ro, ALH, bnf, nf, MatFU, A, csts, dP, Bx;
    1000              :   GEN c1,c2,c3,c4,c90,c91,c14, x0, x1, x2, x3, tmp, eps5, prinfo;
    1001              :   long iroot, ine, n, r, Prec, prec, s,t;
    1002              :   baker_s BS;
    1003          182 :   pari_sp av = avma;
    1004              : 
    1005          182 :   prec = 0; /*-Wall*/
    1006          182 :   bnf = NULL; /*-Wall*/
    1007          182 :   iroot = 1;
    1008          182 :   ine = 1;
    1009              : 
    1010          200 : START:
    1011          200 :   if (S) /* restart from precision problems */
    1012              :   {
    1013           18 :     S = gc_GEN(av, S);
    1014           18 :     prec = precdbl(prec);
    1015           18 :     if (DEBUGLEVEL) pari_warn(warnprec,"thue",prec);
    1016           18 :     tnf = inithue(P, bnf, 0, prec);
    1017              :   }
    1018              :   else
    1019          182 :     S = cgetg(1, t_VEC);
    1020          200 :   bnf= gel(tnf,2);
    1021          200 :   nf = bnf_get_nf(bnf);
    1022          200 :   csts = gel(tnf,7);
    1023          200 :   nf_get_sign(nf, &s, &t);
    1024          200 :   BS.r = r = s+t-1; n = degpol(P);
    1025          200 :   ro     = gel(tnf,3);
    1026          200 :   ALH    = gel(tnf,4);
    1027          200 :   MatFU  = gel(tnf,5);
    1028          200 :   A      = gel(tnf,6);
    1029          200 :   c1     = mpmul(absi_shallow(rhs), gel(csts,1));
    1030          200 :   c2     = gel(csts,2);
    1031          200 :   BS.hal = gel(csts,3);
    1032          200 :   x0     = gel(csts,4);
    1033          200 :   eps5   = gel(csts,5);
    1034          200 :   Prec = itos(gel(csts,6));
    1035          200 :   BS.Ind = gel(csts,7);
    1036          200 :   BS.MatFU = MatFU;
    1037          200 :   BS.bak = muluu(n, (n-1)*(n-2)); /* safe */
    1038          200 :   BS.deg = n;
    1039          200 :   prinfo = gel(csts,8);
    1040              : 
    1041          200 :   if (t) x0 = gmul(x0, absisqrtn(rhs, n, Prec));
    1042          200 :   tmp = divrr(c1,c2);
    1043          200 :   c3 = mulrr(dbltor(1.39), tmp);
    1044          200 :   c4 = mulur(n-1, c3);
    1045          200 :   c14 = mulrr(c4, vecmax_shallow(RgM_sumcol(gabs(A,DEFAULTPREC))));
    1046              : 
    1047          200 :   x1 = gmax_shallow(x0, sqrtnr(shiftr(tmp,1),n));
    1048          200 :   x2 = gmax_shallow(x1, sqrtnr(mulur(10,c14), n));
    1049          200 :   x3 = gmax_shallow(x2, sqrtnr(shiftr(c14, EXPO1+1),n));
    1050          400 :   c90 = gmul(shiftr(mulur(18,mppi(DEFAULTPREC)), 5*(4+r)),
    1051          200 :                     gmul(gmul(mpfact(r+3), powiu(muliu(BS.bak,r+2), r+3)),
    1052          200 :                          glog(muliu(BS.bak,2*(r+2)),DEFAULTPREC)));
    1053              : 
    1054          200 :   dP = ZX_deriv(P);
    1055          200 :   Delta0 = RgM_sumcol(A);
    1056              : 
    1057          571 :   for (; iroot<=s; iroot++)
    1058              :   {
    1059          389 :     GEN Delta = Delta0, Delta2, D, Deps5, MatNE, Hmu, diffRo, c5, c7, ro0;
    1060              :     long i1, iroot1, iroot2, k;
    1061              : 
    1062          389 :     if (iroot <= r) Delta = RgC_add(Delta, RgC_Rg_mul(gel(A,iroot), stoi(-n)));
    1063          389 :     D = gabs(Delta,Prec); i1 = vecindexmax(D);
    1064          389 :     c5 = gel(D, i1);
    1065          389 :     Delta2 = RgC_Rg_div(Delta, gel(Delta, i1));
    1066          389 :     c5  = myround(gprec_w(c5,DEFAULTPREC), 1);
    1067          389 :     Deps5 = divrr(subrr(c5,eps5), eps5);
    1068          389 :     c7  = mulur(r,c5);
    1069          389 :     BS.c10 = divur(n,c7);
    1070          389 :     BS.c13 = divur(n,c5);
    1071          389 :     if (DEBUGLEVEL>1) {
    1072            0 :       err_printf("* real root no %ld/%ld\n", iroot,s);
    1073            0 :       err_printf("  c10 = %Ps\n",BS.c10);
    1074            0 :       err_printf("  c13 = %Ps\n",BS.c13);
    1075              :     }
    1076              : 
    1077          389 :     prec = Prec;
    1078              :     for (;;)
    1079              :     {
    1080          389 :       if (( MatNE = Conj_LH(ne, &Hmu, ro, prec) )) break;
    1081            0 :       prec = precdbl(prec);
    1082            0 :       if (DEBUGLEVEL>1) pari_warn(warnprec,"thue",prec);
    1083            0 :       ro = tnf_get_roots(P, prec, s, t);
    1084              :     }
    1085          389 :     ro0 = gel(ro,iroot);
    1086          389 :     BS.ro    = ro;
    1087          389 :     BS.iroot = iroot;
    1088          389 :     BS.Pi  = mppi(prec);
    1089          389 :     BS.Pi2 = Pi2n(1,prec);
    1090          389 :     diffRo = cgetg(r+1, t_VEC);
    1091         1159 :     for (k=1; k<=r; k++)
    1092              :     {
    1093          770 :       GEN z = gel(ro,k);
    1094          770 :       z = (k == iroot)? gdiv(rhs, poleval(dP, z)): gsub(ro0, z);
    1095          770 :       gel(diffRo,k) = gabs(z, prec);
    1096              :     }
    1097          389 :     other_roots(iroot, &iroot1,&iroot2);
    1098          389 :     BS.divro = gdiv(gsub(ro0, gel(ro,iroot2)), gsub(ro0, gel(ro,iroot1)));
    1099              :     /* Compute h_1....h_r */
    1100          389 :     c91 = c90;
    1101         1159 :     for (k=1; k<=r; k++)
    1102              :     {
    1103          770 :       GEN z = gdiv(gcoeff(MatFU,iroot1,k), gcoeff(MatFU,iroot2,k));
    1104          770 :       z = gmax_shallow(gen_1, abslog(z));
    1105          770 :       c91 = gmul(c91, gmax_shallow(gel(ALH,k), gdiv(z, BS.bak)));
    1106              :     }
    1107          389 :     BS.c91 = c91;
    1108              : 
    1109         4141 :     for (; ine<lg(ne); ine++)
    1110              :     {
    1111         3770 :       pari_sp av2 = avma;
    1112         3770 :       long lS = lg(S);
    1113              :       GEN Lambda, B0, c6, c8;
    1114         3770 :       GEN NE = gel(MatNE,ine), v = cgetg(r+1,t_COL);
    1115              : 
    1116         3770 :       if (DEBUGLEVEL>1) err_printf("  - norm sol. no %ld/%ld\n",ine,lg(ne)-1);
    1117        11652 :       for (k=1; k<=r; k++)
    1118              :       {
    1119         7882 :         GEN z = gdiv(gel(diffRo,k), gabs(gel(NE,k), prec));
    1120         7882 :         gel(v,k) = glog(z, prec);
    1121              :       }
    1122         3770 :       Lambda = RgM_RgC_mul(A,v);
    1123              : 
    1124         3770 :       c6 = addrr(dbltor(0.1), vecmax_shallow(gabs(Lambda,DEFAULTPREC)));
    1125         3770 :       c6 = myround(c6, 1);
    1126         3770 :       c8 = addrr(dbltor(1.23), mulur(r,c6));
    1127         3770 :       BS.c11= mulrr(shiftr(c3,1) , mpexp(divrr(mulur(n,c8),c7)));
    1128         3770 :       BS.c15= mulrr(shiftr(c14,1), mpexp(divrr(mulur(n,c6),c5)));
    1129         3770 :       BS.NE = NE;
    1130         3770 :       BS.Hmu = gel(Hmu,ine);
    1131         3770 :       if (is_pm1(BS.Ind))
    1132              :       {
    1133         1111 :         GEN mu = gel(ne,ine), Lmu = cgetg(lg(prinfo),t_VEC);
    1134              :         long i, j;
    1135              : 
    1136         2229 :         for (i = 1; i < lg(prinfo); i++)
    1137              :         {
    1138         1118 :           GEN v = gel(prinfo,i), PR = gel(v,3), L = cgetg(4, t_VECSMALL);
    1139         4472 :           for (j = 1; j <= 3; j++) L[j] = itou(nf_to_Fq(nf, mu, gel(PR,j)));
    1140         1118 :           gel(Lmu, i) = L;
    1141              :         }
    1142         2213 :         if (! (B0 = get_B0(i1, Delta2, Lambda, Deps5, prec, &BS)) ||
    1143         1102 :             !TrySol(&S, B0, i1, Delta2, Lambda, ro, Lmu, NE,MatFU,prinfo,
    1144              :                     P,rhs))
    1145           18 :           goto START;
    1146         1102 :         if (lg(S) == lS) set_avma(av2);
    1147              :       }
    1148              :       else
    1149              :       {
    1150         2659 :         if (! (Bx = get_Bx_LLL(i1, Delta2, Lambda, prec, &BS)) )
    1151            9 :            goto START;
    1152         2650 :         x3 = gc_upto(av2, gmax_shallow(Bx, x3));
    1153              :       }
    1154              :     }
    1155          371 :     ine = 1;
    1156              :   }
    1157          182 :   x3 = gmax_shallow(x0, MiddleSols(&S, x3, ro, P, rhs, s, c1));
    1158          182 :   return SmallSols(S, x3, P, rhs);
    1159              : }
    1160              : 
    1161              : /* restrict to solutions (x,y) with L | x, replacing each by (x/L, y) */
    1162              : static GEN
    1163          343 : filter_sol_x(GEN S, GEN L)
    1164              : {
    1165              :   long i, k, l;
    1166          343 :   if (is_pm1(L)) return S;
    1167           84 :   l = lg(S); k = 1;
    1168          532 :   for (i = 1; i < l; i++)
    1169              :   {
    1170          448 :     GEN s = gel(S,i), r;
    1171          448 :     gel(s,1) = dvmdii(gel(s,1), L, &r);
    1172          448 :     if (r == gen_0) gel(S, k++) = s;
    1173              :   }
    1174           84 :   setlg(S, k); return S;
    1175              : }
    1176              : static GEN
    1177           70 : filter_sol_Z(GEN S)
    1178              : {
    1179           70 :   long i, k = 1, l = lg(S);
    1180          749 :   for (i = 1; i < l; i++)
    1181              :   {
    1182          679 :     GEN s = gel(S,i);
    1183          679 :     if (RgV_is_ZV(s)) gel(S, k++) = s;
    1184              :   }
    1185           70 :   setlg(S, k); return S;
    1186              : }
    1187              : 
    1188              : static GEN bnfisintnorm_i(GEN bnf, GEN a, long s, GEN z, long flag);
    1189              : static GEN
    1190          175 : tnf_get_Ind(GEN tnf) { return gmael(tnf,7,7); }
    1191              : static GEN
    1192          294 : tnf_get_bnf(GEN tnf) { return gel(tnf,2); }
    1193              : 
    1194              : static void
    1195            0 : maybe_warn(GEN bnf, GEN a, GEN Ind)
    1196              : {
    1197            0 :   if (!is_pm1(Ind) && !is_pm1(bnf_get_no(bnf)) && !is_pm1(a))
    1198            0 :     pari_warn(warner, "The result returned by 'thue' is conditional on the GRH");
    1199            0 : }
    1200              : /* true bnf; return solutions of Norm(x) = a mod U(K)^+ */
    1201              : static GEN
    1202          224 : get_ne(GEN bnf, GEN a, GEN fa, GEN Ind)
    1203              : {
    1204          224 :   if (DEBUGLEVEL) maybe_warn(bnf,a,Ind);
    1205          224 :   return bnfisintnorm_i(bnf, a, signe(a), bnfisintnormabs(bnf, mkvec2(a,fa)), 0);
    1206              : }
    1207              : /* return solutions of |Norm(x)| = |a| mod U(K) */
    1208              : static GEN
    1209           28 : get_neabs(GEN bnf, GEN a, GEN Ind)
    1210              : {
    1211           28 :   if (DEBUGLEVEL) maybe_warn(bnf,a,Ind);
    1212           28 :   return bnfisintnormabs(bnf, a);
    1213              : }
    1214              : 
    1215              : /* Let P(z)=z^2+Bz+C, convert t=u+v*z (mod P) solution of norm equation N(t)=A
    1216              :  * to [x,y] = [u,-v] form: y^2P(x/y) = A */
    1217              : static GEN
    1218          679 : ne2_to_xy(GEN t)
    1219              : {
    1220              :   GEN u,v;
    1221          679 :   if (typ(t) != t_POL) { u = t; v = gen_0; }
    1222          651 :   else switch(degpol(t))
    1223              :   {
    1224            0 :     case -1: u = v = gen_0; break;
    1225           14 :     case 0: u = gel(t,2); v = gen_0; break;
    1226          637 :     default: u = gel(t,2); v = gneg(gel(t,3));
    1227              :   }
    1228          679 :   return mkvec2(u, v);
    1229              : }
    1230              : static GEN
    1231           70 : ne2V_to_xyV(GEN x)
    1232          749 : { pari_APPLY_same(ne2_to_xy(gel(x,i))); }
    1233              : 
    1234              : static GEN
    1235           21 : sol_0(void) { retmkvec( mkvec2(gen_0,gen_0) ); }
    1236              : static void
    1237          140 : sols_from_R(GEN Rab, GEN *pS, GEN P, GEN POL, GEN rhs)
    1238              : {
    1239          140 :   GEN ry = nfrootsQ(Rab);
    1240          140 :   long k, l = lg(ry);
    1241          280 :   for (k = 1; k < l; k++)
    1242          140 :     if (typ(gel(ry,k)) == t_INT) check_y(pS, P, POL, gel(ry,k), rhs);
    1243          140 : }
    1244              : static GEN
    1245           70 : absZ_factor_if_easy(GEN rhs, GEN x3)
    1246              : {
    1247              :   GEN F, U;
    1248           70 :   if (expi(rhs) < 150 || expo(x3) >= BITS_IN_LONG) return absZ_factor(rhs);
    1249            0 :   F = absZ_factor_limit_strict(rhs, 500000, &U);
    1250            0 :   return U? NULL: F;
    1251              : }
    1252              : /* Given a tnf structure as returned by thueinit, a RHS and
    1253              :  * optionally the solutions to the norm equation, returns the solutions to
    1254              :  * the Thue equation F(x,y)=a */
    1255              : GEN
    1256          392 : thue(GEN tnf, GEN rhs, GEN ne)
    1257              : {
    1258          392 :   pari_sp av = avma;
    1259              :   GEN POL, C, L, x3, S;
    1260              : 
    1261          392 :   if (typ(tnf) == t_POL) tnf = thueinit(tnf, 0, DEFAULTPREC);
    1262          392 :   if (!checktnf(tnf)) pari_err_TYPE("thue [please apply thueinit()]", tnf);
    1263          392 :   if (typ(rhs) != t_INT) pari_err_TYPE("thue",rhs);
    1264          392 :   if (ne && typ(ne) != t_VEC) pari_err_TYPE("thue",ne);
    1265              : 
    1266              :   /* solve P(x,y) = rhs <=> POL(L x, y) = C rhs, with POL monic in Z[X] */
    1267          392 :   POL = gel(tnf,1);
    1268          392 :   C = gel(POL,2); rhs = gmul(C, rhs);
    1269          392 :   if (typ(rhs) != t_INT) retgc_const(av, cgetg(1, t_VEC));
    1270          392 :   if (!signe(rhs))
    1271              :   {
    1272           28 :     GEN v = gel(tnf,2);
    1273           28 :     set_avma(av);
    1274              :     /* at least 2 irreducible factors, one of which has degree 1 */
    1275           28 :     if (typ(v) == t_VECSMALL && v[1] ==1)
    1276            7 :       pari_err_DOMAIN("thue","#sols","=",strtoGENstr("oo"),rhs);
    1277           21 :     return sol_0();
    1278              :   }
    1279          364 :   L = gel(POL,3);
    1280          364 :   POL = gel(POL,1);
    1281          364 :   if (lg(tnf) == 8)
    1282              :   {
    1283          182 :     if (!ne)
    1284              :     {
    1285          154 :       GEN F = absZ_factor(rhs);
    1286          154 :       ne = get_ne(tnf_get_bnf(tnf), rhs, F, tnf_get_Ind(tnf));
    1287              :     }
    1288          182 :     if (lg(ne) == 1) retgc_const(av, cgetg(1, t_VEC));
    1289          182 :     S = LargeSols(POL, tnf, rhs, ne);
    1290              :   }
    1291          182 :   else if (typ(gel(tnf,3)) == t_REAL)
    1292              :   { /* Case s=0. All solutions are "small". */
    1293          112 :     GEN bnf = tnf_get_bnf(tnf);
    1294          112 :     GEN c0 = gel(tnf,3), F;
    1295          112 :     x3 = sqrtnr(mulir(absi_shallow(rhs),c0), degpol(POL));
    1296          112 :     x3 = addrr(x3, dbltor(0.1)); /* guard from round-off errors */
    1297          112 :     S = cgetg(1,t_VEC);
    1298          112 :     if (!ne && typ(bnf) == t_VEC && expo(x3) > 10)
    1299              :     {
    1300           70 :       F = absZ_factor_if_easy(rhs, x3);
    1301           70 :       if (F) ne = get_ne(bnf, rhs, F, gen_1);
    1302              :     }
    1303          112 :     if (ne)
    1304              :     {
    1305           91 :       if (lg(ne) == 1) retgc_const(av, cgetg(1, t_VEC));
    1306           77 :       if (degpol(POL) == 2) /* quadratic imaginary */
    1307              :       {
    1308           70 :         GEN u = NULL;
    1309           70 :         long w = 2;
    1310           70 :         if (typ(bnf) == t_VEC)
    1311              :         {
    1312           56 :           u = bnf_get_tuU(bnf);
    1313           56 :           w = bnf_get_tuN(bnf);
    1314              :         }
    1315              :         else
    1316              :         {
    1317           14 :           GEN D = coredisc(ZX_disc(POL));
    1318           14 :           if (cmpis(D, -4) >= 0)
    1319              :           {
    1320           14 :             GEN F, T = quadpoly_i(D);
    1321           14 :             w = equalis(D, -4)? 4: 6;
    1322           14 :             setvarn(T, fetch_var_higher());
    1323           14 :             F = gcoeff(nffactor(POL, T), 1, 1);
    1324           14 :             u = gneg(lift_shallow(gel(F,2))); delete_var();
    1325              :           }
    1326              :         }
    1327           70 :         if (w == 4) /* u = I */
    1328           28 :           ne = shallowconcat(ne, RgXQV_RgXQ_mul(ne,u,POL));
    1329           42 :         else if (w == 6) /* u = j */
    1330              :         {
    1331           28 :           GEN u2 = RgXQ_sqr(u,POL);
    1332           28 :           ne = shallowconcat1(mkvec3(ne, RgXQV_RgXQ_mul(ne,u,POL),
    1333              :                                          RgXQV_RgXQ_mul(ne,u2,POL)));
    1334              :         }
    1335           70 :         S = ne2V_to_xyV(ne);
    1336           70 :         S = filter_sol_Z(S);
    1337           70 :         S = shallowconcat(S, RgV_neg(S));
    1338              :       }
    1339              :     }
    1340           98 :     if (lg(S) == 1) S = SmallSols(S, x3, POL, rhs);
    1341              :   }
    1342           70 :   else if (typ(gel(tnf,3)) == t_INT) /* reducible case, pure power*/
    1343              :   {
    1344           35 :     GEN bnf, ne1 = NULL, ne2 = NULL;
    1345           35 :     long e = itos( gel(tnf,3) );
    1346           35 :     if (!Z_ispowerall(rhs, e, &rhs)) retgc_const(av, cgetg(1, t_VEC));
    1347           28 :     tnf = gel(tnf,2);
    1348           28 :     bnf = tnf_get_bnf(tnf);
    1349           28 :     ne = get_neabs(bnf, rhs, lg(tnf)==8?tnf_get_Ind(tnf): gen_1);
    1350           28 :     ne1= bnfisintnorm_i(bnf,rhs,1,ne,0);
    1351           28 :     S = thue(tnf, rhs, ne1);
    1352           28 :     if (!odd(e) && lg(tnf)==8) /* if s=0, norms are positive */
    1353              :     {
    1354            7 :       ne2 = bnfisintnorm_i(bnf,rhs,-1,ne,0);
    1355            7 :       S = shallowconcat(S, thue(tnf, negi(rhs), ne2));
    1356              :     }
    1357              :   }
    1358              :   else /* other reducible cases */
    1359              :   { /* solve f^e * g = rhs, f irreducible factor of smallest degree */
    1360           35 :     GEN P, D, v = gel(tnf, 2), R = gel(tnf, 3);
    1361           35 :     long i, l, e = v[2], va = v[3], vb = v[4];
    1362           35 :     P = cgetg(lg(POL), t_POL); P[1] = POL[1];
    1363           35 :     D = divisors(rhs); l = lg(D);
    1364           35 :     S = cgetg(1,t_VEC);
    1365          217 :     for (i = 1; i < l; i++)
    1366              :     {
    1367          182 :       GEN Rab, df = gel(D,i), dg = gel(D,l-i); /* df*dg=|rhs| */
    1368          182 :       if (e > 1 && !Z_ispowerall(df, e, &df)) continue;
    1369              :       /* Rab: univariate polynomial in Z[Y], whose roots are the possible y. */
    1370              :       /* Here and below, Rab != 0 */
    1371           70 :       if (signe(rhs) < 0) dg = negi(dg); /* df*dg=rhs */
    1372           70 :       Rab = gsubst(gsubst(R, va, df), vb, dg);
    1373           70 :       sols_from_R(Rab, &S,P,POL,rhs);
    1374           70 :       Rab = gsubst(gsubst(R, va, negi(df)), vb, odd(e)? negi(dg): dg);
    1375           70 :       sols_from_R(Rab, &S,P,POL,rhs);
    1376              :     }
    1377              :   }
    1378          343 :   S = filter_sol_x(S, L);
    1379          343 :   S = gen_sort_uniq(S, (void*)lexcmp, cmp_nodata);
    1380          343 :   return gc_upto(av, S);
    1381              : }
    1382              : 
    1383              : /********************************************************************/
    1384              : /**                                                                **/
    1385              : /**                      BNFISINTNORM (K. Belabas)                 **/
    1386              : /**                                                                **/
    1387              : /********************************************************************/
    1388              : struct sol_abs
    1389              : {
    1390              :   GEN rel; /* Primes PR[i] above a, expressed on generators of Cl(K) */
    1391              :   GEN partrel; /* list of vectors, partrel[i] = rel[1..i] * u[1..i] */
    1392              :   GEN cyc;     /* orders of generators of Cl(K) given in bnf */
    1393              : 
    1394              :   long *f;     /* f[i] = f(PR[i]/p), inertia degree */
    1395              :   long *n;     /* a = prod p^{ n_p }. n[i]=n_p if PR[i] divides p */
    1396              :   long *next;  /* index of first P above next p, 0 if p is last */
    1397              :   long *S;     /* S[i] = n[i] - sum_{ 1<=k<=i } f[k]*u[k] */
    1398              :   long *u;     /* We want principal ideals I = prod PR[i]^u[i] */
    1399              :   GEN  normsol;/* lists of copies of the u[] which are solutions */
    1400              : 
    1401              :   long nPR;    /* length(T->rel) = #PR */
    1402              :   long sindex, smax; /* current index in T->normsol; max. index */
    1403              : };
    1404              : 
    1405              : /* u[1..i] has been filled. Norm(u) is correct.
    1406              :  * Check relations in class group then save it. */
    1407              : static void
    1408        30639 : test_sol(struct sol_abs *T, long i)
    1409              : {
    1410              :   long k, l;
    1411              :   GEN s;
    1412              : 
    1413        30639 :   if (T->partrel && !ZV_dvd(gel(T->partrel, i),  T->cyc)) return;
    1414        14546 :   if (T->sindex == T->smax)
    1415              :   { /* no more room in solution list: enlarge */
    1416            0 :     long new_smax = T->smax << 1;
    1417            0 :     GEN  new_normsol = new_chunk(new_smax+1);
    1418              : 
    1419            0 :     for (k=1; k<=T->smax; k++) gel(new_normsol,k) = gel(T->normsol,k);
    1420            0 :     T->normsol = new_normsol; T->smax = new_smax;
    1421              :   }
    1422        14546 :   gel(T->normsol, ++T->sindex) = s = cgetg_copy(T->u, &l);
    1423        60389 :   for (k=1; k <= i; k++) s[k] = T->u[k];
    1424        26453 :   for (   ; k < l;  k++) s[k] = 0;
    1425        14546 :   if (DEBUGLEVEL>2)
    1426              :   {
    1427            0 :     err_printf("sol = %Ps\n",s);
    1428            0 :     if (T->partrel) err_printf("T->partrel = %Ps\n",T->partrel);
    1429              :   }
    1430              : }
    1431              : /* partrel[i] <-- partrel[i-1] + u[i] * rel[i] */
    1432              : static void
    1433        21665 : fix_partrel(struct sol_abs *T, long i)
    1434              : {
    1435        21665 :   pari_sp av = avma;
    1436        21665 :   GEN part1 = gel(T->partrel,i);
    1437        21665 :   GEN part0 = gel(T->partrel,i-1);
    1438        21665 :   GEN rel = gel(T->rel, i);
    1439        21665 :   ulong u = T->u[i];
    1440        21665 :   long k, l = lg(part1);
    1441        64729 :   for (k=1; k < l; k++)
    1442        43064 :     affii(addii(gel(part0,k), muliu(gel(rel,k), u)), gel(part1,k));
    1443        21665 :   set_avma(av);
    1444        21665 : }
    1445              : 
    1446              : /* assume compatible dimensions */
    1447              : static void
    1448        63273 : ZV_affect(GEN x, GEN y)
    1449              : {
    1450        63273 :   long i, l = lg(y);
    1451       166264 :   for (i = 1; i < l; i++) affii(gel(x,i), gel(y,i));
    1452        63273 : }
    1453              : 
    1454              : /* Recursive loop. Suppose u[1..i] has been filled
    1455              :  * Find possible solutions u such that, Norm(prod PR[i]^u[i]) = a, taking
    1456              :  * into account:
    1457              :  *  1) the relations in the class group if need be.
    1458              :  *  2) the factorization of a. */
    1459              : static void
    1460        80122 : isintnorm_loop(struct sol_abs *T, long i)
    1461              : {
    1462        80122 :   if (T->S[i] == 0) /* sum u[i].f[i] = n[i], do another prime */
    1463              :   {
    1464        34146 :     long k, next = T->next[i];
    1465        34146 :     if (next == 0) { test_sol(T, i); return; } /* no primes left */
    1466              : 
    1467              :     /* some primes left */
    1468        13986 :     if (T->partrel) ZV_affect(gel(T->partrel,i), gel(T->partrel, next-1));
    1469        21091 :     for (k=i+1; k < next; k++) T->u[k] = 0;
    1470        13986 :     i = next-1;
    1471              :   }
    1472        45976 :   else if (i == T->next[i]-2 || i == T->nPR-1)
    1473              :   { /* only one Prime left above prime; change prime, fix u[i+1] */
    1474              :     long q;
    1475        28455 :     if (T->S[i] % T->f[i+1]) return;
    1476        14420 :     q = T->S[i] / T->f[i+1];
    1477        14420 :     i++; T->u[i] = q;
    1478        14420 :     if (T->partrel) fix_partrel(T,i);
    1479        14420 :     if (T->next[i] == 0) { test_sol(T,i); return; }
    1480              :   }
    1481              : 
    1482        35448 :   i++; T->u[i] = 0;
    1483        35448 :   if (T->partrel) ZV_affect(gel(T->partrel,i-1), gel(T->partrel,i));
    1484        35448 :   if (i == T->next[i-1])
    1485              :   { /* change prime */
    1486        31304 :     if (T->next[i] == i+1 || i == T->nPR) /* only one Prime above p */
    1487              :     {
    1488        10598 :       T->S[i] = 0;
    1489        10598 :       T->u[i] = T->n[i] / T->f[i]; /* we already know this is exact */
    1490        10598 :       if (T->partrel) fix_partrel(T, i);
    1491              :     }
    1492        20706 :     else T->S[i] = T->n[i];
    1493              :   }
    1494         4144 :   else T->S[i] = T->S[i-1]; /* same prime, different Prime */
    1495              :   for(;;)
    1496              :   {
    1497        66304 :     isintnorm_loop(T, i);
    1498        66304 :     T->S[i] -= T->f[i]; if (T->S[i] < 0) break;
    1499        30856 :     T->u[i]++;
    1500        30856 :     if (T->partrel) {
    1501        22568 :       pari_sp av = avma;
    1502        22568 :       ZV_affect(ZC_add(gel(T->partrel,i), gel(T->rel,i)), gel(T->partrel,i));
    1503        22568 :       set_avma(av);
    1504              :     }
    1505              :   }
    1506              : }
    1507              : 
    1508              : static int
    1509        21903 : get_sol_abs(struct sol_abs *T, GEN bnf, GEN nf, GEN fact, GEN *ptPR)
    1510              : {
    1511        21903 :   GEN P = gel(fact,1), E = gel(fact,2), PR;
    1512        21903 :   long N = nf_get_degree(nf), nP = lg(P)-1, Ngen, max, nPR, i, j;
    1513              : 
    1514        21903 :   max = nP*N; /* upper bound for T->nPR */
    1515        21903 :   T->f = new_chunk(max+1);
    1516        21903 :   T->n = new_chunk(max+1);
    1517        21903 :   T->next = new_chunk(max+1);
    1518        21903 :   *ptPR = PR = cgetg(max+1, t_COL); /* length to be fixed later */
    1519              : 
    1520        21903 :   nPR = 0;
    1521        55776 :   for (i = 1; i <= nP; i++)
    1522              :   {
    1523        41958 :     GEN L = idealprimedec(nf, gel(P,i));
    1524        41958 :     long lL = lg(L), gcd, k, v;
    1525        41958 :     ulong vn = itou(gel(E,i));
    1526              : 
    1527              :     /* check that gcd_{P | p} f_P  divides  n_p */
    1528        41958 :     gcd = pr_get_f(gel(L,1));
    1529        41986 :     for (j=2; gcd > 1 && j < lL; j++) gcd = ugcd(gcd, pr_get_f(gel(L,j)));
    1530        41958 :     if (gcd > 1 && vn % gcd)
    1531              :     {
    1532         8085 :       if (DEBUGLEVEL>2) err_printf("gcd f_P  does not divide n_p\n");
    1533         8085 :       return 0;
    1534              :     }
    1535        33873 :     v = (i==nP)? 0: nPR + lL;
    1536        93051 :     for (k = 1; k < lL; k++)
    1537              :     {
    1538        59178 :       GEN pr = gel(L,k);
    1539        59178 :       gel(PR, ++nPR) = pr;
    1540        59178 :       T->f[nPR] = pr_get_f(pr) / gcd;
    1541        59178 :       T->n[nPR] = vn / gcd;
    1542        59178 :       T->next[nPR] = v;
    1543              :     }
    1544              :   }
    1545        13818 :   T->nPR = nPR;
    1546        13818 :   setlg(PR, nPR + 1);
    1547              : 
    1548        13818 :   T->u = cgetg(nPR+1, t_VECSMALL);
    1549        13818 :   T->S = new_chunk(nPR+1);
    1550        13818 :   if (bnf) { T->cyc = bnf_get_cyc(bnf); Ngen = lg(T->cyc)-1; }
    1551          119 :   else { T->cyc = NULL; Ngen = 0; }
    1552        13818 :   if (Ngen == 0)
    1553          861 :     T->rel = T->partrel = NULL; /* trivial Cl(K), no relations to check */
    1554              :   else
    1555              :   {
    1556        12957 :     int triv = 1;
    1557        12957 :     T->partrel = new_chunk(nPR+1);
    1558        12957 :     T->rel = new_chunk(nPR+1);
    1559        58842 :     for (i=1; i <= nPR; i++)
    1560              :     {
    1561        45885 :       GEN c = isprincipal(bnf, gel(PR,i));
    1562        45885 :       gel(T->rel,i) = c;
    1563        45885 :       if (triv && !ZV_equal0(c)) triv = 0; /* non trivial relations in Cl(K)*/
    1564              :     }
    1565              :     /* triv = 1: all ideals dividing a are principal */
    1566        12957 :     if (triv) T->rel = T->partrel = NULL;
    1567              :   }
    1568        13818 :   if (T->partrel)
    1569              :   {
    1570        10640 :     long B = ZV_max_lg(T->cyc) + 3;
    1571        60130 :     for (i = 0; i <= nPR; i++)
    1572              :     { /* T->partrel[0] also needs to be initialized */
    1573        49490 :       GEN c = cgetg(Ngen+1, t_COL); gel(T->partrel,i) = c;
    1574       134694 :       for (j=1; j<=Ngen; j++)
    1575              :       {
    1576        85204 :         GEN z = cgeti(B); gel(c,j) = z;
    1577        85204 :         z[1] = evalsigne(0)|evallgefint(B);
    1578              :       }
    1579              :     }
    1580              :   }
    1581        13818 :   T->smax = 511;
    1582        13818 :   T->normsol = new_chunk(T->smax+1);
    1583        13818 :   T->S[0] = T->n[1];
    1584        13818 :   T->next[0] = 1;
    1585        13818 :   T->sindex = 0;
    1586        13818 :   isintnorm_loop(T, 0); return 1;
    1587              : }
    1588              : 
    1589              : /* Return unit of norm -1 (NULL if it doesn't exit). */
    1590              : static GEN
    1591         3038 : get_unit_1(GEN bnf, long flag)
    1592              : {
    1593              :   GEN v;
    1594              :   long i;
    1595              : 
    1596         3038 :   if (DEBUGLEVEL > 2) err_printf("looking for a fundamental unit of norm -1\n");
    1597         3038 :   if (odd(nf_get_degree(bnf_get_nf(bnf)))) return gen_m1;
    1598         1169 :   v = nfsign_fu(bnf, NULL);
    1599         1190 :   for (i = 1; i < lg(v); i++)
    1600         1183 :     if (Flv_sum( gel(v,i), 2))
    1601              :     {
    1602         1162 :       GEN fu = NULL;
    1603         1162 :       if (flag)
    1604              :       {
    1605            7 :         fu = bnf_build_cheapfu(bnf);
    1606            7 :         if (!fu) fu = bnf_compactfu(bnf);
    1607              :       }
    1608         1162 :       if (!fu) fu = bnf_get_fu(bnf);
    1609         1162 :       return gel(fu, i);
    1610              :     }
    1611            7 :   return NULL;
    1612              : }
    1613              : 
    1614              : GEN
    1615        21896 : bnfisintnormabs0(GEN bnf, GEN a, long flag)
    1616              : {
    1617              :   struct sol_abs T;
    1618              :   GEN nf, res, PR, F;
    1619        21896 :   long i, fl = nf_FORCE | nf_GEN_IF_PRINCIPAL | (flag ? nf_GENMAT: 0);
    1620              : 
    1621        21896 :   if ((F = check_arith_all(a,"bnfisintnormabs")))
    1622              :   {
    1623          826 :     a = typ(a) == t_VEC? gel(a,1): factorback(F);
    1624          826 :     if (signe(a) < 0) F = clean_Z_factor(F);
    1625              :   }
    1626        21896 :   nf = bnf_get_nf(bnf);
    1627        21896 :   if (!signe(a)) return mkvec(gen_0);
    1628        21882 :   if (is_pm1(a)) return mkvec(gen_1);
    1629        21777 :   if (!F) F = absZ_factor(a);
    1630        21777 :   if (!get_sol_abs(&T, bnf, nf, F, &PR)) return cgetg(1, t_VEC);
    1631              :   /* |a| > 1 => T.nPR > 0 */
    1632        13699 :   res = cgetg(T.sindex+1, t_VEC);
    1633        27839 :   for (i=1; i<=T.sindex; i++)
    1634              :   {
    1635        14140 :     GEN x = vecsmall_to_col( gel(T.normsol,i) );
    1636        14140 :     x = isprincipalfact(bnf, NULL, PR, x, fl);
    1637        14140 :     if (!flag) x = nf_to_scalar_or_alg(nf, x);
    1638        14140 :     gel(res,i) = x; /* solution, up to sign */
    1639              :   }
    1640        13699 :   return res;
    1641              : }
    1642              : GEN
    1643          252 : bnfisintnormabs(GEN bnf, GEN a)
    1644          252 : { return bnfisintnormabs0(bnf, a, 0); }
    1645              : 
    1646              : /* true nf */
    1647              : GEN
    1648          161 : ideals_by_norm(GEN nf, GEN a)
    1649              : {
    1650              :   struct sol_abs T;
    1651              :   GEN res, PR, F;
    1652              :   long i;
    1653              : 
    1654          161 :   if ((F = check_arith_pos(a,"ideals_by_norm")))
    1655            0 :     a = typ(a) == t_VEC? gel(a,1): factorback(F);
    1656          161 :   if (is_pm1(a)) return mkvec(trivial_fact());
    1657          126 :   if (!F) F = absZ_factor(a);
    1658          126 :   if (!get_sol_abs(&T, NULL, nf, F, &PR)) return cgetg(1, t_VEC);
    1659          119 :   res = cgetg(T.sindex+1, t_VEC);
    1660          525 :   for (i=1; i<=T.sindex; i++)
    1661              :   {
    1662          406 :     GEN x = vecsmall_to_col( gel(T.normsol,i) );
    1663          406 :     gel(res,i) = famat_remove_trivial(mkmat2(PR, x));
    1664              :   }
    1665          119 :   return res;
    1666              : }
    1667              : 
    1668              : /* largest prime used in factorbase */
    1669              : static ulong
    1670           28 : bnf_get_lastp(GEN bnf)
    1671              : {
    1672           28 :   GEN vbase = gel(bnf,5);
    1673           28 :   long l = lg(vbase), i;
    1674           28 :   ulong P = 0;
    1675         1393 :   for (i = 1; i < l; i++)
    1676              :   {
    1677         1365 :     GEN pr = gel(vbase,i);
    1678         1365 :     ulong p = itou(pr_get_p(pr));
    1679         1365 :     if (p > P) P = p;
    1680              :   }
    1681           28 :   return P;
    1682              : }
    1683              : 
    1684              : /* true bnf; z = bnfisintnormabs0(bnf,a,flag), sa = 1 or -1,
    1685              :  * return bnfisintnorm0(bnf,sa*|a|,flag). If flag is set, allow returning
    1686              :  * elements in factored form */
    1687              : static GEN
    1688        21903 : bnfisintnorm_i(GEN bnf, GEN a, long sa, GEN z, long flag)
    1689              : {
    1690        21903 :   GEN nf = bnf_get_nf(bnf), T = nf_get_pol(nf), f = nf_get_index(nf), unit = gen_0;
    1691        21903 :   GEN Tp, A = signe(a) == sa? a: negi(a);
    1692        21903 :   long sNx, i, j, N = degpol(T), l = lg(z);
    1693        21903 :   ulong p, Ap = 0; /* gcc -Wall */
    1694              :   forprime_t S;
    1695        21903 :   if (!signe(a)) return z;
    1696        21889 :   u_forprime_init(&S, flag? bnf_get_lastp(bnf): 3, ULONG_MAX);
    1697        30492 :   while((p = u_forprime_next(&S)))
    1698        30492 :     if (umodiu(f,p) && (Ap = umodiu(A,p))) break;
    1699        21889 :   Tp = ZX_to_Flx(T,p);
    1700              :   /* p > 2 doesn't divide A nor Q_denom(z in Z_K)*/
    1701              : 
    1702              :   /* update z in place to get correct signs: multiply by unit of norm -1 if
    1703              :    * it exists, otherwise delete solution with wrong sign */
    1704        36141 :   for (i = j = 1; i < l; i++)
    1705              :   {
    1706        14252 :     GEN x = gel(z,i);
    1707        14252 :     long tx = typ(x);
    1708              : 
    1709        14252 :     switch(tx)
    1710              :     {
    1711        13307 :       case t_POL:
    1712              :       {
    1713        13307 :         GEN dx, y = Q_remove_denom(x,&dx);
    1714        13307 :         ulong Np = Flx_resultant(Tp, ZX_to_Flx(y,p), p);
    1715        13307 :         ulong dA = dx? Fl_mul(Ap, Fl_powu(umodiu(dx,p), N, p), p): Ap;
    1716              :         /* Nx = Res(T,y) / dx^N = A or -A. Check mod p */
    1717        13307 :         sNx = dA == Np? sa: -sa; break;
    1718              :       }
    1719          273 :       case t_MAT:
    1720              :       {
    1721          273 :         GEN G = gel(x,1), E = gel(x,2);
    1722          273 :         long k, lG = lg(G);
    1723          273 :         GEN g = cgetg(lG, t_VECSMALL), e = cgetg(lG, t_VECSMALL);
    1724              :         ulong Np;
    1725        30849 :         for (k = 1; k < lG; k++)
    1726              :         {
    1727        30576 :           GEN NGk = nfnorm(nf, gel(G,k));
    1728        30576 :           (void)Z_lvalrem(NGk, p, &NGk);
    1729        30576 :           g[k] = umodiu(NGk, p);
    1730        30576 :           e[k] = umodiu(gel(E,k), p-1);
    1731              :         }
    1732              :         /* N.B. p can appear in Norm(G_k), where G = \prod G_k^{e_k},
    1733              :          * but total v_p(Norm(G)) = v_p(A) = 0 */
    1734          273 :         Np = Flv_factorback(g, e, p);
    1735          273 :         sNx = Np == Ap? sa: -sa; break;
    1736              :       }
    1737          672 :       default: sNx = gsigne(x) < 0 && odd(N) ? -1 : 1;
    1738              :     }
    1739        14252 :     if (sNx != sa)
    1740              :     {
    1741         5054 :       if (unit == gen_0) unit = get_unit_1(bnf, flag);
    1742         5054 :       if (!unit)
    1743              :       {
    1744           77 :         if (DEBUGLEVEL > 2) err_printf("%Ps eliminated because of sign\n",x);
    1745           77 :         continue;
    1746              :       }
    1747         4977 :       switch(tx)
    1748              :       {
    1749         4781 :         case t_POL: x = (unit == gen_m1)? RgX_neg(x): RgXQ_mul(unit,x,T); break;
    1750           14 :         case t_MAT: x = famat_mul(x, unit); break;
    1751          182 :         default: x = (unit == gen_m1)? gneg(x): RgX_Rg_mul(unit,x); break;
    1752              :       }
    1753              :     }
    1754        14175 :     gel(z,j++) = x;
    1755              :   }
    1756        21889 :   setlg(z, j); return z;
    1757              : }
    1758              : GEN
    1759          602 : bnfisintnorm(GEN bnf, GEN a)
    1760          602 : { return bnfisintnorm0(bnf, a, 0); }
    1761              : GEN
    1762        21644 : bnfisintnorm0(GEN bnf, GEN a, long flag)
    1763              : {
    1764        21644 :   pari_sp av = avma;
    1765              :   GEN ne;
    1766        21644 :   bnf = checkbnf(bnf);
    1767        21644 :   if (flag < 0 || flag > 1) pari_err_FLAG("bnfisintnorm");
    1768        21644 :   ne = bnfisintnormabs0(bnf, a, flag);
    1769        21644 :   switch(typ(a))
    1770              :   {
    1771          602 :     case t_VEC: a = gel(a,1); break;
    1772            0 :     case t_MAT: a = factorback(a); break;
    1773              :   }
    1774        21644 :   return gc_GEN(av, bnfisintnorm_i(bnf, a, signe(a), ne, flag));
    1775              : }
        

Generated by: LCOV version 2.0-1