smith.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     smith.cpp -- See declarations in smith.hpp.
00004 
00005     This file is a part of the Arageli library.
00006 
00007     Copyright (C) Nikolai Yu. Zolotykh, 1999--2006
00008     Copyright (C) Sergey S. Lyalin, 2005--2006
00009 
00010 *****************************************************************************/
00011 
00018 #include "config.hpp"
00019 
00020 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00021     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_smith)
00022 
00023 #include <cstddef>
00024 
00025 #include "exception.hpp"
00026 #include "std_import.hpp"
00027 #include "factory.hpp"
00028 #include "cmp.hpp"
00029 #include "intalg.hpp"
00030 #include "gcd.hpp"
00031 #include "powerest.hpp"
00032 #include "vector.hpp"
00033 #include "matrix.hpp"
00034 
00035 #include "smith.hpp"
00036 
00037 
00038 namespace Arageli
00039 {
00040 
00041 
00042 namespace _Internal
00043 {
00044 
00045 
00046 template <typename M>
00047 bool find_pivot_item
00048 (const M& B, std::size_t corner, std::size_t& min_i, std::size_t& min_j)
00049 {
00050     typedef typename M::element_type T;
00051     T min = null<T>();
00052 
00053     for(std::size_t i = corner; i < B.nrows(); i++)
00054         for(std::size_t j = corner; j < B.ncols(); j++)
00055             if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00056             {
00057                 min = std::abs(B(i, j));
00058                 min_i = i;
00059                 min_j = j;
00060             }
00061     
00062     return !is_null(min);
00063 }
00064 
00065 
00066 template <typename M>
00067 std::size_t find_pivot_item_in_row
00068 (const M& B, std::size_t corner, std::size_t i)
00069 {
00070     typedef typename M::element_type T;
00071     T min = null<T>();
00072     std::size_t min_j = 0;
00073 
00074     for(std::size_t j = corner; j < B.ncols(); j++)
00075         if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00076         {
00077             min = std::abs(B(i, j));
00078             min_j = j;
00079         }
00080 
00081     return min_j;
00082 }
00083 
00084 
00085 template <typename M>
00086 std::size_t find_pivot_item_in_col
00087 (const M& B, std::size_t corner, std::size_t j)
00088 {
00089     typedef typename M::element_type T;
00090     T min = null<T>();
00091     std::size_t min_i = 0;
00092 
00093     for(std::size_t i = corner; i < B.nrows(); i++)
00094         if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00095         {
00096             min = std::abs(B(i, j));
00097             min_i = i;
00098         }
00099 
00100     return min_i;
00101 }
00102 
00103 
00104 template <typename M>
00105 bool find_non_divisor_of_item
00106 (
00107     const M& B,
00108     std::size_t corner,
00109     typename M::element_type item,
00110     std::size_t& k,  std::size_t& l
00111 )
00112 {
00113     for(std::size_t i = corner; i < B.nrows(); i++)
00114         for(std::size_t j = corner; j < B.ncols(); j++)
00115             if(!is_null(B(i, j) % item))
00116             {
00117                 k = i;
00118                 l = j;
00119                 return true;
00120             }
00121 
00122     return false;
00123 }
00124 
00125 
00126 } // namespace _Internal --------------------------------------
00127 
00128 
00129 template
00130 <
00131     typename MA,
00132     typename MB,
00133     typename MP,
00134     typename MQ,
00135     typename Rank,
00136     typename T_det, typename T_factory,
00137     typename Ctrler, typename Norm
00138 >
00139 void smith
00140 (
00141     const MA& A,
00142     MB& B,
00143     MP& P,
00144     MQ& Q,
00145     Rank& rank,
00146     T_det& det,
00147     const T_factory& tfctr,
00148     Ctrler ctrler,
00149     Norm norm
00150 )
00151 {
00152     typedef typename MB::element_type T_B;
00153 
00154     det = tfctr.unit(det);
00155     std::size_t m = A.nrows();
00156     std::size_t n = A.ncols();
00157     Q.assign_eye(n);
00158     P.assign_eye(m);
00159     B = A;
00160 
00161     ctrler.preamble();
00162     ctrler.current_matrices(Q, B, P);
00163 
00164     for(std::size_t corner = 0; corner < m && corner < n; corner++)
00165     {
00166         std::size_t new_i, new_j, i, j;
00167         T_B pivot_item;
00168 
00169         if(!_Internal::find_pivot_item(B, corner, new_i, new_j))
00170             // the smallest (in absolute value) non-zero entry in the matrix
00171             break; // all others entries are 0
00172 
00173         ctrler.find_smallest_nonzero(new_i, new_j);
00174 
00175         for(;;)
00176         {
00177             if(ctrler.stop(corner, new_i, new_j, Q, B, P))
00178             {
00179                 ctrler.conclusion();
00180                 return;
00181             }
00182         
00183             do
00184             {
00185                 i = new_i;
00186                 j = new_j;
00187                 pivot_item = B(i, j);
00188 
00189                 ctrler.pivot_item(i, j);
00190 
00191                 for(std::size_t jj = 0; jj < n; jj++)
00192                     if(jj != j)
00193                     {
00194                         T_B p = B(i, jj) / pivot_item;
00195                         B.addmult_cols(jj, j, -p);
00196                         Q.addmult_cols(jj, j, -p);
00197                     }
00198                 
00199                 for(std::size_t ii = 0; ii < m; ii++)
00200                     if(ii != i)
00201                     {
00202                         T_B p = B(ii, j) / pivot_item;
00203                         B.addmult_rows(ii, i, -p);
00204                         P.addmult_rows(ii, i, -p);
00205                     }
00206 
00207 
00208                 ctrler.after_pivoting();
00209                 ctrler.current_matrices(Q, B, P);
00210 
00211                 new_j = _Internal::find_pivot_item_in_row(B, corner, i);
00212                 
00213                 if(new_j == j)
00214                     new_i = _Internal::find_pivot_item_in_col(B, corner, j);
00215                 else
00216                     new_i = i;
00217             }while (i != new_i || j != new_j);
00218             // while pivot entry is changing,
00219             // i.e. until others entries in row i and column j are 0
00220 
00221             std::size_t k, l;
00222             if(!_Internal::find_non_divisor_of_item(B, corner, pivot_item, k, l))break;
00223 
00224             B.add_rows(i, k);
00225             P.add_rows(i, k);
00226 
00227             ctrler.nondivisor_entry(k, i, l);
00228             ctrler.current_matrices(Q, B, P);
00229         }
00230 
00231         bool if_alter = false;
00232 
00233         if(i != corner)
00234         {
00235             B.swap_rows(i, corner);
00236             P.swap_rows(i, corner);
00237             opposite(&det);
00238             if_alter = true;
00239         }
00240 
00241         if(j != corner)
00242         {
00243             B.swap_cols(j, corner);
00244             Q.swap_cols(j, corner);
00245             opposite(&det);
00246             if_alter = true;
00247         }
00248         
00249         if(is_negative(B(corner, corner)))
00250         {
00251             B.mult_row(corner, -1);
00252             P.mult_row(corner, -1);
00253             opposite(&det);
00254             if_alter = true;
00255         }
00256         
00257         if(if_alter)
00258         {
00259             ctrler.pivot_adjustment();
00260             ctrler.current_matrices(Q, B, P);
00261         }
00262 
00263     }
00264 
00265     rank = 0;
00266 
00267     for(std::size_t i = 0; i < m && i < n; i++)
00268         if(!is_null(B(i, i)))
00269         {
00270             det *= B(i, i);
00271             norm(B(i, i), P, i);
00272             //for(std::size_t j = 0; j < P.ncols(); ++j)
00273             //  norm(P(i, j));
00274             rank++;
00275         }
00276         else break;
00277 
00278     ctrler.conclusion();
00279 }
00280 
00281 
00282 template <typename M>
00283 M smith (const M& a)
00284 {
00285     typedef typename M::element_type T;
00286     
00287     M b;
00288     matrix<T, false> p, q;
00289     T det;
00290     typename M::size_type rank;
00291     smith(a, b, p, q, rank, det);
00292     return b;
00293 }
00294 
00295 
00296 template
00297 <
00298     typename MA,
00299     typename MB,
00300     typename MP,
00301     typename MQ,
00302     typename Rank,
00303     typename T_det
00304 >
00305 void smith_storjohann
00306 (
00307     const MA &A,
00308     MB &B,
00309     MP &P,
00310     MQ &Q,
00311     Rank &rank,
00312     T_det &det
00313 )
00314 {
00315     typedef typename MA::element_type T_A;
00316 
00317     matrix<T_A, false> U, E, F;
00318     smith_storjohann(A, P, Q, U, E, F, rank, det);
00319     
00320     // WARNING! Hmmm... As far as I know the matrix multiplication is associative
00321     // and maybe better way is firstly compute P = E*U*P, Q = Q*F and then B = P*A*Q.
00322     B = E*(U*(P*A*Q))*F;
00323     P = E*U*P;
00324     Q = Q*F;
00325 }
00326 
00327 
00328 template
00329 <
00330     typename MA,
00331     typename MB,
00332     typename MP,
00333     typename MQ,
00334     typename Rank,
00335     typename T_det
00336 >
00337 void smith_near_optimal
00338 (
00339     const MA &A,
00340     MB &B,
00341     MP &P,
00342     MQ &Q,
00343     Rank &rank,
00344     T_det &det
00345 )
00346 {
00347     typedef typename MA::element_type T_A;
00348     
00349     matrix<T_A, false> U, V;
00350     smith_near_optimal(A, B, P, Q, U, V, rank, det);
00351     P = U*P;
00352     Q = Q*V;
00353 }
00354 
00355 
00356 }
00357 
00358 
00359 #if ARAGELI_DEBUG_LEVEL > 3
00360 
00361 #include "big_int.hpp"
00362 
00363 namespace Arageli
00364 {
00365 
00366 
00367 template void smith_storjohann
00368 (
00369     const matrix<big_int> &A,
00370     matrix<big_int> &B,
00371     matrix<big_int> &P,
00372     matrix<big_int>& Q,
00373     big_int &rank,
00374     big_int &det
00375 );
00376 
00377 template void smith_storjohann
00378 (
00379     const matrix<int> &A,
00380     matrix<int> &B,
00381     matrix<int> &P,
00382     matrix<int>& Q,
00383     int &rank,
00384     int &det
00385 );
00386 
00387 
00388 template void smith_near_optimal
00389 (
00390     const matrix<big_int> &A,
00391     matrix<big_int> &B,
00392     matrix<big_int> &P,
00393     matrix<big_int>& Q,
00394     big_int &rank,
00395     big_int &det
00396 );
00397 
00398 template void smith_near_optimal
00399 (
00400     const matrix<int> &A,
00401     matrix<int> &B,
00402     matrix<int> &P,
00403     matrix<int>& Q,
00404     int &rank,
00405     int &det
00406 );
00407 
00408 
00409 template void smith
00410 (
00411     const matrix<big_int> &A,
00412     matrix<big_int> &B,
00413     matrix<big_int> &P,
00414     matrix<big_int>& Q,
00415     big_int &rank,
00416     big_int &det
00417 );
00418 
00419 template void smith
00420 (
00421     const matrix<int> &A,
00422     matrix<int> &B,
00423     matrix<int> &P,
00424     matrix<int>& Q,
00425     int &rank,
00426     int &det
00427 );
00428 
00429 
00430 }
00431 
00432 #endif
00433 
00434 
00435 
00436 #endif  // #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || ...

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