View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.linear;
24  
25  import org.hipparchus.exception.LocalizedCoreFormats;
26  import org.hipparchus.exception.MathIllegalArgumentException;
27  import org.hipparchus.random.RandomDataGenerator;
28  import org.junit.jupiter.api.Test;
29  
30  import java.util.Random;
31  
32  import static org.junit.jupiter.api.Assertions.assertEquals;
33  import static org.junit.jupiter.api.Assertions.assertTrue;
34  import static org.junit.jupiter.api.Assertions.fail;
35  
36  class SchurTransformerTest {
37  
38      private double[][] testSquare5 = {
39              { 5, 4, 3, 2, 1 },
40              { 1, 4, 0, 3, 3 },
41              { 2, 0, 3, 0, 0 },
42              { 3, 2, 1, 2, 5 },
43              { 4, 2, 1, 4, 1 }
44      };
45  
46      private double[][] testSquare3 = {
47              {  2, -1, 1 },
48              { -1,  2, 1 },
49              {  1, -1, 2 }
50      };
51  
52      // from http://eigen.tuxfamily.org/dox/classEigen_1_1RealSchur.html
53      private double[][] testRandom = {
54              {  0.680, -0.3300, -0.2700, -0.717, -0.687,  0.0259 },
55              { -0.211,  0.5360,  0.0268,  0.214, -0.198,  0.6780 },
56              {  0.566, -0.4440,  0.9040, -0.967, -0.740,  0.2250 },
57              {  0.597,  0.1080,  0.8320, -0.514, -0.782, -0.4080 },
58              {  0.823, -0.0452,  0.2710, -0.726,  0.998,  0.2750 },
59              { -0.605,  0.2580,  0.4350,  0.608, -0.563,  0.0486 }
60      };
61  
62      @Test
63      void testNonSquare() {
64          try {
65              new SchurTransformer(MatrixUtils.createRealMatrix(new double[3][2]));
66              fail("an exception should have been thrown");
67          } catch (MathIllegalArgumentException ime) {
68              assertEquals(LocalizedCoreFormats.NON_SQUARE_MATRIX, ime.getSpecifier());
69          }
70      }
71  
72      @Test
73      void testAEqualPTPt() {
74          checkAEqualPTPt(MatrixUtils.createRealMatrix(testSquare5));
75          checkAEqualPTPt(MatrixUtils.createRealMatrix(testSquare3));
76          checkAEqualPTPt(MatrixUtils.createRealMatrix(testRandom));
77     }
78  
79      @Test
80      void testPOrthogonal() {
81          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare5)).getP());
82          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare3)).getP());
83          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testRandom)).getP());
84      }
85  
86      @Test
87      void testPTOrthogonal() {
88          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare5)).getPT());
89          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare3)).getPT());
90          checkOrthogonal(new SchurTransformer(MatrixUtils.createRealMatrix(testRandom)).getPT());
91      }
92  
93      @Test
94      void testSchurForm() {
95          checkSchurForm(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare5)).getT());
96          checkSchurForm(new SchurTransformer(MatrixUtils.createRealMatrix(testSquare3)).getT());
97          checkSchurForm(new SchurTransformer(MatrixUtils.createRealMatrix(testRandom)).getT());
98      }
99  
100     @Test
101     void testRandomData() {
102         for (int run = 0; run < 100; run++) {
103             Random r = new Random(System.currentTimeMillis());
104 
105             // matrix size
106             int size = r.nextInt(20) + 4;
107 
108             double[][] data = new double[size][size];
109             for (int i = 0; i < size; i++) {
110                 for (int j = 0; j < size; j++) {
111                     data[i][j] = r.nextInt(100);
112                 }
113             }
114 
115             RealMatrix m = MatrixUtils.createRealMatrix(data);
116             RealMatrix s = checkAEqualPTPt(m);
117             checkSchurForm(s);
118         }
119     }
120 
121     @Test
122     void testRandomDataNormalDistribution() {
123         for (int run = 0; run < 100; run++) {
124             Random r = new Random(System.currentTimeMillis());
125             RandomDataGenerator randomDataGenerator = new RandomDataGenerator(100);
126 
127             // matrix size
128             int size = r.nextInt(20) + 4;
129 
130             double[][] data = new double[size][size];
131             for (int i = 0; i < size; i++) {
132                 for (int j = 0; j < size; j++) {
133                     data[i][j] = randomDataGenerator.nextNormal(0.0, r.nextDouble() * 5);
134                 }
135             }
136 
137             RealMatrix m = MatrixUtils.createRealMatrix(data);
138             RealMatrix s = checkAEqualPTPt(m);
139             checkSchurForm(s);
140         }
141     }
142 
143     @Test
144     void testMath848() {
145         double[][] data = {
146                 { 0.1849449280, -0.0646971046,  0.0774755812, -0.0969651755, -0.0692648806,  0.3282344352, -0.0177423074,  0.2063136340},
147                 {-0.0742700134, -0.0289063030, -0.0017269460, -0.0375550146, -0.0487737922, -0.2616837868, -0.0821201295, -0.2530000167},
148                 { 0.2549910127,  0.0995733692, -0.0009718388,  0.0149282808,  0.1791878897, -0.0823182816,  0.0582629256,  0.3219545182},
149                 {-0.0694747557, -0.1880649148, -0.2740630911,  0.0720096468, -0.1800836914, -0.3518996425,  0.2486747833,  0.6257938167},
150                 { 0.0536360918, -0.1339297778,  0.2241579764, -0.0195327484, -0.0054103808,  0.0347564518,  0.5120802482, -0.0329902864},
151                 {-0.5933332356, -0.2488721082,  0.2357173629,  0.0177285473,  0.0856630593, -0.3567126300, -0.1600668126, -0.1010899621},
152                 {-0.0514349819, -0.0854319435,  0.1125050061,  0.0063453560, -0.2250000688, -0.2209343090,  0.1964623477, -0.1512329924},
153                 { 0.0197395947, -0.1997170581, -0.1425959019, -0.2749477910, -0.0969467073,  0.0603688520, -0.2826905192,  0.1794315473}};
154         RealMatrix m = MatrixUtils.createRealMatrix(data);
155         RealMatrix s = checkAEqualPTPt(m);
156         checkSchurForm(s);
157     }
158 
159     ///////////////////////////////////////////////////////////////////////////
160     // Test helpers
161     ///////////////////////////////////////////////////////////////////////////
162 
163     private RealMatrix checkAEqualPTPt(RealMatrix matrix) {
164         SchurTransformer transformer = new SchurTransformer(matrix);
165         RealMatrix p  = transformer.getP();
166         RealMatrix t  = transformer.getT();
167         RealMatrix pT = transformer.getPT();
168 
169         RealMatrix result = p.multiply(t).multiply(pT);
170 
171         double norm = result.subtract(matrix).getNorm1();
172         assertEquals(0, norm, 1.0e-9);
173 
174         return t;
175     }
176 
177     private void checkOrthogonal(RealMatrix m) {
178         RealMatrix mTm = m.transposeMultiply(m);
179         RealMatrix id  = MatrixUtils.createRealIdentityMatrix(mTm.getRowDimension());
180         assertEquals(0, mTm.subtract(id).getNorm1(), 1.0e-14);
181     }
182 
183     private void checkSchurForm(final RealMatrix m) {
184         final int rows = m.getRowDimension();
185         final int cols = m.getColumnDimension();
186         for (int i = 0; i < rows; ++i) {
187             for (int j = 0; j < cols; ++j) {
188                 if (i > j + 1) {
189                     assertEquals(0, m.getEntry(i, j), 1.0e-16);
190                 }
191             }
192         }
193     }
194 
195     @SuppressWarnings("unused")
196     private void checkMatricesValues(double[][] matrix, double[][] pRef, double[][] hRef) {
197 
198         SchurTransformer transformer =
199             new SchurTransformer(MatrixUtils.createRealMatrix(matrix));
200 
201         // check values against known references
202         RealMatrix p = transformer.getP();
203         assertEquals(0, p.subtract(MatrixUtils.createRealMatrix(pRef)).getNorm1(), 1.0e-14);
204 
205         RealMatrix t = transformer.getT();
206         assertEquals(0, t.subtract(MatrixUtils.createRealMatrix(hRef)).getNorm1(), 1.0e-14);
207 
208         // check the same cached instance is returned the second time
209         assertTrue(p == transformer.getP());
210         assertTrue(t == transformer.getT());
211     }
212 }