C++ Program to Find the Inverse of a Matrix

Finding the inverse of a matrix is a fundamental operation in linear algebra, essential for solving systems of linear equations, performing transformations, and more. This article will explore various methods to compute the inverse of a matrix in C++, offering multiple solutions and detailed explanations.

Prerequisites

To effectively follow along with this article, you should have:

  1. Basic understanding of the C++ programming language.
  2. Knowledge of matrices and linear algebra concepts.
  3. Familiarity with loops, arrays, and functions in C++.

Introduction

In this article, we will delve into creating a C++ program to find the inverse of a matrix. The inverse of a matrix is a matrix that, when multiplied by the original matrix, yields the identity matrix. This concept is pivotal in many mathematical and engineering applications, such as solving linear systems, cryptography, and computer graphics.

1. Method 1: Using Adjoint and Determinant

1.1 Explanation

The first method involves calculating the inverse of a matrix using its adjoint and determinant. This approach requires computing the matrix of minors, the matrix of cofactors, and the adjugate matrix, followed by dividing by the determinant.

1.2 Code Implementation

C++
#include <iostream>
#include <vector>
using namespace std;

void getCofactor(vector<vector<float>>& matrix, vector<vector<float>>& temp, int p, int q, int n) {
    int i = 0, j = 0;
    for (int row = 0; row < n; row++) {
        for (int col = 0; col < n; col++) {
            if (row != p && col != q) {
                temp[i][j++] = matrix[row][col];
                if (j == n - 1) {
                    j = 0;
                    i++;
                }
            }
        }
    }
}

float determinant(vector<vector<float>>& matrix, int n) {
    float D = 0;
    if (n == 1)
        return matrix[0][0];

    vector<vector<float>> temp(n, vector<float>(n));
    int sign = 1;

    for (int f = 0; f < n; f++) {
        getCofactor(matrix, temp, 0, f, n);
        D += sign * matrix[0][f] * determinant(temp, n - 1);
        sign = -sign;
    }
    return D;
}

void adjoint(vector<vector<float>>& matrix, vector<vector<float>>& adj) {
    int N = matrix.size();
    if (N == 1) {
        adj[0][0] = 1;
        return;
    }

    int sign = 1;
    vector<vector<float>> temp(N, vector<float>(N));

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            getCofactor(matrix, temp, i, j, N);
            sign = ((i + j) % 2 == 0) ? 1 : -1;
            adj[j][i] = (sign) * (determinant(temp, N - 1));
        }
    }
}

bool inverse(vector<vector<float>>& matrix, vector<vector<float>>& inverse) {
    int N = matrix.size();
    float det = determinant(matrix, N);
    if (det == 0) {
        cout << "Singular matrix, can't find its inverse";
        return false;
    }

    vector<vector<float>> adj(N, vector<float>(N));
    adjoint(matrix, adj);

    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            inverse[i][j] = adj[i][j] / det;

    return true;
}

void display(vector<vector<float>>& matrix) {
    for (int i = 0; i < matrix.size(); i++) {
        for (int j = 0; j < matrix[i].size(); j++)
            cout << matrix[i][j] << " ";
        cout << endl;
    }
}

int main() {
    int N = 3;
    vector<vector<float>> matrix = { {6, 1, 1}, {4, -2, 5}, {2, 8, 7} };
    vector<vector<float>> inv(N, vector<float>(N));

    if (inverse(matrix, inv)) {
        cout << "The inverse is: \n";
        display(inv);
    }

    return 0;
}

1.3 Output

C++
The inverse is: 
0.176471 -0.00326797 -0.0915033 
-0.117647 0.294118 -0.0294118 
-0.0588235 -0.00735294 0.147059

2. Method 2: Using Gauss-Jordan Elimination

2.1 Explanation

The second method uses the Gauss-Jordan elimination technique to find the inverse. This involves augmenting the matrix with the identity matrix and performing row operations to transform the original matrix into the identity matrix while the identity matrix transforms into the inverse.

2.2 Code Implementation

C++
#include <iostream>
using namespace std;

#define N 3

void gaussJordan(float a[N][N], float b[N][N]) {
    float temp;

    for (int i = 0; i < N; i++) {
        temp = a[i][i];
        for (int j = 0; j < N; j++) {
            a[i][j] = a[i][j] / temp;
            b[i][j] = b[i][j] / temp;
        }

        for (int k = 0; k < N; k++) {
            if (i != k) {
                temp = a[k][i];
                for (int j = 0; j < N; j++) {
                    a[k][j] = a[k][j] - a[i][j] * temp;
                    b[k][j] = b[k][j] - b[i][j] * temp;
                }
            }
        }
    }
}

void display(float matrix[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++)
            cout << matrix[i][j] << " ";
        cout << endl;
    }
}

int main() {
    float a[N][N] = {
        {6, 1, 1},
        {4, -2, 5},
        {2, 8, 7}
    };

    float b[N][N] = {
        {1, 0, 0},
        {0, 1, 0},
        {0, 0, 1}
    };

    gaussJordan(a, b);

    cout << "The inverse is: \n";
    display(b);

    return 0;
}

2.3 Output

C++
The inverse is: 
0.176471 -0.00326797 -0.0915033 
-0.117647 0.294118 -0.0294118 
-0.0588235 -0.00735294 0.147059

3. Method 3: Using Eigen Library

3.1 Explanation

The third method uses the Eigen library, a popular C++ template library for linear algebra. This library simplifies matrix operations, including finding the inverse of a matrix.

3.2 Code Implementation

C++
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;

int main() {
    Matrix3f matrix;
    matrix << 6, 1, 1,
              4, -2, 5,
              2, 8, 7;

    Matrix3f inverseMatrix = matrix.inverse();

    cout << "The inverse is: \n" << inverseMatrix << endl;

    return 0;
}

3.3 Output

C++
The inverse is:
  0.176471  -0.00326797  -0.0915033
 -0.117647    0.294118  -0.0294118
 -0.0588235 -0.00735294   0.147059

Conclusion

In this article, we explored different methods to find the inverse of a matrix in C++. We started with a manual method using adjoint and determinant calculations, then moved on to the Gauss-Jordan elimination technique, and finally used the Eigen library for a more streamlined approach. Each method provides unique advantages, from fundamental understanding to efficient computation. Understanding these techniques will enhance your ability to handle complex matrix operations in various applications.