gauss.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002     
00003     gauss.cpp -- See gauss.hpp.
00004 
00005     This file is part of Arageli library.
00006 
00007     Copyright (C) Nikolai Yu. Zolotykh, 1999--2006
00008     Copyright (C) Sergey S. Lyalin, 2005
00009     University of Nizhni Novgorod, Russia
00010 
00011 *****************************************************************************/
00012 
00013 #include "config.hpp"
00014 
00015 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00016     defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_GAUSS)
00017 
00018 #include <cstddef>
00019 #include <cmath>
00020 #include <limits>
00021 
00022 #include "gauss.hpp"
00023 #include "cmp.hpp"
00024 #include "misc.hpp"
00025 #include "submatrix/hpair.hpp"
00026 //#include "rational.hpp"   // compilation fails on GCC 3.4.3 without this
00027 
00028 namespace Arageli
00029 {
00030 
00031 
00032 template <typename M>
00033 void gauss_field_row_iter
00034 (
00035     M& a,
00036     typename M::size_type row,
00037     typename M::size_type col
00038 )
00039 {
00040     ARAGELI_ASSERT_0(row < a.nrows());
00041     ARAGELI_ASSERT_0(col < a.ncols());
00042 
00043     a.div_row(row, safe_reference(a(row, col)));
00044 
00045     typedef typename M::size_type size_type;
00046 
00047     for(size_type i = 0; i < row; ++i)
00048         a.addmult_rows(i, row, -a(i, col));
00049     for(size_type i = row + 1; i < a.nrows(); ++i)
00050         a.addmult_rows(i, row, -a(i, col));
00051 }
00052 
00053 
00054 template <typename M>
00055 void gauss_field_col_iter
00056 (
00057     M& a,
00058     typename M::size_type row,
00059     typename M::size_type col
00060 )
00061 {
00062     ARAGELI_ASSERT_0(row < a.nrows());
00063     ARAGELI_ASSERT_0(col < a.ncols());
00064 
00065     a.div_col(col, safe_reference(a(row, col)));
00066 
00067     typedef typename M::size_type size_type;
00068 
00069     for(size_type j = 0; j < col; ++j)
00070         a.addmult_cols(j, col, -a(row, j));
00071     for(size_type j = col + 1; j < a.ncols(); ++j)
00072         a.addmult_cols(j, col, -a(row, j));
00073 }
00074 
00075 
00076 template <typename M, typename T>
00077 void gauss_bareiss_row_iter
00078 (
00079     M& a,
00080     typename M::size_type row,
00081     typename M::size_type col,
00082     T& det, T& det_denom
00083 )
00084 {
00085     // TODO: Make similar function for column manipulation.
00086 
00087     ARAGELI_ASSERT_0(row < a.nrows());
00088     ARAGELI_ASSERT_0(col < a.ncols());
00089 
00090     typedef typename M::element_type TM;
00091     typedef typename M::size_type size_type;
00092 
00093     TM pivot = a(row, col);
00094 
00095     if(is_negative(pivot))
00096     {
00097         a.mult_row(row, opposite_unit<TM>());
00098         opposite(&pivot);
00099         opposite(&det);
00100     }
00101 
00102     for(size_type i = 0; i < a.nrows(); i++)
00103         if(i != row)
00104         {
00105             TM alpha = a(i, col);
00106             TM delta = gcd(pivot, alpha);
00107             TM bi = -alpha / delta;
00108             TM brow = pivot / delta;
00109             a.mult_row(i, brow);
00110             a.addmult_rows(i, row, bi);
00111             alpha = gcd(a.copy_row(i));
00112             a.div_row(i, alpha);
00113 
00114             det *= alpha;
00115             det_denom *= brow;
00116 
00117             //std::cout << "\ngauss_bareiss_row_iter.i = " << i;
00118         }
00119 }
00120 
00121 
00122 template
00123 <
00124     typename A, typename B, typename Q, typename Basis,
00125     typename T, typename T_factory,
00126     typename Ctrler // control visitor
00127 >
00128 void rref_gauss_field
00129 (
00130     const A& a, B& b, Q& q, Basis& basis,
00131     T& det,
00132     const T_factory& tfctr,
00133     Ctrler ctrler
00134 )
00135 {
00136     ARAGELI_ASSERT_0(!a.is_empty());
00137     
00138     typedef typename B::element_type TB;
00139     typedef typename B::size_type size_type;
00140     
00141     det = tfctr.unit(det);
00142     size_type m = a.nrows(); size_type n = a.ncols();
00143     q.assign_eye(m);
00144     b = a;
00145     basis.resize(0);
00146     TB bnull = null(b(0, 0));   // needed for main loop of the algorithm
00147     hpair_matrix<B, Q> bq(b, q);
00148 
00149     ctrler.preamble(a);
00150 
00151     for(size_type i = 0, j = 0; i < m && j < n; j++)    // (i, j) -- pivot element
00152     {
00153         ctrler.before_iter(b, q, det, basis);
00154         
00155         // Elimination of column j of matrix b.
00156 
00157         // Firstly find the biggest (in absolute value) entry in the column j.
00158 
00159         ctrler.find_biggest_in_col(j);
00160         TB max = bnull;
00161         size_type i_max = i;
00162 
00163         for(size_type ii = i; ii < m; ii++)
00164         {
00165             TB absval = abs(b(ii, j));
00166             if(absval > max)
00167             {
00168                 max = absval;
00169                 i_max = ii;
00170             }
00171         }
00172 
00173         if(is_null(max))
00174         {
00175             // column j is negligible (only zeros)
00176             ctrler.negligible_col(j);
00177             det = tfctr.null(det);
00178             ctrler.after_iter(b, q, det, basis);
00179             continue;   // next column
00180         }
00181 
00182         // Now the pivot item is (i_max, j).
00183         
00184         ctrler.pivot_item(i_max, j);
00185 
00186         // If it is not on the diagonal then swap the rows.
00187 
00188         if(i != i_max)
00189         {
00190             bq.swap_rows(i, i_max);
00191             //q.swap_rows(i, i_max);
00192             opposite(&det);
00193         
00194             ctrler.swap_rows(i, i_max, b, q, det);
00195         }
00196 
00197         // (i, j) is a pivot element now.
00198         // Next eliminate column j.
00199         
00200         ctrler.eliminate_col(j);
00201 
00202         //TB pivot = b(i, j);
00203         //det *= pivot;
00204         det *= b(i, j);
00205 
00206         gauss_field_row_iter(bq, i, j);
00207         
00208         //b.div_row(i, pivot);
00209         //q.div_row(i, pivot);
00210 
00211         //for(size_type ii = 0; ii < m; ii++)  // eliminate in column j
00212         //  if(ii != i)
00213         //  {
00214         //      TB alpha = -b(ii, j);
00215         //      b.addmult_rows(ii, i, alpha);
00216         //      q.addmult_rows(ii, i, alpha);
00217         //  }
00218 
00219         ctrler.after_elimination(b, q, det);
00220 
00221         basis.push_back(j);
00222         i++;
00223 
00224         ctrler.after_iter(b, q, det, basis);
00225     } // end of main loop
00226 
00227     ctrler.conclusion(b, q, det, basis);
00228 }
00229 
00230 
00231 template <typename A1, typename A2, typename I>
00232 void mat_col_copy_order
00233 (const A1& a1, A2& a2, const I& idx)
00234 {
00235     A1 temp = a1;
00236     temp.take_cols(idx, a2);
00237     
00238     for(typename A1::size_type i = 0; i < temp.ncols(); ++i)
00239         a2.insert_col(a2.ncols(), temp.copy_col(i));
00240 }
00241 
00242 
00243 template <typename A1, typename A2, typename I>
00244 void vec_copy_order
00245 (const A1& a1, A2& a2, const I& idx)
00246 {
00247     A1 temp = a1;
00248     temp.take_subvector(idx, a2);
00249     
00250     for(typename A1::size_type i = 0; i < temp.size(); ++i)
00251         a2.push_back(temp[i]);
00252 }
00253 
00254 template <typename A, typename B>
00255 void vec_inverse_permutation (const A& a, B& b)
00256 {
00257     b.resize(a.size());
00258     typedef typename A::size_type size_type;
00259     for(size_type i = 0; i < a.size(); ++i)
00260     {
00261         ARAGELI_ASSERT_0(size_type(a[i]) < a.size());
00262         size_type ii = std::find(a.begin(), a.end(), i) - a.begin();
00263         ARAGELI_ASSERT_0(ii < a.size());
00264         b[i] = ii;
00265     }
00266 }
00267 
00268 
00269 template
00270 <
00271     typename A, typename B, typename Q,
00272     typename Basis_in, typename Basis_out,
00273     typename Det
00274 >
00275 void rref_order
00276 (
00277     const A& a, B& b, Q& q,
00278     const Basis_in& basis_in, Basis_out& basis_out,
00279     Det& det
00280 )
00281 {
00282     A aa;
00283     Basis_in order = basis_in;
00284     for(std::size_t i = 0; i < a.ncols(); ++i)
00285         if(std::find(basis_in.begin(), basis_in.end(), i) == basis_in.end())
00286             order.push_back(i);
00287 
00288     mat_col_copy_order(a, aa, order);
00289     //std::cout << "\norder = " << order;
00290 
00291     Q qq = q; B bb;
00292     rref(aa, bb, qq, basis_out, det);
00293 
00294     Basis_in invorder;
00295     vec_inverse_permutation(order, invorder);
00296     //std::cout << "\ninvorder = " << invorder;
00297 
00298     mat_col_copy_order(bb, b, invorder);
00299     //mat_col_copy_order(qq, q, invorder);
00300     // TODO Something with basis_out
00301 }
00302 
00303 
00304 template <typename T, bool REFCNT>
00305 matrix<T, REFCNT> inverse (const matrix<T, REFCNT>& A)
00306 {
00307     // precondition: A must be square
00308     //if(!A.is_square())throw exception("matrix must be square");
00309     ARAGELI_ASSERT_0(A.is_square());
00310 
00311     matrix<T, false> B;
00312     matrix<T, true> Q;
00313     vector<std::size_t, false> basis;
00314     T det;
00315 
00316     rref(A, B, Q, basis, det);
00317 
00318     if(is_null(det))
00319         throw matrix_is_singular();
00320 
00321     ARAGELI_ASSERT_1
00322     (
00323         !std::numeric_limits<T>::is_specialized ||
00324         !std::numeric_limits<T>::is_exact ||
00325         is_unit(A*Q)
00326     );
00327     
00328     return Q;
00329 }
00330 
00331 
00332 template <typename T, bool REFCNT>
00333 T det (const matrix<T, REFCNT>& A)
00334 {
00335     // precondition: A must be square
00336     //if(!A.is_square())throw exception("matrix must be square");
00337     ARAGELI_ASSERT_0(A.is_square());
00338 
00339     matrix<T, false> B;
00340     matrix<T, false> Q;
00341     vector<std::size_t, false> basis;
00342     T det;
00343 
00344     rref(A, B, Q, basis, det/*, ctrl::make_rref_slog(std::cout)*/);
00345 
00346     return basis.size() < A.nrows() ? null(det) : det;
00347 }
00348 
00349 
00350 template <typename T, bool REFCNT>
00351 typename matrix<T, REFCNT>::size_type rank
00352 (const matrix<T, REFCNT>& A)
00353 {
00354     matrix<T, false> B;
00355     matrix<T, false> Q;
00356     vector<std::size_t, false> basis;
00357     T det;
00358 
00359     rref(A, B, Q, basis, det);
00360 
00361     return basis.size();
00362 }
00363 
00364 
00365 template
00366 <
00367     typename A, typename B, typename Q, typename Basis,
00368     typename T, typename T_factory,
00369     typename Ctrler // control visitor
00370 >
00371 void rref_gauss_bareiss
00372 (
00373     const A& a, B& b, Q& q, Basis& basis,
00374     T& det,
00375     const T_factory& tfctr,
00376     Ctrler ctrler
00377 )
00378 {
00379     typedef typename B::element_type TB;
00380     typedef typename B::size_type size_type;
00381 
00382     det = tfctr.unit(det);
00383     T det_denom = tfctr.unit(det); // differs from the field version
00384     size_type m = a.nrows();
00385     size_type n = a.ncols();
00386     q.assign_eye(m);
00387     b = a;
00388     basis.resize(0);
00389     TB bnull = null(b(0, 0));   // needed for main loop of the algorithm
00390     hpair_matrix<B, Q> bq(b, q);
00391 
00392     ctrler.preamble(a);
00393 
00394     for(size_type i = 0, j = 0; i < m && j < n; j++)
00395     {
00396         //std::cout << "\nrref_gauss_bareiss.i = " << i;
00397 
00398         ctrler.before_iter(b, q, det, basis, det_denom);
00399 
00400         // Elimination of column j of matrix b.
00401 
00402         // Firstly find the biggest (in absolute value) entry in the column j.
00403 
00404         ctrler.find_biggest_in_col(j);
00405         TB max = bnull;
00406         size_type i_max = i;
00407 
00408         for(size_type ii = i; ii < m; ii++)
00409         {
00410             TB absval = abs(b(ii, j));
00411             if(absval > max)
00412             {
00413                 max = absval;
00414                 i_max = ii;
00415             }
00416         }
00417         
00418         if(is_null(max))
00419         {
00420             // column j is negligible (only zeros)
00421             ctrler.negligible_col(j);
00422             det = tfctr.null(det);
00423             ctrler.after_iter(b, q, det, basis, det_denom);
00424             continue;   // next column
00425         }
00426 
00427         ctrler.pivot_item(i_max, j);
00428 
00429         if(i != i_max)
00430         {
00431             bq.swap_rows(i, i_max);
00432             //q.swap_rows(i, i_max);
00433             opposite(&det);
00434             
00435             ctrler.swap_rows(i, i_max, b, q, det, det_denom);
00436         }
00437 
00438         ctrler.eliminate_col(j);
00439 
00440         gauss_bareiss_row_iter(bq, i, j, det, det_denom);
00441 
00442         //TB pivot = b(i, j);
00443 
00444         //if(is_negative(pivot))
00445         //{
00446         //  b.mult_row(i, -1);
00447         //  q.mult_row(i, -1);
00448         //  opposite(&pivot);
00449         //  opposite(&det);
00450         //}
00451 
00452         //for(std::size_t ii = 0; ii < m; ii++) // eliminate in column j
00453         //  if(ii != i)
00454         //  {
00455         //      TB alpha = b(ii, j);
00456         //      TB delta = gcd(pivot, alpha);// differs from field version
00457         //      TB b_ii = -alpha / delta;  // differs from field version
00458         //      TB b_i = pivot / delta;  // differs from field version
00459         //      b.mult_row(ii, b_i);  // differs from field version
00460         //      b.addmult_rows(ii, i, b_ii); // differs from field version
00461         //      q.mult_row(ii, b_i);  // differs from field version
00462         //      q.addmult_rows(ii, i, b_ii); // differs from field version
00463         //      det_denom *= b_i;  // differs from field version
00464         //      alpha = gcd(gcd(b.copy_row(ii)), gcd(q.copy_row(ii)));  // differs from field version
00465         //      b.div_row(ii, alpha);   // differs from field version
00466         //      q.div_row(ii, alpha); // differs from field version
00467         //      det *= alpha;  // differs from field version
00468         //  }
00469 
00470         ctrler.after_elimination(b, q, det, det_denom);
00471 
00472         basis.push_back(j);
00473         i++;
00474         ctrler.after_iter(b, q, det, basis, det_denom);
00475     } // end of main loop
00476 
00477     for(size_type i = 0; i < basis.size(); i++)
00478         det *= b(i, basis[i]);
00479     det /= det_denom;
00480 
00481     ctrler.conclusion(b, q, det, basis);
00482 }
00483 
00484 
00485 template <typename T, bool REFCNT>
00486 T det_int (const matrix<T, REFCNT>& A)
00487 {
00488     // precondition: A must be square
00489     //if(!A.is_square())throw exception("matrix must be square");
00490     ARAGELI_ASSERT_0(A.is_square());
00491 
00492     matrix<T, false> B;
00493     matrix<T, false> Q;
00494     vector<std::size_t, false> basis;
00495     T d;
00496 
00497     rref_int(A, B, Q, basis, d);
00498 
00499     return basis.size() < A.nrows() ? null(d) : d;
00500 }
00501 
00502 
00503 template <typename T, bool REFCNT>
00504 typename matrix<T, REFCNT>::size_type rank_int
00505 (const matrix<T, REFCNT>& A)
00506 {
00507     matrix<T, false> B;
00508     matrix<T, false> Q;
00509     vector<std::size_t, false> basis;
00510     T det;
00511 
00512     rref_int(A, B, Q, basis, det);
00513 
00514     return basis.size();
00515 }
00516 
00517 
00518 
00519 } // namespace Arageli
00520 
00521 
00522 #endif // #ifndef ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE

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