2

How do you calculate the determinant of an NxN matrix C# ?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
user347640
  • 213
  • 1
  • 4
  • 11
  • 12
    Is this homework? –  May 27 '10 at 15:58
  • 3
    Isn't the definition sufficient: http://en.wikipedia.org/wiki/Determinant? When you tried to implement it on C# did you encounter some particular problems you might ask about? – Darin Dimitrov May 27 '10 at 15:59
  • 5
    Give us the code you made so far and we will help you. But we won't code it for you. – Philippe Carriere May 27 '10 at 16:19
  • Whilst I agree that this isn't a very well written question, and it certainly smacks of being homework, I came across this question via a Google search, needing and answer to the very same thing. SO is a place I usually turn to for answering these kinds of things, and this does indeed seem to be the only question on here on this topic. I don't see a reason not to answer it properly, if not for the elusive @vj4u then at least for Joe Coder like me. – Drew Noakes Jun 05 '10 at 15:41
  • I've posted an answer that caters for the 4x4 case (which is what I needed). It raises the question of whether a hardcoded solution beats a generic NxN one when the matrix size is known. – Drew Noakes Jun 05 '10 at 15:42
  • Are you sure you need to calculate a determinant? People often think they need to when they don't. Solving a linear system with Cramer's rule is the most common reason to want a determinant, but that algorithm is horribly inefficient. – John D. Cook Jun 05 '10 at 15:55

4 Answers4

8

The OP posted another question asking specifically about 4x4 matrices, which has been closed as an exact duplicate of this question. Well, if you're not looking for a general solution but instead are constrained to 4x4 matrices alone, then you can use this ugly looking but tried-and-true code:

public double GetDeterminant() {
    var m = _values;
    return
         m[12] * m[9]  * m[6]  * m[3]   -  m[8] * m[13] * m[6]  * m[3]   -
         m[12] * m[5]  * m[10] * m[3]   +  m[4] * m[13] * m[10] * m[3]   +
         m[8]  * m[5]  * m[14] * m[3]   -  m[4] * m[9]  * m[14] * m[3]   -
         m[12] * m[9]  * m[2]  * m[7]   +  m[8] * m[13] * m[2]  * m[7]   +
         m[12] * m[1]  * m[10] * m[7]   -  m[0] * m[13] * m[10] * m[7]   -
         m[8]  * m[1]  * m[14] * m[7]   +  m[0] * m[9]  * m[14] * m[7]   +
         m[12] * m[5]  * m[2]  * m[11]  -  m[4] * m[13] * m[2]  * m[11]  -
         m[12] * m[1]  * m[6]  * m[11]  +  m[0] * m[13] * m[6]  * m[11]  +
         m[4]  * m[1]  * m[14] * m[11]  -  m[0] * m[5]  * m[14] * m[11]  -
         m[8]  * m[5]  * m[2]  * m[15]  +  m[4] * m[9]  * m[2]  * m[15]  +
         m[8]  * m[1]  * m[6]  * m[15]  -  m[0] * m[9]  * m[6]  * m[15]  -
         m[4]  * m[1]  * m[10] * m[15]  +  m[0] * m[5]  * m[10] * m[15];
}

It assumes you store your vector data in a 16-element array called _values (of double in this case, but float would work too), in the following order:

0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
Community
  • 1
  • 1
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • For column-major order: `m[3]*m[6]*m[9]*m[12] - m[2]*m[7]*m[9]*m[12] - m[3]*m[5]*m[10]*m[12] + m[1]*m[7]*m[10]*m[12] + m[2]*m[5]*m[11]*m[12] - m[1]*m[6]*m[11]*m[12] - m[3]*m[6]*m[8]*m[13] + m[2]*m[7]*m[8]*m[13] + m[3]*m[4]*m[10]*m[13] - m[0]*m[7]*m[10]*m[13] - m[2]*m[4]*m[11]*m[13] + m[0]*m[6]*m[11]*m[13] + m[3]*m[5]*m[8]*m[14] - m[1]*m[7]*m[8]*m[14] - m[3]*m[4]*m[9]*m[14] + m[0]*m[7]*m[9]*m[14] + m[1]*m[4]*m[11]*m[14] - m[0]*m[5]*m[11]*m[14] - m[2]*m[5]*m[8]*m[15] + m[1]*m[6]*m[8]*m[15] + m[2]*m[4]*m[9]*m[15] - m[0]*m[6]*m[9]*m[15] - m[1]*m[4]*m[10]*m[15] + m[0]*m[5]*m[10]*m[15]` – maja Apr 16 '20 at 15:09
4

Reduce to upper triangular form, then make a nested loop where you multiply all the values at position i == j together. There you have it.

Brandi
  • 1,549
  • 4
  • 24
  • 32
  • 2
    It doesn't even need to be a nested loop, because if you're doing it for positions (i, j) where i == j you can just do it for all positions (i, i). – JAB May 27 '10 at 16:15
  • 1
    The result you calculate may be the negative of the determinant. You need to take the product of the primary diagonal and then multiply by (-1)^[number of row swaps used to get to upper triangular form] – Kevin May 27 '10 at 16:58
1

The standard method is LU decomposition. You may want to use a library instead of coding it yourself. I don't know about C#, but the 40-year standard is LAPACK.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
1

This solution is achieved using row operations. I took an identity matrix of the same dimensions as of my target matrix and then converted the target matrix to the identity matrix such that, every operation which is performed on target matrix, must also be performed to the identity matrix. In last, the target matrix will become identity matrix and the identity matrix will hold the inverse of the target matrix.

private static double determinant(double[,] matrix, int size)
    {
        double[] diviser = new double[size];// this will be used to make 0 all the elements of a row except (i,i)th value.
        double[] temp = new double[size]; // this will hold the modified ith row after divided by (i,i)th value.
        Boolean flag = false; // this will limit the operation to be performed only when loop n != loop i
        double determinant = 1;

        if (varifyRowsAndColumns(matrix, size)) // verifies that no rows or columns are similar or multiple of another row or column
            for (int i = 0; i < size; i++)
            {
                int count = 0;
                //this will hold the values to be multiplied by temp matrix
                double[] multiplier = new double[size - 1]; 
                diviser[i] = matrix[i, i];
                //if(i,i)th value is 0, determinant shall be 0
                if (diviser[i] == 0)
                {
                    determinant = 0;
                    break;
                }
                /*
                 * whole ith row will be divided by (i,i)th value and result will be stored in temp matrix.
                 * this will generate 1 at (i,i)th position in temp matrix i.e. ith row of matrix
                 */
                for (int j = 0; j < size; j++)
                {
                    temp[j] = matrix[i, j] / diviser[i];
                }
                //setting up multiplier to be used for multiplying the ith row of temp matrix
                for (int o = 0; o < size; o++)
                    if (o != i)
                        multiplier[count++] = matrix[o, i];

                count = 0;
                //for creating 0s at every other position than (i,i)th
                for (int n = 0; n < size; n++)
                {
                    for (int k = 0; k < size; k++)
                    {
                        if (n != i)
                        {
                            flag = true;
                            matrix[n, k] -= (temp[k] * multiplier[count]);
                        }
                    }
                    if (flag)
                        count++;
                    flag = false;
                }

            }
        else determinant = 0;
        //if determinant is not 0, (i,i)th element will be multiplied and the result will be determinant
        if (determinant != 0)
            for (int i = 0; i < size; i++)
            {
                determinant *= matrix[i, i];
            }
        return determinant;
    }


    private static Boolean varifyRowsAndColumns(double[,] matrix, int size)
    {
        List<double[]> rows = new List<double[]>();
        List<double[]> columns = new List<double[]>();


        for (int j = 0; j < size; j++)
        {
            double[] temp = new double[size];
            for (int k = 0; k < size; k++)
            {
                temp[j] = matrix[j, k];
            }
            rows.Add(temp);
        }

        for (int j = 0; j < size; j++)
        {
            double[] temp = new double[size];
            for (int k = 0; k < size; k++)
            {
                temp[j] = matrix[k, j];
            }
            columns.Add(temp);
        }

        if (!RowsAndColumnsComparison(rows, size))
            return false;
        if (!RowsAndColumnsComparison(columns, size))
            return false;
        return true;
    }
    private static Boolean RowsAndColumnsComparison(List<double[]> rows, int size)
    {
        int countEquals = 0;
        int countMod = 0;
        int countMod2 = 0;

        for (int i = 0; i < rows.Count; i++)
        {
            for (int j = 0; j < rows.Count; j++)
            {
                if (i != j)
                {
                    double min = returnMin(rows.ElementAt(i), rows.ElementAt(j));
                    double max = returnMax(rows.ElementAt(i), rows.ElementAt(j));

                    for (int l = 0; l < size; l++)
                    {
                        if (rows.ElementAt(i)[l] == rows.ElementAt(j)[l])
                            countEquals++;

                        for (int m = (int)min; m <= max; m++)
                        {
                            if (rows.ElementAt(i)[l] % m == 0 && rows.ElementAt(j)[l] % m == 0)
                                countMod++;

                            if (rows.ElementAt(j)[l] % m == 0 && rows.ElementAt(i)[l] % m == 0)
                                countMod2++;
                        }
                    }

                    if (countEquals == size)
                    {
                        return false;
                        // one row is equal to another row. determinant is zero
                    }

                    if (countMod == size)
                    {
                        return false;
                    }

                    if (countMod2 == size)
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    private static double returnMin(double[] row1, double[] row2)
    {
        double min1 = row1[0];
        double min2 = row2[0];

        for (int i = 1; i < row1.Length; i++)
            if (min1 > row1[i])
                min1 = row1[i];

        for (int i = 1; i < row2.Length; i++)
            if (min2 > row2[i])
                min2 = row2[i];

        if (min1 < min2)
            return min1;
        else return min2;
    }
    private static double returnMax(double[] col1, double[] col2)
    {
        double max1 = col1[0];
        double max2 = col2[0];

        for (int i = 1; i < col1.Length; i++)
            if (max1 < col1[i])
                max1 = col1[i];

        for (int i = 1; i < col2.Length; i++)
            if (max2 < col2[i])
                max2 = col2[i];

        if (max1 > max2)
            return max1;
        else return max2;
    }
Imran Faruqi
  • 663
  • 9
  • 19
  • I have updated my answer with explanation and commenting in the code to support my explanation. I would appreciate if you either up-vote this post now, or guide me what should I do further. I searched well on all forums but none had n x n matrix determinant solution so I coded it. – Imran Faruqi Apr 08 '19 at 10:09