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