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.scalar.noderiv;
24  
25  
26  import org.hipparchus.analysis.MultivariateFunction;
27  import org.hipparchus.analysis.MultivariateVectorFunction;
28  import org.hipparchus.exception.MathIllegalStateException;
29  import org.hipparchus.exception.MathRuntimeException;
30  import org.hipparchus.linear.Array2DRowRealMatrix;
31  import org.hipparchus.linear.RealMatrix;
32  import org.hipparchus.optim.InitialGuess;
33  import org.hipparchus.optim.MaxEval;
34  import org.hipparchus.optim.PointValuePair;
35  import org.hipparchus.optim.SimpleBounds;
36  import org.hipparchus.optim.nonlinear.scalar.GoalType;
37  import org.hipparchus.optim.nonlinear.scalar.LeastSquaresConverter;
38  import org.hipparchus.optim.nonlinear.scalar.ObjectiveFunction;
39  import org.hipparchus.util.FastMath;
40  import org.junit.Assert;
41  import org.junit.Test;
42  
43  public class SimplexOptimizerNelderMeadTest {
44      @Test(expected=MathRuntimeException.class)
45      public void testBoundsUnsupported() {
46          SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
47          final FourExtrema fourExtrema = new FourExtrema();
48  
49          optimizer.optimize(new MaxEval(100),
50                             new ObjectiveFunction(fourExtrema),
51                             GoalType.MINIMIZE,
52                             new InitialGuess(new double[] { -3, 0 }),
53                             new NelderMeadSimplex(new double[] { 0.2, 0.2 }),
54                             new SimpleBounds(new double[] { -5, -1 },
55                                              new double[] { 5, 1 }));
56      }
57  
58      @Test
59      public void testMinimize1() {
60          SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
61          final FourExtrema fourExtrema = new FourExtrema();
62  
63          final PointValuePair optimum
64              = optimizer.optimize(new MaxEval(100),
65                                   new ObjectiveFunction(fourExtrema),
66                                   GoalType.MINIMIZE,
67                                   new InitialGuess(new double[] { -3, 0 }),
68                                   new NelderMeadSimplex(new double[] { 0.2, 0.2 }));
69          Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 2e-7);
70          Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 2e-5);
71          Assert.assertEquals(fourExtrema.valueXmYp, optimum.getValue(), 6e-12);
72          Assert.assertTrue(optimizer.getEvaluations() > 60);
73          Assert.assertTrue(optimizer.getEvaluations() < 90);
74  
75          // Check that the number of iterations is updated (MATH-949).
76          Assert.assertTrue(optimizer.getIterations() > 0);
77      }
78  
79      @Test
80      public void testMinimize2() {
81          SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
82          final FourExtrema fourExtrema = new FourExtrema();
83  
84          final PointValuePair optimum
85              = optimizer.optimize(new MaxEval(100),
86                                   new ObjectiveFunction(fourExtrema),
87                                   GoalType.MINIMIZE,
88                                   new InitialGuess(new double[] { 1, 0 }),
89                                   new NelderMeadSimplex(new double[] { 0.2, 0.2 }));
90          Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 5e-6);
91          Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 6e-6);
92          Assert.assertEquals(fourExtrema.valueXpYm, optimum.getValue(), 1e-11);
93          Assert.assertTrue(optimizer.getEvaluations() > 60);
94          Assert.assertTrue(optimizer.getEvaluations() < 90);
95  
96          // Check that the number of iterations is updated (MATH-949).
97          Assert.assertTrue(optimizer.getIterations() > 0);
98      }
99  
100     @Test
101     public void testMaximize1() {
102         SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
103         final FourExtrema fourExtrema = new FourExtrema();
104 
105         final PointValuePair optimum
106             = optimizer.optimize(new MaxEval(100),
107                                  new ObjectiveFunction(fourExtrema),
108                                  GoalType.MAXIMIZE,
109                                  new InitialGuess(new double[] { -3, 0 }),
110                                  new NelderMeadSimplex(new double[] { 0.2, 0.2 }));
111         Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 1e-5);
112         Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 3e-6);
113         Assert.assertEquals(fourExtrema.valueXmYm, optimum.getValue(), 3e-12);
114         Assert.assertTrue(optimizer.getEvaluations() > 60);
115         Assert.assertTrue(optimizer.getEvaluations() < 90);
116 
117         // Check that the number of iterations is updated (MATH-949).
118         Assert.assertTrue(optimizer.getIterations() > 0);
119     }
120 
121     @Test
122     public void testMaximize2() {
123         SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
124         final FourExtrema fourExtrema = new FourExtrema();
125 
126         final PointValuePair optimum
127             = optimizer.optimize(new MaxEval(100),
128                                  new ObjectiveFunction(fourExtrema),
129                                  GoalType.MAXIMIZE,
130                                  new InitialGuess(new double[] { 1, 0 }),
131                                  new NelderMeadSimplex(new double[] { 0.2, 0.2 }));
132         Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 4e-6);
133         Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 5e-6);
134         Assert.assertEquals(fourExtrema.valueXpYp, optimum.getValue(), 7e-12);
135         Assert.assertTrue(optimizer.getEvaluations() > 60);
136         Assert.assertTrue(optimizer.getEvaluations() < 90);
137 
138         // Check that the number of iterations is updated (MATH-949).
139         Assert.assertTrue(optimizer.getIterations() > 0);
140     }
141 
142     @Test
143     public void testRosenbrock() {
144 
145         Rosenbrock rosenbrock = new Rosenbrock();
146         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
147         PointValuePair optimum
148         = optimizer.optimize(new MaxEval(100),
149                              new ObjectiveFunction(rosenbrock),
150                              GoalType.MINIMIZE,
151                              new InitialGuess(new double[] { -1.2, 1 }),
152                                 new NelderMeadSimplex(new double[][] {
153                                         { -1.2,  1 },
154                                         { 0.9, 1.2 },
155                                         {  3.5, -2.3 } }));
156 
157         Assert.assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
158         Assert.assertTrue(optimizer.getEvaluations() > 40);
159         Assert.assertTrue(optimizer.getEvaluations() < 50);
160         Assert.assertTrue(optimum.getValue() < 8e-4);
161     }
162 
163     @Test
164     public void testPowell() {
165         Powell powell = new Powell();
166         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
167         PointValuePair optimum =
168             optimizer.optimize(new MaxEval(200),
169                                new ObjectiveFunction(powell),
170                                GoalType.MINIMIZE,
171                                new InitialGuess(new double[] { 3, -1, 0, 1 }),
172                                new NelderMeadSimplex(4));
173         Assert.assertEquals(powell.getCount(), optimizer.getEvaluations());
174         Assert.assertTrue(optimizer.getEvaluations() > 110);
175         Assert.assertTrue(optimizer.getEvaluations() < 130);
176         Assert.assertTrue(optimum.getValue() < 2e-3);
177     }
178 
179     @Test
180     public void testLeastSquares1() {
181         final RealMatrix factors
182             = new Array2DRowRealMatrix(new double[][] {
183                     { 1, 0 },
184                     { 0, 1 }
185                 }, false);
186         LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
187                 public double[] value(double[] variables) {
188                     return factors.operate(variables);
189                 }
190             }, new double[] { 2.0, -3.0 });
191         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
192         PointValuePair optimum =
193             optimizer.optimize(new MaxEval(200),
194                                new ObjectiveFunction(ls),
195                                GoalType.MINIMIZE,
196                                new InitialGuess(new double[] { 10, 10 }),
197                                new NelderMeadSimplex(2));
198         Assert.assertEquals( 2, optimum.getPointRef()[0], 3e-5);
199         Assert.assertEquals(-3, optimum.getPointRef()[1], 4e-4);
200         Assert.assertTrue(optimizer.getEvaluations() > 60);
201         Assert.assertTrue(optimizer.getEvaluations() < 80);
202         Assert.assertTrue(optimum.getValue() < 1.0e-6);
203     }
204 
205     @Test
206     public void testLeastSquares2() {
207         final RealMatrix factors
208             = new Array2DRowRealMatrix(new double[][] {
209                     { 1, 0 },
210                     { 0, 1 }
211                 }, false);
212         LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
213                 public double[] value(double[] variables) {
214                     return factors.operate(variables);
215                 }
216             }, new double[] { 2, -3 }, new double[] { 10, 0.1 });
217         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
218         PointValuePair optimum =
219             optimizer.optimize(new MaxEval(200),
220                                new ObjectiveFunction(ls),
221                                GoalType.MINIMIZE,
222                                new InitialGuess(new double[] { 10, 10 }),
223                                new NelderMeadSimplex(2));
224         Assert.assertEquals( 2, optimum.getPointRef()[0], 5e-5);
225         Assert.assertEquals(-3, optimum.getPointRef()[1], 8e-4);
226         Assert.assertTrue(optimizer.getEvaluations() > 60);
227         Assert.assertTrue(optimizer.getEvaluations() < 80);
228         Assert.assertTrue(optimum.getValue() < 1e-6);
229     }
230 
231     @Test
232     public void testLeastSquares3() {
233         final RealMatrix factors =
234             new Array2DRowRealMatrix(new double[][] {
235                     { 1, 0 },
236                     { 0, 1 }
237                 }, false);
238         LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
239                 public double[] value(double[] variables) {
240                     return factors.operate(variables);
241                 }
242             }, new double[] { 2, -3 }, new Array2DRowRealMatrix(new double [][] {
243                     { 1, 1.2 }, { 1.2, 2 }
244                 }));
245         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
246         PointValuePair optimum
247             = optimizer.optimize(new MaxEval(200),
248                                  new ObjectiveFunction(ls),
249                                  GoalType.MINIMIZE,
250                                  new InitialGuess(new double[] { 10, 10 }),
251                                  new NelderMeadSimplex(2));
252         Assert.assertEquals( 2, optimum.getPointRef()[0], 2e-3);
253         Assert.assertEquals(-3, optimum.getPointRef()[1], 8e-4);
254         Assert.assertTrue(optimizer.getEvaluations() > 60);
255         Assert.assertTrue(optimizer.getEvaluations() < 80);
256         Assert.assertTrue(optimum.getValue() < 1e-6);
257     }
258 
259     @Test(expected=MathIllegalStateException.class)
260     public void testMaxIterations() {
261         Powell powell = new Powell();
262         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
263         optimizer.optimize(new MaxEval(20),
264                            new ObjectiveFunction(powell),
265                            GoalType.MINIMIZE,
266                            new InitialGuess(new double[] { 3, -1, 0, 1 }),
267                            new NelderMeadSimplex(4));
268     }
269 
270     private static class FourExtrema implements MultivariateFunction {
271         // The following function has 4 local extrema.
272         final double xM = -3.841947088256863675365;
273         final double yM = -1.391745200270734924416;
274         final double xP =  0.2286682237349059125691;
275         final double yP = -yM;
276         final double valueXmYm = 0.2373295333134216789769; // Local maximum.
277         final double valueXmYp = -valueXmYm; // Local minimum.
278         final double valueXpYm = -0.7290400707055187115322; // Global minimum.
279         final double valueXpYp = -valueXpYm; // Global maximum.
280 
281         public double value(double[] variables) {
282             final double x = variables[0];
283             final double y = variables[1];
284             return (x == 0 || y == 0) ? 0 :
285                 FastMath.atan(x) * FastMath.atan(x + 2) * FastMath.atan(y) * FastMath.atan(y) / (x * y);
286         }
287     }
288 
289     private static class Rosenbrock implements MultivariateFunction {
290         private int count;
291 
292         public Rosenbrock() {
293             count = 0;
294         }
295 
296         public double value(double[] x) {
297             ++count;
298             double a = x[1] - x[0] * x[0];
299             double b = 1.0 - x[0];
300             return 100 * a * a + b * b;
301         }
302 
303         public int getCount() {
304             return count;
305         }
306     }
307 
308     private static class Powell implements MultivariateFunction {
309         private int count;
310 
311         public Powell() {
312             count = 0;
313         }
314 
315         public double value(double[] x) {
316             ++count;
317             double a = x[0] + 10 * x[1];
318             double b = x[2] - x[3];
319             double c = x[1] - 2 * x[2];
320             double d = x[0] - x[3];
321             return a * a + 5 * b * b + c * c * c * c + 10 * d * d * d * d;
322         }
323 
324         public int getCount() {
325             return count;
326         }
327     }
328 }