algebramix_doc 0.3
|
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