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