#pragma once namespace Aftr { template< typename T> MatrixT::MatrixT() { this->numRows = 1; this->numCols = 1; this->m = new T[ this->numRows * this->numCols ]; this->setMatrixToZeros(); this->originalRowSize = 0; this->originalColSize = 0; } template< typename T> MatrixT::MatrixT( unsigned int numRows, unsigned int numCols ) { if( numRows == 0 || numCols == 0 ) { std::cout << "ERROR: MatrixT must have at least 1 row and 1 column\n" << "User tried to create matrix with " << numRows << " rows and " << numCols << " cols\n..." << "Press ENTER to exit...\n"; std::cin.get(); exit(-1); } this->numRows = numRows; this->numCols = numCols; this->m = new T[numRows * numCols]; this->setMatrixToZeros(); this->originalRowSize = 0; this->originalColSize = 0; } template< typename T> MatrixT::MatrixT( std::vector< std::vector< T > >& m ) { this->numRows = (unsigned int) m.size(); this->numCols = (unsigned int) m[0].size(); this->m = new T[numRows * numCols]; for(size_t c = 0; c < m.size(); c++) for(size_t r = 0; r < m[c].size(); r++) this->at((unsigned int) r,(unsigned int) c) = m[r][c]; this->originalRowSize = 0; this->originalColSize = 0; } template< typename T> MatrixT::MatrixT( std::vector< VectorT* >* m ) { this->numRows = (unsigned int) m->size(); this->numCols = 3; this->m = new T[numRows * numCols]; for(size_t i = 0; i < m->size(); i++) for(int j = 0; j < 3; j++) this->at((unsigned int) i,j) = m->at((unsigned int ) i)->operator[](j); this->originalRowSize = 0; this->originalColSize = 0; } template< typename T> MatrixT::MatrixT( T* colMajor2DArray, unsigned int numRows, unsigned int numCols ) { this->m = colMajor2DArray; this->numRows = numRows; this->numCols = numCols; this->originalRowSize = numRows; this->originalColSize = numCols; } template< typename T> MatrixT::MatrixT( const MatrixT& m ) { this->m = NULL; this->numRows = 0; this->numCols = 0; *this = m; } template< typename T> MatrixT::~MatrixT() { if( this->m != NULL ) { delete [] m; m = NULL; } } template< typename T> T* MatrixT::releaseOwnershipOfInternalColumnMajorData( unsigned int& outNumRows, unsigned int& outNumCols ) { T* ret = m; m = NULL; outNumRows = this->numRows; outNumCols = this->numCols; return ret; } template< typename T> MatrixT& MatrixT::operator=( const MatrixT& m ) { if( this != &m ) { this->resize( m.rows(), m.cols() ); this->originalRowSize = m.originalRowSize; this->originalColSize = m.originalColSize; for( unsigned int c = 0; c < m.cols(); ++c ) for( unsigned int r = 0; r < m.rows(); ++r ) this->at(r,c) = m(r,c); } return *this; } template< typename T> T& MatrixT::operator()( unsigned int row, unsigned int col ) { return this->m[ col * numRows + row ]; } template< typename T> T MatrixT::operator()( unsigned int row, unsigned int col ) const { return this->m[ col * numRows + row ]; } template< typename T> T& MatrixT::at( unsigned int row, unsigned int col ) { return this->m[ col * numRows + row ]; } template< typename T> T MatrixT::at( unsigned int row, unsigned int col ) const { return this->m[ col * numRows + row ]; } #ifdef AFTR_CONFIG_USE_CUDA template< typename T> MatrixT MatrixT::multCUDA( const MatrixT& m ) { // 2x3 * 3x2 matrix... 3==3 so resultant matrix will be 2x2 // 2x5 * 5x4 matrix... 5==5 so resultant matrix will be 2x4 if( this->cols() != m.rows() ) { std::cout << "ERROR: MatrixT muliplication dimensions do not match.\n" << "EX: 2x3 matrix * 3x2 matrix... 3==3 so resultant matrix will be 2x2\n" << "EX: 2x5 matrix * 5x4 matrix... 5==5 so resultant matrix will be 2x4\n" << "Columns of first matrix must match rows of second matrix\n" << "Resultant matrix will have dimension of first matrix's rows\n" << "by second matrix's columns.\n" << "Press ENTER to exit...\n"; std::cin.get(); exit(-1); } T* dA = NULL; //this matrix T* dB = NULL; //matrix m (in passed variable) T* dC = NULL; //result //cudaError_t cudaMalloc(void** devPtr, size_t count) /* Allocate device memory for the matrices */ //cublasStatus s0 = cublasAlloc( this->numRows * this->numCols, // sizeof(T), (void**)&dA ); //cublasStatus s1 = cublasAlloc( m.numRows * m.numCols, // sizeof(T), (void**)&dB ); //cublasStatus s2 = cublasAlloc( this->numRows * m.numCols, // sizeof(T), (void**)&dC ); //if( s0 != CUBLAS_STATUS_SUCCESS || // s1 != CUBLAS_STATUS_SUCCESS || // s2 != CUBLAS_STATUS_SUCCESS ) //{ // std::cout << "ERROR in MatrixT Class: CUDA BLAS: Failed to allocate memory on graphics hardware...\n"; // std::cout << "s0 - " << ManagerCUDA::toStringCublasStatus(s0) << "\n"; // std::cout << "s1 - " << ManagerCUDA::toStringCublasStatus(s1) << "\n"; // std::cout << "s2 - " << ManagerCUDA::toStringCublasStatus(s2) << "\n"; // std::cout << "Press ENTER to exit...\n"; // std::cin.get(); // exit(-1); //} ////std::cout << "Allocated all graphics-side memory...\n"; ///* Initialize the device matrices with the host matrices */ //s0 = cublasSetVector( this->numRows * this->numCols, sizeof( T ), // this->m, 1, dA, 1 ); //s1 = cublasSetVector( m.numRows * m.numCols, sizeof( T ), // m.m, 1, dB, 1 ); ////cublasStatus ////cublasSetMatrix (int rows, int cols, int elemSize, ////const void *A, int lda, void *B, ////int ldb) ////s0 = cublasSetMatrix( this->numRows, this->numCols, sizeof( T ), this->m, this->numRows, dA, this->numRows ); ////s1 = cublasSetMatrix( m.rows(), m.cols(), sizeof( T ), m.m, m.rows(), dB, m.rows() ); //if ( s0 != CUBLAS_STATUS_SUCCESS || // s1 != CUBLAS_STATUS_SUCCESS ) //{ // std::cout << "ERROR in MatrixT Class: CUDA BLAS: Failed to transfer main memory matrix to graphics memory...\n"; // std::cout << "s0 - " << ManagerCUDA::toStringCublasStatus(s0) << "\n"; // std::cout << "s1 - " << ManagerCUDA::toStringCublasStatus(s1) << "\n"; // std::cout << "Press ENTER to exit...\n"; // std::cin.get(); // exit(-1); //} ////std::cout << "Set matrices on graphics-side memory...\n"; ////void cublasSgemm (char transa, char transb, int m, int n, //// int k, T alpha, const T *A, int lda, //// const T *B, int ldb, T beta, //// T *C, int ldc) ////op(A) is m x k matrix ////op(B) is k x n matrix ////C is m x n matrix ////lda,ldb,ldc are leading dimension of two-dimensional array (for column major format ////this is the number of rows in the corresponding matrix). //cublasSgemm( 'n', 'n', this->numRows, m.numCols, m.numRows, 1.0f, // dA, this->numRows, // dB, m.numRows, 0, dC, this->numRows ); ////std::cout << "cublasSgemm result is " << ManagerCUDA::toStringCublasStatus( cublasGetError() ) << "...\n"; //MatrixT p( this->numRows, m.numCols ); ///* Read the result back */ //s0 = cublasGetVector( this->numRows * m.cols(), sizeof( T ), // dC, 1, p.m, 1 ); //////cublasGetMatrix (int rows, int cols, int elemSize, //////const void *A, int lda, void *B, //////int ldb) ////s0 = cublasGetMatrix( this->numRows, m.numCols, sizeof( T ), dA, this->numRows, p.m, this->numRows ); //if( s0 != CUBLAS_STATUS_SUCCESS ) //{ // std::cout << "ERROR in MatrixT Class: CUDA BLAS: Failed to retrieve matrix product from graphics memory...\n"; // std::cout << "s0 - " << ManagerCUDA::toStringCublasStatus(s0) << "\n"; // std::cout << "Press ENTER to exit...\n"; // std::cin.get(); // exit(-1); //} //s0 = cublasFree( dA ); //s1 = cublasFree( dB ); //s2 = cublasFree( dC ); //if( s0 != CUBLAS_STATUS_SUCCESS || // s1 != CUBLAS_STATUS_SUCCESS || // s2 != CUBLAS_STATUS_SUCCESS ) //{ // std::cout << "ERROR in MatrixT Class: CUDA BLAS: Failed to free allocated graphics memory\n"; // std::cout << "s0 - " << ManagerCUDA::toStringCublasStatus(s0) << "\n"; // std::cout << "s1 - " << ManagerCUDA::toStringCublasStatus(s1) << "\n"; // std::cout << "s2 - " << ManagerCUDA::toStringCublasStatus(s2) << "\n"; // std::cout << "Press ENTER to exit...\n"; // std::cin.get(); // exit(-1); //} MatrixT p; return p; } #endif template< typename T> MatrixT MatrixT::operator*( const MatrixT& m ) { #ifdef AFTR_CONFIG_USE_CUDA return this->multCUDA( m ); #elif defined AFTR_CONFIG_USE_BOOST return this->multCPUBoostLIB( m ); #else return this->multCPU( m ); #endif } #ifdef AFTR_CONFIG_USE_BOOST template< typename T> MatrixT MatrixT::multCPUBoostLIB( const MatrixT& m ) { using namespace boost::numeric::ublas; matrix< T > ma( this->numRows, this->numCols ); matrix< T > mb( m.numRows, m.numCols ); matrix< T > mz( this->numRows, m.numCols ); for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) ma( (size_t)r, (size_t)c ) = this->at( r, c ); for( unsigned int c = 0; c < m.numCols; ++c ) for( unsigned int r = 0; r < m.numRows; ++r ) mb( (size_t)r, (size_t)c ) = m.at( r, c ); mz = boost::numeric::ublas::prod( ma, mb ); ma.clear(); mb.clear(); MatrixT ret( this->numRows, m.numCols ); for( unsigned int c = 0; c < m.numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) ret( r, c ) = mz( (size_t)r, (size_t)c ); mz.clear(); return ret; } #endif template< typename T> MatrixT MatrixT::multCPU( const MatrixT& m ) { // 2x3 * 3x2 matrix... 3==3 so resultant matrix will be 2x2 // 2x5 * 5x4 matrix... 5==5 so resultant matrix will be 2x4 if( this->cols() != m.rows() ) { std::cout << "ERROR: MatrixT multiplication dimensions do not match.\n" << "EX: 2x3 matrix * 3x2 matrix... 3==3 so resultant matrix will be 2x2\n" << "EX: 2x5 matrix * 5x4 matrix... 5==5 so resultant matrix will be 2x4\n" << "Columns of first matrix must match rows of second matrix\n" << "Resultant matrix will have dimension of first matrix's rows\n" << "by second matrix's columns.\n" << "Press ENTER to exit...\n"; std::cin.get(); exit(-1); } unsigned int pRows = this->rows(); unsigned int pCols = m.cols(); MatrixT p( pRows, pCols ); p.setMatrixToZeros(); for( unsigned int c = 0; c < pCols; ++c ) for( unsigned int r = 0; r < pRows; ++r ) for( unsigned int i = 0; i < this->numCols; ++i ) p(r,c) += this->at(r,i) * m(i,c); return p; } template< typename T> MatrixT MatrixT::operator*=( const MatrixT& m ) { (*this) = (*this) * m; return *this; } template< typename T> MatrixT MatrixT::operator*( T scalar ) { MatrixT p( this->numRows, this->numCols ); for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) p(r,c) = this->at(r,c) * scalar; return p; } template< typename T> MatrixT MatrixT::operator*=( T scalar ) { for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) this->at(r,c) *= scalar; return *this; } template< typename T> MatrixT MatrixT::multiply( const MatrixT& m ) { return (*this) * m; } template< typename T> MatrixT MatrixT::operator+( const MatrixT& m ) { if(this->numCols == m.numCols && this->numRows == m.numRows) { MatrixT tmp(numRows, numCols); for(unsigned int c = 0; c < numCols; c++) for(unsigned int r = 0; r < numRows; r++) tmp.at(r,c) = this->at(r,c) + m.at(r,c); return tmp; } else { std::cout << "Error, trying to + matrices of mismatch dimensions." << std::endl << "Exiting.\n"; std::cin.get(); exit(-1); } } template< typename T> MatrixT MatrixT::operator+=( const MatrixT& m ) { if( this->numRows == m.numRows && this->numCols == m.numCols ) { for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) this->at(r,c) = this->at(r,c) + m.at(r,c); return *this; } else { std::cout << "MatrixT::operator+= ERROR: Cannot add two matrices of\n" << "different dimensions...\nExiting"; std::cin.get(); exit(-1); } } template< typename T> MatrixT MatrixT::operator-( const MatrixT& m ) { if(this->numCols == m.numCols && this->numRows == m.numRows) { MatrixT p(this->numRows, this->numCols); for(unsigned int c = 0; c < this->numCols; c++) for(unsigned int r = 0; r < this->numRows; r++) p(r,c) = this->at(r,c) - m(r,c); return p; } else { std::cout << "ERROR: MatrixT operator-... The two matrices have mismatched dimensions." << std::endl << "Exiting.\n"; std::cin.get(); exit(-1); } } template< typename T> MatrixT MatrixT::operator-=( const MatrixT& m ) { if( this->numRows == m.numRows && this->numCols == m.numCols ) { for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) this->at(r,c) = this->at(r,c) - m.at(r,c); return *this; } else { std::cout << "MatrixT::operator-= ERROR: Cannot subtract two matrices of\n" << "different dimensions...\nExiting"; std::cin.get(); exit(-1); } } template< typename T> MatrixT MatrixT::operator/( T s ) { MatrixT p( this->numRows, this->numCols ); for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) p.at(r,c) = this->at(r,c) / s; return p; } template< typename T> MatrixT MatrixT::operator/=( T s ) { for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) this->at(r,c) /= s; return *this; } template< typename T> MatrixT MatrixT::transpose() const { MatrixT p( this->numCols, this->numRows ); for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) p(c,r) = this->at(r,c); return p; } template< typename T> bool MatrixT::equals( const MatrixT& m, T epsilon ) { if( this != &m ) { if( this->numRows == m.numRows && this->numCols == m.numCols ) { for( unsigned int c = 0; c < this->numCols; ++c ) { for( unsigned int r = 0; r < this->numRows; ++r ) { if( fabs( this->at(r,c) - m.at(r,c) ) > epsilon ) return false; } } } else return false; } return true; //this matrix == this matrix } template< typename T> MatrixT MatrixT::inverse() { #ifdef AFTR_CONFIG_USE_CUDA //if( this->numCols >= 128 ) return this->inverseCUDA(); #endif return this->inverseCPU(); } template< typename T> MatrixT MatrixT::inverseCPU() { if( this->numRows != this->numCols ) { std::cout << "ERROR:template< typename T> MatrixT::inverse(). Can only find inverse\n" << "of a MxM non-singular matrix. This matrix is not MxM\n" << "Press ENTER to exit...\n"; std::cin.get(); exit( -1 ); } MatrixT inverseMat( this->numRows, this->numCols ); if( this->isInvertable( inverseMat ) ) { return inverseMat; } else { std::cout << "MatrixT::inverse(). This MatrixT is singular\n" << "Cannot invert a singular matrix. Use MatrixT::isInvertable()\n" << "to test if the matrix is invertible.\n" << "Press ENTER to exit...\n"; std::cin.get(); exit( -1 ); inverseMat.setMatrixToIdentity(); return inverseMat; } } template< typename T> bool MatrixT::isInvertable( MatrixT& invertedMatrix ) { //perform LU factorization followed by lu substitution to find inverse of 'this' matrix using namespace boost::numeric::ublas; matrix A = make_matrix_from_pointer( this->numRows, this->numCols, this->m ); // create a boost matrix based off internal matrix data of this instance permutation_matrix pm( A.size1() ); //permutation matrix populated during lu_factorization, // perform LU-factorization size_t res = lu_factorize( A, pm ); if( res != 0 ) return false; //singular matrix, not invertible. Matrix A makes a copy of the data passed to it; therefore, 'this' matrix is unaltered and no leaks occur // create identity matrix of "inverse" matrix< T, column_major > matInv = identity_matrix( A.size1() ); //inverse.assign(ublas::identity_matrix(A.size1())); // back substitute to get the inverse lu_substitute( A, pm, matInv ); invertedMatrix.resize( this->numRows, this->numCols ); std::copy( matInv.data().begin(), matInv.data().end(), invertedMatrix.getInternalMatrixPtr() ); return true; } #ifdef AFTR_CONFIG_USE_CUDA template< typename T> MatrixT MatrixT::inverseCUDA() { if( this->numRows != this->numCols ) { std::cout << "ERROR:template< typename T> MatrixT::inverse(). Can only find inverse\n" << "of a MxM non-singular matrix. This matrix is not MxM\n" << "Press ENTER to exit...\n"; std::cin.get(); exit( -1 ); } //The CUDA-based algorithm excepts that the matrix is a square matrix //that is a square multiple of BLOCKSIZE, as defined in //MatrixInverseCUDA_GPUGausSeidel.h. //Therefore we have to pad the input to the nearest multiple of BLOCKSIZE //greater than or equal to numCols*numCols. //Find nearest multiple of BLOCKSIZE unsigned int numBlocks = (unsigned int)( this->numCols / BLOCKSIZE ); if( this->numCols % BLOCKSIZE > 0 ) //if not evenly divisible, we need another block ++numBlocks; unsigned int dim = numBlocks*BLOCKSIZE; T* rowMajor = new T[dim * dim]; memset( rowMajor, 0, sizeof( T ) * dim * dim ); for( unsigned int i = 0; i < dim; ++i ) rowMajor[i * dim + i] = 1.0f; //set the diagonal to be 1's initially //The GPU implementation expects a single array in row-major form... //Convert this matrix into a single row-major matrix for( unsigned int r = 0; r < this->numRows; ++r ) for( unsigned int c = 0; c < this->numCols; ++c ) rowMajor[r * dim + c] = this->at( r, c ); //////std::cout << "Row Major TO GPU is (" << dim << "x" << dim << "):\n"; //////for( unsigned int i = 0; i < dim*dim; ++i ) //////{ ////// if( i % dim == 0 ) ////// std::cout << "\n"; ////// std::cout << rowMajor[i] << " "; //////} //////std::cout << "\n\n"; GPUGausSeidel( rowMajor, rowMajor, dim ); //////std::cout << "Output FROM GPU is:\n"; //////for( unsigned int i = 0; i < dim * dim; ++i ) ////// std::cout << rowMajor[i] << " "; //////std::cout << "\n\n"; //The result is in row major format. //Place the inverse in the result matrix; ensure the data is //internally stored column major. MatrixT ret( this->numRows, this->numCols ); for( unsigned int r = 0; r < this->numRows; ++r ) for( unsigned int c = 0; c < this->numCols; ++c ) ret( r, c ) = rowMajor[r * dim + c]; delete[] rowMajor; rowMajor = NULL; return ret; } #endif template< typename T> bool MatrixT::gaussianJordanElimination( const MatrixT& a, MatrixT& x, const MatrixT& b ) { //unsigned int rows = 3; //unsigned int cols = 3; //double** lhs = new double*[rows];//(double**)malloc(sizeof(double*)* rows * cols ); //for( size_t i = 0; i < cols; ++i ) // lhs[i] = new double[cols]; //lhs[0][0] = a.x; lhs[0][1] = a.y; lhs[0][2] = a.z; //lhs[1][0] = b.x; lhs[1][1] = b.y; lhs[1][2] = b.z; //lhs[2][0] = c.x; lhs[2][1] = c.y; lhs[2][2] = c.z; double** lhs = new double*[ a.rows() ]; for( unsigned int i = 0; i < a.rows(); ++i ) lhs[i] = new double[ a.cols() ]; for( unsigned int i = 0; i < a.rows(); ++i ) for( unsigned int j = 0; j < a.cols(); ++j ) lhs[i][j] = a( i, j ); double** rhs = new double*[ b.rows() ]; for( unsigned int i = 0; i < b.rows(); ++i ) rhs[i] = new double[ b.cols() ]; for( unsigned int i = 0; i < b.rows(); ++i ) for( unsigned int j = 0; j < b.cols(); ++j ) rhs[i][j] = b( i, j ); if( gaussianJordanElimination( lhs, rhs, a.rows(), b.cols() ) ) { x.resize( b.rows(), b.cols() ); for( unsigned int i = 0; i < x.rows(); ++i ) for( unsigned int j = 0; j < x.cols(); ++j ) x(i,j) = (T) rhs[i][j]; return true; } return false; } template< typename T> MatrixT* MatrixT::appendRowToTopRetMatrixPtr( T initialVal ) { MatrixT* x = new MatrixT( this->numRows + 1, this->numCols ); //create new top row set to initial value for( unsigned int i = 0; i < x->cols(); ++i ) x->at(0,i) = initialVal; //copy rest of matrix for( unsigned int c = 0; c < x->cols(); ++c ) for( unsigned int r = 1; r < x->rows(); ++r ) x->at(r,c) = this->m[ c * this->numRows + (r-1) ]; return x; } template< typename T> void MatrixT::appendRowToTop( T initialVal ) { T* old = this->m; this->m = NULL; this->resize( this->numRows + 1, this->numCols ); for( unsigned int i = 0; i < this->cols(); ++i ) this->at(0,i) = initialVal; for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 1; r < this->numRows; ++r ) this->at(r,c) = old[ c * (this->numRows-1) + (r-1) ]; delete [] old; old = NULL; } template< typename T> MatrixT* MatrixT::appendRowToBottomRetMatrixPtr( T initialVal ) { MatrixT* x = new MatrixT( this->numRows + 1, this->numCols ); //create new bottom row set to initial value for( unsigned int i = 0; i < x->cols(); ++i ) x->at( x->rows()-1, i ) = initialVal; //copy rest of matrix for( unsigned int c = 0; c < x->cols(); ++c ) for( unsigned int r = 0; r < x->rows()-1; ++r ) x->at(r,c) = this->m[ c * (this->numRows) + r ]; return x; } template< typename T> void MatrixT::appendRowToBottom( T initialVal ) { T* old = this->m; this->m = NULL; this->resize( this->numRows + 1, this->numCols ); //create new bottom row set to initial value for( unsigned int i = 0; i < this->cols(); ++i ) this->at( this->rows()-1, i ) = initialVal; //copy rest of matrix for( unsigned int c = 0; c < this->cols(); ++c ) for( unsigned int r = 0; r < this->rows()-1; ++r ) this->at(r,c) = old[ c * (this->numRows-1) + r ]; delete [] old; old = NULL; } template< typename T> MatrixT* MatrixT::appendColToLeftRetMatrixPtr( T initialVal ) { MatrixT* x = new MatrixT( this->numRows, this->numCols + 1 ); //copy original matrix to x not touching first column for( unsigned int c = 1; c < x->cols(); ++c ) for( unsigned int r = 0; r < x->rows(); ++r ) x->at(r,c) = this->m[ (c-1) * this->numRows + r ]; //set new column on left to initial value for( unsigned int i = 0; i < x->rows(); ++i ) x->at(i,0) = initialVal; return x; } template< typename T> void MatrixT::appendColToLeft( T initialVal ) { T* old = this->m; this->m = NULL; this->resize( this->numRows, this->numCols + 1 ); //copy original matrithis to this not touching first column for( unsigned int c = 1; c < this->cols(); ++c ) for( unsigned int r = 0; r < this->rows(); ++r ) this->at(r,c) = old[ (c-1) * (this->numRows) + r ]; //set new column on left to initial value for( unsigned int i = 0; i < this->rows(); ++i ) this->at(i,0) = initialVal; delete [] old; old = NULL; } template< typename T> MatrixT* MatrixT::appendColToRightRetMatrixPtr( T initialVal ) { MatrixT* x = new MatrixT( this->numRows, this->numCols + 1 ); //copy original matrix to x not touching last column for( unsigned int c = 0; c < x->cols(); ++c ) for( unsigned int r = 0; r < x->rows(); ++r ) x->at(r,c) = this->m[ c * this->numRows + r ]; //set new column on right to initial value for( unsigned int i = 0; i < x->rows(); ++i ) x->at(i, x->cols()-1) = initialVal; return x; } template< typename T> void MatrixT::appendColToRight( T initialVal ) { T* old = this->m; this->m = NULL; this->resize( this->numRows, this->numCols + 1 ); //copy original matrithis to this not touching last column for( unsigned int c = 0; c < this->cols()-1; ++c ) for( unsigned int r = 0; r < this->rows(); ++r ) this->at(r,c) = old[ c * this->numRows + r ]; //set new column on right to initial value for( unsigned int i = 0; i < this->rows(); ++i ) this->at(i, this->cols()-1) = initialVal; delete [] old; old = NULL; } template< typename T> void MatrixT::resize( unsigned int numRows, unsigned int numCols ) { if( this->numRows == numRows && this->numCols == numCols ) return; this->numRows = numRows; this->numCols = numCols; if( m != NULL ) { delete [] this->m; this->m = NULL; } this->m = new T[ this->numRows * this->numCols ]; } template< typename T> void MatrixT::setMatrixToZeros() { this->setMatrixTo( 0 ); } template< typename T> void MatrixT::setMatrixToOnes() { this->setMatrixTo( 1 ); } template< typename T> void MatrixT::setMatrixTo( T value ) { for( unsigned int r = 0; r < this->numRows; ++r ) for( unsigned int c = 0; c < this->numCols; ++c ) this->at(r,c) = value; } template< typename T> void MatrixT::setMatrixToIdentity() { this->setMatrixToZeros(); unsigned int c = std::min( this->rows(), this->cols() ); for( unsigned int i = 0; i < c; ++i ) this->at(i,i) = 1.0f; } template< typename T> void MatrixT::setMatrixToColumnMajor2DArray( T* colMajor2DArray, unsigned int numRows, unsigned int numCols ) { if( this->m != NULL ) { delete [] this->m; this->m = NULL; } this->m = colMajor2DArray; this->numRows = numRows; this->numCols = numCols; } template< typename T> MatrixT MatrixT::getColumnVector( unsigned int col ) { if( col >= this->numCols ) { std::cout << "ERROR: MatrixT::getColumnVector...\n" << "MatrixT has " << this->numCols << " columns.\n" << "User attempted to access column " << col << ".\n" << "This index is outside of the matrix...\n" << "Press ENTER to exit...\n"; std::cin.get(); exit(-1); } MatrixT p( this->numRows, 1 ); for( unsigned int r = 0; r < this->numRows; ++r ) p(r,0) = this->at(r,col); return p; } template< typename T> MatrixT MatrixT::getRowVector( unsigned int row ) { if( row >= this->numRows ) { std::cout << "ERROR: MatrixT::getRowVector...\n" << "MatrixT has " << this->numRows << " rows.\n" << "User attempted to access row " << row << ".\n" << "This index is outside of the matrix...\n" << "Press ENTER to exit...\n"; std::cin.get(); exit(-1); } MatrixT p( 1, this->numCols ); for( unsigned int c = 0; c < this->numCols; ++c ) p(0,c) = this->at(row,c); return p; } template< typename T> MatrixT MatrixT::getSubMatrix( unsigned int row, unsigned int numRows, unsigned int col, unsigned int numCols ) { if( row+numRows > this->numRows ) { std::cout << "ERROR: MatrixT::getSubMatrix...\n" << "MatrixT has " << this->numRows << " rows.\n" << "User attempted to access row " << row+numRows << ".\n" << "This is outside of the matrix...\n" << "Press ENTER to exit...\n"; std::abort(); } else if( col+numCols > this->numCols ) { std::cout << "ERROR: MatrixT::getSubMatrix...\n" << "MatrixT has " << this->numCols << " columns.\n" << "User attempted to access column " << col+numCols << ".\n" << "This is outside of the matrix...\n" << "Press ENTER to exit...\n"; std::abort(); } else if( numRows == 0 || numCols == 0 ) { std::cout << "ERROR: MatrixT::getSubMatrix...\n" << "numRows to be retrieved must be at least 1\n" << "numCols to be retrieved must be at least 1\n" << "Press ENTER to exit...\n"; std::abort(); } MatrixT p( numRows, numCols ); for( unsigned int r = row; r < row + numRows; ++r ) for( unsigned int c = col; c < col + numCols; ++c ) p(r-row,c-col) = this->at(r,c); return p; } template< typename T> void MatrixT::getQRDecomposition( MatrixT& Q, MatrixT& R ) { #ifdef AFTR_CONFIG_USE_ALGLIB_2_0_0 ap::real_2d_array b; ap::real_1d_array taub; ap::real_2d_array q; ap::real_2d_array r; ap::real_2d_array q2; //Populate alglib matrix 'b' with this matrix's data b.setbounds( 0, this->numRows, 0, this->numCols ); for( unsigned int r = 0; r < this->numRows; ++r ) for( unsigned int c = 0; c < this->numCols; ++c ) b(r,c) = this->at(r,c); //makeacopy(a, m, n, b); rmatrixqr(b, this->numRows, this->numCols, taub); rmatrixqrunpackq(b, this->numRows, this->numCols, taub, this->numRows, q); rmatrixqrunpackr(b, this->numRows, this->numCols, r); //Q is an orthogonal matrix of size MxM (M are rows, N are cols). //R is an upper triangular (or upper trapezoid) matrix of size MxN. Q.resize( this->numRows, this->numRows ); R.resize( this->numRows, this->numCols ); for( unsigned int r = 0; r < this->numRows; ++r ) for( unsigned int k = 0; k < this->numRows; ++k ) Q(r,k) = (T) q(r,k); for( unsigned int row = 0; row < this->numRows; ++row ) for( unsigned int c = 0; c < this->numCols; ++c ) R(row,c) = (T) r(row,c); #else std::cout << "WARNING: AFTR_CONFIG_USE_ALGLIB_2_0_0 is NOT DEFINED. NO QR Decomposition\n" << " is supported in MatrixT class! Recompile engine with AFTR_CONFIG_USE_ALGLIB_2_0_0\n" << " defined for MatrixT::getQRDecomposition(...) support...\n" << " NOT touching MatrixT& Q or MatrixT& R and returning now...\n"; #endif } template< typename T> std::string MatrixT::toString( unsigned int width ) const { char str[1024]; std::stringstream strWidth; strWidth << width; std::string format = "%."; format.append( strWidth.str() ); format.append( "f" ); std::stringstream ss; for( unsigned int r = 0; r < this->numRows; ++r ) { for( unsigned int c = 0; c < this->numCols; ++c ) { sprintf( str, format.c_str(), this->at(r,c) ); ss << str << " "; } ss << "\n"; } std::string s = ss.str(); return s; } template< typename T> MatrixT MatrixT::sumColumns() { MatrixT temp(1, numCols); for(unsigned int i = 0; i < numCols; i++) for(unsigned int j = 0; j < numRows; j++) { temp.at(0, i) += this->at(j,i); } return temp; } template< typename T> MatrixT MatrixT::componentWiseDivide(MatrixT& m) { if(numRows != m.rows() || numCols != m.cols()) { std::cout << "mismatched matrix dimensions, exiting!\n"; exit(187); } MatrixT temp(this->numRows, this->numCols); for(unsigned int i = 0; i < numRows; i++) for(unsigned int j = 0; j < numCols; j++) temp(i,j) = this->at(i,j) / m.at(i,j); return temp; } template< typename T> MatrixT MatrixT::normalizeEachRow() const { MatrixT ret( *this ); for( unsigned int r = 0; r < ret.numRows; ++r ) { T mag = ret.getMagnitudeOfRow( r ); for( unsigned int c = 0; c < ret.numCols; ++c ) ret.at(r,c) /= mag; } return ret; } template< typename T> void MatrixT::normalizeMeEachRow() { for( unsigned int r = 0; r < this->numRows; ++r ) { T mag = this->getMagnitudeOfRow( r ); for( unsigned int c = 0; c < this->numCols; ++c ) this->at(r,c) /= mag; } } template< typename T> T MatrixT::getMagnitudeOfRow( unsigned int row ) const { return sqrt( this->getMagnitudeSquaredOfRow( row ) ); } template< typename T> T MatrixT::getMagnitudeSquaredOfRow( unsigned int row ) const { T magSq = 0; for( unsigned int c = 0; c < this->numCols; ++c ) magSq += this->at( row, c ) * this->at( row, c ); return magSq; } template< typename T> MatrixT MatrixT::normalizeEachColumn() const { MatrixT ret( *this ); for( unsigned int c = 0; c < ret.numCols; ++c ) { T mag = ret.getMagnitudeOfColumn( c ); for( unsigned int r = 0; r < ret.numRows; ++r ) ret.at(r,c) /= mag; } return ret; } template< typename T> void MatrixT::normalizeMeEachColumn() { for( unsigned int c = 0; c < this->numCols; ++c ) { T mag = this->getMagnitudeOfColumn( c ); for( unsigned int r = 0; r < this->numRows; ++r ) this->at(r,c) /= mag; } } template< typename T> T MatrixT::getMagnitudeOfColumn( unsigned int col ) const { return sqrt( this->getMagnitudeSquaredOfColumn( col ) ); } template< typename T> T MatrixT::getMagnitudeSquaredOfColumn( unsigned int col ) const { T magSq = 0; for( unsigned int r = 0; r < this->numRows; ++r ) magSq += this->at( r, col ) * this->at( r, col ); return magSq; } template< typename T> void MatrixT::toFile( const std::string& filename) { std::ofstream fout; fout.open(filename.c_str()); if(fout.fail()) { std::cout << "Error opening file: " << filename << "\n"; std::cout << "Not writing to file.\n"; std::cin.get(); } else { for(unsigned int i = 0; i < this->rows(); i++) { for(unsigned int j = 0; j < this->cols(); j++) { fout << at(i,j); if(j != this->cols() - 1) fout << ","; } fout << "\n"; } } } template< typename T> void MatrixT::fromFile( const std::string& filename ) { std::ifstream fin; fin.open(filename.c_str()); T x; if(fin.fail()) { std::cout << "Error opening file: " << filename << "\n"; std::cout << "Exiting program.\n"; std::cin.get(); exit(123); } else { fin >> x; std::vector< std::vector< T > > outer; std::vector< T > inner; while(!fin.eof()) { inner.push_back(x); if(fin.peek() == ',') fin.get(); else { outer.push_back(inner); inner.clear(); fin.get(); } fin >> x; } this->resize((unsigned int ) outer.size(), (unsigned int) outer[0].size()); for(size_t i = 0; i < outer.size(); i++) for(size_t j = 0; j < outer[i].size(); j++) this->at((unsigned int) i, (unsigned int) j) = outer[i][j]; } } template< typename T> T* MatrixT::getInternalMatrixPtr() { return this->m; } template< typename T> MatrixT MatrixT::alignWithCUDAHalfWarp( unsigned int byteAlignment ) { //Grow dimensions to the nearest half-warp boundary sizes of the //rows and columns unsigned int quotient = this->numRows / byteAlignment; unsigned int remainder = this->numRows % byteAlignment; if( remainder > 0 ) ++quotient; quotient *= byteAlignment; unsigned int newRowSize = quotient; quotient = this->numCols / byteAlignment; remainder = this->numCols % byteAlignment; if( remainder > 0 ) ++quotient; quotient *= byteAlignment; unsigned int newColSize = quotient; MatrixT a; a.originalRowSize = this->numRows; a.originalColSize = this->numCols; a.resize( newRowSize, newColSize ); a.setMatrixToZeros(); for( unsigned int c = 0; c < this->numCols; ++c ) for( unsigned int r = 0; r < this->numRows; ++r ) a(r,c) = this->at(r,c); return a; } } //namespace Aftr