#pragma once #include "vec.h" #include #include #ifdef _MSC_VER #pragma warning(disable : 4996) //checked iterators #endif namespace cgv { /// namespace with classes and algorithms for mathematics namespace math { template class mat; template struct step_iterator: public std::iterator::value_type> { public: typedef std::iterator::value_type> base_type; typedef typename base_type::pointer pointer; typedef typename base_type::reference reference; typedef typename base_type::value_type value_type; typedef typename base_type::difference_type difference_type; private: RandomAccessIterator internal_iter; int step; friend class mat; step_iterator( RandomAccessIterator begin,int step=1):internal_iter(begin),step(step) {} public: step_iterator():internal_iter(NULL) { step=0; } step_iterator(const step_iterator& other) { internal_iter=other.internal_iter; step=other.step; } step_iterator& operator=(const step_iterator& other) { if(*this != other) { internal_iter = other.internal_iter; step = other.step; } return *this; } bool operator==(const step_iterator& other) const { return internal_iter == other.internal_iter; } bool operator!=(const step_iterator& other) const { return !(*this==other); } reference operator*() { return *internal_iter; } reference operator*() const { return *internal_iter; } pointer operator->() { return &**this; } pointer operator->() const { return &**this; } step_iterator& operator ++() { internal_iter+=step; return *this; } step_iterator operator ++(int) { step_iterator tmp=*this; ++*this; return tmp; } step_iterator& operator --() { internal_iter-=step; return *this; } step_iterator operator --(int) { step_iterator tmp=*this; --*this; return tmp; } step_iterator& operator +=(difference_type n) { internal_iter+=n*step; return *this; } step_iterator& operator -=(difference_type n) { internal_iter-=n*step; return *this; } step_iterator operator -(difference_type n) const { step_iterator tmp=*this; tmp-=n; return tmp; } difference_type operator-(const step_iterator& right) const { return (internal_iter - right.internal_iter)/step; } step_iterator operator +(difference_type n)const { step_iterator tmp=*this; tmp+=n; return tmp; } reference operator[](difference_type offset) const { return (*(*this + offset)); } bool operator <(const step_iterator& other) const { if(step > 0) return internal_iter < other.internal_iter; else return internal_iter > other.internal_iter; } bool operator >(const step_iterator& other) const { if(step > 0) return internal_iter > other.internal_iter; else return internal_iter < other.internal_iter; } bool operator <=(const step_iterator& other) const { if(step > 0) return internal_iter <= other.internal_iter; else return internal_iter >= other.internal_iter; } bool operator >=(const step_iterator& other) const { if(step > 0) return internal_iter >= other.internal_iter; else return internal_iter <= other.internal_iter; } }; /** * A matrix type (full column major storage) * The matrix can be loaded directly into OpenGL without need for transposing! */ template class mat { protected: ///pointer to data storage vec _data; ///number of columns unsigned _ncols; ///number of rows unsigned _nrows; public: typedef typename vec::value_type value_type; typedef typename vec::reference reference; typedef typename vec::const_reference const_reference; typedef typename vec::pointer pointer; typedef typename vec::const_pointer const_pointer; typedef typename vec::iterator iterator; typedef typename vec::const_iterator const_iterator; typedef typename vec::reverse_iterator reverse_iterator; typedef typename vec::const_reverse_iterator const_reverse_iterator; typedef iterator col_iterator; typedef const col_iterator const_col_iterator; typedef std::reverse_iterator reverse_col_iterator; typedef std::reverse_iterator const_reverse_col_iterator; typedef step_iterator row_iterator; typedef const row_iterator const_row_iterator; typedef std::reverse_iterator reverse_row_iterator; typedef std::reverse_iterator const_reverse_row_iterator; typedef step_iterator diag_iterator; typedef const diag_iterator const_diag_iterator; typedef std::reverse_iterator reverse_diag_iterator; typedef std::reverse_iterator const_reverse_diag_iterator; typedef step_iterator anti_diag_iterator; typedef const anti_diag_iterator const_anti_diag_iterator; typedef std::reverse_iterator reverse_anti_diag_iterator; typedef std::reverse_iterator const_reverse_anti_diag_iterator; iterator begin(){return _data.begin();} iterator end(){return _data.end();} const_iterator begin() const{return _data.begin();} const_iterator end() const{return _data.end();} reverse_iterator rbegin(){return _data.rbegin();} reverse_iterator rend(){return _data.rend();} const_reverse_iterator rbegin() const{return _data.rbegin();} const_reverse_iterator rend() const {return _data.rend();} col_iterator col_begin(int c) { return col_iterator(_data.begin()+(c*_nrows)); } col_iterator col_end(int c) { return col_iterator(_data.begin()+(c+1)*_nrows ); } const_col_iterator col_begin(int c) const { return const_col_iterator(_data.begin()+(c*_nrows)); } const_col_iterator col_end(int c) const { return const_col_iterator(_data.begin()+(c+1)*_nrows ); } reverse_col_iterator col_rbegin(int c) { return (reverse_col_iterator(col_end(c))); } reverse_col_iterator col_rend(int c) { return (reverse_col_iterator(col_begin(c))); } const_reverse_col_iterator col_rbegin(int c) const { return (const_reverse_col_iterator(col_end(c))); } const_reverse_col_iterator col_rend(int c) const { return (const_reverse_col_iterator(col_begin(c))); } row_iterator row_begin(int r) { return row_iterator(_data.begin()+r,_nrows); } row_iterator row_end(int r) { return row_iterator(_data.begin()+(r+_ncols*_nrows),_nrows); } const_row_iterator row_begin(int r) const { return const_row_iterator(_data.begin()+r,_nrows); } const_row_iterator row_end(int r) const { return const_row_iterator(_data.begin()+(r+_ncols*_nrows),_nrows); } reverse_row_iterator row_rbegin(int r) { return (reverse_row_iterator(row_end(r))); } reverse_row_iterator row_rend(int r) { return (reverse_row_iterator(row_begin(r))); } const_reverse_row_iterator row_rbegin(int r) const { return (const_reverse_row_iterator(row_end(r))); } const_reverse_row_iterator row_rend(int r) const { return (const_reverse_row_iterator(row_begin(r))); } diag_iterator diag_begin(int d=0) { if(d <= 0) return diag_iterator(_data.begin()-d ,_nrows+1); else return diag_iterator(_data.begin()+d*_nrows,_nrows+1); } diag_iterator diag_end(int d=0) { if(d <= 0) { int n=std::min(_nrows+d,_ncols); return diag_iterator(_data.begin()-d+n*(_nrows+1),_nrows+1); } else { int n = std::min(_ncols-d,_nrows); return diag_iterator(_data.begin()+d*_nrows+n*(_nrows+1),_nrows+1) ; } } const_diag_iterator diag_begin(int d=0) const { if(d <= 0) return const_diag_iterator(begin()-d ,_nrows+1); else return const_diag_iterator(begin()+d*_nrows,_nrows+1); } const_diag_iterator diag_end(int d=0) const { if(d <= 0) { int n=std::min(_nrows+d,_ncols); return const_diag_iterator(_data.begin()-d+n*(_nrows+1),_nrows+1); } else { int n = std::min(_ncols-d,_nrows); return const_diag_iterator(_data.begin()+d*_nrows+n*(_nrows+1),_nrows+1) ; } } reverse_diag_iterator diag_rbegin(int d=0) { return (reverse_diag_iterator(diag_end(d))); } reverse_diag_iterator diag_rend(int d=0) { return (reverse_diag_iterator(diag_begin(d))); } const_reverse_diag_iterator diag_rbegin(int d=0) const { return (const_reverse_diag_iterator(diag_end(d))); } const_reverse_diag_iterator diag_rend(int d=0) const { return (const_reverse_diag_iterator(diag_begin(d))); } anti_diag_iterator anti_diag_begin(int d=0) { if(d >= 0) return anti_diag_iterator(_data.begin()+(_ncols-1-d)*_nrows ,1-_nrows); else return anti_diag_iterator(_data.begin()+(_ncols-1)*_nrows-d ,1-_nrows); } anti_diag_iterator anti_diag_end(int d=0) { if(d >= 0) { int n=std::min(_ncols-d,_nrows); return anti_diag_iterator(_data.begin()+(_ncols-1-d)*_nrows +n*(1-_nrows),1-_nrows); } else { int n=std::min(_nrows+d,_ncols); return anti_diag_iterator(_data.begin()+(_ncols-1)*_nrows-d +n*(1-_nrows),1-_nrows); } } const_anti_diag_iterator anti_diag_begin(int d=0) const { if(d >= 0) return const_anti_diag_iterator(_data.begin()+(_ncols-1-d)*_nrows ,1-_nrows); else return const_anti_diag_iterator(_data.begin()+(_ncols-1)*_nrows-d ,1-_nrows); } const_anti_diag_iterator anti_diag_end(int d=0) const { if(d >= 0) { int n=std::min(_ncols-d,_nrows); return const_anti_diag_iterator(_data.begin()+(_ncols-1-d)*_nrows +n*(1-_nrows),1-_nrows); } else { int n=std::min(_nrows+d,_ncols); return const_anti_diag_iterator(_data.begin()+(_ncols-1)*_nrows-d +n*(1-_nrows),1-_nrows); } } reverse_anti_diag_iterator anti_diag_rbegin(int d=0) { return (reverse_anti_diag_iterator(anti_diag_end(d))); } reverse_anti_diag_iterator anti_diag_rend(int d=0) { return (reverse_anti_diag_iterator(anti_diag_begin(d))); } const_reverse_anti_diag_iterator anti_diag_rbegin(int d=0) const { return (const_reverse_anti_diag_iterator(anti_diag_end(d))); } const_reverse_anti_diag_iterator anti_diag_rend(int d=0) const { return (const_reverse_anti_diag_iterator(anti_diag_begin(d))); } ///standard constructor mat() { _ncols = 0; _nrows = 0; } ///constructor creates a nrows x ncols full matrix mat(unsigned nrows, unsigned ncols) : _data(nrows*ncols) { _nrows = nrows; _ncols = ncols; } ///construct a matrix with all elements set to c mat(unsigned nrows, unsigned ncols, const T& c) :_data(nrows*ncols) { _nrows = nrows; _ncols = ncols; _data.fill(c); } ///creates a matrix from an array ///if the matrix data is stored in a row major fashion set column_major to false mat(unsigned nrows, unsigned ncols, const T* marray,bool column_major=true) :_data(nrows*ncols) { _nrows = nrows; _ncols = ncols; if(column_major) memcpy(_data, marray, size()*sizeof(T)); else { for(unsigned i = 0; i < _nrows; i++) for(unsigned j = 0; j < _ncols;j++) { operator()(i,j) = marray[i*_ncols +j]; } } } ///copy constructor for matrix with different element type template mat(const mat& m):_data(m.size()) { _nrows = m.nrows(); _ncols = m.ncols(); for(unsigned i = 0; i < _nrows; i++) for(unsigned j = 0; j < _ncols;j++) { operator()(i,j)=(T)m(i,j); } } /// set data pointer to an external data array void set_extern_data(unsigned nrows, unsigned ncols, T* data) { _data.set_extern_data(nrows*ncols,data); _nrows = nrows; _ncols = ncols; } void destruct() { _data.destruct(); } ///number of stored elements unsigned size() const { return _data.size(); } ///number of rows unsigned nrows() const { return _nrows; } ///number of columns unsigned ncols() const { return _ncols; } ///assignment of a matrix with a different element type template mat& operator = (const mat& m) { resize(m.nrows(),m.ncols()); for(unsigned i = 0; i < _nrows; i++) for(unsigned j = 0; j < _ncols;j++) { operator()(i,j)=(T)m(i,j); } return *this; } ///assignment of a scalar s to each element of the matrix mat& operator = (const T& s) { fill (s); return *this; } ///resize the matrix, the content of the matrix will be destroyed void resize(unsigned rows, unsigned cols) { unsigned newsize = rows*cols; _nrows = rows; _ncols = cols; _data.resize(newsize); } ///cast operator for non const array operator T*() { return (T*)_data; } ///cast operator const array operator const T*() const { return (const T*)_data; } ///returns true if matrix is a square matrix bool is_square() const { return _ncols == _nrows; } ///fills all elements of the matrix with v template void fill(const S& v) { T val = (T)v; _data.fill(val); } ///access to the element in the ith row in column j T& operator () (unsigned i, unsigned j) { assert(i < _nrows && j < _ncols); return _data[j*_nrows+i]; } ///const access to the element in the ith row on column j const T& operator () (unsigned i, unsigned j) const { assert(_data != NULL && i < _nrows && j < _ncols); return _data[j*_nrows+i]; } ///test for equality template bool operator == (const mat& m) const { if(_ncols != m.ncols() || _nrows != m.nrows()) return false; return _data == m._data; } ///test for inequality template bool operator != (const mat& m) const { if(_ncols != m.ncols() || _nrows != m.nrows()) return false; return _data != m._data; return false; } //in place scalar multiplication mat& operator *= (const T& s) { _data *= (T)s; return *this; } ///scalar multiplication const mat operator*(const T& s) const { mat r=(*this); r*=(T)s; return r; } ///in place division by a scalar mat& operator /= (const T& s) { _data /= (T)s; return *this; } /// division by a scalar const mat operator / (const T& s) const { mat r=(*this); r/=s; return r; } ///in place addition by a scalar mat& operator += (const T& s) { _data += (T)s; return *this; } ///componentwise addition of a scalar const mat operator + (const T& s) { mat r=(*this); r+=s; return r; } ///in place substraction of a scalar mat& operator -= (const T& s) { _data -= (T)s; return *this; } /// componentwise subtraction of a scalar const mat operator - (const T& s) { mat r=(*this); r-=s; return r; } ///negation operator const mat operator-() const { mat r=(*this)*((T)-1); return r; } ///in place addition of matrix template mat& operator += (const mat& m) { assert(_ncols == m.ncols() && _nrows == m.nrows()); _data+=m._data; return *this; } ///in place subtraction of matrix template mat& operator -= (const mat& m) { assert(_ncols == m.ncols() && _nrows == m.nrows()); _data-=m._data; return *this; } ///matrix addition template const mat operator+(const mat m2)const { mat r=(*this); r += m2; return r; } ///matrix subtraction template const mat operator-(const mat m2)const { mat r=(*this); r-= m2; return r; } ///in place matrix multiplication with a ncols x ncols matrix m2 template const mat operator*=(const mat& m2) { assert(ncols() == m2.ncols() && nrows() == m2.nrows() && ncols() == nrows()); mat r(_nrows,_ncols,(T)0); for(unsigned i = 0; i < _nrows; i++) for(unsigned j = 0; j < _ncols;j++) for(unsigned k = 0; k < _ncols; k++) r(i,j) += operator()(i,k) * (T)(m2(k,j)); (*this)=r; return *this; } ///multiplication with a ncols x M matrix m2 template const mat operator*(const mat& m2) const { assert(m2.nrows() == _ncols); unsigned M = m2.ncols(); mat r(_nrows,M,(T)0); for(unsigned i = 0; i < _nrows; i++) for(unsigned j = 0; j < M;j++) for(unsigned k = 0; k < _ncols; k++) r(i,j) += operator()(i,k) * (T)(m2(k,j)); return r; } ///matrix vector multiplication template < typename S> const vec operator*(const vec& v) const { assert(_ncols==v.size()); vec r; r.zeros(_nrows); for(unsigned j = 0; j < _ncols; j++) for(unsigned i = 0; i < _nrows; i++) r(i) += operator()(i,j) * (T)(v(j)); return r; } ///create submatrix m(top,left)...m(top+rows,left+cols) mat sub_mat(unsigned top, unsigned left, unsigned rows, unsigned cols) const { mat mnew(rows,cols); for(unsigned i = 0; i < rows;i++) for(unsigned j = 0; j < cols;j++) mnew(i,j)=operator()(i+top,j+left); return mnew; } ///extract a row from the matrix as a vector const vec row(unsigned i) const { vec mnew(_ncols); for(unsigned j = 0; j < _ncols;j++) mnew(j)=operator()(i,j); return mnew; } ///set row i of the matrix to vector v void set_row(unsigned i,const vec& v) { for(unsigned j = 0; j < _ncols;j++) operator()(i,j)=v(j); } ///extract a column of the matrix as a vector const vec col(unsigned j) const { vec mnew(_nrows); for(unsigned i = 0; i < _nrows;i++) mnew(i)=operator()(i,j); return mnew; } ///set column j of the matrix to vector v void set_col(unsigned j,const vec& v) { for(unsigned i = 0; i < _nrows;i++) operator()(i,j)=v(i); } ///copy submatrix m(top,left)...m(top+rows,left+cols) into submat void copy(unsigned top, unsigned left, unsigned rows, unsigned cols, mat& submat) const { assert(submat.nrows() == rows && submat.ncols() == cols); for(unsigned i = 0; i < rows;i++) for(unsigned j = 0; j < cols;j++) submat(i,j)=operator()(i+top,j+left); } ///paste matrix m at position: top, left void paste(int top, int left,const mat& m) { for(unsigned i = 0; i < m.nrows(); i++) for(unsigned j = 0; j < m.ncols(); j++) operator()(i+top,j+left)=m(i,j); } ///exchange row i with row j void swap_rows(unsigned i, unsigned j) { assert(i < _nrows && j < _nrows); for(unsigned k = 0; k < _ncols;k++) std::swap(operator()(i,k),operator()(j,k)); } ///exchange column i with column j void swap_columns(unsigned i, unsigned j) { assert(i < _ncols && j < _ncols); for(unsigned k = 0; k < _nrows;k++) std::swap(operator()(k,i),operator()(k,j)); } ///exchange diagonal elements (i,i) (j,j) void swap_diagonal_elements(unsigned i, unsigned j) { assert(i < _ncols && j < _ncols); std::swap(operator()(i,i),operator()(j,j)); } ///returns the trace T trace() const { assert(_nrows == _ncols); T t = 0; for(unsigned i = 0; i < _nrows;i++) t+=operator()(i,i); return t; } ///transpose matrix void transpose() { mat r(_ncols,_nrows); for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) r(j,i) = operator()(i,j); *this = r; } //flip columns left-right void fliplr() { mat r(_nrows,_ncols); for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) r(i,j) = operator()(i,_ncols-j-1); *this = r; } //flip rows up-down void flipud() { mat r(_nrows,_ncols); for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) r(i,j) = operator()(_nrows-i-1,j); *this = r; } ///ceil all components of the matrix void ceil() { for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) operator()(i,j) =::ceil(operator()(i,j)); } ///floor all components of the matrix void floor() { for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) operator()(i,j) =::floor(operator()(i,j)); } ///round to integer void round() { for(unsigned i = 0; i < _nrows;i++) for(unsigned j = 0; j < _ncols;j++) operator()(i,j) =::floor(operator()(i,j)+(T)0.5); } ///returns the frobenius norm of matrix m T frobenius_norm() const { T n=0; for(unsigned i =0; i < _nrows;i++) for(unsigned j=0;j <_ncols;j++) n+=operator()(i,j)*operator()(i,j); return (T)sqrt((double)n); } ///set identity matrix void identity() { assert(_ncols == _nrows); zeros(); for(unsigned i = 0; i < _ncols;++i) operator()(i,i)=1; } ///set dim x dim identity matrix void identity(unsigned dim) { zeros(dim,dim); for(unsigned i = 0; i < _ncols;++i) operator()(i,i)=1; } ///set zero matrix void zeros() { fill(0); } ///resize and fill matrix with zeros void zeros(unsigned rows, unsigned cols) { resize(rows,cols); fill((T)0); } ///resize and fill matrix with ones void ones(unsigned rows, unsigned cols) { resize(rows,cols); fill((T)1); } }; template mat zeros(unsigned rows, unsigned cols) { mat m; m.zeros(rows,cols); return m; } template mat ones(unsigned rows, unsigned cols) { mat m(rows,cols); m.fill((T)1); return m; } template mat identity(unsigned dim) { mat m; m.identity(dim); return m; } //return frobenius norm template T frobenius_norm(const mat& m) { return m.frobenius_norm(); } //return trace of matrix template T trace(const mat& m) { return m.trace(); } //concatenate two matrices horizontally template const mat horzcat(const mat& m1, const mat& m2) { assert(m1.nrows() == m2.nrows()); mat r(m1.nrows(),m1.ncols()+m2.ncols()); for(unsigned i = 0; i < m1.nrows();i++) { for(unsigned j = 0; j < m1.ncols(); j++) r(i,j) = m1(i,j); for(unsigned j = 0; j < m2.ncols(); j++) r(i,j+m1.ncols())=(T)m2(i,j); } return r; } //concatenates a matrix and a column vector horizontally template const mat horzcat(const mat& m1, const vec& v) { assert(m1.nrows() == v.size()); mat r(m1.nrows(),m1.ncols()+1); for(unsigned i = 0; i < m1.nrows();i++) { for(unsigned j = 0; j < m1.ncols(); j++) r(i,j) = m1(i,j); r(i,m1.ncols())=(T)v(i); } return r; } //concatenates two vectors horizontally template const mat horzcat(const vec& v1, const vec& v2) { assert(v1.size() == v2.size()); mat r(v1.size(),2); for(unsigned i = 0; i < v1.size();i++) { r(i,0) = v1(i); r(i,1) = v2(i); } return r; } //concatenates two column vectors vertically template const vec vertcat(const vec& v1, const vec& v2) { vec r(v1.size()+v2.size()); unsigned off = v1.size(); for(unsigned i = 0; i < v1.size();i++) r(i) = v1(i); for(unsigned i = 0; i < v2.size();i++) r(i+off) = v2(i); return r; } //concatenates two matrices vertically template const mat vertcat(const mat& m1, const mat& m2) { assert(m1.ncols() == m2.ncols()); mat r(m1.nrows()+m2.nrows(),m1.ncols()); for(unsigned i = 0; i < m1.nrows();i++) { for(unsigned j = 0; j < m1.ncols(); j++) r(i,j) = m1(i,j); } for(unsigned i = 0; i < m2.nrows();i++) { for(unsigned j = 0; j < m1.ncols(); j++) r(i+m1.nrows(),j) = m2(i,j); } return r; } //transpose of a matrix m template const mat transpose(const mat &m) { mat r = m; r.transpose(); return r; } //transpose of a column vector template const mat transpose(const vec &v) { mat r(1, v.size()); for(unsigned i = 0; i < v.size(); i++) r(0,i)= v(i); return r; } ///ceil all components of the matrix template const mat ceil(const mat &m) { mat r = m; r.ceil(); return r; } ///floor all components of the matrix template const mat floor(const mat &m) { mat r = m; r.floor(); return r; } ///round all components of the matrix template const mat round(const mat &m) { mat r = m; r.round(); return r; } ///return the product of a scalar s and a matrix m template mat operator * (const T& s, const mat& m) { return m*(T)s; } ///output of a matrix onto an ostream template std::ostream& operator<<(std::ostream& out, const mat& m) { for (unsigned i=0;i std::istream& operator>>(std::istream& in, mat& m) { assert(m.size() > 0); for (unsigned i=0;i> m(i,j); return in; } //compute transpose(A)*A template void AtA(const mat& a, mat& ata) { ata.resize(a.ncols(),a.ncols()); ata.zeros(); for(unsigned r = 0; r < a.nrows();r++) { for(unsigned i = 0; i < a.ncols();i++) { for(unsigned j = 0; j < a.ncols();j++) { ata(i,j)+=a(r,i)*a(r,j); } } } } //compute A*transpose(A) template void AAt(const mat& a, mat& aat) { aat.resize(a.nrows(),a.nrows()); aat.zeros(); for(unsigned c = 0; c < a.ncols();c++) { for(unsigned i = 0; i < a.nrows();i++) { for(unsigned j = 0; j < a.nrows();j++) { aat(i,j)+=a(i,c)*a(j,c); } } } } template mat reshape(const vec& v,unsigned r,unsigned c) { assert(v.size() == r*c); return mat(r,c,(const T*)v); } template mat reshape(const mat& m,unsigned r,unsigned c) { assert(m.size() == r*c); return mat(r,c,(const T*)m); } template void AtB(const mat& a,const mat& b, mat& atb) { atb.resize(a.ncols(),b.ncols()); atb.zeros(); for(unsigned i = 0; i < a.ncols(); i++) for(unsigned j = 0; j < b.ncols();j++) for(unsigned k = 0; k < a.nrows(); k++) atb(i,j) += a(k,i)*b(k,j); } ///multiply A^T*x /// A is a matrix and x is a vector template void Atx(const mat& a,const vec& x, vec& atx) { atx.resize(a.ncols()); atx.zeros(); for(unsigned i = 0; i < a.ncols(); i++) for(unsigned j = 0; j < a.nrows(); j++) atx(i) += a(j,i) * (T)(x(j)); } ///returns the outer product of vector v and w template < typename T, typename S> mat dyad(const vec& v, const vec& w) { mat m(v.size(),w.size()); for(unsigned i = 0; i < v.size();i++) for(unsigned j = 0; j < w.size();j++) m(i,j) =v(i)*(T)w(j); return m; } } }