Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

/home/r0/dav/atlas.dir/atlas3/sources/utilities/matrix_def.h

Go to the documentation of this file.
00001 /*!
00002 \file
00003   This is matrix_def.h. This module contains some simple utilities for
00004   matrices. When we will need to do stuff for large matrices, we will
00005   need to look elsewhere, or in any case think a lot more.
00006 */
00007 /*
00008   Copyright (C) 2004,2005 Fokko du Cloux
00009   part of the Atlas of Reductive Lie Groups
00010 
00011   See file main.cpp for full copyright notice
00012 */
00013 
00014 #include <cassert>
00015 #include "intutils.h"
00016 
00017 /*****************************************************************************
00018 
00019   This module contains some simple utilities for matrices. When we will need
00020   to do stuff for large matrices, we will need to look elsewhere, or in any
00021   case think a lot more.
00022 
00023 ******************************************************************************/
00024 
00025 namespace atlas {
00026 
00027 namespace matrix {
00028 
00029 namespace {
00030 
00031 template<typename C> void blockReduce(Matrix<C>&, size_t, Matrix<C>&,
00032                                       Matrix<C>&);
00033 template<typename C> void blockShape(Matrix<C>&, size_t, Matrix<C>&,
00034                                      Matrix<C>&);
00035 template<typename C> void columnReduce(Matrix<C>&, size_t, size_t, Matrix<C>&);
00036 template<typename C> bool hasBlockReduction(const Matrix<C>&, size_t);
00037 template<typename C> bool hasReduction(const Matrix<C>&, size_t);
00038 template<typename C> typename Matrix<C>::index_pair
00039   findBlockReduction(const Matrix<C>&, size_t);
00040 template<typename C> typename Matrix<C>::index_pair
00041   findReduction(const Matrix<C>&, size_t);
00042 template<typename C> void rowReduce(Matrix<C>&, size_t, size_t, Matrix<C>&);
00043 
00044 }
00045 
00046 }
00047 
00048 /*****************************************************************************
00049 
00050         Chapter I -- The Matrix class
00051 
00052   We implement a matrix simply as a vector of elements, concatenating the
00053   rows.
00054 
00055 ******************************************************************************/
00056 
00057 namespace matrix {
00058 
00059 /******** constructors *******************************************************/
00060 
00061 template<typename C>
00062 Matrix<C>::Matrix(const std::vector<std::vector<C> >& b)
00063 
00064 /*!
00065   This constructor constructs a matrix from a bunch of vectors, columnwise.
00066   It is assumed that all elements of b have the same size.
00067 */
00068 
00069 {
00070   if (b.empty()) { // empty matrix
00071     d_rows = 0;
00072     d_columns = 0;
00073     return;
00074   }
00075 
00076   d_rows = b[0].size();
00077   d_columns = b.size();
00078   d_data.resize(d_rows*d_columns);
00079 
00080   for (size_t j = 0; j < d_columns; ++j) {
00081     for (size_t i = 0; i < d_rows; ++i)
00082       (*this)(i,j) = b[j][i];
00083   }
00084 }
00085 
00086 template<typename C>
00087 Matrix<C>::Matrix(const Matrix<C>& m, const std::vector<std::vector<C> >& b)
00088   :d_data(m.d_data), d_rows(m.d_rows), d_columns(m.d_columns)
00089 
00090 /*!
00091   This constructor constructs a square matrix, which is the matrix
00092   representing the operator defined by m in the canonical basis, in
00093   the basis b.
00094 */
00095 
00096 {
00097   Matrix<C> p(b);
00098   invConjugate(*this,p);
00099 }
00100 
00101 template<typename C>
00102 Matrix<C>::Matrix(const Matrix<C>& source, size_t r_first, size_t c_first,
00103                   size_t r_last, size_t c_last)
00104   :d_data((r_last-r_first)*(c_last-c_first)),
00105    d_rows(r_last-r_first),
00106    d_columns(c_last-c_first)
00107 
00108 /*!
00109   Synopsis: constructs the matrix corresponding to the block [r_first,r_last[
00110   x [c_first,c_last[ of source.
00111 */
00112 
00113 {
00114   for (size_t j = 0; j < d_columns; ++j)
00115     for (size_t i = 0; i < d_rows; ++i)
00116       (*this)(i,j) = source(r_first+i,c_first+j);
00117 }
00118 
00119 template<typename C> template<typename I>
00120 Matrix<C>::Matrix(const Matrix<C>& m, const I& first, const I& last)
00121   :d_data(m.d_data), d_rows(m.d_rows), d_columns(m.d_columns)
00122 
00123 /*!
00124   Here I is an iterator whose value type is Weight.
00125 
00126   This constructor constructs a square matrix, which is the matrix
00127   representing the operator defined by m in the canonical basis, in
00128   the basis supposed to be contained in [first,last[.
00129 */
00130 
00131 {
00132   Matrix<C> p(first,last,tags::IteratorTag());
00133   invConjugate(*this,p);
00134 }
00135 
00136 template<typename C>
00137 template<typename I> Matrix<C>::Matrix(const I& first, const I& last,
00138                                        tags::IteratorTag)
00139 
00140 /*!
00141   Here I is an iterator type whose value type should be vector<C>.
00142   The idea is that we read the columns of the matrix from the iterator.
00143   However, in order to be able to determine the allocation size,
00144   and since unfortunately we decided to read the matrix in rows, we
00145   need to catch the vectors first.
00146 
00147   Of course it is assumed that all the vectors in the range have the
00148   same size.
00149 */
00150 
00151 {
00152   std::vector<std::vector<C> > b(first,last);
00153 
00154   if (b.empty()) {
00155     d_rows = 0;
00156     d_columns = 0;
00157     return;
00158   }
00159 
00160   d_rows = b[0].size();
00161   d_columns = b.size();
00162   d_data.resize(d_rows*d_columns);
00163 
00164   for (size_t i = 0; i < d_rows; ++i)
00165     for (size_t j = 0; j < d_columns; ++j)
00166       (*this)(i,j) = b[j][i];
00167 }
00168 
00169 /******** accessors **********************************************************/
00170 
00171 template<typename C>
00172 bool Matrix<C>::operator== (const Matrix<C>& m) const
00173 
00174 {
00175   if ((d_rows != m.d_rows) or (d_columns != m.d_columns))
00176     return false;
00177 
00178   return d_data == m.d_data;
00179 }
00180 
00181 template<typename C>
00182 typename Matrix<C>::index_pair Matrix<C>::absMinPos(size_t i_min,
00183                                                     size_t j_min) const
00184 
00185 
00186 /*!
00187   Returns the position of the smallest non-zero entry in absolute value,
00188   in the region i >= i_min, j >= j_min
00189 */
00190 
00191 {
00192   C minCoeff = std::numeric_limits<C>::max();
00193   size_t i_m = d_rows;
00194   size_t j_m = d_columns;
00195 
00196   for (size_t i = i_min; i < d_rows; ++i)
00197     for (size_t j = j_min; j < d_columns; ++j) {
00198       C c = (*this)(i,j);
00199       if (c == 0)
00200         continue;
00201     if (intutils::abs(c) < minCoeff) { // new smallest value
00202       minCoeff = intutils::abs(c);
00203       i_m = i;
00204       j_m = j;
00205       if (minCoeff == 1)
00206         break;
00207     }
00208     }
00209 
00210   return std::make_pair(i_m,j_m);
00211 }
00212 
00213 template<typename C>
00214 void Matrix<C>::apply(std::vector<C>& v, const std::vector<C>& w) const
00215 
00216 /*!
00217   Applies the matrix to the vector w, and puts the result in v. It is
00218   assumed that the size of w is the number of columns, and that the size
00219   of v is the number of rows.
00220 */
00221 
00222 {
00223   std::vector<C> tmp = w; // safeguard in case v = w
00224 
00225   for (size_t i = 0; i < d_rows; ++i) {
00226     C c = 0;
00227     for (size_t j = 0; j < d_columns; ++j) {
00228       C m_ij = (*this)(i,j);
00229       c += m_ij*tmp[j];
00230     }
00231     v[i] = c;
00232   }
00233 
00234   return;
00235 }
00236 
00237 template<typename C> template<typename I, typename O>
00238 void Matrix<C>::apply(const I& first, const I& last, O out) const
00239 
00240 /*!
00241   A pipe-version of apply. We assume that I is an InputIterator with
00242   value-type vector<C>, and O an OutputIterator with the same
00243   value-type. Then we apply our matrix to each vector in [first,last[
00244   and output it to out.
00245 */
00246 
00247 {
00248   for (I i = first; i != last; ++i) {
00249     std::vector<C> v(d_rows);
00250     apply(v,*i);
00251     *out++ = v;
00252   }
00253 
00254   return;
00255 }
00256 
00257 template<typename C>
00258 void Matrix<C>::column(std::vector<C>& v, size_t j) const
00259 
00260 /*!
00261   Puts the j-th column of the matrix in v.
00262 */
00263 
00264 {
00265   v.resize(d_rows);
00266 
00267   for (size_t i = 0; i < d_rows; ++i)
00268     v[i] = (*this)(i,j);
00269 
00270   return;
00271 }
00272 
00273 template<typename C>
00274 bool Matrix<C>::divisible(C c) const
00275 
00276 /*!
00277   Tells if all coefficients of the matrix are divisible by c.
00278 */
00279 
00280 {
00281   for (size_t j = 0; j < d_data.size(); ++j)
00282     if (d_data[j]%c)
00283       return false;
00284 
00285   return true;
00286 }
00287 
00288 template<typename C>
00289 void Matrix<C>::row(std::vector<C>& v, size_t i) const
00290 
00291 /*!
00292   Puts the i-th row of the matrix in v.
00293 */
00294 
00295 {
00296   v.resize(d_columns);
00297 
00298   for (size_t j = 0; j < d_columns; ++j)
00299     v[j] = (*this)(i,j);
00300 
00301   return;
00302 }
00303 
00304 /******** manipulators *******************************************************/
00305 
00306 /*!
00307   Incrementation by addition with m. It is assumed that m and *this
00308   have the same shape.
00309 */
00310 
00311 template<typename C>
00312 Matrix<C>& Matrix<C>::operator+= (const Matrix<C>&  m)
00313 
00314 {
00315   for (size_t k = 0; k < d_data.size(); ++k) {
00316     d_data[k] += m.d_data[k];
00317   }
00318 }
00319 
00320 /*!
00321   Incrementation by subtraction of m. It is assumed that m and *this
00322   have the same shape.
00323 */
00324 template<typename C>
00325 Matrix<C>& Matrix<C>::operator-= (const Matrix<C>&  m)
00326 
00327 
00328 {
00329   for (size_t k = 0; k < d_data.size(); ++k) {
00330     d_data[k] -= m.d_data[k];
00331   }
00332 }
00333 
00334 
00335 template<typename C>
00336 Matrix<C> Matrix<C>::operator* (const Matrix<C>&  m) const
00337 {
00338   Matrix<C> result(d_rows,m.d_columns);
00339 
00340   for (size_t i = 0; i < d_rows; ++i)
00341     for (size_t k = 0; k < m.d_columns; ++k)
00342     {
00343       C c=0;
00344       for (size_t j = 0; j < d_columns; ++j)
00345         c += (*this)(i,j) * m(j,k);
00346 
00347       result(i,k)=c;
00348     }
00349 
00350   return result;
00351 }
00352 
00353 /*!
00354   \brief right multiplication by |m|.
00355 
00356   It is of course required that the number of rows of |m| is equal to the
00357   number of columns of |*this|.
00358 */
00359 template<typename C>
00360 Matrix<C>& Matrix<C>::operator*= (const Matrix<C>&  m)
00361 
00362 {
00363   // I dont think the code below is faster than just |*this= *this * m|, MvL
00364 
00365   C zero = 0; // conversion from int
00366   Matrix<C> prod(d_rows,m.d_columns,zero);
00367 
00368   for (size_t i = 0; i < d_rows; ++i)
00369     for (size_t j = 0; j < m.d_columns; ++j) {
00370       for (size_t k = 0; k < d_columns; ++k) {
00371         C t_ik = (*this)(i,k);
00372         C m_kj = m(k,j);
00373         prod(i,j) += t_ik * m_kj;
00374       }
00375     }
00376 
00377   swap(prod); // replace contents of |*this| by newly computed matrix
00378 
00379   return *this;
00380 }
00381 
00382 
00383 template<typename C>
00384 Matrix<C>& Matrix<C>::operator/= (const C& c)
00385 
00386 /*!
00387   Divides all entries of the matrix by c.
00388 */
00389 
00390 {
00391   if (c == 1)
00392     return *this;
00393 
00394   iterator e = end();
00395 
00396   for (iterator i = begin(); i != e; ++i)
00397     *i /= c;
00398 
00399   return *this;
00400 }
00401 
00402 template<typename C>
00403 void Matrix<C>::changeColumnSign(size_t j)
00404 
00405 /*!
00406   Changes the sign of all the entries in column j.
00407 */
00408 
00409 {
00410   for (size_t i = 0; i < d_rows; ++i) {
00411     (*this)(i,j) *= -1;
00412   }
00413 
00414   return;
00415 }
00416 
00417 template<typename C>
00418 void Matrix<C>::changeRowSign(size_t i)
00419 
00420 /*!
00421   Changes the sign of all the entries in row i.
00422 */
00423 
00424 {
00425   for (size_t j = 0; j < d_columns; ++j) {
00426     (*this)(i,j) *= -1;
00427   }
00428 
00429   return;
00430 }
00431 
00432 template<typename C>
00433 void Matrix<C>::columnOperation(size_t i, size_t j, const C& c)
00434 
00435 /*!
00436   Carries out the column operation consisting of adding c times column j
00437   to column i.
00438 */
00439 
00440 {
00441   for (size_t k = 0; k < columnSize(); ++k)
00442     (*this)(k,i) += c*(*this)(k,j);
00443 
00444   return;
00445 }
00446 
00447 template<typename C>
00448 void Matrix<C>::copy(const Matrix<C>& source, size_t r, size_t c)
00449 
00450 /*!
00451   Copies source to the rectangle of the current matrix with upper left corner
00452   at (r,c) and the appropriate size.
00453 */
00454 
00455 {
00456   for (size_t j = 0; j < source.d_columns; ++j)
00457     for (size_t i = 0; i < source.d_rows; ++i)
00458       (*this)(r+i,c+j) = source(i,j);
00459 
00460   return;
00461 }
00462 
00463 template<typename C>
00464 void Matrix<C>::copyColumn(const Matrix<C>& m, size_t c_d, size_t c_s)
00465 
00466 /*!
00467   Copies the column c_s of the matrix m to the column c_d of the current
00468   matrix. It is assumed that the two columns have the same size.
00469 */
00470 
00471 {
00472   for (size_t i = 0; i < d_rows; ++i)
00473     (*this)(i,c_d) = m(i,c_s);
00474 
00475   return;
00476 }
00477 
00478 template<typename C>
00479 void Matrix<C>::copyRow(const Matrix<C>& m, size_t r_d, size_t r_s)
00480 
00481 /*!
00482   Copies the column r_s of the matrix m to the column r_d of the current
00483   matrix. It is assumed that the two columns have the same size.
00484 */
00485 
00486 {
00487   for (size_t j = 0; j < d_columns; ++j)
00488     (*this)(r_d,j) = m(r_s,j);
00489 
00490   return;
00491 }
00492 
00493 template<typename C>
00494 void Matrix<C>::eraseColumn(size_t j)
00495 
00496 /*!
00497   Erases column j from the matrix.
00498 */
00499 
00500 {
00501   iterator pos = begin() + j;
00502   --d_columns;
00503 
00504   for (size_t k = 0; k < d_rows; ++k, pos += d_columns)
00505     d_data.erase(pos);
00506 
00507   return;
00508 }
00509 
00510 template<typename C>
00511 void Matrix<C>::eraseRow(size_t i)
00512 
00513 /*!
00514   Erases row i from the matrix.
00515 */
00516 
00517 {
00518   iterator first = begin() + i*d_columns;
00519   d_data.erase(first,first+d_columns);
00520   --d_rows;
00521 
00522   return;
00523 }
00524 
00525 /*!
00526   Here we invert the matrix without catching the denominator. The intent
00527   is that it should be used for invertible matrices only.
00528 */
00529 template<typename C> void Matrix<C>::invert()
00530 
00531 {
00532   C d; invert(d);
00533   assert(d==1);
00534 }
00535 
00536 /*!
00537   This function inverts the matrix M. It is assumed that the coefficents
00538   are in an integral domain. At the conclusion of the process, d will contain
00539   the denominator for the inverted matrix (so that the true result is M/d).
00540 
00541   If the matrix is not invertible, the resulting matrix is undefined, and
00542   d is set to 0.
00543 
00544   We have chosen here to avoid divisions as much as possible. So in fact we
00545   take the matrix to Smith normal form through elementary operations; from
00546   there we deduce the smallest possible denominator for the inverse, and
00547   the inverse matrix. The difference with SmithNormal is that we have to
00548   keep track of both row and column operations.
00549 
00550   NOTE : probably the Smith normal stuff can be streamlined a bit so that
00551   functions from there can be called, instead of rewriting things slightly
00552   differently as we do here. In particular, the accounting of the row
00553   operations seems a bit different here from there.
00554 */
00555 template<typename C>
00556 void Matrix<C>::invert(C& d)
00557 {
00558   assert(d_rows==d_columns);
00559   if (d_rows == 0) // do nothing to matrix, but set |d=1|
00560   { d=1; return; }
00561 
00562   C zero = 0; // conversion from int should work!
00563   Matrix<C> row(d_rows,d_rows,zero);
00564 
00565   // set res to identity
00566 
00567   for (size_t j = 0; j < d_rows; ++j)
00568     row(j,j) = 1;
00569 
00570   Matrix<C> col(row);
00571 
00572   // take *this to triangular form
00573 
00574   for (size_t r = 0; r < d_rows; ++r) {
00575 
00576     if (isZero(r,r)) { // null matrix left; matrix is not invertible
00577       d = 0;
00578       return;
00579     }
00580 
00581     index_pair k = absMinPos(r,r);
00582 
00583     if (k.first > r) {
00584       swapRows(r,k.first);
00585       row.swapRows(r,k.first);
00586     }
00587 
00588     if(k.second > r) {
00589       swapColumns(r,k.second);
00590       col.swapColumns(r,k.second);
00591     }
00592 
00593     if ((*this)(r,r) < 0) {
00594       changeRowSign(r);
00595       row.changeRowSign(r);
00596     }
00597 
00598     // ensure m(0,0) divides row and column
00599 
00600     while (hasReduction(*this,r)) {
00601       k = findReduction(*this,r);
00602       if (k.first > r) { // row reduction
00603         rowReduce(*this,k.first,r,row);
00604       }
00605       else { // column reduction
00606         columnReduce(*this,k.second,r,col);
00607       }
00608     }
00609 
00610     // clean up row and column
00611 
00612     blockShape(*this,r,row,col);
00613     blockReduce(*this,r,row,col);
00614 
00615   } // next |r|
00616 
00617   // now multiply out diagonal
00618 
00619   for (size_t j = 1; j < d_rows; ++j) {
00620     (*this)(j,j) *= (*this)(j-1,j-1);
00621   }
00622 
00623   // and write result to |d| and to |*this|
00624 
00625   d = (*this)(d_rows-1,d_rows-1); // minimal denominator
00626 
00627   for (size_t j = 0; j < d_rows; ++j) {
00628     (*this)(j,j) = d/(*this)(j,j);
00629   }
00630 
00631   col *= *this;
00632   col *= row;
00633   swap(col);
00634 
00635   return;
00636 }
00637 
00638 template<typename C>
00639 bool Matrix<C>::isZero(size_t i_min, size_t j_min) const
00640 
00641 /*!
00642   Whether all the entries in rectangle starting at |(i_min,i_max)| are zero.
00643 */
00644 
00645 {
00646   if (d_data.size() == 0) // empty matrix
00647     return true;
00648 
00649   for (size_t i = i_min; i < d_rows; ++i)
00650     for (size_t j = j_min; j < d_columns; ++j)
00651       if ((*this)(i,j))
00652         return false;
00653 
00654   return true;
00655 }
00656 
00657 template<typename C>
00658 void Matrix<C>::negate()
00659 
00660 /*!
00661   Synopsis: change the sign of the matrix.
00662 */
00663 
00664 {
00665   for (size_t i = 0; i < d_rows; ++i)
00666     for (size_t j = 0; j < d_rows; ++j)
00667       (*this)(i,j) = -(*this)(i,j);
00668 
00669   return;
00670 }
00671 
00672 template<typename C>
00673 void Matrix<C>::permute(const setutils::Permutation& a)
00674 
00675 /*!
00676   Synopsis : permutes rows and columns of the matrix according to the
00677   permutation a, resulting in the matrix of the same operator in the basis
00678   e_{a[0]}, ... , e_{a[n-1]}. This amounts to conjugating by the permutation
00679   matrix (delta_{i,a[i]})_{i,j} that transforms from coordinates on the
00680   standard basis to those on the basis e_{a[0]}, ... , e_{a[n-1]}.
00681 
00682   Precondition : m is a square matrix of order n; a holds a permutation
00683   of the matrix n;
00684 
00685   Method: the new entry at (i,j) is set to the old entry at (a[i],a[j]), in a
00686   separate copy (without trying to do the permutation of entries in place)
00687 */
00688 
00689 {
00690   Matrix<C> q(d_columns);
00691 
00692   for (size_t j = 0; j < d_columns; ++j)
00693     for (size_t i = 0; i < d_rows; ++i) {
00694       size_t a_i = a[i];
00695       size_t a_j = a[j];
00696       q(i,j) = (*this)(a_i,a_j);
00697     }
00698 
00699   swap(q);
00700 
00701   return;
00702 }
00703 
00704 template<typename C>
00705 void Matrix<C>::resize(size_t m, size_t n)
00706 
00707 /*!
00708   Synopsis: changes the size of the matrix to m x n.
00709 
00710   NOTE: this is a bad name, and a bit dangerous. One would expect the data
00711   of the matrix in the upper left corner to be preserved, but this is not
00712   done; in other words, the contents of the resized matrix are garbage.
00713 */
00714 
00715 {
00716   d_data.resize(m*n);
00717   d_rows = m;
00718   d_columns = n;
00719 
00720   return;
00721 }
00722 
00723 template<typename C>
00724 void Matrix<C>::resize(size_t m, size_t n, const C& c)
00725 
00726 /*!
00727   Synopsis: changes the size of the matrix to m x n, and resets _all_ elements
00728   to c.
00729 
00730   NOTE: this is a bad name, because it does not behave like resize for vectors.
00731 */
00732 
00733 {
00734   d_data.assign(m*n,c);
00735   d_rows = m;
00736   d_columns = n;
00737 
00738   return;
00739 }
00740 
00741 template<typename C>
00742 void Matrix<C>::rowOperation(size_t i, size_t j, const C& c)
00743 
00744 /*!
00745   Carries out the row operation consisting of adding c times row j
00746   to row i.
00747 */
00748 
00749 {
00750   for (size_t k = 0; k < rowSize(); ++k)
00751     (*this)(i,k) += c*(*this)(j,k);
00752 
00753   return;
00754 }
00755 
00756 template<typename C>
00757 void Matrix<C>::swap(Matrix<C>& m)
00758 
00759 /*!
00760   Swaps m with the current matrix.
00761 */
00762 
00763 {
00764   // swap data
00765 
00766   d_data.swap(m.d_data);
00767 
00768   // swap row and column numbers
00769 
00770   std::swap(d_rows,m.d_rows);
00771   std::swap(d_columns,m.d_columns);
00772 
00773   return;
00774 }
00775 
00776 template<typename C>
00777 void Matrix<C>::swapColumns(size_t i, size_t j)
00778 
00779 /*!
00780   Interchanges columns i and j
00781 */
00782 
00783 {
00784   for (size_t k = 0; k < columnSize(); ++k) {
00785     C tmp = (*this)(k,i);
00786     (*this)(k,i) = (*this)(k,j);
00787     (*this)(k,j) = tmp;
00788   }
00789 
00790   return;
00791 }
00792 
00793 template<typename C>
00794 void Matrix<C>::swapRows(size_t i, size_t j)
00795 
00796 /*!
00797   Interchanges rows i and j
00798 */
00799 
00800 {
00801   for (size_t k = 0; k < rowSize(); ++k) {
00802     C tmp = (*this)(i,k);
00803     (*this)(i,k) = (*this)(j,k);
00804     (*this)(j,k) = tmp;
00805   }
00806 
00807   return;
00808 }
00809 
00810 template<typename C> void Matrix<C>::transpose()
00811 
00812 /*!
00813   Transposes the matrix. We allow ourselves a temporary vector if the matrix
00814   is not square; it could likely be done in-place, but the permutation is
00815   rather complicated!
00816 */
00817 
00818 {
00819   if (d_rows == d_columns) {// matrix is square
00820     for (size_t j = 0; j < d_columns; ++j)
00821       for (size_t i = j+1; i < d_rows; ++i) {
00822         C t = (*this)(i,j);
00823         (*this)(i,j) = (*this)(j,i);
00824         (*this)(j,i) = t;
00825       }
00826     return;
00827   }
00828 
00829   // now assume matrix is not square
00830 
00831   C zero = 0; // conversion from int
00832   std::vector<C> v(d_data.size(),zero);
00833   size_t k = 0;
00834 
00835   // write data for transpose matrix in v
00836 
00837   for (size_t j = 0; j < d_columns; ++j)
00838     for (size_t i = 0; i < d_rows; ++i) {
00839       v[k] = (*this)(i,j);
00840       k++;
00841     }
00842 
00843   // swap data and row- and column- size
00844 
00845   d_data.swap(v);
00846 
00847   size_t t = d_rows;
00848   d_rows = d_columns;
00849   d_columns = t;
00850 
00851   return;
00852 }
00853 
00854 }
00855 
00856 /*****************************************************************************
00857 
00858         Chapter II --- Functions declared in matrix.h
00859 
00860 ******************************************************************************/
00861 
00862 namespace matrix {
00863 
00864 template<typename C>
00865   void columnVectors(std::vector<std::vector<C> >& b, const Matrix<C>& m)
00866 
00867 /*!
00868   Synopsis: writes in b the list of column vectors of m.
00869 */
00870 
00871 {
00872   b.resize(m.numColumns());
00873 
00874   for (size_t j = 0; j < b.size(); ++j) {
00875     m.column(b[j],j);
00876   }
00877 
00878   return;
00879 }
00880 
00881 template<typename C>
00882 Matrix<C>& conjugate(Matrix<C>& m, const Matrix<C>& p)
00883 
00884 /*!
00885   Conjugates m by p, i.e. transforms m into pmp^{-1}. It is assumed that
00886   p is invertible (over the quotient field of the coefficients), and that
00887   denominators cancel out.
00888 */
00889 
00890 {
00891   C d;
00892   Matrix<C> tmp(p*m*p.inverse(d));
00893   tmp /= d;
00894   m.swap(tmp);
00895 
00896   return m;
00897 }
00898 
00899 template<typename C>
00900 void extractBlock(Matrix<C>& dest, const Matrix<C>& source, size_t firstRow,
00901                   size_t lastRow, size_t firstColumn, size_t lastColumn)
00902 
00903 /*!
00904   Synopsis: sets dest equal to the block [firstRow,lastRow[ x [firstColumn,
00905   lastColumn[ in source.
00906 */
00907 
00908 {
00909   dest.resize(lastRow - firstRow, lastColumn - firstColumn);
00910 
00911   for (size_t j = 0; j < dest.numColumns(); ++j)
00912     for (size_t i = 0; i < dest.numRows(); ++i)
00913       dest(i,j) = source(firstRow+i,firstColumn+j);
00914 
00915   return;
00916 }
00917 
00918 template<typename C>
00919 void extractMatrix(Matrix<C>& dest, const Matrix<C>& source,
00920                    const std::vector<size_t>& r, const std::vector<size_t>& c)
00921 
00922 /*!
00923   Synopsis: extracts the sub-matrix corresponding to the subsets r and c of the
00924   row and column indices respectively.
00925 */
00926 
00927 {
00928   dest.resize(r.size(),c.size());
00929 
00930   for (size_t j = 0; j < c.size(); ++j)
00931     for (size_t i = 0; i < c.size(); ++i)
00932       dest(i,j) = source(r[i],c[j]);
00933 
00934   return;
00935 }
00936 
00937 template<typename C> void identityMatrix(Matrix<C>& m, size_t n)
00938 
00939 /*!
00940   Synopsis: puts in q the identity matrix of size n.
00941 */
00942 
00943 {
00944   C zero = 0; // conversion from int
00945   m.resize(n,n,zero);
00946 
00947   for (size_t j = 0; j < n; ++j)
00948     m(j,j) = 1;
00949 
00950   return;
00951 }
00952 
00953 template<typename C> void initBasis(std::vector<std::vector<C> >& b, size_t r)
00954 
00955 /*!
00956   Synopsis: sets b to the canonical basis in dimension r.
00957 */
00958 
00959 {
00960   C zero = 0; // conversion from int
00961   b.assign(r,std::vector<C>(r,zero));
00962 
00963   for (size_t j = 0; j < r; ++j) {
00964     b[j][j] = 1;
00965   }
00966 
00967   return;
00968 }
00969 
00970 template<typename C> Matrix<C>& invConjugate(Matrix<C>& m, const Matrix<C>& p)
00971 
00972 /*!
00973   Conjugates m by p^{-1}, i.e. transforms m into p^{-1}mp. It is assumed that
00974   p is invertible (over the quotient field of the coefficients), and that
00975   denominators cancel out.
00976 */
00977 
00978 {
00979   C d;
00980   Matrix<C> tmp(p.inverse(d)*m*p);
00981   tmp /= d;
00982   m.swap(tmp);
00983 
00984   return m;
00985 }
00986 
00987 
00988 
00989 } // namespace matrix
00990 
00991 /*****************************************************************************
00992 
00993         Chapter III --- Auxiliary functions
00994 
00995 ******************************************************************************/
00996 
00997 namespace matrix {
00998 
00999 namespace {
01000 
01001 template<typename C>
01002 void blockReduce(Matrix<C>& m, size_t d, Matrix<C>& r, Matrix<C>& c)
01003 
01004 /*!
01005   Ensures that m(d,d) divides the block from (d+1,d+1) down.
01006 */
01007 
01008 {
01009   if (m(d,d) == 1) // no reduction
01010     return;
01011 
01012   while(hasBlockReduction(m,d)) {
01013     typename Matrix<C>::index_pair k = findBlockReduction(m,d);
01014     C one = 1; // conversion from int
01015     m.rowOperation(d,k.first,one);
01016     r.rowOperation(d,k.first,one);
01017     while (hasReduction(m,d)) {
01018       k = findReduction(m,d);
01019       if (k.first > d) { // row reduction
01020         rowReduce(m,k.first,d,r);
01021       }
01022       else { // column reduction
01023         columnReduce(m,k.second,d,c);
01024       }
01025     }
01026     blockShape(m,d,r,c);
01027   }
01028 
01029   if (m(d,d) > 1) // divide
01030     for (size_t j = d+1; j < m.rowSize(); ++j)
01031       for (size_t i = d+1; i < m.columnSize(); ++i)
01032         m(i,j) /= m(d,d);
01033 
01034   return;
01035 }
01036 
01037 template<typename C>
01038 void blockShape(Matrix<C>& m, size_t d, Matrix<C>& r,
01039                 Matrix<C>& c)
01040 
01041 /*!
01042   Does the final reduction of m to block shape, recording row reductions in
01043   r and column reductions in c.
01044 */
01045 
01046 {
01047   C a = m(d,d);
01048 
01049   for (size_t j = d+1; j < m.rowSize(); ++j) {
01050     if (m(d,j) == 0)
01051       continue;
01052     C q = m(d,j)/a;
01053     q = -q;
01054     m.columnOperation(j,d,q);
01055     c.columnOperation(j,d,q);
01056   }
01057 
01058   for (size_t i = d+1; i < m.columnSize(); ++i) {
01059     if (m(i,d) == 0)
01060       continue;
01061     C q = m(i,d)/a;
01062     q = -q;
01063     m.rowOperation(i,d,q);
01064     r.rowOperation(i,d,q);
01065   }
01066 
01067   return;
01068 }
01069 
01070 template<typename C>
01071 void columnReduce(Matrix<C>& m, size_t j,
01072                   size_t d, Matrix<C>& c)
01073 
01074 /*!
01075   Does the column reduction for m at place j, and does the same operation
01076   on r. The reduction consists in subtracting from column j the multiple
01077   of column d which leaves at (d,j) the remainder of the Euclidian division
01078   of m(d,j) by m(d,d), and then swapping columns j and d.
01079 */
01080 
01081 {
01082   C a = m(d,d);
01083   C q = intutils::divide(m(d,j),a);
01084   q = -q;
01085   m.columnOperation(j,d,q);
01086   c.columnOperation(j,d,q);
01087   m.swapColumns(d,j);
01088   c.swapColumns(d,j);
01089 
01090   return;
01091 }
01092 
01093 template<typename C>
01094 typename Matrix<C>::index_pair findBlockReduction(const Matrix<C>& m,
01095                                              size_t r)
01096 
01097 /*!
01098   Returns the reduction point of m. Assumes that hasBlockReduction(m,r) has
01099   returned true.
01100 */
01101 
01102 {
01103   C a = m(r,r);
01104 
01105   for (size_t j = r+1; j < m.rowSize(); ++j) {
01106     for (size_t i = r+1; i < m.columnSize(); ++i) {
01107       if (m(i,j)%a)
01108         return std::make_pair(i,j);
01109     }
01110   }
01111 
01112   // this should never be reached
01113   return std::make_pair(static_cast<size_t>(0ul),static_cast<size_t>(0ul));
01114 }
01115 
01116 template<typename C>
01117 typename Matrix<C>::index_pair findReduction(const Matrix<C>& m,
01118                                              size_t r)
01119 
01120 /*!
01121   Returns the reduction point of m. Assumes that hasReduction(m,r) has
01122   returned true.
01123 */
01124 
01125 {
01126   C a = m(r,r);
01127 
01128   for (size_t j = r+1; j < m.rowSize(); ++j) {
01129     if (m(r,j)%a)
01130       return std::make_pair(r,j);
01131   }
01132 
01133   for (size_t i = r+1; i < m.columnSize(); ++i) {
01134     if (m(i,r)%a)
01135       return std::make_pair(i,r);
01136   }
01137 
01138   // this should never be reached
01139   return std::make_pair(static_cast<size_t>(0ul),static_cast<size_t>(0ul));
01140 }
01141 
01142 template<typename C>
01143 bool hasBlockReduction(const Matrix<C>& m, size_t r)
01144 
01145 /*!
01146   Tells if there is an element in the block under (r,r) which is not divisible
01147   bu m(r,r)
01148 */
01149 
01150 {
01151   C a = m(r,r);
01152 
01153   if (a == 1)
01154     return false;
01155 
01156   for (size_t j = r+1; j < m.rowSize(); ++j) {
01157     for (size_t i = r+1; i < m.columnSize(); ++i) {
01158       if (m(i,j)%a)
01159         return true;
01160     }
01161   }
01162 
01163   return false;
01164 }
01165 
01166 template<typename C>
01167 bool hasReduction(const Matrix<C>& m, size_t r)
01168 
01169 /*!
01170   Tells if there is an element in the first row or column not divisible by
01171   m(r,r).
01172 */
01173 
01174 {
01175   C a = m(r,r);
01176 
01177   if (a == 1)
01178     return false;
01179 
01180   for (size_t j = r+1; j < m.rowSize(); ++j) {
01181     if (m(r,j)%a)
01182       return true;
01183   }
01184 
01185   for (size_t i = r+1; i < m.columnSize(); ++i) {
01186     if (m(i,r)%a)
01187       return true;
01188   }
01189 
01190   return false;
01191 }
01192 
01193 template<typename C>
01194 void rowReduce(Matrix<C>& m, size_t i, size_t d, Matrix<C>& r)
01195 
01196 /*!
01197   Does the row reduction for m at place j, and does the same operation
01198   on r. The reduction consists in subtracting from row i the multiple
01199   of row d which leaves at (i,d) the remainder of the Euclidian division
01200   of m(d,j) by m(d,d), and then swapping rows i and d.
01201 */
01202 
01203 {
01204   C a = m(d,d);
01205   C q = intutils::divide(m(i,d),a);
01206   q = -q;
01207   m.rowOperation(i,d,q);
01208   r.rowOperation(i,d,q);
01209   m.swapRows(d,i);
01210   r.swapRows(d,i);
01211 
01212   return;
01213 }
01214 
01215 }
01216 
01217 }
01218 
01219 }

Generated on Wed Mar 26 16:49:40 2008 for atlas by  doxygen 1.3.9.1