Scythe-1.0.3
matrix.h
Go to the documentation of this file.
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 */