#ifndef MATRIX_H #define MATRIX_H #include "MatrixDef.h" /******************************************************************************* * abstract class Matrix - base class for linear algebra subsystem *******************************************************************************/ template class Matrix { protected: Matrix(const Matrix &c); public: Matrix() {} virtual ~Matrix() {} //* stream output functions void print(ostream &o) const { o << tostring(); } void print(ostream &o, const string &name) const; friend ostream& operator<<(ostream &o, const Matrix &m){m.print(o); return o;} void print() const; virtual void print(const string &name) const; virtual string tostring() const; // element by element operations DenseMatrix operator/(const Matrix& B) const; DenseMatrix pow(int n) const; DenseMatrix pow(double n) const; // functions that return a copy DenseMatrix transpose() const; // matrix to scalar functions T sum() const; T stdev() const; T max() const; T min() const; T maxabs() const; T minabs() const; T norm() const; T mean() const; T dot(const Matrix &r) const; T trace() const; // row and column operations T row_sum (INDEX i=0) const { return row(*this,i).sum(); } T row_mean (INDEX i=0) const { return row(*this,i).mean(); } T row_norm (INDEX i=0) const { return row(*this,i).norm(); } T row_stdev(INDEX i=0) const { return row(*this,i).stdev(); } T col_sum (INDEX i=0) const { return column(*this,i).sum(); } T col_mean (INDEX i=0) const { return column(*this,i).mean(); } T col_norm (INDEX i=0) const { return column(*this,i).norm(); } T col_stdev(INDEX i=0) const { return column(*this,i).stdev(); } // pure virtual functions (required to implement these) --------------------- //* reference index operator virtual T& operator()(INDEX i, INDEX j)=0; //* value index operator virtual T operator()(INDEX i, INDEX j)const=0; //* value flat index operator virtual T& operator [](INDEX i)=0; //* reference flat index operator virtual T operator [](INDEX i) const=0; //* returns the # of rows virtual INDEX nRows() const=0; //* returns the # of columns virtual INDEX nCols() const=0; //* returns a pointer to the data (dangerous) virtual T * get_ptr() const=0; //* resizes the matrix, copy what fits default to OFF virtual void resize(INDEX nRows, INDEX nCols=1, bool copy=false)=0; //* resizes the matrix, zero it out default to ON virtual void reset(INDEX nRows, INDEX nCols=1, bool zero=true)=0; //* resizes and copies data virtual void copy(const T * ptr, INDEX nRows, INDEX nCols=1)=0; //* create restart file virtual void write_restart(FILE *f) const=0; //* writes a matlab command to recreate this in a variable named s virtual void matlab(ostream &o, const string &s="M") const; // output to matlab, with variable name s void matlab(const string &s="M") const; Matrix& operator+=(const Matrix &r); Matrix& operator-=(const Matrix &r); //* NOTE these two functions are scaling operations not A.B Matrix& operator*=(const Matrix& R); Matrix& operator/=(const Matrix& R); Matrix& operator+=(const T v); Matrix& operator-=(const T v); Matrix& operator*=(const T v); Matrix& operator/=(T v); Matrix& operator=(const T &v); Matrix& operator=(const Matrix &c); virtual void set_all_elements_to(const T &v); //* adds a matrix scaled by factor s to this one. void add_scaled(const Matrix &A, const T& s); //* sets all elements to zero Matrix& zero(); //* returns the total number of elements virtual INDEX size() const; //* returns true if (i,j) is within the range of the matrix bool in_range(INDEX i, INDEX j) const; //* returns true if the matrix size is rs x cs bool is_size(INDEX rs, INDEX cs) const; //* returns true if the matrix is square and not empty bool is_square() const; //* returns true if Matrix, m, is the same size as this bool same_size(const Matrix &m) const; //* returns true if Matrix a and Matrix b are the same size static bool same_size(const Matrix &a, const Matrix &b); //* checks if memory is contiguous, only can be false for clone vector virtual bool memory_contiguous() const { return true; } protected: virtual void _set_equal(const Matrix &r); }; //* Matrix operations //@{ //* Sets C as b*C + a*A[tranpose?]*B[transpose?] template void MultAB(const Matrix &A, const Matrix &B, DenseMatrix &C, bool At=0, bool Bt=0, T a=1, T b=0); //* performs a matrix-vector multiply template void MultMv(const Matrix &A, const Vector &v, DenseVector &c, const bool At, T a, T b); // returns the inverse of a double precision matrix DenseMatrix inv(const Matrix& A); //* returns the trace of a matrix template T trace(const Matrix& A) { return A.trace(); } //* computes the determinant of a square matrix double det(const Matrix& A); //* Returns the maximum eigenvalue of a matrix. double max_eigenvalue(const Matrix& A); //@} //----------------------------------------------------------------------------- // computes the sum of the difference squared of each element. //----------------------------------------------------------------------------- template double sum_difference_squared(const Matrix& A, const Matrix &B) { SSCK(A, B, "sum_difference_squared"); double v=0.0; for (unsigned i=0; i DenseMatrix operator*(const Matrix &A, const Matrix &B) { DenseMatrix C(0,0,false); MultAB(A,B,C); return C; } //----------------------------------------------------------------------------- //* Multiply a Matrix by a scalar //----------------------------------------------------------------------------- template DenseMatrix operator*(const Matrix &M, const T s) { DenseMatrix R(M); return R*=s; } //----------------------------------------------------------------------------- //* Multiply a Matrix by a scalar template DenseMatrix operator*(const T s, const Matrix &M) { DenseMatrix R(M); return R*=s; } //----------------------------------------------------------------------------- //* inverse scaling operator - must always create memory template DenseMatrix operator/(const Matrix &M, const T s) { DenseMatrix R(M); return R*=(1.0/s); // for integer types this may be worthless } //----------------------------------------------------------------------------- //* Operator for Matrix-matrix sum template DenseMatrix operator+(const Matrix &A, const Matrix &B) { DenseMatrix C(A); return C+=B; } //----------------------------------------------------------------------------- //* Operator for Matrix-matrix subtraction template DenseMatrix operator-(const Matrix &A, const Matrix &B) { DenseMatrix C(A); return C-=B; } /****************************************************************************** * Template definitions for class Matrix ******************************************************************************/ //----------------------------------------------------------------------------- //* performs a matrix-matrix multiply with general type implementation template void MultAB(const Matrix &A, const Matrix &B, DenseMatrix &C, const bool At, const bool Bt, T a, T b) { const INDEX sA[2] = {A.nRows(), A.nCols()}; // m is sA[At] k is sA[!At] const INDEX sB[2] = {B.nRows(), B.nCols()}; // k is sB[Bt] n is sB[!Bt] const INDEX M=sA[At], K=sB[Bt], N=sB[!Bt]; GCK(A, B, sA[!At]!=K, "MultAB shared index not equal size"); if (!C.is_size(M,N)) { C.resize(M,N); // set size of C C.zero(); } else C *= b; for (INDEX p=0; p string Matrix::tostring() const { string s; for (INDEX i=0; i void Matrix::print(ostream &o, const string &name) const { o << "------- Begin "<print(o); o << "\n------- End "< void Matrix::print() const { print(cout); } //----------------------------------------------------------------------------- //* named print operator, use cout by default template void Matrix::print(const string &name) const { print(cout, name); } //----------------------------------------------------------------------------- //* element by element division template DenseMatrix Matrix::operator/ (const Matrix& B) const { SSCK(*this, B, "Matrix::Operator/"); DenseMatrix R(*this); R /= B; return R; } //----------------------------------------------------------------------------- //* element-wise raise to a power template DenseMatrix Matrix::pow(int n) const { DenseMatrix R(*this); FORi { double val = R[i]; for (int k=1; k DenseMatrix Matrix::pow(double n) const { DenseMatrix R(*this); FORi { double val = R[i]; R[i] = pow(val,n); } return R; } //----------------------------------------------------------------------------- //* returns the transpose of this matrix (makes a copy) template DenseMatrix Matrix::transpose() const { DenseMatrix t(this->nCols(), this->nRows()); FORij t(j,i) = (*this)(i,j); return t; } //----------------------------------------------------------------------------- //* returns the transpose of a matrix (makes a copy) template DenseMatrix transpose(const Matrix &A) { return A.transpose(); } //----------------------------------------------------------------------------- //* Returns the sum of all matrix elements template T Matrix::sum() const { if (!size()) return T(0); T v = VIDX(0); for (INDEX i=1; isize(); i++) v += VIDX(i); return v; } //----------------------------------------------------------------------------- //* Returns the standard deviation of the matrix template T Matrix::stdev() const { GCHK(this->size()<2, "Matrix::stdev() size must be > 1"); T mean = this->mean(); T diff = VIDX(0)-mean; T stdev = diff*diff; for (INDEX i=1; isize(); i++) { diff = VIDX(i)-mean; stdev += diff*diff; } return sqrt(stdev/T(this->size()-1)); } //----------------------------------------------------------------------------- //* Returns the maximum of the matrix template T Matrix::max() const { GCHK(!this->size(), "Matrix::max() size must be > 0"); T v = VIDX(0); for (INDEX i=1; isize(); i++) v = std::max(v, VIDX(i)); return v; } //----------------------------------------------------------------------------- //* Returns the minimum of the matrix template T Matrix::min() const { GCHK(!this->size(), "Matrix::min() size must be > 0"); T v = VIDX(0); for (INDEX i=1; isize(); i++) v = std::min(v, VIDX(i)); return v; } //----------------------------------------------------------------------------- //* Returns the maximum absolute value of the matrix template T Matrix::maxabs() const { GCHK(!this->size(), "Matrix::maxabs() size must be > 0"); T v = VIDX(0); for (INDEX i=1; isize(); i++) v = Utility::MaxAbs(v, VIDX(i)); return v; } //----------------------------------------------------------------------------- //* Returns the minimum absoute value of the matrix template T Matrix::minabs() const { GCHK(!this->size(), "Matrix::minabs() size must be > 0"); T v = VIDX(0); for (INDEX i=1; isize(); i++) v = Utility::MinAbs(v, VIDX(i)); return v; } //----------------------------------------------------------------------------- //* returns the L2 norm of the matrix template T Matrix::norm() const { GCHK(!this->size(), "Matrix::norm() size must be > 0"); return sqrt(dot(*this)); } //----------------------------------------------------------------------------- //* returns the average of the matrix template T Matrix::mean() const { GCHK(!this->size(), "Matrix::mean() size must be > 0"); return sum()/T(this->size()); } //----------------------------------------------------------------------------- //* Returns the dot product of two vectors template T Matrix::dot(const Matrix& r) const { SSCK(*this, r, "Matrix::dot"); if (!this->size()) return T(0); T v = r[0]*VIDX(0); for (INDEX i=1; isize(); i++) v += r[i]*VIDX(i); return v; } //----------------------------------------------------------------------------- // returns the sum of the matrix diagonal //----------------------------------------------------------------------------- template T Matrix::trace() const { const INDEX N = std::min(nRows(),nCols()); if (!N) return T(0); T r = MIDX(0,0); for (INDEX i=0; i Matrix& Matrix::operator+=(const Matrix &r) { SSCK(*this, r, "operator+= or operator +"); FORi VIDX(i)+=r[i]; return *this; } //----------------------------------------------------------------------------- // subtracts a matrix from this one //----------------------------------------------------------------------------- template Matrix& Matrix::operator-=(const Matrix &r) { SSCK(*this, r, "operator-= or operator -"); FORi VIDX(i)-=r[i]; return *this; } //----------------------------------------------------------------------------- // multiplies each element in this by the corresponding element in R //----------------------------------------------------------------------------- template Matrix& Matrix::operator*=(const Matrix& R) { SSCK(*this, R, "operator*="); FORi { VIDX(i) *= R[i]; } return *this; } //----------------------------------------------------------------------------- // divides each element in this by the corresponding element in R //----------------------------------------------------------------------------- template Matrix& Matrix::operator/=(const Matrix& R) { SSCK(*this, R, "operator/= or operator/"); FORi { GCHK(fabs(R[i])>0,"Operator/: division by zero"); VIDX(i) /= R[i]; } return *this; } //----------------------------------------------------------------------------- // scales this matrix by a constant //----------------------------------------------------------------------------- template Matrix& Matrix::operator*=(const T v) { FORi VIDX(i)*=v; return *this; } //----------------------------------------------------------------------------- // adds a constant to this matrix //----------------------------------------------------------------------------- template Matrix& Matrix::operator+=(const T v) { FORi VIDX(i)+=v; return *this; } //----------------------------------------------------------------------------- // substracts a constant to this matrix //----------------------------------------------------------------------------- template Matrix& Matrix::operator-=(const T v) { FORi VIDX(i)-=v; return *this; } //----------------------------------------------------------------------------- //* scales this matrix by the inverse of a constant template Matrix& Matrix::operator/=(T v) { return (*this)*=(1.0/v); } //---------------------------------------------------------------------------- // Assigns one matrix to another //---------------------------------------------------------------------------- template Matrix& Matrix::operator=(const Matrix &r) { this->_set_equal(r); return *this; } //---------------------------------------------------------------------------- // general matrix assignment (for densely packed matrices) //---------------------------------------------------------------------------- template void Matrix::_set_equal(const Matrix &r) { this->resize(r.nRows(), r.nCols()); const Matrix *pr = &r; if (const SparseMatrix *ps = sparse_cast(pr)) copy_sparse_to_matrix(ps, *this); else if (diag_cast(pr)) // r is Diagonal? { this->zero(); for (INDEX i=0; iget_ptr(), r.get_ptr(), r.size()*sizeof(T)); } //----------------------------------------------------------------------------- //* sets all elements to a constant template inline Matrix& Matrix::operator=(const T &v) { set_all_elements_to(v); return *this; } //----------------------------------------------------------------------------- //* sets all elements to a constant template void Matrix::set_all_elements_to(const T &v) { FORi VIDX(i) = v; } //---------------------------------------------------------------------------- // adds a matrix scaled by factor s to this one. //---------------------------------------------------------------------------- template void Matrix::add_scaled(const Matrix &A, const T& s) { SSCK(A, *this, "Matrix::add_scaled"); FORi VIDX(i) += A[i]*s; } //----------------------------------------------------------------------------- //* writes a matlab command to the console template void Matrix::matlab(const string &s) const { this->matlab(cout, s); } //----------------------------------------------------------------------------- //* Writes a matlab script defining the vector to the stream template void Matrix::matlab(ostream &o, const string &s) const { o << s <<"=zeros(" << nRows() << ","< inline Matrix& Matrix::zero() { set_all_elements_to(T(0)); return *this; } //----------------------------------------------------------------------------- //* returns the total number of elements template inline INDEX Matrix::size() const { return nRows()*nCols(); } //----------------------------------------------------------------------------- //* returns true if (i,j) is within the range of the matrix template inline bool Matrix::in_range(INDEX i, INDEX j) const { return i inline bool Matrix::is_size(INDEX rs, INDEX cs) const { return nRows()==rs && nCols()==cs; } //----------------------------------------------------------------------------- //* returns true if the matrix is square and not empty template inline bool Matrix::is_square() const { return nRows()==nCols() && nRows(); } //----------------------------------------------------------------------------- //* returns true if Matrix, m, is the same size as this template inline bool Matrix::same_size(const Matrix &m) const { return is_size(m.nRows(), m.nCols()); } //----------------------------------------------------------------------------- //* returns true if Matrix a and Matrix b are the same size template inline bool Matrix::same_size(const Matrix &a, const Matrix &b) { return a.same_size(b); } //----------------------------------------------------------------------------- //* Displays indexing error message and quits template void ierror(const Matrix &a, const char *FILE, int LINE, INDEX i, INDEX j) { cout << "Error: Matrix indexing failure "; cout << "in file: " << FILE << ", line: "<< LINE <<"\n"; cout << "Tried accessing index (" << i << ", " << j <<")\n"; cout << "Matrix size was "<< a.nRows() << "x" << a.nCols() << "\n"; exit(EXIT_FAILURE); } //----------------------------------------------------------------------------- //* Displays custom message and indexing error and quits template void ierror(const Matrix &a, INDEX i, INDEX j, const string m) { cout << m << "\n"; cout << "Tried accessing index (" << i << ", " << j <<")\n"; cout << "Matrix size was "<< a.nRows() << "x" << a.nCols() << "\n"; exit(EXIT_FAILURE); } //----------------------------------------------------------------------------- //* Displays matrix compatibility error message template void merror(const Matrix &a, const Matrix &b, const string m) { cout << "Error: " << m << "\n"; cout << "Matrix sizes were " << a.nRows() << "x" << a.nCols(); if (&a != &b) cout << ", and "<< b.nRows() << "x" << b.nCols(); cout << "\n"; exit(EXIT_FAILURE); } #endif