/** @file Matrix.tcc * This is an internal header file, included by other library headers. * You should not attempt to use it directly. */ #ifndef TNet_Matrix_tcc #define TNet_Matrix_tcc //#pragma GCC system_header #include #include #include #include #include #include #include #include #include #include "Common.h" #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #ifdef HAVE_ATLAS extern "C"{ #include } #endif #include "Common.h" #include "Vector.h" namespace TNet { //****************************************************************************** template Matrix<_ElemT> & Matrix<_ElemT>:: Init(const size_t rows, const size_t cols, bool clear) { if(mpData != NULL) Destroy(); if(rows*cols == 0){ assert(rows==0 && cols==0); mMRows=rows; mMCols=cols; #ifdef STK_MEMALIGN_MANUAL mpFreeData=NULL; #endif mpData=NULL; return *this; } // initialize some helping vars size_t skip; size_t real_cols; size_t size; void* data; // aligned memory block void* free_data; // memory block to be really freed // compute the size of skip and real cols skip = ((16 / sizeof(_ElemT)) - cols % (16 / sizeof(_ElemT))) % (16 / sizeof(_ElemT)); real_cols = cols + skip; size = rows * real_cols * sizeof(_ElemT); // allocate the memory and set the right dimensions and parameters if (NULL != (data = stk_memalign(16, size, &free_data))) { mpData = static_cast<_ElemT *> (data); #ifdef STK_MEMALIGN_MANUAL mpFreeData = static_cast<_ElemT *> (free_data); #endif mMRows = rows; mMCols = cols; mStride = real_cols; } else { throw std::bad_alloc(); } if(clear) Zero(); return *this; } // //**************************************************************************** //**************************************************************************** template template Matrix<_ElemT> & Matrix<_ElemT>:: Copy(const Matrix<_ElemU> & rM, MatrixTrasposeType Trans) { if(Trans==NO_TRANS){ assert(mMRows == rM.Rows() && mMCols == rM.Cols()); for(size_t i = 0; i < mMRows; i++) (*this)[i].Copy(rM[i]); return *this; } else { assert(mMCols == rM.Rows() && mMRows == rM.Cols()); for(size_t i = 0; i < mMRows; i++) for(size_t j = 0; j < mMCols; j++) (*this)(i,j) = rM(j,i); return *this; } } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT> & Matrix<_ElemT>:: CopyVectorSplicedRows(const Vector<_ElemT> &rV, const size_t nRows, const size_t nCols) { assert(rV.Dim() == nRows*nCols); mMRows = nRows; mMCols = nCols; Init(nRows,nCols,true); for(size_t r=0; r Matrix<_ElemT> & Matrix<_ElemT>:: RemoveRow(size_t i) { assert(i < mMRows && "Access out of matrix"); for(size_t j = i + 1; j < mMRows; j++) (*this)[j - 1].Copy((*this)[j]); mMRows--; return *this; } //**************************************************************************** //**************************************************************************** // The destructor template void Matrix<_ElemT>:: Destroy() { // we need to free the data block if it was defined #ifndef STK_MEMALIGN_MANUAL if (NULL != mpData) free(mpData); #else if (NULL != mpData) free(mpFreeData); mpFreeData = NULL; #endif mpData = NULL; mMRows = mMCols = 0; } //**************************************************************************** //**************************************************************************** // template // void // Matrix<_ElemT>:: // VectorizeRows(Vector<_ElemT> &rV) { //#ifdef PARANIOD // assert(rV.Dim() == mMRows*mMCols); //#endif // for(size_t r=0; r bool Matrix<_ElemT>:: LoadHTK(const char* pFileName) { HtkHeader htk_hdr; FILE *fp = fopen(pFileName, "rb"); if(!fp) { return false; } read(fileno(fp), &htk_hdr, sizeof(htk_hdr)); swap4(htk_hdr.mNSamples); swap4(htk_hdr.mSamplePeriod); swap2(htk_hdr.mSampleSize); swap2(htk_hdr.mSampleKind); Init(htk_hdr.mNSamples, htk_hdr.mSampleSize / sizeof(float)); size_t i; size_t j; if (typeid(_ElemT) == typeid(float)) { for (i=0; i< Rows(); ++i) { read(fileno(fp), (*this).pRowData(i), Cols() * sizeof(float)); for(j = 0; j < Cols(); j++) { swap4(((*this)(i,j))); } } } else { float *pmem = new (std::nothrow) float[Cols()]; if (!pmem) { fclose(fp); return false; } for(i = 0; i < Rows(); i++) { read(fileno(fp), pmem, Cols() * sizeof(float)); for (j = 0; j < Cols(); ++j) { swap4(pmem[j]); (*this)(i,j) = static_cast<_ElemT>(pmem[j]); } } delete [] pmem; } fclose(fp); return true; } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT> & Matrix<_ElemT>:: DotMul(const ThisType& a) { size_t i; size_t j; for (i = 0; i < mMRows; ++i) { for (j = 0; j < mMCols; ++j) { (*this)(i,j) *= a(i,j); } } return *this; } //**************************************************************************** //**************************************************************************** template _ElemT & Matrix<_ElemT>:: Sum() const { double sum = 0.0; for (size_t i = 0; i < Rows(); ++i) { for (size_t j = 0; j < Cols(); ++j) { sum += (*this)(i,j); } } return sum; } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT>& Matrix<_ElemT>:: Scale(_ElemT alpha) { #if 0 for (size_t i = 0; i < Rows(); ++i) for (size_t j = 0; j < Cols(); ++j) (*this)(i,j) *= alpha; #else for (size_t i = 0; i < Rows(); ++i) { _ElemT* p_data = pRowData(i); for (size_t j = 0; j < Cols(); ++j) { *p_data++ *= alpha; } } #endif return *this; } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT>& Matrix<_ElemT>:: ScaleRows(const Vector<_ElemT>& scale) // scales each row by scale[i]. { assert(scale.Dim() == Rows()); size_t M = Rows(), N = Cols(); for (size_t i = 0; i < M; i++) { _ElemT this_scale = scale(i); for (size_t j = 0; j < N; j++) { (*this)(i,j) *= this_scale; } } return *this; } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT>& Matrix<_ElemT>:: ScaleCols(const Vector<_ElemT>& scale) // scales each column by scale[i]. { assert(scale.Dim() == Cols()); for (size_t i = 0; i < Rows(); i++) { for (size_t j = 0; j < Cols(); j++) { _ElemT this_scale = scale(j); (*this)(i,j) *= this_scale; } } return *this; } //**************************************************************************** //**************************************************************************** template Matrix<_ElemT>& Matrix<_ElemT>:: Add(const Matrix<_ElemT>& rMatrix) { assert(rMatrix.Cols() == Cols()); assert(rMatrix.Rows() == Rows()); #if 0 //this can be slow for (size_t i = 0; i < Rows(); i++) { for (size_t j = 0; j < Cols(); j++) { (*this)(i,j) += rMatrix(i,j); } } #else //this will be faster (but less secure) for(size_t i=0; i Matrix<_ElemT>& Matrix<_ElemT>:: AddScaled(_ElemT alpha, const Matrix<_ElemT>& rMatrix) { assert(rMatrix.Cols() == Cols()); assert(rMatrix.Rows() == Rows()); #if 0 //this can be slow for (size_t i = 0; i < Rows(); i++) { for (size_t j = 0; j < Cols(); j++) { (*this)(i,j) += rMatrix(i,j) * alpha; } } #else /* //this will be faster (but less secure) for(size_t i=0; i Matrix<_ElemT>& Matrix<_ElemT>:: ApplyLog() { #if 0 //this can be slow for (size_t i = 0; i < Rows(); i++) { for (size_t j = 0; j < Cols(); j++) { (*this)(i,j) = += _LOG((*this)(i,j)); } } #else //this will be faster (but less secure) for(size_t i=0; i Matrix<_ElemT> & Matrix<_ElemT>:: Zero() { for(size_t row=0;row Matrix<_ElemT> & Matrix<_ElemT>:: Unit() { for(size_t row=0;row void Matrix<_ElemT>:: PrintOut(char* file) { FILE* f = fopen(file, "w"); unsigned i,j; fprintf(f, "%dx%d\n", this->mMRows, this->mMCols); for(i=0; imMRows; i++) { _ElemT* row = (*this)[i]; for(j=0; jmStride; j++){ fprintf(f, "%20.17f ",row[j]); } fprintf(f, "\n"); } fclose(f); } //**************************************************************************** //**************************************************************************** template void Matrix<_ElemT>:: ReadIn(char* file) { FILE* f = fopen(file, "r"); int i = 0; int j = 0; fscanf(f, "%dx%d\n", &i,&j); fprintf(stderr, "%dx%d\n", i,j); for(i=0; imMRows; i++) { _ElemT* row = (*this)[i]; for(j=0; jmStride; j++){ fscanf(f, "%f ",&row[j]); } //fprintf(f, "\n"); } fclose(f); } //**************************************************************************** //**************************************************************************** template void Save (std::ostream &rOut, const Matrix<_ElemT> &rM) { for (size_t i = 0; i < rM.Rows(); i++) { for (size_t j = 0; j < rM.Cols(); j++) { rOut << rM(i,j) << ' '; } rOut << '\n'; } if(rOut.fail()) throw std::runtime_error("Failed to write matrix to stream"); } //**************************************************************************** //**************************************************************************** template std::ostream & operator << (std::ostream & rOut, const Matrix<_ElemT> & rM) { rOut << "m " << rM.Rows() << ' ' << rM.Cols() << '\n'; Save(rOut, rM); return rOut; } //**************************************************************************** //**************************************************************************** template void Load (std::istream & rIn, Matrix<_ElemT> & rM) { if(MatrixVectorIostreamControl::Flags(rIn, ACCUMULATE_INPUT)) { for (size_t i = 0; i < rM.Rows(); i++) { std::streamoff pos = rIn.tellg(); for (size_t j = 0; j < rM.Cols(); j++) { _ElemT tmp; rIn >> tmp; rM(i,j) += tmp; if(rIn.fail()){ throw std::runtime_error("Failed to read matrix from stream. File position is "+to_string(pos)); } } } } else { for (size_t i = 0; i < rM.Rows(); i++) { std::streamoff pos = rIn.tellg(); for (size_t j = 0; j < rM.Cols(); j++) { rIn >> rM(i,j); if(rIn.fail()){ throw std::runtime_error("Failed to read matrix from stream. File position is "+to_string(pos)); } } } } } //**************************************************************************** //**************************************************************************** template std::istream & operator >> (std::istream & rIn, Matrix<_ElemT> & rM) { while(isascii(rIn.peek()) && isspace(rIn.peek())) rIn.get(); // eat up space. if(rIn.peek() == 'm'){ // "new" format: m \n 1.0 0.2 4.3 ... rIn.get();// eat up the 'm'. long long int nrows=-1; rIn>>nrows; long long int ncols=-1; rIn>>ncols; if(rIn.fail()||nrows<0||ncols<0){ throw std::runtime_error("Failed to read matrix from stream: no size\n"); } size_t nrows2 = size_t(nrows), ncols2 = size_t(ncols); assert((long long int)nrows2 == nrows && (long long int)ncols2 == ncols); if(rM.Rows()!=nrows2 || rM.Cols()!=ncols2) rM.Init(nrows2,ncols2); } Load(rIn,rM); return rIn; } //**************************************************************************** //**************************************************************************** // Constructor template SubMatrix<_ElemT>:: SubMatrix(const Matrix<_ElemT>& rT, // Matrix cannot be const because SubMatrix can change its contents. Would have to have a ConstSubMatrix or something... const size_t ro, const size_t r, const size_t co, const size_t c) { assert(ro >= 0 && ro <= rT.Rows()); assert(co >= 0 && co <= rT.Cols()); assert(r > 0 && r <= rT.Rows() - ro); assert(c > 0 && c <= rT.Cols() - co); // point to the begining of window Matrix<_ElemT>::mMRows = r; Matrix<_ElemT>::mMCols = c; Matrix<_ElemT>::mStride = rT.Stride(); Matrix<_ElemT>::mpData = rT.pData_workaround() + co + ro * rT.Stride(); } #ifdef HAVE_ATLAS template<> Matrix & Matrix:: BlasGer(const float alpha, const Vector& rA, const Vector& rB); template<> Matrix & Matrix:: BlasGer(const double alpha, const Vector& rA, const Vector& rB); template<> Matrix& Matrix:: BlasGemm(const float alpha, const Matrix& rA, MatrixTrasposeType transA, const Matrix& rB, MatrixTrasposeType transB, const float beta); template<> Matrix& Matrix:: BlasGemm(const double alpha, const Matrix& rA, MatrixTrasposeType transA, const Matrix& rB, MatrixTrasposeType transB, const double beta); template<> Matrix& Matrix:: Axpy(const float alpha, const Matrix& rA, MatrixTrasposeType transA); template<> Matrix& Matrix:: Axpy(const double alpha, const Matrix& rA, MatrixTrasposeType transA); template <> // non-member so automatic namespace lookup can occur. double TraceOfProduct(const Matrix &A, const Matrix &B); template <> // non-member so automatic namespace lookup can occur. double TraceOfProductT(const Matrix &A, const Matrix &B); template <> // non-member so automatic namespace lookup can occur. float TraceOfProduct(const Matrix &A, const Matrix &B); template <> // non-member so automatic namespace lookup can occur. float TraceOfProductT(const Matrix &A, const Matrix &B); #else // HAVE_ATLAS #error Routines in this section are not implemented yet without BLAS #endif // HAVE_ATLAS template bool Matrix<_ElemT>:: IsSymmetric(_ElemT cutoff) const { size_t R=Rows(), C=Cols(); if(R!=C) return false; _ElemT bad_sum=0.0, good_sum=0.0; for(size_t i=0;i cutoff*good_sum) return false; return true; } template bool Matrix<_ElemT>:: IsDiagonal(_ElemT cutoff) const{ size_t R=Rows(), C=Cols(); _ElemT bad_sum=0.0, good_sum=0.0; for(size_t i=0;i good_sum * cutoff)); } template bool Matrix<_ElemT>:: IsUnit(_ElemT cutoff) const { size_t R=Rows(), C=Cols(); if(R!=C) return false; _ElemT bad_sum=0.0; for(size_t i=0;i bool Matrix<_ElemT>:: IsZero(_ElemT cutoff)const { size_t R=Rows(), C=Cols(); _ElemT bad_sum=0.0; for(size_t i=0;i _ElemT Matrix<_ElemT>:: FrobeniusNorm() const{ size_t R=Rows(), C=Cols(); _ElemT sum=0.0; for(size_t i=0;i _ElemT Matrix<_ElemT>:: LargestAbsElem() const{ size_t R=Rows(), C=Cols(); _ElemT largest=0.0; for(size_t i=0;i _ElemT Matrix<_ElemT>:: LogAbsDeterminant(_ElemT *DetSign){ _ElemT LogDet; Matrix<_ElemT> tmp(*this); tmp.Invert(&LogDet, DetSign, false); // false== output not needed (saves some computation). return LogDet; } }// namespace TNet // #define TNet_Matrix_tcc #endif