Matrix 调用gsl_blas_dgemm()是';他没有按预期工作
我正在研究一个需要解3个变量的联立方程组的问题。阅读: 我知道这可以通过确定3个方程的矩阵表示的逆矩阵来解决。我发现这段C代码使用github的GSL库计算逆矩阵: (多亏了它的作者道尔先生。) 我曾读到,如果一个矩阵乘以它的逆矩阵,那么应该得到一个单位矩阵(一个对角线向下1.0,其他地方0.0的矩阵)。因此,作为上述github代码的健全性检查,我可以对其进行修改,以将结果逆乘以原始矩阵并显示结果。如果结果是单位矩阵,则验证反向计算 我发现,至少对于简单的2X2矩阵情况,虽然逆计算的结果看起来正确,但随后的矩阵乘法不会产生单位矩阵 我是这个GSL库的新手,所以我可能只是没有正确调用GSL_blas_dgemm()库函数来执行矩阵乘法 我复制了下面修改过的代码:Matrix 调用gsl_blas_dgemm()是';他没有按预期工作,matrix,gsl,Matrix,Gsl,我正在研究一个需要解3个变量的联立方程组的问题。阅读: 我知道这可以通过确定3个方程的矩阵表示的逆矩阵来解决。我发现这段C代码使用github的GSL库计算逆矩阵: (多亏了它的作者道尔先生。) 我曾读到,如果一个矩阵乘以它的逆矩阵,那么应该得到一个单位矩阵(一个对角线向下1.0,其他地方0.0的矩阵)。因此,作为上述github代码的健全性检查,我可以对其进行修改,以将结果逆乘以原始矩阵并显示结果。如果结果是单位矩阵,则验证反向计算 我发现,至少对于简单的2X2矩阵情况,虽然逆计算的结果看
/* 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("\n");
}
}
/************************************************************
* 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:\n");
print_mat_contents(mat);
printf("\n");
// compute the matrix inverse
gsl_matrix *inverse = invert_a_matrix(mat);
printf("Inverted matrix:\n");
print_mat_contents(inverse);
printf("\n");
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:\n");
print_mat_contents(product);
printf("\n");
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\n", error);
}
printf("inverse * mat:\n");
print_mat_contents(product);
gsl_matrix_free(mat);
gsl_matrix_free(inverse);
gsl_matrix_free(product);
return 0;
}
现在,如果我手工将原始矩阵乘以其逆矩阵,我发现结果是2X2单位矩阵:
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
诚然,单位矩阵的坐标不完全是1.0和0.0,但预计会有一些误差。由此我得出结论,函数invert_a_matrix()做的事情是正确的,至少对于2X2矩阵是这样
但是,尽管我可能会尝试,但我无法弄清楚如何调用gsl_blas_dgemm()来生成标识矩阵
请注意,我通过以下方式从Ubuntu存储库安装了GSL库:
~$sudo apt get安装libgsl dev
关于我做错了什么,有什么线索吗
提前谢谢我解决了这个问题。调用invert_a_matrix()修改传入的矩阵。因此,当我调用gsl_blas_dgemm()时,我并没有用原始矩阵乘以逆矩阵
修复方法是在调用invert_a_matrix()之前分配原始矩阵的副本,并将副本传递给gsl_blas_dgemm()。这是不公平的:我花了大约2个小时才得出相同的结论。下次请在合理的情况下使用poniters来
const
,您会立即发现问题。至少要对这条评论投赞成票:-)不管怎样,至少是一些有趣的谜题和一些真实的东西!我真希望我只用了两个小时就找到了。8^(我写C代码已经有35年了,但几年前退休后,我对调试技能已经很生疏了。很抱歉浪费了大家的时间。没问题。GSL手册中有一个示例程序,它使用了degmm
,运行正常。在绝望中,我开始将您的程序转换为与示例一样的样子,并且当我评论出<代码>反THYTAYMatRX()/<代码>是宾果游戏。我使用GSL Oxasialand它是一个非常巨大的库,界面非常痛苦(至少对于C++程序员来说)。
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