1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.linear;
24
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import org.hipparchus.complex.Complex;
29 import org.hipparchus.complex.ComplexField;
30 import org.hipparchus.exception.LocalizedCoreFormats;
31 import org.hipparchus.exception.MathIllegalStateException;
32 import org.hipparchus.exception.MathRuntimeException;
33 import org.hipparchus.util.FastMath;
34 import org.hipparchus.util.Precision;
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 public class EigenDecompositionNonSymmetric {
88
89 public static final double DEFAULT_EPSILON = 1e-12;
90
91 private final double epsilon;
92
93 private Complex[] eigenvalues;
94
95 private List<FieldVector<Complex>> eigenvectors;
96
97 private RealMatrix cachedV;
98
99 private RealMatrix cachedD;
100
101 private RealMatrix cachedVInv;
102
103
104
105
106
107
108
109 public EigenDecompositionNonSymmetric(final RealMatrix matrix) {
110 this(matrix, DEFAULT_EPSILON);
111 }
112
113
114
115
116
117
118
119
120 public EigenDecompositionNonSymmetric(final RealMatrix matrix, double epsilon)
121 throws MathRuntimeException {
122 this.epsilon = epsilon;
123 findEigenVectorsFromSchur(transformToSchur(matrix));
124 }
125
126
127
128
129
130
131
132
133 public RealMatrix getV() {
134
135 if (cachedV == null) {
136 final int m = eigenvectors.size();
137 cachedV = MatrixUtils.createRealMatrix(m, m);
138 for (int k = 0; k < m; ++k) {
139 final FieldVector<Complex> ek = eigenvectors.get(k);
140 if (eigenvalues[k].getImaginaryPart() >= 0) {
141
142
143 for (int l = 0; l < m; ++l) {
144 cachedV.setEntry(l, k, ek.getEntry(l).getRealPart());
145 }
146 } else {
147
148
149 for (int l = 0; l < m; ++l) {
150 cachedV.setEntry(l, k, -ek.getEntry(l).getImaginaryPart());
151 }
152 }
153 }
154 }
155
156
157 return cachedV;
158
159 }
160
161
162
163
164
165
166
167
168
169 public RealMatrix getD() {
170
171 if (cachedD == null) {
172
173 cachedD = MatrixUtils.createRealMatrix(eigenvalues.length, eigenvalues.length);
174 for (int i = 0; i < eigenvalues.length; ++i) {
175 cachedD.setEntry(i, i, eigenvalues[i].getRealPart());
176 if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) > 0) {
177 cachedD.setEntry(i, i + 1, eigenvalues[i].getImaginaryPart());
178 } else if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) < 0) {
179 cachedD.setEntry(i, i - 1, eigenvalues[i].getImaginaryPart());
180 }
181 }
182 }
183 return cachedD;
184 }
185
186
187
188
189
190
191 public double getEpsilon() {
192 return epsilon;
193 }
194
195
196
197
198
199
200 public RealMatrix getVInv() {
201
202 if (cachedVInv == null) {
203 cachedVInv = MatrixUtils.inverse(getV(), epsilon);
204 }
205
206
207 return cachedVInv;
208 }
209
210
211
212
213
214
215
216
217
218 public Complex[] getEigenvalues() {
219 return eigenvalues.clone();
220 }
221
222
223
224
225
226
227
228
229
230
231 public Complex getEigenvalue(final int i) {
232 return eigenvalues[i];
233 }
234
235
236
237
238
239
240
241
242
243
244
245 public FieldVector<Complex> getEigenvector(final int i) {
246 return eigenvectors.get(i).copy();
247 }
248
249
250
251
252
253
254 public Complex getDeterminant() {
255 Complex determinant = Complex.ONE;
256 for (int i = 0; i < eigenvalues.length; ++i) {
257 determinant = determinant.multiply(eigenvalues[i]);
258 }
259 return determinant;
260 }
261
262
263
264
265
266
267
268 private SchurTransformer transformToSchur(final RealMatrix matrix) {
269 final SchurTransformer schurTransform = new SchurTransformer(matrix, epsilon);
270 final double[][] matT = schurTransform.getT().getData();
271 final double norm = matrix.getNorm1();
272
273 eigenvalues = new Complex[matT.length];
274
275 int i = 0;
276 while (i < eigenvalues.length) {
277 if (i == (eigenvalues.length - 1) ||
278 Precision.equals(matT[i + 1][i], 0.0, norm * epsilon)) {
279 eigenvalues[i] = new Complex(matT[i][i]);
280 i++;
281 } else {
282 final double x = matT[i + 1][i + 1];
283 final double p = 0.5 * (matT[i][i] - x);
284 final double z = FastMath.sqrt(FastMath.abs(p * p + matT[i + 1][i] * matT[i][i + 1]));
285 eigenvalues[i++] = new Complex(x + p, +z);
286 eigenvalues[i++] = new Complex(x + p, -z);
287 }
288 }
289 return schurTransform;
290 }
291
292
293
294
295
296
297
298
299
300
301 private Complex cdiv(final double xr, final double xi,
302 final double yr, final double yi) {
303 return new Complex(xr, xi).divide(new Complex(yr, yi));
304 }
305
306
307
308
309
310
311
312 private void findEigenVectorsFromSchur(final SchurTransformer schur)
313 throws MathRuntimeException {
314 final double[][] matrixT = schur.getT().getData();
315 final double[][] matrixP = schur.getP().getData();
316
317 final int n = matrixT.length;
318
319
320 double norm = 0.0;
321 for (int i = 0; i < n; i++) {
322 for (int j = FastMath.max(i - 1, 0); j < n; j++) {
323 norm += FastMath.abs(matrixT[i][j]);
324 }
325 }
326
327
328 if (norm == 0.0) {
329 throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
330 }
331
332
333
334 double r = 0.0;
335 double s = 0.0;
336 double z = 0.0;
337
338 for (int idx = n - 1; idx >= 0; idx--) {
339 double p = eigenvalues[idx].getRealPart();
340 double q = eigenvalues[idx].getImaginaryPart();
341
342 if (Precision.equals(q, 0.0)) {
343
344 int l = idx;
345 matrixT[idx][idx] = 1.0;
346 for (int i = idx - 1; i >= 0; i--) {
347 double w = matrixT[i][i] - p;
348 r = 0.0;
349 for (int j = l; j <= idx; j++) {
350 r += matrixT[i][j] * matrixT[j][idx];
351 }
352 if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) < 0) {
353 z = w;
354 s = r;
355 } else {
356 l = i;
357 if (Precision.equals(eigenvalues[i].getImaginaryPart(), 0.0)) {
358 if (w != 0.0) {
359 matrixT[i][idx] = -r / w;
360 } else {
361 matrixT[i][idx] = -r / (Precision.EPSILON * norm);
362 }
363 } else {
364
365 double x = matrixT[i][i + 1];
366 double y = matrixT[i + 1][i];
367 q = (eigenvalues[i].getRealPart() - p) * (eigenvalues[i].getRealPart() - p) +
368 eigenvalues[i].getImaginaryPart() * eigenvalues[i].getImaginaryPart();
369 double t = (x * s - z * r) / q;
370 matrixT[i][idx] = t;
371 if (FastMath.abs(x) > FastMath.abs(z)) {
372 matrixT[i + 1][idx] = (-r - w * t) / x;
373 } else {
374 matrixT[i + 1][idx] = (-s - y * t) / z;
375 }
376 }
377
378
379 double t = FastMath.abs(matrixT[i][idx]);
380 if ((Precision.EPSILON * t) * t > 1) {
381 for (int j = i; j <= idx; j++) {
382 matrixT[j][idx] /= t;
383 }
384 }
385 }
386 }
387 } else if (q < 0.0) {
388
389 int l = idx - 1;
390
391
392 if (FastMath.abs(matrixT[idx][idx - 1]) > FastMath.abs(matrixT[idx - 1][idx])) {
393 matrixT[idx - 1][idx - 1] = q / matrixT[idx][idx - 1];
394 matrixT[idx - 1][idx] = -(matrixT[idx][idx] - p) / matrixT[idx][idx - 1];
395 } else {
396 final Complex result = cdiv(0.0, -matrixT[idx - 1][idx],
397 matrixT[idx - 1][idx - 1] - p, q);
398 matrixT[idx - 1][idx - 1] = result.getReal();
399 matrixT[idx - 1][idx] = result.getImaginary();
400 }
401
402 matrixT[idx][idx - 1] = 0.0;
403 matrixT[idx][idx] = 1.0;
404
405 for (int i = idx - 2; i >= 0; i--) {
406 double ra = 0.0;
407 double sa = 0.0;
408 for (int j = l; j <= idx; j++) {
409 ra += matrixT[i][j] * matrixT[j][idx - 1];
410 sa += matrixT[i][j] * matrixT[j][idx];
411 }
412 double w = matrixT[i][i] - p;
413
414 if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) < 0) {
415 z = w;
416 r = ra;
417 s = sa;
418 } else {
419 l = i;
420 if (Precision.equals(eigenvalues[i].getImaginaryPart(), 0.0)) {
421 final Complex c = cdiv(-ra, -sa, w, q);
422 matrixT[i][idx - 1] = c.getReal();
423 matrixT[i][idx] = c.getImaginary();
424 } else {
425
426 double x = matrixT[i][i + 1];
427 double y = matrixT[i + 1][i];
428 double vr = (eigenvalues[i].getRealPart() - p) * (eigenvalues[i].getRealPart() - p) +
429 eigenvalues[i].getImaginaryPart() * eigenvalues[i].getImaginaryPart() - q * q;
430 final double vi = (eigenvalues[i].getRealPart() - p) * 2.0 * q;
431 if (Precision.equals(vr, 0.0) && Precision.equals(vi, 0.0)) {
432 vr = Precision.EPSILON * norm *
433 (FastMath.abs(w) + FastMath.abs(q) + FastMath.abs(x) +
434 FastMath.abs(y) + FastMath.abs(z));
435 }
436 final Complex c = cdiv(x * r - z * ra + q * sa,
437 x * s - z * sa - q * ra, vr, vi);
438 matrixT[i][idx - 1] = c.getReal();
439 matrixT[i][idx] = c.getImaginary();
440
441 if (FastMath.abs(x) > (FastMath.abs(z) + FastMath.abs(q))) {
442 matrixT[i + 1][idx - 1] = (-ra - w * matrixT[i][idx - 1] +
443 q * matrixT[i][idx]) / x;
444 matrixT[i + 1][idx] = (-sa - w * matrixT[i][idx] -
445 q * matrixT[i][idx - 1]) / x;
446 } else {
447 final Complex c2 = cdiv(-r - y * matrixT[i][idx - 1],
448 -s - y * matrixT[i][idx], z, q);
449 matrixT[i + 1][idx - 1] = c2.getReal();
450 matrixT[i + 1][idx] = c2.getImaginary();
451 }
452 }
453
454
455 double t = FastMath.max(FastMath.abs(matrixT[i][idx - 1]),
456 FastMath.abs(matrixT[i][idx]));
457 if ((Precision.EPSILON * t) * t > 1) {
458 for (int j = i; j <= idx; j++) {
459 matrixT[j][idx - 1] /= t;
460 matrixT[j][idx] /= t;
461 }
462 }
463 }
464 }
465 }
466 }
467
468
469 for (int j = n - 1; j >= 0; j--) {
470 for (int i = 0; i <= n - 1; i++) {
471 z = 0.0;
472 for (int k = 0; k <= FastMath.min(j, n - 1); k++) {
473 z += matrixP[i][k] * matrixT[k][j];
474 }
475 matrixP[i][j] = z;
476 }
477 }
478
479 eigenvectors = new ArrayList<>(n);
480 for (int i = 0; i < n; i++) {
481 FieldVector<Complex> ei = new ArrayFieldVector<>(ComplexField.getInstance(), n);
482 for (int j = 0; j < n; j++) {
483 if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) > 0) {
484 ei.setEntry(j, new Complex(matrixP[j][i], +matrixP[j][i + 1]));
485 } else if (Precision.compareTo(eigenvalues[i].getImaginaryPart(), 0.0, epsilon) < 0) {
486 ei.setEntry(j, new Complex(matrixP[j][i - 1], -matrixP[j][i]));
487 } else {
488 ei.setEntry(j, new Complex(matrixP[j][i]));
489 }
490 }
491 eigenvectors.add(ei);
492 }
493 }
494 }