separated iteration counter from function evaluation counters,

some optimizers are based on gradient/jacobian only and cannot
reliably be protected by monitoring the objective function calls.

We now have two or three counters for each algorithm:
 - iteration counter, which is checked against a max allowance
   to prevent infinite loops if no convergence is reached
 - objective function evaluations, for user information only
 - objective function gradient/jacobian if the function is
   differentiable, for user information only

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@757181 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2009-03-22 13:00:00 +00:00
parent cfa4345431
commit 87c0ddbc6e
19 changed files with 293 additions and 218 deletions

View File

@ -118,8 +118,7 @@ public class MessagesResources_fr
{ "equals vertices {0} and {1} in simplex configuration",
"sommets {0} et {1} \u00e9gaux dans la configuration du simplex" },
// org.apache.commons.math.optimization.direct.DirectSearchOptimizer
// org.apache.commons.math.optimization.general.AbstractLeastSquaresOptimizer
// org.apache.commons.math.estimation.AbstractEstimation
{ "maximal number of evaluations exceeded ({0})",
"nombre maximal d''\u00e9valuations d\u00e9pass\u00e9 ({0})" },

View File

@ -38,16 +38,22 @@ import org.apache.commons.math.random.RandomVectorGenerator;
public class MultiStartScalarDifferentiableOptimizer implements ScalarDifferentiableOptimizer {
/** Serializable version identifier. */
private static final long serialVersionUID = 9008747186334431824L;
private static final long serialVersionUID = 6185821146433609962L;
/** Underlying classical optimizer. */
private final ScalarDifferentiableOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of gradient evaluations already performed for all starts. */
private int totalGradientEvaluations;
/** Number of starts to go. */
private int starts;
@ -69,12 +75,14 @@ public class MultiStartScalarDifferentiableOptimizer implements ScalarDifferenti
public MultiStartScalarDifferentiableOptimizer(final ScalarDifferentiableOptimizer optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.totalEvaluations = 0;
this.maxEvaluations = Integer.MAX_VALUE;
this.starts = starts;
this.generator = generator;
this.optima = null;
this.optimizer = optimizer;
this.maxIterations = Integer.MAX_VALUE;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.totalGradientEvaluations = 0;
this.starts = starts;
this.generator = generator;
this.optima = null;
}
/** Get all the optima found during the last call to {@link
@ -110,19 +118,29 @@ public class MultiStartScalarDifferentiableOptimizer implements ScalarDifferenti
return (ScalarPointValuePair[]) optima.clone();
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return totalIterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
public int getGradientEvaluations() {
return totalGradientEvaluations;
}
/** {@inheritDoc} */
@ -141,14 +159,16 @@ public class MultiStartScalarDifferentiableOptimizer implements ScalarDifferenti
double[] startPoint)
throws ObjectiveException, OptimizationException {
optima = new ScalarPointValuePair[starts];
totalEvaluations = 0;
optima = new ScalarPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
totalGradientEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optimizer.setMaxIterations(maxIterations - totalIterations);
optima[i] = optimizer.optimize(f, goalType,
(i == 0) ? startPoint : generator.nextVector());
} catch (ObjectiveException obe) {
@ -157,7 +177,9 @@ public class MultiStartScalarDifferentiableOptimizer implements ScalarDifferenti
optima[i] = null;
}
totalEvaluations += optimizer.getEvaluations();
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
totalGradientEvaluations += optimizer.getGradientEvaluations();
}

View File

@ -38,17 +38,20 @@ import org.apache.commons.math.random.RandomVectorGenerator;
public class MultiStartScalarOptimizer implements ScalarOptimizer {
/** Serializable version identifier. */
private static final long serialVersionUID = 6648351778723282863L;
private static final long serialVersionUID = -7333253288301713047L;
/** Underlying classical optimizer. */
private final ScalarOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of starts to go. */
private int starts;
@ -69,8 +72,9 @@ public class MultiStartScalarOptimizer implements ScalarOptimizer {
public MultiStartScalarOptimizer(final ScalarOptimizer optimizer, final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.maxIterations = Integer.MAX_VALUE;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.maxEvaluations = Integer.MAX_VALUE;
this.starts = starts;
this.generator = generator;
this.optima = null;
@ -109,21 +113,26 @@ public class MultiStartScalarOptimizer implements ScalarOptimizer {
return (ScalarPointValuePair[]) optima.clone();
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return totalIterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(ScalarConvergenceChecker checker) {
optimizer.setConvergenceChecker(checker);
@ -140,14 +149,15 @@ public class MultiStartScalarOptimizer implements ScalarOptimizer {
double[] startPoint)
throws ObjectiveException, OptimizationException {
optima = new ScalarPointValuePair[starts];
optima = new ScalarPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optimizer.setMaxIterations(maxIterations - totalIterations);
optima[i] = optimizer.optimize(f, goalType,
(i == 0) ? startPoint : generator.nextVector());
} catch (ObjectiveException obe) {
@ -156,6 +166,7 @@ public class MultiStartScalarOptimizer implements ScalarOptimizer {
optima[i] = null;
}
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
}

View File

@ -38,20 +38,23 @@ import org.apache.commons.math.random.RandomVectorGenerator;
public class MultiStartVectorialDifferentiableOptimizer implements VectorialDifferentiableOptimizer {
/** Serializable version identifier. */
private static final long serialVersionUID = -6671992853686531955L;
private static final long serialVersionUID = -9109278856437190136L;
/** Underlying classical optimizer. */
private final VectorialDifferentiableOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of jacobian evaluations already performed for all starts. */
private int totalJacobianEvaluations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of starts to go. */
private int starts;
@ -73,9 +76,10 @@ public class MultiStartVectorialDifferentiableOptimizer implements VectorialDiff
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.maxIterations = Integer.MAX_VALUE;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.totalJacobianEvaluations = 0;
this.maxEvaluations = Integer.MAX_VALUE;
this.starts = starts;
this.generator = generator;
this.optima = null;
@ -114,6 +118,21 @@ public class MultiStartVectorialDifferentiableOptimizer implements VectorialDiff
return (VectorialPointValuePair[]) optima.clone();
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return totalIterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
@ -124,16 +143,6 @@ public class MultiStartVectorialDifferentiableOptimizer implements VectorialDiff
return totalJacobianEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(VectorialConvergenceChecker checker) {
optimizer.setConvergenceChecker(checker);
@ -150,15 +159,16 @@ public class MultiStartVectorialDifferentiableOptimizer implements VectorialDiff
final double[] startPoint)
throws ObjectiveException, OptimizationException, IllegalArgumentException {
optima = new VectorialPointValuePair[starts];
totalEvaluations = 0;
optima = new VectorialPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
totalJacobianEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optimizer.setMaxIterations(maxIterations - totalIterations);
optima[i] = optimizer.optimize(f, target, weights,
(i == 0) ? startPoint : generator.nextVector());
} catch (ObjectiveException obe) {
@ -167,6 +177,7 @@ public class MultiStartVectorialDifferentiableOptimizer implements VectorialDiff
optima[i] = null;
}
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
totalJacobianEvaluations += optimizer.getJacobianEvaluations();

View File

@ -30,7 +30,7 @@ import org.apache.commons.math.ConvergenceException;
public class OptimizationException extends ConvergenceException {
/** Serializable version identifier. */
private static final long serialVersionUID = -781139167958631145L;
private static final long serialVersionUID = -357696069587075016L;
/**
* Simple constructor.
@ -42,4 +42,12 @@ public class OptimizationException extends ConvergenceException {
super(specifier, parts);
}
/**
* Create an exception with a given root cause.
* @param cause the exception or error that caused this exception to be thrown
*/
public OptimizationException(Throwable cause) {
super(cause);
}
}

View File

@ -29,38 +29,45 @@ import java.io.Serializable;
*/
public interface ScalarDifferentiableOptimizer extends Serializable {
/** Set the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @param maxEvaluations maximal number of function calls
* .
/** Set the maximal number of iterations of the algorithm.
* @param maxIterations maximal number of function calls
*/
void setMaxEvaluations(int maxEvaluations);
void setMaxIterations(int maxIterations);
/** Get the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @return maximal number of function calls
/** Get the maximal number of iterations of the algorithm.
* @return maximal number of iterations
*/
int getMaxEvaluations();
int getMaxIterations();
/** Get the number of iterations realized by the algorithm.
* <p>
* The number of evaluations corresponds to the last call to the
* {@link #optimize(ScalarDifferentiableObjectiveFunction, GoalType, double[]) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return number of iterations
*/
int getIterations();
/** Get the number of evaluations of the objective function.
* <p>
* The number of evaluation correspond to the last call to the
* {@link #optimize(ScalarObjectiveFunction, GoalType, double[]) optimize}
* The number of evaluations corresponds to the last call to the
* {@link #optimize(ScalarDifferentiableObjectiveFunction, GoalType, double[]) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return number of evaluations of the objective function
*/
int getEvaluations();
int getEvaluations();
/** Get the number of evaluations of the objective function gradient.
* <p>
* The number of evaluations corresponds to the last call to the
* {@link #optimize(ScalarDifferentiableObjectiveFunction, GoalType, double[]) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return number of evaluations of the objective function gradient
*/
int getGradientEvaluations();
/** Set the convergence checker.
* @param checker object to use to check for convergence

View File

@ -29,38 +29,35 @@ import java.io.Serializable;
*/
public interface ScalarOptimizer extends Serializable {
/** Set the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @param maxEvaluations maximal number of function calls
* .
/** Set the maximal number of iterations of the algorithm.
* @param maxIterations maximal number of function calls
*/
void setMaxEvaluations(int maxEvaluations);
void setMaxIterations(int maxIterations);
/** Get the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @return maximal number of function calls
/** Get the maximal number of iterations of the algorithm.
* @return maximal number of iterations
*/
int getMaxEvaluations();
int getMaxIterations();
/** Get the number of iterations realized by the algorithm.
* <p>
* The number of evaluations corresponds to the last call to the
* {@link #optimize(ScalarObjectiveFunction, GoalType, double[]) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return number of iterations
*/
int getIterations();
/** Get the number of evaluations of the objective function.
* <p>
* The number of evaluation correspond to the last call to the
* The number of evaluations corresponds to the last call to the
* {@link #optimize(ScalarObjectiveFunction, GoalType, double[]) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return number of evaluations of the objective function
*/
int getEvaluations();
int getEvaluations();
/** Set the convergence checker.
* @param checker object to use to check for convergence

View File

@ -29,28 +29,21 @@ import java.io.Serializable;
*/
public interface VectorialDifferentiableOptimizer extends Serializable {
/** Set the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @param maxEvaluations maximal number of function calls
/** Set the maximal number of iterations of the algorithm.
* @param maxIterations maximal number of function calls
* .
*/
void setMaxEvaluations(int maxEvaluations);
void setMaxIterations(int maxIterations);
/** Get the maximal number of objective function calls.
* <p>
* The number of objective function calls may be checked <em>after</em> a few
* related calls have been made. This implies that in some cases this number may
* be exceeded by a few units, depending on the dimension of the problem and kind
* of optimizer.
* </p>
* @return maximal number of function calls
/** Get the maximal number of iterations of the algorithm.
* @return maximal number of iterations
*/
int getMaxEvaluations();
int getMaxIterations();
/** Get the number of iterations realized by the algorithm.
* @return number of iterations
*/
int getIterations();
/** Get the number of evaluations of the objective function.
* <p>

View File

@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.optimization.ScalarConvergenceChecker;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.ObjectiveException;
@ -28,7 +29,7 @@ import org.apache.commons.math.optimization.ScalarObjectiveFunction;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.ScalarOptimizer;
import org.apache.commons.math.optimization.ScalarPointValuePair;
import org.apache.commons.math.optimization.SimpleValueChecker;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
/**
* This class implements simplex-based direct search optimization
@ -65,7 +66,7 @@ import org.apache.commons.math.optimization.SimpleValueChecker;
* will occur.</p>
*
* <p>If {@link #setConvergenceChecker(ScalarConvergenceChecker)} is not called,
* a default {@link SimpleValueChecker} is used.</p>
* 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>
@ -95,11 +96,14 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
/** Convergence checker. */
private ScalarConvergenceChecker checker;
/** Number of evaluations already performed for the current start. */
private int evaluations;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of iterations already performed. */
private int iterations;
/** Number of evaluations already performed. */
private int evaluations;
/** Start simplex configuration. */
private double[][] startConfiguration;
@ -107,8 +111,8 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
/** Simple constructor.
*/
protected DirectSearchOptimizer() {
setConvergenceChecker(new SimpleValueChecker());
setMaxEvaluations(Integer.MAX_VALUE);
setConvergenceChecker(new SimpleScalarValueChecker());
setMaxIterations(Integer.MAX_VALUE);
}
/** Set start configuration for simplex.
@ -208,13 +212,23 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return iterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations;
}
/** {@inheritDoc} */
@ -229,7 +243,7 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
/** {@inheritDoc} */
public ScalarPointValuePair optimize(final ScalarObjectiveFunction f, final GoalType goalType,
final double[] startPoint)
final double[] startPoint)
throws ObjectiveException, OptimizationException, IllegalArgumentException {
if (startConfiguration == null) {
@ -251,15 +265,15 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
};
// initialize search
iterations = 0;
evaluations = 0;
buildSimplex(startPoint);
evaluateSimplex(comparator);
ScalarPointValuePair[] previous = new ScalarPointValuePair[simplex.length];
int iterations = 0;
while (evaluations <= maxEvaluations) {
while (true) {
if (++iterations > 1) {
if (iterations > 0) {
boolean converged = true;
for (int i = 0; i < simplex.length; ++i) {
converged &= checker.converged(iterations, previous[i], simplex[i]);
@ -276,22 +290,24 @@ public abstract class DirectSearchOptimizer implements ScalarOptimizer {
}
throw new OptimizationException(
"maximal number of evaluations exceeded ({0})",
evaluations);
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations;
/** Increment the iterations counter by 1.
* @exception OptimizationException if the maximal number
* of iterations is exceeded
*/
protected void incrementIterationsCounter()
throws OptimizationException {
if (++iterations > maxIterations) {
throw new OptimizationException(new MaxIterationsExceededException(maxIterations));
}
}
/** Compute the next simplex of the algorithm.
* @param comparator comparator to use to sort simplex vertices from best to worst
* @exception ObjectiveException if the function cannot be evaluated at
* some point
* @exception OptimizationException if the algorithm failed to converge
* @exception OptimizationException if the algorithm fails to converge
* @exception IllegalArgumentException if the start point dimension is wrong
*/
protected abstract void iterateSimplex(final Comparator<ScalarPointValuePair> comparator)

View File

@ -62,8 +62,9 @@ public class MultiDirectional extends DirectSearchOptimizer {
protected void iterateSimplex(final Comparator<ScalarPointValuePair> comparator)
throws ObjectiveException, OptimizationException, IllegalArgumentException {
final int max = getMaxEvaluations();
while (getEvaluations() < max) {
while (true) {
incrementIterationsCounter();
// save the original vertex
final ScalarPointValuePair[] original = simplex;
@ -94,10 +95,6 @@ public class MultiDirectional extends DirectSearchOptimizer {
}
throw new OptimizationException(
"maximal number of evaluations exceeded ({0})",
getEvaluations());
}
/** Compute and evaluate a new simplex.

View File

@ -20,6 +20,7 @@ package org.apache.commons.math.optimization.direct;
import java.util.Comparator;
import org.apache.commons.math.optimization.ObjectiveException;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.ScalarPointValuePair;
/**
@ -73,7 +74,9 @@ public class NelderMead extends DirectSearchOptimizer {
/** {@inheritDoc} */
protected void iterateSimplex(final Comparator<ScalarPointValuePair> comparator)
throws ObjectiveException {
throws ObjectiveException, OptimizationException {
incrementIterationsCounter();
// the simplex has n+1 point if dimension is n
final int n = simplex.length - 1;

View File

@ -17,6 +17,7 @@
package org.apache.commons.math.optimization.general;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.linear.InvalidMatrixException;
import org.apache.commons.math.linear.MatrixUtils;
import org.apache.commons.math.linear.RealMatrix;
@ -40,20 +41,23 @@ import org.apache.commons.math.optimization.VectorialPointValuePair;
public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferentiableOptimizer {
/** Serializable version identifier */
private static final long serialVersionUID = -3080152374642370722L;
private static final long serialVersionUID = 5413193243329026789L;
/** Default maximal number of objective function evaluations allowed. */
public static final int DEFAULT_MAX_EVALUATIONS = 100;
/** Default maximal number of iterations allowed. */
public static final int DEFAULT_MAX_ITERATIONS = 100;
/** Number of evaluations already performed for the current start. */
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed. */
private int iterations;
/** Number of evaluations already performed. */
private int objectiveEvaluations;
/** Number of jacobian evaluations. */
private int jacobianEvaluations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Convergence checker. */
protected VectorialConvergenceChecker checker;
@ -99,17 +103,22 @@ public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferen
*/
protected AbstractLeastSquaresOptimizer() {
setConvergenceChecker(new SimpleVectorialValueChecker());
setMaxEvaluations(DEFAULT_MAX_EVALUATIONS);
setMaxIterations(DEFAULT_MAX_ITERATIONS);
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return iterations;
}
/** {@inheritDoc} */
@ -132,13 +141,26 @@ public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferen
return checker;
}
/** Increment the iterations counter by 1.
* @exception OptimizationException if the maximal number
* of iterations is exceeded
*/
protected void incrementIterationsCounter()
throws OptimizationException {
if (++iterations > maxIterations) {
if (++iterations > maxIterations) {
throw new OptimizationException(new MaxIterationsExceededException(maxIterations));
}
}
}
/**
* Update the jacobian matrix.
* @exception ObjectiveException if the function jacobian
* cannot be evaluated or its dimension doesn't match problem dimension
*/
protected void updateJacobian() throws ObjectiveException {
incrementJacobianEvaluationsCounter();
++jacobianEvaluations;
jacobian = f.jacobian(variables, objective);
if (jacobian.length != rows) {
throw new ObjectiveException("dimension mismatch {0} != {1}",
@ -153,28 +175,13 @@ public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferen
}
}
/**
* Increment the jacobian evaluations counter.
*/
protected final void incrementJacobianEvaluationsCounter() {
++jacobianEvaluations;
}
/**
* Update the residuals array and cost function value.
* @exception ObjectiveException if the function cannot be evaluated
* or its dimension doesn't match problem dimension
* @exception OptimizationException if the number of cost evaluations
* exceeds the maximum allowed
*/
protected void updateResidualsAndCost()
throws ObjectiveException, OptimizationException {
if (++objectiveEvaluations > maxEvaluations) {
throw new OptimizationException(
"maximal number of evaluations exceeded ({0})",
objectiveEvaluations);
}
throws ObjectiveException {
objective = f.objective(variables);
if (objective.length != rows) {
@ -298,6 +305,7 @@ public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferen
}
// reset counters
iterations = 0;
objectiveEvaluations = 0;
jacobianEvaluations = 0;
@ -327,6 +335,6 @@ public abstract class AbstractLeastSquaresOptimizer implements VectorialDifferen
* @exception IllegalArgumentException if the start point dimension is wrong
*/
abstract protected VectorialPointValuePair doOptimize()
throws ObjectiveException, OptimizationException, IllegalArgumentException;
throws ObjectiveException, OptimizationException, IllegalArgumentException;
}

View File

@ -53,7 +53,7 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
/** Simple constructor with default settings.
* <p>The convergence check is set to a {@link SimpleVectorialValueChecker}
* and the maximal number of evaluation is set to
* {@link AbstractLeastSquaresOptimizer#DEFAULT_MAX_EVALUATIONS}.
* {@link AbstractLeastSquaresOptimizer#DEFAULT_MAX_ITERATIONS}.
* @param useLU if true, the normal equations will be solved using LU
* decomposition, otherwise they will be solved using QR decomposition
*/
@ -67,8 +67,9 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
// iterate until convergence is reached
VectorialPointValuePair current = null;
boolean converged = false;
for (int iteration = 1; ! converged; ++iteration) {
for (boolean converged = false; !converged;) {
incrementIterationsCounter();
// evaluate the objective function and its jacobian
VectorialPointValuePair previous = current;
@ -122,7 +123,7 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
// check convergence
if (previous != null) {
converged = checker.converged(++iteration, previous, current);
converged = checker.converged(getIterations(), previous, current);
}
}

View File

@ -146,7 +146,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
* <p>The default values for the algorithm settings are:
* <ul>
* <li>{@link #setInitialStepBoundFactor initial step bound factor}: 100.0</li>
* <li>{@link #setMaxCostEval maximal cost evaluations}: 1000</li>
* <li>{@link #setMaxIterations maximal iterations}: 1000</li>
* <li>{@link #setCostRelativeTolerance cost relative tolerance}: 1.0e-10</li>
* <li>{@link #setParRelativeTolerance parameters relative tolerance}: 1.0e-10</li>
* <li>{@link #setOrthoTolerance orthogonality tolerance}: 1.0e-10</li>
@ -156,7 +156,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
public LevenbergMarquardtOptimizer() {
// set up the superclass with a default max cost evaluations setting
setMaxEvaluations(1000);
setMaxIterations(1000);
// default values for the tuning parameters
setInitialStepBoundFactor(100.0);
@ -237,6 +237,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
boolean firstIteration = true;
while (true) {
incrementIterationsCounter();
// compute the Q.R. decomposition of the jacobian matrix
updateJacobian();
qrDecomposition();

View File

@ -27,7 +27,7 @@ import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.ObjectiveException;
import org.apache.commons.math.optimization.ScalarObjectiveFunction;
import org.apache.commons.math.optimization.ScalarPointValuePair;
import org.apache.commons.math.optimization.SimpleValueChecker;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
public class MultiDirectionalTest
extends TestCase {
@ -94,8 +94,8 @@ public class MultiDirectionalTest
};
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxEvaluations(200);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxIterations(200);
optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
ScalarPointValuePair optimum;
@ -147,8 +147,8 @@ public class MultiDirectionalTest
count = 0;
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleValueChecker(-1, 1.0e-3));
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
optimizer.setMaxIterations(100);
optimizer.setStartConfiguration(new double[][] {
{ -1.2, 1.0 }, { 0.9, 1.2 } , { 3.5, -2.3 }
});
@ -180,8 +180,8 @@ public class MultiDirectionalTest
count = 0;
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleValueChecker(-1.0, 1.0e-3));
optimizer.setMaxEvaluations(1000);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxIterations(1000);
ScalarPointValuePair optimum =
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
assertEquals(count, optimizer.getEvaluations());

View File

@ -27,7 +27,7 @@ import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.ObjectiveException;
import org.apache.commons.math.optimization.ScalarObjectiveFunction;
import org.apache.commons.math.optimization.ScalarPointValuePair;
import org.apache.commons.math.optimization.SimpleValueChecker;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
public class NelderMeadTest
extends TestCase {
@ -94,8 +94,8 @@ public class NelderMeadTest
};
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxIterations(100);
optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
ScalarPointValuePair optimum;
@ -147,8 +147,8 @@ public class NelderMeadTest
count = 0;
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleValueChecker(-1, 1.0e-3));
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
optimizer.setMaxIterations(100);
optimizer.setStartConfiguration(new double[][] {
{ -1.2, 1.0 }, { 0.9, 1.2 } , { 3.5, -2.3 }
});
@ -180,8 +180,8 @@ public class NelderMeadTest
count = 0;
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleValueChecker(-1.0, 1.0e-3));
optimizer.setMaxEvaluations(200);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxIterations(200);
ScalarPointValuePair optimum =
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
assertEquals(count, optimizer.getEvaluations());

View File

@ -106,7 +106,7 @@ extends TestCase {
LinearProblem problem =
new LinearProblem(new double[][] { { 2 } }, new double[] { 3 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1 }, new double[] { 0 });
@ -122,7 +122,7 @@ extends TestCase {
new double[] { 4.0, 6.0, 1.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 }, new double[] { 0, 0 });
@ -145,7 +145,7 @@ extends TestCase {
{ 0, 0, 0, 0, 0, 2 }
}, new double[] { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1, 1, 1, 1 },
@ -164,7 +164,7 @@ extends TestCase {
{ 0, -1, 1 }
}, new double[] { 1, 1, 1});
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 }, new double[] { 0, 0, 0 });
@ -187,7 +187,7 @@ extends TestCase {
}, new double[] { 2, -9, 2, 2, 1 + epsilon * epsilon, 2});
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1, 1, 1, 1 },
@ -210,7 +210,7 @@ extends TestCase {
{ -3, 0, -9 }
}, new double[] { 1, 1, 1 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 }, new double[] { 0, 0, 0 });
@ -230,7 +230,7 @@ extends TestCase {
{ 7.0, 5.0, 9.0, 10.0 }
}, new double[] { 32, 23, 33, 31 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum1 =
optimizer.optimize(problem1, problem1.target, new double[] { 1, 1, 1, 1 },
@ -267,7 +267,7 @@ extends TestCase {
}, new double[] { 7.0, 3.0, 5.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 },
@ -290,7 +290,7 @@ extends TestCase {
{ 0.0, 0.0, 0.0, -1.0, 1.0, 0.0 }
}, new double[] { 3.0, 12.0, -1.0, 7.0, 1.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1, 1, 1 },
@ -311,7 +311,7 @@ extends TestCase {
}, new double[] { 3.0, 1.0, 5.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 },
@ -330,7 +330,7 @@ extends TestCase {
}, new double[] { 3.0, 1.0, 4.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 }, new double[] { 1, 1 });
assertTrue(optimizer.getRMS() > 0.1);
@ -341,7 +341,7 @@ extends TestCase {
LinearProblem problem =
new LinearProblem(new double[][] { { 1, 0 }, { 0, 1 } }, new double[] { -1, 1 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
@ -382,7 +382,7 @@ extends TestCase {
circle.addPoint( 35.0, 15.0);
circle.addPoint( 45.0, 97.0);
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-15, 1.0e-15));
try {
optimizer.optimize(circle, new double[] { 0, 0, 0, 0, 0 },
@ -404,7 +404,7 @@ extends TestCase {
circle.addPoint( 35.0, 15.0);
circle.addPoint( 45.0, 97.0);
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-13, 1.0e-13));
VectorialPointValuePair optimum =
optimizer.optimize(circle, new double[] { 0, 0, 0, 0, 0 },
@ -458,7 +458,7 @@ extends TestCase {
circle.addPoint(points[i][0], points[i][1]);
}
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxEvaluations(100);
optimizer.setMaxIterations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(circle, target, weights, new double[] { -12, -12 });

View File

@ -379,7 +379,7 @@ public class LevenbergMarquardtOptimizerTest
try {
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
optimizer.setInitialStepBoundFactor(initialStepBoundFactor);
optimizer.setMaxEvaluations(maxCostEval);
optimizer.setMaxIterations(maxCostEval);
optimizer.setCostRelativeTolerance(costRelativeTolerance);
optimizer.setParRelativeTolerance(parRelativeTolerance);
optimizer.setOrthoTolerance(orthoTolerance);

View File

@ -219,7 +219,7 @@ public class MinpackTest extends TestCase {
0.188053165007911,
0.122430604321144,
0.134575665392506
}), true);
}), false);
}
public void testMinpackMeyer()
@ -505,7 +505,7 @@ public class MinpackTest extends TestCase {
private void minpackTest(MinpackFunction function, boolean exceptionExpected) {
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
optimizer.setMaxEvaluations(100 * (function.getN() + 1));
optimizer.setMaxIterations(100 * (function.getN() + 1));
optimizer.setCostRelativeTolerance(Math.sqrt(2.22044604926e-16));
optimizer.setParRelativeTolerance(Math.sqrt(2.22044604926e-16));
optimizer.setOrthoTolerance(2.22044604926e-16);