blob: 2f5d9cbfdeb71d79025c8bd1620996750bf9923b [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.noderiv;
import java.util.Arrays;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.simple.RandomSource;
import org.apache.commons.rng.sampling.distribution.MarsagliaNormalizedGaussianSampler;
import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
import org.apache.commons.math4.legacy.core.jdkmath.AccurateMath;
/**
* Utilities for testing the optimizers.
*/
final class OptimTestUtils {
/** No instances. */
private OptimTestUtils() {}
static class Sphere implements MultivariateFunction {
@Override
public double value(double[] x) {
double f = 0;
for (int i = 0; i < x.length; ++i) {
f += x[i] * x[i];
}
return f;
}
}
static class Cigar implements MultivariateFunction {
private double factor;
Cigar() {
this(1e3);
}
Cigar(double axisratio) {
factor = axisratio * axisratio;
}
@Override
public double value(double[] x) {
double f = x[0] * x[0];
for (int i = 1; i < x.length; ++i) {
f += factor * x[i] * x[i];
}
return f;
}
}
static class Tablet implements MultivariateFunction {
private double factor;
Tablet() {
this(1e3);
}
Tablet(double axisratio) {
factor = axisratio * axisratio;
}
@Override
public double value(double[] x) {
double f = factor * x[0] * x[0];
for (int i = 1; i < x.length; ++i) {
f += x[i] * x[i];
}
return f;
}
}
static class CigTab implements MultivariateFunction {
private double factor;
CigTab() {
this(1e4);
}
CigTab(double axisratio) {
factor = axisratio;
}
@Override
public double value(double[] x) {
int end = x.length - 1;
double f = x[0] * x[0] / factor + factor * x[end] * x[end];
for (int i = 1; i < end; ++i) {
f += x[i] * x[i];
}
return f;
}
}
static class TwoAxes implements MultivariateFunction {
private double factor;
TwoAxes() {
this(1e6);
}
TwoAxes(double axisratio) {
factor = axisratio * axisratio;
}
@Override
public double value(double[] x) {
double f = 0;
for (int i = 0; i < x.length; ++i) {
f += (i < x.length / 2 ? factor : 1) * x[i] * x[i];
}
return f;
}
}
static class ElliRotated implements MultivariateFunction {
private Basis B = new Basis();
private double factor;
ElliRotated() {
this(1e3);
}
ElliRotated(double axisratio) {
factor = axisratio * axisratio;
}
@Override
public double value(double[] x) {
double f = 0;
x = B.Rotate(x);
for (int i = 0; i < x.length; ++i) {
f += AccurateMath.pow(factor, i / (x.length - 1.)) * x[i] * x[i];
}
return f;
}
}
static class Elli implements MultivariateFunction {
private double factor;
Elli() {
this(1e3);
}
Elli(double axisratio) {
factor = axisratio * axisratio;
}
@Override
public double value(double[] x) {
double f = 0;
for (int i = 0; i < x.length; ++i) {
f += AccurateMath.pow(factor, i / (x.length - 1.)) * x[i] * x[i];
}
return f;
}
}
static class MinusElli implements MultivariateFunction {
private final Elli elli = new Elli();
@Override
public double value(double[] x) {
return 1.0 - elli.value(x);
}
}
static class DiffPow implements MultivariateFunction {
@Override
public double value(double[] x) {
double f = 0;
for (int i = 0; i < x.length; ++i) {
f += AccurateMath.pow(AccurateMath.abs(x[i]), 2. + 10 * (double) i
/ (x.length - 1.));
}
return f;
}
}
static class SsDiffPow implements MultivariateFunction {
@Override
public double value(double[] x) {
double f = AccurateMath.pow(new DiffPow().value(x), 0.25);
return f;
}
}
static class Rosen implements MultivariateFunction {
@Override
public double value(double[] x) {
double f = 0;
for (int i = 0; i < x.length - 1; i++) {
final double a = x[i] * x[i] - x[i + 1];
final double b = x[i] - 1;
f += 1e2 * a * a + b * b;
}
return f;
}
}
static class Ackley implements MultivariateFunction {
private static final double A = 20;
private static final double B = 0.2;
private static final double C = 2 * Math.PI;
@Override
public double value(double[] x) {
final int dim = x.length;
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
static class Rastrigin implements MultivariateFunction {
private static final double A = 10;
@Override
public double value(double[] x) {
double sum = 0;
for (int i = 0; i < x.length; i++) {
final double xi = x[i];
sum += xi * xi - A * AccurateMath.cos(2 * Math.PI * xi);
}
return A * x.length + sum;
}
}
static class FourExtrema implements MultivariateFunction {
// The following function has 4 local extrema.
static final double xM = -3.841947088256863675365;
static final double yM = -1.391745200270734924416;
static final double xP = 0.2286682237349059125691;
static final double yP = -yM;
static final double valueXmYm = 0.2373295333134216789769; // Local maximum.
static final double valueXmYp = -valueXmYm; // Local minimum.
static final double valueXpYm = -0.7290400707055187115322; // Global minimum.
static final double valueXpYp = -valueXpYm; // Global maximum.
@Override
public double value(double[] variables) {
final double x = variables[0];
final double y = variables[1];
return (x == 0 || y == 0) ? 0 :
AccurateMath.atan(x) * AccurateMath.atan(x + 2) * AccurateMath.atan(y) * AccurateMath.atan(y) / (x * y);
}
}
static class Rosenbrock implements MultivariateFunction {
@Override
public double value(double[] x) {
double a = x[1] - x[0] * x[0];
double b = 1.0 - x[0];
return 100 * a * a + b * b;
}
}
static class Powell implements MultivariateFunction {
@Override
public double value(double[] x) {
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;
}
}
static class Gaussian2D implements MultivariateFunction {
private final double[] maximumPosition;
private final double std;
Gaussian2D(double xOpt, double yOpt, double std) {
maximumPosition = new double[] { xOpt, yOpt };
this.std = std;
}
public double getMaximum() {
return value(maximumPosition);
}
public double[] getMaximumPosition() {
return maximumPosition.clone();
}
@Override
public double value(double[] point) {
final double x = point[0];
final double y = point[1];
final double twoS2 = 2.0 * std * std;
return 1.0 / (twoS2 * AccurateMath.PI) * AccurateMath.exp(-(x * x + y * y) / twoS2);
}
}
static double[] point(int n, double value) {
final double[] ds = new double[n];
Arrays.fill(ds, value);
return ds;
}
/**
* @param n Dimension.
* @param value Value.
* @param jitter Random noise to add to {@code value}.
*/
static double[] point(int n,
double value,
double jitter) {
final double[] ds = new double[n];
Arrays.fill(ds, value);
return point(ds, jitter);
}
/**
* @param point Point.
* @param jitter Random noise to add to each {@code value} element.
*/
static double[] point(double[] value,
double jitter) {
final ContinuousUniformSampler s = new ContinuousUniformSampler(rng(),
-jitter,
jitter);
final double[] ds = new double[value.length];
for (int i = 0; i < value.length; i++) {
ds[i] = value[i] + s.sample();
}
return ds;
}
/** Creates a RNG instance. */
static UniformRandomProvider rng() {
return RandomSource.create(RandomSource.MWC_256);
}
private static class Basis {
private double[][] basis;
private final MarsagliaNormalizedGaussianSampler rand = MarsagliaNormalizedGaussianSampler.of(rng()); // use not always the same basis
double[] Rotate(double[] x) {
GenBasis(x.length);
double[] y = new double[x.length];
for (int i = 0; i < x.length; ++i) {
y[i] = 0;
for (int j = 0; j < x.length; ++j) {
y[i] += basis[i][j] * x[j];
}
}
return y;
}
void GenBasis(int dim) {
if (basis != null ? basis.length == dim : false) {
return;
}
double sp;
int i;
int j;
int k;
/* generate orthogonal basis */
basis = new double[dim][dim];
for (i = 0; i < dim; ++i) {
/* sample components gaussian */
for (j = 0; j < dim; ++j) {
basis[i][j] = rand.sample();
}
/* substract projection of previous vectors */
for (j = i - 1; j >= 0; --j) {
for (sp = 0., k = 0; k < dim; ++k) {
sp += basis[i][k] * basis[j][k]; /* scalar product */
}
for (k = 0; k < dim; ++k) {
basis[i][k] -= sp * basis[j][k]; /* substract */
}
}
/* normalize */
for (sp = 0., k = 0; k < dim; ++k) {
sp += basis[i][k] * basis[i][k]; /* squared norm */
}
for (k = 0; k < dim; ++k) {
basis[i][k] /= AccurateMath.sqrt(sp);
}
}
}
}
}