gcd.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     gcd.cpp -- see gcd.hpp.
00004 
00005     This file is a part of Arageli library.
00006 
00007     Some functions in this file are part of Anna Bestaeva degree work 2006.
00008     They have been integrated into Arageli by Sergey Lyalin.
00009 
00010     Copyright (C) Nikolai Yu. Zolotykh, 1999--2006
00011     Copyright (C) Anna Bestaeva, 2006
00012 
00013     University of Nizhni Novgorod, Russia
00014 
00015 *****************************************************************************/
00016 
00017 #include "config.hpp"
00018 
00019 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00020     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_GCD)
00021 
00022 #include <cstddef>
00023 #include <algorithm>
00024 
00025 #include "gcd.hpp"
00026 #include "_utility.hpp"
00027 
00028 
00029 namespace Arageli
00030 {
00031 
00032 
00033 namespace _Internal
00034 {
00035 
00036 template <typename T>
00037 inline T& euclid_norm (T& x) { return x; }
00038 
00039 template <typename T, typename P, bool REFCNT>
00040 inline sparse_polynom<T, P, REFCNT>& euclid_norm (sparse_polynom<T, P, REFCNT>& x)
00041 {
00042     if(!is_null(x))x /= x.leading_coef_cpy();
00043     return x;
00044 }
00045 
00046 template <typename T1, typename T2, typename T3>
00047 inline void euclid_norm (T1& x1, T2& x2, T3& x3) {}
00048 
00049 template
00050 <
00051     typename T1, typename P1, bool REFCNT1,
00052     typename T2, typename P2, bool REFCNT2,
00053     typename T3, typename P3, bool REFCNT3
00054 >
00055 inline void euclid_norm
00056 (
00057     sparse_polynom<T1, P1, REFCNT1>& x1,
00058     sparse_polynom<T2, P2, REFCNT2>& x2,
00059     sparse_polynom<T3, P3, REFCNT3>& x3
00060 )
00061 {
00062     if(!is_null(x1))
00063     {
00064         x2 /= x1.leading_coef();
00065         x3 /= x1.leading_coef();
00066         x1 /= x1.leading_coef_cpy();
00067     }
00068 }
00069 
00070 }
00071 
00072 
00073 template <typename T, typename T_factory>
00074 T euclid (T a, T b, const T_factory& tfctr)
00075 {
00076     if(is_negative(a))opposite(&a);
00077     if(is_negative(b))opposite(&b);
00078     
00079     if(is_null(a))
00080         if(is_null(b))return tfctr.unit(a);
00081         else return _Internal::euclid_norm(b);
00082     if(is_null(b))return _Internal::euclid_norm(a);
00083     
00084     while(!is_null(a %= b)){ std::swap(a, b); /*std::cout << "\ngcd: " << a;*/ }
00085     return _Internal::euclid_norm(b);
00086 }
00087 
00088 
00089 template <typename T, typename T_factory>
00090 T euclid_binary (T a, T b, const T_factory& tfctr)
00091 {
00092     if(is_negative(a))opposite(&a);
00093     if(is_negative(b))opposite(&b);
00094 
00095     if(is_null(a))
00096         if(is_null(b))return tfctr.unit(a);
00097         else return _Internal::euclid_norm(b);
00098     if(is_null(b))return _Internal::euclid_norm(a);
00099     
00100     T res = tfctr.unit(a);
00101 
00102     while(!is_unit(a) && !is_unit(b))
00103     {
00104         ARAGELI_ASSERT_1(!is_null(a));
00105         ARAGELI_ASSERT_1(!is_null(b));
00106         
00107         if(is_even(a))
00108             if(is_even(b))
00109             {
00110                 a >>= 1; b >>= 1;
00111                 res <<= 1;
00112             }
00113             else
00114             {
00115                 a >>= 1;
00116             }
00117         else
00118             if(is_even(b))
00119             {
00120                 b >>= 1;
00121             }
00122             else
00123             {
00124                 T t = a - b;
00125                 switch(sign(t))
00126                 {
00127                     case +1:
00128                     {
00129                         a = t;
00130                         a >>= 1;
00131                         break;
00132                     }
00133                     case -1:
00134                     {
00135                         b = -t;
00136                         b >>= 1;
00137                         break;
00138                     }
00139                     case 0: return _Internal::euclid_norm(res *= a);
00140                 }
00141             }
00142     }
00143 
00144     return _Internal::euclid_norm(res);
00145 }
00146 
00147 
00148 template <typename T>
00149 T gcdex (const T& a, const T& b, T&u, T& v, T& w, T& z)
00150 {
00151     T g = euclid_bezout(a, b, u, v);
00152 
00153     if(is_null(g))
00154     {
00155         u = unit(u);
00156         v = null(v);
00157         w = null(w);
00158         z = unit(z);
00159         return g;
00160     }
00161     
00162     z = a/g; w = -b/g;
00163 
00164     ARAGELI_ASSERT_1(is_unit(abs(u*z - w*v)));
00165     ARAGELI_ASSERT_1(is_null(a*w + b*z));
00166 
00167     return g;
00168 }
00169 
00170 
00171 template <typename T>
00172 T gcdex (const T& a, const T& b, const T& N, T&u, T& v, T& w, T& z)
00173 {
00174     ARAGELI_ASSERT_0(is_positive(N));
00175 
00176     T   a_mod_N = mod(a, N),
00177         b_mod_N = mod(b, N),
00178         g = euclid_bezout(a_mod_N, b_mod_N, u, v);
00179 
00180     if(is_null(g))
00181     {
00182         u = unit(u);
00183         v = null(v);
00184         w = null(w);
00185         z = unit(z);
00186         
00187         return g;
00188     }
00189 
00190     u = mod(u, N);
00191     v = mod(v, N);
00192     w = N - b_mod_N/g;
00193     z = a_mod_N/g;
00194 
00195     ARAGELI_ASSERT_1(is_unit(gcd(mod(u*z - w*v, N), N)));
00196     ARAGELI_ASSERT_1(is_null(mod(a*w + b*z,N)));
00197 
00198     return g;
00199 }
00200 
00201 
00202 template <typename T, bool REFCNT, typename T_factory>
00203 T gcd (const vector<T, REFCNT>& v, const T_factory& tfctr)
00204 {
00205     if(v.is_empty())return tfctr.null();    // null as in Maple 9
00206     
00207     T d = v[v.size() - 1];
00208     typedef typename vector<T, REFCNT>::difference_type difftype;
00209     difftype j = difftype(v.size()) - 2;
00210 
00211     while(!is_unit(d) && j >= 0)
00212     {
00213         if(!is_null(v[j]))
00214             d = gcd(v[j], d, tfctr);
00215         --j;
00216     }
00217 
00218     return is_null(d) ? tfctr.unit() : d;
00219 }
00220 
00221 
00222 template <typename T, bool REFCNT, typename T_factory>
00223 T lcm (const vector<T, REFCNT>& v, const T_factory& tfctr)
00224 {
00225     if(v.is_empty())return tfctr.unit();    // unit as in Maple 9
00226     
00227     T d = v[v.size() - 1];
00228     typedef typename vector<T, REFCNT>::difference_type difftype;
00229     difftype j = difftype(v.size()) - 2;
00230 
00231     while(j >= 0)
00232     {
00233         if(!is_null(v[j]))
00234             d = lcm(v[j], d, tfctr);
00235         --j;
00236     }
00237 
00238     return is_null(d) ? tfctr.unit() : d;
00239 }
00240 
00241 
00242 template
00243 <
00244     typename T, bool REFCNT, typename T_factory,
00245     typename T1, bool REFCNT1
00246 >
00247 vector<T, REFCNT> gcd_vec
00248 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00249 {
00250     ARAGELI_ASSERT_0(a.size() == b.size());
00251     std::size_t size = a.size();
00252     vector<T, REFCNT> res(size, T());
00253 
00254     for(std::size_t i = 0; i < size; ++i)
00255         res[i] = gcd(a[i], b[i]);
00256 
00257     return res;
00258 }
00259 
00260 
00261 template
00262 <
00263     typename T, bool REFCNT, typename T_factory,
00264     typename T1, bool REFCNT1
00265 >
00266 vector<T, REFCNT> lcm_vec
00267 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00268 {
00269     ARAGELI_ASSERT_0(a.size() == b.size());
00270 
00271     ARAGELI_ASSERT_0(a.size() == b.size());
00272     std::size_t size = a.size();
00273     vector<T, REFCNT> res(size, T());
00274 
00275     for(std::size_t i = 0; i < size; ++i)
00276         res[i] = lcm(a[i], b[i]);
00277 
00278     return res;
00279 }
00280 
00281 
00282 template
00283 <
00284     typename T, bool REFCNT, typename T_factory,
00285     typename T1, bool REFCNT1
00286 >
00287 vector<T, REFCNT> euclid
00288 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00289 {
00290     ARAGELI_ASSERT_0(a.size() == b.size());
00291 
00292     std::size_t size = a.size();
00293     vector<T, REFCNT> res(size, T());
00294 
00295     for(std::size_t i = 0; i < size; ++i)
00296         res[i] = euclid(a[i], _Internal::noncopy_cast(b[i]), tfctr);
00297 
00298     return res;
00299 }
00300 
00301 
00302 template <typename T, typename T_factory>
00303 T euclid_bezout
00304 (
00305     const T& a, const T& b, T& u, T& v,
00306     const T_factory& tfctr
00307 )
00308 {
00309     //std::cout
00310     //  << "\neuclid_bezout(a, b, u, v):"
00311     //  << "\n\ta = " << a
00312     //  << "\n\tb = " << b;
00313     
00314     u = tfctr.unit(a);
00315     v = tfctr.null(a);
00316     T u_new = v;
00317     T v_new = u;
00318     T r = abs(a);
00319     T r_new = abs(b);
00320 
00321     while(!is_null(r_new))
00322     {
00323         T q = prquot(r, r_new);
00324 
00325         T aux = u_new;
00326         u_new = u - q * u_new;
00327         u     = aux;
00328 
00329         aux   = v_new;
00330         v_new = v - q * v_new;
00331         v     = aux;
00332 
00333         aux   = r_new;
00334         r_new = r - q * r_new;
00335         r     = aux;
00336     }
00337 
00338     if(is_negative(a))opposite(&u);
00339     if(is_negative(b))opposite(&v);
00340     
00341     //std::cout
00342     //  << "\n\tu = " << u
00343     //  << "\n\tv = " << v
00344     //  << "\n\tr = " << r;
00345 
00346     _Internal::euclid_norm(r, u, v);
00347     
00348     //std::cout
00349     //  << "\n\tu = " << u
00350     //  << "\n\tv = " << v
00351     //  << "\n\tr = " << r << "\n";
00352 
00353     ARAGELI_ASSERT_1(a*u + b*v == r);
00354 
00355     return r;
00356 }
00357 
00358 
00359 } // namespace Arageli
00360 
00361 #endif
00362 

Generated on Thu Aug 31 17:38:06 2006 for Arageli by  doxygen 1.4.7