Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - bibli1.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 94.5 % 1243 1175
Test Date: 2026-07-23 17:04:59 Functions: 92.8 % 83 77
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              : /********************************************************************/
      16              : /**                                                                **/
      17              : /**                 LLL Algorithm and close friends                **/
      18              : /**                                                                **/
      19              : /********************************************************************/
      20              : #include "pari.h"
      21              : #include "paripriv.h"
      22              : 
      23              : #define DEBUGLEVEL DEBUGLEVEL_qf
      24              : 
      25              : /********************************************************************/
      26              : /**             QR Factorization via Householder matrices          **/
      27              : /********************************************************************/
      28              : static int
      29     24775018 : no_prec_pb(GEN x)
      30              : {
      31     24699062 :   return (typ(x) != t_REAL || realprec(x) > DEFAULTPREC
      32     49474080 :                            || expo(x) < DEFAULTPREC>>1);
      33              : }
      34              : /* Find a Householder transformation which, applied to x[k..#x], zeroes
      35              :  * x[k+1..#x]; fill L = (mu_{i,j}). Return 0 if precision problem [obtained
      36              :  * a 0 vector], 1 otherwise */
      37              : static int
      38     24785920 : FindApplyQ(GEN x, GEN L, GEN B, long k, GEN Q, long prec)
      39              : {
      40     24785920 :   long i, nx = lg(x)-1;
      41     24785920 :   GEN x2, x1, xd = x + (k-1);
      42              : 
      43     24785920 :   x1 = gel(xd,1);
      44     24785920 :   x2 = mpsqr(x1);
      45     24785920 :   if (k < nx)
      46              :   {
      47     19543175 :     long lv = nx - (k-1) + 1;
      48     19543175 :     GEN beta, Nx, v = cgetg(lv, t_VEC);
      49     78001377 :     for (i=2; i<lv; i++) {
      50     58458202 :       x2 = mpadd(x2, mpsqr(gel(xd,i)));
      51     58458202 :       gel(v,i) = gel(xd,i);
      52              :     }
      53     19543175 :     if (!signe(x2)) return 0;
      54     19534951 :     Nx = gsqrt(x2, prec); if (signe(x1) < 0) setsigne(Nx, -1);
      55     19534951 :     gel(v,1) = mpadd(x1, Nx);
      56              : 
      57     19534951 :     if (!signe(x1))
      58       734109 :       beta = gtofp(x2, prec); /* make sure typ(beta) != t_INT */
      59              :     else
      60     18800842 :       beta = mpadd(x2, mpmul(Nx,x1));
      61     19534951 :     gel(Q,k) = mkvec2(invr(beta), v); /* [t_REAL, vector of t_INT/t_REALs] */
      62              : 
      63     19534951 :     togglesign(Nx);
      64     19534951 :     gcoeff(L,k,k) = Nx; /* nonzero t_REAL */
      65              :   }
      66              :   else /* k = nx */
      67              :   {
      68      5242745 :     gcoeff(L,k,k) = x1; /* t_INT or t_REAL */
      69      5242745 :     if (!signe(x1)) return 0;
      70              :   }
      71     24775018 :   gel(B,k) = x2; /* t_INT or t_REAL */
      72     71758475 :   for (i=1; i<k; i++) gcoeff(L,k,i) = gel(x,i); /* t_INT or t_REAL */
      73     24775018 :   return no_prec_pb(x2);
      74              : }
      75              : 
      76              : /* apply Householder transformation Q = [beta,v] to r with t_INT/t_REAL
      77              :  * coefficients, in place: r -= ((0|v).r * beta) v */
      78              : static void
      79     47001261 : ApplyQ(GEN Q, GEN r)
      80              : {
      81     47001261 :   GEN s, rd, beta = gel(Q,1), v = gel(Q,2);
      82     47001261 :   long i, l = lg(v), lr = lg(r);
      83              : 
      84     47001261 :   rd = r + (lr - l);
      85     47001261 :   s = mpmul(gel(v,1), gel(rd,1));
      86    505949680 :   for (i=2; i<l; i++) s = mpadd(s, mpmul(gel(v,i), gel(rd,i)));
      87     47001261 :   s = mpmul(beta, s);
      88    552950941 :   for (i=1; i<l; i++)
      89    505949680 :     if (signe(gel(v,i))) gel(rd,i) = mpsub(gel(rd,i), mpmul(s, gel(v,i)));
      90     47001261 : }
      91              : /* apply Q[1], ..., Q[j-1] to r */
      92              : static GEN
      93     17027474 : ApplyAllQ(GEN Q, GEN r, long j)
      94              : {
      95     17027474 :   pari_sp av = avma;
      96              :   long i;
      97     17027474 :   r = leafcopy(r);
      98     64028735 :   for (i=1; i<j; i++) ApplyQ(gel(Q,i), r);
      99     17027474 :   return gc_GEN(av, r);
     100              : }
     101              : 
     102              : /* same, arbitrary coefficients [20% slower for t_REAL at DEFAULTPREC] */
     103              : static void
     104        22113 : RgC_ApplyQ(GEN Q, GEN r)
     105              : {
     106        22113 :   GEN s, rd, beta = gel(Q,1), v = gel(Q,2);
     107        22113 :   long i, l = lg(v), lr = lg(r);
     108              : 
     109        22113 :   rd = r + (lr - l);
     110        22113 :   s = gmul(gel(v,1), gel(rd,1));
     111       464373 :   for (i=2; i<l; i++) s = gadd(s, gmul(gel(v,i), gel(rd,i)));
     112        22113 :   s = gmul(beta, s);
     113       486486 :   for (i=1; i<l; i++)
     114       464373 :     if (signe(gel(v,i))) gel(rd,i) = gsub(gel(rd,i), gmul(s, gel(v,i)));
     115        22113 : }
     116              : static GEN
     117          567 : RgC_ApplyAllQ(GEN Q, GEN r, long j)
     118              : {
     119          567 :   pari_sp av = avma;
     120              :   long i;
     121          567 :   r = leafcopy(r);
     122        22680 :   for (i=1; i<j; i++) RgC_ApplyQ(gel(Q,i), r);
     123          567 :   return gc_GEN(av, r);
     124              : }
     125              : 
     126              : int
     127           21 : RgM_QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec)
     128              : {
     129           21 :   x = RgM_gtomp(x, prec);
     130           21 :   return QR_init(x, pB, pQ, pL, prec);
     131              : }
     132              : 
     133              : static void
     134           35 : check_householder(GEN Q)
     135              : {
     136           35 :   long i, l = lg(Q);
     137           35 :   if (typ(Q) != t_VEC) pari_err_TYPE("mathouseholder", Q);
     138          854 :   for (i = 1; i < l; i++)
     139              :   {
     140          826 :     GEN q = gel(Q,i), v;
     141          826 :     if (typ(q) != t_VEC || lg(q) != 3) pari_err_TYPE("mathouseholder", Q);
     142          826 :     v = gel(q,2);
     143          826 :     if (typ(v) != t_VEC || lg(v)+i-2 != l) pari_err_TYPE("mathouseholder", Q);
     144              :   }
     145           28 : }
     146              : 
     147              : GEN
     148           35 : mathouseholder(GEN Q, GEN x)
     149              : {
     150           35 :   long l = lg(Q);
     151           35 :   check_householder(Q);
     152           28 :   switch(typ(x))
     153              :   {
     154           14 :     case t_MAT:
     155           14 :       if (lg(x) == 1) return cgetg(1, t_MAT);
     156           14 :       if (lgcols(x) != l+1) pari_err_TYPE("mathouseholder", x);
     157          574 :       pari_APPLY_same(RgC_ApplyAllQ(Q, gel(x,i), l));
     158            7 :     case t_COL:
     159            7 :       if (lg(x) == l+1) return RgC_ApplyAllQ(Q, x, l);
     160              :   }
     161            7 :   pari_err_TYPE("mathouseholder", x);
     162              :   return NULL; /* LCOV_EXCL_LINE */
     163              : }
     164              : 
     165              : GEN
     166           35 : matqr(GEN x, long flag, long prec)
     167              : {
     168           35 :   pari_sp av = avma;
     169              :   GEN B, Q, L;
     170           35 :   long n = lg(x)-1;
     171           35 :   if (typ(x) != t_MAT) pari_err_TYPE("matqr",x);
     172           35 :   if (!n)
     173              :   {
     174           14 :     if (!flag) retmkvec2(cgetg(1,t_MAT),cgetg(1,t_MAT));
     175            7 :     retmkvec2(cgetg(1,t_VEC),cgetg(1,t_MAT));
     176              :   }
     177           21 :   if (n != nbrows(x)) pari_err_DIM("matqr");
     178           21 :   if (!RgM_QR_init(x, &B,&Q,&L, prec)) pari_err_PREC("matqr");
     179           21 :   if (!flag) Q = shallowtrans(mathouseholder(Q, matid(n)));
     180           21 :   return gc_GEN(av, mkvec2(Q, shallowtrans(L)));
     181              : }
     182              : 
     183              : /* compute B = squared length of orthogonalized vectors x[k]^*,
     184              :  * Q = Householder transforms and L = mu_{i,j}. B[k] t_INT/t_REAL;
     185              :  * L[j,j] a t_REAL for j < #x */
     186              : int
     187      7758446 : QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec)
     188              : {
     189      7758446 :   long j, k = lg(x)-1;
     190      7758446 :   GEN B = cgetg(k+1, t_VEC), Q = cgetg(k, t_VEC), L = zeromatcopy(k,k);
     191     30298626 :   for (j=1; j<=k; j++)
     192              :   {
     193     24785920 :     GEN r = gel(x,j);
     194     24785920 :     if (j > 1) r = ApplyAllQ(Q, r, j);
     195     24785920 :     if (!FindApplyQ(r, L, B, j, Q, prec)) return 0;
     196              :   }
     197      5512706 :   *pB = B; *pQ = Q; *pL = L; return 1;
     198              : }
     199              : /* x a square t_MAT with t_INT / t_REAL entries and maximal rank. Return
     200              :  * qfgaussred(x~*x) */
     201              : GEN
     202       301435 : gaussred_from_QR(GEN x, long prec)
     203              : {
     204       301435 :   long j, k = lg(x)-1;
     205              :   GEN B, Q, L;
     206       301435 :   if (!QR_init(x, &B,&Q,&L, prec)) return NULL;
     207      1075156 :   for (j=1; j<k; j++)
     208              :   {
     209       773721 :     GEN m = gel(L,j), invNx = invr(gel(m,j));
     210              :     long i;
     211       773721 :     gel(m,j) = gel(B,j);
     212      2995205 :     for (i=j+1; i<=k; i++) gel(m,i) = mpmul(invNx, gel(m,i));
     213              :   }
     214       301435 :   gcoeff(L,j,j) = gel(B,j); /* t_INT or t_REAL */
     215       301435 :   return shallowtrans(L);
     216              : }
     217              : GEN
     218        14280 : R_from_QR(GEN x, long prec)
     219              : {
     220              :   GEN B, Q, L;
     221        14280 :   if (!QR_init(x, &B,&Q,&L, prec)) return NULL;
     222        14266 :   return shallowtrans(L);
     223              : }
     224              : 
     225              : /********************************************************************/
     226              : /**             QR Factorization via Gram-Schmidt                  **/
     227              : /********************************************************************/
     228              : /* return x + y, x possibly NULL (= initialized to gen_0) */
     229              : static GEN
     230        62737 : _add(GEN x, GEN y) { return x? gadd(x, y): y; }
     231              : 
     232              : /* return Gram-Schmidt orthogonal basis (f) attached to (e), B is the
     233              :  * vector of the (f_i . f_i)*/
     234              : GEN
     235        56780 : RgM_gram_schmidt(GEN e, GEN *ptB)
     236              : {
     237        56780 :   long i, j, lx = lg(e);
     238        56780 :   GEN f = RgM_shallowcopy(e), B = cgetg(lx, t_VEC), iB = cgetg(lx, t_VEC);
     239              : 
     240       120645 :   for (i = 1; i < lx; i++)
     241              :   {
     242        63865 :     pari_sp av = avma;
     243        63865 :     GEN c = NULL;
     244       126602 :     for (j = 1; j < i; j++)
     245              :     {
     246        62737 :       GEN mu = gmul(RgV_dotproduct(gel(e,i),gel(f,j)), gel(iB,j));
     247        62737 :       c = _add(c, gmul(mu, gel(f,j)));
     248              :     }
     249        63865 :     gel(f,i) = c? gc_upto(av, gsub(gel(e,i), c)): gel(e,i);
     250        63865 :     gel(B,i) = RgV_dotsquare(gel(f,i));
     251        63865 :     gel(iB,i) = ginv(gel(B,i));
     252              :   }
     253        56780 :   *ptB = B; return f;
     254              : }
     255              : 
     256              : /* B a Z-basis (which the caller should LLL-reduce for efficiency), t a vector.
     257              :  * Apply Babai's nearest plane algorithm to (B,t) */
     258              : GEN
     259        56780 : RgM_Babai(GEN B, GEN t)
     260              : {
     261        56780 :   GEN C, N, G = RgM_gram_schmidt(B, &N), b = t;
     262        56780 :   long j, n = lg(B)-1;
     263              : 
     264        56780 :   C = cgetg(n+1,t_COL);
     265       120645 :   for (j = n; j > 0; j--)
     266              :   {
     267        63865 :     GEN c = gdiv( RgV_dotproduct(b, gel(G,j)), gel(N,j) );
     268              :     long e;
     269        63865 :     c = grndtoi(c,&e);
     270        63865 :     if (e >= 0) return NULL;
     271        63865 :     if (signe(c)) b = RgC_sub(b, RgC_Rg_mul(gel(B,j), c));
     272        63865 :     gel(C,j) = c;
     273              :   }
     274        56780 :   return C;
     275              : }
     276              : 
     277              : /********************************************************************/
     278              : /**                                                                **/
     279              : /**                          LLL ALGORITHM                         **/
     280              : /**                                                                **/
     281              : /********************************************************************/
     282              : /* Def: a matrix M is said to be -partially reduced- if | m1 +- m2 | >= |m1|
     283              :  * for any two columns m1 != m2, in M.
     284              :  *
     285              :  * Input: an integer matrix mat whose columns are linearly independent. Find
     286              :  * another matrix T such that mat * T is partially reduced.
     287              :  *
     288              :  * Output: mat * T if flag = 0;  T if flag != 0,
     289              :  *
     290              :  * This routine is designed to quickly reduce lattices in which one row
     291              :  * is huge compared to the other rows.  For example, when searching for a
     292              :  * polynomial of degree 3 with root a mod N, the four input vectors might
     293              :  * be the coefficients of
     294              :  *     X^3 - (a^3 mod N), X^2 - (a^2 mod N), X - (a mod N), N.
     295              :  * All four constant coefficients are O(p) and the rest are O(1). By the
     296              :  * pigeon-hole principle, the coefficients of the smallest vector in the
     297              :  * lattice are O(p^(1/4)), hence significant reduction of vector lengths
     298              :  * can be anticipated.
     299              :  *
     300              :  * An improved algorithm would look only at the leading digits of dot*.  It
     301              :  * would use single-precision calculations as much as possible.
     302              :  *
     303              :  * Original code: Peter Montgomery (1994) */
     304              : static GEN
     305           35 : lllintpartialall(GEN m, long flag)
     306              : {
     307           35 :   const long ncol = lg(m)-1;
     308           35 :   const pari_sp av = avma;
     309              :   GEN tm1, tm2, mid;
     310              : 
     311           35 :   if (ncol <= 1) return flag? matid(ncol): gcopy(m);
     312              : 
     313           14 :   tm1 = flag? matid(ncol): NULL;
     314              :   {
     315           14 :     const pari_sp av2 = avma;
     316           14 :     GEN dot11 = ZV_dotsquare(gel(m,1));
     317           14 :     GEN dot22 = ZV_dotsquare(gel(m,2));
     318           14 :     GEN dot12 = ZV_dotproduct(gel(m,1), gel(m,2));
     319           14 :     GEN tm  = matid(2); /* For first two columns only */
     320              : 
     321           14 :     int progress = 0;
     322           14 :     long npass2 = 0;
     323              : 
     324              : /* Row reduce the first two columns of m. Our best result so far is
     325              :  * (first two columns of m)*tm.
     326              :  *
     327              :  * Initially tm = 2 x 2 identity matrix.
     328              :  * Inner products of the reduced matrix are in dot11, dot12, dot22. */
     329           49 :     while (npass2 < 2 || progress)
     330              :     {
     331           42 :       GEN dot12new, q = diviiround(dot12, dot22);
     332              : 
     333           35 :       npass2++; progress = signe(q);
     334           35 :       if (progress)
     335              :       {/* Conceptually replace (v1, v2) by (v1 - q*v2, v2), where v1 and v2
     336              :         * represent the reduced basis for the first two columns of the matrix.
     337              :         * We do this by updating tm and the inner products. */
     338           21 :         togglesign(q);
     339           21 :         dot12new = addii(dot12, mulii(q, dot22));
     340           21 :         dot11 = addii(dot11, mulii(q, addii(dot12, dot12new)));
     341           21 :         dot12 = dot12new;
     342           21 :         ZC_lincomb1_inplace(gel(tm,1), gel(tm,2), q);
     343              :       }
     344              : 
     345              :       /* Interchange the output vectors v1 and v2.  */
     346           35 :       swap(dot11,dot22);
     347           35 :       swap(gel(tm,1), gel(tm,2));
     348              : 
     349              :       /* Occasionally (including final pass) do garbage collection.  */
     350           35 :       if ((npass2 & 0xff) == 0 || !progress)
     351           14 :         (void)gc_all(av2, 4, &dot11,&dot12,&dot22,&tm);
     352              :     } /* while npass2 < 2 || progress */
     353              : 
     354              :     {
     355              :       long i;
     356            7 :       GEN det12 = subii(mulii(dot11, dot22), sqri(dot12));
     357              : 
     358            7 :       mid = cgetg(ncol+1, t_MAT);
     359           21 :       for (i = 1; i <= 2; i++)
     360              :       {
     361           14 :         GEN tmi = gel(tm,i);
     362           14 :         if (tm1)
     363              :         {
     364           14 :           GEN tm1i = gel(tm1,i);
     365           14 :           gel(tm1i,1) = gel(tmi,1);
     366           14 :           gel(tm1i,2) = gel(tmi,2);
     367              :         }
     368           14 :         gel(mid,i) = ZC_lincomb(gel(tmi,1),gel(tmi,2), gel(m,1),gel(m,2));
     369              :       }
     370           42 :       for (i = 3; i <= ncol; i++)
     371              :       {
     372           35 :         GEN c = gel(m,i);
     373           35 :         GEN dot1i = ZV_dotproduct(gel(mid,1), c);
     374           35 :         GEN dot2i = ZV_dotproduct(gel(mid,2), c);
     375              :        /* ( dot11  dot12 ) (q1)   ( dot1i )
     376              :         * ( dot12  dot22 ) (q2) = ( dot2i )
     377              :         *
     378              :         * Round -q1 and -q2 to nearest integer. Then compute
     379              :         *   c - q1*mid[1] - q2*mid[2].
     380              :         * This will be approximately orthogonal to the first two vectors in
     381              :         * the new basis. */
     382           35 :         GEN q1neg = subii(mulii(dot12, dot2i), mulii(dot22, dot1i));
     383           35 :         GEN q2neg = subii(mulii(dot12, dot1i), mulii(dot11, dot2i));
     384              : 
     385           35 :         q1neg = diviiround(q1neg, det12);
     386           35 :         q2neg = diviiround(q2neg, det12);
     387           35 :         if (tm1)
     388              :         {
     389           35 :           gcoeff(tm1,1,i) = addii(mulii(q1neg, gcoeff(tm,1,1)),
     390           35 :                                   mulii(q2neg, gcoeff(tm,1,2)));
     391           35 :           gcoeff(tm1,2,i) = addii(mulii(q1neg, gcoeff(tm,2,1)),
     392           35 :                                   mulii(q2neg, gcoeff(tm,2,2)));
     393              :         }
     394           35 :         gel(mid,i) = ZC_add(c, ZC_lincomb(q1neg,q2neg, gel(mid,1),gel(mid,2)));
     395              :       } /* for i */
     396              :     } /* local block */
     397              :   }
     398            7 :   if (DEBUGLEVEL>6)
     399              :   {
     400            0 :     if (tm1) err_printf("tm1 = %Ps",tm1);
     401            0 :     err_printf("mid = %Ps",mid); /* = m * tm1 */
     402              :   }
     403            7 :   (void)gc_all(av, tm1? 2: 1, &mid, &tm1);
     404              :   {
     405              :    /* For each pair of column vectors v and w in mid * tm2,
     406              :     * try to replace (v, w) by (v, v - q*w) for some q.
     407              :     * We compute all inner products and check them repeatedly. */
     408            7 :     const pari_sp av3 = avma;
     409            7 :     long i, j, npass = 0, e = LONG_MAX;
     410            7 :     GEN dot = cgetg(ncol+1, t_MAT); /* scalar products */
     411              : 
     412            7 :     tm2 = matid(ncol);
     413           56 :     for (i=1; i <= ncol; i++)
     414              :     {
     415           49 :       gel(dot,i) = cgetg(ncol+1,t_COL);
     416          245 :       for (j=1; j <= i; j++)
     417          196 :         gcoeff(dot,j,i) = gcoeff(dot,i,j) = ZV_dotproduct(gel(mid,i),gel(mid,j));
     418              :     }
     419              :     for(;;)
     420           35 :     {
     421           42 :       long reductions = 0, olde = e;
     422          336 :       for (i=1; i <= ncol; i++)
     423              :       {
     424              :         long ijdif;
     425         2058 :         for (ijdif=1; ijdif < ncol; ijdif++)
     426              :         {
     427              :           long d, k1, k2;
     428              :           GEN codi, q;
     429              : 
     430         1764 :           j = i + ijdif; if (j > ncol) j -= ncol;
     431              :           /* let k1, resp. k2,  index of larger, resp. smaller, column */
     432         1764 :           if (cmpii(gcoeff(dot,i,i), gcoeff(dot,j,j)) > 0) { k1 = i; k2 = j; }
     433         1022 :           else                                             { k1 = j; k2 = i; }
     434         1764 :           codi = gcoeff(dot,k2,k2);
     435         1764 :           q = signe(codi)? diviiround(gcoeff(dot,k1,k2), codi): gen_0;
     436         1764 :           if (!signe(q)) continue;
     437              : 
     438              :           /* Try to subtract a multiple of column k2 from column k1.  */
     439          700 :           reductions++; togglesign_safe(&q);
     440          700 :           ZC_lincomb1_inplace(gel(tm2,k1), gel(tm2,k2), q);
     441          700 :           ZC_lincomb1_inplace(gel(dot,k1), gel(dot,k2), q);
     442          700 :           gcoeff(dot,k1,k1) = addii(gcoeff(dot,k1,k1),
     443          700 :                                     mulii(q, gcoeff(dot,k2,k1)));
     444         5600 :           for (d = 1; d <= ncol; d++) gcoeff(dot,k1,d) = gcoeff(dot,d,k1);
     445              :         } /* for ijdif */
     446          294 :         if (gc_needed(av3,2))
     447              :         {
     448            0 :           if(DEBUGMEM>1) pari_warn(warnmem,"lllintpartialall");
     449            0 :           (void)gc_all(av3, 2, &dot,&tm2);
     450              :         }
     451              :       } /* for i */
     452           42 :       if (!reductions) break;
     453           35 :       e = 0;
     454          280 :       for (i = 1; i <= ncol; i++) e += expi( gcoeff(dot,i,i) );
     455           35 :       if (e == olde) break;
     456           35 :       if (DEBUGLEVEL>6)
     457              :       {
     458            0 :         npass++;
     459            0 :         err_printf("npass = %ld, red. last time = %ld, log_2(det) ~ %ld\n\n",
     460              :                     npass, reductions, e);
     461              :       }
     462              :     } /* for(;;)*/
     463              : 
     464              :    /* Sort columns so smallest comes first in m * tm1 * tm2.
     465              :     * Use insertion sort. */
     466           49 :     for (i = 1; i < ncol; i++)
     467              :     {
     468           42 :       long j, s = i;
     469              : 
     470          189 :       for (j = i+1; j <= ncol; j++)
     471          147 :         if (cmpii(gcoeff(dot,s,s),gcoeff(dot,j,j)) > 0) s = j;
     472           42 :       if (i != s)
     473              :       { /* Exchange with proper column; only the diagonal of dot is updated */
     474           28 :         swap(gel(tm2,i), gel(tm2,s));
     475           28 :         swap(gcoeff(dot,i,i), gcoeff(dot,s,s));
     476              :       }
     477              :     }
     478              :   } /* local block */
     479            7 :   return gc_upto(av, ZM_mul(tm1? tm1: mid, tm2));
     480              : }
     481              : 
     482              : GEN
     483           35 : lllintpartial(GEN mat) { return lllintpartialall(mat,1); }
     484              : 
     485              : GEN
     486            0 : lllintpartial_inplace(GEN mat) { return lllintpartialall(mat,0); }
     487              : 
     488              : /********************************************************************/
     489              : /**                                                                **/
     490              : /**                    COPPERSMITH ALGORITHM                       **/
     491              : /**           Finding small roots of univariate equations.         **/
     492              : /**                                                                **/
     493              : /********************************************************************/
     494              : 
     495              : static int
     496          882 : check(double b, double x, double rho, long d, long dim, long delta, long t)
     497              : {
     498          882 :   double cond = delta * (d * (delta+1) - 2*b*dim + rho * (delta-1 + 2*t))
     499          882 :                 + x*dim*(dim - 1);
     500          882 :   if (DEBUGLEVEL >= 4)
     501            0 :     err_printf("delta = %d, t = %d (%.1lf)\n", delta, t, cond);
     502          882 :   return (cond <= 0);
     503              : }
     504              : 
     505              : static void
     506           21 : choose_params(GEN P, GEN N, GEN X, GEN B, long *pdelta, long *pt)
     507              : {
     508           21 :   long d = degpol(P), dim;
     509           21 :   GEN P0 = leading_coeff(P);
     510           21 :   double logN = dbllog2(N), x, b, rho;
     511           21 :   x = dbllog2(X) / logN;
     512           21 :   b = B? dbllog2(B) / logN: 1.;
     513           21 :   if (x * d >= b * b) pari_err_OVERFLOW("zncoppersmith [bound too large]");
     514              :   /* TODO : remove P0 completely */
     515           14 :   rho = is_pm1(P0)? 0: dbllog2(P0) / logN;
     516              : 
     517              :   /* Enumerate (delta,t) by increasing lattice dimension */
     518           14 :   for(dim = d + 1;; dim++)
     519          161 :   {
     520              :     long delta, t; /* dim = d*delta + t in the loop */
     521         1043 :     for (delta = 0, t = dim; t >= 0; delta++, t -= d)
     522          882 :       if (check(b,x,rho,d,dim,delta,t)) { *pdelta = delta; *pt = t; return; }
     523              :   }
     524              : }
     525              : 
     526              : static int
     527        14021 : sol_OK(GEN x, GEN N, GEN B)
     528        14021 : { return B? (cmpii(gcdii(x,N),B) >= 0): dvdii(x,N); }
     529              : /* deg(P) > 0, x >= 0. Find all j such that gcd(P(j), N) >= B, |j| <= x */
     530              : static GEN
     531            7 : do_exhaustive(GEN P, GEN N, long x, GEN B)
     532              : {
     533            7 :   GEN Pe, Po, sol = vecsmalltrunc_init(2*x + 2);
     534              :   pari_sp av;
     535              :   long j;
     536            7 :   RgX_even_odd(P, &Pe,&Po); av = avma;
     537            7 :   if (sol_OK(gel(P,2), N,B)) vecsmalltrunc_append(sol, 0);
     538         7007 :   for (j = 1; j <= x; j++, set_avma(av))
     539              :   {
     540         7000 :     GEN j2 = sqru(j), E = FpX_eval(Pe,j2,N), O = FpX_eval(Po,j2,N);
     541         7000 :     if (sol_OK(addmuliu(E,O,j), N,B)) vecsmalltrunc_append(sol, j);
     542         7000 :     if (sol_OK(submuliu(E,O,j), N,B)) vecsmalltrunc_append(sol,-j);
     543              :   }
     544            7 :   vecsmall_sort(sol); return zv_to_ZV(sol);
     545              : }
     546              : 
     547              : /* General Coppersmith, look for a root x0 <= p, p >= B, p | N, |x0| <= X.
     548              :  * B = N coded as NULL */
     549              : GEN
     550           35 : zncoppersmith(GEN P, GEN N, GEN X, GEN B)
     551              : {
     552              :   GEN Q, R, N0, M, sh, short_pol, *Xpowers, sol, nsp, cP, Z;
     553           35 :   long delta, i, j, row, d, l, t, dim, bnd = 10;
     554           35 :   const ulong X_SMALL = 1000;
     555           35 :   pari_sp av = avma;
     556              : 
     557           35 :   if (typ(P) != t_POL || !RgX_is_ZX(P)) pari_err_TYPE("zncoppersmith",P);
     558           28 :   if (typ(N) != t_INT) pari_err_TYPE("zncoppersmith",N);
     559           28 :   if (typ(X) != t_INT) {
     560            7 :     X = gfloor(X);
     561            7 :     if (typ(X) != t_INT) pari_err_TYPE("zncoppersmith",X);
     562              :   }
     563           28 :   if (signe(X) < 0) pari_err_DOMAIN("zncoppersmith", "X", "<", gen_0, X);
     564           28 :   P = FpX_red(P, N); d = degpol(P);
     565           28 :   if (d == 0) retgc_const(av, cgetg(1, t_VEC));
     566           28 :   if (d < 0) pari_err_ROOTS0("zncoppersmith");
     567           28 :   if (B && typ(B) != t_INT) B = gceil(B);
     568           28 :   if (abscmpiu(X, X_SMALL) <= 0)
     569            7 :     return gc_upto(av, do_exhaustive(P, N, itos(X), B));
     570              : 
     571           21 :   if (B && equalii(B,N)) B = NULL;
     572           21 :   if (B) bnd = 1; /* bnd-hack is only for the case B = N */
     573           21 :   cP = gel(P,d+2);
     574           21 :   if (!gequal1(cP))
     575              :   {
     576              :     GEN r, z;
     577           14 :     gel(P,d+2) = cP = bezout(cP, N, &z, &r);
     578           35 :     for (j = 0; j < d; j++) gel(P,j+2) = Fp_mul(gel(P,j+2), z, N);
     579           14 :     if (!is_pm1(cP))
     580              :     {
     581            7 :       P = Q_primitive_part(P, &cP);
     582            7 :       if (cP) { N = diviiexact(N,cP); B = gceil(gdiv(B, cP)); }
     583              :     }
     584              :   }
     585           21 :   if (DEBUGLEVEL >= 2) err_printf("Modified P: %Ps\n", P);
     586              : 
     587           21 :   choose_params(P, N, X, B, &delta, &t);
     588           14 :   if (DEBUGLEVEL >= 2)
     589            0 :     err_printf("Init: trying delta = %d, t = %d\n", delta, t);
     590              :   for(;;)
     591              :   {
     592           14 :     dim = d * delta + t;
     593              :     /* TODO: In case of failure do not recompute the full vector */
     594           14 :     Xpowers = (GEN*)new_chunk(dim + 1);
     595           14 :     Xpowers[0] = gen_1;
     596          217 :     for (j = 1; j <= dim; j++) Xpowers[j] = mulii(Xpowers[j-1], X);
     597              : 
     598              :     /* TODO: in case of failure, use the part of the matrix already computed */
     599           14 :     M = zeromatcopy(dim,dim);
     600              : 
     601              :     /* Rows of M correspond to the polynomials
     602              :      * N^delta, N^delta Xi, ... N^delta (Xi)^d-1,
     603              :      * N^(delta-1)P(Xi), N^(delta-1)XiP(Xi), ... N^(delta-1)P(Xi)(Xi)^d-1,
     604              :      * ...
     605              :      * P(Xi)^delta, XiP(Xi)^delta, ..., P(Xi)^delta(Xi)^t-1 */
     606           42 :     for (j = 1; j <= d;   j++) gcoeff(M, j, j) = gel(Xpowers,j-1);
     607              : 
     608              :     /* P-part */
     609           14 :     if (delta) row = d + 1; else row = 0;
     610              : 
     611           14 :     Q = P;
     612           70 :     for (i = 1; i < delta; i++)
     613              :     {
     614          182 :       for (j = 0; j < d; j++,row++)
     615         1239 :         for (l = j + 1; l <= row; l++)
     616         1113 :           gcoeff(M, l, row) = mulii(Xpowers[l-1], gel(Q,l-j+1));
     617           56 :       Q = ZX_mul(Q, P);
     618              :     }
     619           63 :     for (j = 0; j < t; row++, j++)
     620          490 :       for (l = j + 1; l <= row; l++)
     621          441 :         gcoeff(M, l, row) = mulii(Xpowers[l-1], gel(Q,l-j+1));
     622              : 
     623              :     /* N-part */
     624           14 :     row = dim - t; N0 = N;
     625           84 :     while (row >= 1)
     626              :     {
     627          224 :       for (j = 0; j < d; j++,row--)
     628         1421 :         for (l = 1; l <= row; l++)
     629         1267 :           gcoeff(M, l, row) = mulii(gmael(M, row, l), N0);
     630           70 :       if (row >= 1) N0 = mulii(N0, N);
     631              :     }
     632              :     /* Z is the upper bound for the L^1 norm of the polynomial,
     633              :        ie. N^delta if B = N, B^delta otherwise */
     634           14 :     if (B) Z = powiu(B, delta); else Z = N0;
     635              : 
     636           14 :     if (DEBUGLEVEL >= 2)
     637              :     {
     638            0 :       if (DEBUGLEVEL >= 6) err_printf("Matrix to be reduced:\n%Ps\n", M);
     639            0 :       err_printf("Entering LLL\nbitsize bound: %ld\n", expi(Z));
     640            0 :       err_printf("expected shvector bitsize: %ld\n", expi(ZM_det_triangular(M))/dim);
     641              :     }
     642              : 
     643           14 :     sh = ZM_lll(M, 0.75, LLL_INPLACE);
     644              :     /* Take the first vector if it is non constant */
     645           14 :     short_pol = gel(sh,1);
     646           14 :     if (ZV_isscalar(short_pol)) short_pol = gel(sh, 2);
     647              : 
     648           14 :     nsp = gen_0;
     649          217 :     for (j = 1; j <= dim; j++) nsp = addii(nsp, absi_shallow(gel(short_pol,j)));
     650              : 
     651           14 :     if (DEBUGLEVEL >= 2)
     652              :     {
     653            0 :       err_printf("Candidate: %Ps\n", short_pol);
     654            0 :       err_printf("bitsize Norm: %ld\n", expi(nsp));
     655            0 :       err_printf("bitsize bound: %ld\n", expi(mului(bnd, Z)));
     656              :     }
     657           14 :     if (cmpii(nsp, mului(bnd, Z)) < 0) break; /* SUCCESS */
     658              : 
     659              :     /* Failed with the precomputed or supplied value */
     660            0 :     if (++t == d) { delta++; t = 1; }
     661            0 :     if (DEBUGLEVEL >= 2)
     662            0 :       err_printf("Increasing dim, delta = %d t = %d\n", delta, t);
     663              :   }
     664           14 :   bnd = itos(divii(nsp, Z)) + 1;
     665              : 
     666           14 :   while (!signe(gel(short_pol,dim))) dim--;
     667              : 
     668           14 :   R = cgetg(dim + 2, t_POL); R[1] = P[1];
     669          217 :   for (j = 1; j <= dim; j++)
     670          203 :     gel(R,j+1) = diviiexact(gel(short_pol,j), Xpowers[j-1]);
     671           14 :   gel(R,2) = subii(gel(R,2), mului(bnd - 1, N0));
     672              : 
     673           14 :   sol = cgetg(1, t_VEC);
     674           84 :   for (i = -bnd + 1; i < bnd; i++)
     675              :   {
     676           70 :     GEN r = nfrootsQ(R);
     677           70 :     if (DEBUGLEVEL >= 2) err_printf("Roots: %Ps\n", r);
     678           91 :     for (j = 1; j < lg(r); j++)
     679              :     {
     680           21 :       GEN z = gel(r,j);
     681           21 :       if (typ(z) == t_INT && sol_OK(FpX_eval(P,z,N), N,B))
     682           14 :         sol = shallowconcat(sol, z);
     683              :     }
     684           70 :     if (i < bnd) gel(R,2) = addii(gel(R,2), Z);
     685              :   }
     686           14 :   return gc_upto(av, ZV_sort_uniq(sol));
     687              : }
     688              : 
     689              : /********************************************************************/
     690              : /**                                                                **/
     691              : /**                   LINEAR & ALGEBRAIC DEPENDENCE                **/
     692              : /**                                                                **/
     693              : /********************************************************************/
     694              : 
     695              : static int
     696         8123 : real_indep(GEN re, GEN im, long bit)
     697              : {
     698         8123 :   GEN d = gsub(gmul(gel(re,1),gel(im,2)), gmul(gel(re,2),gel(im,1)));
     699         8123 :   return (!gequal0(d) && gexpo(d) > - bit);
     700              : }
     701              : 
     702              : GEN
     703        15302 : lindepfull_bit(GEN x, long bit)
     704              : {
     705        15302 :   long lx = lg(x), ly, i, j;
     706              :   GEN re, im, M;
     707              : 
     708        15302 :   if (! is_vec_t(typ(x))) pari_err_TYPE("lindep2",x);
     709        15302 :   if (lx <= 2)
     710              :   {
     711           21 :     if (lx == 2 && gequal0(x)) return matid(1);
     712           14 :     return NULL;
     713              :   }
     714        15281 :   re = real_i(x);
     715        15281 :   im = imag_i(x);
     716              :   /* independent over R ? */
     717        15281 :   if (lx == 3 && real_indep(re,im,bit)) return NULL;
     718        15267 :   if (gequal0(im)) im = NULL;
     719        15267 :   ly = im? lx+2: lx+1;
     720        15267 :   M = cgetg(lx,t_MAT);
     721        60701 :   for (i=1; i<lx; i++)
     722              :   {
     723        45434 :     GEN c = cgetg(ly,t_COL); gel(M,i) = c;
     724       209394 :     for (j=1; j<lx; j++) gel(c,j) = gen_0;
     725        45434 :     gel(c,i) = gen_1;
     726        45434 :     gel(c,lx)           = gtrunc2n(gel(re,i), bit);
     727        45434 :     if (im) gel(c,lx+1) = gtrunc2n(gel(im,i), bit);
     728              :   }
     729        15267 :   return ZM_lll(M, 0.99, LLL_INPLACE);
     730              : }
     731              : GEN
     732         3311 : lindep_bit(GEN x, long bit)
     733              : {
     734         3311 :   pari_sp av = avma;
     735         3311 :   GEN v, M = lindepfull_bit(x,bit);
     736         3311 :   if (!M) retgc_const(av, cgetg(1, t_COL));
     737         3283 :   v = gel(M,1); setlg(v, lg(M));
     738         3283 :   return gc_GEN(av, v);
     739              : }
     740              : /* deprecated */
     741              : GEN
     742          112 : lindep2(GEN x, long dig)
     743              : {
     744              :   long bit;
     745          112 :   if (dig < 0) pari_err_DOMAIN("lindep2", "accuracy", "<", gen_0, stoi(dig));
     746          112 :   if (dig) bit = (long) (dig/LOG10_2);
     747              :   else
     748              :   {
     749           98 :     bit = gprecision(x);
     750           98 :     if (!bit)
     751              :     {
     752           35 :       x = Q_primpart(x); /* left on stack */
     753           35 :       bit = 32 + gexpo(x);
     754              :     }
     755              :     else
     756           63 :       bit = (long)prec2nbits_mul(bit, 0.8);
     757              :   }
     758          112 :   return lindep_bit(x, bit);
     759              : }
     760              : 
     761              : /* x is a vector of elts of a p-adic field */
     762              : GEN
     763           28 : lindep_padic(GEN x)
     764              : {
     765           28 :   long i, j, prec = LONG_MAX, nx = lg(x)-1, v;
     766           28 :   pari_sp av = avma;
     767           28 :   GEN p = NULL, pn, m, a;
     768              : 
     769           28 :   if (nx < 2) return cgetg(1,t_COL);
     770          147 :   for (i=1; i<=nx; i++)
     771              :   {
     772          119 :     GEN c = gel(x,i), q;
     773          119 :     if (typ(c) != t_PADIC) continue;
     774              : 
     775           91 :     j = precp(c); if (j < prec) prec = j;
     776           91 :     q = padic_p(c);
     777           91 :     if (!p) p = q; else if (!equalii(p, q)) pari_err_MODULUS("lindep_padic", p, q);
     778              :   }
     779           28 :   if (!p) pari_err_TYPE("lindep_padic [not a p-adic vector]",x);
     780           28 :   v = gvaluation(x,p); pn = powiu(p,prec);
     781           28 :   if (v) x = gmul(x, powis(p, -v));
     782           28 :   x = RgV_to_FpV(x, pn);
     783              : 
     784           28 :   a = negi(gel(x,1));
     785           28 :   m = cgetg(nx,t_MAT);
     786          119 :   for (i=1; i<nx; i++)
     787              :   {
     788           91 :     GEN c = zerocol(nx);
     789           91 :     gel(c,1+i) = a;
     790           91 :     gel(c,1) = gel(x,i+1);
     791           91 :     gel(m,i) = c;
     792              :   }
     793           28 :   m = ZM_lll(ZM_hnfmodid(m, pn), 0.99, LLL_INPLACE);
     794           28 :   return gc_GEN(av, gel(m,1));
     795              : }
     796              : /* x is a vector of t_POL/t_SER */
     797              : GEN
     798           77 : lindep_Xadic(GEN x)
     799              : {
     800           77 :   long i, prec = LONG_MAX, deg = 0, lx = lg(x), vx, v;
     801           77 :   pari_sp av = avma;
     802              :   GEN m;
     803              : 
     804           77 :   if (lx == 1) return cgetg(1,t_COL);
     805           77 :   vx = gvar(x);
     806           77 :   if (gequal0(x)) return col_ei(lx-1,1);
     807           70 :   v = gvaluation(x, pol_x(vx));
     808           70 :   if (!v)         x = shallowcopy(x);
     809            0 :   else if (v > 0) x = gdiv(x, pol_xn(v, vx));
     810            0 :   else            x = gmul(x, pol_xn(-v, vx));
     811              :   /* all t_SER have valuation >= 0 */
     812          735 :   for (i=1; i<lx; i++)
     813              :   {
     814          665 :     GEN c = gel(x,i);
     815          665 :     if (gvar(c) != vx) { gel(x,i) = scalarpol_shallow(c, vx); continue; }
     816          658 :     switch(typ(c))
     817              :     {
     818          231 :       case t_POL: deg = maxss(deg, degpol(c)); break;
     819            0 :       case t_RFRAC: pari_err_TYPE("lindep_Xadic", c);
     820          427 :       case t_SER:
     821          427 :         prec = minss(prec, valser(c)+lg(c)-2);
     822          427 :         gel(x,i) = ser2rfrac_i(c);
     823              :     }
     824              :   }
     825           70 :   if (prec == LONG_MAX) prec = deg+1;
     826           70 :   m = RgXV_to_RgM(x, prec);
     827           70 :   return gc_upto(av, deplin(m));
     828              : }
     829              : static GEN
     830           35 : vec_lindep(GEN x)
     831              : {
     832           35 :   pari_sp av = avma;
     833           35 :   long i, l = lg(x); /* > 1 */
     834           35 :   long t = typ(gel(x,1)), h = lg(gel(x,1));
     835           35 :   GEN m = cgetg(l, t_MAT);
     836          126 :   for (i = 1; i < l; i++)
     837              :   {
     838           98 :     GEN y = gel(x,i);
     839           98 :     if (lg(y) != h || typ(y) != t) pari_err_TYPE("lindep",x);
     840           91 :     if (t != t_COL) y = shallowtrans(y); /* Sigh */
     841           91 :     gel(m,i) = y;
     842              :   }
     843           28 :   return gc_upto(av, deplin(m));
     844              : }
     845              : 
     846              : GEN
     847            0 : lindep(GEN x) { return lindep2(x, 0); }
     848              : 
     849              : GEN
     850          434 : lindep0(GEN x,long bit)
     851              : {
     852          434 :   long i, tx = typ(x);
     853          434 :   if (tx == t_MAT) return deplin(x);
     854          147 :   if (! is_vec_t(tx)) pari_err_TYPE("lindep",x);
     855          441 :   for (i = 1; i < lg(x); i++)
     856          357 :     switch(typ(gel(x,i)))
     857              :     {
     858            7 :       case t_PADIC: return lindep_padic(x);
     859           21 :       case t_POL:
     860              :       case t_RFRAC:
     861           21 :       case t_SER: return lindep_Xadic(x);
     862           35 :       case t_VEC:
     863           35 :       case t_COL: return vec_lindep(x);
     864              :     }
     865           84 :   return lindep2(x, bit);
     866              : }
     867              : 
     868              : GEN
     869           77 : algdep0(GEN x, long n, long bit)
     870              : {
     871           77 :   long tx = typ(x), i;
     872              :   pari_sp av;
     873              :   GEN y;
     874              : 
     875           77 :   if (! is_scalar_t(tx)) pari_err_TYPE("algdep0",x);
     876           77 :   if (tx == t_POLMOD)
     877              :   {
     878           14 :     av = avma; y = minpoly(x, 0);
     879           14 :     return (degpol(y) > n)? gc_const(av, gen_1): y;
     880              :   }
     881           63 :   if (gequal0(x)) return pol_x(0);
     882           63 :   if (n <= 0)
     883              :   {
     884           14 :     if (!n) return gen_1;
     885            7 :     pari_err_DOMAIN("algdep", "degree", "<", gen_0, stoi(n));
     886              :   }
     887              : 
     888           49 :   av = avma; y = cgetg(n+2,t_COL);
     889           49 :   gel(y,1) = gen_1;
     890           49 :   gel(y,2) = x; /* n >= 1 */
     891          210 :   for (i=3; i<=n+1; i++) gel(y,i) = gmul(gel(y,i-1),x);
     892           49 :   if (typ(x) == t_PADIC)
     893           21 :     y = lindep_padic(y);
     894              :   else
     895           28 :     y = lindep2(y, bit);
     896           49 :   if (lg(y) == 1) pari_err(e_DOMAIN,"algdep", "degree(x)",">", stoi(n), x);
     897           49 :   y = RgV_to_RgX(y, 0);
     898           49 :   if (signe(leading_coeff(y)) > 0) return gc_GEN(av, y);
     899           14 :   return gc_upto(av, ZX_neg(y));
     900              : }
     901              : 
     902              : GEN
     903            0 : algdep(GEN x, long n)
     904              : {
     905            0 :   return algdep0(x,n,0);
     906              : }
     907              : 
     908              : static GEN
     909           56 : sertomat(GEN S, long p, long r, long vy)
     910              : {
     911              :   long n, m;
     912           56 :   GEN v = cgetg(r*p+1, t_VEC); /* v[r*n+m+1] = s^n * y^m */
     913              :   /* n = 0 */
     914          245 :   for (m = 0; m < r; m++) gel(v, m+1) = pol_xn(m, vy);
     915          175 :   for(n=1; n < p; n++)
     916          546 :     for (m = 0; m < r; m++)
     917              :     {
     918          427 :       GEN c = gel(S,n);
     919          427 :       if (m)
     920              :       {
     921          308 :         c = shallowcopy(c);
     922          308 :         setvalser(c, valser(c) + m);
     923              :       }
     924          427 :       gel(v, r*n + m + 1) = c;
     925              :     }
     926           56 :   return v;
     927              : }
     928              : 
     929              : GEN
     930           42 : seralgdep(GEN s, long p, long r)
     931              : {
     932           42 :   pari_sp av = avma;
     933              :   long vy, i, n, prec;
     934              :   GEN S, v, D;
     935              : 
     936           42 :   if (typ(s) != t_SER) pari_err_TYPE("seralgdep",s);
     937           42 :   if (p <= 0) pari_err_DOMAIN("seralgdep", "p", "<=", gen_0, stoi(p));
     938           42 :   if (r < 0) pari_err_DOMAIN("seralgdep", "r", "<", gen_0, stoi(r));
     939           42 :   if (is_bigint(addiu(muluu(p, r), 1))) pari_err_OVERFLOW("seralgdep");
     940           42 :   vy = varn(s);
     941           42 :   if (!vy) pari_err_PRIORITY("seralgdep", s, ">", 0);
     942           42 :   r++; p++;
     943           42 :   prec = valser(s) + lg(s)-2;
     944           42 :   if (r > prec) r = prec;
     945           42 :   S = cgetg(p+1, t_VEC); gel(S, 1) = s;
     946          119 :   for (i = 2; i <= p; i++) gel(S,i) = gmul(gel(S,i-1), s);
     947           42 :   v = sertomat(S, p, r, vy);
     948           42 :   D = lindep_Xadic(v);
     949           42 :   if (lg(D) == 1) { set_avma(av); return gen_0; }
     950           35 :   v = cgetg(p+1, t_VEC);
     951          133 :   for (n = 0; n < p; n++)
     952           98 :     gel(v, n+1) = RgV_to_RgX(vecslice(D, r*n+1, r*n+r), vy);
     953           35 :   return gc_GEN(av, RgV_to_RgX(v, 0));
     954              : }
     955              : 
     956              : GEN
     957           14 : serdiffdep(GEN s, long p, long r)
     958              : {
     959           14 :   pari_sp av = avma;
     960              :   long vy, i, n, prec;
     961              :   GEN P, S, v, D;
     962              : 
     963           14 :   if (typ(s) != t_SER) pari_err_TYPE("serdiffdep",s);
     964           14 :   if (p <= 0) pari_err_DOMAIN("serdiffdep", "p", "<=", gen_0, stoi(p));
     965           14 :   if (r < 0) pari_err_DOMAIN("serdiffdep", "r", "<", gen_0, stoi(r));
     966           14 :   if (is_bigint(addiu(muluu(p, r), 1))) pari_err_OVERFLOW("serdiffdep");
     967           14 :   vy = varn(s);
     968           14 :   if (!vy) pari_err_PRIORITY("serdiffdep", s, ">", 0);
     969           14 :   r++; p++;
     970           14 :   prec = valser(s) + lg(s)-2;
     971           14 :   if (r > prec) r = prec;
     972           14 :   S = cgetg(p+1, t_VEC); gel(S, 1) = s;
     973           56 :   for (i = 2; i <= p; i++) gel(S,i) = derivser(gel(S,i-1));
     974           14 :   v = sertomat(S, p, r, vy);
     975           14 :   D = lindep_Xadic(v);
     976           14 :   if (lg(D) == 1) { set_avma(av); return gen_0; }
     977           14 :   P = RgV_to_RgX(vecslice(D, 1, r), vy);
     978           14 :   v = cgetg(p, t_VEC);
     979           56 :   for (n = 1; n < p; n++)
     980           42 :     gel(v, n) = RgV_to_RgX(vecslice(D, r*n+1, r*n+r), vy);
     981           14 :   return gc_GEN(av, mkvec2(RgV_to_RgX(v, 0), gneg(P)));
     982              : }
     983              : 
     984              : /* FIXME: could precompute ZM_lll attached to V[2..] */
     985              : static GEN
     986        11991 : lindepcx(GEN V, long bit)
     987              : {
     988        11991 :   GEN Vr = real_i(V), Vi = imag_i(V);
     989        11991 :   long d = gexpo(Vr) - gexpo(Vi);
     990        11991 :   if (d < -bit) V = Vi;
     991        11991 :   else if (d > bit) V = Vr;
     992        11991 :   return lindepfull_bit(V, bit);
     993              : }
     994              : /* c floating point t_REAL or t_COMPLEX, T ZX, recognize in Q[x]/(T).
     995              :  * V helper vector (containing complex roots of T), MODIFIED */
     996              : static GEN
     997        11991 : cx_bestapprnf(GEN c, GEN T, GEN V, long bit)
     998              : {
     999        11991 :   GEN M, a, v = NULL;
    1000              :   long i, l;
    1001        11991 :   gel(V,1) = gneg(c); M = lindepcx(V, bit);
    1002        11991 :   if (!M) pari_err(e_MISC, "cannot rationalize coeff in bestapprnf");
    1003        11991 :   l = lg(M); a = NULL;
    1004        11991 :   for (i = 1; i < l; i ++) { v = gel(M,i); a = gel(v,1); if (signe(a)) break; }
    1005        11991 :   v = RgC_Rg_div(vecslice(v, 2, lg(M)-1), a);
    1006        11991 :   if (!T) return gel(v,1);
    1007         4830 :   v = RgV_to_RgX(v, varn(T)); l = lg(v);
    1008         4830 :   if (l == 2) return gen_0;
    1009         4165 :   if (l == 3) return gel(v,2);
    1010         3668 :   return mkpolmod(v, T);
    1011              : }
    1012              : static GEN
    1013        14784 : bestapprnf_i(GEN x, GEN T, GEN V, long bit)
    1014              : {
    1015        14784 :   long i, l, tx = typ(x);
    1016              :   GEN z;
    1017        14784 :   switch (tx)
    1018              :   {
    1019         1505 :     case t_INT: case t_FRAC: return x;
    1020        11991 :     case t_REAL: case t_COMPLEX: return cx_bestapprnf(x, T, V, bit);
    1021            0 :     case t_POLMOD: if (RgX_equal(gel(x,1),T)) return x;
    1022            0 :                    break;
    1023         1288 :     case t_POL: case t_SER: case t_VEC: case t_COL: case t_MAT:
    1024         1288 :       l = lg(x); z = cgetg(l, tx);
    1025         1974 :       for (i = 1; i < lontyp[tx]; i++) z[i] = x[i];
    1026        13993 :       for (; i < l; i++) gel(z,i) = bestapprnf_i(gel(x,i), T, V, bit);
    1027         1288 :       return z;
    1028              :   }
    1029            0 :   pari_err_TYPE("mfcxtoQ", x);
    1030              :   return NULL;/*LCOV_EXCL_LINE*/
    1031              : }
    1032              : 
    1033              : GEN
    1034         2163 : bestapprnf(GEN x, GEN T, GEN roT, long prec)
    1035              : {
    1036         2163 :   pari_sp av = avma;
    1037         2163 :   long tx = typ(x), dT = 1, bit;
    1038              :   GEN V;
    1039              : 
    1040         2163 :   if (T)
    1041              :   {
    1042         1610 :     if (typ(T) != t_POL) T = nf_get_pol(checknf(T));
    1043         1610 :     else if (!RgX_is_ZX(T)) pari_err_TYPE("bestapprnf", T);
    1044         1610 :     dT = degpol(T);
    1045              :   }
    1046         2163 :   if (is_rational_t(tx)) return gcopy(x);
    1047         2079 :   if (tx == t_POLMOD)
    1048              :   {
    1049            0 :     if (!T || !RgX_equal(T, gel(x,1))) pari_err_TYPE("bestapprnf",x);
    1050            0 :     return gcopy(x);
    1051              :   }
    1052              : 
    1053         2079 :   if (roT)
    1054              :   {
    1055          644 :     long l = gprecision(roT);
    1056          644 :     switch(typ(roT))
    1057              :     {
    1058          644 :       case t_INT: case t_FRAC: case t_REAL: case t_COMPLEX: break;
    1059            0 :       default: pari_err_TYPE("bestapprnf", roT);
    1060              :     }
    1061          644 :     if (prec < l) prec = l;
    1062              :   }
    1063         1435 :   else if (!T)
    1064          525 :     roT = gen_1;
    1065              :   else
    1066              :   {
    1067          910 :     long n = poliscyclo(T); /* cyclotomic is an important special case */
    1068          910 :     roT = n? rootsof1u_cx(n,prec): gel(QX_complex_roots(T,prec), 1);
    1069              :   }
    1070         2079 :   V = vec_prepend(gpowers(roT, dT-1), NULL);
    1071         2079 :   bit = prec2nbits_mul(prec, 0.8);
    1072         2079 :   return gc_GEN(av, bestapprnf_i(x, T, V, bit));
    1073              : }
    1074              : 
    1075              : /********************************************************************/
    1076              : /**                                                                **/
    1077              : /**                              MINIM                             **/
    1078              : /**                                                                **/
    1079              : /********************************************************************/
    1080              : void
    1081       124054 : minim_alloc(long n, double ***q, GEN *x, double **y,  double **z, double **v)
    1082              : {
    1083       124054 :   long i, s = n * sizeof(double);
    1084              : 
    1085       124054 :   *x = cgetg(n, t_VECSMALL);
    1086       124054 :   *q = (double**) new_chunk(n);
    1087       124054 :   *y = (double*) stack_malloc_align(s, sizeof(double));
    1088       124054 :   *z = (double*) stack_malloc_align(s, sizeof(double));
    1089       124054 :   *v = (double*) stack_malloc_align(s, sizeof(double));
    1090       534974 :   for (i=1; i<n; i++) (*q)[i] = (double*) stack_malloc_align(s, sizeof(double));
    1091       124054 : }
    1092              : 
    1093              : static void
    1094           70 : cvp_alloc(long n, double **t, double **tpre)
    1095              : {
    1096           70 :   long s = n * sizeof(double);
    1097           70 :   *t = (double*) stack_malloc_align(s, sizeof(double));
    1098           70 :   *tpre = (double*) stack_malloc_align(s, sizeof(double));
    1099           70 : }
    1100              : 
    1101              : static GEN
    1102         5502 : ZC_canon(GEN V)
    1103              : {
    1104         5502 :   long l = lg(V), j, s;
    1105        11242 :   for (j = 1; j < l; j++)
    1106        11242 :     if ((s = signe(gel(V,j)))) return s < 0? ZC_neg(V): V;
    1107            0 :   return V;
    1108              : }
    1109              : static GEN
    1110         5502 : ZM_zc_mul_canon(GEN u, GEN x) { return ZC_canon(ZM_zc_mul(u,x)); }
    1111              : static GEN
    1112       240366 : ZM_zc_mul_canon_zm(GEN u, GEN x)
    1113              : {
    1114       240366 :   pari_sp av = avma;
    1115       240366 :   GEN y = ZV_to_zv(ZM_zc_mul(u,x));
    1116       240366 :   zv_canon_inplace(y); return gc_upto(av, y);
    1117              : }
    1118              : 
    1119              : struct qfvec
    1120              : {
    1121              :   GEN a, r, u;
    1122              : };
    1123              : 
    1124              : static void
    1125            0 : err_minim(GEN a)
    1126              : {
    1127            0 :   pari_err_DOMAIN("minim0","form","is not",
    1128              :                   strtoGENstr("positive definite"),a);
    1129            0 : }
    1130              : 
    1131              : static GEN
    1132          902 : minim_lll(GEN a, GEN *u)
    1133              : {
    1134          902 :   *u = lllgramint(a);
    1135          902 :   if (lg(*u) != lg(a)) err_minim(a);
    1136          902 :   return qf_ZM_apply(a,*u);
    1137              : }
    1138              : 
    1139              : static void
    1140          902 : forqfvec_init_dolll(struct qfvec *qv, GEN *pa, long dolll)
    1141              : {
    1142          902 :   GEN r, u, a = *pa;
    1143          902 :   if (!dolll) u = NULL;
    1144              :   else
    1145              :   {
    1146          860 :     if (typ(a) != t_MAT || !RgM_is_ZM(a)) pari_err_TYPE("qfminim",a);
    1147          860 :     a = *pa = minim_lll(a, &u);
    1148              :   }
    1149          902 :   qv->a = RgM_gtofp(a, DEFAULTPREC);
    1150          902 :   r = qfgaussred_positive(qv->a);
    1151          902 :   if (!r)
    1152              :   {
    1153            0 :     r = qfgaussred_positive(a); /* exact computation */
    1154            0 :     if (!r) err_minim(a);
    1155            0 :     r = RgM_gtofp(r, DEFAULTPREC);
    1156              :   }
    1157          902 :   qv->r = r;
    1158          902 :   qv->u = u;
    1159          902 : }
    1160              : 
    1161              : static void
    1162           42 : forqfvec_init(struct qfvec *qv, GEN a)
    1163           42 : { forqfvec_init_dolll(qv, &a, 1); }
    1164              : 
    1165              : static void
    1166           42 : forqfvec_i(void *E, long (*fun)(void *, GEN, GEN, double), struct qfvec *qv, GEN BORNE)
    1167              : {
    1168           42 :   GEN x, a = qv->a, r = qv->r, u = qv->u;
    1169           42 :   long n = lg(a)-1, i, j, k;
    1170              :   double p,BOUND,*v,*y,*z,**q;
    1171           42 :   const double eps = 1e-10;
    1172           42 :   if (!BORNE) BORNE = gen_0;
    1173              :   else
    1174              :   {
    1175           28 :     BORNE = gfloor(BORNE);
    1176           28 :     if (typ(BORNE) != t_INT) pari_err_TYPE("minim0",BORNE);
    1177           35 :     if (signe(BORNE) <= 0) return;
    1178              :   }
    1179           35 :   if (n == 0) return;
    1180           28 :   minim_alloc(n+1, &q, &x, &y, &z, &v);
    1181           98 :   for (j=1; j<=n; j++)
    1182              :   {
    1183           70 :     v[j] = rtodbl(gcoeff(r,j,j));
    1184          133 :     for (i=1; i<j; i++) q[i][j] = rtodbl(gcoeff(r,i,j));
    1185              :   }
    1186              : 
    1187           28 :   if (gequal0(BORNE))
    1188              :   {
    1189              :     double c;
    1190           14 :     p = rtodbl(gcoeff(a,1,1));
    1191           42 :     for (i=2; i<=n; i++) { c = rtodbl(gcoeff(a,i,i)); if (c < p) p = c; }
    1192           14 :     BORNE = roundr(dbltor(p));
    1193              :   }
    1194              :   else
    1195           14 :     p = gtodouble(BORNE);
    1196           28 :   BOUND = p * (1 + eps);
    1197           28 :   if (BOUND > (double)ULONG_MAX || (ulong)BOUND != (ulong)p)
    1198            7 :     pari_err_PREC("forqfvec");
    1199              : 
    1200           21 :   k = n; y[n] = z[n] = 0;
    1201           21 :   x[n] = (long)sqrt(BOUND/v[n]);
    1202           56 :   for(;;x[1]--)
    1203              :   {
    1204              :     do
    1205              :     {
    1206          140 :       if (k>1)
    1207              :       {
    1208           84 :         long l = k-1;
    1209           84 :         z[l] = 0;
    1210          245 :         for (j=k; j<=n; j++) z[l] += q[l][j]*x[j];
    1211           84 :         p = (double)x[k] + z[k];
    1212           84 :         y[l] = y[k] + p*p*v[k];
    1213           84 :         x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]);
    1214           84 :         k = l;
    1215              :       }
    1216              :       for(;;)
    1217              :       {
    1218          189 :         p = (double)x[k] + z[k];
    1219          189 :         if (y[k] + p*p*v[k] <= BOUND) break;
    1220           49 :         k++; x[k]--;
    1221              :       }
    1222          140 :     } while (k > 1);
    1223           77 :     if (! x[1] && y[1]<=eps) break;
    1224              : 
    1225           56 :     p = (double)x[1] + z[1]; p = y[1] + p*p*v[1]; /* norm(x) */
    1226           56 :     if (fun(E, u, x, p)) break;
    1227              :   }
    1228              : }
    1229              : 
    1230              : void
    1231            0 : forqfvec(void *E, long (*fun)(void *, GEN, GEN, double), GEN a, GEN BORNE)
    1232              : {
    1233            0 :   pari_sp av = avma;
    1234              :   struct qfvec qv;
    1235            0 :   forqfvec_init(&qv, a);
    1236            0 :   forqfvec_i(E, fun, &qv, BORNE);
    1237            0 :   set_avma(av);
    1238            0 : }
    1239              : 
    1240              : struct qfvecwrap
    1241              : {
    1242              :   void *E;
    1243              :   long (*fun)(void *, GEN);
    1244              : };
    1245              : 
    1246              : static long
    1247           56 : forqfvec_wrap(void *E, GEN u, GEN x, double d)
    1248              : {
    1249           56 :   pari_sp av = avma;
    1250           56 :   struct qfvecwrap *W = (struct qfvecwrap *) E;
    1251              :   (void) d;
    1252           56 :   return gc_long(av, W->fun(W->E, ZM_zc_mul_canon(u, x)));
    1253              : }
    1254              : 
    1255              : void
    1256           42 : forqfvec1(void *E, long (*fun)(void *, GEN), GEN a, GEN BORNE)
    1257              : {
    1258           42 :   pari_sp av = avma;
    1259              :   struct qfvecwrap wr;
    1260              :   struct qfvec qv;
    1261           42 :   wr.E = E; wr.fun = fun;
    1262           42 :   forqfvec_init(&qv, a);
    1263           42 :   forqfvec_i((void*) &wr, forqfvec_wrap, &qv, BORNE);
    1264           35 :   set_avma(av);
    1265           35 : }
    1266              : 
    1267              : void
    1268           42 : forqfvec0(GEN a, GEN BORNE, GEN code)
    1269           42 : { EXPRVOID_WRAP(code, forqfvec1(EXPR_ARGVOID, a,  BORNE)) }
    1270              : 
    1271              : enum { min_ALL = 0, min_FIRST, min_VECSMALL, min_VECSMALL2 };
    1272              : 
    1273              : static int
    1274          923 : stockmax_init(const char *fun, GEN STOCKMAX, long *maxrank)
    1275              : {
    1276          923 :   long r = 200;
    1277          923 :   if (!STOCKMAX) { *maxrank = 200; return 1; }
    1278          511 :   STOCKMAX = gfloor(STOCKMAX);
    1279          511 :   if (typ(STOCKMAX) != t_INT) pari_err_TYPE(fun, STOCKMAX);
    1280          511 :   r = itos(STOCKMAX);
    1281          511 :   if (r < 0)
    1282              :   {
    1283            0 :     char *e = stack_strcat(fun, "[negative number of vectors]");
    1284            0 :     pari_err_TYPE(e, STOCKMAX);
    1285              :   }
    1286          511 :   *maxrank = r; return 0;
    1287              : }
    1288              : 
    1289              : /* Minimal vectors for the integral definite quadratic form: a.
    1290              :  * Result u:
    1291              :  *   u[1]= Number of vectors of square norm <= BORNE
    1292              :  *   u[2]= maximum norm found
    1293              :  *   u[3]= list of vectors found (at most STOCKMAX, unless NULL)
    1294              :  *
    1295              :  *  If BORNE = NULL: Minimal nonzero vectors.
    1296              :  *  flag = min_ALL,   as above
    1297              :  *  flag = min_FIRST, exits when first suitable vector is found.
    1298              :  *  flag = min_VECSMALL, return a t_VECSMALL of (half) the number of vectors
    1299              :  *  for each norm
    1300              :  *  flag = min_VECSMALL2, same but count only vectors with even norm, and shift
    1301              :  *  the answer */
    1302              : static GEN
    1303          847 : minim0_dolll(GEN a, GEN BORNE, GEN STOCKMAX, long flag, long dolll)
    1304              : {
    1305              :   GEN x, u, r, L, gnorme;
    1306          847 :   long n = lg(a)-1, i, j, k, s, maxrank, sBORNE;
    1307          847 :   pari_sp av = avma, av1;
    1308              :   double p,maxnorm,BOUND,*v,*y,*z,**q;
    1309          847 :   const double eps = 1e-10;
    1310              :   int stockall;
    1311              :   struct qfvec qv;
    1312              : 
    1313          847 :   if (!BORNE)
    1314           56 :     sBORNE = 0;
    1315              :   else
    1316              :   {
    1317          791 :     BORNE = gfloor(BORNE);
    1318          791 :     if (typ(BORNE) != t_INT) pari_err_TYPE("minim0",BORNE);
    1319          791 :     if (is_bigint(BORNE)) pari_err_PREC( "qfminim");
    1320          790 :     sBORNE = itos(BORNE); set_avma(av);
    1321          790 :     if (sBORNE < 0) sBORNE = 0;
    1322              :   }
    1323          846 :   stockall = stockmax_init("minim0", STOCKMAX, &maxrank);
    1324              : 
    1325          846 :   switch(flag)
    1326              :   {
    1327          462 :     case min_VECSMALL:
    1328              :     case min_VECSMALL2:
    1329          462 :       if (sBORNE <= 0) return cgetg(1, t_VECSMALL);
    1330          434 :       L = zero_zv(sBORNE);
    1331          434 :       if (flag == min_VECSMALL2) sBORNE <<= 1;
    1332          434 :       if (n == 0) return L;
    1333          434 :       break;
    1334           35 :     case min_FIRST:
    1335           35 :       if (n == 0 || (!sBORNE && BORNE)) return cgetg(1,t_VEC);
    1336           21 :       L = NULL; /* gcc -Wall */
    1337           21 :       break;
    1338          349 :     case min_ALL:
    1339          349 :       if (n == 0 || (!sBORNE && BORNE))
    1340           14 :         retmkvec3(gen_0, gen_0, cgetg(1, t_MAT));
    1341          335 :       L = new_chunk(1+maxrank);
    1342          335 :       break;
    1343            0 :     default:
    1344            0 :       return NULL;
    1345              :   }
    1346          790 :   minim_alloc(n+1, &q, &x, &y, &z, &v);
    1347              : 
    1348          790 :   forqfvec_init_dolll(&qv, &a, dolll);
    1349          790 :   av1 = avma;
    1350          790 :   r = qv.r;
    1351          790 :   u = qv.u;
    1352         5912 :   for (j=1; j<=n; j++)
    1353              :   {
    1354         5122 :     v[j] = rtodbl(gcoeff(r,j,j));
    1355        29579 :     for (i=1; i<j; i++) q[i][j] = rtodbl(gcoeff(r,i,j)); /* |.| <= 1/2 */
    1356              :   }
    1357              : 
    1358          790 :   if (sBORNE) maxnorm = 0.;
    1359              :   else
    1360              :   {
    1361           56 :     GEN B = gcoeff(a,1,1);
    1362           56 :     long t = 1;
    1363          616 :     for (i=2; i<=n; i++)
    1364              :     {
    1365          560 :       GEN c = gcoeff(a,i,i);
    1366          560 :       if (cmpii(c, B) < 0) { B = c; t = i; }
    1367              :     }
    1368           56 :     if (flag == min_FIRST) return gc_GEN(av, mkvec2(B, gel(u,t)));
    1369           49 :     maxnorm = -1.; /* don't update maxnorm */
    1370           49 :     if (is_bigint(B)) return NULL;
    1371           48 :     sBORNE = itos(B);
    1372              :   }
    1373          782 :   BOUND = sBORNE * (1 + eps);
    1374          782 :   if ((long)BOUND != sBORNE) return NULL;
    1375              : 
    1376          770 :   s = 0;
    1377          770 :   k = n; y[n] = z[n] = 0;
    1378          770 :   x[n] = (long)sqrt(BOUND/v[n]);
    1379      1223264 :   for(;;x[1]--)
    1380              :   {
    1381              :     do
    1382              :     {
    1383      2245614 :       if (k>1)
    1384              :       {
    1385      1022259 :         long l = k-1;
    1386      1022259 :         z[l] = 0;
    1387     11756080 :         for (j=k; j<=n; j++) z[l] += q[l][j]*x[j];
    1388      1022259 :         p = (double)x[k] + z[k];
    1389      1022259 :         y[l] = y[k] + p*p*v[k];
    1390      1022259 :         x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]);
    1391      1022259 :         k = l;
    1392              :       }
    1393              :       for(;;)
    1394              :       {
    1395      3263729 :         p = (double)x[k] + z[k];
    1396      3263729 :         if (y[k] + p*p*v[k] <= BOUND) break;
    1397      1018115 :         k++; x[k]--;
    1398              :       }
    1399              :     }
    1400      2245614 :     while (k > 1);
    1401      1224034 :     if (! x[1] && y[1]<=eps) break;
    1402              : 
    1403      1223271 :     p = (double)x[1] + z[1];
    1404      1223271 :     p = y[1] + p*p*v[1]; /* norm(x) */
    1405      1223271 :     if (maxnorm >= 0)
    1406              :     {
    1407      1220723 :       if (p > maxnorm) maxnorm = p;
    1408              :     }
    1409              :     else
    1410              :     { /* maxnorm < 0 : only look for minimal vectors */
    1411         2548 :       pari_sp av2 = avma;
    1412         2548 :       gnorme = roundr(dbltor(p));
    1413         2548 :       if (cmpis(gnorme, sBORNE) >= 0) set_avma(av2);
    1414              :       else
    1415              :       {
    1416           14 :         sBORNE = itos(gnorme); set_avma(av1);
    1417           14 :         BOUND = sBORNE * (1+eps);
    1418           14 :         L = new_chunk(maxrank+1);
    1419           14 :         s = 0;
    1420              :       }
    1421              :     }
    1422      1223271 :     s++;
    1423              : 
    1424      1223271 :     switch(flag)
    1425              :     {
    1426            7 :       case min_FIRST:
    1427            7 :         if (dolll) x = ZM_zc_mul_canon(u,x);
    1428            7 :         return gc_GEN(av, mkvec2(roundr(dbltor(p)), x));
    1429              : 
    1430       248241 :       case min_ALL:
    1431       248241 :         if (s > maxrank && stockall) /* overflow */
    1432              :         {
    1433          490 :           long maxranknew = maxrank << 1;
    1434          490 :           GEN Lnew = new_chunk(1 + maxranknew);
    1435       344890 :           for (i=1; i<=maxrank; i++) Lnew[i] = L[i];
    1436          490 :           L = Lnew; maxrank = maxranknew;
    1437              :         }
    1438       248241 :         if (s<=maxrank) gel(L,s) = leafcopy(x);
    1439       248241 :         break;
    1440              : 
    1441        39200 :       case min_VECSMALL:
    1442        39200 :         { ulong norm = (ulong)(p + 0.5); L[norm]++; }
    1443        39200 :         break;
    1444              : 
    1445       935823 :       case min_VECSMALL2:
    1446       935823 :         { ulong norm = (ulong)(p + 0.5); if (!odd(norm)) L[norm>>1]++; }
    1447       935823 :         break;
    1448              : 
    1449              :     }
    1450              :   }
    1451          763 :   switch(flag)
    1452              :   {
    1453            7 :     case min_FIRST:
    1454            7 :       retgc_const(av, cgetg(1, t_VEC));
    1455          434 :     case min_VECSMALL:
    1456              :     case min_VECSMALL2:
    1457          434 :       set_avma((pari_sp)L); return L;
    1458              :   }
    1459          322 :   r = (maxnorm >= 0) ? roundr(dbltor(maxnorm)): stoi(sBORNE);
    1460          322 :   k = minss(s,maxrank);
    1461          322 :   L[0] = evaltyp(t_MAT) | evallg(k + 1);
    1462          322 :   if (dolll)
    1463       246092 :     for (j=1; j<=k; j++)
    1464       245805 :       gel(L,j) = dolll==1 ? ZM_zc_mul_canon(u, gel(L,j))
    1465       245805 :                           : ZM_zc_mul_canon_zm(u, gel(L,j));
    1466          322 :   return gc_GEN(av, mkvec3(stoi(s<<1), r, L));
    1467              : }
    1468              : 
    1469              : /* Closest vectors for the integral definite quadratic form: a.
    1470              :  * Code bases on minim0_dolll
    1471              :  * Result u:
    1472              :  *   u[1]= Number of closest vectors of square distance <= BORNE
    1473              :  *   u[2]= maximum squared distance found
    1474              :  *   u[3]= list of vectors found (at most STOCKMAX, unless NULL)
    1475              :  *
    1476              :  *  If BORNE = NULL or <= 0.: returns closest vectors.
    1477              :  *  flag = min_ALL,   as above
    1478              :  *  flag = min_FIRST, exits when first suitable vector is found.
    1479              : */
    1480              : static GEN
    1481           91 : cvp0_dolll(GEN a, GEN target, GEN BORNE, GEN STOCKMAX, long flag, long dolll)
    1482              : {
    1483              :   GEN x, u, r, L;
    1484           91 :   long n = lg(a)-1, i, j, k, s, maxrank;
    1485           91 :   pari_sp av = avma, av1;
    1486              :   double p,maxnorm,BOUND,*v,*y,*z,*tt,**q, *tpre, sBORNE;
    1487           91 :   const double eps = 1e-10;
    1488              :   int stockall;
    1489              :   struct qfvec qv;
    1490           91 :   int done = 0;
    1491              : 
    1492           91 :   if (!is_vec_t(typ(target))) pari_err_TYPE("cvp0",target);
    1493           91 :   if (n != lg(target)-1) pari_err_TYPE("cvp0 [different dimensions]",target);
    1494           77 :   if (!BORNE)
    1495            0 :     sBORNE = 0.;
    1496              :   else
    1497              :   {
    1498           77 :     if (!is_real_t(typ(BORNE))) pari_err_TYPE("cvp0",BORNE);
    1499           77 :     sBORNE = gtodouble(BORNE);
    1500           77 :     if (sBORNE < 0.) sBORNE = 0.;
    1501              :   }
    1502           77 :   stockall = stockmax_init("cvp0", STOCKMAX, &maxrank);
    1503              : 
    1504           77 :   L = (flag==min_ALL) ? new_chunk(1+maxrank) : NULL;
    1505           77 :   if (n == 0)
    1506              :   {
    1507            7 :     if (flag==min_ALL) retmkvec3(gen_0, gen_0, cgetg(1, t_MAT));
    1508            0 :     return cgetg(1,t_VEC);
    1509              :   }
    1510              : 
    1511           70 :   minim_alloc(n+1, &q, &x, &y, &z, &v);
    1512           70 :   cvp_alloc(n+1, &tt, &tpre);
    1513              : 
    1514           70 :   forqfvec_init_dolll(&qv, &a, dolll);
    1515           70 :   av1 = avma;
    1516           70 :   r = qv.r;
    1517           70 :   u = qv.u;
    1518          392 :   for (j=1; j<=n; j++)
    1519              :   {
    1520          322 :     v[j] = rtodbl(gcoeff(r,j,j));
    1521         1729 :     for (i=1; i<j; i++) q[i][j] = rtodbl(gcoeff(r,i,j)); /* |.| <= 1/2 */
    1522              :   }
    1523              : 
    1524           70 :   if (dolll)
    1525              :   {
    1526           70 :     GEN tv = RgM_RgC_mul(ZM_inv(u, NULL), target);
    1527          392 :     for (j=1; j<=n; j++) tt[j] = gtodouble(gel(tv, j));
    1528              :   } else
    1529            0 :     for (j=1; j<=n; j++) tt[j] = gtodouble(gel(target, j));
    1530              :   /* precompute contribution of tt to z[l] */
    1531          392 :   for(k=1; k <= n; k++)
    1532              :   {
    1533          322 :     tpre[k] = -tt[k];
    1534         1729 :     for(j=k+1; j<=n; j++) tpre[k] -= q[k][j] * tt[j];
    1535              :   }
    1536              : 
    1537           70 :   if (sBORNE) maxnorm = 0.;
    1538              :   else
    1539              :   {
    1540           28 :     GEN B = gcoeff(a,1,1);
    1541          112 :     for (i = 2; i <= n; i++) B = addii(B, gcoeff(a,i,i));
    1542           28 :     maxnorm = -1.; /* don't update maxnorm */
    1543           28 :     if (is_bigint(B)) return NULL;
    1544           28 :     sBORNE = 0.;
    1545          140 :     for(i=1; i<=n; i++) sBORNE += v[i];
    1546              :   }
    1547           70 :   BOUND = sBORNE * (1 + eps);
    1548              : 
    1549           70 :   s = 0;
    1550           70 :   k = n; y[n] = 0;
    1551           70 :   z[n] = tpre[n];
    1552           70 :   x[n] = (long)floor(sqrt(BOUND/v[n])-z[n]);
    1553          889 :   for(;;x[1]--)
    1554              :   {
    1555              :     do
    1556              :     {
    1557         8582 :       if (k>1)
    1558              :       {
    1559         7665 :         long l = k-1;
    1560         7665 :         z[l] = tpre[l];
    1561        61488 :         for (j=k; j<=n; j++) z[l] += q[l][j]*x[j];
    1562         7665 :         p = (double)x[k] + z[k];
    1563         7665 :         y[l] = y[k] + p*p*v[k];
    1564         7665 :         x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]);
    1565         7665 :         k = l;
    1566              :       }
    1567              :       for(;;)
    1568              :       {
    1569        16247 :         p = (double)x[k] + z[k];
    1570        16247 :         if (y[k] + p*p*v[k] <= BOUND) break;
    1571         7735 :         if (k >= n) { done = 1; break; }
    1572         7665 :         k++; x[k]--;
    1573              :       }
    1574              :     }
    1575         8582 :     while (k > 1 && !done);
    1576          959 :     if (done) break;
    1577              : 
    1578          889 :     p = (double)x[1] + z[1];
    1579          889 :     p = y[1] + p*p*v[1]; /* norm(x-target) */
    1580          889 :     if (maxnorm >= 0)
    1581              :     {
    1582          175 :       if (p > maxnorm) maxnorm = p;
    1583              :     }
    1584              :     else
    1585              :     { /* maxnorm < 0 : only look for closest vectors */
    1586          714 :       if (p * (1+10*eps) < sBORNE) {
    1587          231 :         sBORNE = p; set_avma(av1);
    1588          231 :         BOUND = sBORNE * (1+eps);
    1589          231 :         L = new_chunk(maxrank+1);
    1590          231 :         s = 0;
    1591              :       }
    1592              :     }
    1593          889 :     s++;
    1594              : 
    1595          889 :     switch(flag)
    1596              :     {
    1597            0 :       case min_FIRST:
    1598            0 :         if (dolll) x = ZM_zc_mul(u,x);
    1599            0 :         return gc_GEN(av, mkvec2(dbltor(p), x));
    1600              : 
    1601          889 :       case min_ALL:
    1602          889 :         if (s > maxrank && stockall) /* overflow */
    1603              :         {
    1604            0 :           long maxranknew = maxrank << 1;
    1605            0 :           GEN Lnew = new_chunk(1 + maxranknew);
    1606            0 :           for (i=1; i<=maxrank; i++) Lnew[i] = L[i];
    1607            0 :           L = Lnew; maxrank = maxranknew;
    1608              :         }
    1609          889 :         if (s<=maxrank) gel(L,s) = leafcopy(x);
    1610          889 :         break;
    1611              :     }
    1612              :   }
    1613           70 :   switch(flag)
    1614              :   {
    1615            0 :     case min_FIRST:
    1616            0 :       retgc_const(av, cgetg(1, t_VEC));
    1617              :   }
    1618           70 :   r = (maxnorm >= 0) ? dbltor(maxnorm): dbltor(sBORNE);
    1619           70 :   k = minss(s,maxrank);
    1620           70 :   L[0] = evaltyp(t_MAT) | evallg(k + 1);
    1621          322 :   for (j=1; j<=k; j++)
    1622          252 :     gel(L,j) = dolll==1 ? ZM_zc_mul(u, gel(L,j))
    1623          252 :                         : zc_to_ZC(gel(L,j));
    1624           70 :   return gc_GEN(av, mkvec3(stoi(s), r, L));
    1625              : }
    1626              : 
    1627              : static GEN
    1628          553 : minim0(GEN a, GEN BORNE, GEN STOCKMAX, long flag)
    1629              : {
    1630          553 :   GEN v = minim0_dolll(a, BORNE, STOCKMAX, flag, 1);
    1631          552 :   if (!v) pari_err_PREC("qfminim");
    1632          546 :   return v;
    1633              : }
    1634              : 
    1635              : static GEN
    1636           91 : cvp0(GEN a, GEN target, GEN BORNE, GEN STOCKMAX, long flag)
    1637              : {
    1638           91 :   GEN v = cvp0_dolll(a, target, BORNE, STOCKMAX, flag, 1);
    1639           77 :   if (!v) pari_err_PREC("qfcvp");
    1640           77 :   return v;
    1641              : }
    1642              : 
    1643              : static GEN
    1644          252 : minim0_zm(GEN a, GEN BORNE, GEN STOCKMAX, long flag)
    1645              : {
    1646          252 :   GEN v = minim0_dolll(a, BORNE, STOCKMAX, flag, 2);
    1647          252 :   if (!v) pari_err_PREC("qfminim");
    1648          252 :   return v;
    1649              : }
    1650              : 
    1651              : GEN
    1652          462 : qfrep0(GEN a, GEN borne, long flag)
    1653          462 : { return minim0(a, borne, gen_0, (flag & 1)? min_VECSMALL2: min_VECSMALL); }
    1654              : 
    1655              : GEN
    1656          133 : qfminim0(GEN a, GEN borne, GEN stockmax, long flag, long prec)
    1657              : {
    1658          133 :   switch(flag)
    1659              :   {
    1660           49 :     case 0: return minim0(a,borne,stockmax,min_ALL);
    1661           35 :     case 1: return minim0(a,borne,gen_0   ,min_FIRST);
    1662           49 :     case 2:
    1663              :     {
    1664           49 :       long maxnum = -1;
    1665           49 :       if (typ(a) != t_MAT) pari_err_TYPE("qfminim",a);
    1666           49 :       if (stockmax) {
    1667           14 :         if (typ(stockmax) != t_INT) pari_err_TYPE("qfminim",stockmax);
    1668           14 :         maxnum = itos(stockmax);
    1669              :       }
    1670           49 :       a = fincke_pohst(a,borne,maxnum,prec,NULL);
    1671           42 :       if (!a) pari_err_PREC("qfminim");
    1672           42 :       return a;
    1673              :     }
    1674            0 :     default: pari_err_FLAG("qfminim");
    1675              :   }
    1676              :   return NULL; /* LCOV_EXCL_LINE */
    1677              : }
    1678              : 
    1679              : 
    1680              : GEN
    1681           91 : qfcvp0(GEN a, GEN target, GEN borne, GEN stockmax, long flag)
    1682              : {
    1683           91 :   switch(flag)
    1684              :   {
    1685           91 :     case 0: return cvp0(a,target,borne,stockmax,min_ALL);
    1686            0 :     case 1: return cvp0(a,target,borne,gen_0   ,min_FIRST);
    1687              :     /* case 2:
    1688              :        TODO: more robust finke_pohst enumeration */
    1689            0 :     default: pari_err_FLAG("qfcvp");
    1690              :   }
    1691              :   return NULL; /* LCOV_EXCL_LINE */
    1692              : }
    1693              : 
    1694              : GEN
    1695            7 : minim(GEN a, GEN borne, GEN stockmax)
    1696            7 : { return minim0(a,borne,stockmax,min_ALL); }
    1697              : 
    1698              : GEN
    1699          252 : minim_zm(GEN a, GEN borne, GEN stockmax)
    1700          252 : { return minim0_zm(a,borne,stockmax,min_ALL); }
    1701              : 
    1702              : GEN
    1703           42 : minim_raw(GEN a, GEN BORNE, GEN STOCKMAX)
    1704           42 : { return minim0_dolll(a, BORNE, STOCKMAX, min_ALL, 0); }
    1705              : 
    1706              : GEN
    1707            0 : minim2(GEN a, GEN borne, GEN stockmax)
    1708            0 : { return minim0(a,borne,stockmax,min_FIRST); }
    1709              : 
    1710              : /* If V depends linearly from the columns of the matrix, return 0.
    1711              :  * Otherwise, update INVP and L and return 1. No GC. */
    1712              : static int
    1713         1652 : addcolumntomatrix(GEN V, GEN invp, GEN L)
    1714              : {
    1715         1652 :   long i,j,k, n = lg(invp);
    1716         1652 :   GEN a = cgetg(n, t_COL), ak = NULL, mak;
    1717              : 
    1718        84231 :   for (k = 1; k < n; k++)
    1719        83706 :     if (!L[k])
    1720              :     {
    1721        27902 :       ak = RgMrow_zc_mul(invp, V, k);
    1722        27902 :       if (!gequal0(ak)) break;
    1723              :     }
    1724         1652 :   if (k == n) return 0;
    1725         1127 :   L[k] = 1;
    1726         1127 :   mak = gneg_i(ak);
    1727        43253 :   for (i=k+1; i<n; i++)
    1728        42126 :     gel(a,i) = gdiv(RgMrow_zc_mul(invp, V, i), mak);
    1729        43883 :   for (j=1; j<=k; j++)
    1730              :   {
    1731        42756 :     GEN c = gel(invp,j), ck = gel(c,k);
    1732        42756 :     if (gequal0(ck)) continue;
    1733         8757 :     gel(c,k) = gdiv(ck, ak);
    1734         8757 :     if (j==k)
    1735        43253 :       for (i=k+1; i<n; i++)
    1736        42126 :         gel(c,i) = gmul(gel(a,i), ck);
    1737              :     else
    1738       184814 :       for (i=k+1; i<n; i++)
    1739       177184 :         gel(c,i) = gadd(gel(c,i), gmul(gel(a,i), ck));
    1740              :   }
    1741         1127 :   return 1;
    1742              : }
    1743              : 
    1744              : GEN
    1745           42 : qfperfection(GEN a)
    1746              : {
    1747           42 :   pari_sp av = avma;
    1748              :   GEN u, L;
    1749           42 :   long r, s, k, l, n = lg(a)-1;
    1750              : 
    1751           42 :   if (!n) return gen_0;
    1752           42 :   if (typ(a) != t_MAT || !RgM_is_ZM(a)) pari_err_TYPE("qfperfection",a);
    1753           42 :   a = minim_lll(a, &u);
    1754           42 :   L = minim_raw(a,NULL,NULL);
    1755           42 :   r = (n*(n+1)) >> 1;
    1756           42 :   if (L)
    1757              :   {
    1758              :     GEN D, V, invp;
    1759           35 :     L = gel(L, 3); l = lg(L);
    1760           35 :     if (l == 2) { set_avma(av); return gen_1; }
    1761              :     /* |L[i]|^2 fits  into a long for all i */
    1762           21 :     D = zero_zv(r);
    1763           21 :     V = cgetg(r+1, t_VECSMALL);
    1764           21 :     invp = matid(r);
    1765           21 :     s = 0;
    1766         1659 :     for (k = 1; k < l; k++)
    1767              :     {
    1768         1652 :       pari_sp av2 = avma;
    1769         1652 :       GEN x = gel(L,k);
    1770              :       long i, j, I;
    1771        21098 :       for (i = I = 1; i<=n; i++)
    1772       145278 :         for (j=i; j<=n; j++,I++) V[I] = x[i]*x[j];
    1773         1652 :       if (!addcolumntomatrix(V,invp,D)) set_avma(av2);
    1774         1127 :       else if (++s == r) break;
    1775              :     }
    1776              :   }
    1777              :   else
    1778              :   {
    1779              :     GEN M;
    1780            7 :     L = fincke_pohst(a,NULL,-1, DEFAULTPREC, NULL);
    1781            7 :     if (!L) pari_err_PREC("qfminim");
    1782            7 :     L = gel(L, 3); l = lg(L);
    1783            7 :     if (l == 2) { set_avma(av); return gen_1; }
    1784            7 :     M = cgetg(l, t_MAT);
    1785          959 :     for (k = 1; k < l; k++)
    1786              :     {
    1787          952 :       GEN x = gel(L,k), c = cgetg(r+1, t_COL);
    1788              :       long i, I, j;
    1789        16184 :       for (i = I = 1; i<=n; i++)
    1790       144704 :         for (j=i; j<=n; j++,I++) gel(c,I) = mulii(gel(x,i), gel(x,j));
    1791          952 :       gel(M,k) = c;
    1792              :     }
    1793            7 :     s = ZM_rank(M);
    1794              :   }
    1795           28 :   return gc_utoipos(av, s);
    1796              : }
    1797              : 
    1798              : static GEN
    1799          140 : clonefill(GEN S, long s, long t)
    1800              : { /* initialize to dummy values */
    1801          140 :   GEN T = S, dummy = cgetg(1, t_STR);
    1802              :   long i;
    1803       308822 :   for (i = s+1; i <= t; i++) gel(S,i) = dummy;
    1804          140 :   S = gclone(S); if (isclone(T)) gunclone(T);
    1805          140 :   return S;
    1806              : }
    1807              : 
    1808              : /* increment ZV x, by incrementing cell of index k. Initial value x0[k] was
    1809              :  * chosen to minimize qf(x) for given x0[1..k-1] and x0[k+1,..] = 0
    1810              :  * The last nonzero entry must be positive and goes through x0[k]+1,2,3,...
    1811              :  * Others entries go through: x0[k]+1,-1,2,-2,...*/
    1812              : INLINE void
    1813      2950008 : step(GEN x, GEN y, GEN inc, long k)
    1814              : {
    1815      2950008 :   if (!signe(gel(y,k))) /* x[k+1..] = 0 */
    1816       160807 :     gel(x,k) = addiu(gel(x,k), 1); /* leading coeff > 0 */
    1817              :   else
    1818              :   {
    1819      2789201 :     long i = inc[k];
    1820      2789201 :     gel(x,k) = addis(gel(x,k), i),
    1821      2789201 :     inc[k] = (i > 0)? -1-i: 1-i;
    1822              :   }
    1823      2950008 : }
    1824              : 
    1825              : /* 1 if we are "sure" that x < y, up to few rounding errors, i.e.
    1826              :  * x < y - epsilon. More precisely :
    1827              :  * - sign(x - y) < 0
    1828              :  * - lgprec(x-y) > 3 || expo(x - y) - expo(x) > -24 */
    1829              : static int
    1830      1216062 : mplessthan(GEN x, GEN y)
    1831              : {
    1832      1216062 :   pari_sp av = avma;
    1833      1216062 :   GEN z = mpsub(x, y);
    1834      1216062 :   set_avma(av);
    1835      1216062 :   if (typ(z) == t_INT) return (signe(z) < 0);
    1836      1216062 :   if (signe(z) >= 0) return 0;
    1837        22371 :   if (realprec(z) > LOWDEFAULTPREC) return 1;
    1838        22371 :   return ( expo(z) - mpexpo(x) > -24 );
    1839              : }
    1840              : 
    1841              : /* 1 if we are "sure" that x > y, up to few rounding errors, i.e.
    1842              :  * x > y + epsilon */
    1843              : static int
    1844      4616418 : mpgreaterthan(GEN x, GEN y)
    1845              : {
    1846      4616418 :   pari_sp av = avma;
    1847      4616418 :   GEN z = mpsub(x, y);
    1848      4616418 :   set_avma(av);
    1849      4616418 :   if (typ(z) == t_INT) return (signe(z) > 0);
    1850      4616418 :   if (signe(z) <= 0) return 0;
    1851      2690107 :   if (realprec(z) > LOWDEFAULTPREC) return 1;
    1852       476880 :   return ( expo(z) - mpexpo(x) > -24 );
    1853              : }
    1854              : 
    1855              : /* x a t_INT, y  t_INT or t_REAL */
    1856              : INLINE GEN
    1857      1228154 : mulimp(GEN x, GEN y)
    1858              : {
    1859      1228154 :   if (typ(y) == t_INT) return mulii(x,y);
    1860      1228154 :   return signe(x) ? mulir(x,y): gen_0;
    1861              : }
    1862              : /* x + y*z, x,z two mp's, y a t_INT */
    1863              : INLINE GEN
    1864     13536473 : addmulimp(GEN x, GEN y, GEN z)
    1865              : {
    1866     13536473 :   if (!signe(y)) return x;
    1867      5830244 :   if (typ(z) == t_INT) return mpadd(x, mulii(y, z));
    1868      5830244 :   return mpadd(x, mulir(y, z));
    1869              : }
    1870              : 
    1871              : /* yk + vk * (xk + zk)^2 */
    1872              : static GEN
    1873      5774835 : norm_aux(GEN xk, GEN yk, GEN zk, GEN vk)
    1874              : {
    1875      5774835 :   GEN t = mpadd(xk, zk);
    1876      5774835 :   if (typ(t) == t_INT) { /* probably gen_0, avoid loss of accuracy */
    1877       306205 :     yk = addmulimp(yk, sqri(t), vk);
    1878              :   } else {
    1879      5468630 :     yk = mpadd(yk, mpmul(sqrr(t), vk));
    1880              :   }
    1881      5774835 :   return yk;
    1882              : }
    1883              : /* yk + vk * (xk + zk)^2 < B + epsilon */
    1884              : static int
    1885      4164187 : check_bound(GEN B, GEN xk, GEN yk, GEN zk, GEN vk)
    1886              : {
    1887      4164187 :   pari_sp av = avma;
    1888      4164187 :   int f = mpgreaterthan(norm_aux(xk,yk,zk,vk), B);
    1889      4164187 :   return gc_bool(av, !f);
    1890              : }
    1891              : 
    1892              : /* q(k-th canonical basis vector), where q is given in Cholesky form
    1893              :  * q(x) = sum_{i = 1}^n q[i,i] (x[i] + sum_{j > i} q[i,j] x[j])^2.
    1894              :  * Namely q(e_k) = q[k,k] + sum_{i < k} q[i,i] q[i,k]^2
    1895              :  * Assume 1 <= k <= n. */
    1896              : static GEN
    1897          182 : cholesky_norm_ek(GEN q, long k)
    1898              : {
    1899          182 :   GEN t = gcoeff(q,k,k);
    1900              :   long i;
    1901         1484 :   for (i = 1; i < k; i++) t = norm_aux(gen_0, t, gcoeff(q,i,k), gcoeff(q,i,i));
    1902          182 :   return t;
    1903              : }
    1904              : 
    1905              : /* q is the Cholesky decomposition of a quadratic form
    1906              :  * Enumerate vectors whose norm is less than BORNE (Algo 2.5.7),
    1907              :  * minimal vectors if BORNE = NULL (implies check = NULL).
    1908              :  * If (check != NULL) consider only vectors passing the check, and assumes
    1909              :  *   we only want the smallest possible vectors */
    1910              : static GEN
    1911        14713 : smallvectors(GEN q, GEN BORNE, long maxnum, FP_chk_fun *CHECK)
    1912              : {
    1913        14713 :   long N = lg(q), n = N-1, i, j, k, s, stockmax, checkcnt = 1;
    1914              :   pari_sp av, av1;
    1915              :   GEN inc, S, x, y, z, v, p1, alpha, norms;
    1916              :   GEN norme1, normax1, borne1, borne2;
    1917        14713 :   GEN (*check)(void *,GEN) = CHECK? CHECK->f: NULL;
    1918        14713 :   void *data = CHECK? CHECK->data: NULL;
    1919        14713 :   const long skipfirst = CHECK? CHECK->skipfirst: 0;
    1920        14713 :   const int stockall = (maxnum == -1);
    1921              : 
    1922        14713 :   alpha = dbltor(0.95);
    1923        14713 :   normax1 = gen_0;
    1924              : 
    1925        14713 :   v = cgetg(N,t_VEC);
    1926        14713 :   inc = const_vecsmall(n, 1);
    1927              : 
    1928        14713 :   av = avma;
    1929        14713 :   stockmax = stockall? 2000: maxnum;
    1930        14713 :   norms = cgetg(check?(stockmax+1): 1,t_VEC); /* unused if (!check) */
    1931        14713 :   S = cgetg(stockmax+1,t_VEC);
    1932        14713 :   x = cgetg(N,t_COL);
    1933        14713 :   y = cgetg(N,t_COL);
    1934        14713 :   z = cgetg(N,t_COL);
    1935        97807 :   for (i=1; i<N; i++) {
    1936        83094 :     gel(v,i) = gcoeff(q,i,i);
    1937        83094 :     gel(x,i) = gel(y,i) = gel(z,i) = gen_0;
    1938              :   }
    1939        14713 :   if (BORNE)
    1940              :   {
    1941        14692 :     borne1 = BORNE;
    1942        14692 :     if (gsigne(borne1) <= 0) retmkvec3(gen_0, gen_0, cgetg(1,t_MAT));
    1943        14678 :     if (typ(borne1) != t_REAL)
    1944              :     {
    1945              :       long prec;
    1946          419 :       prec = nbits2prec(gexpo(borne1) + 10);
    1947          419 :       borne1 = gtofp(borne1, maxss(prec, DEFAULTPREC));
    1948              :     }
    1949              :   }
    1950              :   else
    1951              :   {
    1952           21 :     borne1 = gcoeff(q,1,1);
    1953          203 :     for (i=2; i<N; i++)
    1954              :     {
    1955          182 :       GEN b = cholesky_norm_ek(q, i);
    1956          182 :       if (gcmp(b, borne1) < 0) borne1 = b;
    1957              :     }
    1958              :     /* borne1 = norm of smallest basis vector */
    1959              :   }
    1960        14699 :   borne2 = mulrr(borne1,alpha);
    1961        14699 :   if (DEBUGLEVEL>2)
    1962            0 :     err_printf("smallvectors looking for norm < %P.4G\n",borne1);
    1963        14699 :   s = 0; k = n;
    1964       381909 :   for(;; step(x,y,inc,k)) /* main */
    1965              :   { /* x (supposedly) small vector, ZV.
    1966              :      * For all t >= k, we have
    1967              :      *   z[t] = sum_{j > t} q[t,j] * x[j]
    1968              :      *   y[t] = sum_{i > t} q[i,i] * (x[i] + z[i])^2
    1969              :      *        = 0 <=> x[i]=0 for all i>t */
    1970              :     do
    1971              :     {
    1972      1610070 :       int skip = 0;
    1973      1610070 :       if (k > 1)
    1974              :       {
    1975      1228154 :         long l = k-1;
    1976      1228154 :         av1 = avma;
    1977      1228154 :         p1 = mulimp(gel(x,k), gcoeff(q,l,k));
    1978     14458422 :         for (j=k+1; j<N; j++) p1 = addmulimp(p1, gel(x,j), gcoeff(q,l,j));
    1979      1228154 :         gel(z,l) = gc_leaf(av1,p1);
    1980              : 
    1981      1228154 :         av1 = avma;
    1982      1228154 :         p1 = norm_aux(gel(x,k), gel(y,k), gel(z,k), gel(v,k));
    1983      1228154 :         gel(y,l) = gc_leaf(av1, p1);
    1984              :         /* skip the [x_1,...,x_skipfirst,0,...,0] */
    1985      1228154 :         if ((l <= skipfirst && !signe(gel(y,skipfirst)))
    1986      1228154 :          || mplessthan(borne1, gel(y,l))) skip = 1;
    1987              :         else /* initial value, minimizing (x[l] + z[l])^2, hence qf(x) for
    1988              :                 the given x[1..l-1] */
    1989      1214172 :           gel(x,l) = mpround( mpneg(gel(z,l)) );
    1990      1228154 :         k = l;
    1991              :       }
    1992      1228154 :       for(;; step(x,y,inc,k))
    1993              :       { /* at most 2n loops */
    1994      2838224 :         if (!skip)
    1995              :         {
    1996      2824242 :           if (check_bound(borne1, gel(x,k),gel(y,k),gel(z,k),gel(v,k))) break;
    1997      1339945 :           step(x,y,inc,k);
    1998      1339945 :           if (check_bound(borne1, gel(x,k),gel(y,k),gel(z,k),gel(v,k))) break;
    1999              :         }
    2000      1242853 :         skip = 0; inc[k] = 1;
    2001      1242853 :         if (++k > n) goto END;
    2002              :       }
    2003              : 
    2004      1595371 :       if (gc_needed(av,2))
    2005              :       {
    2006           15 :         if(DEBUGMEM>1) pari_warn(warnmem,"smallvectors");
    2007           15 :         if (stockmax) S = clonefill(S, s, stockmax);
    2008           15 :         if (check) {
    2009           15 :           GEN dummy = cgetg(1, t_STR);
    2010         9629 :           for (i=s+1; i<=stockmax; i++) gel(norms,i) = dummy;
    2011              :         }
    2012           15 :         (void)gc_all(av,7,&x,&y,&z,&normax1,&borne1,&borne2,&norms);
    2013              :       }
    2014              :     }
    2015      1595371 :     while (k > 1);
    2016       381909 :     if (!signe(gel(x,1)) && !signe(gel(y,1))) continue; /* exclude 0 */
    2017              : 
    2018       381192 :     av1 = avma;
    2019       381192 :     norme1 = norm_aux(gel(x,1),gel(y,1),gel(z,1),gel(v,1));
    2020       381192 :     if (mpgreaterthan(norme1,borne1)) { set_avma(av1); continue; /* main */ }
    2021              : 
    2022       381192 :     norme1 = gc_leaf(av1,norme1);
    2023       381192 :     if (check)
    2024              :     {
    2025       312606 :       if (checkcnt < 5 && mpcmp(norme1, borne2) < 0)
    2026              :       {
    2027         4420 :         if (!check(data,x)) { checkcnt++ ; continue; /* main */}
    2028          474 :         if (DEBUGLEVEL>4) err_printf("New bound: %Ps", norme1);
    2029          474 :         borne1 = norme1;
    2030          474 :         borne2 = mulrr(borne1, alpha);
    2031          474 :         s = 0; checkcnt = 0;
    2032              :       }
    2033              :     }
    2034              :     else
    2035              :     {
    2036        68586 :       if (!BORNE) /* find minimal vectors */
    2037              :       {
    2038         1890 :         if (mplessthan(norme1, borne1))
    2039              :         { /* strictly smaller vector than previously known */
    2040            0 :           borne1 = norme1; /* + epsilon */
    2041            0 :           s = 0;
    2042              :         }
    2043              :       }
    2044              :       else
    2045        66696 :         if (mpcmp(norme1,normax1) > 0) normax1 = norme1;
    2046              :     }
    2047       377246 :     if (++s > stockmax) continue; /* too many vectors: no longer remember */
    2048       376315 :     if (check) gel(norms,s) = norme1;
    2049       376315 :     gel(S,s) = leafcopy(x);
    2050       376315 :     if (s != stockmax) continue; /* still room, get next vector */
    2051              : 
    2052          125 :     if (check)
    2053              :     { /* overflow, eliminate vectors failing "check" */
    2054          104 :       pari_sp av2 = avma;
    2055              :       long imin, imax;
    2056          104 :       GEN per = indexsort(norms), S2 = cgetg(stockmax+1, t_VEC);
    2057          104 :       if (DEBUGLEVEL>2) err_printf("sorting... [%ld elts]\n",s);
    2058              :       /* let N be the minimal norm so far for x satisfying 'check'. Keep
    2059              :        * all elements of norm N */
    2060        24639 :       for (i = 1; i <= s; i++)
    2061              :       {
    2062        24633 :         long k = per[i];
    2063        24633 :         if (check(data,gel(S,k))) { borne1 = gel(norms,k); break; }
    2064              :       }
    2065          104 :       imin = i;
    2066        21036 :       for (; i <= s; i++)
    2067        21016 :         if (mpgreaterthan(gel(norms,per[i]), borne1)) break;
    2068          104 :       imax = i;
    2069        21036 :       for (i=imin, s=0; i < imax; i++) gel(S2,++s) = gel(S,per[i]);
    2070        21036 :       for (i = 1; i <= s; i++) gel(S,i) = gel(S2,i);
    2071          104 :       set_avma(av2);
    2072          104 :       if (s) { borne2 = mulrr(borne1, alpha); checkcnt = 0; }
    2073          104 :       if (!stockall) continue;
    2074          104 :       if (s > stockmax/2) stockmax <<= 1;
    2075          104 :       norms = cgetg(stockmax+1, t_VEC);
    2076        21036 :       for (i = 1; i <= s; i++) gel(norms,i) = borne1;
    2077              :     }
    2078              :     else
    2079              :     {
    2080           21 :       if (!stockall && BORNE) goto END;
    2081           21 :       if (!stockall) continue;
    2082           21 :       stockmax <<= 1;
    2083              :     }
    2084              : 
    2085              :     {
    2086          125 :       GEN Snew = clonefill(vec_lengthen(S,stockmax), s, stockmax);
    2087          125 :       if (isclone(S)) gunclone(S);
    2088          125 :       S = Snew;
    2089              :     }
    2090              :   }
    2091        14699 : END:
    2092        14699 :   if (s < stockmax) stockmax = s;
    2093        14699 :   if (check)
    2094              :   {
    2095              :     GEN per, alph, pols, p;
    2096        14671 :     if (DEBUGLEVEL>2) err_printf("final sort & check...\n");
    2097        14671 :     setlg(norms,stockmax+1); per = indexsort(norms);
    2098        14671 :     alph = cgetg(stockmax+1,t_VEC);
    2099        14671 :     pols = cgetg(stockmax+1,t_VEC);
    2100        84580 :     for (j=0,i=1; i<=stockmax; i++)
    2101              :     {
    2102        70171 :       long t = per[i];
    2103        70171 :       GEN N = gel(norms,t);
    2104        70171 :       if (j && mpgreaterthan(N, borne1)) break;
    2105        69909 :       if ((p = check(data,gel(S,t))))
    2106              :       {
    2107        55908 :         if (!j) borne1 = N;
    2108        55908 :         j++;
    2109        55908 :         gel(pols,j) = p;
    2110        55908 :         gel(alph,j) = gel(S,t);
    2111              :       }
    2112              :     }
    2113        14671 :     setlg(pols,j+1);
    2114        14671 :     setlg(alph,j+1);
    2115        14671 :     if (stockmax && isclone(S)) { alph = gcopy(alph); gunclone(S); }
    2116        14671 :     return mkvec2(pols, alph);
    2117              :   }
    2118           28 :   if (stockmax)
    2119              :   {
    2120           21 :     setlg(S,stockmax+1);
    2121           21 :     settyp(S,t_MAT);
    2122           21 :     if (isclone(S)) { p1 = S; S = gcopy(S); gunclone(p1); }
    2123              :   }
    2124              :   else
    2125            7 :     S = cgetg(1,t_MAT);
    2126           28 :   return mkvec3(utoi(s<<1), borne1, S);
    2127              : }
    2128              : 
    2129              : static GEN
    2130        14720 : fincke_pohst_i(GEN r, GEN u, GEN B, long stockmax, long prec, FP_chk_fun *CHECK)
    2131              : {
    2132        14720 :   VOLATILE GEN bound = B, res = NULL;
    2133        14720 :   pari_CATCH(e_PREC) { }
    2134              :   pari_TRY {
    2135              :     GEN q;
    2136        14720 :     if (CHECK && CHECK->f_init) bound = CHECK->f_init(CHECK, r, u);
    2137        14713 :     q = gaussred_from_QR(r, prec);
    2138        14713 :     if (!q) return NULL;
    2139        14713 :     res = smallvectors(q, bound, stockmax, CHECK);
    2140        14713 :   } pari_ENDCATCH;
    2141        14720 :   return res;
    2142              : }
    2143              : /* solve q(x) = x~.a.x <= bound, a > 0.
    2144              :  * If check is non-NULL keep x only if check(x).
    2145              :  * If a is a vector, assume a[1] is the LLL-reduced Cholesky form of q */
    2146              : GEN
    2147        14734 : fincke_pohst(GEN a, GEN B0, long stockmax, long PREC, FP_chk_fun *CHECK)
    2148              : {
    2149        14734 :   pari_sp av = avma;
    2150              :   long i, j, l;
    2151              :   GEN r, rinv, rinvtrans, u, v, res, z, vnorm, rperm, perm, uperm;
    2152              : 
    2153        14734 :   if (typ(a) == t_VEC)
    2154              :   {
    2155        14266 :     r = gel(a,1);
    2156        14266 :     u = NULL;
    2157              :   }
    2158              :   else
    2159              :   {
    2160          468 :     long prec = PREC;
    2161          468 :     l = lg(a);
    2162          468 :     if (l == 1)
    2163              :     {
    2164            7 :       if (CHECK) pari_err_TYPE("fincke_pohst [dimension 0]", a);
    2165            7 :       retmkvec3(gen_0, gen_0, cgetg(1,t_MAT));
    2166              :     }
    2167          461 :     u = lllfp(a, 0.75, LLL_GRAM | LLL_IM);
    2168          454 :     if (!u || lg(u) != lg(a)) return gc_NULL(av);
    2169          454 :     r = qf_RgM_apply(a,u);
    2170          454 :     i = gprecision(r);
    2171          454 :     if (i)
    2172          412 :       prec = i;
    2173              :     else {
    2174           42 :       prec = DEFAULTPREC + nbits2extraprec(gexpo(r));
    2175           42 :       if (prec < PREC) prec = PREC;
    2176              :     }
    2177          454 :     if (DEBUGLEVEL>2) err_printf("first LLL: prec = %ld\n", prec);
    2178          454 :     r = qfgaussred_positive(r);
    2179          454 :     if (!r) return gc_NULL(av);
    2180         1984 :     for (i=1; i<l; i++)
    2181              :     {
    2182         1530 :       GEN s = gsqrt(gcoeff(r,i,i), prec);
    2183         1530 :       gcoeff(r,i,i) = s;
    2184         4236 :       for (j=i+1; j<l; j++) gcoeff(r,i,j) = gmul(s, gcoeff(r,i,j));
    2185              :     }
    2186              :   }
    2187              :   /* now r~ * r = a in LLL basis */
    2188        14720 :   rinv = RgM_inv_upper(r);
    2189        14720 :   if (!rinv) return gc_NULL(av);
    2190        14720 :   rinvtrans = shallowtrans(rinv);
    2191        14720 :   if (DEBUGLEVEL>2)
    2192            0 :     err_printf("Fincke-Pohst, final LLL: prec = %ld\n", gprecision(rinvtrans));
    2193        14720 :   v = lll(rinvtrans);
    2194        14720 :   if (lg(v) != lg(rinvtrans)) return gc_NULL(av);
    2195              : 
    2196        14720 :   rinvtrans = RgM_mul(rinvtrans, v);
    2197        14720 :   v = ZM_inv(shallowtrans(v),NULL);
    2198        14720 :   r = RgM_mul(r,v);
    2199        14720 :   u = u? ZM_mul(u,v): v;
    2200              : 
    2201        14720 :   l = lg(r);
    2202        14720 :   vnorm = cgetg(l,t_VEC);
    2203        97842 :   for (j=1; j<l; j++) gel(vnorm,j) = gnorml2(gel(rinvtrans,j));
    2204        14720 :   rperm = cgetg(l,t_MAT);
    2205        14720 :   uperm = cgetg(l,t_MAT); perm = indexsort(vnorm);
    2206        97842 :   for (i=1; i<l; i++) { uperm[l-i] = u[perm[i]]; rperm[l-i] = r[perm[i]]; }
    2207        14720 :   res = fincke_pohst_i(rperm, uperm, B0, stockmax, gprecision(vnorm), CHECK);
    2208        14720 :   if (!res) return gc_NULL(av);
    2209        14713 :   if (CHECK)
    2210              :   {
    2211        14671 :     if (CHECK->f_post) res = CHECK->f_post(CHECK, res, u);
    2212        14671 :     return res;
    2213              :   }
    2214           42 :   z = cgetg(4,t_VEC);
    2215           42 :   gel(z,1) = gcopy(gel(res,1));
    2216           42 :   gel(z,2) = gcopy(gel(res,2));
    2217           42 :   gel(z,3) = ZM_mul(uperm, gel(res,3)); return gc_upto(av,z);
    2218              : }
        

Generated by: LCOV version 2.0-1