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.19.0 lcov report (development 31092-e6893b0017) Lines: 81.2 % 1645 1336
Test Date: 2026-08-10 17:02:30 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        45834 : RgM_is_square_mat(GEN x) { long l = lg(x); return l == 1 || l == lgcols(x); }
      22              : 
      23              : static long
      24      4239494 : ZM_is_upper(GEN R)
      25              : {
      26      4239494 :   long i,j, l = lg(R);
      27      4239494 :   if (l != lgcols(R)) return 0;
      28      8195982 :   for(i = 1; i < l; i++)
      29      8908814 :     for(j = 1; j < i; j++)
      30      4602955 :       if (signe(gcoeff(R,i,j))) return 0;
      31       265375 :   return 1;
      32              : }
      33              : 
      34              : static long
      35       607498 : ZM_is_knapsack(GEN R)
      36              : {
      37       607498 :   long i,j, l = lg(R);
      38       607498 :   if (l != lgcols(R)) return 0;
      39       846687 :   for(i = 2; i < l; i++)
      40      2921459 :     for(j = 1; j < l; j++)
      41      2682270 :       if ( i!=j && signe(gcoeff(R,i,j))) return 0;
      42        92869 :   return 1;
      43              : }
      44              : 
      45              : static long
      46      1205606 : ZM_is_lower(GEN R)
      47              : {
      48      1205606 :   long i,j, l = lg(R);
      49      1205606 :   if (l != lgcols(R)) return 0;
      50      2090771 :   for(i = 1; i < l; i++)
      51      2420099 :     for(j = 1; j < i; j++)
      52      1311881 :       if (signe(gcoeff(R,j,i))) return 0;
      53        34953 :   return 1;
      54              : }
      55              : 
      56              : static GEN
      57        34953 : RgM_flip(GEN R)
      58              : {
      59              :   GEN M;
      60              :   long i,j,l;
      61        34953 :   M = cgetg_copy(R, &l);
      62       181994 :   for(i = 1; i < l; i++)
      63              :   {
      64       147041 :     gel(M,i) = cgetg(l, t_COL);
      65       921196 :     for(j = 1; j < l; j++)
      66       774155 :       gmael(M,i,j) = gmael(R,l-i, l-j);
      67              :   }
      68        34953 :   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      4108859 : mpabscmp(GEN x, GEN y)
      89              : {
      90      4108859 :   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      1347760 : drop(GEN R)
     104              : {
     105      1347760 :   long i, n = lg(R)-1;
     106      1347760 :   long s = 0, m = mpexpo(gcoeff(R, 1, 1));
     107      5456619 :   for (i = 2; i <= n; ++i)
     108              :   {
     109      4108859 :     if (mpabscmp(gcoeff(R, i, i), gcoeff(R, i - 1, i - 1)) >= 0)
     110              :     {
     111      2786358 :       s += m - mpexpo(gcoeff(R, i - 1, i - 1));
     112      2786358 :       m = mpexpo(gcoeff(R, i, i));
     113              :     }
     114              :   }
     115      1347760 :   s += m - mpexpo(gcoeff(R, n, n));
     116      1347760 :   return s;
     117              : }
     118              : 
     119              : static long
     120      1347760 : potential(GEN R)
     121              : {
     122      1347760 :   long i, n = lg(R)-1;
     123      1347760 :   long s = 0, mul = n-1;;
     124      6804379 :   for (i = 1; i <= n; i++, mul-=2) s += mul * mpexpo(gcoeff(R,i,i));
     125      1347760 :   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      4729021 : condition_bound(GEN U, int lower)
     133              : {
     134      4729021 :   long n = lg(U)-1, e, i, j;
     135              :   GEN y;
     136      4729021 :   pari_sp av = avma;
     137      4729021 :   y = cgetg(n+1, t_VECSMALL);
     138      4729021 :   e = y[n] = -gexpo(gcoeff(U,n,n));
     139     18836195 :   for (i=n-1; i>0; i--)
     140              :   {
     141     14107174 :     long s = 0;
     142     50966101 :     for (j=i+1; j<=n; j++)
     143     36858927 :       s = maxss(s, (lower? gexpo(gcoeff(U,j,i)): gexpo(gcoeff(U,i,j))) + y[j]);
     144     14107174 :     y[i] = s - gexpo(gcoeff(U,i,i));
     145     14107174 :     e = maxss(e, y[i]);
     146              :   }
     147      4729021 :   return gc_long(av, gexpo(U) + e);
     148              : }
     149              : 
     150              : INLINE long
     151      7496219 : nbits2prec64(long n)
     152              : {
     153      7496219 :   return nbits2prec(((n+63)>>6)<<6);
     154              : }
     155              : 
     156              : static long
     157      5855635 : spread(GEN R)
     158              : {
     159      5855635 :   long i, n = lg(R)-1, m = mpexpo(gcoeff(R, 1, 1)), M = m;
     160     23619003 :   for (i = 2; i <= n; ++i)
     161              :   {
     162     17763368 :     long e = mpexpo(gcoeff(R, i, i));
     163     17763368 :     if (e < m) m = e;
     164     17763368 :     if (e > M) M = e;
     165              :   }
     166      5855635 :   return M - m;
     167              : }
     168              : 
     169              : static long
     170      4729021 : GS_extraprec(GEN L, int lower)
     171              : {
     172      4729021 :   long C = condition_bound(L, lower), S = spread(L), n = lg(L)-1;
     173      4729021 :   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         4918 :   {
     184              :     long mbitprec;
     185         7906 :     prec = nbits2prec64(bitprec);
     186         7906 :     L = RgM_Cholesky(RgM_gtofp(M, prec), prec); /* upper-triangular */
     187         7906 :     if (!L)
     188              :     {
     189         1486 :       bitprec *= 2;
     190         1486 :       set_avma(ltop);
     191         1486 :       continue;
     192              :     }
     193         6420 :     mbitprec = minprec + GS_extraprec(L, 0);
     194         6420 :     if (bitprec >= mbitprec)
     195         2988 :       break;
     196         3432 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     197         3432 :     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      2695520 : gramschmidt_dynprec(GEN M)
     211              : {
     212      2695520 :   pari_sp ltop = avma;
     213      2695520 :   long minprec = lg(M) + 30, bitprec = minprec;
     214      2695520 :   if (ZM_is_upper(M)) return gramschmidt_upper(M);
     215              :   while (1)
     216      3648605 :   {
     217              :     GEN B, Q, L;
     218      6342723 :     long prec = nbits2prec64(bitprec), mbitprec;
     219      6342723 :     if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec))
     220              :     {
     221      1621524 :       bitprec *= 2;
     222      1621524 :       set_avma(ltop);
     223      1621524 :       continue;
     224              :     }
     225      4721199 :     mbitprec = minprec + GS_extraprec(L, 1);
     226      4721199 :     if (bitprec >= mbitprec)
     227      2694118 :       return gc_GEN(ltop, shallowtrans(L));
     228      2027081 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     229      2027081 :     set_avma(ltop);
     230              :   }
     231              : }
     232              : /* return -T1 * round(T1^-1*(R1^-1*R2)*T3) */
     233              : static GEN
     234      1347760 : sizered(GEN T1, GEN T3, GEN R1, GEN R2)
     235              : {
     236      1347760 :   pari_sp ltop = avma;
     237              :   long e;
     238      1347760 :   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      1347760 : flat(GEN M, long flag, GEN *pt_T, long *pt_s, long *pt_pot)
     244              : {
     245      1347760 :   pari_sp ltop = avma;
     246              :   GEN R, R1, R2, R3, T1, T2, T3, T, S;
     247      1347760 :   long k = lg(M)-1, n = k>>1, n2 = k - n, m = n>>1;
     248      1347760 :   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      1347760 :   R = gramschmidt_dynprec(M);
     252      1347760 :   R1 = matslice(R, 1, n, 1, n);
     253      1347760 :   R2 = matslice(R, 1, n, n + 1, k);
     254      1347760 :   R3 = matslice(R, n + 1, k, n + 1, k);
     255      1347760 :   T1 = lllfp(R1, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY| (keepfirst ? LLL_KEEP_FIRST: 0));
     256      1347760 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     257      1347760 :   T2 = sizered(T1, T3, R1, R2);
     258      1347760 :   T = shallowmatconcat(mkmat22(T1,T2,gen_0,T3));
     259      1347760 :   M = ZM_mul(M, T);
     260      1347760 :   R = gramschmidt_dynprec(M);
     261      1347760 :   R3 = matslice(R, m + 1, m + n2, m + 1, m + n2);
     262      1347760 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     263      2695520 :   S = shallowmatconcat(diagonal(
     264       577282 :        m == 0     ? mkvec2(T3, matid(k - m - n2))
     265            0 :      : m+n2 == k  ? mkvec2(matid(m), T3)
     266       770478 :                   : mkvec3(matid(m), T3, matid(k - m - n2))));
     267      1347760 :   M = ZM_mul(M, S);
     268      1347760 :   if (!inplace) *pt_T = ZM_mul(T, S);
     269      1347760 :   *pt_s = drop(R);
     270      1347760 :   *pt_pot = potential(R);
     271      1347760 :   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       627251 : ZM_flatter(GEN M, long flag)
     291              : {
     292       627251 :   pari_sp av = avma;
     293       627251 :   long i, n = lg(M)-1, s = -1, lti = 1, pot = LONG_MAX;
     294       627251 :   GEN T = NULL;
     295              :   pari_timer ti;
     296       627251 :   long inplace = flag & LLL_INPLACE, cert = !(flag & LLL_NOCERTIFY);
     297              : 
     298       627251 :   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       627251 :   for (i = 1;;i++)
     304       720509 :   {
     305              :     long t, pot2;
     306      1347760 :     GEN U, M2 = flat(M, flag, &U, &t, &pot2);
     307      1347760 :     if (t == 0) { s = t; break; }
     308       764322 :     if (s >= 0)
     309              :     {
     310       437764 :       if (s == t && pot>=pot2) break;
     311       393951 :       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       720509 :     if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     318            0 :       dbg_flatter(&ti, n, i, lti, t, pot2);
     319       720509 :     s = t;
     320       720509 :     pot = pot2;
     321       720509 :     M = M2;
     322       720509 :     if (!inplace)
     323              :     {
     324       692825 :       T = T? ZM_mul(T, U): U;
     325       692825 :       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       627251 :   if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     331            0 :     dbg_flatter(&ti, n, -1, i == lti? -1: lti, s, pot);
     332       627251 :   if (!inplace)
     333              :   {
     334       613236 :     if (!T) return gc_NULL(av);
     335       312711 :     return gc_GEN(av, T);
     336              :   }
     337        14015 :   return  gc_GEN(av, M);
     338              : }
     339              : 
     340              : static GEN
     341       625237 : ZM_flatter_rank(GEN M, long rank, long flag)
     342              : {
     343              :   pari_timer ti;
     344       625237 :   pari_sp av = avma;
     345       625237 :   GEN T = NULL;
     346       625237 :   long i, n = lg(M)-1, sm = LONG_MAX;
     347       625237 :   long inplace = flag & LLL_INPLACE;
     348              : 
     349       625237 :   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     11656149 : pari_rint(double a)
     451              : {
     452              : #ifdef HAS_RINT
     453     11656149 :   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          151 :     if (flag & LLL_KER) return matid(1);
     480          151 :     if (flag & (LLL_IM|LLL_INPLACE)) return cgetg(1,t_MAT);
     481           28 :     retmkvec2(matid(1), cgetg(1,t_MAT));
     482              :   }
     483       756212 :   if (flag & LLL_INPLACE) return gcopy(x);
     484       652528 :   if (flag & LLL_KER) return cgetg(1,t_MAT);
     485       652528 :   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      2093445 : vectail_inplace(GEN x, long k)
     492              : {
     493      2093445 :   if (!k) return x;
     494        58105 :   x[k] = ((ulong)x[0] & ~LGBITS) | _evallg(lg(x) - k);
     495        58105 :   return x + k;
     496              : }
     497              : 
     498              : /* k = dim Kernel */
     499              : static GEN
     500      2168064 : lll_finish(GEN h, long k, long flag)
     501              : {
     502              :   GEN g;
     503      2168064 :   if (!(flag & (LLL_IM|LLL_KER|LLL_ALL|LLL_INPLACE))) return h;
     504      2093459 :   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       938305 : mulshift(GEN y, GEN z, long e)
     513              : {
     514       938305 :   long ly = lgefint(y), lz;
     515              :   pari_sp av;
     516              :   GEN t;
     517       938305 :   if (ly == 2) return gen_0;
     518       456035 :   lz = lgefint(z);
     519       456035 :   av = avma; (void)new_chunk(ly+lz+nbits2lg(e)); /* HACK */
     520       456035 :   t = mulii(z, y);
     521       456035 :   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      2074362 : submulshift(GEN x, GEN y, GEN z, long e)
     527              : {
     528      2074362 :   long lx = lgefint(x), ly, lz;
     529              :   pari_sp av;
     530              :   GEN t;
     531      2074362 :   if (!e) return submulii(x, y, z);
     532      2051874 :   if (lx == 2) { t = mulshift(y, z, e); togglesign(t); return t; }
     533      1538444 :   ly = lgefint(y);
     534      1538444 :   if (ly == 2) return icopy(x);
     535      1093910 :   lz = lgefint(z);
     536      1093910 :   av = avma; (void)new_chunk(lx+ly+lz+nbits2lg(e)); /* HACK */
     537      1093910 :   t = shifti(mulii(z, y), e);
     538      1093910 :   set_avma(av); return subii(x, t);
     539              : }
     540              : static void
     541     33271522 : subzi(GEN *a, GEN b)
     542              : {
     543     33271522 :   pari_sp av = avma;
     544     33271522 :   b = subii(*a, b);
     545     33271522 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     546      2429530 :   else *a = b;
     547     33271522 : }
     548              : 
     549              : static void
     550     32506340 : addzi(GEN *a, GEN b)
     551              : {
     552     32506340 :   pari_sp av = avma;
     553     32506340 :   b = addii(*a, b);
     554     32506340 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     555      2212338 :   else *a = b;
     556     32506340 : }
     557              : 
     558              : /* x - u*y * 2^e */
     559              : INLINE GEN
     560      4742023 : submuliu2n(GEN x, GEN y, ulong u, long e)
     561              : {
     562              :   pari_sp av;
     563      4742023 :   long ly = lgefint(y);
     564      4742023 :   if (ly == 2) return x;
     565      3316703 :   av = avma;
     566      3316703 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     567      3316703 :   y = shifti(mului(u,y), e);
     568      3316703 :   set_avma(av); return subii(x, y);
     569              : }
     570              : /* *x -= u*y * 2^e */
     571              : INLINE void
     572     16867897 : submulzu2n(GEN *x, GEN y, ulong u, long e)
     573              : {
     574              :   pari_sp av;
     575     16867897 :   long ly = lgefint(y);
     576     16867897 :   if (ly == 2) return;
     577      5891164 :   av = avma;
     578      5891164 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     579      5891164 :   y = shifti(mului(u,y), e);
     580      5891164 :   set_avma(av); return subzi(x, y);
     581              : }
     582              : 
     583              : /* x + u*y * 2^e */
     584              : INLINE GEN
     585      4666438 : addmuliu2n(GEN x, GEN y, ulong u, long e)
     586              : {
     587              :   pari_sp av;
     588      4666438 :   long ly = lgefint(y);
     589      4666438 :   if (ly == 2) return x;
     590      3276445 :   av = avma;
     591      3276445 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     592      3276445 :   y = shifti(mului(u,y), e);
     593      3276445 :   set_avma(av); return addii(x, y);
     594              : }
     595              : 
     596              : /* *x += u*y * 2^e */
     597              : INLINE void
     598     17070592 : addmulzu2n(GEN *x, GEN y, ulong u, long e)
     599              : {
     600              :   pari_sp av;
     601     17070592 :   long ly = lgefint(y);
     602     17070592 :   if (ly == 2) return;
     603      5924878 :   av = avma;
     604      5924878 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     605      5924878 :   y = shifti(mului(u,y), e);
     606      5924878 :   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         5460 : gc_lll(pari_sp av, int n, ...)
     612              : {
     613              :   int i, j;
     614              :   GEN *gptr[10];
     615              :   size_t s;
     616         5460 :   va_list a; va_start(a, n);
     617        16380 :   for (i=j=0; i<n; i++)
     618              :   {
     619        10920 :     GEN *x = va_arg(a,GEN*);
     620        10920 :     if (*x) { gptr[j++] = x; *x = (GEN)copy_bin(*x); }
     621              :   }
     622         5460 :   va_end(a); set_avma(av);
     623        13462 :   for (--j; j>=0; j--) *gptr[j] = bin_copy((GENbin*)*gptr[j]);
     624         5460 :   s = pari_mainstack->top - pari_mainstack->bot;
     625              :   /* size of saved objects ~ stacksize / 4 => overflow */
     626         5460 :   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         5460 : }
     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       442325 : absrsmall2(GEN x)
     656              : {
     657       442325 :   long e = expo(x), l, i;
     658       442325 :   if (e < 0) return 1;
     659       230847 :   if (e > 0 || (ulong)x[2] > (3UL << (BITS_IN_LONG-2))) return 0;
     660              :   /* line above assumes l > 2. OK since x != 0 */
     661        79835 :   l = lg(x); for (i = 3; i < l; i++) if (x[i]) return 0;
     662        68365 :   return 1;
     663              : }
     664              : /* x t_REAL; test whether |x| <= 1/2 */
     665              : static int
     666       761889 : absrsmall(GEN x)
     667              : {
     668              :   long e, l, i;
     669       761889 :   if (!signe(x)) return 1;
     670       755848 :   e = expo(x); if (e < -1) return 1;
     671       448631 :   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     33254711 : rotate(GEN A, long k2, long k)
     678              : {
     679              :   long i;
     680     33254711 :   GEN B = gel(A,k2);
     681    107860127 :   for (i = k2; i > k; i--) gel(A,i) = gel(A,i-1);
     682     33254711 :   gel(A,k) = B;
     683     33254711 : }
     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     35108508 : cget_dblvec(long d)
     691     35108508 : { return (double*) stack_malloc_align(d*sizeof(double), sizeof(double)); }
     692              : 
     693              : static double **
     694      8429696 : cget_dblmat(long d) { return (double **) cgetg(d, t_VECSMALL); }
     695              : 
     696              : static double
     697    177075474 : itodbl_exp(GEN x, long *e)
     698              : {
     699    177075474 :   pari_sp av = avma;
     700    177075474 :   GEN r = itor(x,DEFAULTPREC);
     701    177075474 :   *e = expo(r); setexpo(r,0);
     702    177075474 :   return gc_double(av, rtodbl(r));
     703              : }
     704              : 
     705              : static double
     706    129209745 : dbldotproduct(double *x, double *y, long n)
     707              : {
     708              :   long i;
     709    129209745 :   double sum = del(x,1) * del(y,1);
     710   1671961631 :   for (i=2; i<=n; i++) sum += del(x,i) * del(y,i);
     711    129209745 :   return sum;
     712              : }
     713              : 
     714              : static double
     715      2484954 : dbldotsquare(double *x, long n)
     716              : {
     717              :   long i;
     718      2484954 :   double sum = del(x,1) * del(x,1);
     719      8250590 :   for (i=2; i<=n; i++) sum += del(x,i) * del(x,i);
     720      2484954 :   return sum;
     721              : }
     722              : 
     723              : static long
     724     25546661 : set_line(double *appv, GEN v, long n)
     725              : {
     726     25546661 :   long i, maxexp = 0;
     727     25546661 :   pari_sp av = avma;
     728     25546661 :   GEN e = cgetg(n+1, t_VECSMALL);
     729    202622135 :   for (i = 1; i <= n; i++)
     730              :   {
     731    177075474 :     del(appv,i) = itodbl_exp(gel(v,i), e+i);
     732    177075474 :     if (e[i] > maxexp) maxexp = e[i];
     733              :   }
     734    202622135 :   for (i = 1; i <= n; i++) del(appv,i) = ldexp(del(appv,i), e[i]-maxexp);
     735     25546661 :   set_avma(av); return maxexp;
     736              : }
     737              : 
     738              : static void
     739     35878554 : dblrotate(double **A, long k2, long k)
     740              : {
     741              :   long i;
     742     35878554 :   double *B = del(A,k2);
     743    115224945 :   for (i = k2; i > k; i--) del(A,i) = del(A,i-1);
     744     35878554 :   del(A,k) = B;
     745     35878554 : }
     746              : /* update G[kappa][i] from appB */
     747              : static void
     748     23266896 : setG_fast(double **appB, long n, double **G, long kappa, long a, long b)
     749              : { long i;
     750    109217086 :   for (i = a; i <= b; i++)
     751     85950190 :     dmael(G,kappa,i) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     752     23266896 : }
     753              : /* update G[i][kappa] from appB */
     754              : static void
     755     17613082 : setG2_fast(double **appB, long n, double **G, long kappa, long a, long b)
     756              : { long i;
     757     60872637 :   for (i = a; i <= b; i++)
     758     43259555 :     dmael(G,i,kappa) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     759     17613082 : }
     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     22027403 : u64toi(u64 x)
     774              : {
     775              :   GEN y;
     776              :   ulong h;
     777     22027403 :   if (!x) return gen_0;
     778     22027403 :   h = x>>32;
     779     22027403 :   if (!h) return utoipos(x);
     780      1277225 :   y = cgetipos(4);
     781      1277225 :   *int_LSW(y) = x&0xFFFFFFFF;
     782      1277225 :   *int_MSW(y) = x>>32;
     783      1277225 :   return y;
     784              : }
     785              : 
     786              : INLINE GEN
     787       729530 : u64toineg(u64 x)
     788              : {
     789              :   GEN y;
     790              :   ulong h;
     791       729530 :   if (!x) return gen_0;
     792       729530 :   h = x>>32;
     793       729530 :   if (!h) return utoineg(x);
     794       729530 :   y = cgetineg(4);
     795       729530 :   *int_LSW(y) = x&0xFFFFFFFF;
     796       729530 :   *int_MSW(y) = x>>32;
     797       729530 :   return y;
     798              : }
     799              : INLINE GEN
     800     10613593 : addmuliu64_inplace(GEN x, GEN y, u64 u) { return addmulii(x, y, u64toi(u)); }
     801              : 
     802              : INLINE GEN
     803     10666126 : submuliu64_inplace(GEN x, GEN y, u64 u) { return submulii(x, y, u64toi(u)); }
     804              : 
     805              : INLINE GEN
     806       729530 : addmuliu642n(GEN x, GEN y, u64 u, long e) { return submulshift(x, y, u64toineg(u), e); }
     807              : 
     808              : INLINE GEN
     809       747684 : 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     31678254 : 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     31678254 :   GEN B = *pB, U = *pU;
     820     31678254 :   const long n = nbrows(B), d = U ? lg(U)-1: 0;
     821     31678254 :   long k, aa = (a > zeros)? a : zeros+1;
     822     31678254 :   long emaxmu = EX0, emax2mu = EX0;
     823              :   s64 xx;
     824     31678254 :   int did_something = 0;
     825              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
     826              : 
     827     17823246 :   for (;;) {
     828     49501500 :     int go_on = 0;
     829     49501500 :     long i, j, emax3mu = emax2mu;
     830              : 
     831     49501500 :     if (gc_needed(av,2))
     832              :     {
     833          235 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
     834          235 :       gc_lll(av,2,&B,&U);
     835              :     }
     836              :     /* Step2: compute the GSO for stage kappa */
     837     49501500 :     emax2mu = emaxmu; emaxmu = EX0;
     838    196796624 :     for (j=aa; j<kappa; j++)
     839              :     {
     840    147295124 :       double g = dmael(G,kappa,j);
     841    682323156 :       for (k = zeros+1; k < j; k++) g -= dmael(mu,j,k) * dmael(r,kappa,k);
     842    147295124 :       dmael(r,kappa,j) = g;
     843    147295124 :       dmael(mu,kappa,j) = dmael(r,kappa,j) / dmael(r,j,j);
     844    147295124 :       emaxmu = maxss(emaxmu, expoB[kappa]-expoB[j]);
     845              :     }
     846              :     /* maxmu doesn't decrease fast enough */
     847     49501500 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) {*pB = B; *pU = U; return 1;}
     848              : 
     849    186322828 :     for (j=kappa-1; j>zeros; j--)
     850              :     {
     851    154649280 :       double tmp = fabs(ldexp (dmael(mu,kappa,j), expoB[kappa]-expoB[j]));
     852    154649280 :       if (tmp>eta) { go_on = 1; break; }
     853              :     }
     854              : 
     855              :     /* Step3--5: compute the X_j's  */
     856     49496794 :     if (go_on)
     857     85135798 :       for (j=kappa-1; j>zeros; j--)
     858              :       { /* The code below seemingly handles U = NULL, but in this case d = 0 */
     859     67312552 :         int e = expoB[j] - expoB[kappa];
     860     67312552 :         double tmp = ldexp(dmael(mu,kappa,j), -e), atmp = fabs(tmp);
     861              :         /* tmp = Inf is allowed */
     862     67312552 :         if (atmp <= .5) continue; /* size-reduced */
     863     36940453 :         if (gc_needed(av,2))
     864              :         {
     865          473 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
     866          473 :           gc_lll(av,2,&B,&U);
     867              :         }
     868     36940453 :         did_something = 1;
     869              :         /* we consider separately the case |X| = 1 */
     870     36940453 :         if (atmp <= 1.5)
     871              :         {
     872     25471874 :           if (dmael(mu,kappa,j) > 0) { /* in this case, X = 1 */
     873     55924508 :             for (k=zeros+1; k<j; k++)
     874     42957757 :               dmael(mu,kappa,k) -= ldexp(dmael(mu,j,k), e);
     875    192277002 :             for (i=1; i<=n; i++)
     876    179310251 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
     877    137843034 :             for (i=1; i<=d; i++)
     878    124876283 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
     879              :           } else { /* otherwise X = -1 */
     880     55105826 :             for (k=zeros+1; k<j; k++)
     881     42600703 :               dmael(mu,kappa,k) += ldexp(dmael(mu,j,k), e);
     882    189622434 :             for (i=1; i<=n; i++)
     883    177117311 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
     884    135098515 :             for (i=1; i<=d; i++)
     885    122593392 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i), gmael(U,j,i));
     886              :           }
     887     25471874 :           continue;
     888              :         }
     889              :         /* we have |X| >= 2 */
     890     11468579 :         if (atmp < 9007199254740992.)
     891              :         {
     892     10608188 :           tmp = pari_rint(tmp);
     893     26390058 :           for (k=zeros+1; k<j; k++)
     894     15781870 :             dmael(mu,kappa,k) -= ldexp(tmp * dmael(mu,j,k), e);
     895     10608188 :           xx = (s64) tmp;
     896     10608188 :           if (xx > 0) /* = xx */
     897              :           {
     898     50244907 :             for (i=1; i<=n; i++)
     899     44910709 :               gmael(B,kappa,i) = submuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
     900     36930013 :             for (i=1; i<=d; i++)
     901     31595815 :               gmael(U,kappa,i) = submuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
     902              :           }
     903              :           else /* = -xx */
     904              :           {
     905     49948300 :             for (i=1; i<=n; i++)
     906     44674310 :               gmael(B,kappa,i) = addmuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), -xx);
     907     36560249 :             for (i=1; i<=d; i++)
     908     31286259 :               gmael(U,kappa,i) = addmuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), -xx);
     909              :           }
     910              :         }
     911              :         else
     912              :         {
     913              :           int E;
     914       860391 :           xx = (s64) ldexp(frexp(dmael(mu,kappa,j), &E), 53);
     915       860391 :           E -= e + 53;
     916       860391 :           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      2953572 :             for (k=zeros+1; k<j; k++)
     938      2093181 :               dmael(mu,kappa,k) -= ldexp(((double)xx) * dmael(mu,j,k), E + e);
     939       860391 :             if (xx > 0) /* = xx */
     940              :             {
     941      4186422 :               for (i=1; i<=n; i++)
     942      3753652 :                 gmael(B,kappa,i) = submuliu642n(gmael(B,kappa,i), gmael(B,j,i), xx, E);
     943      1622207 :               for (i=1; i<=d; i++)
     944      1189437 :                 gmael(U,kappa,i) = submuliu642n(gmael(U,kappa,i), gmael(U,j,i), xx, E);
     945              :             }
     946              :             else /* = -xx */
     947              :             {
     948      4142983 :               for (i=1; i<=n; i++)
     949      3715362 :                 gmael(B,kappa,i) = addmuliu642n(gmael(B,kappa,i), gmael(B,j,i), -xx, E);
     950      1606884 :               for (i=1; i<=d; i++)
     951      1179263 :                 gmael(U,kappa,i) = addmuliu642n(gmael(U,kappa,i), gmael(U,j,i), -xx, E);
     952              :             }
     953              :           }
     954              :         }
     955              :       }
     956     49496794 :     if (!go_on) break; /* Anything happened? */
     957     17823246 :     expoB[kappa] = set_line(del(appB,kappa), gel(B,kappa), n);
     958     17823246 :     setG_fast(appB, n, G, kappa, zeros+1, kappa-1);
     959     17823246 :     aa = zeros+1;
     960              :   }
     961     31673548 :   if (did_something) setG2_fast(appB, n, G, kappa, kappa, maxG);
     962              : 
     963     31673548 :   del(s,zeros+1) = dmael(G,kappa,kappa);
     964              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
     965    124325468 :   for (k=zeros+1; k<=kappa-2; k++)
     966     92651920 :     del(s,k+1) = del(s,k) - dmael(mu,kappa,k)*dmael(r,kappa,k);
     967     31673548 :   *pB = B; *pU = U; return 0;
     968              : }
     969              : 
     970              : static void
     971     12439465 : update_alpha(GEN alpha, long kappa, long kappa2, long kappamax)
     972              : {
     973              :   long i;
     974     40112597 :   for (i = kappa; i < kappa2; i++)
     975     27673132 :     if (kappa <= alpha[i]) alpha[i] = kappa;
     976     40112597 :   for (i = kappa2; i > kappa; i--) alpha[i] = alpha[i-1];
     977     26387437 :   for (i = kappa2+1; i <= kappamax; i++)
     978     13947972 :     if (kappa < alpha[i]) alpha[i] = kappa;
     979     12439465 :   alpha[kappa] = kappa;
     980     12439465 : }
     981              : static void
     982       479947 : rotateG(GEN G, long kappa2, long kappa, long maxG, GEN Gtmp)
     983              : {
     984              :   long i, j;
     985      3863536 :   for (i=1; i<=kappa2; i++) gel(Gtmp,i) = gmael(G,kappa2,i);
     986      1935078 :   for (   ; i<=maxG; i++)   gel(Gtmp,i) = gmael(G,i,kappa2);
     987      1704282 :   for (i=kappa2; i>kappa; i--)
     988              :     {
     989      6071968 :       for (j=1; j<kappa; j++) gmael(G,i,j) = gmael(G,i-1,j);
     990      1224335 :       gmael(G,i,kappa) = gel(Gtmp,i-1);
     991      4529719 :       for (j=kappa+1; j<=i; j++) gmael(G,i,j) = gmael(G,i-1,j-1);
     992      5084479 :       for (j=kappa2+1; j<=maxG; j++) gmael(G,j,i) = gmael(G,j,i-1);
     993              :     }
     994      2159254 :   for (i=1; i<kappa; i++) gmael(G,kappa,i) = gel(Gtmp,i);
     995       479947 :   gmael(G,kappa,kappa) = gel(Gtmp,kappa2);
     996      1935078 :   for (i=kappa2+1; i<=maxG; i++) gmael(G,i,kappa) = gel(Gtmp,i);
     997       479947 : }
     998              : static void
     999     11959518 : rotateG_fast(double **G, long kappa2, long kappa, long maxG, double *Gtmp)
    1000              : {
    1001              :   long i, j;
    1002     72530350 :   for (i=1; i<=kappa2; i++) del(Gtmp,i) = dmael(G,kappa2,i);
    1003     25314761 :   for (   ; i<=maxG; i++) del(Gtmp,i) = dmael(G,i,kappa2);
    1004     38408315 :   for (i=kappa2; i>kappa; i--)
    1005              :   {
    1006     79371538 :     for (j=1; j<kappa; j++) dmael(G,i,j) = dmael(G,i-1,j);
    1007     26448797 :     dmael(G,i,kappa) = del(Gtmp,i-1);
    1008     92853919 :     for (j=kappa+1; j<=i; j++) dmael(G,i,j) = dmael(G,i-1,j-1);
    1009     54999334 :     for (j=kappa2+1; j<=maxG; j++) dmael(G,j,i) = dmael(G,j,i-1);
    1010              :   }
    1011     34122035 :   for (i=1; i<kappa; i++) dmael(G,kappa,i) = del(Gtmp,i);
    1012     11959518 :   dmael(G,kappa,kappa) = del(Gtmp,kappa2);
    1013     25314761 :   for (i=kappa2+1; i<=maxG; i++) dmael(G,i,kappa) = del(Gtmp,i);
    1014     11959518 : }
    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      2107424 : 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      2107424 :   GEN alpha, expoB, B = *pB, U;
    1027      2107424 :   long cnt = 0;
    1028              : 
    1029      2107424 :   d = lg(B)-1;
    1030      2107424 :   n = nbrows(B);
    1031      2107424 :   U = *pU; /* NULL if inplace */
    1032              : 
    1033      2107424 :   G = cget_dblmat(d+1);
    1034      2107424 :   appB = cget_dblmat(d+1);
    1035      2107424 :   mu = cget_dblmat(d+1);
    1036      2107424 :   r  = cget_dblmat(d+1);
    1037      2107424 :   s  = cget_dblvec(d+1);
    1038      9830839 :   for (j = 1; j <= d; j++)
    1039              :   {
    1040      7723415 :     del(mu,j) = cget_dblvec(d+1);
    1041      7723415 :     del(r,j) = cget_dblvec(d+1);
    1042      7723415 :     del(appB,j) = cget_dblvec(n+1);
    1043      7723415 :     del(G,j) = cget_dblvec(d+1);
    1044     47986034 :     for (i=1; i<=d; i++) dmael(G,j,i) = 0.;
    1045              :   }
    1046      2107424 :   expoB = cgetg(d+1, t_VECSMALL);
    1047      9830839 :   for (i=1; i<=d; i++) expoB[i] = set_line(del(appB,i), gel(B,i), n);
    1048      2107424 :   Gtmp = cget_dblvec(d+1);
    1049      2107424 :   alpha = cgetg(d+1, t_VECSMALL);
    1050      2107424 :   av = avma;
    1051              : 
    1052              :   /* Step2: Initializing the main loop */
    1053      2107424 :   kappamax = 1;
    1054      2107424 :   i = 1;
    1055      2107424 :   maxG = d; /* later updated to kappamax */
    1056              : 
    1057              :   do {
    1058      2272799 :     dmael(G,i,i) = dbldotsquare(del(appB,i),n);
    1059      2272799 :   } while (dmael(G,i,i) <= 0 && (++i <=d));
    1060      2107424 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1061      2107424 :   kappa = i;
    1062      2107424 :   if (zeros < d) dmael(r,zeros+1,zeros+1) = dmael(G,zeros+1,zeros+1);
    1063      9665457 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1064     33780972 :   while (++kappa <= d)
    1065              :   {
    1066     31678254 :     if (kappa > kappamax)
    1067              :     {
    1068      5443650 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1069      5443650 :       maxG = kappamax = kappa;
    1070      5443650 :       setG_fast(appB, n, G, kappa, zeros+1, kappa);
    1071              :     }
    1072              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1073     31678254 :     if (Babai_fast(av, kappa, &B,&U, mu,r,s, appB, expoB, G, alpha[kappa],
    1074         4706 :                    zeros, maxG, eta)) { *pB=B; *pU=U; return -1; }
    1075              : 
    1076     31673548 :     tmp = ldexp(r[kappa-1][kappa-1] * delta, 2*(expoB[kappa-1]-expoB[kappa]));
    1077     31673548 :     if ((keepfirst && kappa == 2) || tmp <= del(s,kappa-1))
    1078              :     { /* Step4: Success of Lovasz's condition */
    1079     19714030 :       alpha[kappa] = kappa;
    1080     19714030 :       tmp = dmael(mu,kappa,kappa-1) * dmael(r,kappa,kappa-1);
    1081     19714030 :       dmael(r,kappa,kappa) = del(s,kappa-1)- tmp;
    1082     19714030 :       continue;
    1083              :     }
    1084              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1085     11959518 :     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     11959518 :     kappa2 = kappa;
    1088              :     do {
    1089     26448797 :       kappa--;
    1090     26448797 :       if (kappa<zeros+2 + (keepfirst ? 1: 0)) break;
    1091     19828605 :       tmp = dmael(r,kappa-1,kappa-1) * delta;
    1092     19828605 :       tmp = ldexp(tmp, 2*(expoB[kappa-1]-expoB[kappa2]));
    1093     19828605 :     } while (del(s,kappa-1) <= tmp);
    1094     11959518 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1095              : 
    1096              :     /* Step6: Update the mu's and r's */
    1097     11959518 :     dblrotate(mu,kappa2,kappa);
    1098     11959518 :     dblrotate(r,kappa2,kappa);
    1099     11959518 :     dmael(r,kappa,kappa) = del(s,kappa);
    1100              : 
    1101              :     /* Step7: Update B, appB, U, G */
    1102     11959518 :     rotate(B,kappa2,kappa);
    1103     11959518 :     dblrotate(appB,kappa2,kappa);
    1104     11959518 :     if (U) rotate(U,kappa2,kappa);
    1105     11959518 :     rotate(expoB,kappa2,kappa);
    1106     11959518 :     rotateG_fast(G,kappa2,kappa, maxG, Gtmp);
    1107              : 
    1108              :     /* Step8: Prepare the next loop iteration */
    1109     11959518 :     if (kappa == zeros+1 && dmael(G,kappa,kappa)<= 0)
    1110              :     {
    1111       212155 :       zeros++; kappa++;
    1112       212155 :       dmael(G,kappa,kappa) = dbldotsquare(del(appB,kappa),n);
    1113       212155 :       dmael(r,kappa,kappa) = dmael(G,kappa,kappa);
    1114              :     }
    1115              :   }
    1116      2102718 :   *pB = B; *pU = U; return zeros;
    1117              : }
    1118              : 
    1119              : /***************** HEURISTIC version (reduced precision) ****************/
    1120              : static GEN
    1121       207826 : realsqrdotproduct(GEN x)
    1122              : {
    1123       207826 :   long i, l = lg(x);
    1124       207826 :   GEN z = sqrr(gel(x,1));
    1125      1463083 :   for (i=2; i<l; i++) z = addrr(z, sqrr(gel(x,i)));
    1126       207826 :   return z;
    1127              : }
    1128              : /* x, y non-empty vector of t_REALs, same length */
    1129              : static GEN
    1130      1289785 : realdotproduct(GEN x, GEN y)
    1131              : {
    1132              :   long i, l;
    1133              :   GEN z;
    1134      1289785 :   if (x == y) return realsqrdotproduct(x);
    1135      1081959 :   l = lg(x); z = mulrr(gel(x,1),gel(y,1));
    1136     10682294 :   for (i=2; i<l; i++) z = addrr(z, mulrr(gel(x,i), gel(y,i)));
    1137      1081959 :   return z;
    1138              : }
    1139              : static void
    1140       217970 : setG_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1141       217970 : { pari_sp av = avma;
    1142              :   long i;
    1143      1030069 :   for (i = a; i <= b; i++)
    1144       812099 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,kappa,i));
    1145       217970 :   set_avma(av);
    1146       217970 : }
    1147              : static void
    1148       195115 : setG2_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1149       195115 : { pari_sp av = avma;
    1150              :   long i;
    1151       672801 :   for (i = a; i <= b; i++)
    1152       477686 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,i,kappa));
    1153       195115 :   set_avma(av);
    1154       195115 : }
    1155              : 
    1156              : /* approximate t_REAL x as m * 2^e, where |m| < 2^bit */
    1157              : static GEN
    1158        24469 : truncexpo(GEN x, long bit, long *e)
    1159              : {
    1160        24469 :   *e = expo(x) + 1 - bit;
    1161        24469 :   if (*e >= 0) return mantissa2nr(x, 0);
    1162         1266 :   *e = 0; return roundr_safe(x);
    1163              : }
    1164              : /* Babai's Nearest Plane algorithm (iterative); see Babai() */
    1165              : static int
    1166       302144 : 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       302144 :   GEN B = *pB, U = *pU;
    1171       302144 :   const long n = nbrows(B), d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    1172       302144 :   long k, aa = (a > zeros)? a : zeros+1;
    1173       302144 :   int did_something = 0;
    1174       302144 :   long emaxmu = EX0, emax2mu = EX0;
    1175              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1176              : 
    1177       205259 :   for (;;) {
    1178       507403 :     int go_on = 0;
    1179       507403 :     long i, j, emax3mu = emax2mu;
    1180              : 
    1181       507403 :     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       507403 :     emax2mu = emaxmu; emaxmu = EX0;
    1188      1993648 :     for (j=aa; j<kappa; j++)
    1189              :     {
    1190      1486245 :       pari_sp btop = avma;
    1191      1486245 :       GEN g = gmael(G,kappa,j);
    1192      5028204 :       for (k = zeros+1; k<j; k++)
    1193      3541959 :         g = subrr(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    1194      1486245 :       affrr(g, gmael(r,kappa,j));
    1195      1486245 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    1196      1486245 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    1197      1486245 :       set_avma(btop);
    1198              :     }
    1199       507403 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5)
    1200         1741 :     { *pB = B; *pU = U; return 1; }
    1201              : 
    1202      1745586 :     for (j=kappa-1; j>zeros; j--)
    1203      1445183 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1204              : 
    1205              :     /* Step3--5: compute the X_j's  */
    1206       505662 :     if (go_on)
    1207       967148 :       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       761889 :         GEN tmp = gmael(mu,kappa,j);
    1211       761889 :         if (absrsmall(tmp)) continue; /* size-reduced */
    1212              : 
    1213       442325 :         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       442325 :         btop = avma; did_something = 1;
    1219              :         /* we consider separately the case |X| = 1 */
    1220       442325 :         if (absrsmall2(tmp))
    1221              :         {
    1222       279843 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    1223       418132 :             for (k=zeros+1; k<j; k++)
    1224       279018 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1225       139114 :             set_avma(btop);
    1226      1359820 :             for (i=1; i<=n; i++)
    1227      1220706 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    1228       855692 :             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       426109 :             for (k=zeros+1; k<j; k++)
    1232       285380 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1233       140729 :             set_avma(btop);
    1234      1384891 :             for (i=1; i<=n; i++)
    1235      1244162 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
    1236       859555 :             for (i=1; i<=d; i++)
    1237       718826 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    1238              :           }
    1239       279843 :           continue;
    1240              :         }
    1241              :         /* we have |X| >= 2 */
    1242       162482 :         if (expo(tmp) < BITS_IN_LONG)
    1243              :         {
    1244       138013 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    1245       138013 :           if (signe(tmp) > 0) /* = xx */
    1246              :           {
    1247       169140 :             for (k=zeros+1; k<j; k++)
    1248        99711 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1249        99711 :                   gmael(mu,kappa,k));
    1250        69429 :             set_avma(btop);
    1251       564786 :             for (i=1; i<=n; i++)
    1252       495357 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1253       330898 :             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       168053 :             for (k=zeros+1; k<j; k++)
    1259        99469 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1260        99469 :                   gmael(mu,kappa,k));
    1261        68584 :             set_avma(btop);
    1262       568434 :             for (i=1; i<=n; i++)
    1263       499850 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1264       315911 :             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        24469 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    1272        24469 :           btop = avma;
    1273       111005 :           for (k=zeros+1; k<j; k++)
    1274              :           {
    1275        86536 :             GEN x = mulir(X, gmael(mu,j,k));
    1276        86536 :             if (e) shiftr_inplace(x, e);
    1277        86536 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    1278              :           }
    1279        24469 :           set_avma(btop);
    1280       557869 :           for (i=1; i<=n; i++)
    1281       533400 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    1282        88217 :           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       505662 :     if (!go_on) break; /* Anything happened? */
    1287      1638364 :     for (i=1 ; i<=n; i++) affir(gmael(B,kappa,i), gmael(appB,kappa,i));
    1288       205259 :     setG_heuristic(appB, G, kappa, zeros+1, kappa-1);
    1289       205259 :     aa = zeros+1;
    1290              :   }
    1291       300403 :   if (did_something) setG2_heuristic(appB, G, kappa, kappa, maxG);
    1292       300403 :   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       300403 :   av = avma;
    1295      1103203 :   for (k=zeros+1; k<=kappa-2; k++)
    1296       802800 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    1297       802800 :           gel(s,k+1));
    1298       300403 :   *pB = B; *pU = U; return gc_bool(av, 0);
    1299              : }
    1300              : 
    1301              : static GEN
    1302        22443 : ZC_to_RC(GEN x, long prec)
    1303       322633 : { pari_APPLY_type(t_COL,itor(gel(x,i),prec)) }
    1304              : 
    1305              : static GEN
    1306         4706 : ZM_to_RM(GEN x, long prec)
    1307        27149 : { 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         4706 : 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         4706 :   GEN mu, r, s, tmp, Gtmp, alpha, G, appB, B = *pB, U;
    1320         4706 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    1321         4706 :   long cnt = 0;
    1322              : 
    1323         4706 :   d = lg(B)-1;
    1324         4706 :   U = *pU; /* NULL if inplace */
    1325              : 
    1326         4706 :   G = cgetg(d+1, t_MAT);
    1327         4706 :   mu = cgetg(d+1, t_MAT);
    1328         4706 :   r  = cgetg(d+1, t_MAT);
    1329         4706 :   s  = cgetg(d+1, t_VEC);
    1330         4706 :   appB = ZM_to_RM(B, prec2);
    1331        27149 :   for (j = 1; j <= d; j++)
    1332              :   {
    1333        22443 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL), S = cgetg(d+1, t_COL);
    1334        22443 :     long l = nbits2lg(prec), l2 = nbits2lg(prec2);
    1335        22443 :     gel(mu,j)= M;
    1336        22443 :     gel(r,j) = R;
    1337        22443 :     gel(G,j) = S;
    1338        22443 :     gel(s,j) = cgetg(l, t_REAL);
    1339       261950 :     for (i = 1; i <= d; i++)
    1340              :     {
    1341       239507 :       gel(R,i) = cgetg(l, t_REAL);
    1342       239507 :       gel(M,i) = cgetg(l, t_REAL);
    1343       239507 :       gel(S,i) = cgetg(l2, t_REAL);
    1344              :     }
    1345              :   }
    1346         4706 :   Gtmp = cgetg(d+1, t_VEC);
    1347         4706 :   alpha = cgetg(d+1, t_VECSMALL);
    1348         4706 :   av = avma;
    1349              : 
    1350              :   /* Step2: Initializing the main loop */
    1351         4706 :   kappamax = 1;
    1352         4706 :   i = 1;
    1353         4706 :   maxG = d; /* later updated to kappamax */
    1354              : 
    1355              :   do {
    1356         4709 :     affrr(RgV_dotsquare(gel(appB,i)), gmael(G,i,i));
    1357         4709 :   } while (signe(gmael(G,i,i)) == 0 && (++i <=d));
    1358         4706 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1359         4706 :   kappa = i;
    1360         4706 :   if (zeros < d) affrr(gmael(G,zeros+1,zeros+1), gmael(r,zeros+1,zeros+1));
    1361        27146 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1362              : 
    1363       305109 :   while (++kappa <= d)
    1364              :   {
    1365       302144 :     if (kappa > kappamax)
    1366              :     {
    1367        12711 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1368        12711 :       maxG = kappamax = kappa;
    1369        12711 :       setG_heuristic(appB, G, kappa, zeros+1, kappa);
    1370              :     }
    1371              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1372       302144 :     if (Babai_heuristic(av, kappa, &B,&U, mu,r,s, appB, G, alpha[kappa], zeros,
    1373         1741 :                         maxG, eta, prec)) { *pB = B; *pU = U; return -1; }
    1374       300403 :     av2 = avma;
    1375       600698 :     if ((keepfirst && kappa == 2) ||
    1376       300295 :         cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0)
    1377              :     { /* Step4: Success of Lovasz's condition */
    1378       179718 :       alpha[kappa] = kappa;
    1379       179718 :       tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1));
    1380       179718 :       affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa));
    1381       179718 :       set_avma(av2); continue;
    1382              :     }
    1383              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1384       120685 :     if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1)))
    1385            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); }
    1386       120685 :     kappa2 = kappa;
    1387              :     do {
    1388       289498 :       kappa--;
    1389       289498 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1390       259513 :       tmp = mulrr(gmael(r,kappa-1,kappa-1), delta);
    1391       259513 :     } while (cmprr(gel(s,kappa-1), tmp) <= 0 );
    1392       120685 :     set_avma(av2);
    1393       120685 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1394              : 
    1395              :     /* Step6: Update the mu's and r's */
    1396       120685 :     rotate(mu,kappa2,kappa);
    1397       120685 :     rotate(r,kappa2,kappa);
    1398       120685 :     affrr(gel(s,kappa), gmael(r,kappa,kappa));
    1399              : 
    1400              :     /* Step7: Update B, appB, U, G */
    1401       120685 :     rotate(B,kappa2,kappa);
    1402       120685 :     rotate(appB,kappa2,kappa);
    1403       120685 :     if (U) rotate(U,kappa2,kappa);
    1404       120685 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    1405              : 
    1406              :     /* Step8: Prepare the next loop iteration */
    1407       120685 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    1408              :     {
    1409            7 :       zeros++; kappa++;
    1410            7 :       affrr(RgV_dotsquare(gel(appB,kappa)), gmael(G,kappa,kappa));
    1411            7 :       affrr(gmael(G,kappa,kappa), gmael(r,kappa,kappa));
    1412              :     }
    1413              :   }
    1414         2965 :   *pB=B; *pU=U; return zeros;
    1415              : }
    1416              : 
    1417              : /************************* PROVED version (t_INT) ***********************/
    1418              : /* dpe inspired by dpe.h by Patrick Pelissier, Paul Zimmermann
    1419              :  * https://gforge.inria.fr/projects/dpe/
    1420              :  */
    1421              : 
    1422              : typedef struct
    1423              : {
    1424              :   double d;  /* significand */
    1425              :   long e; /* exponent */
    1426              : } dpe_t;
    1427              : 
    1428              : #define Dmael(x,i,j) (&((x)[i][j]))
    1429              : #define Del(x,i) (&((x)[i]))
    1430              : 
    1431              : static void
    1432       718524 : dperotate(dpe_t **A, long k2, long k)
    1433              : {
    1434              :   long i;
    1435       718524 :   dpe_t *B = A[k2];
    1436      2588198 :   for (i = k2; i > k; i--) A[i] = A[i-1];
    1437       718524 :   A[k] = B;
    1438       718524 : }
    1439              : 
    1440              : static void
    1441    153382620 : dpe_normalize0(dpe_t *x)
    1442              : {
    1443              :   int e;
    1444    153382620 :   x->d = frexp(x->d, &e);
    1445    153382620 :   x->e += e;
    1446    153382620 : }
    1447              : 
    1448              : static void
    1449     77494763 : dpe_normalize(dpe_t *x)
    1450              : {
    1451     77494763 :   if (x->d == 0.0)
    1452      2211105 :     x->e = -LONG_MAX;
    1453              :   else
    1454     75283658 :     dpe_normalize0(x);
    1455     77494763 : }
    1456              : 
    1457              : static GEN
    1458        26670 : dpetor(dpe_t *x)
    1459              : {
    1460        26670 :   GEN r = dbltor(x->d);
    1461        26670 :   if (signe(r)==0) return r;
    1462        26607 :   setexpo(r, x->e-1);
    1463        26607 :   return r;
    1464              : }
    1465              : 
    1466              : static void
    1467     33168250 : affdpe(dpe_t *y, dpe_t *x)
    1468              : {
    1469     33168250 :   x->d = y->d;
    1470     33168250 :   x->e = y->e;
    1471     33168250 : }
    1472              : 
    1473              : static void
    1474     22440119 : affidpe(GEN y, dpe_t *x)
    1475              : {
    1476     22440119 :   pari_sp av = avma;
    1477     22440119 :   GEN r = itor(y, DEFAULTPREC);
    1478     22440119 :   x->e = expo(r)+1;
    1479     22440119 :   setexpo(r,-1);
    1480     22440119 :   x->d = rtodbl(r);
    1481     22440119 :   set_avma(av);
    1482     22440119 : }
    1483              : 
    1484              : static void
    1485      3210504 : affdbldpe(double y, dpe_t *x)
    1486              : {
    1487      3210504 :   x->d = (double)y;
    1488      3210504 :   x->e = 0;
    1489      3210504 :   dpe_normalize(x);
    1490      3210504 : }
    1491              : 
    1492              : static void
    1493     75175245 : dpe_mulz(dpe_t *x, dpe_t *y, dpe_t *z)
    1494              : {
    1495     75175245 :   z->d = x->d * y->d;
    1496     75175245 :   if (z->d == 0.0)
    1497     10768251 :     z->e = -LONG_MAX;
    1498              :   else
    1499              :   {
    1500     64406994 :     z->e = x->e + y->e;
    1501     64406994 :     dpe_normalize0(z);
    1502              :   }
    1503     75175245 : }
    1504              : 
    1505              : static void
    1506     15649100 : dpe_divz(dpe_t *x, dpe_t *y, dpe_t *z)
    1507              : {
    1508     15649100 :   z->d = x->d / y->d;
    1509     15649100 :   if (z->d == 0.0)
    1510      1957132 :     z->e = -LONG_MAX;
    1511              :   else
    1512              :   {
    1513     13691968 :     z->e = x->e - y->e;
    1514     13691968 :     dpe_normalize0(z);
    1515              :   }
    1516     15649100 : }
    1517              : 
    1518              : static void
    1519       366745 : dpe_negz(dpe_t *y, dpe_t *x)
    1520              : {
    1521       366745 :   x->d = - y->d;
    1522       366745 :   x->e = y->e;
    1523       366745 : }
    1524              : 
    1525              : static void
    1526      6685227 : dpe_addz(dpe_t *y, dpe_t *z, dpe_t *x)
    1527              : {
    1528      6685227 :   if (y->e > z->e + 53)
    1529       985781 :     affdpe(y, x);
    1530      5699446 :   else if (z->e > y->e + 53)
    1531        92121 :     affdpe(z, x);
    1532              :   else
    1533              :   {
    1534      5607325 :     long d = y->e - z->e;
    1535              : 
    1536      5607325 :     if (d >= 0)
    1537              :     {
    1538      4541004 :       x->d = y->d + ldexp(z->d, -d);
    1539      4541004 :       x->e  = y->e;
    1540              :     }
    1541              :     else
    1542              :     {
    1543      1066321 :       x->d = z->d + ldexp(y->d, d);
    1544      1066321 :       x->e = z->e;
    1545              :     }
    1546      5607325 :     dpe_normalize(x);
    1547              :   }
    1548      6685227 : }
    1549              : static void
    1550     76421246 : dpe_subz(dpe_t *y, dpe_t *z, dpe_t *x)
    1551              : {
    1552     76421246 :   if (y->e > z->e + 53)
    1553     16081986 :     affdpe(y, x);
    1554     60339260 :   else if (z->e > y->e + 53)
    1555       366745 :     dpe_negz(z, x);
    1556              :   else
    1557              :   {
    1558     59972515 :     long d = y->e - z->e;
    1559              : 
    1560     59972515 :     if (d >= 0)
    1561              :     {
    1562     55732011 :       x->d = y->d - ldexp(z->d, -d);
    1563     55732011 :       x->e = y->e;
    1564              :     }
    1565              :     else
    1566              :     {
    1567      4240504 :       x->d = ldexp(y->d, d) - z->d;
    1568      4240504 :       x->e = z->e;
    1569              :     }
    1570     59972515 :     dpe_normalize(x);
    1571              :   }
    1572     76421246 : }
    1573              : 
    1574              : static void
    1575      8704419 : dpe_muluz(dpe_t *y, ulong t, dpe_t *x)
    1576              : {
    1577      8704419 :   x->d = y->d * (double)t;
    1578      8704419 :   x->e = y->e;
    1579      8704419 :   dpe_normalize(x);
    1580      8704419 : }
    1581              : 
    1582              : static void
    1583      1345057 : dpe_addmuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1584              : {
    1585              :   dpe_t tmp;
    1586      1345057 :   dpe_muluz(z, t, &tmp);
    1587      1345057 :   dpe_addz(y, &tmp, x);
    1588      1345057 : }
    1589              : 
    1590              : static void
    1591      1433659 : dpe_submuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1592              : {
    1593              :   dpe_t tmp;
    1594      1433659 :   dpe_muluz(z, t, &tmp);
    1595      1433659 :   dpe_subz(y, &tmp, x);
    1596      1433659 : }
    1597              : 
    1598              : static void
    1599     69695441 : dpe_submulz(dpe_t *y,  dpe_t *z, dpe_t *t, dpe_t *x)
    1600              : {
    1601              :   dpe_t tmp;
    1602     69695441 :   dpe_mulz(z, t, &tmp);
    1603     69695441 :   dpe_subz(y, &tmp, x);
    1604     69695441 : }
    1605              : 
    1606              : static int
    1607      5479804 : dpe_cmp(dpe_t *x, dpe_t *y)
    1608              : {
    1609      5479804 :   int sx = x->d < 0. ? -1: x->d > 0.;
    1610      5479804 :   int sy = y->d < 0. ? -1: y->d > 0.;
    1611      5479804 :   int d  = sx - sy;
    1612              : 
    1613      5479804 :   if (d != 0)
    1614       142999 :     return d;
    1615      5336805 :   else if (x->e > y->e)
    1616       550741 :     return (sx > 0) ? 1 : -1;
    1617      4786064 :   else if (y->e > x->e)
    1618      2604063 :     return (sx > 0) ? -1 : 1;
    1619              :   else
    1620      2182001 :     return (x->d < y->d) ? -1 : (x->d > y->d);
    1621              : }
    1622              : 
    1623              : static int
    1624     15812775 : dpe_abscmp(dpe_t *x, dpe_t *y)
    1625              : {
    1626     15812775 :   if (x->e > y->e)
    1627       312064 :     return 1;
    1628     15500711 :   else if (y->e > x->e)
    1629     14574496 :     return -1;
    1630              :   else
    1631       926215 :     return (fabs(x->d) < fabs(y->d)) ? -1 : (fabs(x->d) > fabs(y->d));
    1632              : }
    1633              : 
    1634              : static int
    1635      2183624 : dpe_abssmall(dpe_t *x)
    1636              : {
    1637      2183624 :   return (x->e <= 0) || (x->e == 1 && fabs(x->d) <= .75);
    1638              : }
    1639              : 
    1640              : static int
    1641      5479804 : dpe_cmpmul(dpe_t *x, dpe_t *y, dpe_t *z)
    1642              : {
    1643              :   dpe_t t;
    1644      5479804 :   dpe_mulz(x,y,&t);
    1645      5479804 :   return dpe_cmp(&t, z);
    1646              : }
    1647              : 
    1648              : static dpe_t *
    1649     13317616 : cget_dpevec(long d)
    1650     13317616 : { return (dpe_t*) stack_malloc_align(d*sizeof(dpe_t), sizeof(dpe_t)); }
    1651              : 
    1652              : static dpe_t **
    1653      3210504 : cget_dpemat(long d) { return (dpe_t **) cgetg(d, t_VECSMALL); }
    1654              : 
    1655              : static GEN
    1656         1736 : dpeM_diagonal_shallow(dpe_t **m, long d)
    1657              : {
    1658              :   long i;
    1659         1736 :   GEN y = cgetg(d+1,t_VEC);
    1660        28406 :   for (i=1; i<=d; i++) gel(y, i) = dpetor(Dmael(m,i,i));
    1661         1736 :   return y;
    1662              : }
    1663              : 
    1664              : static void
    1665      2183624 : affii_or_copy_gc(pari_sp av, GEN x, GEN *y)
    1666              : {
    1667      2183624 :   long l = lg(*y);
    1668      2183624 :   if (lgefint(x) <= l && isonstack(*y))
    1669              :   {
    1670      2183612 :     affii(x,*y);
    1671      2183612 :     set_avma(av);
    1672              :   }
    1673              :   else
    1674           12 :     *y = gc_INT(av, x);
    1675      2183624 : }
    1676              : 
    1677              : /* *x -= u*y */
    1678              : INLINE void
    1679     12229399 : submulziu(GEN *x, GEN y, ulong u)
    1680              : {
    1681              :   pari_sp av;
    1682     12229399 :   long ly = lgefint(y);
    1683     12229399 :   if (ly == 2) return;
    1684      6293883 :   av = avma;
    1685      6293883 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1686      6293883 :   y = mului(u,y);
    1687      6293883 :   set_avma(av); subzi(x, y);
    1688              : }
    1689              : 
    1690              : /* *x += u*y */
    1691              : INLINE void
    1692     10826608 : addmulziu(GEN *x, GEN y, ulong u)
    1693              : {
    1694              :   pari_sp av;
    1695     10826608 :   long ly = lgefint(y);
    1696     10826608 :   if (ly == 2) return;
    1697      5767632 :   av = avma;
    1698      5767632 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1699      5767632 :   y = mului(u,y);
    1700      5767632 :   set_avma(av); addzi(x, y);
    1701              : }
    1702              : 
    1703              : /************************** PROVED version (dpe) *************************/
    1704              : 
    1705              : /* Babai's Nearest Plane algorithm (iterative).
    1706              :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    1707              :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    1708              :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    1709              : static int
    1710      4767714 : Babai_dpe(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, dpe_t **mu, dpe_t **r, dpe_t *s,
    1711              :       long a, long zeros, long maxG, dpe_t *eta)
    1712              : {
    1713      4767714 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    1714      4767714 :   long k, d, n, aa = a > zeros? a: zeros+1;
    1715      4767714 :   long emaxmu = EX0, emax2mu = EX0;
    1716              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1717      4767714 :   d = U? lg(U)-1: 0;
    1718      4767714 :   n = B? nbrows(B): 0;
    1719       603686 :   for (;;) {
    1720      5371400 :     int go_on = 0;
    1721      5371400 :     long i, j, emax3mu = emax2mu;
    1722              : 
    1723      5371400 :     if (gc_needed(av,2))
    1724              :     {
    1725            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    1726            0 :       gc_lll(av,3,&G,&B,&U);
    1727              :     }
    1728              :     /* Step2: compute the GSO for stage kappa */
    1729      5371400 :     emax2mu = emaxmu; emaxmu = EX0;
    1730     21020500 :     for (j=aa; j<kappa; j++)
    1731              :     {
    1732              :       dpe_t g;
    1733     15649100 :       affidpe(gmael(G,kappa,j), &g);
    1734     71000758 :       for (k = zeros+1; k < j; k++)
    1735     55351658 :         dpe_submulz(&g, Dmael(mu,j,k), Dmael(r,kappa,k), &g);
    1736     15649100 :       affdpe(&g, Dmael(r,kappa,j));
    1737     15649100 :       dpe_divz(Dmael(r,kappa,j), Dmael(r,j,j), Dmael(mu,kappa,j));
    1738     15649100 :       emaxmu = maxss(emaxmu, Dmael(mu,kappa,j)->e);
    1739              :     }
    1740      5371400 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    1741            0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    1742              : 
    1743     20580489 :     for (j=kappa-1; j>zeros; j--)
    1744     15812775 :       if (dpe_abscmp(Dmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1745              : 
    1746              :     /* Step3--5: compute the X_j's  */
    1747      5371400 :     if (go_on)
    1748      4228640 :       for (j=kappa-1; j>zeros; j--)
    1749              :       {
    1750              :         pari_sp btop;
    1751      3624954 :         dpe_t *tmp = Dmael(mu,kappa,j);
    1752      3624954 :         if (tmp->e < 0) continue; /* (essentially) size-reduced */
    1753              : 
    1754      2183624 :         if (gc_needed(av,2))
    1755              :         {
    1756            0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    1757            0 :           gc_lll(av,3,&G,&B,&U);
    1758              :         }
    1759              :         /* we consider separately the case |X| = 1 */
    1760      2183624 :         if (dpe_abssmall(tmp))
    1761              :         {
    1762      1135663 :           if (tmp->d > 0) { /* in this case, X = 1 */
    1763      2927361 :             for (k=zeros+1; k<j; k++)
    1764      2358410 :               dpe_subz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1765      6368504 :             for (i=1; i<=n; i++)
    1766      5799553 :               subzi(&gmael(B,kappa,i), gmael(B,j,i));
    1767      7700073 :             for (i=1; i<=d; i++)
    1768      7131122 :               subzi(&gmael(U,kappa,i), gmael(U,j,i));
    1769       568951 :             btop = avma;
    1770       568951 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1771       568951 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1772       568951 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1773      3842751 :             for (i=1; i<=j; i++)
    1774      3273800 :               subzi(&gmael(G,kappa,i), gmael(G,j,i));
    1775      3197684 :             for (i=j+1; i<kappa; i++)
    1776      2628733 :               subzi(&gmael(G,kappa,i), gmael(G,i,j));
    1777      2822218 :             for (i=kappa+1; i<=maxG; i++)
    1778      2253267 :               subzi(&gmael(G,i,kappa), gmael(G,i,j));
    1779              :           } else { /* otherwise X = -1 */
    1780      2914915 :             for (k=zeros+1; k<j; k++)
    1781      2348203 :               dpe_addz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1782      6352825 :             for (i=1; i<=n; i++)
    1783      5786113 :               addzi(&gmael(B,kappa,i),gmael(B,j,i));
    1784      7574480 :             for (i=1; i<=d; i++)
    1785      7007768 :               addzi(&gmael(U,kappa,i),gmael(U,j,i));
    1786       566712 :             btop = avma;
    1787       566712 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1788       566712 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1789       566712 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1790      3763207 :             for (i=1; i<=j; i++)
    1791      3196495 :               addzi(&gmael(G,kappa,i), gmael(G,j,i));
    1792      3184909 :             for (i=j+1; i<kappa; i++)
    1793      2618197 :               addzi(&gmael(G,kappa,i), gmael(G,i,j));
    1794      2771969 :             for (i=kappa+1; i<=maxG; i++)
    1795      2205257 :               addzi(&gmael(G,i,kappa), gmael(G,i,j));
    1796              :           }
    1797      1135663 :           continue;
    1798              :         }
    1799              :         /* we have |X| >= 2 */
    1800      1047961 :         if (tmp->e < BITS_IN_LONG-1)
    1801              :         {
    1802       623086 :           if (tmp->d > 0)
    1803              :           {
    1804       335416 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, tmp->e)); /* X fits in an ulong */
    1805      1769075 :             for (k=zeros+1; k<j; k++)
    1806      1433659 :               dpe_submuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1807      4765145 :             for (i=1; i<=n; i++)
    1808      4429729 :               submulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1809      3253134 :             for (i=1; i<=d; i++)
    1810      2917718 :               submulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1811       335416 :             btop = avma;
    1812       335416 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1813       335416 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1814       335416 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1815      2514827 :             for (i=1; i<=j; i++)
    1816      2179411 :               submulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1817      2039934 :             for (i=j+1; i<kappa; i++)
    1818      1704518 :               submulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1819      1333439 :             for (i=kappa+1; i<=maxG; i++)
    1820       998023 :               submulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1821              :           }
    1822              :           else
    1823              :           {
    1824       287670 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, tmp->e)); /* X fits in an ulong */
    1825      1632727 :             for (k=zeros+1; k<j; k++)
    1826      1345057 :               dpe_addmuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1827      4688090 :             for (i=1; i<=n; i++)
    1828      4400420 :               addmulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1829      2503532 :             for (i=1; i<=d; i++)
    1830      2215862 :               addmulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1831       287670 :             btop = avma;
    1832       287670 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1833       287670 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1834       287670 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1835      2168749 :             for (i=1; i<=j; i++)
    1836      1881079 :               addmulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1837      1893326 :             for (i=j+1; i<kappa; i++)
    1838      1605656 :               addmulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1839      1011261 :             for (i=kappa+1; i<=maxG; i++)
    1840       723591 :               addmulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1841              :           }
    1842              :         }
    1843              :         else
    1844              :         {
    1845       424875 :           long e = tmp->e - BITS_IN_LONG + 1;
    1846       424875 :           if (tmp->d > 0)
    1847              :           {
    1848       211202 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, BITS_IN_LONG - 1));
    1849      3144938 :             for (k=zeros+1; k<j; k++)
    1850              :             {
    1851              :               dpe_t x;
    1852      2933736 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1853      2933736 :               x.e += e;
    1854      2933736 :               dpe_subz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1855              :             }
    1856     10752252 :             for (i=1; i<=n; i++)
    1857     10541050 :               submulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1858       319409 :             for (i=1; i<=d; i++)
    1859       108207 :               submulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1860       211202 :             btop = avma;
    1861       211202 :             ztmp = submuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1862       211202 :                 gmael(G,kappa,j), xx, e+1);
    1863       211202 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1864       211202 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1865      3358154 :             for (i=1; i<=j; i++)
    1866      3146952 :               submulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1867      3280865 :             for (   ; i<kappa; i++)
    1868      3069663 :               submulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1869       213227 :             for (i=kappa+1; i<=maxG; i++)
    1870         2025 :               submulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1871              :           } else
    1872              :           {
    1873       213673 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, BITS_IN_LONG - 1));
    1874      3205640 :             for (k=zeros+1; k<j; k++)
    1875              :             {
    1876              :               dpe_t x;
    1877      2991967 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1878      2991967 :               x.e += e;
    1879      2991967 :               dpe_addz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1880              :             }
    1881     10891725 :             for (i=1; i<=n; i++)
    1882     10678052 :               addmulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1883       322287 :             for (i=1; i<=d; i++)
    1884       108614 :               addmulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1885       213673 :             btop = avma;
    1886       213673 :             ztmp = addmuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1887       213673 :                 gmael(G,kappa,j), xx, e+1);
    1888       213673 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1889       213673 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1890      3421132 :             for (i=1; i<=j; i++)
    1891      3207459 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1892      3288274 :             for (   ; i<kappa; i++)
    1893      3074601 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1894       215539 :             for (i=kappa+1; i<=maxG; i++)
    1895         1866 :               addmulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1896              :           }
    1897              :         }
    1898              :       }
    1899      5371400 :     if (!go_on) break; /* Anything happened? */
    1900       603686 :     aa = zeros+1;
    1901              :   }
    1902              : 
    1903      4767714 :   affidpe(gmael(G,kappa,kappa), Del(s,zeros+1));
    1904              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    1905     14703045 :   for (k=zeros+1; k<=kappa-2; k++)
    1906      9935331 :     dpe_submulz(Del(s,k), Dmael(mu,kappa,k), Dmael(r,kappa,k), Del(s,k+1));
    1907      4767714 :   *pG = G; *pB = B; *pU = U; return 0;
    1908              : }
    1909              : 
    1910              : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    1911              :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    1912              :  * If G = NULL, we compute the Gram matrix incrementally.
    1913              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1914              : static long
    1915      1605252 : fplll_dpe(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    1916              :       long keepfirst)
    1917              : {
    1918              :   pari_sp av;
    1919      1605252 :   GEN Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    1920      1605252 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    1921              :   dpe_t delta, eta, **mu, **r, *s;
    1922      1605252 :   affdbldpe(DELTA,&delta);
    1923      1605252 :   affdbldpe(ETA,&eta);
    1924              : 
    1925      1605252 :   if (incgram)
    1926              :   { /* incremental Gram matrix */
    1927      1544696 :     maxG = 2; d = lg(B)-1;
    1928      1544696 :     G = zeromatcopy(d, d);
    1929              :   }
    1930              :   else
    1931        60556 :     maxG = d = lg(G)-1;
    1932              : 
    1933      1605252 :   mu = cget_dpemat(d+1);
    1934      1605252 :   r  = cget_dpemat(d+1);
    1935      1605252 :   s  = cget_dpevec(d+1);
    1936      7461434 :   for (j = 1; j <= d; j++)
    1937              :   {
    1938      5856182 :     mu[j]= cget_dpevec(d+1);
    1939      5856182 :     r[j] = cget_dpevec(d+1);
    1940              :   }
    1941      1605252 :   Gtmp = cgetg(d+1, t_VEC);
    1942      1605252 :   alpha = cgetg(d+1, t_VECSMALL);
    1943      1605252 :   av = avma;
    1944              : 
    1945              :   /* Step2: Initializing the main loop */
    1946      1605252 :   kappamax = 1;
    1947      1605252 :   i = 1;
    1948              :   do {
    1949      1988109 :     if (incgram) gmael(G,i,i) = ZV_dotsquare(gel(B,i));
    1950      1988109 :     affidpe(gmael(G,i,i), Dmael(r,i,i));
    1951      1988109 :   } while (!signe(gmael(G,i,i)) && ++i <= d);
    1952      1605252 :   zeros = i-1; /* all basis vectors b_i with i <= zeros are zero vectors */
    1953      1605252 :   kappa = i;
    1954      7078570 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1955              : 
    1956      6372966 :   while (++kappa <= d)
    1957              :   {
    1958      4767714 :     if (kappa > kappamax)
    1959              :     {
    1960      3868073 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1961      3868073 :       kappamax = kappa;
    1962      3868073 :       if (incgram)
    1963              :       {
    1964     16227078 :         for (i=zeros+1; i<=kappa; i++)
    1965     12559526 :           gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i));
    1966      3667552 :         maxG = kappamax;
    1967              :       }
    1968              :     }
    1969              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1970      4767714 :     if (Babai_dpe(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, &eta))
    1971            0 :     { *pG = incgram? NULL: G; *pB = B; *pU = U; return -1; }
    1972      9435211 :     if ((keepfirst && kappa == 2) ||
    1973      4667497 :         dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) <= 0)
    1974              :     { /* Step4: Success of Lovasz's condition */
    1975      4408452 :       alpha[kappa] = kappa;
    1976      4408452 :       dpe_submulz(Del(s,kappa-1), Dmael(mu,kappa,kappa-1), Dmael(r,kappa,kappa-1), Dmael(r,kappa,kappa));
    1977      4408452 :       continue;
    1978              :     }
    1979              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1980       359262 :     if (DEBUGLEVEL>=4 && kappa==kappamax && Del(s,kappa-1)->d)
    1981            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", Del(s,1)->e-1); }
    1982       359262 :     kappa2 = kappa;
    1983              :     do {
    1984       934837 :       kappa--;
    1985       934837 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1986       812307 :     } while (dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) >= 0);
    1987       359262 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1988              : 
    1989              :     /* Step6: Update the mu's and r's */
    1990       359262 :     dperotate(mu, kappa2, kappa);
    1991       359262 :     dperotate(r, kappa2, kappa);
    1992       359262 :     affdpe(Del(s,kappa), Dmael(r,kappa,kappa));
    1993              : 
    1994              :     /* Step7: Update G, B, U */
    1995       359262 :     if (U) rotate(U, kappa2, kappa);
    1996       359262 :     if (B) rotate(B, kappa2, kappa);
    1997       359262 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    1998              : 
    1999              :     /* Step8: Prepare the next loop iteration */
    2000       359262 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    2001              :     {
    2002        35196 :       zeros++; kappa++;
    2003        35196 :       affidpe(gmael(G,kappa,kappa), Dmael(r,kappa,kappa));
    2004              :     }
    2005              :   }
    2006      1605252 :   if (pr) *pr = dpeM_diagonal_shallow(r,d);
    2007      1605252 :   *pG = G; *pB = B; *pU = U; return zeros; /* success */
    2008              : }
    2009              : 
    2010              : 
    2011              : /************************** PROVED version (t_INT) *************************/
    2012              : 
    2013              : /* Babai's Nearest Plane algorithm (iterative).
    2014              :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    2015              :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    2016              :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    2017              : static int
    2018            0 : Babai(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, GEN mu, GEN r, GEN s,
    2019              :       long a, long zeros, long maxG, GEN eta, long prec)
    2020              : {
    2021            0 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    2022            0 :   long k, aa = a > zeros? a: zeros+1;
    2023            0 :   const long n = B? nbrows(B): 0, d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    2024            0 :   long emaxmu = EX0, emax2mu = EX0;
    2025              :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    2026              : 
    2027            0 :   for (;;) {
    2028            0 :     int go_on = 0;
    2029            0 :     long i, j, emax3mu = emax2mu;
    2030              : 
    2031            0 :     if (gc_needed(av,2))
    2032              :     {
    2033            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    2034            0 :       gc_lll(av,3,&G,&B,&U);
    2035              :     }
    2036              :     /* Step2: compute the GSO for stage kappa */
    2037            0 :     emax2mu = emaxmu; emaxmu = EX0;
    2038            0 :     for (j=aa; j<kappa; j++)
    2039              :     {
    2040            0 :       pari_sp btop = avma;
    2041            0 :       GEN g = gmael(G,kappa,j);
    2042            0 :       k = zeros + 1;
    2043            0 :       if (k >= j)
    2044            0 :         affir(g, gmael(r,kappa,j));
    2045              :       else
    2046              :       {
    2047            0 :         g = subir(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    2048            0 :         for (k++; k < j; k++)
    2049            0 :           g = subrr(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    2050            0 :         affrr(g, gmael(r,kappa,j));
    2051              :       }
    2052            0 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    2053            0 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    2054            0 :       set_avma(btop);
    2055              :     }
    2056            0 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    2057            0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    2058              : 
    2059            0 :     for (j=kappa-1; j>zeros; j--)
    2060            0 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    2061              : 
    2062              :     /* Step3--5: compute the X_j's  */
    2063            0 :     if (go_on)
    2064            0 :       for (j=kappa-1; j>zeros; j--)
    2065              :       {
    2066              :         pari_sp btop;
    2067            0 :         GEN tmp = gmael(mu,kappa,j);
    2068            0 :         if (absrsmall(tmp)) continue; /* size-reduced */
    2069              : 
    2070            0 :         if (gc_needed(av,2))
    2071              :         {
    2072            0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    2073            0 :           gc_lll(av,3,&G,&B,&U);
    2074              :         }
    2075            0 :         btop = avma;
    2076              :         /* we consider separately the case |X| = 1 */
    2077            0 :         if (absrsmall2(tmp))
    2078              :         {
    2079            0 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    2080            0 :             for (k=zeros+1; k<j; k++)
    2081            0 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2082            0 :             set_avma(btop);
    2083            0 :             for (i=1; i<=n; i++)
    2084            0 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    2085            0 :             for (i=1; i<=d; i++)
    2086            0 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
    2087            0 :             btop = avma;
    2088            0 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2089            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2090            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2091            0 :             for (i=1; i<=j; i++)
    2092            0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,j,i));
    2093            0 :             for (i=j+1; i<kappa; i++)
    2094            0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,i,j));
    2095            0 :             for (i=kappa+1; i<=maxG; i++)
    2096            0 :               gmael(G,i,kappa) = subii(gmael(G,i,kappa), gmael(G,i,j));
    2097              :           } else { /* otherwise X = -1 */
    2098            0 :             for (k=zeros+1; k<j; k++)
    2099            0 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2100            0 :             set_avma(btop);
    2101            0 :             for (i=1; i<=n; i++)
    2102            0 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i),gmael(B,j,i));
    2103            0 :             for (i=1; i<=d; i++)
    2104            0 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    2105            0 :             btop = avma;
    2106            0 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2107            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2108            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2109            0 :             for (i=1; i<=j; i++)
    2110            0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,j,i));
    2111            0 :             for (i=j+1; i<kappa; i++)
    2112            0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,i,j));
    2113            0 :             for (i=kappa+1; i<=maxG; i++)
    2114            0 :               gmael(G,i,kappa) = addii(gmael(G,i,kappa), gmael(G,i,j));
    2115              :           }
    2116            0 :           continue;
    2117              :         }
    2118              :         /* we have |X| >= 2 */
    2119            0 :         if (expo(tmp) < BITS_IN_LONG)
    2120              :         {
    2121            0 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    2122            0 :           if (signe(tmp) > 0) /* = xx */
    2123              :           {
    2124            0 :             for (k=zeros+1; k<j; k++)
    2125            0 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2126            0 :                   gmael(mu,kappa,k));
    2127            0 :             set_avma(btop);
    2128            0 :             for (i=1; i<=n; i++)
    2129            0 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2130            0 :             for (i=1; i<=d; i++)
    2131            0 :               gmael(U,kappa,i) = submuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2132            0 :             btop = avma;
    2133            0 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2134            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2135            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2136            0 :             for (i=1; i<=j; i++)
    2137            0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2138            0 :             for (i=j+1; i<kappa; i++)
    2139            0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2140            0 :             for (i=kappa+1; i<=maxG; i++)
    2141            0 :               gmael(G,i,kappa) = submuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2142              :           }
    2143              :           else /* = -xx */
    2144              :           {
    2145            0 :             for (k=zeros+1; k<j; k++)
    2146            0 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2147            0 :                   gmael(mu,kappa,k));
    2148            0 :             set_avma(btop);
    2149            0 :             for (i=1; i<=n; i++)
    2150            0 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2151            0 :             for (i=1; i<=d; i++)
    2152            0 :               gmael(U,kappa,i) = addmuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2153            0 :             btop = avma;
    2154            0 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2155            0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2156            0 :             gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2157            0 :             for (i=1; i<=j; i++)
    2158            0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2159            0 :             for (i=j+1; i<kappa; i++)
    2160            0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2161            0 :             for (i=kappa+1; i<=maxG; i++)
    2162            0 :               gmael(G,i,kappa) = addmuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2163              :           }
    2164              :         }
    2165              :         else
    2166              :         {
    2167              :           long e;
    2168            0 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    2169            0 :           btop = avma;
    2170            0 :           for (k=zeros+1; k<j; k++)
    2171              :           {
    2172            0 :             GEN x = mulir(X, gmael(mu,j,k));
    2173            0 :             if (e) shiftr_inplace(x, e);
    2174            0 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    2175              :           }
    2176            0 :           set_avma(btop);
    2177            0 :           for (i=1; i<=n; i++)
    2178            0 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    2179            0 :           for (i=1; i<=d; i++)
    2180            0 :             gmael(U,kappa,i) = submulshift(gmael(U,kappa,i), gmael(U,j,i), X, e);
    2181            0 :           btop = avma;
    2182            0 :           ztmp = submulshift(mulshift(gmael(G,j,j), sqri(X), 2*e),
    2183            0 :               gmael(G,kappa,j), X, e+1);
    2184            0 :           ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2185            0 :           gmael(G,kappa,kappa) = gc_INT(btop, ztmp);
    2186            0 :           for (i=1; i<=j; i++)
    2187            0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,j,i), X, e);
    2188            0 :           for (   ; i<kappa; i++)
    2189            0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,i,j), X, e);
    2190            0 :           for (i=kappa+1; i<=maxG; i++)
    2191            0 :             gmael(G,i,kappa) = submulshift(gmael(G,i,kappa), gmael(G,i,j), X, e);
    2192              :         }
    2193              :       }
    2194            0 :     if (!go_on) break; /* Anything happened? */
    2195            0 :     aa = zeros+1;
    2196              :   }
    2197              : 
    2198            0 :   affir(gmael(G,kappa,kappa), gel(s,zeros+1));
    2199              :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    2200            0 :   av = avma;
    2201            0 :   for (k=zeros+1; k<=kappa-2; k++)
    2202            0 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    2203            0 :           gel(s,k+1));
    2204            0 :   *pG = G; *pB = B; *pU = U; return gc_bool(av, 0);
    2205              : }
    2206              : 
    2207              : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    2208              :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    2209              :  * If G = NULL, we compute the Gram matrix incrementally.
    2210              :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    2211              : static long
    2212            0 : fplll(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    2213              :       long keepfirst, long prec)
    2214              : {
    2215              :   pari_sp av, av2;
    2216            0 :   GEN mu, r, s, tmp, Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    2217            0 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    2218            0 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    2219              : 
    2220            0 :   if (incgram)
    2221              :   { /* incremental Gram matrix */
    2222            0 :     maxG = 2; d = lg(B)-1;
    2223            0 :     G = zeromatcopy(d, d);
    2224              :   }
    2225              :   else
    2226            0 :     maxG = d = lg(G)-1;
    2227              : 
    2228            0 :   mu = cgetg(d+1, t_MAT);
    2229            0 :   r  = cgetg(d+1, t_MAT);
    2230            0 :   s  = cgetg(d+1, t_VEC);
    2231            0 :   for (j = 1; j <= d; j++)
    2232              :   {
    2233            0 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL);
    2234            0 :     long l = nbits2lg(prec);
    2235            0 :     gel(mu,j)= M;
    2236            0 :     gel(r,j) = R;
    2237            0 :     gel(s,j) = cgetg(l, t_REAL);
    2238            0 :     for (i = 1; i <= d; i++)
    2239              :     {
    2240            0 :       gel(R,i) = cgetg(l, t_REAL);
    2241            0 :       gel(M,i) = cgetg(l, t_REAL);
    2242              :     }
    2243              :   }
    2244            0 :   Gtmp = cgetg(d+1, t_VEC);
    2245            0 :   alpha = cgetg(d+1, t_VECSMALL);
    2246            0 :   av = avma;
    2247              : 
    2248              :   /* Step2: Initializing the main loop */
    2249            0 :   kappamax = 1;
    2250            0 :   i = 1;
    2251              :   do {
    2252            0 :     if (incgram) gmael(G,i,i) = ZV_dotsquare(gel(B,i));
    2253            0 :     affir(gmael(G,i,i), gmael(r,i,i));
    2254            0 :   } while (!signe(gmael(G,i,i)) && ++i <= d);
    2255            0 :   zeros = i-1; /* all basis vectors b_i with i <= zeros are zero vectors */
    2256            0 :   kappa = i;
    2257            0 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    2258              : 
    2259            0 :   while (++kappa <= d)
    2260              :   {
    2261            0 :     if (kappa > kappamax)
    2262              :     {
    2263            0 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    2264            0 :       kappamax = kappa;
    2265            0 :       if (incgram)
    2266              :       {
    2267            0 :         for (i=zeros+1; i<=kappa; i++)
    2268            0 :           gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i));
    2269            0 :         maxG = kappamax;
    2270              :       }
    2271              :     }
    2272              :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    2273            0 :     if (Babai(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, eta, prec))
    2274            0 :     { *pG = incgram? NULL: G; *pB = B; *pU = U; return -1; }
    2275            0 :     av2 = avma;
    2276            0 :     if ((keepfirst && kappa == 2) ||
    2277            0 :         cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0)
    2278              :     { /* Step4: Success of Lovasz's condition */
    2279            0 :       alpha[kappa] = kappa;
    2280            0 :       tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1));
    2281            0 :       affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa));
    2282            0 :       set_avma(av2); continue;
    2283              :     }
    2284              :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    2285            0 :     if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1)))
    2286            0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); }
    2287            0 :     kappa2 = kappa;
    2288              :     do {
    2289            0 :       kappa--;
    2290            0 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    2291            0 :       tmp = mulrr(gmael(r,kappa-1,kappa-1), delta);
    2292            0 :     } while (cmprr(gel(s,kappa-1), tmp) <= 0);
    2293            0 :     set_avma(av2);
    2294            0 :     update_alpha(alpha, kappa, kappa2, kappamax);
    2295              : 
    2296              :     /* Step6: Update the mu's and r's */
    2297            0 :     rotate(mu, kappa2, kappa);
    2298            0 :     rotate(r, kappa2, kappa);
    2299            0 :     affrr(gel(s,kappa), gmael(r,kappa,kappa));
    2300              : 
    2301              :     /* Step7: Update G, B, U */
    2302            0 :     if (U) rotate(U, kappa2, kappa);
    2303            0 :     if (B) rotate(B, kappa2, kappa);
    2304            0 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    2305              : 
    2306              :     /* Step8: Prepare the next loop iteration */
    2307            0 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    2308              :     {
    2309            0 :       zeros++; kappa++;
    2310            0 :       affir(gmael(G,kappa,kappa), gmael(r,kappa,kappa));
    2311              :     }
    2312              :   }
    2313            0 :   if (pr) *pr = RgM_diagonal_shallow(r);
    2314            0 :   *pG = G; *pB = B; *pU = U; return zeros; /* success */
    2315              : }
    2316              : 
    2317              : /* do not support LLL_KER, LLL_ALL, LLL_KEEP_FIRST */
    2318              : static GEN
    2319      4851223 : ZM2_lll_norms(GEN x, long flag, GEN *pN)
    2320              : {
    2321              :   GEN a,b,c,d;
    2322              :   GEN G, U;
    2323      4851223 :   if (flag & LLL_GRAM)
    2324         7356 :     G = x;
    2325              :   else
    2326      4843867 :     G = gram_matrix(x);
    2327      4851223 :   a = gcoeff(G,1,1); b = shifti(gcoeff(G,1,2),1); c = gcoeff(G,2,2);
    2328      4851223 :   d = qfb_disc3(a,b,c);
    2329      4851223 :   if (signe(d)>=0) return NULL;
    2330      4850838 :   G = redimagsl2(mkqfb(a,b,c,d),&U);
    2331      4850838 :   if (pN) (void) RgM_gram_schmidt(G, pN);
    2332      4850838 :   if (flag & LLL_INPLACE) return ZM2_mul(x,U);
    2333      4850838 :   return U;
    2334              : }
    2335              : 
    2336              : static void
    2337       626205 : fplll_flatter(GEN *pG, GEN *pB, GEN *pU, long rank, long flag)
    2338              : {
    2339       626205 :   if (!*pG)
    2340              :   {
    2341       625237 :     GEN T = ZM_flatter_rank(*pB, rank, flag);
    2342       625237 :     if (T)
    2343              :     {
    2344       328484 :       if (*pU)
    2345              :       {
    2346       314476 :         *pU = ZM_mul(*pU, T);
    2347       314476 :         *pB = ZM_mul(*pB, T);
    2348              :       }
    2349        14008 :       else *pB = T;
    2350              :     }
    2351              :   }
    2352              :   else
    2353              :   {
    2354          968 :     GEN T, G = *pG;
    2355          968 :     long i, j, l = lg(G);
    2356         7634 :     for (i = 1; i < l; i++)
    2357        56193 :       for(j = 1; j < i; j++) gmael(G,j,i) = gmael(G,i,j);
    2358          968 :     T = ZM_flattergram_rank(G, rank, flag);
    2359          968 :     if (T)
    2360              :     {
    2361          968 :       if (*pU) *pU = ZM_mul(*pU, T);
    2362          968 :       *pG = qf_ZM_apply(*pG, T);
    2363              :     }
    2364              :   }
    2365       626205 : }
    2366              : 
    2367              : static GEN
    2368      1099641 : get_gramschmidt(GEN M, long rank)
    2369              : {
    2370              :   GEN B, Q, L;
    2371      1099641 :   long r = lg(M)-1, prec = nbits2prec64(3*r + 30);
    2372      1099641 :   if (rank < r) M = vconcat(gshift(M,1), matid(r));
    2373      1099641 :   if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec)) return NULL;
    2374       475537 :   return L;
    2375              : }
    2376              : 
    2377              : static GEN
    2378        44547 : get_cholesky(GEN M, long rank)
    2379              : {
    2380        44547 :   long r = lg(M)-1, prec = nbits2prec64(3*r + 30);
    2381        44547 :   if (rank < r) M = RgM_Rg_add(gshift(M, 1), gen_1);
    2382        44547 :   return RgM_Cholesky(RgM_gtofp(M, prec), prec);
    2383              : }
    2384              : 
    2385              : static long
    2386        92869 : thsn(long n)
    2387              : {
    2388        92869 :   long T[]={23280,30486,50077,44136,78724,15690,1801,1611,
    2389              :             981,1359,978,1042,815,866,788,775,726,712,
    2390              :             626,613,548,564,474,481,504,447,453,508,
    2391              :             705,794,1008,946,767,898,886,763,842,757,
    2392              :             725,774,639,655,705,627,635,704,511,613,
    2393              :             583,595,568,640,541,640,567,540,577,584,
    2394              :             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};
    2395        92869 :   return T[minss(n-3,numberof(T)-1)];
    2396              : }
    2397              : static long
    2398      1033745 : thre(long n)
    2399              : {
    2400      1033745 :   long T[]={31783,34393,20894,22525,13533,1928,672,671,
    2401              :             422,506,315,313,222,205,167,154,139,138,
    2402              :             110,120,98,94,81,75,74,64,74,74,
    2403              :             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,
    2404              :             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};
    2405      1033745 :    return T[minss(n-3,numberof(T)-1)];
    2406              : }
    2407              : 
    2408              : /* Assume x a ZM, if pN != NULL, set it to Gram-Schmidt (squared) norms
    2409              :  * The following modes are supported:
    2410              :  * - flag & LLL_INPLACE: x a lattice basis, return x*U
    2411              :  * - flag & LLL_GRAM: x a Gram matrix / else x a lattice basis; return
    2412              :  *     LLL base change matrix U [LLL_IM]
    2413              :  *     kernel basis [LLL_KER, nonreduced]
    2414              :  *     both [LLL_ALL] */
    2415              : GEN
    2416      7144037 : ZM_lll_norms(GEN x, double DELTA, long flag, GEN *pN)
    2417              : {
    2418      7144037 :   pari_sp av = avma;
    2419      7144037 :   const double ETA = 0.51;
    2420      7144037 :   const long keepfirst = flag & LLL_KEEP_FIRST;
    2421      7144037 :   long p, zeros = -1, n = lg(x)-1, is_upper, is_lower, useflatter, rank;
    2422      7144037 :   GEN G, B, U, L = NULL;
    2423              :   pari_timer T;
    2424      7144037 :   if (n <= 1) return lll_trivial(x, flag);
    2425      7033969 :   if (nbrows(x)==0)
    2426              :   {
    2427        15151 :     if (flag & LLL_KER) return matid(n);
    2428        15151 :     if (flag & (LLL_INPLACE|LLL_IM)) return cgetg(1,t_MAT);
    2429            0 :     retmkvec2(matid(n), cgetg(1,t_MAT));
    2430              :   }
    2431      7018818 :   if (n==2 && nbrows(x)==2  && (flag&LLL_IM) && !keepfirst)
    2432              :   {
    2433      4851223 :     U = ZM2_lll_norms(x, flag, pN);
    2434      4851223 :     if (U) return U;
    2435              :   }
    2436      2167980 :   if (flag & LLL_GRAM)
    2437        60556 :   { G = x; B = NULL; U = matid(n); is_upper = 0; is_lower = 0; }
    2438              :   else
    2439              :   {
    2440      2107424 :     G = NULL; B = x; U = (flag & LLL_INPLACE)? NULL: matid(n);
    2441      2107424 :     is_upper = (flag & LLL_UPPER) || ZM_is_upper(B);
    2442      2107424 :     is_lower = !B || is_upper || keepfirst ? 0: ZM_is_lower(B);
    2443      2107424 :     if (is_lower) L = RgM_flip(B);
    2444              :   }
    2445      2167980 :   rank = useflatter = 0;
    2446      2167980 :   if (n > 2 && !(flag&LLL_NOFLATTER))
    2447              :   {
    2448      1751686 :     pari_sp av2 = avma;
    2449              :     GEN R;
    2450      1751686 :     rank = ZM_rank(x);
    2451      1707139 :     R = B ? (is_upper ? B : (is_lower ? L : get_gramschmidt(B, rank)))
    2452      3458825 :           : get_cholesky(G, rank);
    2453      1751686 :     if (R)
    2454              :     {
    2455      1126614 :       long spr = spread(R), sz = gexpo(R), thr;
    2456      1126614 :       if (DEBUGLEVEL>=5)
    2457            0 :         err_printf("LLL: dim %ld, size %ld, spread %ld\n",n, sz, spr);
    2458      1126614 :       if ((is_upper && ZM_is_knapsack(B)) || (is_lower && ZM_is_knapsack(L)))
    2459        92869 :         thr = thsn(n);
    2460              :       else
    2461              :       {
    2462      1033745 :         thr = thre(n);
    2463      1033745 :         if (n >= 10) sz = spr;
    2464              :       }
    2465      1126614 :       useflatter = sz >= thr;
    2466              :     } else
    2467       625072 :       useflatter = 1;
    2468      1751686 :     set_avma(av2);
    2469              :   }
    2470      2167980 :   if(DEBUGLEVEL>=4) timer_start(&T);
    2471      2167980 :   if (useflatter)
    2472              :   {
    2473       626205 :     if (is_lower)
    2474              :     {
    2475            0 :       fplll_flatter(&G, &L, &U, rank, flag | LLL_UPPER);
    2476            0 :       B = RgM_flop(L);
    2477            0 :       if (U) U = RgM_flop(U);
    2478              :     }
    2479              :     else
    2480       626205 :       fplll_flatter(&G, &B, &U, rank, flag | (is_upper? LLL_UPPER:0));
    2481       626205 :     if (DEBUGLEVEL>=4  && !(flag & LLL_NOCERTIFY))
    2482            0 :       timer_printf(&T, "FLATTER");
    2483              :   }
    2484      2167980 :   if (!(flag & LLL_GRAM))
    2485              :   {
    2486              :     long t;
    2487      2107424 :     long heu_max = n<100 ? 1: 2; /* need better tuning */
    2488      2107424 :     B = gcopy(B);
    2489      2107424 :     if(DEBUGLEVEL>=4)
    2490            0 :       err_printf("Entering L^2 (double): dim %ld, LLL-parameters (%.3f,%.3f)\n",
    2491              :                  n, DELTA,ETA);
    2492      2107424 :     zeros = fplll_fast(&B, &U, DELTA, ETA, keepfirst);
    2493      2107424 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2494      2112130 :     for (p = DEFAULTPREC, t = 0; zeros < 0 && t < heu_max ; p += EXTRAPREC64, t++)
    2495              :     {
    2496         4706 :       if (DEBUGLEVEL>=4)
    2497            0 :         err_printf("Entering L^2 (heuristic): LLL-parameters (%.3f,%.3f), prec = %d/%d\n", DELTA, ETA, p, p);
    2498         4706 :       zeros = fplll_heuristic(&B, &U, DELTA, ETA, keepfirst, p, p);
    2499         4706 :       gc_lll(av, 2, &B, &U);
    2500         4706 :       if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2501              :     }
    2502              :   } else
    2503        60556 :     G = gcopy(G);
    2504      2167980 :   if (zeros < 0 || !(flag & LLL_NOCERTIFY))
    2505              :   {
    2506      1605252 :     if(DEBUGLEVEL>=4)
    2507            0 :       err_printf("Entering L^2 (dpe): LLL-parameters (%.3f,%.3f)\n", DELTA,ETA);
    2508      1605252 :     zeros = fplll_dpe(&G, &B, &U, pN, DELTA, ETA, keepfirst);
    2509      1605252 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2510      1605252 :     if (zeros < 0)
    2511            0 :       for (p = DEFAULTPREC;; p += EXTRAPREC64)
    2512              :       {
    2513            0 :         if (DEBUGLEVEL>=4)
    2514            0 :           err_printf("Entering L^2: LLL-parameters (%.3f,%.3f), prec = %d\n",
    2515              :               DELTA,ETA, p);
    2516            0 :         zeros = fplll(&G, &B, &U, pN, DELTA, ETA, keepfirst, p);
    2517            0 :         if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2518            0 :         if (zeros >= 0) break;
    2519            0 :         gc_lll(av, 3, &G, &B, &U);
    2520              :       }
    2521              :   }
    2522      2167980 :   return lll_finish(U? U: B, zeros, flag);
    2523              : }
    2524              : 
    2525              : /********************************************************************/
    2526              : /**                                                                **/
    2527              : /**                        LLL OVER K[X]                           **/
    2528              : /**                                                                **/
    2529              : /********************************************************************/
    2530              : static int
    2531          504 : pslg(GEN x)
    2532              : {
    2533              :   long tx;
    2534          504 :   if (gequal0(x)) return 2;
    2535          448 :   tx = typ(x); return is_scalar_t(tx)? 3: lg(x);
    2536              : }
    2537              : 
    2538              : static int
    2539          196 : REDgen(long k, long l, GEN h, GEN L, GEN B)
    2540              : {
    2541          196 :   GEN q, u = gcoeff(L,k,l);
    2542              :   long i;
    2543              : 
    2544          196 :   if (pslg(u) < pslg(B)) return 0;
    2545              : 
    2546          140 :   q = gneg(gdeuc(u,B));
    2547          140 :   gel(h,k) = gadd(gel(h,k), gmul(q,gel(h,l)));
    2548          140 :   for (i=1; i<l; i++) gcoeff(L,k,i) = gadd(gcoeff(L,k,i), gmul(q,gcoeff(L,l,i)));
    2549          140 :   gcoeff(L,k,l) = gadd(gcoeff(L,k,l), gmul(q,B)); return 1;
    2550              : }
    2551              : 
    2552              : static int
    2553          196 : do_SWAPgen(GEN h, GEN L, GEN B, long k, GEN fl, int *flc)
    2554              : {
    2555              :   GEN p1, la, la2, Bk;
    2556              :   long ps1, ps2, i, j, lx;
    2557              : 
    2558          196 :   if (!fl[k-1]) return 0;
    2559              : 
    2560          140 :   la = gcoeff(L,k,k-1); la2 = gsqr(la);
    2561          140 :   Bk = gel(B,k);
    2562          140 :   if (fl[k])
    2563              :   {
    2564           56 :     GEN q = gadd(la2, gmul(gel(B,k-1),gel(B,k+1)));
    2565           56 :     ps1 = pslg(gsqr(Bk));
    2566           56 :     ps2 = pslg(q);
    2567           56 :     if (ps1 <= ps2 && (ps1 < ps2 || !*flc)) return 0;
    2568           28 :     *flc = (ps1 != ps2);
    2569           28 :     gel(B,k) = gdiv(q, Bk);
    2570              :   }
    2571              : 
    2572          112 :   swap(gel(h,k-1), gel(h,k)); lx = lg(L);
    2573          112 :   for (j=1; j<k-1; j++) swap(gcoeff(L,k-1,j), gcoeff(L,k,j));
    2574          112 :   if (fl[k])
    2575              :   {
    2576           28 :     for (i=k+1; i<lx; i++)
    2577              :     {
    2578            0 :       GEN t = gcoeff(L,i,k);
    2579            0 :       p1 = gsub(gmul(gel(B,k+1),gcoeff(L,i,k-1)), gmul(la,t));
    2580            0 :       gcoeff(L,i,k) = gdiv(p1, Bk);
    2581            0 :       p1 = gadd(gmul(la,gcoeff(L,i,k-1)), gmul(gel(B,k-1),t));
    2582            0 :       gcoeff(L,i,k-1) = gdiv(p1, Bk);
    2583              :     }
    2584              :   }
    2585           84 :   else if (!gequal0(la))
    2586              :   {
    2587           28 :     p1 = gdiv(la2, Bk);
    2588           28 :     gel(B,k+1) = gel(B,k) = p1;
    2589           28 :     for (i=k+2; i<=lx; i++) gel(B,i) = gdiv(gmul(p1,gel(B,i)),Bk);
    2590           28 :     for (i=k+1; i<lx; i++)
    2591            0 :       gcoeff(L,i,k-1) = gdiv(gmul(la,gcoeff(L,i,k-1)), Bk);
    2592           28 :     for (j=k+1; j<lx-1; j++)
    2593            0 :       for (i=j+1; i<lx; i++)
    2594            0 :         gcoeff(L,i,j) = gdiv(gmul(p1,gcoeff(L,i,j)), Bk);
    2595              :   }
    2596              :   else
    2597              :   {
    2598           56 :     gcoeff(L,k,k-1) = gen_0;
    2599           56 :     for (i=k+1; i<lx; i++)
    2600              :     {
    2601            0 :       gcoeff(L,i,k) = gcoeff(L,i,k-1);
    2602            0 :       gcoeff(L,i,k-1) = gen_0;
    2603              :     }
    2604           56 :     gel(B,k) = gel(B,k-1); fl[k] = 1; fl[k-1] = 0;
    2605              :   }
    2606          112 :   return 1;
    2607              : }
    2608              : 
    2609              : static void
    2610          168 : incrementalGSgen(GEN x, GEN L, GEN B, long k, GEN fl)
    2611              : {
    2612          168 :   GEN u = NULL; /* gcc -Wall */
    2613              :   long i, j;
    2614          420 :   for (j = 1; j <= k; j++)
    2615          252 :     if (j==k || fl[j])
    2616              :     {
    2617          252 :       u = gcoeff(x,k,j);
    2618          252 :       if (!is_extscalar_t(typ(u))) pari_err_TYPE("incrementalGSgen",u);
    2619          336 :       for (i=1; i<j; i++)
    2620           84 :         if (fl[i])
    2621              :         {
    2622           84 :           u = gsub(gmul(gel(B,i+1),u), gmul(gcoeff(L,k,i),gcoeff(L,j,i)));
    2623           84 :           u = gdiv(u, gel(B,i));
    2624              :         }
    2625          252 :       gcoeff(L,k,j) = u;
    2626              :     }
    2627          168 :   if (gequal0(u)) gel(B,k+1) = gel(B,k);
    2628              :   else
    2629              :   {
    2630          112 :     gel(B,k+1) = gcoeff(L,k,k); gcoeff(L,k,k) = gen_1; fl[k] = 1;
    2631              :   }
    2632          168 : }
    2633              : 
    2634              : static GEN
    2635          168 : lllgramallgen(GEN x, long flag)
    2636              : {
    2637          168 :   long lx = lg(x), i, j, k, l, n;
    2638              :   pari_sp av;
    2639              :   GEN B, L, h, fl;
    2640              :   int flc;
    2641              : 
    2642          168 :   n = lx-1; if (n<=1) return lll_trivial(x,flag);
    2643           84 :   if (lgcols(x) != lx) pari_err_DIM("lllgramallgen");
    2644              : 
    2645           84 :   fl = cgetg(lx, t_VECSMALL);
    2646              : 
    2647           84 :   av = avma;
    2648           84 :   B = scalarcol_shallow(gen_1, lx);
    2649           84 :   L = cgetg(lx,t_MAT);
    2650          252 :   for (j=1; j<lx; j++) { gel(L,j) = zerocol(n); fl[j] = 0; }
    2651              : 
    2652           84 :   h = matid(n);
    2653          252 :   for (i=1; i<lx; i++)
    2654          168 :     incrementalGSgen(x, L, B, i, fl);
    2655           84 :   flc = 0;
    2656           84 :   for(k=2;;)
    2657              :   {
    2658          196 :     if (REDgen(k, k-1, h, L, gel(B,k))) flc = 1;
    2659          196 :     if (do_SWAPgen(h, L, B, k, fl, &flc)) { if (k > 2) k--; }
    2660              :     else
    2661              :     {
    2662           84 :       for (l=k-2; l>=1; l--)
    2663            0 :         if (REDgen(k, l, h, L, gel(B,l+1))) flc = 1;
    2664           84 :       if (++k > n) break;
    2665              :     }
    2666          112 :     if (gc_needed(av,1))
    2667              :     {
    2668            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"lllgramallgen");
    2669            0 :       (void)gc_all(av,3,&B,&L,&h);
    2670              :     }
    2671              :   }
    2672          140 :   k=1; while (k<lx && !fl[k]) k++;
    2673           84 :   return lll_finish(h,k-1,flag);
    2674              : }
    2675              : 
    2676              : static GEN
    2677          168 : lllallgen(GEN x, long flag)
    2678              : {
    2679          168 :   pari_sp av = avma;
    2680          168 :   if (!(flag & LLL_GRAM)) x = gram_matrix(x);
    2681           84 :   else if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2682          168 :   return gc_GEN(av, lllgramallgen(x, flag));
    2683              : }
    2684              : GEN
    2685           42 : lllgen(GEN x) { return lllallgen(x, LLL_IM); }
    2686              : GEN
    2687           42 : lllkerimgen(GEN x) { return lllallgen(x, LLL_ALL); }
    2688              : GEN
    2689           42 : lllgramgen(GEN x)  { return lllallgen(x, LLL_IM|LLL_GRAM); }
    2690              : GEN
    2691           42 : lllgramkerimgen(GEN x)  { return lllallgen(x, LLL_ALL|LLL_GRAM); }
    2692              : 
    2693              : static GEN
    2694        36701 : lllall(GEN x, long flag)
    2695        36701 : { pari_sp av = avma; return gc_GEN(av, ZM_lll(x, LLLDFT, flag)); }
    2696              : GEN
    2697          183 : lllint(GEN x) { return lllall(x, LLL_IM); }
    2698              : GEN
    2699           35 : lllkerim(GEN x) { return lllall(x, LLL_ALL); }
    2700              : GEN
    2701        36441 : lllgramint(GEN x)
    2702        36441 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2703        36441 :   return lllall(x, LLL_IM | LLL_GRAM); }
    2704              : GEN
    2705           35 : lllgramkerim(GEN x)
    2706           35 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2707           35 :   return lllall(x, LLL_ALL | LLL_GRAM); }
    2708              : 
    2709              : GEN
    2710      5375534 : lllfp(GEN x, double D, long flag)
    2711              : {
    2712      5375534 :   long n = lg(x)-1;
    2713      5375534 :   pari_sp av = avma;
    2714              :   GEN h;
    2715      5375534 :   if (n <= 1) return lll_trivial(x,flag);
    2716      4713839 :   if (flag & LLL_GRAM)
    2717              :   {
    2718         9274 :     if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2719         9260 :     if (isinexact(x))
    2720              :     {
    2721         9169 :       x = RgM_Cholesky(x, gprecision(x));
    2722         9169 :       if (!x) return NULL;
    2723         9169 :       flag &= ~LLL_GRAM;
    2724              :     }
    2725              :   }
    2726      4713825 :   h = ZM_lll(RgM_rescale_to_int(x), D, flag);
    2727      4713769 :   return gc_GEN(av, h);
    2728              : }
    2729              : 
    2730              : GEN
    2731         9093 : lllgram(GEN x) { return lllfp(x,LLLDFT,LLL_GRAM|LLL_IM); }
    2732              : GEN
    2733      1244995 : lll(GEN x) { return lllfp(x,LLLDFT,LLL_IM); }
    2734              : 
    2735              : static GEN
    2736           63 : qflllgram(GEN x)
    2737              : {
    2738           63 :   GEN T = lllgram(x);
    2739           42 :   if (!T) pari_err_PREC("qflllgram");
    2740           42 :   return T;
    2741              : }
    2742              : 
    2743              : GEN
    2744          301 : qflll0(GEN x, long flag)
    2745              : {
    2746          301 :   if (typ(x) != t_MAT) pari_err_TYPE("qflll",x);
    2747          301 :   switch(flag)
    2748              :   {
    2749           49 :     case 0: return lll(x);
    2750           63 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_NOFLATTER);
    2751           49 :     case 2: RgM_check_ZM(x,"qflll"); return lllintpartial(x);
    2752            7 :     case 3: RgM_check_ZM(x,"qflll"); return lllall(x, LLL_INPLACE);
    2753           49 :     case 4: RgM_check_ZM(x,"qflll"); return lllkerim(x);
    2754           42 :     case 5: return lllkerimgen(x);
    2755           42 :     case 8: return lllgen(x);
    2756            0 :     default: pari_err_FLAG("qflll");
    2757              :   }
    2758              :   return NULL; /* LCOV_EXCL_LINE */
    2759              : }
    2760              : 
    2761              : GEN
    2762          245 : qflllgram0(GEN x, long flag)
    2763              : {
    2764          245 :   if (typ(x) != t_MAT) pari_err_TYPE("qflllgram",x);
    2765          245 :   switch(flag)
    2766              :   {
    2767           63 :     case 0: return qflllgram(x);
    2768           49 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_GRAM | LLL_NOFLATTER);
    2769           49 :     case 4: RgM_check_ZM(x,"qflllgram"); return lllgramkerim(x);
    2770           42 :     case 5: return lllgramkerimgen(x);
    2771           42 :     case 8: return lllgramgen(x);
    2772            0 :     default: pari_err_FLAG("qflllgram");
    2773              :   }
    2774              :   return NULL; /* LCOV_EXCL_LINE */
    2775              : }
    2776              : 
    2777              : /********************************************************************/
    2778              : /**                                                                **/
    2779              : /**                   INTEGRAL KERNEL (LLL REDUCED)                **/
    2780              : /**                                                                **/
    2781              : /********************************************************************/
    2782              : static GEN
    2783           56 : kerint0(GEN M)
    2784              : {
    2785              :   /* return ZM_lll(M, LLLDFT, LLL_KER); */
    2786           56 :   GEN U, H = ZM_hnflll(M,&U,1);
    2787           56 :   long d = lg(M)-lg(H);
    2788           56 :   if (!d) return cgetg(1, t_MAT);
    2789           56 :   return ZM_lll(vecslice(U,1,d), LLLDFT, LLL_INPLACE);
    2790              : }
    2791              : GEN
    2792           28 : kerint(GEN M)
    2793              : {
    2794           28 :   pari_sp av = avma;
    2795           28 :   return gc_GEN(av, kerint0(M));
    2796              : }
    2797              : /* OBSOLETE: use kerint */
    2798              : GEN
    2799           28 : matkerint0(GEN M, long flag)
    2800              : {
    2801           28 :   pari_sp av = avma;
    2802           28 :   if (typ(M) != t_MAT) pari_err_TYPE("matkerint",M);
    2803           28 :   M = Q_primpart(M);
    2804           28 :   RgM_check_ZM(M, "kerint");
    2805           28 :   switch(flag)
    2806              :   {
    2807           28 :     case 0:
    2808           28 :     case 1: return gc_GEN(av, kerint0(M));
    2809            0 :     default: pari_err_FLAG("matkerint");
    2810              :   }
    2811              :   return NULL; /* LCOV_EXCL_LINE */
    2812              : }
        

Generated by: LCOV version 2.0-1