I am working on a problem that requires solving 3 simultaneous equations of 3 variables. Reading:
https://www.mathsisfun.com/algebra/systems-linear-equations-matrices.html
I see that this can be solved by determining an inverse matrix of the matrix representation of the 3 equations. I found this C code that uses the GSL library at github for calculating inverse matrices:
https://gist.github.com/bjd2385/7f4685e703f7437e513608f41c65bbd7
(Many thanks to it's author, Mr. Doyle.)
I had read that if one multiplies a matrix by its inverse one should get an identity matrix (a matrix with 1.0s down the diagonal and 0.0s every where else). So I figured as a sanity check for the above github code, I could modify it to multiply the resultant inverse by the original matrix and display the result. If the result is an identity matrix, that validates the inverse calculation.
What I am finding is that, at least for the simple 2X2 matrix case, while the result of the inverse calculation looks correct, the subsequent matrix multiply is not resulting in an identity matrix.
I'm new to this GSL library, so perhaps I am just not calling the gsl_blas_dgemm() library function correctly to perform the matrix multiplication.
I've copied the modified code below:
/* A simple example of inverting a matrix using the gsl */
/* 1-26-2021, modified to sanity check result */
/* code doesn't seem to work */
#define HAVE_INLINE
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_blas_types.h>
#include <gsl/gsl_matrix_double.h>
#include <gsl/gsl_linalg.h>
gsl_matrix *invert_a_matrix(gsl_matrix *matrix);
void print_mat_contents(gsl_matrix *matrix);
void randomize_mat_contents(gsl_matrix *matrix);
static size_t size = 2;
/************************************************************
* PROCEDURE: invert_a_matrix
*
* DESCRIPTION: Invert a matrix using GSL.
*
* RETURNS:
* gsl_matrix pointer
*/
gsl_matrix *
invert_a_matrix(gsl_matrix *matrix)
{
gsl_permutation *p = gsl_permutation_alloc(size);
int s;
// Compute the LU decomposition of this matrix
gsl_linalg_LU_decomp(matrix, p, &s);
// Compute the inverse of the LU decomposition
gsl_matrix *inv = gsl_matrix_alloc(size, size);
gsl_linalg_LU_invert(matrix, p, inv);
gsl_permutation_free(p);
return inv;
}
/************************************************************
* PROCEDURE: print_mat_contents
*
* DESCRIPTION: Print the contents of a gsl-allocated matrix
*
* RETURNS:
* None.
*/
void
print_mat_contents(gsl_matrix *matrix)
{
size_t i, j;
double element;
for (i = 0; i < size; ++i) {
for (j = 0; j < size; ++j) {
element = gsl_matrix_get(matrix, i, j);
printf("%f ", element);
}
printf("
");
}
}
/************************************************************
* PROCEDURE: randomize_mat_contents
*
* DESCRIPTION: Overwrite entries in matrix with randomly
* generated values.
*
* RETURNS:
* None.
*/
void
randomize_mat_contents(gsl_matrix *matrix)
{
size_t i, j;
double random_value;
double range = 1.0 * RAND_MAX;
for (i = 0; i < size; ++i) {
for (j = 0; j < size; ++j) {
// generate a random value
random_value = rand() / range;
// set entry at i, j to random_value
gsl_matrix_set(matrix, i, j, random_value);
}
}
}
int
main(void)
{
srand(time(NULL));
gsl_matrix *mat = gsl_matrix_alloc(size, size);
// fill this matrix with random doubles
randomize_mat_contents(mat);
// let's see the original now
printf("Original matrix:
");
print_mat_contents(mat);
printf("
");
// compute the matrix inverse
gsl_matrix *inverse = invert_a_matrix(mat);
printf("Inverted matrix:
");
print_mat_contents(inverse);
printf("
");
gsl_matrix *product = gsl_matrix_calloc(size, size);
// if inverse is truly the inverse of mat, then mat * inverse should = identity matrix
printf("product before:
");
print_mat_contents(product);
printf("
");
int error;
// neither of these results in an identity matrix, 8^(
error = gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, inverse, mat, 0.0, product);
// error = gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, mat, inverse, 0.0, product);
// error = gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, inverse, mat, 0.0, product);
if (error) {
fprintf(stderr, "gsl_blas_dgemm returned %d
", error);
}
printf("inverse * mat:
");
print_mat_contents(product);
gsl_matrix_free(mat);
gsl_matrix_free(inverse);
gsl_matrix_free(product);
return 0;
}
In summary:
Create a matrix with random contents, print it.
Calculate its inverse, print the inverse.
Call gsl_blas_dgemm() to multiply the matrix by its inverse, print what should be an identity matrix.
When compile, link and run the program on my ubuntu 20.04 laptop, I get this:
~/opengl/matrix_code/2by2_inverter$ gcc inverter.c -lgsl -lgslcblas -lm
~/opengl/matrix_code/2by2_inverter$ ./a.out
Original matrix:
0.317588 0.113800
0.280836 0.190114
Inverted matrix:
6.689703 -4.004360
-9.882010 11.175224
product before:
0.000000 0.000000
0.000000 0.000000
inverse * mat:
-1.416400 0.402961
6.743603 -0.124569
~/opengl/matrix_code/2by2_inverter$
Now if I do the matrix multiply of the original matrix times its inverse "by hand" I find that the result is a 2X2 identity matrix:
Upper left corner: 0.317588*6.689703+0.113800*-9.882010 = .999996658 ~= 1.0
Upper right corner: 0.317588*-4.004360+0.113800*11.175224 = .000003808 ~= 0.0
Lower left corner: 0.280836*6.689703+0.190114*-9.882010 = .000000982 ~= 0.0
Lower right corner: 0.280836*-4.004360+0.190114*11.175224 = .999998091 ~= 1.0
Granted, the coordinates of the identity matrix are not exactly 1.0 and 0.0, but some error is expected. From this I conclude that the function invert_a_matrix() is doing the right thing, at least for a 2X2 matrix.
But try as I might I cannot figure out how to get the call to gsl_blas_dgemm() to produce the identity matrix.
Note that I installed the GSL libraries from the Ubuntu repository via:
~$ sudo apt-get install libgsl-dev
Any clues as to what I am doing wrong?
Thanks in advance
question from:
https://stackoverflow.com/questions/65927354/call-to-gsl-blas-dgemm-isnt-working-as-expected