一、前言
-
本章开始,详细讲解实数和复数矩阵的转置、复制、行列式、代数余子式、逆等运算,由简入繁,并给出函数和测试demo的C代码,以及与matlab计算的结果;
-
并且,本章出现了我在编写函数、后期与matlab联调跑数据时候出现的几个坑,读者稍微留意一下。
二、复制运算
复制运算,即对矩阵进行复制操作,将一个已知的矩阵原样赋值给另一个矩阵,且原矩阵内容不变:
/* Copy: Complex matrixA = Complex matrixB */
void CopyMatrix(const Matrix* matrix_A, Matrix* matrix_B)
{
if (IsNullComplexMatrix(matrix_A))
{
puts("ERROE: An invalid matrix!\n");
return;
}
//matrix_B->row = MatrixRow(matrix_A);
//matrix_B->column = MatrixColumn(matrix_A);
else
{
int index = 0;
for (int row_i = 0; row_i < matrix_A->row; row_i++)
{
for (int column_j = 0; column_j < matrix_A->column; column_j++)
{
index = matrix_B->column * row_i + column_j;
matrix_B->arrayComplex[index] = matrix_A->arrayComplex[index];
}
}
// OR:
// memcpy(matrix_B->arrayComplex, matrix_A->arrayComplex, MatrixSize(matrix_A) * sizeof(ComplexType));
}
}
说明:
(1) 复制函数较为简单,关于测试的过程笔者就免去了;
(2) 同样对已知的矩阵matrix_A形参添加一个const限定符,然后在函数内部刚开始需要对该矩阵的存在性进行判断;
(3) 其实可以添加一个对被复制和赋值的矩阵matirx_B的行列数的判断,即确保两个矩阵最好size一样:
if( (MatrixRow(matirx_B) != MatrixRow(matrix_A)) ||(MatrixColumn(matrix_B) != MatrixColumn(matrix_A)) )
{
DestroyComplexMatrix(&matirx_B);
InitComplexMatrix(matrix_B, matrix_A.row, matrix_A.column);
}
(4) 这里也可以看到,对矩阵的索引有很多种不同的形式,可以是二维数学矩阵的形式,那就需要两个for循环语句,如果是以一维指针索引的形式,那就是一个for即可,另外考虑到角标冗长,建议读者定义一个局部变量来保存,或者直接用指针来遍历访问cell;
(5) 此外,接(4),因为矩阵元素全部用指针来索引,因此为了充分运用C语言库函数,直接使用memcpy()函数将矩阵整体赋值,完全不用使用for循环增加函数算法的时间复杂度,memcpy()函数包含在头文件string.h中,C++里是cstring,函数原型为:
void *memcpy(void *destin, void *source, unsigned n);
三、转置运算
笔者这里重点讲解一下转置运算。
1.实数矩阵的转置
对于实数矩阵,转置即元胞位置作对称变换即可,即(i, j)--->(j, i)即可。这里我先给出实数矩阵的转置,比较简单:
/* Change Postion: [i, j] -- > [j, i] */
void TransPoseMatrix(const Matrix* matrixA, Matrix* matrixB) // Tip:if A==U * U', then A'==A
{ // So this function is not a necessity
if (IsNullComplexMatrix(matrixA))
{
puts("ERROE: An invalid matrix!\n");
return;
}
else if ((matrixA->row != matrixB->column) || (matrixA->column != matrixB->row))
{
puts("ERROE: An incompatable matrix!\n");
return;
}
else
{
for (int row_i = 0; row_i < matrixA->row; row_i++)
{
for (int column_j = 0; column_j < matrixA->column; column_j++)
{
matrixB->arrayComplex[column_j * matrixB->column + row_i] = \
matrixA->arrayComplex[row_i * matrixA->column + column_j]; // Attention!!!
}
}
}
}
说明:
其测试笔者这里省略,直接在下一节中可以得到验证。
2.复数矩阵的转置
对于复数矩阵,转置不仅是元胞位置做对称变换,还要对每个元胞作共轭运算,即(i, j)--->(j, i),且a+bj--->a-bj,code如下:
/* Conjugate Complex: Complex_B = creal(Complex_A) - cimag(Complpex_A) */
ComplexType ConjugateComplex(const ComplexType Complex_A)
{
ComplexType Complex_B;
Complex_B._Val[0] = creal(Complex_A);
Complex_B._Val[1] = cimag(Complex_A) * (-1.0);
return Complex_B;
}
/* Transposition: Complex matrixB = Complex matrixA' */
void TransMatrix(const Matrix* matrixA, Matrix* matrixB) // matrixB is transposal matrix
{
if (IsNullComplexMatrix(matrixA))
{
puts("ERROE: An invalid matrix!\n");
return;
}
else if ( ( matrixA->row != matrixB->column) || (matrixA->column != matrixB->row) )
{
puts("ERROE: An incompatable matrix!\n");
return;
}
else
{
for (int row_i = 0; row_i < matrixA->row; row_i++)
{
for (int column_j = 0; column_j < matrixA->column; column_j++)
{
// Transpose: position and sign w.r.t a Complex Number; only position w.r.t a Double Number
matrixB->arrayComplex[column_j * matrixB->column + row_i] = \
ConjugateComplex( matrixA->arrayComplex[row_i * matrixA->column + column_j] ); // Attention!!!
// OR
/*
matrixB->arrayComplex[column_j * matrixB->column + row_i]._Val[0] = \
creal(matrixA->arrayComplex[row_i * matrixA->column + column_j]);
matrixB->arrayComplex[column_j * matrixB->column + row_i]._Val[1] = \
cimag(matrixA->arrayComplex[row_i * matrixA->column + column_j]) * (-1.0);
*/
}
}
}
}
说明:
(1) 同样对矩阵的大小、存在性进行判断;
(2) 这里出现了新的嵌套调用的小函数,即第一个函数ConjugateComplex(),用于对一个复数作共轭运算,即虚部取反;
(3) 第二个函数对应于上一小节中的实数矩阵转置运算函数,唯一区别在于调用了共轭运算函数,将每个cell作共轭运算之后赋值给对应转置位置;
(4) 这里提一下,注意两个矩阵指针的下角标索引,这个地方也是我当时出现的一个坑之一,我第一次写的是: