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.math.optimization.direct;
19  
20  import junit.framework.Test;
21  import junit.framework.TestCase;
22  import junit.framework.TestSuite;
23  
24  import org.apache.commons.math.ConvergenceException;
25  import org.apache.commons.math.FunctionEvaluationException;
26  import org.apache.commons.math.analysis.MultivariateRealFunction;
27  import org.apache.commons.math.optimization.GoalType;
28  import org.apache.commons.math.optimization.RealPointValuePair;
29  import org.apache.commons.math.optimization.SimpleScalarValueChecker;
30  
31  public class MultiDirectionalTest
32    extends TestCase {
33  
34    public MultiDirectionalTest(String name) {
35      super(name);
36    }
37  
38    public void testFunctionEvaluationExceptions() {
39        MultivariateRealFunction wrong =
40            new MultivariateRealFunction() {
41              private static final long serialVersionUID = 4751314470965489371L;
42              public double value(double[] x) throws FunctionEvaluationException {
43                  if (x[0] < 0) {
44                      throw new FunctionEvaluationException(x, "{0}", "oops");
45                  } else if (x[0] > 1) {
46                      throw new FunctionEvaluationException(new RuntimeException("oops"), x);
47                  } else {
48                      return x[0] * (1 - x[0]);
49                  }
50              }
51        };
52        try {
53            MultiDirectional optimizer = new MultiDirectional(0.9, 1.9);
54            optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { -1.0 });
55            fail("an exception should have been thrown");
56        } catch (FunctionEvaluationException ce) {
57            // expected behavior
58            assertNull(ce.getCause());
59        } catch (Exception e) {
60            fail("wrong exception caught: " + e.getMessage());
61        } 
62        try {
63            MultiDirectional optimizer = new MultiDirectional(0.9, 1.9);
64            optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { +2.0 });
65            fail("an exception should have been thrown");
66        } catch (FunctionEvaluationException ce) {
67            // expected behavior
68            assertNotNull(ce.getCause());
69        } catch (Exception e) {
70            fail("wrong exception caught: " + e.getMessage());
71        } 
72    }
73  
74    public void testMinimizeMaximize()
75        throws FunctionEvaluationException, ConvergenceException {
76  
77        // the following function has 4 local extrema:
78        final double xM        = -3.841947088256863675365;
79        final double yM        = -1.391745200270734924416;
80        final double xP        =  0.2286682237349059125691;
81        final double yP        = -yM;
82        final double valueXmYm =  0.2373295333134216789769; // local  maximum
83        final double valueXmYp = -valueXmYm;                // local  minimum
84        final double valueXpYm = -0.7290400707055187115322; // global minimum
85        final double valueXpYp = -valueXpYm;                // global maximum
86        MultivariateRealFunction fourExtrema = new MultivariateRealFunction() {
87            private static final long serialVersionUID = -7039124064449091152L;
88            public double value(double[] variables) throws FunctionEvaluationException {
89                final double x = variables[0];
90                final double y = variables[1];
91                return ((x == 0) || (y == 0)) ? 0 : (Math.atan(x) * Math.atan(x + 2) * Math.atan(y) * Math.atan(y) / (x * y));
92            }
93        };
94  
95        MultiDirectional optimizer = new MultiDirectional();
96        optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
97        optimizer.setMaxIterations(200);
98        optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
99        RealPointValuePair optimum;
100 
101       // minimization
102       optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { -3.0, 0 });
103       assertEquals(xM,        optimum.getPoint()[0], 4.0e-6);
104       assertEquals(yP,        optimum.getPoint()[1], 3.0e-6);
105       assertEquals(valueXmYp, optimum.getValue(),    8.0e-13);
106       assertTrue(optimizer.getEvaluations() > 120);
107       assertTrue(optimizer.getEvaluations() < 150);
108 
109       optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { +1, 0 });
110       assertEquals(xP,        optimum.getPoint()[0], 2.0e-8);
111       assertEquals(yM,        optimum.getPoint()[1], 3.0e-6);
112       assertEquals(valueXpYm, optimum.getValue(),    2.0e-12);              
113       assertTrue(optimizer.getEvaluations() > 120);
114       assertTrue(optimizer.getEvaluations() < 150);
115 
116       // maximization
117       optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { -3.0, 0.0 });
118       assertEquals(xM,        optimum.getPoint()[0], 7.0e-7);
119       assertEquals(yM,        optimum.getPoint()[1], 3.0e-7);
120       assertEquals(valueXmYm, optimum.getValue(),    2.0e-14);
121       assertTrue(optimizer.getEvaluations() > 120);
122       assertTrue(optimizer.getEvaluations() < 150);
123 
124       optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { +1, 0 });
125       assertEquals(xP,        optimum.getPoint()[0], 2.0e-8);
126       assertEquals(yP,        optimum.getPoint()[1], 3.0e-6);
127       assertEquals(valueXpYp, optimum.getValue(),    2.0e-12);
128       assertTrue(optimizer.getEvaluations() > 120);
129       assertTrue(optimizer.getEvaluations() < 150);
130 
131   }
132 
133   public void testRosenbrock()
134     throws FunctionEvaluationException, ConvergenceException {
135 
136     MultivariateRealFunction rosenbrock =
137       new MultivariateRealFunction() {
138         private static final long serialVersionUID = -9044950469615237490L;
139         public double value(double[] x) throws FunctionEvaluationException {
140           ++count;
141           double a = x[1] - x[0] * x[0];
142           double b = 1.0 - x[0];
143           return 100 * a * a + b * b;
144         }
145       };
146 
147     count = 0;
148     MultiDirectional optimizer = new MultiDirectional();
149     optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
150     optimizer.setMaxIterations(100);
151     optimizer.setStartConfiguration(new double[][] {
152             { -1.2,  1.0 }, { 0.9, 1.2 } , {  3.5, -2.3 }
153     });
154     RealPointValuePair optimum =
155         optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1.0 });
156 
157     assertEquals(count, optimizer.getEvaluations());
158     assertTrue(optimizer.getEvaluations() > 70);
159     assertTrue(optimizer.getEvaluations() < 100);
160     assertTrue(optimum.getValue() > 1.0e-2);
161 
162   }
163 
164   public void testPowell()
165     throws FunctionEvaluationException, ConvergenceException {
166 
167     MultivariateRealFunction powell =
168       new MultivariateRealFunction() {
169         private static final long serialVersionUID = -832162886102041840L;
170         public double value(double[] x) throws FunctionEvaluationException {
171           ++count;
172           double a = x[0] + 10 * x[1];
173           double b = x[2] - x[3];
174           double c = x[1] - 2 * x[2];
175           double d = x[0] - x[3];
176           return a * a + 5 * b * b + c * c * c * c + 10 * d * d * d * d;
177         }
178       };
179 
180     count = 0;
181     MultiDirectional optimizer = new MultiDirectional();
182     optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
183     optimizer.setMaxIterations(1000);
184     RealPointValuePair optimum =
185       optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
186     assertEquals(count, optimizer.getEvaluations());
187     assertTrue(optimizer.getEvaluations() > 800);
188     assertTrue(optimizer.getEvaluations() < 900);
189     assertTrue(optimum.getValue() > 1.0e-2);
190 
191   }
192 
193   public static Test suite() {
194     return new TestSuite(MultiDirectionalTest.class);
195   }
196 
197   private int count;
198 
199 }