Haelgarin_The_Mad
Haelgarin_The_Mad

Reputation: 23

Issue with code for NxN determinant function (C++)

I'm trying to write a matrix inverse calculator (been doing stuff to do with matrices for my maths module in uni so I figured it would be a good way to get practice with recursive functions).

At the moment I'm working on functions for working out the determinant of functions, one for 2x2, one for 3x3 which calls the 2x2 one (recursive formula for determinants I'm sure you know the drill).

Then a third function takes a matrix as input initially checks if it's 2x2 or 3x3, if so sends it to the appropriate prior mentioned function. Next we eliminate rows and columns recursively following the determinant formula until we end up with a value for the determinant.

This code works up to 4x4 matrices, however any matrix larger than this results in the wrong answer.

I'm on my first year at uni and reletively new to programming, this being my first attempt with recursive functions, any advice would be appreciated. My lecturer for maths suggested maybe using cramers rule instead, but it would be interesting to see if I can get this method working.

Appologies if my formatting isn't the best, stuck on old laptop at the moment.

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

double MatrixDet2By2(vector<vector<double>> matrix);
double MatrixDet3By3(vector<vector<double>> matrix);
double MatrixDet(vector<vector<double>> matrix);
//vector<vector<double>> CalcMinorMatrix(vector<vector<double>> matrix);
//vector<vector<double>> CalcCofactorMatrix(vector<vector<double>> matrix);

int main(int argc, char** argv)
{

    vector<vector<double>> testMatrix = {{1,4},{7,9}};
    vector<vector<double>> testMatrix2 = { {5,3,7},{6,-1,0},{4,-11,-2} };
    vector<vector<double>> testMatrix3 = 
    {
        {5,3,7,6},
        {6,-1,0,4},
        {4,-11,-2,3},
        {1,3,7,9},
    };
    vector<vector<double>> testMatrix4 = 
    {
        {1,2,-1,6,1},
        {6,-1,0,4,3},
        {4,0,-2,3,2},
        {1,3,7,2,3},
        {-2,7,0,2,5},
    };

    //cout << MatrixDet2By2(testMatrix) << endl;
    cout << MatrixDet(testMatrix4) << endl;

    cout << endl;
    return 0;
}

double MatrixDet2By2(vector<vector<double>> matrix)
{
    return (matrix[0][0] * matrix[1][1]) - (matrix[0][1] * matrix[1][0]);
}

double MatrixDet3By3(vector<vector<double>> matrix)
{
    vector<vector<double>> subMatrix1 = {
        {matrix[1][1], matrix[1][2]},
        {matrix[2][1], matrix[2][2]}
    };

    vector<vector<double>> subMatrix2 = {
        {matrix[1][0], matrix[1][2]},
        {matrix[2][0], matrix[2][2]}
    };

    vector<vector<double>> subMatrix3 = {
        {matrix[1][0], matrix[1][1]},
        {matrix[2][0], matrix[2][1]}
    };

    return ((matrix[0][0] * MatrixDet2By2(subMatrix1)) - (matrix[0][1] * MatrixDet2By2(subMatrix2)) + (matrix[0][2] * MatrixDet2By2(subMatrix3)));
}
/*
vector<vector<double>> CalcMinorMatrix(vector<vector<double>> matrix)
{
    vector<vector<double>> subMatrix1 = {
        {matrix[1][1], matrix[1][2]},
        {matrix[2][1], matrix[2][2]}
    };

    vector<vector<double>> subMatrix2 = {
        {matrix[1][0], matrix[1][2]},
        {matrix[2][0], matrix[2][2]}
    };

    vector<vector<double>> subMatrix3 = {
        {matrix[1][0], matrix[1][1]},
        {matrix[2][0], matrix[2][1]}
    };

    vector<vector<double>> subMatrix4 = {
    {matrix[0][1], matrix[0][2]},
    {matrix[2][1], matrix[2][2]}
    };

    vector<vector<double>> subMatrix5 = {
        {matrix[0][0], matrix[0][2]},
        {matrix[2][0], matrix[2][2]}
    };

    vector<vector<double>> subMatrix6 = {
        {matrix[0][0], matrix[0][1]},
        {matrix[2][0], matrix[2][1]}
    };

    vector<vector<double>> subMatrix7 = {
        {matrix[0][1], matrix[0][2]},
        {matrix[1][1], matrix[1][2]}
    };

    vector<vector<double>> subMatrix8 = {
        {matrix[0][0], matrix[0][2]},
        {matrix[1][0], matrix[1][2]}
    };

    vector<vector<double>> subMatrix9 = {
        {matrix[0][0], matrix[0][1]},
        {matrix[1][0], matrix[1][1]}
    };

    vector<vector<double>> matrixOfMinors = {
        {MatrixDet2By2(subMatrix1), MatrixDet2By2(subMatrix2), MatrixDet2By2(subMatrix3)},
        {MatrixDet2By2(subMatrix4), MatrixDet2By2(subMatrix5), MatrixDet2By2(subMatrix6)},
        {MatrixDet2By2(subMatrix7), MatrixDet2By2(subMatrix8), MatrixDet2By2(subMatrix9)},
    };

    return matrixOfMinors;
}

vector<vector<double>> CalcCofactorMatrix(vector<vector<double>> matrix)
{



    return matrix;
}
*/
double MatrixDet(vector<vector<double>> matrix)
{
    vector<vector<double>> tempMatrix{};

    static double totalDeterminant = 0;

    if (matrix.size() != matrix[0].size())
    {
        cout << "\r\nPlease enter a valid square matrix" << endl;
    }

    else if (matrix.size() == 2)
    {
        return MatrixDet2By2(matrix);
    }

    else if (matrix.size() == 3)
    {
        return MatrixDet3By3(matrix);
    }


    else
    {
        size_t pos = 0;


        for (auto value : matrix[0])
        {
            tempMatrix = matrix;
            tempMatrix.erase(tempMatrix.begin());

            for (size_t i = 0; i < tempMatrix.size(); i++)
            {
                if (tempMatrix[i].size() > pos)
                {
                    tempMatrix[i].erase(tempMatrix[i].begin() + pos);
                }
            }

            cout << "\r\n---------" << endl;
            for (auto vec : tempMatrix)
            {
                for (auto val : vec)
                {
                    cout << val << " ";
                }
                cout << endl;
            }
            cout << "\r\n---------" << endl;

            //totalDeterminant += MatrixDet(tempMatrix);


            if ((pos + 1) % 2 == 0)
            {
                totalDeterminant += (-value * MatrixDet(tempMatrix));
            }

            else
            {
                totalDeterminant += (value * MatrixDet(tempMatrix));
            }

            pos++;
        }



    }
    return totalDeterminant;

}

Upvotes: 2

Views: 352

Answers (2)

R Sahu
R Sahu

Reputation: 206607

One error is in the following lines

for (size_t i = 0; i < tempMatrix.size(); i++)
{
    if (tempMatrix[i].size() > pos)
    {
        tempMatrix[i].erase(tempMatrix[i].begin() + pos);
    }
}

The check if (tempMatrix[i].size() > pos) is not necessary.

All you need to get the sub-matrix is to just exclude the pos-th column. You need to use:

// Remove the "pos" column of tempMatrix.
for (size_t i = 0; i < tempMatrix.size(); i++)
{
   tempMatrix[i].erase(tempMatrix[i].begin() + pos);
}

The second error is the use of a static variable for totalDeterminant, as was pointed out by @aschepler. The line

static double totalDeterminant = 0;

needs to be simply

double totalDeterminant = 0;

Upvotes: 0

aschepler
aschepler

Reputation: 72346

Since you define variable totalDeterminant in MatrixDet using the keyword static, there is only one totalDeterminant variable in your program, ever. And the = 0 initializer only applies the very first time the program gets there. So when computing the determinant of the very first 4x4 minor matrix, that goes fine. Then that result is multiplied by matrix[0][0] and added to totalDeterminant. The computation for the second 4x4 minor matrix starts with that strange value (1+matrix[0][0])*detMinor1 and begins adding to it.

In fact, if you just called MatrixDet on two 4x4 matrices in the same program, the second call would return the sum of the two determinants.

You need a separate sum for each main matrix and submatrix computation (since the result of a submatrix determinant needs to be multiplied by an element before being added to anything else). So totalDeterminant needs to NOT be static. When I remove the static from your program, it gives the correct final result of MatrixDet(testMatrix4) == -856.

Note that once the general case is correct, you could remove the code for the 3x3 and possibly even 2x2 case. Don't forget to support a 1x1 matrix: det [[x]] = x.

Upvotes: 2

Related Questions