0

I have run this with 1x1 and 2x2 matrices which has worked, but for larger ones I have not gotten the correct answer. I have a sample 5x5 matrix in the code which should have a determinant of -30024.

I am running this code but it will not give me the correct answer:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define rMax 5

double a[rMax][rMax] = {{-1,2,3,-6,7}, {-2,0,-1,4,2}, {1,-9,8,2,0}, {9,3,5,7,9}, {-5,3,2,-2,2}};
//determinant should be -30024

double matrix_determinant(size_t rowMax, const double z[][rMax])
{
    double final = 0;
    double w[rowMax][rowMax];

    for(size_t row = 0; row < rowMax; row++) //copies z into a new editable matrix
    {
        for(size_t column = 0; column < rowMax; column++)
            w[row][column] = z[row][column];
    }

    if(rowMax > 2) //checks for larger matrix
    {
        for(size_t mat = 0; mat < rowMax; mat++) //loops equal to the max width of the matrix
        {
            double new[rowMax - 1][rowMax - 1]; //new matrix is 1x1 smaller

            for(size_t cRow = 0; cRow < (rowMax - 1); cRow++) //initializing the new matrix
            {
                for(size_t cCol = 0; cCol < (rowMax - 1); cCol++)
                {
                    new[cRow][cCol] = w[cRow + 1][((cCol + mat) % (rowMax - 1)) + 1];
                }           
            }
            if(0 == (mat % 2)) //alternates adding and subtracting
                final += (w[0][mat] * matrix_determinant((rowMax - 1), new));
            else
                final += ((-1) * w[0][mat] * matrix_determinant((rowMax - 1), new));
        }

        return final;
    }

    if(rowMax == 1) //checks for 1x1 matrix
    {
        return w[0][0];
    }

    else //computes final 2x2 matrix (base case)
    {
        final = (w[0][0] * w[1][1]) - (w[0][1] * w[1][0]);
        return final;
    }
}

int main ( void )
{
    size_t s = rMax;
    double det = matrix_determinant(s, a);
    printf("The determinant of matrix a is: %lf\n", det);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ebuko5
  • 1
  • 1
    Why not work on 3x3 determinants first, getting that to work? With that in place, 4x4 and 5x5 and larger NxN determinants should be manageable. The 1x1 and 2x2 values are simple; the 3x3 case is the first that really requires work partitioning the matrix. You might want to work on not needing to make the copy — or you may be better off deferring that until after you have the existing code working. – Jonathan Leffler Apr 03 '20 at 20:51
  • You should probably deal with the `rowMax == 1` and `rowMax == 2` cases before you make the copy — you can work directly with `z` for those two. – Jonathan Leffler Apr 03 '20 at 20:53
  • Have you got code that prints the matrices so that you can see whether your recursive calls are being passed the correct data? – Jonathan Leffler Apr 03 '20 at 20:56
  • I found a sample 3x3 matrix to use that had a a determinant of -32 and i got -41. I also switched the checks so it will check for rowMax = 1 or 2 before anything else. – ebuko5 Apr 03 '20 at 21:01
  • "but for larger ones I have not gotten the correct answer." --> what did you get? what did you expect? (looks like -30024) – chux - Reinstate Monica Apr 03 '20 at 21:04
  • 1
    At least this problem: Wrong to pass `double new[rowMax - 1][rowMax - 1];` to `matrix_determinant(size_t rowMax, const double z[][rMax])`. – chux - Reinstate Monica Apr 03 '20 at 21:14
  • 1
    Picking up [chux](https://stackoverflow.com/users/2410359/chux-reinstate-monica)'s [comment](https://stackoverflow.com/questions/61020088/problem-with-finding-determinant-of-matrix-3x3-or-larger-in-c#comment107955235_61020088) — your function `double matrix_determinant(size_t rowMax, const double z[][rMax])` should be `double matrix_determinant(size_t rowMax, const double z[][rowMax])` given the way you allocate the `new` matrix — or allocate the `new` matrix with `rMax` instead of `rowMax-1` as the dimension. (I avoid using C++ keywords as C variable names — be cautious about `new`.) – Jonathan Leffler Apr 03 '20 at 21:28
  • Is the intent here to compute the determinant, or is it to use a particular approach for computing the determinant? The reason I ask is that the code appears to be (trying to) implement the Laplace expansion, and there are alternative approaches that are (1) simpler to implement and (2) more computationally efficient in both space and time measures. – Peter Apr 03 '20 at 21:56

1 Answers1

2

2 changes.

Wrong type

Wrong to pass double new[rowMax - 1][rowMax - 1]; to matrix_determinant(size_t rowMax, const double z[][rMax]). The final [rowMax - 1] does not certainly match [rMax].

For various reasons (which is a side issue), I also took out the const.

// double matrix_determinant(size_t rowMax,   double z[][rMax])
double matrix_determinant(size_t rowMax,    double z[rowMax][rowMax])

Wrong computation

Reformed new[cRow][cCol] calculation. OP's code did not skip the right column in w[][].

            size_t offset = 0;
            for(size_t cCol = 0; cCol < (rowMax - 1); cCol++) {
                //new[cRow][cCol] = w[cRow + 1][((cCol + mat) % (rowMax - 1)) + 1];
                if (cCol == mat) offset = 1;
                new[cRow][cCol] = w[cRow + 1][cCol + offset];
            }

Result

The determinant of matrix a is: -30024.000000
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I think the whole 'copy to `w`' operation is superfluous. The 'copy to `new`' operation could just as well come from `z` as from `w`, could it not? – Jonathan Leffler Apr 03 '20 at 21:48
  • @JonathanLeffler Agreed. Code could be re-factored without `w[]`. I suspect it was code trying to cope with the different dimensionality of the original `z[]`. – chux - Reinstate Monica Apr 03 '20 at 21:50