0

I am trying to write a function which gets a matrix and the dimension (square), and returns the inverse matrix in C. Further, I will use it in solving a least square matrix solution function!

I have got most of the ideas and algorithms from online sources and tried to change them according to my program. When I build and run it (in Code::Blocks and ideone.com online compiler) I get either runtime error or irrelevant results. Would be great if someone could help me.

Here is my code:

/* Inverse of NxN matrix */

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

double CalcDeterminant(int D, double matrix[D][D])
{
  /* Conversion of matrix to upper triangular */
int i, j, k;
double ratio, det=1;
for (I = 0; I < D; i++) {
    for(j = 0; j < D; j++){
        if(j>i){
            ratio = matrix[j][i]/matrix[i][i];
            for(k = 0; k < D; k++){
                matrix[j][k] -= ratio * matrix[i][k];
            }
        }
    }
 }

 for(i = 0; i < D; i++)
 {
    det *= matrix[i][i];
 }

 return det;
}


double ** MatrixInverse(int size, double matrix[size][size])
{
int p,q,m,n,i,j,k;
double det;
double **m_inverse = (double **) malloc(sizeof(int) * size);
for (k = 0; k < size; k++) {
 m_inverse[k] = (double *) malloc(sizeof(int) * size);
}

double **dummy = (double **) malloc(sizeof(int) * size);
for (k = 0; k < size; k++) {
dummy[k] = (double *) malloc(sizeof(int) * size);
}
 /////////////////////////
 for (q=0;q<size;q++)
 {
     for (p=0;p<size;p++)
     {
         m=0;
         n=0;
         for (i=0;i<size;i++)
         {
             for (j=0;j<size;j++)
             {
                 if (i != q && j != p)
                 {
                    dummy[m][n]=matrix[i][j];
                    if (n<(size-2))
                    {
                       n++;
                    }
                    else
                    {
                        n=0;
                        m++;
                    }
                 }
             }
         }
        det = CalcDeterminant(size-1, dummy);
        printf("%f\n", det);
        m_inverse[q][p]=pow(-1,(q+p))*det;
     }
  }
  for (i=0;i<size;i++)
 {
     for (j=0;j<size;j++)
     {
         dummy[i][j]=m_inverse[j][i];
     }
 }
   det=CalcDeterminant(size, matrix);
 for (i=0;i<size;i++)
 {
     for (j=0;j<size;j++)
     {
         m_inverse[i][j]= dummy[i][j] / det;
     }
  }


 for(i = 0; i < size; i++)
    free(dummy[i]);
 free(dummy);    

return m_inverse;

}


int main()
{
int i, j;
int D = 5;
 // just an example matrix
double A[5][5] = {{1,2,3,4,6},
                  {6,1,5,3,8},
                  {2,6,4,9,9},
                  {1,3,8,3,4},
                  {5,7,8,2,5}};

printf("Original matrix\n");
for(i=0; i<D; i++)
{
    for(j=0; j<D; j++)
    {   
    //  A[i][j] = i+j-5;
        printf("%f\t", A[i][j]);
    }
    printf("\n");
} 
double **A_inverse = MatrixInverse(D, A); 
printf("Inverse Matrix\n");
for(i=0; i<D; i++)
{
    for(j=0; j<D; j++)
    {   
        printf("%f\t", A_inverse[i][j]);
    }
    printf("\n");
}

det = CalcDeterminant(D, A);
printf("%f\n", det);
return 0;
}
MRM
  • 1
  • 6
  • 2
    Standard warning: do not cast `void *` as returned by `malloc`&friends. – too honest for this site Jul 16 '15 at 11:42
  • 2
    Do not ignore compiler warnings. A warning you don't understand means you don't know what you are doing. Don't even think about maybe trying to to run the program until you are warning free. – n. m. could be an AI Jul 16 '15 at 11:55
  • @n.m.: I completely agree, But the standard warnings of most compilers are actually not sufficient - expecially for beginners. One should always have `-Wall` enabled, I generally recommend to add `-Wextra` and `-Wconversion`. The latter should be watched carefully. – too honest for this site Jul 16 '15 at 12:02
  • If you're doing a least square fit for polynomials, there's way to avoid having to invert a matrix. [opls.rtf](http://rcgldr.net/misc/opls.rtf) . – rcgldr Jul 16 '15 at 14:44
  • @opls.rtf thanks for the comment. I am trying to solve a AX=B problem by calculating the pseudo-inverse of A. Do you know if the mentioned way would work in this case? – MRM Jul 17 '15 at 08:31
  • this line: 'for (I = 0; I < D; i++) {' does not compile. I suspect it should be: 'for (i = 0; i < D; i++) {' – user3629249 Jul 17 '15 at 12:53
  • for readability by us humans, please consistently indent the code (never use tabs for indenting) Suggest 4 spaces after every opening brace '{' and un-indent before every closing brace '}' Only place one variable declaration per statement. for two main reasons. 1) for readability 2) so the variables are easy to document, so us humans know what/why each variable is used – user3629249 Jul 17 '15 at 12:57
  • as Olaf mentioned, do not cast the returned value from malloc. Also, always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Jul 17 '15 at 13:01
  • this line: 'det = CalcDeterminant(D, A);' is using 'det' which is not declared. This is an error that results in a compile failure. When asking about a runtime problem. always post code the cleanly compiles, is minimal in size, and clearly demonstrates the problem. always enable all the warnings when compiling, then fix those warnings. (for gcc, at a minimum use: '-Wall -Wextra -pedantic' – user3629249 Jul 17 '15 at 13:06
  • this line: 'det = CalcDeterminant(size-1, dummy);' the second argument is if type double** but function is expecting different argument type – user3629249 Jul 17 '15 at 13:10
  • @MRM - The purpose of using orthogonal polynomials for a least squares fit [opls.rtf](http://rcgldr.net/misc/opls.rtf) is to avoid having to invert a matrix. – rcgldr Jul 18 '15 at 08:20

2 Answers2

2

This line contains a major error, one that will cause problems when sizeof(int) is not equal to sizeof(int *) (which is what usually happens on 64-bit platforms):

double **m_inverse = (double **) malloc(sizeof(int) * size);

Same with the allocation for dummy.

You are allocating an array of pointers to int, so the correct here would be

double **m_inverse = malloc(sizeof(int *) * size);

Later you have a problematic line here:

det = CalcDeterminant(size-1, dummy);

Normally a pointer-to-pointer to some type is not the same an array-of-arrays of some type (see e.g. this old answer of mine to help you understand why).

Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks for your comment. So you mean I should insert (sizeof(int) size) instead ? Sorry I am not really into it. – MRM Jul 16 '15 at 11:45
  • @MRM Check your code, are you missing a closing parenthesis? – Some programmer dude Jul 16 '15 at 11:54
  • So, now it is done with allocation :) And now the determinant function. Shall I define it as CalcDeterminant(int D, double **matrix) ? this case I get runtime error again, and don't know how to call it in main or the Inverse function. – MRM Jul 16 '15 at 11:59
  • @MRM If you declare the argument as a pointer-to-pointer then you get a problem when calling with the matrix from the `main` function, so no matter how you do it you will have to rework more than just the `CalcDeterminant` function. The easiest is probably to allocate and initialize the matrix in the `main` function, and let the function take a `double **` argument. – Some programmer dude Jul 16 '15 at 12:02
  • @MRM Also, you should learn how to use a debugger, because then you can catch the crash "in action", and see exactly where in your code it happens, and will also be able to check the function call stack *as well* as the values of involved variables. – Some programmer dude Jul 16 '15 at 12:03
  • I cannot define it in main, just as I said it would be at the end called by a function named "LeastSquare_MatrixSolve(A,X,b)" and then this function is called in another function. So basically I need to get rid of it here. – MRM Jul 16 '15 at 12:21
  • if using a debugger (a very good idea) then compile/link the code with the appropriate parameters so the debug info is available. (for gcc and gdb, use -ggdb so outputs show line numbers, not addresses – user3629249 Jul 17 '15 at 13:18
1

When allocating memory, always use the correct type for the size. You use sizeof(int) everywhere, even if double or pointer is required. Hint: use sizeof(*<pointer you assign the result to>). This way, you always use the correct size.

Note: Do not cast void * as returned by malloc & friends.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • So as I said to Joachim, this is just a little part of a function, and there are 2 major function calls in que. And I'm a beginner (just worked with matlab!). If double ** Func(...) is a appropriate to return 2d array, what would you suggest to use? I have tried many types, all from online sources, but this was the most suitable one for the rest of the program. – MRM Jul 16 '15 at 12:47
  • @MRM: That is an array of pointers to `double`. I strongly recommend to read a C book; that will cover all the basics. Please understand we cannot provide a tutorial about that here, but that is vital to understand C. Without that knowledge, you will eventually fall into the next tar-pit. A 2D array is actually passed the same as a 1D array - by ` *`. The semantics are informal in C. – too honest for this site Jul 16 '15 at 13:00
  • Thanks @Olaf. I was just following this: – MRM Jul 16 '15 at 13:08
  • @MRM: Blindly following some internet recipe is **always** a bad idea. You might take such as a first idea, but then look up the concepts you do not understand in a book or tutorial (both can be found for free or money). – too honest for this site Jul 16 '15 at 13:16