行列の固有値(フレーム法+ベアストウ法)

/********************************************/
/* 行列の固有値(フレーム法+ベアストウ法) */
/*      coded by Y.Suganuma                 */
/********************************************/
#include <stdio.h>

int Bairstow(int, int, double, double, double,
             double *, double *, double *, double *, double *);
int Frame(int, int, double, double, double, double *, double *, double *,
          double *, double *, double **, double **, double **);

int main()
{
	double **A, **H1, **H2, *a, *b, *c, *rl, *im, p0, q0, eps;
	int i1, ind, ct, n;
					// データの設定
	ct   = 1000;
	eps  = 1.0e-10;
	p0   = 0.0;
	q0   = 0.0;
	n    = 3;
	a    = new double [n+1];
	b    = new double [n+1];
	c    = new double [n+1];
	rl   = new double [n];
	im   = new double [n];
	A    = new double * [n];
	H1   = new double * [n];
	H2   = new double * [n];
	for (i1 = 0; i1 < n; i1++) {
		A[i1]  = new double [n];
		H1[i1] = new double [n];
		H2[i1] = new double [n];
	}

	A[0][0] = 7.0;
	A[0][1] = 2.0;
	A[0][2] = 1.0;

	A[1][0] = 2.0;
	A[1][1] = 1.0;
	A[1][2] = -4.0;

	A[2][0] = 1.0;
	A[2][1] = -4.0;
	A[2][2] = 2.0;
					// 計算
	ind = Frame(n, ct, eps, p0, q0, a, b, c, rl, im, A, H1, H2);
					// 出力
	if (ind > 0)
		printf("収束しませんでした!\n");
	else {
		for (i1 = 0; i1 < n; i1++)
			printf("   %f  i %f\n", rl[i1], im[i1]);
	}

	delete [] a;
	delete [] b;
	delete [] c;
	delete [] rl;
	delete [] im;
	for (i1 = 0; i1 < n; i1++) {
		delete [] A[i1];
		delete [] H1[i1];
		delete [] H2[i1];
	}
	delete [] A;
	delete [] H1;
	delete [] H2;

	return 0;
}

/*************************************************/
/* 行列の固有値(フレーム法+ベアストウ法)      */
/*      n : 次数                                 */
/*      ct : 最大繰り返し回数                    */
/*      eps : 収束判定条件                       */
/*      p0, q0 : x2+px+qにおけるp,qの初期値      */
/*      a : 係数(最高次から与え,値は変化する) */
/*      b, c : 作業域((n+1)次の配列)           */
/*      rl, im : 結果の実部と虚部                */
/*      A : 行列                                 */
/*      H1, H2 : 作業域(nxnの行列)             */
/*      return : =0 : 正常                       */
/*               =1 : 収束せず                   */
/*      coded by Y.Suganuma                      */
/*************************************************/
int Frame(int n, int ct, double eps, double p0, double q0, double *a, double *b,
          double *c, double *rl, double *im, double **A, double **H1, double **H2)
{
	int i1, i2, i3, i4, ind;

	a[0] = 1.0;
					// a1の計算
	a[1] = 0.0;
	for (i1 = 0; i1 < n; i1++)
		a[1] -= A[i1][i1];
					// a2の計算
	for (i1 = 0; i1 < n; i1++) {
		for (i2 = 0; i2 < n; i2++)
			H1[i1][i2] = A[i1][i2];
		H1[i1][i1] += a[1];
	}

	a[2] = 0.0;
	for (i1 = 0; i1 < n; i1++) {
		for (i2 = 0; i2 < n; i2++)
			a[2] -= A[i1][i2] * H1[i2][i1];
	}
	a[2] *= 0.5;
					// a3からanの計算
	for (i1 = 3; i1 <= n; i1++) {

		for (i2 = 0; i2 < n; i2++) {
			for (i3 = 0; i3 < n; i3++) {
				H2[i2][i3] = 0.0;
				for (i4 = 0; i4 < n; i4++)
					H2[i2][i3] += A[i2][i4] * H1[i4][i3];
			}
			H2[i2][i2] += a[i1-1];
		}

		a[i1] = 0.0;
		for (i2 = 0; i2 < n; i2++) {
			for (i3 = 0; i3 < n; i3++)
				a[i1] -= A[i2][i3] * H2[i3][i2];
		}
		a[i1] /= i1;

		for (i2 = 0; i2 < n; i2++) {
			for (i3 = 0; i3 < n; i3++)
				H1[i2][i3] = H2[i2][i3];
		}
	}
					// ベアストウ法
	ind = Bairstow(n, ct, eps, p0, q0, a, b, c, rl, im);

	return ind;
}

/*************************************************/
/* 実係数代数方程式の解(ベアストウ法)          */
/*      n : 次数                                 */
/*      ct : 最大繰り返し回数                    */
/*      eps : 収束判定条件                       */
/*      p0, q0 : x2+px+qにおけるp,qの初期値      */
/*      a : 係数(最高次から与え,値は変化する) */
/*      b, c : 作業域((n+1)次の配列)           */
/*      rl, im : 結果の実部と虚部                */
/*      return : =0 : 正常                       */
/*               =1 : 収束せず                   */
/*      coded by Y.Suganuma                      */
/*************************************************/
#include <math.h>

int Bairstow(int n, int ct, double eps, double p0, double q0, 
             double *a, double *b, double *c, double *rl, double *im)
{
	double D, dp, dq, p1 = p0, p2 = 0.0, q1 = q0, q2 = 0.0;
	int i1, ind = 0, count = 0;
/*
          1次の場合
*/
	if (n == 1) {
		if (fabs(a[0]) < eps)
			ind = 1;
		else {
			rl[0] = -a[1] / a[0];
			im[0] = 0.0;
		}
	}
/*
          2次の場合
*/
	else if (n == 2) {
					// 1次式
		if (fabs(a[0]) < eps) {
			if (fabs(a[1]) < eps)
				ind = 1;
			else {
				rl[0] = -a[2] / a[1];
				im[0] = 0.0;
			}
		}
					// 2次式
		else {
			D = a[1] * a[1] - 4.0 * a[0] * a[2];
			if (D < 0.0) {   // 虚数
				D      = sqrt(-D);
				a[0]  *= 2.0;
				rl[0]  = -a[1] / a[0];
				rl[1]  = -a[1] / a[0];
				im[0]  = D / a[0];
				im[1]  = -im[0];
			}
			else {           // 実数
				D      = sqrt(D);
				a[0]   = 1.0 / (2.0 * a[0]);
				rl[0]  = a[0] * (-a[1] + D);
				rl[1]  = a[0] * (-a[1] - D);
				im[0]  = 0.0;
				im[1]  = 0.0;
			}
		}
	}
					// 3次以上の場合
	else {
						// 因数分解
		ind = 1;
		while (ind > 0 && count <= ct) {
			for (i1 = 0; i1 <= n; i1++) {
				if (i1 == 0)
					b[i1] = a[i1];
				else if (i1 == 1)
					b[i1] = a[i1] - p1 * b[i1-1];
				else
					b[i1] = a[i1] - p1 * b[i1-1] - q1 * b[i1-2];
			}
			for (i1 = 0; i1 <= n; i1++) {
				if (i1 == 0)
					c[i1] = b[i1];
				else if (i1 == 1)
					c[i1] = b[i1] - p1 * c[i1-1];
				else
					c[i1] = b[i1] - p1 * c[i1-1] - q1 * c[i1-2];
			}
			D = c[n-2] * c[n-2] - c[n-3] * (c[n-1] - b[n-1]);
			if (fabs(D) < eps)
				return ind;
			else {
				dp = (b[n-1] * c[n-2] - b[n] * c[n-3]) / D;
				dq = (b[n] * c[n-2] - b[n-1] * (c[n-1] - b[n-1])) / D;
				p2 = p1 + dp;
				q2 = q1 + dq;
				if (fabs(dp) < eps && fabs(dq) < eps)
					ind = 0;
				else {
					count++;
					p1 = p2;
					q1 = q2;
				}
			}
		}

		if (ind == 0) {
						// 2次方程式を解く
			D = p2 * p2 - 4.0 * q2;
			if (D < 0.0) {   // 虚数
				D      = sqrt(-D);
				rl[0]  = -0.5 * p2;
				rl[1]  = -0.5 * p2;
				im[0]  = 0.5 * D;
				im[1]  = -im[0];
			}
			else {           // 実数
				D      = sqrt(D);
				rl[0]  = 0.5 * (-p2 + D);
				rl[1]  = 0.5 * (-p2 - D);
				im[0]  = 0.0;
				im[1]  = 0.0;
			}
						// 残りの方程式を解く
			n -= 2;
			for (i1 = 0; i1 <= n; i1++)
				a[i1] = b[i1];
			ind = Bairstow(n, ct, eps, p0, q0, a, b, c, &rl[2], &im[2]);
		}
	}

	return ind;
}