Calculation of matrix inverse in C/C++

Below is the code to calculate matrix inverse of a matrix of arbitrary size (order) by using analytic solution. This method is known to be slow for very large matrix because of the recursion. However, I used this mainly for calculating inverse of 4×4 matrices and it worked just fine. You can also use CalcDeterminant and GetMinor to calculate determinant of a matrix.

MatrixInversion: the main function to calculate the inverse matrix.
CalcDeterminant
: calculate the determinant of a matrix.
GetMinor:
Get minor matrix.

// matrix inversioon
// the result is put in Y
void MatrixInversion(float **A, int order, float **Y)
{
    // get the determinant of a
    double det = 1.0/CalcDeterminant(A,order);

    // memory allocation
    float *temp = new float[(order-1)*(order-1)];
    float **minor = new float*[order-1];
    for(int i=0;i<order-1;i++)
        minor[i] = temp+(i*(order-1));

    for(int j=0;j<order;j++)
    {
        for(int i=0;i<order;i++)
        {
            // get the co-factor (matrix) of A(j,i)
            GetMinor(A,minor,j,i,order);
            Y[i][j] = det*CalcDeterminant(minor,order-1);
            if( (i+j)%2 == 1)
                Y[i][j] = -Y[i][j];
        }
    }

    // release memory
    delete [] minor[0];
    delete [] minor;
}

// calculate the cofactor of element (row,col)
int GetMinor(float **src, float **dest, int row, int col, int order)
{
    // indicate which col and row is being copied to dest
    int colCount=0,rowCount=0;

    for(int i = 0; i < order; i++ )
    {
        if( i != row )
        {
            colCount = 0;
            for(int j = 0; j < order; j++ )
            {
                // when j is not the element
                if( j != col )
                {
                    dest[rowCount][colCount] = src[i][j];
                    colCount++;
                }
            }
            rowCount++;
        }
    }

    return 1;
}

// Calculate the determinant recursively.
double CalcDeterminant( float **mat, int order)
{
    // order must be >= 0
	// stop the recursion when matrix is a single element
    if( order == 1 )
        return mat[0][0];

    // the determinant value
    float det = 0;

    // allocate the cofactor matrix
    float **minor;
    minor = new float*[order-1];
    for(int i=0;i<order-1;i++)
        minor[i] = new float[order-1];

    for(int i = 0; i < order; i++ )
    {
        // get minor of element (0,i)
        GetMinor( mat, minor, 0, i , order);
        // the recusion is here!
        det += pow( -1.0, i ) * mat[0][i] * CalcDeterminant( minor,order-1 );
    }

    // release memory
    for(int i=0;i<order-1;i++)
        delete [] minor[i];
    delete [] minor;

    return det;
}

If you need to calculate matrix inverse frequently in your codes, you might want to optimize the code by declaring the matrix such as minor and temp as global variables and allocate memories for them only once.

implementation

matrix inversion in C++

23 Responses to “Calculation of matrix inverse in C/C++”

  1. Fab Says:

    Hi,

    Found your webpage in google.
    I think there is a little mistake in your source code l.47 :
    dest[a][b] = src[i][j]; I don’t see any a or b but maybe is it i and j ?

  2. chi3x10 Says:

    Hi, Fab,
    Thanks a lot for finding the bug. It should be dest[rowCount][colCount] instead of dest[a][b].

  3. Vessi Says:

    Hi,
    I found your code for matrix inversion in google, too. But unfortunately I get a runtime error while trying to execute the code. I suppose the problem is conserned to dynamic memory allocation. Would you take a look at the main function, pls?
    I use Dev C++ 4.9.9.1. Here is the code of the main function:

    int main()
    { float cov[6][6]={ {228.585, 120.904, 147.073, 147.073, 228.585, 356.428},
    {164.066, 85.4136, 104.528, 104.528, 164.066, 257.445},
    {130.128, 66.7447, 82.1484, 82.1484, 130.128, 205.378},
    {130.128, 66.7447, 82.1484, 82.1484, 130.128, 205.378},
    {228.585, 120.904, 147.073, 147.073, 228.585, 356.428},
    {286.483, 152.753, 185.253, 185.253, 286.483, 445.253}};
    float **cov1 = new float *[6];
    for(int p=0;p<6;p++)cov1[p]=new float [6];

    for (int i=0; i<6; i++)
    for (int j=0; j<6; j++) cov1[i][j]=cov[i][j];

    for (int i=0; i<6; i++)
    {for (int j=0; j<6; j++) cout<<cov1[i][j]<<” “;
    cout<<endl;
    }

    float **res= new float *[6];
    for(int p=0;p<6;p++)res[p]=new float [6];

    MatrixInversion(cov1,6,res);
    for (int i=0; i<6; i++)
    {for (int j=0; j<6; j++) cout<<res[i][j]<<” “;
    cout<<endl;
    }
    for(int i=0;i<6;i++)
    delete [] cov1[i];
    delete [] cov1;

    for(int i=0;i<6;i++)
    delete [] res[i];
    delete [] res;

    system (“pause”);
    return 0;

    }

  4. Jason Says:

    Quick question. I was trying to implement this, but I don’t know how to declare the initial matrix.

    I tried:

    float MyMatrix[14][14];

    but after I fill it and stick it in the function, I get:

    error: cannot convert ‘float (*)[14]‘ to ‘float**’ …

  5. chi3x10 Says:

    Jason,

    MyMatrix has to be dynamically allocated. For example,
    float **MyMatrix;
    MyMatrix = new float*[14];
    for(int i=0;i<14;i++)
    MyMatrix[i] = new float[14];

    Hope this helps!

  6. Jason Says:

    Thanks, that did help. FYI though, your GetMinor( float **dest, float **src, int row, int col, int order) has the source and destination switched as compared to all the function calls.

    e.g. GetMinor( mat, minor, 0, i , order); //where either the “mat” and “minor” should be switched, or the corresponding in the function itself.

    Took me a while to figure out why I kept getting Segmentation faults.

  7. chi3x10 Says:

    Jason,
    Thanks a lot for pointing out the bug.

  8. Hamid Says:

    Hi Dear Janson,
    Thanks for your code.
    I am beginner in C++ and I don’t know how can i put your code inside of the main function, how to call MatrixInversion and how to input matrix element values.
    Really, pointer-to-pointer is somehow ambiguous and I can’t understand it.

    Thanks.

  9. Hamid Says:

    Sorry for confusing the main code writer.
    I also want to thank chi3×10 due to main contribution.

  10. Cixelsid Says:

    I think your calculation of the determinant is possibly flawed. You’re calculation assumes that row and column indices in the range [0, n-1] where n is the size of the square matrix.

    Generic expansion of a determinant at a row or column calls for row and column indices in the range [1, n], which means your summation should in fact be:

    det += pow( -1.0, 2.0 + i ) * mat[0][i] * CalcDeterminant( minor,order-1 );

    since you are expanding according to the first row of the matrix.

    http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/determinant/

    has a very good explanation of the theory and a C implementation

  11. Cixelsid Says:

    Sorry, my bad…just realized that squaring the square of negative one still produces the same answer. There is nothing wrong with your determinant calculation.

  12. Shannon Says:

    Thanks very much for posting – this is very helpful!

  13. Greg Says:

    chi3×10-
    Thanks for posting this! I’m desperately trying to get my experiments under way and I’ve got enough to do without figuring this out!

    One question: my compiler is setup strictly for C, no C++; I’ve translated the code most of the way (I think) but I’m sketchy on pointers. Can you direct me to anything like a C++ to C translation guide, or better yet post a C version? That’s asking a lot…
    In any case, thank you!

  14. chi3x10 Says:

    Greg,

    All you need to do is to modify memory allocation thing. Use malloc(…..) instead of new. Use free(…) instead of delete. It should work fine.

  15. Greg Says:

    Thanks for the quick reply!

    That’s what I thought (and what I did) but …
    Ok, I just went back and found a bug in my translation, so now I’m not getting warnings, but I’m still segfaulting when I try to call the function.

    To be clear, instead of (for example)
    float *temp = new float[(order-1)*(order-1)];
    float **minor = new float*[order-1];

    I should use:
    float *temp = malloc(sizeof(float)*((order-1)*(order-1)));
    float **minor = malloc(sizeof(float)*(order-1));

    Perhaps I’m having a problem initializing MyMatrix (as the above commenter).
    Can I do direct assignment, i.e. (for 3×3 test case):

    float **MyMatrix=malloc(sizeof(float)*3*3);
    float **MyInverse=malloc(sizeof(float)*3*3);
    MyMatrix[0][0]=1.2;
    MyMatrix[0][1]=0.95;
    //etc,etc

    and then make the call as
    MatrixInversion(MyMatrix, 3, MyInverse);

    Thanks for your help!

  16. Tom Says:

    Hello,

    Thanks for sharing your code.

    I am having a strange problem, the result being returned in Y is basically of type -1.#IND and 1.#QNAN.

    I am using your code exactly as it is, and calling it as follows for a 4×4 matrix. Do you have any idea why? Thanks so much!

    float **MyMatrix;
    MyMatrix = new float*[4];
    for(int i=0;i<4;i++)
    MyMatrix[i] = new float[4];

    float **Y;
    Y = new float*[4];
    for(int i=0;i<4;i++)
    Y[i] = new float[4];

    for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    MyMatrix[i][j] = i * 1.0;

    cout<<endl;
    for (int i=0;i<4;i++)
    for (int j=0;j<4;j++)
    cout<<MyMatrix[i][j]<<” \n”;

    MatrixInversion(MyMatrix, 4, Y);

    for (int i=0;i<4;i++)
    for (int j=0;j<4;j++)
    cout<<Y[i][j]<<” \n”;

  17. chi3x10 Says:

    Tom,

    Maybe the problem is that your matrix is singular. You can check if a matrix is singular by calculating the determinant of the matrix first. If determinant of a matrix is zero, the matrix is invertible.
    Hope this helps

  18. reed Says:

    why do I get an error GetMinor undefined and CalcDeterminant undefined. trying to establish matrix determinant (n less than =to 100)

  19. dcrow Says:

    hey, can anyone post here your full source code? tnx..

  20. Naz Says:

    Hello… i used your code in my work… and it seemed to work fine.. thanks a lot…

  21. chris Says:

    Hi Jason – great work :) … so is it ok to incorporate your code into my GPL’d FOSS project?

    • chi3x10 Says:

      sure! but I hope you knows that this method would become really slow when the dimensionality of the matrix is high (like 10×10).

Leave a Reply