MATH-428
Refactoring of "DirectSearchOptimizer" to separate the optimization and simplex management aspects. Old classes are deprecated. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1027007 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
53ccce4ac1
commit
0d6a91f698
|
@ -24,9 +24,9 @@ import org.apache.commons.math.exception.util.Localizable;
|
|||
|
||||
/**
|
||||
* Base class for all preconditions violation exceptions.
|
||||
* This class is not intended to be instantiated directly: it should serve
|
||||
* as a base class to create all the exceptions that share the semantics of
|
||||
* the standard {@link IllegalArgumentException}, but must also provide a
|
||||
* In most cases, this class should not be instantiated directly: it should
|
||||
* serve as a base class to create all the exceptions that share the semantics
|
||||
* of the standard {@link IllegalArgumentException}, but must also provide a
|
||||
* localized message.
|
||||
*
|
||||
* @since 2.2
|
||||
|
@ -56,9 +56,9 @@ public class MathIllegalArgumentException extends IllegalArgumentException {
|
|||
* @param general Message pattern explaining the cause of the error.
|
||||
* @param args Arguments.
|
||||
*/
|
||||
protected MathIllegalArgumentException(Localizable specific,
|
||||
Localizable general,
|
||||
Object ... args) {
|
||||
public MathIllegalArgumentException(Localizable specific,
|
||||
Localizable general,
|
||||
Object ... args) {
|
||||
this.specific = specific;
|
||||
this.general = general;
|
||||
arguments = ArgUtils.flatten(args);
|
||||
|
@ -67,8 +67,8 @@ public class MathIllegalArgumentException extends IllegalArgumentException {
|
|||
* @param general Message pattern explaining the cause of the error.
|
||||
* @param args Arguments.
|
||||
*/
|
||||
protected MathIllegalArgumentException(Localizable general,
|
||||
Object ... args) {
|
||||
public MathIllegalArgumentException(Localizable general,
|
||||
Object ... args) {
|
||||
this(null, general, args);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,8 @@ import java.io.Serializable;
|
|||
public class RealPointValuePair implements Serializable {
|
||||
/** Serializable version identifier. */
|
||||
private static final long serialVersionUID = 1003888396256744753L;
|
||||
|
||||
/** Point coordinates. */
|
||||
private final double[] point;
|
||||
|
||||
/** Value of the objective function at the point. */
|
||||
private final double value;
|
||||
|
||||
|
@ -45,7 +43,7 @@ public class RealPointValuePair implements Serializable {
|
|||
*/
|
||||
public RealPointValuePair(final double[] point, final double value) {
|
||||
this.point = (point == null) ? null : point.clone();
|
||||
this.value = value;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** Build a point/objective function value pair.
|
||||
|
@ -60,7 +58,7 @@ public class RealPointValuePair implements Serializable {
|
|||
this.point = copyArray ?
|
||||
((point == null) ? null : point.clone()) :
|
||||
point;
|
||||
this.value = value;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** Get the point.
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
import org.apache.commons.math.exception.NotStrictlyPositiveException;
|
||||
import org.apache.commons.math.exception.DimensionMismatchException;
|
||||
import org.apache.commons.math.exception.ZeroException;
|
||||
import org.apache.commons.math.exception.OutOfRangeException;
|
||||
import org.apache.commons.math.exception.NullArgumentException;
|
||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math.optimization.RealPointValuePair;
|
||||
|
||||
/**
|
||||
* This class implements the simplex concept.
|
||||
* It is intended to be used in conjunction with {@link SimplexOptimizer}.
|
||||
* <br/>
|
||||
* The initial configuration of the simplex is set by the constructors
|
||||
* {@link #AbstractSimplex(double[])} or {@link #AbstractSimplex(double[][])}.
|
||||
* The other {@link #AbstractSimplex(int) constructor} will set all steps
|
||||
* to 1, thus building a default configuration from a unit hypercube.
|
||||
* <br/>
|
||||
* Users <em>must</em> call the {@link #build(double[]) build} method in order
|
||||
* to create the data structure that will be acted on by the other methods of
|
||||
* this class.
|
||||
*
|
||||
* @see SimplexOptimizer
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AbstractSimplex {
|
||||
/** Simplex. */
|
||||
private RealPointValuePair[] simplex;
|
||||
/** Start simplex configuration. */
|
||||
private double[][] startConfiguration;
|
||||
/** Simplex dimension (must be equal to {@code simplex.length - 1}). */
|
||||
private final int dimension;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* Build a unit hypercube.
|
||||
*
|
||||
* @param n Dimension of the simplex.
|
||||
*/
|
||||
protected AbstractSimplex(int n) {
|
||||
this(createUnitHypercubeSteps(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* The start configuration for simplex is built from a box parallel to
|
||||
* the canonical axes of the space. The simplex is the subset of vertices
|
||||
* of a box parallel to the canonical axes. It is built as the path followed
|
||||
* while traveling from one vertex of the box to the diagonally opposite
|
||||
* vertex moving only along the box edges. The first vertex of the box will
|
||||
* be located at the start point of the optimization.
|
||||
* As an example, in dimension 3 a simplex has 4 vertices. Setting the
|
||||
* steps to (1, 10, 2) and the start point to (1, 1, 1) would imply the
|
||||
* start simplex would be: { (1, 1, 1), (2, 1, 1), (2, 11, 1), (2, 11, 3) }.
|
||||
* The first vertex would be set to the start point at (1, 1, 1) and the
|
||||
* last vertex would be set to the diagonally opposite vertex at (2, 11, 3).
|
||||
*
|
||||
* @param steps Steps along the canonical axes representing box edges. They
|
||||
* may be negative but not zero.
|
||||
* @throws NullArgumentException if {@code steps} is {@code null}.
|
||||
* @throws ZeroException if one of the steps is zero.
|
||||
*/
|
||||
protected AbstractSimplex(final double[] steps) {
|
||||
if (steps == null) {
|
||||
throw new NullArgumentException();
|
||||
}
|
||||
if (steps.length == 0) {
|
||||
throw new ZeroException();
|
||||
}
|
||||
dimension = steps.length;
|
||||
|
||||
// Only the relative position of the n final vertices with respect
|
||||
// to the first one are stored.
|
||||
startConfiguration = new double[dimension][dimension];
|
||||
for (int i = 0; i < dimension; i++) {
|
||||
final double[] vertexI = startConfiguration[i];
|
||||
for (int j = 0; j < i + 1; j++) {
|
||||
if (steps[j] == 0) {
|
||||
throw new ZeroException(LocalizedFormats.EQUAL_VERTICES_IN_SIMPLEX);
|
||||
}
|
||||
System.arraycopy(steps, 0, vertexI, 0, j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The real initial simplex will be set up by moving the reference
|
||||
* simplex such that its first point is located at the start point of the
|
||||
* optimization.
|
||||
*
|
||||
* @param referenceSimplex Reference simplex.
|
||||
* @throws NotStrictlyPositiveException if the reference simplex does not
|
||||
* contain at least one point.
|
||||
* @throws DimensionMismatchException if there is a dimension mismatch
|
||||
* in the reference simplex.
|
||||
* @throws IllegalArgumentException if one of its vertices is duplicated.
|
||||
*/
|
||||
protected AbstractSimplex(final double[][] referenceSimplex) {
|
||||
if (referenceSimplex.length <= 0) {
|
||||
throw new NotStrictlyPositiveException(LocalizedFormats.SIMPLEX_NEED_ONE_POINT,
|
||||
referenceSimplex.length);
|
||||
}
|
||||
dimension = referenceSimplex.length - 1;
|
||||
|
||||
// Only the relative position of the n final vertices with respect
|
||||
// to the first one are stored.
|
||||
startConfiguration = new double[dimension][dimension];
|
||||
final double[] ref0 = referenceSimplex[0];
|
||||
|
||||
// Loop over vertices.
|
||||
for (int i = 0; i < referenceSimplex.length; i++) {
|
||||
final double[] refI = referenceSimplex[i];
|
||||
|
||||
// Safety checks.
|
||||
if (refI.length != dimension) {
|
||||
throw new DimensionMismatchException(refI.length, dimension);
|
||||
}
|
||||
for (int j = 0; j < i; j++) {
|
||||
final double[] refJ = referenceSimplex[j];
|
||||
boolean allEquals = true;
|
||||
for (int k = 0; k < dimension; k++) {
|
||||
if (refI[k] != refJ[k]) {
|
||||
allEquals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allEquals) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.EQUAL_VERTICES_IN_SIMPLEX,
|
||||
i, j);
|
||||
}
|
||||
}
|
||||
|
||||
// Store vertex i position relative to vertex 0 position.
|
||||
if (i > 0) {
|
||||
final double[] confI = startConfiguration[i - 1];
|
||||
for (int k = 0; k < dimension; k++) {
|
||||
confI[k] = refI[k] - ref0[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get simplex dimension.
|
||||
*
|
||||
* @return the dimension of the simplex.
|
||||
*/
|
||||
public int getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get simplex size.
|
||||
* After calling the {@link #build(double[]) build} method, this method will
|
||||
* will be equivalent to {@code getDimension() + 1}.
|
||||
*
|
||||
* @return the size of the simplex.
|
||||
*/
|
||||
public int getSize() {
|
||||
return simplex.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the next simplex of the algorithm.
|
||||
*
|
||||
* @param evaluationFunction Evaluation function.
|
||||
* @param comparator Comparator to use to sort simplex vertices from best
|
||||
* to worst.
|
||||
* @throws FunctionEvaluationException if the function cannot be evaluated
|
||||
* at some point.
|
||||
* @throws org.apache.commons.math.exception.TooManyEvaluationsException
|
||||
* if the algorithm fails to converge.
|
||||
*/
|
||||
public abstract void iterate(final MultivariateRealFunction evaluationFunction,
|
||||
final Comparator<RealPointValuePair> comparator)
|
||||
throws FunctionEvaluationException;
|
||||
|
||||
/**
|
||||
* Build an initial simplex.
|
||||
*
|
||||
* @param startPoint First point of the simplex.
|
||||
* @throws DimensionMismatchException if the start point does not match
|
||||
* simplex dimension.
|
||||
*/
|
||||
public void build(final double[] startPoint) {
|
||||
if (dimension != startPoint.length) {
|
||||
throw new DimensionMismatchException(dimension, startPoint.length);
|
||||
}
|
||||
|
||||
// Set first vertex.
|
||||
simplex = new RealPointValuePair[dimension + 1];
|
||||
simplex[0] = new RealPointValuePair(startPoint, Double.NaN);
|
||||
|
||||
// Set remaining vertices.
|
||||
for (int i = 0; i < dimension; i++) {
|
||||
final double[] confI = startConfiguration[i];
|
||||
final double[] vertexI = new double[dimension];
|
||||
for (int k = 0; k < dimension; k++) {
|
||||
vertexI[k] = startPoint[k] + confI[k];
|
||||
}
|
||||
simplex[i + 1] = new RealPointValuePair(vertexI, Double.NaN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate all the non-evaluated points of the simplex.
|
||||
*
|
||||
* @param evaluationFunction Evaluation function.
|
||||
* @param comparator Comparator to use to sort simplex vertices from best to worst.
|
||||
* @throws FunctionEvaluationException if no value can be computed for the parameters.
|
||||
* @throws org.apache.commons.math.exception.TooManyEvaluationsException
|
||||
* if the maximal number of evaluations is exceeded.
|
||||
*/
|
||||
public void evaluate(final MultivariateRealFunction evaluationFunction,
|
||||
final Comparator<RealPointValuePair> comparator)
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
// Evaluate the objective function at all non-evaluated simplex points.
|
||||
for (int i = 0; i < simplex.length; i++) {
|
||||
final RealPointValuePair vertex = simplex[i];
|
||||
final double[] point = vertex.getPointRef();
|
||||
if (Double.isNaN(vertex.getValue())) {
|
||||
simplex[i] = new RealPointValuePair(point, evaluationFunction.value(point), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the simplex from best to worst.
|
||||
Arrays.sort(simplex, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the worst point of the simplex by a new point.
|
||||
*
|
||||
* @param pointValuePair Point to insert.
|
||||
* @param comparator Comparator to use for sorting the simplex vertices
|
||||
* from best to worst.
|
||||
*/
|
||||
protected void replaceWorstPoint(RealPointValuePair pointValuePair,
|
||||
final Comparator<RealPointValuePair> comparator) {
|
||||
for (int i = 0; i < dimension; i++) {
|
||||
if (comparator.compare(simplex[i], pointValuePair) > 0) {
|
||||
RealPointValuePair tmp = simplex[i];
|
||||
simplex[i] = pointValuePair;
|
||||
pointValuePair = tmp;
|
||||
}
|
||||
}
|
||||
simplex[dimension] = pointValuePair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the points of the simplex.
|
||||
*
|
||||
* @return all the simplex points.
|
||||
*/
|
||||
public RealPointValuePair[] getPoints() {
|
||||
final RealPointValuePair[] copy = new RealPointValuePair[simplex.length];
|
||||
System.arraycopy(simplex, 0, copy, 0, simplex.length);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the simplex point stored at the requested {@code index}.
|
||||
*
|
||||
* @param index Location.
|
||||
* @return the point at location {@code index}.
|
||||
*/
|
||||
public RealPointValuePair getPoint(int index) {
|
||||
if (index < 0 ||
|
||||
index >= simplex.length) {
|
||||
throw new OutOfRangeException(index, 0, simplex.length - 1);
|
||||
}
|
||||
return simplex[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new point at location {@code index}.
|
||||
* Note that no deep-copy of {@code point} is performed.
|
||||
*
|
||||
* @param index Location.
|
||||
* @param point New value.
|
||||
*/
|
||||
protected void setPoint(int index, RealPointValuePair point) {
|
||||
if (index < 0 ||
|
||||
index >= simplex.length) {
|
||||
throw new OutOfRangeException(index, 0, simplex.length - 1);
|
||||
}
|
||||
simplex[index] = point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all points.
|
||||
* Note that no deep-copy of {@code points} is performed.
|
||||
*
|
||||
* @param points New Points.
|
||||
*/
|
||||
protected void setPoints(RealPointValuePair[] points) {
|
||||
if (points.length != simplex.length) {
|
||||
throw new DimensionMismatchException(points.length, simplex.length);
|
||||
}
|
||||
simplex = points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create steps for a unit hypercube.
|
||||
*
|
||||
* @param n Dimension of the hypercube.
|
||||
* @return unit steps.
|
||||
*/
|
||||
private static double[] createUnitHypercubeSteps(int n) {
|
||||
final double[] steps = new double[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
steps[i] = 1;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
}
|
|
@ -80,6 +80,7 @@ import org.apache.commons.math.optimization.SimpleScalarValueChecker;
|
|||
* @see MultiDirectional
|
||||
* @version $Revision$ $Date$
|
||||
* @since 1.2
|
||||
* @deprecated in 2.2 (to be removed in 3.0). Please use {@link SimplexOptimizer} instead.
|
||||
*/
|
||||
public abstract class DirectSearchOptimizer
|
||||
extends BaseAbstractScalarOptimizer<MultivariateRealFunction> {
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.commons.math.optimization.MultivariateRealOptimizer;
|
|||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @see NelderMead
|
||||
* @deprecated in 2.2 (to be removed in 3.0). Please use {@link MultiDirectionalSimplex} instead.
|
||||
* @since 1.2
|
||||
*/
|
||||
public class MultiDirectional extends DirectSearchOptimizer
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
import org.apache.commons.math.optimization.RealPointValuePair;
|
||||
|
||||
/**
|
||||
* This class implements the multi-directional direct search method.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class MultiDirectionalSimplex extends AbstractSimplex {
|
||||
/** Default value for {@link #khi}: {@value}. */
|
||||
private static final double DEFAULT_KHI = 2;
|
||||
/** Default value for {@link #gamma}: {@value}. */
|
||||
private static final double DEFAULT_GAMMA = 0.5;
|
||||
/** Expansion coefficient. */
|
||||
private final double khi;
|
||||
/** Contraction coefficient. */
|
||||
private final double gamma;
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with default coefficients.
|
||||
* The default values are 2.0 for khi and 0.5 for gamma.
|
||||
*
|
||||
* @param n Dimension of the simplex.
|
||||
*/
|
||||
public MultiDirectionalSimplex(final int n) {
|
||||
this(n, DEFAULT_KHI, DEFAULT_GAMMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with specified coefficients.
|
||||
*
|
||||
* @param n Dimension of the simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(int)}.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
*/
|
||||
public MultiDirectionalSimplex(final int n,
|
||||
final double khi, final double gamma) {
|
||||
super(n);
|
||||
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with default coefficients.
|
||||
* The default values are 2.0 for khi and 0.5 for gamma.
|
||||
*
|
||||
* @param steps Steps along the canonical axes representing box edges.
|
||||
* They may be negative but not zero. See
|
||||
*/
|
||||
public MultiDirectionalSimplex(final double[] steps) {
|
||||
this(steps, DEFAULT_KHI, DEFAULT_GAMMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with specified coefficients.
|
||||
*
|
||||
* @param steps Steps along the canonical axes representing box edges.
|
||||
* They may be negative but not zero. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[])}.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
*/
|
||||
public MultiDirectionalSimplex(final double[] steps,
|
||||
final double khi, final double gamma) {
|
||||
super(steps);
|
||||
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with default coefficients.
|
||||
* The default values are 2.0 for khi and 0.5 for gamma.
|
||||
*
|
||||
* @param referenceSimplex Reference simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[][])}.
|
||||
*/
|
||||
public MultiDirectionalSimplex(final double[][] referenceSimplex) {
|
||||
this(referenceSimplex, DEFAULT_KHI, DEFAULT_GAMMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a multi-directional simplex with specified coefficients.
|
||||
*
|
||||
* @param referenceSimplex Reference simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[][])}.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
* @throws org.apache.commons.math.exception.NotStrictlyPositiveException
|
||||
* if the reference simplex does not contain at least one point.
|
||||
* @throws org.apache.commons.math.exception.DimensionMismatchException
|
||||
* if there is a dimension mismatch in the reference simplex.
|
||||
*/
|
||||
public MultiDirectionalSimplex(final double[][] referenceSimplex,
|
||||
final double khi, final double gamma) {
|
||||
super(referenceSimplex);
|
||||
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void iterate(final MultivariateRealFunction evaluationFunction,
|
||||
final Comparator<RealPointValuePair> comparator)
|
||||
throws FunctionEvaluationException {
|
||||
// Save the original simplex.
|
||||
final RealPointValuePair[] original = getPoints();
|
||||
final RealPointValuePair best = original[0];
|
||||
|
||||
// Perform a reflection step.
|
||||
final RealPointValuePair reflected = evaluateNewSimplex(evaluationFunction,
|
||||
original, 1, comparator);
|
||||
if (comparator.compare(reflected, best) < 0) {
|
||||
// Compute the expanded simplex.
|
||||
final RealPointValuePair[] reflectedSimplex = getPoints();
|
||||
final RealPointValuePair expanded = evaluateNewSimplex(evaluationFunction,
|
||||
original, khi, comparator);
|
||||
if (comparator.compare(reflected, expanded) <= 0) {
|
||||
// Keep the reflected simplex.
|
||||
setPoints(reflectedSimplex);
|
||||
}
|
||||
// Keep the expanded simplex.
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the contracted simplex.
|
||||
final RealPointValuePair contracted = evaluateNewSimplex(evaluationFunction,
|
||||
original, gamma, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and evaluate a new simplex.
|
||||
*
|
||||
* @param evaluationFunction Evaluation function.
|
||||
* @param original Original simplex (to be preserved).
|
||||
* @param coeff Linear coefficient.
|
||||
* @param comparator Comparator to use to sort simplex vertices from best
|
||||
* to poorest.
|
||||
* @return the best point in the transformed simplex.
|
||||
* @throws FunctionEvaluationException if the function cannot be
|
||||
* evaluated at some point.
|
||||
* @throws org.apache.commons.math.exception.TooManyEvaluationsException
|
||||
* if the maximal number of evaluations is exceeded.
|
||||
*/
|
||||
private RealPointValuePair evaluateNewSimplex(final MultivariateRealFunction evaluationFunction,
|
||||
final RealPointValuePair[] original,
|
||||
final double coeff,
|
||||
final Comparator<RealPointValuePair> comparator)
|
||||
throws FunctionEvaluationException {
|
||||
final double[] xSmallest = original[0].getPointRef();
|
||||
// Perform a linear transformation on all the simplex points,
|
||||
// except the first one.
|
||||
setPoint(0, original[0]);
|
||||
final int dim = getDimension();
|
||||
for (int i = 1; i < getSize(); i++) {
|
||||
final double[] xOriginal = original[i].getPointRef();
|
||||
final double[] xTransformed = new double[dim];
|
||||
for (int j = 0; j < dim; j++) {
|
||||
xTransformed[j] = xSmallest[j] + coeff * (xSmallest[j] - xOriginal[j]);
|
||||
}
|
||||
setPoint(i, new RealPointValuePair(xTransformed, Double.NaN, false));
|
||||
}
|
||||
|
||||
// Evaluate the simplex.
|
||||
evaluate(evaluationFunction, comparator);
|
||||
|
||||
return getPoint(0);
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.apache.commons.math.optimization.MultivariateRealOptimizer;
|
|||
* @version $Revision$ $Date$
|
||||
* @see MultiDirectional
|
||||
* @since 1.2
|
||||
* @deprecated in 2.2 (to be removed in 3.0). Please use {@link NelderMeadSimplex} instead.
|
||||
*/
|
||||
public class NelderMead extends DirectSearchOptimizer
|
||||
implements MultivariateRealOptimizer {
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.optimization.RealPointValuePair;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
|
||||
/**
|
||||
* This class implements the Nelder-Mead simplex algorithm.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class NelderMeadSimplex extends AbstractSimplex {
|
||||
/** Default value for {@link #rho}: {@value}. */
|
||||
private static final double DEFAULT_RHO = 1;
|
||||
/** Default value for {@link #khi}: {@value}. */
|
||||
private static final double DEFAULT_KHI = 2;
|
||||
/** Default value for {@link #gamma}: {@value}. */
|
||||
private static final double DEFAULT_GAMMA = 0.5;
|
||||
/** Default value for {@link #sigma}: {@value}. */
|
||||
private static final double DEFAULT_SIGMA = 0.5;
|
||||
/** Reflection coefficient. */
|
||||
private final double rho;
|
||||
/** Expansion coefficient. */
|
||||
private final double khi;
|
||||
/** Contraction coefficient. */
|
||||
private final double gamma;
|
||||
/** Shrinkage coefficient. */
|
||||
private final double sigma;
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with default coefficients.
|
||||
* The default coefficients are 1.0 for rho, 2.0 for khi and 0.5
|
||||
* for both gamma and sigma.
|
||||
*
|
||||
* @param n Dimension of the simplex.
|
||||
*/
|
||||
public NelderMeadSimplex(final int n) {
|
||||
this(n, DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with specified coefficients.
|
||||
*
|
||||
* @param n Dimension of the simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(int)}.
|
||||
* @param rho Reflection coefficient.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
* @param sigma Shrinkage coefficient.
|
||||
*/
|
||||
public NelderMeadSimplex(final int n,
|
||||
final double rho, final double khi,
|
||||
final double gamma, final double sigma) {
|
||||
super(n);
|
||||
|
||||
this.rho = rho;
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
this.sigma = sigma;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with default coefficients.
|
||||
* The default coefficients are 1.0 for rho, 2.0 for khi and 0.5
|
||||
* for both gamma and sigma.
|
||||
*
|
||||
* @param steps Steps along the canonical axes representing box edges.
|
||||
* They may be negative but not zero. See
|
||||
*/
|
||||
public NelderMeadSimplex(final double[] steps) {
|
||||
this(steps, DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with specified coefficients.
|
||||
*
|
||||
* @param steps Steps along the canonical axes representing box edges.
|
||||
* They may be negative but not zero. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[])}.
|
||||
* @param rho Reflection coefficient.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
* @param sigma Shrinkage coefficient.
|
||||
* @throws IllegalArgumentException if one of the steps is zero.
|
||||
*/
|
||||
public NelderMeadSimplex(final double[] steps,
|
||||
final double rho, final double khi,
|
||||
final double gamma, final double sigma) {
|
||||
super(steps);
|
||||
|
||||
this.rho = rho;
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
this.sigma = sigma;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with default coefficients.
|
||||
* The default coefficients are 1.0 for rho, 2.0 for khi and 0.5
|
||||
* for both gamma and sigma.
|
||||
*
|
||||
* @param referenceSimplex Reference simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[][])}.
|
||||
*/
|
||||
public NelderMeadSimplex(final double[][] referenceSimplex) {
|
||||
this(referenceSimplex, DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Nelder-Mead simplex with specified coefficients.
|
||||
*
|
||||
* @param referenceSimplex Reference simplex. See
|
||||
* {@link AbstractSimplex#AbstractSimplex(double[][])}.
|
||||
* @param rho Reflection coefficient.
|
||||
* @param khi Expansion coefficient.
|
||||
* @param gamma Contraction coefficient.
|
||||
* @param sigma Shrinkage coefficient.
|
||||
* @throws org.apache.commons.math.exception.NotStrictlyPositiveException
|
||||
* if the reference simplex does not contain at least one point.
|
||||
* @throws org.apache.commons.math.exception.DimensionMismatchException
|
||||
* if there is a dimension mismatch in the reference simplex.
|
||||
*/
|
||||
public NelderMeadSimplex(final double[][] referenceSimplex,
|
||||
final double rho, final double khi,
|
||||
final double gamma, final double sigma) {
|
||||
super(referenceSimplex);
|
||||
|
||||
this.rho = rho;
|
||||
this.khi = khi;
|
||||
this.gamma = gamma;
|
||||
this.sigma = sigma;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void iterate(final MultivariateRealFunction evaluationFunction,
|
||||
final Comparator<RealPointValuePair> comparator)
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
// The simplex has n + 1 points if dimension is n.
|
||||
final int n = getDimension();
|
||||
|
||||
// Interesting values.
|
||||
final RealPointValuePair best = getPoint(0);
|
||||
final RealPointValuePair secondBest = getPoint(n - 1);
|
||||
final RealPointValuePair worst = getPoint(n);
|
||||
final double[] xWorst = worst.getPointRef();
|
||||
|
||||
// Compute the centroid of the best vertices (dismissing the worst
|
||||
// point at index n).
|
||||
final double[] centroid = new double[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
final double[] x = getPoint(i).getPointRef();
|
||||
for (int j = 0; j < n; j++) {
|
||||
centroid[j] += x[j];
|
||||
}
|
||||
}
|
||||
final double scaling = 1.0 / n;
|
||||
for (int j = 0; j < n; j++) {
|
||||
centroid[j] *= scaling;
|
||||
}
|
||||
|
||||
// compute the reflection point
|
||||
final double[] xR = new double[n];
|
||||
for (int j = 0; j < n; j++) {
|
||||
xR[j] = centroid[j] + rho * (centroid[j] - xWorst[j]);
|
||||
}
|
||||
final RealPointValuePair reflected
|
||||
= new RealPointValuePair(xR, evaluationFunction.value(xR), false);
|
||||
|
||||
if (comparator.compare(best, reflected) <= 0 &&
|
||||
comparator.compare(reflected, secondBest) < 0) {
|
||||
// Accept the reflected point.
|
||||
replaceWorstPoint(reflected, comparator);
|
||||
} else if (comparator.compare(reflected, best) < 0) {
|
||||
// Compute the expansion point.
|
||||
final double[] xE = new double[n];
|
||||
for (int j = 0; j < n; j++) {
|
||||
xE[j] = centroid[j] + khi * (xR[j] - centroid[j]);
|
||||
}
|
||||
final RealPointValuePair expanded
|
||||
= new RealPointValuePair(xE, evaluationFunction.value(xE), false);
|
||||
|
||||
if (comparator.compare(expanded, reflected) < 0) {
|
||||
// Accept the expansion point.
|
||||
replaceWorstPoint(expanded, comparator);
|
||||
} else {
|
||||
// Accept the reflected point.
|
||||
replaceWorstPoint(reflected, comparator);
|
||||
}
|
||||
} else {
|
||||
if (comparator.compare(reflected, worst) < 0) {
|
||||
// Perform an outside contraction.
|
||||
final double[] xC = new double[n];
|
||||
for (int j = 0; j < n; j++) {
|
||||
xC[j] = centroid[j] + gamma * (xR[j] - centroid[j]);
|
||||
}
|
||||
final RealPointValuePair outContracted
|
||||
= new RealPointValuePair(xC, evaluationFunction.value(xC), false);
|
||||
if (comparator.compare(outContracted, reflected) <= 0) {
|
||||
// Accept the contraction point.
|
||||
replaceWorstPoint(outContracted, comparator);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Perform an inside contraction.
|
||||
final double[] xC = new double[n];
|
||||
for (int j = 0; j < n; j++) {
|
||||
xC[j] = centroid[j] - gamma * (centroid[j] - xWorst[j]);
|
||||
}
|
||||
final RealPointValuePair inContracted
|
||||
= new RealPointValuePair(xC, evaluationFunction.value(xC), false);
|
||||
|
||||
if (comparator.compare(inContracted, worst) < 0) {
|
||||
// Accept the contraction point.
|
||||
replaceWorstPoint(inContracted, comparator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a shrink.
|
||||
final double[] xSmallest = getPoint(0).getPointRef();
|
||||
for (int i = 1; i <= n; i++) {
|
||||
final double[] x = getPoint(i).getPoint();
|
||||
for (int j = 0; j < n; j++) {
|
||||
x[j] = xSmallest[j] + sigma * (x[j] - xSmallest[j]);
|
||||
}
|
||||
setPoint(i, new RealPointValuePair(x, Double.NaN, false));
|
||||
}
|
||||
evaluate(evaluationFunction, comparator);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
import org.apache.commons.math.exception.NullArgumentException;
|
||||
import org.apache.commons.math.optimization.GoalType;
|
||||
import org.apache.commons.math.optimization.ConvergenceChecker;
|
||||
import org.apache.commons.math.optimization.RealPointValuePair;
|
||||
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
|
||||
|
||||
/**
|
||||
* This class implements simplex-based direct search optimization.
|
||||
*
|
||||
* <p>
|
||||
* Direct search methods only use objective function values, they do
|
||||
* not need derivatives and don't either try to compute approximation
|
||||
* of the derivatives. According to a 1996 paper by Margaret H. Wright
|
||||
* (<a href="http://cm.bell-labs.com/cm/cs/doc/96/4-02.ps.gz">Direct
|
||||
* Search Methods: Once Scorned, Now Respectable</a>), they are used
|
||||
* when either the computation of the derivative is impossible (noisy
|
||||
* functions, unpredictable discontinuities) or difficult (complexity,
|
||||
* computation cost). In the first cases, rather than an optimum, a
|
||||
* <em>not too bad</em> point is desired. In the latter cases, an
|
||||
* optimum is desired but cannot be reasonably found. In all cases
|
||||
* direct search methods can be useful.
|
||||
* </p>
|
||||
* <p>
|
||||
* Simplex-based direct search methods are based on comparison of
|
||||
* the objective function values at the vertices of a simplex (which is a
|
||||
* set of n+1 points in dimension n) that is updated by the algorithms
|
||||
* steps.
|
||||
* <p>
|
||||
* <p>
|
||||
* The {@link #setSimplex(AbstractSimplex) setSimplex} method <em>must</em>
|
||||
* be called prior to calling the {@code optimize} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Each call to {@link #optimize(MultivariateRealFunction,GoalType,double[])
|
||||
* optimize} will re-use the start configuration of the current simplex and
|
||||
* move it such that its first vertex is at the provided start point of the
|
||||
* optimization. If the {@code optimize} method is called to solve a different
|
||||
* problem and the number of parameters change, the simplex must be
|
||||
* re-initialized to one with the appropriate dimensions.
|
||||
* </p>
|
||||
* <p>
|
||||
* If {@link #setConvergenceChecker(ConvergenceChecker)} is not called,
|
||||
* a default {@link SimpleScalarValueChecker} is used.
|
||||
* </p>
|
||||
* <p>
|
||||
* Convergence is checked by providing the <em>worst</em> points of
|
||||
* previous and current simplex to the convergence checker, not the best
|
||||
* ones.
|
||||
* </p>
|
||||
*
|
||||
* @see AbstractSimplex
|
||||
* @version $Revision$ $Date$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SimplexOptimizer
|
||||
extends BaseAbstractScalarOptimizer<MultivariateRealFunction> {
|
||||
/** Simplex. */
|
||||
private AbstractSimplex simplex;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public SimplexOptimizer() {
|
||||
setConvergenceChecker(new SimpleScalarValueChecker());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rel Relative threshold.
|
||||
* @param abs Absolute threshold.
|
||||
*/
|
||||
public SimplexOptimizer(double rel, double abs) {
|
||||
setConvergenceChecker(new SimpleScalarValueChecker(rel, abs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the simplex algorithm.
|
||||
*
|
||||
* @param simplex Simplex.
|
||||
*/
|
||||
public void setSimplex(AbstractSimplex simplex) {
|
||||
this.simplex = simplex;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected RealPointValuePair doOptimize()
|
||||
throws FunctionEvaluationException {
|
||||
if (simplex == null) {
|
||||
throw new NullArgumentException();
|
||||
}
|
||||
|
||||
// Indirect call to "computeObjectiveValue" in order to update the
|
||||
// evaluations counter.
|
||||
final MultivariateRealFunction evalFunc
|
||||
= new MultivariateRealFunction() {
|
||||
public double value(double[] point)
|
||||
throws FunctionEvaluationException {
|
||||
return computeObjectiveValue(point);
|
||||
}
|
||||
};
|
||||
|
||||
final boolean isMinim = getGoalType() == GoalType.MINIMIZE;
|
||||
final Comparator<RealPointValuePair> comparator
|
||||
= new Comparator<RealPointValuePair>() {
|
||||
public int compare(final RealPointValuePair o1,
|
||||
final RealPointValuePair o2) {
|
||||
final double v1 = o1.getValue();
|
||||
final double v2 = o2.getValue();
|
||||
return isMinim ? Double.compare(v1, v2) : Double.compare(v2, v1);
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize search.
|
||||
simplex.build(getStartPoint());
|
||||
simplex.evaluate(evalFunc, comparator);
|
||||
|
||||
RealPointValuePair[] previous = null;
|
||||
int iteration = 0;
|
||||
final ConvergenceChecker<RealPointValuePair> checker = getConvergenceChecker();
|
||||
while (true) {
|
||||
if (iteration > 0) {
|
||||
boolean converged = true;
|
||||
for (int i = 0; i < simplex.getSize(); i++) {
|
||||
converged &= checker.converged(iteration, previous[i], simplex.getPoint(i));
|
||||
}
|
||||
if (converged) {
|
||||
// We have found an optimum.
|
||||
return simplex.getPoint(0);
|
||||
}
|
||||
}
|
||||
|
||||
// We still need to search.
|
||||
previous = simplex.getPoints();
|
||||
simplex.iterate(evalFunc, comparator);
|
||||
++iteration;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,13 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
If the output is not quite correct, check for invisible trailing spaces!
|
||||
-->
|
||||
<release version="3.0" date="TBD" description="TBD">
|
||||
<action dev="erans" type="fix" issue="MATH-428">
|
||||
Class "DirectSearchOptimizer" (and subclasses "NelderMead"
|
||||
and "MultiDirectional") was refactored into new classes:
|
||||
"SimplexOptimizer" and "AbstractSimplex" (and subclasses
|
||||
"NelderMeadSimplex" and "MultiDirectionalSimplex"). The old
|
||||
classes were deprecated and removed.
|
||||
</action>
|
||||
<action dev="erans" type="update" issue="MATH-425">
|
||||
Replaced old exceptions.
|
||||
</action>
|
||||
|
@ -86,43 +93,50 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
</release>
|
||||
<release version="2.2" date="TBD" description="TBD">
|
||||
<action dev="luc" type="fix" issue="MATH-429">
|
||||
Fixed k-means++ to add several strategies to deal with empty clusters that may appear
|
||||
during iterations
|
||||
Fixed k-means++ to add several strategies to deal with empty clusters that
|
||||
may appear during iterations.
|
||||
</action>
|
||||
<action dev="luc" type="update" issue="MATH-417">
|
||||
Improved Percentile performance by using a selection algorithm instead of a
|
||||
complete sort, and by allowing caching data array and pivots when several
|
||||
different percentiles are desired
|
||||
different percentiles are desired.
|
||||
</action>
|
||||
<action dev="luc" type="fix" issue="MATH-391">
|
||||
Fixed an error preventing zero length vectors to be built by some constructors
|
||||
Fixed an error preventing zero length vectors to be built by some constructors.
|
||||
</action>
|
||||
<action dev="luc" type="fix" issue="MATH-421">
|
||||
Fixed an error preventing ODE solvers to be restarted after they have been stopped by a discrete event
|
||||
Fixed an error preventing ODE solvers to be restarted after they have
|
||||
been stopped by a discrete event.
|
||||
</action>
|
||||
<action dev="luc" type="add" issue="MATH-419">
|
||||
Added new random number generators from the Well Equidistributed Long-period Linear (WELL).
|
||||
Added new random number generators from the Well Equidistributed
|
||||
Long-period Linear (WELL).
|
||||
</action>
|
||||
<action dev="psteitz" type="update" issue="MATH-409">
|
||||
Made intercept / no intercept configurable in multiple regression classes. By default, regression
|
||||
models are estimated with an intercept term. When the "noIntercept" property is set to
|
||||
true, regression models are estimated without intercepts.
|
||||
Made intercept / no intercept configurable in multiple regression
|
||||
classes. By default, regression models are estimated with an intercept
|
||||
term. When the "noIntercept" property is set to true, regression models
|
||||
are estimated without intercepts.
|
||||
</action>
|
||||
<action dev="luc" type="fix" issue="MATH-415">
|
||||
Fixed lost cause in MathRuntimeException.createInternalError. Note that the message is still the default
|
||||
message for internal errors asking to report a bug to commons-math JIRA tracker. In order to retrieve
|
||||
the message from the root cause, one has to get the cause itself by getCause().
|
||||
Fixed lost cause in MathRuntimeException.createInternalError. Note that
|
||||
the message is still the default message for internal errors asking to
|
||||
report a bug to commons-math JIRA tracker. In order to retrieve the
|
||||
message from the root cause, one has to get the cause itself by getCause().
|
||||
</action>
|
||||
<action dev="psteitz" type="fix" issue="MATH-411">
|
||||
Modified multiple regression newSample methods to ensure that by default in all cases,
|
||||
regression models are estimated with intercept terms. Prior to the fix for this issue,
|
||||
newXSampleData(double[][]), newSampleData(double[], double[][]) and
|
||||
newSampleData(double[], double[][], double[][]) all required columns of "1's" to be inserted
|
||||
into the x[][] arrays to create a model with an intercept term; while newSampleData(double[], int, int)
|
||||
created a model including an intercept term without requiring the unitary column. All methods have
|
||||
been changed to eliminate the need for users to add unitary columns to specify regression models.
|
||||
Users of OLSMultipleLinearRegression or GLSMultipleLinearRegression versions 2.0 or 2.1 should either
|
||||
verify that their code either does not use the first set of data loading methods above or set the noIntercept
|
||||
Modified multiple regression newSample methods to ensure that by default
|
||||
in all cases, regression models are estimated with intercept terms.
|
||||
Prior to the fix for this issue, newXSampleData(double[][]),
|
||||
newSampleData(double[], double[][]) and newSampleData(double[], double[][], double[][])
|
||||
all required columns of "1's" to be inserted into the x[][] arrays to
|
||||
create a model with an intercept term; while newSampleData(double[], int, int)
|
||||
created a model including an intercept term without requiring the
|
||||
unitary column. All methods have been changed to eliminate the need for
|
||||
users to add unitary columns to specify regression models.
|
||||
Users of OLSMultipleLinearRegression or GLSMultipleLinearRegression
|
||||
versions 2.0 or 2.1 should either verify that their code either does
|
||||
not use the first set of data loading methods above or set the noIntercept
|
||||
property on estimated models to get the previous behavior.
|
||||
</action>
|
||||
<action dev="luc" type="fix" issue="MATH-412" due-to="Bill Rossi">
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
import org.apache.commons.math.optimization.GoalType;
|
||||
import org.apache.commons.math.optimization.RealPointValuePair;
|
||||
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
|
||||
import org.apache.commons.math.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SimplexOptimizerMultiDirectionalTest {
|
||||
@Test
|
||||
public void testMinimizeMaximize() throws FunctionEvaluationException {
|
||||
// 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() {
|
||||
private static final long serialVersionUID = -7039124064449091152L;
|
||||
public double value(double[] variables) throws FunctionEvaluationException {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(1e-11, 1e-30);
|
||||
optimizer.setMaxEvaluations(200);
|
||||
optimizer.setSimplex(new MultiDirectionalSimplex(new double[] { 0.2, 0.2 }));
|
||||
RealPointValuePair optimum;
|
||||
|
||||
// minimization
|
||||
optimum = optimizer.optimize(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);
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 120);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 150);
|
||||
|
||||
optimum = optimizer.optimize(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);
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 120);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 150);
|
||||
|
||||
// maximization
|
||||
optimum = optimizer.optimize(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);
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 120);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 150);
|
||||
|
||||
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1e-15, 1e-30));
|
||||
optimum = optimizer.optimize(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);
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 180);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 220);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRosenbrock() throws FunctionEvaluationException {
|
||||
MultivariateRealFunction rosenbrock =
|
||||
new MultivariateRealFunction() {
|
||||
private static final long serialVersionUID = -9044950469615237490L;
|
||||
public double value(double[] x) throws FunctionEvaluationException {
|
||||
++count;
|
||||
double a = x[1] - x[0] * x[0];
|
||||
double b = 1.0 - x[0];
|
||||
return 100 * a * a + b * b;
|
||||
}
|
||||
};
|
||||
|
||||
count = 0;
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
|
||||
optimizer.setMaxEvaluations(100);
|
||||
optimizer.setSimplex(new MultiDirectionalSimplex(new double[][] {
|
||||
{ -1.2, 1.0 }, { 0.9, 1.2 } , { 3.5, -2.3 }
|
||||
}));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1 });
|
||||
|
||||
Assert.assertEquals(count, optimizer.getEvaluations());
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 50);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 100);
|
||||
Assert.assertTrue(optimum.getValue() > 1e-2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowell() throws FunctionEvaluationException {
|
||||
MultivariateRealFunction powell =
|
||||
new MultivariateRealFunction() {
|
||||
private static final long serialVersionUID = -832162886102041840L;
|
||||
public double value(double[] x) throws FunctionEvaluationException {
|
||||
++count;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
count = 0;
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
|
||||
optimizer.setMaxEvaluations(1000);
|
||||
optimizer.setSimplex(new MultiDirectionalSimplex(4));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3, -1, 0, 1 });
|
||||
Assert.assertEquals(count, optimizer.getEvaluations());
|
||||
Assert.assertTrue(optimizer.getEvaluations() > 800);
|
||||
Assert.assertTrue(optimizer.getEvaluations() < 900);
|
||||
Assert.assertTrue(optimum.getValue() > 1e-2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMath283() throws FunctionEvaluationException {
|
||||
// fails because MultiDirectional.iterateSimplex is looping forever
|
||||
// the while(true) should be replaced with a convergence check
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer();
|
||||
optimizer.setMaxEvaluations(1000);
|
||||
optimizer.setSimplex(new MultiDirectionalSimplex(2));
|
||||
final Gaussian2D function = new Gaussian2D(0, 0, 1);
|
||||
RealPointValuePair estimate = optimizer.optimize(function,
|
||||
GoalType.MAXIMIZE, function.getMaximumPosition());
|
||||
final double EPSILON = 1e-5;
|
||||
final double expectedMaximum = function.getMaximum();
|
||||
final double actualMaximum = estimate.getValue();
|
||||
Assert.assertEquals(expectedMaximum, actualMaximum, EPSILON);
|
||||
|
||||
final double[] expectedPosition = function.getMaximumPosition();
|
||||
final double[] actualPosition = estimate.getPoint();
|
||||
Assert.assertEquals(expectedPosition[0], actualPosition[0], EPSILON );
|
||||
Assert.assertEquals(expectedPosition[1], actualPosition[1], EPSILON );
|
||||
}
|
||||
|
||||
private static class Gaussian2D implements MultivariateRealFunction {
|
||||
private final double[] maximumPosition;
|
||||
private final double std;
|
||||
|
||||
public 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();
|
||||
}
|
||||
|
||||
public double value(double[] point) {
|
||||
final double x = point[0], y = point[1];
|
||||
final double twoS2 = 2.0 * std * std;
|
||||
return 1.0 / (twoS2 * FastMath.PI) * FastMath.exp(-(x * x + y * y) / twoS2);
|
||||
}
|
||||
}
|
||||
|
||||
private int count;
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* 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.math.optimization.direct;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.exception.TooManyEvaluationsException;
|
||||
import org.apache.commons.math.analysis.MultivariateRealFunction;
|
||||
import org.apache.commons.math.analysis.MultivariateVectorialFunction;
|
||||
import org.apache.commons.math.linear.Array2DRowRealMatrix;
|
||||
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.optimization.SimpleScalarValueChecker;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
|
||||
public class SimplexOptimizerNelderMeadTest {
|
||||
@Test
|
||||
public void testMinimizeMaximize()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
// 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() {
|
||||
private static final long serialVersionUID = -7039124064449091152L;
|
||||
public double value(double[] variables) throws FunctionEvaluationException {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
|
||||
optimizer.setMaxEvaluations(100);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(new double[] { 0.2, 0.2 }));
|
||||
RealPointValuePair optimum;
|
||||
|
||||
// minimization
|
||||
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { -3, 0 });
|
||||
assertEquals(xM, optimum.getPoint()[0], 2e-7);
|
||||
assertEquals(yP, optimum.getPoint()[1], 2e-5);
|
||||
assertEquals(valueXmYp, optimum.getValue(), 6e-12);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 90);
|
||||
|
||||
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { 1, 0 });
|
||||
assertEquals(xP, optimum.getPoint()[0], 5e-6);
|
||||
assertEquals(yM, optimum.getPoint()[1], 6e-6);
|
||||
assertEquals(valueXpYm, optimum.getValue(), 1e-11);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 90);
|
||||
|
||||
// maximization
|
||||
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { -3, 0 });
|
||||
assertEquals(xM, optimum.getPoint()[0], 1e-5);
|
||||
assertEquals(yM, optimum.getPoint()[1], 3e-6);
|
||||
assertEquals(valueXmYm, optimum.getValue(), 3e-12);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 90);
|
||||
|
||||
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { 1, 0 });
|
||||
assertEquals(xP, optimum.getPoint()[0], 4e-6);
|
||||
assertEquals(yP, optimum.getPoint()[1], 5e-6);
|
||||
assertEquals(valueXpYp, optimum.getValue(), 7e-12);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 90);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRosenbrock()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
Rosenbrock rosenbrock = new Rosenbrock();
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
|
||||
optimizer.setMaxEvaluations(100);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(new double[][] {
|
||||
{ -1.2, 1 }, { 0.9, 1.2 } , { 3.5, -2.3 }
|
||||
}));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1 });
|
||||
|
||||
assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
|
||||
assertTrue(optimizer.getEvaluations() > 40);
|
||||
assertTrue(optimizer.getEvaluations() < 50);
|
||||
assertTrue(optimum.getValue() < 8e-4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowell()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
Powell powell = new Powell();
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
|
||||
optimizer.setMaxEvaluations(200);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(4));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3, -1, 0, 1 });
|
||||
assertEquals(powell.getCount(), optimizer.getEvaluations());
|
||||
assertTrue(optimizer.getEvaluations() > 110);
|
||||
assertTrue(optimizer.getEvaluations() < 130);
|
||||
assertTrue(optimum.getValue() < 2e-3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeastSquares1()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
final RealMatrix factors =
|
||||
new Array2DRowRealMatrix(new double[][] {
|
||||
{ 1, 0 },
|
||||
{ 0, 1 }
|
||||
}, false);
|
||||
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
|
||||
public double[] value(double[] variables) {
|
||||
return factors.operate(variables);
|
||||
}
|
||||
}, new double[] { 2.0, -3.0 });
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
|
||||
optimizer.setMaxEvaluations(200);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(2));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10, 10 });
|
||||
assertEquals( 2, optimum.getPointRef()[0], 3e-5);
|
||||
assertEquals(-3, optimum.getPointRef()[1], 4e-4);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 80);
|
||||
assertTrue(optimum.getValue() < 1.0e-6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeastSquares2()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
final RealMatrix factors =
|
||||
new Array2DRowRealMatrix(new double[][] {
|
||||
{ 1, 0 },
|
||||
{ 0, 1 }
|
||||
}, false);
|
||||
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
|
||||
public double[] value(double[] variables) {
|
||||
return factors.operate(variables);
|
||||
}
|
||||
}, new double[] { 2, -3 }, new double[] { 10, 0.1 });
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
|
||||
optimizer.setMaxEvaluations(200);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(2));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10, 10 });
|
||||
assertEquals( 2, optimum.getPointRef()[0], 5e-5);
|
||||
assertEquals(-3, optimum.getPointRef()[1], 8e-4);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 80);
|
||||
assertTrue(optimum.getValue() < 1e-6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeastSquares3()
|
||||
throws FunctionEvaluationException {
|
||||
|
||||
final RealMatrix factors =
|
||||
new Array2DRowRealMatrix(new double[][] {
|
||||
{ 1, 0 },
|
||||
{ 0, 1 }
|
||||
}, false);
|
||||
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
|
||||
public double[] value(double[] variables) {
|
||||
return factors.operate(variables);
|
||||
}
|
||||
}, new double[] { 2, -3 }, new Array2DRowRealMatrix(new double [][] {
|
||||
{ 1, 1.2 }, { 1.2, 2 }
|
||||
}));
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-6);
|
||||
optimizer.setMaxEvaluations(200);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(2));
|
||||
RealPointValuePair optimum =
|
||||
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10, 10 });
|
||||
assertEquals( 2, optimum.getPointRef()[0], 2e-3);
|
||||
assertEquals(-3, optimum.getPointRef()[1], 8e-4);
|
||||
assertTrue(optimizer.getEvaluations() > 60);
|
||||
assertTrue(optimizer.getEvaluations() < 80);
|
||||
assertTrue(optimum.getValue() < 1e-6);
|
||||
}
|
||||
|
||||
@Test(expected = TooManyEvaluationsException.class)
|
||||
public void testMaxIterations() throws FunctionEvaluationException {
|
||||
Powell powell = new Powell();
|
||||
SimplexOptimizer optimizer = new SimplexOptimizer(-1, 1e-3);
|
||||
optimizer.setMaxEvaluations(20);
|
||||
optimizer.setSimplex(new NelderMeadSimplex(4));
|
||||
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3, -1, 0, 1 });
|
||||
}
|
||||
|
||||
private static class Rosenbrock implements MultivariateRealFunction {
|
||||
private int count;
|
||||
|
||||
public Rosenbrock() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
public double value(double[] x) throws FunctionEvaluationException {
|
||||
++count;
|
||||
double a = x[1] - x[0] * x[0];
|
||||
double b = 1.0 - x[0];
|
||||
return 100 * a * a + b * b;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Powell implements MultivariateRealFunction {
|
||||
private int count;
|
||||
|
||||
public Powell() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
public double value(double[] x) throws FunctionEvaluationException {
|
||||
++count;
|
||||
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;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue