解析


 特に物理現象において、対称行列の固有値、固有ベクトルを求める場面が多く、対称行列の場合のみ、ヤコビ法により簡単に固有値問題を解くことができます。非対称行列の場合は「べき乗法」という解法がありますが、絶対値最大の固有値1個しか求められません。

行列、対称行列の実装についてはこちらを参照してください。
行列クラス
対称行列クラス

		
		
SquareMatrix a = new SquareMatrix( 3 );
a.SetRow( 0, 1, 0.446, -0.56 );
a.SetRow( 1, 0.446, 1, -0.239 );
a.SetRow( 2, -0.56, -0.239, 1 );

Vector eigenValue;
List<Vector> eigenVectors;
eigenVectors = GetEigenVectorsByJacobi( a, 100000, 0.00000001, out eigenValue );



/// <summary>正方行列の固有値、固有ベクトルを算出(ヤコビ法・対称行列のみ有効)</summary>
/// <param name="matrix">対称行列</param>
/// <param name="nMaxStep">最大評価ステップ数</param>
/// <param name="dSettleValue">収束値</param>
/// <param name="eigenValue">固有値リスト</param>
/// <returns>固有ベクトルのリスト</returns>
/// <remarks>
/// 非対称行列の場合は「べき乗法」という解法があるが、絶対値最大の固有値しか求まらない。
/// http://www.asahi-net.or.jp/~UC3K-YMD/Lesson/Section03/section03_09.html
/// </remarks>
public static List<Vector> GetEigenVectorsByJacobi( SquareMatrix matrix, int nMaxStep, double dSettleValue, out Vector eigenValue )
{
  eigenValue = null;
  SquareMatrix A1 = ( SquareMatrix )matrix.Clone();
  SquareMatrix X1 = new SquareMatrix( matrix.Size );
  X1.SetUnitMatrix();

  SquareMatrix A2 = new SquareMatrix( matrix.Size );
  SquareMatrix X2 = new SquareMatrix( matrix.Size );
  int nStep = 0, p = 0, q = 0;

  while( nStep < nMaxStep )
  {
    // 最大要素の収束判定
    double dMaxElement = A1.GetMaxElement( out p, out q );
    if( dMaxElement < dSettleValue )
    {
      // 収束した
      break;
    }

    double t = 0.5 * ( A1[ p, p ] - A1[ q, q ] );
    double v = Math.Abs( t ) / Math.Sqrt( A1[ p, q ] * A1[ p, q ] + t * t );
    double sn = Math.Sqrt( 0.5 * ( 1.0 - v ) );
    if( -A1[ p, q ] * t < 0.0 )
    {
      sn = -sn;
    }
    double cs = Math.Sqrt( 1.0 - sn * sn );

    // Akの計算
    for( int i = 0; i < matrix.Size; i++ )
    {
      if( i == p )
      {
        for( int j = 0; j < matrix.Size; j++ )
        {
          if( j == p )
            A2[ p, p ] = A1[ p, p ] * cs * cs + A1[ q, q ] * sn * sn -
                   2.0 * A1[ p, q ] * sn * cs;
          else if( j == q )
            A2[ p, q ] = 0.0;
          else
            A2[ p, j ] = A1[ p, j ] * cs - A1[ q, j ] * sn;
        }
      }
      else if( i == q )
      {
        for( int j = 0; j < matrix.Size; j++ )
        {
          if( j == q )
            A2[ q, q ] = A1[ p, p ] * sn * sn + A1[ q, q ] * cs * cs +
                   2.0 * A1[ p, q ] * sn * cs;
          else if( j == p )
            A2[ q, p ] = 0.0;
          else
            A2[ q, j ] = A1[ q, j ] * cs + A1[ p, j ] * sn;
        }
      }
      else
      {
        for( int j = 0; j < matrix.Size; j++ )
        {
          if( j == p )
            A2[ i, p ] = A1[ i, p ] * cs - A1[ i, q ] * sn;
          else if( j == q )
            A2[ i, q ] = A1[ i, q ] * cs + A1[ i, p ] * sn;
          else
            A2[ i, j ] = A1[ i, j ];
        }
      }
    }
    // Xkの計算
    for( int i = 0; i < matrix.Size; i++ )
    {
      for( int j = 0; j < matrix.Size; j++ )
      {
        if( j == p )
          X2[ i, p ] = X1[ i, p ] * cs - X1[ i, q ] * sn;
        else if( j == q )
          X2[ i, q ] = X1[ i, q ] * cs + X1[ i, p ] * sn;
        else
          X2[ i, j ] = X1[ i, j ];
      }
    }

    A1 = ( SquareMatrix )A2.Clone();
    X1 = ( SquareMatrix )X2.Clone();

    // 次のステップへ
    nStep++;
  }

  if( nStep >= nMaxStep ) return null;

  // 行列A1,X1に固有値と固有ベクトルが設定された。

  // 固有ベクトルリスト
  List<Vector> eigenVectors = new List<Vector>();

  // 固有値リスト
  eigenValue = new Vector( matrix.Size );
  for( int i = 0; i < matrix.Size; i++ )
  {
    // 固有値
    eigenValue[ i ] = A1[ i, i ];

    // 固有ベクトル
    Vector eigenVector = new Vector( matrix.Size );
    for( int j = 0; j < matrix.Size; j++ )
    {
      eigenVector[ j ] = X1[ j, i ];
    }
    eigenVectors.Add( eigenVector );
  }

  return eigenVectors;
}
		
	


inserted by FC2 system