library of assembled shared sources

http://lass.cocamware.com

matrix.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
00047 
00048 #include "num_common.h"
00049 #include "matrix.h"
00050 #include "impl/matrix_solve.h"
00051 #include "../meta/meta_assert.h"
00052 
00053 #define LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(a, b)\
00054     LASS_UTIL_IMPL_MAKE_ENFORCER(\
00055         ::lass::util::impl::TruePredicate,\
00056         ::lass::util::impl::DefaultRaiser,\
00057         (a).rows() == (b).rows() && (a).columns() == (b).columns(),\
00058         int(0), \
00059         "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have different dimensions in '" LASS_HERE "'.")
00060 
00061 #define LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(a, b)\
00062     LASS_UTIL_IMPL_MAKE_ENFORCER(\
00063         ::lass::util::impl::EqualPredicate,\
00064         ::lass::util::impl::DefaultRaiser,\
00065         (a).columns(),\
00066         (b).rows(),\
00067         "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have no matching dimensions for operation at '" LASS_HERE "'.")
00068 
00069 namespace lass
00070 {
00071 namespace num
00072 {
00073 
00074 // --- public --------------------------------------------------------------------------------------
00075 
00076 /** constructs an empty matrix
00077  *
00078  *  @par Exception Safety: 
00079  *      strong guarentee.
00080  */
00081 template <typename T, typename S>
00082 Matrix<T, S>::Matrix():
00083     storage_()
00084 {
00085 }
00086 
00087 
00088 
00089 /** Construct a matrix of dimension @a iRows x @a iColumns.
00090  *  Can be used as default constructor for storage in containers.
00091  *  @param iRows the number of rows of the matrix to be created.
00092  *  @param iColumns the number of columns of the matrix to be created.
00093  *  By default both @a iRows and @a iColumns are zero, what creates an empty matrix.
00094  *  Not very usefull though, except as place holder.  So, it's safe to pass
00095  *  zero as arguments, but you shouldn't pass negative values.
00096  *
00097  *  @par Complexity:
00098  *      O(iRows * iColumns)
00099  *
00100  *  @par Exception Safety: 
00101  *      strong guarentee.
00102  */
00103 template <typename T, typename S>
00104 Matrix<T, S>::Matrix(TSize iRows, TSize iColumns):
00105     storage_(iRows, iColumns)
00106 {
00107 }
00108 
00109 
00110 
00111 template <typename T, typename S>
00112 Matrix<T, S>::Matrix(const TStorage& iStorage):
00113     storage_(iStorage)
00114 {
00115 }
00116 
00117 
00118 
00119 /** assign storage/expression matrix to this (this should be a storage matrix).
00120  *
00121  *  @pre @c this must be an l-value (storage matrix).
00122  *
00123  *  @par Complexity:
00124  *      O(iOther.rows() * iOther.columns())
00125  *
00126  *  @par Exception Safety: 
00127  *      basic guarentee.
00128  */
00129 template <typename T, typename S>
00130 template <typename T2, typename S2>
00131 Matrix<T, S>::Matrix(const Matrix<T2, S2>& iOther):
00132     storage_(iOther.rows(), iOther.columns())
00133 {
00134     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00135 
00136     const S2& other = iOther.storage();
00137     const TSize m = rows();
00138     const TSize n = columns();
00139     for (TSize i = 0; i < m; ++i)
00140     {
00141         for (TSize j = 0; j < n; ++j)
00142         {
00143             storage_(i, j) = other(i, j);
00144         }
00145     }
00146 }
00147 
00148 
00149 
00150 /** assign storage/expression matrix to this (this should be a storage matrix).
00151  *
00152  *  @pre @c this must be an l-value (storage matrix).
00153  *
00154  *  @par Complexity:
00155  *      O(iOther.rows() * iOther.columns())
00156  *
00157  *  @par Exception Safety: 
00158  *      basic guarentee.
00159  */
00160 template <typename T, typename S>
00161 template <typename T2, typename S2>
00162 Matrix<T, S>& Matrix<T, S>::operator=(const Matrix<T2, S2>& iOther)
00163 {
00164     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00165 
00166     const S2& other = iOther.storage();
00167     const TSize m = other.rows();
00168     const TSize n = other.columns();
00169     storage_.resize(m, n);
00170     for (TSize i = 0; i < m; ++i)
00171     {
00172         for (TSize j = 0; j < n; ++j)
00173         {
00174             storage_(i, j) = other(i, j);
00175         }
00176     }
00177     return *this;
00178 }
00179 
00180 
00181 
00182 /** return number of rows in matrix.
00183  *
00184  *  @post should never return be a negative value.
00185  *
00186  *  @par Complexity:
00187  *      O(1)
00188  *
00189  *  @par Exception safety:
00190  *      no-fail
00191  */
00192 template <typename T, typename S> inline
00193 const typename Matrix<T, S>::TSize
00194 Matrix<T, S>::rows() const
00195 {
00196     return storage_.rows();
00197 }
00198 
00199 
00200 
00201 /** return number of columns in matrix.
00202  *
00203  *  @post should never return be a negative value.
00204  *
00205  *  @par Complexity:
00206  *      O(1)
00207  *
00208  *  @par Exception safety:
00209  *      no-fail
00210  */
00211 template <typename T, typename S> inline
00212 const typename Matrix<T, S>::TSize
00213 Matrix<T, S>::columns() const
00214 {
00215     return storage_.columns();
00216 }
00217 
00218 
00219 
00220 /** return the component value at position (iRow, iColumn)
00221  *
00222  *  @pre (iRow, iColumn) shouldn't be out of the range [0, this->rows()) x [0, this->columns()], unless
00223  *  you're asking for trouble.
00224  */
00225 template <typename T, typename S> inline
00226 const typename Matrix<T, S>::TValue
00227 Matrix<T, S>::operator()(TSize iRow, TSize iColumn) const
00228 {
00229     LASS_ASSERT(iRow < rows() && iColumn < columns());
00230     return storage_(iRow, iColumn);
00231 }
00232 
00233 
00234 
00235 /** access the component value at position (iRow, iColumn)
00236  *
00237  *  @pre (iRow, iColumn) shouldn't be out of the range [0, this->rows()) x [0, this->columns()], unless
00238  *  you're asking for trouble.
00239  *
00240  *  @pre @c this must be an l-value (storage matrix).
00241  */
00242 template <typename T, typename S> inline
00243 typename util::CallTraits<T>::TReference
00244 Matrix<T, S>::operator()(TSize iRow, TSize iColumn)
00245 {
00246     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00247     LASS_ASSERT(iRow < rows() && iColumn < columns());
00248     return storage_(iRow, iColumn);
00249 }
00250 
00251 
00252 
00253 /** return the component value at position (iRow, iColumn)
00254  *  (iRow, iColumn) will be wrapped to range [0, this->rows()) x [0, this->columns()] by using a
00255  *  modulus operator
00256  */
00257 template <typename T, typename S> inline
00258 const typename Matrix<T, S>::TValue
00259 Matrix<T, S>::at(signed iRow, signed iColumn) const
00260 {
00261     return storage_(mod(iRow, rows()), mod(iColumn, columns()));
00262 }
00263 
00264 
00265 
00266 /** access the component value at position (iRow, iColumn)
00267  *  (iRow, iColumn) will be wrapped to range [0, this->rows()) x [0, this->columns()] by using a
00268  *  modulus operator
00269  *
00270  *  @pre @c this must be an l-value (storage matrix).
00271  */
00272 template <typename T, typename S> inline
00273 typename util::CallTraits<T>::TReference
00274 Matrix<T, S>::at(signed iRow, signed iColumn)
00275 {
00276     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00277     return storage_(mod(iRow, rows()), mod(iColumn, columns()));
00278 }
00279 
00280 
00281 
00282 /** return a row of matrix.
00283  *  iRow will be wrapped to range [0, this->rows()) by using a modulus operator
00284  */
00285 template <typename T, typename S> inline
00286 typename Matrix<T, S>::ConstRow
00287 Matrix<T, S>::row(signed iRow) const
00288 {
00289     return ConstRow(*this, static_cast<size_t>(mod(iRow, static_cast<int>(rows()))));
00290 }
00291 
00292 
00293 
00294 /** return a row of matrix.
00295  *  iRow will be wrapped to range [0, this->rows()) by using a modulus operator.
00296  *  THIS MUST BE LVALUE (storage matrix).
00297  */
00298 template <typename T, typename S> inline
00299 typename Matrix<T, S>::Row
00300 Matrix<T, S>::row(signed iRow)
00301 {
00302     return Row(*this, static_cast<size_t>(mod(iRow, static_cast<int>(rows()))));
00303 }
00304 
00305 
00306 
00307 /** return a column of matrix.
00308  *  iColumn will be wrapped to range [0, this->columns()) by using a modulus operator
00309  */
00310 template <typename T, typename S> inline
00311 typename Matrix<T, S>::ConstColumn
00312 Matrix<T, S>::column(signed iColumn) const
00313 {
00314     return ConstColumn(*this, static_cast<size_t>(mod(iColumn, static_cast<int>(columns()))));
00315 }
00316 
00317 
00318 
00319 /** return a column of matrix.
00320  *  iColumn will be wrapped to range [0, this->columns()) by using a modulus operator
00321  *  THIS MUST BE LVALUE (storage matrix).
00322  */
00323 template <typename T, typename S> inline
00324 typename Matrix<T, S>::Column
00325 Matrix<T, S>::column(signed iColumn)
00326 {
00327     return Column(*this, static_cast<size_t>(mod(iColumn, static_cast<int>(columns()))));
00328 }
00329 
00330 
00331 
00332 /** A weird way to get back the same object
00333  *
00334  *  @par Complexity:
00335  *      O(1)
00336  *
00337  *  @par Exception safety:
00338  *      no-fail
00339  */
00340 template <typename T, typename S> inline
00341 const Matrix<T, S>& Matrix<T, S>::operator+() const
00342 {
00343     return *this;
00344 }
00345 
00346 
00347 
00348 /** return a vector with all components negated
00349  *  (-a)(i, j) == -(a(i, j)).
00350  *
00351  *  @par Complexity:
00352  *      O(1)
00353  *
00354  *  @par Exception safety:
00355  *      no-fail
00356  */
00357 template <typename T, typename S>
00358 const Matrix<T, impl::MNeg<T, S> >
00359 Matrix<T, S>::operator-() const
00360 {
00361     typedef impl::MNeg<T, S> TExpression;
00362     return Matrix<T, TExpression>(TExpression(storage_));
00363 }
00364 
00365 
00366 
00367 /** componentswise addition assignment of two matrices
00368  *
00369  *  <i>Matrix Addition: Denote the sum of two matrices @n A and @n B (of the same dimensions) by
00370  *  @n C=A+B. The sum is defined by adding entries with the same indices @n Cij=Aij+Bij over all
00371  *  @n i and @n j.</i>
00372  *  http://mathworld.wolfram.com/MatrixAddition.html
00373  *
00374  *  This method implements the assignment addition what reduces to @n Aij+=Bij over all @n i and
00375  *  @n j.
00376  *
00377  *  @pre @c this must be an l-value (storage matrix).
00378  *
00379  *  @par Complexity:
00380  *      O(this->rows() * this->columns())
00381  *
00382  *  @throw an exception is thrown if @a *this and @a iB are not of the same dimensions
00383  */
00384 template <typename T, typename S>
00385 template <typename S2>
00386 Matrix<T, S>& Matrix<T, S>::operator+=(const Matrix<T, S2>& iB)
00387 {
00388     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00389     LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, iB);
00390     const S2& other = iB.storage();
00391     const TSize m = rows();
00392     const TSize n = columns();
00393     for (TSize i = 0; i < m; ++i)
00394     {
00395         for (TSize j = 0; j < n; ++j)
00396         {
00397             storage_(i, j) += other(i, j);
00398         }
00399     }
00400     return *this;
00401 }
00402 
00403 
00404 
00405 /** componentswise subtraction assignment of two matrices
00406  *  This method is equivalent to @n this+=(-iB) .
00407  *
00408  *  @sa Matrix<T>::operator+=
00409  *
00410  *  @pre @c this must be an l-value (storage matrix).
00411  *
00412  *  @par Complexity:
00413  *      O(this->rows() * this->columns())
00414  *
00415  *  @throw an exception is thrown if @a *this and @a iB are not of the same dimensions
00416  */
00417 template <typename T, typename S>
00418 template <typename S2>
00419 Matrix<T, S>& Matrix<T, S>::operator-=(const Matrix<T, S2>& iB)
00420 {
00421     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00422     LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, iB);
00423     const S2& other = iB.storage();
00424     const TSize m = rows();
00425     const TSize n = columns();
00426     for (TSize i = 0; i < m; ++i)
00427     {
00428         for (TSize j = 0; j < n; ++j)
00429         {
00430             storage_(i, j) -= other(i, j);
00431         }
00432     }
00433     return *this;
00434 }
00435 
00436 
00437 
00438 /** scalar multiplication assignment of matrix
00439  *
00440  *  @pre @c this must be an l-value (storage matrix).
00441  *
00442  *  @par Complexity:
00443  *      O(this->rows() * this->columns())
00444  */
00445 template <typename T, typename S>
00446 Matrix<T, S>& Matrix<T, S>::operator*=(TParam iB)
00447 {
00448     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00449     const TSize size = storage_.rows() * storage_.columns();
00450     const TSize m = rows();
00451     const TSize n = columns();
00452     for (TSize i = 0; i < m; ++i)
00453     {
00454         for (TSize j = 0; j < n; ++j)
00455         {
00456             storage_(i, j) *= iB;
00457         }
00458     }
00459     return *this;
00460 }
00461 
00462 
00463 
00464 /** scalar multiplication assignment of matrix
00465  *
00466  *  @pre @c this must be an l-value (storage matrix).
00467  */
00468 template <typename T, typename S>
00469 Matrix<T, S>& Matrix<T, S>::operator /=(TParam iB)
00470 {
00471     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00472     const TSize m = rows();
00473     const TSize n = columns();
00474     for (TSize i = 0; i < m; ++i)
00475     {
00476         for (TSize j = 0; j < n; ++j)
00477         {
00478             storage_(i, j) /= iB;
00479         }
00480     }
00481     return *this;
00482 }
00483 
00484 
00485 
00486 /** set this to a zero matrix of @a iRows rows and @a iColumns columns.
00487  *  @sa Matrix<T>::isZero
00488  *
00489  *  @pre this should be an lvalue
00490  *
00491  *  @par Complexity:
00492  *      O(this->rows() * this->columns())
00493  */
00494 template <typename T, typename S>
00495 void Matrix<T, S>::setZero(TSize iRows, TSize iColumns)
00496 {
00497     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00498     storage_.resize(iRows, iColumns);
00499     for (TSize i = 0; i < iRows; ++i)
00500     {
00501         for (TSize j = 0; j < iColumns; ++j)
00502         {
00503             storage_(i, j) = TNumTraits::zero;
00504         }
00505     }
00506 }
00507 
00508 
00509 
00510 /** set matrix to an identity matrix of size @a iSize.
00511  *  @sa Matrix<T>::isIdentity
00512  *
00513  *  @pre this should be an lvalue
00514  *
00515  *  @par Complexity:
00516  *      O(this->rows() * this->columns())
00517  */
00518 template <typename T, typename S>
00519 void Matrix<T, S>::setIdentity(TSize iSize)
00520 {
00521     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00522     storage_.resize(iSize, iSize);
00523     for (TSize i = 0; i < iSize; ++i)
00524     {
00525         for (TSize j = 0; j < iSize; ++j)
00526         {
00527             storage_(i, j) = i == j ? TNumTraits::one : TNumTraits::zero;
00528         }
00529     }
00530 }
00531 
00532 
00533 
00534 /** return true if this is a (0×0) matrix
00535  *
00536  *  @par Complexity:
00537  *      O(1)
00538  *
00539  *  @par Exception safety:
00540  *      no-fail
00541  */
00542 template <typename T, typename S>
00543 bool Matrix<T, S>::isEmpty() const
00544 {
00545     return storage_.rows() == 0 || storage_.columns() == 0;
00546 }
00547 
00548 
00549 
00550 /** test if this matrix equals a zero matrix.
00551  *
00552  *  <i>A zero matrix is an @n m×n matrix consisting of all 0s (MacDuffee 1943, p. 27), denoted @n 0.
00553  *  Zero matrices are sometimes also known as null matrices (Akivis and Goldberg 1972, p. 71).</i>
00554  *  http://mathworld.wolfram.com/ZeroMatrix.html
00555  *
00556  *  an empty matrix is also a zero matrix.
00557  *
00558  *  @par Complexity:
00559  *      O(this->rows() * this->columns())
00560  */
00561 template <typename T, typename S>
00562 bool Matrix<T, S>::isZero() const
00563 {
00564     const TSize m = rows();
00565     const TSize n = columns();
00566     for (TSize i = 0; i < m; ++i)
00567     {
00568         for (TSize j = 0; j < n; ++j)
00569         {
00570             if (storage_(i, j) != TNumTraits::zero)
00571             {
00572                 return false;
00573             }
00574         }
00575     }
00576     return true;
00577 }
00578 
00579 
00580 
00581 /** test if this matrix equals a identity matrix
00582  *
00583  *  <i>The identity matrix is a the simplest nontrivial diagonal matrix, defined such that @n I(X)=X
00584  *  for all vectors @n X. An identity matrix may be denoted @n 1, @n I, or @n E (the latter being an
00585  *  abbreviation for the German term "Einheitsmatrix"; Courant and Hilbert 1989, p. 7). Identity
00586  *  matrices are sometimes also known as unit matrices (Akivis and Goldberg 1972, p. 71). The
00587  *  @n n×n identity matrix is given explicitly by @n Iij=dij for @n i, @n j = 1, 2, ..., n, where
00588  *  @n dij is the Kronecker delta.</i>
00589  *  http://mathworld.wolfram.com/IdentityMatrix.html
00590  *
00591  *  an empty matrix is also an identity matrix.
00592  *
00593  *  @par Complexity:
00594  *      O(this->rows() * this->columns())
00595  */
00596 template <typename T, typename S>
00597 bool Matrix<T, S>::isIdentity() const
00598 {
00599     if (!isSquare())
00600     {
00601         return false;
00602     }
00603     const TSize m = rows();
00604     const TSize n = columns();
00605     for (TSize i = 0; i < m; ++i)
00606     {
00607         for (TSize j = 0; j < n; ++j)
00608         {
00609             if (storage_(i, j) != ((i == j) ? TNumTraits::one : TNumTraits::zero))
00610             {
00611                 return false;
00612             }
00613         }
00614     }
00615     return true;
00616 }
00617 
00618 
00619 
00620 /** test if this matrix is an diagonal matrix
00621  *
00622  *  <i>A diagonal matrix is a square matrix @n A of the form @n Aij=Ci*dij where @n dij is the
00623  *  Kronecker delta, @n Ci are constants, and @n i, @n j = 1, 2, ..., n, with is no implied
00624  *  summation over indices.</i>
00625  *  http://mathworld.wolfram.com/DiagonalMatrix.html
00626  *
00627  *  @note both square zero matrices and identity matrices will yield true on this one.
00628  *
00629  *  @par Complexity:
00630  *      O(this->rows() * this->columns())
00631  */
00632 template <typename T, typename S>
00633 bool Matrix<T, S>::isDiagonal() const
00634 {
00635     if (!isSquare())
00636     {
00637         return false;
00638     }
00639     const TSize m = rows();
00640     const TSize n = columns();
00641     for (TSize i = 0; i < m; ++i)
00642     {
00643         for (TSize j = 0; j < n; ++j)
00644         {
00645             if (i != j && storage_(i, j) != TNumTraits::zero)
00646             {
00647                 return false;
00648             }
00649         }
00650     }
00651     return true;
00652 }
00653 
00654 
00655 
00656 /** return true if matrix has as many rows as columns
00657  *
00658  *  @par Complexity:
00659  *      O(1)
00660  */
00661 template <typename T, typename S>
00662 bool Matrix<T, S>::isSquare() const
00663 {
00664     return storage_.rows() == storage_.columns();
00665 }
00666 
00667 
00668 
00669 /** return transposed matrix
00670  *
00671  *  @par Complexity:
00672  *      O(1)
00673  */
00674 template <typename T, typename S>
00675 const Matrix<T, impl::MTrans<T, S> >
00676 Matrix<T, S>::transpose() const
00677 {
00678     typedef impl::MTrans<T, S> TExpression;
00679     return Matrix<T, TExpression>(TExpression(storage_));
00680 }
00681 
00682 
00683 
00684 /** replace matrix by its inverse.
00685  *
00686  *  If matrix has no inverse (this is singular), no exception is thrown.  Instead, an empty matrix
00687  *  is made.
00688  *
00689  *  @pre @c this must be an l-value (storage matrix).
00690  *
00691  *  @result true if succeeded, false if not.
00692  *  @throw an exception is thrown if this is not a square matrix
00693  */
00694 template <typename T, typename S>
00695 bool Matrix<T, S>::invert()
00696 {
00697     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00698     LASS_ENFORCE(isSquare());
00699 
00700     const TSize n = rows();
00701     Matrix<T> lu(*this);
00702     std::vector<size_t> index(n);
00703     int d;
00704 
00705     if (!impl::ludecomp(lu.storage().rowMajor(), index.begin(), n, d))
00706     {
00707         setZero(0, 0);
00708         return false; // empty solution
00709     }
00710 
00711     setIdentity(n);
00712     for (TSize i = 0; i < n; ++i)
00713     {
00714         impl::lusolve(lu.storage().rowMajor(), index.begin(), column(i), n);
00715     }
00716 
00717     return true;
00718 }
00719 
00720 
00721 
00722 template <typename T, typename S> inline
00723 const typename Matrix<T, S>::TStorage&
00724 Matrix<T, S>::storage() const
00725 {
00726     return storage_;
00727 }
00728 
00729 
00730 
00731 template <typename T, typename S> inline
00732 typename Matrix<T, S>::TStorage&
00733 Matrix<T, S>::storage()
00734 {
00735     return storage_;
00736 }
00737 
00738 
00739 
00740 /** swap two matrices
00741  *
00742  *  @pre @c this and @a iOther must be an l-value (storage matrix).
00743  *
00744  *  @par Complexity:
00745  *      O(1)
00746  *
00747  *  @par Exception safety:
00748  *      no-fail
00749  */
00750 template <typename T, typename S> inline
00751 void Matrix<T, S>::swap(Matrix<T, S>& iOther)
00752 {
00753     LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00754     storage_.swap(iOther.storage_);
00755 }
00756 
00757 
00758 
00759 // --- protected -----------------------------------------------------------------------------------
00760 
00761 
00762 
00763 // --- private -------------------------------------------------------------------------------------
00764 
00765 
00766 
00767 // --- free ----------------------------------------------------------------------------------------
00768 
00769 /** @relates lass::num::Matrix
00770  *
00771  *  @par Complexity:
00772  *      O(iA.rows() * iA.columns())
00773  */
00774 template <typename T, typename S1, typename S2>
00775 bool operator==(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00776 {
00777     if (iA.rows() != iB.rows() || iA.columns() != iB.columns())
00778     {
00779         return false;
00780     }
00781     typedef typename Matrix<T, S1>::TSize TSize;
00782     const TSize m = iA.rows();
00783     const TSize n = iA.columns();
00784     for (TSize i = 0; i < m; ++i)
00785     {
00786         for (TSize j = 0; j < n; ++j)
00787         {
00788             if (iA(i, j) != iB(i, j))
00789             {
00790                 return false;
00791             }
00792         }
00793     }
00794     return true;
00795 }
00796 
00797 
00798 
00799 /** @relates lass::num::Matrix
00800  *
00801  *  @par Complexity:
00802  *      O(iA.rows() * iA.columns())
00803  */
00804 template <typename T, typename S1, typename S2>
00805 bool operator!=(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00806 {
00807     return !(iA == iB);
00808 }
00809 
00810 
00811 
00812 /** componentwise addition
00813  *  @relates lass::num::Matrix
00814  *
00815  *  @par Complexity:
00816  *      O(1)
00817  */
00818 template <typename T, typename S1, typename S2>
00819 const Matrix<T, impl::MAdd<T, S1, S2> >
00820 operator+(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00821 {
00822     LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(iA, iB);
00823     typedef impl::MAdd<T, S1, S2> TExpression;
00824     return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00825 }
00826 
00827 
00828 
00829 /** componentwise addition
00830  *  @relates lass::num::Matrix
00831  *
00832  *  @par Complexity:
00833  *      O(1)
00834  */
00835 template <typename T, typename S1, typename S2>
00836 const Matrix<T, impl::MSub<T, S1, S2> >
00837 operator-(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00838 {
00839     LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(iA, iB);
00840     typedef impl::MSub<T, S1, S2> TExpression;
00841     return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00842 }
00843 
00844 
00845 
00846 /** Matrix multiplication
00847  *  @relates lass::num::Matrix
00848  *
00849  *  <i>The product @n C of two matrices @n A and @n B is defined by @n Cik=Aij*Bjk, where @n j is
00850  *  summed over for all possible values of @n i and @n k. The implied summation over repeated
00851  *  indices without the presence of an explicit sum sign is called Einstein summation, and is
00852  *  commonly used in both matrix and tensor analysis. Therefore, in order for matrix multiplication
00853  *  to be defined, the dimensions of the matrices must satisfy @n (n×m)*(m×p)=(n×p) where @n (a×b)
00854  *  denotes a matrix with @n a rows and @n b columns.</i>
00855  *  http://mathworld.wolfram.com/MatrixMultiplication.html
00856  *
00857  *  @throw an exception is throw in @a iA and @a iB don't meet the requirement
00858  *         @n iA.columns()==iB.rows() .
00859  *
00860  *  @par Complexity:
00861  *      O(1)
00862  */
00863 template <typename T, typename S1, typename S2>
00864 const Matrix<T, impl::MProd<T, S1, S2> >
00865 operator*(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00866 {
00867     LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(iA, iB);
00868     typedef impl::MProd<T, S1, S2> TExpression;
00869     return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00870 }
00871 
00872 
00873 
00874 /** add @a iA to all components of @a iB
00875  *  @relates lass::num::Matrix
00876  *
00877  *  @par Complexity:
00878  *      O(1)
00879  */
00880 template <typename T, typename S>
00881 const Matrix<T, impl::MAdd<T, impl::MScalar<T>, S> >
00882 operator+(const T& iA, const Matrix<T, S>& iB)
00883 {
00884     typedef impl::MAdd<T, impl::MScalar<T>, S> TExpression;
00885     return Matrix<T, TExpression>(TExpression(
00886         impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00887 }
00888 
00889 
00890 
00891 /** add @a iA to all negated components of @a iB
00892  *  @relates lass::num::Matrix
00893  *
00894  *  @par Complexity:
00895  *      O(1)
00896  */
00897 template <typename T, typename S>
00898 const Matrix<T, impl::MSub<T, impl::MScalar<T>, S> >
00899 operator-(const T& iA, const Matrix<T, S>& iB)
00900 {
00901     typedef impl::MSub<T, impl::MScalar<T>, S> TExpression;
00902     return Matrix<T, TExpression>(TExpression(
00903         impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00904 }
00905 
00906 
00907 
00908 /** multiply @a iA with all components of @a iB
00909  *  @relates lass::num::Matrix
00910  *
00911  *  @par Complexity:
00912  *      O(1)
00913  */
00914 template <typename T, typename S>
00915 const Matrix<T, impl::MMul<T, impl::MScalar<T>, S> >
00916 operator*(const T& iA, const Matrix<T, S>& iB)
00917 {
00918     typedef impl::MMul<T, impl::MScalar<T>, S> TExpression;
00919     return Matrix<T, TExpression>(TExpression(
00920         impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00921 }
00922 
00923 
00924 
00925 /** add @a iB to all components of @a iA
00926  *  @relates lass::num::Matrix
00927  *
00928  *  @par Complexity:
00929  *      O(1)
00930  */
00931 template <typename T, typename S>
00932 const Matrix<T, impl::MAdd<T, S, impl::MScalar<T> > >
00933 operator+(const Matrix<T, S>& iA, const T& iB)
00934 {
00935     typedef impl::MAdd<T, S, impl::MScalar<T> > TExpression;
00936     return Matrix<T, TExpression>(TExpression(
00937         iA.storage(), impl::MScalar<T>(iB, iA.rows(), iA.cols())));
00938 }
00939 
00940 
00941 
00942 /** subtract @a iB from all components of @a iA
00943  *  @relates lass::num::Matrix
00944  *
00945  *  @par Complexity:
00946  *      O(1)
00947  */
00948 template <typename T, typename S>
00949 const Matrix<T, impl::MAdd<T, S, impl::MScalar<T> > >
00950 operator-(const Matrix<T, S>& iA, const T& iB)
00951 {
00952     typedef impl::MSub<T, S, impl::MScalar<T> > TExpression;
00953     return Matrix<T, TExpression>(TExpression(
00954         iA.storage(), impl::MScalar<T>(-iB, iA.rows(), iA.cols())));
00955 }
00956 
00957 
00958 
00959 /** multiply all components of @a iA with @a iB.
00960  *  @relates lass::num::Matrix
00961  *
00962  *  @par Complexity:
00963  *      O(1)
00964  */
00965 template <typename T, typename S>
00966 const Matrix<T, impl::MMul<T, S, impl::MScalar<T> > >
00967 operator*(const Matrix<T, S>& iA, const T& iB)
00968 {
00969     typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
00970     return Matrix<T, TExpression>(TExpression(
00971         iA.storage(), impl::MScalar<T>(iB, iA.rows(), iA.cols())));
00972 }
00973 
00974 
00975 
00976 /** divide all components of @a iA by @a iB.
00977  *  @relates lass::num::Matrix
00978  *
00979  *  @par Complexity:
00980  *      O(1)
00981  */
00982 template <typename T, typename S>
00983 const Matrix<T, impl::MMul<T, S, impl::MScalar<T> > >
00984 operator/(const Matrix<T, S>& iA, const T& iB)
00985 {
00986     typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
00987     return Matrix<T, TExpression>(TExpression(
00988         iA.storage(), impl::MScalar<T>(Matrix<T, S>::TNumTraits::one / iB, iA.rows(), iA.cols())));
00989 }
00990 
00991 
00992 
00993 /** solve equation A * X = B
00994  *
00995  *  @pre @a ioB must be an l-value (storage matrix).
00996  *
00997  *  @relates lass::num::Matrix
00998  *  @return true if solution is found, false if set has no solution.
00999  *  @throw an exception is thrown if dimensions don't match
01000  *         (this->isSquare() && this->columns() == ioB.rows())
01001  */
01002 template <typename T, typename S, typename S2>
01003 bool solve(const Matrix<T, S>& iA, Matrix<T, S2>& ioB)
01004 {
01005     LASS_META_ASSERT(S2::lvalue, ioB_isnt_an_lvalue);
01006     LASS_ENFORCE(iA.isSquare());
01007     LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(iA, ioB);
01008 
01009     size_t n = iA.rows();
01010     Matrix<T> lu(iA);
01011     std::vector<size_t> index(n);
01012     int d;
01013 
01014     if (!impl::ludecomp<T>(lu.storage().rowMajor(), index.begin(), n, d))
01015     {
01016         ioB.setZero(0, 0);
01017         return false; // empty solution
01018     }
01019 
01020     for (size_t i = 0; i < ioB.columns(); ++i)
01021     {
01022         LASS_ASSERT(static_cast<int>(i) >= 0);
01023         impl::lusolve<T>(lu.storage().rowMajor(), index.begin(), ioB.column(static_cast<int>(i)), n);
01024     }
01025     return true;
01026 }
01027 
01028 
01029 
01030 /** @relates lass::num::Matrix
01031  */
01032 template <typename T, typename S, typename Char, typename Traits>
01033 std::basic_ostream<Char, Traits>&
01034 operator<<(std::basic_ostream<Char, Traits>& oOStream, const Matrix<T, S>& iB)
01035 {
01036     typedef typename Matrix<T, S>::TSize TSize;
01037     const TSize m = iB.rows();
01038     const TSize n = iB.columns();
01039 
01040     LASS_ENFORCE_STREAM(oOStream) << "(";
01041     for (TSize i = 0; i < m; ++i)
01042     {
01043         if (i != 0)
01044         {
01045             LASS_ENFORCE_STREAM(oOStream) << ", ";
01046         }
01047         LASS_ENFORCE_STREAM(oOStream) << "(";
01048         if (n > 0)
01049         {
01050             LASS_ENFORCE_STREAM(oOStream) << iB(i, 0);
01051         }
01052         for (TSize j = 1; j < n; ++j)
01053         {
01054             LASS_ENFORCE_STREAM(oOStream) << ", " << iB(i, j);
01055         }
01056         LASS_ENFORCE_STREAM(oOStream) << ")";
01057     }
01058     LASS_ENFORCE_STREAM(oOStream) << ")";
01059     return oOStream;
01060 }
01061 
01062 
01063 
01064 }
01065 
01066 }
01067 
01068 #endif
01069 
01070 // EOF

Generated on Mon Nov 10 14:20:31 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo