1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.hipparchus.optim.nonlinear.vector.leastsquares;
15
16 import java.io.IOException;
17 import java.util.Arrays;
18
19 import org.hipparchus.UnitTestUtils;
20 import org.hipparchus.analysis.MultivariateMatrixFunction;
21 import org.hipparchus.analysis.MultivariateVectorFunction;
22 import org.hipparchus.exception.MathIllegalArgumentException;
23 import org.hipparchus.exception.MathIllegalStateException;
24 import org.hipparchus.linear.ArrayRealVector;
25 import org.hipparchus.linear.DiagonalMatrix;
26 import org.hipparchus.linear.MatrixUtils;
27 import org.hipparchus.linear.RealMatrix;
28 import org.hipparchus.linear.RealVector;
29 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem.Evaluation;
30 import org.hipparchus.util.FastMath;
31 import org.hipparchus.util.Pair;
32 import org.hipparchus.util.Precision;
33 import org.junit.Assert;
34 import org.junit.Test;
35
36
37
38
39
40
41 public class EvaluationTest {
42
43
44
45
46
47
48
49 public LeastSquaresBuilder builder(StatisticalReferenceDataset dataset) {
50 StatisticalReferenceDataset.LeastSquaresProblem problem
51 = dataset.getLeastSquaresProblem();
52 final double[] start = dataset.getParameters();
53 final double[] observed = dataset.getData()[1];
54 final double[] weights = new double[observed.length];
55 Arrays.fill(weights, 1d);
56
57 return new LeastSquaresBuilder()
58 .model(problem.getModelFunction(), problem.getModelFunctionJacobian())
59 .target(observed)
60 .weight(new DiagonalMatrix(weights))
61 .start(start);
62 }
63
64 @Test
65 public void testComputeResiduals() {
66
67 RealVector point = new ArrayRealVector(2);
68 Evaluation evaluation = new LeastSquaresBuilder()
69 .target(new ArrayRealVector(new double[]{3,-1}))
70 .model(new MultivariateJacobianFunction() {
71 public Pair<RealVector, RealMatrix> value(RealVector point) {
72 return new Pair<RealVector, RealMatrix>(
73 new ArrayRealVector(new double[]{1, 2}),
74 MatrixUtils.createRealIdentityMatrix(2)
75 );
76 }
77 })
78 .weight(MatrixUtils.createRealIdentityMatrix(2))
79 .build()
80 .evaluate(point);
81
82
83 Assert.assertArrayEquals(
84 evaluation.getResiduals().toArray(),
85 new double[]{2, -3},
86 Precision.EPSILON);
87 }
88
89 @Test
90 public void testComputeCovariance() throws IOException {
91
92 RealVector point = new ArrayRealVector(2);
93 Evaluation evaluation = new LeastSquaresBuilder()
94 .model(new MultivariateJacobianFunction() {
95 public Pair<RealVector, RealMatrix> value(RealVector point) {
96 return new Pair<RealVector, RealMatrix>(
97 new ArrayRealVector(2),
98 MatrixUtils.createRealDiagonalMatrix(new double[]{1, 1e-2})
99 );
100 }
101 })
102 .weight(MatrixUtils.createRealDiagonalMatrix(new double[]{1, 1}))
103 .target(new ArrayRealVector(2))
104 .build()
105 .evaluate(point);
106
107
108 UnitTestUtils.assertEquals(
109 "covariance",
110 evaluation.getCovariances(FastMath.nextAfter(1e-4, 0.0)),
111 MatrixUtils.createRealMatrix(new double[][]{{1, 0}, {0, 1e4}}),
112 Precision.EPSILON
113 );
114
115
116 try {
117 evaluation.getCovariances(FastMath.nextAfter(1e-4, 1.0));
118 Assert.fail("Expected Exception");
119 } catch (MathIllegalArgumentException e) {
120
121 }
122 }
123
124 @Test
125 public void testComputeValueAndJacobian() {
126
127 final RealVector point = new ArrayRealVector(new double[]{1, 2});
128 Evaluation evaluation = new LeastSquaresBuilder()
129 .weight(new DiagonalMatrix(new double[]{16, 4}))
130 .model(new MultivariateJacobianFunction() {
131 public Pair<RealVector, RealMatrix> value(RealVector actualPoint) {
132
133 Assert.assertArrayEquals(
134 point.toArray(), actualPoint.toArray(), Precision.EPSILON);
135
136 return new Pair<RealVector, RealMatrix>(
137 new ArrayRealVector(new double[]{3, 4}),
138 MatrixUtils.createRealMatrix(new double[][]{{5, 6}, {7, 8}})
139 );
140 }
141 })
142 .target(new double[2])
143 .build()
144 .evaluate(point);
145
146
147 RealVector residuals = evaluation.getResiduals();
148 RealMatrix jacobian = evaluation.getJacobian();
149
150
151 Assert.assertArrayEquals(evaluation.getPoint().toArray(), point.toArray(), 0);
152 Assert.assertArrayEquals(new double[]{-12, -8}, residuals.toArray(), Precision.EPSILON);
153 UnitTestUtils.assertEquals(
154 "jacobian",
155 jacobian,
156 MatrixUtils.createRealMatrix(new double[][]{{20, 24},{14, 16}}),
157 Precision.EPSILON);
158 }
159
160 @Test
161 public void testComputeCost() throws IOException {
162 final StatisticalReferenceDataset dataset
163 = StatisticalReferenceDatasetFactory.createKirby2();
164
165 final LeastSquaresProblem lsp = builder(dataset).build();
166
167 final double expected = dataset.getResidualSumOfSquares();
168 final double cost = lsp.evaluate(lsp.getStart()).getCost();
169 final double actual = cost * cost;
170 Assert.assertEquals(dataset.getName(), expected, actual, 1e-11 * expected);
171 }
172
173 @Test
174 public void testComputeRMS() throws IOException {
175 final StatisticalReferenceDataset dataset
176 = StatisticalReferenceDatasetFactory.createKirby2();
177
178 final LeastSquaresProblem lsp = builder(dataset).build();
179
180 final double expected = FastMath.sqrt(dataset.getResidualSumOfSquares() /
181 dataset.getNumObservations());
182 final double actual = lsp.evaluate(lsp.getStart()).getRMS();
183 Assert.assertEquals(dataset.getName(), expected, actual, 1e-11 * expected);
184 }
185
186 @Test
187 public void testComputeSigma() throws IOException {
188 final StatisticalReferenceDataset dataset
189 = StatisticalReferenceDatasetFactory.createKirby2();
190
191 final LeastSquaresProblem lsp = builder(dataset).build();
192
193 final double[] expected = dataset.getParametersStandardDeviations();
194
195 final Evaluation evaluation = lsp.evaluate(lsp.getStart());
196 final double cost = evaluation.getCost();
197 final RealVector sig = evaluation.getSigma(1e-14);
198 final int dof = lsp.getObservationSize() - lsp.getParameterSize();
199 for (int i = 0; i < sig.getDimension(); i++) {
200 final double actual = FastMath.sqrt(cost * cost / dof) * sig.getEntry(i);
201 Assert.assertEquals(dataset.getName() + ", parameter #" + i,
202 expected[i], actual, 1e-6 * expected[i]);
203 }
204 }
205
206 @Test
207 public void testEvaluateCopiesPoint() throws IOException {
208
209 StatisticalReferenceDataset dataset
210 = StatisticalReferenceDatasetFactory.createKirby2();
211 LeastSquaresProblem lsp = builder(dataset).build();
212 RealVector point = new ArrayRealVector(lsp.getParameterSize());
213
214
215 Evaluation evaluation = lsp.evaluate(point);
216
217
218 Assert.assertNotSame(point, evaluation.getPoint());
219 point.setEntry(0, 1);
220 Assert.assertEquals(evaluation.getPoint().getEntry(0), 0, 0);
221 }
222
223 @Test
224 public void testLazyEvaluation() {
225 final RealVector dummy = new ArrayRealVector(new double[] { 0 });
226
227 final LeastSquaresProblem p
228 = LeastSquaresFactory.create(LeastSquaresFactory.model(dummyModel(), dummyJacobian()),
229 dummy, dummy, null, null, 0, 0, true, null);
230
231
232 final Evaluation eval = p.evaluate(dummy);
233
234 try {
235 eval.getResiduals();
236 Assert.fail("Exception expected");
237 } catch (RuntimeException e) {
238
239 Assert.assertEquals("dummyModel", e.getMessage());
240 }
241
242 try {
243 eval.getJacobian();
244 Assert.fail("Exception expected");
245 } catch (RuntimeException e) {
246
247 Assert.assertEquals("dummyJacobian", e.getMessage());
248 }
249 }
250
251
252 @Test
253 public void testLazyEvaluationPrecondition() {
254 final RealVector dummy = new ArrayRealVector(new double[] { 0 });
255
256
257
258 final MultivariateJacobianFunction m1 = new MultivariateJacobianFunction() {
259 public Pair<RealVector, RealMatrix> value(RealVector notUsed) {
260 return new Pair<RealVector, RealMatrix>(null, null);
261 }
262 };
263
264 try {
265
266 LeastSquaresFactory.create(m1, dummy, dummy, null, null, 0, 0, true, null);
267 Assert.fail("Expecting MathIllegalStateException");
268 } catch (MathIllegalStateException e) {
269
270 }
271
272 final MultivariateJacobianFunction m2 = new ValueAndJacobianFunction() {
273 public Pair<RealVector, RealMatrix> value(RealVector notUsed) {
274 return new Pair<RealVector, RealMatrix>(null, null);
275 }
276 public RealVector computeValue(final double[] params) {
277 return null;
278 }
279 public RealMatrix computeJacobian(final double[] params) {
280 return null;
281 }
282 };
283
284
285 LeastSquaresFactory.create(m2, dummy, dummy, null, null, 0, 0, true, null);
286 }
287
288 @Test
289 public void testDirectEvaluation() {
290 final RealVector dummy = new ArrayRealVector(new double[] { 0 });
291
292 final LeastSquaresProblem p
293 = LeastSquaresFactory.create(LeastSquaresFactory.model(dummyModel(), dummyJacobian()),
294 dummy, dummy, null, null, 0, 0, false, null);
295
296 try {
297
298 p.evaluate(dummy);
299 Assert.fail("Exception expected");
300 } catch (RuntimeException e) {
301
302
303 final String msg = e.getMessage();
304 Assert.assertTrue(msg.equals("dummyModel") ||
305 msg.equals("dummyJacobian"));
306 }
307 }
308
309
310 private MultivariateVectorFunction dummyModel() {
311 return new MultivariateVectorFunction() {
312 public double[] value(double[] p) {
313 throw new RuntimeException("dummyModel");
314 }
315 };
316 }
317
318
319 private MultivariateMatrixFunction dummyJacobian() {
320 return new MultivariateMatrixFunction() {
321 public double[][] value(double[] p) {
322 throw new RuntimeException("dummyJacobian");
323 }
324 };
325 }
326 }