📄 eigen.c
字号:
/***********************************************************
* This eigen() routine works for eigenvalue/vector analysis
* for real general square matrix A
* A will be destroyed
* rr,ri are vectors containing eigenvalues
* vr,vi are matrices containing (right) eigenvectors
*
* A*[vr+vi*i] = [vr+vi*i] * diag{rr+ri*i}
*
* Algorithm: Handbook for Automatic Computation, vol 2
* by Wilkinson and Reinsch, 1971
* most of source codes were taken from a public domain
* solftware called MATCALC.
* Credits: to the authors of MATCALC
*
* return -1 not converged
* 0 no complex eigenvalues/vectors
* 1 complex eigenvalues/vectors
* Tianlin Wang at University of Illinois
* Thu May 6 15:22:31 CDT 1993
***************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define FOR(i,n) for(i=0; i<n; i++)
#define FPN(file) fputc('\n', file)
typedef struct { double re, im; } complex;
#define csize(a) (fabs(a.re)+fabs(a.im))
#define min2(a,b) ((a)<(b)?(a):(b))
#define max2(a,b) ((a)>(b)?(a):(b))
#define BASE 2 /* base of floating point arithmetic */
#define DIGITS 50 /* no. of digits to the base BASE in the fraction */
#define MAXITER 30 /* max2. no. of iterations to converge */
/*
#define DIGITS 40
#define MAXITER 30
*/
#define pos(i,j,n) ((i)*(n)+(j))
int eigen(int job, double A[], int n, double rr[], double ri[],
double vr[], double vi[], double w[]);
void balance(double mat[], int n, int *low, int *hi, double scale[]);
void unbalance(int n, double vr[], double vi[], int low, int hi,
double scale[]);
int realeig(int job, double mat[], int n,int low, int hi, double valr[],
double vali[], double vr[], double vi[]);
void elemhess(int job, double mat[], int n, int low, int hi,
double vr[], double vi[], int work[]);
int eigen(int job, double A[], int n, double rr[], double ri[],
double vr[], double vi[], double work[])
{
/* job=0: eigen values only
1: both eigen values and eigen vectors
double w[n*2]: work space
*/
int low,hi,i,j,k, it, istate=0;
double tiny=sqrt(pow((double)BASE,(double)(1-DIGITS))), t;
balance(A,n,&low,&hi,work);
elemhess(job,A,n,low,hi,vr,vi, (int*)(work+n));
if (-1 == realeig(job,A,n,low,hi,rr,ri,vr,vi)) return (-1);
if (job) unbalance(n,vr,vi,low,hi,work);
/* sort, added by Z. Yang */
for (i=0; i<n; i++) {
for (j=i+1,it=i,t=rr[i]; j<n; j++)
if (t<rr[j]) { t=rr[j]; it=j; }
rr[it]=rr[i]; rr[i]=t;
t=ri[it]; ri[it]=ri[i]; ri[i]=t;
for (k=0; k<n; k++) {
t=vr[k*n+it]; vr[k*n+it]=vr[k*n+i]; vr[k*n+i]=t;
t=vi[k*n+it]; vi[k*n+it]=vi[k*n+i]; vi[k*n+i]=t;
}
if (fabs(ri[i])>tiny) istate=1;
}
return (istate) ;
}
/* complex funcctions
*/
complex compl (double re,double im)
{
complex r;
r.re = re;
r.im = im;
return(r);
}
complex conj2 (complex a)
{
a.im = -a.im;
return(a);
}
#define csize(a) (fabs(a.re)+fabs(a.im))
complex cplus (complex a, complex b)
{
complex c;
c.re = a.re+b.re;
c.im = a.im+b.im;
return (c);
}
complex cminus (complex a, complex b)
{
complex c;
c.re = a.re-b.re;
c.im = a.im-b.im;
return (c);
}
complex cby (complex a, complex b)
{
complex c;
c.re = a.re*b.re-a.im*b.im ;
c.im = a.re*b.im+a.im*b.re ;
return (c);
}
complex cdiv (complex a,complex b)
{
double ratio, den;
complex c;
if (fabs(b.re) <= fabs(b.im)) {
ratio = b.re / b.im;
den = b.im * (1 + ratio * ratio);
c.re = (a.re * ratio + a.im) / den;
c.im = (a.im * ratio - a.re) / den;
}
else {
ratio = b.im / b.re;
den = b.re * (1 + ratio * ratio);
c.re = (a.re + a.im * ratio) / den;
c.im = (a.im - a.re * ratio) / den;
}
return(c);
}
complex cexp (complex a)
{
complex c;
c.re = exp(a.re);
if (fabs(a.im)==0) c.im = 0;
else { c.im = c.re*sin(a.im); c.re*=cos(a.im); }
return (c);
}
complex cfactor (complex x, double a)
{
complex c;
c.re = a*x.re;
c.im = a*x.im;
return (c);
}
int cxtoy (complex x[], complex y[], int n)
{
int i;
FOR (i,n) y[i]=x[i];
return (0);
}
int cmatby (complex a[], complex b[], complex c[], int n,int m,int k)
/* a[n*m], b[m*k], c[n*k] ...... c = a*b
*/
{
int i,j,i1;
complex t;
FOR (i,n) FOR(j,k) {
for (i1=0,t=compl(0,0); i1<m; i1++)
t = cplus (t, cby(a[i*m+i1],b[i1*k+j]));
c[i*k+j] = t;
}
return (0);
}
int cmatout (FILE * fout, complex x[], int n, int m)
{
int i,j;
for (i=0,FPN(fout); i<n; i++,FPN(fout))
FOR(j,m) fprintf(fout, "%7.3f%7.3f ", x[i*m+j].re, x[i*m+j].im);
return (0);
}
int cmatinv( complex x[], int n, int m, double space[])
{
/* complex matrix inversion
x[n*m] ... m>=n
*/
int i,j,k, *irow=(int*) space;
double xmaxsize, ee=1e-20;
complex xmax, t,t1;
FOR(i,n) {
xmaxsize = 0.;
for (j=i; j<n; j++) {
if ( xmaxsize < csize (x[j*m+i])) {
xmaxsize = csize (x[j*m+i]);
xmax = x[j*m+i];
irow[i] = j;
}
}
if (xmaxsize < ee) {
printf("\nDet goes to zero at %8d!\t\n", i+1);
return(-1);
}
if (irow[i] != i) {
FOR(j,m) {
t = x[i*m+j];
x[i*m+j] = x[irow[i]*m+j];
x[ irow[i]*m+j] = t;
}
}
t = cdiv (compl(1,0), x[i*m+i]);
FOR(j,n) {
if (j == i) continue;
t1 = cby (t,x[j*m+i]);
FOR(k,m) x[j*m+k] = cminus (x[j*m+k], cby(t1,x[i*m+k]));
x[j*m+i] = cfactor (t1, -1);
}
FOR(j,m) x[i*m+j] = cby (x[i*m+j], t);
x[i*m+i] = t;
}
for (i=n-1; i>=0; i--) {
if (irow[i] == i) continue;
FOR(j,n) {
t = x[j*m+i];
x[j*m+i] = x[j*m+irow[i]];
x[ j*m+irow[i]] = t;
}
}
return (0);
}
void balance(double mat[], int n,int *low, int *hi, double scale[])
{
/* Balance a matrix for calculation of eigenvalues and eigenvectors
*/
double c,f,g,r,s;
int i,j,k,l,done;
/* search for rows isolating an eigenvalue and push them down */
for (k = n - 1; k >= 0; k--) {
for (j = k; j >= 0; j--) {
for (i = 0; i <= k; i++) {
if (i != j && fabs(mat[pos(j,i,n)]) != 0) break;
}
if (i > k) {
scale[k] = j;
if (j != k) {
for (i = 0; i <= k; i++) {
c = mat[pos(i,j,n)];
mat[pos(i,j,n)] = mat[pos(i,k,n)];
mat[pos(i,k,n)] = c;
}
for (i = 0; i < n; i++) {
c = mat[pos(j,i,n)];
mat[pos(j,i,n)] = mat[pos(k,i,n)];
mat[pos(k,i,n)] = c;
}
}
break;
}
}
if (j < 0) break;
}
/* search for columns isolating an eigenvalue and push them left */
for (l = 0; l <= k; l++) {
for (j = l; j <= k; j++) {
for (i = l; i <= k; i++) {
if (i != j && fabs(mat[pos(i,j,n)]) != 0) break;
}
if (i > k) {
scale[l] = j;
if (j != l) {
for (i = 0; i <= k; i++) {
c = mat[pos(i,j,n)];
mat[pos(i,j,n)] = mat[pos(i,l,n)];
mat[pos(i,l,n)] = c;
}
for (i = l; i < n; i++) {
c = mat[pos(j,i,n)];
mat[pos(j,i,n)] = mat[pos(l,i,n)];
mat[pos(l,i,n)] = c;
}
}
break;
}
}
if (j > k) break;
}
*hi = k;
*low = l;
/* balance the submatrix in rows l through k */
for (i = l; i <= k; i++) {
scale[i] = 1;
}
do {
for (done = 1,i = l; i <= k; i++) {
for (c = 0,r = 0,j = l; j <= k; j++) {
if (j != i) {
c += fabs(mat[pos(j,i,n)]);
r += fabs(mat[pos(i,j,n)]);
}
}
if (c != 0 && r != 0) {
g = r / BASE;
f = 1;
s = c + r;
while (c < g) {
f *= BASE;
c *= BASE * BASE;
}
g = r * BASE;
while (c >= g) {
f /= BASE;
c /= BASE * BASE;
}
if ((c + r) / f < 0.95 * s) {
done = 0;
g = 1 / f;
scale[i] *= f;
for (j = l; j < n; j++) {
mat[pos(i,j,n)] *= g;
}
for (j = 0; j <= k; j++) {
mat[pos(j,i,n)] *= f;
}
}
}
}
} while (!done);
}
/*
* Transform back eigenvectors of a balanced matrix
* into the eigenvectors of the original matrix
*/
void unbalance(int n,double vr[],double vi[], int low, int hi, double scale[])
{
int i,j,k;
double tmp;
for (i = low; i <= hi; i++) {
for (j = 0; j < n; j++) {
vr[pos(i,j,n)] *= scale[i];
vi[pos(i,j,n)] *= scale[i];
}
}
for (i = low - 1; i >= 0; i--) {
if ((k = (int)scale[i]) != i) {
for (j = 0; j < n; j++) {
tmp = vr[pos(i,j,n)];
vr[pos(i,j,n)] = vr[pos(k,j,n)];
vr[pos(k,j,n)] = tmp;
tmp = vi[pos(i,j,n)];
vi[pos(i,j,n)] = vi[pos(k,j,n)];
vi[pos(k,j,n)] = tmp;
}
}
}
for (i = hi + 1; i < n; i++) {
if ((k = (int)scale[i]) != i) {
for (j = 0; j < n; j++) {
tmp = vr[pos(i,j,n)];
vr[pos(i,j,n)] = vr[pos(k,j,n)];
vr[pos(k,j,n)] = tmp;
tmp = vi[pos(i,j,n)];
vi[pos(i,j,n)] = vi[pos(k,j,n)];
vi[pos(k,j,n)] = tmp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -