Creating the matrix class

by Trent Guidry20. June 2009 11:36
What I want to do is create a C# matrix class. This post will be about creating the matrix, cloning it, transposing it, creating an identity matrix, and converting a matrix to and from an array. Other details, such as matrix addition, subtraction, multiplication, scalar multiplication, matrix equation solution through LU decomposition with pivoting (LUP), and matrix inversion will be added in latter posts of this series.
 
The focus of this post will be on implementation of a matrix in C#, I will basically assume that the reader already knows what a matrix is. For those looking for an introduction to matrices, the Wikipedia article Matrix (mathematics) is pretty decent.
While WPF has a System.Windows.Media.Matrix and a System.Windows.Media.Media3D.Matrix3D structure, that really isn’t what I am after here. Those classes are specialized for certain WPF scenarios, for example, both of those classes are fixed in dimensions, 3x3 for Matrix and 4x4 for Matrix3D and can’t be used for a general NxM matrix.
To start with, I created a WPF project to host and test the matrix class and added a class that to represent a matrix.
Two of the properties of a matrix are the number of rows and the number of columns. I will store these values in integers called _rowCount and _columnCount and I will default both of them to 3. I also need to store the actual value of the matrix at a given row and column. I will store those in a two dimensional double array called _values. I also need constructors for the class. The default constructor will just create a 3x3 matrix. I will also create a construction that takes two integers which are used to specify the number of rows and columns of that matrix. Both constructors create the two dimensional array that stores the matrix values. I also added two read only public properties to read the number of rows and columns in the matrix.
I also need a way of reading and writing values for a given row and column, for this I overloaded the indexer of the class so that I can access the matrix values via instance[Row Number, Column Number]. I am using 0 based rows and columns as opposed to 1 based rows and columns because C# uses 0 based arrays.
After doing that, I have the code shown below.
public class Matrix{#region ctorpublic Matrix(){_values = new double[_rowCount, _columnCount];}public Matrix(int rowCount, int columnCount){_rowCount = rowCount;_columnCount = columnCount;_values = new double[_rowCount, _columnCount];}#endregion#region Row Column valuespublic double this[int row, int column]{get { return _values[row, column]; }set { _values[row, column] = value; }}#endregion#region F&Pprivate double[,] _values;private int _rowCount = 3;public int RowCount{get { return _rowCount; }}private int _columnCount = 3;public int ColumnCount{get { return _columnCount; }}#endregion}
The next thing I want to do be able to do with a matrix is to be able to clone it and produce a copy of it. The code for that is shown below.
public Matrix Clone(){Matrix resultMatrix = new Matrix(_rowCount, _columnCount);for (int i = 0; i < _rowCount; i++){for (int j = 0; j < _columnCount; j++){resultMatrix[i, j] = this[i, j];}}return resultMatrix;}
This is a pretty straightforward function. I create a new matrix with the same number of rows and columns as the current matrix and copy the current matrix’s values into the copy. I then return the copy.
 
Another thing I want to be able to do is create an identity matrix. An identity matrix is basically a matrix with all ones in the diagonal and zeroes everywhere else. There is more information about identity matrices on Wikipedia Identity matrix and Wolfram MathWorld Identity Matrix. The code for doing this is shown below:
public static Matrix Identity(int size){Matrix resultMatrix = new Matrix(size, size);for (int i = 0; i < size; i++){for (int j = 0; j < size; j++){resultMatrix[i, j] = (i == j) ? 1.0 : 0.0;}}return resultMatrix;}
This is also a rather simple function. It is a static function where I pass into it the size of the identity matrix that I want to create. I use that size to create a matrix with that many rows and columns and then iterate over the rows and columns. If the row number is equal to the column number, I set the value to 1, otherwise, I set it to 0.
 
The next thing I want to be able to do with a matrix is to be able to transpose it. If you are unfamiliar with transposing a matrix, there is a link on Wikipedia Transpose and Wolfram MathWorld Transpose. The code for doing this is shown below:
public Matrix Transpose(){Matrix resultMatrix = new Matrix(_columnCount, _rowCount);for (int i = 0; i < _rowCount; i++){for (int j = 0; j < _columnCount; j++){resultMatrix[j, i] = this[i, j];}}return resultMatrix;}
This code is also fairly simple. I create a new matrix with the number of rows and columns reversed from the current matrix. I then iterate over the rows and columns and put them into the copy in reverse order. The copy is then returned.
 
I also want to be able to take an array of doubles and convert it into an Mx1 matrix. The code for doing that is shown below:
public static Matrix FromArray(double[] left){int length = left.Length;Matrix resultMatrix = new Matrix(length, 1);for (int i = 0; i < length; i++){resultMatrix[i, 0] = left[i];}return resultMatrix;}public static implicit operator Matrix(double[] left){return FromArray(left);}
The static function FromArray takes an array of doubles. It checks the length of the array and creates a matrix of that length x 1. It then copies the values from the array into the new matrix and returns the matrix. I also added an implicit converter so that double arrays can automatically be converted into matrices. This converter just calls the FromArray function.
 
Another thing that I want to be able to do with an Mx1 or 1xM matrix is to convert it into an array of doubles.
The code for that is shown below:
public static double[] ToArray(Matrix leftMatrix){Debug.Assert((leftMatrix.ColumnCount == 1 && leftMatrix.RowCount >= 1) || (leftMatrix.RowCount == 1 && leftMatrix.ColumnCount >= 1));double[] result = null;if (leftMatrix.ColumnCount > 1){int numElements = leftMatrix.ColumnCount;result = new double[numElements];for (int i = 0; i < numElements; i++){result[i] = leftMatrix[0, i];}}else{int numElements = leftMatrix.RowCount;result = new double[numElements];for (int i = 0; i < numElements; i++){result[i] = leftMatrix[i, 0];}}return result;}public static implicit operator double[](Matrix leftMatrix){return ToArray(leftMatrix);}
The static function ToArray takes a matrix as its argument. It checks to ensure that it is an Mx1 or a 1xN matrix, otherwise converting to an array of doubles doesn’t really make sense. It then creates a new double array and copies the values of the matrix into it. I also added an implicit converter so that matrices can automatically be converted into double arrays. This converter just calls the ToArray function.
 
I also want to be able to convert an MxN double array into an MxN matrix. The code to do this is shown below:
public static Matrix FromDoubleArray(double[,] left){int length0 = left.GetLength(0);int length1 = left.GetLength(1);Matrix resultMatrix = new Matrix(length0, length1);for (int i = 0; i < length0; i++){for (int j = 0; j < length1; j++){resultMatrix[i, j] = left[i, j];}}return resultMatrix;}public static implicit operator Matrix(double[,] left){return FromDoubleArray(left);}
The static function FromDoubleArray takes a two dimensional double array as its argument. It then creates a new matrix and copies the values of the two dimensional double array into it. I also added an implicit converter so that two dimensional double arrays can automatically be converted into matrices. This converter just calls the FromDoubleArray function.
 
Another thing I might want to be able to do with a matrix is to convert it from an MxN matrix into an MxN double array. The code to do this is shown below:
public static double[,] ToDoubleArray(Matrix leftMatrix){double[,] result = new double[leftMatrix.RowCount, leftMatrix.ColumnCount];for (int i = 0; i < leftMatrix.RowCount; i++){for (int j = 0; j < leftMatrix.ColumnCount; j++){result[i, j] = leftMatrix[i, j];}}return result;}public static implicit operator double[,](Matrix leftMatrix){return ToDoubleArray(leftMatrix);}
The static function ToDoubleArray takes a matrix as its argument. It then creates a new two dimensional double array and copies the values of the matrix into it. I also added an implicit converter so that matrices can automatically be converted into two dimensional double arrays. This converter just calls the ToDoubleArray function.
 
This post is getting rather long, so I will save adding more features to the matrix class for the future, where I am planning on adding matrix addition, subtraction, multiplication, scalar multiplication, solution of matrix equations using LU decomposition with pivoting (LUP), and matrix inversion.
The full code for the matrix class at this point is given below.
using System.Diagnostics;namespace NumericalMethods.FirstBlog
{public class Matrix{#region ctorpublic Matrix(){_values = new double[_rowCount, _columnCount];}public Matrix(int rowCount, int columnCount){_rowCount = rowCount;_columnCount = columnCount;_values = new double[_rowCount, _columnCount];}#endregion#region Row Column valuespublic double this[int row, int column]{get { return _values[row, column]; }set { _values[row, column] = value; }}#endregion#region F&Pprivate double[,] _values;private int _rowCount = 3;public int RowCount{get { return _rowCount; }}private int _columnCount = 3;public int ColumnCount{get { return _columnCount; }}#endregion#region basic single matrix stuffpublic static Matrix Identity(int size){Matrix resultMatrix = new Matrix(size, size);for (int i = 0; i < size; i++){for (int j = 0; j < size; j++){resultMatrix[i, j] = (i == j) ? 1.0 : 0.0;}}return resultMatrix;}public Matrix Clone(){Matrix resultMatrix = new Matrix(_rowCount, _columnCount);for (int i = 0; i < _rowCount; i++){for (int j = 0; j < _columnCount; j++){resultMatrix[i, j] = this[i, j];}}return resultMatrix;}public Matrix Transpose(){Matrix resultMatrix = new Matrix(_columnCount, _rowCount);for (int i = 0; i < _rowCount; i++){for (int j = 0; j < _columnCount; j++){resultMatrix[j, i] = this[i, j];}}return resultMatrix;}#endregion#region Assorted Castspublic static Matrix FromArray(double[] left){int length = left.Length;Matrix resultMatrix = new Matrix(length, 1);for (int i = 0; i < length; i++){resultMatrix[i, 0] = left[i];}return resultMatrix;}public static implicit operator Matrix(double[] left){return FromArray(left);}public static double[] ToArray(Matrix leftMatrix){Debug.Assert((leftMatrix.ColumnCount == 1 && leftMatrix.RowCount >= 1) || (leftMatrix.RowCount == 1 && leftMatrix.ColumnCount >= 1));double[] result = null;if (leftMatrix.ColumnCount > 1){int numElements = leftMatrix.ColumnCount;result = new double[numElements];for (int i = 0; i < numElements; i++){result[i] = leftMatrix[0, i];}}else{int numElements = leftMatrix.RowCount;result = new double[numElements];for (int i = 0; i < numElements; i++){result[i] = leftMatrix[i, 0];}}return result;}public static implicit operator double[](Matrix leftMatrix){return ToArray(leftMatrix);}public static Matrix FromDoubleArray(double[,] left){int length0 = left.GetLength(0);int length1 = left.GetLength(1);Matrix resultMatrix = new Matrix(length0, length1);for (int i = 0; i < length0; i++){for (int j = 0; j < length1; j++){resultMatrix[i, j] = left[i, j];}}return resultMatrix;}public static implicit operator Matrix(double[,] left){return FromDoubleArray(left);}public static double[,] ToDoubleArray(Matrix leftMatrix){double[,] result = new double[leftMatrix.RowCount, leftMatrix.ColumnCount];for (int i = 0; i < leftMatrix.RowCount; i++){for (int j = 0; j < leftMatrix.ColumnCount; j++){result[i, j] = leftMatrix[i, j];}}return result;}public static implicit operator double[,](Matrix leftMatrix){return ToDoubleArray(leftMatrix);}#endregion}
}