algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/algebraic_number.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines