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.optim.InitialGuess;
23  import org.apache.commons.math4.legacy.optim.MaxEval;
24  import org.apache.commons.math4.legacy.optim.PointValuePair;
25  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
26  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.ObjectiveFunction;
27  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv.OptimTestUtils.FourExtrema;
28  import org.apache.commons.math4.legacy.core.MathArrays;
29  import org.apache.commons.math4.core.jdkmath.JdkMath;
30  import org.junit.Assert;
31  import org.junit.Test;
32  import org.junit.Ignore;
33  
34  /**
35   * Tests for {@link MultiDirectionalTransform}.
36   */
37  public class SimplexOptimizerMultiDirectionalTest {
38      private static final int DIM = 13;
39  
40      @Test
41      public void testMath283() {
42          SimplexOptimizer optimizer = new SimplexOptimizer(1e-14, 1e-14);
43          final Gaussian2D function = new Gaussian2D(0, 0, 1);
44          PointValuePair estimate = optimizer.optimize(new MaxEval(1000),
45                                                       new ObjectiveFunction(function),
46                                                       GoalType.MAXIMIZE,
47                                                       new InitialGuess(function.getMaximumPosition()),
48                                                       Simplex.equalSidesAlongAxes(2, 1d),
49                                                       new MultiDirectionalTransform());
50          final double EPSILON = 1e-5;
51          final double expectedMaximum = function.getMaximum();
52          final double actualMaximum = estimate.getValue();
53          Assert.assertEquals(expectedMaximum, actualMaximum, EPSILON);
54  
55          final double[] expectedPosition = function.getMaximumPosition();
56          final double[] actualPosition = estimate.getPoint();
57          Assert.assertEquals(expectedPosition[0], actualPosition[0], EPSILON );
58          Assert.assertEquals(expectedPosition[1], actualPosition[1], EPSILON );
59      }
60  
61      @Test
62      public void testFourExtremaMinimize1() {
63          final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
64          doTest(f,
65                 OptimTestUtils.point(new double[] {-3, 0}, 1e-1),
66                 GoalType.MINIMIZE,
67                 105,
68                 Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
69                 new PointValuePair(new double[] {FourExtrema.xM, FourExtrema.yP}, FourExtrema.valueXmYp),
70                 1e-6);
71      }
72      @Test
73      public void testFourExtremaMaximize1() {
74          final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
75          doTest(f,
76                 OptimTestUtils.point(new double[] {-3, 0}, 1e-1),
77                 GoalType.MAXIMIZE,
78                 100,
79                 Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
80                 new PointValuePair(new double[] {FourExtrema.xM, FourExtrema.yM}, FourExtrema.valueXmYm),
81                 1e-6);
82      }
83      @Test
84      public void testFourExtremaMinimize2() {
85          final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
86          doTest(f,
87                 OptimTestUtils.point(new double[] {1, 0}, 1e-1),
88                 GoalType.MINIMIZE,
89                 100,
90                 Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
91                 new PointValuePair(new double[] {FourExtrema.xP, FourExtrema.yM}, FourExtrema.valueXpYm),
92                 1e-6);
93      }
94      @Test
95      public void testFourExtremaMaximize2() {
96          final OptimTestUtils.FourExtrema f = new OptimTestUtils.FourExtrema();
97          doTest(f,
98                 OptimTestUtils.point(new double[] {1, 0}, 1e-1),
99                 GoalType.MAXIMIZE,
100                110,
101                Simplex.alongAxes(OptimTestUtils.point(2, 0.2, 1e-2)),
102                new PointValuePair(new double[] {FourExtrema.xP, FourExtrema.yP}, FourExtrema.valueXpYp),
103                1e-6);
104     }
105 
106     @Ignore("See MATH-1552")@Test
107     public void testElliRotated() {
108         doTest(new OptimTestUtils.ElliRotated(),
109                OptimTestUtils.point(DIM, 1.0, 1e-1),
110                GoalType.MINIMIZE,
111                911,
112                new PointValuePair(OptimTestUtils.point(DIM, 0.0), 0.0),
113                1e-9);
114     }
115 
116     /**
117      * @param func Function to optimize.
118      * @param startPoint Starting point.
119      * @param goal Minimization or maximization.
120      * @param maxEvaluations Maximum number of evaluations.
121      * @param expected Expected optimum.
122      * @param tol Tolerance for checking that the optimum is correct.
123      */
124     private void doTest(MultivariateFunction func,
125                         double[] startPoint,
126                         GoalType goal,
127                         int maxEvaluations,
128                         PointValuePair expected,
129                         double tol) {
130         doTest(func,
131                startPoint,
132                goal,
133                maxEvaluations,
134                Simplex.equalSidesAlongAxes(startPoint.length, 1),
135                expected,
136                tol);
137     }
138 
139     /**
140      * @param func Function to optimize.
141      * @param startPoint Starting point.
142      * @param goal Minimization or maximization.
143      * @param maxEvaluations Maximum number of evaluations.
144      * @param simplexSteps Initial simplex.
145      * @param expected Expected optimum.
146      * @param tol Tolerance for checking that the optimum is correct.
147      */
148     private void doTest(MultivariateFunction func,
149                         double[] startPoint,
150                         GoalType goal,
151                         int maxEvaluations,
152                         Simplex simplex,
153                         PointValuePair expected,
154                         double tol) {
155         final int maxEval = Math.max(maxEvaluations, 12000);
156         final SimplexOptimizer optim = new SimplexOptimizer(1e-13, 1e-14);
157         final PointValuePair result = optim.optimize(new MaxEval(maxEval),
158                                                      new ObjectiveFunction(func),
159                                                      goal,
160                                                      new InitialGuess(startPoint),
161                                                      simplex,
162                                                      new NelderMeadTransform());
163         final String name = func.toString();
164 
165         final double[] endPoint = result.getPoint();
166         final double funcValue = result.getValue();
167         Assert.assertEquals(name + ": value at " + Arrays.toString(endPoint),
168                             expected.getValue(),
169                             funcValue, 1e-2);
170 
171         final double dist = MathArrays.distance(expected.getPoint(),
172                                                 endPoint);
173         Assert.assertEquals(name + ": distance to optimum", 0d, dist, tol);
174 
175         final int nEval = optim.getEvaluations();
176         Assert.assertTrue(name + ": nEval=" + nEval,
177                           nEval < maxEvaluations);
178     }
179 
180     private static final class Gaussian2D implements MultivariateFunction {
181         private final double[] maximumPosition;
182         private final double std;
183 
184         Gaussian2D(double xOpt, double yOpt, double std) {
185             maximumPosition = new double[] { xOpt, yOpt };
186             this.std = std;
187         }
188 
189         public double getMaximum() {
190             return value(maximumPosition);
191         }
192 
193         public double[] getMaximumPosition() {
194             return maximumPosition.clone();
195         }
196 
197         @Override
198         public double value(double[] point) {
199             final double x = point[0];
200             final double y = point[1];
201             final double twoS2 = 2.0 * std * std;
202             return 1.0 / (twoS2 * JdkMath.PI) * JdkMath.exp(-(x * x + y * y) / twoS2);
203         }
204     }
205 }