Blender  V2.59
fmat.h
Go to the documentation of this file.
00001 
00005 /*
00006 
00007 *
00008 * Template Numerical Toolkit (TNT): Linear Algebra Module
00009 *
00010 * Mathematical and Computational Sciences Division
00011 * National Institute of Technology,
00012 * Gaithersburg, MD USA
00013 *
00014 *
00015 * This software was developed at the National Institute of Standards and
00016 * Technology (NIST) by employees of the Federal Government in the course
00017 * of their official duties. Pursuant to title 17 Section 105 of the
00018 * United States Code, this software is not subject to copyright protection
00019 * and is in the public domain.  The Template Numerical Toolkit (TNT) is
00020 * an experimental system.  NIST assumes no responsibility whatsoever for
00021 * its use by other parties, and makes no guarantees, expressed or implied,
00022 * about its quality, reliability, or any other characteristic.
00023 *
00024 * BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
00025 * see http://math.nist.gov/tnt for latest updates.
00026 *
00027 */
00028 
00029 
00030 
00031 // Fortran-compatible matrix: column oriented, 1-based (i,j) indexing
00032 
00033 #ifndef FMAT_H
00034 #define FMAT_H
00035 
00036 #include "subscript.h"
00037 #include "vec.h"
00038 #include <cstdlib>
00039 #include <cassert>
00040 #include <iostream>
00041 #ifdef TNT_USE_REGIONS
00042 #include "region2d.h"
00043 #endif
00044 
00045 // simple 1-based, column oriented Matrix class
00046 
00047 namespace TNT
00048 {
00049 
00050 template <class T>
00051 class Fortran_Matrix 
00052 {
00053 
00054 
00055   public:
00056 
00057     typedef         T   value_type;
00058     typedef         T   element_type;
00059     typedef         T*  pointer;
00060     typedef         T*  iterator;
00061     typedef         T&  reference;
00062     typedef const   T*  const_iterator;
00063     typedef const   T&  const_reference;
00064 
00065     Subscript lbound() const { return 1;}
00066  
00067   protected:
00068     T* v_;                  // these are adjusted to simulate 1-offset
00069     Subscript m_;
00070     Subscript n_;
00071     T** col_;           // these are adjusted to simulate 1-offset
00072 
00073     // internal helper function to create the array
00074     // of row pointers
00075 
00076     void initialize(Subscript M, Subscript N)
00077     {
00078         // adjust col_[] pointers so that they are 1-offset:
00079         //   col_[j][i] is really col_[j-1][i-1];
00080         //
00081         // v_[] is the internal contiguous array, it is still 0-offset
00082         //
00083         v_ = new T[M*N];
00084         col_ = new T*[N];
00085 
00086         assert(v_  != NULL);
00087         assert(col_ != NULL);
00088 
00089 
00090         m_ = M;
00091         n_ = N;
00092         T* p = v_ - 1;              
00093         for (Subscript i=0; i<N; i++)
00094         {
00095             col_[i] = p;
00096             p += M ;
00097             
00098         }
00099         col_ --; 
00100     }
00101    
00102     void copy(const T*  v)
00103     {
00104         Subscript N = m_ * n_;
00105         Subscript i;
00106 
00107 #ifdef TNT_UNROLL_LOOPS
00108         Subscript Nmod4 = N & 3;
00109         Subscript N4 = N - Nmod4;
00110 
00111         for (i=0; i<N4; i+=4)
00112         {
00113             v_[i] = v[i];
00114             v_[i+1] = v[i+1];
00115             v_[i+2] = v[i+2];
00116             v_[i+3] = v[i+3];
00117         }
00118 
00119         for (i=N4; i< N; i++)
00120             v_[i] = v[i];
00121 #else
00122 
00123         for (i=0; i< N; i++)
00124             v_[i] = v[i];
00125 #endif      
00126     }
00127 
00128     void set(const T& val)
00129     {
00130         Subscript N = m_ * n_;
00131         Subscript i;
00132 
00133 #ifdef TNT_UNROLL_LOOPS
00134         Subscript Nmod4 = N & 3;
00135         Subscript N4 = N - Nmod4;
00136 
00137         for (i=0; i<N4; i+=4)
00138         {
00139             v_[i] = val;
00140             v_[i+1] = val;
00141             v_[i+2] = val;
00142             v_[i+3] = val; 
00143         }
00144 
00145         for (i=N4; i< N; i++)
00146             v_[i] = val;
00147 #else
00148 
00149         for (i=0; i< N; i++)
00150             v_[i] = val;
00151         
00152 #endif      
00153     }
00154     
00155 
00156 
00157     void destroy()
00158     {     
00159         /* do nothing, if no memory has been previously allocated */
00160         if (v_ == NULL) return ;
00161 
00162         /* if we are here, then matrix was previously allocated */
00163         delete [] (v_);     
00164         col_ ++;                // changed back to 0-offset
00165         delete [] (col_);
00166     }
00167 
00168 
00169   public:
00170 
00171     T* begin() { return v_; }
00172     const T* begin() const { return v_;}
00173 
00174     T* end() { return v_ + m_*n_; }
00175     const T* end() const { return v_ + m_*n_; }
00176 
00177 
00178     // constructors
00179 
00180     Fortran_Matrix() : v_(0), m_(0), n_(0), col_(0)  {};
00181     Fortran_Matrix(const Fortran_Matrix<T> &A)
00182     {
00183         initialize(A.m_, A.n_);
00184         copy(A.v_);
00185     }
00186 
00187     Fortran_Matrix(Subscript M, Subscript N, const T& value = T())
00188     {
00189         initialize(M,N);
00190         set(value);
00191     }
00192 
00193     Fortran_Matrix(Subscript M, Subscript N, const T* v)
00194     {
00195         initialize(M,N);
00196         copy(v);
00197     }
00198 
00199 
00200     // destructor
00201     ~Fortran_Matrix()
00202     {
00203         destroy();
00204     }
00205 
00206 
00207     // assignments
00208     //
00209     Fortran_Matrix<T>& operator=(const Fortran_Matrix<T> &A)
00210     {
00211         if (v_ == A.v_)
00212             return *this;
00213 
00214         if (m_ == A.m_  && n_ == A.n_)      // no need to re-alloc
00215             copy(A.v_);
00216 
00217         else
00218         {
00219             destroy();
00220             initialize(A.m_, A.n_);
00221             copy(A.v_);
00222         }
00223 
00224         return *this;
00225     }
00226         
00227     Fortran_Matrix<T>& operator=(const T& scalar)
00228     { 
00229         set(scalar); 
00230         return *this;
00231     }
00232 
00233 
00234     Subscript dim(Subscript d) const 
00235     {
00236 #ifdef TNT_BOUNDS_CHECK
00237        assert( d >= 1);
00238         assert( d <= 2);
00239 #endif
00240         return (d==1) ? m_ : ((d==2) ? n_ : 0); 
00241     }
00242 
00243     Subscript num_rows() const { return m_; }
00244     Subscript num_cols() const { return n_; }
00245 
00246     Fortran_Matrix<T>& newsize(Subscript M, Subscript N)
00247     {
00248         if (num_rows() == M && num_cols() == N)
00249             return *this;
00250 
00251         destroy();
00252         initialize(M,N);
00253 
00254         return *this;
00255     }
00256 
00257 
00258 
00259     // 1-based element access
00260     //
00261     inline reference operator()(Subscript i, Subscript j)
00262     { 
00263 #ifdef TNT_BOUNDS_CHECK
00264         assert(1<=i);
00265         assert(i <= m_) ;
00266         assert(1<=j);
00267         assert(j <= n_);
00268 #endif
00269         return col_[j][i]; 
00270     }
00271 
00272     inline const_reference operator() (Subscript i, Subscript j) const
00273     {
00274 #ifdef TNT_BOUNDS_CHECK
00275         assert(1<=i);
00276         assert(i <= m_) ;
00277         assert(1<=j);
00278         assert(j <= n_);
00279 #endif
00280         return col_[j][i]; 
00281     }
00282 
00283 
00284 #ifdef TNT_USE_REGIONS
00285 
00286     typedef Region2D<Fortran_Matrix<T> > Region;
00287     typedef const_Region2D< Fortran_Matrix<T> > const_Region;
00288 
00289     Region operator()(const Index1D &I, const Index1D &J)
00290     {
00291         return Region(*this, I,J);
00292     }
00293 
00294     const_Region operator()(const Index1D &I, const Index1D &J) const
00295     {
00296         return const_Region(*this, I,J);
00297     }
00298 
00299 #endif
00300 
00301 
00302 };
00303 
00304 
00305 /* ***************************  I/O  ********************************/
00306 
00307 template <class T>
00308 std::ostream& operator<<(std::ostream &s, const Fortran_Matrix<T> &A)
00309 {
00310     Subscript M=A.num_rows();
00311     Subscript N=A.num_cols();
00312 
00313     s << M << " " << N << "\n";
00314 
00315     for (Subscript i=1; i<=M; i++)
00316     {
00317         for (Subscript j=1; j<=N; j++)
00318         {
00319             s << A(i,j) << " ";
00320         }
00321         s << "\n";
00322     }
00323 
00324 
00325     return s;
00326 }
00327 
00328 template <class T>
00329 std::istream& operator>>(std::istream &s, Fortran_Matrix<T> &A)
00330 {
00331 
00332     Subscript M, N;
00333 
00334     s >> M >> N;
00335 
00336     if ( !(M == A.num_rows() && N == A.num_cols()))
00337     {
00338         A.newsize(M,N);
00339     }
00340 
00341 
00342     for (Subscript i=1; i<=M; i++)
00343         for (Subscript j=1; j<=N; j++)
00344         {
00345             s >>  A(i,j);
00346         }
00347 
00348 
00349     return s;
00350 }
00351 
00352 // *******************[ basic matrix algorithms ]***************************
00353 
00354 
00355 template <class T>
00356 Fortran_Matrix<T> operator+(const Fortran_Matrix<T> &A, 
00357     const Fortran_Matrix<T> &B)
00358 {
00359     Subscript M = A.num_rows();
00360     Subscript N = A.num_cols();
00361 
00362     assert(M==B.num_rows());
00363     assert(N==B.num_cols());
00364 
00365     Fortran_Matrix<T> tmp(M,N);
00366     Subscript i,j;
00367 
00368     for (i=1; i<=M; i++)
00369         for (j=1; j<=N; j++)
00370             tmp(i,j) = A(i,j) + B(i,j);
00371 
00372     return tmp;
00373 }
00374 
00375 template <class T>
00376 Fortran_Matrix<T> operator-(const Fortran_Matrix<T> &A, 
00377     const Fortran_Matrix<T> &B)
00378 {
00379     Subscript M = A.num_rows();
00380     Subscript N = A.num_cols();
00381 
00382     assert(M==B.num_rows());
00383     assert(N==B.num_cols());
00384 
00385     Fortran_Matrix<T> tmp(M,N);
00386     Subscript i,j;
00387 
00388     for (i=1; i<=M; i++)
00389         for (j=1; j<=N; j++)
00390             tmp(i,j) = A(i,j) - B(i,j);
00391 
00392     return tmp;
00393 }
00394 
00395 // element-wise multiplication  (use matmult() below for matrix
00396 // multiplication in the linear algebra sense.)
00397 //
00398 //
00399 template <class T>
00400 Fortran_Matrix<T> mult_element(const Fortran_Matrix<T> &A, 
00401     const Fortran_Matrix<T> &B)
00402 {
00403     Subscript M = A.num_rows();
00404     Subscript N = A.num_cols();
00405 
00406     assert(M==B.num_rows());
00407     assert(N==B.num_cols());
00408 
00409     Fortran_Matrix<T> tmp(M,N);
00410     Subscript i,j;
00411 
00412     for (i=1; i<=M; i++)
00413         for (j=1; j<=N; j++)
00414             tmp(i,j) = A(i,j) * B(i,j);
00415 
00416     return tmp;
00417 }
00418 
00419 
00420 template <class T>
00421 Fortran_Matrix<T> transpose(const Fortran_Matrix<T> &A)
00422 {
00423     Subscript M = A.num_rows();
00424     Subscript N = A.num_cols();
00425 
00426     Fortran_Matrix<T> S(N,M);
00427     Subscript i, j;
00428 
00429     for (i=1; i<=M; i++)
00430         for (j=1; j<=N; j++)
00431             S(j,i) = A(i,j);
00432 
00433     return S;
00434 }
00435 
00436 
00437     
00438 template <class T>
00439 inline Fortran_Matrix<T> matmult(const Fortran_Matrix<T>  &A, 
00440     const Fortran_Matrix<T> &B)
00441 {
00442 
00443 #ifdef TNT_BOUNDS_CHECK
00444     assert(A.num_cols() == B.num_rows());
00445 #endif
00446 
00447     Subscript M = A.num_rows();
00448     Subscript N = A.num_cols();
00449     Subscript K = B.num_cols();
00450 
00451     Fortran_Matrix<T> tmp(M,K);
00452     T sum;
00453 
00454     for (Subscript i=1; i<=M; i++)
00455     for (Subscript k=1; k<=K; k++)
00456     {
00457         sum = 0;
00458         for (Subscript j=1; j<=N; j++)
00459             sum = sum +  A(i,j) * B(j,k);
00460 
00461         tmp(i,k) = sum; 
00462     }
00463 
00464     return tmp;
00465 }
00466 
00467 template <class T>
00468 inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T> &A, 
00469     const Fortran_Matrix<T> &B)
00470 {
00471     return matmult(A,B);
00472 }
00473 
00474 template <class T>
00475 inline int matmult(Fortran_Matrix<T>& C, const Fortran_Matrix<T>  &A, 
00476     const Fortran_Matrix<T> &B)
00477 {
00478 
00479     assert(A.num_cols() == B.num_rows());
00480 
00481     Subscript M = A.num_rows();
00482     Subscript N = A.num_cols();
00483     Subscript K = B.num_cols();
00484 
00485     C.newsize(M,K);         // adjust shape of C, if necessary
00486 
00487 
00488     T sum; 
00489 
00490     const T* row_i;
00491     const T* col_k;
00492 
00493     for (Subscript i=1; i<=M; i++)
00494     {
00495         for (Subscript k=1; k<=K; k++)
00496         {
00497             row_i = &A(i,1);
00498             col_k = &B(1,k);
00499             sum = 0;
00500             for (Subscript j=1; j<=N; j++)
00501             {
00502                 sum +=  *row_i * *col_k;
00503                 row_i += M;
00504                 col_k ++;
00505             }
00506         
00507             C(i,k) = sum; 
00508         }
00509 
00510     }
00511 
00512     return 0;
00513 }
00514 
00515 
00516 template <class T>
00517 Vector<T> matmult(const Fortran_Matrix<T>  &A, const Vector<T> &x)
00518 {
00519 
00520 #ifdef TNT_BOUNDS_CHECK
00521     assert(A.num_cols() == x.dim());
00522 #endif
00523 
00524     Subscript M = A.num_rows();
00525     Subscript N = A.num_cols();
00526 
00527     Vector<T> tmp(M);
00528     T sum;
00529 
00530     for (Subscript i=1; i<=M; i++)
00531     {
00532         sum = 0;
00533         for (Subscript j=1; j<=N; j++)
00534             sum = sum +  A(i,j) * x(j);
00535 
00536         tmp(i) = sum; 
00537     }
00538 
00539     return tmp;
00540 }
00541 
00542 template <class T>
00543 inline Vector<T> operator*(const Fortran_Matrix<T>  &A, const Vector<T> &x)
00544 {
00545     return matmult(A,x);
00546 }
00547 
00548 template <class T>
00549 inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T>  &A, const T &x)
00550 {
00551     Subscript M = A.num_rows();
00552     Subscript N = A.num_cols();
00553 
00554     Subscript MN = M*N; 
00555 
00556     Fortran_Matrix<T> res(M,N);
00557     const T* a = A.begin();
00558     T* t = res.begin();
00559     T* tend = res.end();
00560 
00561     for (t=res.begin(); t < tend; t++, a++)
00562         *t = *a * x;
00563 
00564     return res;
00565 } 
00566 
00567 }  // namespace TNT
00568 
00569 #endif // FMAT_H
00570