3

I've tried to write a program that should be able to calculate the inverse of a matrix: Here's what I have so far:

#include <iostream>
#include <vector>
#include <math.h>
#include <iomanip>
#include <stdexcept>

double getDeterminant(const std::vector<std::vector<double>> vect) {
    if(vect.size() != vect[0].size()) {
        throw std::runtime_error("Matrix is not quadratic");
    } 
    int dimension = vect.size();

    if(dimension == 0) {
        return 1;
    }

    if(dimension == 1) {
        return vect[0][0];
    }

    //Formula for 2x2-matrix
    if(dimension == 2) {
        return vect[0][0] * vect[1][1] - vect[0][1] * vect[1][0];
    }

    double result = 0;
    int sign = 1;
    for(int i = 0; i < dimension; i++) {

        //Submatrix
        std::vector<std::vector<double>> subVect(dimension - 1, std::vector<double> (dimension - 1));
        for(int m = 1; m < dimension; m++) {
            int z = 0;
            for(int n = 0; n < dimension; n++) {
                if(n != i) {
                    subVect[m-1][z] = vect[m][n];
                    z++;
                }
            }
        }

        //recursive call
        result = result + sign * vect[0][i] * getDeterminant(subVect);
        sign = -sign;
    }

    return result;
}

std::vector<std::vector<double>> getTranspose(const std::vector<std::vector<double>> matrix1) {

    //Transpose-matrix: height = width(matrix), width = height(matrix)
    std::vector<std::vector<double>> solution(matrix1[0].size(), std::vector<double> (matrix1.size()));

    //Filling solution-matrix
    for(size_t i = 0; i < matrix1.size(); i++) {
        for(size_t j = 0; j < matrix1[0].size(); j++) {
            solution[j][i] = matrix1[i][j];
        }
    }
    return solution;
}

std::vector<std::vector<double>> getCofactor(const std::vector<std::vector<double>> vect) {
    if(vect.size() != vect[0].size()) {
        throw std::runtime_error("Matrix is not quadratic");
    } 

    std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
    std::vector<std::vector<double>> subVect(vect.size() - 1, std::vector<double> (vect.size() - 1));

    for(std::size_t i = 0; i < vect.size(); i++) {
        for(std::size_t j = 0; j < vect[0].size(); j++) {

            int p = 0;
            for(size_t x = 0; x < vect.size(); x++) {
                if(x == i) {
                    continue;
                }
                int q = 0;

                for(size_t y = 0; y < vect.size(); y++) {
                    if(y == j) {
                        continue;
                    }

                    subVect[p][q] = vect[x][y];
                    q++;
                }
                p++;
            }
            solution[i][j] = pow(-1, i + j) * getDeterminant(subVect);
        }
    }
    return solution;
}

std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
    if(getDeterminant(vect) == 0) {
        throw std::runtime_error("Determinant is 0");
    } 
    double d = 1.0/getDeterminant(vect);
    std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));

    for(size_t i = 0; i < vect.size(); i++) {
        for(size_t j = 0; j < vect.size(); j++) {
            solution[i][j] = vect[i][j] * d; 
        }
    }

    return getTranspose(getCofactor(solution));
}

void printMatrix(const std::vector<std::vector<double>> vect) {
    for(std::size_t i = 0; i < vect.size(); i++) {
        for(std::size_t j = 0; j < vect[0].size(); j++) {
            std::cout << std::setw(8) << vect[i][j] << " ";
        }
        std::cout << "\n";
    }
}

int main() {
    std::vector<std::vector<double>> matrix(3, std::vector<double> (3));
    matrix = {
        {1,2,3},
        {4,5,6},
        {7,8,8}
    };

    printMatrix(getInverse(matrix));
    return 0;
}

The functions for calculating the determinant, the transpose- and the cofactor-matrix work correctly (as far as I can see), but the function for calculating the inverse-matrix doesn't. I searched the internet and found this, which uses the same function for calculating the inverse.

Is this formula incorrect, or do you have any other idea, why it doesnt work?


The matrix I am using is

and the inverse of it should be

6
  • 1
    Have you tried stepping through your code using a debugger while it is executing? That is generally a good way to narrow down the specific issue. In this case pass a small matrix that you could invert by hand (pen and paper) and see if your code is tracking the same calculations. Commented Feb 19, 2020 at 12:34
  • The formula seems to be partially correct as it works for a few example matrices such as [[1,2],[3,4]]. You must have some subtler bug in there. You need to go through it step-by-step and see where the incorrect numbers start appearing for the first time. Commented Feb 19, 2020 at 12:36
  • I don't remember how to calculate inverse matrix (general formula for all kinds). Maybe on math.stackexchange.com you could find someone who would be expert on matrix to help you with the algorithm. Commented Feb 19, 2020 at 12:38
  • 1
    Aside: if you are going to use std::vector<std::vector<double>> for a matrix, you should probably check every inner vector is the same size as the outer. if(std::any_of(vect.begin(), vect.end(),[size = vect.size()](auto & inner){ return inner.size() != size; })) { throw ... } It will also remove the undefined behaviour of the dimension == 0 case.
    – Caleth
    Commented Feb 19, 2020 at 13:08
  • You may not come back and read comments, but most systems do not calculate the inverse of a matrix this way. A more common method is LU decomposition with pivoting. There's a great book called "Numerical Recipes in C" that provide a great write up and code.
    – duffymo
    Commented Aug 19, 2021 at 13:16

2 Answers 2

3

First of all, thanks for your comments.

The problem was the order of execution. The correct solution is:

std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
    if(getDeterminant(vect) == 0) {
        throw std::runtime_error("Determinant is 0");
    } 

    double d = 1.0/getDeterminant(vect);
    std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));

    for(size_t i = 0; i < vect.size(); i++) {
        for(size_t j = 0; j < vect.size(); j++) {
            solution[i][j] = vect[i][j]; 
        }
    }

    solution = getTranspose(getCofactor(solution));

    for(size_t i = 0; i < vect.size(); i++) {
        for(size_t j = 0; j < vect.size(); j++) {
            solution[i][j] *= d;
        }
    }

    return solution;
}
0

I know this is an old question but your code does not work when the input matrix's dimension is 1. Here is a workaround that I used:

vector<vector<double>> inverse(const vector<vector<double>> A) {
    double d = 1.0/det(A);
    vector<vector<double>> solution(A.size(), vector<double> (A.size()));

    if(A.size() == 1){
        vector<double> ans = {0};
        ans[0] = 1.0/det(A);
        solution[0] = ans;
        return solution;
    }

    for(size_t i = 0; i < A.size(); i++) {
        for(size_t j = 0; j < A.size(); j++) {
            solution[i][j] = A[i][j] * d; 
        }
    }

    return transpose(cofactor(solution));
}