algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : algebraic_number.hpp 00004 * DESCRIPTION: Algebraic extensions based on a primitive element 00005 * COPYRIGHT : (C) 2011 Joris van der Hoeven 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_ALGEBRAIC_NUMBER_HPP 00014 #define __MMX_ALGEBRAIC_NUMBER_HPP 00015 #include <algebramix/algebraic.hpp> 00016 #include <numerix/ball_complex.hpp> 00017 namespace mmx { 00018 #define TMPL_DEF template<typename C, typename Ball> 00019 #define TMPL template<typename C, typename Ball> 00020 #define Extension algebraic_extension<C> 00021 #define Field algebraic_number_extension<C,Ball> 00022 #define Polynomial polynomial<C> 00023 #define Element typename algebraic_number_extension<C,Ball>::El 00024 TMPL class algebraic_number_extension; 00025 TMPL bool shrink (const Polynomial& p, Ball& x); 00026 TMPL Polynomial annihilator (const Field& ext, const Element& p); 00027 00028 /****************************************************************************** 00029 * The algebraic number types 00030 ******************************************************************************/ 00031 00032 TMPL_DEF 00033 class algebraic_number_extension { 00034 MMX_ALLOCATORS; 00035 public: 00036 Extension ext; // algebraic extension 00037 Ball x; // ball containing unique root x 00038 typedef typename Extension::El El; // representation of elements 00039 00040 public: 00041 inline algebraic_number_extension (): 00042 ext (), x (0) {} 00043 inline algebraic_number_extension (const format<C>& fm): 00044 ext (fm), x (0) {} 00045 inline algebraic_number_extension (const Extension& ext2, const Ball& x2): 00046 ext (ext2), x (x2) { shrink_check (ext.mp, x); } 00047 inline algebraic_number_extension (const Polynomial& mp, const Ball& x2): 00048 ext (mp), x (x2) { shrink_check (mp, x); } 00049 template<typename C2, typename Ball2> inline 00050 algebraic_number_extension (const algebraic_number_extension<C2,Ball2>& ext2): 00051 ext (ext2.ext), x (as<Ball> (ext2.x)) { shrink_check (ext.mp, x); } 00052 inline algebraic_number_extension (const pair<Extension,Ball>& p): 00053 ext (p.x1), x (p.x2) {} 00054 inline pair<Extension,Ball> operator * () const { 00055 return pair<Extension,Ball> (ext, x); } 00056 }; 00057 00058 typedef algebraic_number_extension<rational,ball<floating<> > > 00059 algebraic_real_extension; 00060 typedef algebraic_number_extension<rational,ball<complex<floating<> > > > 00061 algebraic_complex_extension; 00062 typedef algebraic<rational,algebraic_real_extension> 00063 algebraic_real; 00064 typedef algebraic<rational,algebraic_complex_extension> 00065 algebraic_number; 00066 00067 UNARY_RETURN_TYPE(STMPL,Re_op,algebraic_number,algebraic_real); 00068 UNARY_RETURN_TYPE(STMPL,abs_op,algebraic_number,algebraic_real); 00069 BINARY_RETURN_TYPE(STMPL,gaussian_op,algebraic_real,algebraic_real,algebraic_number); 00070 00071 /****************************************************************************** 00072 * Basic operations 00073 ******************************************************************************/ 00074 00075 TMPL inline nat hash (const Field& x) { return hash (*x); } 00076 TMPL inline nat exact_hash (const Field& x) { return exact_hash (*x); } 00077 TMPL inline nat hard_hash (const Field& x) { return hard_hash (*x); } 00078 TMPL inline bool operator == (const Field& x, const Field& y) { 00079 return (*x) == (*y); } 00080 TMPL inline bool operator != (const Field& x, const Field& y) { 00081 return (*x) != (*y); } 00082 TMPL inline bool exact_eq (const Field& x, const Field& y) { 00083 return exact_eq (*x, *y); } 00084 TMPL inline bool exact_neq (const Field& x, const Field& y) { 00085 return exact_neq (*x, *y); } 00086 TMPL inline bool hard_eq (const Field& x, const Field& y) { 00087 return hard_eq (*x, *y); } 00088 TMPL inline bool hard_neq (const Field& x, const Field& y) { 00089 return hard_neq (*x, *y); } 00090 00091 TMPL inline syntactic flatten (const Field& x) { 00092 return syn ("Field", flatten (x.ext.mp), flatten (x.x)); } 00093 00094 TMPL 00095 struct binary_helper<Field >: public void_binary_helper<Field > { 00096 typedef pair<Extension,Ball> R; 00097 typedef binary_helper<R> H; 00098 static inline string short_type_name () { 00099 return "Algext" * Short_type_name (C); } 00100 static inline generic full_type_name () { 00101 return gen ("Algebraic_extension", Full_type_name (C)); } 00102 static inline generic disassemble (const Field& x) { 00103 return binary_disassemble<R> (*x); } 00104 static inline Field assemble (const generic& x) { 00105 return Field (binary_assemble<R> (x)); } 00106 static inline void write (const port& out, const Field& x) { 00107 return H::write (out, *x); } 00108 static inline Field read (const port& in) { 00109 return H::read (in); } 00110 }; 00111 00112 /****************************************************************************** 00113 * Numeric approximation of algebraic numbers 00114 ******************************************************************************/ 00115 00116 template<typename C, typename V, typename K> K 00117 eval (const polynomial<C,V>& p, const K& x) { 00118 K sum= 0; 00119 for (int i=deg(p); i>=0; i--) { 00120 sum *= x; 00121 sum += as<K> (p[i]); 00122 } 00123 return sum; 00124 } 00125 00126 TMPL bool 00127 improve_zero (const Polynomial& p, Ball& z) { 00128 typedef Center_type(Ball) CBall; 00129 typedef Radius_type(Ball) RBall; 00130 if (p[0] == 0 && z == 0) { z= Ball (0); return true; } 00131 CBall x= center (copy (z)); 00132 RBall r= radius (z); 00133 Polynomial dp= derive (p); 00134 while (true) { 00135 CBall nx= x - eval (p, x) / eval (dp, x); 00136 RBall nr= as<RBall> (abs (nx - x)); 00137 while (true) { 00138 Ball nb= Ball (nx, nr); 00139 if (eval (dp, nb) == 0) return false; 00140 RBall rr= abs_up (eval (p, sharpen (nb)) / eval (dp, nb)); 00141 if (rr <= nr) break; 00142 nr= max (2 * nr, rr); 00143 } 00144 bool ok= (2 * nr >= r); 00145 x= nx; 00146 r= nr; 00147 if (ok) break; 00148 } 00149 if (!included (Ball (x, r), z)) return false; 00150 z= Ball (x, r); 00151 return true; 00152 } 00153 00154 TMPL bool 00155 shrink (const Polynomial& p, Ball& x) { 00156 nat old_precision= mmx_bit_precision; 00157 mmx_bit_precision *= 2; 00158 Ball x2= copy (x); 00159 bool r= improve_zero (p, x2); 00160 mmx_bit_precision= old_precision; 00161 x= copy (x2); 00162 add_additive_error (x); 00163 return r; 00164 } 00165 00166 TMPL void 00167 shrink_check (const Polynomial& p, Ball& x) { 00168 if (!shrink (p, x)) { 00169 mmerr << "mp= " << p << "\n"; 00170 mmerr << "x = " << x << "\n"; 00171 ERROR ("root not uniquely specified"); 00172 } 00173 } 00174 00175 TMPL void 00176 increase_precision (const Field& ext) { 00177 typedef Center_type(Ball) CBall; 00178 typedef Radius_type(Ball) RBall; 00179 if (precision (ext.x) >= mmx_bit_precision) return; 00180 Ball new_x= ext.x; 00181 if (!improve_zero (ext.ext.mp, new_x)) { 00182 mmerr << "mp= " << ext.ext.mp << "\n"; 00183 mmerr << "x = " << new_x << "\n"; 00184 ERROR ("unexpected situation"); 00185 } 00186 (const_cast<Field*> (&ext)) -> x= new_x; 00187 } 00188 00189 TMPL Ball 00190 eval (const Field& ext, const Element& p1) { 00191 increase_precision (ext); 00192 Ball sum= 0; 00193 for (int i=deg(p1); i>=0; i--) { 00194 sum *= ext.x; 00195 sum += as<Ball> (p1[i]); 00196 } 00197 return sum; 00198 } 00199 00200 TMPL Ball 00201 eval (const Field& ext1, const Field& ext2, const vector<C>& v) { 00202 increase_precision (ext1); 00203 increase_precision (ext2); 00204 Ball sum1= 0; 00205 for (int i1=deg(ext1.ext.mp)-1; i1>=0; i1--) { 00206 Ball sum2= 0; 00207 for (int i2=deg(ext2.ext.mp)-1; i2>=0; i2--) { 00208 sum2 *= ext2.x; 00209 sum2 += as<Ball> (v[i1*deg(ext2.ext.mp) + i2]); 00210 } 00211 sum1 *= ext1.x; 00212 sum1 += sum2; 00213 } 00214 return sum1; 00215 } 00216 00217 TMPL Ball 00218 as_ball (const algebraic<C,Field >& a) { 00219 return eval (field (a), value (a)); 00220 } 00221 00222 TMPL Center_type(Ball ) 00223 as_floating (const algebraic<C,Field >& a) { 00224 return center (as_ball (a)); 00225 } 00226 00227 /****************************************************************************** 00228 * Basic arithmetic 00229 ******************************************************************************/ 00230 00231 TMPL inline Element 00232 square (const Field& ext, const Element& p1) { 00233 return square (ext.ext, p1); 00234 } 00235 00236 TMPL inline Element 00237 mul (const Field& ext, const Element& p1, const Element& p2) { 00238 return mul (ext.ext, p1, p2); 00239 } 00240 00241 TMPL inline Element 00242 invert (const Field& ext, const Element& p1) { 00243 return invert (ext.ext, p1); 00244 } 00245 00246 TMPL inline Element 00247 div (const Field& ext, const C& c1, const Element& p2) { 00248 return div (ext.ext, c1, p2); 00249 } 00250 00251 TMPL inline Element 00252 div (const Field& ext, const Element& p1, const Element& p2) { 00253 return div (ext.ext, p1, p2); 00254 } 00255 00256 TMPL inline bool 00257 is_zero (const Field& ext, const Element& p1) { 00258 if (deg (p1) <= 0) return is_zero (ext.ext, p1); 00259 Ball y= eval (ext, p1); 00260 if (is_non_zero (y)) return false; 00261 Polynomial ann= annihilator (ext, p1); 00262 if (ann[0] == 0 && is_non_zero (eval (derive (ann), y))) return true; 00263 nat old_precision= mmx_bit_precision; 00264 mmx_bit_precision *= 2; 00265 bool r= is_zero (ext, p1); 00266 mmx_bit_precision= old_precision; 00267 return r; 00268 } 00269 00270 TMPL inline int 00271 sign (const Field& ext, const Element& p1) { 00272 if (deg (p1) <= 0) return sign (ext.ext, p1); 00273 Ball y= eval (ext, p1); 00274 if (is_non_zero (y)) return sign (y); 00275 Polynomial ann= annihilator (ext, p1); 00276 if (ann[0] == 0 && is_non_zero (eval (derive (ann), y))) return 0; 00277 nat old_precision= mmx_bit_precision; 00278 mmx_bit_precision *= 2; 00279 int r= sign (ext, p1); 00280 mmx_bit_precision= old_precision; 00281 return r; 00282 } 00283 00284 /****************************************************************************** 00285 * Joining algebraic number extensions 00286 ******************************************************************************/ 00287 00288 TMPL Field 00289 join (const Field& ext1, const Field& ext2, Element& z1, Element& z2) { 00290 // Return the smallest common extension ext of ext1 and ext2 00291 // On exit, z1 and z2 contains the primitive els of ext1 and ext2 inside ext 00292 if (deg (ext1.ext.mp) == 1) { 00293 z1= Polynomial (-ext1.ext.mp[0]/ext1.ext.mp[1]); 00294 z2= Polynomial (C(1), (nat) 1); 00295 return ext2; 00296 } 00297 else if (deg (ext2.ext.mp) == 1) { 00298 z1= Polynomial (C(1), (nat) 1); 00299 z2= Polynomial (-ext2.ext.mp[0]/ext2.ext.mp[1]); 00300 return ext1; 00301 } 00302 else if (hard_eq (ext1, ext2)) { 00303 z1= Polynomial (C(1), (nat) 1); 00304 z2= Polynomial (C(1), (nat) 1); 00305 return ext1; 00306 } 00307 else { 00308 nat n= deg (ext1.ext.mp) * deg (ext2.ext.mp); 00309 matrix<C> m= transpose (pow_matrix (ext1.ext, ext2.ext)); 00310 matrix<C> u= invert (range (m, 0, 0, n, n)); 00311 vector<C> v= - (u * column (m, n)); 00312 v << C(1); 00313 Polynomial mp= Polynomial (v); 00314 Polynomial sf= square_free (mp); 00315 Extension ext= Extension (sf); 00316 v= fill<C> (C(0), n); 00317 v[deg(ext2.ext.mp)]= C(1); 00318 z1= Element (u * v); 00319 if (deg (sf) < deg (mp)) z1= rem (z1, sf); 00320 v= fill<C> (C(0), n); 00321 v[1]= C(1); 00322 z2= Element (u * v); 00323 if (deg (sf) < deg (mp)) z2= rem (z2, sf); 00324 Ball x; 00325 nat old_precision= mmx_bit_precision; 00326 while (true) { 00327 x= eval (ext1, ext2, column (m, 1)); 00328 if (shrink (ext.mp, x)) break; 00329 mmx_bit_precision= mmx_bit_precision << 1; 00330 } 00331 mmx_bit_precision= old_precision; 00332 return Field (ext, x); 00333 } 00334 } 00335 00336 /****************************************************************************** 00337 * Upgrading to larger algebraic extensions 00338 ******************************************************************************/ 00339 00340 TMPL Field 00341 upgrade (const Field& ext1, const Field& ext2, Element& p1, Element& p2) { 00342 if (hard_eq (ext1, ext2)) return ext1; 00343 Element z1, z2; 00344 Field ext= join (ext1, ext2, z1, z2); 00345 if (!hard_eq (ext1, ext)) p1= compose (ext.ext, p1, z1); 00346 if (!hard_eq (ext2, ext)) p2= compose (ext.ext, p2, z2); 00347 return ext; 00348 } 00349 00350 /****************************************************************************** 00351 * Computing the minimal annihilator of an element 00352 ******************************************************************************/ 00353 00354 TMPL Polynomial 00355 annihilator (const Field& ext, const Element& p) { 00356 return annihilator (ext.ext, p); 00357 } 00358 00359 TMPL Field 00360 normalize (const Field& ext, const Element& p) { 00361 Polynomial mp= annihilator (ext.ext, p); 00362 Ball z; 00363 nat old_precision= mmx_bit_precision; 00364 while (true) { 00365 z= eval (ext, p); 00366 if (shrink (mp, z)) break; 00367 mmx_bit_precision= mmx_bit_precision << 1; 00368 } 00369 mmx_bit_precision= old_precision; 00370 return Field (Extension (mp), z); 00371 } 00372 00373 /****************************************************************************** 00374 * Ramification 00375 ******************************************************************************/ 00376 00377 TMPL Field 00378 ramify (const Field& ext, nat p) { 00379 Ball z= (p == 2? sqrt (ext.x): exp (log (ext.x) / ((int) p))); 00380 return Field (ramify (ext.ext, p), z); 00381 } 00382 00383 /****************************************************************************** 00384 * Complex arithmetic 00385 ******************************************************************************/ 00386 00387 inline void 00388 set_imaginary (algebraic_number& z) { 00389 typedef ball<complex<floating<> > > B; 00390 polynomial<rational> mp (vec<rational> (1, 0, 1)); 00391 polynomial<rational> i (vec<rational> (0, 1)); 00392 algebraic_complex_extension ext (mp, imaginary_cst<B> ()); 00393 z= algebraic_number (ext, i); 00394 } 00395 00396 inline algebraic_number 00397 times_i (const algebraic_number& z) { 00398 return z * imaginary_cst<algebraic_number> (); 00399 } 00400 00401 inline algebraic_number 00402 over_i (const algebraic_number& z) { 00403 return -z * imaginary_cst<algebraic_number> (); 00404 } 00405 00406 inline algebraic_number 00407 gaussian (const algebraic_real& x, const algebraic_real& y) { 00408 return algebraic_number (x) + times_i (algebraic_number (y)); 00409 } 00410 00411 TMPL inline Field 00412 conj (const Field& ext) { 00413 return Field (ext.ext, conj (ext.x)); 00414 } 00415 00416 inline algebraic_number 00417 conj (const algebraic_number& z) { 00418 return algebraic_number (conj (field (z)), value (z)); 00419 } 00420 00421 inline algebraic_real 00422 Re (const algebraic_number& z) { 00423 algebraic_number x= normalize ((z + conj (z)) / rational (2)); 00424 algebraic_complex_extension cext= field (x); 00425 algebraic_real_extension rext (cext.ext, Re (cext.x)); 00426 return algebraic_real (rext, value (x)); 00427 } 00428 00429 inline algebraic_real 00430 Im (const algebraic_number& z) { 00431 return Re (over_i (z)); 00432 } 00433 00434 inline algebraic_real 00435 abs (const algebraic_number& z) { 00436 algebraic_number x= normalize (sqrt (z * conj (z))); 00437 algebraic_complex_extension cext= field (x); 00438 algebraic_real_extension rext (cext.ext, Re (cext.x)); 00439 return algebraic_real (rext, value (x)); 00440 } 00441 00442 #undef TMPL_DEF 00443 #undef TMPL 00444 #undef Extension 00445 #undef Field 00446 #undef Polynomial 00447 #undef Element 00448 } // namespace mmx 00449 #endif // __MMX_ALGEBRAIC_NUMBER_HPP