// Copyright (C) 2009 foam // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include "Vector.h" #ifndef FOAM_MATRIX #define FOAM_MATRIX template class Matrix { public: Matrix(); Matrix(unsigned int r, unsigned int c); ~Matrix(); Matrix(const Matrix &other); Matrix(unsigned int r, unsigned int c, float *data); // Row proxy classes to allow matrix[r][c] notation class Row { public: Row(Matrix *owner, unsigned int r) { m_Data=&owner->GetRawData()[r*owner->GetCols()]; m_Cols=owner->GetCols(); } T &operator[](unsigned int c) { assert(cGetRawDataConst()[r*owner->GetCols()]; m_Cols=owner->GetCols(); } const T &operator[](unsigned int c) const { assert(c GetRowVector(unsigned int r) const; Vector GetColVector(unsigned int c) const; void SetRowVector(unsigned int r, const Vector &row); void SetColVector(unsigned int c, const Vector &col); void NormaliseRows(); void NormaliseCols(); void Print() const; void SetAll(T s); void Zero() { SetAll(0); } bool IsInf(); Matrix Transposed() const; Matrix Inverted() const; Matrix &operator=(const Matrix &other); Matrix operator+(const Matrix &other) const; Matrix operator-(const Matrix &other) const; Matrix operator*(const Matrix &other) const; Vector operator*(const Vector &other) const; Vector VecMulTransposed(const Vector &other) const; Matrix &operator+=(const Matrix &other); Matrix &operator-=(const Matrix &other); Matrix &operator*=(const Matrix &other); bool operator==(const Matrix &other) const; void SortRows(Vector &v); void SortCols(Vector &v); Matrix CropRows(unsigned int s, unsigned int e); Matrix CropCols(unsigned int s, unsigned int e); void Save(FILE *f) const; void Load(FILE *f); static void RunTests(); private: unsigned int m_Rows; unsigned int m_Cols; T *m_Data; }; template Matrix::Matrix(unsigned int r, unsigned int c) : m_Rows(r), m_Cols(c) { m_Data=new T[r*c]; } template Matrix::Matrix() : m_Rows(0), m_Cols(0), m_Data(NULL) { } template Matrix::Matrix(unsigned int r, unsigned int c, float *data) : m_Rows(r), m_Cols(c), m_Data(data) { } template Matrix::~Matrix() { delete[] m_Data; } template Matrix::Matrix(const Matrix &other) { m_Rows = other.m_Rows; m_Cols = other.m_Cols; m_Data=new T[m_Rows*m_Cols]; memcpy(m_Data,other.m_Data,m_Rows*m_Cols*sizeof(T)); } template Matrix &Matrix::operator=(const Matrix &other) { if (m_Data!=NULL) { delete[] m_Data; } m_Rows = other.m_Rows; m_Cols = other.m_Cols; m_Data=new T[m_Rows*m_Cols]; memcpy(m_Data,other.m_Data,m_Rows*m_Cols*sizeof(T)); return *this; } template void Matrix::Print() const { for (unsigned int i=0; i void Matrix::SetAll(T s) { for (unsigned int i=0; i bool Matrix::IsInf() { for (unsigned int i=0; i Matrix Matrix::Transposed() const { Matrix copy(m_Cols,m_Rows); for (unsigned int i=0; i Matrix Matrix::Inverted() const { assert(m_Rows==m_Cols); // only works for square matrices Matrix ret(m_Rows,m_Cols); matrix_inverse(GetRawDataConst(),ret.GetRawData(),m_Rows); return ret; } template Matrix Matrix::operator+(const Matrix &other) const { assert(m_Rows==other.m_Rows); assert(m_Cols==other.m_Cols); Matrix ret(m_Rows,m_Cols); for (unsigned int i=0; i Matrix Matrix::operator-(const Matrix &other) const { assert(m_Rows==other.m_Rows); assert(m_Cols==other.m_Cols); Matrix ret(m_Rows,m_Cols); for (unsigned int i=0; i Matrix Matrix::operator*(const Matrix &other) const { assert(m_Cols==other.m_Rows); Matrix ret(m_Rows,other.m_Cols); for (unsigned int i=0; i Vector Matrix::operator*(const Vector &other) const { assert(m_Cols==other.Size()); Vector ret(m_Rows); for (unsigned int i=0; i Vector Matrix::VecMulTransposed(const Vector &other) const { assert(m_Rows==other.Size()); Vector ret(m_Cols); for (unsigned int i=0; i Matrix &Matrix::operator+=(const Matrix &other) { (*this)=(*this)+other; return *this; } template Matrix &Matrix::operator-=(const Matrix &other) { (*this)=(*this)-other; return *this; } template Matrix &Matrix::operator*=(const Matrix &other) { (*this)=(*this)*other; return *this; } template bool Matrix::operator==(const Matrix &other) const { if (m_Rows != other.m_Rows || m_Cols != other.m_Cols) { return false; } for (unsigned int i=0; i Vector Matrix::GetRowVector(unsigned int r) const { assert(r ret(m_Cols); for (unsigned int j=0; j Vector Matrix::GetColVector(unsigned int c) const { assert(c ret(m_Rows); for (unsigned int i=0; i void Matrix::SetRowVector(unsigned int r, const Vector &row) { assert(r void Matrix::SetColVector(unsigned int c, const Vector &col) { assert(c void Matrix::SortRows(Vector &v) { assert(v.Size()==m_Rows); bool sorted=false; while(!sorted) { sorted=true; for (unsigned int i=0; i rtmp = GetRowVector(i); SetRowVector(i,GetRowVector(i+1)); SetRowVector(i+1,rtmp); } } } } // sort cols by v template void Matrix::SortCols(Vector &v) { assert(v.Size()==m_Cols); bool sorted=false; while(!sorted) { sorted=true; for (unsigned int i=0; i rtmp = GetColVector(i); SetColVector(i,GetColVector(i+1)); SetColVector(i+1,rtmp); } } } } template Matrix Matrix::CropRows(unsigned int s, unsigned int e) { assert(s Matrix Matrix::CropCols(unsigned int s, unsigned int e) { assert(s void Matrix::NormaliseRows() { for(unsigned int i=0; i void Matrix::NormaliseCols() { for(unsigned int i=0; i void Matrix::Save(FILE* f) const { int version = 1; fwrite(&version,1,sizeof(version),f); fwrite(&m_Rows,1,sizeof(m_Rows),f); fwrite(&m_Cols,1,sizeof(m_Cols),f); fwrite(m_Data,1,sizeof(T)*m_Rows*m_Cols,f); } template void Matrix::Load(FILE* f) { int version; fread(&version,sizeof(version),1,f); fread(&m_Rows,sizeof(m_Rows),1,f); fread(&m_Cols,sizeof(m_Cols),1,f); m_Data=new T[m_Rows*m_Cols]; fread(m_Data,sizeof(T)*m_Rows*m_Cols,1,f); } template void Matrix::RunTests() { Vector::RunTests(); std::cerr<<"running matrix tests"< m(10,10); m.SetAll(0); assert(m[0][0]==0); m[5][2]=0.5; assert(m[5][2]==0.5); Matrix om(m); assert(om[5][2]==0.5); Matrix a(2,3); a[0][0]=1; a[0][1]=2; a[0][2]=3; a[1][0]=4; a[1][1]=5; a[1][2]=6; Matrix b(3,1); b[0][0]=3; b[1][0]=1; b[2][0]=2; Matrix c=a*b; assert(c[0][0]==11 && c[1][0]==29); // test matrix * vector Vector d(3); d[0]=3; d[1]=1; d[2]=2; Vector e=a*d; assert(e[0]==11 && e[1]==29); Matrix f=a.CropCols(1,3); assert(f.GetRows()==2 && f.GetCols()==2 && f[0][0]==2); Matrix g=a.CropRows(0,1); assert(g.GetRows()==1 && g.GetCols()==3 && g[0][0]==1); // test matrix invert Matrix h(3,3); h.Zero(); h[0][0]=1; h[1][1]=1; h[2][2]=1; Matrix i=h.Inverted(); i==h; // some transforms from fluxus Matrix j(4,4); j[0][0]=1.0; j[0][1]=0.0 ; j[0][2]=0.0; j[0][3]=0.0; j[1][0]=0.0 ; j[1][1]=0.7071067690849304 ; j[1][2]=0.7071067690849304 ; j[1][3]=0.0 ; j[2][0]=0.0 ; j[2][1]=-0.7071067690849304 ; j[2][2]=0.7071067690849304 ; j[2][3]=0.0 ; j[3][0]=1.0 ; j[3][1]=2.0 ; j[3][2]=3.0 ; j[3][3]=1.0 ; Matrix k(4,4); k[0][0]=1.0 ; k[0][1]=0.0 ; k[0][2]=0.0 ; k[0][3]=0.0 ; k[1][0]=0.0 ; k[1][1]=0.7071068286895752 ; k[1][2]=-0.7071068286895752 ; k[1][3]=0.0 ; k[2][0]=0.0 ; k[2][1]=0.7071068286895752 ; k[2][2]=0.7071068286895752 ; k[2][3]=0.0 ; k[3][0]=-0.9999999403953552 ; k[3][1]=-3.535533905029297 ; k[3][2]=-0.7071067690849304 ; k[3][3]=0.9999999403953552 ; assert(j.Inverted()==k); Matrix l(2,2); l[0][0]=3; l[0][1]=3; l[1][0]=0; l[1][1]=0; Matrix n(2,2); n[0][0]=2; n[0][1]=2; n[1][0]=0; n[1][1]=0; n*=l; Matrix o(4,4); o.Zero(); o[0][0]=1; o[1][1]=1; o[2][2]=1; o[3][3]=1; j*=k; assert(j==o); { Matrix a(2,3); Matrix b(3,2); a[0][0]=1; a[0][1]=2; a[0][2]=3; a[1][0]=4; a[1][1]=5; a[1][2]=6; b[0][0]=2; b[0][1]=3; b[1][0]=-1; b[1][1]=1; b[2][0]=1; b[2][1]=2; Matrix result(2,2); result[0][0]=3; result[0][1]=11; result[1][0]=9; result[1][1]=29; assert(a*b==result); } } #endif