Matrix and Vec
Download: matrix.zip.
See: matrix.h, matrix.cpp, main.cpp (small test program)
The Matrix
class is a matrix data structure and routines for
matrix manuipulation. The class Vec
is a simple column
(or row) vector.
matrix.h
/*\file matrix.h * * matrix data structure, and routines for matrix manipulation. */ #if !defined(__MATRIX_H) #define __MATRIX_H #include <string> #include <assert.h> // \typedef //! pointer to a function which returns a double and takes as argument a double typedef double (*V_FCT_PTR)(double); //! defines a vector of doubles class Vec { public: Vec(): n(0), body(0) { } //!< default no-argument constructor //! constructs a vector of length n Vec(int size): n(0), body(0) { create(size); } Vec(const Vec &src): n(0), body(0) { copy(src); } //!< copy constructor ~Vec() { delete [] body; body=0; n=0; } //!< destructor //! creates (or resets) vector length and allocated space void create(int size); //! returns the length (number of elements) of the vector int length() const { return n; } //! prints vector contents to stdout void print() const; //! set to constant value Vec &set(double v) { for (int i=0; i<length(); i++) body[i] = v; return *this; } //! subscript operator (non-const object) double &operator[](int n) {return body[n]; } //! subscript operator (const object) const double &operator[](int n) const { return body[n]; } Vec &operator=(const Vec &src) { return (this==&src? *this: copy(src)); } //!< dst = src //! applys function fct element-by-element Vec &apply(V_FCT_PTR fct); double max(); //!< returns maximum Vec element double min(); //!< returns minimum Vec element double norm(); //< returns 2-norm (magnitude) of Vec void normalize(); //< convert Vec to unit magnitude //! returns dot product of a and b static double dot(const Vec &a, const Vec &b); // operator overloads friend Vec operator+(const Vec &a, const Vec &b); //!< returns a+b friend Vec operator-(const Vec &a, const Vec &b); //!< returns a-b friend Vec operator*(double c, const Vec &a); //!< returns scalar multiplied by Vec friend Vec operator*(const Vec &a, double c); //!< returns Vec multiplied by scalar friend Vec operator*(const Vec &a, double c); //!< returns Vec divided by scalar private: double *body; //!< contains the elements of the vector int n; //!< number of elements in the vector Vec ©(const Vec &src); //!< replace current vector with src }; std::ostream& operator << (std::ostream& s, const Vec& v); //! defines a two-dimensional Matrix of doubles class Matrix { public: //! default (no argument) constructor Matrix(): nrows(0), ncols(0), body(0) {} //! constructs a Matrix of specified size Matrix(int rows, int cols): nrows(0), ncols(0), body(0) { create(rows,cols);} Matrix(const Matrix &src): nrows(0), ncols(0), body(0) { copy(src); } //!< copy constructor ~Matrix(); //!< destructor //! creates(or resets) Matrix size and allocated space. void create(int rows, int cols); int cols()const { return ncols; } //!< returns the number of columns int rows()const { return nrows; } //!< returns the number of rows //! set Matrix elements to v Matrix &set(double v); Matrix &operator =(const Matrix &mx) { return (this==&mx? *this: copy(mx)); } Matrix operator *(const Matrix &mx) const; //static Vec mul(const Matrix &mx, const Vec &v); //static Vec mul(const Vec &v, const Matrix &mx); //! swap rows void swaprows(int i, int j); //! returns the transpose of the Matrix Matrix transpose(); //! returns a pointer to a Matrix row double * operator [](int n) const { return body[n]; } //const double * operator [](int n) const { return body[n]; } //! prints Matrix (using mprint) void print() const; // friends friend Vec operator *(const Matrix &mx, const Vec &v); //!< matix multipled by Vec friend Vec operator *(const Vec &v, const Matrix &mx); //!< Vec multiplied by Matrix private: int nrows; //!< number of rows in the Matrix int ncols; //!< number of columns in the Matrix double **body; //!< space allocated for the Matrix Matrix ©(const Matrix &mx); //!< replaces Matrix with Matrix mx }; /*! returns the inner (or dot) product of a vector * @param a first vector * @param b second vector * @returns (a dot b) */ inline double Vec::dot(const Vec &a, const Vec &b) { double sum = 0.0; int n = a.length(); assert(b.length()==n); for (int i=0; i<n; i++) sum += a[i]*b[i]; return sum; } Matrix identity(int size); Matrix diagonal(double *v, int size); int read_matrix(Matrix &mx, std::string &title, FILE *in); void print_vector(double *v, int n); void copy_matrix(Matrix &dst, Matrix &src); double *vector(int length); int *ivector(int length); void errmsg(char *text); #endif
matrix.cpp
/* matrix.cpp * * Utility routines for allocating space for matrices and vectors, * printing matrices and vectors, and copying one matrix to another. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <math.h> #include <iostream> using namespace std; #include "matrix.h" void Matrix::create(int rows, int cols) { if (rows==nrows && cols==ncols) return; while (nrows) delete [] body[--nrows]; if (body) delete body; nrows = rows; ncols = cols; body = new double * [nrows]; assert(body); for (int i=0; i<nrows; i++) { body[i]= new double[ncols]; assert(body[i]); } } /*! * Copy Matrix src to the current Matrix */ Matrix &Matrix::copy(const Matrix &src) { int i, j; double *up, *vp; create(src.rows(),src.cols()); for (i=0; i<nrows; i++) { up = src[i]; vp = body[i]; for (j=0; j<ncols; j++) *vp++ = *up++; } return *this; } Matrix::~Matrix() { while (nrows) delete [] body[--nrows]; delete [] body; } Matrix &Matrix::set(double v) { int i, j; double *p; for (i=0; i<nrows; i++) { p = body[i]; for (j=0; j<ncols; j++) *p++ = v; } return *this; } void Matrix::swaprows(int i,int j) { double *p = body[i]; body[i]=body[j]; body[j]=p; } Matrix Matrix::transpose() { int i, j; Matrix out(ncols,nrows); for (i=0; i<nrows; i++) { for (j=0; j<ncols; j++) { out[j][i] = body[i][j]; } } return out; } //! Matrix multiplication Matrix Matrix::operator *(const Matrix &mx) const { int i, j, k; double sum; double *vp; assert(ncols == mx.rows()); // check for non-conforming Matrix multiplication Matrix out(nrows,mx.cols()); for (i=0; i<nrows; i++) { vp = out[i]; for (j=0; j<mx.cols(); j++) { sum = 0.0; for (k=0; k<ncols; k++) sum += body[i][k] * mx[k][j]; *vp++ = sum; } } return out; } Vec operator *(const Matrix &mx, const Vec &v) { int i, j; int m = mx.rows(); int n = mx.cols(); double sum; assert(m>0 && n>0); assert(n==v.length()); Vec vout(m); for (i=0; i<m; i++) { sum = 0.0; double *ptr = mx[i]; for (j=0; j<n; j++) sum += (*ptr++) * v[j]; vout[i] = sum; } return vout; } Vec operator *(const Vec &v, const Matrix &mx) { int i, j; int m = mx.rows(); int n = mx.cols(); double sum; assert(m>0 && n>0); assert(m==v.length()); Vec vout(n); for (j=0; j<n; j++) { sum = 0.0; for (i=0; i<m; i++) sum += v[i] * mx[i][j]; vout[j] = sum; } return vout; } //! create an Identity Matrix Matrix identity(int size) { int i, j; double *vp; Matrix out(size,size); for (i=0; i<size; i++) { vp = out[i]; for (j=0; j<size; j++) vp[j]=0.0; vp[i] = 1.0; } return out; } //! create a diagonal Matrix /*! * @param v is an array of diagonal elements * @param size is the length of the array * */ Matrix diagonal(double *v, int size) { int i, j; double *vp; Matrix out(size,size); for (i=0; i<size; i++) { vp = out[i]; for (j=0; j<size; j++) vp[j]=0.0; vp[i] = v[i]; } return out; } //! read Matrix from text file /*! @param mx destination Matrix * @param title c-string comment (remainder of header line) * @param in input file * * The first two entries are number of rows and columns.\n * The rest of the line is a title.\n * The body of the Matrix follows.\n */ int read_matrix(Matrix &mx, string &title, FILE *in) { int i, j; int nrows, ncols; double *v; double vin; char *cp; char buf[256]; fscanf_s(in," %d %d",&nrows,&ncols); if (feof(in)) return -1; fgets(buf,255,in); if (feof(in)) return -1; cp = buf; while (*cp) { if (*cp=='\n') *cp = 0; else cp++; } title = buf; mx.create(nrows,ncols); for (j=0; j<nrows; j++) { v = mx[j]; for (i=0; i<ncols; i++) { fscanf_s(in," %lf",&vin); *v++ = vin; } if (feof(in)) { printf("\nerror reading %s\n",title); printf("Matrix has %d rows and %d columns\n", mx.rows(),mx.cols()); printf("Unexpected EOF reading row %d",j+1); return -1; } } return 0; } //! create memory for elements of vector void Vec::create(int size) { assert(size); if (size == n) return; if (body != 0) delete [] body; body = new double[size]; assert(body!=0); n = size; //memset((void *)body, 0, (size_t)(n*sizeof(double)); } //! copy constructor Vec &Vec::copy(const Vec &src) { int size = src.length(); create(size); for (int i=0; i<n; i++) body[i] = src[i]; return *this; } double Vec::max() { double vmax = body[0]; for (int i=1; i<n; i++) if (body[i]>vmax) vmax = body[i]; return vmax; } double Vec::min() { double vmin = body[0]; for (int i=1; i<n; i++) if (body[i]<vmin) vmin = body[i]; return vmin; } double Vec::norm() { double sum = 0;0; for (int i=0; i<n; i++) sum += body[i]*body[i]; return sqrt(sum); } void Vec::normalize() { double vnorm = norm(); for (int i=0; i<n; i++) body[i] /= vnorm; } Vec& Vec::apply(V_FCT_PTR fct) { for (int i=0; i<n; i++) body[i] = (*fct)(body[i]); return *this; } //! returns a + b Vec operator +(const Vec &a, const Vec &b) { int n = a.length(); assert(b.length()==n); Vec sum(n); for (int i=0; i<n; i++) sum[i] = a[i] + b[i]; return sum; } //! returns a - b Vec operator -(const Vec &a, const Vec &b) { int n = a.length(); assert(b.length()==n); Vec diff(n); for (int i=0; i<n; i++) diff[i] = a[i] - b[i]; return diff; } //! returns scalar multiplied by a vector Vec operator *(double c, const Vec &a) { int n = a.length(); Vec vout(n); for (int i=0; i<n; i++) vout[i] = c*a[i]; return vout; } //! returns vector mutliplied by a scalar Vec operator *(const Vec &a, double c) { int n = a.length(); Vec vout(n); for (int i=0; i<n; i++) vout[i] = c*a[i]; return vout; } //! returns vector divided by a scalar Vec operator /(const Vec &a, double c) { int n = a.length(); Vec vout(n); for (int i=0; i<n; i++) vout[i] = a[i]/c; return vout; } double *vector(int n) { double *v; v = new double[n]; assert(v); return v; } int *ivector(int n) { int *iv; iv = new int[n]; assert(iv); return iv; } void Matrix::print() const { int i, j; const double tiny = 1e-13; double *vp; double v; for (j=0; j<nrows; j++) { vp = body[j]; for (i=0; i<ncols; i++) { v = *vp++; if (fabs(v)<tiny) v = 0.0; printf("% 10.4g", v); } printf("\n"); } } void Vec::print() const { double *v = body; int size = n; while (size--) { printf(" %10.4g", *v++); } printf("\n"); } //! copy one Matrix to another /*! * @param dst destination Matrix * @param src source Matrix * if destination is smaller than the source, the source is truncated.\n * if destination is larger than the source, the remainder is * zero-filled\n */ void copy_matrix(Matrix &dst, Matrix &src) { int i, j; int nrows, ncols; double *s, *t;; nrows = (dst.rows()<src.rows()? dst.rows(): src.rows()); ncols = (dst.cols()<src.cols()? dst.cols(): src.cols()); for (j=0; j<nrows; j++) { s = src[j]; t = dst[j]; for (i=0; i<ncols; i++) *t++ = *s++; } // Append zero-filled rows to destination for (j=src.rows(); j<nrows; j++) { t = dst[j]; for (i=0; i<ncols; i++) t[i] = 0.0; } // Append zero-filled columns to destination if (src.cols() < ncols) { for (j=0; j<dst.rows(); j++) { t = dst[j]; for (i=src.cols(); i<ncols; i++) t[i] = 0.0; } } } // overloaded insertion operator << std::ostream& operator << (std::ostream& s, const Vec& v) { char buf[16]; int n = v.length(); if (n > 0) { //int old_precision = s.precision() ; // get current precision s << "[" ; for (int i=0; i<n; i++) { sprintf_s(buf,15,"%.4g",v[i]); //s << setprecision (2) //<< setiosflags (ios_base::showpoint|ios_base::fixed) s << buf ; i!=n-1 ? s << ", " : s << "]" ; } //s << endl ; // reset precision and ios flags //s.precision (old_precision) ; //std::resetiosflags (ios::showpoint|std::ios::fixed) ; } return s ; }
main.cpp
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <iostream> #include "matrix.h" using namespace std; //! Tests operation of vector/matrix classes int main() { Matrix G(5,3); Vec a(3), b(3); int i, j; for (i=0; i<3; i++) { a[i] = i+1; b[i] = i-1; } printf("vector a =\n"); a.print(); cout << a << endl; printf("vector b =\n"); b.print(); Vec c = a+b; //vec::add(a,b); printf("vector a + b =\n"); c.print(); c = a; // copy vector to c a[0] = 4; printf("element by element sqrt:\n"); c.apply(sqrt).print(); printf("a dot b = %g\n",Vec::dot(a,b)); for (j=0; j<G.cols(); j++) { for (i=0; i<G.rows(); i++) G[i][j] = (i+1)*10 + (j+1); } printf("matrix G =\n"); G.print(); Vec d = G*b; // Matrix::mul(G,b); printf("G*b = \n"); cout << d << endl; printf("matrix %d x %d\n",G.rows(),G.cols()); Vec e(5); for (i=0; i<5; i++) e[i]=i-2; printf("vector e = \n"); cout << e << endl; Vec f = e*G; //Matrix::mul(e,G); printf("e*G =\n"); cout << f << endl; return EXIT_SUCCESS; }
C:\classes\ece538\Matrix1\Matrix>main vector a = 1 2 3 [1, 2, 3] vector b = -1 0 1 vector a + b = 0 2 4 element by element sqrt: 1 1.414 1.732 a dot b = -1 matrix G = 11 12 13 21 22 23 31 32 33 41 42 43 51 52 53 G*b = [2, 2, 2, 2, 2] matrix 5 x 3 vector e = [-2, -1, 0, 1, 2] e*G = [100, 100, 100]
Maintained by John Loomis, updated Wed Feb 07 22:46:23 2007