namespace ewalena
0.2.15
ewalena is not an acronym
|
00001 // ------------------------------------------------------------------- 00002 // @author Toby D. Young 00003 // @version $Id: matrix.h 1002 2012-12-04 15:01:40Z oneliefleft $ 00004 // 00005 // Copyright 2012 namespace ewalena authors. All rights reserved. 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions 00009 // are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above 00015 // copyright notice, this list of conditions and the following 00016 // disclaimer in the documentation and/or other materials provided 00017 // with the distribution. 00018 // 00019 // THIS SOFTWARE IS PROVIDED BY THE NAMEPSACE EWALENA AUTHORS ``AS 00020 // IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00022 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00023 // NAMESPACE EWALENA AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00024 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00025 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00026 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00027 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 00028 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 00030 // OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // The views and conclusions contained in the software and 00033 // documentation are those of the authors and should not be 00034 // interpreted as representing official policies, either expressed or 00035 // implied, of the namespace ewalena authors. 00036 // ------------------------------------------------------------------- 00037 00038 #include <cassert> 00039 #include <cstring> 00040 #include <stdlib.h> 00041 #include <iostream> 00042 00043 #ifndef __ewalena_matrix_h 00044 #define __ewalena_matrix_h 00045 00046 #ifdef EWALENA_HAVE_CONFIG_H 00047 #include <ewalena/base/config.h> 00048 #endif 00049 00050 #include <ewalena/base/tensor.h> 00051 #include <ewalena/lac/vector_basis.h> 00052 00053 namespace ewalena 00054 { 00055 00056 template <int, int, typename> class Tensor; 00057 template <typename> class VectorBasis; 00058 00069 template <typename ValueType = double> 00070 class Matrix 00071 { 00072 00073 00074 public: 00075 00079 Matrix (); 00080 00084 ~Matrix (); 00085 00092 explicit Matrix (const unsigned int m, 00093 const unsigned int n, 00094 const bool zero = true); 00095 00100 Matrix (std::pair<const unsigned int, const unsigned int> mn_pair, 00101 const bool zero = true); 00102 00110 template <int dim> 00111 Matrix (const class Tensor<dim, 2, ValueType> &T); 00112 00117 Matrix (const class VectorBasis<ValueType> &V); 00118 00123 Matrix (const Matrix& M); 00124 00128 unsigned int n_rows () const; 00129 00133 unsigned int n_cols () const; 00134 00138 unsigned int size () const; 00139 00144 void reinit (const unsigned int m, 00145 const unsigned int n, 00146 const bool zero = true); 00147 00151 void reinit (); 00152 00157 ValueType& operator () (const unsigned int i, 00158 const unsigned int j); 00159 00164 const ValueType& operator () (const unsigned int i, 00165 const unsigned int j) const; 00166 00170 void invert (const Matrix<ValueType> &M); 00171 00176 void mult (const Matrix<ValueType> &M_a, 00177 const Matrix<ValueType> &M_b); 00178 00183 void Tmult (const Matrix<ValueType> &M_a, 00184 const Matrix<ValueType> &M_b); 00185 00190 void multT (const Matrix<ValueType> &M_a, 00191 const Matrix<ValueType> &M_b); 00192 00197 void identity (); 00198 00202 ValueType norm (); 00203 00208 void operator += (const Matrix<ValueType> &M); 00209 00214 void operator -= (const Matrix<ValueType> &M); 00215 00220 void operator *= (const ValueType &scalar); 00221 00226 void operator /= (const ValueType &scalar); 00227 00231 void operator = (const Matrix<ValueType> &M); 00232 00237 bool operator == (const Matrix<ValueType> &M) const; 00238 00243 bool is_symmetric () const; 00244 00248 friend std::ostream& operator << (std::ostream &output, 00249 const Matrix<ValueType> &M) 00250 { 00251 for (unsigned int i=0; i<M.n_rows ()*M.n_cols (); ++i) 00252 00253 /* Try to pretty print */ 00254 (M.data[i]<(ValueType) 0.) 00255 ? 00256 output << M.data[i] << " " 00257 : 00258 output << " " 00259 << M.data[i] << " "; 00260 00261 return output; 00262 } 00263 00264 protected: 00265 00270 inline 00271 const 00272 ValueType* operator* () const 00273 { 00274 return (*this).data; 00275 } 00276 00281 inline 00282 ValueType* operator* () 00283 { 00284 return (*this).data; 00285 } 00286 00287 private: 00288 00294 unsigned int __n_rows; 00295 00301 unsigned int __n_cols; 00302 00307 ValueType* data; 00308 00309 }; /* Matrix */ 00310 00311 /*-------------- Inline and Other Functions -----------------------*/ 00312 00313 template <typename ValueType> 00314 inline 00315 const ValueType& 00316 Matrix<ValueType>::operator () (const unsigned int i, 00317 const unsigned int j) const 00318 { 00319 assert (i<__n_rows); 00320 assert (j<__n_cols); 00321 00322 /* return data[ index[0].begin () + i*index[0].increment () */ 00323 /* + */ 00324 /* n_rows*(index[1].begin () + j*index[1].increment ()) ]; */ 00325 00326 return data[__n_cols*i+j]; 00327 } 00328 00329 template <typename ValueType> 00330 inline 00331 ValueType& 00332 Matrix<ValueType>::operator () (const unsigned int i, 00333 const unsigned int j) 00334 { 00335 assert (i<__n_rows); 00336 assert (j<__n_cols); 00337 00338 return data[__n_cols*i+j]; 00339 } 00340 00341 template <typename ValueType> 00342 inline 00343 unsigned int 00344 Matrix<ValueType>::n_rows () const 00345 { 00346 return this->__n_rows; 00347 } 00348 00349 template <typename ValueType> 00350 inline 00351 unsigned int 00352 Matrix<ValueType>::n_cols () const 00353 { 00354 return this->__n_cols; 00355 } 00356 00357 template <typename ValueType> 00358 inline 00359 unsigned int 00360 Matrix<ValueType>::size () const 00361 { 00362 return (this->__n_rows)*(this->__n_cols); 00363 } 00364 00365 template <typename ValueType> 00366 inline 00367 void 00368 Matrix<ValueType>::operator += (const Matrix<ValueType> &M) 00369 { 00370 assert (M.__n_rows == this->__n_rows); 00371 assert (M.__n_cols == this->__n_cols); 00372 00373 for (unsigned int i=0; i<__n_rows*__n_cols; ++i) 00374 data[i] += M.data[i]; 00375 } 00376 00377 template <typename ValueType> 00378 inline 00379 void 00380 Matrix<ValueType>::operator -= (const Matrix<ValueType> &M) 00381 { 00382 assert (M.__n_rows == this->__n_rows); 00383 assert (M.__n_cols == this->__n_cols); 00384 00385 for (unsigned int i=0; i<__n_rows*__n_cols; ++i) 00386 data[i] -= M.data[i]; 00387 } 00388 00389 template <typename ValueType> 00390 inline 00391 void 00392 Matrix<ValueType>::operator *= (const ValueType &scalar) 00393 { 00394 for (unsigned int i=0; i<__n_rows*__n_cols; ++i) 00395 data[i] *= scalar; 00396 } 00397 00398 template <typename ValueType> 00399 inline 00400 void 00401 Matrix<ValueType>::operator /= (const ValueType &scalar) 00402 { 00403 for (unsigned int i=0; i<__n_rows*__n_cols; ++i) 00404 data[i] /= scalar; 00405 } 00406 00407 template <typename ValueType> 00408 void 00409 Matrix<ValueType>::operator = (const Matrix<ValueType> &M) 00410 { 00411 assert (M.data); 00412 00413 assert (M.__n_rows == this->__n_rows); 00414 assert (M.__n_cols == this->__n_cols); 00415 00416 for (unsigned int i=0; i<__n_rows; ++i) 00417 for (unsigned int j=0; j<__n_cols; ++j) 00418 (*this)(i,j) = M(i,j); 00419 } 00420 00421 template <typename ValueType> 00422 inline 00423 bool 00424 Matrix<ValueType>::operator == (const Matrix<ValueType> &M) const 00425 { 00426 assert (M.__n_rows == this->__n_rows); 00427 assert (M.__n_cols == this->__n_cols); 00428 00429 return static_cast<bool> (!std::memcmp (this->data, M.data, sizeof(ValueType)*(__n_rows*__n_cols))); 00430 } 00431 00432 template <typename ValueType> 00433 inline 00434 bool 00435 Matrix<ValueType>::is_symmetric () const 00436 { 00437 assert (this->data); 00438 assert (__n_rows == __n_cols); 00439 00440 /* The matrix is trivially symmetric if it has zero size. */ 00441 if (data) 00442 for (unsigned int i=0; i<__n_rows; ++i) 00443 for (unsigned int j=i+1; j<__n_cols; ++j) 00444 if ((*this)(i,j) != (*this)(j,i)) 00445 return false; 00446 00447 return true; 00448 } 00449 00450 template <typename ValueType> 00451 inline 00452 void 00453 Matrix<ValueType>::identity () 00454 { 00455 /* An identity matrix is always a square matrix. */ 00456 assert (this->__n_rows == this->__n_cols); 00457 this->reinit (); 00458 00459 /* If the matrix is zero size - there is nothing to do. */ 00460 if (__n_rows==0) 00461 return; 00462 00463 /* This is a cyclic counter that runs one past the length of a 00464 column; ie. where 1 appears cyclicly in an identity 00465 matrix. */ 00466 unsigned int j = __n_rows+1; 00467 00468 for (unsigned int i=0; i<(__n_rows*__n_cols); ++i, ++j) 00469 { 00470 if (j==__n_rows+1) 00471 { 00472 this->data[i] = ValueType(1); 00473 j=0; 00474 } 00475 } 00476 } 00477 00478 template <typename ValueType> 00479 inline 00480 ValueType 00481 Matrix<ValueType>::norm () 00482 { 00483 assert (this->data); 00484 00485 ValueType scalar = ValueType(0); 00486 00487 for (unsigned int i=0; i<(this->__n_rows)*(this->__n_cols); ++i) 00488 scalar += std::fabs (this->data[i]); 00489 00490 return scalar; 00491 } 00492 00493 template <typename ValueType> 00494 inline 00495 void 00496 Matrix<ValueType>::mult (const Matrix<ValueType> &M_a, 00497 const Matrix<ValueType> &M_b) 00498 { 00499 assert (M_a.data); 00500 assert (M_b.data); 00501 00502 assert (M_a.__n_rows == M_b.__n_cols); 00503 assert (M_a.__n_cols == M_b.__n_rows); 00504 00505 for (unsigned int i=0; i<M_a.__n_rows; ++i) 00506 for (unsigned int j=0; j<M_b.__n_cols; ++j) 00507 for (unsigned int k=0; k<M_b.__n_rows; ++k) 00508 (*this)(i,j) += M_a(i,k)*M_b(k,j); 00509 } 00510 00511 template <typename ValueType> 00512 inline 00513 void 00514 Matrix<ValueType>::Tmult (const Matrix<ValueType> &M_a, 00515 const Matrix<ValueType> &M_b) 00516 { 00517 assert (M_a.data); 00518 assert (M_b.data); 00519 00520 assert (M_a.__n_rows == M_b.__n_rows); 00521 assert (M_a.__n_cols == M_b.__n_cols); 00522 00523 for (unsigned int i=0; i<M_a.__n_rows; ++i) 00524 for (unsigned int j=0; j<M_b.__n_cols; ++j) 00525 for (unsigned int k=0; k<M_b.__n_rows; ++k) 00526 (*this)(i,j) += M_a(k,i)*M_b(k,j); 00527 } 00528 00529 template <typename ValueType> 00530 inline 00531 void 00532 Matrix<ValueType>::multT (const Matrix<ValueType> &M_a, 00533 const Matrix<ValueType> &M_b) 00534 { 00535 assert (M_a.data); 00536 assert (M_b.data); 00537 00538 assert (M_a.__n_rows == M_b.__n_rows); 00539 assert (M_a.__n_cols == M_b.__n_cols); 00540 00541 for (unsigned int i=0; i<M_a.__n_rows; ++i) 00542 for (unsigned int j=0; j<M_b.__n_cols; ++j) 00543 for (unsigned int k=0; k<M_b.__n_rows; ++k) 00544 (*this)(i,j) += M_a(i,k)*M_b(j,k); 00545 } 00546 00547 /*-------------- Template and Other Functions ---------------------*/ 00548 00549 template <typename ValueType> 00550 template <int dim> 00551 Matrix<ValueType>::Matrix (const Tensor<dim, 2, ValueType> &T) 00552 { 00553 00554 /* @todo: Generalise this for rank \neq 2. */ 00555 __n_rows = dim; 00556 __n_cols = dim; 00557 data = new ValueType[__n_rows*__n_cols]; 00558 00559 if ((__n_rows != 0) && (__n_cols !=0)) 00560 std::memcpy (this->data, *T, sizeof(ValueType)*(__n_rows*__n_cols)); 00561 } 00562 00563 template <typename ValueType> 00564 Matrix<ValueType>::Matrix (const VectorBasis<ValueType> &V) 00565 { 00566 __n_rows = V.n_rows (); 00567 __n_cols = V.size (); 00568 data = new ValueType[__n_rows*__n_cols]; 00569 00570 if ((__n_rows != 0) && (__n_cols !=0)) 00571 std::memcpy (this->data, *V, sizeof(ValueType)*(__n_rows*__n_cols)); 00572 } 00573 00574 template <typename ValueType> 00575 inline 00576 void 00577 Matrix<ValueType>::invert (const Matrix<ValueType> &M) 00578 { 00579 assert (M.data); 00580 assert (M.__n_rows==M.__n_cols); 00581 00582 this->reinit (M.__n_rows,M.__n_cols); 00583 00584 switch (M.__n_cols) 00585 { 00586 case 0: 00587 { 00588 /* Undefined operation. */ 00589 assert (false); 00590 } 00591 00592 case 1: 00593 { 00594 assert (M(0,0)!=ValueType (0)); 00595 (*this)(0,0) = ValueType (1) / M(0,0); 00596 break; 00597 } 00598 00599 case 2: 00600 { 00601 const ValueType determinant = M(0,0)*M(1,1) - M(0,1)*M(1,0); 00602 assert (determinant!=ValueType (0)); 00603 00604 (*this)(0,0) = M(1,1) / determinant; 00605 (*this)(0,1) = -M(0,1) / determinant; 00606 (*this)(1,0) = -M(1,0) / determinant; 00607 (*this)(1,1) = M(0,0) / determinant; 00608 00609 break; 00610 } 00611 00612 case 3: 00613 { 00614 const ValueType determinant 00615 = M(0,0)*(M(2,2)*M(1,1) - M(2,1)*M(1,2)) 00616 - M(1,0)*(M(2,2)*M(0,1) - M(2,1)*M(0,2)) 00617 + M(2,0)*(M(1,2)*M(0,1) - M(1,1)*M(0,2)); 00618 assert (determinant!=ValueType (0)); 00619 00620 (*this)(0,0) = (M(2,2)*M(1,1) - M(2,1)*M(1,2)) / determinant; 00621 (*this)(0,1) = - (M(2,2)*M(0,1) - M(2,1)*M(0,2)) / determinant; 00622 (*this)(0,2) = (M(1,2)*M(0,1) - M(1,1)*M(0,2)) / determinant; 00623 00624 (*this)(1,0) = - (M(2,2)*M(1,0) - M(2,0)*M(1,2)) / determinant; 00625 (*this)(1,1) = (M(2,2)*M(0,0) - M(2,0)*M(0,2)) / determinant; 00626 (*this)(1,2) = - (M(1,2)*M(0,0) - M(1,0)*M(0,2)) / determinant; 00627 00628 (*this)(2,0) = (M(2,1)*M(1,0) - M(2,0)*M(1,1)) / determinant; 00629 (*this)(2,1) = - (M(2,1)*M(0,0) - M(2,0)*M(0,1)) / determinant; 00630 (*this)(2,2) = (M(1,1)*M(0,0) - M(1,0)*M(0,1)) / determinant; 00631 00632 break; 00633 00634 } 00635 00636 /* This is not likely to work well for big or even medium 00637 sized matrices - so don't do it. */ 00638 default: 00639 assert (false); 00640 } 00641 00642 } 00643 00644 } /* namespace ewalena */ 00645 00646 #endif /* __ewalena_matrix_h */ 00647