algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/polynomial_naive.hpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : polynomial_naive.hpp
00004 * DESCRIPTION: naive polynomial arithmetic over fields
00005 * COPYRIGHT  : (C) 2003  Joris van der Hoeven and Gregoire Lecerf
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #ifndef __MMX__POLYNOMIAL_NAIVE__HPP
00014 #define __MMX__POLYNOMIAL_NAIVE__HPP
00015 #include <basix/port.hpp>
00016 #include <basix/vector.hpp>
00017 
00018 namespace mmx {
00019 #define TMPL  template <typename C>
00020 #define TMPLK template <typename C, typename K>
00021 #define TMPLX template <typename C, typename X>
00022 #define TMPLP template <typename Polynomial>
00023 #define Vector vector<C>
00024 template <typename C, typename V> struct polynomial;
00025 
00026 /******************************************************************************
00027 * Naive variant for polynomials
00028 ******************************************************************************/
00029 
00030 struct polynomial_naive {
00031   typedef vector_naive Vec;            // Polynomials as vectors
00032   typedef polynomial_naive Naive;      // Naive variant
00033   typedef polynomial_naive Positive;   // Multiplication without subtractions
00034   typedef polynomial_naive No_simd;    // Variant without SIMD instructions
00035   typedef polynomial_naive No_thread;  // Variant without threads
00036   typedef polynomial_naive No_scaled;  // Variant without preconditioning
00037 };
00038 
00039 template<typename C>
00040 struct polynomial_variant_helper {
00041   typedef polynomial_naive PV;
00042 };
00043 
00044 /******************************************************************************
00045 * Variable name storage, default is R[x]
00046 ******************************************************************************/
00047 
00048 struct polynomial_defaults {};
00049 
00050 template<typename V>
00051 struct implementation<polynomial_defaults,V,polynomial_naive> {
00052   template<typename P>
00053   class global_variables {
00054     static inline generic& dyn_name () {
00055       static generic name = "x";
00056       return name; }
00057   public:
00058     static inline void set_variable_name (const generic& x) { dyn_name () = x; }
00059     static inline generic get_variable_name () { return dyn_name (); }
00060   };
00061 
00062 }; // implementation<polynomial_defaults,V,polynomial_naive>
00063 
00064 /******************************************************************************
00065 * Inheritance from vectors
00066 ******************************************************************************/
00067 
00068 template<typename V>
00069 struct implementation<vector_defaults,V,polynomial_naive>:
00070   public implementation<vector_defaults,V,typename V::Vec> {};
00071 
00072 template<typename V>
00073 struct implementation<vector_allocate,V,polynomial_naive>:
00074   public implementation<vector_allocate,V,typename V::Vec> {};
00075 
00076 template<typename V>
00077 struct implementation<vector_abstractions,V,polynomial_naive>:
00078   public implementation<vector_abstractions,V,typename V::Vec> {};
00079 
00080 template<typename V>
00081 struct implementation<vector_abstractions_stride,V,polynomial_naive>:
00082   public implementation<vector_abstractions_stride,V,typename V::Vec> {};
00083 
00084 template<typename V>
00085 struct implementation<vector_linear,V,polynomial_naive>:
00086   public implementation<vector_linear,V,typename V::Vec> {};
00087 
00088 /******************************************************************************
00089 * Vectorial operations
00090 ******************************************************************************/
00091 
00092 struct polynomial_vectorial {};
00093 
00094 template<typename V>
00095 struct implementation<polynomial_vectorial,V,polynomial_naive>:
00096   public implementation<polynomial_defaults,V>
00097 {
00098   typedef implementation<vector_linear,V> Vec;
00099 
00100 TMPLX static inline void set (C* dest, const X& c, nat n) {
00101   Vec::set (dest, c, n); }
00102 TMPL static inline void clear (C* dest, nat n) {
00103   Vec::clear (dest, n); }
00104 TMPL static inline void copy (C* dest, const C* s, nat n) {
00105   Vec::copy (dest, s, n); }
00106 TMPLX static inline void cast (C* dest, const X* s, nat n) {
00107   Vec::cast (dest, s, n); }
00108 TMPL static inline void reverse (C* dest, const C* s, nat n) {
00109   Vec::vec_reverse (dest, s, n); }
00110 TMPL static inline void neg (C* dest, const C* s, nat n) {
00111   Vec::neg (dest, s, n); }
00112 TMPL static inline void neg (C* dest, nat n) {
00113   Vec::neg (dest, n); }
00114 TMPL static inline void add (C* dest, const C* s1, const C* s2, nat n) {
00115   Vec::add (dest, s1, s2, n); }
00116 TMPL static inline void add (C* dest, const C* s, nat n) {
00117   Vec::add (dest, s, n); }
00118 TMPL static inline void sub (C* dest, const C* s1, const C* s2, nat n) {
00119   Vec::sub (dest, s1, s2, n); }
00120 TMPL static inline void sub (C* dest, const C* s, nat n) {
00121   Vec::sub (dest, s, n); }
00122 TMPL static inline void mul_add (C* dest, const C* s1, const C* s2, nat n) {
00123   Vec::mul_add (dest, s1, s2, n); }
00124 TMPLX static inline void mul_add (C* dest, const C* s, const X& c, nat n) {
00125   Vec::mul_add (dest, s, c, n); }
00126 TMPLX static inline void mul_add (C* dest, const X& c, const C* s, nat n) {
00127   Vec::mul_add (dest, c, s, n); }
00128 TMPL static inline void mul_sc (C* dest, const C* s, const C& c, nat n) {
00129   Vec::mul (dest, s, c, n); }
00130 TMPL static inline void mul_sc (C* dest, const C& c, nat n) {
00131   Vec::mul (dest, c, n); }
00132 TMPL static inline void div_sc (C* dest, const C* s, const C& c, nat n) {
00133   Vec::div (dest, s, c, n); }
00134 TMPL static inline void div_sc (C* dest, const C& c, nat n) {
00135   Vec::div (dest, c, n); }
00136 TMPL static inline void quo_sc (C* dest, const C* s, const C& c, nat n) {
00137   Vec::quo (dest, s, c, n); }
00138 TMPL static inline void quo_sc (C* dest, const C& c, nat n) {
00139   Vec::quo (dest, c, n); }
00140 TMPL static inline void rem_sc (C* dest, const C* s, const C& c, nat n) {
00141   Vec::rem (dest, s, c, n); }
00142 TMPL static inline void rem_sc (C* dest, const C& c, nat n) {
00143   Vec::rem (dest, c, n); }
00144 TMPL static inline bool equal (const C* s1, const C* s2, nat n) {
00145   return Vec::equal (s1, s2, n); }
00146 TMPL static inline bool equal (const C* s, const C& c, nat n) {
00147   return Vec::equal (s, c, n); }
00148 TMPL static inline bool exact_eq (const C* s1, const C* s2, nat n) {
00149   return Vec::exact_eq (s1, s2, n); }
00150 TMPL static inline bool exact_eq (const C* s, const C& c, nat n) {
00151   return Vec::exact_eq (s, c, n); }
00152 TMPL static inline void trim (const C* s, nat& n) {
00153   while (n > 0 && s[n-1] == 0) n--; }
00154 
00155 }; // implementation<polynomial_vectorial,V,polynomial_naive>
00156 
00157 /******************************************************************************
00158 * Other linear time operators
00159 ******************************************************************************/
00160 
00161 struct polynomial_linear {};
00162 
00163 template<typename V>
00164 struct implementation<polynomial_linear,V,polynomial_naive>:
00165   public implementation<polynomial_vectorial,V>
00166 {
00167   typedef implementation<vector_linear,V> Vec;
00168   typedef implementation<polynomial_vectorial,V> Pol;
00169 
00170 TMPL static inline int
00171 sign (C* s, nat n) {
00172   while (n != 0) {
00173     int sgn= sign (*s);
00174     if (sgn != 0) return sgn;
00175     s++; n--;
00176   }
00177   return 0;
00178 }
00179 
00180 TMPL static inline int
00181 cmp (const C* s1, const C* s2, nat n) {
00182   while (n != 0) {
00183     int sgn= compare (*s1, *s2);
00184     if (sgn != 0) return sgn;
00185     s1++; s2++; n--;
00186   }
00187   return 0;
00188 }
00189 
00190 TMPL static inline void
00191 derive (C* dest, nat n) {
00192   for (nat i=1; i<n; i++)
00193     dest[i-1]= promote ((int) i, dest[i]) * dest[i];
00194 }
00195 
00196 TMPL static inline void
00197 derive (C* dest, nat n, nat order) {
00198   if (order == 0) return;
00199   for (nat i=order; i<n; i++) {
00200     dest[i-order]= promote (i, dest[i]) * dest[i];
00201     for (nat j=1; j<order; j++)
00202       dest[i-order] *= promote ((int) (i-j), dest[i]);
00203   }
00204 }
00205 
00206 TMPL static inline void
00207 derive (C* dest, const C* s, nat n) {
00208   for (nat i=1; i<n; i++)
00209     dest[i-1]= promote ((int) i, s[i]) * s[i];
00210 }
00211 
00212 TMPL static inline void
00213 derive (C* dest, const C* s, nat n, nat order) {
00214   for (nat i=order; i<n; i++) {
00215     dest[i-order]= s[i];
00216     for (nat j=0; j<order; j++)
00217       dest[i-order] *= promote ((int) (i-j), s[i]);
00218   }
00219 }
00220 
00221 TMPL static inline void
00222 xderive (C* dest, nat n) {
00223   for (nat i=0; i<n; i++)
00224     dest[i]= promote ((int) i, dest[i]) * dest[i];
00225 }
00226 
00227 TMPL static inline void
00228 xderive (C* dest, const C* s, nat n) {
00229   for (nat i=0; i<n; i++)
00230     dest[i]= promote ((int) i, s[i]) * s[i];
00231 }
00232 
00233 TMPL static inline void
00234 integrate (C* dest, const C* s, nat n) {
00235   dest[0]= promote (0, dest[0]);
00236   for (nat i=0; i<n; i++)
00237     dest[i+1]= s[i] / promote ((int) (i+1), s[i]);
00238 }
00239 
00240 TMPLK static inline void
00241 q_difference (C* dest, const C* s, const K& q, nat n) {
00242   K p= promote (1, q);
00243   while (n != 0) {
00244     *dest= p * (*s);
00245     dest++; s++; n--; p *= q;
00246   }
00247 }
00248 
00249 TMPL static inline void
00250 dilate (C* dest, const C* s, nat p, nat n) {
00251   Vec::clear (dest, (n-1)*p + 1);
00252   while (n != 0) {
00253     *dest= *s;
00254     dest += p; s++; n--;
00255   }
00256 }
00257 
00258 TMPL inline static C
00259 big_gcd (const C* s, nat n) {
00260   return Vec::template vec_unary_big<gcd_op, C> (s, n);
00261 }
00262 
00263 }; // implementation<polynomial_linear,V,polynomial_naive>
00264 
00265 /******************************************************************************
00266 * Multiplication
00267 ******************************************************************************/
00268 
00269 struct polynomial_multiply {};
00270 
00271 template<typename V>
00272 struct implementation<polynomial_multiply,V,polynomial_naive>:
00273   public implementation<polynomial_linear,V>
00274 {
00275   typedef implementation<polynomial_linear,V> Pol;
00276   typedef implementation<vector_linear,V> Vec;
00277 
00278 TMPLK static void
00279 mul (C* dest, const C* s1, const K* s2, nat n1, nat n2) {
00280   if (n1+n2>0)
00281     Pol::clear (dest, n1+n2-1);
00282   while (n2 != 0) {
00283     Pol::mul_add (dest, s1, *s2, n1);
00284     dest++; s2++; n2--;
00285   }
00286 }
00287 
00288 TMPL static void
00289 square (C* dest, const C* s, nat n) {
00290   if (n>0)
00291     Pol::clear (dest, n+n-1);
00292   else return;
00293   for (nat i=0; i<n-1; i++)
00294     Pol::mul_add (dest+i+i+1, s+i+1, s[i], n-i-1);
00295   for (nat i=1; i<n+n-2; i++)
00296     dest[i] = dest[i] + dest[i];
00297   for (nat i=0; i<n; i++)
00298     dest[i+i] += s[i] * s[i];
00299 }
00300 
00301 TMPL static void
00302 tmul (C* dest, const C* s1, const C* s2, nat n1, nat n2) {
00303   // transposed multiplication
00304   // s1 has length n1, dest has length n2 and s2 has length n1+n2-1
00305   Pol::clear (dest, n2);
00306   while (n1 != 0) {
00307     Pol::mul_add (dest, *s1, s2, n2);
00308     s1++; s2++; n1--;
00309   }
00310 }
00311 
00312 }; // implementation<polynomial_multiply,V,polynomial_naive>
00313 
00314 /******************************************************************************
00315 * Graeffe transforms
00316 ******************************************************************************/
00317 
00318 struct polynomial_graeffe {};
00319 
00320 template<typename V>
00321 struct implementation<polynomial_graeffe,V,polynomial_naive>:
00322   public implementation<polynomial_multiply,V>
00323 {
00324   typedef implementation<polynomial_multiply,V> Pol;
00325   typedef implementation<vector_linear,V> Vec;
00326 
00327 TMPL static void
00328 graeffe (C* dest, const C* s, nat n) {
00329   if (n <= 1) return;
00330   nat l1= (n+1) >> 1, l2= n >> 1;
00331   nat l= aligned_size<C,V> (n << 1);
00332   C* c1 = mmx_new<C> (l);
00333   C* c2 = c1 + l1;
00334   C* aux= c2 + l2;
00335   if (n>0) dest[n-1]= C(0);
00336   Vec::half_copy (c1, s, l1);
00337   Vec::half_copy (c2, s+1, l2);
00338   Pol::square (dest, c1, l1);
00339   Pol::square (aux , c2, l2);
00340   Pol::sub (dest+1, aux, (l2<<1) - 1);
00341   mmx_delete<C> (c1, l);
00342 }
00343 
00344 }; // implementation<polynomial_graeffe,V,polynomial_naive>
00345 
00346 /******************************************************************************
00347 * Division
00348 ******************************************************************************/
00349 
00350 struct polynomial_divide {};
00351 
00352 template<typename V>
00353 struct implementation<polynomial_divide,V,polynomial_naive>:
00354   public implementation<polynomial_multiply,V>
00355 {
00356   typedef implementation<polynomial_multiply,V> Pol;
00357   typedef implementation<vector_linear,V> Vec;
00358 
00359 TMPL static void
00360 quo_rem (C* dest, C* s1, const C* s2, nat n1, nat n2) {
00361   // (s1, n1) contains the numerator on input and the remainder on output
00362   // (s2, n2) contains the denominator. We assume n2>0 and s2[n2-1] != 0
00363   // (dest, n1-n2+1) contains the quotient
00364   while (n1 >= n2 && n1 != 0) {
00365     int d= n1-n2;
00366     C q= quo (s1[n1-1], s2[n2-1]);
00367     dest[d]= q;
00368     for (nat i=0; i<n2; i++)
00369       s1[i+d] -= q * s2[i];
00370     n1--;
00371   }
00372 }
00373 
00374 TMPL static void
00375 tquo_rem (C* dest, const C* s1, const C* s2, nat n1, nat n2) {
00376   // (s1, n2-1) contains the part corresponding to the remainder, while
00377   // (s2+n2-1, n1-n2+1) contains the one of the quotient.
00378   // We assume n2>0 and s2[n2-1] != 0.
00379   // (dest, n1) contains the output.
00380   C c = s2[n2-1];
00381   Pol::copy (dest, s1, n2-1);
00382   s1 += n2-1;
00383   for (nat i = n2-1; i < n1; i++, dest++, s1++)
00384     dest[n2-1] = quo (*s1 - Vec::inn_prod (dest, s2, n2-1), c);
00385 }
00386 
00387 TMPL static void
00388 pquo_rem (C* dest, C* s1, const C* s2, nat n1, nat n2) {
00389   // (s1, n1) contains the numerator on input
00390   //          and the pseudo-remainder on output
00391   // (s2, n2) contains the denominator.
00392   // We assume n2>0 and s2[n2-1] != 0
00393   // (dest, n1-n2+1) contains the pseudo-quotient
00394   nat l= n1 - n2 + 1;
00395   while (n1 >= n2 && n1 != 0) {
00396     int d= n1-n2;
00397     dest[d]= s1[n1-1];
00398     for (nat i=0; i<n1-1; i++)
00399       s1[i]*= s2[n2-1];
00400     for (nat i=0; i<n2-1; i++)
00401       s1[i+d]-= s1[n1-1] * s2[i];
00402     s1[n1-1]=0;
00403     n1--;
00404   }
00405   C c= s2[n2-1];
00406   for (nat i = 1; i < l; i++) {
00407     dest[i] *= c;
00408     c *= s2[n2-1];
00409   }
00410 }
00411 
00412 }; // implementation<polynomial_divide,V,polynomial_naive>
00413 
00414 /******************************************************************************
00415 * Exact division
00416 ******************************************************************************/
00417 
00418 struct polynomial_exact_divide {};
00419 
00420 template<typename V>
00421 struct polynomial_exact_divide_threshold {};
00422 
00423 template<typename V>
00424 struct implementation<polynomial_exact_divide,V,polynomial_naive>:
00425   public implementation<polynomial_divide,V>
00426 {
00427   typedef implementation<polynomial_divide,V> Pol;
00428   typedef implementation<vector_linear,V> Vec;
00429 
00430 TMPL static void
00431 div (C* dest, const C* s1, const C* s2, nat n1, nat n2) {
00432   // (s1, n1) contains the numerator on input
00433   // (s2, n2) contains the denominator. We assume n2>0 and s2[n2-1] != 0
00434   // (dest, n1-n2+1) contains the quotient
00435   nat l1= aligned_size<C,V> (n1);
00436   C* r= mmx_new<C> (l1);
00437   Vec::copy (r, s1, n1);
00438   Pol::quo_rem (dest, r, s2, n1, n2);
00439   if (! Pol::equal (r, C(0), n1)) {
00440     mmx_delete<C> (r, l1);
00441     ERROR ("division must be exact");
00442   }
00443   mmx_delete<C> (r, l1);
00444 }
00445 
00446 }; // implementation<polynomial_exact_divide,V,polynomial_naive>:
00447 
00448 /******************************************************************************
00449 * Composition
00450 ******************************************************************************/
00451 
00452 struct polynomial_compose {};
00453 
00454 template<typename V>
00455 struct implementation<polynomial_compose,V,polynomial_naive>:
00456   // FIXME: really a dichotomic algorithm; also implement naive version
00457   public implementation<polynomial_multiply,V>
00458 {
00459   typedef implementation<polynomial_multiply,V> Pol;
00460 
00461 TMPLK static void
00462 compose (C* dest, K* p, const C* s1, const K* s2, nat n1, nat n2) {
00463   // computes compose ((s1, n1), (s2, n2)) and pow ((s2, n2), n1)
00464   if (n1 == 1) {
00465     *dest= *s1;
00466     Pol::copy (p, s2, n2);
00467   }
00468   else {
00469     nat d2= n2 - 1;
00470     nat h1= n1 >> 1, h2= n1 - h1;
00471     nat l1= (h1-1) * d2 + 1, l2= (h2-1) * d2 + 1;
00472     nat k1= l1 + d2, k2= l2 + d2;
00473     nat alloc_c1= aligned_size<C,V> (l1 + l2);
00474     C* c1= mmx_new<C> (alloc_c1);
00475     C* c2= c1 + l1;
00476     nat alloc_p1= aligned_size<K,V> (k1 + k2);
00477     C* p1= mmx_new<K> (alloc_p1);
00478     K* p2= p1 + k1;
00479     compose (c1, p1, s1, s2, h1, n2);
00480     compose (c2, p2, s1+h1, s2, h2, n2);
00481     Pol::mul (dest, c2, p1, l2, k1);
00482     Pol::add (dest, c1, l1);
00483     Pol::mul (p, p1, p2, k1, k2);
00484     mmx_delete<K> (p1, alloc_p1);
00485     mmx_delete<C> (c1, alloc_c1);
00486   }
00487 }
00488 
00489 TMPLK static void
00490 compose (C* dest, const C* s1, const K* s2, nat n1, nat n2) {
00491   ASSERT (n1 > 0 && n2 > 0, "composition of empty segments");
00492   if (n1 == 1) *dest= *s1;
00493   else {
00494     nat d2= n2 - 1;
00495     nat h1= n1 >> 1, h2= n1 - h1;
00496     nat l1= (h1-1) * d2 + 1, l2= (h2-1) * d2 + 1;
00497     nat k1= l1 + d2;
00498     nat alloc_c1= aligned_size<C,V> (l1 + l2);
00499     C* c1= mmx_new<C> (alloc_c1);
00500     C* c2= c1 + l1;
00501     nat alloc_p1= aligned_size<K,V> (k1);
00502     K* p1= mmx_new<K> (alloc_p1);
00503     compose (c1, p1, s1, s2, h1, n2);
00504     compose (c2, s1+h1, s2, h2, n2);
00505     Pol::mul (dest, c2, p1, l2, k1);
00506     Pol::add (dest, c1, l1);
00507     mmx_delete<K> (p1, alloc_p1);
00508     mmx_delete<C> (c1, alloc_c1);
00509   }
00510 }
00511 
00512 TMPLK static void
00513 shift (C* dest, const C* s, const K& sh, nat n) {
00514   if (n <= 1 || sh == 0) Pol::copy (dest, s, n);
00515   else {
00516     K q[2]; q[0]= sh; q[1]= promote (1, sh);
00517     compose (dest, s, q, n, 2);
00518   }
00519 }
00520 
00521 }; // implementation<polynomial_compose,V,polynomial_naive>
00522 
00523 /******************************************************************************
00524 * Euclidean sequence
00525 ******************************************************************************/
00526 
00527 struct polynomial_euclidean {};
00528 
00529 template<typename V>
00530 struct implementation<polynomial_euclidean,V,polynomial_naive>:
00531   public implementation<polynomial_divide,V>
00532 {
00533   typedef implementation<polynomial_divide,V> Pol;
00534   typedef implementation<vector_linear,V> Vec;
00535 
00536 private:
00537 // Cf "Modern Computer Algebra", Chap. 6.
00538 // d1 and d2 contains the given polynomials at input, with n1 >= n2.
00539 // At the end, we have d1 = u1 s1 + u2 s2,  d2 = v1 s1 + v2 s2, being
00540 // the Bezout relations where the algorithm stops.
00541 
00542 // The normalized remainder of size i is stored in r[i].
00543 // Defected cases are also stored as for a subresultant sequence.
00544 // The respective quotient is stored in q.
00545 // The normalization coefficient is stored in rho[i].
00546 
00547 // n contains the sequence of the sizes of the successive remainders.
00548 
00549 TMPL static void
00550 euclidean_sequence (C*& d1, C*& d2, nat& n1 , nat& n2,
00551                     C*& u1, C*& u2, nat& nu1, nat& nu2,
00552                     C*& v1, C*& v2, nat& nv1, nat& nv2,
00553                     nat* n, C* rho, C* q, C** r, C** co1, C** co2,
00554                     nat k) {
00555   // d1 and d2 must have size n1 >= n2.
00556   // n, rho, q, r, co1, co2 must have size n2.
00557   // u1 and v1 (resp. u2 and v2) must have size n2 (resp. n1).
00558   // The algorithm stops with the last remainder d1 of size bigger than k,
00559   // and d2 of size at most k.
00560   VERIFY (n1 >= n2, "bug");
00561   VERIFY (n1 > k, "bug");
00562   if (n != NULL) Vec::clear (n, n2);
00563   C c1= invert (d1[n1-1]), c2= invert (d2[n2-1]);
00564   Vec::mul (d1, c1, n1); Vec::mul (d2, c2, n2);
00565   if (rho != NULL) Pol::clear (rho, n2);
00566   if (u1 != NULL) {
00567     VERIFY (v1 != NULL, "bug");
00568     Pol::clear (u1, n2); u1[0]= c1; nu1= 1;
00569     Pol::clear (v1, n2);            nv1= 0; }
00570   if (u2 != NULL) {
00571     VERIFY (v2 != NULL, "bug");
00572     Pol::clear (u2, n1);            nu2= 0;
00573     Pol::clear (v2, n1); v2[0]= c2; nv2= 1; }
00574   nat i= 0;
00575   while (n2 > k)
00576     if (n1 >= n2) {
00577       C m= - d1[n1-1]; nat s= n1-n2;
00578       if (q != NULL) q[n1-1]= m;
00579       Vec::mul_add (d1 + s, m, d2, n2); Pol::trim (d1, n1);
00580       if (u1 != NULL && nv1 != 0) {
00581         Vec::mul_add (u1 + s, m, v1, nv1);
00582         nu1 = max (nu1, nv1 + s); Pol::trim (u1, nu1);
00583       }
00584       if (u2 != NULL && nv2 != 0 ) {
00585         Vec::mul_add (u2 + s, m, v2, nv2);
00586         nu2 = max (nu2, nv2 + s); Pol::trim (u2, nu2);
00587       }
00588     }
00589     else {
00590       if (n != NULL) n[i]= n1; i++;
00591       if (rho != NULL)
00592         rho[n1]= rho[n2-1]= n1 == 0 ? promote (1, c1) : d1[n1-1];
00593       c1= invert (n1 == 0 ? promote (1, c1) : d1[n1-1]);
00594       Vec::mul (d1, c1, n1);
00595       if (u1 != NULL) Vec::mul (u1, c1, nu1);
00596       if (u2 != NULL) Vec::mul (u2, c1, nu2);
00597       if (r != NULL && r[n1] != NULL)
00598         Pol::copy (r[n1], d1, n1);
00599       if (n1 + 1 != n2 && r != NULL && r[n2-1] != NULL)
00600         Pol::copy (r[n2-1], d1, n1);
00601       if (co1 != NULL && co1[n1] != NULL)
00602         Pol::copy (co1[n1], u1, nu1);
00603       if (n1 + 1 != n2 && co1 != NULL && co1[n2-1] != NULL)
00604         Pol::copy (co1[n2-1], u1, nu1);
00605       if (co2 != NULL && co2[n1] != NULL)
00606         Pol::copy (co2[n1], u2, nu2);
00607       if (n1 + 1 != n2 && co2 != NULL && co2[n2-1] != NULL)
00608         Pol::copy (co2[n2-1], u2, nu2);
00609       swap (d1, d2); swap (n1 , n2 );
00610       swap (u1, v1); swap (nu1, nv1);
00611       swap (u2, v2); swap (nu2, nv2);
00612     }
00613 }
00614 
00615 public:
00616 
00617 TMPL static void
00618 euclidean_sequence (const C* s1, const C* s2, nat n1, nat n2,
00619                     C* d1, C* d2, nat& m1 , nat& m2,
00620                     C* u1, C* u2, nat& nu1, nat& nu2,
00621                     C* v1, C* v2, nat& nv1, nat& nv2,
00622                     nat* n, C* rho, C* q, C** r, C** co1, C** co2, nat k= 0) {
00623   // Wrap the previous function, so that any argument becomes optional.
00624   VERIFY (n1 >= n2, "bug");
00625   nat l1= aligned_size<C,V> (n1), l2= aligned_size<C,V> (n2);
00626   nat l= max (l1, l2);
00627   C* t1= mmx_new<C> (l), * t2= mmx_new<C> (l);
00628   Pol::copy (t1, s1, n1); Pol::copy (t2, s2, n2);
00629   bool opt_co1= ! (u1 == NULL && v1 == NULL && co1 == NULL);
00630   bool opt_co2= ! (u2 == NULL && v2 == NULL && co2 == NULL);
00631   C* uu1= NULL, * uu2= NULL, * vv1= NULL, * vv2= NULL;
00632   if (opt_co1) { uu1= mmx_new<C> (l2); vv1= mmx_new<C> (l2); }
00633   if (opt_co2) { uu2= mmx_new<C> (l1); vv2= mmx_new<C> (l1); }
00634   nat mm1= n1, mm2= n2, mu1, mu2, mv1, mv2;
00635   // If the final remainders are not requested then we stop earlier:
00636   if (d1 == NULL && d2 == NULL && !opt_co1 && !opt_co2) {
00637     while (k < n2 &&
00638            (r   == NULL || r  [k] == NULL) &&
00639            (co1 == NULL || co1[k] == NULL) &&
00640            (co2 == NULL || co2[k] == NULL)) k++;
00641   }
00642   euclidean_sequence (t1 , t2 , mm1, mm2,
00643                       uu1, uu2, mu1, mu2,
00644                       vv1, vv2, mv1, mv2,
00645                       n, rho, q, r, co1, co2, k);
00646   if (d1 != NULL) { Pol::copy (d1, t1, mm1); m1= mm1; }
00647   if (d2 != NULL) { Pol::copy (d2, t2, mm2); m2= mm2; }
00648   mmx_delete<C> (t1, l); mmx_delete<C> (t2, l);
00649   if (u1 != NULL) { Pol::copy (u1, uu1, mu1); nu1= mu1; }
00650   if (u2 != NULL) { Pol::copy (u2, uu2, mu2); nu2= mu2; }
00651   if (v1 != NULL) { Pol::copy (v1, vv1, mv1); nv1= mv1; }
00652   if (v2 != NULL) { Pol::copy (v2, vv2, mv2); nv2= mv2; }
00653   if (opt_co1) { mmx_delete<C> (uu1, l2); mmx_delete<C> (vv1, l2); }
00654   if (opt_co2) { mmx_delete<C> (uu2, l1); mmx_delete<C> (vv2, l1); }
00655 }
00656   
00657 TMPL static void
00658 gcd (C* g, nat& n, const C* s1, const C* s2, nat n1, nat n2,
00659      C* u1, C* u2, nat& nu1, nat& nu2) {
00660   VERIFY (n1>0 && n2>0 && s1[n1-1] != 0 && s2[n2-1] != 0,
00661           "invalid hypothesis for gcd computation");
00662   if (n1 < n2) return gcd (g, n, s2, s1, n2, n1, u2, u1, nu2, nu1);
00663   n= max (n1, n2); nat m= min (n1, n2);
00664   nat l1= aligned_size<C,V> (n1), l2= aligned_size<C,V> (n2);
00665   nat l= aligned_size<C,V> (n);
00666   C* d1= mmx_new<C> (l), * d2= mmx_new<C> (l);
00667   C* v1= u1 == NULL ? NULL : mmx_new<C> (l2);
00668   C* v2= u2 == NULL ? NULL : mmx_new<C> (l1);
00669   nat m1=0, m2=0, nv1=0, nv2=0;
00670   euclidean_sequence (s1, s2, n1, n2,
00671                       d1, d2, m1, m2,
00672                       u1, u2, nu1, nu2,
00673                       v1, v2, nv1, nv2,
00674                       (nat*)NULL, (C*)NULL, (C*)NULL,
00675                       (C**)NULL, (C**)NULL, (C**)NULL);
00676   Pol::copy (g, d1, m1); Pol::clear (g + m1, m - m1); n= m1;
00677   mmx_delete<C> (d1, l); mmx_delete<C> (d2, l);
00678   if (u1 != NULL) mmx_delete<C> (v1, l2);
00679   if (u2 != NULL) mmx_delete<C> (v2, l1);
00680 }
00681 
00682 TMPL static void
00683 pade (C* r, C* t, const C* s, nat m, nat n, nat k) {
00684   // r (resp. t) must have allocated length at least k (resp. n-k+1)
00685   // s = r / t + O(x^n), deg r < k, deg t <= n-k
00686   // "Modern Computer Algebra", Corollary 5.21
00687   VERIFY (n > k && n > 0 && s[m-1]!= 0 && m <= n,
00688           "invalid hypothesis for pade approximant");
00689   nat n1= n+1, n2= m, l1= aligned_size<C,V> (n1);
00690   C* s1= mmx_new<C> (l1);
00691   Pol::clear (s1, n); s1[n]= 1;
00692   C* d1= NULL, * d2= mmx_new<C> (l1);
00693   C* u1= NULL, * u2= mmx_new<C> (l1);
00694   C* v1= NULL, * v2= mmx_new<C> (l1);
00695   nat nu1=0, nu2=0, nv1=0, nv2=0, nd1=0, nd2=0;
00696   euclidean_sequence (s1, s , n1, n2,
00697                       d1, d2, nd1, nd2,
00698                       u1, u2, nu1, nu2,
00699                       v1, v2, nv1, nv2,
00700                       (nat*)NULL, (C*)NULL, (C*)NULL,
00701                       (C**)NULL, (C**)NULL, (C**)NULL, k);
00702   VERIFY (nd2 <= k, "bug");
00703   VERIFY (nv2 <= n-k+1, "bug");
00704   Pol::copy (r, d2, nd2); Pol::clear (r + nd2, k - nd2);
00705   Pol::copy (t, v2, nv2); Pol::clear (t + nv2, n-k+1 - nv2);
00706   mmx_delete<C> (d2, l1);
00707   mmx_delete<C> (u2, l1); mmx_delete<C> (v2, l1);
00708 }
00709 
00710 }; // implementation<polynomial_euclidean,V,polynomial_naive>
00711 
00712 /******************************************************************************
00713 * Gcd computations
00714 ******************************************************************************/
00715 
00716 struct polynomial_gcd {};
00717 
00718 template<typename V>
00719 struct implementation<polynomial_gcd,V,polynomial_naive>:
00720   public implementation<polynomial_divide,V>
00721 {
00722   typedef implementation<polynomial_euclidean,V> Pol;
00723   typedef implementation<vector_linear,V> Vec;
00724 
00725 #define C typename scalar_type_helper<Polynomial >::val
00726   
00727 TMPLP static Polynomial
00728 gcd (const Polynomial& P1, const Polynomial& P2,
00729      Polynomial& U1, Polynomial& U2) {
00730   bool opt1= U1 != 0, opt2= U2 != 0;
00731   nat n1= N(P1), n2= N(P2);
00732   C c1= P1[n1-1], c2= P2[n2-1];
00733   if (n1 == 0 && n2 == 0) {
00734     if (opt1) set_as (U1, 0);
00735     if (opt2) set_as (U2, 0);
00736     return promote (0, P1); }
00737   if (n2 == 0) {
00738     if (opt1) U1= promote (1, c1) / c1;
00739     if (opt2) set_as (U2, 0);
00740     return P1 / c1; }
00741   if (n1 == 0) {
00742     if (opt1) set_as (U1, 0);
00743     if (opt2) U2= promote (1, c2) / c2;
00744     return P2 / c2; }
00745   nat m = min (n1, n2), nu1, nu2;
00746   nat l = aligned_size<C,V> (m);
00747   nat l1= aligned_size<C,V> (n1), l2= aligned_size<C,V> (n2);
00748   C* tmp= mmx_new<C> (l);
00749   C* u1= opt1 ? mmx_new<C> (l2) : NULL;
00750   C* u2= opt2 ? mmx_new<C> (l1) : NULL;
00751   Pol::gcd (tmp, m, seg (P1), seg (P2), n1, n2, u1, u2, nu1, nu2);
00752   if (opt1) U1= Polynomial (u1, nu1, l2, CF(P1));
00753   if (opt2) U2= Polynomial (u2, nu2, l1, CF(P1));
00754   nat lg = aligned_size<C,V> (m);
00755   C* g= mmx_new<C> (lg);
00756   Pol::copy (g, tmp, m);
00757   mmx_delete<C> (tmp, l);
00758   return Polynomial (g, m, lg, CF(P1)); }
00759 
00760 TMPLP static Polynomial
00761 gcd (const Polynomial& P1, const Polynomial& P2) {
00762   Polynomial U1= promote (0, P1), U2= promote (0, P2);
00763   return gcd (P1, P2, U1, U2); }
00764 
00765 TMPLP static inline Polynomial
00766 lcm (const Polynomial& P1, const Polynomial& P2) {
00767   Polynomial U1= promote (0, P1), U2= promote (0, P1);
00768   return
00769     (P1 == 0 && P2 == 0) ?
00770     promote (0, P1) :
00771     P1 * (P2 / gcd (P1, P2, U1, U2)); }
00772 
00773 TMPLP static Polynomial
00774 invert_mod (const Polynomial& P, const Polynomial& Q) {
00775   // inverse of P modulo Q, return 0 if non-invertible
00776   Polynomial inv_P= C(1), dummy= C(0);
00777   Polynomial G= gcd (P, Q, inv_P, dummy);
00778   if (deg (G) != 0 || G[0] == 0) inv_P= 0;
00779   return inv_P / G[0]; }
00780 
00781 TMPLP static void
00782 pade (const Polynomial& P, nat n, nat k,
00783       Polynomial& Num, Polynomial& Den) {
00784   // In return P = Num/Den + O(x^n), with
00785   // deg (Num) < k and deg (Den) <= n-k.
00786   // Note that Num and Den are not ensured to be coprime.
00787   VERIFY (k <= n && k > 0, "invalid argument");
00788   nat m= N(P);
00789   if (n == 0 || m == 0) { Num= 0; Den= 1; return; }
00790   if (k == n) { Num= P; Den= 1; return; }
00791   nat lnum = aligned_size<C,V> (k), lden= aligned_size<C,V> (n-k+1);
00792   C* num= mmx_new<C> (lnum), * den= mmx_new<C> (lden);
00793   Pol::pade (num, den, seg (P), m, n, k);
00794   Num= Polynomial (num, k, lnum, CF(P));
00795   Den= Polynomial (den, n-k+1, lden, CF(P)); }
00796 
00797 #undef C
00798 }; // implementation<polynomial_gcd,V,polynomial_naive>
00799 
00800 /******************************************************************************
00801 * Subresultants
00802 ******************************************************************************/
00803 
00804 struct polynomial_subresultant_base {};
00805 struct polynomial_subresultant {};
00806 
00807 template<typename V>
00808 struct implementation<polynomial_subresultant_base,V,polynomial_naive>:
00809   public implementation<polynomial_divide,V>
00810 {
00811   typedef implementation<polynomial_euclidean,V> Pol;
00812   typedef implementation<vector_linear,V> Vec;
00813 
00814 TMPLP static void
00815 subresultant_sequence (const Polynomial& f, const Polynomial& g,
00816                        vector<Polynomial>& res,
00817                        vector<Polynomial>& cof, vector<Polynomial>& cog,
00818                        Polynomial& d1, Polynomial& u1, Polynomial& v1,
00819                        Polynomial& d2, Polynomial& u2, Polynomial& v2,
00820                        nat dest_deg= 0) {
00821   /* In return res[k] contains the kth subresultant of f and g.
00822    * If res[k] is zero in input then this computation is skipped.
00823    * The same rule applies to the cofactors cof and cog, and d1, u1, etc
00824    * When all the following entries are actually filled we have:
00825    *   res[k] = cof[k] * f[k] + cog[k] * g[k]
00826    * d1 contains the smallest subresultant of degree at least dest_deg.
00827    * u1 and v1 are the corresponding cofactors: d1= u1 * f + v1 * g.
00828    * d2 contains the largest subresultant of degree less than dest_deg.
00829    * u2 and v2 are the corresponding cofactors: d2= u2 * f + v2 * g.
00830    */
00831   typedef typename scalar_type_helper<Polynomial>::val C;
00832   nat n1= N(f), n2= N(g);
00833   VERIFY (n1 >= n2, "bug");
00834   if (n2 <= 1) return;
00835   nat l1= aligned_size<C,V> (n1), l2= aligned_size<C,V> (n2);
00836   vector<C> rho (C(0), n2); C** sub= mmx_new<C*> (n2, (C*) NULL);
00837   vector<nat> ns ((nat) 0, n2);
00838   C* dd1= (d1 == 0 && u1 == 0 && v1 == 0) ? NULL : mmx_new<C> (l1);
00839   C* dd2= (d2 == 0 && u2 == 0 && v2 == 0) ? NULL : mmx_new<C> (l1);
00840   C* uu1= u1 == 0 ? NULL : mmx_new<C> (l2);
00841   C* vv1= v1 == 0 ? NULL : mmx_new<C> (l1);
00842   C* uu2= u2 == 0 ? NULL : mmx_new<C> (l2);
00843   C* vv2= v2 == 0 ? NULL : mmx_new<C> (l1);
00844   nat nd1= 0, nd2= 0, nu1= 0, nu2= 0, nv1= 0, nv2= 0;
00845   C** co1= mmx_new<C*> (n2, (C*) NULL); C** co2= mmx_new<C*> (n2, (C*) NULL);
00846   for (nat i = 1; i < n2; i++) {
00847     if (i-1 < N(res) && res[i-1] != 0)
00848       sub[i]= mmx_new<C> (aligned_size<C,V> (i), C(0));
00849     if (i-1 < N(cof) && cof[i-1] != 0)
00850       co1[i]= mmx_new<C> (l2, C(0));
00851     if (i-1 < N(cog) && cog[i-1] != 0)
00852       co2[i]= mmx_new<C> (l1, C(0));
00853   }
00854   Pol::euclidean_sequence (seg(f), seg(g), n1, n2,
00855                            dd1, dd2, nd1, nd2,
00856                            uu1, uu2, nu1, nu2,
00857                            vv1, vv2, nv1, nv2,
00858                            seg (ns), seg (rho), (C*) NULL,
00859                            sub, co1, co2, dest_deg);
00860   for (nat i = 1; i < n2; i++) {
00861     if (i-1 < N(res) && res[i-1] != 0)
00862       res[i-1]= Polynomial (sub[i], i, aligned_size<C,V> (i), CF(f));
00863     if (i-1 < N(cof) && cof[i-1] != 0)
00864       cof[i-1]= Polynomial (co1[i], n2, l2, CF(f));
00865     if (i-1 < N(cog) && cog[i-1] != 0)
00866       cog[i-1]= Polynomial (co2[i], n1, l1, CF(f));
00867   }
00868   if (d1 != 0) d1= Polynomial (dd1, nd1, l1, CF(f));
00869   if (d2 != 0) d2= Polynomial (dd2, nd2, l1, CF(f));
00870   if (u1 != 0) u1= Polynomial (uu1, nu1, l2, CF(f));
00871   if (u2 != 0) u2= Polynomial (uu2, nu2, l2, CF(f));
00872   if (v1 != 0) v1= Polynomial (vv1, nv1, l1, CF(f));
00873   if (v2 != 0) v2= Polynomial (vv2, nv2, l1, CF(f));
00874   mmx_delete<C*> (sub, n2);
00875   mmx_delete<C*> (co1, n2); mmx_delete<C*> (co2, n2);
00876   vector<C> c (promote (0, CF(f)), n2);
00877     // vector of the leading coefficients of the
00878     // subresultants (including the defective cases)
00879   nat n= n2 - 1, m= ns[0] - 1, i= 0;
00880   C c_n= g[n], c_n_1= f[n1-1] * binpow (g[n], n1 - n2 + 1) * rho[ns[0]];
00881   C d= binpow (g[n], n1 - n2);
00882   c[n-1]= c_n_1;
00883   while (m + 1 > 0) {
00884     C t0= binpow (c_n_1, n-m-1), t1= binpow (d, n-m-1);
00885     c[m]= (t0 / t1) * c_n_1;
00886     if (m == 0) break;
00887     t0 *= square_op::op (c_n_1); t1 *= ((n-m) & 1) ? c_n * d : -c_n * d;
00888     c[m-1]= (t0 * c_n * rho[m]) / t1;
00889     n= m; c_n= c[m]; d= c[m]; c_n_1= c[m-1]; i++; m= ns[i] - 1;
00890   }
00891   for (nat i= 0; i < N(res); i++) res[i] *= c[i];
00892   for (nat i= 0; i < N(cof); i++) cof[i] *= c[i];
00893   for (nat i= 0; i < N(cog); i++) cog[i] *= c[i];
00894   d= (nd1 > n2 || nd1 == 0) ? promote (0, d) : c[nd1 - 1];
00895   d1 *= d; u1 *= d; v1 *= d;
00896   d= (nd1 > n2 || nd1 <  2) ? promote (1, d) : c[nd1 - 2];
00897   d2 *= d; u2 *= d; v2 *= d; }
00898 
00899 }; // implementation<polynomial_subresultant_base,V,polynomial_naive>
00900 
00901 template<typename V>
00902 struct implementation<polynomial_subresultant,V,polynomial_naive>:
00903   public implementation<polynomial_subresultant_base,V>
00904 {
00905   // Common handle for when degree (f) < degree (g) or f or g is zero.
00906   typedef implementation<polynomial_subresultant_base,V> Pol;
00907 
00908 TMPLP static void
00909 subresultant_sequence (const Polynomial& f, const Polynomial& g,
00910                        vector<Polynomial>& res,
00911                        vector<Polynomial>& cof, vector<Polynomial>& cog,
00912                        Polynomial& d1, Polynomial& u1, Polynomial& v1,
00913                        Polynomial& d2, Polynomial& u2, Polynomial& v2,
00914                        nat dest_deg= 0) {
00915   int n= degree (f), m= degree (g);
00916   if (n <= 0 || m <= 0) {
00917     set_as (d1, 0); set_as (u1, 0); set_as (v1, 0);
00918     set_as (d2, 0); set_as (u2, 0); set_as (v2, 0);
00919     return;
00920   }
00921   if (n < m) {
00922     Pol::subresultant_sequence (g, f, res, cog, cof,
00923                                 d1, v1, u1, d2, v2, u2, dest_deg);
00924     for (nat k= 0; k < (nat) n; k++)
00925       if ((m+n-1) & (n-k) & 1) {
00926         if (k < N(res)) res[k]= -res[k];
00927         if (k < N(cof)) cof[k]= -cof[k];
00928         if (k < N(cog)) cog[k]= -cog[k];
00929       }
00930     if ((m+n-1) & (n-degree (d1)) & 1) { d1= -d1; u1= -u1; v1= -v1; }
00931     else { d2= -d2; u2= -u2; v2= -v2; }
00932   }
00933   else
00934     Pol::subresultant_sequence (f, g, res, cof, cog,
00935                                 d1, u1, v1, d2, u2, v2, dest_deg); }
00936 
00937 }; // implementation<polynomial_subresultant,V,polynomial_naive>
00938 
00939 /******************************************************************************
00940 * Efficient evaluation of polynomials
00941 ******************************************************************************/
00942 
00943 struct polynomial_evaluate {};
00944 
00945 template<typename V>
00946 struct implementation<polynomial_evaluate,V,polynomial_naive>:
00947   public implementation<polynomial_divide,V>
00948 {
00949   typedef implementation<polynomial_divide,V> Pol;
00950   typedef implementation<vector_linear,V> Vec;
00951 
00952 TMPL static void
00953 multi_mod (C* r, const C* p, const C* q, const nat* d, nat n, nat k) {
00954   // The polynomial (p, n) is divided by k polynomials
00955   // (q, d[0]), (q + d[0], d[1]), ..., (q + d[0] + ... + d[k-2], d[k-1])
00956   // The remainders of these divisions are put into
00957   // (r, d[0]-1), (r + d[0], d[1]-1), ..., (r + d[0] + ... + d[k-2], d[k-1]-1)
00958   nat l= aligned_size<C,V> (n);
00959   C* tmp_q= mmx_new <C> (l);
00960   C* tmp_r= mmx_new <C> (l);
00961   for (nat i= 0; i < k; i++) {
00962     if (n < d[i]) {
00963       Pol::copy (r, p, n);
00964       Pol::clear (r+n, d[i]-1-n);
00965     }
00966     else {
00967       Pol::copy (tmp_r, p, n);
00968       quo_rem (tmp_q, tmp_r, q, n, d[i]);
00969       Pol::copy (r, tmp_r, d[i]-1);
00970     }
00971     r += d[i]; q += d[i];
00972   }
00973   mmx_delete<C> (tmp_q, l);
00974   mmx_delete<C> (tmp_r, l);
00975 }
00976 
00977 TMPL static void
00978 annulator (C* d, const C* s, nat n) {
00979   // Given n constants s[0],...s[n-1],
00980   // construct the polynomial (z-s[0]) ... (z-s[n-1])
00981   switch (n) {
00982   case 0:
00983     d[0]= promote (1, d[0]);
00984     break;
00985   case 1:
00986     d[1]= promote (1, d[0]);
00987     d[0]= -s[0];
00988     break;
00989   case 2:
00990     d[2]= promote (1, d[0]);
00991     d[1]= -(s[0]+s[1]);
00992     d[0]= s[0]*s[1];
00993     break;
00994   case 3:
00995     d[3]= promote (1, d[0]);
00996     d[2]= -(s[0]+s[1]+s[2]);
00997     d[1]= s[0]*s[1] + s[1]*s[2]+ s[2]*s[0];
00998     d[0]= -s[0]*s[1]*s[2];
00999     break;
01000   default:
01001     {
01002       nat h= n>>1;
01003       nat l= aligned_size<C,V> (n+2);
01004       C* aux= mmx_new<C> (l);
01005       annulator (aux, s, h);
01006       annulator (aux+h+1, s+h, n-h);
01007       Pol::mul (d, aux, aux+h+1, h+1, n+1-h);
01008       mmx_delete<C> (aux, l);
01009     }
01010   }
01011 }
01012 
01013 TMPL static C
01014 evaluate (const C* p, const C& x, nat l) {
01015   // Evaluate the polynomial (p, n) at x
01016   if (l == 0) return 0;
01017   C r= p[l-1];
01018   for (nat i=l-2; i!=((nat)(-1)); i--)
01019     r= (x*r) + p[i];
01020   return r;
01021 }
01022 
01023 TMPL void
01024 tevaluate (const C& v, C* p, const C& x, nat l) {
01025   // Transposed evaluation of the polynomial (p, l) at x
01026   if (l == 0) return;
01027   p[0] = v;
01028   for (nat i= 1; i < l; i++) p[i] = x * p[i-1];
01029 }
01030 
01031 TMPL static void
01032 evaluate (C* v, const C* p, const C* x, nat l, nat n) {
01033   // Evaluate the polynomial (p, l) at points x[0], ..., x[n-1]
01034   for (nat j=0; j<n; j++)
01035     if (l == 0) v[j]= 0;
01036     else {
01037       C r= p[l-1];
01038       for (nat i=l-2; i!=((nat)(-1)); i--)
01039         r= (x[j]*r) + p[i];
01040       v[j]= r;
01041     }
01042 }
01043 
01044 TMPL static void
01045 tevaluate (const C* v, C* p, const C* x, nat l, nat n) {
01046   // Transposed evaluation of (p, l) at points x[0], ..., x[n-1]
01047   nat l_y= aligned_size<C,V> (n);
01048   C* y= mmx_new<C> (l_y);
01049   Pol::set (y, C(1), n);
01050   for (nat j= 0; j < l; j++) {
01051     p[j]= Vec::inn_prod (y, v, n);
01052     Vec::mul (y, x, n);
01053   }
01054   mmx_delete<C> (y, l_y);
01055 }
01056 
01057 TMPL static void
01058 interpolate (C* p, const C* v, const C* x, nat n) {
01059   // Interpolate the polynomial (p, n) from values
01060   // v[0], ... , v[n-1] at points x[0], ..., x[n-1]
01061   if (n == 0) return;
01062   format<C> fm= get_format (v[0]);
01063   nat l= aligned_size<C,V> (n+1), i, j;
01064   C ** buf= mmx_new<C*> (n+1);
01065   for (i= 0; i < n+1; i++)
01066     buf[i]= mmx_formatted_new<C> (l, fm);
01067   C * tmp0= mmx_formatted_new<C> (l, fm);
01068   C * tmp1= mmx_formatted_new<C> (l, fm);
01069   buf[0][0]= promote (1, fm);
01070   for (i= 0; i < n; i++) {
01071     for (j= 0; j < i; j++) {
01072       Pol::copy (tmp0 + 1, buf[j], i); tmp0[0]= promote (0, fm);
01073       Pol::mul_sc (tmp1, buf[j], x[i], i); tmp1[i]= promote (0, fm);
01074       Pol::sub (buf[j], tmp0, tmp1, i+1);
01075     }
01076     Pol::copy (tmp0 + 1, buf[j], i + 1); tmp0[0]= promote (0, fm);
01077     Pol::mul_sc (tmp1, buf[j], x[i], i + 1); tmp1[i+1]= promote (0, fm);
01078     Pol::sub (buf[j+1], tmp0, tmp1, i + 2);
01079   }
01080   Pol::derive (tmp1, buf[n], n+1);
01081   evaluate (tmp0, tmp1, x, n, n);
01082   Vec::div (tmp1, v, tmp0, n);
01083   Pol::clear (p, n);
01084   for (i= 0; i < n; i++) {
01085     Pol::mul_sc (tmp0, buf[i], tmp1[i], n);
01086     Pol::add (p, tmp0, n);
01087   }
01088   mmx_delete<C> (tmp0, l); mmx_delete<C> (tmp1, l);
01089   for (i= 0; i < n+1; i++) mmx_delete<C> (buf[i], l);
01090   mmx_delete<C*> (buf, n+1);
01091 }
01092 
01093 TMPL static void
01094 tinterpolate (const C* p, C* v, const C* x, nat n) {
01095   // Interpolate the polynomial (p, n) from values
01096   // v[0], ... , v[n-1] at points x[0], ..., x[n-1]
01097   if (n == 0) return;
01098   format<C> fm= get_format (v[0]);
01099   nat l= aligned_size<C,V> (n+1), i, j;
01100   C ** buf= mmx_new<C*> (n+1);
01101   for (i= 0; i < n+1; i++)
01102     buf[i]= mmx_formatted_new<C> (l, fm);
01103   C * tmp0= mmx_formatted_new<C> (l, fm);
01104   C * tmp1= mmx_formatted_new<C> (l, fm);
01105   buf[0][0]= promote (1, fm);
01106   for (i= 0; i < n; i++) {
01107     for (j= 0; j < i; j++) {
01108       Pol::copy (tmp0 + 1, buf[j], i); tmp0[0]= promote (0, fm);
01109       Pol::mul_sc (tmp1, buf[j], x[i], i); tmp1[i]= promote (0, fm);
01110       Pol::sub (buf[j], tmp0, tmp1, i+1);
01111     }
01112     Pol::copy (tmp0 + 1, buf[j], i + 1); tmp0[0]= promote (0, fm);
01113     Pol::mul_sc (tmp1, buf[j], x[i], i + 1); tmp1[i+1]= promote (0, fm);
01114     Pol::sub (buf[j+1], tmp0, tmp1, i + 2);
01115   }
01116   Pol::derive (tmp1, buf[n], n+1);
01117   evaluate (tmp0, tmp1, x, n, n);
01118   for (i= 0; i < n; i++)
01119     v[i]= Vec::inn_prod (buf[i], p, n);
01120   Vec::div (v, tmp0, n);
01121   mmx_delete<C> (tmp0, l); mmx_delete<C> (tmp1, l);
01122   for (i= 0; i < n+1; i++) mmx_delete<C> (buf[i], l);
01123   mmx_delete<C*> (buf, n+1);
01124 }
01125 
01126 TMPL static void
01127 expand (C** v, const C* p, const C* x, const nat* nu, nat n, nat k) {
01128   (void) v; (void) p; (void) x; (void) nu; (void) n; (void) k;
01129   ERROR ("expand not yet implemented");
01130 }
01131 
01132 #define C typename scalar_type_helper<Polynomial>::val
01133 
01134 TMPLP static vector<Polynomial>
01135 multi_rem (const Polynomial& p, const vector<Polynomial>& q) {
01136   ASSERT (is_non_scalar (q), "non-scalar vector expected");
01137   nat k= N(q), n= N(p);
01138   if (k == 0) return q;
01139   vector<nat> d ((nat) 0, k);
01140   for (nat i= 0; i < k; i++) {
01141     d[i]= N(q[i]);
01142     ASSERT (d[i] > 0, "division by 0");
01143   }
01144   if (n == 0) return vector<Polynomial> (Polynomial (C(0)), k);
01145   nat m= big_add (d), l= aligned_size<C,V> (m);
01146   C* qq= mmx_new<C> (l), * r= mmx_new<C> (l), * tmp= qq;
01147   for (nat i= 0; i < k; i++) {
01148     Pol::copy (tmp, seg (q[i]), d[i]);
01149     if (q[i][d[i]-1] != 1)
01150       Pol::mul_sc (tmp, 1/q[i][d[i]-1], d[i]);
01151     tmp += d[i];
01152   }
01153   multi_mod (r, seg(p), qq, seg (d), n, k);
01154 
01155   mmx_delete<C> (qq, l);
01156   vector<Polynomial> ans (Polynomial (C(0)), k);  
01157   tmp= r;
01158   for (nat i= 0; i < k; i++) {
01159     nat l_t= aligned_size<C,V> (d[i]-1);
01160     C* t= mmx_new<C> (l_t);
01161     Pol::copy (t, tmp, d[i]-1);
01162     ans[i]= Polynomial (t, d[i]-1, l_t, CF(p));
01163     tmp += d[i];
01164   }
01165   mmx_delete<C> (r, l);
01166   return ans; }
01167 
01168 TMPLP static vector<Polynomial>
01169 multi_prem (const Polynomial& P, const vector<Polynomial>& Q) {
01170   return binary_map_scalar<prem_op> (Q, P); }
01171 
01172 TMPLP static vector<Polynomial>
01173 multi_gcd (const Polynomial& P, const vector<Polynomial>& Q) {
01174   return binary_map<gcd_op> (rem (P, Q), Q); }
01175 
01176 TMPLP static Polynomial
01177 annulator (const Vector& x) {
01178   ASSERT (is_non_scalar (x), "non-scalar vector expected");
01179   nat l= aligned_size<C,V> (N(x)+1);
01180   C* r= mmx_new<C> (l);
01181   annulator (r, seg(x), N(x));
01182   return Polynomial (r, N(x)+1, l, CF(x)); }
01183 
01184 TMPLP static inline Vector
01185 evaluate (const Polynomial& p, const Vector& x) {
01186   ASSERT (is_non_scalar (x), "non-scalar vector expected");
01187   nat l= default_aligned_size<C> (N(x));
01188   C* r= mmx_new<C> (l);
01189   evaluate (r, seg(p), seg(x), N(p), N(x));
01190   return Vector (r, N(x), l, CF(x)); }
01191 
01192 TMPLP static inline Polynomial
01193 tevaluate (const Vector& v, const Vector& x, nat l) {
01194   ASSERT (is_non_scalar (x), "non-scalar vector expected");
01195   nat l_r= aligned_size<C,V> (l), n= N(x);
01196   C* r= mmx_new<C> (l_r);
01197   tevaluate (seg(v), r, seg(x), l, n);
01198   return Polynomial (r, l, l_r, CF(v)); }
01199 
01200 TMPLP static Polynomial
01201 interpolate (const Vector& v, const Vector& x) {
01202   ASSERT (is_non_scalar (x), "non-scalar vector expected");
01203   ASSERT (N(v) == N(x), "dimensions don't match");
01204   nat n= N(v), l= aligned_size<C,V> (n);
01205   C* r= mmx_new<C> (l);
01206   interpolate (r, seg(v), seg(x), n);
01207   return Polynomial (r, n, l, CF(v)); }
01208 
01209 TMPLP static Vector
01210 tinterpolate (const Polynomial& p, const Vector& x) {
01211   ASSERT (is_non_scalar (x), "non-scalar vector expected");
01212   ASSERT (N(p) <= N(x), "dimensions don't match");
01213   nat n= N(x), lv = default_aligned_size<C> (n);
01214   nat lp= aligned_size<C,V> (n); 
01215   C* r= mmx_new<C> (lv); C* tmp= mmx_new<C> (lp);
01216   Pol::copy (tmp, seg(p), N(p)); Pol::clear (tmp + N(p), n - N(p)); 
01217   tinterpolate (tmp, r, seg(x), n);
01218   mmx_delete<C> (tmp, lp);
01219   return Vector (r, n, lv); }
01220 #undef C
01221 
01222 }; // implementation<polynomial_evaluate,V,polynomial_naive>
01223 
01224 #undef TMPL
01225 #undef TMPLK
01226 #undef TMPLX
01227 #undef TMPLP
01228 } // namespace mmx
01229 #endif //__MMX__POLYNOMIAL_NAIVE__HPP
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines