// Authors: Unknown. Please, if you are the author of this file, or if you // know who are the authors of this file, let us know, so we can give the // adequate credits and/or get the adequate authorizations. #ifdef MATRIX_H // Do nothing if not included from matrix.h #define INDEX(i,j) ((i) * m_cols + (j)) namespace libNumerics { /// Constructor for \a m*\a n matrix. /// \param m number of rows. /// \param n number of columns. template matrix::matrix(int m, int n) { alloc(m, n); } /// Copy constructor. template matrix::matrix(const matrix& m) { alloc(m.m_rows, m.m_cols); for(int i = nElements()-1; i >= 0; i--) p[i] = m.p[i]; } /// Destructor. template matrix::~matrix() { free(); } /// Assignment operator. template matrix& matrix::operator=(const matrix& m) { if(&m == this) return *this; if(m.nElements() != nElements()){ free(); alloc(m.m_rows, m.m_cols); } else { m_rows = m.m_rows; m_cols = m.m_cols; } for(int i = nElements()-1; i >= 0; i--) p[i] = m.p[i]; return *this; } /// Access the coefficient on the \a i-th row, \a j-th column. template inline T matrix::operator() (int i, int j) const { assert(i >= 0 && i < m_rows && j >= 0 && j < m_cols); return p[INDEX(i,j)]; } /// Access the coefficient on the \a i-th row, \a j-th column. template inline T& matrix::operator() (int i, int j) { assert(i >= 0 && i < m_rows && j >= 0 && j < m_cols); return p[INDEX(i,j)]; } template inline T matrix::operator() (int i) const { assert(i >= 0 && i < nElements()); return p[i]; } template inline T& matrix::operator() (int i) { assert(i >= 0 && i < nElements()); return p[i]; } /// Set matrix at constant value. /// /// Assign all coefficients to the value \a a. template inline void matrix::operator=(T a) { for(int i = nElements()-1; i >= 0; i--) p[i] = a; } /// Multiply a matrix by scalar. /// \param a a scalar. template matrix matrix::operator*(T a) const { matrix prod(m_rows, m_cols); for(int i = nElements()-1; i >= 0; i--) prod.p[i] = a * p[i]; return prod; } /// Multiply a matrix by scalar. /// \param a a scalar. template void matrix::operator*=(T a) { for(int i = nElements()-1; i >= 0; i--) p[i] *= a; } /// Divide a matrix by scalar. /// \param a a scalar. template matrix matrix::operator/(T a) const { return (*this) * ((T)1/a); } /// Divide a matrix by scalar. /// \param a a scalar. template void matrix::operator/=(T a) { *this *= (T)1 / a; } /// Matrix sum. template matrix matrix::operator+(const matrix& m) const { assert(m.m_rows == m_rows && m.m_cols == m_cols); matrix sum(m_rows,m_cols); for(int i = nElements()-1; i >= 0; i--) sum.p[i] = p[i] + m.p[i]; return sum; } /// Matrix sum. template void matrix::operator+=(const matrix& m) { assert(m.m_rows == m_rows && m.m_cols == m_cols); for(int i = nElements()-1; i >= 0; i--) p[i] += m.p[i]; } /// Matrix subtraction. template matrix matrix::operator-(const matrix& m) const { assert(m.m_rows == m_rows && m.m_cols == m_cols); matrix sub(m_rows,m_cols); for(int i = nElements()-1; i >= 0; i--) sub.p[i] = p[i] - m.p[i]; return sub; } /// Matrix subtraction. template void matrix::operator-=(const matrix& m) { assert(m.m_rows == m_rows && m.m_cols == m_cols); for(int i = nElements()-1; i >= 0; i--) p[i] -= m.p[i]; } template matrix matrix::operator-() const { matrix opp(m_rows, m_cols); for(int i = nElements()-1; i >= 0; i--) opp.p[i] = -p[i]; return opp; } /// Matrix multiplication. template matrix matrix::operator*(const matrix& m) const { assert(m_cols == m.m_rows); matrix prod(m_rows, m.m_cols); T* out = prod.p; for(int i = 0; i < prod.m_rows; i++) { const T* left = p + i*m_cols; for(int j = 0; j < prod.m_cols; j++, out++) { const T* right = m.p + j; *out = 0; for(int k = 0; k < m_cols; k++) { *out += left[k] * *right; right += m.m_cols; } } } return prod; } /// Matrix-vector multiplication. template vector matrix::operator*(const vector& m) const { assert(m_cols == m.m_rows); vector prod(m_rows); T* out = prod.p; for(int i = 0; i < prod.m_rows; i++, out++) { const T* left = p + i*m_cols; const T* right = m.p; *out = 0; for(int k = 0; k < m_cols; k++) *out += left[k] * right[k]; } return prod; } /// Tranposed of matrix. template matrix matrix::t() const { matrix t(ncol(), nrow()); T* out = t.p; for(int i = 0; i < t.nrow(); i++) { const T* in = p + i; for(int j = 0; j < t.ncol(); j++) { *out++ = *in; in += ncol(); } } return t; } /// Symmetrize upper part of matrix. template void matrix::symUpper() { assert(m_rows == m_cols); for(int i = 1; i < m_rows; i++) { const T* in = p + i; T* out = p + m_cols*i; for(int j = 0; j < i; j++) { *out++ = *in; in += m_cols; } } } /// Symmetrize lower part of matrix. template void matrix::symLower() { assert(m_rows == m_cols); for(int i = 1; i < m_rows; i++) { const T* in = p + m_cols*i; T* out = p + i; for(int j = 0; j < i; j++) { *out = *in++; out += m_cols; } } } template vector matrix::diag() const { assert(m_rows == m_cols); vector t(m_rows); for(int i = 0; i < m_rows; i++) t.p[i] = p[i*(m_cols+1)]; return t; } /// Matrix made of zeros. template matrix matrix::zeros(int m, int n) { matrix M(m,n); for(int i = M.nElements()-1; i >= 0; i--) M.p[i] = (T)0; return M; } /// Matrix made of ones. template matrix matrix::ones(int m, int n) { matrix M(m,n); for(int i = M.nElements()-1; i >= 0; i--) M.p[i] = (T)1; return M; } /// Identity matrix. template matrix matrix::eye(int n) { matrix M(n,n); for(int i = M.nElements()-1; i >= 0; i--) M.p[i] = (T)0; for(int i = n-1; i >= 0; i--) M.p[i*(n+1)] = (T)1; return M; } /// Extract the submatrix [i0,i1]x[j0,j1]. /// \param i0 first row /// \param i1 last row /// \param j0 first column /// \param j1 last column template matrix matrix::copy(int i0, int i1, int j0, int j1) const { assert(0 <= i0 && i0 <= i1 && i1 <= m_rows && 0 <= j0 && j0 <= j1 && j1 <= m_cols); matrix sub(i1-i0+1,j1-j0+1); T* out = sub.p; for(int i = i0; i <= i1; i++) { const T* in = p + INDEX(i, j0); for(int j = j0; j <= j1; j++) *out++ = *in++; } return sub; } /// Extract the columns of index in [j0,j1]. /// \param j0 first column /// \param j1 last column template matrix matrix::copyCols(int j0, int j1) const { return copy(0, lastRow(), j0, j1); } /// Extract the rows of index in [i0,i1]. /// \param i0 first row /// \param i1 last row template matrix matrix::copyRows(int i0, int i1) const { return copy(i0, i1, 0, lastCol()); } /// Paste a matrix in another one, at position (\a i0,\a j0) /// \param i0 first row where to paste in /// \param j0 first column where to paste in /// \param matrix to paste template void matrix::paste(int i0, int j0, const matrix& m) { assert(i0 >= 0 && i0+m.m_rows <= m_rows && j0 >= 0 && j0+m.m_cols <= m_cols); const T* in = m.p; for(int i = 0; i < m.m_rows; i++) { T* out = p + INDEX(i0+i, j0); for(int j = 0; j < m.m_cols; j++) *out++ = *in++; } } /// Concatenate matrices. template matrix cat(const matrix& m1, const matrix& m2) { assert(m1.m_rows == m2.m_rows); matrix m(m1.m_rows, m1.m_cols+m2.m_cols); m.paste(0, 0, m1); m.paste(0, m1.m_cols, m2); return m; } /// Copy column number \a j. template vector matrix::col(int j) const { assert(j >= 0 && j < m_cols); vector c(m_rows); const T* in = p + j; for(int i = 0; i < m_rows; i++) { c(i) = *in; in += m_cols; } return c; } /// Copy row number \a i. template inline matrix matrix::row(int i) const { return copy(i, i, 0, lastCol()); } template void swap(matrix& A, matrix& B) { int i=A.m_rows; A.m_rows = B.m_rows; B.m_rows = i; i = A.m_cols; A.m_cols = B.m_cols; B.m_cols = i; T* p = A.p; A.p = B.p; B.p = p; } template void matrix::swapRows(int i0, int i1) { assert(0 <= i0 && i0 < m_rows && 0 <= i1 && i1 < m_rows); T* row0 = p + i0*m_cols; T* row1 = p + i1*m_cols; for(int j = m_cols-1; j >= 0; j--) { T tmp = *row0; *row0++ = *row1; *row1++ = tmp; } } template void matrix::swapCols(int j0, int j1) { assert(0 <= j0 && j0 < m_cols && 0 <= j1 && j1 < m_cols); T* col0 = p + j0; T* col1 = p + j1; for(int i = m_rows-1; i >= 0; i--) { T tmp = *col0; *col0 = *col1; *col1 = tmp; col0 += m_cols; col1 += m_cols; } } /// Copy the array values in a matrix, row by row. /// \param m number of rows /// \param n number of columns /// \param v an array of scalar of size m*n template template void matrix::read(const U* v) { for(int i = nElements()-1; i >= 0; i--) p[i] = (T)v[i]; } /// Read the coefficients from \a m. template inline void matrix::read(const matrix& m) { assert(m.nElements() == nElements()); read(m.p); } /// Copy the matrix coefficients in an array. /// /// The matrix is scanned row by row. template void matrix::write(T* vect) const { for(int i = nElements()-1; i >= 0; i--) vect[i] = p[i]; } template void matrix::alloc(int m, int n) { assert(m > 0 && n > 0); m_rows = m; m_cols = n; p = new T[m*n]; } template inline void matrix::free() { delete [] p; p = NULL; } template inline int matrix::nElements() const { return m_rows*m_cols; } /// Submatrix without row \a i0 and col \a j0. template matrix& matrix::sub(matrix& s, int i0, int j0) const { const T* in = p; T* out = s.p; for(int i = 0; i < i0; i++) { for(int j = 0; j < j0; j++) *out++ = *in++; ++in; // Skip col j0 for(int j = j0+1; j < m_cols; j++) *out++ = *in++; } in += m_cols; // Skip row i0 for(int i = i0+1; i < m_rows; i++) { for(int j = 0; j < j0; j++) *out++ = *in++; ++in; // Skip col j0 for(int j = j0+1; j < m_cols; j++) *out++ = *in++; } return s; } /// Trace. template T matrix::tr() const { assert(m_rows == m_cols); T res = (T)0; for(int i = 0; i < m_rows; i++) res += p[i*(m_cols+1)]; return res; } /// Determinant. Slow, use only for small matrices. template T matrix::det() const { assert(m_rows == m_cols); if(m_rows == 1) return p[0]; if(m_rows == 2) return (p[0]*p[3]-p[1]*p[2]); T res = (T)0; T sign = (T)1; matrix s(m_rows-1, m_cols-1); for(int j = 0; j < m_cols; j++) { res += sign*p[j]*sub(s,0,j).det(); sign = -sign; } return res; } /// Inverse. Slow, use only for small matrices. template matrix matrix::inv() const { assert(m_rows == m_cols); matrix res(m_rows, m_cols); if(m_rows == 1) res.p[0] = (T)1/p[0]; else { T d = (T)1 / det(); T signi = (T)1; T* out = res.p; matrix s(m_rows-1, m_cols-1); for(int i = 0; i < m_rows; i++) { T signj = signi; for(int j = 0; j < m_cols; j++) { *out++ = signj*d*sub(s,j,i).det(); signj = -signj; } signi = -signi; } } return res; } } // namespace libNumerics #undef INDEX #endif // MATRIX_H