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 - lll.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 81.3 % 1643 1335
Test Date: 2026-07-23 17:04:59 Functions: 96.2 % 131 126
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2008  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : #include "pari.h"
      16              : #include "paripriv.h"
      17              : 
      18              : #define DEBUGLEVEL DEBUGLEVEL_qflll
      19              : 
      20              : static int
      21        45828 : RgM_is_square_mat(GEN x) { long l = lg(x); return l == 1 || l == lgcols(x); }
      22              : 
      23              : static long
      24      4239602 : ZM_is_upper(GEN R)
      25              : {
      26      4239602 :   long i,j, l = lg(R);
      27      4239602 :   if (l != lgcols(R)) return 0;
      28      8195848 :   for(i = 1; i < l; i++)
      29      8904191 :     for(j = 1; j < i; j++)
      30      4598602 :       if (signe(gcoeff(R,i,j))) return 0;
      31       265369 :   return 1;
      32              : }
      33              : 
      34              : static long
      35       607647 : ZM_is_knapsack(GEN R)
      36              : {
      37       607647 :   long i,j, l = lg(R);
      38       607647 :   if (l != lgcols(R)) return 0;
      39       846800 :   for(i = 2; i < l; i++)
      40      2921816 :     for(j = 1; j < l; j++)
      41      2682663 :       if ( i!=j && signe(gcoeff(R,i,j))) return 0;
      42        92851 :   return 1;
      43              : }
      44              : 
      45              : static long
      46      1205580 : ZM_is_lower(GEN R)
      47              : {
      48      1205580 :   long i,j, l = lg(R);
      49      1205580 :   if (l != lgcols(R)) return 0;
      50      2090535 :   for(i = 1; i < l; i++)
      51      2417231 :     for(j = 1; j < i; j++)
      52      1309257 :       if (signe(gcoeff(R,j,i))) return 0;
      53        34939 :   return 1;
      54              : }
      55              : 
      56              : static GEN
      57        34939 : RgM_flip(GEN R)
      58              : {
      59              :   GEN M;
      60              :   long i,j,l;
      61        34939 :   M = cgetg_copy(R, &l);
      62       181714 :   for(i = 1; i < l; i++)
      63              :   {
      64       146775 :     gel(M,i) = cgetg(l, t_COL);
      65       915372 :     for(j = 1; j < l; j++)
      66       768597 :       gmael(M,i,j) = gmael(R,l-i, l-j);
      67              :   }
      68        34939 :   return M;
      69              : }
      70              : 
      71              : static GEN
      72            0 : RgM_flop(GEN R)
      73              : {
      74              :   GEN M;
      75              :   long i,j,l;
      76            0 :   M = cgetg_copy(R, &l);
      77            0 :   for(i = 1; i < l; i++)
      78              :   {
      79            0 :     gel(M,i) = cgetg(l, t_COL);
      80            0 :     for(j = 1; j < l; j++)
      81            0 :       gmael(M,i,j) = gmael(R,i, l-j);
      82              :   }
      83            0 :   return M;
      84              : }
      85              : 
      86              : /* Assume x and y has same type! */
      87              : INLINE int
      88      4109269 : mpabscmp(GEN x, GEN y)
      89              : {
      90      4109269 :   return (typ(x)==t_INT) ? abscmpii(x,y) : abscmprr(x,y);
      91              : }
      92              : 
      93              : /****************************************************************************/
      94              : /***                             FLATTER                                  ***/
      95              : /****************************************************************************/
      96              : /* Implementation of "FLATTER" algorithm based on
      97              :  * <https://eprint.iacr.org/2023/237>
      98              :  * Fast Practical Lattice Reduction through Iterated Compression
      99              :  *
     100              :  * Keegan Ryan, University of California, San Diego
     101              :  * Nadia Heninger, University of California, San Diego. BA20230925 */
     102              : static long
     103      1347830 : drop(GEN R)
     104              : {
     105      1347830 :   long i, n = lg(R)-1;
     106      1347830 :   long s = 0, m = mpexpo(gcoeff(R, 1, 1));
     107      5457099 :   for (i = 2; i <= n; ++i)
     108              :   {
     109      4109269 :     if (mpabscmp(gcoeff(R, i, i), gcoeff(R, i - 1, i - 1)) >= 0)
     110              :     {
     111      2786538 :       s += m - mpexpo(gcoeff(R, i - 1, i - 1));
     112      2786538 :       m = mpexpo(gcoeff(R, i, i));
     113              :     }
     114              :   }
     115      1347830 :   s += m - mpexpo(gcoeff(R, n, n));
     116      1347830 :   return s;
     117              : }
     118              : 
     119              : static long
     120      1347830 : potential(GEN R)
     121              : {
     122      1347830 :   long i, n = lg(R)-1;
     123      1347830 :   long s = 0, mul = n-1;;
     124      6804929 :   for (i = 1; i <= n; i++, mul-=2) s += mul * mpexpo(gcoeff(R,i,i));
     125      1347830 :   return s;
     126              : }
     127              : 
     128              : /* U upper-triangular invertible:
     129              :  * Bound on the exponent of the condition number of U.
     130              :  * Algo 8.13 in Higham, Accuracy and stability of numercal algorithms. */
     131              : static long
     132      4729266 : condition_bound(GEN U, int lower)
     133              : {
     134      4729266 :   long n = lg(U)-1, e, i, j;
     135              :   GEN y;
     136      4729266 :   pari_sp av = avma;
     137      4729266 :   y = cgetg(n+1, t_VECSMALL);
     138      4729266 :   e = y[n] = -gexpo(gcoeff(U,n,n));
     139     18837933 :   for (i=n-1; i>0; i--)
     140              :   {
     141     14108667 :     long s = 0;
     142     50973211 :     for (j=i+1; j<=n; j++)
     143     36864544 :       s = maxss(s, (lower? gexpo(gcoeff(U,j,i)): gexpo(gcoeff(U,i,j))) + y[j]);
     144     14108667 :     y[i] = s - gexpo(gcoeff(U,i,i));
     145     14108667 :     e = maxss(e, y[i]);
     146              :   }
     147      4729266 :   return gc_long(av, gexpo(U) + e);
     148              : }
     149              : 
     150              : INLINE long
     151      7496565 : nbits2prec64(long n)
     152              : {
     153      7496565 :   return nbits2prec(((n+63)>>6)<<6);
     154              : }
     155              : 
     156              : static long
     157      5856032 : spread(GEN R)
     158              : {
     159      5856032 :   long i, n = lg(R)-1, m = mpexpo(gcoeff(R, 1, 1)), M = m;
     160     23621604 :   for (i = 2; i <= n; ++i)
     161              :   {
     162     17765572 :     long e = mpexpo(gcoeff(R, i, i));
     163     17765572 :     if (e < m) m = e;
     164     17765572 :     if (e > M) M = e;
     165              :   }
     166      5856032 :   return M - m;
     167              : }
     168              : 
     169              : static long
     170      4729266 : GS_extraprec(GEN L, int lower)
     171              : {
     172      4729266 :   long C = condition_bound(L, lower), S = spread(L), n = lg(L)-1;
     173      4729266 :   return maxss(2*S+2*n, C-S-2*n); /* = 2*S + 2*n + maxss(0, C-3*S-4*n) */
     174              : }
     175              : 
     176              : static GEN
     177         2988 : RgM_Cholesky_dynprec(GEN M)
     178              : {
     179         2988 :   pari_sp ltop = avma;
     180              :   GEN L;
     181         2988 :   long minprec = lg(M) + 30, bitprec = minprec, prec;
     182              :   while (1)
     183         4919 :   {
     184              :     long mbitprec;
     185         7907 :     prec = nbits2prec64(bitprec);
     186         7907 :     L = RgM_Cholesky(RgM_gtofp(M, prec), prec); /* upper-triangular */
     187         7907 :     if (!L)
     188              :     {
     189         1486 :       bitprec *= 2;
     190         1486 :       set_avma(ltop);
     191         1486 :       continue;
     192              :     }
     193         6421 :     mbitprec = minprec + GS_extraprec(L, 0);
     194         6421 :     if (bitprec >= mbitprec)
     195         2988 :       break;
     196         3433 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     197         3433 :     set_avma(ltop);
     198              :   }
     199         2988 :   return gc_GEN(ltop, L);
     200              : }
     201              : 
     202              : static GEN
     203         1402 : gramschmidt_upper(GEN M)
     204              : {
     205         1402 :   long bitprec = lg(M)-1 + 31 + GS_extraprec(M, 0);
     206         1402 :   return RgM_gtofp(M, nbits2prec64(bitprec));
     207              : }
     208              : 
     209              : static GEN
     210      2695660 : gramschmidt_dynprec(GEN M)
     211              : {
     212      2695660 :   pari_sp ltop = avma;
     213      2695660 :   long minprec = lg(M) + 30, bitprec = minprec;
     214      2695660 :   if (ZM_is_upper(M)) return gramschmidt_upper(M);
     215              :   while (1)
     216      3648789 :   {
     217              :     GEN B, Q, L;
     218      6343047 :     long prec = nbits2prec64(bitprec), mbitprec;
     219      6343047 :     if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec))
     220              :     {
     221      1621604 :       bitprec *= 2;
     222      1621604 :       set_avma(ltop);
     223      1621604 :       continue;
     224              :     }
     225      4721443 :     mbitprec = minprec + GS_extraprec(L, 1);
     226      4721443 :     if (bitprec >= mbitprec)
     227      2694258 :       return gc_GEN(ltop, shallowtrans(L));
     228      2027185 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     229      2027185 :     set_avma(ltop);
     230              :   }
     231              : }
     232              : /* return -T1 * round(T1^-1*(R1^-1*R2)*T3) */
     233              : static GEN
     234      1347830 : sizered(GEN T1, GEN T3, GEN R1, GEN R2)
     235              : {
     236      1347830 :   pari_sp ltop = avma;
     237              :   long e;
     238      1347830 :   return gc_upto(ltop, ZM_mul(ZM_neg(T1), grndtoi(gmul(ZM_inv(T1,NULL),
     239              :          RgM_mul(RgM_mul(RgM_inv_upper(R1), R2), T3)), &e)));
     240              : }
     241              : 
     242              : static GEN
     243      1347830 : flat(GEN M, long flag, GEN *pt_T, long *pt_s, long *pt_pot)
     244              : {
     245      1347830 :   pari_sp ltop = avma;
     246              :   GEN R, R1, R2, R3, T1, T2, T3, T, S;
     247      1347830 :   long k = lg(M)-1, n = k>>1, n2 = k - n, m = n>>1;
     248      1347830 :   long keepfirst = flag & LLL_KEEP_FIRST, inplace = flag & LLL_INPLACE;
     249              :   /* for k = 3, we want n = 1; n2  = 2; m = 0 */
     250              :   /* for k = 5,         n = 2; n2 = 3; m = 1 */
     251      1347830 :   R = gramschmidt_dynprec(M);
     252      1347830 :   R1 = matslice(R, 1, n, 1, n);
     253      1347830 :   R2 = matslice(R, 1, n, n + 1, k);
     254      1347830 :   R3 = matslice(R, n + 1, k, n + 1, k);
     255      1347830 :   T1 = lllfp(R1, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY| (keepfirst ? LLL_KEEP_FIRST: 0));
     256      1347830 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     257      1347830 :   T2 = sizered(T1, T3, R1, R2);
     258      1347830 :   T = shallowmatconcat(mkmat22(T1,T2,gen_0,T3));
     259      1347830 :   M = ZM_mul(M, T);
     260      1347830 :   R = gramschmidt_dynprec(M);
     261      1347830 :   R3 = matslice(R, m + 1, m + n2, m + 1, m + n2);
     262      1347830 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     263      2695660 :   S = shallowmatconcat(diagonal(
     264       577280 :        m == 0     ? mkvec2(T3, matid(k - m - n2))
     265            0 :      : m+n2 == k  ? mkvec2(matid(m), T3)
     266       770550 :                   : mkvec3(matid(m), T3, matid(k - m - n2))));
     267      1347830 :   M = ZM_mul(M, S);
     268      1347830 :   if (!inplace) *pt_T = ZM_mul(T, S);
     269      1347830 :   *pt_s = drop(R);
     270      1347830 :   *pt_pot = potential(R);
     271      1347830 :   return gc_all(ltop, inplace ? 1: 2, &M, pt_T);
     272              : }
     273              : 
     274              : static void
     275            0 : dbg_flatter(pari_timer *ti, long n, long i, long lti, double t, double pot2)
     276              : {
     277            0 :   double s = t / n, p = pot2 / (n*(n+1));
     278              :   const char *str;
     279            0 :   if (i == -1)
     280            0 :     str = (i == lti)? "final"
     281            0 :                     : stack_sprintf("steps %ld-final", lti);
     282              :   else
     283            0 :     str = (i == lti)? stack_sprintf("step %ld", i)
     284            0 :                     : stack_sprintf("steps %ld-%ld", lti, i);
     285            0 :   timer_printf(ti, "FLATTER, dim %ld, %s: \t slope=%0.10g \t pot=%0.10g",
     286              :                n, str, s, p);
     287            0 : }
     288              : 
     289              : static GEN
     290       627269 : ZM_flatter(GEN M, long flag)
     291              : {
     292       627269 :   pari_sp av = avma;
     293       627269 :   long i, n = lg(M)-1, s = -1, lti = 1, pot = LONG_MAX;
     294       627269 :   GEN T = NULL;
     295              :   pari_timer ti;
     296       627269 :   long inplace = flag & LLL_INPLACE, cert = !(flag & LLL_NOCERTIFY);
     297              : 
     298       627269 :   if (DEBUGLEVEL>=3)
     299              :   {
     300            0 :     timer_start(&ti);
     301            0 :     if (cert) err_printf("FLATTER dim = %ld size = %ld\n", n, ZM_max_expi(M));
     302              :   }
     303       627269 :   for (i = 1;;i++)
     304       720561 :   {
     305              :     long t, pot2;
     306      1347830 :     GEN U, M2 = flat(M, flag, &U, &t, &pot2);
     307      1347830 :     if (t == 0) { s = t; break; }
     308       764393 :     if (s >= 0)
     309              :     {
     310       437815 :       if (s == t && pot>=pot2) break;
     311       393983 :       if (s < t && i > 20)
     312              :       {
     313            0 :         if (DEBUGLEVEL >= 3) err_printf("BACK:%ld:%ld:%g\n", n, i, s);
     314            0 :         break;
     315              :       }
     316              :     }
     317       720561 :     if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     318            0 :       dbg_flatter(&ti, n, i, lti, t, pot2);
     319       720561 :     s = t;
     320       720561 :     pot = pot2;
     321       720561 :     M = M2;
     322       720561 :     if (!inplace)
     323              :     {
     324       692877 :       T = T? ZM_mul(T, U): U;
     325       692877 :       if (gc_needed(av, 1)) (void)gc_all(av, 2, &M, &T);
     326              :     }
     327              :     else
     328        27684 :       if (gc_needed(av, 1)) M = gc_GEN(av, M);
     329              :   }
     330       627269 :   if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     331            0 :     dbg_flatter(&ti, n, -1, i == lti? -1: lti, s, pot);
     332       627269 :   if (!inplace)
     333              :   {
     334       613254 :     if (!T) return gc_NULL(av);
     335       312731 :     return gc_GEN(av, T);
     336              :   }
     337        14015 :   return  gc_GEN(av, M);
     338              : }
     339              : 
     340              : static GEN
     341       625255 : ZM_flatter_rank(GEN M, long rank, long flag)
     342              : {
     343              :   pari_timer ti;
     344       625255 :   pari_sp av = avma;
     345       625255 :   GEN T = NULL;
     346       625255 :   long i, n = lg(M)-1, sm = LONG_MAX;
     347       625255 :   long inplace = flag & LLL_INPLACE;
     348              : 
     349       625255 :   if (rank == n) return ZM_flatter(M, flag);
     350         3785 :   if (DEBUGLEVEL>=3) timer_start(&ti);
     351         3785 :   for (i = 1;; i++)
     352         2014 :   {
     353         5799 :     GEN S = ZM_flatter(vconcat(gshift(M,i),matid(n)), flag);
     354              :     long s;
     355         5799 :     if (!S || (s = expi(gnorml2(S))) >= sm) break;
     356         2014 :     sm = s;
     357         2014 :     if (DEBUGLEVEL>=3) timer_printf(&ti,"FLATTERRANK step %ld: %ld",i,sm);
     358         2014 :     T = T? ZM_mul(T, S): S;
     359         2014 :     M = ZM_mul(M, S);
     360         2014 :     if (gc_needed(av, 1)) (void)gc_all(av, 2, &M, &T);
     361              :   }
     362         3785 :   if (!inplace)
     363              :   {
     364         3778 :     if (!T) { set_avma(av); return matid(n); }
     365         1951 :     return gc_GEN(av, T);
     366              :   }
     367            7 :   return  gc_GEN(av, M);
     368              : }
     369              : 
     370              : static GEN
     371         2988 : flattergram_i(GEN M, long flag)
     372              : {
     373         2988 :   pari_sp av = avma;
     374         2988 :   GEN T, R = RgM_Cholesky_dynprec(M);
     375         2988 :   T = lllfp(R, 0.99, LLL_IM|LLL_UPPER|LLL_NOCERTIFY | (flag&LLL_KEEP_FIRST));
     376         2988 :   return gc_upto(av, T);
     377              : }
     378              : 
     379              : static void
     380            0 : dbg_flattergram(pari_timer *t, long n, long i, long s)
     381            0 : { timer_printf(t, "FLATTERGRAM, dim %ld step %ld, slope=%0.10g", n, i,
     382            0 :                ((double)s)/n); }
     383              : /* return base change, NULL if identity */
     384              : static GEN
     385          968 : ZM_flattergram(GEN M, long flag)
     386              : {
     387          968 :   pari_sp av = avma;
     388          968 :   GEN T = NULL;
     389          968 :   long i, n = lg(M)-1, s = -1;
     390              : 
     391              :   pari_timer ti;
     392          968 :   if (DEBUGLEVEL>=3)
     393              :   {
     394            0 :     timer_start(&ti);
     395            0 :     err_printf("FLATTERGRAM dim = %ld size = %ld\n", n, ZM_max_expi(M));
     396              :   }
     397          968 :   for (i = 1;; i++)
     398         2020 :   {
     399         2988 :     GEN S = flattergram_i(M, flag);
     400         2988 :     long t = expi(gnorml2(S));
     401         2988 :     if (t == 0) { s = t;  break; }
     402         2988 :     if (s)
     403              :     {
     404         2988 :       double st = s - t;
     405         2988 :       if (st == 0) break;
     406         2020 :       if (st < 0 && i > 20)
     407              :       {
     408            0 :         if (DEBUGLEVEL >= 3)
     409            0 :           err_printf("BACK:%ld:%ld:%0.10g\n", n, i, ((double)s)/n);
     410            0 :         break;
     411              :       }
     412              :     }
     413         2020 :     T = T? ZM_mul(T, S): S;
     414         2020 :     M = qf_ZM_apply(M, S);
     415         2020 :     s = t;
     416         2020 :     if (DEBUGLEVEL >= 3) dbg_flattergram(&ti, n, i, s);
     417         2020 :     if (gc_needed(av, 1)) (void)gc_all(av, 2, &M, &T);
     418              :   }
     419          968 :   if (DEBUGLEVEL >= 3) dbg_flattergram(&ti, n, i, s);
     420          968 :   if (!T && ZM_isidentity(T)) return gc_NULL(av);
     421          968 :   return gc_GEN(av, T);
     422              : }
     423              : 
     424              : /* return base change, NULL if identity */
     425              : static GEN
     426          968 : ZM_flattergram_rank(GEN M, long rank, long flag)
     427              : {
     428              :   pari_timer ti;
     429          968 :   pari_sp av = avma;
     430          968 :   GEN T = NULL;
     431          968 :   long i, n = lg(M)-1;
     432          968 :   if (rank == n) return ZM_flattergram(M, flag);
     433            0 :   if (DEBUGLEVEL>=3) timer_start(&ti);
     434            0 :   for (i = 1;; i++)
     435            0 :   {
     436            0 :     GEN S = ZM_flattergram(RgM_Rg_add(gshift(M, i), gen_1), flag);
     437            0 :     if (DEBUGLEVEL>=3)
     438            0 :       timer_printf(&ti,"FLATTERGRAMRANK step %ld: %ld",i,expi(gnorml2(S)));
     439            0 :     if (!S) break;
     440            0 :     T = T? ZM_mul(T, S): S;
     441            0 :     M = qf_ZM_apply(M, S);
     442            0 :     if (gc_needed(av, 1)) (void)gc_all(av, 2, &M, &T);
     443              :   }
     444            0 :   if (!T || ZM_isidentity(T)) return gc_NULL(av);
     445            0 :   return gc_GEN(av, T);
     446              : }
     447              : 
     448              : /* round to closest integer (as a double). If |a| >= 2^52, return it */
     449              : static double
     450     11638556 : pari_rint(double a)
     451              : {
     452              : #ifdef HAS_RINT
     453     11638556 :   return rint(a);
     454              : #else
     455              :   const double pow2 = 4.5035996273704960e+15; /* 2^52 */
     456              :   double r, fa = fabs(a);
     457              :   if (fa >= pow2) return a;
     458              :   r = (pow2 + fa) - pow2;
     459              :   if (a < 0) r = -r;
     460              :   return r;
     461              : #endif
     462              : }
     463              : 
     464              : /* default quality ratio for LLL */
     465              : static const double LLLDFT = 0.99;
     466              : 
     467              : /* assume flag & (LLL_KER|LLL_IM|LLL_ALL). LLL_INPLACE implies LLL_IM */
     468              : static GEN
     469       771847 : lll_trivial(GEN x, long flag)
     470              : {
     471       771847 :   if (lg(x) == 1)
     472              :   { /* dim x = 0 */
     473        15484 :     if (! (flag & LLL_ALL)) return cgetg(1,t_MAT);
     474           28 :     retmkvec2(cgetg(1,t_MAT), cgetg(1,t_MAT));
     475              :   }
     476              :   /* dim x = 1 */
     477       756363 :   if (gequal0(gel(x,1)))
     478              :   {
     479          153 :     if (flag & LLL_KER) return matid(1);
     480          153 :     if (flag & (LLL_IM|LLL_INPLACE)) return cgetg(1,t_MAT);
     481           28 :     retmkvec2(matid(1), cgetg(1,t_MAT));
     482              :   }
     483       756210 :   if (flag & LLL_INPLACE) return gcopy(x);
     484       652526 :   if (flag & LLL_KER) return cgetg(1,t_MAT);
     485       652526 :   if (flag & LLL_IM)  return matid(1);
     486           28 :   retmkvec2(cgetg(1,t_MAT), (flag & LLL_GRAM)? gcopy(x): matid(1));
     487              : }
     488              : 
     489              : /* vecslice(x,#x-k,#x) in place. Works for t_MAT, t_VEC/t_COL */
     490              : static GEN
     491      2093562 : vectail_inplace(GEN x, long k)
     492              : {
     493      2093562 :   if (!k) return x;
     494        58091 :   x[k] = ((ulong)x[0] & ~LGBITS) | _evallg(lg(x) - k);
     495        58091 :   return x + k;
     496              : }
     497              : 
     498              : /* k = dim Kernel */
     499              : static GEN
     500      2168181 : lll_finish(GEN h, long k, long flag)
     501              : {
     502              :   GEN g;
     503      2168181 :   if (!(flag & (LLL_IM|LLL_KER|LLL_ALL|LLL_INPLACE))) return h;
     504      2093576 :   if (flag & (LLL_IM|LLL_INPLACE)) return vectail_inplace(h, k);
     505           84 :   if (flag & LLL_KER) { setlg(h,k+1); return h; }
     506           70 :   g = vecslice(h,1,k); /* done first: vectail_inplace kills h */
     507           70 :   return mkvec2(g, vectail_inplace(h, k));
     508              : }
     509              : 
     510              : /* y * z * 2^e, e >= 0; y,z t_INT */
     511              : INLINE GEN
     512       933199 : mulshift(GEN y, GEN z, long e)
     513              : {
     514       933199 :   long ly = lgefint(y), lz;
     515              :   pari_sp av;
     516              :   GEN t;
     517       933199 :   if (ly == 2) return gen_0;
     518       451238 :   lz = lgefint(z);
     519       451238 :   av = avma; (void)new_chunk(ly+lz+nbits2lg(e)); /* HACK */
     520       451238 :   t = mulii(z, y);
     521       451238 :   set_avma(av); return shifti(t, e);
     522              : }
     523              : 
     524              : /* x - y * z * 2^e, e >= 0; x,y,z t_INT */
     525              : INLINE GEN
     526      2066712 : submulshift(GEN x, GEN y, GEN z, long e)
     527              : {
     528      2066712 :   long lx = lgefint(x), ly, lz;
     529              :   pari_sp av;
     530              :   GEN t;
     531      2066712 :   if (!e) return submulii(x, y, z);
     532      2044449 :   if (lx == 2) { t = mulshift(y, z, e); togglesign(t); return t; }
     533      1531367 :   ly = lgefint(y);
     534      1531367 :   if (ly == 2) return icopy(x);
     535      1087264 :   lz = lgefint(z);
     536      1087264 :   av = avma; (void)new_chunk(lx+ly+lz+nbits2lg(e)); /* HACK */
     537      1087264 :   t = shifti(mulii(z, y), e);
     538      1087264 :   set_avma(av); return subii(x, t);
     539              : }
     540              : static void
     541     32809395 : subzi(GEN *a, GEN b)
     542              : {
     543     32809395 :   pari_sp av = avma;
     544     32809395 :   b = subii(*a, b);
     545     32809395 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     546      2428064 :   else *a = b;
     547     32809395 : }
     548              : 
     549              : static void
     550     32045830 : addzi(GEN *a, GEN b)
     551              : {
     552     32045830 :   pari_sp av = avma;
     553     32045830 :   b = addii(*a, b);
     554     32045830 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     555      2210453 :   else *a = b;
     556     32045830 : }
     557              : 
     558              : /* x - u*y * 2^e */
     559              : INLINE GEN
     560      4718260 : submuliu2n(GEN x, GEN y, ulong u, long e)
     561              : {
     562              :   pari_sp av;
     563      4718260 :   long ly = lgefint(y);
     564      4718260 :   if (ly == 2) return x;
     565      3295146 :   av = avma;
     566      3295146 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     567      3295146 :   y = shifti(mului(u,y), e);
     568      3295146 :   set_avma(av); return subii(x, y);
     569              : }
     570              : /* *x -= u*y * 2^e */
     571              : INLINE void
     572     16768355 : submulzu2n(GEN *x, GEN y, ulong u, long e)
     573              : {
     574              :   pari_sp av;
     575     16768355 :   long ly = lgefint(y);
     576     16768355 :   if (ly == 2) return;
     577      5792793 :   av = avma;
     578      5792793 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     579      5792793 :   y = shifti(mului(u,y), e);
     580      5792793 :   set_avma(av); return subzi(x, y);
     581              : }
     582              : 
     583              : /* x + u*y * 2^e */
     584              : INLINE GEN
     585      4642157 : addmuliu2n(GEN x, GEN y, ulong u, long e)
     586              : {
     587              :   pari_sp av;
     588      4642157 :   long ly = lgefint(y);
     589      4642157 :   if (ly == 2) return x;
     590      3254382 :   av = avma;
     591      3254382 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     592      3254382 :   y = shifti(mului(u,y), e);
     593      3254382 :   set_avma(av); return addii(x, y);
     594              : }
     595              : 
     596              : /* *x += u*y * 2^e */
     597              : INLINE void
     598     16967395 : addmulzu2n(GEN *x, GEN y, ulong u, long e)
     599              : {
     600              :   pari_sp av;
     601     16967395 :   long ly = lgefint(y);
     602     16967395 :   if (ly == 2) return;
     603      5823150 :   av = avma;
     604      5823150 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     605      5823150 :   y = shifti(mului(u,y), e);
     606      5823150 :   set_avma(av); return addzi(x, y);
     607              : }
     608              : 
     609              : /* n < 10; (void)gc_all supporting &NULL arguments. Maybe rename and export ? */
     610              : INLINE void
     611         5446 : gc_lll(pari_sp av, int n, ...)
     612              : {
     613              :   int i, j;
     614              :   GEN *gptr[10];
     615              :   size_t s;
     616         5446 :   va_list a; va_start(a, n);
     617        16338 :   for (i=j=0; i<n; i++)
     618              :   {
     619        10892 :     GEN *x = va_arg(a,GEN*);
     620        10892 :     if (*x) { gptr[j++] = x; *x = (GEN)copy_bin(*x); }
     621              :   }
     622         5446 :   va_end(a); set_avma(av);
     623        13434 :   for (--j; j>=0; j--) *gptr[j] = bin_copy((GENbin*)*gptr[j]);
     624         5446 :   s = pari_mainstack->top - pari_mainstack->bot;
     625              :   /* size of saved objects ~ stacksize / 4 => overflow */
     626         5446 :   if (av - avma > (s >> 2))
     627              :   {
     628            0 :     size_t t = avma - pari_mainstack->bot;
     629            0 :     av = avma; new_chunk((s + t) / sizeof(long)); set_avma(av); /* double */
     630              :   }
     631         5446 : }
     632              : 
     633              : /********************************************************************/
     634              : /**                                                                **/
     635              : /**                   FPLLL (adapted from D. Stehle's code)        **/
     636              : /**                                                                **/
     637              : /********************************************************************/
     638              : /* Babai* and fplll* are a conversion to libpari API and data types
     639              :    of fplll-1.3 by Damien Stehle'.
     640              : 
     641              :   Copyright 2005, 2006 Damien Stehle'.
     642              : 
     643              :   This program is free software; you can redistribute it and/or modify it
     644              :   under the terms of the GNU General Public License as published by the
     645              :   Free Software Foundation; either version 2 of the License, or (at your
     646              :   option) any later version.
     647              : 
     648              :   This program implements ideas from the paper "Floating-point LLL Revisited",
     649              :   by Phong Nguyen and Damien Stehle', in the Proceedings of Eurocrypt'2005,
     650              :   Springer-Verlag; and was partly inspired by Shoup's NTL library:
     651              :   http://www.shoup.net/ntl/ */
     652              : 
     653              : /* x t_REAL, |x| >= 1/2. Test whether |x| <= 3/2 */
     654              : static int
     655       441842 : absrsmall2(GEN x)
     656              : {
     657       441842 :   long e = expo(x), l, i;
     658       441842 :   if (e < 0) return 1;
     659       230428 :   if (e > 0 || (ulong)x[2] > (3UL << (BITS_IN_LONG-2))) return 0;
     660              :   /* line above assumes l > 2. OK since x != 0 */
     661        79759 :   l = lg(x); for (i = 3; i < l; i++) if (x[i]) return 0;
     662        68298 :   return 1;
     663              : }
     664              : /* x t_REAL; test whether |x| <= 1/2 */
     665              : static int
     666       761350 : absrsmall(GEN x)
     667              : {
     668              :   long e, l, i;
     669       761350 :   if (!signe(x)) return 1;
     670       755309 :   e = expo(x); if (e < -1) return 1;
     671       448148 :   if (e > -1 || (ulong)x[2] > HIGHBIT) return 0;
     672         7148 :   l = lg(x); for (i = 3; i < l; i++) if (x[i]) return 0;
     673         6306 :   return 1;
     674              : }
     675              : 
     676              : static void
     677     33251056 : rotate(GEN A, long k2, long k)
     678              : {
     679              :   long i;
     680     33251056 :   GEN B = gel(A,k2);
     681    107837833 :   for (i = k2; i > k; i--) gel(A,i) = gel(A,i-1);
     682     33251056 :   gel(A,k) = B;
     683     33251056 : }
     684              : 
     685              : /************************* FAST version (double) ************************/
     686              : #define dmael(x,i,j) ((x)[i][j])
     687              : #define del(x,i) ((x)[i])
     688              : 
     689              : static double *
     690     35109252 : cget_dblvec(long d)
     691     35109252 : { return (double*) stack_malloc_align(d*sizeof(double), sizeof(double)); }
     692              : 
     693              : static double **
     694      8430168 : cget_dblmat(long d) { return (double **) cgetg(d, t_VECSMALL); }
     695              : 
     696              : static double
     697    176918914 : itodbl_exp(GEN x, long *e)
     698              : {
     699    176918914 :   pari_sp av = avma;
     700    176918914 :   GEN r = itor(x,DEFAULTPREC);
     701    176918914 :   *e = expo(r); setexpo(r,0);
     702    176918914 :   return gc_double(av, rtodbl(r));
     703              : }
     704              : 
     705              : static double
     706    129123782 : dbldotproduct(double *x, double *y, long n)
     707              : {
     708              :   long i;
     709    129123782 :   double sum = del(x,1) * del(y,1);
     710   1669744547 :   for (i=2; i<=n; i++) sum += del(x,i) * del(y,i);
     711    129123782 :   return sum;
     712              : }
     713              : 
     714              : static double
     715      2485309 : dbldotsquare(double *x, long n)
     716              : {
     717              :   long i;
     718      2485309 :   double sum = del(x,1) * del(x,1);
     719      8250669 :   for (i=2; i<=n; i++) sum += del(x,i) * del(x,i);
     720      2485309 :   return sum;
     721              : }
     722              : 
     723              : static long
     724     25542035 : set_line(double *appv, GEN v, long n)
     725              : {
     726     25542035 :   long i, maxexp = 0;
     727     25542035 :   pari_sp av = avma;
     728     25542035 :   GEN e = cgetg(n+1, t_VECSMALL);
     729    202460949 :   for (i = 1; i <= n; i++)
     730              :   {
     731    176918914 :     del(appv,i) = itodbl_exp(gel(v,i), e+i);
     732    176918914 :     if (e[i] > maxexp) maxexp = e[i];
     733              :   }
     734    202460949 :   for (i = 1; i <= n; i++) del(appv,i) = ldexp(del(appv,i), e[i]-maxexp);
     735     25542035 :   set_avma(av); return maxexp;
     736              : }
     737              : 
     738              : static void
     739     35873628 : dblrotate(double **A, long k2, long k)
     740              : {
     741              :   long i;
     742     35873628 :   double *B = del(A,k2);
     743    115196946 :   for (i = k2; i > k; i--) del(A,i) = del(A,i-1);
     744     35873628 :   del(A,k) = B;
     745     35873628 : }
     746              : /* update G[kappa][i] from appB */
     747              : static void
     748     23262321 : setG_fast(double **appB, long n, double **G, long kappa, long a, long b)
     749              : { long i;
     750    109153677 :   for (i = a; i <= b; i++)
     751     85891356 :     dmael(G,kappa,i) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     752     23262321 : }
     753              : /* update G[i][kappa] from appB */
     754              : static void
     755     17608495 : setG2_fast(double **appB, long n, double **G, long kappa, long a, long b)
     756              : { long i;
     757     60840921 :   for (i = a; i <= b; i++)
     758     43232426 :     dmael(G,i,kappa) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     759     17608495 : }
     760              : const long EX0 = -2; /* uninitialized; any value less than expo(0.51) = -1 */
     761              : 
     762              : #ifdef LONG_IS_64BIT
     763              : typedef long s64;
     764              : #define addmuliu64_inplace addmuliu_inplace
     765              : #define submuliu64_inplace submuliu_inplace
     766              : #define submuliu642n submuliu2n
     767              : #define addmuliu642n addmuliu2n
     768              : #else
     769              : typedef long long s64;
     770              : typedef unsigned long long u64;
     771              : 
     772              : INLINE GEN
     773     21996172 : u64toi(u64 x)
     774              : {
     775              :   GEN y;
     776              :   ulong h;
     777     21996172 :   if (!x) return gen_0;
     778     21996172 :   h = x>>32;
     779     21996172 :   if (!h) return utoipos(x);
     780      1270627 :   y = cgetipos(4);
     781      1270627 :   *int_LSW(y) = x&0xFFFFFFFF;
     782      1270627 :   *int_MSW(y) = x>>32;
     783      1270627 :   return y;
     784              : }
     785              : 
     786              : INLINE GEN
     787       726330 : u64toineg(u64 x)
     788              : {
     789              :   GEN y;
     790              :   ulong h;
     791       726330 :   if (!x) return gen_0;
     792       726330 :   h = x>>32;
     793       726330 :   if (!h) return utoineg(x);
     794       726330 :   y = cgetineg(4);
     795       726330 :   *int_LSW(y) = x&0xFFFFFFFF;
     796       726330 :   *int_MSW(y) = x>>32;
     797       726330 :   return y;
     798              : }
     799              : INLINE GEN
     800     10599145 : addmuliu64_inplace(GEN x, GEN y, u64 u) { return addmulii(x, y, u64toi(u)); }
     801              : 
     802              : INLINE GEN
     803     10652343 : submuliu64_inplace(GEN x, GEN y, u64 u) { return submulii(x, y, u64toi(u)); }
     804              : 
     805              : INLINE GEN
     806       726330 : addmuliu642n(GEN x, GEN y, u64 u, long e) { return submulshift(x, y, u64toineg(u), e); }
     807              : 
     808              : INLINE GEN
     809       744684 : submuliu642n(GEN x, GEN y, u64 u, long e) { return submulshift(x, y, u64toi(u), e); }
     810              : 
     811              : #endif
     812              : 
     813              : /* Babai's Nearest Plane algorithm (iterative); see Babai() */
     814              : static int
     815     31670503 : Babai_fast(pari_sp av, long kappa, GEN *pB, GEN *pU, double **mu, double **r,
     816              :            double *s, double **appB, GEN expoB, double **G,
     817              :            long a, long zeros, long maxG, double eta)
     818              : {
     819     31670503 :   GEN B = *pB, U = *pU;
     820     31670503 :   const long n = nbrows(B), d = U ? lg(U)-1: 0;
     821     31670503 :   long k, aa = (a > zeros)? a : zeros+1;
     822     31670503 :   long emaxmu = EX0, emax2mu = EX0;
     823              :   s64 xx;
     824     31670503 :   int did_something = 0;
     825              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
     826              : 
     827     17818493 :   for (;;) {
     828     49488996 :     int go_on = 0;
     829     49488996 :     long i, j, emax3mu = emax2mu;
     830              : 
     831     49488996 :     if (gc_needed(av,2))
     832              :     {
     833          229 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
     834          229 :       gc_lll(av,2,&B,&U);
     835              :     }
     836              :     /* Step2: compute the GSO for stage kappa */
     837     49488996 :     emax2mu = emaxmu; emaxmu = EX0;
     838    196685322 :     for (j=aa; j<kappa; j++)
     839              :     {
     840    147196326 :       double g = dmael(G,kappa,j);
     841    681541091 :       for (k = zeros+1; k < j; k++) g -= dmael(mu,j,k) * dmael(r,kappa,k);
     842    147196326 :       dmael(r,kappa,j) = g;
     843    147196326 :       dmael(mu,kappa,j) = dmael(r,kappa,j) / dmael(r,j,j);
     844    147196326 :       emaxmu = maxss(emaxmu, expoB[kappa]-expoB[j]);
     845              :     }
     846              :     /* maxmu doesn't decrease fast enough */
     847     49488996 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) {*pB = B; *pU = U; return 1;}
     848              : 
     849    186216546 :     for (j=kappa-1; j>zeros; j--)
     850              :     {
     851    154550735 :       double tmp = fabs(ldexp (dmael(mu,kappa,j), expoB[kappa]-expoB[j]));
     852    154550735 :       if (tmp>eta) { go_on = 1; break; }
     853              :     }
     854              : 
     855              :     /* Step3--5: compute the X_j's  */
     856     49484304 :     if (go_on)
     857     85077307 :       for (j=kappa-1; j>zeros; j--)
     858              :       { /* The code below seemingly handles U = NULL, but in this case d = 0 */
     859     67258814 :         int e = expoB[j] - expoB[kappa];
     860     67258814 :         double tmp = ldexp(dmael(mu,kappa,j), -e), atmp = fabs(tmp);
     861              :         /* tmp = Inf is allowed */
     862     67258814 :         if (atmp <= .5) continue; /* size-reduced */
     863     36915119 :         if (gc_needed(av,2))
     864              :         {
     865          479 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
     866          479 :           gc_lll(av,2,&B,&U);
     867              :         }
     868     36915119 :         did_something = 1;
     869              :         /* we consider separately the case |X| = 1 */
     870     36915119 :         if (atmp <= 1.5)
     871              :         {
     872     25454962 :           if (dmael(mu,kappa,j) > 0) { /* in this case, X = 1 */
     873     55867833 :             for (k=zeros+1; k<j; k++)
     874     42909435 :               dmael(mu,kappa,k) -= ldexp(dmael(mu,j,k), e);
     875    192057191 :             for (i=1; i<=n; i++)
     876    179098793 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
     877    137840030 :             for (i=1; i<=d; i++)
     878    124881632 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
     879              :           } else { /* otherwise X = -1 */
     880     55046629 :             for (k=zeros+1; k<j; k++)
     881     42550065 :               dmael(mu,kappa,k) += ldexp(dmael(mu,j,k), e);
     882    189397450 :             for (i=1; i<=n; i++)
     883    176900886 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
     884    135097227 :             for (i=1; i<=d; i++)
     885    122600663 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i), gmael(U,j,i));
     886              :           }
     887     25454962 :           continue;
     888              :         }
     889              :         /* we have |X| >= 2 */
     890     11460157 :         if (atmp < 9007199254740992.)
     891              :         {
     892     10601495 :           tmp = pari_rint(tmp);
     893     26330112 :           for (k=zeros+1; k<j; k++)
     894     15728617 :             dmael(mu,kappa,k) -= ldexp(tmp * dmael(mu,j,k), e);
     895     10601495 :           xx = (s64) tmp;
     896     10601495 :           if (xx > 0) /* = xx */
     897              :           {
     898     50148993 :             for (i=1; i<=n; i++)
     899     44818060 :               gmael(B,kappa,i) = submuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
     900     36938858 :             for (i=1; i<=d; i++)
     901     31607925 :               gmael(U,kappa,i) = submuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
     902              :           }
     903              :           else /* = -xx */
     904              :           {
     905     49847438 :             for (i=1; i<=n; i++)
     906     44576876 :               gmael(B,kappa,i) = addmuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), -xx);
     907     36570078 :             for (i=1; i<=d; i++)
     908     31299516 :               gmael(U,kappa,i) = addmuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), -xx);
     909              :           }
     910              :         }
     911              :         else
     912              :         {
     913              :           int E;
     914       858662 :           xx = (s64) ldexp(frexp(dmael(mu,kappa,j), &E), 53);
     915       858662 :           E -= e + 53;
     916       858662 :           if (E <= 0)
     917              :           {
     918            0 :             xx = xx << -E;
     919            0 :             for (k=zeros+1; k<j; k++)
     920            0 :               dmael(mu,kappa,k) -= ldexp(((double)xx) * dmael(mu,j,k), e);
     921            0 :             if (xx > 0) /* = xx */
     922              :             {
     923            0 :               for (i=1; i<=n; i++)
     924            0 :                 gmael(B,kappa,i) = submuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
     925            0 :               for (i=1; i<=d; i++)
     926            0 :                 gmael(U,kappa,i) = submuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
     927              :             }
     928              :             else /* = -xx */
     929              :             {
     930            0 :               for (i=1; i<=n; i++)
     931            0 :                 gmael(B,kappa,i) = addmuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), -xx);
     932            0 :               for (i=1; i<=d; i++)
     933            0 :                 gmael(U,kappa,i) = addmuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), -xx);
     934              :             }
     935              :           } else
     936              :           {
     937      2939081 :             for (k=zeros+1; k<j; k++)
     938      2080419 :               dmael(mu,kappa,k) -= ldexp(((double)xx) * dmael(mu,j,k), E + e);
     939       858662 :             if (xx > 0) /* = xx */
     940              :             {
     941      4164300 :               for (i=1; i<=n; i++)
     942      3732376 :                 gmael(B,kappa,i) = submuliu642n(gmael(B,kappa,i), gmael(B,j,i), xx, E);
     943      1621385 :               for (i=1; i<=d; i++)
     944      1189461 :                 gmael(U,kappa,i) = submuliu642n(gmael(U,kappa,i), gmael(U,j,i), xx, E);
     945              :             }
     946              :             else /* = -xx */
     947              :             {
     948      4120004 :               for (i=1; i<=n; i++)
     949      3693266 :                 gmael(B,kappa,i) = addmuliu642n(gmael(B,kappa,i), gmael(B,j,i), -xx, E);
     950      1606005 :               for (i=1; i<=d; i++)
     951      1179267 :                 gmael(U,kappa,i) = addmuliu642n(gmael(U,kappa,i), gmael(U,j,i), -xx, E);
     952              :             }
     953              :           }
     954              :         }
     955              :       }
     956     49484304 :     if (!go_on) break; /* Anything happened? */
     957     17818493 :     expoB[kappa] = set_line(del(appB,kappa), gel(B,kappa), n);
     958     17818493 :     setG_fast(appB, n, G, kappa, zeros+1, kappa-1);
     959     17818493 :     aa = zeros+1;
     960              :   }
     961     31665811 :   if (did_something) setG2_fast(appB, n, G, kappa, kappa, maxG);
     962              : 
     963     31665811 :   del(s,zeros+1) = dmael(G,kappa,kappa);
     964              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
     965    124239188 :   for (k=zeros+1; k<=kappa-2; k++)
     966     92573377 :     del(s,k+1) = del(s,k) - dmael(mu,kappa,k)*dmael(r,kappa,k);
     967     31665811 :   *pB = B; *pU = U; return 0;
     968              : }
     969              : 
     970              : static void
     971     12436610 : update_alpha(GEN alpha, long kappa, long kappa2, long kappamax)
     972              : {
     973              :   long i;
     974     40097134 :   for (i = kappa; i < kappa2; i++)
     975     27660524 :     if (kappa <= alpha[i]) alpha[i] = kappa;
     976     40097134 :   for (i = kappa2; i > kappa; i--) alpha[i] = alpha[i-1];
     977     26373039 :   for (i = kappa2+1; i <= kappamax; i++)
     978     13936429 :     if (kappa < alpha[i]) alpha[i] = kappa;
     979     12436610 :   alpha[kappa] = kappa;
     980     12436610 : }
     981              : static void
     982       478734 : rotateG(GEN G, long kappa2, long kappa, long maxG, GEN Gtmp)
     983              : {
     984              :   long i, j;
     985      3847193 :   for (i=1; i<=kappa2; i++) gel(Gtmp,i) = gmael(G,kappa2,i);
     986      1929977 :   for (   ; i<=maxG; i++)   gel(Gtmp,i) = gmael(G,i,kappa2);
     987      1698152 :   for (i=kappa2; i>kappa; i--)
     988              :     {
     989      6041216 :       for (j=1; j<kappa; j++) gmael(G,i,j) = gmael(G,i-1,j);
     990      1219418 :       gmael(G,i,kappa) = gel(Gtmp,i-1);
     991      4499836 :       for (j=kappa+1; j<=i; j++) gmael(G,i,j) = gmael(G,i-1,j-1);
     992      5070158 :       for (j=kappa2+1; j<=maxG; j++) gmael(G,j,i) = gmael(G,j,i-1);
     993              :     }
     994      2149041 :   for (i=1; i<kappa; i++) gmael(G,kappa,i) = gel(Gtmp,i);
     995       478734 :   gmael(G,kappa,kappa) = gel(Gtmp,kappa2);
     996      1929977 :   for (i=kappa2+1; i<=maxG; i++) gmael(G,i,kappa) = gel(Gtmp,i);
     997       478734 : }
     998              : static void
     999     11957876 : rotateG_fast(double **G, long kappa2, long kappa, long maxG, double *Gtmp)
    1000              : {
    1001              :   long i, j;
    1002     72510605 :   for (i=1; i<=kappa2; i++) del(Gtmp,i) = dmael(G,kappa2,i);
    1003     25305462 :   for (   ; i<=maxG; i++) del(Gtmp,i) = dmael(G,i,kappa2);
    1004     38398982 :   for (i=kappa2; i>kappa; i--)
    1005              :   {
    1006     79336899 :     for (j=1; j<kappa; j++) dmael(G,i,j) = dmael(G,i-1,j);
    1007     26441106 :     dmael(G,i,kappa) = del(Gtmp,i-1);
    1008     92807777 :     for (j=kappa+1; j<=i; j++) dmael(G,i,j) = dmael(G,i-1,j-1);
    1009     54972836 :     for (j=kappa2+1; j<=maxG; j++) dmael(G,j,i) = dmael(G,j,i-1);
    1010              :   }
    1011     34111623 :   for (i=1; i<kappa; i++) dmael(G,kappa,i) = del(Gtmp,i);
    1012     11957876 :   dmael(G,kappa,kappa) = del(Gtmp,kappa2);
    1013     25305462 :   for (i=kappa2+1; i<=maxG; i++) dmael(G,i,kappa) = del(Gtmp,i);
    1014     11957876 : }
    1015              : 
    1016              : /* LLL-reduces (B,U) in place [apply base change transforms to B and U].
    1017              :  * Gram matrix, and GSO performed on matrices of 'double'.
    1018              :  * If (keepfirst), never swap with first vector.
    1019              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1020              : static long
    1021      2107542 : fplll_fast(GEN *pB, GEN *pU, double delta, double eta, long keepfirst)
    1022              : {
    1023              :   pari_sp av;
    1024              :   long kappa, kappa2, d, n, i, j, zeros, kappamax, maxG;
    1025              :   double **mu, **r, *s, tmp, *Gtmp, **G, **appB;
    1026      2107542 :   GEN alpha, expoB, B = *pB, U;
    1027      2107542 :   long cnt = 0;
    1028              : 
    1029      2107542 :   d = lg(B)-1;
    1030      2107542 :   n = nbrows(B);
    1031      2107542 :   U = *pU; /* NULL if inplace */
    1032              : 
    1033      2107542 :   G = cget_dblmat(d+1);
    1034      2107542 :   appB = cget_dblmat(d+1);
    1035      2107542 :   mu = cget_dblmat(d+1);
    1036      2107542 :   r  = cget_dblmat(d+1);
    1037      2107542 :   s  = cget_dblvec(d+1);
    1038      9831084 :   for (j = 1; j <= d; j++)
    1039              :   {
    1040      7723542 :     del(mu,j) = cget_dblvec(d+1);
    1041      7723542 :     del(r,j) = cget_dblvec(d+1);
    1042      7723542 :     del(appB,j) = cget_dblvec(n+1);
    1043      7723542 :     del(G,j) = cget_dblvec(d+1);
    1044     47983650 :     for (i=1; i<=d; i++) dmael(G,j,i) = 0.;
    1045              :   }
    1046      2107542 :   expoB = cgetg(d+1, t_VECSMALL);
    1047      9831084 :   for (i=1; i<=d; i++) expoB[i] = set_line(del(appB,i), gel(B,i), n);
    1048      2107542 :   Gtmp = cget_dblvec(d+1);
    1049      2107542 :   alpha = cgetg(d+1, t_VECSMALL);
    1050      2107542 :   av = avma;
    1051              : 
    1052              :   /* Step2: Initializing the main loop */
    1053      2107542 :   kappamax = 1;
    1054      2107542 :   i = 1;
    1055      2107542 :   maxG = d; /* later updated to kappamax */
    1056              : 
    1057              :   do {
    1058      2272916 :     dmael(G,i,i) = dbldotsquare(del(appB,i),n);
    1059      2272916 :   } while (dmael(G,i,i) <= 0 && (++i <=d));
    1060      2107542 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1061      2107542 :   kappa = i;
    1062      2107542 :   if (zeros < d) dmael(r,zeros+1,zeros+1) = dmael(G,zeros+1,zeros+1);
    1063      9665703 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1064     33773353 :   while (++kappa <= d)
    1065              :   {
    1066     31670503 :     if (kappa > kappamax)
    1067              :     {
    1068      5443828 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1069      5443828 :       maxG = kappamax = kappa;
    1070      5443828 :       setG_fast(appB, n, G, kappa, zeros+1, kappa);
    1071              :     }
    1072              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1073     31670503 :     if (Babai_fast(av, kappa, &B,&U, mu,r,s, appB, expoB, G, alpha[kappa],
    1074         4692 :                    zeros, maxG, eta)) { *pB=B; *pU=U; return -1; }
    1075              : 
    1076     31665811 :     tmp = ldexp(r[kappa-1][kappa-1] * delta, 2*(expoB[kappa-1]-expoB[kappa]));
    1077     31665811 :     if ((keepfirst && kappa == 2) || tmp <= del(s,kappa-1))
    1078              :     { /* Step4: Success of Lovasz's condition */
    1079     19707935 :       alpha[kappa] = kappa;
    1080     19707935 :       tmp = dmael(mu,kappa,kappa-1) * dmael(r,kappa,kappa-1);
    1081     19707935 :       dmael(r,kappa,kappa) = del(s,kappa-1)- tmp;
    1082     19707935 :       continue;
    1083              :     }
    1084              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1085     11957876 :     if (DEBUGLEVEL>=4 && kappa==kappamax && del(s,kappa-1)!=0)
    1086            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", 2*expoB[1] + dblexpo(del(s,1))); }
    1087     11957876 :     kappa2 = kappa;
    1088              :     do {
    1089     26441106 :       kappa--;
    1090     26441106 :       if (kappa<zeros+2 + (keepfirst ? 1: 0)) break;
    1091     19820810 :       tmp = dmael(r,kappa-1,kappa-1) * delta;
    1092     19820810 :       tmp = ldexp(tmp, 2*(expoB[kappa-1]-expoB[kappa2]));
    1093     19820810 :     } while (del(s,kappa-1) <= tmp);
    1094     11957876 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1095              : 
    1096              :     /* Step6: Update the mu's and r's */
    1097     11957876 :     dblrotate(mu,kappa2,kappa);
    1098     11957876 :     dblrotate(r,kappa2,kappa);
    1099     11957876 :     dmael(r,kappa,kappa) = del(s,kappa);
    1100              : 
    1101              :     /* Step7: Update B, appB, U, G */
    1102     11957876 :     rotate(B,kappa2,kappa);
    1103     11957876 :     dblrotate(appB,kappa2,kappa);
    1104     11957876 :     if (U) rotate(U,kappa2,kappa);
    1105     11957876 :     rotate(expoB,kappa2,kappa);
    1106     11957876 :     rotateG_fast(G,kappa2,kappa, maxG, Gtmp);
    1107              : 
    1108              :     /* Step8: Prepare the next loop iteration */
    1109     11957876 :     if (kappa == zeros+1 && dmael(G,kappa,kappa)<= 0)
    1110              :     {
    1111       212393 :       zeros++; kappa++;
    1112       212393 :       dmael(G,kappa,kappa) = dbldotsquare(del(appB,kappa),n);
    1113       212393 :       dmael(r,kappa,kappa) = dmael(G,kappa,kappa);
    1114              :     }
    1115              :   }
    1116      2102850 :   *pB = B; *pU = U; return zeros;
    1117              : }
    1118              : 
    1119              : /***************** HEURISTIC version (reduced precision) ****************/
    1120              : static GEN
    1121       207602 : realsqrdotproduct(GEN x)
    1122              : {
    1123       207602 :   long i, l = lg(x);
    1124       207602 :   GEN z = sqrr(gel(x,1));
    1125      1457483 :   for (i=2; i<l; i++) z = addrr(z, sqrr(gel(x,i)));
    1126       207602 :   return z;
    1127              : }
    1128              : /* x, y non-empty vector of t_REALs, same length */
    1129              : static GEN
    1130      1288707 : realdotproduct(GEN x, GEN y)
    1131              : {
    1132              :   long i, l;
    1133              :   GEN z;
    1134      1288707 :   if (x == y) return realsqrdotproduct(x);
    1135      1081105 :   l = lg(x); z = mulrr(gel(x,1),gel(y,1));
    1136     10660944 :   for (i=2; i<l; i++) z = addrr(z, mulrr(gel(x,i), gel(y,i)));
    1137      1081105 :   return z;
    1138              : }
    1139              : static void
    1140       217683 : setG_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1141       217683 : { pari_sp av = avma;
    1142              :   long i;
    1143      1029110 :   for (i = a; i <= b; i++)
    1144       811427 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,kappa,i));
    1145       217683 :   set_avma(av);
    1146       217683 : }
    1147              : static void
    1148       194933 : setG2_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1149       194933 : { pari_sp av = avma;
    1150              :   long i;
    1151       672213 :   for (i = a; i <= b; i++)
    1152       477280 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,i,kappa));
    1153       194933 :   set_avma(av);
    1154       194933 : }
    1155              : 
    1156              : /* approximate t_REAL x as m * 2^e, where |m| < 2^bit */
    1157              : static GEN
    1158        24411 : truncexpo(GEN x, long bit, long *e)
    1159              : {
    1160        24411 :   *e = expo(x) + 1 - bit;
    1161        24411 :   if (*e >= 0) return mantissa2nr(x, 0);
    1162         1259 :   *e = 0; return roundr_safe(x);
    1163              : }
    1164              : /* Babai's Nearest Plane algorithm (iterative); see Babai() */
    1165              : static int
    1166       301906 : Babai_heuristic(pari_sp av, long kappa, GEN *pB, GEN *pU, GEN mu, GEN r, GEN s,
    1167              :                 GEN appB, GEN G, long a, long zeros, long maxG,
    1168              :                 GEN eta, long prec)
    1169              : {
    1170       301906 :   GEN B = *pB, U = *pU;
    1171       301906 :   const long n = nbrows(B), d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    1172       301906 :   long k, aa = (a > zeros)? a : zeros+1;
    1173       301906 :   int did_something = 0;
    1174       301906 :   long emaxmu = EX0, emax2mu = EX0;
    1175              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1176              : 
    1177       205014 :   for (;;) {
    1178       506920 :     int go_on = 0;
    1179       506920 :     long i, j, emax3mu = emax2mu;
    1180              : 
    1181       506920 :     if (gc_needed(av,2))
    1182              :     {
    1183           36 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    1184           36 :       gc_lll(av,2,&B,&U);
    1185              :     }
    1186              :     /* Step2: compute the GSO for stage kappa */
    1187       506920 :     emax2mu = emaxmu; emaxmu = EX0;
    1188      1992213 :     for (j=aa; j<kappa; j++)
    1189              :     {
    1190      1485293 :       pari_sp btop = avma;
    1191      1485293 :       GEN g = gmael(G,kappa,j);
    1192      5026517 :       for (k = zeros+1; k<j; k++)
    1193      3541224 :         g = subrr(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    1194      1485293 :       affrr(g, gmael(r,kappa,j));
    1195      1485293 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    1196      1485293 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    1197      1485293 :       set_avma(btop);
    1198              :     }
    1199       506920 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5)
    1200         1727 :     { *pB = B; *pU = U; return 1; }
    1201              : 
    1202      1744641 :     for (j=kappa-1; j>zeros; j--)
    1203      1444462 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1204              : 
    1205              :     /* Step3--5: compute the X_j's  */
    1206       505193 :     if (go_on)
    1207       966364 :       for (j=kappa-1; j>zeros; j--)
    1208              :       { /* The code below seemingly handles U = NULL, but in this case d = 0 */
    1209              :         pari_sp btop;
    1210       761350 :         GEN tmp = gmael(mu,kappa,j);
    1211       761350 :         if (absrsmall(tmp)) continue; /* size-reduced */
    1212              : 
    1213       441842 :         if (gc_needed(av,2))
    1214              :         {
    1215           10 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    1216           10 :           gc_lll(av,2,&B,&U);
    1217              :         }
    1218       441842 :         btop = avma; did_something = 1;
    1219              :         /* we consider separately the case |X| = 1 */
    1220       441842 :         if (absrsmall2(tmp))
    1221              :         {
    1222       279712 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    1223       418025 :             for (k=zeros+1; k<j; k++)
    1224       278975 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1225       139050 :             set_avma(btop);
    1226      1358156 :             for (i=1; i<=n; i++)
    1227      1219106 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    1228       855628 :             for (i=1; i<=d; i++)
    1229       716578 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
    1230              :           } else { /* otherwise X = -1 */
    1231       426008 :             for (k=zeros+1; k<j; k++)
    1232       285346 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1233       140662 :             set_avma(btop);
    1234      1383149 :             for (i=1; i<=n; i++)
    1235      1242487 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
    1236       859488 :             for (i=1; i<=d; i++)
    1237       718826 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    1238              :           }
    1239       279712 :           continue;
    1240              :         }
    1241              :         /* we have |X| >= 2 */
    1242       162130 :         if (expo(tmp) < BITS_IN_LONG)
    1243              :         {
    1244       137719 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    1245       137719 :           if (signe(tmp) > 0) /* = xx */
    1246              :           {
    1247       168816 :             for (k=zeros+1; k<j; k++)
    1248        99549 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1249        99549 :                   gmael(mu,kappa,k));
    1250        69267 :             set_avma(btop);
    1251       560574 :             for (i=1; i<=n; i++)
    1252       491307 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1253       330736 :             for (i=1; i<=d; i++)
    1254       261469 :               gmael(U,kappa,i) = submuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    1255              :           }
    1256              :           else /* = -xx */
    1257              :           {
    1258       167851 :             for (k=zeros+1; k<j; k++)
    1259        99399 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1260        99399 :                   gmael(mu,kappa,k));
    1261        68452 :             set_avma(btop);
    1262       565002 :             for (i=1; i<=n; i++)
    1263       496550 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1264       315779 :             for (i=1; i<=d; i++)
    1265       247327 :               gmael(U,kappa,i) = addmuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    1266              :           }
    1267              :         }
    1268              :         else
    1269              :         {
    1270              :           long e;
    1271        24411 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    1272        24411 :           btop = avma;
    1273       110906 :           for (k=zeros+1; k<j; k++)
    1274              :           {
    1275        86495 :             GEN x = mulir(X, gmael(mu,j,k));
    1276        86495 :             if (e) shiftr_inplace(x, e);
    1277        86495 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    1278              :           }
    1279        24411 :           set_avma(btop);
    1280       556361 :           for (i=1; i<=n; i++)
    1281       531950 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    1282        88159 :           for (i=1; i<=d; i++)
    1283        63748 :             gmael(U,kappa,i) = submulshift(gmael(U,kappa,i), gmael(U,j,i), X, e);
    1284              :         }
    1285              :       }
    1286       505193 :     if (!go_on) break; /* Anything happened? */
    1287      1631994 :     for (i=1 ; i<=n; i++) affir(gmael(B,kappa,i), gmael(appB,kappa,i));
    1288       205014 :     setG_heuristic(appB, G, kappa, zeros+1, kappa-1);
    1289       205014 :     aa = zeros+1;
    1290              :   }
    1291       300179 :   if (did_something) setG2_heuristic(appB, G, kappa, kappa, maxG);
    1292       300179 :   affrr(gmael(G,kappa,kappa), gel(s,zeros+1));
    1293              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    1294       300179 :   av = avma;
    1295      1102776 :   for (k=zeros+1; k<=kappa-2; k++)
    1296       802597 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    1297       802597 :           gel(s,k+1));
    1298       300179 :   *pB = B; *pU = U; return gc_bool(av, 0);
    1299              : }
    1300              : 
    1301              : static GEN
    1302        22240 : ZC_to_RC(GEN x, long prec)
    1303       317355 : { pari_APPLY_type(t_COL,itor(gel(x,i),prec)) }
    1304              : 
    1305              : static GEN
    1306         4692 : ZM_to_RM(GEN x, long prec)
    1307        26932 : { pari_APPLY_same(ZC_to_RC(gel(x,i),prec)) }
    1308              : 
    1309              : /* LLL-reduces (B,U) in place [apply base change transforms to B and U].
    1310              :  * Gram matrix made of t_REAL at precision prec2, performe GSO at prec.
    1311              :  * If (keepfirst), never swap with first vector.
    1312              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1313              : static long
    1314         4692 : fplll_heuristic(GEN *pB, GEN *pU, double DELTA, double ETA, long keepfirst,
    1315              :                 long prec, long prec2)
    1316              : {
    1317              :   pari_sp av, av2;
    1318              :   long kappa, kappa2, d, i, j, zeros, kappamax, maxG;
    1319         4692 :   GEN mu, r, s, tmp, Gtmp, alpha, G, appB, B = *pB, U;
    1320         4692 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    1321         4692 :   long cnt = 0;
    1322              : 
    1323         4692 :   d = lg(B)-1;
    1324         4692 :   U = *pU; /* NULL if inplace */
    1325              : 
    1326         4692 :   G = cgetg(d+1, t_MAT);
    1327         4692 :   mu = cgetg(d+1, t_MAT);
    1328         4692 :   r  = cgetg(d+1, t_MAT);
    1329         4692 :   s  = cgetg(d+1, t_VEC);
    1330         4692 :   appB = ZM_to_RM(B, prec2);
    1331        26932 :   for (j = 1; j <= d; j++)
    1332              :   {
    1333        22240 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL), S = cgetg(d+1, t_COL);
    1334        22240 :     gel(mu,j)= M;
    1335        22240 :     gel(r,j) = R;
    1336        22240 :     gel(G,j) = S;
    1337        22240 :     gel(s,j) = cgetr(prec);
    1338       256952 :     for (i = 1; i <= d; i++)
    1339              :     {
    1340       234712 :       gel(R,i) = cgetr(prec);
    1341       234712 :       gel(M,i) = cgetr(prec);
    1342       234712 :       gel(S,i) = cgetr(prec2);
    1343              :     }
    1344              :   }
    1345         4692 :   Gtmp = cgetg(d+1, t_VEC);
    1346         4692 :   alpha = cgetg(d+1, t_VECSMALL);
    1347         4692 :   av = avma;
    1348              : 
    1349              :   /* Step2: Initializing the main loop */
    1350         4692 :   kappamax = 1;
    1351         4692 :   i = 1;
    1352         4692 :   maxG = d; /* later updated to kappamax */
    1353              : 
    1354              :   do {
    1355         4695 :     affrr(RgV_dotsquare(gel(appB,i)), gmael(G,i,i));
    1356         4695 :   } while (signe(gmael(G,i,i)) == 0 && (++i <=d));
    1357         4692 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1358         4692 :   kappa = i;
    1359         4692 :   if (zeros < d) affrr(gmael(G,zeros+1,zeros+1), gmael(r,zeros+1,zeros+1));
    1360        26929 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1361              : 
    1362       304871 :   while (++kappa <= d)
    1363              :   {
    1364       301906 :     if (kappa > kappamax)
    1365              :     {
    1366        12669 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1367        12669 :       maxG = kappamax = kappa;
    1368        12669 :       setG_heuristic(appB, G, kappa, zeros+1, kappa);
    1369              :     }
    1370              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1371       301906 :     if (Babai_heuristic(av, kappa, &B,&U, mu,r,s, appB, G, alpha[kappa], zeros,
    1372         1727 :                         maxG, eta, prec)) { *pB = B; *pU = U; return -1; }
    1373       300179 :     av2 = avma;
    1374       600250 :     if ((keepfirst && kappa == 2) ||
    1375       300071 :         cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0)
    1376              :     { /* Step4: Success of Lovasz's condition */
    1377       179599 :       alpha[kappa] = kappa;
    1378       179599 :       tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1));
    1379       179599 :       affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa));
    1380       179599 :       set_avma(av2); continue;
    1381              :     }
    1382              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1383       120580 :     if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1)))
    1384            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); }
    1385       120580 :     kappa2 = kappa;
    1386              :     do {
    1387       289302 :       kappa--;
    1388       289302 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1389       259380 :       tmp = mulrr(gmael(r,kappa-1,kappa-1), delta);
    1390       259380 :     } while (cmprr(gel(s,kappa-1), tmp) <= 0 );
    1391       120580 :     set_avma(av2);
    1392       120580 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1393              : 
    1394              :     /* Step6: Update the mu's and r's */
    1395       120580 :     rotate(mu,kappa2,kappa);
    1396       120580 :     rotate(r,kappa2,kappa);
    1397       120580 :     affrr(gel(s,kappa), gmael(r,kappa,kappa));
    1398              : 
    1399              :     /* Step7: Update B, appB, U, G */
    1400       120580 :     rotate(B,kappa2,kappa);
    1401       120580 :     rotate(appB,kappa2,kappa);
    1402       120580 :     if (U) rotate(U,kappa2,kappa);
    1403       120580 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    1404              : 
    1405              :     /* Step8: Prepare the next loop iteration */
    1406       120580 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    1407              :     {
    1408            7 :       zeros++; kappa++;
    1409            7 :       affrr(RgV_dotsquare(gel(appB,kappa)), gmael(G,kappa,kappa));
    1410            7 :       affrr(gmael(G,kappa,kappa), gmael(r,kappa,kappa));
    1411              :     }
    1412              :   }
    1413         2965 :   *pB=B; *pU=U; return zeros;
    1414              : }
    1415              : 
    1416              : /************************* PROVED version (t_INT) ***********************/
    1417              : /* dpe inspired by dpe.h by Patrick Pelissier, Paul Zimmermann
    1418              :  * https://gforge.inria.fr/projects/dpe/
    1419              :  */
    1420              : 
    1421              : typedef struct
    1422              : {
    1423              :   double d;  /* significand */
    1424              :   long e; /* exponent */
    1425              : } dpe_t;
    1426              : 
    1427              : #define Dmael(x,i,j) (&((x)[i][j]))
    1428              : #define Del(x,i) (&((x)[i]))
    1429              : 
    1430              : static void
    1431       716308 : dperotate(dpe_t **A, long k2, long k)
    1432              : {
    1433              :   long i;
    1434       716308 :   dpe_t *B = A[k2];
    1435      2576540 :   for (i = k2; i > k; i--) A[i] = A[i-1];
    1436       716308 :   A[k] = B;
    1437       716308 : }
    1438              : 
    1439              : static void
    1440    151968279 : dpe_normalize0(dpe_t *x)
    1441              : {
    1442              :   int e;
    1443    151968279 :   x->d = frexp(x->d, &e);
    1444    151968279 :   x->e += e;
    1445    151968279 : }
    1446              : 
    1447              : static void
    1448     76719052 : dpe_normalize(dpe_t *x)
    1449              : {
    1450     76719052 :   if (x->d == 0.0)
    1451      2211084 :     x->e = -LONG_MAX;
    1452              :   else
    1453     74507968 :     dpe_normalize0(x);
    1454     76719052 : }
    1455              : 
    1456              : static GEN
    1457        25844 : dpetor(dpe_t *x)
    1458              : {
    1459        25844 :   GEN r = dbltor(x->d);
    1460        25844 :   if (signe(r)==0) return r;
    1461        25795 :   setexpo(r, x->e-1);
    1462        25795 :   return r;
    1463              : }
    1464              : 
    1465              : static void
    1466     33062959 : affdpe(dpe_t *y, dpe_t *x)
    1467              : {
    1468     33062959 :   x->d = y->d;
    1469     33062959 :   x->e = y->e;
    1470     33062959 : }
    1471              : 
    1472              : static void
    1473     22363572 : affidpe(GEN y, dpe_t *x)
    1474              : {
    1475     22363572 :   pari_sp av = avma;
    1476     22363572 :   GEN r = itor(y, DEFAULTPREC);
    1477     22363572 :   x->e = expo(r)+1;
    1478     22363572 :   setexpo(r,-1);
    1479     22363572 :   x->d = rtodbl(r);
    1480     22363572 :   set_avma(av);
    1481     22363572 : }
    1482              : 
    1483              : static void
    1484      3210438 : affdbldpe(double y, dpe_t *x)
    1485              : {
    1486      3210438 :   x->d = (double)y;
    1487      3210438 :   x->e = 0;
    1488      3210438 :   dpe_normalize(x);
    1489      3210438 : }
    1490              : 
    1491              : static void
    1492     74585258 : dpe_mulz(dpe_t *x, dpe_t *y, dpe_t *z)
    1493              : {
    1494     74585258 :   z->d = x->d * y->d;
    1495     74585258 :   if (z->d == 0.0)
    1496     10747735 :     z->e = -LONG_MAX;
    1497              :   else
    1498              :   {
    1499     63837523 :     z->e = x->e + y->e;
    1500     63837523 :     dpe_normalize0(z);
    1501              :   }
    1502     74585258 : }
    1503              : 
    1504              : static void
    1505     15577747 : dpe_divz(dpe_t *x, dpe_t *y, dpe_t *z)
    1506              : {
    1507     15577747 :   z->d = x->d / y->d;
    1508     15577747 :   if (z->d == 0.0)
    1509      1954959 :     z->e = -LONG_MAX;
    1510              :   else
    1511              :   {
    1512     13622788 :     z->e = x->e - y->e;
    1513     13622788 :     dpe_normalize0(z);
    1514              :   }
    1515     15577747 : }
    1516              : 
    1517              : static void
    1518       366301 : dpe_negz(dpe_t *y, dpe_t *x)
    1519              : {
    1520       366301 :   x->d = - y->d;
    1521       366301 :   x->e = y->e;
    1522       366301 : }
    1523              : 
    1524              : static void
    1525      6613235 : dpe_addz(dpe_t *y, dpe_t *z, dpe_t *x)
    1526              : {
    1527      6613235 :   if (y->e > z->e + 53)
    1528       984873 :     affdpe(y, x);
    1529      5628362 :   else if (z->e > y->e + 53)
    1530        91749 :     affdpe(z, x);
    1531              :   else
    1532              :   {
    1533      5536613 :     long d = y->e - z->e;
    1534              : 
    1535      5536613 :     if (d >= 0)
    1536              :     {
    1537      4485087 :       x->d = y->d + ldexp(z->d, -d);
    1538      4485087 :       x->e  = y->e;
    1539              :     }
    1540              :     else
    1541              :     {
    1542      1051526 :       x->d = z->d + ldexp(y->d, d);
    1543      1051526 :       x->e = z->e;
    1544              :     }
    1545      5536613 :     dpe_normalize(x);
    1546              :   }
    1547      6613235 : }
    1548              : static void
    1549     75767142 : dpe_subz(dpe_t *y, dpe_t *z, dpe_t *x)
    1550              : {
    1551     75767142 :   if (y->e > z->e + 53)
    1552     16050436 :     affdpe(y, x);
    1553     59716706 :   else if (z->e > y->e + 53)
    1554       366301 :     dpe_negz(z, x);
    1555              :   else
    1556              :   {
    1557     59350405 :     long d = y->e - z->e;
    1558              : 
    1559     59350405 :     if (d >= 0)
    1560              :     {
    1561     55189522 :       x->d = y->d - ldexp(z->d, -d);
    1562     55189522 :       x->e = y->e;
    1563              :     }
    1564              :     else
    1565              :     {
    1566      4160883 :       x->d = ldexp(y->d, d) - z->d;
    1567      4160883 :       x->e = z->e;
    1568              :     }
    1569     59350405 :     dpe_normalize(x);
    1570              :   }
    1571     75767142 : }
    1572              : 
    1573              : static void
    1574      8621596 : dpe_muluz(dpe_t *y, ulong t, dpe_t *x)
    1575              : {
    1576      8621596 :   x->d = y->d * (double)t;
    1577      8621596 :   x->e = y->e;
    1578      8621596 :   dpe_normalize(x);
    1579      8621596 : }
    1580              : 
    1581              : static void
    1582      1323853 : dpe_addmuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1583              : {
    1584              :   dpe_t tmp;
    1585      1323853 :   dpe_muluz(z, t, &tmp);
    1586      1323853 :   dpe_addz(y, &tmp, x);
    1587      1323853 : }
    1588              : 
    1589              : static void
    1590      1410109 : dpe_submuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1591              : {
    1592              :   dpe_t tmp;
    1593      1410109 :   dpe_muluz(z, t, &tmp);
    1594      1410109 :   dpe_subz(y, &tmp, x);
    1595      1410109 : }
    1596              : 
    1597              : static void
    1598     69115457 : dpe_submulz(dpe_t *y,  dpe_t *z, dpe_t *t, dpe_t *x)
    1599              : {
    1600              :   dpe_t tmp;
    1601     69115457 :   dpe_mulz(z, t, &tmp);
    1602     69115457 :   dpe_subz(y, &tmp, x);
    1603     69115457 : }
    1604              : 
    1605              : static int
    1606      5469801 : dpe_cmp(dpe_t *x, dpe_t *y)
    1607              : {
    1608      5469801 :   int sx = x->d < 0. ? -1: x->d > 0.;
    1609      5469801 :   int sy = y->d < 0. ? -1: y->d > 0.;
    1610      5469801 :   int d  = sx - sy;
    1611              : 
    1612      5469801 :   if (d != 0)
    1613       142831 :     return d;
    1614      5326970 :   else if (x->e > y->e)
    1615       547883 :     return (sx > 0) ? 1 : -1;
    1616      4779087 :   else if (y->e > x->e)
    1617      2601091 :     return (sx > 0) ? -1 : 1;
    1618              :   else
    1619      2177996 :     return (x->d < y->d) ? -1 : (x->d > y->d);
    1620              : }
    1621              : 
    1622              : static int
    1623     15746499 : dpe_abscmp(dpe_t *x, dpe_t *y)
    1624              : {
    1625     15746499 :   if (x->e > y->e)
    1626       311110 :     return 1;
    1627     15435389 :   else if (y->e > x->e)
    1628     14511719 :     return -1;
    1629              :   else
    1630       923670 :     return (fabs(x->d) < fabs(y->d)) ? -1 : (fabs(x->d) > fabs(y->d));
    1631              : }
    1632              : 
    1633              : static int
    1634      2162095 : dpe_abssmall(dpe_t *x)
    1635              : {
    1636      2162095 :   return (x->e <= 0) || (x->e == 1 && fabs(x->d) <= .75);
    1637              : }
    1638              : 
    1639              : static int
    1640      5469801 : dpe_cmpmul(dpe_t *x, dpe_t *y, dpe_t *z)
    1641              : {
    1642              :   dpe_t t;
    1643      5469801 :   dpe_mulz(x,y,&t);
    1644      5469801 :   return dpe_cmp(&t, z);
    1645              : }
    1646              : 
    1647              : static dpe_t *
    1648     13316637 : cget_dpevec(long d)
    1649     13316637 : { return (dpe_t*) stack_malloc_align(d*sizeof(dpe_t), sizeof(dpe_t)); }
    1650              : 
    1651              : static dpe_t **
    1652      3210438 : cget_dpemat(long d) { return (dpe_t **) cgetg(d, t_VECSMALL); }
    1653              : 
    1654              : static GEN
    1655         1694 : dpeM_diagonal_shallow(dpe_t **m, long d)
    1656              : {
    1657              :   long i;
    1658         1694 :   GEN y = cgetg(d+1,t_VEC);
    1659        27538 :   for (i=1; i<=d; i++) gel(y, i) = dpetor(Dmael(m,i,i));
    1660         1694 :   return y;
    1661              : }
    1662              : 
    1663              : static void
    1664      2162095 : affii_or_copy_gc(pari_sp av, GEN x, GEN *y)
    1665              : {
    1666      2162095 :   long l = lg(*y);
    1667      2162095 :   if (lgefint(x) <= l && isonstack(*y))
    1668              :   {
    1669      2162083 :     affii(x,*y);
    1670      2162083 :     set_avma(av);
    1671              :   }
    1672              :   else
    1673           12 :     *y = gc_INT(av, x);
    1674      2162095 : }
    1675              : 
    1676              : /* *x -= u*y */
    1677              : INLINE void
    1678     12094839 : submulziu(GEN *x, GEN y, ulong u)
    1679              : {
    1680              :   pari_sp av;
    1681     12094839 :   long ly = lgefint(y);
    1682     12094839 :   if (ly == 2) return;
    1683      6161175 :   av = avma;
    1684      6161175 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1685      6161175 :   y = mului(u,y);
    1686      6161175 :   set_avma(av); subzi(x, y);
    1687              : }
    1688              : 
    1689              : /* *x += u*y */
    1690              : INLINE void
    1691     10701531 : addmulziu(GEN *x, GEN y, ulong u)
    1692              : {
    1693              :   pari_sp av;
    1694     10701531 :   long ly = lgefint(y);
    1695     10701531 :   if (ly == 2) return;
    1696      5644034 :   av = avma;
    1697      5644034 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1698      5644034 :   y = mului(u,y);
    1699      5644034 :   set_avma(av); addzi(x, y);
    1700              : }
    1701              : 
    1702              : /************************** PROVED version (dpe) *************************/
    1703              : 
    1704              : /* Babai's Nearest Plane algorithm (iterative).
    1705              :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    1706              :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    1707              :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    1708              : static int
    1709      4762323 : Babai_dpe(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, dpe_t **mu, dpe_t **r, dpe_t *s,
    1710              :       long a, long zeros, long maxG, dpe_t *eta)
    1711              : {
    1712      4762323 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    1713      4762323 :   long k, d, n, aa = a > zeros? a: zeros+1;
    1714      4762323 :   long emaxmu = EX0, emax2mu = EX0;
    1715              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1716      4762323 :   d = U? lg(U)-1: 0;
    1717      4762323 :   n = B? nbrows(B): 0;
    1718       600507 :   for (;;) {
    1719      5362830 :     int go_on = 0;
    1720      5362830 :     long i, j, emax3mu = emax2mu;
    1721              : 
    1722      5362830 :     if (gc_needed(av,2))
    1723              :     {
    1724            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    1725            0 :       gc_lll(av,3,&G,&B,&U);
    1726              :     }
    1727              :     /* Step2: compute the GSO for stage kappa */
    1728      5362830 :     emax2mu = emaxmu; emaxmu = EX0;
    1729     20940577 :     for (j=aa; j<kappa; j++)
    1730              :     {
    1731              :       dpe_t g;
    1732     15577747 :       affidpe(gmael(G,kappa,j), &g);
    1733     70406537 :       for (k = zeros+1; k < j; k++)
    1734     54828790 :         dpe_submulz(&g, Dmael(mu,j,k), Dmael(r,kappa,k), &g);
    1735     15577747 :       affdpe(&g, Dmael(r,kappa,j));
    1736     15577747 :       dpe_divz(Dmael(r,kappa,j), Dmael(r,j,j), Dmael(mu,kappa,j));
    1737     15577747 :       emaxmu = maxss(emaxmu, Dmael(mu,kappa,j)->e);
    1738              :     }
    1739      5362830 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    1740            0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    1741              : 
    1742     20508822 :     for (j=kappa-1; j>zeros; j--)
    1743     15746499 :       if (dpe_abscmp(Dmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1744              : 
    1745              :     /* Step3--5: compute the X_j's  */
    1746      5362830 :     if (go_on)
    1747      4188086 :       for (j=kappa-1; j>zeros; j--)
    1748              :       {
    1749              :         pari_sp btop;
    1750      3587579 :         dpe_t *tmp = Dmael(mu,kappa,j);
    1751      3587579 :         if (tmp->e < 0) continue; /* (essentially) size-reduced */
    1752              : 
    1753      2162095 :         if (gc_needed(av,2))
    1754              :         {
    1755            0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    1756            0 :           gc_lll(av,3,&G,&B,&U);
    1757              :         }
    1758              :         /* we consider separately the case |X| = 1 */
    1759      2162095 :         if (dpe_abssmall(tmp))
    1760              :         {
    1761      1125034 :           if (tmp->d > 0) { /* in this case, X = 1 */
    1762      2890476 :             for (k=zeros+1; k<j; k++)
    1763      2326779 :               dpe_subz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1764      6231950 :             for (i=1; i<=n; i++)
    1765      5668253 :               subzi(&gmael(B,kappa,i), gmael(B,j,i));
    1766      7694813 :             for (i=1; i<=d; i++)
    1767      7131116 :               subzi(&gmael(U,kappa,i), gmael(U,j,i));
    1768       563697 :             btop = avma;
    1769       563697 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1770       563697 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1771       563697 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1772      3799256 :             for (i=1; i<=j; i++)
    1773      3235559 :               subzi(&gmael(G,kappa,i), gmael(G,j,i));
    1774      3156382 :             for (i=j+1; i<kappa; i++)
    1775      2592685 :               subzi(&gmael(G,kappa,i), gmael(G,i,j));
    1776      2791511 :             for (i=kappa+1; i<=maxG; i++)
    1777      2227814 :               subzi(&gmael(G,i,kappa), gmael(G,i,j));
    1778              :           } else { /* otherwise X = -1 */
    1779      2877882 :             for (k=zeros+1; k<j; k++)
    1780      2316545 :               dpe_addz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1781      6213250 :             for (i=1; i<=n; i++)
    1782      5651913 :               addzi(&gmael(B,kappa,i),gmael(B,j,i));
    1783      7569084 :             for (i=1; i<=d; i++)
    1784      7007747 :               addzi(&gmael(U,kappa,i),gmael(U,j,i));
    1785       561337 :             btop = avma;
    1786       561337 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1787       561337 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1788       561337 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1789      3719376 :             for (i=1; i<=j; i++)
    1790      3158039 :               addzi(&gmael(G,kappa,i), gmael(G,j,i));
    1791      3142201 :             for (i=j+1; i<kappa; i++)
    1792      2580864 :               addzi(&gmael(G,kappa,i), gmael(G,i,j));
    1793      2741420 :             for (i=kappa+1; i<=maxG; i++)
    1794      2180083 :               addzi(&gmael(G,i,kappa), gmael(G,i,j));
    1795              :           }
    1796      1125034 :           continue;
    1797              :         }
    1798              :         /* we have |X| >= 2 */
    1799      1037061 :         if (tmp->e < BITS_IN_LONG-1)
    1800              :         {
    1801       616944 :           if (tmp->d > 0)
    1802              :           {
    1803       332247 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, tmp->e)); /* X fits in an ulong */
    1804      1742356 :             for (k=zeros+1; k<j; k++)
    1805      1410109 :               dpe_submuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1806      4682926 :             for (i=1; i<=n; i++)
    1807      4350679 :               submulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1808      3249944 :             for (i=1; i<=d; i++)
    1809      2917697 :               submulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1810       332247 :             btop = avma;
    1811       332247 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1812       332247 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1813       332247 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1814      2484674 :             for (i=1; i<=j; i++)
    1815      2152427 :               submulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1816      2009292 :             for (i=j+1; i<kappa; i++)
    1817      1677045 :               submulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1818      1329238 :             for (i=kappa+1; i<=maxG; i++)
    1819       996991 :               submulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1820              :           }
    1821              :           else
    1822              :           {
    1823       284697 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, tmp->e)); /* X fits in an ulong */
    1824      1608550 :             for (k=zeros+1; k<j; k++)
    1825      1323853 :               dpe_addmuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1826      4610792 :             for (i=1; i<=n; i++)
    1827      4326095 :               addmulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1828      2500559 :             for (i=1; i<=d; i++)
    1829      2215862 :               addmulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1830       284697 :             btop = avma;
    1831       284697 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1832       284697 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1833       284697 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1834      2141410 :             for (i=1; i<=j; i++)
    1835      1856713 :               addmulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1836      1865183 :             for (i=j+1; i<kappa; i++)
    1837      1580486 :               addmulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1838      1007072 :             for (i=kappa+1; i<=maxG; i++)
    1839       722375 :               addmulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1840              :           }
    1841              :         }
    1842              :         else
    1843              :         {
    1844       420117 :           long e = tmp->e - BITS_IN_LONG + 1;
    1845       420117 :           if (tmp->d > 0)
    1846              :           {
    1847       208860 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, BITS_IN_LONG - 1));
    1848      3123657 :             for (k=zeros+1; k<j; k++)
    1849              :             {
    1850              :               dpe_t x;
    1851      2914797 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1852      2914797 :               x.e += e;
    1853      2914797 :               dpe_subz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1854              :             }
    1855     10691360 :             for (i=1; i<=n; i++)
    1856     10482500 :               submulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1857       317067 :             for (i=1; i<=d; i++)
    1858       108207 :               submulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1859       208860 :             btop = avma;
    1860       208860 :             ztmp = submuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1861       208860 :                 gmael(G,kappa,j), xx, e+1);
    1862       208860 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1863       208860 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1864      3334383 :             for (i=1; i<=j; i++)
    1865      3125523 :               submulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1866      3258960 :             for (   ; i<kappa; i++)
    1867      3050100 :               submulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1868       210885 :             for (i=kappa+1; i<=maxG; i++)
    1869         2025 :               submulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1870              :           } else
    1871              :           {
    1872       211257 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, BITS_IN_LONG - 1));
    1873      3184094 :             for (k=zeros+1; k<j; k++)
    1874              :             {
    1875              :               dpe_t x;
    1876      2972837 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1877      2972837 :               x.e += e;
    1878      2972837 :               dpe_addz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1879              :             }
    1880     10828909 :             for (i=1; i<=n; i++)
    1881     10617652 :               addmulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1882       319871 :             for (i=1; i<=d; i++)
    1883       108614 :               addmulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1884       211257 :             btop = avma;
    1885       211257 :             ztmp = addmuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1886       211257 :                 gmael(G,kappa,j), xx, e+1);
    1887       211257 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1888       211257 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1889      3397006 :             for (i=1; i<=j; i++)
    1890      3185749 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1891      3264771 :             for (   ; i<kappa; i++)
    1892      3053514 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1893       213123 :             for (i=kappa+1; i<=maxG; i++)
    1894         1866 :               addmulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1895              :           }
    1896              :         }
    1897              :       }
    1898      5362830 :     if (!go_on) break; /* Anything happened? */
    1899       600507 :     aa = zeros+1;
    1900              :   }
    1901              : 
    1902      4762323 :   affidpe(gmael(G,kappa,kappa), Del(s,zeros+1));
    1903              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    1904     14644821 :   for (k=zeros+1; k<=kappa-2; k++)
    1905      9882498 :     dpe_submulz(Del(s,k), Dmael(mu,kappa,k), Dmael(r,kappa,k), Del(s,k+1));
    1906      4762323 :   *pG = G; *pB = B; *pU = U; return 0;
    1907              : }
    1908              : 
    1909              : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    1910              :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    1911              :  * If G = NULL, we compute the Gram matrix incrementally.
    1912              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1913              : static long
    1914      1605219 : fplll_dpe(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    1915              :       long keepfirst)
    1916              : {
    1917              :   pari_sp av;
    1918      1605219 :   GEN Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    1919      1605219 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    1920              :   dpe_t delta, eta, **mu, **r, *s;
    1921      1605219 :   affdbldpe(DELTA,&delta);
    1922      1605219 :   affdbldpe(ETA,&eta);
    1923              : 
    1924      1605219 :   if (incgram)
    1925              :   { /* incremental Gram matrix */
    1926      1544664 :     maxG = 2; d = lg(B)-1;
    1927      1544664 :     G = zeromatcopy(d, d);
    1928              :   }
    1929              :   else
    1930        60555 :     maxG = d = lg(G)-1;
    1931              : 
    1932      1605219 :   mu = cget_dpemat(d+1);
    1933      1605219 :   r  = cget_dpemat(d+1);
    1934      1605219 :   s  = cget_dpevec(d+1);
    1935      7460928 :   for (j = 1; j <= d; j++)
    1936              :   {
    1937      5855709 :     mu[j]= cget_dpevec(d+1);
    1938      5855709 :     r[j] = cget_dpevec(d+1);
    1939              :   }
    1940      1605219 :   Gtmp = cgetg(d+1, t_VEC);
    1941      1605219 :   alpha = cgetg(d+1, t_VECSMALL);
    1942      1605219 :   av = avma;
    1943              : 
    1944              :   /* Step2: Initializing the main loop */
    1945      1605219 :   kappamax = 1;
    1946      1605219 :   i = 1;
    1947              :   do {
    1948      1988313 :     if (incgram) gmael(G,i,i) = ZV_dotsquare(gel(B,i));
    1949      1988313 :     affidpe(gmael(G,i,i), Dmael(r,i,i));
    1950      1988313 :   } while (!signe(gmael(G,i,i)) && ++i <= d);
    1951      1605219 :   zeros = i-1; /* all basis vectors b_i with i <= zeros are zero vectors */
    1952      1605219 :   kappa = i;
    1953      7077827 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1954              : 
    1955      6367542 :   while (++kappa <= d)
    1956              :   {
    1957      4762323 :     if (kappa > kappamax)
    1958              :     {
    1959      3867396 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1960      3867396 :       kappamax = kappa;
    1961      3867396 :       if (incgram)
    1962              :       {
    1963     16216978 :         for (i=zeros+1; i<=kappa; i++)
    1964     12550101 :           gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i));
    1965      3666877 :         maxG = kappamax;
    1966              :       }
    1967              :     }
    1968              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1969      4762323 :     if (Babai_dpe(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, &eta))
    1970            0 :     { *pG = incgram? NULL: G; *pB = B; *pU = U; return -1; }
    1971      9424429 :     if ((keepfirst && kappa == 2) ||
    1972      4662106 :         dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) <= 0)
    1973              :     { /* Step4: Success of Lovasz's condition */
    1974      4404169 :       alpha[kappa] = kappa;
    1975      4404169 :       dpe_submulz(Del(s,kappa-1), Dmael(mu,kappa,kappa-1), Dmael(r,kappa,kappa-1), Dmael(r,kappa,kappa));
    1976      4404169 :       continue;
    1977              :     }
    1978              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1979       358154 :     if (DEBUGLEVEL>=4 && kappa==kappamax && Del(s,kappa-1)->d)
    1980            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", Del(s,1)->e-1); }
    1981       358154 :     kappa2 = kappa;
    1982              :     do {
    1983       930116 :       kappa--;
    1984       930116 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1985       807695 :     } while (dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) >= 0);
    1986       358154 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1987              : 
    1988              :     /* Step6: Update the mu's and r's */
    1989       358154 :     dperotate(mu, kappa2, kappa);
    1990       358154 :     dperotate(r, kappa2, kappa);
    1991       358154 :     affdpe(Del(s,kappa), Dmael(r,kappa,kappa));
    1992              : 
    1993              :     /* Step7: Update G, B, U */
    1994       358154 :     if (U) rotate(U, kappa2, kappa);
    1995       358154 :     if (B) rotate(B, kappa2, kappa);
    1996       358154 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    1997              : 
    1998              :     /* Step8: Prepare the next loop iteration */
    1999       358154 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    2000              :     {
    2001        35189 :       zeros++; kappa++;
    2002        35189 :       affidpe(gmael(G,kappa,kappa), Dmael(r,kappa,kappa));
    2003              :     }
    2004              :   }
    2005      1605219 :   if (pr) *pr = dpeM_diagonal_shallow(r,d);
    2006      1605219 :   *pG = G; *pB = B; *pU = U; return zeros; /* success */
    2007              : }
    2008              : 
    2009              : 
    2010              : /************************** PROVED version (t_INT) *************************/
    2011              : 
    2012              : /* Babai's Nearest Plane algorithm (iterative).
    2013              :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    2014              :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    2015              :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    2016              : static int
    2017            0 : Babai(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, GEN mu, GEN r, GEN s,
    2018              :       long a, long zeros, long maxG, GEN eta, long prec)
    2019              : {
    2020            0 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    2021            0 :   long k, aa = a > zeros? a: zeros+1;
    2022            0 :   const long n = B? nbrows(B): 0, d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    2023            0 :   long emaxmu = EX0, emax2mu = EX0;
    2024              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    2025              : 
    2026            0 :   for (;;) {
    2027            0 :     int go_on = 0;
    2028            0 :     long i, j, emax3mu = emax2mu;
    2029              : 
    2030            0 :     if (gc_needed(av,2))
    2031              :     {
    2032            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    2033            0 :       gc_lll(av,3,&G,&B,&U);
    2034              :     }
    2035              :     /* Step2: compute the GSO for stage kappa */
    2036            0 :     emax2mu = emaxmu; emaxmu = EX0;
    2037            0 :     for (j=aa; j<kappa; j++)
    2038              :     {
    2039            0 :       pari_sp btop = avma;
    2040            0 :       GEN g = gmael(G,kappa,j);
    2041            0 :       k = zeros + 1;
    2042            0 :       if (k >= j)
    2043            0 :         affir(g, gmael(r,kappa,j));
    2044              :       else
    2045              :       {
    2046            0 :         g = subir(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    2047            0 :         for (k++; k < j; k++)
    2048            0 :           g = subrr(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    2049            0 :         affrr(g, gmael(r,kappa,j));
    2050              :       }
    2051            0 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    2052            0 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    2053            0 :       set_avma(btop);
    2054              :     }
    2055            0 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    2056            0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    2057              : 
    2058            0 :     for (j=kappa-1; j>zeros; j--)
    2059            0 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    2060              : 
    2061              :     /* Step3--5: compute the X_j's  */
    2062            0 :     if (go_on)
    2063            0 :       for (j=kappa-1; j>zeros; j--)
    2064              :       {
    2065              :         pari_sp btop;
    2066            0 :         GEN tmp = gmael(mu,kappa,j);
    2067            0 :         if (absrsmall(tmp)) continue; /* size-reduced */
    2068              : 
    2069            0 :         if (gc_needed(av,2))
    2070              :         {
    2071            0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    2072            0 :           gc_lll(av,3,&G,&B,&U);
    2073              :         }
    2074            0 :         btop = avma;
    2075              :         /* we consider separately the case |X| = 1 */
    2076            0 :         if (absrsmall2(tmp))
    2077              :         {
    2078            0 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    2079            0 :             for (k=zeros+1; k<j; k++)
    2080            0 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2081            0 :             set_avma(btop);
    2082            0 :             for (i=1; i<=n; i++)
    2083            0 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    2084            0 :             for (i=1; i<=d; i++)
    2085            0 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
    2086            0 :             btop = avma;
    2087            0 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2088            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2089            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2090            0 :             for (i=1; i<=j; i++)
    2091            0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,j,i));
    2092            0 :             for (i=j+1; i<kappa; i++)
    2093            0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,i,j));
    2094            0 :             for (i=kappa+1; i<=maxG; i++)
    2095            0 :               gmael(G,i,kappa) = subii(gmael(G,i,kappa), gmael(G,i,j));
    2096              :           } else { /* otherwise X = -1 */
    2097            0 :             for (k=zeros+1; k<j; k++)
    2098            0 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2099            0 :             set_avma(btop);
    2100            0 :             for (i=1; i<=n; i++)
    2101            0 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i),gmael(B,j,i));
    2102            0 :             for (i=1; i<=d; i++)
    2103            0 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    2104            0 :             btop = avma;
    2105            0 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2106            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2107            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2108            0 :             for (i=1; i<=j; i++)
    2109            0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,j,i));
    2110            0 :             for (i=j+1; i<kappa; i++)
    2111            0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,i,j));
    2112            0 :             for (i=kappa+1; i<=maxG; i++)
    2113            0 :               gmael(G,i,kappa) = addii(gmael(G,i,kappa), gmael(G,i,j));
    2114              :           }
    2115            0 :           continue;
    2116              :         }
    2117              :         /* we have |X| >= 2 */
    2118            0 :         if (expo(tmp) < BITS_IN_LONG)
    2119              :         {
    2120            0 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    2121            0 :           if (signe(tmp) > 0) /* = xx */
    2122              :           {
    2123            0 :             for (k=zeros+1; k<j; k++)
    2124            0 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2125            0 :                   gmael(mu,kappa,k));
    2126            0 :             set_avma(btop);
    2127            0 :             for (i=1; i<=n; i++)
    2128            0 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2129            0 :             for (i=1; i<=d; i++)
    2130            0 :               gmael(U,kappa,i) = submuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2131            0 :             btop = avma;
    2132            0 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2133            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2134            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2135            0 :             for (i=1; i<=j; i++)
    2136            0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2137            0 :             for (i=j+1; i<kappa; i++)
    2138            0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2139            0 :             for (i=kappa+1; i<=maxG; i++)
    2140            0 :               gmael(G,i,kappa) = submuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2141              :           }
    2142              :           else /* = -xx */
    2143              :           {
    2144            0 :             for (k=zeros+1; k<j; k++)
    2145            0 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2146            0 :                   gmael(mu,kappa,k));
    2147            0 :             set_avma(btop);
    2148            0 :             for (i=1; i<=n; i++)
    2149            0 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2150            0 :             for (i=1; i<=d; i++)
    2151            0 :               gmael(U,kappa,i) = addmuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2152            0 :             btop = avma;
    2153            0 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2154            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2155            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2156            0 :             for (i=1; i<=j; i++)
    2157            0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2158            0 :             for (i=j+1; i<kappa; i++)
    2159            0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2160            0 :             for (i=kappa+1; i<=maxG; i++)
    2161            0 :               gmael(G,i,kappa) = addmuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2162              :           }
    2163              :         }
    2164              :         else
    2165              :         {
    2166              :           long e;
    2167            0 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    2168            0 :           btop = avma;
    2169            0 :           for (k=zeros+1; k<j; k++)
    2170              :           {
    2171            0 :             GEN x = mulir(X, gmael(mu,j,k));
    2172            0 :             if (e) shiftr_inplace(x, e);
    2173            0 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    2174              :           }
    2175            0 :           set_avma(btop);
    2176            0 :           for (i=1; i<=n; i++)
    2177            0 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    2178            0 :           for (i=1; i<=d; i++)
    2179            0 :             gmael(U,kappa,i) = submulshift(gmael(U,kappa,i), gmael(U,j,i), X, e);
    2180            0 :           btop = avma;
    2181            0 :           ztmp = submulshift(mulshift(gmael(G,j,j), sqri(X), 2*e),
    2182            0 :               gmael(G,kappa,j), X, e+1);
    2183            0 :           ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2184            0 :           gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2185            0 :           for (i=1; i<=j; i++)
    2186            0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,j,i), X, e);
    2187            0 :           for (   ; i<kappa; i++)
    2188            0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,i,j), X, e);
    2189            0 :           for (i=kappa+1; i<=maxG; i++)
    2190            0 :             gmael(G,i,kappa) = submulshift(gmael(G,i,kappa), gmael(G,i,j), X, e);
    2191              :         }
    2192              :       }
    2193            0 :     if (!go_on) break; /* Anything happened? */
    2194            0 :     aa = zeros+1;
    2195              :   }
    2196              : 
    2197            0 :   affir(gmael(G,kappa,kappa), gel(s,zeros+1));
    2198              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    2199            0 :   av = avma;
    2200            0 :   for (k=zeros+1; k<=kappa-2; k++)
    2201            0 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    2202            0 :           gel(s,k+1));
    2203            0 :   *pG = G; *pB = B; *pU = U; return gc_bool(av, 0);
    2204              : }
    2205              : 
    2206              : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    2207              :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    2208              :  * If G = NULL, we compute the Gram matrix incrementally.
    2209              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    2210              : static long
    2211            0 : fplll(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    2212              :       long keepfirst, long prec)
    2213              : {
    2214              :   pari_sp av, av2;
    2215            0 :   GEN mu, r, s, tmp, Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    2216            0 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    2217            0 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    2218              : 
    2219            0 :   if (incgram)
    2220              :   { /* incremental Gram matrix */
    2221            0 :     maxG = 2; d = lg(B)-1;
    2222            0 :     G = zeromatcopy(d, d);
    2223              :   }
    2224              :   else
    2225            0 :     maxG = d = lg(G)-1;
    2226              : 
    2227            0 :   mu = cgetg(d+1, t_MAT);
    2228            0 :   r  = cgetg(d+1, t_MAT);
    2229            0 :   s  = cgetg(d+1, t_VEC);
    2230            0 :   for (j = 1; j <= d; j++)
    2231              :   {
    2232            0 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL);
    2233            0 :     gel(mu,j)= M;
    2234            0 :     gel(r,j) = R;
    2235            0 :     gel(s,j) = cgetr(prec);
    2236            0 :     for (i = 1; i <= d; i++)
    2237              :     {
    2238            0 :       gel(R,i) = cgetr(prec);
    2239            0 :       gel(M,i) = cgetr(prec);
    2240              :     }
    2241              :   }
    2242            0 :   Gtmp = cgetg(d+1, t_VEC);
    2243            0 :   alpha = cgetg(d+1, t_VECSMALL);
    2244            0 :   av = avma;
    2245              : 
    2246              :   /* Step2: Initializing the main loop */
    2247            0 :   kappamax = 1;
    2248            0 :   i = 1;
    2249              :   do {
    2250            0 :     if (incgram) gmael(G,i,i) = ZV_dotsquare(gel(B,i));
    2251            0 :     affir(gmael(G,i,i), gmael(r,i,i));
    2252            0 :   } while (!signe(gmael(G,i,i)) && ++i <= d);
    2253            0 :   zeros = i-1; /* all basis vectors b_i with i <= zeros are zero vectors */
    2254            0 :   kappa = i;
    2255            0 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    2256              : 
    2257            0 :   while (++kappa <= d)
    2258              :   {
    2259            0 :     if (kappa > kappamax)
    2260              :     {
    2261            0 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    2262            0 :       kappamax = kappa;
    2263            0 :       if (incgram)
    2264              :       {
    2265            0 :         for (i=zeros+1; i<=kappa; i++)
    2266            0 :           gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i));
    2267            0 :         maxG = kappamax;
    2268              :       }
    2269              :     }
    2270              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    2271            0 :     if (Babai(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, eta, prec))
    2272            0 :     { *pG = incgram? NULL: G; *pB = B; *pU = U; return -1; }
    2273            0 :     av2 = avma;
    2274            0 :     if ((keepfirst && kappa == 2) ||
    2275            0 :         cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0)
    2276              :     { /* Step4: Success of Lovasz's condition */
    2277            0 :       alpha[kappa] = kappa;
    2278            0 :       tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1));
    2279            0 :       affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa));
    2280            0 :       set_avma(av2); continue;
    2281              :     }
    2282              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    2283            0 :     if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1)))
    2284            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); }
    2285            0 :     kappa2 = kappa;
    2286              :     do {
    2287            0 :       kappa--;
    2288            0 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    2289            0 :       tmp = mulrr(gmael(r,kappa-1,kappa-1), delta);
    2290            0 :     } while (cmprr(gel(s,kappa-1), tmp) <= 0);
    2291            0 :     set_avma(av2);
    2292            0 :     update_alpha(alpha, kappa, kappa2, kappamax);
    2293              : 
    2294              :     /* Step6: Update the mu's and r's */
    2295            0 :     rotate(mu, kappa2, kappa);
    2296            0 :     rotate(r, kappa2, kappa);
    2297            0 :     affrr(gel(s,kappa), gmael(r,kappa,kappa));
    2298              : 
    2299              :     /* Step7: Update G, B, U */
    2300            0 :     if (U) rotate(U, kappa2, kappa);
    2301            0 :     if (B) rotate(B, kappa2, kappa);
    2302            0 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    2303              : 
    2304              :     /* Step8: Prepare the next loop iteration */
    2305            0 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    2306              :     {
    2307            0 :       zeros++; kappa++;
    2308            0 :       affir(gmael(G,kappa,kappa), gmael(r,kappa,kappa));
    2309              :     }
    2310              :   }
    2311            0 :   if (pr) *pr = RgM_diagonal_shallow(r);
    2312            0 :   *pG = G; *pB = B; *pU = U; return zeros; /* success */
    2313              : }
    2314              : 
    2315              : /* do not support LLL_KER, LLL_ALL, LLL_KEEP_FIRST */
    2316              : static GEN
    2317      4851314 : ZM2_lll_norms(GEN x, long flag, GEN *pN)
    2318              : {
    2319              :   GEN a,b,c,d;
    2320              :   GEN G, U;
    2321      4851314 :   if (flag & LLL_GRAM)
    2322         7355 :     G = x;
    2323              :   else
    2324      4843959 :     G = gram_matrix(x);
    2325      4851314 :   a = gcoeff(G,1,1); b = shifti(gcoeff(G,1,2),1); c = gcoeff(G,2,2);
    2326      4851314 :   d = qfb_disc3(a,b,c);
    2327      4851314 :   if (signe(d)>=0) return NULL;
    2328      4850929 :   G = redimagsl2(mkqfb(a,b,c,d),&U);
    2329      4850929 :   if (pN) (void) RgM_gram_schmidt(G, pN);
    2330      4850929 :   if (flag & LLL_INPLACE) return ZM2_mul(x,U);
    2331      4850929 :   return U;
    2332              : }
    2333              : 
    2334              : static void
    2335       626223 : fplll_flatter(GEN *pG, GEN *pB, GEN *pU, long rank, long flag)
    2336              : {
    2337       626223 :   if (!*pG)
    2338              :   {
    2339       625255 :     GEN T = ZM_flatter_rank(*pB, rank, flag);
    2340       625255 :     if (T)
    2341              :     {
    2342       328504 :       if (*pU)
    2343              :       {
    2344       314496 :         *pU = ZM_mul(*pU, T);
    2345       314496 :         *pB = ZM_mul(*pB, T);
    2346              :       }
    2347        14008 :       else *pB = T;
    2348              :     }
    2349              :   }
    2350              :   else
    2351              :   {
    2352          968 :     GEN T, G = *pG;
    2353          968 :     long i, j, l = lg(G);
    2354         7634 :     for (i = 1; i < l; i++)
    2355        56193 :       for(j = 1; j < i; j++) gmael(G,j,i) = gmael(G,i,j);
    2356          968 :     T = ZM_flattergram_rank(G, rank, flag);
    2357          968 :     if (T)
    2358              :     {
    2359          968 :       if (*pU) *pU = ZM_mul(*pU, T);
    2360          968 :       *pG = qf_ZM_apply(*pG, T);
    2361              :     }
    2362              :   }
    2363       626223 : }
    2364              : 
    2365              : static GEN
    2366      1099663 : get_gramschmidt(GEN M, long rank)
    2367              : {
    2368              :   GEN B, Q, L;
    2369      1099663 :   long r = lg(M)-1, prec = nbits2prec64(3*r + 30);
    2370      1099663 :   if (rank < r) M = vconcat(gshift(M,1), matid(r));
    2371      1099663 :   if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec)) return NULL;
    2372       475541 :   return L;
    2373              : }
    2374              : 
    2375              : static GEN
    2376        44546 : get_cholesky(GEN M, long rank)
    2377              : {
    2378        44546 :   long r = lg(M)-1, prec = nbits2prec64(3*r + 30);
    2379        44546 :   if (rank < r) M = RgM_Rg_add(gshift(M, 1), gen_1);
    2380        44546 :   return RgM_Cholesky(RgM_gtofp(M, prec), prec);
    2381              : }
    2382              : 
    2383              : static long
    2384        92851 : thsn(long n)
    2385              : {
    2386        92851 :   long T[]={23280,30486,50077,44136,78724,15690,1801,1611,
    2387              :             981,1359,978,1042,815,866,788,775,726,712,
    2388              :             626,613,548,564,474,481,504,447,453,508,
    2389              :             705,794,1008,946,767,898,886,763,842,757,
    2390              :             725,774,639,655,705,627,635,704,511,613,
    2391              :             583,595,568,640,541,640,567,540,577,584,
    2392              :             546,509,526,572,637,746,772,743,743,742,800,708,832,768,707,692,692,768,696,635,709,694,768,719,655,569,590,644,685,623,627,720,633,636,602,635,575,631,642,647,632,656,573,511,688,640,528,616,511,559,601,620,635,688,608,768,658,582,644,704,555,673,600,601,641,661,601,670};
    2393        92851 :   return T[minss(n-3,numberof(T)-1)];
    2394              : }
    2395              : static long
    2396      1033915 : thre(long n)
    2397              : {
    2398      1033915 :   long T[]={31783,34393,20894,22525,13533,1928,672,671,
    2399              :             422,506,315,313,222,205,167,154,139,138,
    2400              :             110,120,98,94,81,75,74,64,74,74,
    2401              :             79,96,112,111,105,104,96,86,84,78,75,70,66,62,62,57,56,47,45,52,50,44,48,42,36,35,35,34,40,33,34,32,36,31,
    2402              :             38,38,40,38,38,37,35,31,34,36,34,32,34,32,28,27,25,31,25,27,28,26,25,21,21,25,25,22,21,24,24,22,21,23,22,22,22,22,21,24,21,22,19,20,19,20,19,19,19,18,19,18,18,20,19,20,18,19,18,21,18,20,18,18};
    2403      1033915 :    return T[minss(n-3,numberof(T)-1)];
    2404              : }
    2405              : 
    2406              : /* Assume x a ZM, if pN != NULL, set it to Gram-Schmidt (squared) norms
    2407              :  * The following modes are supported:
    2408              :  * - flag & LLL_INPLACE: x a lattice basis, return x*U
    2409              :  * - flag & LLL_GRAM: x a Gram matrix / else x a lattice basis; return
    2410              :  *     LLL base change matrix U [LLL_IM]
    2411              :  *     kernel basis [LLL_KER, nonreduced]
    2412              :  *     both [LLL_ALL] */
    2413              : GEN
    2414      7144245 : ZM_lll_norms(GEN x, double DELTA, long flag, GEN *pN)
    2415              : {
    2416      7144245 :   pari_sp av = avma;
    2417      7144245 :   const double ETA = 0.51;
    2418      7144245 :   const long keepfirst = flag & LLL_KEEP_FIRST;
    2419      7144245 :   long p, zeros = -1, n = lg(x)-1, is_upper, is_lower, useflatter, rank;
    2420      7144245 :   GEN G, B, U, L = NULL;
    2421              :   pari_timer T;
    2422      7144245 :   if (n <= 1) return lll_trivial(x, flag);
    2423      7034175 :   if (nbrows(x)==0)
    2424              :   {
    2425        15149 :     if (flag & LLL_KER) return matid(n);
    2426        15149 :     if (flag & (LLL_INPLACE|LLL_IM)) return cgetg(1,t_MAT);
    2427            0 :     retmkvec2(matid(n), cgetg(1,t_MAT));
    2428              :   }
    2429      7019026 :   if (n==2 && nbrows(x)==2  && (flag&LLL_IM) && !keepfirst)
    2430              :   {
    2431      4851314 :     U = ZM2_lll_norms(x, flag, pN);
    2432      4851314 :     if (U) return U;
    2433              :   }
    2434      2168097 :   if (flag & LLL_GRAM)
    2435        60555 :   { G = x; B = NULL; U = matid(n); is_upper = 0; is_lower = 0; }
    2436              :   else
    2437              :   {
    2438      2107542 :     G = NULL; B = x; U = (flag & LLL_INPLACE)? NULL: matid(n);
    2439      2107542 :     is_upper = (flag & LLL_UPPER) || ZM_is_upper(B);
    2440      2107542 :     is_lower = !B || is_upper || keepfirst ? 0: ZM_is_lower(B);
    2441      2107542 :     if (is_lower) L = RgM_flip(B);
    2442              :   }
    2443      2168097 :   rank = useflatter = 0;
    2444      2168097 :   if (n > 2 && !(flag&LLL_NOFLATTER))
    2445              :   {
    2446      1751856 :     pari_sp av2 = avma;
    2447              :     GEN R;
    2448      1751856 :     rank = ZM_rank(x);
    2449      1707310 :     R = B ? (is_upper ? B : (is_lower ? L : get_gramschmidt(B, rank)))
    2450      3459166 :           : get_cholesky(G, rank);
    2451      1751856 :     if (R)
    2452              :     {
    2453      1126766 :       long spr = spread(R), sz = gexpo(R), thr;
    2454      1126766 :       if (DEBUGLEVEL>=5)
    2455            0 :         err_printf("LLL: dim %ld, size %ld, spread %ld\n",n, sz, spr);
    2456      1126766 :       if ((is_upper && ZM_is_knapsack(B)) || (is_lower && ZM_is_knapsack(L)))
    2457        92851 :         thr = thsn(n);
    2458              :       else
    2459              :       {
    2460      1033915 :         thr = thre(n);
    2461      1033915 :         if (n >= 10) sz = spr;
    2462              :       }
    2463      1126766 :       useflatter = sz >= thr;
    2464              :     } else
    2465       625090 :       useflatter = 1;
    2466      1751856 :     set_avma(av2);
    2467              :   }
    2468      2168097 :   if(DEBUGLEVEL>=4) timer_start(&T);
    2469      2168097 :   if (useflatter)
    2470              :   {
    2471       626223 :     if (is_lower)
    2472              :     {
    2473            0 :       fplll_flatter(&G, &L, &U, rank, flag | LLL_UPPER);
    2474            0 :       B = RgM_flop(L);
    2475            0 :       if (U) U = RgM_flop(U);
    2476              :     }
    2477              :     else
    2478       626223 :       fplll_flatter(&G, &B, &U, rank, flag | (is_upper? LLL_UPPER:0));
    2479       626223 :     if (DEBUGLEVEL>=4  && !(flag & LLL_NOCERTIFY))
    2480            0 :       timer_printf(&T, "FLATTER");
    2481              :   }
    2482      2168097 :   if (!(flag & LLL_GRAM))
    2483              :   {
    2484              :     long t;
    2485      2107542 :     long heu_max = n<100 ? 1: 2; /* need better tuning */
    2486      2107542 :     B = gcopy(B);
    2487      2107542 :     if(DEBUGLEVEL>=4)
    2488            0 :       err_printf("Entering L^2 (double): dim %ld, LLL-parameters (%.3f,%.3f)\n",
    2489              :                  n, DELTA,ETA);
    2490      2107542 :     zeros = fplll_fast(&B, &U, DELTA, ETA, keepfirst);
    2491      2107542 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2492      2112234 :     for (p = DEFAULTPREC, t = 0; zeros < 0 && t < heu_max ; p += EXTRAPREC64, t++)
    2493              :     {
    2494         4692 :       if (DEBUGLEVEL>=4)
    2495            0 :         err_printf("Entering L^2 (heuristic): LLL-parameters (%.3f,%.3f), prec = %d/%d\n", DELTA, ETA, p, p);
    2496         4692 :       zeros = fplll_heuristic(&B, &U, DELTA, ETA, keepfirst, p, p);
    2497         4692 :       gc_lll(av, 2, &B, &U);
    2498         4692 :       if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2499              :     }
    2500              :   } else
    2501        60555 :     G = gcopy(G);
    2502      2168097 :   if (zeros < 0 || !(flag & LLL_NOCERTIFY))
    2503              :   {
    2504      1605219 :     if(DEBUGLEVEL>=4)
    2505            0 :       err_printf("Entering L^2 (dpe): LLL-parameters (%.3f,%.3f)\n", DELTA,ETA);
    2506      1605219 :     zeros = fplll_dpe(&G, &B, &U, pN, DELTA, ETA, keepfirst);
    2507      1605219 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2508      1605219 :     if (zeros < 0)
    2509            0 :       for (p = DEFAULTPREC;; p += EXTRAPREC64)
    2510              :       {
    2511            0 :         if (DEBUGLEVEL>=4)
    2512            0 :           err_printf("Entering L^2: LLL-parameters (%.3f,%.3f), prec = %d\n",
    2513              :               DELTA,ETA, p);
    2514            0 :         zeros = fplll(&G, &B, &U, pN, DELTA, ETA, keepfirst, p);
    2515            0 :         if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2516            0 :         if (zeros >= 0) break;
    2517            0 :         gc_lll(av, 3, &G, &B, &U);
    2518              :       }
    2519              :   }
    2520      2168097 :   return lll_finish(U? U: B, zeros, flag);
    2521              : }
    2522              : 
    2523              : /********************************************************************/
    2524              : /**                                                                **/
    2525              : /**                        LLL OVER K[X]                           **/
    2526              : /**                                                                **/
    2527              : /********************************************************************/
    2528              : static int
    2529          504 : pslg(GEN x)
    2530              : {
    2531              :   long tx;
    2532          504 :   if (gequal0(x)) return 2;
    2533          448 :   tx = typ(x); return is_scalar_t(tx)? 3: lg(x);
    2534              : }
    2535              : 
    2536              : static int
    2537          196 : REDgen(long k, long l, GEN h, GEN L, GEN B)
    2538              : {
    2539          196 :   GEN q, u = gcoeff(L,k,l);
    2540              :   long i;
    2541              : 
    2542          196 :   if (pslg(u) < pslg(B)) return 0;
    2543              : 
    2544          140 :   q = gneg(gdeuc(u,B));
    2545          140 :   gel(h,k) = gadd(gel(h,k), gmul(q,gel(h,l)));
    2546          140 :   for (i=1; i<l; i++) gcoeff(L,k,i) = gadd(gcoeff(L,k,i), gmul(q,gcoeff(L,l,i)));
    2547          140 :   gcoeff(L,k,l) = gadd(gcoeff(L,k,l), gmul(q,B)); return 1;
    2548              : }
    2549              : 
    2550              : static int
    2551          196 : do_SWAPgen(GEN h, GEN L, GEN B, long k, GEN fl, int *flc)
    2552              : {
    2553              :   GEN p1, la, la2, Bk;
    2554              :   long ps1, ps2, i, j, lx;
    2555              : 
    2556          196 :   if (!fl[k-1]) return 0;
    2557              : 
    2558          140 :   la = gcoeff(L,k,k-1); la2 = gsqr(la);
    2559          140 :   Bk = gel(B,k);
    2560          140 :   if (fl[k])
    2561              :   {
    2562           56 :     GEN q = gadd(la2, gmul(gel(B,k-1),gel(B,k+1)));
    2563           56 :     ps1 = pslg(gsqr(Bk));
    2564           56 :     ps2 = pslg(q);
    2565           56 :     if (ps1 <= ps2 && (ps1 < ps2 || !*flc)) return 0;
    2566           28 :     *flc = (ps1 != ps2);
    2567           28 :     gel(B,k) = gdiv(q, Bk);
    2568              :   }
    2569              : 
    2570          112 :   swap(gel(h,k-1), gel(h,k)); lx = lg(L);
    2571          112 :   for (j=1; j<k-1; j++) swap(gcoeff(L,k-1,j), gcoeff(L,k,j));
    2572          112 :   if (fl[k])
    2573              :   {
    2574           28 :     for (i=k+1; i<lx; i++)
    2575              :     {
    2576            0 :       GEN t = gcoeff(L,i,k);
    2577            0 :       p1 = gsub(gmul(gel(B,k+1),gcoeff(L,i,k-1)), gmul(la,t));
    2578            0 :       gcoeff(L,i,k) = gdiv(p1, Bk);
    2579            0 :       p1 = gadd(gmul(la,gcoeff(L,i,k-1)), gmul(gel(B,k-1),t));
    2580            0 :       gcoeff(L,i,k-1) = gdiv(p1, Bk);
    2581              :     }
    2582              :   }
    2583           84 :   else if (!gequal0(la))
    2584              :   {
    2585           28 :     p1 = gdiv(la2, Bk);
    2586           28 :     gel(B,k+1) = gel(B,k) = p1;
    2587           28 :     for (i=k+2; i<=lx; i++) gel(B,i) = gdiv(gmul(p1,gel(B,i)),Bk);
    2588           28 :     for (i=k+1; i<lx; i++)
    2589            0 :       gcoeff(L,i,k-1) = gdiv(gmul(la,gcoeff(L,i,k-1)), Bk);
    2590           28 :     for (j=k+1; j<lx-1; j++)
    2591            0 :       for (i=j+1; i<lx; i++)
    2592            0 :         gcoeff(L,i,j) = gdiv(gmul(p1,gcoeff(L,i,j)), Bk);
    2593              :   }
    2594              :   else
    2595              :   {
    2596           56 :     gcoeff(L,k,k-1) = gen_0;
    2597           56 :     for (i=k+1; i<lx; i++)
    2598              :     {
    2599            0 :       gcoeff(L,i,k) = gcoeff(L,i,k-1);
    2600            0 :       gcoeff(L,i,k-1) = gen_0;
    2601              :     }
    2602           56 :     gel(B,k) = gel(B,k-1); fl[k] = 1; fl[k-1] = 0;
    2603              :   }
    2604          112 :   return 1;
    2605              : }
    2606              : 
    2607              : static void
    2608          168 : incrementalGSgen(GEN x, GEN L, GEN B, long k, GEN fl)
    2609              : {
    2610          168 :   GEN u = NULL; /* gcc -Wall */
    2611              :   long i, j;
    2612          420 :   for (j = 1; j <= k; j++)
    2613          252 :     if (j==k || fl[j])
    2614              :     {
    2615          252 :       u = gcoeff(x,k,j);
    2616          252 :       if (!is_extscalar_t(typ(u))) pari_err_TYPE("incrementalGSgen",u);
    2617          336 :       for (i=1; i<j; i++)
    2618           84 :         if (fl[i])
    2619              :         {
    2620           84 :           u = gsub(gmul(gel(B,i+1),u), gmul(gcoeff(L,k,i),gcoeff(L,j,i)));
    2621           84 :           u = gdiv(u, gel(B,i));
    2622              :         }
    2623          252 :       gcoeff(L,k,j) = u;
    2624              :     }
    2625          168 :   if (gequal0(u)) gel(B,k+1) = gel(B,k);
    2626              :   else
    2627              :   {
    2628          112 :     gel(B,k+1) = gcoeff(L,k,k); gcoeff(L,k,k) = gen_1; fl[k] = 1;
    2629              :   }
    2630          168 : }
    2631              : 
    2632              : static GEN
    2633          168 : lllgramallgen(GEN x, long flag)
    2634              : {
    2635          168 :   long lx = lg(x), i, j, k, l, n;
    2636              :   pari_sp av;
    2637              :   GEN B, L, h, fl;
    2638              :   int flc;
    2639              : 
    2640          168 :   n = lx-1; if (n<=1) return lll_trivial(x,flag);
    2641           84 :   if (lgcols(x) != lx) pari_err_DIM("lllgramallgen");
    2642              : 
    2643           84 :   fl = cgetg(lx, t_VECSMALL);
    2644              : 
    2645           84 :   av = avma;
    2646           84 :   B = scalarcol_shallow(gen_1, lx);
    2647           84 :   L = cgetg(lx,t_MAT);
    2648          252 :   for (j=1; j<lx; j++) { gel(L,j) = zerocol(n); fl[j] = 0; }
    2649              : 
    2650           84 :   h = matid(n);
    2651          252 :   for (i=1; i<lx; i++)
    2652          168 :     incrementalGSgen(x, L, B, i, fl);
    2653           84 :   flc = 0;
    2654           84 :   for(k=2;;)
    2655              :   {
    2656          196 :     if (REDgen(k, k-1, h, L, gel(B,k))) flc = 1;
    2657          196 :     if (do_SWAPgen(h, L, B, k, fl, &flc)) { if (k > 2) k--; }
    2658              :     else
    2659              :     {
    2660           84 :       for (l=k-2; l>=1; l--)
    2661            0 :         if (REDgen(k, l, h, L, gel(B,l+1))) flc = 1;
    2662           84 :       if (++k > n) break;
    2663              :     }
    2664          112 :     if (gc_needed(av,1))
    2665              :     {
    2666            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"lllgramallgen");
    2667            0 :       (void)gc_all(av,3,&B,&L,&h);
    2668              :     }
    2669              :   }
    2670          140 :   k=1; while (k<lx && !fl[k]) k++;
    2671           84 :   return lll_finish(h,k-1,flag);
    2672              : }
    2673              : 
    2674              : static GEN
    2675          168 : lllallgen(GEN x, long flag)
    2676              : {
    2677          168 :   pari_sp av = avma;
    2678          168 :   if (!(flag & LLL_GRAM)) x = gram_matrix(x);
    2679           84 :   else if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2680          168 :   return gc_GEN(av, lllgramallgen(x, flag));
    2681              : }
    2682              : GEN
    2683           42 : lllgen(GEN x) { return lllallgen(x, LLL_IM); }
    2684              : GEN
    2685           42 : lllkerimgen(GEN x) { return lllallgen(x, LLL_ALL); }
    2686              : GEN
    2687           42 : lllgramgen(GEN x)  { return lllallgen(x, LLL_IM|LLL_GRAM); }
    2688              : GEN
    2689           42 : lllgramkerimgen(GEN x)  { return lllallgen(x, LLL_ALL|LLL_GRAM); }
    2690              : 
    2691              : static GEN
    2692        36699 : lllall(GEN x, long flag)
    2693        36699 : { pari_sp av = avma; return gc_GEN(av, ZM_lll(x, LLLDFT, flag)); }
    2694              : GEN
    2695          183 : lllint(GEN x) { return lllall(x, LLL_IM); }
    2696              : GEN
    2697           35 : lllkerim(GEN x) { return lllall(x, LLL_ALL); }
    2698              : GEN
    2699        36439 : lllgramint(GEN x)
    2700        36439 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2701        36439 :   return lllall(x, LLL_IM | LLL_GRAM); }
    2702              : GEN
    2703           35 : lllgramkerim(GEN x)
    2704           35 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2705           35 :   return lllall(x, LLL_ALL | LLL_GRAM); }
    2706              : 
    2707              : GEN
    2708      5375739 : lllfp(GEN x, double D, long flag)
    2709              : {
    2710      5375739 :   long n = lg(x)-1;
    2711      5375739 :   pari_sp av = avma;
    2712              :   GEN h;
    2713      5375739 :   if (n <= 1) return lll_trivial(x,flag);
    2714      4714046 :   if (flag & LLL_GRAM)
    2715              :   {
    2716         9270 :     if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2717         9256 :     if (isinexact(x))
    2718              :     {
    2719         9165 :       x = RgM_Cholesky(x, gprecision(x));
    2720         9165 :       if (!x) return NULL;
    2721         9165 :       flag &= ~LLL_GRAM;
    2722              :     }
    2723              :   }
    2724      4714032 :   h = ZM_lll(RgM_rescale_to_int(x), D, flag);
    2725      4713976 :   return gc_GEN(av, h);
    2726              : }
    2727              : 
    2728              : GEN
    2729         9089 : lllgram(GEN x) { return lllfp(x,LLLDFT,LLL_GRAM|LLL_IM); }
    2730              : GEN
    2731      1244994 : lll(GEN x) { return lllfp(x,LLLDFT,LLL_IM); }
    2732              : 
    2733              : static GEN
    2734           63 : qflllgram(GEN x)
    2735              : {
    2736           63 :   GEN T = lllgram(x);
    2737           42 :   if (!T) pari_err_PREC("qflllgram");
    2738           42 :   return T;
    2739              : }
    2740              : 
    2741              : GEN
    2742          301 : qflll0(GEN x, long flag)
    2743              : {
    2744          301 :   if (typ(x) != t_MAT) pari_err_TYPE("qflll",x);
    2745          301 :   switch(flag)
    2746              :   {
    2747           49 :     case 0: return lll(x);
    2748           63 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_NOFLATTER);
    2749           49 :     case 2: RgM_check_ZM(x,"qflll"); return lllintpartial(x);
    2750            7 :     case 3: RgM_check_ZM(x,"qflll"); return lllall(x, LLL_INPLACE);
    2751           49 :     case 4: RgM_check_ZM(x,"qflll"); return lllkerim(x);
    2752           42 :     case 5: return lllkerimgen(x);
    2753           42 :     case 8: return lllgen(x);
    2754            0 :     default: pari_err_FLAG("qflll");
    2755              :   }
    2756              :   return NULL; /* LCOV_EXCL_LINE */
    2757              : }
    2758              : 
    2759              : GEN
    2760          245 : qflllgram0(GEN x, long flag)
    2761              : {
    2762          245 :   if (typ(x) != t_MAT) pari_err_TYPE("qflllgram",x);
    2763          245 :   switch(flag)
    2764              :   {
    2765           63 :     case 0: return qflllgram(x);
    2766           49 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_GRAM | LLL_NOFLATTER);
    2767           49 :     case 4: RgM_check_ZM(x,"qflllgram"); return lllgramkerim(x);
    2768           42 :     case 5: return lllgramkerimgen(x);
    2769           42 :     case 8: return lllgramgen(x);
    2770            0 :     default: pari_err_FLAG("qflllgram");
    2771              :   }
    2772              :   return NULL; /* LCOV_EXCL_LINE */
    2773              : }
    2774              : 
    2775              : /********************************************************************/
    2776              : /**                                                                **/
    2777              : /**                   INTEGRAL KERNEL (LLL REDUCED)                **/
    2778              : /**                                                                **/
    2779              : /********************************************************************/
    2780              : static GEN
    2781           56 : kerint0(GEN M)
    2782              : {
    2783              :   /* return ZM_lll(M, LLLDFT, LLL_KER); */
    2784           56 :   GEN U, H = ZM_hnflll(M,&U,1);
    2785           56 :   long d = lg(M)-lg(H);
    2786           56 :   if (!d) return cgetg(1, t_MAT);
    2787           56 :   return ZM_lll(vecslice(U,1,d), LLLDFT, LLL_INPLACE);
    2788              : }
    2789              : GEN
    2790           28 : kerint(GEN M)
    2791              : {
    2792           28 :   pari_sp av = avma;
    2793           28 :   return gc_GEN(av, kerint0(M));
    2794              : }
    2795              : /* OBSOLETE: use kerint */
    2796              : GEN
    2797           28 : matkerint0(GEN M, long flag)
    2798              : {
    2799           28 :   pari_sp av = avma;
    2800           28 :   if (typ(M) != t_MAT) pari_err_TYPE("matkerint",M);
    2801           28 :   M = Q_primpart(M);
    2802           28 :   RgM_check_ZM(M, "kerint");
    2803           28 :   switch(flag)
    2804              :   {
    2805           28 :     case 0:
    2806           28 :     case 1: return gc_GEN(av, kerint0(M));
    2807            0 :     default: pari_err_FLAG("matkerint");
    2808              :   }
    2809              :   return NULL; /* LCOV_EXCL_LINE */
    2810              : }
        

Generated by: LCOV version 2.0-1