-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjacobi.h
200 lines (171 loc) · 4.11 KB
/
jacobi.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/************************************************************************
Jacobi iteration routines for computing eigenvalues/eigenvectors.
NOTE: This code was adapted from VTK source code (vtkMath.cxx) which
seems to have been adapted directly from Numerical Recipes in C.
$Id: jacobi.cxx,v 1.2 2001/09/24 21:57:17 garland Exp $
************************************************************************/
#include <gfx/gfx.h>
#include <gfx/mat3.h>
#include <gfx/mat4.h>
#define ROT(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);a[k][l]=h+s*(g-h*tau)
#define MAX_ROTATIONS 60
// Description:
// Jacobi iteration for the solution of eigenvectors/eigenvalues of a NxN
// real symmetric matrix. Square NxN matrix a; output eigenvalues in w;
// and output eigenvectors in v. Resulting eigenvalues/vectors are sorted
// in decreasing order; eigenvectors are normalized.
//
template<class Vec, class Mat>
bool __jacobi(Mat &a, Vec &w, Mat &v)
{
const int N = Vec::dim();
int i, j, k, iq, ip;
double tresh, theta, tau, t, sm, s, h, g, c;
double tmp;
Vec b, z;
// initialize
for (ip=0; ip<N; ip++)
{
for (iq=0; iq<N; iq++) v[ip][iq] = 0.0;
v[ip][ip] = 1.0;
}
for (ip=0; ip<N; ip++)
{
b[ip] = w[ip] = a[ip][ip];
z[ip] = 0.0;
}
// begin rotation sequence
for (i=0; i<MAX_ROTATIONS; i++)
{
sm = 0.0;
for (ip=0; ip<2; ip++)
{
for (iq=ip+1; iq<N; iq++) sm += fabs(a[ip][iq]);
}
if (sm == 0.0) break;
if (i < 4) tresh = 0.2*sm/(9);
else tresh = 0.0;
for (ip=0; ip<2; ip++)
{
for (iq=ip+1; iq<N; iq++)
{
g = 100.0*fabs(a[ip][iq]);
if (i > 4 && (fabs(w[ip])+g) == fabs(w[ip])
&& (fabs(w[iq])+g) == fabs(w[iq]))
{
a[ip][iq] = 0.0;
}
else if (fabs(a[ip][iq]) > tresh)
{
h = w[iq] - w[ip];
if ( (fabs(h)+g) == fabs(h)) t = (a[ip][iq]) / h;
else
{
theta = 0.5*h / (a[ip][iq]);
t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0) t = -t;
}
c = 1.0 / sqrt(1+t*t);
s = t*c;
tau = s/(1.0+c);
h = t*a[ip][iq];
z[ip] -= h;
z[iq] += h;
w[ip] -= h;
w[iq] += h;
a[ip][iq]=0.0;
for (j=0;j<ip-1;j++)
{
ROT(a,j,ip,j,iq);
}
for (j=ip+1;j<iq-1;j++)
{
ROT(a,ip,j,j,iq);
}
for (j=iq+1; j<N; j++)
{
ROT(a,ip,j,iq,j);
}
for (j=0; j<N; j++)
{
ROT(v,j,ip,j,iq);
}
}
}
}
for (ip=0; ip<N; ip++)
{
b[ip] += z[ip];
w[ip] = b[ip];
z[ip] = 0.0;
}
}
if ( i >= MAX_ROTATIONS )
return false;
// sort eigenfunctions
for (j=0; j<N; j++)
{
k = j;
tmp = w[k];
for (i=j; i<N; i++)
{
if (w[i] >= tmp)
{
k = i;
tmp = w[k];
}
}
if (k != j)
{
w[k] = w[j];
w[j] = tmp;
for (i=0; i<N; i++)
{
tmp = v[i][j];
v[i][j] = v[i][k];
v[i][k] = tmp;
}
}
}
// VTK addition to original Numerical Recipes code:
// insure eigenvector consistency (i.e., Jacobi can compute
// vectors that are negative of one another (.707,.707,0) and
// (-.707,-.707,0). This can wreak havoc in
// hyperstreamline/other stuff. We will select the most
// positive eigenvector.
int numPos;
for (j=0; j<N; j++)
{
for (numPos=0, i=0; i<N; i++) if ( v[i][j] >= 0.0 ) numPos++;
if ( numPos < 2 ) for(i=0; i<N; i++) v[i][j] *= -1.0;
}
return true;
}
#undef ROT
#undef MAX_ROTATIONS
bool eigen(const Mat3& m, Vec3& eig_vals, Vec3 eig_vecs[3])
{
Mat3 a, v; Vec3 w;
int i,j;
for(i=0;i<3;i++) for(j=0;j<3;j++) a[i][j] = m(i,j);
bool result = __jacobi(a, w, v);
if( result )
{
for(i=0;i<3;i++) eig_vals[i] = w[i];
for(i=0;i<3;i++) for(j=0;j<3;j++) eig_vecs[i][j] = v[j][i];
}
return result;
}
bool eigen(const Mat4& m, Vec4& eig_vals, Vec4 eig_vecs[4])
{
Mat4 a, v; Vec4 w;
int i,j;
for(i=0;i<4;i++) for(j=0;j<4;j++) a[i][j] = m(i,j);
bool result = __jacobi(a, w, v);
if( result )
{
for(i=0;i<4;i++) eig_vals[i] = w[i];
for(i=0;i<4;i++) for(j=0;j<4;j++) eig_vecs[i][j] = v[j][i];
}
return result;
}