You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2021/08/22 00:33:25 UTC
[commons-math] 01/13: Simplify data format for
"SimplexOptimizerTest" (randomized) input.
This is an automated email from the ASF dual-hosted git repository.
erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 3ba0221c267e299525d385c496840c2b92eeac9c
Author: Gilles Sadowski <gi...@gmail.com>
AuthorDate: Fri Aug 20 12:51:09 2021 +0200
Simplify data format for "SimplexOptimizerTest" (randomized) input.
This commit also makes the following changes (unit tests):
* Add/remove/rename/rewrite test functions.
---
.../optim/nonlinear/scalar/TestFunction.java | 67 ++++++++++++----------
.../scalar/noderiv/BOBYQAOptimizerTest.java | 16 +-----
.../scalar/noderiv/CMAESOptimizerTest.java | 21 +------
.../scalar/noderiv/SimplexOptimizerTest.java | 61 +++++++++++---------
4 files changed, 76 insertions(+), 89 deletions(-)
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/TestFunction.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/TestFunction.java
index 0292bd8..f28bf11 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/TestFunction.java
+++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/TestFunction.java
@@ -19,7 +19,6 @@ package org.apache.commons.math4.legacy.optim.nonlinear.scalar;
import java.util.function.Function;
import java.util.function.DoubleUnaryOperator;
import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
-import org.apache.commons.math4.legacy.core.jdkmath.AccurateMath;
/**
* Generators of {@link MultivariateFunction multivariate scalar functions}.
@@ -71,20 +70,26 @@ public enum TestFunction {
};
}),
TWO_AXES(dim -> {
+ final int halfDim = dim / 2;
return x -> {
double f = 0;
- for (int i = 0; i < dim; i++) {
- f += (i < dim / 2 ? 1e6 : 1) * x[i] * x[i];
+ for (int i = 0; i < halfDim; i++) {
+ f += 1e6 * x[i] * x[i];
+ }
+ for (int i = halfDim; i < dim; i++) {
+ f += x[i] * x[i];
}
return f;
};
}),
ELLI(dim -> {
- final double last = dim - 1;
+ final double M = Math.pow(1e3, 1d / (dim - 1));
return x -> {
+ double factor = 1;
double f = 0;
for (int i = 0; i < dim; i++) {
- f += Math.pow(1e3, i / last) * x[i] * x[i];
+ f += factor * x[i] * x[i];
+ factor *= M;
}
return f;
};
@@ -96,22 +101,15 @@ public enum TestFunction {
};
}),
// https://www.sfu.ca/~ssurjano/sumpow.html
- DIFF_POW(dim -> {
+ SUM_POW(dim -> {
return x -> {
double f = 0;
for (int i = 0; i < dim; i++) {
- f += AccurateMath.pow(Math.abs(x[i]), i + 2);
+ f += Math.pow(Math.abs(x[i]), i + 2);
}
return f;
};
}),
- SS_DIFF_POW(dim -> {
- final MultivariateFunction diffPow = DIFF_POW.withDimension(dim);
- return x -> {
- double f = Math.pow(diffPow.value(x), 0.25);
- return f;
- };
- }),
// https://www.sfu.ca/~ssurjano/ackley.html
ACKLEY(dim -> {
final double A = 20;
@@ -134,33 +132,26 @@ public enum TestFunction {
// https://www.sfu.ca/~ssurjano/rastr.html
RASTRIGIN(dim -> {
final double A = 10;
+ final double twopi = 2 * Math.PI;
return x -> {
double sum = 0;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
- sum += xi * xi - A * Math.cos(2 * Math.PI * xi);
+ sum += xi * xi - A * Math.cos(twopi * xi);
}
return A * dim + sum;
};
}),
- // https://www.sfu.ca/~ssurjano/powell.html
- POWELL(dim -> {
- final int last = dim / 4;
+ // http://benchmarkfcns.xyz/benchmarkfcns/salomonfcn.html
+ SALOMON(dim -> {
return x -> {
- double f = 0;
- for (int i = 0; i < last; i++) {
- final int fourI = 4 * i;
- final double x4i = x[fourI];
- final double x4iP1 = x[fourI + 1];
- final double x4iP2 = x[fourI + 2];
- final double x4iP3 = x[fourI + 3];
- final double a = x4i + 10 * x4iP1;
- final double b = x4iP2 - x4iP3;
- final double c = x4iP1 - 2 * x4iP2;
- final double d = x4i - x4iP3;
- f += a * a + 5 * b * b + c * c * c * c + 10 * d * d * d * d;
+ double sum = 0;
+ for (int i = 0; i < dim; i++) {
+ final double xi = x[i];
+ sum += xi * xi;
}
- return f;
+ final double sqrtSum = Math.sqrt(sum);
+ return 1 - Math.cos(2 * Math.PI * sqrtSum) + 0.1 * sqrtSum;
};
}),
ROSENBROCK(dim -> {
@@ -177,6 +168,20 @@ public enum TestFunction {
return f;
};
}),
+ // http://benchmarkfcns.xyz/benchmarkfcns/happycatfcn.html
+ HAPPY_CAT(dim -> {
+ final double alpha = 0.125;
+ return x -> {
+ double sum = 0;
+ double sumSq = 0;
+ for (int i = 0; i < dim; i++) {
+ final double xi = x[i];
+ sum += xi;
+ sumSq += xi * xi;
+ }
+ return Math.pow(sumSq - dim, 2 * alpha) + (0.5 * sumSq + sum) / dim + 0.5;
+ };
+ }),
PARABOLA(dim -> {
return x -> {
double f = 0;
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/BOBYQAOptimizerTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/BOBYQAOptimizerTest.java
index bd6cd3a..45e4b29 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/BOBYQAOptimizerTest.java
+++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/BOBYQAOptimizerTest.java
@@ -177,30 +177,18 @@ public class BOBYQAOptimizerTest {
}
@Test
- public void testDiffPow() {
+ public void testSumPow() {
final int dim = DIM / 2;
double[] startPoint = OptimTestUtils.point(dim, 1.0);
double[][] boundaries = null;
PointValuePair expected =
new PointValuePair(OptimTestUtils.point(dim, 0.0), 0.0);
- doTest(TestFunction.DIFF_POW.withDimension(dim), startPoint, boundaries,
+ doTest(TestFunction.SUM_POW.withDimension(dim), startPoint, boundaries,
GoalType.MINIMIZE,
1e-8, 1e-1, 21000, expected);
}
@Test
- public void testSsDiffPow() {
- final int dim = DIM / 2;
- double[] startPoint = OptimTestUtils.point(dim, 1.0);
- double[][] boundaries = null;
- PointValuePair expected =
- new PointValuePair(OptimTestUtils.point(dim, 0.0), 0.0);
- doTest(TestFunction.SS_DIFF_POW.withDimension(dim), startPoint, boundaries,
- GoalType.MINIMIZE,
- 1e-2, 1.3e-1, 50000, expected);
- }
-
- @Test
public void testAckley() {
double[] startPoint = OptimTestUtils.point(DIM,0.1);
double[][] boundaries = null;
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/CMAESOptimizerTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/CMAESOptimizerTest.java
index bf9bdb4..9724e27 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/CMAESOptimizerTest.java
+++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/CMAESOptimizerTest.java
@@ -299,36 +299,21 @@ public class CMAESOptimizerTest {
}
@Test
- public void testDiffPow() {
+ public void testSumPow() {
double[] startPoint = OptimTestUtils.point(DIM,1.0);
double[] insigma = OptimTestUtils.point(DIM,0.1);
double[][] boundaries = null;
PointValuePair expected =
new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
- doTest(TestFunction.DIFF_POW.withDimension(DIM), startPoint, insigma, boundaries,
+ doTest(TestFunction.SUM_POW.withDimension(DIM), startPoint, insigma, boundaries,
GoalType.MINIMIZE, 10, true, 0, 1e-13,
1e-8, 1e-1, 100000, expected);
- doTest(TestFunction.DIFF_POW.withDimension(DIM), startPoint, insigma, boundaries,
+ doTest(TestFunction.SUM_POW.withDimension(DIM), startPoint, insigma, boundaries,
GoalType.MINIMIZE, 10, false, 0, 1e-13,
1e-8, 2e-1, 100000, expected);
}
@Test
- public void testSsDiffPow() {
- double[] startPoint = OptimTestUtils.point(DIM,1.0);
- double[] insigma = OptimTestUtils.point(DIM,0.1);
- double[][] boundaries = null;
- PointValuePair expected =
- new PointValuePair(OptimTestUtils.point(DIM,0.0),0.0);
- doTest(TestFunction.SS_DIFF_POW.withDimension(DIM), startPoint, insigma, boundaries,
- GoalType.MINIMIZE, 10, true, 0, 1e-13,
- 1e-4, 1e-1, 200000, expected);
- doTest(TestFunction.SS_DIFF_POW.withDimension(DIM), startPoint, insigma, boundaries,
- GoalType.MINIMIZE, 10, false, 0, 1e-13,
- 1e-4, 1e-1, 200000, expected);
- }
-
- @Test
public void testAckley() {
double[] startPoint = OptimTestUtils.point(DIM,1.0);
double[] insigma = OptimTestUtils.point(DIM,1.0);
diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/SimplexOptimizerTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/SimplexOptimizerTest.java
index 23cc75f..a8fc3ff 100644
--- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/SimplexOptimizerTest.java
+++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/noderiv/SimplexOptimizerTest.java
@@ -33,7 +33,10 @@ import org.junit.jupiter.params.aggregator.ArgumentsAccessor;
import org.junit.jupiter.params.aggregator.ArgumentsAggregationException;
import org.junit.jupiter.params.aggregator.AggregateWith;
import org.junit.jupiter.params.provider.CsvFileSource;
+import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.simple.RandomSource;
+import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
+import org.apache.commons.rng.sampling.UnitSphereSampler;
import org.apache.commons.math4.legacy.core.MathArrays;
import org.apache.commons.math4.legacy.exception.MathUnsupportedOperationException;
import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException;
@@ -89,7 +92,7 @@ public class SimplexOptimizerTest {
@ParameterizedTest
@CsvFileSource(resources = NELDER_MEAD_INPUT_FILE)
void testFunctionWithNelderMead(@AggregateWith(TaskAggregator.class) Task task) {
- // task.checkAlongLine(1000, true);
+ // task.checkAlongLine(1000);
task.run(new NelderMeadTransform());
}
@@ -114,7 +117,7 @@ public class SimplexOptimizerTest {
/** Default convergence criterion. */
private static final double CONVERGENCE_CHECK = 1e-9;
/** Default cooling factor. */
- private static final double SA_COOL_FACTOR = 0.5;
+ private static final double SA_COOL_FACTOR = 0.7;
/** Default acceptance probability at beginning of SA. */
private static final double SA_START_PROB = 0.9;
/** Default acceptance probability at end of SA. */
@@ -131,8 +134,6 @@ public class SimplexOptimizerTest {
private final int functionEvaluations;
/** Side length of initial simplex. */
private final double simplexSideLength;
- /** Range of random noise. */
- private final double jitter;
/** Whether to perform simulated annealing. */
private final boolean withSA;
/** File prefix (for saving debugging info). */
@@ -148,7 +149,6 @@ public class SimplexOptimizerTest {
* {@code optimum}.
* @param functionEvaluations Allowed number of function evaluations.
* @param simplexSideLength Side length of initial simplex.
- * @param jitter Size of random jitter.
* @param withSA Whether to perform simulated annealing.
* @param tracePrefix Prefix of the file where to save simplex
* transformations during the optimization.
@@ -162,7 +162,6 @@ public class SimplexOptimizerTest {
double pointTolerance,
int functionEvaluations,
double simplexSideLength,
- double jitter,
boolean withSA,
String tracePrefix,
int[] traceIndices) {
@@ -172,7 +171,6 @@ public class SimplexOptimizerTest {
this.pointTolerance = pointTolerance;
this.functionEvaluations = functionEvaluations;
this.simplexSideLength = simplexSideLength;
- this.jitter = jitter;
this.withSA = withSA;
this.tracePrefix = tracePrefix;
this.traceIndices = traceIndices;
@@ -219,16 +217,12 @@ public class SimplexOptimizerTest {
optim.addObserver(createCallback(factory));
}
- final Simplex initialSimplex =
- Simplex.alongAxes(OptimTestUtils.point(dim,
- simplexSideLength,
- jitter));
- final double[] startPoint = OptimTestUtils.point(start, jitter);
+ final Simplex initialSimplex = Simplex.equalSidesAlongAxes(dim, simplexSideLength);
final PointValuePair result =
optim.optimize(new MaxEval(maxEval),
new ObjectiveFunction(function),
GoalType.MINIMIZE,
- new InitialGuess(startPoint),
+ new InitialGuess(start),
initialSimplex,
factory,
sa,
@@ -258,6 +252,7 @@ public class SimplexOptimizerTest {
final String sep = "__";
final String name = tracePrefix + sanitizeBasename(function + sep +
+ Arrays.toString(start) + sep +
factory + sep);
// Create file; write first data block (optimum) and columns header.
@@ -274,15 +269,17 @@ public class SimplexOptimizerTest {
out.println();
out.println("#");
- out.print("# <1: evaluations> <2: objective>");
+ out.print("# <1: evaluations> <2: f(x)> <3: |f(x) - f(optimum)|>");
for (int i = 0; i < start.length; i++) {
- out.print(" <" + (i + 3) + ": coordinate " + i + ">");
+ out.print(" <" + (i + 4) + ": x[" + i + "]>");
}
out.println();
} catch (IOException e) {
Assertions.fail(e.getMessage());
}
+ final double fAtOptimum = function.value(optimum);
+
// Return callback function.
return (simplex, isInit, numEval) -> {
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(Paths.get(name),
@@ -300,7 +297,8 @@ public class SimplexOptimizerTest {
for (int index : traceIndices) {
final PointValuePair p = points.get(index);
out.print(numEval + fieldSep +
- p.getValue() + fieldSep);
+ p.getValue() + fieldSep +
+ Math.abs(p.getValue() - fAtOptimum) + fieldSep);
final double[] coord = p.getPoint();
for (int i = 0; i < coord.length; i++) {
@@ -321,12 +319,10 @@ public class SimplexOptimizerTest {
* {@link #start} is reached at the {@link #optimum}.
*
* @param numPoints Number of points at which to evaluate the function.
- * @param plot Whether to generate a file (for visual debugging).
*/
- public void checkAlongLine(int numPoints,
- boolean plot) {
- if (plot) {
- final String name = createPlotBasename(function, start, optimum);
+ public void checkAlongLine(int numPoints) {
+ if (tracePrefix != null) {
+ final String name = tracePrefix + createPlotBasename(function, start, optimum);
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(Paths.get(name)))) {
checkAlongLine(numPoints, out);
} catch (IOException e) {
@@ -448,14 +444,29 @@ public class SimplexOptimizerTest {
final TestFunction funcGen = a.get(index++, TestFunction.class);
final int dim = a.getInteger(index++);
- final double[] start = toArrayOfDoubles(a.getString(index++), dim);
final double[] optimum = toArrayOfDoubles(a.getString(index++), dim);
+ final double minRadius = a.getDouble(index++);
+ final double maxRadius = a.getDouble(index++);
+ if (minRadius < 0 ||
+ maxRadius < 0 ||
+ minRadius >= maxRadius) {
+ throw new ArgumentsAggregationException("radii");
+ }
final double pointTol = a.getDouble(index++);
final int funcEval = a.getInteger(index++);
- final double sideLength = a.getDouble(index++);
- final double jitter = a.getDouble(index++);
final boolean withSA = a.getBoolean(index++);
+ // Generate a start point within a spherical shell around the optimum.
+ final UniformRandomProvider rng = OptimTestUtils.rng();
+ final double radius = ContinuousUniformSampler.of(rng, minRadius, maxRadius).sample();
+ final double[] start = UnitSphereSampler.of(rng, dim).sample();
+ for (int i = 0; i < dim; i++) {
+ start[i] *= radius;
+ start[i] += optimum[i];
+ }
+ // Simplex side.
+ final double sideLength = 0.5 * (maxRadius - minRadius);
+
if (index == a.size()) {
// No more arguments.
return new Task(funcGen.withDimension(dim),
@@ -464,7 +475,6 @@ public class SimplexOptimizerTest {
pointTol,
funcEval,
sideLength,
- jitter,
withSA,
null,
null);
@@ -481,7 +491,6 @@ public class SimplexOptimizerTest {
pointTol,
funcEval,
sideLength,
- jitter,
withSA,
tracePrefix,
spxIndices);