OscProb
zheevh3.cxx
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// Numerical diagonalization of 3x3 matrcies
3// Copyright (C) 2006 Joachim Kopp
4// ----------------------------------------------------------------------------
5// This library is free software; you can redistribute it and/or
6// modify it under the terms of the GNU Lesser General Public
7// License as published by the Free Software Foundation; either
8// version 2.1 of the License, or (at your option) any later version.
9//
10// This library is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public
16// License along with this library; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18// ----------------------------------------------------------------------------
19#include <stdio.h>
20#include <cmath>
21#include <complex>
22#include <float.h>
23#include "zheevc3.h"
24#include "zheevq3.h"
25
26// Macros
27#define SQR(x) ((x)*(x)) // x^2
28#define SQR_ABS(x) (SQR(real(x)) + SQR(imag(x))) // |x|^2
29
30// ----------------------------------------------------------------------------
31int zheevh3(std::complex<double> A[3][3], std::complex<double> Q[3][3], double w[3])
32// ----------------------------------------------------------------------------
33// Calculates the eigenvalues and normalized eigenvectors of a hermitian 3x3
34// matrix A using Cardano's method for the eigenvalues and an analytical
35// method based on vector cross products for the eigenvectors. However,
36// if conditions are such that a large error in the results is to be
37// expected, the routine falls back to using the slower, but more
38// accurate QL algorithm. Only the diagonal and upper triangular parts of A need
39// to contain meaningful values. Access to A is read-only.
40// ----------------------------------------------------------------------------
41// Parameters:
42// A: The hermitian input matrix
43// Q: Storage buffer for eigenvectors
44// w: Storage buffer for eigenvalues
45// ----------------------------------------------------------------------------
46// Return value:
47// 0: Success
48// -1: Error
49// ----------------------------------------------------------------------------
50// Dependencies:
51// zheevc3(), zhetrd3(), zheevq3()
52// ----------------------------------------------------------------------------
53// Version history:
54// v1.1: Simplified fallback condition --> speed-up
55// v1.0: First released version
56// ----------------------------------------------------------------------------
57{
58#ifndef EVALS_ONLY
59 double norm; // Squared norm or inverse norm of current eigenvector
60// double n0, n1; // Norm of first and second columns of A
61 double error; // Estimated maximum roundoff error
62 double t, u; // Intermediate storage
63 int j; // Loop counter
64#endif
65
66 // Calculate eigenvalues
67 zheevc3(A, w);
68
69#ifndef EVALS_ONLY
70// n0 = SQR(real(A[0][0])) + SQR_ABS(A[0][1]) + SQR_ABS(A[0][2]);
71// n1 = SQR_ABS(A[0][1]) + SQR(real(A[1][1])) + SQR_ABS(A[1][2]);
72
73 t = fabs(w[0]);
74 if ((u=fabs(w[1])) > t)
75 t = u;
76 if ((u=fabs(w[2])) > t)
77 t = u;
78 if (t < 1.0)
79 u = t;
80 else
81 u = SQR(t);
82 error = 256.0 * DBL_EPSILON * SQR(u);
83// error = 256.0 * DBL_EPSILON * (n0 + u) * (n1 + u);
84
85 Q[0][1] = A[0][1]*A[1][2] - A[0][2]*real(A[1][1]);
86 Q[1][1] = A[0][2]*conj(A[0][1]) - A[1][2]*real(A[0][0]);
87 Q[2][1] = SQR_ABS(A[0][1]);
88
89 // Calculate first eigenvector by the formula
90 // v[0] = conj( (A - w[0]).e1 x (A - w[0]).e2 )
91 Q[0][0] = Q[0][1] + A[0][2]*w[0];
92 Q[1][0] = Q[1][1] + A[1][2]*w[0];
93 Q[2][0] = (real(A[0][0]) - w[0]) * (real(A[1][1]) - w[0]) - Q[2][1];
94 norm = SQR_ABS(Q[0][0]) + SQR_ABS(Q[1][0]) + SQR(real(Q[2][0]));
95
96 // If vectors are nearly linearly dependent, or if there might have
97 // been large cancellations in the calculation of A(I,I) - W(1), fall
98 // back to QL algorithm
99 // Note that this simultaneously ensures that multiple eigenvalues do
100 // not cause problems: If W(1) = W(2), then A - W(1) * I has rank 1,
101 // i.e. all columns of A - W(1) * I are linearly dependent.
102 if (norm <= error)
103 return zheevq3(A, Q, w);
104 else // This is the standard branch
105 {
106 norm = sqrt(1.0 / norm);
107 for (j=0; j < 3; j++)
108 Q[j][0] = Q[j][0] * norm;
109 }
110
111 // Calculate second eigenvector by the formula
112 // v[1] = conj( (A - w[1]).e1 x (A - w[1]).e2 )
113 Q[0][1] = Q[0][1] + A[0][2]*w[1];
114 Q[1][1] = Q[1][1] + A[1][2]*w[1];
115 Q[2][1] = (real(A[0][0]) - w[1]) * (real(A[1][1]) - w[1]) - real(Q[2][1]);
116 norm = SQR_ABS(Q[0][1]) + SQR_ABS(Q[1][1]) + SQR(real(Q[2][1]));
117 if (norm <= error)
118 return zheevq3(A, Q, w);
119 else
120 {
121 norm = sqrt(1.0 / norm);
122 for (j=0; j < 3; j++)
123 Q[j][1] = Q[j][1] * norm;
124 }
125
126 // Calculate third eigenvector according to
127 // v[2] = conj(v[0] x v[1])
128 Q[0][2] = conj(Q[1][0]*Q[2][1] - Q[2][0]*Q[1][1]);
129 Q[1][2] = conj(Q[2][0]*Q[0][1] - Q[0][0]*Q[2][1]);
130 Q[2][2] = conj(Q[0][0]*Q[1][1] - Q[1][0]*Q[0][1]);
131#endif
132
133 return 0;
134}
135
int zheevc3(std::complex< double > A[3][3], double w[3])
Definition: zheevc3.cxx:33
#define SQR_ABS(x)
Definition: zheevh3.cxx:28
int zheevh3(std::complex< double > A[3][3], std::complex< double > Q[3][3], double w[3])
Definition: zheevh3.cxx:31
#define SQR(x)
Definition: zheevh3.cxx:27
int zheevq3(std::complex< double > A[3][3], std::complex< double > Q[3][3], double w[3])
Definition: zheevq3.cxx:31