source: git/ntl/src/ZZ_pXFactoring.c @ 33a041

spielwiese
Last change on this file since 33a041 was 311902, checked in by Hans Schönemann <hannes@…>, 20 years ago
*hannes: 5.3.2-C++-fix git-svn-id: file:///usr/local/Singular/svn/trunk@7474 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 29.4 KB
Line 
1
2#include <NTL/ZZ_pXFactoring.h>
3#include <NTL/vec_ZZVec.h>
4#include <NTL/fileio.h>
5#include <NTL/FacVec.h>
6
7#include <stdio.h>
8
9#include <NTL/new.h>
10
11NTL_START_IMPL
12
13
14
15
16
17void SquareFreeDecomp(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff)
18{
19   ZZ_pX f = ff;
20
21   if (!IsOne(LeadCoeff(f)))
22      Error("SquareFreeDecomp: bad args");
23
24   ZZ_pX r, t, v, tmp1;
25   long m, j, finished, done;
26
27   u.SetLength(0);
28
29   if (deg(f) == 0)
30      return;
31
32   m = 1;
33   finished = 0;
34
35   do {
36      j = 1;
37      diff(tmp1, f);
38      GCD(r, f, tmp1);
39      div(t, f, r);
40
41      if (deg(t) > 0) {
42         done = 0;
43         do {
44            GCD(v, r, t);
45            div(tmp1, t, v);
46            if (deg(tmp1) > 0) append(u, cons(tmp1, j*m));
47            if (deg(v) > 0) {
48               div(r, r, v);
49               t = v;
50               j++;
51            }
52            else
53               done = 1;
54         } while (!done);
55         if (deg(r) == 0) finished = 1;
56      }
57
58      if (!finished) {
59         /* r is a p-th power */
60         long p, k, d;
61         conv(p, ZZ_p::modulus());
62         d = deg(r)/p;
63         f.rep.SetLength(d+1);
64         for (k = 0; k <= d; k++) 
65            f.rep[k] = r.rep[k*p];
66         m = m*p;
67      }
68   } while (!finished);
69}
70         
71
72
73static
74void NullSpace(long& r, vec_long& D, vec_ZZVec& M, long verbose)
75{
76   long k, l, n;
77   long i, j;
78   long pos;
79   ZZ t1, t2;
80   ZZ *x, *y;
81
82   const ZZ& p = ZZ_p::modulus();
83
84   n = M.length();
85
86   D.SetLength(n);
87   for (j = 0; j < n; j++) D[j] = -1;
88
89   r = 0;
90
91   l = 0;
92   for (k = 0; k < n; k++) {
93
94      pos = -1;
95      for (i = l; i < n; i++) {
96         rem(t1, M[i][k], p);
97         M[i][k] = t1;
98         if (pos == -1 && !IsZero(t1))
99            pos = i;
100      }
101
102      if (pos != -1) {
103         swap(M[pos], M[l]);
104
105         // make M[l, k] == -1 mod p, and make row l reduced
106
107         InvMod(t1, M[l][k], p);
108         NegateMod(t1, t1, p);
109         for (j = k+1; j < n; j++) {
110            rem(t2, M[l][j], p);
111            MulMod(M[l][j], t2, t1, p);
112         }
113
114         for (i = l+1; i < n; i++) {
115            // M[i] = M[i] + M[l]*M[i,k]
116
117            t1 = M[i][k];   // this is already reduced
118
119            x = M[i].elts() + (k+1);
120            y = M[l].elts() + (k+1);
121
122            for (j = k+1; j < n; j++, x++, y++) {
123               // *x = *x + (*y)*t1
124
125               mul(t2, *y, t1);
126               add(*x, *x, t2);
127            }
128         }
129
130         D[k] = l;   // variable k is defined by row l
131         l++;
132
133      }
134      else {
135         r++;
136      }
137   }
138}
139
140
141
142static
143void BuildMatrix(vec_ZZVec& M, long n, const ZZ_pX& g, const ZZ_pXModulus& F,
144                 long verbose)
145{
146   long i, j, m;
147   ZZ_pXMultiplier G;
148   ZZ_pX h;
149
150   ZZ t;
151   sqr(t, ZZ_p::modulus());
152   mul(t, t, n);
153
154   long size = t.size();
155
156   M.SetLength(n);
157   for (i = 0; i < n; i++)
158      M[i].SetSize(n, size);
159
160   build(G, g, F);
161
162   set(h);
163   for (j = 0; j < n; j++) {
164
165      m = deg(h);
166      for (i = 0; i < n; i++) {
167         if (i <= m)
168            M[i][j] = rep(h.rep[i]);
169         else
170            clear(M[i][j]);
171      }
172
173      if (j < n-1)
174         MulMod(h, h, G, F);
175   }
176
177   for (i = 0; i < n; i++)
178      AddMod(M[i][i], M[i][i], -1, ZZ_p::modulus());
179
180}
181
182
183
184static
185void RecFindRoots(vec_ZZ_p& x, const ZZ_pX& f)
186{
187   if (deg(f) == 0) return;
188
189   if (deg(f) == 1) {
190      long k = x.length();
191      x.SetLength(k+1);
192      negate(x[k], ConstTerm(f));
193      return;
194   }
195     
196   ZZ_pX h;
197
198   ZZ_p r;
199   ZZ p1;
200
201
202   RightShift(p1, ZZ_p::modulus(), 1);
203   
204   {
205      ZZ_pXModulus F;
206      build(F, f);
207
208      do {
209         random(r);
210         PowerXPlusAMod(h, r, p1, F);
211         add(h, h, -1);
212         GCD(h, h, f);
213      } while (deg(h) <= 0 || deg(h) == deg(f));
214   }
215
216   RecFindRoots(x, h);
217   div(h, f, h); 
218   RecFindRoots(x, h);
219}
220
221void FindRoots(vec_ZZ_p& x, const ZZ_pX& ff)
222{
223   ZZ_pX f = ff;
224
225   if (!IsOne(LeadCoeff(f)))
226      Error("FindRoots: bad args");
227
228   x.SetMaxLength(deg(f));
229   x.SetLength(0);
230   RecFindRoots(x, f);
231}
232
233
234static
235void RandomBasisElt(ZZ_pX& g, const vec_long& D, const vec_ZZVec& M)
236{
237   ZZ t1, t2;
238
239   long n = D.length();
240
241   long i, j, s;
242
243   g.rep.SetLength(n);
244
245   vec_ZZ_p& v = g.rep;
246
247   for (j = n-1; j >= 0; j--) {
248      if (D[j] == -1)
249         random(v[j]);
250      else {
251         i = D[j];
252
253         // v[j] = sum_{s=j+1}^{n-1} v[s]*M[i,s]
254
255         clear(t1);
256
257         for (s = j+1; s < n; s++) {
258            mul(t2, rep(v[s]), M[i][s]);
259            add(t1, t1, t2);
260         }
261
262         conv(v[j], t1);
263      }
264   }
265
266   g.normalize();
267}
268
269
270
271static
272void split(ZZ_pX& f1, ZZ_pX& g1, ZZ_pX& f2, ZZ_pX& g2,
273           const ZZ_pX& f, const ZZ_pX& g, 
274           const vec_ZZ_p& roots, long lo, long mid)
275{
276   long r = mid-lo+1;
277
278   ZZ_pXModulus F;
279   build(F, f);
280
281   vec_ZZ_p lroots(INIT_SIZE, r);
282   long i;
283
284   for (i = 0; i < r; i++)
285      lroots[i] = roots[lo+i];
286
287
288   ZZ_pX h, a, d;
289   BuildFromRoots(h, lroots);
290   CompMod(a, h, g, F);
291
292
293   GCD(f1, a, f);
294   
295   div(f2, f, f1);
296
297   rem(g1, g, f1);
298   rem(g2, g, f2);
299}
300
301static
302void RecFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g,
303                    const vec_ZZ_p& roots, long lo, long hi)
304{
305   long r = hi-lo+1;
306
307   if (r == 0) return;
308
309   if (r == 1) {
310      append(factors, f);
311      return;
312   }
313
314   ZZ_pX f1, g1, f2, g2;
315
316   long mid = (lo+hi)/2;
317
318   split(f1, g1, f2, g2, f, g, roots, lo, mid);
319
320   RecFindFactors(factors, f1, g1, roots, lo, mid);
321   RecFindFactors(factors, f2, g2, roots, mid+1, hi);
322}
323
324
325static
326void FindFactors(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& g,
327                 const vec_ZZ_p& roots)
328{
329   long r = roots.length();
330
331   factors.SetMaxLength(r);
332   factors.SetLength(0);
333
334   RecFindFactors(factors, f, g, roots, 0, r-1);
335}
336
337#if 0
338
339static
340void IterFindFactors(vec_ZZ_pX& factors, const ZZ_pX& f,
341                     const ZZ_pX& g, const vec_ZZ_p& roots)
342{
343   long r = roots.length();
344   long i;
345   ZZ_pX h;
346
347   factors.SetLength(r);
348
349   for (i = 0; i < r; i++) {
350      sub(h, g, roots[i]);
351      GCD(factors[i], f, h);
352   }
353}
354
355#endif
356
357
358   
359
360void SFBerlekamp(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose)
361{
362   ZZ_pX f = ff;
363
364   if (!IsOne(LeadCoeff(f)))
365      Error("SFBerlekamp: bad args");
366
367   if (deg(f) == 0) {
368      factors.SetLength(0);
369      return;
370   }
371
372   if (deg(f) == 1) {
373      factors.SetLength(1);
374      factors[0] = f;
375      return;
376   }
377
378   double t;
379
380   const ZZ& p = ZZ_p::modulus();
381
382   long n = deg(f);
383
384   ZZ_pXModulus F;
385
386   build(F, f);
387
388   ZZ_pX g, h;
389
390   PowerXMod(g, p, F);
391
392   vec_long D;
393   long r;
394
395   vec_ZZVec M;
396
397   BuildMatrix(M, n, g, F, verbose);
398
399   NullSpace(r, D, M, verbose);
400
401
402   if (r == 1) {
403      factors.SetLength(1);
404      factors[0] = f;
405      return;
406   }
407
408   vec_ZZ_p roots;
409
410   RandomBasisElt(g, D, M);
411   MinPolyMod(h, g, F, r);
412   if (deg(h) == r) M.kill();
413   FindRoots(roots, h);
414   FindFactors(factors, f, g, roots);
415
416   ZZ_pX g1;
417   vec_ZZ_pX S, S1;
418   long i;
419
420   while (factors.length() < r) {
421      RandomBasisElt(g, D, M);
422      S.kill();
423      for (i = 0; i < factors.length(); i++) {
424         const ZZ_pX& f = factors[i];
425         if (deg(f) == 1) {
426            append(S, f);
427            continue;
428         }
429         build(F, f);
430         rem(g1, g, F);
431         if (deg(g1) <= 0) {
432            append(S, f);
433            continue;
434         }
435         MinPolyMod(h, g1, F, min(deg(f), r-factors.length()+1));
436         FindRoots(roots, h);
437         S1.kill();
438         FindFactors(S1, f, g1, roots);
439         append(S, S1);
440      }
441      swap(factors, S);
442   }
443
444}
445
446
447void berlekamp(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose)
448{
449   double t;
450   vec_pair_ZZ_pX_long sfd;
451   vec_ZZ_pX x;
452
453   if (!IsOne(LeadCoeff(f)))
454      Error("berlekamp: bad args");
455
456   
457   SquareFreeDecomp(sfd, f);
458
459   factors.SetLength(0);
460
461   long i, j;
462
463   for (i = 0; i < sfd.length(); i++) {
464
465      SFBerlekamp(x, sfd[i].a, verbose);
466
467      for (j = 0; j < x.length(); j++)
468         append(factors, cons(x[j], sfd[i].b));
469   }
470}
471
472
473
474static
475void AddFactor(vec_pair_ZZ_pX_long& factors, const ZZ_pX& g, long d, long verbose)
476{
477   append(factors, cons(g, d));
478}
479
480static
481void ProcessTable(ZZ_pX& f, vec_pair_ZZ_pX_long& factors, 
482                  const ZZ_pXModulus& F, long limit, const vec_ZZ_pX& tbl,
483                  long d, long verbose)
484
485{
486   if (limit == 0) return;
487
488   ZZ_pX t1;
489
490   if (limit == 1) {
491      GCD(t1, f, tbl[0]);
492      if (deg(t1) > 0) {
493         AddFactor(factors, t1, d, verbose);
494         div(f, f, t1);
495      }
496
497      return;
498   }
499
500   long i;
501
502   t1 = tbl[0];
503   for (i = 1; i < limit; i++)
504      MulMod(t1, t1, tbl[i], F);
505
506   GCD(t1, f, t1);
507
508   if (deg(t1) == 0) return;
509
510   div(f, f, t1);
511
512   ZZ_pX t2;
513
514   i = 0;
515   d = d - limit + 1;
516
517   while (2*d <= deg(t1)) {
518      GCD(t2, tbl[i], t1); 
519      if (deg(t2) > 0) {
520         AddFactor(factors, t2, d, verbose);
521         div(t1, t1, t2);
522      }
523
524      i++;
525      d++;
526   }
527
528   if (deg(t1) > 0)
529      AddFactor(factors, t1, deg(t1), verbose);
530}
531
532
533void TraceMap(ZZ_pX& w, const ZZ_pX& a, long d, const ZZ_pXModulus& F, 
534              const ZZ_pX& b)
535
536{
537   if (d < 0) Error("TraceMap: bad args");
538
539   ZZ_pX y, z, t;
540
541   z = b;
542   y = a;
543   clear(w);
544
545   while (d) {
546      if (d == 1) {
547         if (IsZero(w)) 
548            w = y;
549         else {
550            CompMod(w, w, z, F);
551            add(w, w, y);
552         }
553      }
554      else if ((d & 1) == 0) {
555         Comp2Mod(z, t, z, y, z, F);
556         add(y, t, y);
557      }
558      else if (IsZero(w)) {
559         w = y;
560         Comp2Mod(z, t, z, y, z, F);
561         add(y, t, y);
562      }
563      else {
564         Comp3Mod(z, t, w, z, y, w, z, F);
565         add(w, w, y);
566         add(y, t, y);
567      }
568
569      d = d >> 1;
570   }
571}
572
573
574void PowerCompose(ZZ_pX& y, const ZZ_pX& h, long q, const ZZ_pXModulus& F)
575{
576   if (q < 0) Error("PowerCompose: bad args");
577
578   ZZ_pX z(INIT_SIZE, F.n);
579   long sw;
580
581   z = h;
582   SetX(y);
583
584   while (q) {
585      sw = 0;
586
587      if (q > 1) sw = 2;
588      if (q & 1) {
589         if (IsX(y))
590            y = z;
591         else
592            sw = sw | 1;
593      }
594
595      switch (sw) {
596      case 0:
597         break;
598
599      case 1:
600         CompMod(y, y, z, F);
601         break;
602
603      case 2:
604         CompMod(z, z, z, F);
605         break;
606
607      case 3:
608         Comp2Mod(y, z, y, z, z, F);
609         break;
610      }
611
612      q = q >> 1;
613   }
614}
615
616
617long ProbIrredTest(const ZZ_pX& f, long iter)
618{
619   long n = deg(f);
620
621   if (n <= 0) return 0;
622   if (n == 1) return 1;
623
624   const ZZ& p = ZZ_p::modulus();
625
626   ZZ_pXModulus F;
627
628   build(F, f);
629
630   ZZ_pX b, r, s;
631
632   PowerXMod(b, p, F);
633
634   long i;
635
636   for (i = 0; i < iter; i++) {
637      random(r, n);
638      TraceMap(s, r, n, F, b);
639
640      if (deg(s) > 0) return 0;
641   }
642
643   if (p >= n) return 1;
644
645   long pp;
646
647   conv(pp, p);
648   
649   if (n % pp != 0) return 1;
650
651   PowerCompose(s, b, n/pp, F);
652   return !IsX(s);
653}
654
655long ZZ_pX_BlockingFactor = 10;
656
657void DDF(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff, const ZZ_pX& hh, 
658         long verbose)
659{
660   ZZ_pX f = ff;
661   ZZ_pX h = hh;
662
663   if (!IsOne(LeadCoeff(f)))
664      Error("DDF: bad args");
665
666   factors.SetLength(0);
667
668   if (deg(f) == 0)
669      return;
670
671   if (deg(f) == 1) {
672      AddFactor(factors, f, 1, verbose);
673      return;
674   }
675
676   long CompTableSize = 2*SqrRoot(deg(f)); 
677
678   long GCDTableSize = ZZ_pX_BlockingFactor;
679
680   ZZ_pXModulus F;
681   build(F, f);
682
683   ZZ_pXArgument H;
684
685   build(H, h, F, min(CompTableSize, deg(f)));
686
687   long i, d, limit, old_n;
688   ZZ_pX g, X;
689
690
691   vec_ZZ_pX tbl(INIT_SIZE, GCDTableSize);
692
693   SetX(X);
694
695   i = 0;
696   g = h;
697   d = 1;
698   limit = GCDTableSize;
699
700
701   while (2*d <= deg(f)) {
702
703      old_n = deg(f);
704      sub(tbl[i], g, X);
705      i++;
706      if (i == limit) {
707         ProcessTable(f, factors, F, i, tbl, d, verbose);
708         i = 0;
709      }
710
711      d = d + 1;
712      if (2*d <= deg(f)) {
713         // we need to go further
714
715         if (deg(f) < old_n) {
716            // f has changed
717
718            build(F, f);
719            rem(h, h, f);
720            rem(g, g, f);
721            build(H, h, F, min(CompTableSize, deg(f)));
722         }
723
724         CompMod(g, g, H, F);
725      }
726   }
727
728   ProcessTable(f, factors, F, i, tbl, d-1, verbose);
729
730   if (!IsOne(f)) AddFactor(factors, f, deg(f), verbose);
731}
732
733
734
735void RootEDF(vec_ZZ_pX& factors, const ZZ_pX& f, long verbose)
736{
737   vec_ZZ_p roots;
738   double t;
739
740   FindRoots(roots, f);
741
742   long r = roots.length();
743   factors.SetLength(r);
744   for (long j = 0; j < r; j++) {
745      SetX(factors[j]);
746      sub(factors[j], factors[j], roots[j]);
747   }
748}
749
750static
751void EDFSplit(vec_ZZ_pX& v, const ZZ_pX& f, const ZZ_pX& b, long d)
752{
753   ZZ_pX a, g, h;
754   ZZ_pXModulus F;
755   vec_ZZ_p roots;
756   
757   build(F, f);
758   long n = F.n;
759   long r = n/d;
760   random(a, n);
761   TraceMap(g, a, d, F, b);
762   MinPolyMod(h, g, F, r);
763   FindRoots(roots, h);
764   FindFactors(v, f, g, roots);
765}
766
767static
768void RecEDF(vec_ZZ_pX& factors, const ZZ_pX& f, const ZZ_pX& b, long d,
769            long verbose)
770{
771   vec_ZZ_pX v;
772   long i;
773   ZZ_pX bb;
774
775   EDFSplit(v, f, b, d);
776   for (i = 0; i < v.length(); i++) {
777      if (deg(v[i]) == d) {
778         append(factors, v[i]);
779      }
780      else {
781         ZZ_pX bb;
782         rem(bb, b, v[i]);
783         RecEDF(factors, v[i], bb, d, verbose);
784      }
785   }
786}
787         
788
789void EDF(vec_ZZ_pX& factors, const ZZ_pX& ff, const ZZ_pX& bb,
790         long d, long verbose)
791
792{
793   ZZ_pX f = ff;
794   ZZ_pX b = bb;
795
796   if (!IsOne(LeadCoeff(f)))
797      Error("EDF: bad args");
798
799   long n = deg(f);
800   long r = n/d;
801
802   if (r == 0) {
803      factors.SetLength(0);
804      return;
805   }
806
807   if (r == 1) {
808      factors.SetLength(1);
809      factors[0] = f;
810      return;
811   }
812
813   if (d == 1) {
814      RootEDF(factors, f, verbose);
815      return;
816   }
817
818   
819   factors.SetLength(0);
820
821   RecEDF(factors, f, b, d, verbose);
822
823}
824
825
826void SFCanZass(vec_ZZ_pX& factors, const ZZ_pX& ff, long verbose)
827{
828   ZZ_pX f = ff;
829
830   if (!IsOne(LeadCoeff(f)))
831      Error("SFCanZass: bad args");
832
833   if (deg(f) == 0) {
834      factors.SetLength(0);
835      return;
836   }
837
838   if (deg(f) == 1) {
839      factors.SetLength(1);
840      factors[0] = f;
841      return;
842   }
843
844   factors.SetLength(0);
845
846   double t;
847
848   const ZZ& p = ZZ_p::modulus();
849
850   
851   ZZ_pXModulus F;
852   build(F, f);
853
854   ZZ_pX h;
855
856   PowerXMod(h, p, F);
857
858   vec_pair_ZZ_pX_long u;
859   NewDDF(u, f, h, verbose);
860
861   ZZ_pX hh;
862   vec_ZZ_pX v;
863
864   long i;
865   for (i = 0; i < u.length(); i++) {
866      const ZZ_pX& g = u[i].a;
867      long d = u[i].b;
868      long r = deg(g)/d;
869
870      if (r == 1) {
871         // g is already irreducible
872
873         append(factors, g);
874      }
875      else {
876         // must perform EDF
877
878         if (d == 1) {
879            // root finding
880            RootEDF(v, g, verbose);
881            append(factors, v);
882         }
883         else {
884            // general case
885            rem(hh, h, g);
886            EDF(v, g, hh, d, verbose);
887            append(factors, v);
888         }
889      }
890   }
891}
892   
893void CanZass(vec_pair_ZZ_pX_long& factors, const ZZ_pX& f, long verbose)
894{
895   if (!IsOne(LeadCoeff(f)))
896      Error("CanZass: bad args");
897
898   double t;
899   vec_pair_ZZ_pX_long sfd;
900   vec_ZZ_pX x;
901
902   
903   SquareFreeDecomp(sfd, f);
904
905   factors.SetLength(0);
906
907   long i, j;
908
909   for (i = 0; i < sfd.length(); i++) {
910
911      SFCanZass(x, sfd[i].a, verbose);
912
913      for (j = 0; j < x.length(); j++)
914         append(factors, cons(x[j], sfd[i].b));
915   }
916}
917
918void mul(ZZ_pX& f, const vec_pair_ZZ_pX_long& v)
919{
920   long i, j, n;
921
922   n = 0;
923   for (i = 0; i < v.length(); i++)
924      n += v[i].b*deg(v[i].a);
925
926   ZZ_pX g(INIT_SIZE, n+1);
927
928   set(g);
929   for (i = 0; i < v.length(); i++)
930      for (j = 0; j < v[i].b; j++) {
931         mul(g, g, v[i].a);
932      }
933
934   f = g;
935}
936
937
938
939
940static
941long BaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F)
942{
943   long b, e;
944   ZZ_pX lh(INIT_SIZE, F.n);
945
946   lh = h;
947   b = 1;
948   e = 0;
949   while (e < a-1 && !IsX(lh)) {
950      e++;
951      b *= q;
952      PowerCompose(lh, lh, q, F);
953   }
954
955   if (!IsX(lh)) b *= q;
956
957   return b;
958}
959
960
961
962static
963void TandemPowerCompose(ZZ_pX& y1, ZZ_pX& y2, const ZZ_pX& h, 
964                        long q1, long q2, const ZZ_pXModulus& F)
965{
966   ZZ_pX z(INIT_SIZE, F.n);
967   long sw;
968
969   z = h;
970   SetX(y1);
971   SetX(y2);
972
973   while (q1 || q2) {
974      sw = 0;
975
976      if (q1 > 1 || q2 > 1) sw = 4;
977
978      if (q1 & 1) {
979         if (IsX(y1))
980            y1 = z;
981         else
982            sw = sw | 2;
983      }
984
985      if (q2 & 1) {
986         if (IsX(y2))
987            y2 = z;
988         else
989            sw = sw | 1;
990      }
991
992      switch (sw) {
993      case 0:
994         break;
995
996      case 1:
997         CompMod(y2, y2, z, F);
998         break;
999
1000      case 2:
1001         CompMod(y1, y1, z, F);
1002         break;
1003
1004      case 3:
1005         Comp2Mod(y1, y2, y1, y2, z, F);
1006         break;
1007
1008      case 4:
1009         CompMod(z, z, z, F);
1010         break;
1011
1012      case 5:
1013         Comp2Mod(z, y2, z, y2, z, F);
1014         break;
1015
1016      case 6:
1017         Comp2Mod(z, y1, z, y1, z, F);
1018         break;
1019
1020      case 7:
1021         Comp3Mod(z, y1, y2, z, y1, y2, z, F);
1022         break;
1023      }
1024
1025      q1 = q1 >> 1;
1026      q2 = q2 >> 1;
1027   }
1028}
1029
1030
1031
1032static
1033long RecComputeDegree(long u, const ZZ_pX& h, const ZZ_pXModulus& F,
1034                      FacVec& fvec)
1035{
1036   if (IsX(h)) return 1;
1037
1038   if (fvec[u].link == -1) return BaseCase(h, fvec[u].q, fvec[u].a, F);
1039
1040   ZZ_pX h1, h2;
1041   long q1, q2, r1, r2;
1042
1043   q1 = fvec[fvec[u].link].val; 
1044   q2 = fvec[fvec[u].link+1].val;
1045
1046   TandemPowerCompose(h1, h2, h, q1, q2, F);
1047   r1 = RecComputeDegree(fvec[u].link, h2, F, fvec);
1048   r2 = RecComputeDegree(fvec[u].link+1, h1, F, fvec);
1049   return r1*r2;
1050}
1051
1052   
1053
1054
1055long ComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F)
1056   // f = F.f is assumed to be an "equal degree" polynomial
1057   // h = X^p mod f
1058   // the common degree of the irreducible factors of f is computed
1059{
1060   if (F.n == 1 || IsX(h)) return 1;
1061
1062   FacVec fvec;
1063
1064   FactorInt(fvec, F.n);
1065
1066   return RecComputeDegree(fvec.length()-1, h, F, fvec);
1067}
1068
1069long ProbComputeDegree(const ZZ_pX& h, const ZZ_pXModulus& F)
1070{
1071   if (F.n == 1 || IsX(h))
1072      return 1;
1073
1074   long n = F.n;
1075
1076   ZZ_pX P1, P2, P3;
1077
1078   random(P1, n);
1079   TraceMap(P2, P1, n, F, h);
1080   ProbMinPolyMod(P3, P2, F, n/2);
1081
1082   long r = deg(P3);
1083
1084   if (r <= 0 || n % r != 0)
1085      return 0;
1086   else
1087      return n/r;
1088}
1089
1090
1091
1092void FindRoot(ZZ_p& root, const ZZ_pX& ff)
1093// finds a root of ff.
1094// assumes that ff is monic and splits into distinct linear factors
1095
1096{
1097   ZZ_pXModulus F;
1098   ZZ_pX h, h1, f;
1099   ZZ_p r;
1100   ZZ p1;
1101
1102   f = ff;
1103   
1104   if (!IsOne(LeadCoeff(f)))
1105      Error("FindRoot: bad args");
1106
1107   if (deg(f) == 0)
1108      Error("FindRoot: bad args");
1109
1110   RightShift(p1, ZZ_p::modulus(), 1);
1111   h1 = 1;
1112
1113   while (deg(f) > 1) {
1114      build(F, f);
1115      random(r);
1116      PowerXPlusAMod(h, r, p1, F);
1117      sub(h, h, h1);
1118      GCD(h, h, f);
1119      if (deg(h) > 0 && deg(h) < deg(f)) {
1120         if (deg(h) > deg(f)/2)
1121            div(f, f, h);
1122         else
1123            f = h;
1124      }
1125   }
1126
1127   negate(root, ConstTerm(f));
1128}
1129
1130
1131static
1132long power(long a, long e)
1133{
1134   long i, res;
1135
1136   res = 1;
1137   for (i = 1; i <= e; i++)
1138      res = res * a;
1139
1140   return res;
1141}
1142
1143
1144static
1145long IrredBaseCase(const ZZ_pX& h, long q, long a, const ZZ_pXModulus& F)
1146{
1147   long e;
1148   ZZ_pX X, s, d;
1149
1150   e = power(q, a-1);
1151   PowerCompose(s, h, e, F);
1152   SetX(X);
1153   sub(s, s, X);
1154   GCD(d, F.f, s);
1155   return IsOne(d);
1156}
1157
1158
1159static
1160long RecIrredTest(long u, const ZZ_pX& h, const ZZ_pXModulus& F,
1161                 const FacVec& fvec)
1162{
1163   long  q1, q2;
1164   ZZ_pX h1, h2;
1165
1166   if (IsX(h)) return 0;
1167
1168   if (fvec[u].link == -1) {
1169      return IrredBaseCase(h, fvec[u].q, fvec[u].a, F);
1170   }
1171
1172
1173   q1 = fvec[fvec[u].link].val; 
1174   q2 = fvec[fvec[u].link+1].val;
1175
1176   TandemPowerCompose(h1, h2, h, q1, q2, F);
1177   return RecIrredTest(fvec[u].link, h2, F, fvec) 
1178          && RecIrredTest(fvec[u].link+1, h1, F, fvec);
1179}
1180
1181long DetIrredTest(const ZZ_pX& f)
1182{
1183   if (deg(f) <= 0) return 0;
1184   if (deg(f) == 1) return 1;
1185
1186   ZZ_pXModulus F;
1187
1188   build(F, f);
1189   
1190   ZZ_pX h;
1191
1192   PowerXMod(h, ZZ_p::modulus(), F);
1193
1194   ZZ_pX s;
1195   PowerCompose(s, h, F.n, F);
1196   if (!IsX(s)) return 0;
1197
1198   FacVec fvec;
1199
1200   FactorInt(fvec, F.n);
1201
1202   return RecIrredTest(fvec.length()-1, h, F, fvec);
1203}
1204
1205
1206
1207long IterIrredTest(const ZZ_pX& f)
1208{
1209   if (deg(f) <= 0) return 0;
1210   if (deg(f) == 1) return 1;
1211
1212   ZZ_pXModulus F;
1213
1214   build(F, f);
1215   
1216   ZZ_pX h;
1217
1218   PowerXMod(h, ZZ_p::modulus(), F);
1219
1220   long CompTableSize = 2*SqrRoot(deg(f));
1221
1222   ZZ_pXArgument H;
1223
1224   build(H, h, F, CompTableSize);
1225
1226   long i, d, limit, limit_sqr;
1227   ZZ_pX g, X, t, prod;
1228
1229
1230   SetX(X);
1231
1232   i = 0;
1233   g = h;
1234   d = 1;
1235   limit = 2;
1236   limit_sqr = limit*limit;
1237
1238   set(prod);
1239
1240
1241   while (2*d <= deg(f)) {
1242      sub(t, g, X);
1243      MulMod(prod, prod, t, F);
1244      i++;
1245      if (i == limit_sqr) {
1246         GCD(t, f, prod);
1247         if (!IsOne(t)) return 0;
1248
1249         set(prod);
1250         limit++;
1251         limit_sqr = limit*limit;
1252         i = 0;
1253      }
1254
1255      d = d + 1;
1256      if (2*d <= deg(f)) {
1257         CompMod(g, g, H, F);
1258      }
1259   }
1260
1261   if (i > 0) {
1262      GCD(t, f, prod);
1263      if (!IsOne(t)) return 0;
1264   }
1265
1266   return 1;
1267}
1268
1269
1270static
1271void MulByXPlusY(vec_ZZ_pX& h, const ZZ_pX& f, const ZZ_pX& g)
1272// h represents the bivariate polynomial h[0] + h[1]*Y + ... + h[n-1]*Y^k,
1273// where the h[i]'s are polynomials in X, each of degree < deg(f),
1274// and k < deg(g).
1275// h is replaced by the bivariate polynomial h*(X+Y) (mod f(X), g(Y)).
1276
1277{
1278   long n = deg(g);
1279   long k = h.length()-1;
1280
1281   if (k < 0) return;
1282
1283   if (k < n-1) {
1284      h.SetLength(k+2);
1285      h[k+1] = h[k];
1286      for (long i = k; i >= 1; i--) {
1287         MulByXMod(h[i], h[i], f);
1288         add(h[i], h[i], h[i-1]);
1289      }
1290      MulByXMod(h[0], h[0], f);
1291   }
1292   else {
1293      ZZ_pX b, t;
1294
1295      b = h[n-1];
1296      for (long i = n-1; i >= 1; i--) {
1297         mul(t, b, g.rep[i]);
1298         MulByXMod(h[i], h[i], f);
1299         add(h[i], h[i], h[i-1]);
1300         sub(h[i], h[i], t);
1301      }
1302      mul(t, b, g.rep[0]);
1303      MulByXMod(h[0], h[0], f);
1304      sub(h[0], h[0], t);
1305   }
1306
1307   // normalize
1308
1309   k = h.length()-1;
1310   while (k >= 0 && IsZero(h[k])) k--;
1311   h.SetLength(k+1);
1312}
1313
1314
1315static
1316void IrredCombine(ZZ_pX& x, const ZZ_pX& f, const ZZ_pX& g)
1317{
1318   if (deg(f) < deg(g)) {
1319      IrredCombine(x, g, f);
1320      return;
1321   }
1322
1323   // deg(f) >= deg(g)...not necessary, but maybe a little more
1324   //                    time & space efficient
1325
1326   long df = deg(f);
1327   long dg = deg(g);
1328   long m = df*dg;
1329
1330   vec_ZZ_pX h(INIT_SIZE, dg);
1331
1332   long i;
1333   for (i = 0; i < dg; i++) h[i].SetMaxLength(df);
1334
1335   h.SetLength(1);
1336   set(h[0]);
1337
1338   vec_ZZ_p a;
1339
1340   a.SetLength(2*m);
1341
1342   for (i = 0; i < 2*m; i++) {
1343      a[i] = ConstTerm(h[0]);
1344      if (i < 2*m-1)
1345         MulByXPlusY(h, f, g);
1346   }
1347
1348   MinPolySeq(x, a, m);
1349}
1350
1351
1352static
1353void BuildPrimePowerIrred(ZZ_pX& f, long q, long e)
1354{
1355   long n = power(q, e);
1356
1357   do {
1358      random(f, n);
1359      SetCoeff(f, n);
1360   } while (!IterIrredTest(f));
1361}
1362
1363static
1364void RecBuildIrred(ZZ_pX& f, long u, const FacVec& fvec)
1365{
1366   if (fvec[u].link == -1)
1367      BuildPrimePowerIrred(f, fvec[u].q, fvec[u].a);
1368   else {
1369      ZZ_pX g, h;
1370      RecBuildIrred(g, fvec[u].link, fvec);
1371      RecBuildIrred(h, fvec[u].link+1, fvec);
1372      IrredCombine(f, g, h);
1373   }
1374}
1375
1376
1377void BuildIrred(ZZ_pX& f, long n)
1378{
1379   if (n <= 0)
1380      Error("BuildIrred: n must be positive");
1381
1382   if (NTL_OVERFLOW(n, 1, 0)) Error("overflow in BuildIrred");
1383
1384   if (n == 1) {
1385      SetX(f);
1386      return;
1387   }
1388
1389   FacVec fvec;
1390
1391   FactorInt(fvec, n);
1392
1393   RecBuildIrred(f, fvec.length()-1, fvec);
1394}
1395
1396
1397
1398void BuildRandomIrred(ZZ_pX& f, const ZZ_pX& g)
1399{
1400   ZZ_pXModulus G;
1401   ZZ_pX h, ff;
1402
1403   build(G, g);
1404   do {
1405      random(h, deg(g));
1406      IrredPolyMod(ff, h, G);
1407   } while (deg(ff) < deg(g));
1408
1409   f = ff;
1410}
1411
1412
1413/************* NEW DDF ****************/
1414
1415long ZZ_pX_GCDTableSize = 4;
1416char ZZ_pX_stem[256] = "";
1417
1418double ZZ_pXFileThresh = 256;
1419
1420static vec_ZZ_pX BabyStepFile;
1421static vec_ZZ_pX GiantStepFile;
1422
1423
1424static 
1425double CalcTableSize(long n, long k)
1426{
1427   double sz = ZZ_p::storage();
1428   sz = sz * n;
1429   sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p);
1430   sz = sz * k;
1431   sz = sz/1024;
1432   return sz;
1433}
1434
1435
1436static
1437void GenerateBabySteps(ZZ_pX& h1, const ZZ_pX& f, const ZZ_pX& h, long k,
1438                       long verbose)
1439
1440{
1441   ZZ_pXModulus F;
1442   build(F, f);
1443
1444   ZZ_pXArgument H;
1445   build(H, h, F, 2*SqrRoot(F.n));
1446
1447
1448   h1 = h;
1449
1450   long i;
1451
1452      BabyStepFile.kill();
1453      BabyStepFile.SetLength(k-1);
1454
1455   for (i = 1; i <= k-1; i++) {
1456         BabyStepFile(i) = h1;
1457
1458      CompMod(h1, h1, H, F);
1459   }
1460
1461}
1462
1463
1464static
1465void GenerateGiantSteps(const ZZ_pX& f, const ZZ_pX& h, long l, long verbose)
1466{
1467
1468   ZZ_pXModulus F;
1469   build(F, f);
1470
1471   ZZ_pXArgument H;
1472   build(H, h, F, 2*SqrRoot(F.n));
1473
1474   ZZ_pX h1;
1475
1476   h1 = h;
1477
1478   long i;
1479
1480      GiantStepFile.kill();
1481      GiantStepFile.SetLength(l);
1482
1483   for (i = 1; i <= l-1; i++) {
1484         GiantStepFile(i) = h1;
1485
1486      CompMod(h1, h1, H, F);
1487   }
1488
1489      GiantStepFile(i) = h1;
1490
1491}
1492
1493static
1494void FileCleanup(long k, long l)
1495{
1496      BabyStepFile.kill();
1497      GiantStepFile.kill();
1498}
1499
1500
1501static
1502void NewAddFactor(vec_pair_ZZ_pX_long& u, const ZZ_pX& g, long m, long verbose)
1503{
1504   long len = u.length();
1505
1506   u.SetLength(len+1);
1507   u[len].a = g;
1508   u[len].b = m;
1509
1510}
1511
1512   
1513
1514
1515static
1516void NewProcessTable(vec_pair_ZZ_pX_long& u, ZZ_pX& f, const ZZ_pXModulus& F,
1517                     vec_ZZ_pX& buf, long size, long StartInterval,
1518                     long IntervalLength, long verbose)
1519
1520{
1521   if (size == 0) return;
1522
1523   ZZ_pX& g = buf[size-1];
1524
1525   long i;
1526
1527   for (i = 0; i < size-1; i++)
1528      MulMod(g, g, buf[i], F);
1529
1530   GCD(g, f, g);
1531
1532   if (deg(g) == 0) return;
1533
1534   div(f, f, g);
1535
1536   long d = (StartInterval-1)*IntervalLength + 1;
1537   i = 0;
1538   long interval = StartInterval;
1539
1540   while (i < size-1 && 2*d <= deg(g)) {
1541      GCD(buf[i], buf[i], g);
1542      if (deg(buf[i]) > 0) {
1543         NewAddFactor(u, buf[i], interval, verbose);
1544         div(g, g, buf[i]);
1545      }
1546
1547      i++;
1548      interval++;
1549      d += IntervalLength;
1550   }
1551
1552   if (deg(g) > 0) {
1553      if (i == size-1)
1554         NewAddFactor(u, g, interval, verbose);
1555      else
1556         NewAddFactor(u, g, (deg(g)+IntervalLength-1)/IntervalLength, verbose);
1557   }
1558}
1559
1560
1561static
1562void FetchGiantStep(ZZ_pX& g, long gs, const ZZ_pXModulus& F)
1563{
1564      g = GiantStepFile(gs);
1565
1566   rem(g, g, F);
1567}
1568
1569
1570static
1571void FetchBabySteps(vec_ZZ_pX& v, long k)
1572{
1573   v.SetLength(k);
1574
1575   SetX(v[0]);
1576
1577   long i;
1578   for (i = 1; i <= k-1; i++) {
1579         v[i] = BabyStepFile(i);
1580   }
1581}
1582     
1583
1584
1585static
1586void GiantRefine(vec_pair_ZZ_pX_long& u, const ZZ_pX& ff, long k, long l,
1587                 long verbose)
1588
1589{
1590   u.SetLength(0);
1591
1592   vec_ZZ_pX BabyStep;
1593
1594   FetchBabySteps(BabyStep, k);
1595
1596   vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize);
1597
1598   ZZ_pX f;
1599   f = ff;
1600
1601   ZZ_pXModulus F;
1602   build(F, f);
1603
1604   ZZ_pX g;
1605   ZZ_pX h;
1606
1607   long size = 0;
1608
1609   long first_gs;
1610
1611   long d = 1;
1612
1613   while (2*d <= deg(f)) {
1614
1615      long old_n = deg(f);
1616
1617      long gs = (d+k-1)/k;
1618      long bs = gs*k - d;
1619
1620      if (bs == k-1) {
1621         size++;
1622         if (size == 1) first_gs = gs;
1623         FetchGiantStep(g, gs, F);
1624         sub(buf[size-1], g, BabyStep[bs]);
1625      }
1626      else {
1627         sub(h, g, BabyStep[bs]);
1628         MulMod(buf[size-1], buf[size-1], h, F);
1629      }
1630
1631      if (size == ZZ_pX_GCDTableSize && bs == 0) {
1632         NewProcessTable(u, f, F, buf, size, first_gs, k, verbose);
1633         size = 0;
1634      }
1635
1636      d++;
1637
1638      if (2*d <= deg(f) && deg(f) < old_n) {
1639         build(F, f);
1640
1641         long i;
1642         for (i = 1; i <= k-1; i++) 
1643            rem(BabyStep[i], BabyStep[i], F);
1644      }
1645   }
1646
1647   if (size > 0) {
1648      NewProcessTable(u, f, F, buf, size, first_gs, k, verbose);
1649   }
1650
1651   if (deg(f) > 0) 
1652      NewAddFactor(u, f, 0, verbose);
1653
1654}
1655
1656
1657static
1658void IntervalRefine(vec_pair_ZZ_pX_long& factors, const ZZ_pX& ff,
1659                    long k, long gs, const vec_ZZ_pX& BabyStep, long verbose)
1660
1661{
1662   vec_ZZ_pX buf(INIT_SIZE, ZZ_pX_GCDTableSize);
1663
1664   ZZ_pX f;
1665   f = ff;
1666
1667   ZZ_pXModulus F;
1668   build(F, f);
1669
1670   ZZ_pX g;
1671
1672   FetchGiantStep(g, gs, F);
1673
1674   long size = 0;
1675
1676   long first_d;
1677
1678   long d = (gs-1)*k + 1;
1679   long bs = k-1;
1680
1681   while (bs >= 0 && 2*d <= deg(f)) {
1682
1683      long old_n = deg(f);
1684
1685      if (size == 0) first_d = d;
1686      rem(buf[size], BabyStep[bs], F);
1687      sub(buf[size], buf[size], g);
1688      size++;
1689
1690      if (size == ZZ_pX_GCDTableSize) {
1691         NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose);
1692         size = 0;
1693      }
1694
1695      d++;
1696      bs--;
1697
1698      if (bs >= 0 && 2*d <= deg(f) && deg(f) < old_n) {
1699         build(F, f);
1700         rem(g, g, F);
1701      }
1702   }
1703
1704   NewProcessTable(factors, f, F, buf, size, first_d, 1, verbose);
1705
1706   if (deg(f) > 0) 
1707      NewAddFactor(factors, f, deg(f), verbose);
1708}
1709   
1710
1711
1712
1713static
1714void BabyRefine(vec_pair_ZZ_pX_long& factors, const vec_pair_ZZ_pX_long& u,
1715                long k, long l, long verbose)
1716
1717{
1718
1719   factors.SetLength(0);
1720
1721   vec_ZZ_pX BabyStep;
1722
1723   long i;
1724   for (i = 0; i < u.length(); i++) {
1725      const ZZ_pX& g = u[i].a;
1726      long gs = u[i].b;
1727
1728      if (gs == 0 || 2*((gs-1)*k+1) > deg(g))
1729         NewAddFactor(factors, g, deg(g), verbose);
1730      else {
1731         if (BabyStep.length() == 0)
1732            FetchBabySteps(BabyStep, k);
1733         IntervalRefine(factors, g, k, gs, BabyStep, verbose);
1734      }
1735   }
1736}
1737
1738     
1739     
1740
1741     
1742
1743void NewDDF(vec_pair_ZZ_pX_long& factors,
1744            const ZZ_pX& f,
1745            const ZZ_pX& h,
1746            long verbose)
1747
1748{
1749   if (!IsOne(LeadCoeff(f)))
1750      Error("NewDDF: bad args");
1751
1752   if (deg(f) == 0) {
1753      factors.SetLength(0);
1754      return;
1755   }
1756
1757   if (deg(f) == 1) {
1758      factors.SetLength(0);
1759      append(factors, cons(f, 1));
1760      return;
1761   }
1762
1763   if (!ZZ_pX_stem[0])
1764      sprintf(ZZ_pX_stem, "ddf-%ld", RandomBnd(10000));
1765     
1766   long B = deg(f)/2;
1767   long k = SqrRoot(B);
1768   long l = (B+k-1)/k;
1769
1770   ZZ_pX h1;
1771
1772   GenerateBabySteps(h1, f, h, k, verbose);
1773
1774   GenerateGiantSteps(f, h1, l, verbose);
1775
1776   vec_pair_ZZ_pX_long u;
1777   GiantRefine(u, f, k, l, verbose);
1778   BabyRefine(factors, u, k, l, verbose);
1779
1780   FileCleanup(k, l);
1781}
1782
1783NTL_END_IMPL
Note: See TracBrowser for help on using the repository browser.