Matrix class in C++

Back to Home

Introduction:

Matrix is a simple c++ program including operations and functions for matrices.

The program is a modified version of Matrix class by Jos de Jong.

It supports operators: + - * / and output operator <<

It supports functions: Ones, Zeros, Diag.

About:

matrix program modified by Hamid Soltani. (gmail: hsoltanim)

Code:

Download matrix.cpp

/*
A simple matrix class
c++ code
Author: Jos de Jong, Nov 2007. Updated March 2010
Modified by by Hamid Soltani. (gmail: hsoltanim)
<< opeator added, Inv function improved, some minor changes
https://csvparser.github.io/
Last modified: Aug. 2016.

With this class you can:
- create a 2D matrix with custom size
- get/set the cell values
- use operators +, -, *, /
- use functions Ones(), Zeros(), Diag(), Inv()
- print the content of the matrix

Usage:
you can create a matrix by:
Matrix A;
Matrix A = Matrix(rows, cols);
Matrix A = B;

you can get and set matrix elements by:
A(2,3) = 5.6;    // set an element of Matix A
value = A(3,1);   // get an element of Matrix A
value = A.get(3,1); // get an element of a constant Matrix A
A = B;        // copy content of Matrix B to Matrix A

you can apply operations with matrices and doubles:
A = B + C;
A = B - C;
A = -B;
A = B * C;
A = B / C;

the following functions are available:
A = Ones(rows, cols);
A = Zeros(rows, cols);
A = Diag(n);
A = Diag(B);
A = Inv(B);
cols = A.GetCols();
rows = A.GetRows();

you can quick-print the content of a matrix with << operator
*/

#include "stdafx.h"

#include < cstdlib >
#include < cstdio >
#include < math.h >

#include < iostream >
#include < iomanip > 
#include < limits >
using namespace std;

// Declarations
class Matrix;
static double lastDet; // Determinant computed by Inv function
Matrix Diag(const int n); 
Matrix Diag(const Matrix& v);
Matrix Inv(const Matrix& a);
Matrix Ones(const int rows, const int cols);
int Size(const Matrix& a, const int i);
Matrix Zeros(const int rows, const int cols);


/*
 * a simple exception class
 * you can create an exeption by entering: throw Exception("...Error description...");
 * and get the error message from the data msg for displaying: err.msg
 */
class Exception
{
public:
	const char* msg;
	Exception(const char* arg) : msg(arg) {	}
};


class Matrix
{
private:
	int rows;
	int cols;
	double** p;     // pointer to a matrix with doubles

public:
	// constructor
	Matrix()
	{
		p = NULL;
		rows = 0;
		cols = 0;
	}

	// constructor
	Matrix(const int row_count, const int column_count)
	{
		// create a Matrix object with given number of rows and columns
		p = NULL;

		if (row_count > 0 && column_count > 0)
		{
			rows = row_count;
			cols = column_count;

			p = new double*[rows];
			for (int r = 0; r < rows; r++)
			{
				p[r] = new double[cols];

				// initially fill in zeros for all values in the matrix;
				for (int c = 0; c < cols; c++)
					p[r][c] = 0;
			}
		}
	}

	// assignment operator
	Matrix(const Matrix& a)
	{
		rows = a.rows;
		cols = a.cols;
		p = new double*[a.rows];
		for (int r = 0; r < a.rows; r++)
		{
			p[r] = new double[a.cols];

			// copy the values from the matrix a
			for (int c = 0; c < a.cols; c++)
				p[r][c] = a.p[r][c];
		}
	}

	// index operator. You can use this class like myMatrix(col, row)
	// the indexes are one-based, not zero based.
	double& operator()(const int r, const int c)
	{
		if (p != NULL && r > 0 && r <= rows && c > 0 && c <= cols)
			return p[r - 1][c - 1];
		else
			throw Exception("Subscript out of range");
	}

	// index operator. You can use this class like myMatrix.get(col, row)
	// the indexes are one-based, not zero based.
	// use this function get if you want to read from a const Matrix
	double get(const int r, const int c) const
	{
		if (p != NULL && r > 0 && r <= rows && c > 0 && c <= cols)
			return p[r - 1][c - 1];
		else
			throw Exception("Subscript out of range");
	}

	// assignment operator
	Matrix& operator= (const Matrix& a)
	{
		rows = a.rows;
		cols = a.cols;
		p = new double*[a.rows];
		for (int r = 0; r < a.rows; r++)
		{
			p[r] = new double[a.cols];

			// copy the values from the matrix a
			for (int c = 0; c < a.cols; c++)
				p[r][c] = a.p[r][c];
		}
		return *this;
	}

	// add a double value (elements wise)
	Matrix& Add(const double v)
	{
		for (int r = 0; r < rows; r++)
			for (int c = 0; c < cols; c++)
				p[r][c] += v;
		return *this;
	}

	// subtract a double value (elements wise)
	Matrix& Subtract(const double v)
	{
		return Add(-v);
	}

	// multiply a double value (elements wise)
	Matrix& Multiply(const double v)
	{
		for (int r = 0; r < rows; r++)
			for (int c = 0; c < cols; c++)
				p[r][c] *= v;
		return *this;
	}

	// divide a double value (elements wise)
	Matrix& Divide(const double v)
	{
		return Multiply(1 / v);
	}

	// addition of Matrix with Matrix
	friend Matrix operator+(const Matrix& a, const Matrix& b)
	{
		// check if the dimensions match
		if (a.rows == b.rows && a.cols == b.cols)
		{
			Matrix res(a.rows, a.cols);

			for (int r = 0; r < a.rows; r++)
				for (int c = 0; c < a.cols; c++)
					res.p[r][c] = a.p[r][c] + b.p[r][c];
			return res;
		}
		else	
			throw Exception("Dimensions does not match");

		// return an empty matrix (this never happens but just for safety)
		return Matrix();
	}

	// addition of Matrix with double
	friend Matrix operator+ (const Matrix& a, const double b)
	{
		Matrix res = a;
		res.Add(b);
		return res;
	}
	// addition of double with Matrix
	friend Matrix operator+ (const double b, const Matrix& a)
	{
		Matrix res = a;
		res.Add(b);
		return res;
	}

	// subtraction of Matrix with Matrix
	friend Matrix operator- (const Matrix& a, const Matrix& b)
	{
		// check if the dimensions match
		if (a.rows == b.rows && a.cols == b.cols)
		{
			Matrix res(a.rows, a.cols);

			for (int r = 0; r < a.rows; r++)
				for (int c = 0; c < a.cols; c++)
					res.p[r][c] = a.p[r][c] - b.p[r][c];
			return res;
		}
		else
			throw Exception("Dimensions does not match");

		// return an empty matrix (this never happens but just for safety)
		return Matrix();
	}

	// subtraction of Matrix with double
	friend Matrix operator- (const Matrix& a, const double b)
	{
		Matrix res = a;
		res.Subtract(b);
		return res;
	}
	// subtraction of double with Matrix
	friend Matrix operator- (const double b, const Matrix& a)
	{
		Matrix res = -a;
		res.Add(b);
		return res;
	}

	// operator unary minus
	friend Matrix operator- (const Matrix& a)
	{
		Matrix res(a.rows, a.cols);

		for (int r = 0; r < a.rows; r++)
			for (int c = 0; c < a.cols; c++)
				res.p[r][c] = -a.p[r][c];

		return res;
	}

	// operator multiplication
	friend Matrix operator* (const Matrix& a, const Matrix& b)
	{
		// check if the dimensions match
		if (a.cols == b.rows)
		{
			Matrix res(a.rows, b.cols);

			for (int r = 0; r < a.rows; r++)
				for (int c_res = 0; c_res < b.cols; c_res++)
					for (int c = 0; c < a.cols; c++)
						res.p[r][c_res] += a.p[r][c] * b.p[c][c_res];

			return res;
		}
		else
			throw Exception("Dimensions does not match");

		// return an empty matrix (this never happens but just for safety)
		return Matrix();
	}

	// multiplication of Matrix with double
	friend Matrix operator* (const Matrix& a, const double b)
	{
		Matrix res = a;
		res.Multiply(b);
		return res;
	}
	// multiplication of double with Matrix
	friend Matrix operator* (const double b, const Matrix& a)
	{
		Matrix res = a;
		res.Multiply(b);
		return res;
	}

	// division of Matrix with Matrix
	friend Matrix operator/ (const Matrix& a, const Matrix& b)
	{
		// check if the dimensions match: must be square and equal sizes
		if (a.rows == a.cols && a.rows == a.cols && b.rows == b.cols)
		{
			Matrix res(a.rows, a.cols);

			res = a * Inv(b);

			return res;
		}
		else
			throw Exception("Dimensions does not match");

		// return an empty matrix (this never happens but just for safety)
		return Matrix();
	}

	// division of Matrix with double
	friend Matrix operator/ (const Matrix& a, const double b)
	{
		Matrix res = a;
		res.Divide(b);
		return res;
	}

	// division of double with Matrix
	friend Matrix operator/ (const double b, const Matrix& a)
	{
		Matrix b_matrix(1, 1);
		b_matrix(1, 1) = b;

		Matrix res = b_matrix / a;
		return res;
	}

	// returns the number of rows
	int GetRows() const
	{
		return rows;
	}

	// returns the number of columns
	int GetCols() const
	{
		return cols;
	}

	// output operator
	friend ostream& operator<<(ostream& os, const Matrix& M)
	{
		if (M.p != NULL)
			for (int r = 0; r < M.rows; r++)
				for (int c = 0; c < M.cols; c++)
					os << ((c==0) ? ((r == 0) ? "[" : " ") : "")
					   << setw(10) << setprecision(4) << M.p[r][c] 
					   << ((c == M.cols - 1) ? ((r == M.rows - 1) ? "]" : ";\n") : ",");
		else
			os << "[ ]";
		return os;
	}

public:
	// destructor
	~Matrix()
	{
		// clean up allocated memory
		for (int r = 0; r < rows; r++)
		{
			delete p[r];
		}
		delete p;
		p = NULL;
	}

};

/**
* returns a matrix with size cols x rows with ones as values
*/
Matrix Ones(const int rows, const int cols)
{
	Matrix res = Matrix(rows, cols);

	for (int r = 1; r <= rows; r++)
		for (int c = 1; c <= cols; c++)
			res(r, c) = 1;

	return res;
}

/**
* returns a matrix with size cols x rows with zeros as values
*/
Matrix Zeros(const int rows, const int cols)
{
	return Matrix(rows, cols);
}


/**
* returns a diagonal matrix with size n x n with ones at the diagonal
* @param  v a vector
* @return a diagonal matrix with ones on the diagonal
*/
Matrix Diag(const int n)
{
	Matrix res = Matrix(n, n);
	for (int i = 1; i <= n; i++)
		res(i, i) = 1;
	return res;
}

/**
* returns a diagonal matrix
* @param  v a vector
* @return a diagonal matrix with the given vector v on the diagonal
*/
Matrix Diag(const Matrix& v)
{
	Matrix res;
	if (v.GetCols() == 1)
	{
		// the given matrix is a vector n x 1
		int rows = v.GetRows();
		res = Matrix(rows, rows);

		// copy the values of the vector to the matrix
		for (int r = 1; r <= rows; r++)
			res(r, r) = v.get(r, 1);
	}
	else if (v.GetRows() == 1)
	{
		// the given matrix is a vector 1 x n
		int cols = v.GetCols();
		res = Matrix(cols, cols);

		// copy the values of the vector to the matrix
		for (int c = 1; c <= cols; c++)
			res(c, c) = v.get(1, c);
	}
	else
		throw Exception("Parameter for diag must be a vector");
	return res;
}

// swap two values
void Swap(double& a, double& b)
{
	double temp = a;
	a = b;
	b = temp;
}

/*
* returns the inverse of Matrix a, stores determinent in DT
*/
Matrix Inv(const Matrix& a, double& DT)
{
	Matrix res;
	int rows = a.GetRows();
	int cols = a.GetRows();

	if (rows != cols)
	{
		throw Exception("Matrix must be square");
		return res;
	}
	// this is a matrix of 3 x 3 or larger
	// calculate inverse using gauss-jordan elimination
	//   http://mathworld.wolfram.com/MatrixInverse.html
	//   http://math.uww.edu/~mcfarlat/inverse.htm
	res = Diag(rows);   // a diagonal matrix with ones at the diagonal
	Matrix ai = a;    // make a copy of Matrix a
	DT = 1;
	for (int c = 1; c <= cols; c++)
	{
		// element (c, c) should be non zero. if not, swap content
		// of lower rows
		int r;
		for (r = c; r <= rows && ai(r, c) == 0; r++) {	}
		if (r >rows)
		{
			DT = 0;
			throw Exception("Determinant of matrix is zero");
			return res;
		}
		if (r != c)
		{
			// swap rows
			for (int s = 1; s <= cols; s++)
			{
				Swap(ai(c, s), ai(r, s));
				Swap(res(c, s), res(r, s));
			}
		}

		// eliminate non-zero values on the other rows at column c
		for (int r = 1; r <= rows; r++)
		{
			if (r != c)
			{
				// eleminate value at column c and row r
				if (ai(r, c) != 0)
				{
					double f = -ai(r, c) / ai(c, c);

					// add (f * row c) to row r to eleminate the value
					// at column c
					for (int s = 1; s <= cols; s++)
					{
						ai(r, s) += f * ai(c, s);
						res(r, s) += f * res(c, s);
					}
				}
			}
			else
			{
				// make value at (c, c) one,
				// divide each value on row r with the value at ai(c,c)
				double f = ai(c, c);
				DT *= f;
				for (int s = 1; s <= cols; s++)
				{
					ai(r, s) /= f;
					res(r, s) /= f;
				}
			}
		}
	}
	return res;
}
/*
* returns the inverse of Matrix a, stores determinent in lastDet
*/
Matrix Inv(const Matrix& a)
{
	return Inv(a, lastDet);
}

int main(int argc, char *argv[])
{
	// below some demonstration of the usage of the Matrix class
	try
	{
		// create an empty matrix of 3x3 (will initially contain zeros)
		int cols = 3;
		int rows = 3;
		Matrix A = Matrix(cols, rows);

		// fill in some values in matrix a
		int count = 0;
		for (int r = 1; r <= rows; r++)
			for (int c = 1; c <= cols; c++)
				A(r, c) = ++count;

		// adjust a value in the matrix (indexes are one-based)
		A(2, 1) = 1.23;

		// print the whole matrix
		cout << "A= \n" << A << "\n";

		Matrix B = Ones(rows, cols) + Diag(rows);
		cout << "B= \n" << B << "\n";

		Matrix B2 = Matrix(rows, 1);    // a vector
		count = 1;
		for (int r = 1; r <= rows; r++)
			B2(r, 1) = ++count * 2;
		cout << "B2= \n" << B2 << "\n";

		cout << "A + B= \n" << A + B << "\n";
		cout << "A - B= \n" << A - B << "\n";
		cout << "A * B2= \n" << A * B2 << "\n";

		cout << "Diag. B2= \n" << Diag(B2) << "\n";

		cout << "A= \n" << A << "\n";
		cout << "3 - A= \n" << 3 - A << "\n";
		Matrix A_inv = Inv(A);
		cout << "Inv(A)= \n" << A_inv << "\n";
		cout << "Det(A)=" << lastDet << "\n";
		cout << "A * Inv(A)= \n" << A * Inv(A) << "\n";

		cout << "B / A = \n" << B / A << "\n";
		cout << "A / 3 = \n" << A / 3 << "\n";

		rows = 2;
		cols = 5;
		Matrix H = Matrix(rows, cols);
		for (int r = 1; r <= rows; r++)
			for (int c = 1; c <= cols; c++)
				H(r, c) = ++count;
		cout << "H= \n" << H << "\n";

		int test = 1000;
		int band = 20;
		cout << "\n\nCreating a " << test << "*" << test
			<< " Matrix with " << 2 * band + 1
			<< " non-zero middle elements at each row, please wait...";

		Matrix M = Matrix(test, test);
		for (int i = 1;i <= test;i++)
		{
			int a = (i <= band) ? 1 : i - band;
			int b = (i > test - band) ? test : i + band;
			for (int j = a;j <= b;j++)
				M(i, j) = 1.0 + rand() % 10;
		}
		cout << "\n\nComputing Inv M, please wait...";
		Matrix MI = Inv(M);
		cout << "\n\nComputing M*Inv M, please wait...";
		Matrix MMI = M*Inv(M);

		double e1 = 1e300;
		double d1 = e1;
		double e2 = -e1;
		double d2 = e2;
		for (int i = 1; i <= test;i++)
			for (int j = 1; j <= test;j++)
				if (i == j)
				{
					if (d1 > MMI(i, j)) d1 = MMI(i, j);
					if (d2 < MMI(i, j)) d2 = MMI(i, j);
				} else {
					if (e1 > MMI(i, j)) e1 = MMI(i, j);
					if (e2 < MMI(i, j)) e2 = MMI(i, j);
				}
		typedef numeric_limits< double > dbl;
		cout  << setprecision (dbl::max_digits10)
			<< "\n\nDiagonal elements ranging from " << d1 << " to " << d2
			<< "\nNon-diagonal elements ranging from " << e1 << " to " << e2;
	}
	catch (Exception err)
	{
		cout << "Error: %s\n" << err.msg;
	}
	catch (...)
	{
		cout << "An error occured...\n";
	}

	cout << "\n\nPress Enter to exit...\n";
	getchar();

	return EXIT_SUCCESS;
}