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) Hit Total Coverage
Test: PARI/GP v2.18.1 lcov report (development 29875-1c62f24b5e) Lines: 1335 1641 81.4 %
Date: 2025-01-17 09:09:20 Functions: 125 130 96.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2008  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : 
      18             : #define DEBUGLEVEL DEBUGLEVEL_qflll
      19             : 
      20             : static int
      21       45828 : RgM_is_square_mat(GEN x) { long l = lg(x); return l == 1 || l == lgcols(x); }
      22             : 
      23             : static long
      24     4178618 : ZM_is_upper(GEN R)
      25             : {
      26     4178618 :   long i,j, l = lg(R);
      27     4178618 :   if (l != lgcols(R)) return 0;
      28     8072560 :   for(i = 1; i < l; i++)
      29     8717309 :     for(j = 1; j < i; j++)
      30     4482514 :       if (signe(gcoeff(R,i,j))) return 0;
      31      252063 :   return 1;
      32             : }
      33             : 
      34             : static long
      35      606195 : ZM_is_knapsack(GEN R)
      36             : {
      37      606195 :   long i,j, l = lg(R);
      38      606195 :   if (l != lgcols(R)) return 0;
      39      843433 :   for(i = 2; i < l; i++)
      40     2901033 :     for(j = 1; j < l; j++)
      41     2663795 :       if ( i!=j && signe(gcoeff(R,i,j))) return 0;
      42       92365 :   return 1;
      43             : }
      44             : 
      45             : static long
      46     1182514 : ZM_is_lower(GEN R)
      47             : {
      48     1182514 :   long i,j, l = lg(R);
      49     1182514 :   if (l != lgcols(R)) return 0;
      50     2058900 :   for(i = 1; i < l; i++)
      51     2383977 :     for(j = 1; j < i; j++)
      52     1291916 :       if (signe(gcoeff(R,j,i))) return 0;
      53       34904 :   return 1;
      54             : }
      55             : 
      56             : static GEN
      57       34904 : RgM_flip(GEN R)
      58             : {
      59             :   GEN M;
      60             :   long i,j,l;
      61       34904 :   M = cgetg_copy(R, &l);
      62      181320 :   for(i = 1; i < l; i++)
      63             :   {
      64      146417 :     gel(M,i) = cgetg(l, t_COL);
      65      910392 :     for(j = 1; j < l; j++)
      66      763976 :       gmael(M,i,j) = gmael(R,l-i, l-j);
      67             :   }
      68       34903 :   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     4064374 : mpabscmp(GEN x, GEN y)
      89             : {
      90     4064374 :   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     1335813 : drop(GEN R)
     104             : {
     105     1335813 :   long i, n = lg(R)-1;
     106     1335813 :   long s = 0, m = mpexpo(gcoeff(R, 1, 1));
     107     5400187 :   for (i = 2; i <= n; ++i)
     108             :   {
     109     4064374 :     if (mpabscmp(gcoeff(R, i, i), gcoeff(R, i - 1, i - 1)) >= 0)
     110             :     {
     111     2753593 :       s += m - mpexpo(gcoeff(R, i - 1, i - 1));
     112     2753593 :       m = mpexpo(gcoeff(R, i, i));
     113             :     }
     114             :   }
     115     1335813 :   s += m - mpexpo(gcoeff(R, n, n));
     116     1335813 :   return s;
     117             : }
     118             : 
     119             : static long
     120     1335813 : potential(GEN R)
     121             : {
     122     1335813 :   long i, n = lg(R)-1;
     123     1335813 :   long s = 0, mul = n-1;;
     124     6736000 :   for (i = 1; i <= n; i++, mul-=2) s += mul * mpexpo(gcoeff(R,i,i));
     125     1335813 :   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     4689909 : condition_bound(GEN U, int lower)
     133             : {
     134     4689909 :   long n = lg(U)-1, e, i, j;
     135             :   GEN y;
     136     4689909 :   pari_sp av = avma;
     137     4689909 :   y = cgetg(n+1, t_VECSMALL);
     138     4689913 :   e = y[n] = -gexpo(gcoeff(U,n,n));
     139    18643244 :   for (i=n-1; i>0; i--)
     140             :   {
     141    13953328 :     long s = 0;
     142    49610297 :     for (j=i+1; j<=n; j++)
     143    35656973 :       s = maxss(s, (lower? gexpo(gcoeff(U,j,i)): gexpo(gcoeff(U,i,j))) + y[j]);
     144    13953324 :     y[i] = s - gexpo(gcoeff(U,i,i));
     145    13953327 :     e = maxss(e, y[i]);
     146             :   }
     147     4689916 :   return gc_long(av, gexpo(U) + e);
     148             : }
     149             : 
     150             : static long
     151     5149934 : gsisinv(GEN M)
     152             : {
     153     5149934 :   long i, l = lg(M);
     154    25909352 :   for (i = 1; i < l; ++i)
     155    20759826 :     if (! signe(gmael(M, i, i))) return 0;
     156     5149526 :   return 1;
     157             : }
     158             : 
     159             : INLINE long
     160     7415592 : nbits2prec64(long n)
     161             : {
     162     7415592 :   return nbits2prec(((n+63)>>6)<<6);
     163             : }
     164             : 
     165             : static long
     166     5806757 : spread(GEN R)
     167             : {
     168     5806757 :   long i, n = lg(R)-1, m = mpexpo(gcoeff(R, 1, 1)), M = m;
     169    23366045 :   for (i = 2; i <= n; ++i)
     170             :   {
     171    17559280 :     long e = mpexpo(gcoeff(R, i, i));
     172    17559285 :     if (e < m) m = e;
     173    17559285 :     if (e > M) M = e;
     174             :   }
     175     5806765 :   return M - m;
     176             : }
     177             : 
     178             : static long
     179     4689908 : GS_extraprec(GEN L, int lower)
     180             : {
     181     4689908 :   long C = condition_bound(L, lower), S = spread(L), n = lg(L)-1;
     182     4689915 :   return maxss(2*S+2*n, C-S-2*n); /* = 2*S + 2*n + maxss(0, C-3*S-4*n) */
     183             : }
     184             : 
     185             : static GEN
     186        2967 : RgM_Cholesky_dynprec(GEN M)
     187             : {
     188        2967 :   pari_sp ltop = avma;
     189             :   GEN L;
     190        2967 :   long minprec = lg(M) + 30, bitprec = minprec, prec;
     191             :   while (1)
     192        4877 :   {
     193             :     long mbitprec;
     194        7844 :     prec = nbits2prec64(bitprec);
     195        7844 :     L = RgM_Cholesky(RgM_gtofp(M, prec), prec); /* upper-triangular */
     196        7844 :     if (!L)
     197             :     {
     198        1458 :       bitprec *= 2;
     199        1458 :       set_avma(ltop);
     200        1458 :       continue;
     201             :     }
     202        6386 :     mbitprec = minprec + GS_extraprec(L, 0);
     203        6386 :     if (bitprec >= mbitprec)
     204        2967 :       break;
     205        3419 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     206        3419 :     set_avma(ltop);
     207             :   }
     208        2967 :   return gerepilecopy(ltop, L);
     209             : }
     210             : 
     211             : static GEN
     212        1336 : gramschmidt_upper(GEN M)
     213             : {
     214        1336 :   long bitprec = lg(M)-1 + 31 + GS_extraprec(M, 0);
     215        1336 :   return RgM_gtofp(M, nbits2prec64(bitprec));
     216             : }
     217             : 
     218             : static GEN
     219     2671627 : gramschmidt_dynprec(GEN M)
     220             : {
     221     2671627 :   pari_sp ltop = avma;
     222     2671627 :   long minprec = lg(M) + 30, bitprec = minprec;
     223     2671627 :   if (ZM_is_upper(M)) return gramschmidt_upper(M);
     224             :   while (1)
     225     3609208 :   {
     226             :     GEN B, Q, L;
     227     6279499 :     long prec = nbits2prec64(bitprec), mbitprec;
     228     6279497 :     if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec) || !gsisinv(L))
     229             :     {
     230     1597297 :       bitprec *= 2;
     231     1597297 :       set_avma(ltop);
     232     1597304 :       continue;
     233             :     }
     234     4682185 :     mbitprec = minprec + GS_extraprec(L, 1);
     235     4682193 :     if (bitprec >= mbitprec)
     236     2670289 :       return gerepilecopy(ltop, shallowtrans(L));
     237     2011904 :     bitprec = maxss((4*bitprec)/3, mbitprec);
     238     2011904 :     set_avma(ltop);
     239             :   }
     240             : }
     241             : /* return -T1 * round(T1^-1*(R1^-1*R2)*T3) */
     242             : static GEN
     243     1335814 : sizered(GEN T1, GEN T3, GEN R1, GEN R2)
     244             : {
     245     1335814 :   pari_sp ltop = avma;
     246             :   long e;
     247     1335814 :   return gerepileupto(ltop, ZM_mul(ZM_neg(T1), grndtoi(gmul(ZM_inv(T1,NULL),
     248             :          RgM_mul(RgM_mul(RgM_inv_upper(R1), R2), T3)), &e)));
     249             : }
     250             : 
     251             : static GEN
     252     1335813 : flat(GEN M, long flag, GEN *pt_T, long *pt_s, long *pt_pot)
     253             : {
     254     1335813 :   pari_sp ltop = avma;
     255             :   GEN R, R1, R2, R3, T1, T2, T3, T, S;
     256     1335813 :   long k = lg(M)-1, n = k>>1, n2 = k - n, m = n>>1;
     257     1335813 :   long keepfirst = flag & LLL_KEEP_FIRST, inplace = flag & LLL_INPLACE;
     258             :   /* for k = 3, we want n = 1; n2  = 2; m = 0 */
     259             :   /* for k = 5,         n = 2; n2 = 3; m = 1 */
     260     1335813 :   R = gramschmidt_dynprec(M);
     261     1335814 :   R1 = matslice(R, 1, n, 1, n);
     262     1335813 :   R2 = matslice(R, 1, n, n + 1, k);
     263     1335814 :   R3 = matslice(R, n + 1, k, n + 1, k);
     264     1335813 :   T1 = lllfp(R1, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY| (keepfirst ? LLL_KEEP_FIRST: 0));
     265     1335814 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     266     1335814 :   T2 = sizered(T1, T3, R1, R2);
     267     1335814 :   T = shallowmatconcat(mkmat22(T1,T2,gen_0,T3));
     268     1335814 :   M = ZM_mul(M, T);
     269     1335814 :   R = gramschmidt_dynprec(M);
     270     1335814 :   R3 = matslice(R, m + 1, m + n2, m + 1, m + n2);
     271     1335814 :   T3 = lllfp(R3, 0.99, LLL_IM| LLL_UPPER| LLL_NOCERTIFY);
     272     2671628 :   S = shallowmatconcat(diagonal(
     273      576071 :        m == 0     ? mkvec2(T3, matid(k - m - n2))
     274           0 :      : m+n2 == k  ? mkvec2(matid(m), T3)
     275      759743 :                   : mkvec3(matid(m), T3, matid(k - m - n2))));
     276     1335814 :   M = ZM_mul(M, S);
     277     1335813 :   if (!inplace) *pt_T = ZM_mul(T, S);
     278     1335813 :   *pt_s = drop(R);
     279     1335813 :   *pt_pot = potential(R);
     280     1335813 :   return gc_all(ltop, inplace ? 1: 2, &M, pt_T);
     281             : }
     282             : 
     283             : static void
     284           0 : dbg_flatter(pari_timer *ti, long n, long i, long lti, double t, double pot2)
     285             : {
     286           0 :   double s = t / n, p = pot2 / (n*(n+1));
     287             :   const char *str;
     288           0 :   if (i == -1)
     289           0 :     str = (i == lti)? "final"
     290           0 :                     : stack_sprintf("steps %ld-final", lti);
     291             :   else
     292           0 :     str = (i == lti)? stack_sprintf("step %ld", i)
     293           0 :                     : stack_sprintf("steps %ld-%ld", lti, i);
     294           0 :   timer_printf(ti, "FLATTER, dim %ld, %s: \t slope=%0.10g \t pot=%0.10g",
     295             :                n, str, s, p);
     296           0 : }
     297             : 
     298             : static GEN
     299      618391 : ZM_flatter(GEN M, long flag)
     300             : {
     301      618391 :   pari_sp av = avma;
     302      618391 :   long i, n = lg(M)-1, s = -1, lti = 1, pot = LONG_MAX;
     303      618391 :   GEN T = NULL;
     304             :   pari_timer ti;
     305      618391 :   long inplace = flag & LLL_INPLACE, cert = !(flag & LLL_NOCERTIFY);
     306             : 
     307      618391 :   if (DEBUGLEVEL>=3)
     308             :   {
     309           0 :     timer_start(&ti);
     310           0 :     if (cert) err_printf("FLATTER dim = %ld size = %ld\n", n, ZM_max_expi(M));
     311             :   }
     312      618391 :   for (i = 1;;i++)
     313      717422 :   {
     314             :     long t, pot2;
     315     1335813 :     GEN U, M2 = flat(M, flag, &U, &t, &pot2);
     316     1335814 :     if (t == 0) { s = t; break; }
     317      760710 :     if (s >= 0)
     318             :     {
     319      435620 :       if (s == t && pot>=pot2) break;
     320      392332 :       if (s < t && i > 20)
     321             :       {
     322           0 :         if (DEBUGLEVEL >= 3) err_printf("BACK:%ld:%ld:%g\n", n, i, s);
     323           0 :         break;
     324             :       }
     325             :     }
     326      717422 :     if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     327           0 :       dbg_flatter(&ti, n, i, lti, t, pot2);
     328      717422 :     s = t;
     329      717422 :     pot = pot2;
     330      717422 :     M = M2;
     331      717422 :     if (!inplace)
     332             :     {
     333      689790 :       T = T? ZM_mul(T, U): U;
     334      689790 :       if (gc_needed(av, 1)) gerepileall(av, 2, &M, &T);
     335             :     }
     336             :     else
     337       27632 :       if (gc_needed(av, 1)) M = gerepilecopy(av, M);
     338             :   }
     339      618392 :   if (DEBUGLEVEL>=3 && (cert || timer_get(&ti) > 1000))
     340           0 :     dbg_flatter(&ti, n, -1, i == lti? -1: lti, s, pot);
     341      618392 :   if (!inplace)
     342             :   {
     343      604384 :     if (!T) return gc_NULL(av);
     344      311250 :     return gerepilecopy(av, T);
     345             :   }
     346       14008 :   return  gerepilecopy(av, M);
     347             : }
     348             : 
     349             : static GEN
     350      616377 : ZM_flatter_rank(GEN M, long rank, long flag)
     351             : {
     352             :   pari_timer ti;
     353      616377 :   pari_sp av = avma;
     354      616377 :   GEN T = NULL;
     355      616377 :   long i, n = lg(M)-1, sm = LONG_MAX;
     356      616377 :   long inplace = flag & LLL_INPLACE;
     357             : 
     358      616377 :   if (rank == n) return ZM_flatter(M, flag);
     359        3785 :   if (DEBUGLEVEL>=3) timer_start(&ti);
     360        3785 :   for (i = 1;; i++)
     361        2014 :   {
     362        5799 :     GEN S = ZM_flatter(vconcat(gshift(M,i),matid(n)), flag);
     363             :     long s;
     364        5799 :     if (!S || (s = expi(gnorml2(S))) >= sm) break;
     365        2014 :     sm = s;
     366        2014 :     if (DEBUGLEVEL>=3) timer_printf(&ti,"FLATTERRANK step %ld: %ld",i,sm);
     367        2014 :     T = T? ZM_mul(T, S): S;
     368        2014 :     M = ZM_mul(M, S);
     369        2014 :     if (gc_needed(av, 1)) gerepileall(av, 2, &M, &T);
     370             :   }
     371        3785 :   if (!inplace)
     372             :   {
     373        3778 :     if (!T) { set_avma(av); return matid(n); }
     374        1951 :     return gerepilecopy(av, T);
     375             :   }
     376           7 :   return  gerepilecopy(av, M);
     377             : }
     378             : 
     379             : static GEN
     380        2967 : flattergram_i(GEN M, long flag)
     381             : {
     382        2967 :   pari_sp av = avma;
     383        2967 :   GEN T, R = RgM_Cholesky_dynprec(M);
     384        2967 :   T = lllfp(R, 0.99, LLL_IM|LLL_UPPER|LLL_NOCERTIFY | (flag&LLL_KEEP_FIRST));
     385        2967 :   return gerepileupto(av, T);
     386             : }
     387             : 
     388             : static void
     389           0 : dbg_flattergram(pari_timer *t, long n, long i, long s)
     390           0 : { timer_printf(t, "FLATTERGRAM, dim %ld step %ld, slope=%0.10g", n, i,
     391           0 :                ((double)s)/n); }
     392             : /* return base change, NULL if identity */
     393             : static GEN
     394         961 : ZM_flattergram(GEN M, long flag)
     395             : {
     396         961 :   pari_sp av = avma;
     397         961 :   GEN T = NULL;
     398         961 :   long i, n = lg(M)-1, s = -1;
     399             : 
     400             :   pari_timer ti;
     401         961 :   if (DEBUGLEVEL>=3)
     402             :   {
     403           0 :     timer_start(&ti);
     404           0 :     err_printf("FLATTERGRAM dim = %ld size = %ld\n", n, ZM_max_expi(M));
     405             :   }
     406         961 :   for (i = 1;; i++)
     407        2006 :   {
     408        2967 :     GEN S = flattergram_i(M, flag);
     409        2967 :     long t = expi(gnorml2(S));
     410        2967 :     if (t == 0) { s = t;  break; }
     411        2967 :     if (s)
     412             :     {
     413        2967 :       double st = s - t;
     414        2967 :       if (st == 0) break;
     415        2006 :       if (st < 0 && i > 20)
     416             :       {
     417           0 :         if (DEBUGLEVEL >= 3)
     418           0 :           err_printf("BACK:%ld:%ld:%0.10g\n", n, i, ((double)s)/n);
     419           0 :         break;
     420             :       }
     421             :     }
     422        2006 :     T = T? ZM_mul(T, S): S;
     423        2006 :     M = qf_ZM_apply(M, S);
     424        2006 :     s = t;
     425        2006 :     if (DEBUGLEVEL >= 3) dbg_flattergram(&ti, n, i, s);
     426        2006 :     if (gc_needed(av, 1)) gerepileall(av, 2, &M, &T);
     427             :   }
     428         961 :   if (DEBUGLEVEL >= 3) dbg_flattergram(&ti, n, i, s);
     429         961 :   if (!T && ZM_isidentity(T)) return gc_NULL(av);
     430         961 :   return gerepilecopy(av, T);
     431             : }
     432             : 
     433             : /* return base change, NULL if identity */
     434             : static GEN
     435         961 : ZM_flattergram_rank(GEN M, long rank, long flag)
     436             : {
     437             :   pari_timer ti;
     438         961 :   pari_sp av = avma;
     439         961 :   GEN T = NULL;
     440         961 :   long i, n = lg(M)-1;
     441         961 :   if (rank == n) return ZM_flattergram(M, flag);
     442           0 :   if (DEBUGLEVEL>=3) timer_start(&ti);
     443           0 :   for (i = 1;; i++)
     444           0 :   {
     445           0 :     GEN S = ZM_flattergram(RgM_Rg_add(gshift(M, i), gen_1), flag);
     446           0 :     if (DEBUGLEVEL>=3)
     447           0 :       timer_printf(&ti,"FLATTERGRAMRANK step %ld: %ld",i,expi(gnorml2(S)));
     448           0 :     if (!S) break;
     449           0 :     T = T? ZM_mul(T, S): S;
     450           0 :     M = qf_ZM_apply(M, S);
     451           0 :     if (gc_needed(av, 1)) gerepileall(av, 2, &M, &T);
     452             :   }
     453           0 :   if (!T || ZM_isidentity(T)) return gc_NULL(av);
     454           0 :   return gerepilecopy(av, T);
     455             : }
     456             : 
     457             : /* round to closest integer (as a double). If |a| >= 2^52, return it */
     458             : static double
     459    10721246 : pari_rint(double a)
     460             : {
     461             : #ifdef HAS_RINT
     462    10721246 :   return rint(a);
     463             : #else
     464             :   const double pow2 = 4.5035996273704960e+15; /* 2^52 */
     465             :   double r, fa = fabs(a);
     466             :   if (fa >= pow2) return a;
     467             :   r = (pow2 + fa) - pow2;
     468             :   if (a < 0) r = -r;
     469             :   return r;
     470             : #endif
     471             : }
     472             : 
     473             : /* default quality ratio for LLL */
     474             : static const double LLLDFT = 0.99;
     475             : 
     476             : /* assume flag & (LLL_KER|LLL_IM|LLL_ALL). LLL_INPLACE implies LLL_IM */
     477             : static GEN
     478      769920 : lll_trivial(GEN x, long flag)
     479             : {
     480      769920 :   if (lg(x) == 1)
     481             :   { /* dim x = 0 */
     482       15498 :     if (! (flag & LLL_ALL)) return cgetg(1,t_MAT);
     483          28 :     retmkvec2(cgetg(1,t_MAT), cgetg(1,t_MAT));
     484             :   }
     485             :   /* dim x = 1 */
     486      754422 :   if (gequal0(gel(x,1)))
     487             :   {
     488         144 :     if (flag & LLL_KER) return matid(1);
     489         144 :     if (flag & (LLL_IM|LLL_INPLACE)) return cgetg(1,t_MAT);
     490          28 :     retmkvec2(matid(1), cgetg(1,t_MAT));
     491             :   }
     492      754274 :   if (flag & LLL_INPLACE) return gcopy(x);
     493      650889 :   if (flag & LLL_KER) return cgetg(1,t_MAT);
     494      650889 :   if (flag & LLL_IM)  return matid(1);
     495          28 :   retmkvec2(cgetg(1,t_MAT), (flag & LLL_GRAM)? gcopy(x): matid(1));
     496             : }
     497             : 
     498             : /* vecslice(x,#x-k,#x) in place. Works for t_MAT, t_VEC/t_COL */
     499             : static GEN
     500     2055117 : vectail_inplace(GEN x, long k)
     501             : {
     502     2055117 :   if (!k) return x;
     503       57765 :   x[k] = ((ulong)x[0] & ~LGBITS) | _evallg(lg(x) - k);
     504       57765 :   return x + k;
     505             : }
     506             : 
     507             : /* k = dim Kernel */
     508             : static GEN
     509     2129107 : lll_finish(GEN h, long k, long flag)
     510             : {
     511             :   GEN g;
     512     2129107 :   if (!(flag & (LLL_IM|LLL_KER|LLL_ALL|LLL_INPLACE))) return h;
     513     2055145 :   if (flag & (LLL_IM|LLL_INPLACE)) return vectail_inplace(h, k);
     514          98 :   if (flag & LLL_KER) { setlg(h,k+1); return h; }
     515          70 :   g = vecslice(h,1,k); /* done first: vectail_inplace kills h */
     516          70 :   return mkvec2(g, vectail_inplace(h, k));
     517             : }
     518             : 
     519             : /* y * z * 2^e, e >= 0; y,z t_INT */
     520             : INLINE GEN
     521      318717 : mulshift(GEN y, GEN z, long e)
     522             : {
     523      318717 :   long ly = lgefint(y), lz;
     524             :   pari_sp av;
     525             :   GEN t;
     526      318717 :   if (ly == 2) return gen_0;
     527       46676 :   lz = lgefint(z);
     528       46676 :   av = avma; (void)new_chunk(ly+lz+nbits2lg(e)); /* HACK */
     529       46676 :   t = mulii(z, y);
     530       46676 :   set_avma(av); return shifti(t, e);
     531             : }
     532             : 
     533             : /* x - y * z * 2^e, e >= 0; x,y,z t_INT */
     534             : INLINE GEN
     535     1508434 : submulshift(GEN x, GEN y, GEN z, long e)
     536             : {
     537     1508434 :   long lx = lgefint(x), ly, lz;
     538             :   pari_sp av;
     539             :   GEN t;
     540     1508434 :   if (!e) return submulii(x, y, z);
     541     1498805 :   if (lx == 2) { t = mulshift(y, z, e); togglesign(t); return t; }
     542     1199090 :   ly = lgefint(y);
     543     1199090 :   if (ly == 2) return icopy(x);
     544      960953 :   lz = lgefint(z);
     545      960953 :   av = avma; (void)new_chunk(lx+ly+lz+nbits2lg(e)); /* HACK */
     546      960953 :   t = shifti(mulii(z, y), e);
     547      960953 :   set_avma(av); return subii(x, t);
     548             : }
     549             : static void
     550    18516049 : subzi(GEN *a, GEN b)
     551             : {
     552    18516049 :   pari_sp av = avma;
     553    18516049 :   b = subii(*a, b);
     554    18516066 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     555     2104159 :   else *a = b;
     556    18516101 : }
     557             : 
     558             : static void
     559    17772480 : addzi(GEN *a, GEN b)
     560             : {
     561    17772480 :   pari_sp av = avma;
     562    17772480 :   b = addii(*a, b);
     563    17772466 :   if (lgefint(b)<=lg(*a) && isonstack(*a)) { affii(b,*a); set_avma(av); }
     564     1876516 :   else *a = b;
     565    17772512 : }
     566             : 
     567             : /* x - u*y * 2^e */
     568             : INLINE GEN
     569     4164796 : submuliu2n(GEN x, GEN y, ulong u, long e)
     570             : {
     571             :   pari_sp av;
     572     4164796 :   long ly = lgefint(y);
     573     4164796 :   if (ly == 2) return x;
     574     2854878 :   av = avma;
     575     2854878 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     576     2856662 :   y = shifti(mului(u,y), e);
     577     2855561 :   set_avma(av); return subii(x, y);
     578             : }
     579             : /* *x -= u*y * 2^e */
     580             : INLINE void
     581      262957 : submulzu2n(GEN *x, GEN y, ulong u, long e)
     582             : {
     583             :   pari_sp av;
     584      262957 :   long ly = lgefint(y);
     585      262957 :   if (ly == 2) return;
     586      172642 :   av = avma;
     587      172642 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     588      172642 :   y = shifti(mului(u,y), e);
     589      172642 :   set_avma(av); return subzi(x, y);
     590             : }
     591             : 
     592             : /* x + u*y * 2^e */
     593             : INLINE GEN
     594     4073511 : addmuliu2n(GEN x, GEN y, ulong u, long e)
     595             : {
     596             :   pari_sp av;
     597     4073511 :   long ly = lgefint(y);
     598     4073511 :   if (ly == 2) return x;
     599     2795564 :   av = avma;
     600     2795564 :   (void)new_chunk(3+ly+lgefint(x)+nbits2lg(e)); /* HACK */
     601     2797272 :   y = shifti(mului(u,y), e);
     602     2796203 :   set_avma(av); return addii(x, y);
     603             : }
     604             : 
     605             : /* *x += u*y * 2^e */
     606             : INLINE void
     607      270968 : addmulzu2n(GEN *x, GEN y, ulong u, long e)
     608             : {
     609             :   pari_sp av;
     610      270968 :   long ly = lgefint(y);
     611      270968 :   if (ly == 2) return;
     612      178036 :   av = avma;
     613      178036 :   (void)new_chunk(3+ly+lgefint(*x)+nbits2lg(e)); /* HACK */
     614      178036 :   y = shifti(mului(u,y), e);
     615      178036 :   set_avma(av); return addzi(x, y);
     616             : }
     617             : 
     618             : /* n < 10; gerepileall supporting &NULL arguments. Maybe rename and export ? */
     619             : INLINE void
     620        4726 : gc_lll(pari_sp av, int n, ...)
     621             : {
     622             :   int i, j;
     623             :   GEN *gptr[10];
     624             :   size_t s;
     625        4726 :   va_list a; va_start(a, n);
     626       14178 :   for (i=j=0; i<n; i++)
     627             :   {
     628        9452 :     GEN *x = va_arg(a,GEN*);
     629        9452 :     if (*x) { gptr[j++] = x; *x = (GEN)copy_bin(*x); }
     630             :   }
     631        4726 :   va_end(a); set_avma(av);
     632       11776 :   for (--j; j>=0; j--) *gptr[j] = bin_copy((GENbin*)*gptr[j]);
     633        4726 :   s = pari_mainstack->top - pari_mainstack->bot;
     634             :   /* size of saved objects ~ stacksize / 4 => overflow */
     635        4726 :   if (av - avma > (s >> 2))
     636             :   {
     637           0 :     size_t t = avma - pari_mainstack->bot;
     638           0 :     av = avma; new_chunk((s + t) / sizeof(long)); set_avma(av); /* double */
     639             :   }
     640        4726 : }
     641             : 
     642             : /********************************************************************/
     643             : /**                                                                **/
     644             : /**                   FPLLL (adapted from D. Stehle's code)        **/
     645             : /**                                                                **/
     646             : /********************************************************************/
     647             : /* Babai* and fplll* are a conversion to libpari API and data types
     648             :    of fplll-1.3 by Damien Stehle'.
     649             : 
     650             :   Copyright 2005, 2006 Damien Stehle'.
     651             : 
     652             :   This program is free software; you can redistribute it and/or modify it
     653             :   under the terms of the GNU General Public License as published by the
     654             :   Free Software Foundation; either version 2 of the License, or (at your
     655             :   option) any later version.
     656             : 
     657             :   This program implements ideas from the paper "Floating-point LLL Revisited",
     658             :   by Phong Nguyen and Damien Stehle', in the Proceedings of Eurocrypt'2005,
     659             :   Springer-Verlag; and was partly inspired by Shoup's NTL library:
     660             :   http://www.shoup.net/ntl/ */
     661             : 
     662             : /* x t_REAL, |x| >= 1/2. Test whether |x| <= 3/2 */
     663             : static int
     664      396441 : absrsmall2(GEN x)
     665             : {
     666      396441 :   long e = expo(x), l, i;
     667      396441 :   if (e < 0) return 1;
     668      199227 :   if (e > 0 || (ulong)x[2] > (3UL << (BITS_IN_LONG-2))) return 0;
     669             :   /* line above assumes l > 2. OK since x != 0 */
     670       73816 :   l = lg(x); for (i = 3; i < l; i++) if (x[i]) return 0;
     671       63266 :   return 1;
     672             : }
     673             : /* x t_REAL; test whether |x| <= 1/2 */
     674             : static int
     675      689755 : absrsmall(GEN x)
     676             : {
     677             :   long e, l, i;
     678      689755 :   if (!signe(x)) return 1;
     679      685589 :   e = expo(x); if (e < -1) return 1;
     680      401851 :   if (e > -1 || (ulong)x[2] > HIGHBIT) return 0;
     681        6119 :   l = lg(x); for (i = 3; i < l; i++) if (x[i]) return 0;
     682        5410 :   return 1;
     683             : }
     684             : 
     685             : static void
     686    31734577 : rotate(GEN A, long k2, long k)
     687             : {
     688             :   long i;
     689    31734577 :   GEN B = gel(A,k2);
     690   101403390 :   for (i = k2; i > k; i--) gel(A,i) = gel(A,i-1);
     691    31734577 :   gel(A,k) = B;
     692    31734577 : }
     693             : 
     694             : /************************* FAST version (double) ************************/
     695             : #define dmael(x,i,j) ((x)[i][j])
     696             : #define del(x,i) ((x)[i])
     697             : 
     698             : static double *
     699    34484113 : cget_dblvec(long d)
     700    34484113 : { return (double*) stack_malloc_align(d*sizeof(double), sizeof(double)); }
     701             : 
     702             : static double **
     703     8275010 : cget_dblmat(long d) { return (double **) cgetg(d, t_VECSMALL); }
     704             : 
     705             : static double
     706   161645288 : itodbl_exp(GEN x, long *e)
     707             : {
     708   161645288 :   pari_sp av = avma;
     709   161645288 :   GEN r = itor(x,DEFAULTPREC);
     710   161630489 :   *e = expo(r); setexpo(r,0);
     711   161627062 :   return gc_double(av, rtodbl(r));
     712             : }
     713             : 
     714             : static double
     715   117604382 : dbldotproduct(double *x, double *y, long n)
     716             : {
     717             :   long i;
     718   117604382 :   double sum = del(x,1) * del(y,1);
     719  1381251540 :   for (i=2; i<=n; i++) sum += del(x,i) * del(y,i);
     720   117604382 :   return sum;
     721             : }
     722             : 
     723             : static double
     724     2440441 : dbldotsquare(double *x, long n)
     725             : {
     726             :   long i;
     727     2440441 :   double sum = del(x,1) * del(x,1);
     728     8094142 :   for (i=2; i<=n; i++) sum += del(x,i) * del(x,i);
     729     2440441 :   return sum;
     730             : }
     731             : 
     732             : static long
     733    24698411 : set_line(double *appv, GEN v, long n)
     734             : {
     735    24698411 :   long i, maxexp = 0;
     736    24698411 :   pari_sp av = avma;
     737    24698411 :   GEN e = cgetg(n+1, t_VECSMALL);
     738   186325842 :   for (i = 1; i <= n; i++)
     739             :   {
     740   161640219 :     del(appv,i) = itodbl_exp(gel(v,i), e+i);
     741   161625907 :     if (e[i] > maxexp) maxexp = e[i];
     742             :   }
     743   186412673 :   for (i = 1; i <= n; i++) del(appv,i) = ldexp(del(appv,i), e[i]-maxexp);
     744    24685623 :   set_avma(av); return maxexp;
     745             : }
     746             : 
     747             : static void
     748    34421164 : dblrotate(double **A, long k2, long k)
     749             : {
     750             :   long i;
     751    34421164 :   double *B = del(A,k2);
     752   109034486 :   for (i = k2; i > k; i--) del(A,i) = del(A,i-1);
     753    34421164 :   del(A,k) = B;
     754    34421164 : }
     755             : /* update G[kappa][i] from appB */
     756             : static void
     757    22462817 : setG_fast(double **appB, long n, double **G, long kappa, long a, long b)
     758             : { long i;
     759   101267585 :   for (i = a; i <= b; i++)
     760    78804998 :     dmael(G,kappa,i) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     761    22462587 : }
     762             : /* update G[i][kappa] from appB */
     763             : static void
     764    16907404 : setG2_fast(double **appB, long n, double **G, long kappa, long a, long b)
     765             : { long i;
     766    55710321 :   for (i = a; i <= b; i++)
     767    38802925 :     dmael(G,i,kappa) = dbldotproduct(del(appB,kappa), del(appB,i), n);
     768    16907396 : }
     769             : const long EX0 = -2; /* uninitialized; any value less than expo(0.51) = -1 */
     770             : 
     771             : #ifdef LONG_IS_64BIT
     772             : typedef long s64;
     773             : #define addmuliu64_inplace addmuliu_inplace
     774             : #define submuliu64_inplace submuliu_inplace
     775             : #define submuliu642n submuliu2n
     776             : #define addmuliu642n addmuliu2n
     777             : #else
     778             : typedef long long s64;
     779             : typedef unsigned long long u64;
     780             : 
     781             : INLINE GEN
     782    19651882 : u64toi(u64 x)
     783             : {
     784             :   GEN y;
     785             :   ulong h;
     786    19651882 :   if (!x) return gen_0;
     787    19651882 :   h = x>>32;
     788    19651882 :   if (!h) return utoipos(x);
     789     1141961 :   y = cgetipos(4);
     790     1141961 :   *int_LSW(y) = x&0xFFFFFFFF;
     791     1141961 :   *int_MSW(y) = x>>32;
     792     1141961 :   return y;
     793             : }
     794             : 
     795             : INLINE GEN
     796      672343 : u64toineg(u64 x)
     797             : {
     798             :   GEN y;
     799             :   ulong h;
     800      672343 :   if (!x) return gen_0;
     801      672343 :   h = x>>32;
     802      672343 :   if (!h) return utoineg(x);
     803      672343 :   y = cgetineg(4);
     804      672343 :   *int_LSW(y) = x&0xFFFFFFFF;
     805      672343 :   *int_MSW(y) = x>>32;
     806      672343 :   return y;
     807             : }
     808             : INLINE GEN
     809     9454199 : addmuliu64_inplace(GEN x, GEN y, u64 u) { return addmulii(x, y, u64toi(u)); }
     810             : 
     811             : INLINE GEN
     812     9509362 : submuliu64_inplace(GEN x, GEN y, u64 u) { return submulii(x, y, u64toi(u)); }
     813             : 
     814             : INLINE GEN
     815      672343 : addmuliu642n(GEN x, GEN y, u64 u, long e) { return submulshift(x, y, u64toineg(u), e); }
     816             : 
     817             : INLINE GEN
     818      688321 : submuliu642n(GEN x, GEN y, u64 u, long e) { return submulshift(x, y, u64toi(u), e); }
     819             : 
     820             : #endif
     821             : 
     822             : /* Babai's Nearest Plane algorithm (iterative); see Babai() */
     823             : static int
     824    30011902 : Babai_fast(pari_sp av, long kappa, GEN *pB, GEN *pU, double **mu, double **r,
     825             :            double *s, double **appB, GEN expoB, double **G,
     826             :            long a, long zeros, long maxG, double eta)
     827             : {
     828    30011902 :   GEN B = *pB, U = *pU;
     829    30011902 :   const long n = nbrows(B), d = U ? lg(U)-1: 0;
     830    30011720 :   long k, aa = (a > zeros)? a : zeros+1;
     831    30011720 :   long emaxmu = EX0, emax2mu = EX0;
     832             :   s64 xx;
     833    30011720 :   int did_something = 0;
     834             :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
     835             : 
     836    17114384 :   for (;;) {
     837    47126104 :     int go_on = 0;
     838    47126104 :     long i, j, emax3mu = emax2mu;
     839             : 
     840    47126104 :     if (gc_needed(av,2))
     841             :     {
     842         197 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
     843         197 :       gc_lll(av,2,&B,&U);
     844             :     }
     845             :     /* Step2: compute the GSO for stage kappa */
     846    47125212 :     emax2mu = emaxmu; emaxmu = EX0;
     847   180606485 :     for (j=aa; j<kappa; j++)
     848             :     {
     849   133482002 :       double g = dmael(G,kappa,j);
     850   573285449 :       for (k = zeros+1; k < j; k++) g -= dmael(mu,j,k) * dmael(r,kappa,k);
     851   133482002 :       dmael(r,kappa,j) = g;
     852   133482002 :       dmael(mu,kappa,j) = dmael(r,kappa,j) / dmael(r,j,j);
     853   133482002 :       emaxmu = maxss(emaxmu, expoB[kappa]-expoB[j]);
     854             :     }
     855             :     /* maxmu doesn't decrease fast enough */
     856    47124483 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) {*pB = B; *pU = U; return 1;}
     857             : 
     858   167670520 :     for (j=kappa-1; j>zeros; j--)
     859             :     {
     860   137664690 :       double tmp = fabs(ldexp (dmael(mu,kappa,j), expoB[kappa]-expoB[j]));
     861   137664690 :       if (tmp>eta) { go_on = 1; break; }
     862             :     }
     863             : 
     864             :     /* Step3--5: compute the X_j's  */
     865    47120346 :     if (go_on)
     866    77699245 :       for (j=kappa-1; j>zeros; j--)
     867             :       { /* The code below seemingly handles U = NULL, but in this case d = 0 */
     868    60585400 :         int e = expoB[j] - expoB[kappa];
     869    60585400 :         double tmp = ldexp(dmael(mu,kappa,j), -e), atmp = fabs(tmp);
     870             :         /* tmp = Inf is allowed */
     871    60585400 :         if (atmp <= .5) continue; /* size-reduced */
     872    33962506 :         if (gc_needed(av,2))
     873             :         {
     874         346 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
     875         346 :           gc_lll(av,2,&B,&U);
     876             :         }
     877    33964969 :         did_something = 1;
     878             :         /* we consider separately the case |X| = 1 */
     879    33964969 :         if (atmp <= 1.5)
     880             :         {
     881    22873176 :           if (dmael(mu,kappa,j) > 0) { /* in this case, X = 1 */
     882    46830496 :             for (k=zeros+1; k<j; k++)
     883    35156447 :               dmael(mu,kappa,k) -= ldexp(dmael(mu,j,k), e);
     884   157974680 :             for (i=1; i<=n; i++)
     885   146302465 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
     886   104241699 :             for (i=1; i<=d; i++)
     887    92569328 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
     888             :           } else { /* otherwise X = -1 */
     889    45999625 :             for (k=zeros+1; k<j; k++)
     890    34800498 :               dmael(mu,kappa,k) += ldexp(dmael(mu,j,k), e);
     891   155292328 :             for (i=1; i<=n; i++)
     892   144094600 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
     893   101542662 :             for (i=1; i<=d; i++)
     894    90344861 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i), gmael(U,j,i));
     895             :           }
     896    22870172 :           continue;
     897             :         }
     898             :         /* we have |X| >= 2 */
     899    11091793 :         if (atmp < 9007199254740992.)
     900             :         {
     901    10254076 :           tmp = pari_rint(tmp);
     902    24486105 :           for (k=zeros+1; k<j; k++)
     903    14232017 :             dmael(mu,kappa,k) -= ldexp(tmp * dmael(mu,j,k), e);
     904    10254088 :           xx = (s64) tmp;
     905    10254088 :           if (xx > 0) /* = xx */
     906             :           {
     907    46049218 :             for (i=1; i<=n; i++)
     908    40892188 :               gmael(B,kappa,i) = submuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
     909    33108780 :             for (i=1; i<=d; i++)
     910    27951726 :               gmael(U,kappa,i) = submuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
     911             :           }
     912             :           else /* = -xx */
     913             :           {
     914    45726460 :             for (i=1; i<=n; i++)
     915    40629596 :               gmael(B,kappa,i) = addmuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), -xx);
     916    32734409 :             for (i=1; i<=d; i++)
     917    27637533 :               gmael(U,kappa,i) = addmuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), -xx);
     918             :           }
     919             :         }
     920             :         else
     921             :         {
     922             :           int E;
     923      837717 :           xx = (s64) ldexp(frexp(dmael(mu,kappa,j), &E), 53);
     924      837717 :           E -= e + 53;
     925      837717 :           if (E <= 0)
     926             :           {
     927           0 :             xx = xx << -E;
     928           0 :             for (k=zeros+1; k<j; k++)
     929           0 :               dmael(mu,kappa,k) -= ldexp(((double)xx) * dmael(mu,j,k), e);
     930           0 :             if (xx > 0) /* = xx */
     931             :             {
     932           0 :               for (i=1; i<=n; i++)
     933           0 :                 gmael(B,kappa,i) = submuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
     934           0 :               for (i=1; i<=d; i++)
     935           0 :                 gmael(U,kappa,i) = submuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
     936             :             }
     937             :             else /* = -xx */
     938             :             {
     939           0 :               for (i=1; i<=n; i++)
     940           0 :                 gmael(B,kappa,i) = addmuliu64_inplace(gmael(B,kappa,i), gmael(B,j,i), -xx);
     941           0 :               for (i=1; i<=d; i++)
     942           0 :                 gmael(U,kappa,i) = addmuliu64_inplace(gmael(U,kappa,i), gmael(U,j,i), -xx);
     943             :             }
     944             :           } else
     945             :           {
     946     2786782 :             for (k=zeros+1; k<j; k++)
     947     1949065 :               dmael(mu,kappa,k) -= ldexp(((double)xx) * dmael(mu,j,k), E + e);
     948      837717 :             if (xx > 0) /* = xx */
     949             :             {
     950     3932703 :               for (i=1; i<=n; i++)
     951     3511018 :                 gmael(B,kappa,i) = submuliu642n(gmael(B,kappa,i), gmael(B,j,i), xx, E);
     952     1507176 :               for (i=1; i<=d; i++)
     953     1085491 :                 gmael(U,kappa,i) = submuliu642n(gmael(U,kappa,i), gmael(U,j,i), xx, E);
     954             :             }
     955             :             else /* = -xx */
     956             :             {
     957     3883301 :               for (i=1; i<=n; i++)
     958     3467222 :                 gmael(B,kappa,i) = addmuliu642n(gmael(B,kappa,i), gmael(B,j,i), -xx, E);
     959     1484104 :               for (i=1; i<=d; i++)
     960     1068025 :                 gmael(U,kappa,i) = addmuliu642n(gmael(U,kappa,i), gmael(U,j,i), -xx, E);
     961             :             }
     962             :           }
     963             :         }
     964             :       }
     965    47119706 :     if (!go_on) break; /* Anything happened? */
     966    17112277 :     expoB[kappa] = set_line(del(appB,kappa), gel(B,kappa), n);
     967    17114004 :     setG_fast(appB, n, G, kappa, zeros+1, kappa-1);
     968    17114384 :     aa = zeros+1;
     969             :   }
     970    30007429 :   if (did_something) setG2_fast(appB, n, G, kappa, kappa, maxG);
     971             : 
     972    30007706 :   del(s,zeros+1) = dmael(G,kappa,kappa);
     973             :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
     974   109288774 :   for (k=zeros+1; k<=kappa-2; k++)
     975    79281068 :     del(s,k+1) = del(s,k) - dmael(mu,kappa,k)*dmael(r,kappa,k);
     976    30007706 :   *pB = B; *pU = U; return 0;
     977             : }
     978             : 
     979             : static void
     980    11914879 : update_alpha(GEN alpha, long kappa, long kappa2, long kappamax)
     981             : {
     982             :   long i;
     983    37890660 :   for (i = kappa; i < kappa2; i++)
     984    25975781 :     if (kappa <= alpha[i]) alpha[i] = kappa;
     985    37890670 :   for (i = kappa2; i > kappa; i--) alpha[i] = alpha[i-1];
     986    23107185 :   for (i = kappa2+1; i <= kappamax; i++)
     987    11192306 :     if (kappa < alpha[i]) alpha[i] = kappa;
     988    11914879 :   alpha[kappa] = kappa;
     989    11914879 : }
     990             : static void
     991      441021 : rotateG(GEN G, long kappa2, long kappa, long maxG, GEN Gtmp)
     992             : {
     993             :   long i, j;
     994     3416550 :   for (i=1; i<=kappa2; i++) gel(Gtmp,i) = gmael(G,kappa2,i);
     995     1816610 :   for (   ; i<=maxG; i++)   gel(Gtmp,i) = gmael(G,i,kappa2);
     996     1545331 :   for (i=kappa2; i>kappa; i--)
     997             :     {
     998     5248677 :       for (j=1; j<kappa; j++) gmael(G,i,j) = gmael(G,i-1,j);
     999     1104310 :       gmael(G,i,kappa) = gel(Gtmp,i-1);
    1000     3981073 :       for (j=kappa+1; j<=i; j++) gmael(G,i,j) = gmael(G,i-1,j-1);
    1001     4788765 :       for (j=kappa2+1; j<=maxG; j++) gmael(G,j,i) = gmael(G,j,i-1);
    1002             :     }
    1003     1871219 :   for (i=1; i<kappa; i++) gmael(G,kappa,i) = gel(Gtmp,i);
    1004      441021 :   gmael(G,kappa,kappa) = gel(Gtmp,kappa2);
    1005     1816610 :   for (i=kappa2+1; i<=maxG; i++) gmael(G,i,kappa) = gel(Gtmp,i);
    1006      441021 : }
    1007             : static void
    1008    11473744 : rotateG_fast(double **G, long kappa2, long kappa, long maxG, double *Gtmp)
    1009             : {
    1010             :   long i, j;
    1011    66677253 :   for (i=1; i<=kappa2; i++) del(Gtmp,i) = dmael(G,kappa2,i);
    1012    22152788 :   for (   ; i<=maxG; i++) del(Gtmp,i) = dmael(G,i,kappa2);
    1013    36344987 :   for (i=kappa2; i>kappa; i--)
    1014             :   {
    1015    69484377 :     for (j=1; j<kappa; j++) dmael(G,i,j) = dmael(G,i-1,j);
    1016    24871243 :     dmael(G,i,kappa) = del(Gtmp,i-1);
    1017    84745687 :     for (j=kappa+1; j<=i; j++) dmael(G,i,j) = dmael(G,i-1,j-1);
    1018    46856403 :     for (j=kappa2+1; j<=maxG; j++) dmael(G,j,i) = dmael(G,j,i-1);
    1019             :   }
    1020    30332546 :   for (i=1; i<kappa; i++) dmael(G,kappa,i) = del(Gtmp,i);
    1021    11473744 :   dmael(G,kappa,kappa) = del(Gtmp,kappa2);
    1022    22152822 :   for (i=kappa2+1; i<=maxG; i++) dmael(G,i,kappa) = del(Gtmp,i);
    1023    11473744 : }
    1024             : 
    1025             : /* LLL-reduces (B,U) in place [apply base change transforms to B and U].
    1026             :  * Gram matrix, and GSO performed on matrices of 'double'.
    1027             :  * If (keepfirst), never swap with first vector.
    1028             :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1029             : static long
    1030     2068757 : fplll_fast(GEN *pB, GEN *pU, double delta, double eta, long keepfirst)
    1031             : {
    1032             :   pari_sp av;
    1033             :   long kappa, kappa2, d, n, i, j, zeros, kappamax, maxG;
    1034             :   double **mu, **r, *s, tmp, *Gtmp, **G, **appB;
    1035     2068757 :   GEN alpha, expoB, B = *pB, U;
    1036     2068757 :   long cnt = 0;
    1037             : 
    1038     2068757 :   d = lg(B)-1;
    1039     2068757 :   n = nbrows(B);
    1040     2068760 :   U = *pU; /* NULL if inplace */
    1041             : 
    1042     2068760 :   G = cget_dblmat(d+1);
    1043     2068757 :   appB = cget_dblmat(d+1);
    1044     2068755 :   mu = cget_dblmat(d+1);
    1045     2068756 :   r  = cget_dblmat(d+1);
    1046     2068754 :   s  = cget_dblvec(d+1);
    1047     9655473 :   for (j = 1; j <= d; j++)
    1048             :   {
    1049     7586714 :     del(mu,j) = cget_dblvec(d+1);
    1050     7586720 :     del(r,j) = cget_dblvec(d+1);
    1051     7586709 :     del(appB,j) = cget_dblvec(n+1);
    1052     7586713 :     del(G,j) = cget_dblvec(d+1);
    1053    46818742 :     for (i=1; i<=d; i++) dmael(G,j,i) = 0.;
    1054             :   }
    1055     2068759 :   expoB = cgetg(d+1, t_VECSMALL);
    1056     9655357 :   for (i=1; i<=d; i++) expoB[i] = set_line(del(appB,i), gel(B,i), n);
    1057     2068722 :   Gtmp = cget_dblvec(d+1);
    1058     2068753 :   alpha = cgetg(d+1, t_VECSMALL);
    1059     2068750 :   av = avma;
    1060             : 
    1061             :   /* Step2: Initializing the main loop */
    1062     2068750 :   kappamax = 1;
    1063     2068750 :   i = 1;
    1064     2068750 :   maxG = d; /* later updated to kappamax */
    1065             : 
    1066             :   do {
    1067     2234371 :     dmael(G,i,i) = dbldotsquare(del(appB,i),n);
    1068     2234373 :   } while (dmael(G,i,i) <= 0 && (++i <=d));
    1069     2068752 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1070     2068752 :   kappa = i;
    1071     2068752 :   if (zeros < d) dmael(r,zeros+1,zeros+1) = dmael(G,zeros+1,zeros+1);
    1072     9489828 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1073    32076554 :   while (++kappa <= d)
    1074             :   {
    1075    30011930 :     if (kappa > kappamax)
    1076             :     {
    1077     5348771 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1078     5348771 :       maxG = kappamax = kappa;
    1079     5348771 :       setG_fast(appB, n, G, kappa, zeros+1, kappa);
    1080             :     }
    1081             :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1082    30011926 :     if (Babai_fast(av, kappa, &B,&U, mu,r,s, appB, expoB, G, alpha[kappa],
    1083        4137 :                    zeros, maxG, eta)) { *pB=B; *pU=U; return -1; }
    1084             : 
    1085    30007685 :     tmp = ldexp(r[kappa-1][kappa-1] * delta, 2*(expoB[kappa-1]-expoB[kappa]));
    1086    30007685 :     if ((keepfirst && kappa == 2) || tmp <= del(s,kappa-1))
    1087             :     { /* Step4: Success of Lovasz's condition */
    1088    18533819 :       alpha[kappa] = kappa;
    1089    18533819 :       tmp = dmael(mu,kappa,kappa-1) * dmael(r,kappa,kappa-1);
    1090    18533819 :       dmael(r,kappa,kappa) = del(s,kappa-1)- tmp;
    1091    18533819 :       continue;
    1092             :     }
    1093             :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1094    11473866 :     if (DEBUGLEVEL>=4 && kappa==kappamax && del(s,kappa-1)!=0)
    1095           0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", 2*expoB[1] + dblexpo(del(s,1))); }
    1096    11473863 :     kappa2 = kappa;
    1097             :     do {
    1098    24871492 :       kappa--;
    1099    24871492 :       if (kappa<zeros+2 + (keepfirst ? 1: 0)) break;
    1100    18330622 :       tmp = dmael(r,kappa-1,kappa-1) * delta;
    1101    18330622 :       tmp = ldexp(tmp, 2*(expoB[kappa-1]-expoB[kappa2]));
    1102    18330622 :     } while (del(s,kappa-1) <= tmp);
    1103    11473863 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1104             : 
    1105             :     /* Step6: Update the mu's and r's */
    1106    11473849 :     dblrotate(mu,kappa2,kappa);
    1107    11473820 :     dblrotate(r,kappa2,kappa);
    1108    11473791 :     dmael(r,kappa,kappa) = del(s,kappa);
    1109             : 
    1110             :     /* Step7: Update B, appB, U, G */
    1111    11473791 :     rotate(B,kappa2,kappa);
    1112    11473788 :     dblrotate(appB,kappa2,kappa);
    1113    11473759 :     if (U) rotate(U,kappa2,kappa);
    1114    11473759 :     rotate(expoB,kappa2,kappa);
    1115    11473743 :     rotateG_fast(G,kappa2,kappa, maxG, Gtmp);
    1116             : 
    1117             :     /* Step8: Prepare the next loop iteration */
    1118    11473983 :     if (kappa == zeros+1 && dmael(G,kappa,kappa)<= 0)
    1119             :     {
    1120      206071 :       zeros++; kappa++;
    1121      206071 :       dmael(G,kappa,kappa) = dbldotsquare(del(appB,kappa),n);
    1122      206071 :       dmael(r,kappa,kappa) = dmael(G,kappa,kappa);
    1123             :     }
    1124             :   }
    1125     2064624 :   *pB = B; *pU = U; return zeros;
    1126             : }
    1127             : 
    1128             : /***************** HEURISTIC version (reduced precision) ****************/
    1129             : static GEN
    1130      194272 : realsqrdotproduct(GEN x)
    1131             : {
    1132      194272 :   long i, l = lg(x);
    1133      194272 :   GEN z = sqrr(gel(x,1));
    1134     1258625 :   for (i=2; i<l; i++) z = addrr(z, sqrr(gel(x,i)));
    1135      194272 :   return z;
    1136             : }
    1137             : /* x, y non-empty vector of t_REALs, same length */
    1138             : static GEN
    1139     1171084 : realdotproduct(GEN x, GEN y)
    1140             : {
    1141             :   long i, l;
    1142             :   GEN z;
    1143     1171084 :   if (x == y) return realsqrdotproduct(x);
    1144      976812 :   l = lg(x); z = mulrr(gel(x,1),gel(y,1));
    1145     8489443 :   for (i=2; i<l; i++) z = addrr(z, mulrr(gel(x,i), gel(y,i)));
    1146      976812 :   return z;
    1147             : }
    1148             : static void
    1149      202440 : setG_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1150      202440 : { pari_sp av = avma;
    1151             :   long i;
    1152      922908 :   for (i = a; i <= b; i++)
    1153      720468 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,kappa,i));
    1154      202440 :   set_avma(av);
    1155      202440 : }
    1156             : static void
    1157      184589 : setG2_heuristic(GEN appB, GEN G, long kappa, long a, long b)
    1158      184589 : { pari_sp av = avma;
    1159             :   long i;
    1160      635205 :   for (i = a; i <= b; i++)
    1161      450616 :     affrr(realdotproduct(gel(appB,kappa),gel(appB,i)), gmael(G,i,kappa));
    1162      184589 :   set_avma(av);
    1163      184589 : }
    1164             : 
    1165             : /* approximate t_REAL x as m * 2^e, where |m| < 2^bit */
    1166             : static GEN
    1167       12118 : truncexpo(GEN x, long bit, long *e)
    1168             : {
    1169       12118 :   *e = expo(x) + 1 - bit;
    1170       12118 :   if (*e >= 0) return mantissa2nr(x, 0);
    1171         928 :   *e = 0; return roundr_safe(x);
    1172             : }
    1173             : /* Babai's Nearest Plane algorithm (iterative); see Babai() */
    1174             : static int
    1175      284767 : Babai_heuristic(pari_sp av, long kappa, GEN *pB, GEN *pU, GEN mu, GEN r, GEN s,
    1176             :                 GEN appB, GEN G, long a, long zeros, long maxG,
    1177             :                 GEN eta, long prec)
    1178             : {
    1179      284767 :   GEN B = *pB, U = *pU;
    1180      284767 :   const long n = nbrows(B), d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    1181      284767 :   long k, aa = (a > zeros)? a : zeros+1;
    1182      284767 :   int did_something = 0;
    1183      284767 :   long emaxmu = EX0, emax2mu = EX0;
    1184             :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1185             : 
    1186      192757 :   for (;;) {
    1187      477524 :     int go_on = 0;
    1188      477524 :     long i, j, emax3mu = emax2mu;
    1189             : 
    1190      477524 :     if (gc_needed(av,2))
    1191             :     {
    1192          27 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    1193          27 :       gc_lll(av,2,&B,&U);
    1194             :     }
    1195             :     /* Step2: compute the GSO for stage kappa */
    1196      477524 :     emax2mu = emaxmu; emaxmu = EX0;
    1197     1841469 :     for (j=aa; j<kappa; j++)
    1198             :     {
    1199     1363945 :       pari_sp btop = avma;
    1200     1363945 :       GEN g = gmael(G,kappa,j);
    1201     4437163 :       for (k = zeros+1; k<j; k++)
    1202     3073218 :         g = subrr(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    1203     1363945 :       affrr(g, gmael(r,kappa,j));
    1204     1363945 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    1205     1363945 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    1206     1363945 :       set_avma(btop);
    1207             :     }
    1208      477524 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5)
    1209        1327 :     { *pB = B; *pU = U; return 1; }
    1210             : 
    1211     1620943 :     for (j=kappa-1; j>zeros; j--)
    1212     1337503 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1213             : 
    1214             :     /* Step3--5: compute the X_j's  */
    1215      476197 :     if (go_on)
    1216      882512 :       for (j=kappa-1; j>zeros; j--)
    1217             :       { /* The code below seemingly handles U = NULL, but in this case d = 0 */
    1218             :         pari_sp btop;
    1219      689755 :         GEN tmp = gmael(mu,kappa,j);
    1220      689755 :         if (absrsmall(tmp)) continue; /* size-reduced */
    1221             : 
    1222      396441 :         if (gc_needed(av,2))
    1223             :         {
    1224          19 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    1225          19 :           gc_lll(av,2,&B,&U);
    1226             :         }
    1227      396441 :         btop = avma; did_something = 1;
    1228             :         /* we consider separately the case |X| = 1 */
    1229      396441 :         if (absrsmall2(tmp))
    1230             :         {
    1231      260480 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    1232      383478 :             for (k=zeros+1; k<j; k++)
    1233      253759 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1234      129719 :             set_avma(btop);
    1235     1231403 :             for (i=1; i<=n; i++)
    1236     1101684 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    1237      803952 :             for (i=1; i<=d; i++)
    1238      674233 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
    1239             :           } else { /* otherwise X = -1 */
    1240      388385 :             for (k=zeros+1; k<j; k++)
    1241      257624 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    1242      130761 :             set_avma(btop);
    1243     1245541 :             for (i=1; i<=n; i++)
    1244     1114780 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i), gmael(B,j,i));
    1245      805553 :             for (i=1; i<=d; i++)
    1246      674792 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    1247             :           }
    1248      260480 :           continue;
    1249             :         }
    1250             :         /* we have |X| >= 2 */
    1251      135961 :         if (expo(tmp) < BITS_IN_LONG)
    1252             :         {
    1253      123843 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    1254      123843 :           if (signe(tmp) > 0) /* = xx */
    1255             :           {
    1256      136118 :             for (k=zeros+1; k<j; k++)
    1257       73654 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1258       73654 :                   gmael(mu,kappa,k));
    1259       62464 :             set_avma(btop);
    1260      414774 :             for (i=1; i<=n; i++)
    1261      352310 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1262      306150 :             for (i=1; i<=d; i++)
    1263      243686 :               gmael(U,kappa,i) = submuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    1264             :           }
    1265             :           else /* = -xx */
    1266             :           {
    1267      132794 :             for (k=zeros+1; k<j; k++)
    1268       71415 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    1269       71415 :                   gmael(mu,kappa,k));
    1270       61379 :             set_avma(btop);
    1271      407650 :             for (i=1; i<=n; i++)
    1272      346271 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    1273      292768 :             for (i=1; i<=d; i++)
    1274      231389 :               gmael(U,kappa,i) = addmuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    1275             :           }
    1276             :         }
    1277             :         else
    1278             :         {
    1279             :           long e;
    1280       12118 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    1281       12118 :           btop = avma;
    1282       29480 :           for (k=zeros+1; k<j; k++)
    1283             :           {
    1284       17362 :             GEN x = mulir(X, gmael(mu,j,k));
    1285       17362 :             if (e) shiftr_inplace(x, e);
    1286       17362 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    1287             :           }
    1288       12118 :           set_avma(btop);
    1289       99012 :           for (i=1; i<=n; i++)
    1290       86894 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    1291       72994 :           for (i=1; i<=d; i++)
    1292       60876 :             gmael(U,kappa,i) = submulshift(gmael(U,kappa,i), gmael(U,j,i), X, e);
    1293             :         }
    1294             :       }
    1295      476197 :     if (!go_on) break; /* Anything happened? */
    1296     1444936 :     for (i=1 ; i<=n; i++) affir(gmael(B,kappa,i), gmael(appB,kappa,i));
    1297      192757 :     setG_heuristic(appB, G, kappa, zeros+1, kappa-1);
    1298      192757 :     aa = zeros+1;
    1299             :   }
    1300      283440 :   if (did_something) setG2_heuristic(appB, G, kappa, kappa, maxG);
    1301      283440 :   affrr(gmael(G,kappa,kappa), gel(s,zeros+1));
    1302             :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    1303      283440 :   av = avma;
    1304     1016465 :   for (k=zeros+1; k<=kappa-2; k++)
    1305      733025 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    1306      733025 :           gel(s,k+1));
    1307      283440 :   *pB = B; *pU = U; return gc_bool(av, 0);
    1308             : }
    1309             : 
    1310             : static GEN
    1311       15722 : ZC_to_RC(GEN x, long prec)
    1312      103277 : { pari_APPLY_type(t_COL,itor(gel(x,i),prec)) }
    1313             : 
    1314             : static GEN
    1315        4137 : ZM_to_RM(GEN x, long prec)
    1316       19859 : { pari_APPLY_same(ZC_to_RC(gel(x,i),prec)) }
    1317             : 
    1318             : /* LLL-reduces (B,U) in place [apply base change transforms to B and U].
    1319             :  * Gram matrix made of t_REAL at precision prec2, performe GSO at prec.
    1320             :  * If (keepfirst), never swap with first vector.
    1321             :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1322             : static long
    1323        4137 : fplll_heuristic(GEN *pB, GEN *pU, double DELTA, double ETA, long keepfirst,
    1324             :                 long prec, long prec2)
    1325             : {
    1326             :   pari_sp av, av2;
    1327             :   long kappa, kappa2, d, i, j, zeros, kappamax, maxG;
    1328        4137 :   GEN mu, r, s, tmp, Gtmp, alpha, G, appB, B = *pB, U;
    1329        4137 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    1330        4137 :   long cnt = 0;
    1331             : 
    1332        4137 :   d = lg(B)-1;
    1333        4137 :   U = *pU; /* NULL if inplace */
    1334             : 
    1335        4137 :   G = cgetg(d+1, t_MAT);
    1336        4137 :   mu = cgetg(d+1, t_MAT);
    1337        4137 :   r  = cgetg(d+1, t_MAT);
    1338        4137 :   s  = cgetg(d+1, t_VEC);
    1339        4137 :   appB = ZM_to_RM(B, prec2);
    1340       19859 :   for (j = 1; j <= d; j++)
    1341             :   {
    1342       15722 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL), S = cgetg(d+1, t_COL);
    1343       15722 :     gel(mu,j)= M;
    1344       15722 :     gel(r,j) = R;
    1345       15722 :     gel(G,j) = S;
    1346       15722 :     gel(s,j) = cgetr(prec);
    1347       95028 :     for (i = 1; i <= d; i++)
    1348             :     {
    1349       79306 :       gel(R,i) = cgetr(prec);
    1350       79306 :       gel(M,i) = cgetr(prec);
    1351       79306 :       gel(S,i) = cgetr(prec2);
    1352             :     }
    1353             :   }
    1354        4137 :   Gtmp = cgetg(d+1, t_VEC);
    1355        4137 :   alpha = cgetg(d+1, t_VECSMALL);
    1356        4137 :   av = avma;
    1357             : 
    1358             :   /* Step2: Initializing the main loop */
    1359        4137 :   kappamax = 1;
    1360        4137 :   i = 1;
    1361        4137 :   maxG = d; /* later updated to kappamax */
    1362             : 
    1363             :   do {
    1364        4140 :     affrr(RgV_dotsquare(gel(appB,i)), gmael(G,i,i));
    1365        4140 :   } while (signe(gmael(G,i,i)) == 0 && (++i <=d));
    1366        4137 :   zeros = i-1; /* all vectors B[i] with i <= zeros are zero vectors */
    1367        4137 :   kappa = i;
    1368        4137 :   if (zeros < d) affrr(gmael(G,zeros+1,zeros+1), gmael(r,zeros+1,zeros+1));
    1369       19856 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1370             : 
    1371      287577 :   while (++kappa <= d)
    1372             :   {
    1373      284767 :     if (kappa > kappamax)
    1374             :     {
    1375        9683 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1376        9683 :       maxG = kappamax = kappa;
    1377        9683 :       setG_heuristic(appB, G, kappa, zeros+1, kappa);
    1378             :     }
    1379             :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1380      284767 :     if (Babai_heuristic(av, kappa, &B,&U, mu,r,s, appB, G, alpha[kappa], zeros,
    1381        1327 :                         maxG, eta, prec)) { *pB = B; *pU = U; return -1; }
    1382      283440 :     av2 = avma;
    1383      566771 :     if ((keepfirst && kappa == 2) ||
    1384      283331 :         cmprr(mulrr(gmael(r,kappa-1,kappa-1), delta), gel(s,kappa-1)) <= 0)
    1385             :     { /* Step4: Success of Lovasz's condition */
    1386      168115 :       alpha[kappa] = kappa;
    1387      168115 :       tmp = mulrr(gmael(mu,kappa,kappa-1), gmael(r,kappa,kappa-1));
    1388      168115 :       affrr(subrr(gel(s,kappa-1), tmp), gmael(r,kappa,kappa));
    1389      168115 :       set_avma(av2); continue;
    1390             :     }
    1391             :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1392      115325 :     if (DEBUGLEVEL>=4 && kappa==kappamax && signe(gel(s,kappa-1)))
    1393           0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", expo(gel(s,1))); }
    1394      115325 :     kappa2 = kappa;
    1395             :     do {
    1396      275109 :       kappa--;
    1397      275109 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1398      245838 :       tmp = mulrr(gmael(r,kappa-1,kappa-1), delta);
    1399      245838 :     } while (cmprr(gel(s,kappa-1), tmp) <= 0 );
    1400      115325 :     set_avma(av2);
    1401      115325 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1402             : 
    1403             :     /* Step6: Update the mu's and r's */
    1404      115325 :     rotate(mu,kappa2,kappa);
    1405      115325 :     rotate(r,kappa2,kappa);
    1406      115325 :     affrr(gel(s,kappa), gmael(r,kappa,kappa));
    1407             : 
    1408             :     /* Step7: Update B, appB, U, G */
    1409      115325 :     rotate(B,kappa2,kappa);
    1410      115325 :     rotate(appB,kappa2,kappa);
    1411      115325 :     if (U) rotate(U,kappa2,kappa);
    1412      115325 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    1413             : 
    1414             :     /* Step8: Prepare the next loop iteration */
    1415      115325 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    1416             :     {
    1417           0 :       zeros++; kappa++;
    1418           0 :       affrr(RgV_dotsquare(gel(appB,kappa)), gmael(G,kappa,kappa));
    1419           0 :       affrr(gmael(G,kappa,kappa), gmael(r,kappa,kappa));
    1420             :     }
    1421             :   }
    1422        2810 :   *pB=B; *pU=U; return zeros;
    1423             : }
    1424             : 
    1425             : /************************* PROVED version (t_INT) ***********************/
    1426             : /* dpe inspired by dpe.h by Patrick Pelissier, Paul Zimmermann
    1427             :  * https://gforge.inria.fr/projects/dpe/
    1428             :  */
    1429             : 
    1430             : typedef struct
    1431             : {
    1432             :   double d;  /* significand */
    1433             :   long e; /* exponent */
    1434             : } dpe_t;
    1435             : 
    1436             : #define Dmael(x,i,j) (&((x)[i][j]))
    1437             : #define Del(x,i) (&((x)[i]))
    1438             : 
    1439             : static void
    1440      651392 : dperotate(dpe_t **A, long k2, long k)
    1441             : {
    1442             :   long i;
    1443      651392 :   dpe_t *B = A[k2];
    1444     2309794 :   for (i = k2; i > k; i--) A[i] = A[i-1];
    1445      651392 :   A[k] = B;
    1446      651392 : }
    1447             : 
    1448             : static void
    1449   108017724 : dpe_normalize0(dpe_t *x)
    1450             : {
    1451             :   int e;
    1452   108017724 :   x->d = frexp(x->d, &e);
    1453   108017724 :   x->e += e;
    1454   108017724 : }
    1455             : 
    1456             : static void
    1457    47896566 : dpe_normalize(dpe_t *x)
    1458             : {
    1459    47896566 :   if (x->d == 0.0)
    1460      496226 :     x->e = -LONG_MAX;
    1461             :   else
    1462    47400340 :     dpe_normalize0(x);
    1463    47896610 : }
    1464             : 
    1465             : static GEN
    1466       93935 : dpetor(dpe_t *x)
    1467             : {
    1468       93935 :   GEN r = dbltor(x->d);
    1469       93935 :   if (signe(r)==0) return r;
    1470       93935 :   setexpo(r, x->e-1);
    1471       93935 :   return r;
    1472             : }
    1473             : 
    1474             : static void
    1475    25559615 : affdpe(dpe_t *y, dpe_t *x)
    1476             : {
    1477    25559615 :   x->d = y->d;
    1478    25559615 :   x->e = y->e;
    1479    25559615 : }
    1480             : 
    1481             : static void
    1482    20520677 : affidpe(GEN y, dpe_t *x)
    1483             : {
    1484    20520677 :   pari_sp av = avma;
    1485    20520677 :   GEN r = itor(y, DEFAULTPREC);
    1486    20520407 :   x->e = expo(r)+1;
    1487    20520407 :   setexpo(r,-1);
    1488    20520349 :   x->d = rtodbl(r);
    1489    20520311 :   set_avma(av);
    1490    20520275 : }
    1491             : 
    1492             : static void
    1493     3135893 : affdbldpe(double y, dpe_t *x)
    1494             : {
    1495     3135893 :   x->d = (double)y;
    1496     3135893 :   x->e = 0;
    1497     3135893 :   dpe_normalize(x);
    1498     3135894 : }
    1499             : 
    1500             : static void
    1501    56707082 : dpe_mulz(dpe_t *x, dpe_t *y, dpe_t *z)
    1502             : {
    1503    56707082 :   z->d = x->d * y->d;
    1504    56707082 :   if (z->d == 0.0)
    1505     8143860 :     z->e = -LONG_MAX;
    1506             :   else
    1507             :   {
    1508    48563222 :     z->e = x->e + y->e;
    1509    48563222 :     dpe_normalize0(z);
    1510             :   }
    1511    56707283 : }
    1512             : 
    1513             : static void
    1514    13954866 : dpe_divz(dpe_t *x, dpe_t *y, dpe_t *z)
    1515             : {
    1516    13954866 :   z->d = x->d / y->d;
    1517    13954866 :   if (z->d == 0.0)
    1518     1900412 :     z->e = -LONG_MAX;
    1519             :   else
    1520             :   {
    1521    12054454 :     z->e = x->e - y->e;
    1522    12054454 :     dpe_normalize0(z);
    1523             :   }
    1524    13954916 : }
    1525             : 
    1526             : static void
    1527      244142 : dpe_negz(dpe_t *y, dpe_t *x)
    1528             : {
    1529      244142 :   x->d = - y->d;
    1530      244142 :   x->e = y->e;
    1531      244142 : }
    1532             : 
    1533             : static void
    1534     1941891 : dpe_addz(dpe_t *y, dpe_t *z, dpe_t *x)
    1535             : {
    1536     1941891 :   if (y->e > z->e + 53)
    1537      112039 :     affdpe(y, x);
    1538     1829852 :   else if (z->e > y->e + 53)
    1539       41670 :     affdpe(z, x);
    1540             :   else
    1541             :   {
    1542     1788182 :     long d = y->e - z->e;
    1543             : 
    1544     1788182 :     if (d >= 0)
    1545             :     {
    1546     1344061 :       x->d = y->d + ldexp(z->d, -d);
    1547     1344061 :       x->e  = y->e;
    1548             :     }
    1549             :     else
    1550             :     {
    1551      444121 :       x->d = z->d + ldexp(y->d, d);
    1552      444121 :       x->e = z->e;
    1553             :     }
    1554     1788182 :     dpe_normalize(x);
    1555             :   }
    1556     1941891 : }
    1557             : static void
    1558    53542919 : dpe_subz(dpe_t *y, dpe_t *z, dpe_t *x)
    1559             : {
    1560    53542919 :   if (y->e > z->e + 53)
    1561    11125470 :     affdpe(y, x);
    1562    42417449 :   else if (z->e > y->e + 53)
    1563      244142 :     dpe_negz(z, x);
    1564             :   else
    1565             :   {
    1566    42173307 :     long d = y->e - z->e;
    1567             : 
    1568    42173307 :     if (d >= 0)
    1569             :     {
    1570    39413912 :       x->d = y->d - ldexp(z->d, -d);
    1571    39413912 :       x->e = y->e;
    1572             :     }
    1573             :     else
    1574             :     {
    1575     2759395 :       x->d = ldexp(y->d, d) - z->d;
    1576     2759395 :       x->e = z->e;
    1577             :     }
    1578    42173307 :     dpe_normalize(x);
    1579             :   }
    1580    53543124 : }
    1581             : 
    1582             : static void
    1583      799035 : dpe_muluz(dpe_t *y, ulong t, dpe_t *x)
    1584             : {
    1585      799035 :   x->d = y->d * (double)t;
    1586      799035 :   x->e = y->e;
    1587      799035 :   dpe_normalize(x);
    1588      799035 : }
    1589             : 
    1590             : static void
    1591      342647 : dpe_addmuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1592             : {
    1593             :   dpe_t tmp;
    1594      342647 :   dpe_muluz(z, t, &tmp);
    1595      342647 :   dpe_addz(y, &tmp, x);
    1596      342647 : }
    1597             : 
    1598             : static void
    1599      411904 : dpe_submuluz(dpe_t *y,  dpe_t *z, ulong t, dpe_t *x)
    1600             : {
    1601             :   dpe_t tmp;
    1602      411904 :   dpe_muluz(z, t, &tmp);
    1603      411904 :   dpe_subz(y, &tmp, x);
    1604      411904 : }
    1605             : 
    1606             : static void
    1607    51512996 : dpe_submulz(dpe_t *y,  dpe_t *z, dpe_t *t, dpe_t *x)
    1608             : {
    1609             :   dpe_t tmp;
    1610    51512996 :   dpe_mulz(z, t, &tmp);
    1611    51512997 :   dpe_subz(y, &tmp, x);
    1612    51513037 : }
    1613             : 
    1614             : static int
    1615     5194206 : dpe_cmp(dpe_t *x, dpe_t *y)
    1616             : {
    1617     5194206 :   int sx = x->d < 0. ? -1: x->d > 0.;
    1618     5194206 :   int sy = y->d < 0. ? -1: y->d > 0.;
    1619     5194206 :   int d  = sx - sy;
    1620             : 
    1621     5194206 :   if (d != 0)
    1622      141619 :     return d;
    1623     5052587 :   else if (x->e > y->e)
    1624      481159 :     return (sx > 0) ? 1 : -1;
    1625     4571428 :   else if (y->e > x->e)
    1626     2501627 :     return (sx > 0) ? -1 : 1;
    1627             :   else
    1628     2069801 :     return (x->d < y->d) ? -1 : (x->d > y->d);
    1629             : }
    1630             : 
    1631             : static int
    1632    14395699 : dpe_abscmp(dpe_t *x, dpe_t *y)
    1633             : {
    1634    14395699 :   if (x->e > y->e)
    1635      271158 :     return 1;
    1636    14124541 :   else if (y->e > x->e)
    1637    13274138 :     return -1;
    1638             :   else
    1639      850403 :     return (fabs(x->d) < fabs(y->d)) ? -1 : (fabs(x->d) > fabs(y->d));
    1640             : }
    1641             : 
    1642             : static int
    1643     1387788 : dpe_abssmall(dpe_t *x)
    1644             : {
    1645     1387788 :   return (x->e <= 0) || (x->e == 1 && fabs(x->d) <= .75);
    1646             : }
    1647             : 
    1648             : static int
    1649     5194209 : dpe_cmpmul(dpe_t *x, dpe_t *y, dpe_t *z)
    1650             : {
    1651             :   dpe_t t;
    1652     5194209 :   dpe_mulz(x,y,&t);
    1653     5194206 :   return dpe_cmp(&t, z);
    1654             : }
    1655             : 
    1656             : static dpe_t *
    1657    13041772 : cget_dpevec(long d)
    1658    13041772 : { return (dpe_t*) stack_malloc_align(d*sizeof(dpe_t), sizeof(dpe_t)); }
    1659             : 
    1660             : static dpe_t **
    1661     3135889 : cget_dpemat(long d) { return (dpe_t **) cgetg(d, t_VECSMALL); }
    1662             : 
    1663             : static GEN
    1664       20252 : dpeM_diagonal_shallow(dpe_t **m, long d)
    1665             : {
    1666             :   long i;
    1667       20252 :   GEN y = cgetg(d+1,t_VEC);
    1668      114187 :   for (i=1; i<=d; i++) gel(y, i) = dpetor(Dmael(m,i,i));
    1669       20252 :   return y;
    1670             : }
    1671             : 
    1672             : static void
    1673     1387780 : affii_or_copy_gc(pari_sp av, GEN x, GEN *y)
    1674             : {
    1675     1387780 :   long l = lg(*y);
    1676     1387780 :   if (lgefint(x) <= l && isonstack(*y))
    1677             :   {
    1678     1387767 :     affii(x,*y);
    1679     1387769 :     set_avma(av);
    1680             :   }
    1681             :   else
    1682          12 :     *y = gerepileuptoint(av, x);
    1683     1387786 : }
    1684             : 
    1685             : /* *x -= u*y */
    1686             : INLINE void
    1687     5919990 : submulziu(GEN *x, GEN y, ulong u)
    1688             : {
    1689             :   pari_sp av;
    1690     5919990 :   long ly = lgefint(y);
    1691     5919990 :   if (ly == 2) return;
    1692     3251911 :   av = avma;
    1693     3251911 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1694     3251965 :   y = mului(u,y);
    1695     3251946 :   set_avma(av); subzi(x, y);
    1696             : }
    1697             : 
    1698             : /* *x += u*y */
    1699             : INLINE void
    1700     4576899 : addmulziu(GEN *x, GEN y, ulong u)
    1701             : {
    1702             :   pari_sp av;
    1703     4576899 :   long ly = lgefint(y);
    1704     4576899 :   if (ly == 2) return;
    1705     2755362 :   av = avma;
    1706     2755362 :   (void)new_chunk(3+ly+lgefint(*x)); /* HACK */
    1707     2755375 :   y = mului(u,y);
    1708     2755369 :   set_avma(av); addzi(x, y);
    1709             : }
    1710             : 
    1711             : /************************** PROVED version (dpe) *************************/
    1712             : 
    1713             : /* Babai's Nearest Plane algorithm (iterative).
    1714             :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    1715             :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    1716             :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    1717             : static int
    1718     4585961 : Babai_dpe(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, dpe_t **mu, dpe_t **r, dpe_t *s,
    1719             :       long a, long zeros, long maxG, dpe_t *eta)
    1720             : {
    1721     4585961 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    1722     4585961 :   long k, d, n, aa = a > zeros? a: zeros+1;
    1723     4585961 :   long emaxmu = EX0, emax2mu = EX0;
    1724             :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    1725     4585961 :   d = U? lg(U)-1: 0;
    1726     4585961 :   n = B? nbrows(B): 0;
    1727      522163 :   for (;;) {
    1728     5108138 :     int go_on = 0;
    1729     5108138 :     long i, j, emax3mu = emax2mu;
    1730             : 
    1731     5108138 :     if (gc_needed(av,2))
    1732             :     {
    1733           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    1734           0 :       gc_lll(av,3,&G,&B,&U);
    1735             :     }
    1736             :     /* Step2: compute the GSO for stage kappa */
    1737     5108136 :     emax2mu = emaxmu; emaxmu = EX0;
    1738    19063044 :     for (j=aa; j<kappa; j++)
    1739             :     {
    1740             :       dpe_t g;
    1741    13954900 :       affidpe(gmael(G,kappa,j), &g);
    1742    52324925 :       for (k = zeros+1; k < j; k++)
    1743    38370095 :         dpe_submulz(&g, Dmael(mu,j,k), Dmael(r,kappa,k), &g);
    1744    13954830 :       affdpe(&g, Dmael(r,kappa,j));
    1745    13954865 :       dpe_divz(Dmael(r,kappa,j), Dmael(r,j,j), Dmael(mu,kappa,j));
    1746    13954872 :       emaxmu = maxss(emaxmu, Dmael(mu,kappa,j)->e);
    1747             :     }
    1748     5108144 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    1749           0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    1750             : 
    1751    18981671 :     for (j=kappa-1; j>zeros; j--)
    1752    14395699 :       if (dpe_abscmp(Dmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    1753             : 
    1754             :     /* Step3--5: compute the X_j's  */
    1755     5108143 :     if (go_on)
    1756     3030756 :       for (j=kappa-1; j>zeros; j--)
    1757             :       {
    1758             :         pari_sp btop;
    1759     2508589 :         dpe_t *tmp = Dmael(mu,kappa,j);
    1760     2508589 :         if (tmp->e < 0) continue; /* (essentially) size-reduced */
    1761             : 
    1762     1387787 :         if (gc_needed(av,2))
    1763             :         {
    1764           0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    1765           0 :           gc_lll(av,3,&G,&B,&U);
    1766             :         }
    1767             :         /* we consider separately the case |X| = 1 */
    1768     1387787 :         if (dpe_abssmall(tmp))
    1769             :         {
    1770      920630 :           if (tmp->d > 0) { /* in this case, X = 1 */
    1771     2057658 :             for (k=zeros+1; k<j; k++)
    1772     1596111 :               dpe_subz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1773     3016920 :             for (i=1; i<=n; i++)
    1774     2555373 :               subzi(&gmael(B,kappa,i), gmael(B,j,i));
    1775     6970743 :             for (i=1; i<=d; i++)
    1776     6509199 :               subzi(&gmael(U,kappa,i), gmael(U,j,i));
    1777      461544 :             btop = avma;
    1778      461544 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1779      461545 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1780      461546 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1781     2859409 :             for (i=1; i<=j; i++)
    1782     2397862 :               subzi(&gmael(G,kappa,i), gmael(G,j,i));
    1783     2191662 :             for (i=j+1; i<kappa; i++)
    1784     1730118 :               subzi(&gmael(G,kappa,i), gmael(G,i,j));
    1785     2360873 :             for (i=kappa+1; i<=maxG; i++)
    1786     1899331 :               subzi(&gmael(G,i,kappa), gmael(G,i,j));
    1787             :           } else { /* otherwise X = -1 */
    1788     2035780 :             for (k=zeros+1; k<j; k++)
    1789     1576697 :               dpe_addz(Dmael(mu,kappa,k), Dmael(mu,j,k), Dmael(mu,kappa,k));
    1790     3011875 :             for (i=1; i<=n; i++)
    1791     2552792 :               addzi(&gmael(B,kappa,i),gmael(B,j,i));
    1792     6843738 :             for (i=1; i<=d; i++)
    1793     6384652 :               addzi(&gmael(U,kappa,i),gmael(U,j,i));
    1794      459086 :             btop = avma;
    1795      459086 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    1796      459083 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1797      459084 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1798     2770252 :             for (i=1; i<=j; i++)
    1799     2311170 :               addzi(&gmael(G,kappa,i), gmael(G,j,i));
    1800     2195496 :             for (i=j+1; i<kappa; i++)
    1801     1736414 :               addzi(&gmael(G,kappa,i), gmael(G,i,j));
    1802     2313485 :             for (i=kappa+1; i<=maxG; i++)
    1803     1854404 :               addzi(&gmael(G,i,kappa), gmael(G,i,j));
    1804             :           }
    1805      920623 :           continue;
    1806             :         }
    1807             :         /* we have |X| >= 2 */
    1808      467159 :         if (tmp->e < BITS_IN_LONG-1)
    1809             :         {
    1810      448162 :           if (tmp->d > 0)
    1811             :           {
    1812      247183 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, tmp->e)); /* X fits in an ulong */
    1813      659087 :             for (k=zeros+1; k<j; k++)
    1814      411904 :               dpe_submuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1815      722230 :             for (i=1; i<=n; i++)
    1816      475047 :               submulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1817     3107309 :             for (i=1; i<=d; i++)
    1818     2860129 :               submulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1819      247180 :             btop = avma;
    1820      247180 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1821      247178 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1822      247179 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1823     1313767 :             for (i=1; i<=j; i++)
    1824     1066583 :               submulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1825      807869 :             for (i=j+1; i<kappa; i++)
    1826      560689 :               submulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1827     1204789 :             for (i=kappa+1; i<=maxG; i++)
    1828      957609 :               submulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1829             :           }
    1830             :           else
    1831             :           {
    1832      200979 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, tmp->e)); /* X fits in an ulong */
    1833      543626 :             for (k=zeros+1; k<j; k++)
    1834      342647 :               dpe_addmuluz(Dmael(mu,kappa,k), Dmael(mu,j,k), xx, Dmael(mu,kappa,k));
    1835      687415 :             for (i=1; i<=n; i++)
    1836      486436 :               addmulziu(&gmael(B,kappa,i), gmael(B,j,i), xx);
    1837     2359206 :             for (i=1; i<=d; i++)
    1838     2158227 :               addmulziu(&gmael(U,kappa,i), gmael(U,j,i), xx);
    1839      200979 :             btop = avma;
    1840      200979 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    1841      200979 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1842      200979 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1843      989995 :             for (i=1; i<=j; i++)
    1844      789018 :               addmulziu(&gmael(G,kappa,i), gmael(G,j,i), xx);
    1845      662168 :             for (i=j+1; i<kappa; i++)
    1846      461191 :               addmulziu(&gmael(G,kappa,i), gmael(G,i,j), xx);
    1847      883028 :             for (i=kappa+1; i<=maxG; i++)
    1848      682050 :               addmulziu(&gmael(G,i,kappa), gmael(G,i,j), xx);
    1849             :           }
    1850             :         }
    1851             :         else
    1852             :         {
    1853       18997 :           long e = tmp->e - BITS_IN_LONG + 1;
    1854       18997 :           if (tmp->d > 0)
    1855             :           {
    1856        9396 :             ulong xx = (ulong) pari_rint(ldexp(tmp->d, BITS_IN_LONG - 1));
    1857       31333 :             for (k=zeros+1; k<j; k++)
    1858             :             {
    1859             :               dpe_t x;
    1860       21937 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1861       21937 :               x.e += e;
    1862       21937 :               dpe_subz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1863             :             }
    1864      124323 :             for (i=1; i<=n; i++)
    1865      114927 :               submulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1866       87036 :             for (i=1; i<=d; i++)
    1867       77640 :               submulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1868        9396 :             btop = avma;
    1869        9396 :             ztmp = submuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1870        9396 :                 gmael(G,kappa,j), xx, e+1);
    1871        9396 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1872        9396 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1873       40927 :             for (i=1; i<=j; i++)
    1874       31531 :               submulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1875       47343 :             for (   ; i<kappa; i++)
    1876       37947 :               submulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1877       10308 :             for (i=kappa+1; i<=maxG; i++)
    1878         912 :               submulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1879             :           } else
    1880             :           {
    1881        9601 :             ulong xx = (ulong) pari_rint(ldexp(-tmp->d, BITS_IN_LONG - 1));
    1882       32153 :             for (k=zeros+1; k<j; k++)
    1883             :             {
    1884             :               dpe_t x;
    1885       22547 :               dpe_muluz(Dmael(mu,j,k), xx, &x);
    1886       22547 :               x.e += e;
    1887       22547 :               dpe_addz(Dmael(mu,kappa,k), &x, Dmael(mu,kappa,k));
    1888             :             }
    1889      128490 :             for (i=1; i<=n; i++)
    1890      118884 :               addmulzu2n(&gmael(B,kappa,i), gmael(B,j,i), xx, e);
    1891       89277 :             for (i=1; i<=d; i++)
    1892       79671 :               addmulzu2n(&gmael(U,kappa,i), gmael(U,j,i), xx, e);
    1893        9606 :             btop = avma;
    1894        9606 :             ztmp = addmuliu2n(mulshift(gmael(G,j,j), sqru(xx), 2*e),
    1895        9606 :                 gmael(G,kappa,j), xx, e+1);
    1896        9606 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    1897        9606 :             affii_or_copy_gc(btop, ztmp, &gmael(G,kappa,kappa));
    1898       41957 :             for (i=1; i<=j; i++)
    1899       32351 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,j,i), xx, e);
    1900       48921 :             for (   ; i<kappa; i++)
    1901       39315 :               addmulzu2n(&gmael(G,kappa,i), gmael(G,i,j), xx, e);
    1902       10353 :             for (i=kappa+1; i<=maxG; i++)
    1903         747 :               addmulzu2n(&gmael(G,i,kappa), gmael(G,i,j), xx, e);
    1904             :           }
    1905             :         }
    1906             :       }
    1907     5108139 :     if (!go_on) break; /* Anything happened? */
    1908      522163 :     aa = zeros+1;
    1909             :   }
    1910             : 
    1911     4585976 :   affidpe(gmael(G,kappa,kappa), Del(s,zeros+1));
    1912             :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    1913    13468745 :   for (k=zeros+1; k<=kappa-2; k++)
    1914     8882769 :     dpe_submulz(Del(s,k), Dmael(mu,kappa,k), Dmael(r,kappa,k), Del(s,k+1));
    1915     4585976 :   *pG = G; *pB = B; *pU = U; return 0;
    1916             : }
    1917             : 
    1918             : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    1919             :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    1920             :  * If G = NULL, we compute the Gram matrix incrementally.
    1921             :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    1922             : static long
    1923     1567948 : fplll_dpe(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    1924             :       long keepfirst)
    1925             : {
    1926             :   pari_sp av;
    1927     1567948 :   GEN Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    1928     1567948 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    1929             :   dpe_t delta, eta, **mu, **r, *s;
    1930     1567948 :   affdbldpe(DELTA,&delta);
    1931     1567948 :   affdbldpe(ETA,&eta);
    1932             : 
    1933     1567950 :   if (incgram)
    1934             :   { /* incremental Gram matrix */
    1935     1507675 :     maxG = 2; d = lg(B)-1;
    1936     1507675 :     G = zeromatcopy(d, d);
    1937             :   }
    1938             :   else
    1939       60275 :     maxG = d = lg(G)-1;
    1940             : 
    1941     1567947 :   mu = cget_dpemat(d+1);
    1942     1567943 :   r  = cget_dpemat(d+1);
    1943     1567940 :   s  = cget_dpevec(d+1);
    1944     7304878 :   for (j = 1; j <= d; j++)
    1945             :   {
    1946     5736932 :     mu[j]= cget_dpevec(d+1);
    1947     5736932 :     r[j] = cget_dpevec(d+1);
    1948             :   }
    1949     1567946 :   Gtmp = cgetg(d+1, t_VEC);
    1950     1567944 :   alpha = cgetg(d+1, t_VECSMALL);
    1951     1567941 :   av = avma;
    1952             : 
    1953             :   /* Step2: Initializing the main loop */
    1954     1567941 :   kappamax = 1;
    1955     1567941 :   i = 1;
    1956             :   do {
    1957     1944935 :     if (incgram) gmael(G,i,i) = ZV_dotsquare(gel(B,i));
    1958     1944889 :     affidpe(gmael(G,i,i), Dmael(r,i,i));
    1959     1944895 :   } while (!signe(gmael(G,i,i)) && ++i <= d);
    1960     1567901 :   zeros = i-1; /* all basis vectors b_i with i <= zeros are zero vectors */
    1961     1567901 :   kappa = i;
    1962     6927721 :   for (i=zeros+1; i<=d; i++) alpha[i]=1;
    1963             : 
    1964     6153907 :   while (++kappa <= d)
    1965             :   {
    1966     4585972 :     if (kappa > kappamax)
    1967             :     {
    1968     3791935 :       if (DEBUGLEVEL>=4) err_printf("K%ld ",kappa);
    1969     3791935 :       kappamax = kappa;
    1970     3791935 :       if (incgram)
    1971             :       {
    1972    15911308 :         for (i=zeros+1; i<=kappa; i++)
    1973    12318931 :           gmael(G,kappa,i) = ZV_dotproduct(gel(B,kappa), gel(B,i));
    1974     3592377 :         maxG = kappamax;
    1975             :       }
    1976             :     }
    1977             :     /* Step3: Call to the Babai algorithm, mu,r,s updated in place */
    1978     4585728 :     if (Babai_dpe(av, kappa, &G,&B,&U, mu,r,s, alpha[kappa], zeros, maxG, &eta))
    1979           0 :     { *pG = incgram? NULL: G; *pB = B; *pU = U; return -1; }
    1980     9072665 :     if ((keepfirst && kappa == 2) ||
    1981     4486681 :         dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) <= 0)
    1982             :     { /* Step4: Success of Lovasz's condition */
    1983     4260288 :       alpha[kappa] = kappa;
    1984     4260288 :       dpe_submulz(Del(s,kappa-1), Dmael(mu,kappa,kappa-1), Dmael(r,kappa,kappa-1), Dmael(r,kappa,kappa));
    1985     4260293 :       continue;
    1986             :     }
    1987             :     /* Step5: Find the right insertion index kappa, kappa2 = initial kappa */
    1988      325696 :     if (DEBUGLEVEL>=4 && kappa==kappamax && Del(s,kappa-1)->d)
    1989           0 :       if (++cnt > 20) { cnt = 0; err_printf("(%ld) ", Del(s,1)->e-1); }
    1990      325696 :     kappa2 = kappa;
    1991             :     do {
    1992      829201 :       kappa--;
    1993      829201 :       if (kappa < zeros+2 + (keepfirst ? 1: 0)) break;
    1994      707518 :     } while (dpe_cmpmul(Dmael(r,kappa-1,kappa-1), &delta, Del(s,kappa-1)) >= 0);
    1995      325696 :     update_alpha(alpha, kappa, kappa2, kappamax);
    1996             : 
    1997             :     /* Step6: Update the mu's and r's */
    1998      325696 :     dperotate(mu, kappa2, kappa);
    1999      325696 :     dperotate(r, kappa2, kappa);
    2000      325696 :     affdpe(Del(s,kappa), Dmael(r,kappa,kappa));
    2001             : 
    2002             :     /* Step7: Update G, B, U */
    2003      325696 :     if (U) rotate(U, kappa2, kappa);
    2004      325696 :     if (B) rotate(B, kappa2, kappa);
    2005      325696 :     rotateG(G,kappa2,kappa, maxG, Gtmp);
    2006             : 
    2007             :     /* Step8: Prepare the next loop iteration */
    2008      325696 :     if (kappa == zeros+1 && !signe(gmael(G,kappa,kappa)))
    2009             :     {
    2010       35161 :       zeros++; kappa++;
    2011       35161 :       affidpe(gmael(G,kappa,kappa), Dmael(r,kappa,kappa));
    2012             :     }
    2013             :   }
    2014     1567935 :   if (pr) *pr = dpeM_diagonal_shallow(r,d);
    2015     1567935 :   *pG = G; *pB = B; *pU = U; return zeros; /* success */
    2016             : }
    2017             : 
    2018             : 
    2019             : /************************** PROVED version (t_INT) *************************/
    2020             : 
    2021             : /* Babai's Nearest Plane algorithm (iterative).
    2022             :  * Size-reduces b_kappa using mu_{i,j} and r_{i,j} for j<=i <kappa
    2023             :  * Update B[,kappa]; compute mu_{kappa,j}, r_{kappa,j} for j<=kappa and s[kappa]
    2024             :  * mu, r, s updated in place (affrr). Return 1 on failure, else 0. */
    2025             : static int
    2026           0 : Babai(pari_sp av, long kappa, GEN *pG, GEN *pB, GEN *pU, GEN mu, GEN r, GEN s,
    2027             :       long a, long zeros, long maxG, GEN eta, long prec)
    2028             : {
    2029           0 :   GEN G = *pG, B = *pB, U = *pU, ztmp;
    2030           0 :   long k, aa = a > zeros? a: zeros+1;
    2031           0 :   const long n = B? nbrows(B): 0, d = U ? lg(U)-1: 0, bit = prec2nbits(prec);
    2032           0 :   long emaxmu = EX0, emax2mu = EX0;
    2033             :   /* N.B: we set d = 0 (resp. n = 0) to avoid updating U (resp. B) */
    2034             : 
    2035           0 :   for (;;) {
    2036           0 :     int go_on = 0;
    2037           0 :     long i, j, emax3mu = emax2mu;
    2038             : 
    2039           0 :     if (gc_needed(av,2))
    2040             :     {
    2041           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"Babai[1], a=%ld", aa);
    2042           0 :       gc_lll(av,3,&G,&B,&U);
    2043             :     }
    2044             :     /* Step2: compute the GSO for stage kappa */
    2045           0 :     emax2mu = emaxmu; emaxmu = EX0;
    2046           0 :     for (j=aa; j<kappa; j++)
    2047             :     {
    2048           0 :       pari_sp btop = avma;
    2049           0 :       GEN g = gmael(G,kappa,j);
    2050           0 :       for (k = zeros+1; k < j; k++)
    2051           0 :         g = mpsub(g, mulrr(gmael(mu,j,k), gmael(r,kappa,k)));
    2052           0 :       mpaff(g, gmael(r,kappa,j));
    2053           0 :       affrr(divrr(gmael(r,kappa,j), gmael(r,j,j)), gmael(mu,kappa,j));
    2054           0 :       emaxmu = maxss(emaxmu, expo(gmael(mu,kappa,j)));
    2055           0 :       set_avma(btop);
    2056             :     }
    2057           0 :     if (emax3mu != EX0 && emax3mu <= emax2mu + 5) /* precision too low */
    2058           0 :     { *pG = G; *pB = B; *pU = U; return 1; }
    2059             : 
    2060           0 :     for (j=kappa-1; j>zeros; j--)
    2061           0 :       if (abscmprr(gmael(mu,kappa,j), eta) > 0) { go_on = 1; break; }
    2062             : 
    2063             :     /* Step3--5: compute the X_j's  */
    2064           0 :     if (go_on)
    2065           0 :       for (j=kappa-1; j>zeros; j--)
    2066             :       {
    2067             :         pari_sp btop;
    2068           0 :         GEN tmp = gmael(mu,kappa,j);
    2069           0 :         if (absrsmall(tmp)) continue; /* size-reduced */
    2070             : 
    2071           0 :         if (gc_needed(av,2))
    2072             :         {
    2073           0 :           if(DEBUGMEM>1) pari_warn(warnmem,"Babai[2], a=%ld, j=%ld", aa,j);
    2074           0 :           gc_lll(av,3,&G,&B,&U);
    2075             :         }
    2076           0 :         btop = avma;
    2077             :         /* we consider separately the case |X| = 1 */
    2078           0 :         if (absrsmall2(tmp))
    2079             :         {
    2080           0 :           if (signe(tmp) > 0) { /* in this case, X = 1 */
    2081           0 :             for (k=zeros+1; k<j; k++)
    2082           0 :               affrr(subrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2083           0 :             set_avma(btop);
    2084           0 :             for (i=1; i<=n; i++)
    2085           0 :               gmael(B,kappa,i) = subii(gmael(B,kappa,i), gmael(B,j,i));
    2086           0 :             for (i=1; i<=d; i++)
    2087           0 :               gmael(U,kappa,i) = subii(gmael(U,kappa,i), gmael(U,j,i));
    2088           0 :             btop = avma;
    2089           0 :             ztmp = subii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2090           0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2091           0 :             gmael(G,kappa,kappa) = gerepileuptoint(btop, ztmp);
    2092           0 :             for (i=1; i<=j; i++)
    2093           0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,j,i));
    2094           0 :             for (i=j+1; i<kappa; i++)
    2095           0 :               gmael(G,kappa,i) = subii(gmael(G,kappa,i), gmael(G,i,j));
    2096           0 :             for (i=kappa+1; i<=maxG; i++)
    2097           0 :               gmael(G,i,kappa) = subii(gmael(G,i,kappa), gmael(G,i,j));
    2098             :           } else { /* otherwise X = -1 */
    2099           0 :             for (k=zeros+1; k<j; k++)
    2100           0 :               affrr(addrr(gmael(mu,kappa,k), gmael(mu,j,k)), gmael(mu,kappa,k));
    2101           0 :             set_avma(btop);
    2102           0 :             for (i=1; i<=n; i++)
    2103           0 :               gmael(B,kappa,i) = addii(gmael(B,kappa,i),gmael(B,j,i));
    2104           0 :             for (i=1; i<=d; i++)
    2105           0 :               gmael(U,kappa,i) = addii(gmael(U,kappa,i),gmael(U,j,i));
    2106           0 :             btop = avma;
    2107           0 :             ztmp = addii(gmael(G,j,j), shifti(gmael(G,kappa,j), 1));
    2108           0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2109           0 :             gmael(G,kappa,kappa) = gerepileuptoint(btop, ztmp);
    2110           0 :             for (i=1; i<=j; i++)
    2111           0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,j,i));
    2112           0 :             for (i=j+1; i<kappa; i++)
    2113           0 :               gmael(G,kappa,i) = addii(gmael(G,kappa,i), gmael(G,i,j));
    2114           0 :             for (i=kappa+1; i<=maxG; i++)
    2115           0 :               gmael(G,i,kappa) = addii(gmael(G,i,kappa), gmael(G,i,j));
    2116             :           }
    2117           0 :           continue;
    2118             :         }
    2119             :         /* we have |X| >= 2 */
    2120           0 :         if (expo(tmp) < BITS_IN_LONG)
    2121             :         {
    2122           0 :           ulong xx = roundr_safe(tmp)[2]; /* X fits in an ulong */
    2123           0 :           if (signe(tmp) > 0) /* = xx */
    2124             :           {
    2125           0 :             for (k=zeros+1; k<j; k++)
    2126           0 :               affrr(subrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2127           0 :                   gmael(mu,kappa,k));
    2128           0 :             set_avma(btop);
    2129           0 :             for (i=1; i<=n; i++)
    2130           0 :               gmael(B,kappa,i) = submuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2131           0 :             for (i=1; i<=d; i++)
    2132           0 :               gmael(U,kappa,i) = submuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2133           0 :             btop = avma;
    2134           0 :             ztmp = submuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2135           0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2136           0 :             gmael(G,kappa,kappa) = gerepileuptoint(btop, ztmp);
    2137           0 :             for (i=1; i<=j; i++)
    2138           0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2139           0 :             for (i=j+1; i<kappa; i++)
    2140           0 :               gmael(G,kappa,i) = submuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2141           0 :             for (i=kappa+1; i<=maxG; i++)
    2142           0 :               gmael(G,i,kappa) = submuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2143             :           }
    2144             :           else /* = -xx */
    2145             :           {
    2146           0 :             for (k=zeros+1; k<j; k++)
    2147           0 :               affrr(addrr(gmael(mu,kappa,k), mulur(xx, gmael(mu,j,k))),
    2148           0 :                   gmael(mu,kappa,k));
    2149           0 :             set_avma(btop);
    2150           0 :             for (i=1; i<=n; i++)
    2151           0 :               gmael(B,kappa,i) = addmuliu_inplace(gmael(B,kappa,i), gmael(B,j,i), xx);
    2152           0 :             for (i=1; i<=d; i++)
    2153           0 :               gmael(U,kappa,i) = addmuliu_inplace(gmael(U,kappa,i), gmael(U,j,i), xx);
    2154           0 :             btop = avma;
    2155           0 :             ztmp = addmuliu2n(mulii(gmael(G,j,j), sqru(xx)), gmael(G,kappa,j), xx, 1);
    2156           0 :             ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2157           0 :             gmael(G,kappa,kappa) = gerepileuptoint(btop, ztmp);
    2158           0 :             for (i=1; i<=j; i++)
    2159           0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,j,i), xx);
    2160           0 :             for (i=j+1; i<kappa; i++)
    2161           0 :               gmael(G,kappa,i) = addmuliu_inplace(gmael(G,kappa,i), gmael(G,i,j), xx);
    2162           0 :             for (i=kappa+1; i<=maxG; i++)
    2163           0 :               gmael(G,i,kappa) = addmuliu_inplace(gmael(G,i,kappa), gmael(G,i,j), xx);
    2164             :           }
    2165             :         }
    2166             :         else
    2167             :         {
    2168             :           long e;
    2169           0 :           GEN X = truncexpo(tmp, bit, &e); /* tmp ~ X * 2^e */
    2170           0 :           btop = avma;
    2171           0 :           for (k=zeros+1; k<j; k++)
    2172             :           {
    2173           0 :             GEN x = mulir(X, gmael(mu,j,k));
    2174           0 :             if (e) shiftr_inplace(x, e);
    2175           0 :             affrr(subrr(gmael(mu,kappa,k), x), gmael(mu,kappa,k));
    2176             :           }
    2177           0 :           set_avma(btop);
    2178           0 :           for (i=1; i<=n; i++)
    2179           0 :             gmael(B,kappa,i) = submulshift(gmael(B,kappa,i), gmael(B,j,i), X, e);
    2180           0 :           for (i=1; i<=d; i++)
    2181           0 :             gmael(U,kappa,i) = submulshift(gmael(U,kappa,i), gmael(U,j,i), X, e);
    2182           0 :           btop = avma;
    2183           0 :           ztmp = submulshift(mulshift(gmael(G,j,j), sqri(X), 2*e),
    2184           0 :               gmael(G,kappa,j), X, e+1);
    2185           0 :           ztmp = addii(gmael(G,kappa,kappa), ztmp);
    2186           0 :           gmael(G,kappa,kappa) = gerepileuptoint(btop, ztmp);
    2187           0 :           for (i=1; i<=j; i++)
    2188           0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,j,i), X, e);
    2189           0 :           for (   ; i<kappa; i++)
    2190           0 :             gmael(G,kappa,i) = submulshift(gmael(G,kappa,i), gmael(G,i,j), X, e);
    2191           0 :           for (i=kappa+1; i<=maxG; i++)
    2192           0 :             gmael(G,i,kappa) = submulshift(gmael(G,i,kappa), gmael(G,i,j), X, e);
    2193             :         }
    2194             :       }
    2195           0 :     if (!go_on) break; /* Anything happened? */
    2196           0 :     aa = zeros+1;
    2197             :   }
    2198             : 
    2199           0 :   affir(gmael(G,kappa,kappa), gel(s,zeros+1));
    2200             :   /* the last s[kappa-1]=r[kappa][kappa] is computed only if kappa increases */
    2201           0 :   av = avma;
    2202           0 :   for (k=zeros+1; k<=kappa-2; k++)
    2203           0 :     affrr(subrr(gel(s,k), mulrr(gmael(mu,kappa,k), gmael(r,kappa,k))),
    2204           0 :           gel(s,k+1));
    2205           0 :   *pG = G; *pB = B; *pU = U; return gc_bool(av, 0);
    2206             : }
    2207             : 
    2208             : /* G integral Gram matrix, LLL-reduces (G,B,U) in place [apply base change
    2209             :  * transforms to B and U]. If (keepfirst), never swap with first vector.
    2210             :  * If G = NULL, we compute the Gram matrix incrementally.
    2211             :  * Return -1 on failure, else zeros = dim Kernel (>= 0) */
    2212             : static long
    2213           0 : fplll(GEN *pG, GEN *pB, GEN *pU, GEN *pr, double DELTA, double ETA,
    2214             :       long keepfirst, long prec)
    2215             : {
    2216             :   pari_sp av, av2;
    2217           0 :   GEN mu, r, s, tmp, Gtmp, alpha, G = *pG, B = *pB, U = *pU;
    2218           0 :   GEN delta = dbltor(DELTA), eta = dbltor(ETA);
    2219           0 :   long d, maxG, kappa, kappa2, i, j, zeros, kappamax, incgram = !G, cnt = 0;
    2220             : 
    2221           0 :   if (incgram)
    2222             :   { /* incremental Gram matrix */
    2223           0 :     maxG = 2; d = lg(B)-1;
    2224           0 :     G = zeromatcopy(d, d);
    2225             :   }
    2226             :   else
    2227           0 :     maxG = d = lg(G)-1;
    2228             : 
    2229           0 :   mu = cgetg(d+1, t_MAT);
    2230           0 :   r  = cgetg(d+1, t_MAT);
    2231           0 :   s  = cgetg(d+1, t_VEC);
    2232           0 :   for (j = 1; j <= d; j++)
    2233             :   {
    2234           0 :     GEN M = cgetg(d+1, t_COL), R = cgetg(d+1, t_COL);
    2235           0 :     gel(mu,j)= M;
    2236           0 :     gel(r,j) = R;
    2237           0 :     gel(s,j) = cgetr(prec);
    2238           0 :     for (i = 1; i <= d; i++)
    2239             :     {
    2240           0 :       gel(R,i) = cgetr(prec);
    2241           0 :       gel(M,i) = cgetr(prec);
    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     4701053 : ZM2_lll_norms(GEN x, long flag, GEN *pN)
    2320             : {
    2321             :   GEN a,b,c,d;
    2322             :   GEN G, U;
    2323     4701053 :   if (flag & LLL_GRAM)
    2324        7355 :     G = x;
    2325             :   else
    2326     4693698 :     G = gram_matrix(x);
    2327     4701040 :   a = gcoeff(G,1,1); b = shifti(gcoeff(G,1,2),1); c = gcoeff(G,2,2);
    2328     4701000 :   d = qfb_disc3(a,b,c);
    2329     4700971 :   if (signe(d)>=0) return NULL;
    2330     4700586 :   G = redimagsl2(mkqfb(a,b,c,d),&U);
    2331     4700673 :   if (pN) (void) RgM_gram_schmidt(G, pN);
    2332     4700673 :   if (flag & LLL_INPLACE) return ZM2_mul(x,U);
    2333     4700673 :   return U;
    2334             : }
    2335             : 
    2336             : static void
    2337      617338 : fplll_flatter(GEN *pG, GEN *pB, GEN *pU, long rank, long flag)
    2338             : {
    2339      617338 :   if (!*pG)
    2340             :   {
    2341      616377 :     GEN T = ZM_flatter_rank(*pB, rank, flag);
    2342      616378 :     if (T)
    2343             :     {
    2344      327016 :       if (*pU)
    2345             :       {
    2346      313015 :         *pU = ZM_mul(*pU, T);
    2347      313015 :         *pB = ZM_mul(*pB, T);
    2348             :       }
    2349       14001 :       else *pB = T;
    2350             :     }
    2351             :   }
    2352             :   else
    2353             :   {
    2354         961 :     GEN T, G = *pG;
    2355         961 :     long i, j, l = lg(G);
    2356        7207 :     for (i = 1; i < l; i++)
    2357       43383 :       for(j = 1; j < i; j++) gmael(G,j,i) = gmael(G,i,j);
    2358         961 :     T = ZM_flattergram_rank(G, rank, flag);
    2359         961 :     if (T)
    2360             :     {
    2361         961 :       if (*pU) *pU = ZM_mul(*pU, T);
    2362         961 :       *pG = qf_ZM_apply(*pG, T);
    2363             :     }
    2364             :   }
    2365      617339 : }
    2366             : 
    2367             : static GEN
    2368     1082659 : get_gramschmidt(GEN M, long rank)
    2369             : {
    2370             :   GEN B, Q, L;
    2371     1082659 :   long r = lg(M)-1, bitprec = 3*r + 30;
    2372     1082659 :   long prec = nbits2prec64(bitprec);
    2373     1082659 :   if (rank < r) M = vconcat(gshift(M,1), matid(r));
    2374     1082660 :   if (!QR_init(RgM_gtofp(M, prec), &B, &Q, &L, prec) || !gsisinv(L)) return NULL;
    2375      467351 :   return L;
    2376             : }
    2377             : 
    2378             : static GEN
    2379       44259 : get_gaussred(GEN M, long rank)
    2380             : {
    2381       44259 :   pari_sp ltop = avma;
    2382       44259 :   long r = lg(M)-1, bitprec = 3*r + 30, prec = nbits2prec64(bitprec);
    2383             :   GEN R;
    2384       44259 :   if (rank < r) M = RgM_Rg_add(gshift(M, 1), gen_1);
    2385       44259 :   R = RgM_Cholesky(RgM_gtofp(M, prec), prec);
    2386       44259 :   if (!R) return NULL;
    2387       43298 :   return gerepilecopy(ltop, R);
    2388             : }
    2389             : 
    2390             : /* Assume x a ZM, if pN != NULL, set it to Gram-Schmidt (squared) norms
    2391             :  * The following modes are supported:
    2392             :  * - flag & LLL_INPLACE: x a lattice basis, return x*U
    2393             :  * - flag & LLL_GRAM: x a Gram matrix / else x a lattice basis; return
    2394             :  *     LLL base change matrix U [LLL_IM]
    2395             :  *     kernel basis [LLL_KER, nonreduced]
    2396             :  *     both [LLL_ALL] */
    2397             : GEN
    2398     6954146 : ZM_lll_norms(GEN x, double DELTA, long flag, GEN *pN)
    2399             : {
    2400     6954146 :   pari_sp av = avma;
    2401     6954146 :   const double ETA = 0.51;
    2402     6954146 :   const long keepfirst = flag & LLL_KEEP_FIRST;
    2403     6954146 :   long p, zeros = -1, n = lg(x)-1, is_upper, is_lower, useflatter = 0, rank;
    2404     6954146 :   GEN G, B, U, L = NULL;
    2405             :   pari_timer T;
    2406     6954146 :   long thre[]={31783,34393,20894,22525,13533,1928,672,671,
    2407             :                 422,506,315,313,222,205,167,154,139,138,
    2408             :                 110,120,98,94,81,75,74,64,74,74,
    2409             :                 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,
    2410             :                 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};
    2411     6954146 :   long thsn[]={23280,30486,50077,44136,78724,15690,1801,1611,
    2412             :                981,1359,978,1042,815,866,788,775,726,712,
    2413             :                626,613,548,564,474,481,504,447,453,508,
    2414             :                705,794,1008,946,767,898,886,763,842,757,
    2415             :                725,774,639,655,705,627,635,704,511,613,
    2416             :                583,595,568,640,541,640,567,540,577,584,
    2417             :                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};
    2418     6954146 :   if (n <= 1) return lll_trivial(x, flag);
    2419     6844709 :   if (nbrows(x)==0)
    2420             :   {
    2421       15172 :     if (flag & LLL_KER) return matid(n);
    2422       15172 :     if (flag & (LLL_INPLACE|LLL_IM)) return cgetg(1,t_MAT);
    2423           0 :     retmkvec2(matid(n), cgetg(1,t_MAT));
    2424             :   }
    2425     6829705 :   if (n==2 && nbrows(x)==2  && (flag&LLL_IM) && !keepfirst)
    2426             :   {
    2427     4701053 :     U = ZM2_lll_norms(x, flag, pN);
    2428     4701058 :     if (U) return U;
    2429             :   }
    2430     2129031 :   if (flag & LLL_GRAM)
    2431       60275 :   { G = x; B = NULL; U = matid(n); is_upper = 0; is_lower = 0; }
    2432             :   else
    2433             :   {
    2434     2068756 :     G = NULL; B = x; U = (flag & LLL_INPLACE)? NULL: matid(n);
    2435     2068760 :     is_upper = (flag & LLL_UPPER) || ZM_is_upper(B);
    2436     2068760 :     is_lower = !B || is_upper || keepfirst ? 0: ZM_is_lower(B);
    2437     2068759 :     if (is_lower) L = RgM_flip(B);
    2438             :   }
    2439     2129034 :   rank = (flag&LLL_NOFLATTER) ? 0: ZM_rank(x);
    2440     2129026 :   if (n > 2 && !(flag&LLL_NOFLATTER))
    2441     1733112 :   {
    2442     1688855 :     GEN R = B ? (is_upper ? B : (is_lower ? L : get_gramschmidt(B, rank)))
    2443     3421957 :               : get_gaussred(G, rank);
    2444     1733106 :     if (R)
    2445             :     {
    2446     1116846 :       long spr = spread(R), sz = mpexpo(gsupnorm(R, DEFAULTPREC)), thr;
    2447     1116852 :       if (DEBUGLEVEL>=5) err_printf("LLL: dim %ld, size %ld, spread %ld\n",n, sz, spr);
    2448     1116852 :       if ((is_upper && ZM_is_knapsack(B)) || (is_lower && ZM_is_knapsack(L)))
    2449       92365 :         thr = thsn[minss(n-3,numberof(thsn)-1)];
    2450             :       else
    2451             :       {
    2452     1024487 :         thr = thre[minss(n-3,numberof(thre)-1)];
    2453     1024487 :         if (n>=10) sz = spr;
    2454             :       }
    2455     1116852 :       useflatter = sz >= thr;
    2456             :     } else
    2457      616260 :       useflatter = 1;
    2458      395912 :   } else useflatter = 0;
    2459     2129024 :   if(DEBUGLEVEL>=4) timer_start(&T);
    2460     2129024 :   if (useflatter)
    2461             :   {
    2462      617338 :     if (is_lower)
    2463             :     {
    2464           0 :       fplll_flatter(&G, &L, &U, rank, flag | LLL_UPPER);
    2465           0 :       B = RgM_flop(L);
    2466           0 :       if (U) U = RgM_flop(U);
    2467             :     }
    2468             :     else
    2469      617338 :       fplll_flatter(&G, &B, &U, rank, flag | (is_upper? LLL_UPPER:0));
    2470      617338 :     if (DEBUGLEVEL>=4  && !(flag & LLL_NOCERTIFY))
    2471           0 :       timer_printf(&T, "FLATTER");
    2472             :   }
    2473     2129024 :   if (!(flag & LLL_GRAM))
    2474             :   {
    2475             :     long t;
    2476     2068750 :     B = gcopy(B);
    2477     2068754 :     if(DEBUGLEVEL>=4)
    2478           0 :       err_printf("Entering L^2 (double): dim %ld, LLL-parameters (%.3f,%.3f)\n",
    2479             :                  n, DELTA,ETA);
    2480     2068754 :     zeros = fplll_fast(&B, &U, DELTA, ETA, keepfirst);
    2481     2068761 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2482     2072898 :     for (p = DEFAULTPREC, t = 0; zeros < 0 && t < 1 ; p += EXTRAPREC64, t++)
    2483             :     {
    2484        4137 :       if (DEBUGLEVEL>=4)
    2485           0 :         err_printf("Entering L^2 (heuristic): LLL-parameters (%.3f,%.3f), prec = %d/%d\n", DELTA, ETA, p, p);
    2486        4137 :       zeros = fplll_heuristic(&B, &U, DELTA, ETA, keepfirst, p, p);
    2487        4137 :       gc_lll(av, 2, &B, &U);
    2488        4137 :       if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2489             :     }
    2490             :   } else
    2491       60274 :     G = gcopy(G);
    2492     2129035 :   if (zeros < 0 || !(flag & LLL_NOCERTIFY))
    2493             :   {
    2494     1567948 :     if(DEBUGLEVEL>=4)
    2495           0 :       err_printf("Entering L^2 (dpe): LLL-parameters (%.3f,%.3f)\n", DELTA,ETA);
    2496     1567948 :     zeros = fplll_dpe(&G, &B, &U, pN, DELTA, ETA, keepfirst);
    2497     1567934 :     if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2498     1567938 :     if (zeros < 0)
    2499           0 :       for (p = DEFAULTPREC;; p += EXTRAPREC64)
    2500             :       {
    2501           0 :         if (DEBUGLEVEL>=4)
    2502           0 :           err_printf("Entering L^2: LLL-parameters (%.3f,%.3f), prec = %d\n",
    2503             :               DELTA,ETA, p);
    2504           0 :         zeros = fplll(&G, &B, &U, pN, DELTA, ETA, keepfirst, p);
    2505           0 :         if (DEBUGLEVEL>=4) timer_printf(&T, zeros < 0? "LLL (failed)": "LLL");
    2506           0 :         if (zeros >= 0) break;
    2507           0 :         gc_lll(av, 3, &G, &B, &U);
    2508             :       }
    2509             :   }
    2510     2129025 :   return lll_finish(U? U: B, zeros, flag);
    2511             : }
    2512             : 
    2513             : /********************************************************************/
    2514             : /**                                                                **/
    2515             : /**                        LLL OVER K[X]                           **/
    2516             : /**                                                                **/
    2517             : /********************************************************************/
    2518             : static int
    2519         504 : pslg(GEN x)
    2520             : {
    2521             :   long tx;
    2522         504 :   if (gequal0(x)) return 2;
    2523         448 :   tx = typ(x); return is_scalar_t(tx)? 3: lg(x);
    2524             : }
    2525             : 
    2526             : static int
    2527         196 : REDgen(long k, long l, GEN h, GEN L, GEN B)
    2528             : {
    2529         196 :   GEN q, u = gcoeff(L,k,l);
    2530             :   long i;
    2531             : 
    2532         196 :   if (pslg(u) < pslg(B)) return 0;
    2533             : 
    2534         140 :   q = gneg(gdeuc(u,B));
    2535         140 :   gel(h,k) = gadd(gel(h,k), gmul(q,gel(h,l)));
    2536         140 :   for (i=1; i<l; i++) gcoeff(L,k,i) = gadd(gcoeff(L,k,i), gmul(q,gcoeff(L,l,i)));
    2537         140 :   gcoeff(L,k,l) = gadd(gcoeff(L,k,l), gmul(q,B)); return 1;
    2538             : }
    2539             : 
    2540             : static int
    2541         196 : do_SWAPgen(GEN h, GEN L, GEN B, long k, GEN fl, int *flc)
    2542             : {
    2543             :   GEN p1, la, la2, Bk;
    2544             :   long ps1, ps2, i, j, lx;
    2545             : 
    2546         196 :   if (!fl[k-1]) return 0;
    2547             : 
    2548         140 :   la = gcoeff(L,k,k-1); la2 = gsqr(la);
    2549         140 :   Bk = gel(B,k);
    2550         140 :   if (fl[k])
    2551             :   {
    2552          56 :     GEN q = gadd(la2, gmul(gel(B,k-1),gel(B,k+1)));
    2553          56 :     ps1 = pslg(gsqr(Bk));
    2554          56 :     ps2 = pslg(q);
    2555          56 :     if (ps1 <= ps2 && (ps1 < ps2 || !*flc)) return 0;
    2556          28 :     *flc = (ps1 != ps2);
    2557          28 :     gel(B,k) = gdiv(q, Bk);
    2558             :   }
    2559             : 
    2560         112 :   swap(gel(h,k-1), gel(h,k)); lx = lg(L);
    2561         112 :   for (j=1; j<k-1; j++) swap(gcoeff(L,k-1,j), gcoeff(L,k,j));
    2562         112 :   if (fl[k])
    2563             :   {
    2564          28 :     for (i=k+1; i<lx; i++)
    2565             :     {
    2566           0 :       GEN t = gcoeff(L,i,k);
    2567           0 :       p1 = gsub(gmul(gel(B,k+1),gcoeff(L,i,k-1)), gmul(la,t));
    2568           0 :       gcoeff(L,i,k) = gdiv(p1, Bk);
    2569           0 :       p1 = gadd(gmul(la,gcoeff(L,i,k-1)), gmul(gel(B,k-1),t));
    2570           0 :       gcoeff(L,i,k-1) = gdiv(p1, Bk);
    2571             :     }
    2572             :   }
    2573          84 :   else if (!gequal0(la))
    2574             :   {
    2575          28 :     p1 = gdiv(la2, Bk);
    2576          28 :     gel(B,k+1) = gel(B,k) = p1;
    2577          28 :     for (i=k+2; i<=lx; i++) gel(B,i) = gdiv(gmul(p1,gel(B,i)),Bk);
    2578          28 :     for (i=k+1; i<lx; i++)
    2579           0 :       gcoeff(L,i,k-1) = gdiv(gmul(la,gcoeff(L,i,k-1)), Bk);
    2580          28 :     for (j=k+1; j<lx-1; j++)
    2581           0 :       for (i=j+1; i<lx; i++)
    2582           0 :         gcoeff(L,i,j) = gdiv(gmul(p1,gcoeff(L,i,j)), Bk);
    2583             :   }
    2584             :   else
    2585             :   {
    2586          56 :     gcoeff(L,k,k-1) = gen_0;
    2587          56 :     for (i=k+1; i<lx; i++)
    2588             :     {
    2589           0 :       gcoeff(L,i,k) = gcoeff(L,i,k-1);
    2590           0 :       gcoeff(L,i,k-1) = gen_0;
    2591             :     }
    2592          56 :     gel(B,k) = gel(B,k-1); fl[k] = 1; fl[k-1] = 0;
    2593             :   }
    2594         112 :   return 1;
    2595             : }
    2596             : 
    2597             : static void
    2598         168 : incrementalGSgen(GEN x, GEN L, GEN B, long k, GEN fl)
    2599             : {
    2600         168 :   GEN u = NULL; /* gcc -Wall */
    2601             :   long i, j;
    2602         420 :   for (j = 1; j <= k; j++)
    2603         252 :     if (j==k || fl[j])
    2604             :     {
    2605         252 :       u = gcoeff(x,k,j);
    2606         252 :       if (!is_extscalar_t(typ(u))) pari_err_TYPE("incrementalGSgen",u);
    2607         336 :       for (i=1; i<j; i++)
    2608          84 :         if (fl[i])
    2609             :         {
    2610          84 :           u = gsub(gmul(gel(B,i+1),u), gmul(gcoeff(L,k,i),gcoeff(L,j,i)));
    2611          84 :           u = gdiv(u, gel(B,i));
    2612             :         }
    2613         252 :       gcoeff(L,k,j) = u;
    2614             :     }
    2615         168 :   if (gequal0(u)) gel(B,k+1) = gel(B,k);
    2616             :   else
    2617             :   {
    2618         112 :     gel(B,k+1) = gcoeff(L,k,k); gcoeff(L,k,k) = gen_1; fl[k] = 1;
    2619             :   }
    2620         168 : }
    2621             : 
    2622             : static GEN
    2623         168 : lllgramallgen(GEN x, long flag)
    2624             : {
    2625         168 :   long lx = lg(x), i, j, k, l, n;
    2626             :   pari_sp av;
    2627             :   GEN B, L, h, fl;
    2628             :   int flc;
    2629             : 
    2630         168 :   n = lx-1; if (n<=1) return lll_trivial(x,flag);
    2631          84 :   if (lgcols(x) != lx) pari_err_DIM("lllgramallgen");
    2632             : 
    2633          84 :   fl = cgetg(lx, t_VECSMALL);
    2634             : 
    2635          84 :   av = avma;
    2636          84 :   B = scalarcol_shallow(gen_1, lx);
    2637          84 :   L = cgetg(lx,t_MAT);
    2638         252 :   for (j=1; j<lx; j++) { gel(L,j) = zerocol(n); fl[j] = 0; }
    2639             : 
    2640          84 :   h = matid(n);
    2641         252 :   for (i=1; i<lx; i++)
    2642         168 :     incrementalGSgen(x, L, B, i, fl);
    2643          84 :   flc = 0;
    2644          84 :   for(k=2;;)
    2645             :   {
    2646         196 :     if (REDgen(k, k-1, h, L, gel(B,k))) flc = 1;
    2647         196 :     if (do_SWAPgen(h, L, B, k, fl, &flc)) { if (k > 2) k--; }
    2648             :     else
    2649             :     {
    2650          84 :       for (l=k-2; l>=1; l--)
    2651           0 :         if (REDgen(k, l, h, L, gel(B,l+1))) flc = 1;
    2652          84 :       if (++k > n) break;
    2653             :     }
    2654         112 :     if (gc_needed(av,1))
    2655             :     {
    2656           0 :       if(DEBUGMEM>1) pari_warn(warnmem,"lllgramallgen");
    2657           0 :       gerepileall(av,3,&B,&L,&h);
    2658             :     }
    2659             :   }
    2660         140 :   k=1; while (k<lx && !fl[k]) k++;
    2661          84 :   return lll_finish(h,k-1,flag);
    2662             : }
    2663             : 
    2664             : static GEN
    2665         168 : lllallgen(GEN x, long flag)
    2666             : {
    2667         168 :   pari_sp av = avma;
    2668         168 :   if (!(flag & LLL_GRAM)) x = gram_matrix(x);
    2669          84 :   else if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2670         168 :   return gerepilecopy(av, lllgramallgen(x, flag));
    2671             : }
    2672             : GEN
    2673          42 : lllgen(GEN x) { return lllallgen(x, LLL_IM); }
    2674             : GEN
    2675          42 : lllkerimgen(GEN x) { return lllallgen(x, LLL_ALL); }
    2676             : GEN
    2677          42 : lllgramgen(GEN x)  { return lllallgen(x, LLL_IM|LLL_GRAM); }
    2678             : GEN
    2679          42 : lllgramkerimgen(GEN x)  { return lllallgen(x, LLL_ALL|LLL_GRAM); }
    2680             : 
    2681             : static GEN
    2682       36699 : lllall(GEN x, long flag)
    2683       36699 : { pari_sp av = avma; return gerepilecopy(av, ZM_lll(x, LLLDFT, flag)); }
    2684             : GEN
    2685         183 : lllint(GEN x) { return lllall(x, LLL_IM); }
    2686             : GEN
    2687          35 : lllkerim(GEN x) { return lllall(x, LLL_ALL); }
    2688             : GEN
    2689       36439 : lllgramint(GEN x)
    2690       36439 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2691       36439 :   return lllall(x, LLL_IM | LLL_GRAM); }
    2692             : GEN
    2693          35 : lllgramkerim(GEN x)
    2694          35 : { if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2695          35 :   return lllall(x, LLL_ALL | LLL_GRAM); }
    2696             : 
    2697             : GEN
    2698     5269048 : lllfp(GEN x, double D, long flag)
    2699             : {
    2700     5269048 :   long n = lg(x)-1;
    2701     5269048 :   pari_sp av = avma;
    2702             :   GEN h;
    2703     5269048 :   if (n <= 1) return lll_trivial(x,flag);
    2704     4608649 :   if (flag & LLL_GRAM)
    2705             :   {
    2706        9270 :     if (!RgM_is_square_mat(x)) pari_err_DIM("qflllgram");
    2707        9256 :     if (isinexact(x))
    2708             :     {
    2709        9165 :       x = RgM_Cholesky(x, gprecision(x));
    2710        9165 :       if (!x) return NULL;
    2711        9165 :       flag &= ~LLL_GRAM;
    2712             :     }
    2713             :   }
    2714     4608635 :   h = ZM_lll(RgM_rescale_to_int(x), D, flag);
    2715     4608584 :   return gerepilecopy(av, h);
    2716             : }
    2717             : 
    2718             : GEN
    2719        9089 : lllgram(GEN x) { return lllfp(x,LLLDFT,LLL_GRAM|LLL_IM); }
    2720             : GEN
    2721     1175019 : lll(GEN x) { return lllfp(x,LLLDFT,LLL_IM); }
    2722             : 
    2723             : static GEN
    2724          63 : qflllgram(GEN x)
    2725             : {
    2726          63 :   GEN T = lllgram(x);
    2727          42 :   if (!T) pari_err_PREC("qflllgram");
    2728          42 :   return T;
    2729             : }
    2730             : 
    2731             : GEN
    2732         301 : qflll0(GEN x, long flag)
    2733             : {
    2734         301 :   if (typ(x) != t_MAT) pari_err_TYPE("qflll",x);
    2735         301 :   switch(flag)
    2736             :   {
    2737          49 :     case 0: return lll(x);
    2738          63 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_NOFLATTER);
    2739          49 :     case 2: RgM_check_ZM(x,"qflll"); return lllintpartial(x);
    2740           7 :     case 3: RgM_check_ZM(x,"qflll"); return lllall(x, LLL_INPLACE);
    2741          49 :     case 4: RgM_check_ZM(x,"qflll"); return lllkerim(x);
    2742          42 :     case 5: return lllkerimgen(x);
    2743          42 :     case 8: return lllgen(x);
    2744           0 :     default: pari_err_FLAG("qflll");
    2745             :   }
    2746             :   return NULL; /* LCOV_EXCL_LINE */
    2747             : }
    2748             : 
    2749             : GEN
    2750         245 : qflllgram0(GEN x, long flag)
    2751             : {
    2752         245 :   if (typ(x) != t_MAT) pari_err_TYPE("qflllgram",x);
    2753         245 :   switch(flag)
    2754             :   {
    2755          63 :     case 0: return qflllgram(x);
    2756          49 :     case 1: return lllfp(x, LLLDFT, LLL_IM | LLL_GRAM | LLL_NOFLATTER);
    2757          49 :     case 4: RgM_check_ZM(x,"qflllgram"); return lllgramkerim(x);
    2758          42 :     case 5: return lllgramkerimgen(x);
    2759          42 :     case 8: return lllgramgen(x);
    2760           0 :     default: pari_err_FLAG("qflllgram");
    2761             :   }
    2762             :   return NULL; /* LCOV_EXCL_LINE */
    2763             : }
    2764             : 
    2765             : /********************************************************************/
    2766             : /**                                                                **/
    2767             : /**                   INTEGRAL KERNEL (LLL REDUCED)                **/
    2768             : /**                                                                **/
    2769             : /********************************************************************/
    2770             : static GEN
    2771          70 : kerint0(GEN M)
    2772             : {
    2773             :   /* return ZM_lll(M, LLLDFT, LLL_KER); */
    2774          70 :   GEN U, H = ZM_hnflll(M,&U,1);
    2775          70 :   long d = lg(M)-lg(H);
    2776          70 :   if (!d) return cgetg(1, t_MAT);
    2777          70 :   return ZM_lll(vecslice(U,1,d), LLLDFT, LLL_INPLACE);
    2778             : }
    2779             : GEN
    2780          42 : kerint(GEN M)
    2781             : {
    2782          42 :   pari_sp av = avma;
    2783          42 :   return gerepilecopy(av, kerint0(M));
    2784             : }
    2785             : /* OBSOLETE: use kerint */
    2786             : GEN
    2787          28 : matkerint0(GEN M, long flag)
    2788             : {
    2789          28 :   pari_sp av = avma;
    2790          28 :   if (typ(M) != t_MAT) pari_err_TYPE("matkerint",M);
    2791          28 :   M = Q_primpart(M);
    2792          28 :   RgM_check_ZM(M, "kerint");
    2793          28 :   switch(flag)
    2794             :   {
    2795          28 :     case 0:
    2796          28 :     case 1: return gerepilecopy(av, kerint0(M));
    2797           0 :     default: pari_err_FLAG("matkerint");
    2798             :   }
    2799             :   return NULL; /* LCOV_EXCL_LINE */
    2800             : }

Generated by: LCOV version 1.16