source: git/ntl/src/LLL.c @ 287cc8

spielwiese
Last change on this file since 287cc8 was 287cc8, checked in by Hans Schönemann <hannes@…>, 14 years ago
ntl 5.5.2 git-svn-id: file:///usr/local/Singular/svn/trunk@12402 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 12.1 KB
Line 
1
2#include <NTL/LLL.h>
3
4#include <NTL/new.h>
5
6NTL_START_IMPL
7
8
9static void ExactDiv(ZZ& qq, const ZZ& a, const ZZ& b)
10{
11   static ZZ q, r;
12
13   DivRem(q, r, a, b);
14   if (!IsZero(r)) {
15      Error("ExactDiv: nonzero remainder");
16   }
17   qq = q;
18}
19
20
21static void BalDiv(ZZ& q, const ZZ& a, const ZZ& d)
22
23//  rounds a/d to nearest integer, breaking ties
24//    by rounding towards zero.  Assumes d > 0.
25
26{
27   static ZZ r;
28   DivRem(q, r, a, d);
29
30
31   add(r, r, r);
32
33   long cmp = compare(r, d);
34   if (cmp > 0 || (cmp == 0 && q < 0))
35      add(q, q, 1);
36}
37
38
39
40static void MulAddDiv(ZZ& c, const ZZ& c1, const ZZ& c2,
41                      const ZZ& x, const ZZ& y, const ZZ& z)
42
43// c = (x*c1 + y*c2)/z
44
45{
46   static ZZ t1, t2;
47
48   mul(t1, x, c1);
49   mul(t2, y, c2);
50   add(t1, t1, t2);
51   ExactDiv(c, t1, z);
52}
53
54
55static void MulSubDiv(ZZ& c, const ZZ& c1, const ZZ& c2,
56                      const ZZ& x, const ZZ& y, const ZZ& z)
57
58// c = (x*c1 - y*c2)/z
59
60{
61   static ZZ t1, t2;
62
63   mul(t1, x, c1);
64   mul(t2, y, c2);
65   sub(t1, t1, t2);
66   ExactDiv(c, t1, z);
67}
68
69
70
71
72
73#if 0
74
75static void MulSubDiv(vec_ZZ& c, const vec_ZZ& c1, const vec_ZZ& c2,
76                      const ZZ& x, const ZZ& y, const ZZ& z)
77
78// c = (x*c1 + y*c2)/z
79
80{
81   long n = c1.length();
82   if (c2.length() != n) Error("MulSubDiv: length mismatch");
83   c.SetLength(n);
84
85   long i;
86   for (i = 1; i <= n; i++)
87      MulSubDiv(c(i), c1(i), c2(i), x, y, z);
88}
89
90#endif
91
92static void RowTransform(vec_ZZ& c1, vec_ZZ& c2,
93                         const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v)
94
95// (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2)
96
97{
98   long n = c1.length();
99   if (c2.length() != n) Error("MulSubDiv: length mismatch");
100   static ZZ t1, t2, t3, t4;
101
102   long i;
103   for (i = 1; i <= n; i++) {
104      mul(t1, x, c1(i));
105      mul(t2, y, c2(i));
106      add(t1, t1, t2);
107
108      mul(t3, u, c1(i));
109      mul(t4, v, c2(i));
110      add(t3, t3, t4);
111
112      c1(i) = t1;
113      c2(i) = t3;
114   }
115}
116
117static void RowTransform(ZZ& c1, ZZ& c2,
118                         const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v)
119
120// (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2)
121
122{
123   static ZZ t1, t2, t3, t4;
124
125   mul(t1, x, c1);
126   mul(t2, y, c2);
127   add(t1, t1, t2);
128
129   mul(t3, u, c1);
130   mul(t4, v, c2);
131   add(t3, t3, t4);
132
133   c1 = t1;
134   c2 = t3;
135}
136
137
138
139static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, const ZZ& x)
140
141// c = c - x*c2
142
143{
144   long n = c.length();
145   if (c2.length() != n) Error("MulSubFrom: length mismatch");
146
147   long i;
148   for (i = 1; i <= n; i++)
149      MulSubFrom(c(i), c2(i), x);
150}
151
152static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, long x)
153
154// c = c - x*c2
155
156{
157   long n = c.length();
158   if (c2.length() != n) Error("MulSubFrom: length mismatch");
159
160   long i;
161   for (i = 1; i <= n; i++)
162      MulSubFrom(c(i), c2(i), x);
163}
164
165
166
167
168
169static long SwapTest(const ZZ& d0, const ZZ& d1, const ZZ& d2, const ZZ& lam,
170                     long a, long b)
171
172// test if a*d1^2 > b*(d0*d2 + lam^2)
173
174{
175   static ZZ t1, t2;
176
177   mul(t1, d0, d2);
178   sqr(t2, lam);
179   add(t1, t1, t2);
180   mul(t1, t1, b);
181
182   sqr(t2, d1);
183   mul(t2, t2, a);
184
185   return t2 > t1;
186}
187
188
189
190
191
192
193static
194void reduce(long k, long l,
195            mat_ZZ& B, vec_long& P, vec_ZZ& D,
196            vec_vec_ZZ& lam, mat_ZZ* U)
197{
198   static ZZ t1;
199   static ZZ r;
200
201   if (P(l) == 0) return;
202   add(t1, lam(k)(P(l)), lam(k)(P(l)));
203   abs(t1, t1);
204   if (t1 <= D[P(l)]) return;
205
206   long j;
207   long rr, small_r;
208
209   BalDiv(r, lam(k)(P(l)), D[P(l)]);
210
211   if (r.WideSinglePrecision()) {
212      small_r = 1;
213      rr = to_long(r);
214   }
215   else {
216      small_r = 0;
217   }
218
219   if (small_r) {
220      MulSubFrom(B(k), B(l), rr);
221
222      if (U) MulSubFrom((*U)(k), (*U)(l), rr);
223
224      for (j = 1; j <= l-1; j++)
225         if (P(j) != 0)
226            MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), rr);
227      MulSubFrom(lam(k)(P(l)), D[P(l)], rr);
228   }
229   else {
230      MulSubFrom(B(k), B(l), r);
231
232      if (U) MulSubFrom((*U)(k), (*U)(l), r);
233
234      for (j = 1; j <= l-1; j++)
235         if (P(j) != 0)
236            MulSubFrom(lam(k)(P(j)), lam(l)(P(j)), r);
237      MulSubFrom(lam(k)(P(l)), D[P(l)], r);
238   }
239
240
241}
242
243
244static
245long swap(long k, mat_ZZ& B, vec_long& P, vec_ZZ& D,
246          vec_vec_ZZ& lam, mat_ZZ* U, long m, long verbose)
247
248// swaps vectors k-1 and k;  assumes P(k-1) != 0
249// returns 1 if vector k-1 need to be reduced after the swap...
250//    this only occurs in 'case 2' when there are linear dependencies
251
252{
253   long i, j;
254   static ZZ t1, t2, t3, e, x, y;
255
256
257   if (P(k) != 0) {
258
259      swap(B(k-1), B(k));
260      if (U) swap((*U)(k-1), (*U)(k));
261
262      for (j = 1; j <= k-2; j++)
263         if (P(j) != 0)
264            swap(lam(k-1)(P(j)), lam(k)(P(j)));
265
266      for (i = k+1; i <= m; i++) {
267         MulAddDiv(t1, lam(i)(P(k)-1), lam(i)(P(k)),
268                   lam(k)(P(k)-1), D[P(k)-2], D[P(k)-1]);
269         MulSubDiv(t2, lam(i)(P(k)-1), lam(i)(P(k)),
270                   D[P(k)], lam(k)(P(k)-1), D[P(k)-1]);
271         lam(i)(P(k)-1) = t1;
272         lam(i)(P(k)) = t2;
273      }
274
275      MulAddDiv(D[P(k)-1], D[P(k)], lam(k)(P(k)-1),
276                D[P(k)-2], lam(k)(P(k)-1), D[P(k)-1]);
277
278      return 0;
279   }
280   else if (!IsZero(lam(k)(P(k-1)))) {
281      XGCD(e, x, y, lam(k)(P(k-1)), D[P(k-1)]);
282
283      ExactDiv(t1, lam(k)(P(k-1)), e);
284      ExactDiv(t2, D[P(k-1)], e);
285
286      t3 = t2;
287      negate(t2, t2);
288      RowTransform(B(k-1), B(k), t1, t2, y, x);
289      if (U) RowTransform((*U)(k-1), (*U)(k), t1, t2, y, x);
290      for (j = 1; j <= k-2; j++)
291         if (P(j) != 0)
292            RowTransform(lam(k-1)(P(j)), lam(k)(P(j)), t1, t2, y, x);
293
294      sqr(t2, t2);
295      ExactDiv(D[P(k-1)], D[P(k-1)], t2);
296
297      for (i = k+1; i <= m; i++)
298         if (P(i) != 0) {
299            ExactDiv(D[P(i)], D[P(i)], t2);
300            for (j = i+1; j <= m; j++) {
301               ExactDiv(lam(j)(P(i)), lam(j)(P(i)), t2);
302            }
303         }
304
305      for (i = k+1; i <= m; i++) {
306         ExactDiv(lam(i)(P(k-1)), lam(i)(P(k-1)), t3);
307      }
308
309      swap(P(k-1), P(k));
310
311      return 1;
312   }
313   else {
314      swap(B(k-1), B(k));
315      if (U) swap((*U)(k-1), (*U)(k));
316
317      for (j = 1; j <= k-2; j++)
318         if (P(j) != 0)
319            swap(lam(k-1)(P(j)), lam(k)(P(j)));
320
321      swap(P(k-1), P(k));
322
323      return 0;
324   }
325}
326
327
328
329
330static
331void IncrementalGS(mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam,
332                   long& s, long k)
333{
334   long n = B.NumCols();
335   long m = B.NumRows();
336
337   static ZZ u, t1, t2;
338
339   long i, j;
340
341   for (j = 1; j <= k-1; j++) {
342      long posj = P(j);
343      if (posj == 0) continue;
344
345      InnerProduct(u, B(k), B(j));
346      for (i = 1; i <= posj-1; i++) {
347         mul(t1, D[i], u);
348         mul(t2, lam(k)(i), lam(j)(i));
349         sub(t1, t1, t2);
350         div(t1, t1, D[i-1]);
351         u = t1;
352      }
353
354      lam(k)(posj) = u;
355   }
356
357   InnerProduct(u, B(k), B(k));
358   for (i = 1; i <= s; i++) {
359      mul(t1, D[i], u);
360      mul(t2, lam(k)(i), lam(k)(i));
361      sub(t1, t1, t2);
362      div(t1, t1, D[i-1]);
363      u = t1;
364   }
365
366   if (u == 0) {
367      P(k) = 0;
368   }
369   else {
370      s++;
371      P(k) = s;
372      D[s] = u;
373   }
374}
375
376
377static
378long LLL(vec_ZZ& D, mat_ZZ& B, mat_ZZ* U, long a, long b, long verbose)
379{
380   long m = B.NumRows();
381   long n = B.NumCols();
382
383   long force_reduce = 1;
384
385   vec_long P;
386   P.SetLength(m);
387
388   D.SetLength(m+1);
389   D[0] = 1;
390
391   vec_vec_ZZ lam;
392
393   lam.SetLength(m);
394
395   long j;
396   for (j = 1; j <= m; j++)
397      lam(j).SetLength(m);
398
399   if (U) ident(*U, m);
400
401   long s = 0;
402
403   long k = 1;
404   long max_k = 0;
405
406
407   while (k <= m) {
408      if (k > max_k) {
409         IncrementalGS(B, P, D, lam, s, k);
410         max_k = k;
411      }
412
413      if (k == 1) {
414         force_reduce = 1;
415         k++;
416         continue;
417      }
418
419      if (force_reduce)
420         for (j = k-1; j >= 1; j--)
421            reduce(k, j, B, P, D, lam, U);
422
423      if (P(k-1) != 0 &&
424          (P(k) == 0 ||
425           SwapTest(D[P(k)], D[P(k)-1], D[P(k)-2], lam(k)(P(k)-1), a, b))) {
426         force_reduce = swap(k, B, P, D, lam, U, max_k, verbose);
427         k--;
428      }
429      else {
430         force_reduce = 1;
431         k++;
432      }
433   }
434
435   D.SetLength(s+1);
436   return s;
437}
438
439
440
441static
442long image(ZZ& det, mat_ZZ& B, mat_ZZ* U, long verbose)
443{
444   long m = B.NumRows();
445   long n = B.NumCols();
446
447   long force_reduce = 1;
448
449   vec_long P;
450   P.SetLength(m);
451
452   vec_ZZ D;
453   D.SetLength(m+1);
454   D[0] = 1;
455
456   vec_vec_ZZ lam;
457
458   lam.SetLength(m);
459
460   long j;
461   for (j = 1; j <= m; j++)
462      lam(j).SetLength(m);
463
464   if (U) ident(*U, m);
465
466   long s = 0;
467
468   long k = 1;
469   long max_k = 0;
470
471
472   while (k <= m) {
473      if (k > max_k) {
474         IncrementalGS(B, P, D, lam, s, k);
475         max_k = k;
476      }
477
478      if (k == 1) {
479         force_reduce = 1;
480         k++;
481         continue;
482      }
483
484      if (force_reduce)
485         for (j = k-1; j >= 1; j--)
486            reduce(k, j, B, P, D, lam, U);
487
488      if (P(k-1) != 0 && P(k) == 0) {
489         force_reduce = swap(k, B, P, D, lam, U, max_k, verbose);
490         k--;
491      }
492      else {
493         force_reduce = 1;
494         k++;
495      }
496   }
497
498   det = D[s];
499   return s;
500}
501
502long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose)
503{
504   vec_ZZ D;
505   long s;
506   s = LLL(D, B, &U, 3, 4, verbose);
507   det = D[s];
508   return s;
509}
510
511long LLL(ZZ& det, mat_ZZ& B, long verbose)
512{
513   vec_ZZ D;
514   long s;
515   s = LLL(D, B, 0, 3, 4, verbose);
516   det = D[s];
517   return s;
518}
519
520long LLL(ZZ& det, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose)
521{
522   if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL: bad args");
523
524   vec_ZZ D;
525   long s;
526   s = LLL(D, B, &U, a, b, verbose);
527   det = D[s];
528   return s;
529}
530
531long LLL(ZZ& det, mat_ZZ& B, long a, long b, long verbose)
532{
533   if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL: bad args");
534
535   vec_ZZ D;
536   long s;
537   s = LLL(D, B, 0, a, b, verbose);
538   det = D[s];
539   return s;
540}
541
542
543long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long verbose)
544{
545   vec_ZZ D;
546   long s;
547   s = LLL(D, B, &U, 3, 4, verbose);
548   D_out = D;
549   return s;
550}
551
552long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long verbose)
553{
554   vec_ZZ D;
555   long s;
556   s = LLL(D, B, 0, 3, 4, verbose);
557   D_out = D;
558   return s;
559}
560
561long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, mat_ZZ& U, long a, long b, long verbose)
562{
563   if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL_plus: bad args");
564
565   vec_ZZ D;
566   long s;
567   s = LLL(D, B, &U, a, b, verbose);
568   D_out = D;
569   return s;
570}
571
572long LLL_plus(vec_ZZ& D_out, mat_ZZ& B, long a, long b, long verbose)
573{
574   if (a <= 0 || b <= 0 || a > b || b/4 >= a) Error("LLL_plus: bad args");
575
576   vec_ZZ D;
577   long s;
578   s = LLL(D, B, 0, a, b, verbose);
579   D_out = D;
580   return s;
581}
582
583
584long image(ZZ& det, mat_ZZ& B, mat_ZZ& U, long verbose)
585{
586   return image(det, B, &U, verbose);
587}
588
589long image(ZZ& det, mat_ZZ& B, long verbose)
590{
591   return image(det, B, 0, verbose);
592}
593
594long LatticeSolve(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& y, long reduce)
595{
596   long n = A.NumRows();
597   long m = A.NumCols();
598
599   if (y.length() != m)
600      Error("LatticeSolve: dimension mismatch");
601
602   if (reduce < 0 || reduce > 2)
603      Error("LatticeSolve: bad reduce parameter");
604
605   if (IsZero(y)) {
606      x.SetLength(n);
607      clear(x);
608      return 1;
609   }
610
611   mat_ZZ A1, U1;
612   ZZ det2;
613   long im_rank, ker_rank;
614
615   A1 = A;
616
617   im_rank = image(det2, A1, U1);
618   ker_rank = n - im_rank;
619
620   mat_ZZ A2, U2;
621   long new_rank;
622   long i;
623
624   A2.SetDims(im_rank + 1, m);
625   for (i = 1; i <= im_rank; i++)
626      A2(i) = A1(ker_rank + i);
627
628   A2(im_rank + 1) = y;
629
630   new_rank = image(det2, A2, U2);
631
632   if (new_rank != im_rank ||
633      (U2(1)(im_rank+1) != 1  && U2(1)(im_rank+1) != -1))
634      return 0;
635
636   vec_ZZ x1;
637   x1.SetLength(im_rank);
638
639   for (i = 1; i <= im_rank; i++)
640      x1(i) = U2(1)(i);
641
642   if (U2(1)(im_rank+1) == 1)
643      negate(x1, x1);
644
645   vec_ZZ x2, tmp;
646   x2.SetLength(n);
647   clear(x2);
648   tmp.SetLength(n);
649
650   for (i = 1; i <= im_rank; i++) {
651      mul(tmp, U1(ker_rank+i), x1(i));
652      add(x2, x2, tmp);
653   }
654
655   if (reduce == 0) {
656      x = x2;
657      return 1;
658   }
659   else if (reduce == 1) {
660      U1.SetDims(ker_rank+1, n);
661      U1(ker_rank+1) = x2;
662      image(det2, U1);
663
664      x = U1(ker_rank + 1);
665      return 1;
666   }
667   else if (reduce == 2) {
668      U1.SetDims(ker_rank, n);
669      LLL(det2, U1);
670      U1.SetDims(ker_rank+1, n);
671      U1(ker_rank+1) = x2;
672      image(det2, U1);
673
674      x = U1(ker_rank + 1);
675      return 1;
676   }
677
678   return 0;
679}
680
681
682
683NTL_END_IMPL
Note: See TracBrowser for help on using the repository browser.