⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eigen.cpp

📁 Computes the eigenvalues and eigenvectors of a real upper-Hessenberg Matrix using the QR method
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <math.h>
#include "stdafx.h"
#include "drishti.h"
#include "Eigen.h"
#include "MemUtil.h"

Eigen::Eigen(){
}

void Eigen::cdivA(double ar, double ai, double br, double bi, double **A, int in1, int in2, int in3) {
	// Division routine for dividing one complex number into another:
	// This routine does (ar + ai)/(br + bi) and returns the results in the specified
	// elements of the A matrix.
	
	double s, ars, ais, brs, bis;
	
	s = fabs(br) + fabs(bi);
	ars = ar/s;
	ais = ai/s;
	brs = br/s;
	bis = bi/s;
	s = brs*brs + bis*bis;
	A[in1][in2] = (ars*brs + ais*bis)/s;
	A[in1][in3] = (-(ars*bis) + ais*brs)/s;
	return;
} // End cdivA

void Eigen::hqr2(double **A, int N, double **B, int low, int igh, double *wr, double *wi, int &ierr) {
/* Computes the eigenvalues and eigenvectors of a real upper-Hessenberg Matrix using 
	the QR method. */
	
	double norm = 0.0, r, t = 0.0, tst1, tst2, p, q, ra, s, sa, vi, vr, w, x, y, zz;
	int k = 0, l, m, mp2, en = igh, incrFlag = 1, its, itn = 30*N, enm2, na, notlas;
	int i, j, ii, jj;
	
	for (i = 0; i < N; i++){ // Store eigenvalues already isolated and compute matrix norm.
		for (j = k; j < N; j++)
			norm += fabs(A[i][j]);
		k = i;
		if ((i < low) || (i > igh)){
			wi[i] = 0.0;
			wr[i] = A[i][i];
		} //End if (i < low or i > igh)
	}  // End for i
	
	// Search next eigenvalues
	while (en >= low){
		
		if (incrFlag) { //Skip this part if incrFlag is set to 0 at very end of while loop
			its = 0;
			na = en - 1;
			enm2 = na - 1;
		} //End if (incrFlag)
		else
			incrFlag = 1;
		
		/*Look for single small sub-diagonal element for l = en step -1 until low */
		
		for (i = low; i <= en; i++){
			l = en + low - i;
			if (l == low)
				break;
			s = fabs(A[l - 1][l - 1]) + fabs(A[l][l]);
			if (s == 0.0)
				s = norm;
			tst1 = s;
			tst2 = tst1 + fabs(A[l][l - 1]);
			if (tst2 == tst1)
				break;
		} //End for i
		
		x = A[en][en];
		
		if (l == en){  //One root found
			wr[en] = A[en][en] = x + t;
			wi[en] = 0.0;
			en--;
			continue;
		} //End if (l == en)
		
		y = A[na][na];
		w = A[en][na]*A[na][en];
		
		if (l == na){  //Two roots found
			p = (-x + y)/2;
			q = p*p + w;
			zz = sqrt(fabs(q));
			x = A[en][en] = x + t;
			A[na][na] = y + t;
			if (q >= 0.0){//Real Pair
				zz = ((p < 0.0) ? (-1*zz + p) : (p + zz));
				wr[en] = wr[na] = x + zz;
				if (zz != 0.0)
					wr[en] = -(w/zz) + x;
				wi[en] = wi[na] = 0.0;
				x = A[en][na];
				s = fabs(x) + fabs(zz);
				p = x/s;
				q = zz/s;
				r = sqrt(p*p + q*q);
				p /= r;
				q /= r;
				for (j = na; j < N; j++){ //Row modification
					zz = A[na][j];
					A[na][j] = q*zz + p*A[en][j];
					A[en][j] = -(p*zz) + q*A[en][j];
				}//End for j
				for (j = 0; j <= en; j++){ // Column modification
					zz = A[j][na];
					A[j][na] = q*zz + p*A[j][en];
					A[j][en] = -(p*zz) + q*A[j][en];
				}//End for j
				for (j = low; j <= igh; j++){//Accumulate transformations
					zz = B[j][na];
					B[j][na] = q*zz + p*B[j][en];
					B[j][en] = -(p*zz) + q*B[j][en];
				}//End for j
			} //End if (q >= 0.0)
			else {//else q < 0.0
				wr[en] = wr[na] = x + p;
				wi[na] = zz;
				wi[en] = -zz;
			} //End else
			en--;
			en--;
			continue;
		}//End if (l == na)
		
		if (itn == 0){ //Set error; all eigenvalues have not converged after 30 iterations.
			ierr = en + 1;
			return;
		}//End if (itn == 0)
		
		if ((its == 10) || (its == 20)){ //Form exceptional shift
			t += x;
			for (i = low; i <= en; i++)
				A[i][i] += -x;
			s = fabs(A[en][na]) + fabs(A[na][enm2]);
			y = x = 0.75*s;
			w = -0.4375*s*s;
		} //End if (its equals 10 or 20)
		
		its++;
		itn--;
		
		/*Look for two consecutive small sub-diagonal elements. Do m = en - 2 to l in 
		increments of -1 */
		
		for (m = enm2; m >= l; m--){
			zz = A[m][m];
			r = -zz + x;
			s = -zz + y;
			p = (-w + r*s)/A[m + 1][m] + A[m][m + 1];
			q = -(zz + r + s) + A[m + 1][m + 1] ;
			r = A[m + 2][m + 1];
			s = fabs(p) + fabs(q) + fabs(r);
			p /= s;
			q /= s;
			r /= s;
			if (m == l)
				break;
			tst1 = fabs(p) * (fabs(A[m - 1][m - 1]) + fabs(zz) + fabs(A[m + 1][m + 1]));
			tst2 = tst1 + fabs(A[m][m - 1]) * (fabs(q) + fabs(r));
			if (tst1 == tst2)
				break;
		}//End for m
		
		mp2 = m + 2;
		
		for (i = mp2; i <= en; i++){
			A[i][i - 2] = 0.0;
			if (i == mp2)
				continue;
			A[i][i - 3] = 0.0;
		}//End for i
		
		/* Double qr step involving rows l to en and columns m to en. */
		
		for (i = m; i <= na; i++){
			notlas = ((i != na) ? 1 : 0);
			if (i != m){
				p = A[i][i - 1];
				q = A[i + 1][i - 1];
				r = ((notlas) ? A[i + 2][i - 1] : 0.0);
				x = fabs(p) + fabs(q) + fabs(r);
				if (x == 0.0)      //Drop through rest of for i loop
					continue;
				p /= x;
				q /= x;
				r /= x;
			} //End if (i != m)
			
			s = sqrt(p*p + q*q + r*r);
			if (p < 0.0)
				s = -s;
			
			if (i != m)
				A[i][i - 1] = -(s*x);
			else {
				if (l != m)
					A[i][i - 1] = -A[i][i - 1];
			}
			
			p += s;
			x = p/s;
			y = q/s;
			zz = r/s;
			q /= p;
			r /= p;
			k = ((i + 3 < en) ? i + 3 : en);
			
			if (notlas){ //Do row modification
				for (j = i; j < N; j++) {
					p = A[i][j] + q*A[i + 1][j] + r*A[i + 2][j];
					A[i][j] += -(p*x);
					A[i + 1][j] += -(p*y);
					A[i + 2][j] += -(p*zz);
				}//End for j
				
				for (j = 0; j <= k; j++) {//Do column modification
					p = x*A[j][i] + y*A[j][i + 1] + zz*A[j][i + 2];
					A[j][i] += -p;
					A[j][i + 1] += -(p*q);
					A[j][i + 2] += -(p*r);
				}//End for j
				
				for (j = low; j <= igh; j++) {//Accumulate transformations
					p = x*B[j][i] + y*B[j][i + 1] + zz*B[j][i + 2];
					B[j][i] += -p;
					B[j][i + 1] += -(p*q);
					B[j][i + 2] += -(p*r);
				} // End for j
			}//End if notlas
			
			else {
				for (j = i; j < N; j++) {//Row modification
					p = A[i][j] + q*A[i + 1][j];
					A[i][j] += -(p*x);
					A[i + 1][j] += -(p*y);
				}//End for j
				
				for (j = 0; j <= k; j++){//Column modification
					p = x*A[j][i] + y*A[j][i +1];
					A[j][i] += -p;
					A[j][i + 1] += -(p*q);
				}//End for j
				
				for (j = low; j <= igh; j++){//Accumulate transformations
					p = x*B[j][i] + y*B[j][i +1];
					B[j][i] += -p;
					B[j][i + 1] += -(p*q);
				}//End for j
				
			} //End else if notlas
		}//End for i
		incrFlag = 0;
		}//End while (en >= low)
		
		if (norm == 0.0)
			return;
		
		//Step from (N - 1) to 0 in steps of -1
		
		for (en = (N - 1); en >= 0; en--){
			p = wr[en];
			q = wi[en];
			na = en - 1;
			
			if (q > 0.0)
				continue;
			
			if (q == 0.0){//Real vector
				m = en;
				A[en][en] = 1.0;
				
				for (j = na; j >= 0; j--){
					w = -p + A[j][j];
					r = 0.0;
					for (ii = m; ii <= en; ii++)
						r += A[j][ii]*A[ii][en];
					
					if (wi[j] < 0.0){
						zz = w;
						s = r;
					}//End wi[j] < 0.0
					
					else {//wi[j] >= 0.0
						m = j;
						if (wi[j] == 0.0){
							t = w;
							if (t == 0.0){
								t = tst1 = norm;
								do {
									t *= 0.01;
									tst2 = norm + t;
								} while (tst2 > tst1);
							} //End if t == 0.0
							A[j][en] = -(r/t);
						}//End if wi[j] == 0.0
						
						else { //else wi[j] > 0.0; Solve real equations
							x = A[j][j + 1];
							y = A[j + 1][j];
							q = (-p + wr[j])*(-p + wr[j]) + wi[j]*wi[j];
							A[j][en] = t = (-(zz*r) + x*s)/q;
							A[j + 1][en] = ((fabs(x) > fabs(zz)) ? -(r + w*t)/x : -(s + y*t)/zz);
						}//End  else wi[j] > 0.0
						
						// Overflow control
						t = fabs(A[j][en]);
						if (t == 0.0)
							continue; //go up to top of for j loop
						tst1 = t;
						tst2 = tst1 + 1.0/tst1;
						if (tst2 > tst1)
							continue; //go up to top of for j loop
						for (ii = j; ii <= en; ii++)
							A[ii][en] /= t;
						
					}//End else wi[j] >= 0.0
					
				}//End for j
				
			}      //End q == 0.0
			
			else {//else q < 0.0, complex vector
				//Last vector component chosen imaginary so that eigenvector matrix is triangular
				m = na;
				
				if (fabs(A[en][na]) <= fabs(A[na][en]))
					cdivA(0.0, -A[na][en], -p + A[na][na], q, A, na, na, en);
				else {
					A[na][na] = q/A[en][na];
					A[na][en] = -(-p + A[en][en])/A[en][na];
				} //End else (abs(A[en][na] > abs(A[na][en])
				
				A[en][na] = 0.0;
				A[en][en] = 1.0;
				
				for (j = (na - 1); j >= 0; j--) {
					w = -p + A[j][j];
					sa = ra = 0.0;
					
					for (ii = m; ii <= en; ii++) {
						ra += A[j][ii]*A[ii][na];
						sa += A[j][ii]*A[ii][en];
					} //End for ii
					
					if (wi[j] < 0.0){
						zz = w;
						r = ra;
						s = sa;
						continue;
					} //End if (wi[j] < 0.0)
					
					//else wi[j] >= 0.0
					m = j;
					if (wi[j] == 0.0)
						cdivA(-ra, -sa, w, q, A, j, na, en);
					else {// else wi[j] > 0.0; solve complex equations
						x = A[j][j + 1];
						y = A[j + 1][j];
						vr = -(q*q) + (-p + wr[j])*(-p + wr[j]) + wi[j]*wi[j];
						vi = (-p + wr[j])*2.0*q;
						if ((vr == 0.0) && (vi == 0.0)){
							tst1 = norm*(fabs(w) + fabs(q) + fabs(x) + fabs(y) + fabs(zz));
							vr = tst1;
							do {
								vr *= 0.01;
								tst2 = tst1 + vr;
							} while (tst2 > tst1);
						} //End if vr and vi == 0.0
						cdivA(-(zz*ra) + x*r + q*sa, -(zz*sa + q*ra) + x*s, vr, vi, A, j, na, en);
						
						if (fabs(x) > (fabs(zz) + fabs(q))){
							A[j + 1][na] = (-(ra + w*A[j][na]) + q*A[j][en])/x;
							A[j + 1][en] = -(sa + w*A[j][en] + q*A[j][na])/x;
						}//End if
						else
							cdivA(-(r + y*A[j][na]), -(s + y*A[j][en]), zz, q, A, j + 1, na, en);
						
					}//End else wi[j] > 0.0
					
					t = ((fabs(A[j][na]) >= fabs(A[j][en])) ? fabs(A[j][na]) : fabs(A[j][en]));
					
					if (t == 0.0)
						continue; // go to top of for j loop
					

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -