A lite library for operations in linear algebra
MATRIX_LIB.cpp
- Committer:
- benson516
- Date:
- 2017-02-10
- Revision:
- 0:33b75d52d2a7
File content as of revision 0:33b75d52d2a7:
#include "MATRIX_LIB.h" // No pre-assignments, empty matrix Mat::Mat(void): _nRow(0), _nCol(0), data(0, vector<float>()) { } // Pre-assign sizes Mat::Mat(size_t nRow_in, size_t nCol_in): _nRow(nRow_in), _nCol(nCol_in), data(nRow_in, vector<float>(nCol_in)) { } // Pre-assign sizes and elements Mat::Mat(size_t nRow_in, size_t nCol_in, float element_in): _nRow(nRow_in), _nCol(nCol_in), data(nRow_in, vector<float>(nCol_in, element_in)) { } // Public methods //----------------------------------// // Size --- // "Get" the size of the matrix size_t Mat::nRow() { return this->_nRow; } size_t Mat::nCol() { return this->_nCol; } size_t Mat::nElement() { // Number of elements return (_nRow*_nCol); } // const functions size_t Mat::nRow() const { return this->_nRow; } size_t Mat::nCol() const { return this->_nCol; } size_t Mat::nElement() const { // Number of elements return (_nRow*_nCol); } // "Set" and "get" the new size of the matrix size_t Mat::nRow(size_t nRow_in){ _nRow = nRow_in; // Resize the matrix data.resize(_nRow, vector<float>(_nCol)); return _nRow; } size_t Mat::nCol(size_t nCol_in){ _nCol = nCol_in; // Resize the matrix for (size_t i = 0; i < _nRow; ++i){ data[i].resize(_nCol); } return _nCol; } // "Set" and "get" the new size of the matrix with assignment to new elements size_t Mat::nRow(size_t nRow_in, float element_in){ _nRow = nRow_in; // Resize the matrix data.resize(_nRow, vector<float>(_nCol, element_in)); return _nRow; } size_t Mat::nCol(size_t nCol_in, float element_in){ _nCol = nCol_in; // Resize the matrix for (size_t i = 0; i < _nRow; ++i){ data[i].resize(_nCol, element_in); } return _nCol; } // Resize on both row and column void Mat::resize(size_t nRow_in, size_t nCol_in){ // Check the size if (_nRow == nRow_in && _nCol == nCol_in){ return; // Nothing to do } // Change the nCol first to resize the old row vector _nCol = nCol_in; // Resize the matrix for (size_t i = 0; i < _nRow; ++i){ data[i].resize(_nCol); } // Then extend the row _nRow = nRow_in; data.resize(_nRow, vector<float>(_nCol)); } void Mat::resize(size_t nRow_in, size_t nCol_in, float element_in){ // Assign the new element_in to new elements // Check the size if (_nRow == nRow_in && _nCol == nCol_in){ return; // Nothing to do } // Change the nCol first to resize the old row vector _nCol = nCol_in; // Resize the matrix for (size_t i = 0; i < _nRow; ++i){ data[i].resize(_nCol, element_in); } // Then extend the row _nRow = nRow_in; data.resize(_nRow, vector<float>(_nCol, element_in)); } // Reshape the matrix, keep all the elements but change the shpae of the matrix (eg. 1 by 6 -> 2 by 3 or 3 by 2) void Mat::reshape(size_t nRow_in, size_t nCol_in, bool is_Row_first){ // If is_Row_first, keep the elements' order the same in the row direction; otherwise, keep the order the same in column direction. // Note: nRow_in * nCol_in should be better be the same as this->nElement(), or some elemnets will be lost or be added (add zeros, actually) // Mat M_new(nRow_in, nCol_in); // The index for the old matrix size_t io = 0; size_t jo = 0; // if (is_Row_first){ // Row go first // for (size_t i = 0; i < nRow_in; ++i){ for (size_t j = 0; j < nCol_in; ++j){ // Row go first //-------------------// // In-range check: if (io < this->_nRow && jo < this->_nCol){ // In range M_new.data[i][j] = this->data[io][jo]; // Row go first jo++; // Change row if (jo >= this->_nCol){ jo = 0; io++; } // }else{ // Out of range M_new.data[i][j] = 0.0; } //-------------------// } } }else{ // Column go first // for (size_t j = 0; j < nCol_in; ++j){ for (size_t i = 0; i < nRow_in; ++i){ // Column go first //-------------------// // In-range check: if (io < this->_nRow && jo < this->_nCol){ // In range M_new.data[i][j] = this->data[io][jo]; // Column go fist io++; // Change row if (io >= this->_nRow){ io = 0; jo++; } // }else{ // Out of range M_new.data[i][j] = 0.0; } //-------------------// } } } // // Update this matrix *this = M_new; } // Synchronize the _nRow and _nCol with the true size of data void Mat::syncSizeInData(){ // this->_nRow = this->data.size(); // if (this->_nRow == 0){ // Empty this->_nCol = 0; }else{ this->_nCol = this->data[0].size(); } } // Assignment --- void Mat::assign(std::stringstream &ss_in, size_t nRow_in, size_t nCol_in){ // The stringstream ss_in contains a nRow_in by nCol_in matrix. // Resize this->resize(nRow_in, nCol_in); // for (size_t i = 0; i < this->_nRow; ++i){ for (size_t j = 0; j < this->_nCol; ++j){ ss_in >> this->data[i][j]; } } } // From primitive array in c++ void Mat::assign(float* Matrix_in, size_t nRow_in, size_t nCol_in){ // From primitive 1-D array in c++, Matrix_in is a nRow_in by nCol_in matrix. // Resize this->resize(nRow_in, nCol_in); // for (size_t i = 0; i < this->_nRow; ++i){ for (size_t j = 0; j < this->_nCol; ++j){ // this->data[i][j] = Matrix_in[i][j]; this->data[i][j] = *Matrix_in; Matrix_in++; } } } void Mat::assign(const vector<float> &vec_in, bool is_RowVec){ // From 1-D vector size_t n = vec_in.size(); // if (is_RowVec){ // Row vector // this->resize(1,n); // for (size_t j = 0; j < _nCol; ++j){ this->data[0][j] = vec_in[j]; } // }else{ // Column vector // this->resize(n,1); // for (size_t i = 0; i < _nRow; ++i){ this->data[i][0] = vec_in[i]; } // } } void Mat::assign(const vector<vector<float> > &MatData_in){ // A = MatData_in, assign a primitive matrix directly this->data = MatData_in; this->syncSizeInData(); } // Partial asignment void Mat::setPart(const Mat &M_part, size_t m_from, size_t n_from){ // The block starts from (m_from, n_from) size_t m_to, n_to; // The index of the last element of the inserted block m_to = m_from + M_part.nRow() - 1; n_to = n_from + M_part.nCol() - 1; //-------------------------------// // Note: if the region of the insertion block exceed the region of this matrix, // resize to a biger one and insert zero at the blank sides. // The size of the new matrix size_t M,N; // M = this->_nRow; N = this->_nCol; // // Check if block exceeds the region if (m_to >= M ){ M = m_to + 1; } if(n_to >= N){ N = n_to + 1; } // Deside if the resize action is needed this->resize(M, N, 0.0); // Start the insertion // // Initialization size_t ip = 0; size_t jp = 0; for (size_t i = m_from; i <= m_to; ++i ){ jp = 0; for (size_t j = n_from; j <= n_to; ++j){ // M_part.data[ip][jp] = data[i][j]; // <- get this->data[i][j] = M_part.data[ip][jp]; // <- insert // jp++; } ip++; } } // Spetial assignments void Mat::zeros(size_t nRow_in, size_t nCol_in){ // zeros(m,n) resize(0,0); resize(nRow_in,nCol_in, 0.0); } void Mat::ones(size_t nRow_in, size_t nCol_in){ // ones(m,n) resize(0,0); resize(nRow_in,nCol_in, 1.0); } void Mat::eye(size_t nRow_in, size_t nCol_in){ // Identity matrix, eye(m,n) zeros(nRow_in, nCol_in); // size_t K; // // min() if (nRow_in < nCol_in){ K = nRow_in; }else{ K = nCol_in; } // for (size_t i = 0; i < K; ++i){ data[i][i] = 1.0; } // } void Mat::diag(const Mat &M_diag){ // Transform the row/column vector to a diagonal matrix and assign into this matrix size_t M = M_diag.nRow(); size_t N = M_diag.nCol(); size_t nE = M_diag.nElement(); // this->zeros(nE,nE); // nE by nE matrix // size_t id = 0; size_t jd = 0; for (size_t i = 0; i < nE; ++i){ this->data[i][i] = M_diag.data[id][jd]; jd++; if (jd >= N){ jd = 0; id++; } } } // Get elements --- float Mat::at(size_t m, size_t n){ // Get the element at (m,n) return data[m][n]; } Mat Mat::getPart(size_t m_from, size_t m_to, size_t n_from, size_t n_to){ // Get partial, M_part = M(m_from:m_to, n_from:n_to) int M = m_to - m_from + 1; int N = n_to - n_from + 1; // if (M < 0 || N < 0){ Mat Empty; return Empty; } // Mat M_part(M,N); // // Initialization size_t ip = 0; size_t jp = 0; // for (size_t i = m_from; i <= m_to; ++i ){ jp = 0; for (size_t j = n_from; j <= n_to; ++j){ // In-range check if (i < this->_nRow && j < this->_nCol){ M_part.data[ip][jp] = this->data[i][j]; }else{ // Out of bound, set elements to zeros M_part.data[ip][jp] = 0.0; } // jp++; } ip++; } return M_part; } Mat Mat::getCol(size_t n){ // Get a specific column vector in 2-D matrix form return getPart(0, (this->_nRow-1), n, n); } Mat Mat::getRow(size_t m){ // Get a specific row vector in 2-D matrix form return getPart(m, m, 0, (this->_nCol-1)); } vector<float> Mat::getColVec(size_t n){ // Return a c++ vector, M(:,n) vector<float> ColVec(this->_nRow); for (size_t i = 0; i < this->_nRow; ++i){ ColVec[i] = this->data[i][n]; } return ColVec; } vector<float> Mat::getRowVec(size_t m){ // Return a c++ vector, M(m,:) return this->data[m]; } // Print out matrix --- std::string Mat::print(void){ // Print this matrix out as string /* std::string str_out; // std::string endl("\n"); // The end line character // str_out += endl; for (size_t i = 0; i < this->_nRow; ++i){ for (size_t j = 0; j < this->_nCol; ++j){ str_out += std::to_string( this->data[i][j] ) + "\t"; } str_out += endl; } str_out += endl; // return str_out; */ // Using stringstream std::stringstream ss_out; // ss_out << std::endl; // for (size_t i = 0; i < this->_nRow; ++i){ for (size_t j = 0; j < this->_nCol; ++j){ ss_out << this->data[i][j] << "\t"; } ss_out << std::endl; } ss_out << std::endl; // return ss_out.str(); } // Operations ===== // Comparison bool Mat::is_equal(const Mat &M_in){ // if (M_in.nRow() != this->_nRow || M_in.nCol() != this->_nCol){ return false; } // They are of the same size. for (size_t i = 0; i < this->_nRow; ++i){ for (size_t j = 0; j < this->_nCol; ++j){ if ( this->data[i][j] != M_in.data[i][j] ){ return false; } } } return true; } // Self-operation (affecting on this matrix) --- void Mat::scaleUp(float scale){ // M *= scale // for (size_t i = 0; i < _nRow; ++i){ MP::Get_VectorScaleUp(data[i], scale); } } void Mat::scaleUp_Mat(const Mat &M_right){ // M = M.times(M_right), element-wise multiplication // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ data[i][j] *= M_right.data[i][j]; } } } void Mat::increase(float scale){ // M += scale, for each element in M // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ data[i][j] += scale; } } } void Mat::decrease(float scale){ // M -= scale, for each element in M // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ data[i][j] -= scale; } } } void Mat::increase(const Mat &M_right){ // M += M_right // for (size_t i = 0; i < _nRow; ++i){ MP::Get_VectorIncrement(data[i], M_right.data[i], false); // += } } void Mat::decrease(const Mat &M_right){ // M -= M_right // for (size_t i = 0; i < _nRow; ++i){ MP::Get_VectorIncrement(data[i], M_right.data[i], true); // -= } } // Single-operation, output another matrix --- // Transpose Mat& Mat::T(void){ // Return the transposed version of this matrix // // Mat M_t(_nCol, _nRow); static Mat M_t; M_t.resize(_nCol, _nRow); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_t.data[j][i] = data[i][j]; } } return M_t; } // Inverse Mat& Mat::inverse(void){ // Return the inversion of this matrix // The output matrix static Mat M_inv; if (this->_nRow != this->_nCol){ M_inv.resize(0,0); // Empty matrix return M_inv; } // M_inv.resize( _nCol, _nRow); // Maybe we will impliment the psodo inverse next time // M_inv.data = MP::MatrixInversion(this->data); // Update the _nRow and _nCol M_inv.syncSizeInData(); return M_inv; } Mat& Mat::intPower(int power){ // M^power, M^0 -> I, M^-1 -> M_inverse // The output matrix static Mat M_out; // Spetial case M^1 -> M if (power == 1){ M_out = *this; return M_out; } // Spetial case M^0 -> I if (power == 0){ M_out.eye(_nRow,_nCol); return M_out; } // Check for square matrix if (this->_nRow != this->_nCol){ M_out.resize(0,0); // Error, return empty matrix return M_out; } //-----------------------------------------------// // Spetial case M^-1 -> this->inverse() if (power == -1){ // M^-1, special case for speed up the frequent useage return this->inverse(); } // // Other cases // if (power > 1){ // power > 1 M_out = *this; for (size_t i = 0; i < (power-1); ++i){ M_out = this->dot(M_out); } }else if (power < -1){ // power < -1 Mat M_inv = this->inverse(); M_out = M_inv; // this->inverse() for (size_t i = 0; i < (-power - 1); ++i){ M_out = M_inv.dot(M_out); } }else{ // Nothing, power \in {-1, 0, 1} has been processed } // return M_out; } // Duo-operation, output another matrix --- // Plus Mat& Mat::plus(float scale){ // (M + scale), for each element in M // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] + scale; } } return M_out; } Mat& Mat::minus(float scale){ // (M - scale), for each element in M // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] - scale; } } return M_out; } Mat& Mat::minus(float scale, bool is_reversed){ // is_reversed -> (scale - M), for each element in M // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // if (is_reversed){ // Reversed for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = scale - this->data[i][j]; // (scale - M) } } }else{ for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] - scale; // (M - scale) } } } return M_out; } Mat& Mat::plus(const Mat &M_right){ // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] + M_right.data[i][j]; } } return M_out; } Mat& Mat::minus(const Mat &M_right){ // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] - M_right.data[i][j]; } } return M_out; } // Concatenation Mat Mat::cat_below(const Mat &M_in){ // Below this matrix, [A; B] Mat M_cat; // Using setPart(), the size will be automatically changed. //------------------------------// // Put this matrix at (0, 0) M_cat.setPart(*this, 0, 0); // Put M_in at (_nRow, 0) M_cat.setPart(M_in, this->_nRow, 0); //------------------------------// return M_cat; } Mat Mat::cat_right(const Mat &M_in){ // Right-side of this matrix, [A, B] Mat M_cat; // Using setPart(), the size will be automatically changed. //------------------------------// // Put this matrix at (0, 0) M_cat.setPart(*this, 0, 0); // Put M_in at (0, _nCol) M_cat.setPart(M_in, 0, this->_nCol); //------------------------------// return M_cat; } Mat Mat::cat(const Mat &M_in, bool is_horizontal){ // is_horizontal --> cat_Right(); otherwise --> cat_Below() // if(is_horizontal){ // [A, B] return this->cat_right(M_in); }else{ // [A; B] return this->cat_below(M_in); } } // Scalar/Element-wise multiplication Mat& Mat::times(float scale){ // Scalar multiplication // Create the output matrix // Mat M_out(_nRow,_nCol); // static Mat M_out; M_out.resize(_nRow, _nCol); if(scale == -1.0){ // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = -(this->data[i][j]); } } }else{ // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] * scale; } } } return M_out; } Mat& Mat::times(const Mat &M_right){ // Element-wise multiplication // Create the output matrix // Mat M_out(_nRow,_nCol); static Mat M_out; M_out.resize(_nRow,_nCol); // for (size_t i = 0; i < _nRow; ++i){ for (size_t j = 0; j < _nCol; ++j){ M_out.data[i][j] = this->data[i][j] * M_right.data[i][j]; } } return M_out; } // Matrix multiplication // Note: this matrix is the "left" one Mat& Mat::dot(const Mat &M_right){ // Similar to the nomenclature of numpy in Python // Size check // mxn = (mxk)*(kxn) size_t M, K, N; // M = _nRow; K = _nCol; N = M_right.nCol(); // The output matrix // Mat M_out(M, N); static Mat M_out; M_out.resize(M, N); // cout << "here in\n"; float* ptr_data = NULL; // Using indexing for (size_t i = 0; i < M; ++i){ // row in m_out // // cout << "#i: " << i << "\n"; // for (size_t j = 0; j < N; ++j){ // column in m_out // // cout << "#j: " << j << "\n"; // ptr_data = &(M_out.data[i][j]); // *ptr_data = 0.0; for (size_t k = 0; k < K; ++k){ if (data[i][k] != 0.0 && M_right.data[k][j] != 0.0) *ptr_data += data[i][k]*M_right.data[k][j]; } } } return M_out; } Mat& Mat::dot(bool Transpose_left, const Mat &M_right, bool Transpose_right){ // Extended version for conbining the ability of transpose of both mtrices // Size check // mxn = (mxk)*(kxn) size_t M,K,N; // Left transpose if (Transpose_left){ M = _nCol; K = _nRow; }else{ M = _nRow; K = _nCol; } // Right transpose if (Transpose_right){ N = M_right.nRow(); }else{ N = M_right.nCol(); } // The output matrix // Mat M_out(M, N); static Mat M_out; M_out.resize(M, N); // float* ptr_data = NULL; // // Check the conditions of transpotations if(Transpose_left){ if(Transpose_right){ // Both transposed // // Using indexing for (size_t i = 0; i < M; ++i){ // row in m_out for (size_t j = 0; j < N; ++j){ // column in m_out // M_out.data[i][j] = 0.0; ptr_data = &(M_out.data[i][j]); *ptr_data = 0.0; // for (size_t k = 0; k < K; ++k){ if (data[k][i] != 0.0 && M_right.data[j][k] != 0.0) // (i,k) -> (k,i), (k,j) -> (j,k) *ptr_data += data[k][i]*M_right.data[j][k]; // (i,k) -> (k,i), (k,j) -> (j,k) } } } // }else{ // Only left transpose // // Using indexing for (size_t i = 0; i < M; ++i){ // row in m_out for (size_t j = 0; j < N; ++j){ // column in m_out // M_out.data[i][j] = 0.0; ptr_data = &(M_out.data[i][j]); *ptr_data = 0.0; // for (size_t k = 0; k < K; ++k){ if (data[k][i] != 0.0 && M_right.data[k][j] != 0.0) // (i,k) -> (k,i) *ptr_data += data[k][i]*M_right.data[k][j]; // (i,k) -> (k,i) } } } // } }else{ if(Transpose_right){ // Only right transpose // // Using indexing for (size_t i = 0; i < M; ++i){ // row in m_out for (size_t j = 0; j < N; ++j){ // column in m_out // M_out.data[i][j] = 0.0; ptr_data = &(M_out.data[i][j]); *ptr_data = 0.0; // for (size_t k = 0; k < K; ++k){ if (data[i][k] != 0.0 && M_right.data[j][k] != 0.0) // (k,j) -> (j,k) *ptr_data += data[i][k]*M_right.data[j][k]; // (k,j) -> (j,k) } } } // }else{ // Normal // // Using indexing for (size_t i = 0; i < M; ++i){ // row in m_out for (size_t j = 0; j < N; ++j){ // column in m_out // M_out.data[i][j] = 0.0; ptr_data = &(M_out.data[i][j]); *ptr_data = 0.0; // for (size_t k = 0; k < K; ++k){ if (data[i][k] != 0.0 && M_right.data[k][j] != 0.0) *ptr_data += data[i][k]*M_right.data[k][j]; } } } // } } return M_out; } // Operator overloading //---------------------------------------// // Member // A <- b, assignment Mat& Mat::operator = (float scale){ // Assign a real number as 1 by 1 matrix // this->resize(1,1, scale); this->resize(1,1); this->data[0][0] = scale; return *this; } Mat& Mat::operator = (const vector<float> &colVec_in){ // A = vec_in, assign as a column vector this->assign(colVec_in, false); // A column vector return *this; } Mat& Mat::operator = (const vector<vector<float> > &MatData_in){ // A = MatData_in, assign a primitive matrix directly this->assign(MatData_in); return *this; } // b <- A, get value, using implicit type conversion // Note: no implicit conversion to float, since it would be ambiguous in other operator overriding Mat::operator float (){ // Get the first element as float, good for a 1 by 1 matrix return this->data[0][0]; } Mat::operator std::vector<float> (){ // Get the column vector as std::vector<float> in c++ return this->getColVec(0); } // A[] vector<float>& Mat::operator [] (size_t m){ // Indexing the m-th row, equivalent to data[m] return this->data[m]; } // A == B bool Mat::operator == (Mat const& B){ // is_equal() return this->is_equal(B); } // A^z, z \in Z Mat& Mat::operator ^ (int power){ // A^power, this->intPower() return this->intPower(power); } // Non-member // // -A Mat& operator - (const Mat &A){ return Mat(A).times(-1.0); } // A + B Mat& operator + (float a, const Mat &B){ return Mat(B).plus(a); } Mat& operator + (const Mat &A, float b){ return Mat(A).plus(b); } Mat& operator + (const Mat &A, const Mat &B){ return Mat(A).plus(B); } // A - B Mat& operator - (float a, const Mat &B){ return Mat(B).minus(a, true); // (a - B) } Mat& operator - (const Mat &A, float b){ return Mat(A).minus(b); } Mat& operator - (const Mat &A, const Mat &B){ return Mat(A).minus(B); } // A * B Mat& operator * (float a, const Mat &B){ return Mat(B).times(a); } Mat& operator * (const Mat &A, float b){ return Mat(A).times(b); } Mat& operator * (const Mat &A, const Mat &B){ // Matrix multiplication return Mat(A).dot(B); } // A/B, including matrix inversion (eg, (1.0/B) <--> B^-1) Mat& operator / (float a, const Mat &B){ // a*(B^-1), for that B to be inversed if (a == 1.0){ return Mat(B).inverse(); } return ( ( Mat(B).inverse()).times(a) ); } Mat& operator / (const Mat &A, float b){ // A*(1/b), scalar multiplication of 1/b return Mat(A).times(1.0/b); } Mat& operator / (const Mat &A, const Mat &B){ // A*(B^-1), for that B to be inversed return ( Mat(A).dot(Mat(B).inverse()) ); } // A += B Mat& operator += (Mat &A, float b){ A.increase(b); return A; } Mat& operator += (Mat &A, const Mat &B){ A.increase(B); return A; } // A -= B Mat& operator -= (Mat &A, float b){ A.decrease(b); return A; } Mat& operator -= (Mat &A, const Mat &B){ A.decrease(B); return A; } // A *= B Mat& operator *= (Mat &A, float b){ A.scaleUp(b); return A; } Mat& operator *= (Mat &A, const Mat &B){ // Matrix multiplication A = A.dot(B); return A; } //---------------------------------------// // end Operator overloading