Author: erans
Date: Wed Jul 28 12:03:41 2010
New Revision: 980032
URL: http://svn.apache.org/viewvc?rev=980032&view=rev
Log:
MATH-395: Another bug uncovered; all things being equal, the code now behaves
like the Puthon implementation.
MATH-397: Modified "BrentOptimizer" following the changes in
"AbstractUnivariateRealOptimizer".
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/ConvergingAlgorithmImpl.java
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/AbstractUnivariateRealOptimizer.java
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/BrentOptimizer.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/MultiStartUnivariateRealOptimizerTest.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/univariate/BrentOptimizerTest.java
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/ConvergingAlgorithmImpl.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ConvergingAlgorithmImpl.java?rev=980032&r1=980031&r2=980032&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/ConvergingAlgorithmImpl.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/ConvergingAlgorithmImpl.java
Wed Jul 28 12:03:41 2010
@@ -139,14 +139,14 @@ public abstract class ConvergingAlgorith
/**
* Increment the iterations counter by 1.
*
- * @throws OptimizationException if the maximal number
+ * @throws MaxIterationsExceededException if the maximal number
* of iterations is exceeded.
* @since 2.2
*/
protected void incrementIterationsCounter()
- throws ConvergenceException {
+ throws MaxIterationsExceededException {
if (++iterationCount > maximalIterationCount) {
- throw new ConvergenceException(new
MaxIterationsExceededException(maximalIterationCount));
+ throw new MaxIterationsExceededException(maximalIterationCount);
}
}
}
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/AbstractUnivariateRealOptimizer.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/AbstractUnivariateRealOptimizer.java?rev=980032&r1=980031&r2=980032&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/AbstractUnivariateRealOptimizer.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/AbstractUnivariateRealOptimizer.java
Wed Jul 28 12:03:41 2010
@@ -260,5 +260,6 @@ public abstract class AbstractUnivariate
*
* @return the optimum.
*/
- protected abstract double doOptimize();
+ protected abstract double doOptimize()
+ throws MaxIterationsExceededException, FunctionEvaluationException;
}
Modified:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/BrentOptimizer.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/BrentOptimizer.java?rev=980032&r1=980031&r2=980032&view=diff
==============================================================================
---
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/BrentOptimizer.java
(original)
+++
commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/univariate/BrentOptimizer.java
Wed Jul 28 12:03:41 2010
@@ -41,39 +41,37 @@ public class BrentOptimizer extends Abst
* Construct a solver.
*/
public BrentOptimizer() {
- super(100, 1E-10);
+ setMaxEvaluations(1000);
+ setMaximalIterationCount(100);
+ setAbsoluteAccuracy(1e-11);
+ setRelativeAccuracy(1e-9);
}
- /** {...@inheritdoc} */
- public double optimize(final UnivariateRealFunction f, final GoalType
goalType,
- final double min, final double max, final double
startValue)
+ /**
+ * Perform the optimization.
+ *
+ * @return the optimum.
+ */
+ protected double doOptimize()
throws MaxIterationsExceededException, FunctionEvaluationException {
- clearResult();
- return localMin(f, goalType, min, startValue, max,
+ return localMin(getGoalType() == GoalType.MINIMIZE,
+ getMin(), getStartValue(), getMax(),
getRelativeAccuracy(), getAbsoluteAccuracy());
}
- /** {...@inheritdoc} */
- public double optimize(final UnivariateRealFunction f, final GoalType
goalType,
- final double min, final double max)
- throws MaxIterationsExceededException, FunctionEvaluationException {
- return optimize(f, goalType, min, max, min + GOLDEN_SECTION * (max -
min));
- }
-
/**
- * Find the minimum of the function {...@code f} within the interval
{...@code (a, b)}.
+ * Find the minimum of the function within the interval {...@code (lo,
hi)}.
*
- * If the function {...@code f} is defined on the interval {...@code (a,
b)}, then
- * this method finds an approximation {...@code x} to the point at which
{...@code f}
- * attains its minimum.<br/>
- * {...@code t} and {...@code eps} define a tolerance {...@code tol = eps
|x| + t} and
- * {...@code f} is never evaluated at two points closer together than
{...@code tol}.
- * {...@code eps} should be no smaller than <em>2 macheps</em> and
preferable not
- * much less than <em>sqrt(macheps)</em>, where <em>macheps</em> is the
relative
- * machine precision. {...@code t} should be positive.
- * @param f the function to solve.
- * @param goalType type of optimization goal: either {...@link
GoalType#MAXIMIZE}
- * or {...@link GoalType#MINIMIZE}.
+ * If the function is defined on the interval {...@code (lo, hi)}, then
+ * this method finds an approximation {...@code x} to the point at which
+ * the function attains its minimum.<br/>
+ * {...@code t} and {...@code eps} define a tolerance {...@code tol = eps
|x| + t}
+ * and the function is never evaluated at two points closer together than
+ * {...@code tol}. {...@code eps} should be no smaller than <em>2
macheps</em> and
+ * preferable not much less than <em>sqrt(macheps)</em>, where
+ * <em>macheps</em> is the relative machine precision. {...@code t} should
be
+ * positive.
+ * @param isMinim {...@code true} when minimizing the function.
* @param lo Lower bound of the interval.
* @param mid Point inside the interval {...@code [lo, hi]}.
* @param hi Higher bound of the interval.
@@ -85,8 +83,7 @@ public class BrentOptimizer extends Abst
* @throws FunctionEvaluationException if an error occurs evaluating
* the function.
*/
- private double localMin(UnivariateRealFunction f,
- GoalType goalType,
+ private double localMin(boolean isMinim,
double lo, double mid, double hi,
double eps, double t)
throws MaxIterationsExceededException, FunctionEvaluationException {
@@ -108,16 +105,16 @@ public class BrentOptimizer extends Abst
double x = mid;
double v = x;
double w = x;
+ double d = 0;
double e = 0;
- double fx = computeObjectiveValue(f, x);
- if (goalType == GoalType.MAXIMIZE) {
+ double fx = computeObjectiveValue(x);
+ if (!isMinim) {
fx = -fx;
}
double fv = fx;
double fw = fx;
- int count = 0;
- while (count < maximalIterationCount) {
+ while (true) {
double m = 0.5 * (a + b);
final double tol1 = eps * Math.abs(x) + t;
final double tol2 = 2 * tol1;
@@ -127,7 +124,6 @@ public class BrentOptimizer extends Abst
double p = 0;
double q = 0;
double r = 0;
- double d = 0;
double u = 0;
if (Math.abs(e) > tol1) { // Fit parabola.
@@ -191,8 +187,8 @@ public class BrentOptimizer extends Abst
u = x + d;
}
- double fu = computeObjectiveValue(f, u);
- if (goalType == GoalType.MAXIMIZE) {
+ double fu = computeObjectiveValue(u);
+ if (!isMinim) {
fu = -fu;
}
@@ -229,16 +225,10 @@ public class BrentOptimizer extends Abst
}
}
} else { // termination
- setResult(x, (goalType == GoalType.MAXIMIZE) ? -fx : fx,
count);
+ setFunctionValue(isMinim ? fx : -fx);
return x;
}
- ++count;
+ incrementIterationsCounter();
}
- throw new MaxIterationsExceededException(maximalIterationCount);
- }
-
- /** Temporary workaround. */
- protected double doOptimize() {
- throw new UnsupportedOperationException();
}
}
Modified:
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/MultiStartUnivariateRealOptimizerTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/MultiStartUnivariateRealOptimizerTest.java?rev=980032&r1=980031&r2=980032&view=diff
==============================================================================
---
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/MultiStartUnivariateRealOptimizerTest.java
(original)
+++
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/MultiStartUnivariateRealOptimizerTest.java
Wed Jul 28 12:03:41 2010
@@ -48,8 +48,8 @@ public class MultiStartUnivariateRealOpt
assertEquals(-1.0, f.value(optima[i]), 1.0e-10);
assertEquals(f.value(optima[i]), optimaValues[i], 1.0e-10);
}
- assertTrue(minimizer.getEvaluations() > 1500);
- assertTrue(minimizer.getEvaluations() < 1700);
+ assertTrue(minimizer.getEvaluations() > 150);
+ assertTrue(minimizer.getEvaluations() < 250);
}
@Test
@@ -84,8 +84,8 @@ public class MultiStartUnivariateRealOpt
}
double result = minimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2);
- assertEquals(-0.27195612525275803, result, 1.0e-13);
- assertEquals(-0.27195612525275803, minimizer.getResult(), 1.0e-13);
+ assertEquals(-0.2719561270319131, result, 1.0e-13);
+ assertEquals(-0.2719561270319131, minimizer.getResult(), 1.0e-13);
assertEquals(-0.04433426954946637, minimizer.getFunctionValue(),
1.0e-13);
double[] optima = minimizer.getOptima();
@@ -93,10 +93,9 @@ public class MultiStartUnivariateRealOpt
for (int i = 0; i < optima.length; ++i) {
assertEquals(f.value(optima[i]), optimaValues[i], 1.0e-10);
}
-
- assertTrue(minimizer.getEvaluations() >= 300);
- assertTrue(minimizer.getEvaluations() <= 420);
- assertTrue(minimizer.getIterationCount() >= 100);
- assertTrue(minimizer.getIterationCount() <= 140);
+ assertTrue(minimizer.getEvaluations() >= 120);
+ assertTrue(minimizer.getEvaluations() <= 170);
+ assertTrue(minimizer.getIterationCount() >= 120);
+ assertTrue(minimizer.getIterationCount() <= 170);
}
}
Modified:
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/univariate/BrentOptimizerTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/univariate/BrentOptimizerTest.java?rev=980032&r1=980031&r2=980032&view=diff
==============================================================================
---
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/univariate/BrentOptimizerTest.java
(original)
+++
commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/univariate/BrentOptimizerTest.java
Wed Jul 28 12:03:41 2010
@@ -29,6 +29,7 @@ import org.apache.commons.math.analysis.
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.UnivariateRealOptimizer;
+import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.junit.Test;
/**
@@ -50,13 +51,13 @@ public final class BrentOptimizerTest {
} catch (Exception e) {
fail("wrong exception caught");
}
- assertEquals(3 * Math.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE,
4, 5), 70 * minimizer.getAbsoluteAccuracy());
+ assertEquals(3 * Math.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE,
4, 5), 10 * minimizer.getRelativeAccuracy());
assertTrue(minimizer.getIterationCount() <= 50);
- assertEquals(3 * Math.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE,
1, 5), 70 * minimizer.getAbsoluteAccuracy());
+ assertEquals(3 * Math.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE,
1, 5), 10 * minimizer.getRelativeAccuracy());
assertTrue(minimizer.getIterationCount() <= 50);
assertTrue(minimizer.getEvaluations() <= 100);
- assertTrue(minimizer.getEvaluations() >= 30);
- minimizer.setMaxEvaluations(50);
+ assertTrue(minimizer.getEvaluations() >= 15);
+ minimizer.setMaxEvaluations(10);
try {
minimizer.optimize(f, GoalType.MINIMIZE, 4, 5);
fail("an exception should have been thrown");
@@ -82,35 +83,35 @@ public final class BrentOptimizerTest {
}
@Test
- public void testQuinticMinPythonComparison() throws MathException {
+ public void testQuinticMinStatistics() throws MathException {
// The function has local minima at -0.27195613 and 0.82221643.
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
- minimizer.setRelativeAccuracy(1e-12);
+ minimizer.setRelativeAccuracy(1e-10);
minimizer.setAbsoluteAccuracy(1e-11);
- double result;
- int nIter, nEval;
+ final DescriptiveStatistics[] stat = new DescriptiveStatistics[3];
+ for (int i = 0; i < stat.length; i++) {
+ stat[i] = new DescriptiveStatistics();
+ }
+
+ final double min = -0.75;
+ final double max = 0.25;
+ final int nSamples = 200;
+ final double delta = (max - min) / nSamples;
+ for (int i = 0; i < nSamples; i++) {
+ final double start = min + i * delta;
+ stat[0].addValue(minimizer.optimize(f, GoalType.MINIMIZE, min,
max, start));
+ stat[1].addValue(minimizer.getIterationCount());
+ stat[2].addValue(minimizer.getEvaluations());
+ }
- result = minimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2, -0.25);
- nIter = minimizer.getIterationCount();
- nEval = minimizer.getEvaluations();
- // XXX Python: -0.27195612805911351 (instead of -0.2719561279558559).
- assertEquals(-0.2719561279558559, result, 1e-12);
- // XXX Python: 15 (instead of 18).
- assertEquals(18, nEval);
- // XXX Python: 11 (instead of 17).
- assertEquals(17, nIter);
-
- result = minimizer.optimize(f, GoalType.MINIMIZE, 0.7, 0.9, 0.8);
- nIter = minimizer.getIterationCount();
- nEval = minimizer.getEvaluations();
- // XXX Python: 0.82221643488363705 (instead of 0.8222164326561908).
- assertEquals(0.8222164326561908, result, 1e-12);
- // XXX Python: 25 (instead of 43).
- assertEquals(43, nEval);
- // XXX Python: 21 (instead of 24).
- assertEquals(24, nIter);
+ final double meanOptValue = stat[0].getMean();
+ final double medianIter = stat[1].getPercentile(50);
+ final double medianEval = stat[2].getPercentile(50);
+ assertTrue(meanOptValue > -0.27195612812 && meanOptValue <
-0.27195612811);
+ assertEquals(medianIter, 17, Math.ulp(1d));
+ assertEquals(medianEval, 18, Math.ulp(1d));
}
@Test
@@ -120,7 +121,7 @@ public final class BrentOptimizerTest {
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
assertEquals(0.27195613, minimizer.optimize(f, GoalType.MAXIMIZE, 0.2,
0.3), 1.0e-8);
- minimizer.setMaximalIterationCount(20);
+ minimizer.setMaximalIterationCount(5);
try {
minimizer.optimize(f, GoalType.MAXIMIZE, 0.2, 0.3);
fail("an exception should have been thrown");
@@ -136,11 +137,13 @@ public final class BrentOptimizerTest {
UnivariateRealFunction f = new SinFunction();
UnivariateRealOptimizer solver = new BrentOptimizer();
+ solver.setRelativeAccuracy(1e-8);
+
// endpoint is minimum
double result = solver.optimize(f, GoalType.MINIMIZE, 3 * Math.PI / 2,
5);
- assertEquals(3 * Math.PI / 2, result, 70 *
solver.getAbsoluteAccuracy());
+ assertEquals(3 * Math.PI / 2, result, 10 *
solver.getRelativeAccuracy());
result = solver.optimize(f, GoalType.MINIMIZE, 4, 3 * Math.PI / 2);
- assertEquals(3 * Math.PI / 2, result, 80 *
solver.getAbsoluteAccuracy());
+ assertEquals(3 * Math.PI / 2, result, 10 *
solver.getRelativeAccuracy());
}
}