3

I am writing a method that will calculate the determinant of a matrix (here, a two-dimensional array) containing doubles. Here is what I've written:

/// <summary>
/// Checks to see if a matrix is square, and then computes its determinant
/// </summary>
/// <returns></returns>
public double Determinant()
{
    // Check to make sure the matrix is square.  Only square matrices 
    // have determinants.
    if (!this.isSquare())
    {
        throw new Exception("The matrix does not have a determinant");
    }

    // Check to see if the matrix has dimensions 1x1.  
    // The determinant of a 1x1 matrix is equal to the value stored at (0,0).
    if (this.NumberOfRows == 1)
    {
        return this.GetElement(0, 0);
    }

    double determinant = 0;

    // Loop through the top row of the matrix.
    for (int columnIndex = 0; columnIndex < this.NumberOfColumns; columnIndex++)
    {
        Matrix cofactor = new Matrix(this.NumberOfRows - 1, this.NumberOfColumns - 1);

        //fill cofactor
        //I dont Know what to do here?


        determinant += this.GetElement(1, columnIndex) * cofactor.Determinant();
    }

    return determinant;
}

What I am missing is what should go at the line fill cofactor.

Can someone suggest what I should do there? Basically, what is the best way to add elements to cofactor from the original matrix while ignoring those that appear in the row or column of my current location in the matrix?

  • Is there a reason that `Matrix.Determinant` doesn't fill your needs? (http://msdn.microsoft.com/en-us/library/system.windows.media.matrix.determinant(v=vs.110).aspx) – Gjeltema Jun 25 '14 at 20:15
  • We are writing our own library to maximize flexibility – tjahrenholz Jun 25 '14 at 20:20
  • Flexibility for what? There's only so many ways to calculate a determinant. You're already using a Matrix class internally - you could just initialize it and call .Determinant, and return that, then implement the other functions you're interested in in your flexible manner. – Gjeltema Jun 25 '14 at 20:31
  • Well, we wrote that matrix class, and it doesn't have a determinant method yet. – tjahrenholz Jun 25 '14 at 20:37
  • @Gjeltema using [`Matrix.Determinant`](http://msdn.microsoft.com/en-us/library/system.windows.media.matrix.determinant(v=vs.110).aspx) requires the application to always be able to access the silverlight namespace as of .net 4.5. For an example of unportable code load a dll into [xamarin scan](http://scan.xamarin.com/) – jth41 Jun 25 '14 at 20:56
  • `If (this.NumberOfRows == 2)` should be included to return 1/(ad-bc) or throw an error (no determinant) if ad==bc. – Andrew Morton Jun 25 '14 at 21:57
  • @Gjeltema et al: Apparently it's not *that* Matrix class. – Andrew Morton Jun 25 '14 at 22:02

1 Answers1

2

You just need to remove the first (zeroth) row and the column which you don't want. The following may be of use to you:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        /// <summary>
        /// Helper to show array.
        /// </summary>
        /// <param name="mat"></param>
        static void ShowArray(double[,] mat)
        {
            int ubound = mat.GetUpperBound(0);

            for (int row = 0; row <= ubound; row++)
            {
                for (int col = 0; col <= ubound; col++)
                {
                    Console.Write(string.Format("{0,2} ", mat[col, row]));
                }
                Console.WriteLine();
            };

            Console.WriteLine();

        }

        /// <summary>
        /// Get an array without the zeroth row and without a specified column.
        /// </summary>
        /// <param name="mat">The square array to remove items from.</param>
        /// <param name="knockoutCol">The column to eliminate.</param>
        /// <returns>A square array of size one less than the input array.</returns>
        static double[,] SubMatrix(double[,] mat, int knockoutCol)
        {
            if (mat.GetUpperBound(0) != mat.GetUpperBound(1))
            {
                throw new ArgumentException("Array is not square.");
            }

            int ubound = mat.GetUpperBound(0);
            double[,] m = new double[ubound, ubound];

            int mCol = 0;
            int mRow = 0;

            for (int row = 1; row <= ubound; row++)
            {
                mCol = 0;
                for (int col = 0; col <= ubound; col++)
                {
                    if (col == knockoutCol)
                    {
                        continue;
                    }
                    else
                    {
                        m[mCol, mRow] = mat[col, row];
                        mCol += 1;
                    }
                }
                mRow += 1;

            };

            return m;
        }

        static void Main(string[] args)
        {
            int arraySize = 4;
            double[,] mat = new double[arraySize, arraySize];
            int ubound = mat.GetUpperBound(0);

            // Initialise array for inspection.
            for (int row = 0; row <= ubound; row++)
            {
                for (int col = 0; col <= ubound; col++)
                {
                    mat[col, row] = (arraySize * row) + col;
                }
            };

            ShowArray(mat);

            ShowArray(SubMatrix(mat, 0));
            ShowArray(SubMatrix(mat, 1));
            ShowArray(SubMatrix(mat, 2));

            Console.ReadLine();

        }
    }
}

Outputs:

 0  1  2  3
 4  5  6  7
 8  9 10 11
12 13 14 15

 5  6  7
 9 10 11
13 14 15

 4  6  7
 8 10 11
12 14 15

 4  5  7
 8  9 11
12 13 15

If I was thinking about it more carefully when I started out, I might have swapped the rows and columns.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84