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    *      http://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  package org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv;
19  
20  import java.util.Arrays;
21  import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
22  import org.apache.commons.math4.legacy.analysis.MultivariateVectorFunction;
23  import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix;
24  import org.apache.commons.math4.legacy.linear.RealMatrix;
25  import org.apache.commons.math4.legacy.optim.InitialGuess;
26  import org.apache.commons.math4.legacy.optim.MaxEval;
27  import org.apache.commons.math4.legacy.optim.PointValuePair;
28  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
29  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.LeastSquaresConverter;
30  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.ObjectiveFunction;
31  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv.OptimTestUtils.FourExtrema;
32  import org.apache.commons.math4.legacy.core.MathArrays;
33  import org.junit.Assert;
34  import org.junit.Test;
35  import org.junit.Ignore;
36  
37  /**
38   * Tests for {@link NelderMeadTransform}.
39   */
40  public class SimplexOptimizerNelderMeadTest {
41      private static final int DIM = 13;
42  
43      @Test
44      public void testLeastSquares1() {
45          final RealMatrix factors
46              = new Array2DRowRealMatrix(new double[][] {
47                      { 1, 0 },
48                      { 0, 1 }
49                  }, false);
50          LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
51                  @Override
52                  public double[] value(double[] variables) {
53                      return factors.operate(variables);
54                  }
55              }, new double[] { 2.0, -3.0 });
56          SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
57          PointValuePair optimum =
58              optimizer.optimize(new MaxEval(200),
59                                 new ObjectiveFunction(ls),
60                                 GoalType.MINIMIZE,
61                                 new InitialGuess(new double[] { 10, 10 }),
62                                 Simplex.equalSidesAlongAxes(2, 1d),
63                                 new NelderMeadTransform());
64          Assert.assertEquals( 2, optimum.getPointRef()[0], 1e-3);
65          Assert.assertEquals(-3, optimum.getPointRef()[1], 4e-4);
66          final int nEval = optimizer.getEvaluations();
67          Assert.assertTrue("nEval=" + nEval, nEval > 60);
68          Assert.assertTrue("nEval=" + nEval, nEval < 80);
69          Assert.assertTrue(optimum.getValue() < 1.0e-6);
70      }
71  
72      @Test
73      public void testLeastSquares2() {
74          final RealMatrix factors
75              = new Array2DRowRealMatrix(new double[][] {
76                      { 1, 0 },
77                      { 0, 1 }
78                  }, false);
79          LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
80                  @Override
81                  public double[] value(double[] variables) {
82                      return factors.operate(variables);
83                  }
84              }, new double[] { 2, -3 }, new double[] { 10, 0.1 });
85          SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
86          PointValuePair optimum =
87              optimizer.optimize(new MaxEval(200),
88                                 new ObjectiveFunction(ls),
89                                 GoalType.MINIMIZE,
90                                 new InitialGuess(new double[] { 10, 10 }),
91                                 Simplex.equalSidesAlongAxes(2, 1d),
92                                 new NelderMeadTransform());
93          Assert.assertEquals( 2, optimum.getPointRef()[0], 1e-4);
94          Assert.assertEquals(-3, optimum.getPointRef()[1], 8e-4);
95          final int nEval = optimizer.getEvaluations();
96          Assert.assertTrue("nEval=" + nEval, nEval > 70);
97          Assert.assertTrue("nEval=" + nEval, nEval < 85);
98          Assert.assertTrue(optimum.getValue() < 1e-6);
99      }
100 
101     @Test
102     public void testLeastSquares3() {
103         final RealMatrix factors =
104             new Array2DRowRealMatrix(new double[][] {
105                     { 1, 0 },
106                     { 0, 1 }
107                 }, false);
108         LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorFunction() {
109                 @Override
110                 public double[] value(double[] variables) {
111                     return factors.operate(variables);
112                 }
113             }, new double[] { 2, -3 }, new Array2DRowRealMatrix(new double [][] {
114                     { 1, 1.2 }, { 1.2, 2 }
115                 }));
116         SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
117         PointValuePair optimum
118             = optimizer.optimize(new MaxEval(200),
119                                  new ObjectiveFunction(ls),
120                                  GoalType.MINIMIZE,
121                                  new InitialGuess(new double[] { 10, 10 }),
122                                  Simplex.equalSidesAlongAxes(2, 1d),
123                                  new NelderMeadTransform());
124         Assert.assertEquals( 2, optimum.getPointRef()[0], 1e-2);
125         Assert.assertEquals(-3, optimum.getPointRef()[1], 1e-2);
126         final int nEval = optimizer.getEvaluations();
127         Assert.assertTrue("nEval=" + nEval, nEval > 60);
128         Assert.assertTrue("nEval=" + nEval, nEval < 80);
129         Assert.assertTrue(optimum.getValue() < 1e-6);
130     }
131 
132     @Test
133     public void testFourExtremaMinimize1() {
134         final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
135         doTest(f,
136                OptimTestUtils.point(new double[] {-3, 0}, 1e-1),
137                GoalType.MINIMIZE,
138                105,
139                Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
140                new PointValuePair(new double[] {FourExtrema.xM, FourExtrema.yP}, FourExtrema.valueXmYp),
141                1e-6);
142     }
143     @Test
144     public void testFourExtremaMaximize1() {
145         final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
146         doTest(f,
147                OptimTestUtils.point(new double[] {-3, 0}, 1e-1),
148                GoalType.MAXIMIZE,
149                100,
150                Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
151                new PointValuePair(new double[] {FourExtrema.xM, FourExtrema.yM}, FourExtrema.valueXmYm),
152                1e-6);
153     }
154     @Test
155     public void testFourExtremaMinimize2() {
156         final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
157         doTest(f,
158                OptimTestUtils.point(new double[] {1, 0}, 1e-1),
159                GoalType.MINIMIZE,
160                100,
161                Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
162                new PointValuePair(new double[] {FourExtrema.xP, FourExtrema.yM}, FourExtrema.valueXpYm),
163                1e-6);
164     }
165     @Test
166     public void testFourExtremaMaximize2() {
167         final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
168         doTest(f,
169                OptimTestUtils.point(new double[] {1, 0}, 1e-1),
170                GoalType.MAXIMIZE,
171                110,
172                Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
173                new PointValuePair(new double[] {FourExtrema.xP, FourExtrema.yP}, FourExtrema.valueXpYp),
174                1e-6);
175     }
176 
177     @Ignore("See MATH-1552")@Test
178     public void testElliRotated() {
179         doTest(new OptimTestUtils.ElliRotated(),
180                OptimTestUtils.point(DIM, 1.0, 1e-1),
181                GoalType.MINIMIZE,
182                7467,
183                new PointValuePair(OptimTestUtils.point(DIM, 0.0), 0.0),
184                1e-14);
185     }
186 
187     /**
188      * @param func Function to optimize.
189      * @param startPoint Starting point.
190      * @param goal Minimization or maximization.
191      * @param maxEvaluations Maximum number of evaluations.
192      * @param expected Expected optimum.
193      * @param tol Tolerance for checking that the optimum is correct.
194      */
195     private void doTest(MultivariateFunction func,
196                         double[] startPoint,
197                         GoalType goal,
198                         int maxEvaluations,
199                         PointValuePair expected,
200                         double tol) {
201         doTest(func,
202                startPoint,
203                goal,
204                maxEvaluations,
205                Simplex.equalSidesAlongAxes(startPoint.length, 1d),
206                expected,
207                tol);
208     }
209 
210     /**
211      * @param func Function to optimize.
212      * @param startPoint Starting point.
213      * @param goal Minimization or maximization.
214      * @param maxEvaluations Maximum number of evaluations.
215      * @param simplexSteps Initial simplex.
216      * @param expected Expected optimum.
217      * @param tol Tolerance for checking that the optimum is correct.
218      */
219     private void doTest(MultivariateFunction func,
220                         double[] startPoint,
221                         GoalType goal,
222                         int maxEvaluations,
223                         Simplex simplex,
224                         PointValuePair expected,
225                         double tol) {
226         final String name = func.toString();
227 
228         final int maxEval = Math.max(maxEvaluations, 12000);
229         final SimplexOptimizer optim = new SimplexOptimizer(1e-13, 1e-14);
230         final PointValuePair result = optim.optimize(new MaxEval(maxEval),
231                                                      new ObjectiveFunction(func),
232                                                      goal,
233                                                      new InitialGuess(startPoint),
234                                                      simplex,
235                                                      new NelderMeadTransform());
236 
237         final double[] endPoint = result.getPoint();
238         final double funcValue = result.getValue();
239         Assert.assertEquals(name + ": value at " + Arrays.toString(endPoint),
240                             expected.getValue(),
241                             funcValue, 1e-2);
242 
243         final double dist = MathArrays.distance(expected.getPoint(),
244                                                 endPoint);
245         Assert.assertEquals(name + ": distance to optimum", 0d, dist, tol);
246 
247         final int nEval = optim.getEvaluations();
248         Assert.assertTrue(name + ": nEval=" + nEval + " < " + maxEvaluations,
249                           nEval < maxEvaluations);
250     }
251 }