00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00030
00031
00032 TMPL_DEF
00033 class algebraic_number_extension {
00034 MMX_ALLOCATORS;
00035 public:
00036 Extension ext;
00037 Ball x;
00038 typedef typename Extension::El El;
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
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
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
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
00286
00287
00288 TMPL Field
00289 join (const Field& ext1, const Field& ext2, Element& z1, Element& z2) {
00290
00291
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
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
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
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
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 }
00449 #endif // __MMX_ALGEBRAIC_NUMBER_HPP