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.optim.nonlinear.vector.leastsquares;
24  
25  import org.hipparchus.exception.LocalizedCoreFormats;
26  import org.hipparchus.exception.MathIllegalStateException;
27  import org.hipparchus.geometry.euclidean.threed.Plane;
28  import org.hipparchus.geometry.euclidean.threed.Vector3D;
29  import org.hipparchus.linear.SingularValueDecomposer;
30  import org.hipparchus.optim.SimpleVectorValueChecker;
31  import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
32  import org.hipparchus.util.FastMath;
33  import org.junit.jupiter.api.Test;
34  
35  import java.io.IOException;
36  
37  import static org.junit.jupiter.api.Assertions.assertEquals;
38  
39  /**
40   * <p>Some of the unit tests are re-implementations of the MINPACK <a
41   * href="http://www.netlib.org/minpack/ex/file17">file17</a> and <a
42   * href="http://www.netlib.org/minpack/ex/file22">file22</a> test files.
43   * The redistribution policy for MINPACK is available <a
44   * href="http://www.netlib.org/minpack/disclaimer">here</a>/
45   *
46   */
47  public class GaussNewtonOptimizerWithSVDTest
48      extends AbstractLeastSquaresOptimizerAbstractTest {
49  
50      @Override
51      public int getMaxIterations() {
52          return 1000;
53      }
54  
55      @Override
56      public LeastSquaresOptimizer getOptimizer() {
57          return new GaussNewtonOptimizer(new SingularValueDecomposer(), false);
58      }
59  
60      @Test
61      void testMaxEvaluations() throws Exception {
62          try{
63          CircleVectorial circle = new CircleVectorial();
64          circle.addPoint( 30.0,  68.0);
65          circle.addPoint( 50.0,  -6.0);
66          circle.addPoint(110.0, -20.0);
67          circle.addPoint( 35.0,  15.0);
68          circle.addPoint( 45.0,  97.0);
69  
70          LeastSquaresProblem lsp = builder(circle)
71                  .checkerPair(new SimpleVectorValueChecker(1e-30, 1e-30))
72                  .maxIterations(Integer.MAX_VALUE)
73                  .start(new double[]{98.680, 47.345})
74                  .build();
75  
76          optimizer.optimize(lsp);
77  
78              customFail(optimizer);
79          }catch (MathIllegalStateException e){
80              //expected
81          }
82      }
83  
84      @Override
85      @Test
86      public void testCircleFittingBadInit() {
87          /*
88           * This test converged to the wrong solution with this optimizer.
89           * It seems that the state becomes so large that the convergence
90           * checker's relative tolerance test passes.
91           */
92          try {
93              super.testCircleFittingBadInit();
94              customFail(optimizer);
95          } catch (AssertionError e) {
96              //expected
97          }
98      }
99  
100     @Override
101     @Test
102     public void testHahn1() throws IOException {
103         try {
104             /*
105              * When NOT FORMING normal equations, the optimizer diverges and hit max evaluations.
106              * When FORMING normal equations, the optimizer converges,
107              * but the results are very bad
108              */
109             super.testHahn1();
110             customFail(optimizer);
111         } catch (MathIllegalStateException e) {
112             assertEquals(LocalizedCoreFormats.MAX_COUNT_EXCEEDED, e.getSpecifier());
113         }
114     }
115 
116     @Test
117     @Override
118     public void testGetIterations() {
119         /* this diverges with SVD and no normal equations */
120         try {
121             super.testGetIterations();
122             customFail(optimizer);
123         } catch (MathIllegalStateException e) {
124             assertEquals(LocalizedCoreFormats.MAX_COUNT_EXCEEDED,
125                                 e.getSpecifier());
126         }
127     }
128 
129     @Test
130     @Override
131     public void testNonInvertible() throws Exception {
132         /*  SVD can compute a solution to singular problems.
133          *  In this case the target vector, b, is not in the
134          *  span of the jacobian matrix, A. The closest point
135          *  to b on the plane spanned by A is computed.
136          */
137         LinearProblem problem = new LinearProblem(new double[][]{
138                 {1, 2, -3},
139                 {2, 1, 3},
140                 {-3, 0, -9}
141         }, new double[]{1, 1, 1});
142 
143         Optimum optimum = optimizer.optimize(problem.getBuilder().build());
144 
145         Plane span = new Plane(Vector3D.ZERO, new Vector3D(1, 2, -3), new Vector3D(2, 1, 0), TOl);
146         double expected = FastMath.abs(span.getOffset(new Vector3D(1, 1, 1)));
147         double actual = optimum.getResiduals().getNorm();
148 
149         //verify
150         assertEquals(expected, actual, TOl);
151     }
152 
153 }