1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.linear;
18
19 import org.hipparchus.complex.Complex;
20 import org.hipparchus.complex.ComplexField;
21 import org.hipparchus.exception.LocalizedCoreFormats;
22 import org.hipparchus.exception.MathIllegalArgumentException;
23 import org.hipparchus.util.FastMath;
24 import org.junit.jupiter.api.Test;
25
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29 import static org.junit.jupiter.api.Assertions.fail;
30
31 class ComplexEigenDecompositionTest {
32
33 @Test
34 void testNonSquare() {
35 try {
36 new ComplexEigenDecomposition(MatrixUtils.createRealMatrix(2, 3), 1.0e-5, 1.0e-12, 1.0e-6);
37 fail("an axception should have been thrown");
38 } catch (MathIllegalArgumentException miae) {
39 assertEquals(LocalizedCoreFormats.NON_SQUARE_MATRIX, miae.getSpecifier());
40 }
41 }
42
43 @Test
44 void testRealEigenValues() {
45 final RealMatrix m = MatrixUtils.createRealMatrix(new double[][] { { 2, 0 }, { 0, 3 } });
46 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(m);
47 assertFalse(eigenDecomp.hasComplexEigenvalues());
48 }
49
50 @Test
51 void testGetEigenValues() {
52 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
53 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
54 Complex ev1 = eigenDecomp.getEigenvalues()[0];
55 Complex ev2 = eigenDecomp.getEigenvalues()[1];
56 assertEquals(new Complex(1, +2), ev1);
57 assertEquals(new Complex(1, -2), ev2);
58 }
59
60 @Test
61 void testHasComplexEigenValues() {
62 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
63 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
64 assertTrue(eigenDecomp.hasComplexEigenvalues());
65 }
66
67 @Test
68 void testGetDeterminant() {
69 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
70 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
71 assertEquals(5, eigenDecomp.getDeterminant(), 1.0e-12);
72 }
73
74 @Test
75 void testGetEigenVectors() {
76 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
77 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
78 checkScaledVector(eigenDecomp.getEigenvector(0), buildVector(new Complex(1), new Complex(1, -1)), 1.0e-15);
79 checkScaledVector(eigenDecomp.getEigenvector(1), buildVector(new Complex(1), new Complex(1, +1)), 1.0e-15);
80 }
81
82 @Test
83 void testEigenValuesAndVectors() {
84 final RealMatrix aR = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
85 final ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(aR);
86 final FieldMatrix<Complex> aC = toComplex(aR);
87 for (int i = 0; i < aR.getRowDimension(); ++i) {
88 final Complex lambda = eigenDecomp.getEigenvalues()[i];
89 final FieldVector<Complex> u = eigenDecomp.getEigenvector(i);
90 final FieldVector<Complex> v = aC.operate(u);
91 checkScaledVector(v, u.mapMultiplyToSelf(lambda), 1.0e-12);
92 }
93 }
94
95 @Test
96 void testGetV() {
97 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
98 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
99 FieldMatrix<Complex> V = eigenDecomp.getV();
100 assertEquals(0.0, new Complex(.5, .5).subtract(V.getEntry(0, 0)).norm(), 1.0e-15);
101 assertEquals(0.0, new Complex(.5, -.5).subtract(V.getEntry(0, 1)).norm(), 1.0e-15);
102 assertEquals(0.0, new Complex(1).subtract(V.getEntry(1, 0)).norm(), 1.0e-15);
103 assertEquals(0.0, new Complex(1).subtract(V.getEntry(1, 1)).norm(), 1.0e-15);
104 }
105
106 @Test
107 void testGetVT() {
108 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
109 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
110 FieldMatrix<Complex> V = eigenDecomp.getVT();
111 assertEquals(0.0, new Complex(.5, .5).subtract(V.getEntry(0, 0)).norm(), 1.0e-15);
112 assertEquals(0.0, new Complex(.5, -.5).subtract(V.getEntry(1, 0)).norm(), 1.0e-15);
113 assertEquals(0.0, new Complex(1).subtract(V.getEntry(0, 1)).norm(), 1.0e-15);
114 assertEquals(0.0, new Complex(1).subtract(V.getEntry(1, 1)).norm(), 1.0e-15);
115 }
116
117 @Test
118 void testGetD() {
119 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
120 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
121 FieldMatrix<Complex> D = eigenDecomp.getD();
122 assertEquals(0.0, new Complex(1, +2).subtract(D.getEntry(0, 0)).norm(), 1.0e-15);
123 assertEquals(0.0, new Complex(0).subtract(D.getEntry(0, 1)).norm(), 1.0e-15);
124 assertEquals(0.0, new Complex(0).subtract(D.getEntry(0, 1)).norm(), 1.0e-15);
125 assertEquals(0.0, new Complex(1, -2).subtract(D.getEntry(1, 1)).norm(), 1.0e-15);
126 }
127
128 @Test
129 void testEqualEigenvalues() {
130
131 final RealMatrix A = MatrixUtils.createRealMatrix(new double[][] {
132 { 1.0, 0.0, 0.0 },
133 { 0.0, 1.0, 0.0 },
134 { 0.0, 0.0, 1.0 }
135 });
136 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(A);
137
138 assertEquals(3, eigenDecomp.getEigenvalues().length);
139 for (Complex z : eigenDecomp.getEigenvalues()) {
140 assertEquals(Complex.ONE, z);
141 }
142
143 checkScaledVector(buildVector(Complex.ONE, Complex.ZERO, Complex.ZERO), eigenDecomp.getEigenvector(0), 1.0e-12);
144 checkScaledVector(buildVector(Complex.ZERO, Complex.ONE, Complex.ZERO), eigenDecomp.getEigenvector(1), 1.0e-12);
145 checkScaledVector(buildVector(Complex.ZERO, Complex.ZERO, Complex.ONE), eigenDecomp.getEigenvector(2), 1.0e-12);
146
147 }
148
149 @Test
150 void testDefinition() {
151
152 final RealMatrix aR = MatrixUtils.createRealMatrix(new double[][] { { 3, -2 }, { 4, -1 } });
153 ComplexEigenDecomposition eigenDecomp = new ComplexEigenDecomposition(aR);
154 FieldMatrix<Complex> aC = toComplex(aR);
155
156
157 checkScaledVector(aC.operate(eigenDecomp.getEigenvector(0)),
158 eigenDecomp.getEigenvector(0).mapMultiply(eigenDecomp.getEigenvalues()[0]),
159 1.0e-12);
160
161
162 checkScaledVector(aC.operate(eigenDecomp.getEigenvector(1)),
163 eigenDecomp.getEigenvector(1).mapMultiply(eigenDecomp.getEigenvalues()[1]),
164 1.0e-12);
165
166
167 checkMatrix(aC.multiply(eigenDecomp.getV()),
168 eigenDecomp.getV().multiply(eigenDecomp.getD()),
169 1.0e-12);
170 }
171
172 @Test
173 void testIssue249() {
174
175
176
177
178
179 final RealMatrix matrix = new Array2DRowRealMatrix(new double[][] {
180 { 1.0, 0.0, 0.0 },
181 { -2.0, 1.0, 0.0 },
182 { 0.0, 0.0, 1.0 }
183 });
184
185 final ComplexEigenDecomposition ced = new OrderedComplexEigenDecomposition(matrix,
186 ComplexEigenDecomposition.DEFAULT_EIGENVECTORS_EQUALITY,
187 ComplexEigenDecomposition.DEFAULT_EPSILON,
188 ComplexEigenDecomposition.DEFAULT_EPSILON_AV_VD_CHECK,
189 (c1, c2) -> Double.compare(c2.norm(), c1.norm()));
190
191 assertEquals(3, ced.getEigenvalues().length);
192 assertEquals(1.0, ced.getEigenvector(0).dotProduct(ced.getEigenvector(0)).norm(), 1.0e-15);
193 assertEquals(1.0, ced.getEigenvector(1).dotProduct(ced.getEigenvector(1)).norm(), 1.0e-15);
194 assertEquals(0.0, ced.getEigenvector(2).dotProduct(ced.getEigenvector(2)).norm(), 1.0e-15);
195
196 }
197
198 private FieldMatrix<Complex> toComplex(final RealMatrix m) {
199 FieldMatrix<Complex> c = MatrixUtils.createFieldMatrix(ComplexField.getInstance(),
200 m.getRowDimension(),
201 m.getColumnDimension());
202 for (int i = 0; i < m.getRowDimension(); ++i) {
203 for (int j = 0; j < m.getColumnDimension(); ++j) {
204 c.setEntry(i, j, new Complex(m.getEntry(i, j)));
205 }
206 }
207
208 return c;
209
210 }
211
212 private FieldVector<Complex> buildVector(final Complex... vi) {
213 return new ArrayFieldVector<>(vi);
214 }
215
216 private void checkScaledVector(final FieldVector<Complex> v, final FieldVector<Complex> reference, final double tol) {
217
218 assertEquals(reference.getDimension(), v.getDimension());
219
220
221 Complex scale = Complex.NaN;
222 double norm = Double.NEGATIVE_INFINITY;
223 for (int i = 0; i < reference.getDimension(); i++) {
224 final Complex ri = reference.getEntry(i);
225 final double ni = FastMath.hypot(ri.getReal(), ri.getImaginary());
226 if (ni > norm) {
227 scale = ri.divide(v.getEntry(i));
228 norm = ni;
229 }
230 }
231
232
233 for (int i = 0; i < reference.getDimension(); ++i) {
234 final Complex ri = reference.getEntry(i);
235 final Complex vi = v.getEntry(i);
236 final Complex si = vi.multiply(scale);
237 assertEquals(ri.getReal(), si.getReal(), tol, "" + (ri.getReal() - si.getReal()));
238 assertEquals(ri.getImaginary(), si.getImaginary(), tol, "" + (ri.getImaginary() - si.getImaginary()));
239 }
240
241 }
242
243 private void checkMatrix(final FieldMatrix<Complex> m, final FieldMatrix<Complex> reference, final double tol) {
244 assertEquals(reference.getRowDimension(), m.getRowDimension());
245 assertEquals(reference.getColumnDimension(), m.getColumnDimension());
246 for (int i = 0; i < reference.getRowDimension(); ++i) {
247 for (int j = 0; j < reference.getColumnDimension(); ++j) {
248 assertEquals(reference.getEntry(i, j).getReal(), m.getEntry(i, j).getReal(), tol, "" + (reference.getEntry(i, j).getReal() - m.getEntry(i, j).getReal()));
249 assertEquals(reference.getEntry(i, j).getImaginary(), m.getEntry(i, j).getImaginary(), tol, "" + (reference.getEntry(i, j).getImaginary() - m.getEntry(i, j).getImaginary()));
250 }
251 }
252 }
253
254 }