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           referenceNew(M.size());
01280           scythe::copy<ORDER,ORDER>(M, *this);
01281         } else // STYLE == View
01282           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           referenceNew(M.size());
01327           scythe::copy<ORDER,ORDER> (M, *this);
01328         } else // STYLE == View
01329           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           referenceOther(M);
01478           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 
01891       /**** ASSIGNMENT OPERATORS ****/
01892 
01893        /*
01894        * As with the copy constructor, we need to
01895        * explicitly define the same-order-same-style assignment
01896        * operator or the default operator will take over.
01897        *
01898        * TODO With views, it may be desirable to auto-grow (and,
01899        * technically, detach) views to the null matrix.  This means
01900        * you can write something like:
01901        *
01902        * Matrix<double, Col, View> X;
01903        * X = ...
01904        *
01905        * and not run into trouble because you didn't presize.  Still,
01906        * not sure this won't encourage silly mistakes...need to think
01907        * about it.
01908        */
01909 
01959       Matrix& operator= (const Matrix& M)
01960       {
01961         if (STYLE == Concrete) {
01962           resize2Match(M);
01963           scythe::copy<ORDER,ORDER> (M, *this);
01964         } else {
01965 #ifndef SCYTHE_VIEW_ASSIGNMENT_RECYCLE
01966           SCYTHE_CHECK_10 (Base::size() != M.size(),
01967               scythe_conformation_error,
01968               "LHS has dimensions (" << Base::rows() 
01969               << ", " << Base::cols()
01970               << ") while RHS has dimensions (" << M.rows() << ", "
01971               << M.cols() << ")");
01972 
01973           scythe::copy<ORDER,ORDER> (M, *this);
01974 #else
01975           copy_recycle<ORDER,ORDER>(M, *this);
01976 #endif
01977         }
01978 
01979         return *this;
01980       }
01981       
02032       template <matrix_order O, matrix_style S>
02033       Matrix &operator= (const Matrix<T_type, O, S> &M)
02034       {
02035         if (STYLE == Concrete) {
02036           resize2Match(M);
02037           scythe::copy<ORDER,ORDER> (M, *this);
02038         } else {
02039 #ifndef SCYTHE_VIEW_ASSIGNMENT_RECYCLE
02040           SCYTHE_CHECK_10 (Base::size() != M.size(),
02041               scythe_conformation_error,
02042               "LHS has dimensions (" << Base::rows() 
02043               << ", " << Base::cols()
02044               << ") while RHS has dimensions (" << M.rows() << ", "
02045               << M.cols() << ")");
02046 
02047           scythe::copy<ORDER,ORDER> (M, *this);
02048 #else
02049           copy_recycle<ORDER,ORDER>(M, *this);
02050 #endif
02051         }
02052 
02053         return *this;
02054       }
02055       
02056       /* List-wise initialization behavior is a touch complicated.
02057        * List needs to be less than or equal to matrix in size and it
02058        * is copied into the matrix with R-style recycling.
02059        *
02060        * The one issue is that, if you want true assignment of a
02061        * scalar to a concrete matrix (resize the matrix to a scalar)
02062        * you need to be explicit:
02063        *
02064        * Matrix<> A(2, 2);
02065        * double x = 3;
02066        * ...
02067        * A = Matrix<>(x); // -> 3
02068        *
02069        * A = x; // -> 3 3
02070        *        //    3 3
02071        */
02072 
02103       ListInitializer<T_type, iterator, ORDER, STYLE> 
02104       operator=(T_type x)
02105       {
02106         return (ListInitializer<T_type, iterator, ORDER, STYLE> 
02107           (x, begin(),end(), this));
02108       }
02109 
02137       template <typename ITERATOR, matrix_order O, matrix_style S>
02138       Matrix &operator=(ListInitializer<T_type, ITERATOR, O, S> li)
02139       {
02140         li.populate();
02141         *this = *(li.matrix_);
02142         return *this;
02143       }
02144 
02145       /**** ARITHMETIC OPERATORS ****/
02146 
02147     private:
02148       /* Reusable chunk of code for element-wise operator
02149        * assignments.  Updates are done in-place except for the 1x1 by
02150        * nXm case, which forces a resize.
02151        */
02152       template <typename OP, matrix_order O, matrix_style S>
02153       inline Matrix&
02154       elementWiseOperatorAssignment (const Matrix<T_type, O, S>& M, 
02155                                      OP op)
02156       {
02157         SCYTHE_CHECK_10 (Base::size() != 1 && M.size() != 1 && 
02158             (Base::rows () != M.rows() || Base::cols() != M.cols()),
02159             scythe_conformation_error,
02160             "Matrices with dimensions (" << Base::rows() 
02161             << ", " << Base::cols()
02162             << ") and (" << M.rows() << ", " << M.cols()
02163             << ") are not conformable");
02164         
02165         if (Base::size() == 1) { // 1x1 += nXm
02166           T_type tmp = (*this)(0);
02167           resize2Match(M);
02168           std::transform(M.begin_f<ORDER>(), M.end_f<ORDER>(), 
02169               begin_f(), std::bind1st(op, tmp));
02170         } else if (M.size() == 1) { // nXm += 1x1
02171           std::transform(begin_f(), end_f(), begin_f(),
02172               std::bind2nd(op, M(0)));
02173         } else { // nXm += nXm
02174             std::transform(begin_f(), end_f(), M.begin_f<ORDER>(), 
02175                 begin_f(), op);
02176         }
02177 
02178         return *this;
02179       }
02180 
02181     public:
02201       template <matrix_order O, matrix_style S>
02202       inline Matrix& operator+= (const Matrix<T_type, O, S> &M)
02203       {
02204         return elementWiseOperatorAssignment(M, std::plus<T_type> ());
02205       }
02206 
02223       inline Matrix& operator+= (T_type x)
02224       {
02225         return elementWiseOperatorAssignment(Matrix(x), 
02226             std::plus<T_type> ());
02227       }
02228       
02248       template <matrix_order O, matrix_style S>
02249       inline Matrix& operator-= (const Matrix<T_type, O, S> &M)
02250       {
02251         return elementWiseOperatorAssignment(M, std::minus<T_type> ());
02252       }
02253 
02270       inline Matrix& operator-= (T_type x)
02271       {
02272         return elementWiseOperatorAssignment(Matrix(x), 
02273             std::minus<T_type> ());
02274       }
02275       
02300       template <matrix_order O, matrix_style S>
02301       inline Matrix& operator%= (const Matrix<T_type, O, S> &M)
02302       {
02303         return elementWiseOperatorAssignment(M, 
02304             std::multiplies<T_type> ());
02305       }
02306 
02323       inline Matrix& operator%= (T_type x)
02324       {
02325         return elementWiseOperatorAssignment(Matrix(x), 
02326             std::multiplies<T_type> ());
02327       }
02328       
02349       template <matrix_order O, matrix_style S>
02350       inline Matrix& operator/= (const Matrix<T_type, O, S> &M)
02351       {
02352         return elementWiseOperatorAssignment(M, std::divides<T_type>());
02353       }
02354 
02371       inline Matrix& operator/= (T_type x)
02372       {
02373         return elementWiseOperatorAssignment(Matrix(x), 
02374             std::divides<T_type> ());
02375       }
02376 
02397       template <matrix_order O, matrix_style S>
02398       inline Matrix& operator^= (const Matrix<T_type, O, S> &M)
02399       {
02400         return elementWiseOperatorAssignment(M, 
02401             exponentiate<T_type>());
02402       }
02403 
02420       inline Matrix& operator^= (T_type x)
02421       {
02422         return elementWiseOperatorAssignment(Matrix(x), 
02423             exponentiate<T_type> ());
02424       }
02425 
02426       /* Matrix mult always disengages views because it generally
02427        * requires a resize.  We force a disengage in the one place it
02428        * isn't absolutely necessary(this->size()==1), for consistency.
02429        */
02430 
02461       template <matrix_order O, matrix_style S>
02462       Matrix& operator*= (const Matrix<T_type, O, S>& M)
02463       {
02464         /* Farm out the work to the plain old * operator and make this
02465          * matrix a reference (the only reference) to the result.  We
02466          * always have to create a new matrix here, so there is no
02467          * speed-up from using *=.
02468          */
02469         
02470         /* This saves a copy over 
02471          * *this = (*this) * M;
02472          * if we're concrete
02473          */
02474         Matrix<T_type, ORDER> res = (*this) * M;
02475         referenceOther(res);
02476         mimic(res);
02477 
02478         return *this;
02479       }
02480 
02504       inline Matrix& operator*= (T_type x)
02505       {
02506         return elementWiseOperatorAssignment(Matrix(x), 
02507             std::multiplies<T_type> ());
02508       }
02509 
02534       template <matrix_order O, matrix_style S> Matrix& kronecker
02535         (const Matrix<T_type, O, S>& M) { uint totalrows =
02536           Base::rows() * M.rows(); uint totalcols = Base::cols() *
02537             M.cols();
02538         // Even if we're a view, make this guy concrete.
02539         Matrix<T_type,ORDER> res(totalrows, totalcols, false);
02540 
02541         /* TODO: This the most natural way to write this in scythe
02542          * (with a small optimization based on ordering) but probably
02543          * not the fastest because it uses submatrix assignments.
02544          * Optimizations should be considered.
02545          */
02546         forward_iterator it = begin_f();
02547         if (ORDER == Row) {
02548           for (uint row = 0; row < totalrows; row += M.rows()) {
02549             for (uint col = 0; col < totalcols; col += M.cols()){
02550               res(row, col, row + M.rows() - 1, col + M.cols() - 1)
02551                  = (*it) * M;
02552               it++;
02553             }
02554           }
02555         } else {
02556           for (uint col = 0; col < totalcols; col += M.cols()) {
02557             for (uint row = 0; row < totalrows; row += M.rows()){
02558               res(row, col, row + M.rows() - 1, col + M.cols() - 1)
02559                 = (*it) * M;
02560               it++;
02561             }
02562           }
02563         }
02564        
02565         referenceOther(res);
02566         mimic(res);
02567 
02568         return *this;
02569       }
02570         
02592       inline Matrix& kronecker (T_type x)
02593       {
02594         return elementWiseOperatorAssignment(Matrix(x), 
02595             std::multiplies<T_type> ());
02596       }
02597 
02598       /* Logical assignment operators */
02599 
02619       template <matrix_order O, matrix_style S>
02620       inline Matrix& operator&= (const Matrix<T_type, O, S> &M)
02621       {
02622         return elementWiseOperatorAssignment(M, 
02623             std::logical_and<T_type>());
02624       }
02625 
02642       inline Matrix& operator&= (T_type x)
02643       {
02644         return elementWiseOperatorAssignment(Matrix(x), 
02645             std::logical_and<T_type> ());
02646       }
02647 
02667       template <matrix_order O, matrix_style S>
02668       inline Matrix& operator|= (const Matrix<T_type, O, S> &M)
02669       {
02670         return elementWiseOperatorAssignment(M, 
02671             std::logical_or<T_type>());
02672       }
02673 
02690       inline Matrix& operator|= (T_type x)
02691       {
02692         return elementWiseOperatorAssignment(Matrix(x), 
02693             std::logical_or<T_type> ());
02694       }
02695 
02696       /**** MODIFIERS ****/
02697 
02698       /* Resize a matrix view.  resize() takes dimensions as
02699        * parameters while resize2Match() takes a matrix reference and
02700        * uses its dimensions.
02701        */
02702 
02732       void resize (uint rows, uint cols, bool preserve=false)
02733       {
02734         if (preserve) {
02735           /* TODO Optimize this case.  It is rather clunky. */
02736           Matrix<T_type, ORDER, View> tmp(*this);
02737           DBRef::referenceNew(rows * cols);
02738           Base::resize(rows, cols);
02739           uint min_cols = std::min(Base::cols(), tmp.cols());
02740           uint min_rows = std::min(Base::rows(), tmp.rows());
02741 
02742           // TODO use iterators here perhaps
02743           if (ORDER == Col) {
02744             for (uint j = 0; j < min_cols; ++j)
02745               for (uint i = 0; i < min_rows; ++i)
02746                 (*this)(i, j) = tmp(i, j);
02747           } else {
02748             for (uint i = 0; i < min_rows; ++i)
02749               for (uint j = 0; j < min_cols; ++j)
02750                 (*this)(i, j) = tmp(i, j);
02751           }
02752         } else {
02753           DBRef::referenceNew(rows * cols);
02754           Base::resize(rows, cols);
02755         }
02756       }
02757 
02773       template <typename T, matrix_order O, matrix_style S>
02774       inline void resize2Match(const Matrix<T, O, S> &M,
02775                                bool preserve=false)
02776       {
02777         resize(M.rows(), M.cols(), preserve);
02778       }
02779 
02780       /* Copy this matrix to a new datablock in contiguous storage */
02798       inline void detach ()
02799       {
02800         resize2Match(*this, true);
02801       }
02802 
02803       /* Swap operator: sort of a dual copy constructor.  Part of the
02804        * standard STL container interface. We only support swaps
02805        * between matrices of like order and style because things get
02806        * hairy otherwise.  The behavior of this for concrete matrices
02807        * is a little hairy in any case.
02808        *
02809        * Matrix<> A, B;
02810        * ... // fill in A and B
02811        * Matrix<double, Col, View> v1 = A(_, 1);
02812        * A.swap(B);
02813        * Matrix<double, Col, View> v2 = B(_, 1);
02814        * 
02815        * v1 == v2; // evaluates to true
02816        *
02817        */
02818 
02834       inline void swap (Matrix &M)
02835       {
02836         Matrix tmp = *this;
02837 
02838         /* This are just reference() calls, but we do this explicitly
02839          * here to avoid throwing errors on the concrete case.  While
02840          * having a concrete matrix reference another matrix is
02841          * generally a bad idea, it is safe when the referenced matrix
02842          * is concrete, has the same order, and gets deallocated (or
02843          * redirected at another block) like here.
02844          */
02845 
02846         referenceOther(M);
02847         mimic(M);
02848 
02849         M.referenceOther(tmp);
02850         M.mimic(tmp);
02851       }
02852 
02853       /**** ACCESSORS ****/
02854 
02855       /* Accessors that don't access the data itself (that don't rely
02856        * on T_type) are in Matrix_base
02857        */
02858 
02859       /* Are all the elements of this Matrix == 0 */
02860 
02869       inline bool isZero () const
02870       {
02871         const_forward_iterator last = end_f();
02872         return (last == std::find_if(begin_f(), last, 
02873           std::bind1st(std::not_equal_to<T_type> (), 0)));
02874       }
02875 
02876       /* M(i,j) == 0 when i != j */
02888       inline bool isDiagonal() const
02889       {
02890         if (! Base::isSquare())
02891           return false;
02892         /* Always travel in order.  It would be nice to use iterators
02893          * here, but we'd need to take views and their iterators are
02894          * too slow at the moment.
02895          * TODO redo with views and iterators if optimized.
02896          */
02897         if (ORDER == Row) {
02898           for (uint i = 0; i < Base::rows(); ++i) {
02899             for (uint j = 0; j < Base::cols(); ++j) {
02900               if (i != j && (*this)(i, j) != 0)
02901                 return false;
02902             }
02903           }
02904         } else { // ORDER == Col
02905           for (uint j = 0; j < Base::cols(); ++j) {
02906             for (uint i = 0; i < Base::rows(); ++i) {
02907               if (i != j && (*this)(i, j) != 0)
02908                 return false;
02909             }
02910           }
02911         }
02912         return true;
02913       }
02914 
02915       /* M(I, j) == 0 when i!= j and 1 when i == j */
02927       inline bool isIdentity () const
02928       {
02929         if (! Base::isSquare())
02930           return false;
02931         // TODO redo with views and iterator if optimized
02932         if (ORDER == Row) {
02933           for (uint i = 0; i < Base::rows(); ++i) {
02934             for (uint j = 0; j < Base::cols(); ++j) {
02935               if (i != j) {
02936                 if ((*this)(i,j) != 0)
02937                   return false;
02938               } else if ((*this)(i,j) != 1)
02939                 return false;
02940             }
02941           }
02942         } else { // ORDER == Col
02943           for (uint j = 0; j < Base::rows(); ++j) {
02944             for (uint i = 0; i < Base::cols(); ++i) {
02945               if (i != j) {
02946                 if ((*this)(i,j) != 0)
02947                   return false;
02948               } else if ((*this)(i,j) != 1)
02949                 return false;
02950             }
02951           }
02952         }
02953         return true;
02954       }
02955 
02956       /* M(i,j) == 0 when i < j */
02966       inline bool isLowerTriangular () const
02967       {
02968         // TODO view+iterator if optimized
02969         if (ORDER == Row) {
02970           for (uint i = 0; i < Base::rows(); ++i)
02971             for (uint j = i + 1; j < Base::cols(); ++j)
02972               if ((*this)(i,j) != 0)
02973                 return false;
02974         } else {
02975           for (uint j = 0; j < Base::cols(); ++j)
02976             for (uint i = 0; i < j; ++i)
02977               if ((*this)(i,j) != 0)
02978                 return false;
02979        }
02980         return true;
02981       }
02982 
02983       /* M(i,j) == 0 when i > j */
02993       inline bool isUpperTriangular () const
02994       {
02995         // TODO view+iterator if optimized
02996         if (ORDER == Row) {
02997           for (uint i = 0; i < Base::rows(); ++i)
02998             for (uint j = 0; j < i; ++j)
02999               if ((*this)(i,j) != 0)
03000                 return false;
03001         } else {
03002           for (uint j = 0; j < Base::cols(); ++j)
03003             for (uint i = j + 1; i < Base::rows(); ++i)
03004               if ((*this)(i,j) != 0)
03005                 return false;
03006        }
03007         return true;
03008       }
03009 
03016       inline bool isSingular() const
03017       {
03018         if (! Base::isSquare() || Base::isNull())
03019           return false;
03020         if ((~(*this)) == (T_type) 0)
03021           return true;
03022         return false;
03023       }
03024 
03025       /* Square and t(M) = M(inv(M) * t(M) == I */
03035       inline bool isSymmetric () const
03036       {
03037         if (! Base::isSquare())
03038           return false;
03039         // No point in order optimizing here
03040         for (uint i = 1; i < Base::rows(); ++i)
03041           for (uint j = 0; j < i; ++j)
03042             if ((*this)(i, j) != (*this)(j, i))
03043               return false;
03044 
03045         return true;
03046       }
03047 
03048       /* The matrix is square and t(A) = -A */
03059       inline bool isSkewSymmetric () const
03060       {
03061         if (! Base::isSquare())
03062           return false;
03063         // No point in order optimizing here
03064         for (uint i = 1; i < Base::rows(); ++i)
03065           for (uint j = 0; j < i; ++j)
03066             if ((*this)(i, j) != 0 - (*this)(j, i))
03067               return false;
03068 
03069         return true;
03070       }
03071 
03084       template <matrix_order O, matrix_style S>
03085       inline bool
03086       equals(const Matrix<T_type, O, S>& M) const
03087       {
03088         if (data_ == M.data_ && STYLE == Concrete && S == Concrete)
03089           return true;
03090         else if (data_ == M.data_ && Base::rows() == M.rows() 
03091                  && Base::cols() == M.cols()) {
03092           return true;
03093         } else if (this->isNull() && M.isNull())
03094           return true;
03095         else if (Base::rows() != M.rows() || Base::cols() != M.cols())
03096           return false;
03097 
03098         return std::equal(begin_f(), end_f(),
03099             M.template begin_f<ORDER>());
03100       }
03101 
03112       inline bool
03113       equals(T_type x) const
03114       {
03115         const_forward_iterator last = end_f();
03116         return (last == std::find_if(begin_f(), last, 
03117           std::bind1st(std::not_equal_to<T_type> (), x)));
03118       }
03119 
03120 
03121       /**** OTHER UTILITIES ****/
03122 
03138       inline T_type* getArray () const
03139       {
03140         return data_;
03141       }
03142 
03167       inline void
03168       save (const std::string& path, const char flag = 'n',
03169             const bool header = false)
03170       {
03171         std::ofstream out;
03172         if (flag == 'n') {
03173           std::fstream temp(path.c_str(), std::ios::in);
03174           if (! temp)
03175             out.open(path.c_str(), std::ios::out);
03176           else {
03177             temp.close();
03178             SCYTHE_THROW(scythe_file_error, "Cannot overwrite file "
03179                 << path << " when flag = n");
03180           }
03181         } else if (flag == 'o')
03182           out.open(path.c_str(), std::ios::out | std::ios::trunc);
03183         else if (flag == 'a')
03184           out.open(path.c_str(), std::ios::out | std::ios::app);
03185         else
03186           SCYTHE_THROW(scythe_invalid_arg, "Invalid flag: " << flag);
03187 
03188         if (! out)
03189           SCYTHE_THROW(scythe_file_error, 
03190               "Could not open file " << path); 
03191 
03192         if (header) {
03193           out << Base::rows() << " " << Base::cols();
03194           for (uint i = 0; i < Base::size(); ++i)
03195             out << " " << (*this)[i];
03196           out << std::endl;
03197         } else {
03198           for (uint i = 0; i < Base::rows(); ++i) {
03199             for (uint j = 0; j < Base::cols(); ++j)
03200               out << (*this)(i,j) << " ";
03201             out << "\n";
03202           }
03203         }
03204         out.close();
03205       }
03206 
03207 
03208       /**** ITERATOR FACTORIES ****/
03209 
03210       /* TODO Write some cpp macro code to reduce this to something
03211        * manageable.
03212        */
03213 
03214       /* Random Access Iterator Factories */
03215       
03216       /* Generalized versions */
03217 
03227       template <matrix_order I_ORDER>
03228       inline 
03229       matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE>
03230       begin ()
03231       {
03232         return matrix_random_access_iterator<T_type, I_ORDER, ORDER,
03233                                              STYLE>(*this);
03234       }
03235       
03246       template <matrix_order I_ORDER>
03247       inline
03248       const_matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE>
03249       begin() const
03250       {
03251         return const_matrix_random_access_iterator<T_type, I_ORDER,
03252                                                    ORDER, STYLE>
03253           (*this);
03254       }
03255 
03266       template <matrix_order I_ORDER>
03267       inline 
03268       matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE>
03269       end ()
03270       {
03271         return (begin<I_ORDER>() + Base::size());
03272       }
03273       
03284       template <matrix_order I_ORDER>
03285       inline 
03286       const_matrix_random_access_iterator<T_type, I_ORDER, ORDER, STYLE>
03287       end () const
03288       {
03289         return (begin<I_ORDER>() + Base::size());
03290       }
03291 
03302       template <matrix_order I_ORDER>
03303       inline std::reverse_iterator<matrix_random_access_iterator<T_type,
03304                                    I_ORDER, ORDER, STYLE> >
03305       rbegin()
03306       {
03307         return std::reverse_iterator<matrix_random_access_iterator
03308                                      <T_type, I_ORDER, ORDER, STYLE> > 
03309                (end<I_ORDER>());
03310       }
03311 
03322       template <matrix_order I_ORDER>
03323       inline 
03324       std::reverse_iterator<const_matrix_random_access_iterator
03325                             <T_type, I_ORDER, ORDER, STYLE> > 
03326       rbegin() const
03327       {
03328         return std::reverse_iterator<const_matrix_random_access_iterator
03329                                      <T_type, I_ORDER, ORDER, STYLE> > 
03330         (end<I_ORDER>());
03331       }
03332 
03344       template <matrix_order I_ORDER>
03345       inline std::reverse_iterator<matrix_random_access_iterator
03346                                    <T_type, I_ORDER, ORDER, STYLE> >
03347       rend()
03348       {
03349         return std::reverse_iterator<matrix_random_access_iterator
03350                                      <T_type, I_ORDER, ORDER, STYLE> > 
03351                (begin<I_ORDER>());
03352       }
03353 
03364       template <matrix_order I_ORDER>
03365       inline 
03366       std::reverse_iterator<const_matrix_random_access_iterator
03367                             <T_type, I_ORDER, ORDER, STYLE> > 
03368       rend() const
03369       {
03370         return std::reverse_iterator<const_matrix_random_access_iterator
03371                                      <T_type, I_ORDER, ORDER, STYLE> > 
03372           (begin<I_ORDER>());
03373       }
03374 
03375       /* Specific versions --- the generalized versions force you
03376        * choose the ordering explicitly.  These definitions set up
03377        * in-order iteration as a default */
03378       
03390       inline iterator begin ()
03391       {
03392         return iterator(*this);
03393       }
03394       
03406       inline const_iterator begin() const
03407       {
03408         return const_iterator (*this);
03409       }
03410 
03422       inline iterator end ()
03423       {
03424         return (begin() + Base::size());
03425       }
03426       
03438       inline 
03439       const_iterator end () const
03440       {
03441         return (begin() + Base::size());
03442       }
03443 
03455       inline reverse_iterator rbegin()
03456       {
03457         return reverse_iterator (end());
03458       }
03459 
03472       inline const_reverse_iterator rbegin() const
03473       {
03474         return const_reverse_iterator (end());
03475       }
03476 
03489       inline reverse_iterator rend()
03490       {
03491         return reverse_iterator (begin());
03492       }
03493 
03506       inline const_reverse_iterator rend() const
03507       {
03508         return const_reverse_iterator (begin());
03509       }
03510 
03511       /* Forward Iterator Factories */
03512 
03513       /* Generalized versions */
03514 
03524       template <matrix_order I_ORDER>
03525       inline 
03526       matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE>
03527       begin_f ()
03528       {
03529         return matrix_forward_iterator<T_type, I_ORDER, ORDER,
03530                                              STYLE>(*this);
03531       }
03532       
03543       template <matrix_order I_ORDER>
03544       inline
03545       const_matrix_forward_iterator <T_type, I_ORDER, ORDER, STYLE>
03546       begin_f () const
03547       {
03548         return const_matrix_forward_iterator <T_type, I_ORDER,
03549                                                    ORDER, STYLE>
03550           (*this);
03551       }
03552 
03562       template <matrix_order I_ORDER>
03563       inline 
03564       matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE>
03565       end_f ()
03566       {
03567         return (begin_f<I_ORDER>().set_end());
03568       }
03569       
03580       template <matrix_order I_ORDER>
03581       inline 
03582       const_matrix_forward_iterator<T_type, I_ORDER, ORDER, STYLE>
03583       end_f () const
03584       {
03585         return (begin_f<I_ORDER>().set_end());
03586       }
03587 
03588       /* Default Versions */
03589       
03601       inline forward_iterator begin_f ()
03602       {
03603         return forward_iterator(*this);
03604       }
03605       
03618       inline const_forward_iterator begin_f () const
03619       {
03620         return const_forward_iterator (*this);
03621       }
03622 
03634       inline forward_iterator end_f ()
03635       {
03636         return (begin_f().set_end());
03637       }
03638       
03651       inline 
03652       const_forward_iterator end_f () const
03653       {
03654         return (begin_f().set_end());
03655       }
03656 
03657       /* Bidirectional Iterator Factories */
03658 
03659       /* Generalized versions */
03660 
03671       template <matrix_order I_ORDER>
03672       inline 
03673       matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE>
03674       begin_bd ()
03675       {
03676         return matrix_bidirectional_iterator<T_type, I_ORDER, ORDER,
03677                                              STYLE>(*this);
03678       }
03679       
03690       template <matrix_order I_ORDER>
03691       inline
03692       const_matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE>
03693       begin_bd () const
03694       {
03695         return const_matrix_bidirectional_iterator<T_type, I_ORDER,
03696                                                    ORDER, STYLE>
03697           (*this);
03698       }
03699 
03710       template <matrix_order I_ORDER>
03711       inline 
03712       matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE>
03713       end_bd ()
03714       {
03715         return (begin_bd<I_ORDER>().set_end());
03716       }
03717       
03728       template <matrix_order I_ORDER>
03729       inline 
03730       const_matrix_bidirectional_iterator<T_type, I_ORDER, ORDER, STYLE>
03731       end_bd () const
03732       {
03733         return (begin_bd<I_ORDER>.set_end());
03734       }
03735 
03746       template <matrix_order I_ORDER>
03747       inline std::reverse_iterator<matrix_bidirectional_iterator<T_type,
03748                                    I_ORDER, ORDER, STYLE> >
03749       rbegin_bd ()
03750       {
03751         return std::reverse_iterator<matrix_bidirectional_iterator
03752                                      <T_type, I_ORDER, ORDER, STYLE> > 
03753                (end_bd<I_ORDER>());
03754       }
03755 
03766       template <matrix_order I_ORDER>
03767       inline 
03768       std::reverse_iterator<const_matrix_bidirectional_iterator
03769                             <T_type, I_ORDER, ORDER, STYLE> > 
03770       rbegin_bd () const
03771       {
03772         return std::reverse_iterator<const_matrix_bidirectional_iterator
03773                                      <T_type, I_ORDER, ORDER, STYLE> > 
03774         (end_bd<I_ORDER>());
03775       }
03776 
03788       template <matrix_order I_ORDER>
03789       inline std::reverse_iterator<matrix_bidirectional_iterator
03790                                    <T_type, I_ORDER, ORDER, STYLE> >
03791       rend_bd ()
03792       {
03793         return std::reverse_iterator<matrix_bidirectional_iterator
03794                                      <T_type, I_ORDER, ORDER, STYLE> > 
03795                (begin_bd<I_ORDER>());
03796       }
03797 
03808       template <matrix_order I_ORDER>
03809       inline 
03810       std::reverse_iterator<const_matrix_bidirectional_iterator
03811                             <T_type, I_ORDER, ORDER, STYLE> > 
03812       rend_bd () const
03813       {
03814         return std::reverse_iterator<const_matrix_bidirectional_iterator
03815                                      <T_type, I_ORDER, ORDER, STYLE> > 
03816           (begin_bd<I_ORDER>());
03817       }
03818 
03819       /* Specific versions --- the generalized versions force you
03820        * choose the ordering explicitly.  These definitions set up
03821        * in-order iteration as a default */
03822       
03835       inline bidirectional_iterator begin_bd ()
03836       {
03837         return bidirectional_iterator(*this);
03838       }
03839       
03852       inline const_bidirectional_iterator begin_bd() const
03853       {
03854         return const_bidirectional_iterator (*this);
03855       }
03856 
03869       inline bidirectional_iterator end_bd ()
03870       {
03871         return (begin_bd().set_end());
03872       }
03873       
03886       inline 
03887       const_bidirectional_iterator end_bd () const
03888       {
03889         return (begin_bd().set_end());
03890       }
03891 
03904       inline reverse_bidirectional_iterator rbegin_bd()
03905       {
03906         return reverse_bidirectional_iterator (end_bd());
03907       }
03908 
03921       inline const_reverse_bidirectional_iterator rbegin_bd () const
03922       {
03923         return const_reverse_bidirectional_iterator (end_bd());
03924       }
03925 
03938       inline reverse_bidirectional_iterator rend_bd ()
03939       {
03940         return reverse_bidirectional_iterator (begin_bd());
03941       }
03942 
03955       inline const_reverse_iterator rend_bd () const
03956       {
03957         return const_reverse_bidirectiona_iterator (begin_bd());
03958       }
03959 
03960     protected:
03961       /**** INSTANCE VARIABLES ****/
03962 
03963       /* I know the point of C++ is to force you to write 20 times
03964        * more code than should be necessary but "using" inherited ivs
03965        * is just stupid.
03966        */
03967       using DBRef::data_;  // refer to inherited data pointer directly 
03968       using Base::rows_;   // " # of rows directly
03969       using Base::cols_;   // " # of cols directly
03970 
03971   }; // end class Matrix
03972 
03973   /**** EXTERNAL OPERATORS ****/
03974 
03975   /* External operators include a range of binary matrix operations
03976    * such as tests for equality, and arithmetic.  Style
03977    * (concrete/view) of the returned matrix is that of the left hand
03978    * side parameter by default
03979    *
03980    * There is also a question of the ordering of the returned matrix.
03981    * We adopt the convention of returning a matrix ordered like that
03982    * of the left hand side argument, by default.
03983    *
03984    * Whenever there is only one matrix argument (lhs is scalar) we use
03985    * its order and style as the default.
03986    *
03987    * A general template version of each operator also exists and users
03988    * can coerce the return type to whatever they prefer using some
03989    * ugly syntax; ex:
03990    *
03991    * Matrix<> A; ...  Matrix<double, Row> B = operator*<Row,Concrete>
03992    *                                          (A, A);
03993    *
03994    * In general, the matrix class copy constructor will quietly
03995    * convert whatever matrix template is returned to the type of the
03996    * matrix it is being copied into on return, but one might want to
03997    * specify the type for objects that only exist for a second (ex:
03998    * (operator*<Row,Concrete>(A, A)).begin()).  Also, note that the
03999    * fact that we return concrete matrices by default does not
04000    * preclude the user from taking advantage of fast view copies.  It
04001    * is the template type of the object being copy-constructed that
04002    * matters---in terms of underlying implementation all matrices are
04003    * views, concrete matrices just maintain a particular policy.
04004    *
04005    * TODO Consider the best type for scalar args to these functions.
04006    * For the most part, these will be primitives---doubles mostly.
04007    * Passing these by reference is probably less efficient than
04008    * passing by value.  But, for user-defined types pass-by-reference
04009    * might be the way to go and the cost in this case will be much
04010    * higher than the value-reference trade-off for primitives.  Right
04011    * now we use pass-by-reference but we might reconsider...
04012    */
04013 
04014   /**** ARITHMETIC OPERATORS ****/
04015 
04016   /* These macros provide templates for the basic definitions required
04017    * for all of the binary operators.  Each operator requires 6
04018    * definitions.  First, a general matrix definition must be
04019    * provided.  This definition can return a matrix of a different
04020    * style and order than its arguments but can only be called if its
04021    * template type is explicitly specified.  The actual logic of the
04022    * operator should be specified within this function.  The macros
04023    * provide definitions for the other 5 required templates, one
04024    * default matrix by matrix, general matrix by scalar, default
04025    * matrix by scalar, general scalar by matrix, default scalar by
04026    * matrix.  The default versions call the more general versions with
04027    * such that they will return concrete matrices with order equal to
04028    * the left-hand (or only) matrix passed to the default version.
04029    *
04030    */
04031 
04032 #define SCYTHE_BINARY_OPERATOR_DMM(OP)                                \
04033   template <matrix_order ORDER, matrix_style L_STYLE,                 \
04034             matrix_order R_ORDER, matrix_style R_STYLE,               \
04035             typename T_type>                                          \
04036   inline Matrix<T_type, ORDER, Concrete>                              \
04037   OP (const Matrix<T_type, ORDER, L_STYLE>& lhs,                      \
04038       const Matrix<T_type, R_ORDER, R_STYLE>& rhs)                    \
04039   {                                                                   \
04040     return OP <T_type, ORDER, Concrete>(lhs, rhs);                    \
04041   }
04042 
04043 #define SCYTHE_BINARY_OPERATOR_GMS(OP)                                \
04044   template <typename T_type, matrix_order ORDER, matrix_style STYLE,  \
04045             matrix_order L_ORDER, matrix_style L_STYLE>               \
04046   inline Matrix<T_type, ORDER, STYLE>                                 \
04047   OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,                    \
04048       const typename Matrix<T_type>::ttype &rhs)                       \
04049   {                                                                   \
04050     return  (OP <T_type, ORDER, STYLE>                                \
04051         (lhs, Matrix<T_type, L_ORDER>(rhs)));                         \
04052   }
04053 
04054 #define SCYTHE_BINARY_OPERATOR_DMS(OP)                                \
04055   template <matrix_order ORDER, matrix_style L_STYLE,                 \
04056             typename T_type>                                          \
04057   inline Matrix<T_type, ORDER, Concrete>                              \
04058   OP (const Matrix<T_type, ORDER, L_STYLE>& lhs,                      \
04059       const typename Matrix<T_type>::ttype &rhs)                      \
04060   {                                                                   \
04061     return (OP <T_type, ORDER, Concrete> (lhs, rhs));                 \
04062   }
04063   
04064 #define SCYTHE_BINARY_OPERATOR_GSM(OP)                                \
04065   template <typename T_type, matrix_order ORDER, matrix_style STYLE,  \
04066             matrix_order R_ORDER, matrix_style R_STYLE>               \
04067   inline Matrix<T_type, ORDER, STYLE>                                 \
04068   OP (const typename Matrix<T_type>::ttype &lhs,                      \
04069       const Matrix<T_type, R_ORDER, R_STYLE>& rhs) \
04070   {                                                                   \
04071     return  (OP <T_type, ORDER, STYLE>                                \
04072         (Matrix<T_type, R_ORDER>(lhs), rhs));                         \
04073   }
04074 
04075 #define SCYTHE_BINARY_OPERATOR_DSM(OP)                                \
04076   template <matrix_order ORDER, matrix_style R_STYLE,                 \
04077             typename T_type>                                          \
04078   inline Matrix<T_type, ORDER, Concrete>                              \
04079   OP (const typename Matrix<T_type>::ttype &lhs,                      \
04080       const Matrix<T_type, ORDER, R_STYLE>& rhs)                      \
04081   {                                                                   \
04082     return (OP <T_type, ORDER, Concrete> (lhs, rhs));                 \
04083   }
04084 
04085 #define SCYTHE_BINARY_OPERATOR_DEFS(OP)                               \
04086   SCYTHE_BINARY_OPERATOR_DMM(OP)                                      \
04087   SCYTHE_BINARY_OPERATOR_GMS(OP)                                      \
04088   SCYTHE_BINARY_OPERATOR_DMS(OP)                                      \
04089   SCYTHE_BINARY_OPERATOR_GSM(OP)                                      \
04090   SCYTHE_BINARY_OPERATOR_DSM(OP)
04091 
04092   /* Matrix multiplication */
04093   
04094   /* General template version. Must be called with operator*<> syntax
04095    */
04096  
04097   /* We provide two symmetric algorithms for matrix multiplication,
04098    * one for col-major and the other for row-major matrices.  They are
04099    * designed to minimize cache misses.The decision is based on the
04100    * return type of the template so, when using matrices of multiple
04101    * orders, this can get ugly.  These optimizations only really start
04102    * paying dividends as matrices get big, because cache misses are
04103    * rare with smaller matrices.
04104    */
04105 
04153   template <typename T_type, matrix_order ORDER, matrix_style STYLE,
04154             matrix_order L_ORDER, matrix_style L_STYLE,
04155             matrix_order R_ORDER, matrix_style R_STYLE>
04156   inline Matrix<T_type, ORDER, STYLE>
04157   operator* (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,
04158              const Matrix<T_type, R_ORDER, R_STYLE>& rhs)
04159   {
04160     if (lhs.size() == 1 || rhs.size() == 1)
04161       return (lhs % rhs);
04162 
04163     SCYTHE_CHECK_10 (lhs.cols() != rhs.rows(),
04164         scythe_conformation_error,
04165         "Matrices with dimensions (" << lhs.rows() 
04166         << ", " << lhs.cols()
04167         << ") and (" << rhs.rows() << ", " << rhs.cols()
04168         << ") are not multiplication-conformable");
04169 
04170     Matrix<T_type, ORDER, Concrete> result (lhs.rows(), rhs.cols(), false);
04171 
04172     T_type tmp;
04173     if (ORDER == Col) { // col-major optimized
04174      for (uint j = 0; j < rhs.cols(); ++j) {
04175        for (uint i = 0; i < lhs.rows(); ++i)
04176         result(i, j) = (T_type) 0;
04177        for (uint l = 0; l < lhs.cols(); ++l) {
04178          tmp = rhs(l, j);
04179          for (uint i = 0; i < lhs.rows(); ++i)
04180            result(i, j) += tmp * lhs(i, l);
04181        }
04182      }
04183     } else { // row-major optimized
04184      for (uint i = 0; i < lhs.rows(); ++i) {
04185        for (uint j = 0; j < rhs.cols(); ++j)
04186          result(i, j) = (T_type) 0;
04187        for (uint l = 0; l < rhs.rows(); ++l) {
04188          tmp = lhs(i, l);
04189          for (uint j = 0; j < rhs.cols(); ++j)
04190            result(i, j) += tmp * rhs(l,j);
04191        }
04192      }
04193     }
04194 
04195     SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, result)
04196   }
04197 
04198   SCYTHE_BINARY_OPERATOR_DEFS(operator*)
04199 
04200   
04225   template <typename T_type, matrix_order ORDER, matrix_style STYLE,
04226             matrix_order L_ORDER, matrix_style L_STYLE,
04227             matrix_order R_ORDER, matrix_style R_STYLE>
04228   inline Matrix<T_type, ORDER, STYLE>
04229   kronecker (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,
04230              const Matrix<T_type, R_ORDER, R_STYLE>& rhs)
04231   {
04232     Matrix<T_type,ORDER,Concrete> res = lhs;
04233     res.kronecker(rhs);
04234     return (res);
04235   }
04236 
04237   SCYTHE_BINARY_OPERATOR_DEFS(kronecker)
04238 
04239   /* Macro definition for general return type templates of standard
04240    * binary operators (this handles, +, -, %, /, but not *)
04241    */
04242     
04243 #define SCYTHE_GENERAL_BINARY_OPERATOR(OP,FUNCTOR)                    \
04244   template <typename T_type, matrix_order ORDER, matrix_style STYLE,  \
04245             matrix_order L_ORDER, matrix_style L_STYLE,               \
04246             matrix_order R_ORDER, matrix_style R_STYLE>               \
04247   inline Matrix<T_type, ORDER, STYLE>                                 \
04248   OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,                    \
04249       const Matrix<T_type, R_ORDER, R_STYLE>& rhs)                    \
04250   {                                                                   \
04251     SCYTHE_CHECK_10(lhs.size() != 1 && rhs.size() != 1 &&             \
04252         (lhs.rows() != rhs.rows() || lhs.cols() != rhs.cols()),       \
04253         scythe_conformation_error,                                    \
04254         "Matrices with dimensions (" << lhs.rows()                    \
04255         << ", " << lhs.cols()                                         \
04256         << ") and (" << rhs.rows() << ", " << rhs.cols()              \
04257         << ") are not conformable");                                  \
04258                                                                       \
04259     if (lhs.size() == 1) {                                            \
04260       Matrix<T_type,ORDER,Concrete> res(rhs.rows(),rhs.cols(),false); \
04261       std::transform(rhs.begin_f(), rhs.end_f(),                      \
04262           res.template begin_f<R_ORDER>(),                            \
04263           std::bind1st(FUNCTOR <T_type>(), lhs(0)));                  \
04264       SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res)                   \
04265     }                                                                 \
04266                                                                       \
04267     Matrix<T_type,ORDER,Concrete> res(lhs.rows(), lhs.cols(), false); \
04268                                                                       \
04269     if (rhs.size() == 1) {                                            \
04270       std::transform(lhs.begin_f(), lhs.end_f(),                      \
04271           res.template begin_f<L_ORDER> (),                           \
04272           std::bind2nd(FUNCTOR <T_type>(), rhs(0)));                  \
04273     } else {                                                          \
04274       std::transform(lhs.begin_f(), lhs.end_f(),                      \
04275           rhs.template begin_f<L_ORDER>(),                            \
04276           res.template begin_f<L_ORDER>(),                            \
04277           FUNCTOR <T_type> ());                                       \
04278     }                                                                 \
04279                                                                       \
04280     SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res)                     \
04281   }
04282 
04283   /* Addition operators */
04284 
04315   SCYTHE_GENERAL_BINARY_OPERATOR (operator+, std::plus)
04316   SCYTHE_BINARY_OPERATOR_DEFS (operator+)
04317 
04318   /* Subtraction operators */
04319 
04350   SCYTHE_GENERAL_BINARY_OPERATOR (operator-, std::minus)
04351   SCYTHE_BINARY_OPERATOR_DEFS (operator-)
04352 
04353   /* Element-by-element multiplication operators */
04354 
04386   SCYTHE_GENERAL_BINARY_OPERATOR (operator%, std::multiplies)
04387   SCYTHE_BINARY_OPERATOR_DEFS(operator%)
04388 
04389   /* Element-by-element division */
04390 
04421   SCYTHE_GENERAL_BINARY_OPERATOR (operator/, std::divides)
04422   SCYTHE_BINARY_OPERATOR_DEFS (operator/)
04423 
04424   /* Element-by-element exponentiation */
04425 
04456   SCYTHE_GENERAL_BINARY_OPERATOR (operator^, exponentiate)
04457   SCYTHE_BINARY_OPERATOR_DEFS (operator^)
04458 
04459   /* Negation operators */
04460 
04461   // General return type version
04475   template <typename T_type, matrix_order R_ORDER, matrix_style R_STYLE,
04476             matrix_order ORDER, matrix_style STYLE>
04477   inline Matrix<T_type, R_ORDER, R_STYLE>
04478   operator- (const Matrix<T_type, ORDER, STYLE>& M)
04479   {
04480     Matrix<T_type, R_ORDER, Concrete> result(M.rows(), M.cols(), false);
04481     std::transform(M.template begin_f<ORDER>(), 
04482                    M.template end_f<ORDER>(), 
04483                    result.template begin_f<R_ORDER>(),
04484                    std::negate<T_type> ());
04485     SCYTHE_VIEW_RETURN(T_type, R_ORDER, R_STYLE, result)
04486   }
04487   
04488   // Default return type version
04489   template <matrix_order ORDER, matrix_style P_STYLE, typename T_type>
04490   inline Matrix<T_type, ORDER, Concrete>
04491   operator- (const Matrix<T_type, ORDER, P_STYLE>& M)
04492   {
04493     return operator-<T_type, ORDER, Concrete> (M);
04494   }
04495 
04496   /* Unary not operators */
04497 
04513   template <matrix_order R_ORDER, matrix_style R_STYLE, typename T_type,
04514             matrix_order ORDER, matrix_style STYLE>
04515   inline Matrix<bool, R_ORDER, R_STYLE>
04516   operator! (const Matrix<T_type, ORDER, STYLE>& M)
04517   {
04518     Matrix<bool, R_ORDER, Concrete> result(M.rows(), M.cols(), false);
04519     std::transform(M.template begin_f<ORDER>(), 
04520                    M.template end_f<ORDER>(), 
04521                    result.template begin_f<R_ORDER>(),
04522                    std::logical_not<T_type> ());
04523     SCYTHE_VIEW_RETURN(T_type, R_ORDER, R_STYLE, result)
04524   }
04525   
04526   // Default return type version
04527   template <typename T_type, matrix_order ORDER, matrix_style P_STYLE>
04528   inline Matrix<bool, ORDER, Concrete>
04529   operator! (const Matrix<T_type, ORDER, P_STYLE>& M)
04530   {
04531     return (operator!<ORDER, Concrete> (M));
04532   }
04533   /**** COMPARISON OPERATORS ****/
04534 
04535   /* These macros are analogous to those above, except they return
04536    * only boolean matrices and use slightly different template
04537    * parameter orderings.  Kind of redundant, but less confusing than
04538    * making omnibus macros that handle both cases.
04539    */
04540 #define SCYTHE_GENERAL_BINARY_BOOL_OPERATOR(OP,FUNCTOR)               \
04541   template <matrix_order ORDER, matrix_style STYLE, typename T_type,  \
04542             matrix_order L_ORDER, matrix_style L_STYLE,               \
04543             matrix_order R_ORDER, matrix_style R_STYLE>               \
04544   inline Matrix<bool, ORDER, STYLE>                                   \
04545   OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,                    \
04546       const Matrix<T_type, R_ORDER, R_STYLE>& rhs)                    \
04547   {                                                                   \
04548     SCYTHE_CHECK_10(lhs.size() != 1 && rhs.size() != 1 &&             \
04549         (lhs.rows() != rhs.rows() || lhs.cols() != rhs.cols()),       \
04550         scythe_conformation_error,                                    \
04551         "Matrices with dimensions (" << lhs.rows()                    \
04552         << ", " << lhs.cols()                                         \
04553         << ") and (" << rhs.rows() << ", " << rhs.cols()              \
04554         << ") are not conformable");                                  \
04555                                                                       \
04556     if (lhs.size() == 1) {                                            \
04557       Matrix<bool,ORDER,Concrete> res(rhs.rows(),rhs.cols(),false);   \
04558       std::transform(rhs.begin_f(), rhs.end_f(),                      \
04559           res.template begin_f<R_ORDER>(),                            \
04560           std::bind1st(FUNCTOR <T_type>(), lhs(0)));                  \
04561       SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res)                   \
04562     }                                                                 \
04563                                                                       \
04564     Matrix<bool,ORDER,Concrete> res(lhs.rows(), lhs.cols(), false);   \
04565                                                                       \
04566     if (rhs.size() == 1) {                                            \
04567       std::transform(lhs.begin_f(), lhs.end_f(),                      \
04568           res.template begin_f<L_ORDER> (),                           \
04569           std::bind2nd(FUNCTOR <T_type>(), rhs(0)));                  \
04570     } else {                                                          \
04571       std::transform(lhs.begin_f(), lhs.end_f(),                      \
04572           rhs.template begin_f<L_ORDER>(),                            \
04573           res.template begin_f<L_ORDER>(),                            \
04574           FUNCTOR <T_type> ());                                       \
04575     }                                                                 \
04576                                                                       \
04577     SCYTHE_VIEW_RETURN(T_type, ORDER, STYLE, res)                     \
04578   }
04579 
04580 #define SCYTHE_BINARY_BOOL_OPERATOR_DMM(OP)                           \
04581   template <typename T_type, matrix_order ORDER, matrix_style L_STYLE,\
04582             matrix_order R_ORDER, matrix_style R_STYLE>               \
04583   inline Matrix<bool, ORDER, Concrete>                                \
04584   OP (const Matrix<T_type, ORDER, L_STYLE>& lhs,                      \
04585              const Matrix<T_type, R_ORDER, R_STYLE>& rhs)             \
04586   {                                                                   \
04587     return OP <ORDER, Concrete>(lhs, rhs);                            \
04588   }
04589 
04590 #define SCYTHE_BINARY_BOOL_OPERATOR_GMS(OP)                           \
04591   template <matrix_order ORDER, matrix_style STYLE, typename T_type,  \
04592             matrix_order L_ORDER, matrix_style L_STYLE>               \
04593   inline Matrix<bool, ORDER, STYLE>                                   \
04594   OP (const Matrix<T_type, L_ORDER, L_STYLE>& lhs,                    \
04595       const typename Matrix<T_type>::ttype &rhs)                      \
04596   {                                                                   \
04597     return  (OP <ORDER, STYLE>                                        \
04598         (lhs, Matrix<T_type, L_ORDER>(rhs)));                         \
04599   }
04600 
04601 #define SCYTHE_BINARY_BOOL_OPERATOR_DMS(OP)                           \
04602   template <typename T_type, matrix_order ORDER, matrix_style L_STYLE>\
04603   inline Matrix<bool, ORDER, Concrete>                                \
04604   OP (const Matrix<T_type, ORDER, L_STYLE>& lhs,                      \
04605       const typename Matrix<T_type>::ttype &rhs)                      \
04606   {                                                                   \
04607     return (OP <ORDER, Concrete> (lhs, rhs));                         \
04608   }
04609   
04610 #define SCYTHE_BINARY_BOOL_OPERATOR_GSM(OP)                           \
04611   template <matrix_order ORDER, matrix_style STYLE, typename T_type,  \
04612             matrix_order R_ORDER, matrix_style R_STYLE>               \
04613   inline Matrix<bool, ORDER, STYLE>                                   \
04614   OP (const typename Matrix<T_type>::ttype &lhs,                      \
04615       const Matrix<T_type, R_ORDER, R_STYLE>& rhs)                    \
04616   {                                                                   \
04617     return  (OP <ORDER, STYLE>                                        \
04618         (Matrix<T_type, R_ORDER>(lhs), rhs));                         \
04619   }
04620 
04621 #define SCYTHE_BINARY_BOOL_OPERATOR_DSM(OP)                           \
04622   template <typename T_type, matrix_order ORDER, matrix_style R_STYLE>\
04623   inline Matrix<bool, ORDER, Concrete>                                \
04624   OP (const typename Matrix<T_type>::ttype &lhs,                      \
04625       const Matrix<T_type, ORDER, R_STYLE>& rhs)                      \
04626   {                                                                   \
04627     return (OP <ORDER, Concrete> (lhs, rhs));                         \
04628   }
04629 
04630 #define SCYTHE_BINARY_BOOL_OPERATOR_DEFS(OP)                          \
04631   SCYTHE_BINARY_BOOL_OPERATOR_DMM(OP)                                 \
04632   SCYTHE_BINARY_BOOL_OPERATOR_GMS(OP)                                 \
04633   SCYTHE_BINARY_BOOL_OPERATOR_DMS(OP)                                 \
04634   SCYTHE_BINARY_BOOL_OPERATOR_GSM(OP)                                 \
04635   SCYTHE_BINARY_BOOL_OPERATOR_DSM(OP)
04636 
04637   /* Element-wise Equality operator
04638    * See equals() method for straight equality checks
04639    */
04640 
04675   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator==, std::equal_to)
04676   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator==)
04677 
04712   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator!=, std::not_equal_to)
04713   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator!=)
04714 
04750   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator<, std::less)
04751   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator<)
04752 
04789   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator<=, std::less_equal)
04790   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator<=)
04791 
04827   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator>, std::greater)
04828   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator>)
04829 
04866   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator>=, std::greater_equal)
04867   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator>=)
04868 
04904   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator&, std::logical_and)
04905   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator&)
04906 
04907 
04943   SCYTHE_GENERAL_BINARY_BOOL_OPERATOR (operator|, std::logical_or)
04944   SCYTHE_BINARY_BOOL_OPERATOR_DEFS (operator|)
04945 
04946   /**** INPUT-OUTPUT ****/
04947 
04948 
04949   /* This function simply copies values from an input stream into a
04950    * matrix.  It relies on the iterators for bounds checking.
04951    */
04952 
04966   template <typename T, matrix_order O, matrix_style S>
04967   std::istream& operator>> (std::istream& is, Matrix<T,O,S>& M)
04968   {
04969     std::copy(std::istream_iterator<T> (is), std::istream_iterator<T>(),
04970          M.begin_f());
04971 
04972     return is;
04973   }
04974 
04975   /* Writes a matrix to an ostream in readable format.  This is
04976    * intended to be used to pretty-print to the terminal.
04977    */
04978 
04993   template <typename T, matrix_order O, matrix_style S>
04994   std::ostream& operator<< (std::ostream& os, const Matrix<T,O,S>& M)
04995   {
04996     /* This function take two passes to figure out appropriate field
04997      * widths.  Speed isn't really the point here.
04998      */
04999 
05000     // Store previous io settings
05001     std::ios_base::fmtflags preop = os.flags();
05002 
05003     uint mlen = os.width();
05004     std::ostringstream oss;
05005     oss.precision(os.precision());
05006     oss << std::setiosflags(std::ios::fixed);
05007     
05008     typename Matrix<T,O,S>::const_forward_iterator last = M.end_f();
05009     for (typename Matrix<T,O,S>::const_forward_iterator i = M.begin_f();
05010         i != last; ++i) {
05011       oss.str("");
05012       oss << (*i);
05013       if (oss.str().length() > mlen)
05014         mlen = oss.str().length();
05015     }
05016 
05017 
05018     /* Write the stream */
05019     // Change to a fixed with format.  Users should control precision
05020     os << std::setiosflags(std::ios::fixed);
05021 
05022     
05023     for (uint i = 0; i < M.rows(); ++i) {
05024       Matrix<T, O, View> row = M(i, _);
05025       //for (uint i = 0; i < row.size(); ++i)
05026       //  os << std::setw(mlen) << row[i] << " ";
05027       typename Matrix<T,O,View>::const_forward_iterator row_last 
05028         = row.end_f();
05029       for (typename 
05030           Matrix<T,O,View>::forward_iterator el = row.begin_f();
05031           el != row_last; ++el) {
05032         os << std::setw(mlen) << *el << " ";
05033       }
05034       os << std::endl;
05035     }
05036     
05037     
05038     // Restore pre-op flags
05039     os.flags(preop);
05040 
05041     return os;
05042   }
05043 
05044 #ifdef SCYTHE_LAPACK
05045   /* A template specialization of operator* for col-major, concrete
05046    * matrices of doubles that is only visible when a LAPACK library is
05047    * available.  This function is an analog of the above function and
05048    * the above doxygen documentation serves for both.
05049    *
05050    * This needs to go below % so it can see the template definition
05051    * (since it isn't actually in the template itself.
05052    */
05053 
05054   template<>
05055   Matrix<>
05056   operator*<double,Col,Concrete,Col,Concrete>
05057   (const Matrix<>& lhs, const Matrix<>& rhs)
05058   {
05059     if (lhs.size() == 1 || rhs.size() == 1)
05060       return (lhs % rhs);
05061 
05062     SCYTHE_DEBUG_MSG("Using lapack/blas for matrix multiplication");
05063     SCYTHE_CHECK_10 (lhs.cols() != rhs.rows(),
05064         scythe_conformation_error,
05065         "Matrices with dimensions (" << lhs.rows() 
05066         << ", " << lhs.cols()
05067         << ") and (" << rhs.rows() << ", " << rhs.cols()
05068         << ") are not multiplication-conformable");
05069 
05070     Matrix<> result (lhs.rows(), rhs.cols(), false);
05071 
05072     // Get pointers to the internal arrays and set up some vars
05073     double* lhspnt = lhs.getArray();
05074     double* rhspnt = rhs.getArray();
05075     double* resultpnt = result.getArray();
05076     const double one(1.0);
05077     const double zero(0.0);
05078     int rows = (int) lhs.rows();
05079     int cols = (int) rhs.cols();
05080     int innerDim = (int) rhs.rows();
05081 
05082     // Call the lapack routine.
05083     lapack::dgemm_("N", "N", &rows, &cols, &innerDim, &one, lhspnt,
05084                    &rows, rhspnt, &innerDim, &zero, resultpnt, &rows);
05085 
05086     return result;
05087   }
05088 #endif
05089 
05090 } // end namespace scythe
05091 
05092 #endif /* SCYTHE_MATRIX_H */

Generated on Wed Aug 15 14:53:38 2007 for Scythe-1.0.2 by  doxygen 1.4.7