化Hertinan matrix eigen problem into a real symmetric matrix eigen problem:
原理:
与matlab的结果进行对比:
A=[ ...
( 3.0 + 0.0*j) (-2.0 -2.0*j) (-0.9 -0.9*j) (-0.5 -0.5*j); ...
(-2.0 + 2.0*j) ( 4.0 + 0.0*j) ( 1.0 + 1.0*j) (-0.7 -0.5*j); ...
(-0.9 + 0.9*j) ( 1.0 -1.0*j) (-1.0 + 0.0*j) ( 0.1 + 0.1*j); ...
(-0.5 + 0.5*j) (-0.7 + 0.5*j) ( 0.1 -0.1*j) ( 1.0 + 0.0*j); ...
][V D]=eig(A)
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>using namespace std;
struct float2 {float x;float y;
};typedef struct float2 float2;void print_matrix(float* A, int M, int N, int lda);
void print_matrix_complex(float2* A, int M, int N, int lda);
void print_vector(float* A, int N);
/
void real_neimag_real_imag_fill(float2* A_h, int N, int lda, float* S, int n, int lds);
float max(float x, float y);
void swap(float& x, float& y);
void tred2(float* V, float* d, float* e, int n, int ldv);
void tql2(float* V, float* d, float* e, int n, int ldv);
void eigen_vector_decompose_hermitian(float2* A, int N, int lda, float2* V_cevd, float* d_cevd);
/#define NA 4/*
* complex A=(4x4) math topology:( 3.0, 0.0), (-2.0, -2.0), (-0.9, -0.9), (-0.5, -0.5),(-2.0, 2.0), ( 4.0, 0.0), ( 1.0, 1.0), (-0.7, -0.5),(-0.9, 0.9), ( 1.0, -1.0), (-1.0, 0.0), ( 0.1, 0.1),(-0.5, 0.5), (-0.7, 0.5), ( 0.1, -0.1), ( 1.0, 0.0)float A_h[NA * (2*NA)] = {//complex columnMajor: mem topology3.0, 0.0, -2.0, 2.0, -0.9, 0.9, -0.5,0.5,-2.0,-2.0, 4.0, 0.0, 1.0,-1.0, -0.7, 0.5,-0.9,-0.9, 1.0, 1.0, -1.0, 0.0, 0.1,-0.1,-0.5,-0.5, -0.7,-0.5, 0.1, 0.1, 1.0, 0.0*/int main() {float A_h[NA * (2 * NA)] = {//complex columnMajor:3.0, 0.0, -2.0, 2.0, -0.9, 0.9, -0.5, 0.5,-2.0,-2.0, 4.0, 0.0, 1.0,-1.0, -0.7, 0.5,-0.9,-0.9, 1.0, 1.0, -1.0, 0.0, 0.1,-0.1,-0.5,-0.5, -0.7,-0.5, 0.1, 0.1, 1.0, 0.0};///Parameters:int N = NA;int lda = N;float2* A = nullptr;
//___________________________________________________________________A = (float2*)malloc(lda * N * sizeof(float2));memcpy(A, A_h, lda * N * sizeof(float2));printf("A(ma)=\n");print_matrix_complex(A, N, N, N);
//______________________________________________________________// void eigen_vector_decompose(float2 * A, int N, int lda, float2 * V_cevd, float* d_cevd);float* d_cevd = nullptr;float2* V_cevd = nullptr;int ldv_cevd = N;d_cevd = (float*)malloc(N * sizeof(float));V_cevd = (float2*)malloc(ldv_cevd * N * sizeof(float2));eigen_vector_decompose_hermitian(A, N, lda, V_cevd, d_cevd);#if 0int n = 2 * N;int lds = n;float* S = nullptr;S = (float*)malloc(lds * n * sizeof(float));real_neimag_real_imag_fill((float2*)A, N, lda, S, n, lds);printf("S(ma)=\n");print_matrix(S, n, n, lds);
//______________________________________________________________int ldv_evd = n;float* V_evd = nullptr;V_evd = (float*)malloc(lds * n * sizeof(float));memcpy(V_evd, S, lds * n * sizeof(float));printf("V_evd(ma)=\n");print_matrix(V_evd, n, n, ldv_evd);float* e = nullptr;float* d_evd = nullptr;e = (float*)malloc(n * sizeof(float));d_evd = (float*)malloc(n * sizeof(float));//______________________________________________________________//void tred2(float* V, float* e, float* d, int n, int ldv);tred2(V_evd, d_evd, e, n, ldv_evd);printf("V_evd-tred2=\n");print_matrix(V_evd, n, n, ldv_evd);printf("\nd-tred2=\n");print_vector(d_evd, n);printf("\ne-tred2=\n");print_vector(e, n);//void tql2(float* V, float* d, float* e, int n, int ldv);tql2(V_evd, d_evd, e, n, ldv_evd);printf("\nV_evd-tql2=\n");print_matrix(V_evd, n, n, ldv_evd);printf("\nd-tql2=\n");print_vector(d_evd, n);printf("\ne-tql2=\n");print_vector(e, n);
//_________________________________________________________________________________/**float* d_cevd = nullptr;float2* V_cevd = nullptr;int ldv_cevd = N;d_cevd = (float*)malloc(N * sizeof(float));V_cevd = (float2*)malloc(ldv_cevd * N * sizeof(float2));*/for(int i=0; i<N; i++)d_cevd[i] = d_evd[2 * i];printf("\nd_cevd=\n");print_vector(d_cevd, N);for (int j = 0; j < N; ++j){int j2 = 2 * j;for (int i = 0; i < N; ++i) {V_cevd[i + j * ldv_cevd].x = V_evd[i + j2 * ldv_evd];//complex<Type>(RV[i][j2], RV[i + N][j2]);V_cevd[i + j * ldv_cevd].y = V_evd[(i + N) + j2 * ldv_evd];}}printf("\nV_cevd=\n");print_matrix_complex(V_cevd, N, N, ldv_cevd);#endifreturn 0;
}void real_neimag_real_imag_fill( float2 * A_h, int N, int lda, float* S, int n, int lds)//n=2*N
{float2 *A;A = A_h;for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {S[i +j*lds] = A[i+ j*lda].x;S[i +(j + N)*lds] = -A[i +j*lda].y;S[(i + N)+ j*lds] = -S[i +(j + N)*lds];S[(i + N)+ (j + N)*lds] = S[i+ j*lds];}}
}//typedef float float;void tred2(float *V, float* d, float *e, int n, int ldv)
{for (int j = 0; j < n; ++j)//LL::d[j] = V[n - 1][j];d[j] = V[(n - 1)+j*ldv];// Householder reduction to tridiagonal formfor (int i = n - 1; i > 0; --i){// scale to avoid under/overflowfloat scale = 0;float h = 0;for (int k = 0; k < i; ++k) {// scale += fabs(d[k]);printf(" d[k]=%f", d[k]);scale += fabs(d[k]);printf(" scale=%f", scale);}printf("\n______________\n");if (scale == 0){e[i] = d[i - 1];for (int j = 0; j < i; ++j){d[j] = V[(i - 1)+j*ldv];V[i+j*ldv] = 0;V[j+i*ldv] = 0;}}else{// generate Householder vectorfor (int k = 0; k < i; ++k){d[k] /= scale;h += d[k] * d[k];}float f = d[i - 1];float g = sqrt(h);if (f > 0)g = -g;e[i] = scale * g;h = h - f * g;d[i - 1] = f - g;for (int j = 0; j < i; ++j)e[j] = 0;// Apply similarity transformation to remaining columns.for (int j = 0; j < i; ++j){f = d[j];V[j+i*ldv] = f;g = e[j] + V[j+j*ldv] * f;for (int k = j + 1; k <= i - 1; ++k){g += V[k+j*ldv] * d[k];e[k] += V[k+j*ldv] * f;}e[j] = g;}f = 0;for (int j = 0; j < i; ++j){e[j] /= h;f += e[j] * d[j];}float hh = f / (h + h);for (int j = 0; j < i; ++j)e[j] -= hh * d[j];for (int j = 0; j < i; ++j){f = d[j];g = e[j];for (int k = j; k <= i - 1; ++k)V[k+j*ldv] -= (f * e[k] + g * d[k]);d[j] = V[(i - 1)+j*ldv];V[i+j*ldv] = 0;}}d[i] = h;}// accumulate transformationsfor (int i = 0; i < n - 1; i++){V[n - 1+i*ldv] = V[i+i * ldv];V[i+i * ldv] = 1;float h = d[i + 1];if (h != 0){for (int k = 0; k <= i; ++k)d[k] = V[k+(i + 1) *ldv] / h;for (int j = 0; j <= i; ++j){float g = 0;for (int k = 0; k <= i; ++k)g += V[k+(i + 1) * ldv] * V[k+j * ldv];for (int k = 0; k <= i; ++k)V[k+j * ldv] -= g * d[k];}}for (int k = 0; k <= i; ++k)V[k+(i + 1) * ldv] = 0;}for (int j = 0; j < n; ++j){d[j] = V[(n - 1)+j * ldv];V[(n - 1)+j * ldv] = 0;}V[(n - 1)+(n - 1) * ldv] = 1;e[0] = 0;
}float max(float x, float y) {return (x > y) ? x : y;
}void swap(float& x, float& y) {float tmp;tmp = x;x = y;y = tmp;
}void tql2(float* V, float* d, float* e, int n, int ldv)
{for (int i = 1; i < n; ++i)e[i - 1] = e[i];e[n - 1] = 0;float f = 0;float tst1 = 0;float eps = pow(2.0, -52.0);for (int l = 0; l < n; ++l){// find small subdiagonal elementtst1 = max(tst1, fabs(d[l]) + fabs(e[l]));int m = l;// original while-loop from Java codewhile (m < n){if (fabs(e[m]) <= eps * tst1)break;m++;}// if m == l, d[l] is an eigenvalue, otherwise, iterateif (m > l){int iter = 0;do{iter = iter + 1;// compute implicit shiftfloat g = d[l];float p = (d[l + 1] - g) / (2.0 * e[l]);float r = hypot(p, 1.0);if (p < 0)r = -r;d[l] = e[l] / (p + r);d[l + 1] = e[l] * (p + r);float dl1 = d[l + 1];float h = g - d[l];for (int i = l + 2; i < n; ++i)d[i] -= h;f += h;// implicit QL transformation.p = d[m];float c = 1;float c2 = c;float c3 = c;float el1 = e[l + 1];float s = 0;float s2 = 0;for (int i = m - 1; i >= l; --i){c3 = c2;c2 = c;s2 = s;g = c * e[i];h = c * p;r = hypot(p, e[i]);e[i + 1] = s * r;s = e[i] / r;c = p / r;p = c * d[i] - s * g;d[i + 1] = h + s * (c * g + s * d[i]);// accumulate transformation.for (int k = 0; k < n; ++k){h = V[k+(i + 1)*ldv];V[k+(i + 1) * ldv] = s * V[k+i * ldv] + c * h;V[k+i * ldv] = c * V[k+i * ldv] - s * h;}}p = -s * s2 * c3 * el1 * e[l] / dl1;e[l] = s * p;d[l] = c * p;} while (fabs(e[l]) > eps * tst1);}d[l] += f;e[l] = 0;}// Sort eigenvalues and corresponding vectors.for (int i = 0; i < n - 1; ++i){int k = i;float p = d[i];for (int j = i + 1; j < n; ++j)if (d[j] < p){k = j;p = d[j];}if (k != i){d[k] = d[i];d[i] = p;for (int j = 0; j < n; ++j)swap(V[j+i * ldv], V[j+k * ldv]);}}
}void eigen_vector_decompose_hermitian(float2* A, int N, int lda, float2* V_cevd, float* d_cevd)
{int n = 2 * N;int lds = n;float* S = nullptr;S = (float*)malloc(lds * n * sizeof(float));real_neimag_real_imag_fill((float2*)A, N, lda, S, n, lds);printf("S(ma)=\n");print_matrix(S, n, n, lds);//______________________________________________________________int ldv_evd = n;float* V_evd = nullptr;V_evd = (float*)malloc(lds * n * sizeof(float));memcpy(V_evd, S, lds * n * sizeof(float));printf("V_evd(ma)=\n");print_matrix(V_evd, n, n, ldv_evd);float* e = nullptr;float* d_evd = nullptr;e = (float*)malloc(n * sizeof(float));d_evd = (float*)malloc(n * sizeof(float));//______________________________________________________________//void tred2(float* V, float* e, float* d, int n, int ldv);tred2(V_evd, d_evd, e, n, ldv_evd);printf("V_evd-tred2=\n");print_matrix(V_evd, n, n, ldv_evd);printf("\nd-tred2=\n");print_vector(d_evd, n);printf("\ne-tred2=\n");print_vector(e, n);//void tql2(float* V, float* d, float* e, int n, int ldv);tql2(V_evd, d_evd, e, n, ldv_evd);printf("\nV_evd-tql2=\n");print_matrix(V_evd, n, n, ldv_evd);printf("\nd-tql2=\n");print_vector(d_evd, n);printf("\ne-tql2=\n");print_vector(e, n);//_________________________________________________________________________________/**float* d_cevd = nullptr;float2* V_cevd = nullptr;d_cevd = (float*)malloc(N * sizeof(float));V_cevd = (float2*)malloc(ldv_cevd * N * sizeof(float2));*/int ldv_cevd = N;for (int i = 0; i < N; i++)d_cevd[i] = d_evd[2 * i];printf("\nd_cevd=\n");print_vector(d_cevd, N);for (int j = 0; j < N; ++j){int j2 = 2 * j;for (int i = 0; i < N; ++i) {V_cevd[i + j * ldv_cevd].x = V_evd[i + j2 * ldv_evd];//complex<Type>(RV[i][j2], RV[i + N][j2]);V_cevd[i + j * ldv_cevd].y = V_evd[(i + N) + j2 * ldv_evd];}}printf("\nV_cevd=\n");print_matrix_complex(V_cevd, N, N, ldv_cevd);}void print_vector(float* A, int N) {for (int idx = 0; idx < N; idx++) {printf("%7.4f ", A[idx]);}
}
void print_matrix(float* A, int M, int N, int lda)
{for (int i = 0; i < M; i++) {for (int j = 0; j < N; j++) {printf("%7.4f ", A[i + j * lda]);}printf("\n");}
}
void print_matrix_complex(float2* A, int M, int N, int lda) {for (int i = 0; i < M; i++) {for (int j = 0; j < N; j++) {//*(sizeof(complex<float>)/sizeof(float))printf("(%7.4f, %7.4f)", A[i + j * lda].x, A[i + j * lda].y);}printf("\n");}
}
运行:
结果分析:
matlab: