Percy++
A C++ implementation of Private Information Retrieval (PIR) protocols
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
FXY.h
1 // Percy++ Copyright 2007,2012,2013,2014
2 // Ian Goldberg <iang@cs.uwaterloo.ca>,
3 // Casey Devet <cjdevet@uwaterloo.ca>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of version 2 of the GNU General Public License as
7 // published by the Free Software Foundation.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // There is a copy of the GNU General Public License in the COPYING file
15 // packaged with this plugin; if you cannot find it, write to the Free
16 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 // 02110-1301 USA
18 
19 // The FXY.cc and FXY.h files are adapted from files in version
20 // 5.4 of the NTL package by Victor Shoup <victor@shoup.net>, with
21 // modifications by M. Jason Hinek <mjhinek@alumni.uwaterloo.ca> and
22 // Ian Goldberg <iang@cs.uwaterloo.ca>.
23 
24 #ifndef __FXY_H__
25 #define __FXY_H__
26 
27 #include <NTL/ZZ_pX.h>
28 #include <NTL/GF2EX.h>
29 
30 NTL_OPEN_NNS
31 
32 #define FTXY FXY<F,FX,vec_FX>
33 
34 
35 
36 /************************************************************
37 
38  FXY
39 
40 The class FXY implements bivariate polynomial arithmetic over a field F.
41 Polynomials are represented as vec_FX's.
42 If f is a FXY, then f.rep is a vec_FX.
43 The zero polynomial is represented as a zero length vector.
44 Otherwise. f.rep[0] is the constant-term, and f.rep[f.rep.length()-1]
45 is the leading coefficient, which is always non-zero.
46 The member f.rep is public, so the vector representation is fully
47 accessible.
48 Use the member function normalize() to strip leading zeros.
49 
50 **************************************************************/
51 
52 template <class F, class FX, class vec_FX>
53 class FXY {
54 
55 public:
56 
57 typedef vec_FX VectorBaseType;
58 
59 
60 vec_FX rep;
61 
62 
63 /***************************************************************
64 
65  Constructors, Destructors, and Assignment
66 
67 ****************************************************************/
68 
69 
70 FXY()
71 // initial value 0
72 
73  { }
74 
75 
76 FXY(INIT_SIZE_TYPE, long n) { rep.SetMaxLength(n); }
77 
78 FXY(const FXY& a) : rep(a.rep) { }
79 // initial value is a
80 
81 
82 FXY& operator=(const FXY& a)
83  { rep = a.rep; return *this; }
84 
85 ~FXY() { }
86 
87 // strip leading zeros
88 void normalize(){
89  long n;
90  FX* p;
91 
92  // First normalize the coefficients
93  n = rep.length();
94  if (n == 0) return;
95  p = rep.elts() + n;
96  while (n > 0) {
97  --p;
98  p->normalize();
99  --n;
100  }
101 
102  n = rep.length();
103  p = rep.elts() + n;
104  while (n > 0 && IsZero(*--p)) {
105  n--;
106  }
107  rep.SetLength(n);
108 }
109 
110 void SetMaxLength(long n)
111 // pre-allocate space for n coefficients.
112 // Value is unchanged
113 
114  { rep.SetMaxLength(n); }
115 
116 
117 void kill()
118 // free space held by this polynomial. Value becomes 0.
119 
120  { rep.kill(); }
121 
122 static const FXY& zero() {
123  static FXY z;
124  return z;
125 }
126 
127 
128 FXY(FXY& x, INIT_TRANS_TYPE) : rep(x.rep, INIT_TRANS) { }
129 
130 inline FXY(long i, const FX& c);
131 inline FXY(long i, const F& c);
132 inline FXY(long i, long c);
133 
134 FXY& operator=(long a) { conv(*this, a); return *this; }
135 FXY& operator=(const F& a) { conv(*this, a); return *this; }
136 FXY& operator=(const FX& a) { conv(*this, a); return *this; }
137 
138 
139 };
140 
141 
142 
143 /********************************************************************
144 
145  input and output
146 
147 I/O format:
148 
149  [a_0 a_1 ... a_n],
150 
151 represents the polynomial a_0 + a_1*Y + ... + a_n*Y^n.
152 
153 On output, all coefficients will be polynomials of the type FX.
154 amd a_n not zero (the zero polynomial is [ ]).
155 On input, the coefficients are arbitrary polynomials which are
156 then reduced modulo p, and leading zeros stripped.
157 
158 *********************************************************************/
159 
160 
161 template <class F, class FX, class vec_FX>
162 NTL_SNS istream& operator>>(NTL_SNS istream& s, FXY<F,FX,vec_FX>& x)
163 {
164  s >> x.rep;
165  x.normalize();
166  return s;
167 }
168 
169 template <class F, class FX, class vec_FX>
170 NTL_SNS ostream& operator<<(NTL_SNS ostream& s, const FXY<F,FX,vec_FX>& a)
171 {
172  return s << a.rep;
173 }
174 
175 
176 
177 
178 /**********************************************************
179 
180  Some utility routines
181 
182 ***********************************************************/
183 
184 
185 
186 template <class F, class FX, class vec_FX>
187 inline long deg(const FXY<F,FX,vec_FX>& a) { return a.rep.length() - 1; }
188 // degree of a polynomial in Z_p[X][Y] (ie, degree wrt y).
189 // note that the zero polynomial has degree -1.
190 
191 template <class F, class FX, class vec_FX>
192 inline long degY(const FXY<F,FX,vec_FX>& a) { return a.rep.length() - 1; }
193 // degree of a polynomial in Z_p[X][Y] (ie, degree wrt y)
194 // note that the zero polynomial has degree -1.
195 
196 // degree of a polynomial in Z_p[Y][X] instead of Z_p[X][Y] (ie, degree wrt x)
197 // note that the zero polynomial has degree -1.
198 template <class F, class FX, class vec_FX>
199 long degX(const FXY<F,FX,vec_FX>& a)
200 {
201  //
202  // degree of polynomial in Z_p[Y][X] instead of Z_p[X][Y]
203  //
204  //
205 
206  long degY = a.rep.length() - 1;
207  long degX = -1;
208 
209  if(degY > -1){
210  degX = deg(a.rep[0]);
211  for(long i = 1; i <= degY; i++){
212  if( deg(a.rep[i]) > degX )
213  degX = deg(a.rep[i]);
214  }
215 
216  }
217 
218  return degX;
219 
220 }
221 
222 
223 
224 // zero if i not in range
225 template <class F, class FX, class vec_FX>
226 const FX& coeff(const FXY<F,FX,vec_FX>& a, long i)
227 {
228  if (i < 0 || i > deg(a))
229  return FX::zero();
230  else
231  return a.rep[i];
232 }
233 
234 // x = a[i], or zero if i not in range
235 template <class F, class FX, class vec_FX>
236 void GetCoeff(FX& x, const FXY<F,FX,vec_FX>& a, long i)
237 {
238  if (i < 0 || i > deg(a))
239  clear(x);
240  else
241  x = a.rep[i];
242 }
243 
244 // zero if a == 0
245 template <class F, class FX, class vec_FX>
246 const FX& LeadCoeff(const FXY<F,FX,vec_FX>& a)
247 {
248  if (IsZero(a))
249  return FX::zero();
250  else
251  return a.rep[deg(a)];
252 }
253 
254 // zero if a == 0
255 template <class F, class FX, class vec_FX>
256 const FX& ConstTerm(const FXY<F,FX,vec_FX>& a)
257 {
258  if (IsZero(a))
259  return FX::zero();
260  else
261  return a.rep[0];
262 }
263 
264 // x[i][j] = a, error is raised if i < 0
265 template <class F, class FX, class vec_FX>
266 void SetCoeff(FXY<F,FX,vec_FX>& x, long i, long j, const F& a)
267 {
268  long k, m;
269 
270  if (i < 0)
271  Error("SetCoeff: negative index");
272 
273  if (NTL_OVERFLOW(i, 1, 0))
274  Error("overflow in SetCoeff");
275 
276  m = deg(x);
277 
278  if (i > m) {
279  /* careful: a may alias a coefficient of x */
280 
281 #if 0
282  long alloc = x.rep.allocated();
283 
284  if (alloc > 0 && i >= alloc) {
285  FXTemp aa_tmp; FX& aa = aa_tmp.val();
286  aa = a;
287  x.rep.SetLength(i+1);
288  x.rep[i] = aa;
289  }
290  else {
291 #endif
292  x.rep.SetLength(i+1);
293  SetCoeff(x.rep[i], j, a);
294 #if 0
295  }
296 #endif
297 
298  for (k = m+1; k < i; k++)
299  clear(x.rep[k]);
300  }
301  else
302  SetCoeff(x.rep[i], j, a);
303 
304  x.normalize();
305 }
306 
307 // x[i] = a, error is raised if i < 0
308 template <class F, class FX, class vec_FX>
309 void SetCoeff(FXY<F,FX,vec_FX>& x, long i, const FX& a)
310 {
311  long j, m;
312 
313  if (i < 0)
314  Error("SetCoeff: negative index");
315 
316  if (NTL_OVERFLOW(i, 1, 0))
317  Error("overflow in SetCoeff");
318 
319  m = deg(x);
320 
321  if (i > m) {
322  /* careful: a may alias a coefficient of x */
323 
324 #if 0
325  long alloc = x.rep.allocated();
326 
327  if (alloc > 0 && i >= alloc) {
328  FXTemp aa_tmp; FX& aa = aa_tmp.val();
329  aa = a;
330  x.rep.SetLength(i+1);
331  x.rep[i] = aa;
332  }
333  else {
334 #endif
335  x.rep.SetLength(i+1);
336  x.rep[i] = a;
337 #if 0
338  }
339 #endif
340 
341  for (j = m+1; j < i; j++)
342  clear(x.rep[j]);
343  }
344  else
345  x.rep[i] = a;
346 
347  x.normalize();
348 }
349 
350 template <class F, class FX, class vec_FX>
351 void SetCoeff(FXY<F,FX,vec_FX>& x, long i, long a)
352 {
353  if (a == 1)
354  SetCoeff(x, i);
355  else {
356  FX T;
357  conv(T, a);
358  SetCoeff(x, i, T);
359  }
360 }
361 
362 // x[i] = 1, error is raised if i < 0
363 template <class F, class FX, class vec_FX>
364 void SetCoeff(FXY<F,FX,vec_FX>& x, long i)
365 {
366  long j, m;
367 
368  if (i < 0)
369  Error("coefficient index out of range");
370 
371  if (NTL_OVERFLOW(i, 1, 0))
372  Error("overflow in SetCoeff");
373 
374  m = deg(x);
375 
376  if (i > m) {
377  x.rep.SetLength(i+1);
378  for (j = m+1; j < i; j++)
379  clear(x.rep[j]);
380  }
381  set(x.rep[i]);
382  x.normalize();
383 }
384 
385 template <class F, class FX, class vec_FX>
386 inline FXY<F,FX,vec_FX>::FXY(long i, const FX& a)
387  { SetCoeff(*this, i, a); }
388 
389 template <class F, class FX, class vec_FX>
390 inline FXY<F,FX,vec_FX>::FXY(long i, long a)
391  { SetCoeff(*this, i, a); }
392 
393 // y is set to the monomial Y
394 template <class F, class FX, class vec_FX>
395 void SetY(FXY<F,FX,vec_FX>& y)
396 {
397  clear(y);
398  SetCoeff(y, 1);
399 }
400 
401 // test if a = Y
402 template <class F, class FX, class vec_FX>
403 long IsY(const FXY<F,FX,vec_FX>& a)
404 {
405  return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a));
406 }
407 
408 template <class F, class FX, class vec_FX>
409 inline void clear(FXY<F,FX,vec_FX>& x)
410 // x = 0
411 
412  { x.rep.SetLength(0); }
413 
414 template <class F, class FX, class vec_FX>
415 inline void set(FXY<F,FX,vec_FX>& x)
416 // x = 1
417 
418  { x.rep.SetLength(1); set(x.rep[0]); }
419 
420 template <class F, class FX, class vec_FX>
421 inline void swap(FXY<F,FX,vec_FX>& x, FXY<F,FX,vec_FX>& y)
422 // swap x & y (only pointers are swapped)
423 
424  { swap(x.rep, y.rep); }
425 
426 template <class F, class FX, class vec_FX>
427 void random(FXY<F,FX,vec_FX>& x, long n);
428 template <class F, class FX, class vec_FX>
429 inline FXY<F,FX,vec_FX> random_FXY(long n)
430  { FXY<F,FX,vec_FX> x; random(x, n); NTL_OPT_RETURN(FTXY, x); }
431 // generate a random polynomial of degree < n
432 
433 template <class F, class FX, class vec_FX>
434 void trunc(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long m);
435 // x = a % Y^m
436 
437 template <class F, class FX, class vec_FX>
438 inline FXY<F,FX,vec_FX> trunc(const FXY<F,FX,vec_FX>& a, long m)
439  { FXY<F,FX,vec_FX> x; trunc(x, a, m); NTL_OPT_RETURN(FTXY, x); }
440 
441 template <class F, class FX, class vec_FX>
442 void RightShift(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long n);
443 // x = a/Y^n
444 
445 template <class F, class FX, class vec_FX>
446 inline FXY<F,FX,vec_FX> RightShift(const FXY<F,FX,vec_FX>& a, long n)
447  { FXY<F,FX,vec_FX> x; RightShift(x, a, n); NTL_OPT_RETURN(FTXY, x); }
448 
449 template <class F, class FX, class vec_FX>
450 void LeftShift(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long n);
451 // x = a*Y^n
452 
453 template <class F, class FX, class vec_FX>
454 inline FXY<F,FX,vec_FX> LeftShift(const FXY<F,FX,vec_FX>& a, long n)
455  { FXY<F,FX,vec_FX> x; LeftShift(x, a, n); NTL_OPT_RETURN(FTXY, x); }
456 
457 // a = X^n * P(X)
458 template <class F, class FX, class vec_FX>
459 FX shiftX(const FX& P, long n)
460 {
461  // a = X^n * P(X)
462  // n >= 0 for now
463 
464  long deg = P.rep.length()-1;
465 
466  FX x;
467  x.rep.SetLength( deg+1+n );
468 
469  for(long i = 0; i < n; i++){
470  x.rep[i] = 0;
471  }
472  for(long i = 0; i <= deg; i++){
473  x.rep[i+n] = P.rep[i];
474  }
475  return x;
476 }
477 
478 // returns P(X) / X^n
479 template <class F, class FX, class vec_FX>
480 FXY<F,FX,vec_FX> backShiftX(const FXY<F,FX,vec_FX>& P, long n)
481 {
482  // returns P(X) / X^n
483 
484  long deg = P.rep.length() - 1;
485  long degX;
486 
488  x.rep.SetLength( deg+1 );
489 
490  for(long i = 0; i <= deg; i++){ // work on each coefficient of Y
491  if( IsZero(P.rep[i]) ){
492  x.rep[i] = P.rep[i];
493  }else{
494  degX = (P.rep[i].rep.length()-1)-n;
495  x.rep[i].rep.SetLength( degX + 1);
496  for(long j = 0; j <= degX; j++){
497  x.rep[i].rep[j] = P.rep[i].rep[j+n];
498  }
499  }
500  }
501  x.normalize();
502  return x;
503 }
504 
505 #ifndef NTL_TRANSITION
506 
507 template <class F, class FX, class vec_FX>
508 inline FXY<F,FX,vec_FX> operator>>(const FXY<F,FX,vec_FX>& a, long n)
509  { FXY<F,FX,vec_FX> x; RightShift(x, a, n); NTL_OPT_RETURN(FTXY, x); }
510 
511 template <class F, class FX, class vec_FX>
512 inline FXY<F,FX,vec_FX> operator<<(const FXY<F,FX,vec_FX>& a, long n)
513  { FXY<F,FX,vec_FX> x; LeftShift(x, a, n); NTL_OPT_RETURN(FTXY, x); }
514 
515 template <class F, class FX, class vec_FX>
516 inline FXY<F,FX,vec_FX>& operator<<=(FXY<F,FX,vec_FX>& x, long n)
517  { LeftShift(x, x, n); return x; }
518 
519 template <class F, class FX, class vec_FX>
520 inline FXY<F,FX,vec_FX>& operator>>=(FXY<F,FX,vec_FX>& x, long n)
521  { RightShift(x, x, n); return x; }
522 
523 #endif
524 
525 
526 
527 template <class F, class FX, class vec_FX>
528 void diff(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a);
529 // x = derivative of a wrt Y
530 
531 template <class F, class FX, class vec_FX>
532 inline FXY<F,FX,vec_FX> diff(const FXY<F,FX,vec_FX>& a)
533  { FXY<F,FX,vec_FX> x; diff(x, a); NTL_OPT_RETURN(FTXY, x); }
534 
535 
536 template <class F, class FX, class vec_FX>
537 void MakeMonic(FXY<F,FX,vec_FX>& x)
538 {
539  if (IsZero(x))
540  return;
541 
542  F lc = LeadCoeff(LeadCoeff(x));
543  if (lc == 1)
544  return;
545 
546  F lcinv;
547  inv(lcinv, lc);
548  x *= lcinv;
549 }
550 
551 template <class F, class FX, class vec_FX>
552 void reverse(FXY<F,FX,vec_FX>& c, const FXY<F,FX,vec_FX>& a, long hi);
553 
554 template <class F, class FX, class vec_FX>
555 inline FXY<F,FX,vec_FX> reverse(const FXY<F,FX,vec_FX>& a, long hi)
556  { FXY<F,FX,vec_FX> x; reverse(x, a, hi); NTL_OPT_RETURN(FTXY, x); }
557 
558 template <class F, class FX, class vec_FX>
559 inline void reverse(FXY<F,FX,vec_FX>& c, const FXY<F,FX,vec_FX>& a)
560 { reverse(c, a, deg(a)); }
561 
562 template <class F, class FX, class vec_FX>
563 inline FXY<F,FX,vec_FX> reverse(const FXY<F,FX,vec_FX>& a)
564  { FXY<F,FX,vec_FX> x; reverse(x, a); NTL_OPT_RETURN(FTXY, x); }
565 
566 // Returns the degree of the rightmost term whose coefficient has the highest
567 // degree. Returns -1 if the given polynomial is 0;
568 template <class F, class FX, class vec_FX>
569 long pivotIndex (const FXY<F,FX,vec_FX>& a) {
570  long max_index = -1;
571  long max_degree = -1;
572  for (long i = 0; i < a.rep.length(); ++i) {
573  long d = deg(a.rep[i]);
574  if (d >= max_degree) {
575  max_index = i;
576  max_degree = d;
577  }
578  }
579  return max_index;
580 }
581 
582 template <class F, class FX, class vec_FX>
583 FXY<F,FX,vec_FX> swapVarOrder (const FXY<F,FX,vec_FX>& a) {
584  FXY<F,FX,vec_FX> new_a;
585  for (long i = 0; i < a.rep.length(); ++i) {
586  for (long j = 0; j <= deg(a.rep[i]); ++j) {
587  if (j > deg(new_a)) {
588  SetCoeff(new_a, j, FX(i, coeff(a.rep[i], j)));
589  } else {
590  SetCoeff(new_a.rep[j], i, coeff(a.rep[i], j));
591  }
592  }
593  }
594  return new_a;
595 }
596 
597 template <class F, class FX, class vec_FX>
598 FX eval(const FXY<F,FX,vec_FX>& a, F x) {
599  FX result;
600  for (long i = 0; i < a.rep.length(); ++i) {
601  result += power(x, i) * a.rep[i];
602  }
603  return result;
604 }
605 
606 
607 /*******************************************************************
608 
609  conversion routines
610 
611 ********************************************************************/
612 
613 
614 
615 template <class F, class FX, class vec_FX>
616 void conv(FXY<F,FX,vec_FX>& x, long a)
617 {
618  if (a == 0)
619  clear(x);
620  else if (a == 1)
621  set(x);
622  else {
623  FX T;
624  conv(T, a);
625  conv(x, T);
626  }
627 }
628 
629 template <class F, class FX, class vec_FX>
630 void conv(FXY<F,FX,vec_FX>& x, const F& a)
631 {
632  if (IsZero(a))
633  clear(x);
634  else {
635  FX T;
636  conv(T, a);
637  conv(x, T);
638  }
639 }
640 
641 template <class F, class FX, class vec_FX>
642 void conv(FXY<F,FX,vec_FX>& x, const FX& a)
643 {
644  if (IsZero(a))
645  x.rep.SetLength(0);
646  else {
647  x.rep.SetLength(1);
648  x.rep[0] = a;
649 
650  // note: if a aliases x.rep[i], i > 0, this code
651  // will still work, since is is assumed that
652  // SetLength(1) will not relocate or destroy x.rep[i]
653  }
654 }
655 template <class F, class FX, class vec_FX>
656 void conv(FXY<F,FX,vec_FX>& x, const vec_FX& a)
657 {
658  x.rep = a;
659  x.normalize();
660 }
661 
662 template <class F, class FX, class vec_FX>
663 inline FXY<F,FX,vec_FX> to_FXY(long a)
664  { FXY<F,FX,vec_FX> x; conv(x, a); NTL_OPT_RETURN(FTXY, x); }
665 
666 template <class F, class FX, class vec_FX>
667 inline FXY<F,FX,vec_FX> to_FXY(const F& a)
668  { FXY<F,FX,vec_FX> x; conv(x, a); NTL_OPT_RETURN(FTXY, x); }
669 
670 template <class F, class FX, class vec_FX>
671 inline FXY<F,FX,vec_FX> to_FXY(const FX& a)
672  { FXY<F,FX,vec_FX> x; conv(x, a); NTL_OPT_RETURN(FTXY, x); }
673 
674 template <class F, class FX, class vec_FX>
675 inline FXY<F,FX,vec_FX> to_FXY(const vec_FX& a)
676  { FXY<F,FX,vec_FX> x; conv(x, a); NTL_OPT_RETURN(FTXY, x); }
677 
678 
679 
680 /*************************************************************
681 
682  Comparison
683 
684 **************************************************************/
685 
686 template <class F, class FX, class vec_FX>
687 long IsZero(const FXY<F,FX,vec_FX>& a)
688 {
689  return a.rep.length() == 0;
690 }
691 
692 template <class F, class FX, class vec_FX>
693 long IsOne(const FXY<F,FX,vec_FX>& a)
694 {
695  return a.rep.length() == 1 && IsOne(a.rep[0]);
696 }
697 
698 template <class F, class FX, class vec_FX>
699 inline long operator==(const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
700 {
701  return a.rep == b.rep;
702 }
703 
704 template <class F, class FX, class vec_FX>
705 inline long operator!=(const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
706 {
707  return !(a == b);
708 }
709 
710 template <class F, class FX, class vec_FX>
711 long operator==(const FXY<F,FX,vec_FX>& a, long b)
712 {
713  if (b == 0)
714  return IsZero(a);
715 
716  if (b == 1)
717  return IsOne(a);
718 
719  long da = deg(a);
720 
721  if (da > 0)
722  return 0;
723 
724  F bb;
725  bb = b;
726 
727  if (da < 0)
728  return IsZero(bb);
729 
730  return a.rep[0] == bb;
731 }
732 
733 template <class F, class FX, class vec_FX>
734 long operator==(const FXY<F,FX,vec_FX>& a, const F& b)
735 {
736  if (IsZero(b))
737  return IsZero(a);
738 
739  long da = deg(a);
740 
741  if (da != 0)
742  return 0;
743 
744  return a.rep[0] == b;
745 }
746 
747 template <class F, class FX, class vec_FX>
748 long operator==(const FXY<F,FX,vec_FX>& a, const FX& b)
749 {
750  if (IsZero(b))
751  return IsZero(a);
752 
753  long da = deg(a);
754 
755  if (da != 0)
756  return 0;
757 
758  return a.rep[0] == b;
759 }
760 
761 template <class F, class FX, class vec_FX>
762 inline long operator==(long a, const FXY<F,FX,vec_FX>& b) { return b == a; }
763 template <class F, class FX, class vec_FX>
764 inline long operator==(const F& a, const FXY<F,FX,vec_FX>& b) { return b == a; }
765 template <class F, class FX, class vec_FX>
766 inline long operator==(const FX& a, const FXY<F,FX,vec_FX>& b) { return b == a; }
767 
768 template <class F, class FX, class vec_FX>
769 inline long operator!=(const FXY<F,FX,vec_FX>& a, long b) { return !(a == b); }
770 template <class F, class FX, class vec_FX>
771 inline long operator!=(const FXY<F,FX,vec_FX>& a, const F& b) { return !(a == b); }
772 template <class F, class FX, class vec_FX>
773 inline long operator!=(const FXY<F,FX,vec_FX>& a, const FX& b) { return !(a == b); }
774 
775 template <class F, class FX, class vec_FX>
776 inline long operator!=(long a, const FXY<F,FX,vec_FX>& b) { return !(a == b); }
777 template <class F, class FX, class vec_FX>
778 inline long operator!=(const F& a, const FXY<F,FX,vec_FX>& b) { return !(a == b); }
779 template <class F, class FX, class vec_FX>
780 inline long operator!=(const FX& a, const FXY<F,FX,vec_FX>& b) { return !(a == b); }
781 
782 
783 /***************************************************************
784 
785  Addition
786 
787 ****************************************************************/
788 
789 //
790 // x = a + b
791 //
792 template <class F, class FX, class vec_FX>
793 void add(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
794 {
795  long degYa = deg(a);
796  long degYb = deg(b);
797  long minab = min(degYa, degYb);
798  long maxab = max(degYa, degYb);
799  x.rep.SetLength(maxab+1);
800 
801  long i;
802  const FX *ap, *bp;
803  FX* xp;
804 
805  for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts();
806  i; i--, ap++, bp++, xp++)
807  add(*xp, (*ap), (*bp));
808 
809  if (degYa > minab && &x != &a)
810  for (i = degYa-minab; i; i--, xp++, ap++)
811  *xp = *ap;
812  else if (degYb > minab && &x != &b)
813  for (i = degYb-minab; i; i--, xp++, bp++)
814  *xp = *bp;
815  else
816  x.normalize();
817 }
818 
819 template <class F, class FX, class vec_FX>
820 void add(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FX& b)
821 {
822  long n = a.rep.length();
823  if (n == 0) {
824  conv(x, b);
825  }
826  else if (&x == &a) {
827  add(x.rep[0], a.rep[0], b);
828  x.normalize();
829  }
830  else if (x.rep.MaxLength() == 0) {
831  x = a;
832  add(x.rep[0], a.rep[0], b);
833  x.normalize();
834  }
835  else {
836  // ugly...b could alias a coeff of x
837 
838  FX *xp = x.rep.elts();
839  add(xp[0], a.rep[0], b);
840  x.rep.SetLength(n);
841  xp = x.rep.elts();
842  const FX *ap = a.rep.elts();
843  long i;
844  for (i = 1; i < n; i++)
845  xp[i] = ap[i];
846  x.normalize();
847  }
848 }
849 
850 template <class F, class FX, class vec_FX>
851 void add(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const F& b)
852 {
853  if (a.rep.length() == 0) {
854  conv(x, b);
855  }
856  else {
857  if (&x != &a) x = a;
858  add(x.rep[0], x.rep[0], b);
859  x.normalize();
860  }
861 }
862 
863 template <class F, class FX, class vec_FX>
864 void add(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long b)
865 {
866  if (a.rep.length() == 0) {
867  conv(x, b);
868  }
869  else {
870  if (&x != &a) x = a;
871  add(x.rep[0], x.rep[0], b);
872  x.normalize();
873  }
874 }
875 
876 template <class F, class FX, class vec_FX>
877 inline void add(FXY<F,FX,vec_FX>& x, const FX& a, const FXY<F,FX,vec_FX>& b) { add(x, b, a); }
878 template <class F, class FX, class vec_FX>
879 inline void add(FXY<F,FX,vec_FX>& x, const F& a, const FXY<F,FX,vec_FX>& b) { add(x, b, a); }
880 template <class F, class FX, class vec_FX>
881 inline void add(FXY<F,FX,vec_FX>& x, long a, const FXY<F,FX,vec_FX>& b) { add(x, b, a); }
882 
883 
884 //
885 // x = a - b
886 //
887 template <class F, class FX, class vec_FX>
888 void sub(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
889 {
890  long da = deg(a);
891  long db = deg(b);
892  long minab = min(da, db);
893  long maxab = max(da, db);
894  x.rep.SetLength(maxab+1);
895 
896  long i;
897  const FX *ap, *bp;
898  FX* xp;
899 
900  for (i = minab+1, ap = a.rep.elts(), bp = b.rep.elts(), xp = x.rep.elts();
901  i; i--, ap++, bp++, xp++)
902  sub(*xp, (*ap), (*bp));
903 
904  if (da > minab && &x != &a)
905  for (i = da-minab; i; i--, xp++, ap++)
906  *xp = *ap;
907  else if (db > minab)
908  for (i = db-minab; i; i--, xp++, bp++)
909  negate(*xp, *bp);
910  else
911  x.normalize();
912 
913 }
914 
915 template <class F, class FX, class vec_FX>
916 void sub(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FX& b)
917 {
918  long n = a.rep.length();
919  if (n == 0) {
920  conv(x, b);
921  negate(x, x);
922  }
923  else if (&x == &a) {
924  sub(x.rep[0], a.rep[0], b);
925  x.normalize();
926  }
927  else if (x.rep.MaxLength() == 0) {
928  x = a;
929  sub(x.rep[0], a.rep[0], b);
930  x.normalize();
931  }
932  else {
933  // ugly...b could alias a coeff of x
934 
935  FX *xp = x.rep.elts();
936  sub(xp[0], a.rep[0], b);
937  x.rep.SetLength(n);
938  xp = x.rep.elts();
939  const FX *ap = a.rep.elts();
940  long i;
941  for (i = 1; i < n; i++)
942  xp[i] = ap[i];
943  x.normalize();
944  }
945 }
946 
947 template <class F, class FX, class vec_FX>
948 void sub(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const F& b)
949 {
950  if (IsZero(b)) {
951  x = a;
952  return;
953  }
954 
955  if (a.rep.length() == 0) {
956  x.rep.SetLength(1);
957  x.rep[0] = b;
958  negate(x.rep[0], x.rep[0]);
959  }
960  else {
961  if (&x != &a) x = a;
962  sub(x.rep[0], x.rep[0], b);
963  }
964  x.normalize();
965 }
966 
967 template <class F, class FX, class vec_FX>
968 void sub(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long b)
969 {
970  if (b == 0) {
971  x = a;
972  return;
973  }
974 
975  if (a.rep.length() == 0) {
976  x.rep.SetLength(1);
977  x.rep[0] = b;
978  negate(x.rep[0], x.rep[0]);
979  }
980  else {
981  if (&x != &a) x = a;
982  sub(x.rep[0], x.rep[0], b);
983  }
984  x.normalize();
985 }
986 
987 template <class F, class FX, class vec_FX>
988 void sub(FXY<F,FX,vec_FX>& x, const FX& a, const FXY<F,FX,vec_FX>& b)
989 {
990  FXY<F,FX,vec_FX> temp;
991  conv(temp,a);
992 
993  negate(x, b);
994  add(x, x, temp);
995 }
996 
997 template <class F, class FX, class vec_FX>
998 void sub(FXY<F,FX,vec_FX>& x, const F& a, const FXY<F,FX,vec_FX>& b)
999 {
1000  FXY<F,FX,vec_FX> temp;
1001  conv(temp,a);
1002 
1003  negate(x, b);
1004  add(x, x, temp);
1005 }
1006 
1007 template <class F, class FX, class vec_FX>
1008 void sub(FXY<F,FX,vec_FX>& x, long a, const FXY<F,FX,vec_FX>& b)
1009 {
1010  FXY<F,FX,vec_FX> temp;
1011  conv(temp,a);
1012 
1013  negate(x, b);
1014  add(x, x, temp);
1015 }
1016 
1017 
1018 //
1019 // x = -a
1020 //
1021 template <class F, class FX, class vec_FX>
1022 void negate(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a)
1023 {
1024  long n = a.rep.length();
1025  x.rep.SetLength(n);
1026 
1027  const FX* ap = a.rep.elts();
1028  FX* xp = x.rep.elts();
1029  long i;
1030 
1031  for (i = n; i; i--, ap++, xp++)
1032  negate((*xp), (*ap));
1033 
1034 }
1035 
1036 
1037 //
1038 // operator versions for add, sub and negate
1039 //
1040 template <class F, class FX, class vec_FX>
1041 inline FXY<F,FX,vec_FX> operator+(const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
1042  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1043 
1044 template <class F, class FX, class vec_FX>
1045 inline FXY<F,FX,vec_FX> operator+(const FXY<F,FX,vec_FX>& a, const FX& b)
1046  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1047 
1048 template <class F, class FX, class vec_FX>
1049 inline FXY<F,FX,vec_FX> operator+(const FXY<F,FX,vec_FX>& a, const F& b)
1050  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1051 
1052 template <class F, class FX, class vec_FX>
1053 inline FXY<F,FX,vec_FX> operator+(const FXY<F,FX,vec_FX>& a, long b)
1054  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1055 
1056 template <class F, class FX, class vec_FX>
1057 inline FXY<F,FX,vec_FX> operator+(const FX& a, const FXY<F,FX,vec_FX>& b)
1058  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1059 
1060 template <class F, class FX, class vec_FX>
1061 inline FXY<F,FX,vec_FX> operator+(const F& a, const FXY<F,FX,vec_FX>& b)
1062  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1063 
1064 template <class F, class FX, class vec_FX>
1065 inline FXY<F,FX,vec_FX> operator+(long a, const FXY<F,FX,vec_FX>& b)
1066  { FXY<F,FX,vec_FX> x; add(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1067 
1068 
1069 template <class F, class FX, class vec_FX>
1070 inline FXY<F,FX,vec_FX> operator-(const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
1071  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1072 
1073 template <class F, class FX, class vec_FX>
1074 inline FXY<F,FX,vec_FX> operator-(const FXY<F,FX,vec_FX>& a, const FX& b)
1075  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1076 
1077 template <class F, class FX, class vec_FX>
1078 inline FXY<F,FX,vec_FX> operator-(const FXY<F,FX,vec_FX>& a, const F& b)
1079  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1080 
1081 template <class F, class FX, class vec_FX>
1082 inline FXY<F,FX,vec_FX> operator-(const FXY<F,FX,vec_FX>& a, long b)
1083  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1084 
1085 
1086 template <class F, class FX, class vec_FX>
1087 inline FXY<F,FX,vec_FX> operator-(const FX& a, const FXY<F,FX,vec_FX>& b)
1088  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1089 
1090 template <class F, class FX, class vec_FX>
1091 inline FXY<F,FX,vec_FX> operator-(const F& a, const FXY<F,FX,vec_FX>& b)
1092  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1093 
1094 template <class F, class FX, class vec_FX>
1095 inline FXY<F,FX,vec_FX> operator-(long a, const FXY<F,FX,vec_FX>& b)
1096  { FXY<F,FX,vec_FX> x; sub(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1097 
1098 
1099 template <class F, class FX, class vec_FX>
1100 inline FXY<F,FX,vec_FX>& operator+=(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& b)
1101  { add(x, x, b); return x; }
1102 
1103 template <class F, class FX, class vec_FX>
1104 inline FXY<F,FX,vec_FX>& operator+=(FXY<F,FX,vec_FX>& x, const FX& b)
1105  { add(x, x, b); return x; }
1106 
1107 template <class F, class FX, class vec_FX>
1108 inline FXY<F,FX,vec_FX>& operator+=(FXY<F,FX,vec_FX>& x, const F& b)
1109  { add(x, x, b); return x; }
1110 
1111 template <class F, class FX, class vec_FX>
1112 inline FXY<F,FX,vec_FX>& operator+=(FXY<F,FX,vec_FX>& x, long b)
1113  { add(x, x, b); return x; }
1114 
1115 
1116 template <class F, class FX, class vec_FX>
1117 inline FXY<F,FX,vec_FX>& operator-=(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& b)
1118  { sub(x, x, b); return x; }
1119 
1120 template <class F, class FX, class vec_FX>
1121 inline FXY<F,FX,vec_FX>& operator-=(FXY<F,FX,vec_FX>& x, const FX& b)
1122  { sub(x, x, b); return x; }
1123 
1124 template <class F, class FX, class vec_FX>
1125 inline FXY<F,FX,vec_FX>& operator-=(FXY<F,FX,vec_FX>& x, const F& b)
1126  { sub(x, x, b); return x; }
1127 
1128 template <class F, class FX, class vec_FX>
1129 inline FXY<F,FX,vec_FX>& operator-=(FXY<F,FX,vec_FX>& x, long b)
1130  { sub(x, x, b); return x; }
1131 
1132 
1133 template <class F, class FX, class vec_FX>
1134 inline FXY<F,FX,vec_FX> operator-(const FXY<F,FX,vec_FX>& a)
1135  { FXY<F,FX,vec_FX> x; negate(x, a); NTL_OPT_RETURN(FTXY, x); }
1136 
1137 template <class F, class FX, class vec_FX>
1138 inline FXY<F,FX,vec_FX>& operator++(FXY<F,FX,vec_FX>& x)
1139  { add(x, x, 1); return x; }
1140 
1141 template <class F, class FX, class vec_FX>
1142 inline void operator++(FXY<F,FX,vec_FX>& x, int)
1143  { add(x, x, 1); }
1144 
1145 template <class F, class FX, class vec_FX>
1146 inline FXY<F,FX,vec_FX>& operator--(FXY<F,FX,vec_FX>& x)
1147  { sub(x, x, 1); return x; }
1148 
1149 template <class F, class FX, class vec_FX>
1150 inline void operator--(FXY<F,FX,vec_FX>& x, int)
1151  { sub(x, x, 1); }
1152 
1153 
1154 
1155 /*************************************************************
1156 
1157  Computing y-roots
1158 
1159 **************************************************************/
1160 
1161 ZZ comb(long n, long k);
1162 
1163 template <class F, class FX, class vec_FX>
1164 void mul(FX &x, const FX &a, const ZZ &b)
1165 {
1166  F T;
1167  conv(T, b);
1168  mul(x, a, T);
1169 }
1170 
1171 //
1172 // returns Q(x,xy+a)/X^m, for largest m>=0 such that division is exact
1173 //
1174 template <class F, class FX, class vec_FX>
1175 FXY<F,FX,vec_FX> mapit(const FXY<F,FX,vec_FX>& Q, const F& a)
1176 {
1177 
1178  //
1179  // if Q(x,y) has no y terms (ie deg(Q) < 1)
1180  // there is nothing to do here
1181  //
1182 
1183  if( deg(Q) < 1 ) return Q;
1184 
1185 
1186  //
1187  // Q(x,y) has some y terms, so here comes the work
1188  //
1189 
1190  FXY<F,FX,vec_FX> temp; // we build up the new
1191  // polynomial in temp
1192 
1193  long degY = deg(Q);
1194  temp.rep.SetLength( degY + 1 );
1195 
1196  FX coef1, coef2; // we build up each coefficient with coef
1197 
1198  F aa;
1199 
1200  //
1201  // first we let y --> xy + a
1202  //
1203 
1204  //std::cout << "--- mapit ---" << endl;
1205 
1206  for(long i = 0; i <= degY; i++){
1207  coef1 = 0;
1208 
1209  for(long j = i; j <= degY; j++){
1210  coef2 = 0;
1211 
1212  power(aa,a,j-i);
1213 
1214  mul(coef2, Q.rep[j], aa);
1215  //std::cout << "." ;
1216  mul<F,FX,vec_FX>(coef2, coef2, comb(j,i));
1217  // std::cout << "." ;
1218  add(coef1,coef1,coef2);
1219  //std::cout << "." << endl;
1220  // std::cout << ".." << coef2 << " " << aa << endl;
1221 
1222  } // for j
1223 
1224  //std::cout << "-shift " << coef1 << endl;
1225  coef1 = shiftX<F,FX,vec_FX>(coef1, i);
1226  // std::cout << "." << coef1 << endl;
1227  temp.rep[i] = coef1;
1228 
1229  } // for i
1230 
1231  //std::cout << "start back-shift" << endl;
1232  //std::cout << temp << " -- " << minX(temp) << endl;
1233  temp.normalize();
1234  temp = backShiftX(temp, minX(temp));
1235  //std::cout << "end back-shift" << temp << endl;
1236 
1237  return temp;
1238 }
1239 
1240 // returns all roots of polynomial P(x)
1241 template <class F, class vec_F, class FX, class vec_FX, class vec_pair_FX_long>
1242 vec_F findroots_FX(const FX &P)
1243 {
1244 
1245 
1246  FX Q; //
1247  Q = P; // Q = monic version of P
1248  MakeMonic(Q); //
1249 
1250  FX factor; // one square free factor
1251 
1252  vec_FX factors; // all factors (of factor) from Berlekamp
1253  long nfactors; //
1254 
1255  vec_F roots; // list of roots of Q
1256  long nroots = 0; //
1257 
1258  F root; // a single root of Q
1259 
1260 
1261  // first do square free decomposition
1262  vec_pair_FX_long sqrfreeQ = SquareFreeDecomp(Q);
1263  // std::cout << "sqrfree = " << sqrfreeQ << endl;
1264 
1265 
1266  // work on each factor from square free decomposition
1267  for(long i = 0; i < sqrfreeQ.length(); i++){
1268  factor = sqrfreeQ[i].a;
1269  // std::cout << "factor = " << sqrfreeQ[i] << endl;
1270 
1271  factors = SFBerlekamp(factor);
1272  nfactors = factors.length();
1273 
1274  // std::cout << ".." << factors << " " << nfactors << endl;
1275 
1276  for(long j = 0; j < nfactors; j++){
1277  // std::cout << factors[j] << deg( factors[j] ) << endl;
1278  if( deg(factors[j]) == 1 ){
1279  root = FindRoot( factors[j] );
1280  // std::cout << "root " << root << endl;
1281  append(roots, root);
1282  // std::cout << roots[nroots] << endl;
1283  nroots++;
1284  }
1285 
1286  }
1287 
1288  }
1289 
1290  return roots;
1291 
1292 }
1293 
1294 
1295 template <class F, class FX, class vec_FX>
1296 long minDegX(const FX& P, long max)
1297 {
1298  //
1299  // return m >= 0 such that X^m divides P(X)
1300  //
1301 
1302  if( IsZero(P) ) return max;
1303 
1304  long min = 0;
1305  while( IsZero(P.rep[min]) ){
1306  min++;
1307  }
1308  return min;
1309 }
1310 
1311 template <class F, class FX, class vec_FX>
1312 long minX(const FXY<F,FX,vec_FX>& Q)
1313 {
1314  //
1315  // return largest m >= 0 such that X^m divides Q(x,y)
1316  //
1317 
1318  if( IsZero(Q) ) return 0;
1319 
1320  long max = degX(Q);
1321  long minX = minDegX<F,FX,vec_FX>(Q.rep[0],max);
1322  long degreeY = deg(Q);
1323  long currentMinX;
1324 
1325  for( long i = 1; i <= degreeY; i++){
1326  currentMinX = minDegX<F,FX,vec_FX>(Q.rep[i], max);
1327  if( currentMinX < minX)
1328  minX = currentMinX;
1329  }
1330 
1331  return minX;
1332 }
1333 
1334 template <class F, class FX, class vec_FX>
1335 void multiply(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& Q, long a)
1336 {
1337  //
1338  // x = aQ (ie, Q added to itself a times)
1339  //
1340 
1341  // do the easy stuff
1342  if (a < 1) {
1343  Error("multiply: multiplier smaller than 1");
1344  }
1345 
1346  if ( IsOne(Q) || a == 1) { // a1 = 1, 1Q = Q
1347  x = Q;
1348  return;
1349  }
1350 
1351  if (a == 2){
1352  add(x,Q,Q);
1353  return;
1354  }
1355 
1356  long dQ = deg(Q);
1357 
1358 /* if (dQ == 0) { */
1359 /* x = multiply(ConstTerm(Q), a); */
1360 /* return; */
1361 /* } */
1362 
1363  FXY<F,FX,vec_FX> res;
1364  res.SetMaxLength(dQ + 1);
1365  res = 0;
1366 
1367  long k = NumBits(a);
1368  long i;
1369 
1370  // double & add
1371  for (i = k - 1; i >= 0; i--) {
1372  add(res,res,res); // double
1373  if (bit(a, i))
1374  add(res,res,Q); // add
1375  }
1376 
1377  x = res;
1378 }
1379 
1380 template <class F, class FX, class vec_FX>
1381 void multiply(FX& x, const FX& Q, long a)
1382 {
1383  //
1384  // x = aQ (ie, Q added to itself a times)
1385  //
1386 
1387  // do the easy stuff
1388  if (a < 1) {
1389  Error("multiply: multiplier smaller than 1");
1390  }
1391 
1392  if ( IsOne(Q) || a == 1) { // a1 = 1, 1Q = Q
1393  x = Q;
1394  return;
1395  }
1396 
1397  if (a == 2){
1398  add(x,Q,Q);
1399  return;
1400  }
1401 
1402  long dQ = deg(Q);
1403 
1404 /* if (dQ == 0) { */
1405 /* x = multiply(ConstTerm(Q), a); */
1406 /* return; */
1407 /* } */
1408 
1409  FX res;
1410  res.SetMaxLength(dQ + 1);
1411  res = 0;
1412 
1413  long k = NumBits(a);
1414  long i;
1415 
1416  for (i = k - 1; i >= 0; i--) {
1417  add(res,res,res); // double
1418  if (bit(a, i))
1419  add(res,res,Q); // add
1420  }
1421 
1422  x = res;
1423 }
1424 
1425 template <class F, class FX, class vec_FX>
1426 void multiply(FX& x, const FX& Q, ZZ a)
1427 {
1428  //
1429  // x = aQ (ie, Q added to itself a times)
1430  //
1431 
1432  // do the easy stuff
1433  if( a < to_ZZ(1) ) {
1434  Error("multiply: multiplier smaller than 1");
1435  }
1436 
1437  if( IsOne(Q) || IsOne(a) ) { // a1 = 1, 1Q = Q
1438  x = Q;
1439  return;
1440  }
1441 
1442  if (a == to_ZZ(2)){
1443  add(x,Q,Q);
1444  return;
1445  }
1446 
1447  long dQ = deg(Q);
1448 
1449 /* if (dQ == 0) { */
1450 /* x = multiply(ConstTerm(Q), a); */
1451 /* return; */
1452 /* } */
1453 
1454  FX res;
1455  res.SetMaxLength(dQ + 1);
1456  res = 0;
1457 
1458  long k = NumBits(a);
1459  long i;
1460 
1461  for (i = k - 1; i >= 0; i--) {
1462  add(res,res,res); // double
1463  if (bit(a, i))
1464  add(res,res,Q); // add
1465  }
1466 
1467  x = res;
1468 }
1469 
1470 /*****************************************************************
1471 
1472  Multiplication
1473 
1474 ******************************************************************/
1475 
1476 //
1477 // x = a * b (and associated operations)
1478 //
1479 
1480 // x = a * b
1481 template <class F, class FX, class vec_FX>
1482 void mul(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
1483 {
1484  long da = deg(a);
1485  long db = deg(b);
1486 
1487  // do the easy cases first
1488 
1489  if (da < 0 || db < 0){ // a or b is zero
1490  clear(x);
1491  return;
1492  }
1493 
1494  if (da == 0 && db == 0){ // a and b are FX
1495  x.rep.SetLength(1); // x is FX too then
1496  mul( x.rep[0], a.rep[0], b.rep[0] );
1497  return;
1498  }
1499 
1500  if (da == 0){ // a is FX and b is FXY
1501  mul(x,b,a.rep[0]);
1502  return;
1503  }
1504 
1505  if (db == 0){ // b is FX and a is FXY
1506  mul(x,a,b.rep[0]);
1507  return;
1508  }
1509 
1510  // da,db >= 1
1511 
1512  PlainMul(x,a,b);
1513 }
1514 
1515 template <class F, class FX, class vec_FX>
1516 void mul(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FX& b)
1517 {
1518  long da = deg(a);
1519  long db = deg(b);
1520 
1521  // do the easy cases first
1522 
1523  if (da < 0 || db < 0){ // a or b is zero
1524  clear(x);
1525  return;
1526  }
1527 
1528  if (da == 0){ // a and b are both FX
1529  x.rep.SetLength(da+1);
1530  mul( x.rep[0], a.rep[0], b );
1531  return;
1532  }
1533 
1534  if (db == 0){ // b is F
1535  mul(x, a, b.rep[0]);
1536  return;
1537  }
1538 
1539  // da >= 1 (simply multiply each coefficient of a by b)
1540 
1541  x = a;
1542  for(long i = 0; i <= da; i++){
1543  mul(x.rep[i],a.rep[i],b);
1544  }
1545  x.normalize();
1546 
1547 }
1548 
1549 template <class F, class FX, class vec_FX>
1550 void mul(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const F& b)
1551 {
1552  if (IsZero(b)) {
1553  clear(x);
1554  return;
1555  }
1556 
1557  if (IsOne(b)) {
1558  x = a;
1559  return;
1560  }
1561 
1562  long i, da;
1563 
1564  const FX *ap;
1565  FX* xp;
1566 
1567  F t;
1568  t = b;
1569 
1570  da = deg(a);
1571  x.rep.SetLength(da+1);
1572  ap = a.rep.elts();
1573  xp = x.rep.elts();
1574 
1575  for (i = 0; i <= da; i++)
1576  mul(xp[i], ap[i], t);
1577 
1578  x.normalize();
1579 }
1580 
1581 template <class F, class FX, class vec_FX>
1582 void mul(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long b)
1583 {
1584  F T;
1585  conv(T, b);
1586  mul(x, a, T);
1587 }
1588 
1589 // x = a^2
1590 template <class F, class FX, class vec_FX>
1591 void sqr(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a)
1592 {
1593  mul(x,a,a); // I'll take the easy way out for now!
1594 }
1595 
1596 template <class F, class FX, class vec_FX>
1597 void sqr(FXY<F,FX,vec_FX>& x, const FX& a)
1598 {
1599  FX temp;
1600  sqr(temp,a);
1601  conv(x,temp);
1602 }
1603 
1604 template <class F, class FX, class vec_FX>
1605 void sqr(FXY<F,FX,vec_FX>& x, const F& a)
1606 {
1607  F temp;
1608  sqr(temp,a);
1609  conv(x,temp);
1610 }
1611 
1612 template <class F, class FX, class vec_FX>
1613 void sqr(FXY<F,FX,vec_FX>& x, long a)
1614 {
1615  F ap;
1616  ap = a;
1617  F temp;
1618  sqr(temp, ap);
1619  conv(x,temp);
1620 }
1621 
1622 // x = a^e (e >= 0)
1623 template <class F, class FX, class vec_FX>
1624 void power(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, long e)
1625 {
1626  // do the easy stuff
1627  if (e < 0) {
1628  Error("power: negative exponent");
1629  }
1630 
1631  if (e == 0) { // a^0 = 1
1632  x = 1;
1633  return;
1634  }
1635 
1636  if (a == 0 || a == 1 || e == 1) {
1637  x = a;
1638  return;
1639  }
1640 
1641  if (e == 2){
1642  sqr(x,a);
1643  return;
1644  }
1645 
1646  long da = deg(a);
1647 
1648  if (da == 0) {
1649  x = power(ConstTerm(a), e);
1650  return;
1651  }
1652 
1653  if (da > (NTL_MAX_LONG-1)/e)
1654  Error("overflow in power");
1655 
1656  FXY<F,FX,vec_FX> res;
1657  res.SetMaxLength(da*e + 1);
1658  res = 1;
1659 
1660  long k = NumBits(e);
1661  long i;
1662 
1663  for (i = k - 1; i >= 0; i--) {
1664  sqr(res, res);
1665  if (bit(e, i))
1666  mul(res, res, a);
1667  }
1668 
1669  x = res;
1670 }
1671 
1672 
1673 
1674 // inline versions
1675 
1676 template <class F, class FX, class vec_FX>
1677 inline FXY<F,FX,vec_FX> sqr(const FXY<F,FX,vec_FX>& a)
1678  { FXY<F,FX,vec_FX> x; sqr(x, a); NTL_OPT_RETURN(FTXY, x); }
1679 
1680 template <class F, class FX, class vec_FX>
1681 inline FXY<F,FX,vec_FX> power(const FXY<F,FX,vec_FX>& a, long e)
1682  { FXY<F,FX,vec_FX> x; power(x, a, e); NTL_OPT_RETURN(FTXY, x); }
1683 
1684 
1685 
1686 
1687 // other variations (of input arguments)
1688 
1689 template <class F, class FX, class vec_FX>
1690 inline void mul(FXY<F,FX,vec_FX>& x, const FX& a, const FXY<F,FX,vec_FX>& b)
1691  { mul(x, b, a); }
1692 
1693 template <class F, class FX, class vec_FX>
1694 inline void mul(FXY<F,FX,vec_FX>& x, const F& a, const FXY<F,FX,vec_FX>& b)
1695  { mul(x, b, a); }
1696 
1697 template <class F, class FX, class vec_FX>
1698 inline void mul(FXY<F,FX,vec_FX>& x, long a, const FXY<F,FX,vec_FX>& b)
1699  { mul(x, b, a); }
1700 
1701 
1702 // operator versions
1703 
1704 template <class F, class FX, class vec_FX>
1705 inline FXY<F,FX,vec_FX> operator*(const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
1706  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1707 
1708 template <class F, class FX, class vec_FX>
1709 inline FXY<F,FX,vec_FX> operator*(const FXY<F,FX,vec_FX>& a, const FX& b)
1710  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1711 
1712 template <class F, class FX, class vec_FX>
1713 inline FXY<F,FX,vec_FX> operator*(const FXY<F,FX,vec_FX>& a, const F& b)
1714  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1715 
1716 template <class F, class FX, class vec_FX>
1717 inline FXY<F,FX,vec_FX> operator*(const FXY<F,FX,vec_FX>& a, long b)
1718  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1719 
1720 
1721 template <class F, class FX, class vec_FX>
1722 inline FXY<F,FX,vec_FX> operator*(const FX& a, const FXY<F,FX,vec_FX>& b)
1723  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1724 
1725 template <class F, class FX, class vec_FX>
1726 inline FXY<F,FX,vec_FX> operator*(const F& a, const FXY<F,FX,vec_FX>& b)
1727  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1728 
1729 template <class F, class FX, class vec_FX>
1730 inline FXY<F,FX,vec_FX> operator*(long a, const FXY<F,FX,vec_FX>& b)
1731  { FXY<F,FX,vec_FX> x; mul(x, a, b); NTL_OPT_RETURN(FTXY, x); }
1732 
1733 
1734 
1735 template <class F, class FX, class vec_FX>
1736 inline FXY<F,FX,vec_FX>& operator*=(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& b)
1737  { mul(x, x, b); return x; }
1738 
1739 template <class F, class FX, class vec_FX>
1740 inline FXY<F,FX,vec_FX>& operator*=(FXY<F,FX,vec_FX>& x, const FX& b)
1741  { mul(x, x, b); return x; }
1742 
1743 template <class F, class FX, class vec_FX>
1744 inline FXY<F,FX,vec_FX>& operator*=(FXY<F,FX,vec_FX>& x, const F& b)
1745  { mul(x, x, b); return x; }
1746 
1747 template <class F, class FX, class vec_FX>
1748 inline FXY<F,FX,vec_FX>& operator*=(FXY<F,FX,vec_FX>& x, long b)
1749  { mul(x, x, b); return x; }
1750 
1751 
1752 
1753 
1754 
1755 
1756 //
1757 // Classical (plain) n^2 algorithms
1758 //
1759 
1760 template <class F, class FX, class vec_FX>
1761 void PlainMul(FXY<F,FX,vec_FX>& x, const FXY<F,FX,vec_FX>& a, const FXY<F,FX,vec_FX>& b)
1762 {
1763  long da = deg(a);
1764  long db = deg(b);
1765 
1766  // do the easy cases first
1767 
1768  if (da < 0 || db < 0){ // a or b is zero
1769  clear(x);
1770  return;
1771  }
1772 
1773  if (da == 0 && db == 0){ // a and b are FX
1774  x.rep.SetLength(1); // x is FX too then
1775  mul( x.rep[0], a.rep[0], b.rep[0] );
1776  return;
1777  }
1778 
1779  if (da == 0){ // a is FX and b is FXY
1780  mul(x,b,a.rep[0]);
1781  return;
1782  }
1783 
1784  if (db == 0){ // b is FX and a is FXY
1785  mul(x,a,b.rep[0]);
1786  return;
1787  }
1788 
1789  // da,db >= 1
1790 
1791  long d = da+db; // degree of new polynomial
1792 
1793  FXY<F,FX,vec_FX> la, lb; // create new copies of a and b
1794  la = a; // just in case &x == &a or &x == &b
1795  lb = b; //
1796 
1797  x.rep.SetLength(d+1);
1798 
1799  long i, j, jmin, jmax;
1800  static FX t, accum;
1801 
1802  for (i = 0; i <= d; i++) {
1803  jmin = max(0, i-db);
1804  jmax = min(da, i);
1805  clear(accum);
1806  for (j = jmin; j <= jmax; j++) {
1807  mul(t, la.rep[j], lb.rep[i-j]);
1808  //mul(t, rep(ap[j]), rep(bp[i-j]));
1809  add(accum, accum, t);
1810  }
1811  SetCoeff( x, i, accum);
1812  }
1813  x.normalize();
1814 }
1815 
1818 
1819 NTL_CLOSE_NNS
1820 
1821 #endif
Definition: FXY.h:53