001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.math.optimization.direct;
019    
020    import junit.framework.Test;
021    import junit.framework.TestCase;
022    import junit.framework.TestSuite;
023    
024    import org.apache.commons.math.ConvergenceException;
025    import org.apache.commons.math.FunctionEvaluationException;
026    import org.apache.commons.math.analysis.MultivariateRealFunction;
027    import org.apache.commons.math.optimization.GoalType;
028    import org.apache.commons.math.optimization.RealPointValuePair;
029    import org.apache.commons.math.optimization.SimpleScalarValueChecker;
030    
031    public class MultiDirectionalTest
032      extends TestCase {
033    
034      public MultiDirectionalTest(String name) {
035        super(name);
036      }
037    
038      public void testFunctionEvaluationExceptions() {
039          MultivariateRealFunction wrong =
040              new MultivariateRealFunction() {
041                private static final long serialVersionUID = 4751314470965489371L;
042                public double value(double[] x) throws FunctionEvaluationException {
043                    if (x[0] < 0) {
044                        throw new FunctionEvaluationException(x, "{0}", "oops");
045                    } else if (x[0] > 1) {
046                        throw new FunctionEvaluationException(new RuntimeException("oops"), x);
047                    } else {
048                        return x[0] * (1 - x[0]);
049                    }
050                }
051          };
052          try {
053              MultiDirectional optimizer = new MultiDirectional(0.9, 1.9);
054              optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { -1.0 });
055              fail("an exception should have been thrown");
056          } catch (FunctionEvaluationException ce) {
057              // expected behavior
058              assertNull(ce.getCause());
059          } catch (Exception e) {
060              fail("wrong exception caught: " + e.getMessage());
061          } 
062          try {
063              MultiDirectional optimizer = new MultiDirectional(0.9, 1.9);
064              optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { +2.0 });
065              fail("an exception should have been thrown");
066          } catch (FunctionEvaluationException ce) {
067              // expected behavior
068              assertNotNull(ce.getCause());
069          } catch (Exception e) {
070              fail("wrong exception caught: " + e.getMessage());
071          } 
072      }
073    
074      public void testMinimizeMaximize()
075          throws FunctionEvaluationException, ConvergenceException {
076    
077          // the following function has 4 local extrema:
078          final double xM        = -3.841947088256863675365;
079          final double yM        = -1.391745200270734924416;
080          final double xP        =  0.2286682237349059125691;
081          final double yP        = -yM;
082          final double valueXmYm =  0.2373295333134216789769; // local  maximum
083          final double valueXmYp = -valueXmYm;                // local  minimum
084          final double valueXpYm = -0.7290400707055187115322; // global minimum
085          final double valueXpYp = -valueXpYm;                // global maximum
086          MultivariateRealFunction fourExtrema = new MultivariateRealFunction() {
087              private static final long serialVersionUID = -7039124064449091152L;
088              public double value(double[] variables) throws FunctionEvaluationException {
089                  final double x = variables[0];
090                  final double y = variables[1];
091                  return ((x == 0) || (y == 0)) ? 0 : (Math.atan(x) * Math.atan(x + 2) * Math.atan(y) * Math.atan(y) / (x * y));
092              }
093          };
094    
095          MultiDirectional optimizer = new MultiDirectional();
096          optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
097          optimizer.setMaxIterations(200);
098          optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
099          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    }