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  package org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv;
18  
19  import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
20  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
21  import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
22  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
23  import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException;
24  import org.apache.commons.math4.legacy.optim.InitialGuess;
25  import org.apache.commons.math4.legacy.optim.MaxEval;
26  import org.apache.commons.math4.legacy.optim.PointValuePair;
27  import org.apache.commons.math4.legacy.optim.SimpleBounds;
28  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
29  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.ObjectiveFunction;
30  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.TestFunction;
31  import org.junit.Assert;
32  import org.junit.Ignore;
33  import org.junit.Test;
34  
35  /**
36   * Test for {@link BOBYQAOptimizer}.
37   */
38  public class BOBYQAOptimizerTest {
39      private static final int DIM = 13;
40  
41      @Test(expected=NumberIsTooLargeException.class)
42      public void testInitOutOfBounds() {
43          final int dim = 12;
44          double[] startPoint = OptimTestUtils.point(dim, 3);
45          double[][] boundaries = boundaries(dim, -1, 2);
46          doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
47                  GoalType.MINIMIZE,
48                  1e-13, 1e-6, 2000, null);
49      }
50  
51      @Test(expected=DimensionMismatchException.class)
52      public void testBoundariesDimensionMismatch() {
53          final int dim = 12;
54          double[] startPoint = OptimTestUtils.point(dim, 0.5);
55          double[][] boundaries = boundaries(dim + 1, -1, 2);
56          doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
57                 GoalType.MINIMIZE,
58                 1e-13, 1e-6, 2000, null);
59      }
60  
61      @Test(expected=NumberIsTooSmallException.class)
62      public void testProblemDimensionTooSmall() {
63          final int dim = 12;
64          double[] startPoint = OptimTestUtils.point(1, 0.5);
65          doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, null,
66                 GoalType.MINIMIZE,
67                 1e-13, 1e-6, 2000, null);
68      }
69  
70      @Test(expected=TooManyEvaluationsException.class)
71      public void testMaxEvaluations() {
72          final int dim = 12;
73          final int lowMaxEval = 2;
74          double[] startPoint = OptimTestUtils.point(dim, 0.1);
75          double[][] boundaries = null;
76          doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
77                 GoalType.MINIMIZE,
78                 1e-13, 1e-6, lowMaxEval, null);
79       }
80  
81      @Test
82      public void testRosen() {
83          final int dim = 12;
84          double[] startPoint = OptimTestUtils.point(dim, 0.1);
85          double[][] boundaries = null;
86          PointValuePair expected = new PointValuePair(OptimTestUtils.point(dim, 1.0), 0.0);
87          doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
88                  GoalType.MINIMIZE,
89                  1e-13, 1e-6, 3000, expected);
90       }
91  
92      @Test
93      public void testMaximize() {
94          double[] startPoint = OptimTestUtils.point(DIM,1.0);
95          double[][] boundaries = null;
96          PointValuePair expected = new PointValuePair(OptimTestUtils.point(DIM,0.0),1.0);
97          doTest(TestFunction.MINUS_ELLI.withDimension(DIM), startPoint, boundaries,
98                  GoalType.MAXIMIZE,
99                  2e-10, 5e-6, 1000, expected);
100         boundaries = boundaries(DIM,-0.3,0.3);
101         startPoint = OptimTestUtils.point(DIM,0.1);
102         doTest(TestFunction.MINUS_ELLI.withDimension(DIM), startPoint, boundaries,
103                 GoalType.MAXIMIZE,
104                 2e-10, 5e-6, 1000, expected);
105     }
106 
107     @Test
108     public void testEllipse() {
109         double[] startPoint = OptimTestUtils.point(DIM,1.0);
110         double[][] boundaries = null;
111         PointValuePair expected =
112             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
113         doTest(TestFunction.ELLI.withDimension(DIM), startPoint, boundaries,
114                 GoalType.MINIMIZE,
115                 1e-13, 1e-6, 1000, expected);
116      }
117 
118     @Test
119     public void testElliRotated() {
120         double[] startPoint = OptimTestUtils.point(DIM,1.0);
121         double[][] boundaries = null;
122         PointValuePair expected =
123             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
124         doTest(new OptimTestUtils.ElliRotated(), startPoint, boundaries,
125                 GoalType.MINIMIZE,
126                 1e-12, 1e-6, 10000, expected);
127     }
128 
129     @Test
130     public void testCigar() {
131         double[] startPoint = OptimTestUtils.point(DIM,1.0);
132         double[][] boundaries = null;
133         PointValuePair expected =
134             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
135         doTest(TestFunction.CIGAR.withDimension(DIM), startPoint, boundaries,
136                 GoalType.MINIMIZE,
137                 1e-13, 1e-6, 100, expected);
138     }
139 
140     @Test
141     public void testTwoAxes() {
142         double[] startPoint = OptimTestUtils.point(DIM,1.0);
143         double[][] boundaries = null;
144         PointValuePair expected =
145             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
146         doTest(TestFunction.TWO_AXES.withDimension(DIM), startPoint, boundaries,
147                 GoalType.MINIMIZE,
148                 2e-13, 1e-6, 100, expected);
149      }
150 
151     @Test
152     public void testCigTab() {
153         double[] startPoint = OptimTestUtils.point(DIM,1.0);
154         double[][] boundaries = null;
155         PointValuePair expected =
156             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
157         doTest(TestFunction.CIG_TAB.withDimension(DIM), startPoint, boundaries,
158                 GoalType.MINIMIZE,
159                 1e-13, 5e-5, 100, expected);
160      }
161 
162     @Test
163     public void testSphere() {
164         double[] startPoint = OptimTestUtils.point(DIM,1.0);
165         double[][] boundaries = null;
166         PointValuePair expected =
167             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
168         doTest(TestFunction.CIG_TAB.withDimension(DIM), startPoint, boundaries,
169                 GoalType.MINIMIZE,
170                 1e-13, 1e-6, 100, expected);
171     }
172 
173     @Test
174     public void testTablet() {
175         double[] startPoint = OptimTestUtils.point(DIM,1.0);
176         double[][] boundaries = null;
177         PointValuePair expected =
178             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
179         doTest(TestFunction.TABLET.withDimension(DIM), startPoint, boundaries,
180                 GoalType.MINIMIZE,
181                 1e-13, 1e-6, 100, expected);
182     }
183 
184     @Test
185     public void testSumPow() {
186         final int dim = DIM / 2;
187         double[] startPoint = OptimTestUtils.point(dim, 1.0);
188         double[][] boundaries = null;
189         PointValuePair expected =
190             new PointValuePair(OptimTestUtils.point(dim, 0.0), 0.0);
191         doTest(TestFunction.SUM_POW.withDimension(dim), startPoint, boundaries,
192                 GoalType.MINIMIZE,
193                 1e-8, 1e-1, 21720, expected);
194     }
195 
196     @Test
197     public void testAckley() {
198         double[] startPoint = OptimTestUtils.point(DIM,0.1);
199         double[][] boundaries = null;
200         PointValuePair expected =
201             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
202         doTest(TestFunction.ACKLEY.withDimension(DIM), startPoint, boundaries,
203                 GoalType.MINIMIZE,
204                 1e-7, 1e-5, 1000, expected);
205     }
206 
207     @Test
208     public void testRastrigin() {
209         double[] startPoint = OptimTestUtils.point(DIM,1.0);
210 
211         double[][] boundaries = null;
212         PointValuePair expected =
213             new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
214         doTest(TestFunction.RASTRIGIN.withDimension(DIM), startPoint, boundaries,
215                 GoalType.MINIMIZE,
216                 1e-13, 1e-6, 1000, expected);
217     }
218 
219     @Test
220     public void testConstrainedRosen() {
221         final int dim = 12;
222         double[] startPoint = OptimTestUtils.point(dim, 0.1);
223 
224         double[][] boundaries = boundaries(dim, -1, 2);
225         PointValuePair expected =
226             new PointValuePair(OptimTestUtils.point(dim, 1.0), 0.0);
227         doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
228                 GoalType.MINIMIZE,
229                 1e-13, 1e-6, 3000, expected);
230     }
231 
232     // See MATH-728
233     // TODO: this test is temporarily disabled for 3.2 release as a bug in Cobertura
234     //       makes it run for several hours before completing
235     @Ignore @Test
236     public void testConstrainedRosenWithMoreInterpolationPoints() {
237         final int dim = 12;
238         final double[] startPoint = OptimTestUtils.point(dim, 0.1);
239         final double[][] boundaries = boundaries(dim, -1, 2);
240         final PointValuePair expected = new PointValuePair(OptimTestUtils.point(dim, 1.0), 0.0);
241 
242         // This should have been 78 because in the code the hard limit is
243         // said to be
244         //   ((DIM + 1) * (DIM + 2)) / 2 - (2 * DIM + 1)
245         // i.e. 78 in this case, but the test fails for 48, 59, 62, 63, 64,
246         // 65, 66, ...
247         final int maxAdditionalPoints = 47;
248 
249         for (int num = 1; num <= maxAdditionalPoints; num++) {
250             doTest(TestFunction.ROSENBROCK.withDimension(dim), startPoint, boundaries,
251                    GoalType.MINIMIZE,
252                    1e-12, 1e-6, 2000,
253                    num,
254                    expected,
255                    "num=" + num);
256         }
257     }
258 
259     /**
260      * @param func Function to optimize.
261      * @param startPoint Starting point.
262      * @param boundaries Upper / lower point limit.
263      * @param goal Minimization or maximization.
264      * @param fTol Tolerance relative error on the objective function.
265      * @param pointTol Tolerance for checking that the optimum is correct.
266      * @param maxEvaluations Maximum number of evaluations.
267      * @param expected Expected point / value.
268      */
269     private void doTest(MultivariateFunction func,
270                         double[] startPoint,
271                         double[][] boundaries,
272                         GoalType goal,
273                         double fTol,
274                         double pointTol,
275                         int maxEvaluations,
276                         PointValuePair expected) {
277         doTest(func,
278                startPoint,
279                boundaries,
280                goal,
281                fTol,
282                pointTol,
283                maxEvaluations,
284                0,
285                expected,
286                "");
287     }
288 
289     /**
290      * @param func Function to optimize.
291      * @param startPoint Starting point.
292      * @param boundaries Upper / lower point limit.
293      * @param goal Minimization or maximization.
294      * @param fTol Tolerance relative error on the objective function.
295      * @param pointTol Tolerance for checking that the optimum is correct.
296      * @param maxEvaluations Maximum number of evaluations.
297      * @param additionalInterpolationPoints Number of interpolation to used
298      * in addition to the default (2 * dim + 1).
299      * @param expected Expected point / value.
300      */
301     private void doTest(MultivariateFunction func,
302                         double[] startPoint,
303                         double[][] boundaries,
304                         GoalType goal,
305                         double fTol,
306                         double pointTol,
307                         int maxEvaluations,
308                         int additionalInterpolationPoints,
309                         PointValuePair expected,
310                         String assertMsg) {
311 
312 //         System.out.println(func.getClass().getName() + " BEGIN"); // XXX
313 
314         int dim = startPoint.length;
315         final int numIterpolationPoints = 2 * dim + 1 + additionalInterpolationPoints;
316         BOBYQAOptimizer optim = new BOBYQAOptimizer(numIterpolationPoints);
317         PointValuePair result = boundaries == null ?
318             optim.optimize(new MaxEval(maxEvaluations),
319                            new ObjectiveFunction(func),
320                            goal,
321                            SimpleBounds.unbounded(dim),
322                            new InitialGuess(startPoint)) :
323             optim.optimize(new MaxEval(maxEvaluations),
324                            new ObjectiveFunction(func),
325                            goal,
326                            new InitialGuess(startPoint),
327                            new SimpleBounds(boundaries[0],
328                                             boundaries[1]));
329 //        System.out.println(func.getClass().getName() + " = "
330 //              + optim.getEvaluations() + " f(");
331 //        for (double x: result.getPoint())  System.out.print(x + " ");
332 //        System.out.println(") = " +  result.getValue());
333         Assert.assertEquals(assertMsg, expected.getValue(), result.getValue(), fTol);
334         for (int i = 0; i < dim; i++) {
335             Assert.assertEquals(expected.getPoint()[i],
336                                 result.getPoint()[i], pointTol);
337         }
338 
339 //         System.out.println(func.getClass().getName() + " END"); // XXX
340     }
341 
342     private static double[][] boundaries(int dim,
343             double lower, double upper) {
344         double[][] boundaries = new double[2][dim];
345         for (int i = 0; i < dim; i++) {
346             boundaries[0][i] = lower;
347         }
348         for (int i = 0; i < dim; i++) {
349             boundaries[1][i] = upper;
350         }
351         return boundaries;
352     }
353 }