Пример #1
0
// Warning: This method only works for symmetric, Hermitian matrices
// Find Eigenvectors and return three orthogonal vectors in columns of the matrix
// Input is Vector with eigenvalues of this matrix (not needed for 3D matrices)
// No error checking (that is symmetric and no error in algorithm)
Matrix3 Matrix3::Eigenvectors(Vector &Eigenvals) const
{
    Matrix3 Eigenvecs;
	
    if(is2D)
	{	double cs,sn;
		dsyev2(m[0][0],m[0][1],m[1][1],&(Eigenvals.x),&(Eigenvals.y),&cs,&sn);
		Eigenvecs.set(cs,-sn,sn,cs,1.);
    }
    
    else
	{	// set to 3D matrix
		double w[3];
		double Q[3][3];
		double A[3][3];
		A[0][0] = m[0][0];
		A[0][1] = m[0][1];
		A[0][2] = m[0][2];
		A[1][1] = m[1][1];
		A[1][2] = m[1][2];
		A[2][2] = m[2][2];
		dsyevq3(A, Q, w);
		Eigenvecs.set(Q);
		Eigenvals.x = w[0];
		Eigenvals.y = w[1];
		Eigenvals.z = w[2];
	}

    return Eigenvecs;
}
// Compute eigenvalues and eigenvectors of a 3x3 matrix A.
// At output, the eigenvalues are saved in lambdas in decending order.
// The columns of A are replaced by the orthonormal eigenvectors. 
void FaceOffset_3::
compute_eigenvectors( Vector_3 A[3], Vector_3 &lambdas) {

  double abuf[3][3] = { {A[0][0], A[0][1], A[0][2]},
			{A[1][0], A[1][1], A[1][2]},
			{A[2][0], A[2][1], A[2][2]}};
  double ebuf[3][3];
  
  int info = dsyevq3( abuf, ebuf, &lambdas[0]);
  COM_assertion_msg( info==0, "Computation of eigenvectos failed");

  std::swap( ebuf[0][1], ebuf[1][0]);
  std::swap( ebuf[0][2], ebuf[2][0]);
  std::swap( ebuf[1][2], ebuf[2][1]);

  const Vector_3 *buf = (const Vector_3*)&ebuf[0][0];

  if ( lambdas[0]<lambdas[1]) {
    if ( lambdas[1]<lambdas[2]) { // l2>l1>l0
      std::swap( lambdas[0], lambdas[2]);
      A[0] = buf[2]; A[1] = buf[1]; A[2] = buf[0];
    }
    else { 
      double t = lambdas[0];
      lambdas[0] = lambdas[1]; 
      A[0] = buf[1];

      if ( t<lambdas[2]) { // l1>=l2>l0
	lambdas[1] = lambdas[2]; lambdas[2] = t;
	A[1] = buf[2]; A[2] = buf[0];
      }
      else { // l1>l0>=l2
	lambdas[1] = t;
	A[1] = buf[0]; A[2] = buf[2];
      }
    }
  }
  else if ( lambdas[0]<lambdas[2]) { // l2>l0>=l1
    double t = lambdas[0];
    lambdas[0] = lambdas[2]; lambdas[2] = lambdas[1]; lambdas[1] = t;
    A[0] = buf[2]; A[1] = buf[0]; A[2] = buf[1];
  }
  else {
    A[0] = buf[0];
    if ( lambdas[1]<lambdas[2]) { // l0>=l2>l1
      std::swap( lambdas[1], lambdas[2]);
      A[1] = buf[2]; A[2] = buf[1];
    }
    else {// l0>=l1>=l2
      A[1] = buf[1]; A[2] = buf[2]; 
    }
  }
}
Пример #3
0
// ----------------------------------------------------------------------------
int dsyevh3(double A[3][3], double Q[3][3], double w[3])
// ----------------------------------------------------------------------------
// Calculates the eigenvalues and normalized eigenvectors of a symmetric 3x3
// matrix A using Cardano's method for the eigenvalues and an analytical
// method based on vector cross products for the eigenvectors. However,
// if conditions are such that a large error in the results is to be
// expected, the routine falls back to using the slower, but more
// accurate QL algorithm. Only the diagonal and upper triangular parts of A need
// to contain meaningful values. Access to A is read-only.
// ----------------------------------------------------------------------------
// Parameters:
//   A: The symmetric input matrix
//   Q: Storage buffer for eigenvectors
//   w: Storage buffer for eigenvalues
// ----------------------------------------------------------------------------
// Return value:
//   0: Success
//  -1: Error
// ----------------------------------------------------------------------------
// Dependencies:
//   dsyevc3(), dsytrd3(), dsyevq3()
// ----------------------------------------------------------------------------
// Version history:
//   v1.1: Simplified fallback condition --> speed-up
//   v1.0: First released version
// ----------------------------------------------------------------------------
{
#ifndef EVALS_ONLY
  double norm;          // Squared norm or inverse norm of current eigenvector
//  double n0, n1;        // Norm of first and second columns of A
  double error;         // Estimated maximum roundoff error
  double t, u;          // Intermediate storage
  int j;                // Loop counter
#endif

  // Calculate eigenvalues
  dsyevc3(A, w);

#ifndef EVALS_ONLY
//  n0 = SQR(A[0][0]) + SQR(A[0][1]) + SQR(A[0][2]);
//  n1 = SQR(A[0][1]) + SQR(A[1][1]) + SQR(A[1][2]);
  
  t = fabs(w[0]);
  if ((u=fabs(w[1])) > t)
    t = u;
  if ((u=fabs(w[2])) > t)
    t = u;
  if (t < 1.0)
    u = t;
  else
    u = SQR(t);
  error = 256.0 * DBL_EPSILON * SQR(u);
//  error = 256.0 * DBL_EPSILON * (n0 + u) * (n1 + u);

  Q[0][1] = A[0][1]*A[1][2] - A[0][2]*A[1][1];
  Q[1][1] = A[0][2]*A[0][1] - A[1][2]*A[0][0];
  Q[2][1] = SQR(A[0][1]);

  // Calculate first eigenvector by the formula
  //   v[0] = (A - w[0]).e1 x (A - w[0]).e2
  Q[0][0] = Q[0][1] + A[0][2]*w[0];
  Q[1][0] = Q[1][1] + A[1][2]*w[0];
  Q[2][0] = (A[0][0] - w[0]) * (A[1][1] - w[0]) - Q[2][1];
  norm    = SQR(Q[0][0]) + SQR(Q[1][0]) + SQR(Q[2][0]);

  // If vectors are nearly linearly dependent, or if there might have
  // been large cancellations in the calculation of A[i][i] - w[0], fall
  // back to QL algorithm
  // Note that this simultaneously ensures that multiple eigenvalues do
  // not cause problems: If w[0] = w[1], then A - w[0] * I has rank 1,
  // i.e. all columns of A - w[0] * I are linearly dependent.
  if (norm <= error)
    return dsyevq3(A, Q, w);
  else                      // This is the standard branch
  {
    norm = sqrt(1.0 / norm);
    for (j=0; j < 3; j++)
      Q[j][0] = Q[j][0] * norm;
  }
  
  // Calculate second eigenvector by the formula
  //   v[1] = (A - w[1]).e1 x (A - w[1]).e2
  Q[0][1]  = Q[0][1] + A[0][2]*w[1];
  Q[1][1]  = Q[1][1] + A[1][2]*w[1];
  Q[2][1]  = (A[0][0] - w[1]) * (A[1][1] - w[1]) - Q[2][1];
  norm     = SQR(Q[0][1]) + SQR(Q[1][1]) + SQR(Q[2][1]);
  if (norm <= error)
    return dsyevq3(A, Q, w);
  else
  {
    norm = sqrt(1.0 / norm);
    for (j=0; j < 3; j++)
      Q[j][1] = Q[j][1] * norm;
  }
  // Calculate third eigenvector according to
  //   v[2] = v[0] x v[1]
  Q[0][2] = Q[1][0]*Q[2][1] - Q[2][0]*Q[1][1];
  Q[1][2] = Q[2][0]*Q[0][1] - Q[0][0]*Q[2][1];
  Q[2][2] = Q[0][0]*Q[1][1] - Q[1][0]*Q[0][1];
#endif

  return 0;
}