blob: a82d47a0d5792918d666280c728251e88d441b72 [file] [log] [blame]
/*
* 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.math4.legacy.optim.nonlinear.scalar;
import java.util.function.Function;
import java.util.function.DoubleUnaryOperator;
import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
/**
* Generators of {@link MultivariateFunction multivariate scalar functions}.
* The functions are intended for testing optimizer implementations.
* <p>
* Note: The {@link #withDimension(int) function generators} take the space
* dimension (i.e. the length of the array argument passed to the generated
* function) as argument; it is thus assumed that the test functions can be
* generalized to any dimension.
*/
public enum TestFunction {
// https://www.sfu.ca/~ssurjano/spheref.html
SPHERE(dim -> {
return x -> {
double f = 0;
for (int i = 0; i < dim; i++) {
f += x[i] * x[i];
}
return f;
};
}),
CIGAR(dim -> {
return x -> {
double f = x[0] * x[0];
for (int i = 1; i < dim; i++) {
f += 1e3 * x[i] * x[i];
}
return f;
};
}),
TABLET(dim -> {
return x -> {
double f = 1e3 * x[0] * x[0];
for (int i = 1; i < dim; i++) {
f += x[i] * x[i];
}
return f;
};
}),
CIG_TAB(dim -> {
final double factor = 1e4;
final int last = dim - 1;
return x -> {
double f = x[0] * x[0] / factor + factor * x[last] * x[last];
for (int i = 1; i < last; i++) {
f += x[i] * x[i];
}
return f;
};
}),
TWO_AXES(dim -> {
final int halfDim = dim / 2;
return x -> {
double f = 0;
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 M = Math.pow(1e3, 1d / (dim - 1));
return x -> {
double factor = 1;
double f = 0;
for (int i = 0; i < dim; i++) {
f += factor * x[i] * x[i];
factor *= M;
}
return f;
};
}),
MINUS_ELLI(dim -> {
final MultivariateFunction elli = ELLI.withDimension(dim);
return x -> {
return 1 - elli.value(x);
};
}),
// https://www.sfu.ca/~ssurjano/sumpow.html
SUM_POW(dim -> {
return x -> {
double f = 0;
for (int i = 0; i < dim; i++) {
f += Math.pow(Math.abs(x[i]), i + 2);
}
return f;
};
}),
// https://www.sfu.ca/~ssurjano/ackley.html
ACKLEY(dim -> {
final double A = 20;
final double B = 0.2;
final double C = 2 * Math.PI;
return x -> {
double acc1 = 0;
double acc2 = 0;
for (int i = 0; i < dim; i++) {
final double v = x[i];
acc1 += v * v;
acc2 += Math.cos(C * v);
}
acc1 = -B * Math.sqrt(acc1 / dim);
acc2 /= dim;
return -A * Math.exp(acc1) - Math.exp(acc2) + A + Math.E;
};
}),
// 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(twopi * xi);
}
return A * dim + sum;
};
}),
// http://benchmarkfcns.xyz/benchmarkfcns/salomonfcn.html
SALOMON(dim -> {
return x -> {
double sum = 0;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
sum += xi * xi;
}
final double sqrtSum = Math.sqrt(sum);
return 1 - Math.cos(2 * Math.PI * sqrtSum) + 0.1 * sqrtSum;
};
}),
// https://scholarship.rice.edu/handle/1911/16304
ROSENBROCK(dim -> {
if (dim % 2 != 0) {
throw new IllegalArgumentException("Must be a multiple of 2 (was: " + dim + ")");
}
final int last = dim / 2;
return x -> {
double f = 0;
for (int i = 1; i <= last; i++) {
final int twoI = 2 * i;
final int i0 = twoI - 1;
final int i1 = twoI;
final double x2iM1 = x[i0 - 1];
final double x2i = x[i1 - 1];
final double t2iM1 = x2i - x2iM1 * x2iM1;
final double t2i = 1 - x2iM1;
f += 100 * t2iM1 * t2iM1 + t2i * t2i;
}
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;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
f += xi * xi;
}
return f;
};
}),
// https://www.sfu.ca/~ssurjano/griewank.html
GRIEWANK(dim -> {
final double A = 4000;
return x -> {
double sum = 0;
double prod = 1;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
sum += xi * xi;
prod *= Math.cos(xi / Math.sqrt(i + 1));
}
return sum / A - prod + 1;
};
}),
// https://www.sfu.ca/~ssurjano/levy.html
LEVY(dim -> {
final int last = dim - 1;
final DoubleUnaryOperator w = x -> 1 + 0.25 * (x - 1);
return x -> {
final double a0 = Math.sin(Math.PI * w.applyAsDouble(x[0]));
double sum = a0 * a0;
for (int i = 0; i < last; i++) {
final double wi = w.applyAsDouble(x[i]);
final double wiM1 = wi - 1;
final double ai = Math.sin(Math.PI * wi + 1);
sum += wiM1 * wiM1 * (1 + 10 * ai * ai);
}
final double wl = w.applyAsDouble(x[last]);
final double wlM1 = wl - 1;
final double al = Math.sin(2 * Math.PI * wl);
return sum + wlM1 * wlM1 * (1 + al * al);
};
}),
// https://www.sfu.ca/~ssurjano/schwef.html
SCHWEFEL(dim -> {
final double A = 418.9829;
return x -> {
double sum = 0;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
sum += xi * Math.sin(Math.sqrt(Math.abs(xi)));
}
return A * dim - sum;
};
}),
// https://www.sfu.ca/~ssurjano/zakharov.html
ZAKHAROV(dim -> {
final double A = 0.5;
return x -> {
double sum1 = 0;
double sum2 = 0;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
sum1 += xi * xi;
sum2 += A * (i + 1) * xi;
}
final double sum22 = sum2 * sum2;
return sum1 + sum22 + sum22 * sum22;
};
}),
// https://www.sfu.ca/~ssurjano/permdb.html
PERM(dim -> {
final double BETA = 10;
return x -> {
double sum1 = 0;
for (int i = 0; i < dim; i++) {
final double iP1 = i + 1;
double sum2 = 0;
for (int j = 0; j < dim; j++) {
final double jP1 = j + 1;
final double a = Math.pow(jP1, iP1) + BETA;
final double b = Math.pow(x[j] / jP1, iP1) - 1;
sum2 += a * b;
}
sum1 += sum2 * sum2;
}
return sum1;
};
}),
// https://www.sfu.ca/~ssurjano/stybtang.html
STYBLINSKI_TANG(dim -> {
final double A = 0.5;
final double B = 16;
final double C = 5;
return x -> {
double sum = 0;
for (int i = 0; i < dim; i++) {
final double xi = x[i];
final double xi2 = xi * xi;
final double xi4 = xi2 * xi2;
sum += xi4 - B * xi2 + C * xi;
}
return A * sum;
};
}),
// https://scholarship.rice.edu/handle/1911/16304
POWELL(dim -> {
if (dim % 4 != 0) {
throw new IllegalArgumentException("Must be a multiple of 4 (was: " + dim + ")");
}
final int last = dim / 4;
return x -> {
double sum = 0;
for (int i = 1; i <= last; i++) {
final int fourI = 4 * i;
final int i0 = fourI - 3;
final int i1 = fourI - 2;
final int i2 = fourI - 1;
final int i3 = fourI;
final double x4iM3 = x[i0 - 1];
final double x4iM2 = x[i1 - 1];
final double x4iM1 = x[i2 - 1];
final double x4i = x[i3 - 1];
final double t4iM3 = x4iM3 + 10 * x4iM2;
final double t4iM2 = x4iM1 - x4i;
final double t4iM1 = x4iM2 - 2 * x4iM1;
final double sqT4iM1 = t4iM1 * t4iM1;
final double t4i = x4iM3 - x4i;
final double sqT4i = t4i * t4i;
sum += t4iM3 * t4iM3 + 5 * t4iM2 * t4iM2 + sqT4iM1 * sqT4iM1 + 10 * sqT4i * sqT4i;
}
return sum;
};
});
/** Template for variable dimension. */
private final Function<Integer, MultivariateFunction> generator;
/**
* @param gen Template for variable dimension.
*/
TestFunction(Function<Integer, MultivariateFunction> gen) {
generator = gen;
}
/**
* @param dim Dimension.
* @return the function for the given dimension.
*/
public MultivariateFunction withDimension(final int dim) {
return new MultivariateFunction() {
/** Delegate. */
private final MultivariateFunction f = generator.apply(dim);
@Override
public double value(double[] x) {
if (x.length != dim) {
throw new IllegalArgumentException("Dimension mismatch: " + x.length +
"(expected: " + dim + ")");
}
return f.value(x);
};
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("[")
.append(TestFunction.this.toString())
.append(" dim=")
.append(dim)
.append("]");
return sb.toString();
}
};
}
}