You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2009/05/27 20:54:49 UTC

svn commit: r779273 - in /commons/proper/math/trunk/src: java/org/apache/commons/math/ java/org/apache/commons/math/optimization/ java/org/apache/commons/math/optimization/direct/ site/xdoc/ test/org/apache/commons/math/optimization/direct/

Author: luc
Date: Wed May 27 18:54:48 2009
New Revision: 779273

URL: http://svn.apache.org/viewvc?rev=779273&view=rev
Log:
Added a way to limit the number of functions evaluations in optimizers
(the number of iterations could already be limited)

Added:
    commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java   (with props)
Modified:
    commons/proper/math/trunk/src/java/org/apache/commons/math/MessagesResources_fr.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultiStartMultivariateRealOptimizer.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultivariateRealOptimizer.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/DirectSearchOptimizer.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/MultiDirectional.java
    commons/proper/math/trunk/src/site/xdoc/changes.xml
    commons/proper/math/trunk/src/test/org/apache/commons/math/optimization/direct/NelderMeadTest.java

Added: commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java?rev=779273&view=auto
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java (added)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java Wed May 27 18:54:48 2009
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math;
+
+import org.apache.commons.math.ConvergenceException;
+
+/**
+ * Error thrown when a numerical computation exceeds its allowed
+ * number of functions evaluations.
+ *
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class MaxEvaluationsExceededException extends ConvergenceException {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = -5921271447220129118L;
+
+    /** Maximal number of evaluations allowed. */
+    private final int maxEvaluations;
+
+    /**
+     * Constructs an exception with specified formatted detail message.
+     * Message formatting is delegated to {@link java.text.MessageFormat}.
+     * @param maxEvaluations maximal number of evaluations allowed
+     */
+    public MaxEvaluationsExceededException(final int maxEvaluations) {
+        super("Maximal number of evaluations ({0}) exceeded", maxEvaluations);
+        this.maxEvaluations = maxEvaluations;
+    }
+
+    /**
+     * Constructs an exception with specified formatted detail message.
+     * Message formatting is delegated to {@link java.text.MessageFormat}.
+     * @param maxEvaluations the exceeded maximal number of evaluations
+     * @param pattern format specifier
+     * @param arguments format arguments
+     */
+    public MaxEvaluationsExceededException(final int maxEvaluations,
+                                          final String pattern, final Object ... arguments) {
+        super(pattern, arguments);
+        this.maxEvaluations = maxEvaluations;
+    }
+
+    /** Get the maximal number of evaluations allowed.
+     * @return maximal number of evaluations allowed
+     */
+    public int getMaxEvaluations() {
+        return maxEvaluations;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/java/org/apache/commons/math/MaxEvaluationsExceededException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/MessagesResources_fr.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/MessagesResources_fr.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/MessagesResources_fr.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/MessagesResources_fr.java Wed May 27 18:54:48 2009
@@ -83,6 +83,10 @@
     { "Maximal number of iterations ({0}) exceeded",
       "Nombre maximal d''it\u00e9rations ({0}) d\u00e9pass\u00e9" },
 
+    // org.apache.commons.math.MaxEvaluationsExceededException
+    { "Maximal number of evaluations ({0}) exceeded",
+      "Nombre maximal d''\u00e9valuations ({0}) d\u00e9pass\u00e9" },
+
     // org.apache.commons.math.analysis.interpolation.SplineInterpolator
     // org.apache.commons.math.analysis.polynomials.PolynomialFunctionLagrangeForm
     // org.apache.commons.math.DimensionMismatchException

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultiStartMultivariateRealOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultiStartMultivariateRealOptimizer.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultiStartMultivariateRealOptimizer.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultiStartMultivariateRealOptimizer.java Wed May 27 18:54:48 2009
@@ -51,6 +51,9 @@
     /** Maximal number of iterations allowed. */
     private int maxIterations;
 
+    /** Maximal number of evaluations allowed. */
+    private int maxEvaluations;
+
     /** Number of iterations already performed for all starts. */
     private int totalIterations;
 
@@ -130,6 +133,16 @@
     }
 
     /** {@inheritDoc} */
+    public void setMaxEvaluations(int maxEvaluations) {
+        this.maxEvaluations = maxEvaluations;
+    }
+
+    /** {@inheritDoc} */
+    public int getMaxEvaluations() {
+        return maxEvaluations;
+    }
+
+    /** {@inheritDoc} */
     public int getIterations() {
         return totalIterations;
     }
@@ -164,6 +177,7 @@
 
             try {
                 optimizer.setMaxIterations(maxIterations - totalIterations);
+                optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
                 optima[i] = optimizer.optimize(f, goalType,
                                                (i == 0) ? startPoint : generator.nextVector());
             } catch (FunctionEvaluationException fee) {

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultivariateRealOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultivariateRealOptimizer.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultivariateRealOptimizer.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/MultivariateRealOptimizer.java Wed May 27 18:54:48 2009
@@ -33,10 +33,15 @@
 public interface MultivariateRealOptimizer {
 
     /** Set the maximal number of iterations of the algorithm.
-     * @param maxIterations maximal number of function calls
+     * @param maxIterations maximal number of algorithm iterations
      */
     void setMaxIterations(int maxIterations);
 
+    /** Set the maximal number of evaluations of the algorithm.
+     * @param maxEvaluations maximal number of function calls
+     */
+    void setMaxEvaluations(int maxEvaluations);
+
     /** Get the maximal number of iterations of the algorithm.
      * @return maximal number of iterations
      */

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/DirectSearchOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/DirectSearchOptimizer.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/DirectSearchOptimizer.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/DirectSearchOptimizer.java Wed May 27 18:54:48 2009
@@ -23,6 +23,7 @@
 
 import org.apache.commons.math.FunctionEvaluationException;
 import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxEvaluationsExceededException;
 import org.apache.commons.math.MaxIterationsExceededException;
 import org.apache.commons.math.analysis.MultivariateRealFunction;
 import org.apache.commons.math.optimization.GoalType;
@@ -104,6 +105,9 @@
     /** Maximal number of iterations allowed. */
     private int maxIterations;
 
+    /** Maximal number of evaluations allowed. */
+    private int maxEvaluations;
+
     /** Number of iterations already performed. */
     private int iterations;
 
@@ -118,6 +122,7 @@
     protected DirectSearchOptimizer() {
         setConvergenceChecker(new SimpleScalarValueChecker());
         setMaxIterations(Integer.MAX_VALUE);
+        setMaxEvaluations(Integer.MAX_VALUE);
     }
 
     /** Set start configuration for simplex.
@@ -222,6 +227,11 @@
     }
 
     /** {@inheritDoc} */
+    public void setMaxEvaluations(int maxEvaluations) {
+        this.maxEvaluations = maxEvaluations;
+    }
+
+    /** {@inheritDoc} */
     public int getMaxIterations() {
         return maxIterations;
     }
@@ -329,10 +339,13 @@
      * @return objective function value at the given point
      * @exception FunctionEvaluationException if no value can be computed for the parameters
      * @exception IllegalArgumentException if the start point dimension is wrong
+     * @exception OptimizationException if the maximal number of evaluations is exceeded
      */
     protected double evaluate(final double[] x)
-        throws FunctionEvaluationException, IllegalArgumentException {
-        evaluations++;
+        throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
+        if (++evaluations > maxEvaluations) {
+            throw new OptimizationException(new MaxEvaluationsExceededException(maxEvaluations));
+        }
         return f.value(x);
     }
 
@@ -370,9 +383,10 @@
     /** Evaluate all the non-evaluated points of the simplex.
      * @param comparator comparator to use to sort simplex vertices from best to worst
      * @exception FunctionEvaluationException if no value can be computed for the parameters
+     * @exception OptimizationException if the maximal number of evaluations is exceeded
      */
     protected void evaluateSimplex(final Comparator<RealPointValuePair> comparator)
-        throws FunctionEvaluationException {
+        throws FunctionEvaluationException, OptimizationException {
 
         // evaluate the objective function at all non-evaluated simplex points
         for (int i = 0; i < simplex.length; ++i) {

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/MultiDirectional.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/MultiDirectional.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/MultiDirectional.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/optimization/direct/MultiDirectional.java Wed May 27 18:54:48 2009
@@ -110,11 +110,12 @@
      * @return best point in the transformed simplex
      * @exception FunctionEvaluationException if the function cannot be evaluated at
      * some point
+     * @exception OptimizationException if the maximal number of evaluations is exceeded
      */
     private RealPointValuePair evaluateNewSimplex(final RealPointValuePair[] original,
                                               final double coeff,
                                               final Comparator<RealPointValuePair> comparator)
-        throws FunctionEvaluationException {
+        throws FunctionEvaluationException, OptimizationException {
 
         final double[] xSmallest = original[0].getPointRef();
         final int n = xSmallest.length;

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Wed May 27 18:54:48 2009
@@ -39,10 +39,14 @@
   </properties>
   <body>
     <release version="2.0" date="TBD" description="TBD">
-      <action dev="psteitz" type="add" issue="MATH-267" due=to="Ted Dunning">
+      <action dev="luc" type="add" due-to="Gilles Sadowski">
+        Added a way to limit the number of functions evaluations in optimizers
+        (the number of iterations could already be limited)
+      </action>
+       <action dev="psteitz" type="add" issue="MATH-267" due-to="Ted Dunning">
         Added digamma function.
       </action>
-      <action dev="psteitz" type="add" issue="MATH-136" due=to="John Gant">
+      <action dev="psteitz" type="add" issue="MATH-136" due-to="John Gant">
         Added Spearman's rank correlation (SpearmansCorrelation).
       </action>
       <action dev="psteitz" type="add">

Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/optimization/direct/NelderMeadTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/optimization/direct/NelderMeadTest.java?rev=779273&r1=779272&r2=779273&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/org/apache/commons/math/optimization/direct/NelderMeadTest.java (original)
+++ commons/proper/math/trunk/src/test/org/apache/commons/math/optimization/direct/NelderMeadTest.java Wed May 27 18:54:48 2009
@@ -17,24 +17,27 @@
 
 package org.apache.commons.math.optimization.direct;
 
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import org.apache.commons.math.ConvergenceException;
 import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.MaxEvaluationsExceededException;
+import org.apache.commons.math.MaxIterationsExceededException;
 import org.apache.commons.math.analysis.MultivariateRealFunction;
 import org.apache.commons.math.optimization.GoalType;
+import org.apache.commons.math.optimization.OptimizationException;
 import org.apache.commons.math.optimization.RealPointValuePair;
 import org.apache.commons.math.optimization.SimpleScalarValueChecker;
+import org.junit.Test;
 
-public class NelderMeadTest
-  extends TestCase {
-
-  public NelderMeadTest(String name) {
-    super(name);
-  }
+public class NelderMeadTest {
 
+  @Test
   public void testFunctionEvaluationExceptions() {
       MultivariateRealFunction wrong =
           new MultivariateRealFunction() {
@@ -71,6 +74,7 @@
       } 
   }
 
+  @Test
   public void testMinimizeMaximize()
       throws FunctionEvaluationException, ConvergenceException {
 
@@ -130,21 +134,11 @@
 
   }
 
+  @Test
   public void testRosenbrock()
     throws FunctionEvaluationException, ConvergenceException {
 
-    MultivariateRealFunction rosenbrock =
-      new MultivariateRealFunction() {
-        private static final long serialVersionUID = -9044950469615237490L;
-        public double value(double[] x) throws FunctionEvaluationException {
-          ++count;
-          double a = x[1] - x[0] * x[0];
-          double b = 1.0 - x[0];
-          return 100 * a * a + b * b;
-        }
-      };
-
-    count = 0;
+    Rosenbrock rosenbrock = new Rosenbrock();
     NelderMead optimizer = new NelderMead();
     optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
     optimizer.setMaxIterations(100);
@@ -154,46 +148,104 @@
     RealPointValuePair optimum =
         optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1.0 });
 
-    assertEquals(count, optimizer.getEvaluations());
+    assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
     assertTrue(optimizer.getEvaluations() > 40);
     assertTrue(optimizer.getEvaluations() < 50);
     assertTrue(optimum.getValue() < 8.0e-4);
 
   }
 
+  @Test
   public void testPowell()
     throws FunctionEvaluationException, ConvergenceException {
 
-    MultivariateRealFunction powell =
-      new MultivariateRealFunction() {
-        private static final long serialVersionUID = -832162886102041840L;
-        public double value(double[] x) throws FunctionEvaluationException {
-          ++count;
-          double a = x[0] + 10 * x[1];
-          double b = x[2] - x[3];
-          double c = x[1] - 2 * x[2];
-          double d = x[0] - x[3];
-          return a * a + 5 * b * b + c * c * c * c + 10 * d * d * d * d;
-        }
-      };
-
-    count = 0;
+    Powell powell = new Powell();
     NelderMead optimizer = new NelderMead();
     optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
     optimizer.setMaxIterations(200);
     RealPointValuePair optimum =
       optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
-    assertEquals(count, optimizer.getEvaluations());
+    assertEquals(powell.getCount(), optimizer.getEvaluations());
     assertTrue(optimizer.getEvaluations() > 110);
     assertTrue(optimizer.getEvaluations() < 130);
     assertTrue(optimum.getValue() < 2.0e-3);
 
   }
 
-  public static Test suite() {
-    return new TestSuite(NelderMeadTest.class);
+  @Test(expected = MaxIterationsExceededException.class)
+  public void testMaxIterations() throws MathException {
+      try {
+          Powell powell = new Powell();
+          NelderMead optimizer = new NelderMead();
+          optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
+          optimizer.setMaxIterations(20);
+          optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
+      } catch (OptimizationException oe) {
+          if (oe.getCause() instanceof ConvergenceException) {
+              throw (ConvergenceException) oe.getCause();
+          }
+          throw oe;
+      }
   }
 
-  private int count;
+  @Test(expected = MaxEvaluationsExceededException.class)
+  public void testMaxEvaluations() throws MathException {
+      try {
+          Powell powell = new Powell();
+          NelderMead optimizer = new NelderMead();
+          optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
+          optimizer.setMaxEvaluations(20);
+          optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
+      } catch (OptimizationException oe) {
+          if (oe.getCause() instanceof ConvergenceException) {
+              throw (ConvergenceException) oe.getCause();
+          }
+          throw oe;
+      }
+  }
+
+  private class Rosenbrock implements MultivariateRealFunction {
+
+      private int count;
+
+      public Rosenbrock() {
+          count = 0;
+      }
+
+      public double value(double[] x) throws FunctionEvaluationException {
+          ++count;
+          double a = x[1] - x[0] * x[0];
+          double b = 1.0 - x[0];
+          return 100 * a * a + b * b;
+      }
+
+      public int getCount() {
+          return count;
+      }
+
+  }
+
+  private class Powell implements MultivariateRealFunction {
+
+      private int count;
+
+      public Powell() {
+          count = 0;
+      }
+
+      public double value(double[] x) throws FunctionEvaluationException {
+          ++count;
+          double a = x[0] + 10 * x[1];
+          double b = x[2] - x[3];
+          double c = x[1] - 2 * x[2];
+          double d = x[0] - x[3];
+          return a * a + 5 * b * b + c * c * c * c + 10 * d * d * d * d;
+      }
+
+      public int getCount() {
+          return count;
+      }
+
+  }
 
 }