Serge's World

Blogging about software development, astronomy, genealogy and more.

Matrices

Matrices are a very useful thing in computer programming, especially in 3D graphics programming. Out of all the mathematics I learned at University, matrices are the one thing that keep rearing their head over and over.

I am not going to go into major detail over what a matrix is - wikipedia can tell you that much better than I can - so will focus mainly on how to implement one in C#.

Essentially, a matrix is a 2-dimensional array of numbers, often representing a set of equations. The number of columns and rows is flexible.

Using the Matrix class below, the constructor can either take an x and y value or an array to determine how big to make the internal array for the matrix.

The Zero() function sets all entries in the matrix to zero by looping through the entire array.

The SetIdentity() function makes the matrix an identity matrix, which means that all the values are 0, except for the values along the diagonal from top left to bottom right being set to 1.

The Transpose function transforms the columns of the matrix into the rows, and vice versa.

The Scale function multiplies each value in the matrix by a scaling factor.

The determinant of an array is found by adding all the products of the entries of each diagonal sloping in a right direction, and subtracting the products of the entries of each diagonal sloping in a opposite direction. This is done with the Determinant function

The Trace function returns the sum of the main diagonal of the matrix.

The matrix class has also got a few overloaded operators, to make handling matrices easier.

The + operator is overloaded so that when passed two matrices, each value in the one matrix is added to the equivalent value in the second matrix. Both matrices need to be the same size for this to work.

A second overload for the + operator takes a scalar value and adds it to the matrix, which just adds that value to each value in the matrix.

The - operator performs identically to the + operator, except that it subtracts instead of adds the matrices.

The** * **operator multiplies the two matrices together, which is a little more involved than addition.

namespace MathLib
{
    public class Matrix
    {
        public double[,] Values;
        public int Cols;
        public int Rows;

        public Matrix(int X, int Y)
        {
            Cols = X;
            Rows = Y;
            Values = new double[Rows, Cols];
            Zero();
        }

        public Matrix(double[,] values)
        {
            Values = values;
            Cols = Values.GetLength(1);
            Rows = Values.GetLength(0);
        }

        public void Zero()
        {
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    Values[i, j] = 0;
                }
            }
        }
        public void SetIdentity()
        {
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    if (i == j)
                    {
                        Values[i, j] = 1;
                    }
                    else
                    {
                        Values[i, j] = 0;
                    }
                }
            }
        }
        public Matrix Transpose()
        {
            double[,] values = new double[Cols, Rows];
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    values[j, i] = Values[i, j];
                }
            }
            return new Matrix(values);
        }

        public Matrix Scale(double factor)
        {
            double[,] values = new double[Rows, Cols];
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    values[i, j] = factor * Values[i, j];
                }
            }
            return new Matrix(values);
        }

        public double Determinant()
        {
            double determinant = 0;
            int colIndex = 0;
            double value = 1;
            int k;
            for (int i = 0; i < Cols; i++)
            {
                k = 0;
                value = 1;
                for (int j = 0; j < Cols; j++)
                {
                    colIndex = (i + j) % 3;
                    value *= Values[colIndex, k];
                    k++;
                }
                determinant += value;
            }
            for (int i = 0; i < Cols; i++)
            {
                k = 0;
                value = 1;
                for (int j = Cols-1; j >= 0; j--)
                {
                    colIndex = (i + j) % 3;
                    value *= Values[colIndex, k];
                    k++;
                }
                determinant -= value;
            }

            return determinant;
        }
        public double Trace()
        {
            if (Rows != Cols)
            {
                return 0;
            }
            double trace = 0;
            for (int i = 0; i < Rows; i++)
            {

               trace += Values[i, i];
            }
            return trace;            
        }

        public override string ToString()
        {
            string sStr = "";
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    sStr += Values[i, j].ToString() + ",";
                }
                sStr += Environment.NewLine;
            }
            return sStr;
        }

        public static Matrix operator +(Matrix left, Matrix right)
        {
            if ((left.Cols != right.Cols) || (left.Rows != right.Rows))
            {
                return left;
            }
            double[,] values = new double[left.Rows, left.Cols];

            for (int i = 0; i < left.Rows; i++)
            {
                for (int j = 0; j < left.Cols; j++)
                {
                    values[i,j] = left.Values[i,j] + right.Values[i,j];
                }
            }
            return (new Matrix(values));
        }

        public static Matrix operator +(double left, Matrix right)
        {
            double[,] values = new double[right.Rows, right.Cols];

            for (int i = 0; i < right.Rows; i++)
            {
                for (int j = 0; j < right.Cols; j++)
                {
                    values[i, j] = left + right.Values[i, j];
                }
            }
            return (new Matrix(values));
        }

        public static Matrix operator -(Matrix left, Matrix right)
        {
            if ((left.Cols != right.Cols) || (left.Rows != right.Rows))
            {
                return left;
            }
            double[,] values = new double[left.Cols, left.Rows];

            for (int i = 0; i < left.Rows; i++)
            {
                for (int j = 0; j < left.Cols; j++)
                {
                    values[i, j] = left.Values[i, j] - right.Values[i, j];
                }
            }
            return (new Matrix(values));
        }

        public static Matrix operator *(Matrix left, Matrix right)
        {
            double[,] values = new double[left.Rows, right.Cols];

            for (int h = 0; h < left.Rows; h++)
            {
                for (int i = 0; i < right.Cols; i++)
                {
                    for (int j = 0; j < left.Cols; j++)
                    {
                            values[h, i] += left.Values[h, j] * right.Values[j, i];
                    }
                }
            }
            return (new Matrix(values));
        }

    }
}

The full sourcecode for the MathLib library is available at https://github.com/sjmeunier/mathlib

Originally posted on my old blog, Smoky Cogs, on 23 Oct 2009

Updated 5 Oct 2016: Updated code snippet after refactoring MathLib library

Tag Cloud

Algorithms (3) Android (10) Astronomy (25) Audio (1) Audiobooks (1) Barcodes (9) C# (69) Css (1) Deep sky (6) Esoteric languages (3) Family (3) Fractals (10) Gaming (1) Genealogy (14) General (2) Geodesy (3) Google (1) Graphics (3) Hubble (2) Humour (1) Image processing (23) Java (8) Javascript (5) jQuery (3) Jupiter (3) Maths (22) Moon (5) Music (4) Pets (5) Programming (88) Saturn (1) Science (1) Spitzer (4) Sun (4) Tutorials (68) Unity (3) Web (9) Whisky (13) Windows (1) Xamarin (2)