diff --git a/src/main/java/org/apache/commons/math/optimization/direct/SimplexOptimizer.java b/src/main/java/org/apache/commons/math/optimization/direct/SimplexOptimizer.java index bff63ef8c..ef87f0656 100644 --- a/src/main/java/org/apache/commons/math/optimization/direct/SimplexOptimizer.java +++ b/src/main/java/org/apache/commons/math/optimization/direct/SimplexOptimizer.java @@ -63,10 +63,6 @@ import org.apache.commons.math.optimization.MultivariateRealOptimizer; * re-initialized to one with the appropriate dimensions. *

*

- * If {@link #setConvergenceChecker(ConvergenceChecker)} is not called, - * a default {@link SimpleScalarValueChecker} is used. - *

- *

* Convergence is checked by providing the worst points of * previous and current simplex to the convergence checker, not the best * ones. @@ -83,10 +79,18 @@ public class SimplexOptimizer private AbstractSimplex simplex; /** - * Default constructor. + * Constructor using a default {@link SimpleScalarValueChecker convergence + * checker}. */ public SimplexOptimizer() { - setConvergenceChecker(new SimpleScalarValueChecker()); + this(new SimpleScalarValueChecker()); + } + + /** + * @param checker Convergence checker. + */ + public SimplexOptimizer(ConvergenceChecker checker) { + super(checker); } /** @@ -94,7 +98,7 @@ public class SimplexOptimizer * @param abs Absolute threshold. */ public SimplexOptimizer(double rel, double abs) { - setConvergenceChecker(new SimpleScalarValueChecker(rel, abs)); + this(new SimpleScalarValueChecker(rel, abs)); } /** diff --git a/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerMultiDirectionalTest.java b/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerMultiDirectionalTest.java index 044a601c0..86ac26dc8 100644 --- a/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerMultiDirectionalTest.java +++ b/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerMultiDirectionalTest.java @@ -27,57 +27,61 @@ import org.junit.Test; public class SimplexOptimizerMultiDirectionalTest { @Test - public void testMinimizeMaximize() { - // the following function has 4 local extrema: - final double xM = -3.841947088256863675365; - final double yM = -1.391745200270734924416; - final double xP = 0.2286682237349059125691; - final double yP = -yM; - final double valueXmYm = 0.2373295333134216789769; // local maximum - final double valueXmYp = -valueXmYm; // local minimum - final double valueXpYm = -0.7290400707055187115322; // global minimum - final double valueXpYp = -valueXpYm; // global maximum - MultivariateRealFunction fourExtrema = new MultivariateRealFunction() { - public double value(double[] variables) { - final double x = variables[0]; - final double y = variables[1]; - return ((x == 0) || (y == 0)) ? 0 : - (FastMath.atan(x) * FastMath.atan(x + 2) * FastMath.atan(y) * FastMath.atan(y) / (x * y)); - } - }; - + public void testMinimize1() { SimplexOptimizer optimizer = new SimplexOptimizer(1e-11, 1e-30); optimizer.setSimplex(new MultiDirectionalSimplex(new double[] { 0.2, 0.2 })); - RealPointValuePair optimum; + final FourExtrema fourExtrema = new FourExtrema(); - // minimization - optimum = optimizer.optimize(200, fourExtrema, GoalType.MINIMIZE, new double[] { -3, 0 }); - Assert.assertEquals(xM, optimum.getPoint()[0], 4e-6); - Assert.assertEquals(yP, optimum.getPoint()[1], 3e-6); - Assert.assertEquals(valueXmYp, optimum.getValue(), 8e-13); + final RealPointValuePair optimum + = optimizer.optimize(200, fourExtrema, GoalType.MINIMIZE, new double[] { -3, 0 }); + Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 4e-6); + Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 3e-6); + Assert.assertEquals(fourExtrema.valueXmYp, optimum.getValue(), 8e-13); Assert.assertTrue(optimizer.getEvaluations() > 120); Assert.assertTrue(optimizer.getEvaluations() < 150); + } - optimum = optimizer.optimize(200, fourExtrema, GoalType.MINIMIZE, new double[] { 1, 0 }); - Assert.assertEquals(xP, optimum.getPoint()[0], 2e-8); - Assert.assertEquals(yM, optimum.getPoint()[1], 3e-6); - Assert.assertEquals(valueXpYm, optimum.getValue(), 2e-12); + @Test + public void testMinimize2() { + SimplexOptimizer optimizer = new SimplexOptimizer(1e-11, 1e-30); + optimizer.setSimplex(new MultiDirectionalSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(200, fourExtrema, GoalType.MINIMIZE, new double[] { 1, 0 }); + Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 2e-8); + Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 3e-6); + Assert.assertEquals(fourExtrema.valueXpYm, optimum.getValue(), 2e-12); Assert.assertTrue(optimizer.getEvaluations() > 120); Assert.assertTrue(optimizer.getEvaluations() < 150); + } - // maximization - optimum = optimizer.optimize(200, fourExtrema, GoalType.MAXIMIZE, new double[] { -3.0, 0.0 }); - Assert.assertEquals(xM, optimum.getPoint()[0], 7e-7); - Assert.assertEquals(yM, optimum.getPoint()[1], 3e-7); - Assert.assertEquals(valueXmYm, optimum.getValue(), 2e-14); + @Test + public void testMaximize1() { + SimplexOptimizer optimizer = new SimplexOptimizer(1e-11, 1e-30); + optimizer.setSimplex(new MultiDirectionalSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(200, fourExtrema, GoalType.MAXIMIZE, new double[] { -3.0, 0.0 }); + Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 7e-7); + Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 3e-7); + Assert.assertEquals(fourExtrema.valueXmYm, optimum.getValue(), 2e-14); Assert.assertTrue(optimizer.getEvaluations() > 120); Assert.assertTrue(optimizer.getEvaluations() < 150); + } - optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1e-15, 1e-30)); - optimum = optimizer.optimize(200, fourExtrema, GoalType.MAXIMIZE, new double[] { 1, 0 }); - Assert.assertEquals(xP, optimum.getPoint()[0], 2e-8); - Assert.assertEquals(yP, optimum.getPoint()[1], 3e-6); - Assert.assertEquals(valueXpYp, optimum.getValue(), 2e-12); + @Test + public void testMaximize2() { + SimplexOptimizer optimizer = new SimplexOptimizer(new SimpleScalarValueChecker(1e-15, 1e-30)); + optimizer.setSimplex(new MultiDirectionalSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(200, fourExtrema, GoalType.MAXIMIZE, new double[] { 1, 0 }); + Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 2e-8); + Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 3e-6); + Assert.assertEquals(fourExtrema.valueXpYp, optimum.getValue(), 2e-12); Assert.assertTrue(optimizer.getEvaluations() > 180); Assert.assertTrue(optimizer.getEvaluations() < 220); } @@ -153,6 +157,25 @@ public class SimplexOptimizerMultiDirectionalTest { Assert.assertEquals(expectedPosition[1], actualPosition[1], EPSILON ); } + private static class FourExtrema implements MultivariateRealFunction { + // The following function has 4 local extrema. + final double xM = -3.841947088256863675365; + final double yM = -1.391745200270734924416; + final double xP = 0.2286682237349059125691; + final double yP = -yM; + final double valueXmYm = 0.2373295333134216789769; // Local maximum. + final double valueXmYp = -valueXmYm; // Local minimum. + final double valueXpYm = -0.7290400707055187115322; // Global minimum. + final double valueXpYp = -valueXpYm; // Global maximum. + + public double value(double[] variables) { + final double x = variables[0]; + final double y = variables[1]; + return (x == 0 || y == 0) ? 0 : + FastMath.atan(x) * FastMath.atan(x + 2) * FastMath.atan(y) * FastMath.atan(y) / (x * y); + } + } + private static class Gaussian2D implements MultivariateRealFunction { private final double[] maximumPosition; private final double std; diff --git a/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerNelderMeadTest.java b/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerNelderMeadTest.java index e8dee3a0c..e9bb98476 100644 --- a/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerNelderMeadTest.java +++ b/src/test/java/org/apache/commons/math/optimization/direct/SimplexOptimizerNelderMeadTest.java @@ -26,62 +26,67 @@ import org.apache.commons.math.linear.RealMatrix; import org.apache.commons.math.optimization.GoalType; import org.apache.commons.math.optimization.LeastSquaresConverter; import org.apache.commons.math.optimization.RealPointValuePair; +import org.apache.commons.math.util.FastMath; import org.junit.Assert; import org.junit.Test; public class SimplexOptimizerNelderMeadTest { @Test - public void testMinimizeMaximize() { - - // the following function has 4 local extrema: - final double xM = -3.841947088256863675365; - final double yM = -1.391745200270734924416; - final double xP = 0.2286682237349059125691; - final double yP = -yM; - final double valueXmYm = 0.2373295333134216789769; // local maximum - final double valueXmYp = -valueXmYm; // local minimum - final double valueXpYm = -0.7290400707055187115322; // global minimum - final double valueXpYp = -valueXpYm; // global maximum - MultivariateRealFunction fourExtrema = new MultivariateRealFunction() { - public double value(double[] variables) { - final double x = variables[0]; - final double y = variables[1]; - return (x == 0 || y == 0) ? 0 : - (Math.atan(x) * Math.atan(x + 2) * Math.atan(y) * Math.atan(y) / (x * y)); - } - }; - + public void testMinimize1() { SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30); optimizer.setSimplex(new NelderMeadSimplex(new double[] { 0.2, 0.2 })); - RealPointValuePair optimum; + final FourExtrema fourExtrema = new FourExtrema(); - // minimization - optimum = optimizer.optimize(100, fourExtrema, GoalType.MINIMIZE, new double[] { -3, 0 }); - Assert.assertEquals(xM, optimum.getPoint()[0], 2e-7); - Assert.assertEquals(yP, optimum.getPoint()[1], 2e-5); - Assert.assertEquals(valueXmYp, optimum.getValue(), 6e-12); + final RealPointValuePair optimum + = optimizer.optimize(100, fourExtrema, GoalType.MINIMIZE, new double[] { -3, 0 }); + Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 2e-7); + Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 2e-5); + Assert.assertEquals(fourExtrema.valueXmYp, optimum.getValue(), 6e-12); Assert.assertTrue(optimizer.getEvaluations() > 60); Assert.assertTrue(optimizer.getEvaluations() < 90); + } - optimum = optimizer.optimize(100, fourExtrema, GoalType.MINIMIZE, new double[] { 1, 0 }); - Assert.assertEquals(xP, optimum.getPoint()[0], 5e-6); - Assert.assertEquals(yM, optimum.getPoint()[1], 6e-6); - Assert.assertEquals(valueXpYm, optimum.getValue(), 1e-11); + @Test + public void testMinimize2() { + SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30); + optimizer.setSimplex(new NelderMeadSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(100, fourExtrema, GoalType.MINIMIZE, new double[] { 1, 0 }); + Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 5e-6); + Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 6e-6); + Assert.assertEquals(fourExtrema.valueXpYm, optimum.getValue(), 1e-11); Assert.assertTrue(optimizer.getEvaluations() > 60); Assert.assertTrue(optimizer.getEvaluations() < 90); + } - // maximization - optimum = optimizer.optimize(100, fourExtrema, GoalType.MAXIMIZE, new double[] { -3, 0 }); - Assert.assertEquals(xM, optimum.getPoint()[0], 1e-5); - Assert.assertEquals(yM, optimum.getPoint()[1], 3e-6); - Assert.assertEquals(valueXmYm, optimum.getValue(), 3e-12); + @Test + public void testMaximize1() { + SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30); + optimizer.setSimplex(new NelderMeadSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(100, fourExtrema, GoalType.MAXIMIZE, new double[] { -3, 0 }); + Assert.assertEquals(fourExtrema.xM, optimum.getPoint()[0], 1e-5); + Assert.assertEquals(fourExtrema.yM, optimum.getPoint()[1], 3e-6); + Assert.assertEquals(fourExtrema.valueXmYm, optimum.getValue(), 3e-12); Assert.assertTrue(optimizer.getEvaluations() > 60); Assert.assertTrue(optimizer.getEvaluations() < 90); + } - optimum = optimizer.optimize(100, fourExtrema, GoalType.MAXIMIZE, new double[] { 1, 0 }); - Assert.assertEquals(xP, optimum.getPoint()[0], 4e-6); - Assert.assertEquals(yP, optimum.getPoint()[1], 5e-6); - Assert.assertEquals(valueXpYp, optimum.getValue(), 7e-12); + @Test + public void testMaximize2() { + SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30); + optimizer.setSimplex(new NelderMeadSimplex(new double[] { 0.2, 0.2 })); + final FourExtrema fourExtrema = new FourExtrema(); + + final RealPointValuePair optimum + = optimizer.optimize(100, fourExtrema, GoalType.MAXIMIZE, new double[] { 1, 0 }); + Assert.assertEquals(fourExtrema.xP, optimum.getPoint()[0], 4e-6); + Assert.assertEquals(fourExtrema.yP, optimum.getPoint()[1], 5e-6); + Assert.assertEquals(fourExtrema.valueXpYp, optimum.getValue(), 7e-12); Assert.assertTrue(optimizer.getEvaluations() > 60); Assert.assertTrue(optimizer.getEvaluations() < 90); } @@ -199,6 +204,25 @@ public class SimplexOptimizerNelderMeadTest { optimizer.optimize(20, powell, GoalType.MINIMIZE, new double[] { 3, -1, 0, 1 }); } + private static class FourExtrema implements MultivariateRealFunction { + // The following function has 4 local extrema. + final double xM = -3.841947088256863675365; + final double yM = -1.391745200270734924416; + final double xP = 0.2286682237349059125691; + final double yP = -yM; + final double valueXmYm = 0.2373295333134216789769; // Local maximum. + final double valueXmYp = -valueXmYm; // Local minimum. + final double valueXpYm = -0.7290400707055187115322; // Global minimum. + final double valueXpYp = -valueXpYm; // Global maximum. + + public double value(double[] variables) { + final double x = variables[0]; + final double y = variables[1]; + return (x == 0 || y == 0) ? 0 : + FastMath.atan(x) * FastMath.atan(x + 2) * FastMath.atan(y) * FastMath.atan(y) / (x * y); + } + } + private static class Rosenbrock implements MultivariateRealFunction { private int count;