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) Hit Total Coverage
Test: PARI/GP v2.18.0 lcov report (development 29806-4d001396c7) Lines: 937 985 95.1 %
Date: 2024-12-21 09:08:57 Functions: 63 64 98.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.16