#include #include #include #include #include #include "Random.hh" #include "Matrix.hh" #include "Exception.hh" #include "String.hh" #if NEXTPOW2 #include #endif // NEXTPOW2 // TODO: // - File I/O // - Visualization // - Matrix manipulation: // - horzcat vertcat blkdiag // - Data functions: // - mean median std var // - randperm rsort csort // - diff gradient del2 // - corrcoef cov // - cumsum cumprod // - hist histc // - Matrix functions (using LAPACK/BLAS): // - norm rank det trace null orth rref subspace // - mldivide mrdivide inverse rcond cond chol lu qr lsqnonneg pinv // - eig svd gsvd eigs svds poly // - expm logm sqrtm #ifndef NOBLAS extern "C" void dgemm_( // C := alpha*op(A)*op(B) + beta*C char* transa, char* transb, int* m, int* n, int* k, double* alpha, double* a, int* lda, double* b, int* ldb, double* beta, double* c, int* ldc); #endif // nan, inf static const u_int64_t _qnan = 0x7ff7ffffffffffffll; static const u_int64_t _snan = 0x7fffffffffffffffll; static const u_int64_t _inf = 0x7ff0000000000000ll; static const double qnan = *(double*)&_qnan; static const double snan = *(double*)&_snan; static const double inf = *(double*)&_inf; // trunc //static inline double trunc (double x) { // return (x > 0) ? floor(x) : ceil(x); //} // trigonometric functions static inline double sec (double x) { return cos(1.0/x); } static inline double sech (double x) { return cosh(1.0/x); } static inline double asec (double x) { return acos(1.0/x); } static inline double asech (double x) { return acosh(1.0/x); } static inline double csc (double x) { return sin(1.0/x); } static inline double csch (double x) { return sinh(1.0/x); } static inline double acsc (double x) { return asin(1.0/x); } static inline double acsch (double x) { return asinh(1.0/x); } static inline double cot (double x) { return tan(1.0/x); } static inline double coth (double x) { return tanh(1.0/x); } static inline double acot (double x) { return atan(1.0/x); } static inline double acoth (double x) { return atanh(1.0/x); } // exponential functions //static inline double log2 (double x) { return log(x) / log(2); } static inline double pow2 (double x) { return pow(2,x); } // matlab-style remainder / modulus functions static inline double rem (double x, double y) { return (y==0) ? qnan : (x - y*trunc(x/y)); } static inline double mod (double x, double y) { return (y==0) ? x : (x - y*floor(x/y)); } #if NEXTPOW2 // return smallest integer i s.t. 2^i > abs(x) static inline double nextpow2 (double x) { if (!finite(x)) { return x; } ieee754_double val; val.d = x; int e = (int)val.ieee.exponent - IEEE754_DOUBLE_BIAS; if (val.ieee.mantissa0 != 0) { return e+1; } if (val.ieee.mantissa1 != 0) { return e+2; } return e; } #endif // NEXTPOW2 Matrix zeros (int rows, int cols) { return Matrix(rows,cols,Matrix::zeros); } Matrix ones (int rows, int cols) { return Matrix(rows,cols,Matrix::ones); } Matrix eye (int rows, int cols) { return Matrix(rows,cols,Matrix::eye); } Matrix rand (int rows, int cols) { return Matrix(rows,cols,Matrix::rand); } Matrix randn (int rows, int cols) { return Matrix(rows,cols,Matrix::randn); } Matrix zeros (int sz) { return Matrix(sz,sz,Matrix::zeros); } Matrix ones (int sz) { return Matrix(sz,sz,Matrix::ones); } Matrix eye (int sz) { return Matrix(sz,sz,Matrix::eye); } Matrix rand (int sz) { return Matrix(sz,sz,Matrix::rand); } Matrix randn (int sz) { return Matrix(sz,sz,Matrix::randn); } Matrix::Matrix () { _alloc(0,0,undef); } Matrix::Matrix (int sz, FillType type) { sz = std::max(0,sz); _alloc(sz,sz,type); } Matrix::Matrix (int rows, int cols, FillType type) { rows = std::max(0,rows); cols = std::max(0,cols); _alloc(rows,cols,type); } Matrix::Matrix (const Matrix& that) { _alloc(that._rows,that._cols,undef); *this = that; } Matrix::Matrix (int rows, int cols, double* data) { _rows = std::max(0,rows); _cols = std::max(0,cols); _data = data; _wrapped = true; } Matrix::~Matrix () { _delete(); } void Matrix::reshape (int rows, int cols) { rows = std::max(0,rows); cols = std::max(0,cols); if (rows*cols != _n) { throw Exception (String ( "Reshape cannot change number of elements: (%d,%d) vs. (%d,%d).", rows, cols, _rows, _cols)); } _rows = rows; _cols = cols; } Matrix reshape (const Matrix& a, int rows, int cols) { Matrix z(a); z.reshape(rows,cols); return z; } void Matrix::resize (int rows, int cols, FillType type) { rows = std::max(0,rows); cols = std::max(0,cols); _delete(); _alloc(rows,cols,type); } // array properties bool Matrix::isvec () const { return (_rows == 1 || _cols == 1); } bool Matrix::isrowvec () const { return (_rows == 1); } bool Matrix::iscolvec () const { return (_cols == 1); } bool Matrix::isempty () const { return (_n == 0); } bool Matrix::isscalar () const { return (_n == 1); } int Matrix::nrows () const { return _rows; } int Matrix::ncols () const { return _cols; } int Matrix::numel () const { return _n; } int Matrix::length () const { return (_n==0) ? 0 : std::max(_rows,_cols); } Matrix Matrix::size () const { Matrix a (1,2); a(0) = _rows; a(1) = _cols; return a; } bool Matrix::samesize (const Matrix& a) const { return issize(a._rows,a._cols); } bool samesize (const Matrix& a, const Matrix& b) { return a.samesize(b); } bool isvec (const Matrix& a) { return a.isvec(); } bool isrowvec (const Matrix& a) { return a.isrowvec(); } bool iscolvec (const Matrix& a) { return a.iscolvec(); } bool isempty (const Matrix& a) { return a.isempty(); } bool isscalar (const Matrix& a) { return a.isscalar(); } bool issize (const Matrix& a, int rows, int cols) { return a.issize(rows,cols); } int nrows (const Matrix& a) { return a.nrows(); } int ncols (const Matrix& a) { return a.ncols(); } int numel (const Matrix& a) { return a.numel(); } int length (const Matrix& a) { return a.length(); } Matrix size (const Matrix& a) { return a.size(); } bool Matrix::issize (int rows, int cols) const { return (_rows == rows && _cols == cols); } void ind2sub ( const Matrix& siz, const Matrix& ind, Matrix& i, Matrix& j) { if (siz.numel() != 2) { throw Exception ("ind2sub: siz must have 2 elements."); } const int rows = (int) siz(0); i = zeros(ind._rows,ind._cols); j = zeros(ind._rows,ind._cols); for (int index = 0; index < ind._n; index++) { const int indi = (int) ind._data[index]; i._data[index] = indi % rows; j._data[index] = indi / rows; } } void sub2ind ( const Matrix& siz, const Matrix& i, const Matrix& j, Matrix& ind) { if (siz.numel() != 2) { throw Exception ("sub2ind: siz must have 2 elements."); } if (!samesize(i,j)) { throw Exception ("sub2ind: i and j just be the same size."); } const int rows = (int) siz(0); ind = zeros(i._rows,i._cols); for (int index = 0; index < ind._n; index++) { const int ii = (int) i._data[index]; const int ji = (int) i._data[index]; ind._data[index] = ji*rows + ii; } } void Matrix::ind2sub (const Matrix& ind, Matrix& i, Matrix& j) { return ::ind2sub(::size(*this),ind,i,j); } void Matrix::sub2ind (const Matrix& i, const Matrix& j, Matrix& ind) { return ::sub2ind(::size(*this),i,j,ind); } bool Matrix::iswrapped () const { return _wrapped; } bool iswrapped (const Matrix &a) { return a.iswrapped(); } double* Matrix::data () { return _data; } double& Matrix::operator() (int index) { if ((unsigned)index >= (unsigned)_n) { throw Exception (String ( "Index (%d) exceeds matrix length (%d).", index, _n)); } return _data[index]; } const double& Matrix::operator() (int index) const { if ((unsigned)index >= (unsigned)_n) { throw Exception (String ( "Index (%d) exceeds matrix dimension (%d).", index, _n)); } return _data[index]; } double& Matrix::operator() (int row, int col) { if ((unsigned)row >= (unsigned)_rows || (unsigned)col >= (unsigned)_cols) { throw Exception (String ( "Index (%d,%d) exceeds matrix dimensions (%d,%d).", row, col, _rows, _cols)); } int index = col*_rows + row; return _data[index]; } const double& Matrix::operator() (int row, int col) const { if ((unsigned)row >= (unsigned)_rows || (unsigned)col >= (unsigned)_cols) { throw Exception (String ( "Index (%d,%d) exceeds matrix dimensions (%d,%d).", row, col, _rows, _cols)); } int index = col*_rows + row; return _data[index]; } void Matrix::operator= (const double& val) { if (val == 0) { memset(_data, 0, _n*sizeof(*_data)); } else { for (int i = 0; i < _n; i++) { _data[i] = val; } } } void Matrix::operator= (const Matrix& that) { if (_n == that._n) { _rows = that._rows; _cols = that._cols; memcpy (_data, that._data, _n*sizeof(*_data)); } else { _delete(); _alloc(that._rows,that._cols,undef); *this = that; } } bool Matrix::isequal (const Matrix& a) const { if (_rows != a._rows) { return false; } if (_cols != a._cols) { return false; } for (int i = 0; i < _n; i++) { if (_data[i] != a._data[i]) { return false; } } return true; } bool isequal (const Matrix& a, const Matrix& b) { return a.isequal(b); } void Matrix::linspace (double a, double b) { if (_n == 0) { return; } if (_n == 1) { _data[0] = b; } else { double skip = (b-a) / (_n-1); for (int i = 0; i < _n; i++) { _data[i] = a + i*skip; } } } void Matrix::logspace (double a, double b) { if (_n == 0) { return; } if (b == M_PI) { b = ::log10(b); } if (_n == 1) { _data[0] = ::pow(10,b); } else { double skip = (b-a) / (_n-1); for (int i = 0; i < _n; i++) { _data[i] = ::pow (10, a + i*skip); } } } Matrix linspace (double a, double b, int n) { n = std::max(1,n); Matrix z(n,1,Matrix::undef); z.linspace(a,b); return z; } Matrix logspace (double a, double b, int n) { n = std::max(1,n); Matrix z(n,1,Matrix::undef); z.logspace(a,b); return z; } void Matrix::transpose () { if (isvec()) { reshape(_cols,_rows); return; } if (_rows == _cols) { for (int row = 0; row < _rows; row++) { for (int col = row+1; col < _cols; col++) { int index1 = col*_rows + row; int index2 = row*_rows + col; std::swap(_data[index1],_data[index2]); } } } else { Matrix m (_cols, _rows, Matrix::undef); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m(col,row) = _data[index]; } } reshape(_cols,_rows); *this = m; } } // flip columns void Matrix::fliplr () { for (int col=0; col < _cols/2; col++) { const int col2 = _cols - 1 - col; for (int row=0; row < _rows; row++) { std::swap((*this)(row,col),(*this)(row,col2)); } } } // flip rows void Matrix::flipud () { for (int row=0; row < _rows/2; row++) { const int row2 = _rows - 1 - row; for (int col=0; col < _cols; col++) { std::swap((*this)(row,col),(*this)(row2,col)); } } } // rotate matrix void Matrix::rot90 (int k) { int n = k % 4; if (n < 0) { n += 4; }; switch (n) { case 0: break; case 1: transpose(); flipud(); break; case 2: flipud(); fliplr(); break; case 3: flipud(); transpose(); break; default: assert(0); } } Matrix transpose (const Matrix& a) { Matrix z (a); z.transpose(); return z; } // could be faster Matrix fliplr (const Matrix& a) { Matrix z (a); z.fliplr(); return z; } // could be faster Matrix flipud (const Matrix& a) { Matrix z (a); z.flipud(); return z; } // could be faster Matrix rot90 (const Matrix& a, int k) { Matrix z (a); z.rot90(k); return z; } Matrix Matrix::repmat (int m, int n) const { m = std::max(0,m); n = std::max(0,n); Matrix a (_rows*m, _cols*n, Matrix::undef); // copy this matrix m times into a double* p = a._data; for (int col = 0; col < _cols; col++) { for (int i = 0; i < m; i++) { const double* q = &(*this)(0,col); memcpy (p, q, _rows*sizeof(*_data)); p += _rows; } } // copy the block we just wrote n-1 times const int count = _cols * _rows * m; for (int j = 1; j < n; j++) { memcpy (p, a._data, count*sizeof(*_data)); p += count; } return a; } Matrix repmat (const Matrix& a, int m, int n) { return a.repmat(m,n); } // find indices of non-zero elements Matrix Matrix::find () const { // count non-zeros int count = 0; for (int i=0; i < _n; i++) { if (_data[i] != 0) { count++; } } // allocate column vector Matrix m (count,1,Matrix::undef); // extract indices for (int i=0, j=0; i < _n; i++) { if (_data[i] != 0) { assert (j < count); m._data[j++] = i; } } return m; } Matrix find (const Matrix& a) { return a.find(); } Matrix Matrix::operator() (const Matrix& indices) const { return gather(indices); } Matrix Matrix::gather (const Matrix& indices) const { Matrix m (indices._rows,indices._cols,Matrix::undef); for (int i = 0; i < indices._n; i++) { const int index = (int) indices._data[i]; if ((unsigned)index >= (unsigned)_n) { throw Exception (String ( "Matrix::gather: index %d exceeds matrix " "dimension (%d).", index, _n)); } m._data[i] = _data[index]; } return m; } void Matrix::scatter (const Matrix& indices, const Matrix& values) { if (indices._n != values._n) { throw Exception (String ( "Matrix::scatter: indices and values not the same " "length (%d and %d).", indices._n, values._n)); } for (int i = 0; i < indices._n; i++) { const int index = (int) indices._data[i]; if ((unsigned)index >= (unsigned)_n) { throw Exception (String ( "Matrix::scatter: index %d exceeds matrix " "dimension (%d).", index, _n)); } _data[index] = values._data[i]; } } void Matrix::scatter (const Matrix& indices, double value) { for (int i = 0; i < indices._n; i++) { const int index = (int) indices._data[i]; if ((unsigned)index >= (unsigned)_n) { throw Exception (String ( "Matrix::scatter: index %d exceeds matrix " "dimension (%d).", index, _n)); } _data[index] = value; } } Matrix scatter (const Matrix& a, const Matrix& indices, const Matrix& values) { Matrix z(a); z.scatter(indices,values); return z; } Matrix scatter (const Matrix& a, const Matrix& indices, double value) { Matrix z(a); z.scatter(indices,value); return z; } Matrix Matrix::operator() (int r1, int r2, int c1, int c2) const { if (r1 < 0 || r1 >= _rows || r2 < 0 || r2 >= _rows || c1 < 0 || c1 >= _cols || c2 < 0 || c2 >= _cols) { throw Exception (String ( "Matrix extract (%d:%d,%d:%d) exceeds matrix dimensions (%d,%d).", r1, r2, c1, c2, _rows, _cols)); } int rows = (r1<=r2) ? r2-r1+1 : 0; int cols = (c1<=c2) ? c2-c1+1 : 0; Matrix m (rows,cols); for (int col = 0; col < cols; col++) { double* to = &m(0,col); const double* from = &(*this)(r1,c1+col); memcpy (to, from, rows*sizeof(*_data)); } return m; } void Matrix::insert (const Matrix& m, int r1, int r2, int c1, int c2) { if (r1 < 0 || r1 >= _rows || r2 < 0 || r2 >= _rows || c1 < 0 || c1 >= _cols || c2 < 0 || c2 >= _cols) { throw Exception (String ( "Matrix insert (%d:%d,%d:%d) exceeds matrix dimensions (%d,%d).", r1, r2, c1, c2, _rows, _cols)); } int rows = (r1<=r2) ? r2-r1+1 : 0; int cols = (c1<=c2) ? c2-c1+1 : 0; for (int col = 0; col < cols; col++) { double* to = &(*this)(r1,c1+col); const double* from = &m(0,col); memcpy (to, from, rows*sizeof(*_data)); } } // not as efficient as possible, but not too bad Matrix insert (const Matrix& a, const Matrix& m, int r1, int r2, int c1, int c2) { Matrix z(a); z.insert(m,r1,r2,c1,c2); return z; } // mask out upper triangle void Matrix::tril (int k) { for (int col=0, index=0; col<_cols; col++) { for (int row=0; row<_rows; row++, index++) { if (col-row > k) { _data[index] = 0; } } } } // mask out lower triangle void Matrix::triu (int k) { for (int col=0, index=0; col<_cols; col++) { for (int row=0; row<_rows; row++, index++) { if (col-row < k) { _data[index] = 0; } } } } Matrix tril (const Matrix& a, int k) { Matrix z(a); z.tril(k); return z; } Matrix triu (const Matrix& a, int k) { Matrix z(a); z.triu(k); return z; } // set diagonal from scalar void Matrix::setdiag (double val, int k) { const int row = (k<0)*::abs(k); const int col = (k>0)*::abs(k); const int len = std::min(_rows-row,_cols-col); for (int i = 0; i < len; i++) { (*this)(row+i,col+i) = val; } } // set diagonal from vector void Matrix::setdiag (const Matrix& d, int k) { const int row = (k<0)*::abs(k); const int col = (k>0)*::abs(k); const int len = std::max(0,std::min(_rows-row,_cols-col)); if (d.numel() != len) { throw Exception (String ( "Matrix::diag(): diagonal %d of matrix is length %d, " "but the diagonal vector is length %d.", k, len, d.numel())); } for (int i = 0; i < len; i++) { (*this)(row+i,col+i) = d(i); } } // get diagonal Matrix Matrix::getdiag (int k) const { const int row = (k<0)*::abs(k); const int col = (k>0)*::abs(k); const int len = std::min(_rows-row,_cols-col); Matrix d (len,1); for (int i = 0; i < len; i++) { d(i) = (*this)(row+i,col+i); } return d; } Matrix diag (const Matrix& a, int k) { if (a.isvec()) { // create diagonal matrix const int n = a._n + ::abs(k); Matrix z(n,n,Matrix::zeros); const int row = (k>0)*::abs(k); const int col = (k<0)*::abs(k); for (int i = 0; i < a._n; i++) { z(row+i,col+i) = a(i); } return z; } else { // extract diagonal return a.getdiag(k); } } // or reduction bool Matrix::any () const { for (int i = 0; i < _n; i++) { if (_data[i] != 0) { return true; } } return false; } // and reduction bool Matrix::all () const { for (int i = 0; i < _n; i++) { if (_data[i] == 0) { return false; } } return true; } // sum reduction double Matrix::sum () const { double x = 0; for (int i = 0; i < _n; i++) { x += _data[i]; } return x; } // row sums Matrix Matrix::rsum () const { Matrix m (_rows,1,zeros); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[row] += _data[index]; } } return m; } // column sums Matrix Matrix::csum () const { Matrix m (1,_cols,zeros); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[col] += _data[index]; } } return m; } // product reduction double Matrix::prod () const { double x = 1; for (int i = 0; i < _n; i++) { x *= _data[i]; } return x; } // row products Matrix Matrix::rprod () const { Matrix m (_rows,1,ones); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[row] *= _data[index]; } } return m; } // column products Matrix Matrix::cprod () const { Matrix m (1,_cols,ones); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[col] *= _data[index]; } } return m; } bool any (const Matrix& a) { return a.any(); } bool all (const Matrix& a) { return a.all(); } double sum (const Matrix& a) { return a.sum(); } Matrix rsum (const Matrix& a) { return a.rsum(); } Matrix csum (const Matrix& a) { return a.csum(); } double prod (const Matrix& a) { return a.prod(); } Matrix rprod (const Matrix& a) { return a.rprod(); } Matrix cprod (const Matrix& a) { return a.cprod(); } double Matrix::min () const { if (_n == 0) { throw Exception ("Matrix::min(): empty matrix"); } double x = _data[0]; for (int i = 1; i < _n; i++) { x = std::min(x,_data[i]); } return x; } double Matrix::min (int& index) const { if (_n == 0) { throw Exception ("Matrix::min(): empty matrix"); } double x = _data[0]; int ind = 0; for (int i = 1; i < _n; i++) { if (_data[i] < x) { x = _data[i]; ind = i; } } index = ind; return x; } Matrix Matrix::rmin () const { if (_n == 0) { throw Exception ("Matrix::rmin(): empty matrix"); } Matrix m (_rows,1,undef); memcpy(m._data,_data,_rows*(sizeof(*_data))); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[row] = std::min(m._data[row],_data[index]); } } return m; } Matrix Matrix::rmin (Matrix& indices) const { if (_n == 0) { throw Exception ("Matrix::rmin(): empty matrix"); } Matrix m (_rows,1,undef); indices = ::zeros(_rows,1); memcpy(m._data,_data,_rows*(sizeof(*_data))); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { if (_data[index] < m._data[row]) { m._data[row] = _data[index]; indices._data[row] = col; } } } return m; } Matrix Matrix::cmin () const { if (_n == 0) { throw Exception ("Matrix::cmin(): empty matrix"); } Matrix m (1,_cols,undef); for (int col=0; col < _cols; col++) { m._data[col] = (*this)(0,col); } for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[col] = std::min(m._data[col],_data[index]); } } return m; } Matrix Matrix::cmin (Matrix& indices) const { if (_n == 0) { throw Exception ("Matrix::cmin(): empty matrix"); } Matrix m (1,_cols,undef); indices = ::zeros(1,_cols); for (int col=0; col < _cols; col++) { m._data[col] = (*this)(0,col); } for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { if (_data[index] < m._data[row]) { m._data[row] = _data[index]; indices._data[row] = col; } } } return m; } double Matrix::max () const { if (_n == 0) { throw Exception ("Matrix::max(): empty matrix"); } double x = _data[0]; for (int i = 1; i < _n; i++) { x = std::max(x,_data[i]); } return x; } double Matrix::max (int& index) const { if (_n == 0) { throw Exception ("Matrix::max(): empty matrix"); } double x = _data[0]; int ind = 0; for (int i = 1; i < _n; i++) { if (_data[i] > x) { x = _data[i]; ind = i; } } index = ind; return x; } Matrix Matrix::rmax () const { if (_n == 0) { throw Exception ("Matrix::rmax(): empty matrix"); } Matrix m (_rows,1,undef); memcpy(m._data,_data,_rows*(sizeof(*_data))); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[row] = std::max(m._data[row],_data[index]); } } return m; } Matrix Matrix::rmax (Matrix& indices) const { if (_n == 0) { throw Exception ("Matrix::rmax(): empty matrix"); } Matrix m (_rows,1,undef); indices = ::zeros(_rows,1); memcpy(m._data,_data,_rows*(sizeof(*_data))); for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { if (_data[index] > m._data[row]) { m._data[row] = _data[index]; indices._data[row] = col; } } } return m; } Matrix Matrix::cmax () const { if (_n == 0) { throw Exception ("Matrix::cmax(): empty matrix"); } Matrix m (1,_cols,undef); for (int col=0; col < _cols; col++) { m._data[col] = (*this)(0,col); } for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { m._data[col] = std::max(m._data[col],_data[index]); } } return m; } Matrix Matrix::cmax (Matrix& indices) const { if (_n == 0) { throw Exception ("Matrix::cmax(): empty matrix"); } Matrix m (1,_cols,undef); indices = ::zeros(1,_cols); for (int col=0; col < _cols; col++) { m._data[col] = (*this)(0,col); } for (int col=0, index=0; col < _cols; col++) { for (int row=0; row < _rows; row++, index++) { if (_data[index] > m._data[row]) { m._data[row] = _data[index]; indices._data[row] = col; } } } return m; } double min (const Matrix& a) { return a.min(); } double min (const Matrix& a, int& index) { return a.min(index); } Matrix rmin (const Matrix& a) { return a.rmin(); } Matrix rmin (const Matrix& a, Matrix& indices) { return a.rmin(indices); } Matrix cmin (const Matrix& a) { return a.cmin(); } Matrix cmin (const Matrix& a, Matrix& indices) { return a.cmin(indices); } double max (const Matrix& a) { return a.max(); } double max (const Matrix& a, int& index) { return a.max(index); } Matrix rmax (const Matrix& a) { return a.rmax(); } Matrix rmax (const Matrix& a, Matrix& indices) { return a.rmax(indices); } Matrix cmax (const Matrix& a) { return a.cmax(); } Matrix cmax (const Matrix& a, Matrix& indices) { return a.cmax(indices); } Matrix min (const Matrix& a, const Matrix& b) { if (a._rows != b._rows || a._cols != b._cols) { throw Exception (String ( "Matrix size mismatch in binary operation 'min': " "(%d,%d) vs. (%d,%d).", a._rows, a._cols, b._rows, b._cols)); } Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = std::min(a._data[i],b._data[i]); } return c; } Matrix min (const Matrix& a, double b) { Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = std::min(a._data[i],b); } return c; } Matrix min (double a, const Matrix& b) { Matrix c (b._rows, b._cols, Matrix::undef); for (int i = 0; i < b._n; i++) { c._data[i] = std::min(a,b._data[i]); } return c; } Matrix max (const Matrix& a, const Matrix& b) { if (a._rows != b._rows || a._cols != b._cols) { throw Exception (String ( "Matrix size mismatch in binary operation 'max': " "(%d,%d) vs. (%d,%d).", a._rows, a._cols, b._rows, b._cols)); } Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = std::max(a._data[i],b._data[i]); } return c; } Matrix max (const Matrix& a, double b) { Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = std::max(a._data[i],b); } return c; } Matrix max (double a, const Matrix& b) { Matrix c (b._rows, b._cols, Matrix::undef); for (int i = 0; i < b._n; i++) { c._data[i] = std::max(a,b._data[i]); } return c; } void Matrix::ceil () { for (int i = 0; i < _n; i++) { _data[i] = ::ceil(_data[i]); } } void Matrix::floor () { for (int i = 0; i < _n; i++) { _data[i] = ::floor(_data[i]); } } void Matrix::round () { for (int i = 0; i < _n; i++) { _data[i] = ::rint(_data[i]); } } void Matrix::fix () { for (int i = 0; i < _n; i++) { _data[i] = ::trunc(_data[i]); } } Matrix ceil (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::ceil(a._data[i]); } return z; } Matrix floor (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::floor(a._data[i]); } return z; } Matrix round (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::rint(a._data[i]); } return z; } Matrix fix (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::trunc(a._data[i]); } return z; } Matrix iznan (const Matrix& a) { Matrix b (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { b._data[i] = isnan(a._data[i]); } return b; } Matrix izinf (const Matrix& a) { Matrix b (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { b._data[i] = isinf(a._data[i]); } return b; } Matrix izfinite (const Matrix& a) { Matrix b (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { b._data[i] = ::finite(a._data[i]); } return b; } void Matrix::iznan () { for (int i = 0; i < _n; i++) { _data[i] = isnan(_data[i]); } } void Matrix::izinf () { for (int i = 0; i < _n; i++) { _data[i] = isinf(_data[i]); } } void Matrix::izfinite () { for (int i = 0; i < _n; i++) { _data[i] = ::finite(_data[i]); } } void Matrix::abs () { for (int i = 0; i < _n; i++) { _data[i] = ::fabs(_data[i]); } } void Matrix::sign () { for (int i = 0; i < _n; i++) { const double x = _data[i]; _data[i] = (x == 0) ? 0 : (x > 0 ? 1 : -1); } } Matrix abs (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::fabs(a._data[i]); } return z; } Matrix sign (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { const double x = a._data[i]; z._data[i] = (x == 0) ? 0 : (x > 0 ? 1 : -1); } return z; } void Matrix::exp () { for (int i = 0; i < _n; i++) { _data[i] = ::exp(_data[i]); } } void Matrix::log () { for (int i = 0; i < _n; i++) { _data[i] = ::log(_data[i]); } } void Matrix::log10 () { for (int i = 0; i < _n; i++) { _data[i] = ::log10(_data[i]); } } void Matrix::log2 () { for (int i = 0; i < _n; i++) { _data[i] = ::log2(_data[i]); } } void Matrix::pow2 () { for (int i = 0; i < _n; i++) { _data[i] = ::pow2(_data[i]); } } void Matrix::sqrt () { for (int i = 0; i < _n; i++) { _data[i] = ::sqrt(_data[i]); } } #if NEXTPOW2 void Matrix::nextpow2 () { for (int i = 0; i < _n; i++) { _data[i] = ::nextpow2(_data[i]); } } #endif // NEXTPOW2 Matrix exp (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::exp(a._data[i]); } return z; } Matrix log (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::log(a._data[i]); } return z; } Matrix log10 (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::log10(a._data[i]); } return z; } Matrix log2 (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::log2(a._data[i]); } return z; } Matrix pow2 (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::pow2(a._data[i]); } return z; } Matrix sqrt (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::sqrt(a._data[i]); } return z; } #if NEXTPOW2 Matrix nextpow2 (const Matrix& a) { Matrix z (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { z._data[i] = ::nextpow2(a._data[i]); } return z; } #endif // NEXTPOW2 void Matrix::sin () { for (int i = 0; i < _n; i++) { _data[i] = ::sin(_data[i]); } } void Matrix::sinh () { for (int i = 0; i < _n; i++) { _data[i] = ::sinh(_data[i]); } } void Matrix::asin () { for (int i = 0; i < _n; i++) { _data[i] = ::asin(_data[i]); } } void Matrix::asinh () { for (int i = 0; i < _n; i++) { _data[i] = ::asinh(_data[i]); } } void Matrix::cos () { for (int i = 0; i < _n; i++) { _data[i] = ::cos(_data[i]); } } void Matrix::cosh () { for (int i = 0; i < _n; i++) { _data[i] = ::cosh(_data[i]); } } void Matrix::acos () { for (int i = 0; i < _n; i++) { _data[i] = ::acos(_data[i]); } } void Matrix::acosh () { for (int i = 0; i < _n; i++) { _data[i] = ::acosh(_data[i]); } } void Matrix::tan () { for (int i = 0; i < _n; i++) { _data[i] = ::tan(_data[i]); } } void Matrix::tanh () { for (int i = 0; i < _n; i++) { _data[i] = ::tanh(_data[i]); } } void Matrix::atan () { for (int i = 0; i < _n; i++) { _data[i] = ::atan(_data[i]); } } void Matrix::atanh () { for (int i = 0; i < _n; i++) { _data[i] = ::atanh(_data[i]); } } void Matrix::sec () { for (int i = 0; i < _n; i++) { _data[i] = ::sec(_data[i]); } } void Matrix::sech () { for (int i = 0; i < _n; i++) { _data[i] = ::sech(_data[i]); } } void Matrix::asec () { for (int i = 0; i < _n; i++) { _data[i] = ::asec(_data[i]); } } void Matrix::asech () { for (int i = 0; i < _n; i++) { _data[i] = ::asech(_data[i]); } } void Matrix::csc () { for (int i = 0; i < _n; i++) { _data[i] = ::csc(_data[i]); } } void Matrix::csch () { for (int i = 0; i < _n; i++) { _data[i] = ::csch(_data[i]); } } void Matrix::acsc () { for (int i = 0; i < _n; i++) { _data[i] = ::acsc(_data[i]); } } void Matrix::acsch () { for (int i = 0; i < _n; i++) { _data[i] = ::acsch(_data[i]); } } void Matrix::cot () { for (int i = 0; i < _n; i++) { _data[i] = ::cot(_data[i]); } } void Matrix::coth () { for (int i = 0; i < _n; i++) { _data[i] = ::coth(_data[i]); } } void Matrix::acot () { for (int i = 0; i < _n; i++) { _data[i] = ::acot(_data[i]); } } void Matrix::acoth () { for (int i = 0; i < _n; i++) { _data[i] = ::acoth(_data[i]); } } Matrix sin (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::sin(a._data[i]); } return z; } Matrix sinh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::sinh(a._data[i]); } return z; } Matrix asin (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::asin(a._data[i]); } return z; } Matrix asinh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::asinh(a._data[i]); } return z; } Matrix cos (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::cos(a._data[i]); } return z; } Matrix cosh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::cosh(a._data[i]); } return z; } Matrix acos (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acos(a._data[i]); } return z; } Matrix acosh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acosh(a._data[i]); } return z; } Matrix tan (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::tan(a._data[i]); } return z; } Matrix tanh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::tanh(a._data[i]); } return z; } Matrix atan (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::atan(a._data[i]); } return z; } Matrix atanh (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::atanh(a._data[i]); } return z; } Matrix sec (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::sec(a._data[i]); } return z; } Matrix sech (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::sech(a._data[i]); } return z; } Matrix asec (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::asec(a._data[i]); } return z; } Matrix asech (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::asech(a._data[i]); } return z; } Matrix csc (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::csc(a._data[i]); } return z; } Matrix csch (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::csch(a._data[i]); } return z; } Matrix acsc (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acsc(a._data[i]); } return z; } Matrix acsch (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acsch(a._data[i]); } return z; } Matrix cot (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::cot(a._data[i]); } return z; } Matrix coth (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::coth(a._data[i]); } return z; } Matrix acot (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acot(a._data[i]); } return z; } Matrix acoth (const Matrix& a) { Matrix z (a._rows, a._cols); for (int i = 0; i < a._n; i++) { z._data[i] = ::acoth(a._data[i]); } return z; } // computed assignment #define DEFOP(OP) \ Matrix& Matrix::operator OP (const double& val) { \ for (int i = 0; i < _n; i++) { \ _data[i] OP val; \ } \ return *this; \ } \ Matrix& Matrix::operator OP (const Matrix& that) { \ if (_rows != _rows || _cols != that._cols) { \ throw Exception (String ( \ "Matrix size mismatch in operation '%s': " \ "(%d,%d) vs. (%d,%d).", \ __STRING(OP), _rows, _cols, that._rows, that._cols)); \ } \ for (int i = 0; i < _n; i++) { \ _data[i] OP that._data[i]; \ } \ return *this; \ } DEFOP(+=); DEFOP(-=); DEFOP(*=); DEFOP(/=); #undef DEFOP Matrix& Matrix::operator^= (const double& val) { for (int i = 0; i < _n; i++) { _data[i] = ::pow(_data[i],val); } return *this; } Matrix& Matrix::operator^= (const Matrix& that) { if (_rows != _rows || _cols != that._cols) { throw Exception (String ( "Matrix size mismatch in operation '^=': " "(%d,%d) vs. (%d,%d).", _rows, _cols, that._rows, that._cols)); } for (int i = 0; i < _n; i++) { _data[i] = ::pow(_data[i],that._data[i]); } return *this; } // binary operators #define DEFOP(OP) \ Matrix operator OP (const Matrix& a, const Matrix& b) { \ if (a._rows != b._rows || a._cols != b._cols) { \ throw Exception (String ( \ "Matrix size mismatch in binary operation '%s': " \ "(%d,%d) vs. (%d,%d).", \ __STRING(OP), a._rows, a._cols, b._rows, b._cols)); \ } \ Matrix c (a._rows, a._cols, Matrix::undef); \ for (int i = 0; i < a._n; i++) { \ c._data[i] = a._data[i] OP b._data[i]; \ } \ return c; \ } \ Matrix operator OP (const Matrix& a, double b) { \ Matrix c (a._rows, a._cols, Matrix::undef); \ for (int i = 0; i < a._n; i++) { \ c._data[i] = a._data[i] OP b; \ } \ return c; \ } \ Matrix operator OP (double a, const Matrix& b) { \ Matrix c (b._rows, b._cols, Matrix::undef); \ for (int i = 0; i < b._n; i++) { \ c._data[i] = a OP b._data[i]; \ } \ return c; \ } DEFOP(+); DEFOP(-); DEFOP(*); DEFOP(/); DEFOP(<); DEFOP(>); DEFOP(==); DEFOP(!=); DEFOP(<=); DEFOP(>=); DEFOP(&&); DEFOP(||); #undef DEFOP Matrix operator^ (const Matrix& a, const Matrix& b) { if (a._rows != b._rows || a._cols != b._cols) { throw Exception (String ( "Matrix size mismatch in binary operation '^': " "(%d,%d) vs. (%d,%d).", a._rows, a._cols, b._rows, b._cols)); } Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = ::pow(a._data[i],b._data[i]); } return c; } Matrix operator^ (const Matrix& a, double b) { Matrix c (a._rows, a._cols, Matrix::undef); for (int i = 0; i < a._n; i++) { c._data[i] = ::pow(a._data[i],b); } return c; } Matrix operator^ (double a, const Matrix& b) { Matrix c (b._rows, b._cols, Matrix::undef); for (int i = 0; i < b._n; i++) { c._data[i] = ::pow(a,b._data[i]); } return c; } // unary operators #define DEFOP(OP) \ Matrix operator OP (const Matrix& a) { \ Matrix c (a._rows, a._cols, Matrix::undef); \ for (int i = 0; i < a._n; i++) { \ c._data[i] = OP a._data[i]; \ } \ return c; \ } DEFOP(!); #undef DEFOP // misc binary functions #define DEFOP(OP,FUNC) \ Matrix OP (const Matrix& a, const Matrix& b) { \ if (a._rows != b._rows || a._cols != b._cols) { \ throw Exception (String ( \ "Matrix size mismatch in %s: (%d,%d) vs. (%d,%d).", \ __STRING(OP), a._rows, a._cols, b._rows, b._cols)); \ } \ Matrix c (a._rows, a._cols, Matrix::undef); \ for (int i = 0; i < a._n; i++) { \ c._data[i] = FUNC (a._data[i], b._data[i]); \ } \ return c; \ } \ Matrix OP (const Matrix& a, double b) { \ Matrix c (a._rows, a._cols, Matrix::undef); \ for (int i = 0; i < a._n; i++) { \ c._data[i] = FUNC (a._data[i], b); \ } \ return c; \ } \ Matrix OP (double a, const Matrix& b) { \ Matrix c (b._rows, b._cols, Matrix::undef); \ for (int i = 0; i < b._n; i++) { \ c._data[i] = FUNC (a, b._data[i]); \ } \ return c; \ } DEFOP(rem,::rem); DEFOP(mod,::mod); DEFOP(atan2,::atan2); #undef DEFOP Matrix mtimes (const Matrix& a, const Matrix& b) { if (a.isscalar()) { return a(0)*b; } if (b.isscalar()) { return a*b(0); } if (a._cols != b._rows) { throw Exception (String ( "Matrix::mtimes: inner dimensions (%d,%d)x(%d,%d) " "don't match.", a._rows, a._cols, b._rows, b._cols)); } Matrix c (a._rows, b._cols, Matrix::zeros); #ifndef NOBLAS char transa='n', transb='n'; int m=a._rows, n=b._cols, k=b._rows; int lda=m, ldb=k, ldc=m; double alpha=1, beta=0; dgemm_ (&transa, &transb, &m, &n, &k, &alpha, a._data, &lda, b._data, &ldb, &beta, c._data, &ldc); #else // NOBLAS for (int i = 0; i < c._rows; i++) { for (int j = 0; j < c._cols; j++) { for (int k = 0; k < a._cols; k++) { c(i,j) += a(i,k) * b(k,j); } } } #endif // NOBLAS return c; } void Matrix::_alloc (int rows, int cols, FillType type) { assert (rows >= 0); assert (cols >= 0); _rows = rows; _cols = cols; _n = rows*cols; _wrapped = false; switch (type) { case undef: _data = (double*) malloc (_n * sizeof(*_data)); break; case zeros: _data = (double*) calloc (_n, sizeof(*_data)); break; case ones: _data = (double*) malloc (_n * sizeof(*_data)); *this = 1; break; case eye: { _data = (double*) calloc (_n, sizeof(*_data)); const int mindim = std::min(_rows,_cols); for (int i = 0; i < mindim; i++) { int index = i*_rows + i; _data[index] = 1; } break; } case rand: _data = (double*) malloc (_n * sizeof(*_data)); for (int i = 0; i < _n; i++) { _data[i] = Random::rand.fp(); } break; case randn: _data = (double*) malloc (_n * sizeof(*_data)); for (int i = 0; i < _n; i++) { const double x = Random::rand.fp(); _data[i] = ::sqrt(-::log(x)); if (Random::rand.fp() > 0.5) { _data[i] = -_data[i]; } } break; default: assert(0); } } void Matrix::_delete () { assert (_data != NULL); if (!_wrapped) { free(_data); } _zero(); } void Matrix::_zero () { _rows = _cols = _n = 0; _data = NULL; _wrapped = false; }