source: git/ntl/src/ZZ_pX1.c @ 2cfffe

spielwiese
Last change on this file since 2cfffe was 2cfffe, checked in by Hans Schönemann <hannes@…>, 21 years ago
This commit was generated by cvs2svn to compensate for changes in r6316, which included commits to RCS files with non-trunk default branches. git-svn-id: file:///usr/local/Singular/svn/trunk@6317 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 34.6 KB
Line 
1
2#include <NTL/ZZ_pX.h>
3
4#include <NTL/new.h>
5
6NTL_START_IMPL
7
8
9
10
11long divide(ZZ_pX& q, const ZZ_pX& a, const ZZ_pX& b)
12{
13   if (IsZero(b)) {
14      if (IsZero(a)) {
15         clear(q);
16         return 1;
17      }
18      else
19         return 0;
20   }
21
22   ZZ_pX lq, r;
23   DivRem(lq, r, a, b);
24   if (!IsZero(r)) return 0; 
25   q = lq;
26   return 1;
27}
28
29long divide(const ZZ_pX& a, const ZZ_pX& b)
30{
31   if (IsZero(b)) return IsZero(a);
32   ZZ_pX lq, r;
33   DivRem(lq, r, a, b);
34   if (!IsZero(r)) return 0; 
35   return 1;
36}
37
38
39
40
41void ZZ_pXMatrix::operator=(const ZZ_pXMatrix& M)
42{
43   elts[0][0] = M.elts[0][0];
44   elts[0][1] = M.elts[0][1];
45   elts[1][0] = M.elts[1][0];
46   elts[1][1] = M.elts[1][1];
47}
48
49
50void RightShift(ZZ_pX& x, const ZZ_pX& a, long n)
51{
52   if (n < 0) {
53      if (n < -NTL_MAX_LONG) Error("overflow in RightShift");
54      LeftShift(x, a, -n);
55      return;
56   }
57
58   long da = deg(a);
59   long i;
60 
61   if (da < n) {
62      clear(x);
63      return;
64   }
65
66   if (&x != &a)
67      x.rep.SetLength(da-n+1);
68
69   for (i = 0; i <= da-n; i++)
70      x.rep[i] = a.rep[i+n];
71
72   if (&x == &a)
73      x.rep.SetLength(da-n+1);
74
75   x.normalize();
76}
77
78void LeftShift(ZZ_pX& x, const ZZ_pX& a, long n)
79{
80   if (n < 0) {
81      if (n < -NTL_MAX_LONG) Error("overflow in LeftShift");
82      RightShift(x, a, -n);
83      return;
84   }
85
86   if (n >= (1L << (NTL_BITS_PER_LONG-4)))
87      Error("overflow in LeftShift");
88
89   if (IsZero(a)) {
90      clear(x);
91      return;
92   }
93
94   long m = a.rep.length();
95
96   x.rep.SetLength(m+n);
97
98   long i;
99   for (i = m-1; i >= 0; i--)
100      x.rep[i+n] = a.rep[i];
101
102   for (i = 0; i < n; i++)
103      clear(x.rep[i]);
104}
105
106
107void ShiftAdd(ZZ_pX& U, const ZZ_pX& V, long n)
108// assumes input does not alias output
109{
110   if (IsZero(V))
111      return;
112
113   long du = deg(U);
114   long dv = deg(V);
115
116   long d = max(du, n+dv);
117
118   U.rep.SetLength(d+1);
119   long i;
120
121   for (i = du+1; i <= d; i++)
122      clear(U.rep[i]);
123
124   for (i = 0; i <= dv; i++)
125      add(U.rep[i+n], U.rep[i+n], V.rep[i]);
126
127   U.normalize();
128}
129
130void ShiftSub(ZZ_pX& U, const ZZ_pX& V, long n)
131// assumes input does not alias output
132{
133   if (IsZero(V))
134      return;
135
136   long du = deg(U);
137   long dv = deg(V);
138
139   long d = max(du, n+dv);
140
141   U.rep.SetLength(d+1);
142   long i;
143
144   for (i = du+1; i <= d; i++)
145      clear(U.rep[i]);
146
147   for (i = 0; i <= dv; i++)
148      sub(U.rep[i+n], U.rep[i+n], V.rep[i]);
149
150   U.normalize();
151}
152
153
154void mul(ZZ_pX& U, ZZ_pX& V, const ZZ_pXMatrix& M)
155// (U, V)^T = M*(U, V)^T
156{
157   long d = deg(U) - deg(M(1,1));
158   long k = NextPowerOfTwo(d - 1);
159
160   // When the GCD algorithm is run on polynomials of degree n, n-1,
161   // where n is a power of two, then d-1 is likely to be a power of two.
162   // It would be more natural to set k = NextPowerOfTwo(d+1), but this
163   // would be much less efficient in this case.
164
165   // We optimize this case, as it does sometimes arise naturally
166   // in some situations.
167
168   long n = (1L << k);
169   long xx;
170   ZZ_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0;
171   static ZZ t1, t2;
172
173   if (n == d-1)
174      xx = 1;
175   else if (n == d)
176      xx = 2;
177   else 
178      xx = 3;
179
180   switch (xx) {
181   case 1:
182      GetCoeff(a0, M(0,0), 0);
183      GetCoeff(a1, M(0,0), 1);
184      GetCoeff(b0, M(0,1), 0);
185      GetCoeff(b1, M(0,1), 1);
186      GetCoeff(c0, M(1,0), 0);
187      GetCoeff(d0, M(1,1), 0);
188
189      GetCoeff(u0, U, 0);
190      GetCoeff(u1, U, 1);
191      GetCoeff(v0, V, 0);
192      GetCoeff(v1, V, 1);
193
194      mul(t1, rep(a0), rep(u0));
195      mul(t2, rep(b0), rep(v0));
196      add(t1, t1, t2); 
197      conv(nu0, t1);
198
199      mul(t1, rep(a1), rep(u0));
200      mul(t2, rep(a0), rep(u1));
201      add(t1, t1, t2);
202      mul(t2, rep(b1), rep(v0));
203      add(t1, t1, t2);
204      mul(t2, rep(b0), rep(v1));
205      add(t1, t1, t2);
206      conv(nu1, t1);
207
208      mul(t1, rep(c0), rep(u0));
209      mul(t2, rep(d0), rep(v0));
210      add (t1, t1, t2);
211      conv(nv0, t1);
212   
213      break;
214
215   case 2:
216      GetCoeff(a0, M(0,0), 0);
217      GetCoeff(b0, M(0,1), 0);
218
219      GetCoeff(u0, U, 0);
220      GetCoeff(v0, V, 0);
221
222      mul(t1, rep(a0), rep(u0));
223      mul(t2, rep(b0), rep(v0));
224      add(t1, t1, t2); 
225      conv(nu0, t1);
226
227      break;
228
229   case 3:
230      break;
231
232   }
233
234   FFTRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), 
235          R2(INIT_SIZE, k);
236
237   ToFFTRep(RU, U, k); 
238   ToFFTRep(RV, V, k); 
239
240   ToFFTRep(R1, M(0,0), k);
241   mul(R1, R1, RU);
242   ToFFTRep(R2, M(0,1), k);
243   mul(R2, R2, RV);
244   add(R1, R1, R2);
245   FromFFTRep(U, R1, 0, d);
246
247   ToFFTRep(R1, M(1,0), k);
248   mul(R1, R1, RU);
249   ToFFTRep(R2, M(1,1), k);
250   mul(R2, R2, RV);
251   add(R1, R1, R2);
252   FromFFTRep(V, R1, 0, d-1);
253
254   // now fix-up results
255
256   switch (xx) {
257   case 1:
258      GetCoeff(u0, U, 0);
259      sub(u0, u0, nu0);
260      SetCoeff(U, d-1, u0);
261      SetCoeff(U, 0, nu0);
262
263      GetCoeff(u1, U, 1);
264      sub(u1, u1, nu1);
265      SetCoeff(U, d, u1);
266      SetCoeff(U, 1, nu1);
267
268      GetCoeff(v0, V, 0);
269      sub(v0, v0, nv0);
270      SetCoeff(V, d-1, v0);
271      SetCoeff(V, 0, nv0);
272
273      break;
274     
275
276   case 2:
277      GetCoeff(u0, U, 0);
278      sub(u0, u0, nu0);
279      SetCoeff(U, d, u0);
280      SetCoeff(U, 0, nu0);
281
282      break;
283
284   }
285}
286
287
288void mul(ZZ_pXMatrix& A, ZZ_pXMatrix& B, ZZ_pXMatrix& C)
289// A = B*C, B and C are destroyed
290{
291   long db = deg(B(1,1));
292   long dc = deg(C(1,1));
293   long da = db + dc;
294
295   long k = NextPowerOfTwo(da+1);
296
297   FFTRep B00, B01, B10, B11, C0, C1, T1, T2;
298   
299   ToFFTRep(B00, B(0,0), k); B(0,0).kill();
300   ToFFTRep(B01, B(0,1), k); B(0,1).kill();
301   ToFFTRep(B10, B(1,0), k); B(1,0).kill();
302   ToFFTRep(B11, B(1,1), k); B(1,1).kill();
303
304   ToFFTRep(C0, C(0,0), k);  C(0,0).kill();
305   ToFFTRep(C1, C(1,0), k);  C(1,0).kill();
306
307   mul(T1, B00, C0);
308   mul(T2, B01, C1);
309   add(T1, T1, T2);
310   FromFFTRep(A(0,0), T1, 0, da);
311
312   mul(T1, B10, C0);
313   mul(T2, B11, C1);
314   add(T1, T1, T2);
315   FromFFTRep(A(1,0), T1, 0, da);
316
317   ToFFTRep(C0, C(0,1), k);  C(0,1).kill();
318   ToFFTRep(C1, C(1,1), k);  C(1,1).kill();
319
320   mul(T1, B00, C0);
321   mul(T2, B01, C1);
322   add(T1, T1, T2);
323   FromFFTRep(A(0,1), T1, 0, da);
324
325   mul(T1, B10, C0);
326   mul(T2, B11, C1);
327   add(T1, T1, T2);
328   FromFFTRep(A(1,1), T1, 0, da);
329}
330
331void IterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red)
332{
333   M_out(0,0).SetMaxLength(d_red);
334   M_out(0,1).SetMaxLength(d_red);
335   M_out(1,0).SetMaxLength(d_red);
336   M_out(1,1).SetMaxLength(d_red);
337
338   set(M_out(0,0));   clear(M_out(0,1));
339   clear(M_out(1,0)); set(M_out(1,1));
340
341   long goal = deg(U) - d_red;
342
343   if (deg(V) <= goal)
344      return;
345
346   ZZVec tmp(deg(U)+1, ZZ_pInfo->ExtendedModulusSize);
347   ZZ_pX Q, t(INIT_SIZE, d_red);
348
349   while (deg(V) > goal) {
350      PlainDivRem(Q, U, U, V, tmp);
351      swap(U, V);
352
353      mul(t, Q, M_out(1,0));
354      sub(t, M_out(0,0), t);
355      M_out(0,0) = M_out(1,0);
356      M_out(1,0) = t;
357
358      mul(t, Q, M_out(1,1));
359      sub(t, M_out(0,1), t);
360      M_out(0,1) = M_out(1,1);
361      M_out(1,1) = t;
362   }
363}
364   
365
366
367void HalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red)
368{
369   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
370      set(M_out(0,0));   clear(M_out(0,1));
371      clear(M_out(1,0)); set(M_out(1,1));
372 
373      return;
374   }
375
376
377   long n = deg(U) - 2*d_red + 2;
378   if (n < 0) n = 0;
379
380   ZZ_pX U1, V1;
381
382   RightShift(U1, U, n);
383   RightShift(V1, V, n);
384
385   if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) {
386      IterHalfGCD(M_out, U1, V1, d_red);
387      return;
388   }
389
390   long d1 = (d_red + 1)/2;
391   if (d1 < 1) d1 = 1;
392   if (d1 >= d_red) d1 = d_red - 1;
393
394   ZZ_pXMatrix M1;
395
396   HalfGCD(M1, U1, V1, d1);
397   mul(U1, V1, M1);
398
399   long d2 = deg(V1) - deg(U) + n + d_red;
400
401   if (IsZero(V1) || d2 <= 0) {
402      M_out = M1;
403      return;
404   }
405
406
407   ZZ_pX Q;
408   ZZ_pXMatrix M2;
409
410   DivRem(Q, U1, U1, V1);
411   swap(U1, V1);
412
413   HalfGCD(M2, U1, V1, d2);
414
415   ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
416
417   mul(t, Q, M1(1,0));
418   sub(t, M1(0,0), t);
419   swap(M1(0,0), M1(1,0));
420   swap(M1(1,0), t);
421
422   t.kill();
423
424   t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
425
426   mul(t, Q, M1(1,1));
427   sub(t, M1(0,1), t);
428   swap(M1(0,1), M1(1,1));
429   swap(M1(1,1), t);
430
431   t.kill();
432
433   mul(M_out, M2, M1); 
434}
435
436
437
438
439void XHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red)
440{
441   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
442      set(M_out(0,0));   clear(M_out(0,1));
443      clear(M_out(1,0)); set(M_out(1,1));
444 
445      return;
446   }
447
448   long du = deg(U);
449
450   if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) {
451      IterHalfGCD(M_out, U, V, d_red);
452      return;
453   }
454
455   long d1 = (d_red + 1)/2;
456   if (d1 < 1) d1 = 1;
457   if (d1 >= d_red) d1 = d_red - 1;
458
459   ZZ_pXMatrix M1;
460
461   HalfGCD(M1, U, V, d1);
462   mul(U, V, M1);
463
464   long d2 = deg(V) - du + d_red;
465
466   if (IsZero(V) || d2 <= 0) {
467      M_out = M1;
468      return;
469   }
470
471
472   ZZ_pX Q;
473   ZZ_pXMatrix M2;
474
475   DivRem(Q, U, U, V);
476   swap(U, V);
477
478   XHalfGCD(M2, U, V, d2);
479
480   ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
481
482   mul(t, Q, M1(1,0));
483   sub(t, M1(0,0), t);
484   swap(M1(0,0), M1(1,0));
485   swap(M1(1,0), t);
486
487   t.kill();
488
489   t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
490
491   mul(t, Q, M1(1,1));
492   sub(t, M1(0,1), t);
493   swap(M1(0,1), M1(1,1));
494   swap(M1(1,1), t);
495
496   t.kill();
497
498   mul(M_out, M2, M1); 
499}
500
501void HalfGCD(ZZ_pX& U, ZZ_pX& V)
502{
503   long d_red = (deg(U)+1)/2;
504
505   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
506      return;
507   }
508
509   long du = deg(U);
510
511
512   long d1 = (d_red + 1)/2;
513   if (d1 < 1) d1 = 1;
514   if (d1 >= d_red) d1 = d_red - 1;
515
516   ZZ_pXMatrix M1;
517
518   HalfGCD(M1, U, V, d1);
519   mul(U, V, M1);
520
521   long d2 = deg(V) - du + d_red;
522
523   if (IsZero(V) || d2 <= 0) {
524      return;
525   }
526
527   M1(0,0).kill();
528   M1(0,1).kill();
529   M1(1,0).kill();
530   M1(1,1).kill();
531
532
533   ZZ_pX Q;
534
535   DivRem(Q, U, U, V);
536   swap(U, V);
537
538   HalfGCD(M1, U, V, d2);
539
540   mul(U, V, M1); 
541}
542
543
544void GCD(ZZ_pX& d, const ZZ_pX& u, const ZZ_pX& v)
545{
546   ZZ_pX u1, v1;
547
548   u1 = u;
549   v1 = v;
550
551   if (deg(u1) == deg(v1)) {
552      if (IsZero(u1)) {
553         clear(d);
554         return;
555      }
556
557      rem(v1, v1, u1);
558   }
559   else if (deg(u1) < deg(v1)) {
560      swap(u1, v1);
561   }
562
563   // deg(u1) > deg(v1)
564
565   while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) {
566      HalfGCD(u1, v1);
567
568      if (!IsZero(v1)) {
569         rem(u1, u1, v1);
570         swap(u1, v1);
571      }
572   }
573
574   PlainGCD(d, u1, v1);
575}
576
577
578
579void XGCD(ZZ_pX& d, ZZ_pX& s, ZZ_pX& t, const ZZ_pX& a, const ZZ_pX& b)
580{
581   ZZ_p w;
582
583   if (IsZero(a) && IsZero(b)) {
584      clear(d);
585      set(s);
586      clear(t);
587      return;
588   }
589
590   ZZ_pX U, V, Q;
591
592   U = a;
593   V = b;
594
595   long flag = 0;
596
597   if (deg(U) == deg(V)) {
598      DivRem(Q, U, U, V);
599      swap(U, V);
600      flag = 1;
601   }
602   else if (deg(U) < deg(V)) {
603      swap(U, V);
604      flag = 2;
605   }
606
607   ZZ_pXMatrix M;
608
609   XHalfGCD(M, U, V, deg(U)+1);
610
611   d = U;
612
613   if (flag == 0) {
614      s = M(0,0); 
615      t = M(0,1);
616   }
617   else if (flag == 1) {
618      s = M(0,1);
619      mul(t, Q, M(0,1));
620      sub(t, M(0,0), t);
621   }
622   else {  /* flag == 2 */
623      s = M(0,1);
624      t = M(0,0);
625   }
626
627   // normalize
628
629   inv(w, LeadCoeff(d));
630   mul(d, d, w);
631   mul(s, s, w);
632   mul(t, t, w);
633}
634
635     
636
637
638
639
640
641void IterBuild(ZZ_p* a, long n)
642{
643   long i, k;
644   ZZ_p b, t;
645
646   if (n <= 0) return;
647
648   negate(a[0], a[0]);
649
650   for (k = 1; k <= n-1; k++) {
651      negate(b, a[k]);
652      add(a[k], b, a[k-1]);
653      for (i = k-1; i >= 1; i--) {
654         mul(t, a[i], b);
655         add(a[i], t, a[i-1]);
656      }
657      mul(a[0], a[0], b);
658   }
659} 
660
661void mul(ZZ_p* x, const ZZ_p* a, const ZZ_p* b, long n)
662{
663   static ZZ t, accum;
664
665   long i, j, jmin, jmax;
666
667   long d = 2*n-1;
668
669   for (i = 0; i <= d; i++) {
670      jmin = max(0, i-(n-1));
671      jmax = min(n-1, i);
672      clear(accum);
673      for (j = jmin; j <= jmax; j++) {
674         mul(t, rep(a[j]), rep(b[i-j]));
675         add(accum, accum, t);
676      }
677      if (i >= n) {
678         add(accum, accum, rep(a[i-n]));
679         add(accum, accum, rep(b[i-n]));
680      }
681
682      conv(x[i], accum);
683   }
684}
685
686
687void BuildFromRoots(ZZ_pX& x, const vec_ZZ_p& a)
688{
689   long n = a.length();
690
691   if (n == 0) {
692      set(x);
693      return;
694   }
695
696   long k0 = NextPowerOfTwo(NTL_ZZ_pX_FFT_CROSSOVER);
697   long crossover = 1L << k0;
698
699   if (n <= crossover) {
700      x.rep.SetMaxLength(n+1);
701      x.rep = a;
702      IterBuild(&x.rep[0], n);
703      x.rep.SetLength(n+1);
704      SetCoeff(x, n);
705      return;
706   }
707
708   long k = NextPowerOfTwo(n);
709
710   long m = 1L << k;
711   long i, j;
712   long l, width;
713
714   ZZ_pX b(INIT_SIZE, m+1);
715
716   b.rep = a;
717   b.rep.SetLength(m+1);
718   for (i = n; i < m; i++)
719      clear(b.rep[i]);
720
721   set(b.rep[m]);
722   
723   FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k);
724
725
726   ZZ_p t1, one;
727   set(one);
728
729   vec_ZZ_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover);
730   ZZ_p *g = G.elts();
731   ZZ_p *h = H.elts();
732   ZZ_p *tmp;
733   
734   for (i = 0; i < m; i+= crossover) {
735      for (j = 0; j < crossover; j++)
736         negate(g[j], b.rep[i+j]);
737
738      if (k0 > 0) {
739         for (j = 0; j < crossover; j+=2) {
740            mul(t1, g[j], g[j+1]);
741            add(g[j+1], g[j], g[j+1]);
742            g[j] = t1;
743         }
744      }
745   
746      for (l = 1; l < k0; l++) {
747         width = 1L << l;
748
749         for (j = 0; j < crossover; j += 2*width)
750            mul(&h[j], &g[j], &g[j+width], width);
751     
752         tmp = g; g = h; h = tmp;
753      }
754
755      for (j = 0; j < crossover; j++)
756         b.rep[i+j] = g[j];
757   }
758
759   for (l = k0; l < k; l++) {
760      width = 1L << l;
761      for (i = 0; i < m; i += 2*width) {
762         t1 = b.rep[i+width];
763         set(b.rep[i+width]);
764         ToFFTRep(R1, b, l+1, i, i+width);
765         b.rep[i+width] = t1;
766         t1 = b.rep[i+2*width];
767         set(b.rep[i+2*width]);
768         ToFFTRep(R2, b, l+1, i+width, i+2*width);
769         b.rep[i+2*width] = t1;
770         mul(R1, R1, R2);
771         FromFFTRep(&b.rep[i], R1, 0, 2*width-1);
772         sub(b.rep[i], b.rep[i], one);
773      }
774   }
775
776   x.rep.SetLength(n+1);
777   long delta = m-n;
778   for (i = 0; i <= n; i++)
779     x.rep[i] = b.rep[i+delta];
780
781   // no need to normalize
782}
783
784
785
786void eval(ZZ_p& b, const ZZ_pX& f, const ZZ_p& a)
787// does a Horner evaluation
788{
789   ZZ_p acc;
790   long i;
791
792   clear(acc);
793   for (i = deg(f); i >= 0; i--) {
794      mul(acc, acc, a);
795      add(acc, acc, f.rep[i]);
796   }
797
798   b = acc;
799}
800
801
802
803void eval(vec_ZZ_p& b, const ZZ_pX& f, const vec_ZZ_p& a)
804// naive algorithm:  repeats Horner
805{
806   if (&b == &f.rep) {
807      vec_ZZ_p bb;
808      eval(bb, f, a);
809      b = bb;
810      return;
811   }
812
813   long m = a.length();
814   b.SetLength(m);
815   long i;
816   for (i = 0; i < m; i++) 
817      eval(b[i], f, a[i]);
818}
819
820
821
822
823void interpolate(ZZ_pX& f, const vec_ZZ_p& a, const vec_ZZ_p& b)
824{
825   long m = a.length();
826   if (b.length() != m) Error("interpolate: vector length mismatch");
827
828   if (m == 0) {
829      clear(f);
830      return;
831   }
832
833   vec_ZZ_p prod;
834   prod = a;
835
836   ZZ_p t1, t2;
837
838   long k, i;
839
840   vec_ZZ_p res;
841   res.SetLength(m);
842
843   for (k = 0; k < m; k++) {
844
845      const ZZ_p& aa = a[k];
846
847      set(t1);
848      for (i = k-1; i >= 0; i--) {
849         mul(t1, t1, aa);
850         add(t1, t1, prod[i]);
851      }
852
853      clear(t2);
854      for (i = k-1; i >= 0; i--) {
855         mul(t2, t2, aa);
856         add(t2, t2, res[i]);
857      }
858
859
860      inv(t1, t1);
861      sub(t2, b[k], t2);
862      mul(t1, t1, t2);
863
864      for (i = 0; i < k; i++) {
865         mul(t2, prod[i], t1);
866         add(res[i], res[i], t2);
867      }
868
869      res[k] = t1;
870
871      if (k < m-1) {
872         if (k == 0)
873            negate(prod[0], prod[0]);
874         else {
875            negate(t1, a[k]);
876            add(prod[k], t1, prod[k-1]);
877            for (i = k-1; i >= 1; i--) {
878               mul(t2, prod[i], t1);
879               add(prod[i], t2, prod[i-1]);
880            }
881            mul(prod[0], prod[0], t1);
882         }
883      }
884   }
885
886   while (m > 0 && IsZero(res[m-1])) m--; 
887   res.SetLength(m);
888   f.rep = res;
889}
890
891NTL_vector_impl(ZZ_pX,vec_ZZ_pX)
892
893NTL_eq_vector_impl(ZZ_pX,vec_ZZ_pX)
894
895NTL_io_vector_impl(ZZ_pX,vec_ZZ_pX)
896
897
898
899   
900void InnerProduct(ZZ_pX& x, const vec_ZZ_p& v, long low, long high, 
901                   const vec_ZZ_pX& H, long n, ZZVec& t)
902{
903   static ZZ s;
904   long i, j;
905
906   for (j = 0; j < n; j++)
907      clear(t[j]);
908
909   high = min(high, v.length()-1);
910   for (i = low; i <= high; i++) {
911      const vec_ZZ_p& h = H[i-low].rep;
912      long m = h.length();
913      const ZZ& w = rep(v[i]);
914
915      for (j = 0; j < m; j++) {
916         mul(s, w, rep(h[j]));
917         add(t[j], t[j], s);
918      }
919   }
920
921   x.rep.SetLength(n);
922   for (j = 0; j < n; j++)
923      conv(x.rep[j], t[j]);
924   x.normalize();
925}
926
927
928void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& A, 
929             const ZZ_pXModulus& F)
930{
931   if (deg(g) <= 0) {
932      x = g;
933      return;
934   }
935
936
937   ZZ_pX s, t;
938   ZZVec scratch(F.n, ZZ_pInfo->ExtendedModulusSize);
939
940   long m = A.H.length() - 1;
941   long l = ((g.rep.length()+m-1)/m) - 1;
942
943   ZZ_pXMultiplier M;
944   build(M, A.H[m], F);
945
946   InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch);
947   for (long i = l-1; i >= 0; i--) {
948      InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch);
949      MulMod(t, t, M, F);
950      add(t, t, s);
951   }
952
953   x = t;
954}
955
956
957void build(ZZ_pXArgument& A, const ZZ_pX& h, const ZZ_pXModulus& F, long m)
958{
959   if (m <= 0 || deg(h) >= F.n) Error("build: bad args");
960
961   if (m > F.n) m = F.n;
962
963   long i;
964
965   if (ZZ_pXArgBound > 0) {
966      double sz = ZZ_p::storage();
967      sz = sz*F.n;
968      sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p);
969      sz = sz/1024;
970      m = min(m, long(ZZ_pXArgBound/sz));
971      m = max(m, 1);
972   }
973
974   ZZ_pXMultiplier M;
975
976   build(M, h, F);
977
978   A.H.SetLength(m+1);
979
980   set(A.H[0]);
981   A.H[1] = h;
982   for (i = 2; i <= m; i++) 
983      MulMod(A.H[i], A.H[i-1], M, F);
984}
985
986
987
988
989long ZZ_pXArgBound = 0;
990
991
992void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pX& h, const ZZ_pXModulus& F)
993   // x = g(h) mod f
994{
995   long m = SqrRoot(g.rep.length());
996
997   if (m == 0) {
998      clear(x);
999      return;
1000   }
1001
1002   ZZ_pXArgument A;
1003
1004   build(A, h, F, m);
1005
1006   CompMod(x, g, A, F);
1007}
1008
1009
1010
1011
1012void Comp2Mod(ZZ_pX& x1, ZZ_pX& x2, const ZZ_pX& g1, const ZZ_pX& g2,
1013              const ZZ_pX& h, const ZZ_pXModulus& F)
1014
1015{
1016   long m = SqrRoot(g1.rep.length() + g2.rep.length());
1017
1018   if (m == 0) {
1019      clear(x1);
1020      clear(x2);
1021      return;
1022   }
1023
1024   ZZ_pXArgument A;
1025
1026   build(A, h, F, m);
1027
1028   ZZ_pX xx1, xx2;
1029
1030   CompMod(xx1, g1, A, F);
1031   CompMod(xx2, g2, A, F);
1032
1033   x1 = xx1;
1034   x2 = xx2;
1035}
1036
1037void Comp3Mod(ZZ_pX& x1, ZZ_pX& x2, ZZ_pX& x3, 
1038              const ZZ_pX& g1, const ZZ_pX& g2, const ZZ_pX& g3,
1039              const ZZ_pX& h, const ZZ_pXModulus& F)
1040
1041{
1042   long m = SqrRoot(g1.rep.length() + g2.rep.length() + g3.rep.length());
1043
1044   if (m == 0) {
1045      clear(x1);
1046      clear(x2);
1047      clear(x3);
1048      return;
1049   }
1050
1051   ZZ_pXArgument A;
1052
1053   build(A, h, F, m);
1054
1055   ZZ_pX xx1, xx2, xx3;
1056
1057   CompMod(xx1, g1, A, F);
1058   CompMod(xx2, g2, A, F);
1059   CompMod(xx3, g3, A, F);
1060
1061   x1 = xx1;
1062   x2 = xx2;
1063   x3 = xx3;
1064}
1065
1066
1067static void StripZeroes(vec_ZZ_p& x)
1068{
1069   long n = x.length();
1070   while (n > 0 && IsZero(x[n-1]))
1071      n--;
1072   x.SetLength(n);
1073}
1074
1075
1076void PlainUpdateMap(vec_ZZ_p& xx, const vec_ZZ_p& a, 
1077                    const ZZ_pX& b, const ZZ_pX& f)
1078{
1079   long n = deg(f);
1080   long i, m;
1081
1082   if (IsZero(b)) {
1083      xx.SetLength(0);
1084      return;
1085   }
1086
1087   m = n-1 - deg(b);
1088
1089   vec_ZZ_p x(INIT_SIZE, n);
1090
1091   for (i = 0; i <= m; i++)
1092      InnerProduct(x[i], a, b.rep, i);
1093
1094   if (deg(b) != 0) {
1095      ZZ_pX c(INIT_SIZE, n);
1096      LeftShift(c, b, m);
1097
1098      for (i = m+1; i < n; i++) {
1099         MulByXMod(c, c, f);
1100         InnerProduct(x[i], a, c.rep);
1101      }
1102   }
1103
1104   xx = x;
1105}
1106   
1107
1108void UpdateMap(vec_ZZ_p& x, const vec_ZZ_p& aa, 
1109               const ZZ_pXMultiplier& B, const ZZ_pXModulus& F)
1110{
1111   long n = F.n;
1112   long i;
1113
1114
1115   vec_ZZ_p a;
1116   a = aa;
1117   StripZeroes(a);
1118
1119   if (a.length() > n) Error("UpdateMap: bad args");
1120
1121   if (!B.UseFFT) {
1122      PlainUpdateMap(x, a, B.b, F.f);
1123      StripZeroes(x);
1124      return;
1125   }
1126
1127   FFTRep R1(INIT_SIZE, F.k), R2(INIT_SIZE, F.l);
1128   vec_ZZ_p V1(INIT_SIZE, n);
1129
1130
1131   RevToFFTRep(R1, a, F.k, 0, a.length()-1, 0);
1132   mul(R2, R1, F.FRep);
1133   RevFromFFTRep(V1, R2, 0, n-2);
1134   for (i = 0; i <= n-2; i++)  negate(V1[i], V1[i]);
1135   RevToFFTRep(R2, V1, F.l, 0, n-2, n-1);
1136   mul(R2, R2, B.B1);
1137   mul(R1, R1, B.B2);
1138
1139   AddExpand(R2, R1);
1140   RevFromFFTRep(x, R2, 0, n-1);
1141   StripZeroes(x);
1142}
1143
1144   
1145
1146void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
1147                   const ZZ_pXArgument& H, const ZZ_pXModulus& F)
1148
1149{
1150   long n = F.n;
1151
1152   if (a.length() > n || k < 0 || k >= (1L << (NTL_BITS_PER_LONG-4))) 
1153      Error("ProjectPowers: bad args");
1154
1155   long m = H.H.length()-1;
1156   long l = (k+m-1)/m - 1;
1157
1158   ZZ_pXMultiplier M;
1159   build(M, H.H[m], F);
1160
1161   vec_ZZ_p s(INIT_SIZE, n);
1162   s = a;
1163   StripZeroes(s);
1164
1165   x.SetLength(k);
1166
1167   for (long i = 0; i <= l; i++) {
1168      long m1 = min(m, k-i*m);
1169      ZZ_p* w = &x[i*m];
1170      for (long j = 0; j < m1; j++)
1171         InnerProduct(w[j], H.H[j].rep, s);
1172      if (i < l)
1173         UpdateMap(s, s, M, F);
1174   }
1175}
1176
1177
1178
1179void ProjectPowers(vec_ZZ_p& x, const vec_ZZ_p& a, long k,
1180                   const ZZ_pX& h, const ZZ_pXModulus& F)
1181
1182{
1183   if (a.length() > F.n || k < 0) Error("ProjectPowers: bad args");
1184
1185   if (k == 0) {
1186      x.SetLength(0);
1187      return;
1188   }
1189
1190   long m = SqrRoot(k);
1191
1192   ZZ_pXArgument H;
1193
1194   build(H, h, F, m);
1195   ProjectPowers(x, a, k, H, F);
1196}
1197
1198
1199void BerlekampMassey(ZZ_pX& h, const vec_ZZ_p& a, long m)
1200{
1201   ZZ_pX Lambda, Sigma, Temp;
1202   long L;
1203   ZZ_p Delta, Delta1, t1;
1204   long shamt;
1205
1206   // cerr << "*** " << m << "\n";
1207
1208   Lambda.SetMaxLength(m+1);
1209   Sigma.SetMaxLength(m+1);
1210   Temp.SetMaxLength(m+1);
1211
1212   L = 0;
1213   set(Lambda);
1214   clear(Sigma);
1215   set(Delta);
1216   shamt = 0;
1217
1218   long i, r, dl;
1219
1220   for (r = 1; r <= 2*m; r++) {
1221      // cerr << r << "--";
1222      clear(Delta1);
1223      dl = deg(Lambda);
1224      for (i = 0; i <= dl; i++) {
1225         mul(t1, Lambda.rep[i], a[r-i-1]);
1226         add(Delta1, Delta1, t1);
1227      }
1228
1229      if (IsZero(Delta1)) {
1230         shamt++;
1231         // cerr << "case 1: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n";
1232      }
1233      else if (2*L < r) {
1234         div(t1, Delta1, Delta);
1235         mul(Temp, Sigma, t1);
1236         Sigma = Lambda;
1237         ShiftSub(Lambda, Temp, shamt+1);
1238         shamt = 0;
1239         L = r-L;
1240         Delta = Delta1;
1241         // cerr << "case 2: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n";
1242      }
1243      else {
1244         shamt++;
1245         div(t1, Delta1, Delta);
1246         mul(Temp, Sigma, t1);
1247         ShiftSub(Lambda, Temp, shamt);
1248         // cerr << "case 3: " << deg(Lambda) << " " << deg(Sigma) << " " << shamt << "\n";
1249      }
1250   }
1251
1252   // cerr << "finished: " << L << " " << deg(Lambda) << "\n";
1253
1254   dl = deg(Lambda);
1255   h.rep.SetLength(L + 1);
1256
1257   for (i = 0; i < L - dl; i++)
1258      clear(h.rep[i]);
1259
1260   for (i = L - dl; i <= L; i++)
1261      h.rep[i] = Lambda.rep[L - i];
1262}
1263
1264
1265
1266
1267void GCDMinPolySeq(ZZ_pX& h, const vec_ZZ_p& x, long m)
1268{
1269   long i;
1270   ZZ_pX a, b;
1271   ZZ_pXMatrix M;
1272   ZZ_p t;
1273
1274   a.rep.SetLength(2*m);
1275   for (i = 0; i < 2*m; i++) a.rep[i] = x[2*m-1-i];
1276   a.normalize();
1277
1278   SetCoeff(b, 2*m);
1279
1280   HalfGCD(M, b, a, m+1);
1281
1282   /* make monic */
1283
1284   inv(t, LeadCoeff(M(1,1)));
1285   mul(h, M(1,1), t);
1286}
1287
1288
1289void MinPolySeq(ZZ_pX& h, const vec_ZZ_p& a, long m)
1290{
1291   if (m < 0 || m >= (1L << (NTL_BITS_PER_LONG-4))) Error("MinPoly: bad args");
1292   if (a.length() < 2*m) Error("MinPoly: sequence too short");
1293
1294   if (m > NTL_ZZ_pX_BERMASS_CROSSOVER)
1295      GCDMinPolySeq(h, a, m);
1296   else
1297      BerlekampMassey(h, a, m);
1298}
1299
1300
1301void DoMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m,
1302               const vec_ZZ_p& R) 
1303{
1304   vec_ZZ_p x;
1305
1306   ProjectPowers(x, R, 2*m, g, F);
1307   MinPolySeq(h, x, m);
1308}
1309
1310
1311void ProbMinPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) 
1312{
1313   long n = F.n;
1314   if (m < 1 || m > n) Error("ProbMinPoly: bad args");
1315   
1316   long i;
1317   vec_ZZ_p R(INIT_SIZE, n);
1318
1319   for (i = 0; i < n; i++) random(R[i]);
1320   DoMinPolyMod(h, g, F, m, R);
1321}
1322
1323void MinPolyMod(ZZ_pX& hh, const ZZ_pX& g, const ZZ_pXModulus& F, long m) 
1324{
1325   ZZ_pX h, h1;
1326   long n = F.n;
1327   if (m < 1 || m > n) Error("MinPoly: bad args");
1328
1329   /* probabilistically compute min-poly */
1330
1331   ProbMinPolyMod(h, g, F, m);
1332   if (deg(h) == m) { hh = h; return; }
1333   CompMod(h1, h, g, F);
1334   if (IsZero(h1)) { hh = h; return; }
1335
1336   /* not completely successful...must iterate */
1337
1338   long i;
1339
1340   ZZ_pX h2, h3;
1341   ZZ_pXMultiplier H1;
1342   vec_ZZ_p R(INIT_SIZE, n);
1343
1344   for (;;) {
1345      R.SetLength(n);
1346      for (i = 0; i < n; i++) random(R[i]);
1347      build(H1, h1, F);
1348      UpdateMap(R, R, H1, F);
1349      DoMinPolyMod(h2, g, F, m-deg(h), R);
1350
1351      mul(h, h, h2);
1352      if (deg(h) == m) { hh = h; return; }
1353      CompMod(h3, h2, g, F);
1354      MulMod(h1, h3, H1, F);
1355      if (IsZero(h1)) { hh = h; return; }
1356   }
1357}
1358
1359
1360
1361void IrredPolyMod(ZZ_pX& h, const ZZ_pX& g, const ZZ_pXModulus& F, long m) 
1362{
1363   vec_ZZ_p R(INIT_SIZE, 1);
1364   if (m < 1 || m > F.n) Error("IrredPoly: bad args");
1365
1366   set(R[0]);
1367   DoMinPolyMod(h, g, F, m, R);
1368}
1369
1370
1371
1372void diff(ZZ_pX& x, const ZZ_pX& a)
1373{
1374   long n = deg(a);
1375   long i;
1376
1377   if (n <= 0) {
1378      clear(x);
1379      return;
1380   }
1381
1382   if (&x != &a)
1383      x.rep.SetLength(n);
1384
1385   for (i = 0; i <= n-1; i++) {
1386      mul(x.rep[i], a.rep[i+1], i+1);
1387   }
1388
1389   if (&x == &a)
1390      x.rep.SetLength(n);
1391
1392   x.normalize();
1393}
1394
1395
1396void MakeMonic(ZZ_pX& x)
1397{
1398   if (IsZero(x))
1399      return;
1400
1401   if (IsOne(LeadCoeff(x)))
1402      return;
1403
1404   ZZ_p t;
1405
1406   inv(t, LeadCoeff(x));
1407   mul(x, x, t);
1408}
1409
1410
1411     
1412void PlainMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n)
1413{
1414   ZZ_pX y;
1415   mul(y, a, b);
1416   trunc(x, y, n);
1417}
1418
1419
1420void FFTMulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n)
1421{
1422   if (IsZero(a) || IsZero(b)) {
1423      clear(x);
1424      return;
1425   }
1426
1427   long d = deg(a) + deg(b);
1428   if (n > d + 1)
1429      n = d + 1;
1430
1431   long k = NextPowerOfTwo(d + 1);
1432   FFTRep R1(INIT_SIZE, k), R2(INIT_SIZE, k);
1433
1434   ToFFTRep(R1, a, k);
1435   ToFFTRep(R2, b, k);
1436   mul(R1, R1, R2);
1437   FromFFTRep(x, R1, 0, n-1);
1438}
1439
1440void MulTrunc(ZZ_pX& x, const ZZ_pX& a, const ZZ_pX& b, long n)
1441{
1442   if (n < 0) Error("MulTrunc: bad args");
1443
1444   if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER || deg(b) <= NTL_ZZ_pX_FFT_CROSSOVER)
1445      PlainMulTrunc(x, a, b, n);
1446   else
1447      FFTMulTrunc(x, a, b, n);
1448}
1449
1450     
1451void PlainSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n)
1452{
1453   ZZ_pX y;
1454   sqr(y, a);
1455   trunc(x, y, n);
1456}
1457
1458
1459void FFTSqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n)
1460{
1461   if (IsZero(a)) {
1462      clear(x);
1463      return;
1464   }
1465
1466   long d = 2*deg(a);
1467   if (n > d + 1)
1468      n = d + 1;
1469
1470   long k = NextPowerOfTwo(d + 1);
1471   FFTRep R1(INIT_SIZE, k);
1472
1473   ToFFTRep(R1, a, k);
1474   mul(R1, R1, R1);
1475   FromFFTRep(x, R1, 0, n-1);
1476}
1477
1478void SqrTrunc(ZZ_pX& x, const ZZ_pX& a, long n)
1479{
1480   if (n < 0) Error("SqrTrunc: bad args");
1481
1482   if (deg(a) <= NTL_ZZ_pX_FFT_CROSSOVER)
1483      PlainSqrTrunc(x, a, n);
1484   else
1485      FFTSqrTrunc(x, a, n);
1486}
1487
1488
1489void FastTraceVec(vec_ZZ_p& S, const ZZ_pX& f)
1490{
1491   long n = deg(f);
1492
1493   if (n <= 0) 
1494      Error("FastTraceVec: bad args");
1495
1496   if (n == 0) {
1497      S.SetLength(0);
1498      return;
1499   }
1500
1501   if (n == 1) {
1502      S.SetLength(1);
1503      set(S[0]);
1504      return;
1505   }
1506   
1507   long i;
1508   ZZ_pX f1;
1509
1510   f1.rep.SetLength(n-1);
1511   for (i = 0; i <= n-2; i++)
1512      f1.rep[i] = f.rep[n-i];
1513   f1.normalize();
1514
1515   ZZ_pX f2;
1516   f2.rep.SetLength(n-1);
1517   for (i = 0; i <= n-2; i++)
1518      mul(f2.rep[i], f.rep[n-1-i], i+1);
1519   f2.normalize();
1520
1521   ZZ_pX f3;
1522   InvTrunc(f3, f1, n-1);
1523   MulTrunc(f3, f3, f2, n-1);
1524
1525   S.SetLength(n);
1526
1527   S[0] = n;
1528   for (i = 1; i < n; i++)
1529      negate(S[i], coeff(f3, i-1));
1530}
1531
1532
1533void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& ff)
1534{
1535   if (deg(ff) <= 0)
1536      Error("TraceVec: bad args");
1537
1538   ZZ_pX f;
1539   f = ff;
1540
1541   MakeMonic(f);
1542
1543   long n = deg(f);
1544
1545   S.SetLength(n);
1546
1547   if (n == 0)
1548      return;
1549
1550   long k, i;
1551   ZZ acc, t;
1552   ZZ_p t1;
1553
1554   S[0] = n;
1555
1556   for (k = 1; k < n; k++) {
1557      mul(acc, rep(f.rep[n-k]), k);
1558
1559      for (i = 1; i < k; i++) {
1560         mul(t, rep(f.rep[n-i]), rep(S[k-i]));
1561         add(acc, acc, t);
1562      }
1563
1564      conv(t1, acc);
1565      negate(S[k], t1);
1566   }
1567}
1568
1569void TraceVec(vec_ZZ_p& S, const ZZ_pX& f)
1570{
1571   if (deg(f) <= NTL_ZZ_pX_TRACE_CROSSOVER)
1572      PlainTraceVec(S, f);
1573   else
1574      FastTraceVec(S, f);
1575}
1576
1577void ComputeTraceVec(const ZZ_pXModulus& F)
1578{
1579   vec_ZZ_p& S = *((vec_ZZ_p *) &F.tracevec);
1580
1581   if (S.length() > 0)
1582      return;
1583
1584   if (!F.UseFFT) {
1585      PlainTraceVec(S, F.f);
1586      return;
1587   }
1588
1589   long i;
1590   long n = F.n;
1591
1592   FFTRep R;
1593   ZZ_pX P, g;
1594
1595   g.rep.SetLength(n-1);
1596   for (i = 1; i < n; i++)
1597      mul(g.rep[n-i-1], F.f.rep[n-i], i); 
1598   g.normalize();
1599
1600   ToFFTRep(R, g, F.l);
1601   mul(R, R, F.HRep);
1602   FromFFTRep(P, R, n-2, 2*n-4);
1603
1604   S.SetLength(n);
1605
1606   S[0] = n;
1607   for (i = 1; i < n; i++)
1608      negate(S[i], coeff(P, n-1-i));
1609}
1610
1611void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pXModulus& F)
1612{
1613   long n = F.n;
1614
1615   if (deg(a) >= n)
1616      Error("trace: bad args");
1617
1618   if (F.tracevec.length() == 0) 
1619      ComputeTraceVec(F);
1620
1621   InnerProduct(x, a.rep, F.tracevec);
1622}
1623
1624void TraceMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f)
1625{
1626   if (deg(a) >= deg(f) || deg(f) <= 0)
1627      Error("trace: bad args");
1628
1629   project(x, TraceVec(f), a);
1630}
1631
1632void PlainResultant(ZZ_p& rres, const ZZ_pX& a, const ZZ_pX& b)
1633{
1634   ZZ_p res;
1635 
1636   if (IsZero(a) || IsZero(b))
1637      clear(res);
1638   else if (deg(a) == 0 && deg(b) == 0) 
1639      set(res);
1640   else {
1641      long d0, d1, d2;
1642      ZZ_p lc;
1643      set(res);
1644
1645      long n = max(deg(a),deg(b)) + 1;
1646      ZZ_pX u(INIT_SIZE, n), v(INIT_SIZE, n);
1647      ZZVec tmp(n, ZZ_pInfo->ExtendedModulusSize);
1648
1649      u = a;
1650      v = b;
1651
1652      for (;;) {
1653         d0 = deg(u);
1654         d1 = deg(v);
1655         lc = LeadCoeff(v);
1656
1657         PlainRem(u, u, v, tmp);
1658         swap(u, v);
1659
1660         d2 = deg(v);
1661         if (d2 >= 0) {
1662            power(lc, lc, d0-d2);
1663            mul(res, res, lc);
1664            if (d0 & d1 & 1) negate(res, res);
1665         }
1666         else {
1667            if (d1 == 0) {
1668               power(lc, lc, d0);
1669               mul(res, res, lc);
1670            }
1671            else
1672               clear(res);
1673       
1674            break;
1675         }
1676      }
1677
1678      rres = res;
1679   }
1680}
1681
1682
1683void ResIterHalfGCD(ZZ_pXMatrix& M_out, ZZ_pX& U, ZZ_pX& V, long d_red,
1684                    vec_ZZ_p& cvec, vec_long& dvec)
1685{
1686   M_out(0,0).SetMaxLength(d_red);
1687   M_out(0,1).SetMaxLength(d_red);
1688   M_out(1,0).SetMaxLength(d_red);
1689   M_out(1,1).SetMaxLength(d_red);
1690
1691   set(M_out(0,0));   clear(M_out(0,1));
1692   clear(M_out(1,0)); set(M_out(1,1));
1693
1694   long goal = deg(U) - d_red;
1695
1696   if (deg(V) <= goal)
1697      return;
1698
1699   ZZVec tmp(deg(U)+1, ZZ_pInfo->ExtendedModulusSize);
1700   ZZ_pX Q, t(INIT_SIZE, d_red);
1701
1702
1703   while (deg(V) > goal) {
1704      append(cvec, LeadCoeff(V));
1705      append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V));
1706      PlainDivRem(Q, U, U, V, tmp);
1707      swap(U, V);
1708
1709      mul(t, Q, M_out(1,0));
1710      sub(t, M_out(0,0), t);
1711      M_out(0,0) = M_out(1,0);
1712      M_out(1,0) = t;
1713
1714      mul(t, Q, M_out(1,1));
1715      sub(t, M_out(0,1), t);
1716      M_out(0,1) = M_out(1,1);
1717      M_out(1,1) = t;
1718   }
1719}
1720   
1721
1722
1723void ResHalfGCD(ZZ_pXMatrix& M_out, const ZZ_pX& U, const ZZ_pX& V, long d_red,
1724                vec_ZZ_p& cvec, vec_long& dvec)
1725{
1726   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
1727      set(M_out(0,0));   clear(M_out(0,1));
1728      clear(M_out(1,0)); set(M_out(1,1));
1729 
1730      return;
1731   }
1732
1733
1734   long n = deg(U) - 2*d_red + 2;
1735   if (n < 0) n = 0;
1736
1737   ZZ_pX U1, V1;
1738
1739   RightShift(U1, U, n);
1740   RightShift(V1, V, n);
1741
1742   if (d_red <= NTL_ZZ_pX_HalfGCD_CROSSOVER) { 
1743      ResIterHalfGCD(M_out, U1, V1, d_red, cvec, dvec);
1744      return;
1745   }
1746
1747   long d1 = (d_red + 1)/2;
1748   if (d1 < 1) d1 = 1;
1749   if (d1 >= d_red) d1 = d_red - 1;
1750
1751   ZZ_pXMatrix M1;
1752
1753   ResHalfGCD(M1, U1, V1, d1, cvec, dvec);
1754   mul(U1, V1, M1);
1755
1756   long d2 = deg(V1) - deg(U) + n + d_red;
1757
1758   if (IsZero(V1) || d2 <= 0) {
1759      M_out = M1;
1760      return;
1761   }
1762
1763
1764   ZZ_pX Q;
1765   ZZ_pXMatrix M2;
1766
1767   append(cvec, LeadCoeff(V1));
1768   append(dvec, dvec[dvec.length()-1]-deg(U1)+deg(V1));
1769   DivRem(Q, U1, U1, V1);
1770   swap(U1, V1);
1771
1772   ResHalfGCD(M2, U1, V1, d2, cvec, dvec);
1773
1774   ZZ_pX t(INIT_SIZE, deg(M1(1,1))+deg(Q)+1);
1775
1776   mul(t, Q, M1(1,0));
1777   sub(t, M1(0,0), t);
1778   swap(M1(0,0), M1(1,0));
1779   swap(M1(1,0), t);
1780
1781   t.kill();
1782
1783   t.SetMaxLength(deg(M1(1,1))+deg(Q)+1);
1784
1785   mul(t, Q, M1(1,1));
1786   sub(t, M1(0,1), t);
1787   swap(M1(0,1), M1(1,1));
1788   swap(M1(1,1), t);
1789
1790   t.kill();
1791
1792   mul(M_out, M2, M1); 
1793}
1794
1795void ResHalfGCD(ZZ_pX& U, ZZ_pX& V, vec_ZZ_p& cvec, vec_long& dvec)
1796{
1797   long d_red = (deg(U)+1)/2;
1798
1799   if (IsZero(V) || deg(V) <= deg(U) - d_red) {
1800      return;
1801   }
1802
1803   long du = deg(U);
1804
1805
1806   long d1 = (d_red + 1)/2;
1807   if (d1 < 1) d1 = 1;
1808   if (d1 >= d_red) d1 = d_red - 1;
1809
1810   ZZ_pXMatrix M1;
1811
1812   ResHalfGCD(M1, U, V, d1, cvec, dvec);
1813   mul(U, V, M1);
1814
1815   long d2 = deg(V) - du + d_red;
1816
1817   if (IsZero(V) || d2 <= 0) {
1818      return;
1819   }
1820
1821   M1(0,0).kill();
1822   M1(0,1).kill();
1823   M1(1,0).kill();
1824   M1(1,1).kill();
1825
1826
1827   ZZ_pX Q;
1828
1829   append(cvec, LeadCoeff(V));
1830   append(dvec, dvec[dvec.length()-1]-deg(U)+deg(V));
1831   DivRem(Q, U, U, V);
1832   swap(U, V);
1833
1834   ResHalfGCD(M1, U, V, d2, cvec, dvec);
1835
1836   mul(U, V, M1); 
1837}
1838
1839
1840void resultant(ZZ_p& rres, const ZZ_pX& u, const ZZ_pX& v)
1841{
1842   if (deg(u) <= NTL_ZZ_pX_GCD_CROSSOVER || deg(v) <= NTL_ZZ_pX_GCD_CROSSOVER) { 
1843      PlainResultant(rres, u, v);
1844      return;
1845   }
1846
1847   ZZ_pX u1, v1;
1848
1849   u1 = u;
1850   v1 = v;
1851
1852   ZZ_p res, t;
1853   set(res);
1854
1855   if (deg(u1) == deg(v1)) {
1856      rem(u1, u1, v1);
1857      swap(u1, v1);
1858
1859      if (IsZero(v1)) {
1860         clear(rres);
1861         return;
1862      }
1863
1864      power(t, LeadCoeff(u1), deg(u1) - deg(v1));
1865      mul(res, res, t);
1866      if (deg(u1) & 1)
1867         negate(res, res);
1868   }
1869   else if (deg(u1) < deg(v1)) {
1870      swap(u1, v1);
1871      if (deg(u1) & deg(v1) & 1)
1872         negate(res, res);
1873   }
1874
1875   // deg(u1) > deg(v1) && v1 != 0
1876
1877   vec_ZZ_p cvec;
1878   vec_long  dvec;
1879
1880   cvec.SetMaxLength(deg(v1)+2);
1881   dvec.SetMaxLength(deg(v1)+2);
1882
1883   append(cvec, LeadCoeff(u1));
1884   append(dvec, deg(u1));
1885
1886
1887   while (deg(u1) > NTL_ZZ_pX_GCD_CROSSOVER && !IsZero(v1)) { 
1888      ResHalfGCD(u1, v1, cvec, dvec);
1889
1890      if (!IsZero(v1)) {
1891         append(cvec, LeadCoeff(v1));
1892         append(dvec, deg(v1));
1893         rem(u1, u1, v1);
1894         swap(u1, v1);
1895      }
1896   }
1897
1898   if (IsZero(v1) && deg(u1) > 0) {
1899      clear(rres);
1900      return;
1901   }
1902
1903   long i, l;
1904   l = dvec.length();
1905
1906   if (deg(u1) == 0) {
1907      // we went all the way...
1908
1909      for (i = 0; i <= l-3; i++) {
1910         power(t, cvec[i+1], dvec[i]-dvec[i+2]);
1911         mul(res, res, t);
1912         if (dvec[i] & dvec[i+1] & 1)
1913            negate(res, res);
1914      }
1915
1916      power(t, cvec[l-1], dvec[l-2]);
1917      mul(res, res, t);
1918   }
1919   else {
1920      for (i = 0; i <= l-3; i++) {
1921         power(t, cvec[i+1], dvec[i]-dvec[i+2]);
1922         mul(res, res, t);
1923         if (dvec[i] & dvec[i+1] & 1)
1924            negate(res, res);
1925      }
1926
1927      power(t, cvec[l-1], dvec[l-2]-deg(v1));
1928      mul(res, res, t);
1929      if (dvec[l-2] & dvec[l-1] & 1)
1930         negate(res, res);
1931
1932      PlainResultant(t, u1, v1);
1933      mul(res, res, t);
1934   }
1935
1936   rres = res;
1937}
1938
1939void NormMod(ZZ_p& x, const ZZ_pX& a, const ZZ_pX& f)
1940{
1941   if (deg(f) <= 0 || deg(a) >= deg(f)) 
1942      Error("norm: bad args");
1943
1944   if (IsZero(a)) {
1945      clear(x);
1946      return;
1947   }
1948
1949   ZZ_p t;
1950   resultant(t, f, a);
1951   if (!IsOne(LeadCoeff(f))) {
1952      ZZ_p t1;
1953      power(t1, LeadCoeff(f), deg(a));
1954      inv(t1, t1);
1955      mul(t, t, t1);
1956   }
1957
1958   x = t;
1959}
1960
1961NTL_END_IMPL
Note: See TracBrowser for help on using the repository browser.