//******************************************************************** //Matrix.h C++ template class //Author: Jun Hong //web:http://www2.uic.edu/~jhong4/sample.html //Email:jhong4@uic.edu //******************************************************************** //Note: This matrix.h file defines three classes including Matrix, //SubMatRef, and const_SubMatRef. The Matrix class defines //most of the matrix operations as overloaded operators or methods. //For the Matrix class, two smart pointers, SubMatRef and //const_SubMatRef, are defined. Users can used them to develop //other matrix opertions. Iterators could be also added later by Users as //nested class in Matrix #include #include #include #include #include #include #include // declarations of classes and functions template class Matrix; template class const_SubMatRef; template class SubMatRef; template bool operator == (const Matrix& m1, const Matrix& m2); template bool operator != (const Matrix& m1, const Matrix& m2); template Matrix operator * (const Matrix& m, const F& no); template Matrix operator * (const F& no, const Matrix& m); template Matrix operator * (const Matrix& m1, const Matrix& m2); template Matrix operator * (int no, const Matrix& m); template Matrix operator * (const Matrix& m, int no); //=================Define Template Class Matrix========================= template class Matrix { friend class SubMatRef; friend class const_SubMatRef; public: // Constructors and destructor Matrix (const Matrix& m); Matrix (size_t row , size_t col ); Matrix (size_t n); Matrix (size_t row, size_t col, char* s); ~Matrix (); // Size, this function returns a pair s, s.first and s.second pair size() const { return pair (md->RowSiz, md->ColSiz);} //RowNo and ColNo size_t RowNo() const {return md->Row;} size_t ColNo() const {return md->Col;} // assignment operators overloaded = Matrix& operator = (const Matrix& m); // unary operators + and - Matrix operator + () { return *this;} Matrix operator - (); // subscript operators F& operator ()(size_t row, size_t col) const; F& operator ()(size_t row, size_t col); // transpose Matrix transpose (); // Null void Null(); // Combined assignment +=,-=, *= Matrix& operator += (const Matrix& m); Matrix& operator -= (const Matrix& m); Matrix& operator *= (const Matrix& m); // logical operators friend bool operator == <>(const Matrix& m1, const Matrix& m2); friend bool operator != <>(const Matrix& m1, const Matrix& m2); // binary calculation operators + - * Matrix operator+ (const Matrix&m2); Matrix operator- (const Matrix&m2); friend Matrix operator * <>(const Matrix& m1, const Matrix&m2); friend Matrix operator * <>(const Matrix& m, const F& no); friend Matrix operator * <>(const F& no, const Matrix& m); friend Matrix operator * <>(int no, const Matrix& m); friend Matrix operator * <>(const Matrix& m, int no); // Miscellaneous methods F Det() const; void Unit (); // identity static Matrix identity (const size_t& n); // inverse pair > inverse () const { return inverse( Field_traits::arith_type() ); } pair > inverse(arith_exact) const; pair > inverse(arith_approx) const; // rowBasis Matrix rowBasis() const { return rowBasis( Field_traits::arith_type() ); } Matrix rowBasis(arith_exact) const; Matrix rowBasis(arith_approx) const; // conversion template Matrix(const Matrix & p); //a(r1, r2, c1, c2); SubMatRef operator ()(size_t a, size_t b, size_t c, size_t d){ return SubMatRef(*this, a, b, c, d); } const_SubMatRef operator ()(size_t a, size_t b, size_t c, size_t d) const{ return const_SubMatRef(*this, a, b, c, d); } //a[i] SubMatRef operator[] (size_t i){ return SubMatRef(*this, i, i, 0, size().second-1); } const_SubMatRef operator[] (size_t i) const{ return const_SubMatRef(*this, i, i, 0, size().second-1); } //Function to swap this matrix with another void swap (Matrix &a){ if (size()!=a.size()) throw "size error"; for (size_t i=0; iRow; i++) for (size_t j=0; jCol; j++) std::swap(md->element[i][j], a(i,j)); } //assign SubMatRef to Matrix Matrix& operator= (const SubMatRef& a){ md =new membervariables (a.r2-a.r1+1, a.c2-a.c1+1, 0); for(size_t i=0, ii=a.r1; ielement[i][j]=a.rA(ii,jj); return *this; } private: struct membervariables { F**element; size_t Row, Col, RowSiz, ColSiz; int count; membervariables (size_t row, size_t col, F** v) { Row = row; RowSiz = row; Col = col; ColSiz = col; count = 1; element = new F* [row]; size_t rowlen = col * sizeof(F); for (size_t i=0; i < row; i++){ element[i] = new F[col]; if (v) memcpy( element[i], v[i], rowlen); } } ~membervariables (){ for (size_t i=0; i < RowSiz; i++) delete [] element[i]; delete [] element; } }; membervariables *md; void clone (); void realloc (size_t row, size_t col); int pivot (size_t row); }; //=======================definition of template class const_SubMatRef==== template class const_SubMatRef{ friend class Matrix; friend class SubMatRef; protected: Matrix &rA; size_t r1, r2, c1, c2; const_SubMatRef(const Matrix &aa, size_t a, size_t b, size_t c, size_t d): rA(const_cast &>(aa)), r1(a), r2(b), c1(c), c2(d) {} public: //Conversion to Matrix operator Matrix () const{ Matrix a(r2-r1+1,c2-c1+1); for (size_t i=0, ii=r1; i<=r2-r1; i++, ii++) for (size_t j=0, jj=c1; j<=c2-c1; j++, jj++) a.md->element[i][j]=rA.md->element[ii][jj]; return a; } //This function is used by ref-=mu*cref friend pair > operator* (F mu, const const_SubMatRef& m){ return pair >(mu, m); } }; //====================definition of template class SubMatRef=========== template class SubMatRef: public const_SubMatRef { friend class Matrix; private: SubMatRef(const Matrix& aa, size_t u, size_t v, size_t w, size_t x): const_SubMatRef (aa, u, v, w, x){} public: //Conversion to Matrix operator Matrix () const{ Matrix a(r2-r1+1, c2-c1+1); for (size_t i=0, ii=r1; i<=r2-r1; i++, ii++) for (size_t j=0, jj=c1; j<=c2-c1; j++, jj++) a.md->element[i][j]=rA.md->element[ii][jj]; return a; } SubMatRef& operator=(const Matrix &a){ if(a.size().first !=r2-r1+1 || a.size().second !=c2-c1+1 ) throw "Size error"; for(size_t r=r1, i=0; r<=r2; r++, i++) for (size_t c=c1, j=0; c<=c2; c++, j++) rA(r,c)=a(i,j); return *this; } SubMatRef& operator=(const const_SubMatRef &s){ if ( r2-r1!=s.r2-s.r1 || c2-c1!=s.c2-s.c1) throw "Size error"; for(size_t r=r1, i=s.r1; r<=r2; ++r, ++i) for (size_t c=c1, j=s.c1; c<=c2; ++c, ++j) rA(r,c)=s.rA(i,j); return *this; } //Function to swap this SubMatRef with another void swap (SubMatRef a){ if (r2-r1!=a.r2-a.r1||c2-c1!=a.c2-a.c1) throw "size error"; for (size_t i=r1, ii=a.r1; i<=r2; i++, ii++) for (size_t j=c1, jj=a.c1; j<=c2; j++, jj++) std::swap(rA(i,j), a.rA(ii,jj)); } //ref*=mu SubMatRef& operator*= (F mu){ for (size_t i=r1; i<=r2; i++) for (size_t j=c1; j<=c2; j++) rA(i,j)*=mu; return *this; } //ref+ref Matrix operator + (const SubMatRef &a){ Matrix A(a.r2-a.r1+1, a.c2-c1+1); A=a; Matrix B(r2-r1+1, c2-c1+1); B=*this; Matrix C(r2-r1+1, c2-c1+1); C=A+B; return C; } //ref-ref Matrix operator - (const SubMatRef &a){ Matrix A(a.r2-a.r1+1, a.c2-c1+1); A=a; Matrix B(r2-r1+1, c2-c1+1); B=*this; Matrix C(r2-r1+1, c2-c1+1); C=B-A; return C; } //ref+Matrix Matrix operator + (const Matrix& a){ Matrix A(r2-r1+1, c2-c1+1); A=*this; Matrix C(r2-r1+1, c2-c1+1); C=A+a; return C; } //ref-=mu*cref SubMatRef& operator -= ( pair > a){ for (size_t i=r1, ii=a.second.r1; i<=r2; i++, ii++) for (size_t j=c1, jj=a.second.c1; j<=c2; j++, jj++) rA(i,j) -= (a.second.rA(ii,jj)*a.first); return *this; } SubMatRef& operator=( const SubMatRef &s){ for (size_t i=r1, ii=s.r1; i<=r2; i++, ii++) for (size_t j=c1, jj=s.c1; j<=c2; j++, jj++) rA(i,j)=s.rA(ii, jj); return *this; } }; //=======================Definiation of Class Member Functions========== // Constructor template inline Matrix::Matrix (size_t row, size_t col) { md = new membervariables ( row, col, 0); Null(); } // Constructor template inline Matrix::Matrix (size_t n){ md=new membervariables (n,n,0); Null(); } // Copy constructor template inline Matrix::Matrix (const Matrix& m) { md = m.md; md->count++; } // Constructor template inline Matrix::Matrix (size_t row, size_t col, char* s) { F* elt=new F[row*col]; istrstream iss(s); for (size_t i=0; i> elt[i]; md=new membervariables (row, col, 0); if (md->count>1) clone(); size_t a=0; for (size_t k=0; kRow; ++k) for (size_t j=0; jCol; ++j) (md->element)[k][j] = elt[a++]; } // clone constructor template inline void Matrix::clone () { md->count--; md = new membervariables ( md->Row, md->Col, md->element); } // Destructor template inline Matrix::~Matrix () { if (--md->count == 0) delete md; } // assignment operator template inline Matrix& Matrix::operator = (const Matrix& m) { m.md->count++; if (--md->count == 0) delete md; md = m.md; return *this; } // reallocation method template inline void Matrix::realloc (size_t row, size_t col) { if (row == md->RowSiz && col == md->ColSiz) { md->Row = md->RowSiz; md->Col = md->ColSiz; return; } membervariables *m1 = new membervariables ( row, col, NULL); size_t colSize = (md->ColCol:col) * sizeof(T); size_t minRow = (md->RowRow:row); for (size_t i=0; i < minRow; i++) memcpy( m1->element[i], md->element[i], colSize); if (--md->count == 0) delete md; md = m1; return; } // a==b template inline bool operator == (const Matrix& m1, const Matrix& m2) { if (m1.RowNo() != m2.RowNo() || m1.ColNo() != m2.ColNo()) return false; for (size_t i=0; i < m1.RowNo(); i++) for (size_t j=0; j < m1.ColNo(); j++) if (m1.md->element[i][j] != m2.md->element[i][j]) return false; return true; } // a!=b template inline bool operator != (const Matrix& m1, const Matrix& m2) { return (m1 == m2) ? false : true; } // a+=b template inline Matrix& Matrix::operator += (const Matrix& m) { if (md->Row != m.md->Row || md->Col != m.md->Col) cout<< "Inconsistent Matrix sizes in += !"; if (md->count > 1) clone(); for (size_t i=0; i < m.md->Row; i++) for (size_t j=0; j < m.md->Col; j++) md->element[i][j] += m.md->element[i][j]; return *this; } // a-=b template inline Matrix& Matrix::operator -= (const Matrix& m) { if (md->Row != m.md->Row || md->Col != m.md->Col) cout<< "Inconsistent Matrix sizes in -= !"; if (md->count > 1) clone(); for (size_t i=0; i < m.md->Row; i++) for (size_t j=0; j < m.md->Col; j++) md->element[i][j] -= m.md->element[i][j]; return *this; } // a *=b template inline Matrix& Matrix::operator *= (const Matrix& m) { if (md->Col != m.md->Row) cout<< "Inconsistent Matrix sizes in *= !"; *this = *this * m; return *this; } // -a template inline Matrix Matrix::operator - () { Matrix temp(md->Row,md->Col); for (size_t i=0; i < md->Row; i++) for (size_t j=0; j < md->Col; j++) temp.md->element[i][j] = - md->element[i][j]; return temp; } // a+b template inline Matrix Matrix::operator + (const Matrix& m2) { if (md->Row != m2.md->Row || md->Col != m2.md->Col) cout<< "Inconsistent Matrix size in addition!"; Matrix temp(md->Row, md->Col); for (size_t i=0; i < m2.md->Row; i++) for (size_t j=0; j < m2.md->Col; j++) temp.md->element[i][j] = md->element[i][j]+m2.md->element[i][j]; return temp; } // a-b template inline Matrix Matrix::operator - (const Matrix& m2){ if (md->Row != m2.md->Row || md->Col != m2.md->Col) cout<< "Inconsistent Matrix size in subtraction!"; Matrix temp(md->Row, md->Col); for (size_t i=0; i < md->Row; i++) for (size_t j=0; j < md->Col; j++) temp.md->element[i][j] =md->element[i][j]-m2.md->element[i][j]; return temp; } // mu*a int template inline Matrix operator * (const Matrix& m, int no) { Matrix temp(m.md->Row, m.md->Col); for (size_t i=0; i < m.md->Row; i++) for (size_t j=0; j < m.md->Col; j++) temp.md->element[i][j] = no * m.md->element[i][j]; return temp; } // mu*a template inline Matrix operator * (const Matrix& m, const F& no) { Matrix temp(m.md->Row, m.md->Col); for (size_t i=0; i < m.md->Row; i++) for (size_t j=0; j < m.md->Col; j++) temp.md->element[i][j] = no * m.md->element[i][j]; return temp; } // a*mu template inline Matrix operator * (const F& no, const Matrix& m) { return (m * no); } // int a*mu template inline Matrix operator * (int no, const Matrix& m) { return (m * no); } // a*b template inline Matrix operator * (const Matrix& m1, const Matrix& m2) { if (m1.md->Col != m2.md->Row) cout<<"Matrix::operator*: Inconsistent Matrix size in multiplication!"; Matrix temp(m1.md->Row, m2.md->Col); for (size_t i=0; i < m1.md->Row; i++) for (size_t j=0; j < m2.md->Col; j++) { temp.md->element[i][j] = F(0); for (size_t k=0; k < m1.md->Col; k++) temp.md->element[i][j] += m1.md->element[i][k] * m2.md->element[k][j]; } return temp; } // Transpose template inline Matrix Matrix::transpose(){ Matrix temp (md->Col,md->Row); for (size_t i=0; i < md->Row; i++){ for (size_t j=0; j Col; j++) temp.md->element[j][i] = md->element [i][j];} return temp; } //Null set all elements in a Matrix to F(0) template inline void Matrix::Null() { if (md->count > 1) clone(); for (size_t i=0; i < md->Row; i++) for (size_t j=0; j < md->Col; j++) md->element[i][j] = F(0); return; } // Identity template inline Matrix Matrix::identity (const size_t& n){ Matrix temp(n); for (size_t i=0; i < temp.md->Row; i++) for (size_t j=0; j < temp.md->Col; j++) temp.md->element[i][j] = i == j ? F(1) : F(0); return temp; } //Unit template inline void Matrix ::Unit () { if (md->count > 1) clone(); size_t row = (md->RowCol? md->Row:md->Col); md->Row = md->Col = row; for (size_t i=0; i < md->Row; i++) for (size_t j=0; j < md->Col; j++) md->element[i][j] = i == j ? F(1) : F(0); return; } //Subscript template inline F& Matrix ::operator () (size_t row, size_t col) { if (row >= md->Row || col >= md->Col) cout<< "Index out of range!"; if (md->count>1) clone(); return md->element[row][col]; } //Subscript for const template inline F& Matrix :: operator ()(size_t row, size_t col) const{ if (row >= md->Row || col >= md->Col) cout<< "Index out of range!"; return md->element[row][col]; } //Converstion template template inline Matrix:: Matrix(const Matrix & p) { md=new membervariables(p.RowNo(), p.ColNo(), 0); for (size_t i=0; ielement[i]= new F[p.ColNo()]; for (size_t j=0; jelement[i][j] = p(i,j);} } //Inverse template inline pair > Matrix::inverse( arith_exact ) const { Matrix A(md->Row, md->Col); for(size_t i=0; iRow; i++) for(size_t j=0; jCol; j++) A.md->element[i][j]=md->element[i][j]; Matrix B=Matrix::identity (ColNo()); F det(1); for (size_t r=0; r >(0,*this); } F temp=A(r,r); A[r] *=(F(1)/temp); B[r] *=(F(1)/temp); det *=temp; for (size_t k=0; k >(det, B); } template inline pair > Matrix::inverse(arith_approx) const { Matrix A(md->Row,md->Col); for(size_t i=0; iRow; i++) for(size_t j=0; jCol; j++) A.md->element[i][j]=md->element[i][j]; Matrix B=Matrix::identity (ColNo()); F det(1); for (size_t r=0; r::insignificant()){ for(size_t q=r+1; qField_traits::insignificant()){ A[r].swap(A[q]); B[r].swap(B[q]); det=-det; } if(abs(A(r,r))<=Field_traits::insignificant()) return pair >(0, *this); } F temp=A(r,r); A[r] *=(F(1)/temp); B[r] *=(F(1)/temp); det *=temp; for (size_t k=0; k >(det, B); } //RowBasis template inline Matrix Matrix::rowBasis(arith_exact) const { Matrix A(md->Row, md->Col); for(size_t i=0; iRow; i++) for(size_t j=0; jCol; j++) A.md->element[i][j]=md->element[i][j]; size_t r=0, c=0; while (rr) A[r].swap(A[k]); A[r]*=(F(1)/A(r,c)); for (k=0; k K=A(0, r-1, 0, A.ColNo()-1); return K; } template inline Matrix Matrix::rowBasis(arith_approx) const { Matrix A(md->Row, md->Col); for(size_t i=0; iRow; i++) for(size_t j=0; jCol; j++) A.md->element[i][j]=md->element[i][j]; size_t r=0, c=0; while (r ::insignificant(); k++); if(kr) A[r].swap(A[k]); A[r]*=(F(1)/A(r,c)); for (k=0; k K=A(0, r-1, 0, A.ColNo()-1); return K; }