Scythe-1.0.3
|
00001 /* 00002 * Scythe Statistical Library Copyright (C) 2000-2002 Andrew D. Martin 00003 * and Kevin M. Quinn; 2002-present Andrew D. Martin, Kevin M. Quinn, 00004 * and Daniel Pemstein. All Rights Reserved. 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify under the terms of the GNU General Public License as 00008 * published by Free Software Foundation; either version 2 of the 00009 * License, or (at your option) any later version. See the text files 00010 * COPYING and LICENSE, distributed with this source code, for further 00011 * information. 00012 * -------------------------------------------------------------------- 00013 * scythe's/matrix.h 00014 * 00015 */ 00016 00044 #ifndef SCYTHE_MATRIX_H 00045 #define SCYTHE_MATRIX_H 00046 00047 #include <climits> 00048 #include <iostream> 00049 #include <iomanip> 00050 #include <string> 00051 #include <sstream> 00052 #include <fstream> 00053 #include <iterator> 00054 #include <algorithm> 00055 //#include <numeric> 00056 #include <functional> 00057 #include <list> 00058 00059 #ifdef SCYTHE_COMPILE_DIRECT 00060 #include "defs.h" 00061 #include "algorithm.h" 00062 #include "error.h" 00063 #include "datablock.h" 00064 #include "matrix_random_access_iterator.h" 00065 #include "matrix_forward_iterator.h" 00066 #include "matrix_bidirectional_iterator.h" 00067 #ifdef SCYTHE_LAPACK 00068 #include "lapack.h" 00069 #endif 00070 #else 00071 #include "scythestat/defs.h" 00072 #include "scythestat/algorithm.h" 00073 #include "scythestat/error.h" 00074 #include "scythestat/datablock.h" 00075 #include "scythestat/matrix_random_access_iterator.h" 00076 #include "scythestat/matrix_forward_iterator.h" 00077 #include "scythestat/matrix_bidirectional_iterator.h" 00078 #ifdef SCYTHE_LAPACK 00079 #include "scythestat/lapack.h" 00080 #endif 00081 #endif 00082 00083 namespace scythe { 00084 00085 namespace { // make the uint typedef local to this file 00086 /* Convenience typedefs */ 00087 typedef unsigned int uint; 00088 } 00089 00090 /* Forward declare the matrix multiplication functions for *= to use 00091 * within Matrix proper . 00092 */ 00093 00094 template <typename T_type, matrix_order ORDER, matrix_style STYLE, 00095 matrix_order L_ORDER, matrix_style L_STYLE, 00096 matrix_order R_ORDER, matrix_style R_STYLE> 00097 Matrix<T_type, ORDER, STYLE> 00098 operator* (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, 00099 const Matrix<T_type, R_ORDER, R_STYLE>& rhs); 00100 00101 00102 template <matrix_order L_ORDER, matrix_style L_STYLE, 00103 matrix_order R_ORDER, matrix_style R_STYLE, typename T_type> 00104 Matrix<T_type, L_ORDER, Concrete> 00105 operator* (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, 00106 const Matrix<T_type, R_ORDER, R_STYLE>& rhs); 00107 00108 /* forward declaration of the matrix class */ 00109 template <typename T_type, matrix_order ORDER, matrix_style STYLE> 00110 class Matrix; 00111 00152 template<typename T_elem, typename T_iter, 00153 matrix_order O, matrix_style S> 00154 class ListInitializer { 00155 // An unbound friend 00156 template <class T, matrix_order OO, matrix_style SS> 00157 friend class Matrix; 00158 00159 public: 00160 ListInitializer (T_elem val, T_iter begin, T_iter end, 00161 Matrix<T_elem,O,S>* matrix) 00162 : vals_ (), 00163 iter_ (begin), 00164 end_ (end), 00165 matrix_ (matrix), 00166 populated_ (false) 00167 { 00168 vals_.push_back(val); 00169 } 00170 00171 ~ListInitializer () 00172 { 00173 if (! populated_) 00174 populate(); 00175 } 00176 00177 ListInitializer &operator, (T_elem x) 00178 { 00179 vals_.push_back(x); 00180 return *this; 00181 } 00182 00183 private: 00184 void populate () 00185 { 00186 typename std::list<T_elem>::iterator vi = vals_.begin(); 00187 00188 while (iter_ < end_) { 00189 if (vi == vals_.end()) 00190 vi = vals_.begin(); 00191 *iter_ = *vi; 00192 ++iter_; ++vi; 00193 } 00194 00195 populated_ = true; 00196 } 00197 00198 std::list<T_elem> vals_; 00199 T_iter iter_; 00200 T_iter end_; 00201 Matrix<T_elem, O, S>* matrix_; 00202 bool populated_; 00203 }; 00204 00219 template <matrix_order ORDER = Col, matrix_style STYLE = Concrete> 00220 class Matrix_base 00221 { 00222 protected: 00223 /**** CONSTRUCTORS ****/ 00224 00225 /* Default constructor */ 00226 Matrix_base () 00227 : rows_ (0), 00228 cols_ (0), 00229 rowstride_ (0), 00230 colstride_ (0), 00231 storeorder_ (ORDER) 00232 {} 00233 00234 /* Standard constructor */ 00235 Matrix_base (uint rows, uint cols) 00236 : rows_ (rows), 00237 cols_ (cols), 00238 storeorder_ (ORDER) 00239 { 00240 if (ORDER == Col) { 00241 rowstride_ = 1; 00242 colstride_ = rows; 00243 } else { 00244 rowstride_ = cols; 00245 colstride_ = 1; 00246 } 00247 } 00248 00249 /* Copy constructors 00250 * 00251 * The first version handles matrices of the same order and 00252 * style. The second handles matrices with different 00253 * orders/styles. The same- templates are more specific, 00254 * so they will always catch same- cases. 00255 * 00256 */ 00257 00258 Matrix_base (const Matrix_base &m) 00259 : rows_ (m.rows()), 00260 cols_ (m.cols()), 00261 rowstride_ (m.rowstride()), 00262 colstride_ (m.colstride()) 00263 { 00264 if (STYLE == View) 00265 storeorder_ = m.storeorder(); 00266 else 00267 storeorder_ = ORDER; 00268 } 00269 00270 template <matrix_order O, matrix_style S> 00271 Matrix_base (const Matrix_base<O, S> &m) 00272 : rows_ (m.rows()), 00273 cols_ (m.cols()) 00274 { 00275 if (STYLE == View) { 00276 storeorder_ = m.storeorder(); 00277 rowstride_ = m.rowstride(); 00278 colstride_ = m.colstride(); 00279 } else { 00280 storeorder_ = ORDER; 00281 if (ORDER == Col) { 00282 rowstride_ = 1; 00283 colstride_ = rows_; 00284 } else { 00285 rowstride_ = cols_; 00286 colstride_ = 1; 00287 } 00288 } 00289 } 00290 00291 /* Submatrix constructor */ 00292 template <matrix_order O, matrix_style S> 00293 Matrix_base (const Matrix_base<O, S> &m, 00294 uint x1, uint y1, uint x2, uint y2) 00295 : rows_ (x2 - x1 + 1), 00296 cols_ (y2 - y1 + 1), 00297 rowstride_ (m.rowstride()), 00298 colstride_ (m.colstride()), 00299 storeorder_ (m.storeorder()) 00300 { 00301 /* Submatrices always have to be views, but the whole 00302 * concrete-view thing is just a policy maintained by the 00303 * software. Therefore, we need to ensure this constructor 00304 * only returns views. There's no neat way to do it but this 00305 * is still a compile time check, even if it only reports at 00306 * run-time. Of course, we should never get this far. 00307 */ 00308 if (STYLE == Concrete) { 00309 SCYTHE_THROW(scythe_style_error, 00310 "Tried to construct a concrete submatrix (Matrix_base)!"); 00311 } 00312 } 00313 00314 00315 /**** DESTRUCTOR ****/ 00316 00317 ~Matrix_base () 00318 {} 00319 00320 /**** OPERRATORS ****/ 00321 00322 // I'm defining one just to make sure we don't get any subtle 00323 // bugs from defaults being called. 00324 Matrix_base& operator=(const Matrix_base& m) 00325 { 00326 SCYTHE_THROW(scythe_unexpected_default_error, 00327 "Unexpected call to Matrix_base default assignment operator"); 00328 } 00329 00330 /**** MODIFIERS ****/ 00331 00332 /* Make this Matrix_base an exact copy of the matrix passed in. 00333 * Just like an assignment operator but can be called from a derived 00334 * class w/out making the = optor public and doing something 00335 * like 00336 * *(dynamic_cast<Matrix_base *> (this)) = M; 00337 * in the derived class. 00338 * 00339 * Works across styles, but should be used with care 00340 */ 00341 template <matrix_order O, matrix_style S> 00342 inline void mimic (const Matrix_base<O, S> &m) 00343 { 00344 rows_ = m.rows(); 00345 cols_ = m.cols(); 00346 rowstride_ = m.rowstride(); 00347 colstride_ = m.colstride(); 00348 storeorder_ = m.storeorder(); 00349 } 00350 00351 /* Reset the dimensions of this Matrix_base. 00352 * 00353 * TODO This function is a bit of an interface weakness. It 00354 * assumes a resize always means a fresh matrix (concrete or 00355 * view) with no slack between dims and strides. This happens to 00356 * always be the case when it is called, but it tightly couples 00357 * Matrix_base and extending classes. Not a big issue (since 00358 * Matrix is probably the only class that will ever extend this) 00359 * but something to maybe fix down the road. 00360 */ 00361 inline void resize (uint rows, uint cols) 00362 { 00363 rows_ = rows; 00364 cols_ = cols; 00365 00366 if (ORDER == Col) { 00367 rowstride_ = 1; 00368 colstride_ = rows; 00369 } else { 00370 rowstride_ = cols; 00371 colstride_ = 1; 00372 } 00373 00374 storeorder_ = ORDER; 00375 } 00376 00377 public: 00378 /**** ACCESSORS ****/ 00379 00386 inline uint size () const 00387 { 00388 return (rows() * cols()); 00389 } 00390 00396 inline uint rows() const 00397 { 00398 return rows_; 00399 } 00400 00406 inline uint cols () const 00407 { 00408 return cols_; 00409 } 00410 00418 inline matrix_order order() const 00419 { 00420 return ORDER; 00421 } 00422 00430 inline matrix_style style() const 00431 { 00432 return STYLE; 00433 } 00434 00447 inline matrix_order storeorder () const 00448 { 00449 return storeorder_; 00450 } 00451 00458 inline uint rowstride () const 00459 { 00460 return rowstride_; 00461 } 00462 00469 inline uint colstride () const 00470 { 00471 return colstride_; 00472 } 00473 00481 inline uint max_size () const 00482 { 00483 return UINT_MAX; 00484 } 00485 00490 inline bool isScalar () const 00491 { 00492 return (rows() == 1 && cols() == 1); 00493 } 00494 00500 inline bool isRowVector () const 00501 { 00502 return (rows() == 1); 00503 } 00504 00510 inline bool isColVector () const 00511 { 00512 return (cols() == 1); 00513 } 00514 00520 inline bool isVector () const 00521 { 00522 return (cols() == 1 || rows() == 1); 00523 } 00524 00532 inline bool isSquare () const 00533 { 00534 return (cols() == rows()); 00535 } 00536 00542 inline bool isNull () const 00543 { 00544 return (rows() == 0); 00545 } 00546 00554 inline bool empty () const 00555 { 00556 return (rows() == 0); 00557 } 00558 00559 00560 /**** HELPERS ****/ 00561 00576 inline bool inRange (uint i) const 00577 { 00578 return (i < size()); 00579 } 00580 00596 inline bool inRange (uint i, uint j) const 00597 { 00598 return (i < rows() && j < cols()); 00599 } 00600 00601 protected: 00602 /* These methods take offsets into a matrix and convert them 00603 * into that actual position in the referenced memory block, 00604 * taking stride into account. Protection is debatable. They 00605 * could be useful to outside functions in the library but most 00606 * callers should rely on the public () operator in the derived 00607 * class or iterators. 00608 * 00609 * Note that these are very fast for concrete matrices but not 00610 * so great for views. Of course, the type checks are done at 00611 * compile time. 00612 */ 00613 00614 /* Turn an index into a true offset into the data. */ 00615 inline uint index (uint i) const 00616 { 00617 if (STYLE == View) { 00618 if (ORDER == Col) { 00619 uint col = i / rows(); 00620 uint row = i % rows(); 00621 return (index(row, col)); 00622 } else { 00623 uint row = i / cols(); 00624 uint col = i % cols(); 00625 return (index(row, col)); 00626 } 00627 } else 00628 return(i); 00629 } 00630 00631 /* Turn an i, j into an index. */ 00632 inline uint index (uint row, uint col) const 00633 { 00634 if (STYLE == Concrete) { 00635 if (ORDER == Col) 00636 return (col * rows() + row); 00637 else 00638 return (row * cols() + col); 00639 } else { // view 00640 if (storeorder_ == Col) 00641 return (col * colstride() + row); 00642 else 00643 return (row * rowstride() + col); 00644 } 00645 } 00646 00647 00648 /**** INSTANCE VARIABLES ****/ 00649 protected: 00650 uint rows_; // # of rows 00651 uint cols_; // # of cols 00652 00653 private: 00654 /* The derived class shouldn't have to worry about this 00655 * implementation detail. 00656 */ 00657 uint rowstride_; // the in-memory number of elements from the 00658 uint colstride_; // beginning of one column(row) to the next 00659 matrix_order storeorder_; // The in-memory storage order of this 00660 // matrix. This will always be the 00661 // same as ORDER for concrete 00662 // matrices but views can look at 00663 // matrices with storage orders that 00664 // differ from their own. 00665 // TODO storeorder is always known at 00666 // compile time, so we could probably 00667 // add a third template param to deal 00668 // with this. That would speed up 00669 // views a touch. Bit messy maybe. 00670 }; 00671 00672 /**** MATRIX CLASS ****/ 00673 00791 template <typename T_type = double, matrix_order ORDER = Col, 00792 matrix_style STYLE = Concrete> 00793 class Matrix : public Matrix_base<ORDER, STYLE>, 00794 public DataBlockReference<T_type> 00795 { 00796 public: 00797 /**** TYPEDEFS ****/ 00798 00799 /* Iterator types */ 00800 00819 typedef matrix_random_access_iterator<T_type, ORDER, ORDER, STYLE> 00820 iterator; 00821 00840 typedef const_matrix_random_access_iterator<T_type, ORDER, ORDER, 00841 STYLE> const_iterator; 00842 00861 typedef typename 00862 std::reverse_iterator<matrix_random_access_iterator<T_type, 00863 ORDER, ORDER, STYLE> > reverse_iterator; 00864 00883 typedef typename 00884 std::reverse_iterator<const_matrix_random_access_iterator 00885 <T_type, ORDER, ORDER, STYLE> > 00886 const_reverse_iterator; 00887 00906 typedef matrix_forward_iterator<T_type, ORDER, ORDER, STYLE> 00907 forward_iterator; 00908 00928 typedef const_matrix_forward_iterator<T_type, ORDER, ORDER, STYLE> 00929 const_forward_iterator; 00930 00950 typedef matrix_bidirectional_iterator<T_type, ORDER, ORDER, STYLE> 00951 bidirectional_iterator; 00952 00972 typedef const_matrix_bidirectional_iterator<T_type, ORDER, ORDER, 00973 STYLE> const_bidirectional_iterator; 00974 00993 typedef typename 00994 std::reverse_iterator<matrix_bidirectional_iterator<T_type, 00995 ORDER, ORDER, STYLE> > reverse_bidirectional_iterator; 00996 01015 typedef typename 01016 std::reverse_iterator<const_matrix_bidirectional_iterator 01017 <T_type, ORDER, ORDER, STYLE> > 01018 const_reverse_bidirectional_iterator; 01019 01025 typedef T_type ttype; 01026 01027 private: 01028 /* Some convenience typedefs */ 01029 typedef DataBlockReference<T_type> DBRef; 01030 typedef Matrix_base<ORDER, STYLE> Base; 01031 01032 public: 01033 /**** CONSTRUCTORS ****/ 01034 01054 Matrix () 01055 : Base (), 01056 DBRef () 01057 { 01058 } 01059 01080 Matrix (T_type element) 01081 : Base (1, 1), 01082 DBRef (1) 01083 { 01084 data_[Base::index(0)] = element; // ALWAYS use index() 01085 } 01086 01114 Matrix (uint rows, uint cols, bool fill = true, 01115 T_type fill_value = 0) 01116 : Base (rows, cols), 01117 DBRef (rows * cols) 01118 { 01119 // TODO Might use iterator here for abstraction. 01120 if (fill) 01121 for (uint i = 0; i < Base::size(); ++i) 01122 data_[Base::index(i)] = fill_value; // we know data contig 01123 } 01124 01153 template <typename T_iterator> 01154 Matrix (uint rows, uint cols, T_iterator it) 01155 : Base (rows, cols), 01156 DBRef (rows * cols) 01157 { 01158 // TODO again, should probably use iterator 01159 for (uint i = 0; i < Base::size(); ++i) { 01160 data_[Base::index(i)] = *it; // we know data_ is contig 01161 ++it; 01162 } 01163 } 01164 01194 Matrix (const std::string& path, bool oldstyle=false) 01195 : Base (), 01196 DBRef () 01197 { 01198 std::ifstream file(path.c_str()); 01199 SCYTHE_CHECK_10(! file, scythe_file_error, 01200 "Could not open file " << path); 01201 01202 if (oldstyle) { 01203 uint rows, cols; 01204 file >> rows >> cols; 01205 resize(rows, cols); 01206 std::copy(std::istream_iterator<T_type> (file), 01207 std::istream_iterator<T_type>(), begin_f<Row>()); 01208 } else { 01209 std::string row; 01210 01211 unsigned int cols = -1; 01212 std::vector<std::vector<T_type> > vals; 01213 unsigned int rows = 0; 01214 while (std::getline(file, row)) { 01215 std::vector<T_type> column; 01216 std::istringstream rowstream(row); 01217 std::copy(std::istream_iterator<T_type> (rowstream), 01218 std::istream_iterator<T_type>(), 01219 std::back_inserter(column)); 01220 01221 if (cols == -1) 01222 cols = (unsigned int) column.size(); 01223 01224 SCYTHE_CHECK_10(cols != column.size(), scythe_file_error, 01225 "Row " << (rows + 1) << " of input file has " 01226 << column.size() << " elements, but should have " << cols); 01227 01228 vals.push_back(column); 01229 rows++; 01230 } 01231 01232 resize(rows, cols); 01233 for (unsigned int i = 0; i < rows; ++i) 01234 operator()(i, _) = Matrix<T_type>(1, cols, vals[i].begin()); 01235 } 01236 } 01237 01238 /* Copy constructors. Uses template args to set up correct 01239 * behavior for both concrete and view matrices. The branches 01240 * are no-ops and get optimized away at compile time. 01241 * 01242 * We have to define this twice because we must explicitly 01243 * override the default copy constructor; otherwise it is the 01244 * most specific template in a lot of cases and causes ugliness. 01245 */ 01246 01274 Matrix (const Matrix& M) 01275 : Base (M), // this call deals with concrete-view conversions 01276 DBRef () 01277 { 01278 if (STYLE == Concrete) { 01279 this->referenceNew(M.size()); 01280 scythe::copy<ORDER,ORDER>(M, *this); 01281 } else // STYLE == View 01282 this->referenceOther(M); 01283 } 01284 01320 template <matrix_order O, matrix_style S> 01321 Matrix (const Matrix<T_type, O, S> &M) 01322 : Base (M), // this call deals with concrete-view conversions 01323 DBRef () 01324 { 01325 if (STYLE == Concrete) { 01326 this->referenceNew(M.size()); 01327 scythe::copy<ORDER,ORDER> (M, *this); 01328 } else // STYLE == View 01329 this->referenceOther(M); 01330 } 01331 01363 template <typename S_type, matrix_order O, matrix_style S> 01364 Matrix (const Matrix<S_type, O, S> &M) 01365 : Base(M), // this call deal with concrete-view conversions 01366 DBRef (M.size()) 01367 { 01368 scythe::copy<ORDER,ORDER> (M, *this); 01369 } 01370 01411 template <matrix_order O, matrix_style S> 01412 Matrix (const Matrix<T_type, O, S> &M, 01413 uint x1, uint y1, uint x2, uint y2) 01414 : Base(M, x1, y1, x2, y2), 01415 DBRef(M, Base::index(x1, y1)) 01416 { 01417 /* Submatrices always have to be views, but the whole 01418 * concrete-view thing is just a policy maintained by the 01419 * software. Therefore, we need to ensure this constructor 01420 * only returns views. There's no neat way to do it but this 01421 * is still a compile time check, even if it only reports at 01422 * run-time. 01423 */ 01424 if (STYLE == Concrete) { 01425 SCYTHE_THROW(scythe_style_error, 01426 "Tried to construct a concrete submatrix (Matrix)!"); 01427 } 01428 } 01429 01430 public: 01431 /**** DESTRUCTOR ****/ 01432 01435 ~Matrix() {} 01436 01437 /**** COPY/REFERENCE METHODS ****/ 01438 01439 /* Make this matrix a view of another's data. If this matrix's 01440 * previous datablock is not viewed by any other object it is 01441 * deallocated. Concrete matrices cannot be turned into views 01442 * at run-time! Therefore, we generate an error here if *this 01443 * is concrete. 01444 */ 01445 01470 template <matrix_order O, matrix_style S> 01471 inline void reference (const Matrix<T_type, O, S> &M) 01472 { 01473 if (STYLE == Concrete) { 01474 SCYTHE_THROW(scythe_style_error, 01475 "Concrete matrices cannot reference other matrices"); 01476 } else { 01477 this->referenceOther(M); 01478 this->mimic(M); 01479 } 01480 } 01481 01500 inline Matrix<T_type, ORDER, Concrete> copy () const 01501 { 01502 Matrix<T_type, ORDER> res (Base::rows(), Base::cols(), false); 01503 std::copy(begin_f(), end_f(), res.begin_f()); 01504 01505 return res; 01506 } 01507 01508 /* Make this matrix a copy of another. The matrix retains its 01509 * own order and style in this case, because that can't change 01510 * at run time. 01511 */ 01534 template <matrix_order O, matrix_style S> 01535 inline void copy (const Matrix<T_type, O, S>& M) 01536 { 01537 resize2Match(M); 01538 scythe::copy<ORDER,ORDER> (M, *this); 01539 } 01540 01541 /**** INDEXING OPERATORS ****/ 01542 01560 inline T_type& operator[] (uint i) 01561 { 01562 SCYTHE_CHECK_30 (! Base::inRange(i), scythe_bounds_error, 01563 "Index " << i << " out of range"); 01564 01565 return data_[Base::index(i)]; 01566 } 01567 01585 inline T_type& operator[] (uint i) const 01586 { 01587 SCYTHE_CHECK_30 (! Base::inRange(i), scythe_bounds_error, 01588 "Index " << i << " out of range"); 01589 01590 return data_[Base::index(i)]; 01591 } 01592 01610 inline T_type& operator() (uint i) 01611 { 01612 SCYTHE_CHECK_30 (! Base::inRange(i), scythe_bounds_error, 01613 "Index " << i << " out of range"); 01614 01615 return data_[Base::index(i)]; 01616 } 01617 01635 inline T_type& operator() (uint i) const 01636 { 01637 SCYTHE_CHECK_30 (! Base::inRange(i), scythe_bounds_error, 01638 "Index " << i << " out of range"); 01639 01640 return data_[Base::index(i)]; 01641 } 01642 01661 inline T_type& operator() (uint i, uint j) 01662 { 01663 SCYTHE_CHECK_30 (! Base::inRange(i, j), scythe_bounds_error, 01664 "Index (" << i << ", " << j << ") out of range"); 01665 01666 return data_[Base::index(i, j)]; 01667 } 01668 01687 inline T_type& operator() (uint i, uint j) const 01688 { 01689 SCYTHE_CHECK_30 (! Base::inRange(i, j), scythe_bounds_error, 01690 "Index (" << i << ", " << j << ") out of range"); 01691 01692 return data_[Base::index(i, j)]; 01693 } 01694 01695 /**** SUBMATRIX OPERATORS ****/ 01696 01697 01698 /* Submatrices are always views. An extra (but relatively 01699 * cheap) copy constructor call is made when mixing and matching 01700 * orders like 01701 * 01702 * Matrix<> A; 01703 * ... 01704 * Matrix<double, Row> B = A(2, 2, 4, 4); 01705 * 01706 * It is technically possible to get around this, by providing 01707 * templates of each function of the form 01708 * template <matrix_order O> 01709 * Matrix<T_type, O, View> operator() (...) 01710 * 01711 * but the syntax to call them (crappy return type inference): 01712 * 01713 * Matrix<double, Row> B = A.template operator()<Row>(2, 2, 4, 4) 01714 * 01715 * is such complete gibberish that I don't think this is worth 01716 * the slight optimization. 01717 */ 01718 01741 inline Matrix<T_type, ORDER, View> 01742 operator() (uint x1, uint y1, uint x2, uint y2) 01743 { 01744 SCYTHE_CHECK_20 (! Base::inRange(x1, y1) 01745 || ! Base::inRange(x2, y2) 01746 || x1 > x2 || y1 > y2, 01747 scythe_bounds_error, 01748 "Submatrix (" << x1 << ", " << y1 << ") ; (" 01749 << x2 << ", " << y2 << ") out of range or ill-formed"); 01750 01751 return (Matrix<T_type, ORDER, View>(*this, x1, y1, x2, y2)); 01752 } 01753 01773 inline Matrix<T_type, ORDER, View> 01774 operator() (uint x1, uint y1, uint x2, uint y2) const 01775 { 01776 SCYTHE_CHECK_20 (! Base::inRange(x1, y1) 01777 || ! Base::inRange(x2, y2) 01778 || x1 > x2 || y1 > y2, 01779 scythe_bounds_error, 01780 "Submatrix (" << x1 << ", " << y1 << ") ; (" 01781 << x2 << ", " << y2 << ") out of range or ill-formed"); 01782 01783 return (Matrix<T_type, ORDER, View>(*this, x1, y1, x2, y2)); 01784 } 01785 01804 inline Matrix<T_type, ORDER, View> 01805 operator() (const all_elements a, uint j) 01806 { 01807 SCYTHE_CHECK_20 (j >= Base::cols(), scythe_bounds_error, 01808 "Column vector index " << j << " out of range"); 01809 01810 return (Matrix<T_type, ORDER, View> 01811 (*this, 0, j, Base::rows() - 1, j)); 01812 } 01813 01829 inline Matrix<T_type, ORDER, View> 01830 operator() (const all_elements a, uint j) const 01831 { 01832 SCYTHE_CHECK_20 (j >= Base::cols(), scythe_bounds_error, 01833 "Column vector index " << j << " out of range"); 01834 01835 return (Matrix<T_type, ORDER, View> 01836 (*this, 0, j, Base::rows() - 1, j)); 01837 } 01838 01857 inline Matrix<T_type, ORDER, View> 01858 operator() (uint i, const all_elements b) 01859 { 01860 SCYTHE_CHECK_20 (i >= Base::rows(), scythe_bounds_error, 01861 "Row vector index " << i << " out of range"); 01862 01863 return (Matrix<T_type, ORDER, View> 01864 (*this, i, 0, i, Base::cols() - 1)); 01865 } 01866 01882 inline Matrix<T_type, ORDER, View> 01883 operator() (uint i, const all_elements b) const 01884 { 01885 SCYTHE_CHECK_20 (i >= Base::rows(), scythe_bounds_error, 01886 "Row vector index " << i << " out of range"); 01887 return (Matrix<T_type, ORDER, View> 01888 (*this, i, 0, i, Base::cols() - 1)); 01889 } 01890 01902 /**** ASSIGNMENT OPERATORS ****/ 01903 01904 /* 01905 * As with the copy constructor, we need to 01906 * explicitly define the same-order-same-style assignment 01907 * operator or the default operator will take over. 01908 * 01909 * TODO With views, it may be desirable to auto-grow (and, 01910 * technically, detach) views to the null matrix. This means 01911 * you can write something like: 01912 * 01913 * Matrix<double, Col, View> X; 01914 * X = ... 01915 * 01916 * and not run into trouble because you didn't presize. Still, 01917 * not sure this won't encourage silly mistakes...need to think 01918 * about it. 01919 */ 01920 01970 Matrix& operator= (const Matrix& M) 01971 { 01972 if (STYLE == Concrete) { 01973 resize2Match(M); 01974 scythe::copy<ORDER,ORDER> (M, *this); 01975 } else { 01976 #ifndef SCYTHE_VIEW_ASSIGNMENT_RECYCLE 01977 SCYTHE_CHECK_10 (Base::size() != M.size(), 01978 scythe_conformation_error, 01979 "LHS has dimensions (" << Base::rows() 01980 << ", " << Base::cols() 01981 << ") while RHS has dimensions (" << M.rows() << ", " 01982 << M.cols() << ")"); 01983 01984 scythe::copy<ORDER,ORDER> (M, *this); 01985 #else 01986 copy_recycle<ORDER,ORDER>(M, *this); 01987 #endif 01988 } 01989 01990 return *this; 01991 } 01992 02043 template <matrix_order O, matrix_style S> 02044 Matrix &operator= (const Matrix<T_type, O, S> &M) 02045 { 02046 if (STYLE == Concrete) { 02047 resize2Match(M); 02048 scythe::copy<ORDER,ORDER> (M, *this); 02049 } else { 02050 #ifndef SCYTHE_VIEW_ASSIGNMENT_RECYCLE 02051 SCYTHE_CHECK_10 (Base::size() != M.size(), 02052 scythe_conformation_error, 02053 "LHS has dimensions (" << Base::rows() 02054 << ", " << Base::cols() 02055 << ") while RHS has dimensions (" << M.rows() << ", " 02056 << M.cols() << ")"); 02057 02058 scythe::copy<ORDER,ORDER> (M, *this); 02059 #else 02060 copy_recycle<ORDER,ORDER>(M, *this); 02061 #endif 02062 } 02063 02064 return *this; 02065 } 02066 02067 /* List-wise initialization behavior is a touch complicated. 02068 * List needs to be less than or equal to matrix in size and it 02069 * is copied into the matrix with R-style recycling. 02070 * 02071 * The one issue is that, if you want true assignment of a 02072 * scalar to a concrete matrix (resize the matrix to a scalar) 02073 * you need to be explicit: 02074 * 02075 * Matrix<> A(2, 2); 02076 * double x = 3; 02077 * ... 02078 * A = Matrix<>(x); // -> 3 02079 * 02080 * A = x; // -> 3 3 02081 * // 3 3 02082 */ 02083 02114 ListInitializer<T_type, iterator, ORDER, STYLE> 02115 operator=(T_type x) 02116 { 02117 return (ListInitializer<T_type, iterator, ORDER, STYLE> 02118 (x, begin(),end(), this)); 02119 } 02120 02148 template <typename ITERATOR, matrix_order O, matrix_style S> 02149 Matrix &operator=(ListInitializer<T_type, ITERATOR, O, S> li) 02150 { 02151 li.populate(); 02152 *this = *(li.matrix_); 02153 return *this; 02154 } 02155 02156 /**** ARITHMETIC OPERATORS ****/ 02157 02158 private: 02159 /* Reusable chunk of code for element-wise operator 02160 * assignments. Updates are done in-place except for the 1x1 by 02161 * nXm case, which forces a resize. 02162 */ 02163 template <typename OP, matrix_order O, matrix_style S> 02164 inline Matrix& 02165 elementWiseOperatorAssignment (const Matrix<T_type, O, S>& M, 02166 OP op) 02167 { 02168 SCYTHE_CHECK_10 (Base::size() != 1 && M.size() != 1 && 02169 (Base::rows () != M.rows() || Base::cols() != M.cols()), 02170 scythe_conformation_error, 02171 "Matrices with dimensions (" << Base::rows() 02172 << ", " << Base::cols() 02173 << ") and (" << M.rows() << ", " << M.cols() 02174 << ") are not conformable"); 02175 02176 if (Base::size() == 1) { // 1x1 += nXm 02177 T_type tmp = (*this)(0); 02178 resize2Match(M); 02179 std::transform(M.begin_f<ORDER>(), M.end_f<ORDER>(), 02180 begin_f(), std::bind1st(op, tmp)); 02181 } else if (M.size() == 1) { // nXm += 1x1 02182 std::transform(begin_f(), end_f(), begin_f(), 02183 std::bind2nd(op, M(0))); 02184 } else { // nXm += nXm 02185 std::transform(begin_f(), end_f(), M.begin_f<ORDER>(), 02186 begin_f(), op); 02187 } 02188 02189 return *this; 02190 } 02191 02192 public: 02212 template <matrix_order O, matrix_style S> 02213 inline Matrix& operator+= (const Matrix<T_type, O, S> &M) 02214 { 02215 return elementWiseOperatorAssignment(M, std::plus<T_type> ()); 02216 } 02217 02234 inline Matrix& operator+= (T_type x) 02235 { 02236 return elementWiseOperatorAssignment(Matrix(x), 02237 std::plus<T_type> ()); 02238 } 02239 02259 template <matrix_order O, matrix_style S> 02260 inline Matrix& operator-= (const Matrix<T_type, O, S> &M) 02261 { 02262 return elementWiseOperatorAssignment(M, std::minus<T_type> ()); 02263 } 02264 02281 inline Matrix& operator-= (T_type x) 02282 { 02283 return elementWiseOperatorAssignment(Matrix(x), 02284 std::minus<T_type> ()); 02285 } 02286 02311 template <matrix_order O, matrix_style S> 02312 inline Matrix& operator%= (const Matrix<T_type, O, S> &M) 02313 { 02314 return elementWiseOperatorAssignment(M, 02315 std::multiplies<T_type> ()); 02316 } 02317 02334 inline Matrix& operator%= (T_type x) 02335 { 02336 return elementWiseOperatorAssignment(Matrix(x), 02337 std::multiplies<T_type> ()); 02338 } 02339 02360 template <matrix_order O, matrix_style S> 02361 inline Matrix& operator/= (const Matrix<T_type, O, S> &M) 02362 { 02363 return elementWiseOperatorAssignment(M, std::divides<T_type>()); 02364 } 02365 02382 inline Matrix& operator/= (T_type x) 02383 { 02384 return elementWiseOperatorAssignment(Matrix(x), 02385 std::divides<T_type> ()); 02386 } 02387 02408 template <matrix_order O, matrix_style S> 02409 inline Matrix& operator^= (const Matrix<T_type, O, S> &M) 02410 { 02411 return elementWiseOperatorAssignment(M, 02412 exponentiate<T_type>()); 02413 } 02414 02431 inline Matrix& operator^= (T_type x) 02432 { 02433 return elementWiseOperatorAssignment(Matrix(x), 02434 exponentiate<T_type> ()); 02435 } 02436 02437 /* Matrix mult always disengages views because it generally 02438 * requires a resize. We force a disengage in the one place it 02439 * isn't absolutely necessary(this->size()==1), for consistency. 02440 */ 02441 02472 template <matrix_order O, matrix_style S> 02473 Matrix& operator*= (const Matrix<T_type, O, S>& M) 02474 { 02475 /* Farm out the work to the plain old * operator and make this 02476 * matrix a reference (the only reference) to the result. We 02477 * always have to create a new matrix here, so there is no 02478 * speed-up from using *=. 02479 */ 02480 02481 /* This saves a copy over 02482 * *this = (*this) * M; 02483 * if we're concrete 02484 */ 02485 Matrix<T_type, ORDER> res = (*this) * M; 02486 this->referenceOther(res); 02487 this->mimic(res); 02488 02489 return *this; 02490 } 02491 02515 inline Matrix& operator*= (T_type x) 02516 { 02517 return elementWiseOperatorAssignment(Matrix(x), 02518 std::multiplies<T_type> ()); 02519 } 02520 02545 template <matrix_order O, matrix_style S> Matrix& kronecker 02546 (const Matrix<T_type, O, S>& M) { uint totalrows = 02547 Base::rows() * M.rows(); uint totalcols = Base::cols() * 02548 M.cols(); 02549 // Even if we're a view, make this guy concrete. 02550 Matrix<T_type,ORDER> res(totalrows, totalcols, false); 02551 02552 /* TODO: This the most natural way to write this in scythe 02553 * (with a small optimization based on ordering) but probably 02554 * not the fastest because it uses submatrix assignments. 02555 * Optimizations should be considered. 02556 */ 02557 forward_iterator it = begin_f(); 02558 if (ORDER == Row) { 02559 for (uint row = 0; row < totalrows; row += M.rows()) { 02560 for (uint col = 0; col < totalcols; col += M.cols()){ 02561 res(row, col, row + M.rows() - 1, col + M.cols() - 1) 02562 = (*it) * M; 02563 it++; 02564 } 02565 } 02566 } else { 02567 for (uint col = 0; col < totalcols; col += M.cols()) { 02568 for (uint row = 0; row < totalrows; row += M.rows()){ 02569 res(row, col, row + M.rows() - 1, col + M.cols() - 1) 02570 = (*it) * M; 02571 it++; 02572 } 02573 } 02574 } 02575 02576 this->referenceOther(res); 02577 this->mimic(res); 02578 02579 return *this; 02580 } 02581 02603 inline Matrix& kronecker (T_type x) 02604 { 02605 return elementWiseOperatorAssignment(Matrix(x), 02606 std::multiplies<T_type> ()); 02607 } 02608 02609 /* Logical assignment operators */ 02610 02630 template <matrix_order O, matrix_style S> 02631 inline Matrix& operator&= (const Matrix<T_type, O, S> &M) 02632 { 02633 return elementWiseOperatorAssignment(M, 02634 std::logical_and<T_type>()); 02635 } 02636 02653 inline Matrix& operator&= (T_type x) 02654 { 02655 return elementWiseOperatorAssignment(Matrix(x), 02656 std::logical_and<T_type> ()); 02657 } 02658 02678 template <matrix_order O, matrix_style S> 02679 inline Matrix& operator|= (const Matrix<T_type, O, S> &M) 02680 { 02681 return elementWiseOperatorAssignment(M, 02682 std::logical_or<T_type>()); 02683 } 02684 02701 inline Matrix& operator|= (T_type x) 02702 { 02703 return elementWiseOperatorAssignment(Matrix(x), 02704 std::logical_or<T_type> ()); 02705 } 02706 02707 /**** MODIFIERS ****/ 02708 02709 /* Resize a matrix view. resize() takes dimensions as 02710 * parameters while resize2Match() takes a matrix reference and 02711 * uses its dimensions. 02712 */ 02713 02743 void resize (uint rows, uint cols, bool preserve=false) 02744 { 02745 if (preserve) { 02746 /* TODO Optimize this case. It is rather clunky. */ 02747 Matrix<T_type, ORDER, View> tmp(*this); 02748 this->referenceNew(rows * cols); 02749 Base::resize(rows, cols); 02750 uint min_cols = std::min(Base::cols(), tmp.cols()); 02751 uint min_rows = std::min(Base::rows(), tmp.rows()); 02752 02753 // TODO use iterators here perhaps 02754 if (ORDER == Col) { 02755 for (uint j = 0; j < min_cols; ++j) 02756 for (uint i = 0; i < min_rows; ++i) 02757 (*this)(i, j) = tmp(i, j); 02758 } else { 02759 for (uint i = 0; i < min_rows; ++i) 02760 for (uint j = 0; j < min_cols; ++j) 02761 (*this)(i, j) = tmp(i, j); 02762 } 02763 } else { 02764 this->referenceNew(rows * cols); 02765 Base::resize(rows, cols); 02766 } 02767 } 02768 02784 template <typename T, matrix_order O, matrix_style S> 02785 inline void resize2Match(const Matrix<T, O, S> &M, 02786 bool preserve=false) 02787 { 02788 resize(M.rows(), M.cols(), preserve); 02789 } 02790 02791 /* Copy this matrix to a new datablock in contiguous storage */ 02809 inline void detach () 02810 { 02811 resize2Match(*this, true); 02812 } 02813 02814 /* Swap operator: sort of a dual copy constructor. Part of the 02815 * standard STL container interface. We only support swaps 02816 * between matrices of like order and style because things get 02817 * hairy otherwise. The behavior of this for concrete matrices 02818 * is a little hairy in any case. 02819 * 02820 * Matrix<> A, B; 02821 * ... // fill in A and B 02822 * Matrix<double, Col, View> v1 = A(_, 1); 02823 * A.swap(B); 02824 * Matrix<double, Col, View> v2 = B(_, 1); 02825 * 02826 * v1 == v2; // evaluates to true 02827 * 02828 */ 02829 02845 inline void swap (Matrix &M) 02846 { 02847 Matrix tmp = *this; 02848 02849 /* This are just reference() calls, but we do this explicitly 02850 * here to avoid throwing errors on the concrete case. While 02851 * having a concrete matrix reference another matrix is 02852 * generally a bad idea, it is safe when the referenced matrix 02853 * is concrete, has the same order, and gets deallocated (or 02854 * redirected at another block) like here. 02855 */ 02856 02857 this->referenceOther(M); 02858 this->mimic(M); 02859 02860 M.referenceOther(tmp); 02861 M.mimic(tmp); 02862 } 02863 02864 /**** ACCESSORS ****/ 02865 02866 /* Accessors that don't access the data itself (that don't rely 02867 * on T_type) are in Matrix_base 02868 */ 02869 02870 /* Are all the elements of this Matrix == 0 */ 02871 02880 inline bool isZero () const 02881 { 02882 const_forward_iterator last = end_f(); 02883 return (last == std::find_if(begin_f(), last, 02884 std::bind1st(std::not_equal_to<T_type> (), 0))); 02885 } 02886 02887 /* M(i,j) == 0 when i != j */ 02899 inline bool isDiagonal() const 02900 { 02901 if (! Base::isSquare()) 02902 return false; 02903 /* Always travel in order. It would be nice to use iterators 02904 * here, but we'd need to take views and their iterators are 02905 * too slow at the moment. 02906 * TODO redo with views and iterators if optimized. 02907 */ 02908 if (ORDER == Row) { 02909 for (uint i = 0; i < Base::rows(); ++i) { 02910 for (uint j = 0; j < Base::cols(); ++j) { 02911 if (i != j && (*this)(i, j) != 0) 02912 return false; 02913 } 02914 } 02915 } else { // ORDER == Col 02916 for (uint j = 0; j < Base::cols(); ++j) { 02917 for (uint i = 0; i < Base::rows(); ++i) { 02918 if (i != j && (*this)(i, j) != 0) 02919 return false; 02920 } 02921 } 02922 } 02923 return true; 02924 } 02925 02926 /* M(I, j) == 0 when i!= j and 1 when i == j */ 02938 inline bool isIdentity () const 02939 { 02940 if (! Base::isSquare()) 02941 return false; 02942 // TODO redo with views and iterator if optimized 02943 if (ORDER == Row) { 02944 for (uint i = 0; i < Base::rows(); ++i) { 02945 for (uint j = 0; j < Base::cols(); ++j) { 02946 if (i != j) { 02947 if ((*this)(i,j) != 0) 02948 return false; 02949 } else if ((*this)(i,j) != 1) 02950 return false; 02951 } 02952 } 02953 } else { // ORDER == Col 02954 for (uint j = 0; j < Base::rows(); ++j) { 02955 for (uint i = 0; i < Base::cols(); ++i) { 02956 if (i != j) { 02957 if ((*this)(i,j) != 0) 02958 return false; 02959 } else if ((*this)(i,j) != 1) 02960 return false; 02961 } 02962 } 02963 } 02964 return true; 02965 } 02966 02967 /* M(i,j) == 0 when i < j */ 02977 inline bool isLowerTriangular () const 02978 { 02979 if (! Base::isSquare()) 02980 return false; 02981 // TODO view+iterator if optimized 02982 if (ORDER == Row) { 02983 for (uint i = 0; i < Base::rows(); ++i) 02984 for (uint j = i + 1; j < Base::cols(); ++j) 02985 if ((*this)(i,j) != 0) 02986 return false; 02987 } else { 02988 for (uint j = 0; j < Base::cols(); ++j) 02989 for (uint i = 0; i < j; ++i) 02990 if ((*this)(i,j) != 0) 02991 return false; 02992 } 02993 return true; 02994 } 02995 02996 /* M(i,j) == 0 when i > j */ 03006 inline bool isUpperTriangular () const 03007 { 03008 if (! Base::isSquare()) 03009 return false; 03010 // TODO view+iterator if optimized 03011 if (ORDER == Row) { 03012 for (uint i = 0; i < Base::rows(); ++i) 03013 for (uint j = 0; j < i; ++j) 03014 if ((*this)(i,j) != 0) 03015 return false; 03016 } else { 03017 for (uint j = 0; j < Base::cols(); ++j) 03018 for (uint i = j + 1; i < Base::rows(); ++i) 03019 if ((*this)(i,j) != 0) 03020 return false; 03021 } 03022 return true; 03023 } 03024 03031 inline bool isSingular() const 03032 { 03033 if (! Base::isSquare() || Base::isNull()) 03034 return false; 03035 if ((~(*this)) == (T_type) 0) 03036 return true; 03037 return false; 03038 } 03039 03040 /* Square and t(M) = M(inv(M) * t(M) == I */ 03050 inline bool isSymmetric () const 03051 { 03052 if (! Base::isSquare()) 03053 return false; 03054 // No point in order optimizing here 03055 for (uint i = 1; i < Base::rows(); ++i) 03056 for (uint j = 0; j < i; ++j) 03057 if ((*this)(i, j) != (*this)(j, i)) 03058 return false; 03059 03060 return true; 03061 } 03062 03063 /* The matrix is square and t(A) = -A */ 03074 inline bool isSkewSymmetric () const 03075 { 03076 if (! Base::isSquare()) 03077 return false; 03078 // No point in order optimizing here 03079 for (uint i = 1; i < Base::rows(); ++i) 03080 for (uint j = 0; j < i; ++j) 03081 if ((*this)(i, j) != 0 - (*this)(j, i)) 03082 return false; 03083 03084 return true; 03085 } 03086 03099 template <matrix_order O, matrix_style S> 03100 inline bool 03101 equals(const Matrix<T_type, O, S>& M) const 03102 { 03103 if (data_ == M.getArray() && STYLE == Concrete && S == Concrete) 03104 return true; 03105 else if (data_ == M.getArray() && Base::rows() == M.rows() 03106 && Base::cols() == M.cols()) { 03107 return true; 03108 } else if (this->isNull() && M.isNull()) 03109 return true; 03110 else if (Base::rows() != M.rows() || Base::cols() != M.cols()) 03111 return false; 03112 03113 return std::equal(begin_f(), end_f(), 03114 M.template begin_f<ORDER>()); 03115 } 03116 03127 inline bool 03128 equals(T_type x) const 03129 { 03130 const_forward_iterator last = end_f(); 03131 return (last == std::find_if(begin_f(), last, 03132 std::bind1st(std::not_equal_to<T_type> (), x))); 03133 } 03134 03135 03136 /**** OTHER UTILITIES ****/ 03137 03153 inline T_type* getArray () const 03154 { 03155 return data_; 03156 } 03157 03182 inline void 03183 save (const std::string& path, const char flag = 'n', 03184 const bool header = false) const 03185 { 03186 std::ofstream out; 03187 if (flag == 'n') { 03188 std::fstream temp(path.c_str(), std::ios::in); 03189 if (! temp) 03190 out.open(path.c_str(), std::ios::out); 03191 else { 03192 temp.close(); 03193 SCYTHE_THROW(scythe_file_error, "Cannot overwrite file " 03194 << path << " when flag = n"); 03195 } 03196 } else if (flag == 'o') 03197 out.open(path.c_str(), std::ios::out | std::ios::trunc); 03198 else if (flag == 'a') 03199 out.open(path.c_str(), std::ios::out | std::ios::app); 03200 else 03201 SCYTHE_THROW(scythe_invalid_arg, "Invalid flag: " << flag); 03202 03203 if (! out) 03204 SCYTHE_THROW(scythe_file_error, 03205 "Could not open file " << path); 03206 03207 if (header) { 03208 out << Base::rows() << " " << Base::cols(); 03209 for (uint i = 0; i < Base::size(); ++i) 03210 out << " " << (*this)[i]; 03211 out << std::endl; 03212 } else { 03213 for (uint i = 0; i < Base::rows(); ++i) { 03214 for (uint j = 0; j < Base::cols(); ++j) 03215 out << (*this)(i,j) << " "; 03216 out << "\n"; 03217 } 03218 } 03219 out.close(); 03220 } 03221 03222 03223 /**** ITERATOR FACTORIES ****/ 03224 03225 /* TODO Write some cpp macro code to reduce this to something 03226 * manageable. 03227 */ 03228 03229 /* Random Access Iterator Factories */ 03230 03231 /* Generalized versions */ 03232 03242 template <matrix_order I_ORDER> 03243 inline 03244 matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE> 03245 begin () 03246 { 03247 return matrix_random_access_iterator<T_type, I_ORDER, ORDER, 03248 STYLE>(*this); 03249 } 03250 03261 template <matrix_order I_ORDER> 03262 inline 03263 const_matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE> 03264 begin() const 03265 { 03266 return const_matrix_random_access_iterator<T_type, I_ORDER, 03267 ORDER, STYLE> 03268 (*this); 03269 } 03270 03281 template <matrix_order I_ORDER> 03282 inline 03283 matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE> 03284 end () 03285 { 03286 return (begin<I_ORDER>() + Base::size()); 03287 } 03288 03299 template <matrix_order I_ORDER> 03300 inline 03301 const_matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE> 03302 end () const 03303 { 03304 return (begin<I_ORDER>() + Base::size()); 03305 } 03306 03317 template <matrix_order I_ORDER> 03318 inline std::reverse_iterator<matrix_random_access_iterator<T_type, 03319 I_ORDER, ORDER, STYLE> > 03320 rbegin() 03321 { 03322 return std::reverse_iterator<matrix_random_access_iterator 03323 <T_type, I_ORDER, ORDER, STYLE> > 03324 (end<I_ORDER>()); 03325 } 03326 03337 template <matrix_order I_ORDER> 03338 inline 03339 std::reverse_iterator<const_matrix_random_access_iterator 03340 <T_type, I_ORDER, ORDER, STYLE> > 03341 rbegin() const 03342 { 03343 return std::reverse_iterator<const_matrix_random_access_iterator 03344 <T_type, I_ORDER, ORDER, STYLE> > 03345 (end<I_ORDER>()); 03346 } 03347 03359 template <matrix_order I_ORDER> 03360 inline std::reverse_iterator<matrix_random_access_iterator 03361 <T_type, I_ORDER, ORDER, STYLE> > 03362 rend() 03363 { 03364 return std::reverse_iterator<matrix_random_access_iterator 03365 <T_type, I_ORDER, ORDER, STYLE> > 03366 (begin<I_ORDER>()); 03367 } 03368 03379 template <matrix_order I_ORDER> 03380 inline 03381 std::reverse_iterator<const_matrix_random_access_iterator 03382 <T_type, I_ORDER, ORDER, STYLE> > 03383 rend() const 03384 { 03385 return std::reverse_iterator<const_matrix_random_access_iterator 03386 <T_type, I_ORDER, ORDER, STYLE> > 03387 (begin<I_ORDER>()); 03388 } 03389 03390 /* Specific versions --- the generalized versions force you 03391 * choose the ordering explicitly. These definitions set up 03392 * in-order iteration as a default */ 03393 03405 inline iterator begin () 03406 { 03407 return iterator(*this); 03408 } 03409 03421 inline const_iterator begin() const 03422 { 03423 return const_iterator (*this); 03424 } 03425 03437 inline iterator end () 03438 { 03439 return (begin() + Base::size()); 03440 } 03441 03453 inline 03454 const_iterator end () const 03455 { 03456 return (begin() + Base::size()); 03457 } 03458 03470 inline reverse_iterator rbegin() 03471 { 03472 return reverse_iterator (end()); 03473 } 03474 03487 inline const_reverse_iterator rbegin() const 03488 { 03489 return const_reverse_iterator (end()); 03490 } 03491 03504 inline reverse_iterator rend() 03505 { 03506 return reverse_iterator (begin()); 03507 } 03508 03521 inline const_reverse_iterator rend() const 03522 { 03523 return const_reverse_iterator (begin()); 03524 } 03525 03526 /* Forward Iterator Factories */ 03527 03528 /* Generalized versions */ 03529 03539 template <matrix_order I_ORDER> 03540 inline 03541 matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE> 03542 begin_f () 03543 { 03544 return matrix_forward_iterator<T_type, I_ORDER, ORDER, 03545 STYLE>(*this); 03546 } 03547 03558 template <matrix_order I_ORDER> 03559 inline 03560 const_matrix_forward_iterator <T_type, I_ORDER, ORDER, STYLE> 03561 begin_f () const 03562 { 03563 return const_matrix_forward_iterator <T_type, I_ORDER, 03564 ORDER, STYLE> 03565 (*this); 03566 } 03567 03577 template <matrix_order I_ORDER> 03578 inline 03579 matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE> 03580 end_f () 03581 { 03582 return (begin_f<I_ORDER>().set_end()); 03583 } 03584 03595 template <matrix_order I_ORDER> 03596 inline 03597 const_matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE> 03598 end_f () const 03599 { 03600 return (begin_f<I_ORDER>().set_end()); 03601 } 03602 03603 /* Default Versions */ 03604 03616 inline forward_iterator begin_f () 03617 { 03618 return forward_iterator(*this); 03619 } 03620 03633 inline const_forward_iterator begin_f () const 03634 { 03635 return const_forward_iterator (*this); 03636 } 03637 03649 inline forward_iterator end_f () 03650 { 03651 return (begin_f().set_end()); 03652 } 03653 03666 inline 03667 const_forward_iterator end_f () const 03668 { 03669 return (begin_f().set_end()); 03670 } 03671 03672 /* Bidirectional Iterator Factories */ 03673 03674 /* Generalized versions */ 03675 03686 template <matrix_order I_ORDER> 03687 inline 03688 matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE> 03689 begin_bd () 03690 { 03691 return matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, 03692 STYLE>(*this); 03693 } 03694 03705 template <matrix_order I_ORDER> 03706 inline 03707 const_matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE> 03708 begin_bd () const 03709 { 03710 return const_matrix_bidirectional_iterator<T_type, I_ORDER, 03711 ORDER, STYLE> 03712 (*this); 03713 } 03714 03725 template <matrix_order I_ORDER> 03726 inline 03727 matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE> 03728 end_bd () 03729 { 03730 return (begin_bd<I_ORDER>().set_end()); 03731 } 03732 03743 template <matrix_order I_ORDER> 03744 inline 03745 const_matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE> 03746 end_bd () const 03747 { 03748 return (begin_bd<I_ORDER>.set_end()); 03749 } 03750 03761 template <matrix_order I_ORDER> 03762 inline std::reverse_iterator<matrix_bidirectional_iterator<T_type, 03763 I_ORDER, ORDER, STYLE> > 03764 rbegin_bd () 03765 { 03766 return std::reverse_iterator<matrix_bidirectional_iterator 03767 <T_type, I_ORDER, ORDER, STYLE> > 03768 (end_bd<I_ORDER>()); 03769 } 03770 03781 template <matrix_order I_ORDER> 03782 inline 03783 std::reverse_iterator<const_matrix_bidirectional_iterator 03784 <T_type, I_ORDER, ORDER, STYLE> > 03785 rbegin_bd () const 03786 { 03787 return std::reverse_iterator<const_matrix_bidirectional_iterator 03788 <T_type, I_ORDER, ORDER, STYLE> > 03789 (end_bd<I_ORDER>()); 03790 } 03791 03803 template <matrix_order I_ORDER> 03804 inline std::reverse_iterator<matrix_bidirectional_iterator 03805 <T_type, I_ORDER, ORDER, STYLE> > 03806 rend_bd () 03807 { 03808 return std::reverse_iterator<matrix_bidirectional_iterator 03809 <T_type, I_ORDER, ORDER, STYLE> > 03810 (begin_bd<I_ORDER>()); 03811 } 03812 03823 template <matrix_order I_ORDER> 03824 inline 03825 std::reverse_iterator<const_matrix_bidirectional_iterator 03826 <T_type, I_ORDER, ORDER, STYLE> > 03827 rend_bd () const 03828 { 03829 return std::reverse_iterator<const_matrix_bidirectional_iterator 03830 <T_type, I_ORDER, ORDER, STYLE> > 03831 (begin_bd<I_ORDER>()); 03832 } 03833 03834 /* Specific versions --- the generalized versions force you 03835 * choose the ordering explicitly. These definitions set up 03836 * in-order iteration as a default */ 03837 03850 inline bidirectional_iterator begin_bd () 03851 { 03852 return bidirectional_iterator(*this); 03853 } 03854 03867 inline const_bidirectional_iterator begin_bd() const 03868 { 03869 return const_bidirectional_iterator (*this); 03870 } 03871 03884 inline bidirectional_iterator end_bd () 03885 { 03886 return (begin_bd().set_end()); 03887 } 03888 03901 inline 03902 const_bidirectional_iterator end_bd () const 03903 { 03904 return (begin_bd().set_end()); 03905 } 03906 03919 inline reverse_bidirectional_iterator rbegin_bd() 03920 { 03921 return reverse_bidirectional_iterator (end_bd()); 03922 } 03923 03936 inline const_reverse_bidirectional_iterator rbegin_bd () const 03937 { 03938 return const_reverse_bidirectional_iterator (end_bd()); 03939 } 03940 03953 inline reverse_bidirectional_iterator rend_bd () 03954 { 03955 return reverse_bidirectional_iterator (begin_bd()); 03956 } 03957 03970 inline const_reverse_iterator rend_bd () const 03971 { 03972 return const_reverse_bidirectiona_iterator (begin_bd()); 03973 } 03974 03975 protected: 03976 /**** INSTANCE VARIABLES ****/ 03977 03978 /* I know the point of C++ is to force you to write 20 times 03979 * more code than should be necessary but "using" inherited ivs 03980 * is just stupid. 03981 */ 03982 using DBRef::data_; // refer to inherited data pointer directly 03983 using Base::rows_; // " # of rows directly 03984 using Base::cols_; // " # of cols directly 03985 03986 }; // end class Matrix 03987 03988 /**** EXTERNAL OPERATORS ****/ 03989 03990 /* External operators include a range of binary matrix operations 03991 * such as tests for equality, and arithmetic. Style 03992 * (concrete/view) of the returned matrix is that of the left hand 03993 * side parameter by default 03994 * 03995 * There is also a question of the ordering of the returned matrix. 03996 * We adopt the convention of returning a matrix ordered like that 03997 * of the left hand side argument, by default. 03998 * 03999 * Whenever there is only one matrix argument (lhs is scalar) we use 04000 * its order and style as the default. 04001 * 04002 * A general template version of each operator also exists and users 04003 * can coerce the return type to whatever they prefer using some 04004 * ugly syntax; ex: 04005 * 04006 * Matrix<> A; ... Matrix<double, Row> B = operator*<Row,Concrete> 04007 * (A, A); 04008 * 04009 * In general, the matrix class copy constructor will quietly 04010 * convert whatever matrix template is returned to the type of the 04011 * matrix it is being copied into on return, but one might want to 04012 * specify the type for objects that only exist for a second (ex: 04013 * (operator*<Row,Concrete>(A, A)).begin()). Also, note that the 04014 * fact that we return concrete matrices by default does not 04015 * preclude the user from taking advantage of fast view copies. It 04016 * is the template type of the object being copy-constructed that 04017 * matters---in terms of underlying implementation all matrices are 04018 * views, concrete matrices just maintain a particular policy. 04019 * 04020 * TODO Consider the best type for scalar args to these functions. 04021 * For the most part, these will be primitives---doubles mostly. 04022 * Passing these by reference is probably less efficient than 04023 * passing by value. But, for user-defined types pass-by-reference 04024 * might be the way to go and the cost in this case will be much 04025 * higher than the value-reference trade-off for primitives. Right 04026 * now we use pass-by-reference but we might reconsider... 04027 */ 04028 04029 /**** ARITHMETIC OPERATORS ****/ 04030 04031 /* These macros provide templates for the basic definitions required 04032 * for all of the binary operators. Each operator requires 6 04033 * definitions. First, a general matrix definition must be 04034 * provided. This definition can return a matrix of a different 04035 * style and order than its arguments but can only be called if its 04036 * template type is explicitly specified. The actual logic of the 04037 * operator should be specified within this function. The macros 04038 * provide definitions for the other 5 required templates, one 04039 * default matrix by matrix, general matrix by scalar, default 04040 * matrix by scalar, general scalar by matrix, default scalar by 04041 * matrix. The default versions call the more general versions with 04042 * such that they will return concrete matrices with order equal to 04043 * the left-hand (or only) matrix passed to the default version. 04044 * 04045 */ 04046 04047 #define SCYTHE_BINARY_OPERATOR_DMM(OP) \ 04048 template <matrix_order ORDER, matrix_style L_STYLE, \ 04049 matrix_order R_ORDER, matrix_style R_STYLE, \ 04050 typename T_type> \ 04051 inline Matrix<T_type, ORDER, Concrete> \ 04052 OP (const Matrix<T_type, ORDER, L_STYLE>& lhs, \ 04053 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04054 { \ 04055 return OP <T_type, ORDER, Concrete>(lhs, rhs); \ 04056 } 04057 04058 #define SCYTHE_BINARY_OPERATOR_GMS(OP) \ 04059 template <typename T_type, matrix_order ORDER, matrix_style STYLE, \ 04060 matrix_order L_ORDER, matrix_style L_STYLE> \ 04061 inline Matrix<T_type, ORDER, STYLE> \ 04062 OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, \ 04063 const typename Matrix<T_type>::ttype &rhs) \ 04064 { \ 04065 return (OP <T_type, ORDER, STYLE> \ 04066 (lhs, Matrix<T_type, L_ORDER>(rhs))); \ 04067 } 04068 04069 #define SCYTHE_BINARY_OPERATOR_DMS(OP) \ 04070 template <matrix_order ORDER, matrix_style L_STYLE, \ 04071 typename T_type> \ 04072 inline Matrix<T_type, ORDER, Concrete> \ 04073 OP (const Matrix<T_type, ORDER, L_STYLE>& lhs, \ 04074 const typename Matrix<T_type>::ttype &rhs) \ 04075 { \ 04076 return (OP <T_type, ORDER, Concrete> (lhs, rhs)); \ 04077 } 04078 04079 #define SCYTHE_BINARY_OPERATOR_GSM(OP) \ 04080 template <typename T_type, matrix_order ORDER, matrix_style STYLE, \ 04081 matrix_order R_ORDER, matrix_style R_STYLE> \ 04082 inline Matrix<T_type, ORDER, STYLE> \ 04083 OP (const typename Matrix<T_type>::ttype &lhs, \ 04084 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04085 { \ 04086 return (OP <T_type, ORDER, STYLE> \ 04087 (Matrix<T_type, R_ORDER>(lhs), rhs)); \ 04088 } 04089 04090 #define SCYTHE_BINARY_OPERATOR_DSM(OP) \ 04091 template <matrix_order ORDER, matrix_style R_STYLE, \ 04092 typename T_type> \ 04093 inline Matrix<T_type, ORDER, Concrete> \ 04094 OP (const typename Matrix<T_type>::ttype &lhs, \ 04095 const Matrix<T_type, ORDER, R_STYLE>& rhs) \ 04096 { \ 04097 return (OP <T_type, ORDER, Concrete> (lhs, rhs)); \ 04098 } 04099 04100 #define SCYTHE_BINARY_OPERATOR_DEFS(OP) \ 04101 SCYTHE_BINARY_OPERATOR_DMM(OP) \ 04102 SCYTHE_BINARY_OPERATOR_GMS(OP) \ 04103 SCYTHE_BINARY_OPERATOR_DMS(OP) \ 04104 SCYTHE_BINARY_OPERATOR_GSM(OP) \ 04105 SCYTHE_BINARY_OPERATOR_DSM(OP) 04106 04107 /* Matrix multiplication */ 04108 04109 /* General template version. Must be called with operator*<> syntax 04110 */ 04111 04112 /* We provide two symmetric algorithms for matrix multiplication, 04113 * one for col-major and the other for row-major matrices. They are 04114 * designed to minimize cache misses.The decision is based on the 04115 * return type of the template so, when using matrices of multiple 04116 * orders, this can get ugly. These optimizations only really start 04117 * paying dividends as matrices get big, because cache misses are 04118 * rare with smaller matrices. 04119 */ 04120 04168 template <typename T_type, matrix_order ORDER, matrix_style STYLE, 04169 matrix_order L_ORDER, matrix_style L_STYLE, 04170 matrix_order R_ORDER, matrix_style R_STYLE> 04171 inline Matrix<T_type, ORDER, STYLE> 04172 operator* (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, 04173 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) 04174 { 04175 if (lhs.size() == 1 || rhs.size() == 1) 04176 return (lhs % rhs); 04177 04178 SCYTHE_CHECK_10 (lhs.cols() != rhs.rows(), 04179 scythe_conformation_error, 04180 "Matrices with dimensions (" << lhs.rows() 04181 << ", " << lhs.cols() 04182 << ") and (" << rhs.rows() << ", " << rhs.cols() 04183 << ") are not multiplication-conformable"); 04184 04185 Matrix<T_type, ORDER, Concrete> result (lhs.rows(), rhs.cols(), false); 04186 04187 T_type tmp; 04188 if (ORDER == Col) { // col-major optimized 04189 for (uint j = 0; j < rhs.cols(); ++j) { 04190 for (uint i = 0; i < lhs.rows(); ++i) 04191 result(i, j) = (T_type) 0; 04192 for (uint l = 0; l < lhs.cols(); ++l) { 04193 tmp = rhs(l, j); 04194 for (uint i = 0; i < lhs.rows(); ++i) 04195 result(i, j) += tmp * lhs(i, l); 04196 } 04197 } 04198 } else { // row-major optimized 04199 for (uint i = 0; i < lhs.rows(); ++i) { 04200 for (uint j = 0; j < rhs.cols(); ++j) 04201 result(i, j) = (T_type) 0; 04202 for (uint l = 0; l < rhs.rows(); ++l) { 04203 tmp = lhs(i, l); 04204 for (uint j = 0; j < rhs.cols(); ++j) 04205 result(i, j) += tmp * rhs(l,j); 04206 } 04207 } 04208 } 04209 04210 SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, result) 04211 } 04212 04213 SCYTHE_BINARY_OPERATOR_DEFS(operator*) 04214 04215 04240 template <typename T_type, matrix_order ORDER, matrix_style STYLE, 04241 matrix_order L_ORDER, matrix_style L_STYLE, 04242 matrix_order R_ORDER, matrix_style R_STYLE> 04243 inline Matrix<T_type, ORDER, STYLE> 04244 kronecker (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, 04245 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) 04246 { 04247 Matrix<T_type,ORDER,Concrete> res = lhs; 04248 res.kronecker(rhs); 04249 return (res); 04250 } 04251 04252 SCYTHE_BINARY_OPERATOR_DEFS(kronecker) 04253 04254 /* Macro definition for general return type templates of standard 04255 * binary operators (this handles, +, -, %, /, but not *) 04256 */ 04257 04258 #define SCYTHE_GENERAL_BINARY_OPERATOR(OP,FUNCTOR) \ 04259 template <typename T_type, matrix_order ORDER, matrix_style STYLE, \ 04260 matrix_order L_ORDER, matrix_style L_STYLE, \ 04261 matrix_order R_ORDER, matrix_style R_STYLE> \ 04262 inline Matrix<T_type, ORDER, STYLE> \ 04263 OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, \ 04264 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04265 { \ 04266 SCYTHE_CHECK_10(lhs.size() != 1 && rhs.size() != 1 && \ 04267 (lhs.rows() != rhs.rows() || lhs.cols() != rhs.cols()), \ 04268 scythe_conformation_error, \ 04269 "Matrices with dimensions (" << lhs.rows() \ 04270 << ", " << lhs.cols() \ 04271 << ") and (" << rhs.rows() << ", " << rhs.cols() \ 04272 << ") are not conformable"); \ 04273 \ 04274 if (lhs.size() == 1) { \ 04275 Matrix<T_type,ORDER,Concrete> res(rhs.rows(),rhs.cols(),false); \ 04276 std::transform(rhs.begin_f(), rhs.end_f(), \ 04277 res.template begin_f<R_ORDER>(), \ 04278 std::bind1st(FUNCTOR <T_type>(), lhs(0))); \ 04279 SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res) \ 04280 } \ 04281 \ 04282 Matrix<T_type,ORDER,Concrete> res(lhs.rows(), lhs.cols(), false); \ 04283 \ 04284 if (rhs.size() == 1) { \ 04285 std::transform(lhs.begin_f(), lhs.end_f(), \ 04286 res.template begin_f<L_ORDER> (), \ 04287 std::bind2nd(FUNCTOR <T_type>(), rhs(0))); \ 04288 } else { \ 04289 std::transform(lhs.begin_f(), lhs.end_f(), \ 04290 rhs.template begin_f<L_ORDER>(), \ 04291 res.template begin_f<L_ORDER>(), \ 04292 FUNCTOR <T_type> ()); \ 04293 } \ 04294 \ 04295 SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res) \ 04296 } 04297 04298 /* Addition operators */ 04299 04330 SCYTHE_GENERAL_BINARY_OPERATOR (operator+, std::plus) 04331 SCYTHE_BINARY_OPERATOR_DEFS (operator+) 04332 04333 /* Subtraction operators */ 04334 04365 SCYTHE_GENERAL_BINARY_OPERATOR (operator-, std::minus) 04366 SCYTHE_BINARY_OPERATOR_DEFS (operator-) 04367 04368 /* Element-by-element multiplication operators */ 04369 04401 SCYTHE_GENERAL_BINARY_OPERATOR (operator%, std::multiplies) 04402 SCYTHE_BINARY_OPERATOR_DEFS(operator%) 04403 04404 /* Element-by-element division */ 04405 04436 SCYTHE_GENERAL_BINARY_OPERATOR (operator/, std::divides) 04437 SCYTHE_BINARY_OPERATOR_DEFS (operator/) 04438 04439 /* Element-by-element exponentiation */ 04440 04471 SCYTHE_GENERAL_BINARY_OPERATOR (operator^, exponentiate) 04472 SCYTHE_BINARY_OPERATOR_DEFS (operator^) 04473 04474 /* Negation operators */ 04475 04476 // General return type version 04490 template <typename T_type, matrix_order R_ORDER, matrix_style R_STYLE, 04491 matrix_order ORDER, matrix_style STYLE> 04492 inline Matrix<T_type, R_ORDER, R_STYLE> 04493 operator- (const Matrix<T_type, ORDER, STYLE>& M) 04494 { 04495 Matrix<T_type, R_ORDER, Concrete> result(M.rows(), M.cols(), false); 04496 std::transform(M.template begin_f<ORDER>(), 04497 M.template end_f<ORDER>(), 04498 result.template begin_f<R_ORDER>(), 04499 std::negate<T_type> ()); 04500 SCYTHE_VIEW_RETURN(T_type, R_ORDER, R_STYLE, result) 04501 } 04502 04503 // Default return type version 04504 template <matrix_order ORDER, matrix_style P_STYLE, typename T_type> 04505 inline Matrix<T_type, ORDER, Concrete> 04506 operator- (const Matrix<T_type, ORDER, P_STYLE>& M) 04507 { 04508 return operator-<T_type, ORDER, Concrete> (M); 04509 } 04510 04511 /* Unary not operators */ 04512 04528 template <matrix_order R_ORDER, matrix_style R_STYLE, typename T_type, 04529 matrix_order ORDER, matrix_style STYLE> 04530 inline Matrix<bool, R_ORDER, R_STYLE> 04531 operator! (const Matrix<T_type, ORDER, STYLE>& M) 04532 { 04533 Matrix<bool, R_ORDER, Concrete> result(M.rows(), M.cols(), false); 04534 std::transform(M.template begin_f<ORDER>(), 04535 M.template end_f<ORDER>(), 04536 result.template begin_f<R_ORDER>(), 04537 std::logical_not<T_type> ()); 04538 SCYTHE_VIEW_RETURN(T_type, R_ORDER, R_STYLE, result) 04539 } 04540 04541 // Default return type version 04542 template <typename T_type, matrix_order ORDER, matrix_style P_STYLE> 04543 inline Matrix<bool, ORDER, Concrete> 04544 operator! (const Matrix<T_type, ORDER, P_STYLE>& M) 04545 { 04546 return (operator!<ORDER, Concrete> (M)); 04547 } 04548 /**** COMPARISON OPERATORS ****/ 04549 04550 /* These macros are analogous to those above, except they return 04551 * only boolean matrices and use slightly different template 04552 * parameter orderings. Kind of redundant, but less confusing than 04553 * making omnibus macros that handle both cases. 04554 */ 04555 #define SCYTHE_GENERAL_BINARY_BOOL_OPERATOR(OP,FUNCTOR) \ 04556 template <matrix_order ORDER, matrix_style STYLE, typename T_type, \ 04557 matrix_order L_ORDER, matrix_style L_STYLE, \ 04558 matrix_order R_ORDER, matrix_style R_STYLE> \ 04559 inline Matrix<bool, ORDER, STYLE> \ 04560 OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, \ 04561 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04562 { \ 04563 SCYTHE_CHECK_10(lhs.size() != 1 && rhs.size() != 1 && \ 04564 (lhs.rows() != rhs.rows() || lhs.cols() != rhs.cols()), \ 04565 scythe_conformation_error, \ 04566 "Matrices with dimensions (" << lhs.rows() \ 04567 << ", " << lhs.cols() \ 04568 << ") and (" << rhs.rows() << ", " << rhs.cols() \ 04569 << ") are not conformable"); \ 04570 \ 04571 if (lhs.size() == 1) { \ 04572 Matrix<bool,ORDER,Concrete> res(rhs.rows(),rhs.cols(),false); \ 04573 std::transform(rhs.begin_f(), rhs.end_f(), \ 04574 res.template begin_f<R_ORDER>(), \ 04575 std::bind1st(FUNCTOR <T_type>(), lhs(0))); \ 04576 SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res) \ 04577 } \ 04578 \ 04579 Matrix<bool,ORDER,Concrete> res(lhs.rows(), lhs.cols(), false); \ 04580 \ 04581 if (rhs.size() == 1) { \ 04582 std::transform(lhs.begin_f(), lhs.end_f(), \ 04583 res.template begin_f<L_ORDER> (), \ 04584 std::bind2nd(FUNCTOR <T_type>(), rhs(0))); \ 04585 } else { \ 04586 std::transform(lhs.begin_f(), lhs.end_f(), \ 04587 rhs.template begin_f<L_ORDER>(), \ 04588 res.template begin_f<L_ORDER>(), \ 04589 FUNCTOR <T_type> ()); \ 04590 } \ 04591 \ 04592 SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res) \ 04593 } 04594 04595 #define SCYTHE_BINARY_BOOL_OPERATOR_DMM(OP) \ 04596 template <typename T_type, matrix_order ORDER, matrix_style L_STYLE,\ 04597 matrix_order R_ORDER, matrix_style R_STYLE> \ 04598 inline Matrix<bool, ORDER, Concrete> \ 04599 OP (const Matrix<T_type, ORDER, L_STYLE>& lhs, \ 04600 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04601 { \ 04602 return OP <ORDER, Concrete>(lhs, rhs); \ 04603 } 04604 04605 #define SCYTHE_BINARY_BOOL_OPERATOR_GMS(OP) \ 04606 template <matrix_order ORDER, matrix_style STYLE, typename T_type, \ 04607 matrix_order L_ORDER, matrix_style L_STYLE> \ 04608 inline Matrix<bool, ORDER, STYLE> \ 04609 OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs, \ 04610 const typename Matrix<T_type>::ttype &rhs) \ 04611 { \ 04612 return (OP <ORDER, STYLE> \ 04613 (lhs, Matrix<T_type, L_ORDER>(rhs))); \ 04614 } 04615 04616 #define SCYTHE_BINARY_BOOL_OPERATOR_DMS(OP) \ 04617 template <typename T_type, matrix_order ORDER, matrix_style L_STYLE>\ 04618 inline Matrix<bool, ORDER, Concrete> \ 04619 OP (const Matrix<T_type, ORDER, L_STYLE>& lhs, \ 04620 const typename Matrix<T_type>::ttype &rhs) \ 04621 { \ 04622 return (OP <ORDER, Concrete> (lhs, rhs)); \ 04623 } 04624 04625 #define SCYTHE_BINARY_BOOL_OPERATOR_GSM(OP) \ 04626 template <matrix_order ORDER, matrix_style STYLE, typename T_type, \ 04627 matrix_order R_ORDER, matrix_style R_STYLE> \ 04628 inline Matrix<bool, ORDER, STYLE> \ 04629 OP (const typename Matrix<T_type>::ttype &lhs, \ 04630 const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \ 04631 { \ 04632 return (OP <ORDER, STYLE> \ 04633 (Matrix<T_type, R_ORDER>(lhs), rhs)); \ 04634 } 04635 04636 #define SCYTHE_BINARY_BOOL_OPERATOR_DSM(OP) \ 04637 template <typename T_type, matrix_order ORDER, matrix_style R_STYLE>\ 04638 inline Matrix<bool, ORDER, Concrete> \ 04639 OP (const typename Matrix<T_type>::ttype &lhs, \ 04640 const Matrix<T_type, ORDER, R_STYLE>& rhs) \ 04641 { \ 04642 return (OP <ORDER, Concrete> (lhs, rhs)); \ 04643 } 04644 04645 #define SCYTHE_BINARY_BOOL_OPERATOR_DEFS(OP) \ 04646 SCYTHE_BINARY_BOOL_OPERATOR_DMM(OP) \ 04647 SCYTHE_BINARY_BOOL_OPERATOR_GMS(OP) \ 04648 SCYTHE_BINARY_BOOL_OPERATOR_DMS(OP) \ 04649 SCYTHE_BINARY_BOOL_OPERATOR_GSM(OP) \ 04650 SCYTHE_BINARY_BOOL_OPERATOR_DSM(OP) 04651 04652 /* Element-wise Equality operator 04653 * See equals() method for straight equality checks 04654 */ 04655 04690 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator==, std::equal_to) 04691 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator==) 04692 04727 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator!=, std::not_equal_to) 04728 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator!=) 04729 04765 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator<, std::less) 04766 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator<) 04767 04804 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator<=, std::less_equal) 04805 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator<=) 04806 04842 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator>, std::greater) 04843 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator>) 04844 04881 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator>=, std::greater_equal) 04882 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator>=) 04883 04919 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator&, std::logical_and) 04920 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator&) 04921 04922 04958 SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator|, std::logical_or) 04959 SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator|) 04960 04961 /**** INPUT-OUTPUT ****/ 04962 04963 04964 /* This function simply copies values from an input stream into a 04965 * matrix. It relies on the iterators for bounds checking. 04966 */ 04967 04981 template <typename T, matrix_order O, matrix_style S> 04982 std::istream& operator>> (std::istream& is, Matrix<T,O,S>& M) 04983 { 04984 std::copy(std::istream_iterator<T> (is), std::istream_iterator<T>(), 04985 M.begin_f()); 04986 04987 return is; 04988 } 04989 04990 /* Writes a matrix to an ostream in readable format. This is 04991 * intended to be used to pretty-print to the terminal. 04992 */ 04993 05008 template <typename T, matrix_order O, matrix_style S> 05009 std::ostream& operator<< (std::ostream& os, const Matrix<T,O,S>& M) 05010 { 05011 /* This function take two passes to figure out appropriate field 05012 * widths. Speed isn't really the point here. 05013 */ 05014 05015 // Store previous io settings 05016 std::ios_base::fmtflags preop = os.flags(); 05017 05018 uint mlen = os.width(); 05019 std::ostringstream oss; 05020 oss.precision(os.precision()); 05021 oss << std::setiosflags(std::ios::fixed); 05022 05023 typename Matrix<T,O,S>::const_forward_iterator last = M.end_f(); 05024 for (typename Matrix<T,O,S>::const_forward_iterator i = M.begin_f(); 05025 i != last; ++i) { 05026 oss.str(""); 05027 oss << (*i); 05028 if (oss.str().length() > mlen) 05029 mlen = oss.str().length(); 05030 } 05031 05032 05033 /* Write the stream */ 05034 // Change to a fixed with format. Users should control precision 05035 os << std::setiosflags(std::ios::fixed); 05036 05037 05038 for (uint i = 0; i < M.rows(); ++i) { 05039 Matrix<T, O, View> row = M(i, _); 05040 //for (uint i = 0; i < row.size(); ++i) 05041 // os << std::setw(mlen) << row[i] << " "; 05042 typename Matrix<T,O,View>::const_forward_iterator row_last 05043 = row.end_f(); 05044 for (typename 05045 Matrix<T,O,View>::forward_iterator el = row.begin_f(); 05046 el != row_last; ++el) { 05047 os << std::setw(mlen) << *el << " "; 05048 } 05049 os << std::endl; 05050 } 05051 05052 05053 // Restore pre-op flags 05054 os.flags(preop); 05055 05056 return os; 05057 } 05058 05059 #ifdef SCYTHE_LAPACK 05060 /* A template specialization of operator* for col-major, concrete 05061 * matrices of doubles that is only visible when a LAPACK library is 05062 * available. This function is an analog of the above function and 05063 * the above doxygen documentation serves for both. 05064 * 05065 * This needs to go below % so it can see the template definition 05066 * (since it isn't actually in the template itself. 05067 */ 05068 05069 template<> 05070 inline Matrix<> 05071 operator*<double,Col,Concrete,Col,Concrete> 05072 (const Matrix<>& lhs, const Matrix<>& rhs) 05073 { 05074 if (lhs.size() == 1 || rhs.size() == 1) 05075 return (lhs % rhs); 05076 05077 SCYTHE_DEBUG_MSG("Using lapack/blas for matrix multiplication"); 05078 SCYTHE_CHECK_10 (lhs.cols() != rhs.rows(), 05079 scythe_conformation_error, 05080 "Matrices with dimensions (" << lhs.rows() 05081 << ", " << lhs.cols() 05082 << ") and (" << rhs.rows() << ", " << rhs.cols() 05083 << ") are not multiplication-conformable"); 05084 05085 Matrix<> result (lhs.rows(), rhs.cols(), false); 05086 05087 // Get pointers to the internal arrays and set up some vars 05088 double* lhspnt = lhs.getArray(); 05089 double* rhspnt = rhs.getArray(); 05090 double* resultpnt = result.getArray(); 05091 const double one(1.0); 05092 const double zero(0.0); 05093 int rows = (int) lhs.rows(); 05094 int cols = (int) rhs.cols(); 05095 int innerDim = (int) rhs.rows(); 05096 05097 // Call the lapack routine. 05098 lapack::dgemm_("N", "N", &rows, &cols, &innerDim, &one, lhspnt, 05099 &rows, rhspnt, &innerDim, &zero, resultpnt, &rows); 05100 05101 return result; 05102 } 05103 #endif 05104 05105 } // end namespace scythe 05106 05107 #endif /* SCYTHE_MATRIX_H */