コード例 #1
0
/*
Description:
  Find the eigen values and eigen vectors of a real symmetric
  3x3 matrix

         A D F
         D B E
         F E C

Parameters:
  A - [in] matrix entry
  B - [in] matrix entry
  C - [in] matrix entry
  D - [in] matrix entry
  E - [in] matrix entry
  F - [in] matrix entry
  e1 - [out] eigen value
  E1 - [out] eigen vector with eigen value e1
  e2 - [out] eigen value
  E2 - [out] eigen vector with eigen value e2
  e3 - [out] eigen value
  E3 - [out] eigen vector with eigen value e3
Returns:
  True if successful.
*/
bool ON_Sym3x3EigenSolver( double A, double B, double C,
                           double D, double E, double F,
                           double* e1, ON_3dVector E1,
                           double* e2, ON_3dVector E2,
                           double* e3, ON_3dVector E3
                           )
{
  // STEP 1: reduce to tri-diagonal form
  double cos_phi = 1.0;
  double sin_phi = 0.0;
  double AA = A, BB = B, CC = C, DD = D, EE = E, FF = F;
  if ( F != 0.0 )
  {
    double theta = 0.5*(C-A)/F;

    double t;
    if ( fabs(theta) > 1.0e154 )
    {
      t = 0.5/fabs(theta);
    }
    else if ( fabs(theta) > 1.0 )
    {
      t = 1.0/(fabs(theta)*(1.0 + sqrt(1.0 + 1.0/(theta*theta))));
    }
    else
    {
      t = 1.0/(fabs(theta) + sqrt(1.0+theta*theta));
    }

    if ( theta < 0.0 )
      t = -t;

    if ( fabs(t) > 1.0 )
    {
      double tt = 1.0/t;
      cos_phi = 1.0/(fabs(t)*sqrt(1.0 + tt*tt));
    }
    else
      cos_phi = 1.0/sqrt(1.0 + t*t);
    
    sin_phi = t*cos_phi;

    double tau = sin_phi/(1.0 + cos_phi);

    AA = A - t*F;
    BB = B;
    CC = C + t*F;
    DD = D - sin_phi*(E + tau*D);
    EE = E + sin_phi*(D + tau*E);

    // debugging test - FF should be close to zero.
    // cos_phi*cos_phi + sin_phi*size_phi should be close to 1
    FF = (cos_phi*cos_phi - sin_phi*sin_phi)*F + sin_phi*cos_phi*(A-C);
  }

  double ee1, ee2, ee3;
  ON_3dVector EE1, EE2, EE3;
  bool rc = ON_SymTriDiag3x3EigenSolver( AA, BB, CC, DD, EE,
                                    &ee1, EE1,
                                    &ee2, EE2,
                                    &ee3, EE3 );

  E1.Set(cos_phi*EE1.x - sin_phi*EE1.z, EE1.y, sin_phi*EE1.x + cos_phi*EE1.z );
  E2.Set(cos_phi*EE2.x - sin_phi*EE2.z, EE2.y, sin_phi*EE2.x + cos_phi*EE2.z );
  E3.Set(cos_phi*EE3.x - sin_phi*EE3.z, EE3.y, sin_phi*EE3.x + cos_phi*EE3.z );
  if ( e1 )
    *e1 = ee1;
  if ( e2 )
    *e2 = ee2;
  if ( e3 )
    *e3 = ee3;

  // debugging check of eigen values
  ON_3dVector err1, err2, err3;
  {
    err1.x = (A*E1.x + D*E1.y + F*E1.z) - ee1*E1.x;
    err1.y = (D*E1.x + B*E1.y + E*E1.z) - ee1*E1.y;
    err1.z = (F*E1.x + E*E1.y + C*E1.z) - ee1*E1.z;

    err2.x = (A*E2.x + D*E2.y + F*E2.z) - ee2*E2.x;
    err2.y = (D*E2.x + B*E2.y + E*E2.z) - ee2*E2.y;
    err2.z = (F*E2.x + E*E2.y + C*E2.z) - ee2*E2.z;

    err3.x = (A*E3.x + D*E3.y + F*E3.z) - ee3*E3.x;
    err3.y = (D*E3.x + B*E3.y + E*E3.z) - ee3*E3.y;
    err3.z = (F*E3.x + E*E3.y + C*E3.z) - ee3*E3.z;
  }

  return rc;
}