MATH-394, MATH-397, MATH-404

Overhaul of the "optimization" package.
Removed lots of duplicate code.
Removed methods referring to the concept of "iteration".
Removed interface methods to access the number of evaluations of the
gradient and Jacobian.
Removed all references to "OptimizationException" (replaced by
"ConvergenceException").
Javadoc comments updated.



git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@990792 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gilles Sadowski 2010-08-30 13:06:22 +00:00
parent 320194b3cb
commit a21faeae6e
59 changed files with 2636 additions and 2855 deletions

View File

@ -26,6 +26,8 @@ package org.apache.commons.math;
* @see ConvergenceException
* @version $Revision$ $Date$
* @since 2.0
* @deprecated in 2.2 (to be removed in 3.0). Please use
* {@link IterativeAlgorithm} instead.
*/
public interface ConvergingAlgorithm {

View File

@ -23,6 +23,7 @@ package org.apache.commons.math;
*
* @version $Revision$ $Date$
* @since 2.0
* @deprecated in 2.2 (to be removed in 3.0).
*/
public abstract class ConvergingAlgorithmImpl implements ConvergingAlgorithm {

View File

@ -0,0 +1,85 @@
/*
* 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;
import org.apache.commons.math.util.MathUtils;
/**
* Base class for all convergence checker implementations.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public abstract class AbstractConvergenceChecker<T>
implements ConvergenceChecker<T> {
/**
* Default relative threshold.
*/
private static final double DEFAULT_RELATIVE_THRESHOLD = 100 * MathUtils.EPSILON;
/**
* Default absolute threshold.
*/
private static final double DEFAULT_ABSOLUTE_THRESHOLD = 100 * MathUtils.SAFE_MIN;
/**
* Relative tolerance threshold.
*/
private final double relativeThreshold;
/**
* Absolute tolerance threshold.
*/
private final double absoluteThreshold;
/**
* Build an instance with default thresholds.
*/
public AbstractConvergenceChecker() {
this.relativeThreshold = DEFAULT_RELATIVE_THRESHOLD;
this.absoluteThreshold = DEFAULT_ABSOLUTE_THRESHOLD;
}
/**
* Build an instance with a specified thresholds.
*
* @param relativeThreshold relative tolerance threshold
* @param absoluteThreshold absolute tolerance threshold
*/
public AbstractConvergenceChecker(final double relativeThreshold,
final double absoluteThreshold) {
this.relativeThreshold = relativeThreshold;
this.absoluteThreshold = absoluteThreshold;
}
/**
* {@inheritDoc}
*/
public double getRelativeThreshold() {
return relativeThreshold;
}
/**
* {@inheritDoc}
*/
public double getAbsoluteThreshold() {
return absoluteThreshold;
}
/**
* {@inheritDoc}
*/
public abstract boolean converged(int iteration, T ... points);
}

View File

@ -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;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.MultivariateRealFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomVectorGenerator;
/**
* Base class for all implementations of a multi-start optimizer.
*
* This interface is mainly intended to enforce the internal coherence of
* Commons-Math. Users of the API are advised to base their code on
* {@link MultiStartMultivariateRealOptimizer} or on
* {@link MultiStartDifferentiableMultivariateRealOptimizer}.
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public class BaseMultiStartMultivariateRealOptimizer<FUNC extends MultivariateRealFunction>
implements BaseMultivariateRealOptimizer<FUNC> {
/** Underlying classical optimizer. */
private final BaseMultivariateRealOptimizer<FUNC> optimizer;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomVectorGenerator generator;
/** Found optima. */
private RealPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1.
* @param generator Random vector generator to use for restarts.
*/
protected BaseMultiStartMultivariateRealOptimizer(final BaseMultivariateRealOptimizer<FUNC> optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.starts = starts;
this.generator = generator;
}
/**
* Get all the optima found during the last call to {@link
* #optimize(FUNC,GoalType,double[]) optimize}.
* The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(FUNC,GoalType,double[])
* optimize} method returns the best point only. This method
* returns all the points found at the end of each starts,
* including the best one already returned by the {@link
* #optimize(FUNC,GoalType,double[]) optimize} method.
* <br/>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by and null elements
* corresponding to the runs that did not converge. This means all
* elements will be null if the {@link #optimize(FUNC,GoalType,double[])
* optimize} method did throw a {@link ConvergenceException}).
* This also means that if the first element is not {@code null}, it
* is the best point found across all starts.
*
* @return an array containing the optima.
* @throws MathIllegalStateException if {@link
* #optimize(FUNC,GoalType,double[]) optimize} has not been called.
*/
public RealPointValuePair[] getOptima() {
if (optima == null) {
throw new MathIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optima.clone();
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
optimizer.setMaxEvaluations(maxEvaluations);
}
/** {@inheritDoc} */
public void setConvergenceChecker(ConvergenceChecker<RealPointValuePair> checker) {
optimizer.setConvergenceChecker(checker);
}
/** {@inheritDoc} */
public ConvergenceChecker<RealPointValuePair> getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/**
* @param f Function to optimize.
* @param goal Goal type ({@link GoalType#MINIMIZE} or
* {@link GoalType#MAXIMIZE}).
* @param startPoint Start point.
*/
public RealPointValuePair optimize(final FUNC f,
final GoalType goal,
double[] startPoint)
throws FunctionEvaluationException {
optima = new RealPointValuePair[starts];
// Multi-start loop.
for (int i = 0; i < starts; ++i) {
try {
optima[i] = optimizer.optimize(f, goal,
(i == 0 ? startPoint :
generator.nextVector()));
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (ConvergenceException oe) {
optima[i] = null;
}
final int usedEvaluations = optimizer.getEvaluations();
optimizer.setMaxEvaluations(optimizer.getMaxEvaluations() - usedEvaluations);
totalEvaluations += usedEvaluations;
}
sortPairs(goal);
if (optima[0] == null) {
throw new ConvergenceException(LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// Return the found point given the best objective function value.
return optima[0];
}
/**
* Sort the optima from best to worst, followed by {@code null} elements.
*
* @param goal Goal type.
*/
private void sortPairs(final GoalType goal) {
Arrays.sort(optima, new Comparator<RealPointValuePair>() {
public int compare(final RealPointValuePair o1,
final RealPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : 1;
} else if (o2 == null) {
return -1;
}
final double v1 = o1.getValue();
final double v2 = o2.getValue();
return (goal == GoalType.MINIMIZE) ?
Double.compare(v1, v2) : Double.compare(v2, v1);
}
});
}
}

View File

@ -0,0 +1,202 @@
/*
* 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;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.MultivariateVectorialFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomVectorGenerator;
/**
* Base class for all implementations of a multi-start optimizer.
*
* This interface is mainly intended to enforce the internal coherence of
* Commons-Math. Users of the API are advised to base their code on
* {@link MultiStartDifferentiableMultivariateVectorialOptimizer}.
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public class BaseMultiStartMultivariateVectorialOptimizer<FUNC extends MultivariateVectorialFunction>
implements BaseMultivariateVectorialOptimizer<FUNC> {
/** Underlying classical optimizer. */
private final BaseMultivariateVectorialOptimizer<FUNC> optimizer;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomVectorGenerator generator;
/** Found optima. */
private VectorialPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1.
* @param generator Random vector generator to use for restarts.
*/
protected BaseMultiStartMultivariateVectorialOptimizer(final BaseMultivariateVectorialOptimizer<FUNC> optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.starts = starts;
this.generator = generator;
}
/**
* Get all the optima found during the last call to {@link
* #optimize(FUNC,double[],double[],double[]) optimize}.
* The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(FUNC,double[],double[],double[])
* optimize} method returns the best point only. This method
* returns all the points found at the end of each starts, including
* the best one already returned by the {@link
* #optimize(FUNC,double[],double[],double[]) optimize} method.
* <br/>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e. in ascending order if minimizing and in
* descending order if maximizing), followed by and null elements
* corresponding to the runs that did not converge. This means all
* elements will be null if the {@link
* #optimize(FUNC,double[],double[],double[]) optimize} method did
* throw a {@link ConvergenceException}). This also means that if
* the first element is not {@code null}, it is the best point found
* across all starts.
*
* @return array containing the optima
* @throws MathIllegalStateException if {@link
* #optimize(FUNC,double[],double[],double[]) optimize} has not been
* called.
*/
public VectorialPointValuePair[] getOptima() {
if (optima == null) {
throw new MathIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optima.clone();
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
optimizer.setMaxEvaluations(maxEvaluations);
}
/** {@inheritDoc} */
public void setConvergenceChecker(ConvergenceChecker<VectorialPointValuePair> checker) {
optimizer.setConvergenceChecker(checker);
}
/** {@inheritDoc} */
public ConvergenceChecker<VectorialPointValuePair> getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/**
* {@inheritDoc}
*/
public VectorialPointValuePair optimize(final FUNC f,
double[] target, double[] weights,
double[] startPoint)
throws FunctionEvaluationException {
optima = new VectorialPointValuePair[starts];
// Multi-start loop.
for (int i = 0; i < starts; ++i) {
try {
optima[i] = optimizer.optimize(f, target, weights,
(i == 0 ? startPoint :
generator.nextVector()));
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (ConvergenceException oe) {
optima[i] = null;
}
final int usedEvaluations = optimizer.getEvaluations();
optimizer.setMaxEvaluations(optimizer.getMaxEvaluations() - usedEvaluations);
totalEvaluations += usedEvaluations;
}
sortPairs(target, weights);
if (optima[0] == null) {
throw new ConvergenceException(LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// Return the found point given the best objective function value.
return optima[0];
}
/**
* Sort the optima from best to worst, followed by {@code null} elements.
*
* @param target Target value for the objective functions at optimum.
* @param weights Weights for the least-squares cost computation.
*/
private void sortPairs(final double[] target,
final double[] weights) {
Arrays.sort(optima, new Comparator<VectorialPointValuePair>() {
public int compare(final VectorialPointValuePair o1,
final VectorialPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : 1;
} else if (o2 == null) {
return -1;
}
return Double.compare(weightedResidual(o1), weightedResidual(o2));
}
private double weightedResidual(final VectorialPointValuePair pv) {
final double[] value = pv.getValueRef();
double sum = 0;
for (int i = 0; i < value.length; ++i) {
final double ri = value[i] - target[i];
sum += weights[i] * ri * ri;
}
return sum;
}
});
}
}

View File

@ -21,95 +21,36 @@ import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.MultivariateRealFunction;
/**
* Optimization algorithms find the input point set that either {@link GoalType
* maximize or minimize} an objective function.
* This interface is mainly intended to enforce the internal coherence of
* Commons-FastMath. Users of the API are advised to base their code on
* {@link MultivariateRealOptimizer} or on
* {@link DifferentiableMultivariateRealOptimizer}.
* @param <T> the type of the objective function to be optimized
* the following interfaces:
* <ul>
* <li>{@link org.apache.commons.math.optimization.MultivariateRealOptimizer}</li>
* <li>{@link org.apache.commons.math.optimization.DifferentiableMultivariateRealOptimizer}</li>
* </ul>
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @see MultivariateRealOptimizer
* @see DifferentiableMultivariateRealOptimizer
* @version $Revision$ $Date$
* @since 2.2
* @since 3.0
*/
public interface BaseMultivariateRealOptimizer<T extends MultivariateRealFunction> {
/**
* Set the maximal number of iterations of the algorithm.
*
* @param maxIterations Maximal number of algorithm iterations.
*/
void setMaxIterations(int maxIterations);
/**
* Get the maximal number of iterations of the algorithm.
*
* @return the maximal number of iterations.
*/
int getMaxIterations();
/**
* Set the maximal number of functions evaluations.
*
* @param maxEvaluations Maximal number of function evaluations.
*/
void setMaxEvaluations(int maxEvaluations);
/**
* Get the maximal number of functions evaluations.
*
* @return the maximal number of functions evaluations.
*/
int getMaxEvaluations();
/**
* Get the number of iterations realized by the algorithm.
* The number of iterations corresponds to the last call to the
* {@code optimize} method. It is 0 if the method has not been
* called yet.
*
* @return the number of iterations.
*/
int getIterations();
/**
* Get the number of evaluations of the objective function.
* The number of evaluations corresponds to the last call to the
* {@code optimize} method. It is 0 if the method has not been
* called yet.
*
* @return the number of evaluations of the objective function.
*/
int getEvaluations();
/**
* Set the convergence checker.
*
* @param checker Object to use to check for convergence.
*/
void setConvergenceChecker(RealConvergenceChecker checker);
/**
* Get the convergence checker.
*
* @return the object used to check for convergence.
*/
RealConvergenceChecker getConvergenceChecker();
public interface BaseMultivariateRealOptimizer<FUNC extends MultivariateRealFunction>
extends BaseOptimizer<RealPointValuePair> {
/**
* Optimize an objective function.
*
* @param f Objective function.
* @param goalType Type of optimization goal: either {@link GoalType#MAXIMIZE}
* or {@link GoalType#MINIMIZE}.
* @param goalType Type of optimization goal: either
* {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}.
* @param startPoint Start point for optimization.
* @return the point/value pair giving the optimal value for objective function.
* @throws FunctionEvaluationException if the objective function throws one during
* the search.
* @throws OptimizationException if the algorithm failed to converge.
* @throws IllegalArgumentException if the start point dimension is wrong.
* @return the point/value pair giving the optimal value for objective
* function.
* @throws FunctionEvaluationException if the objective function throws one
* during the search.
* @throws DimensionMismatchException if the start point dimension is wrong.
* @throws TooManyEvaluationsException if the maximal number of evaluations is
* exceeded.
*/
RealPointValuePair optimize(T f, GoalType goalType, double[] startPoint)
throws FunctionEvaluationException, OptimizationException;
RealPointValuePair optimize(FUNC f, GoalType goalType, double[] startPoint)
throws FunctionEvaluationException;
}

View File

@ -0,0 +1,59 @@
/*
* 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;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.MultivariateVectorialFunction;
/**
* This interface is mainly intended to enforce the internal coherence of
* Commons-Math. Users of the API are advised to base their code on
* the following interfaces:
* <ul>
* <li>{@link org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer}</li>
* </ul>
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public interface BaseMultivariateVectorialOptimizer<FUNC extends MultivariateVectorialFunction>
extends BaseOptimizer<VectorialPointValuePair> {
/**
* Optimize an objective function.
* Optimization is considered to be a weighted least-squares minimization.
* The cost function to be minimized is
* <code>&sum;weight<sub>i</sub>(objective<sub>i</sub> - target<sub>i</sub>)<sup>2</sup></code>
*
* @param f Objective function.
* @param target Target value for the objective functions at optimum.
* @param weight Weights for the least squares cost computation.
* @param startPoint Start point for optimization.
* @return the point/value pair giving the optimal value for objective
* function.
* @throws FunctionEvaluationException if the objective function throws one
* during the search.
* @throws DimensionMismatchException if the start point dimension is wrong.
* @throws TooManyEvaluationsException if the maximal number of evaluations is
* exceeded.
*/
VectorialPointValuePair optimize(FUNC f, double[] target, double[] weight,
double[] startPoint)
throws FunctionEvaluationException;
}

View File

@ -0,0 +1,77 @@
/*
* 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;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.MultivariateRealFunction;
/**
* This interface is mainly intended to enforce the internal coherence of
* Commons-Math. Users of the API are advised to base their code on
* the following interfaces:
* <ul>
* <li>{@link org.apache.commons.math.optimization.MultivariateRealOptimizer}</li>
* <li>{@link org.apache.commons.math.optimization.DifferentiableMultivariateRealOptimizer}</li>
* <li>{@link org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer}</li>
* <li>{@link org.apache.commons.math.optimization.univariate.UnivariateRealOptimizer}</li>
* </ul>
*
* @param <PAIR> Type of the point/objective pair.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public interface BaseOptimizer<PAIR> {
/**
* Set the maximal number of function evaluations.
*
* @param maxEvaluations Maximal number of function evaluations.
*/
void setMaxEvaluations(int maxEvaluations);
/**
* Get the maximal number of function evaluations.
*
* @return the maximal number of function evaluations.
*/
int getMaxEvaluations();
/**
* Get the number of evaluations of the objective function.
* The number of evaluations corresponds to the last call to the
* {@code optimize} method. It is 0 if the method has not been
* called yet.
*
* @return the number of evaluations of the objective function.
*/
int getEvaluations();
/**
* Set the convergence checker.
*
* @param checker Object to use to check for convergence.
*/
void setConvergenceChecker(ConvergenceChecker<PAIR> checker);
/**
* Get the convergence checker.
*
* @return the object used to check for convergence.
*/
ConvergenceChecker<PAIR> getConvergenceChecker();
}

View File

@ -0,0 +1,58 @@
/*
* 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;
/**
* This interface specifies how to check if an optimization algorithm has
* converged.
* Deciding if convergence has been reached is a problem-dependent issue. The
* user should provide a class implementing this interface to allow the
* optimization algorithm to stop its search according to the problem at hand.
*
* @param <PAIR> Type of the (point, objective value) pair.
*
* @see org.apache.commons.math.optimization.SimpleScalarValueChecker
* @see org.apache.commons.math.optimization.SimpleRealPointChecker
*
* @version $Revision$ $Date$
* @since 3.0
*/
public interface ConvergenceChecker<PAIR> {
/**
* Check if the optimization algorithm has converged.
*
* @param iteration Current iteration.
* @param points Data used for checking the convergence.
* @return {@code true} if the algorithm is considered to have converged.
*/
boolean converged(int iteration, PAIR ... points);
/**
* Get the relative tolerance.
*
* @return the relative threshold.
*/
double getRelativeThreshold();
/**
* Get the absolute tolerance.
*
* @return the absolute threshold.
*/
double getAbsoluteThreshold();
}

View File

@ -28,18 +28,9 @@ import org.apache.commons.math.analysis.DifferentiableMultivariateRealFunction;
*
* @see MultivariateRealOptimizer
* @see DifferentiableMultivariateVectorialOptimizer
*
* @version $Revision$ $Date$
* @since 2.0
*/
public interface DifferentiableMultivariateRealOptimizer
extends BaseMultivariateRealOptimizer<DifferentiableMultivariateRealFunction> {
/**
* Get the number of evaluations of the objective function gradient.
* The number of evaluations corresponds to the last call to the
* {@code optimize} method (see {@link BaseMultivariateRealOptimizer}).
* It is 0 if the method has not been called yet.
*
* @return the number of evaluations of the objective function gradient.
*/
int getGradientEvaluations();
}
extends BaseMultivariateRealOptimizer<DifferentiableMultivariateRealFunction> {}

View File

@ -21,94 +21,12 @@ import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
/**
* This interface represents an optimization algorithm for {@link DifferentiableMultivariateVectorialFunction
* vectorial differentiable objective functions}.
* <p>Optimization algorithms find the input point set that either {@link GoalType
* maximize or minimize} an objective function.</p>
* @see MultivariateRealOptimizer
* @see DifferentiableMultivariateRealOptimizer
* This interface represents an optimization algorithm for
* {@link DifferentiableMultivariateVectorialFunction vectorial differentiable
* objective functions}.
*
* @version $Revision$ $Date$
* @since 2.0
* @since 3.0
*/
public interface DifferentiableMultivariateVectorialOptimizer {
/** Set the maximal number of iterations of the algorithm.
* @param maxIterations maximal number of function calls
* .
*/
void setMaxIterations(int maxIterations);
/** Get the maximal number of iterations of the algorithm.
* @return maximal number of iterations
*/
int getMaxIterations();
/** Get the number of iterations realized by the algorithm.
* @return number of iterations
*/
int getIterations();
/** Set the maximal number of functions evaluations.
* @param maxEvaluations maximal number of function evaluations
*/
void setMaxEvaluations(int maxEvaluations);
/** Get the maximal number of functions evaluations.
* @return maximal number of functions evaluations
*/
int getMaxEvaluations();
/** Get the number of evaluations of the objective function.
* <p>
* The number of evaluation correspond to the last call to the
* {@link #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], 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();
/** Get the number of evaluations of the objective function jacobian .
* <p>
* The number of evaluation correspond to the last call to the
* {@link #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], double[]) optimize} method. It is 0 if
* the method has not been called yet.
* </p>
* @return number of evaluations of the objective function jacobian
*/
int getJacobianEvaluations();
/** Set the convergence checker.
* @param checker object to use to check for convergence
*/
void setConvergenceChecker(VectorialConvergenceChecker checker);
/** Get the convergence checker.
* @return object used to check for convergence
*/
VectorialConvergenceChecker getConvergenceChecker();
/** Optimizes an objective function.
* <p>
* Optimization is considered to be a weighted least-squares minimization.
* The cost function to be minimized is
* &sum;weight<sub>i</sub>(objective<sub>i</sub>-target<sub>i</sub>)<sup>2</sup>
* </p>
* @param f objective function
* @param target target value for the objective functions at optimum
* @param weights weight for the least squares cost computation
* @param startPoint the start point for optimization
* @return the point/value pair giving the optimal value for objective function
* @exception FunctionEvaluationException if the objective function throws one during
* the search
* @exception OptimizationException if the algorithm failed to converge
* @exception IllegalArgumentException if the start point dimension is wrong
*/
VectorialPointValuePair optimize(DifferentiableMultivariateVectorialFunction f,
double[] target, double[] weights,
double[] startPoint)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException;
}
public interface DifferentiableMultivariateVectorialOptimizer
extends BaseMultivariateVectorialOptimizer<DifferentiableMultivariateVectorialFunction> {}

View File

@ -21,208 +21,38 @@ import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.DifferentiableMultivariateRealFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomVectorGenerator;
/**
* Special implementation of the {@link DifferentiableMultivariateRealOptimizer} interface adding
* multi-start features to an existing optimizer.
* <p>
* Special implementation of the {@link DifferentiableMultivariateRealOptimizer}
* interface adding multi-start features to an existing optimizer.
*
* This class wraps a classical optimizer to use it several times in
* turn with different starting points in order to avoid being trapped
* into a local extremum when looking for a global one.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
*/
public class MultiStartDifferentiableMultivariateRealOptimizer
extends BaseMultiStartMultivariateRealOptimizer<DifferentiableMultivariateRealFunction>
implements DifferentiableMultivariateRealOptimizer {
/** Underlying classical optimizer. */
private final DifferentiableMultivariateRealOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of gradient evaluations already performed for all starts. */
private int totalGradientEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomVectorGenerator generator;
/** Found optima. */
private RealPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer
* @param optimizer single-start optimizer to wrap
* @param starts number of starts to perform (including the
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1
* @param generator random vector generator to use for restarts
* equal to 1.
* @param generator Random vector generator to use for restarts.
*/
public MultiStartDifferentiableMultivariateRealOptimizer(final DifferentiableMultivariateRealOptimizer optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.totalGradientEvaluations = 0;
this.starts = starts;
this.generator = generator;
this.optima = null;
setMaxIterations(Integer.MAX_VALUE);
setMaxEvaluations(Integer.MAX_VALUE);
super(optimizer, starts, generator);
}
/** Get all the optima found during the last call to {@link
* #optimize(DifferentiableMultivariateRealFunction, GoalType, double[])
* optimize}.
* <p>The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(DifferentiableMultivariateRealFunction,
* GoalType, double[]) optimize} method returns the best point only. This
* method returns all the points found at the end of each starts,
* including the best one already returned by the {@link
* #optimize(DifferentiableMultivariateRealFunction, GoalType, double[])
* optimize} method.
* </p>
* <p>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by and null elements
* corresponding to the runs that did not converge. This means all
* elements will be null if the {@link #optimize(DifferentiableMultivariateRealFunction,
* GoalType, double[]) optimize} method did throw a {@link
* org.apache.commons.math.ConvergenceException ConvergenceException}).
* This also means that if the first element is non null, it is the best
* point found across all starts.</p>
* @return array containing the optima
* @exception IllegalStateException if {@link #optimize(DifferentiableMultivariateRealFunction,
* GoalType, double[]) optimize} has not been called
*/
public RealPointValuePair[] getOptima() throws IllegalStateException {
if (optima == null) {
throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return 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 void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public int getGradientEvaluations() {
return totalGradientEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(RealConvergenceChecker checker) {
optimizer.setConvergenceChecker(checker);
}
/** {@inheritDoc} */
public RealConvergenceChecker getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/** {@inheritDoc} */
public RealPointValuePair optimize(final DifferentiableMultivariateRealFunction f,
final GoalType goalType,
double[] startPoint)
throws FunctionEvaluationException, OptimizationException {
optima = new RealPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
totalGradientEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxIterations(maxIterations - totalIterations);
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optima[i] = optimizer.optimize(f, goalType,
(i == 0) ? startPoint : generator.nextVector());
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (OptimizationException oe) {
optima[i] = null;
}
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
totalGradientEvaluations += optimizer.getGradientEvaluations();
}
// sort the optima from best to worst, followed by null elements
Arrays.sort(optima, new Comparator<RealPointValuePair>() {
public int compare(final RealPointValuePair o1, final RealPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : +1;
} else if (o2 == null) {
return -1;
}
final double v1 = o1.getValue();
final double v2 = o2.getValue();
return (goalType == GoalType.MINIMIZE) ?
Double.compare(v1, v2) : Double.compare(v2, v1);
}
});
if (optima[0] == null) {
throw new OptimizationException(
LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// return the found point given the best objective function value
return optima[0];
}
}

View File

@ -17,222 +17,36 @@
package org.apache.commons.math.optimization;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomVectorGenerator;
/**
* Special implementation of the {@link DifferentiableMultivariateVectorialOptimizer} interface adding
* multi-start features to an existing optimizer.
* <p>
* Special implementation of the {@link DifferentiableMultivariateVectorialOptimizer}
* interface addind multi-start features to an existing optimizer.
*
* This class wraps a classical optimizer to use it several times in
* turn with different starting points in order to avoid being trapped
* into a local extremum when looking for a global one.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
*/
public class MultiStartDifferentiableMultivariateVectorialOptimizer
extends BaseMultiStartMultivariateVectorialOptimizer<DifferentiableMultivariateVectorialFunction>
implements DifferentiableMultivariateVectorialOptimizer {
/** Serializable version identifier. */
private static final long serialVersionUID = 9206382258980561530L;
/** Underlying classical optimizer. */
private final DifferentiableMultivariateVectorialOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of jacobian evaluations already performed for all starts. */
private int totalJacobianEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomVectorGenerator generator;
/** Found optima. */
private VectorialPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer
* @param optimizer single-start optimizer to wrap
* @param starts number of starts to perform (including the
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1
* @param generator random vector generator to use for restarts
* equal to 1.
* @param generator Random vector generator to use for restarts.
*/
public MultiStartDifferentiableMultivariateVectorialOptimizer(
final DifferentiableMultivariateVectorialOptimizer optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.totalJacobianEvaluations = 0;
this.starts = starts;
this.generator = generator;
this.optima = null;
setMaxIterations(Integer.MAX_VALUE);
setMaxEvaluations(Integer.MAX_VALUE);
super(optimizer, starts, generator);
}
/** Get all the optima found during the last call to {@link
* #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], double[]) optimize}.
* <p>The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], double[]) optimize} method returns the
* best point only. This method returns all the points found at the
* end of each starts, including the best one already returned by the {@link
* #optimize(DifferentiableMultivariateVectorialFunction, double[],
* double[], double[]) optimize} method.
* </p>
* <p>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by and null elements
* corresponding to the runs that did not converge. This means all
* elements will be null if the {@link #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], double[]) optimize} method did throw a {@link
* org.apache.commons.math.ConvergenceException ConvergenceException}).
* This also means that if the first element is non null, it is the best
* point found across all starts.</p>
* @return array containing the optima
* @exception IllegalStateException if {@link #optimize(DifferentiableMultivariateVectorialFunction,
* double[], double[], double[]) optimize} has not been called
*/
public VectorialPointValuePair[] getOptima() throws IllegalStateException {
if (optima == null) {
throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return 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 void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public int getJacobianEvaluations() {
return totalJacobianEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(VectorialConvergenceChecker checker) {
optimizer.setConvergenceChecker(checker);
}
/** {@inheritDoc} */
public VectorialConvergenceChecker getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/** {@inheritDoc} */
public VectorialPointValuePair optimize(final DifferentiableMultivariateVectorialFunction f,
final double[] target, final double[] weights,
final double[] startPoint)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
optima = new VectorialPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
totalJacobianEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxIterations(maxIterations - totalIterations);
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optima[i] = optimizer.optimize(f, target, weights,
(i == 0) ? startPoint : generator.nextVector());
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (OptimizationException oe) {
optima[i] = null;
}
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
totalJacobianEvaluations += optimizer.getJacobianEvaluations();
}
// sort the optima from best to worst, followed by null elements
Arrays.sort(optima, new Comparator<VectorialPointValuePair>() {
public int compare(final VectorialPointValuePair o1, final VectorialPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : +1;
} else if (o2 == null) {
return -1;
}
return Double.compare(weightedResidual(o1), weightedResidual(o2));
}
private double weightedResidual(final VectorialPointValuePair pv) {
final double[] value = pv.getValueRef();
double sum = 0;
for (int i = 0; i < value.length; ++i) {
final double ri = value[i] - target[i];
sum += weights[i] * ri * ri;
}
return sum;
}
});
if (optima[0] == null) {
throw new OptimizationException(
LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// return the found point given the best objective function value
return optima[0];
}
}

View File

@ -17,200 +17,35 @@
package org.apache.commons.math.optimization;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.analysis.MultivariateRealFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomVectorGenerator;
/**
* Special implementation of the {@link MultivariateRealOptimizer} interface adding
* multi-start features to an existing optimizer.
* <p>
*
* This class wraps a classical optimizer to use it several times in
* turn with different starting points in order to avoid being trapped
* into a local extremum when looking for a global one.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
*/
public class MultiStartMultivariateRealOptimizer
extends BaseMultiStartMultivariateRealOptimizer<MultivariateRealFunction>
implements MultivariateRealOptimizer {
/** Underlying classical optimizer. */
private final MultivariateRealOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomVectorGenerator generator;
/** Found optima. */
private RealPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer
* @param optimizer single-start optimizer to wrap
* @param starts number of starts to perform (including the
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1
* @param generator random vector generator to use for restarts
* equal to 1.
* @param generator Random vector generator to use for restarts.
*/
public MultiStartMultivariateRealOptimizer(final MultivariateRealOptimizer optimizer,
final int starts,
final RandomVectorGenerator generator) {
this.optimizer = optimizer;
this.totalIterations = 0;
this.totalEvaluations = 0;
this.starts = starts;
this.generator = generator;
this.optima = null;
setMaxIterations(Integer.MAX_VALUE);
setMaxEvaluations(Integer.MAX_VALUE);
super(optimizer, starts, generator);
}
/** Get all the optima found during the last call to {@link
* #optimize(MultivariateRealFunction, GoalType, double[]) optimize}.
* <p>The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(MultivariateRealFunction, GoalType,
* double[]) optimize} method returns the best point only. This
* method returns all the points found at the end of each starts,
* including the best one already returned by the {@link
* #optimize(MultivariateRealFunction, GoalType, double[]) optimize}
* method.
* </p>
* <p>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by and null elements
* corresponding to the runs that did not converge. This means all
* elements will be null if the {@link #optimize(MultivariateRealFunction,
* GoalType, double[]) optimize} method did throw a {@link
* org.apache.commons.math.ConvergenceException ConvergenceException}).
* This also means that if the first element is non null, it is the best
* point found across all starts.</p>
* @return array containing the optima
* @exception IllegalStateException if {@link #optimize(MultivariateRealFunction,
* GoalType, double[]) optimize} has not been called
*/
public RealPointValuePair[] getOptima() throws IllegalStateException {
if (optima == null) {
throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optima.clone();
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getIterations() {
return totalIterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(RealConvergenceChecker checker) {
optimizer.setConvergenceChecker(checker);
}
/** {@inheritDoc} */
public RealConvergenceChecker getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/** {@inheritDoc} */
public RealPointValuePair optimize(final MultivariateRealFunction f,
final GoalType goalType,
double[] startPoint)
throws FunctionEvaluationException, OptimizationException {
optima = new RealPointValuePair[starts];
totalIterations = 0;
totalEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaxIterations(maxIterations - totalIterations);
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
optima[i] = optimizer.optimize(f, goalType,
(i == 0) ? startPoint : generator.nextVector());
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (OptimizationException oe) {
optima[i] = null;
}
totalIterations += optimizer.getIterations();
totalEvaluations += optimizer.getEvaluations();
}
// sort the optima from best to worst, followed by null elements
Arrays.sort(optima, new Comparator<RealPointValuePair>() {
public int compare(final RealPointValuePair o1, final RealPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : +1;
} else if (o2 == null) {
return -1;
}
final double v1 = o1.getValue();
final double v2 = o2.getValue();
return (goalType == GoalType.MINIMIZE) ?
Double.compare(v1, v2) : Double.compare(v2, v1);
}
});
if (optima[0] == null) {
throw new OptimizationException(
LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// return the found point given the best objective function value
return optima[0];
}
}

View File

@ -1,319 +0,0 @@
/*
* 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;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomGenerator;
import org.apache.commons.math.util.FastMath;
/**
* Special implementation of the {@link UnivariateRealOptimizer} interface adding
* multi-start features to an existing optimizer.
* <p>
* This class wraps a classical optimizer to use it several times in
* turn with different starting points in order to avoid being trapped
* into a local extremum when looking for a global one.
* </p>
* @version $Revision$ $Date$
* @since 2.0
*/
public class MultiStartUnivariateRealOptimizer implements UnivariateRealOptimizer {
/** Serializable version identifier. */
private static final long serialVersionUID = 5983375963110961019L;
/** Underlying classical optimizer. */
private final UnivariateRealOptimizer optimizer;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of iterations already performed for all starts. */
private int totalIterations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomGenerator generator;
/** Found optima. */
private double[] optima;
/** Found function values at optima. */
private double[] optimaValues;
/**
* Create a multi-start optimizer from a single-start optimizer
* @param optimizer single-start optimizer to wrap
* @param starts number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1
* @param generator random generator to use for restarts
*/
public MultiStartUnivariateRealOptimizer(final UnivariateRealOptimizer optimizer,
final int starts,
final RandomGenerator generator) {
this.optimizer = optimizer;
this.totalIterations = 0;
this.starts = starts;
this.generator = generator;
this.optima = null;
setMaximalIterationCount(Integer.MAX_VALUE);
setMaxEvaluations(Integer.MAX_VALUE);
}
/** {@inheritDoc} */
public double getFunctionValue() {
return optimaValues[0];
}
/** {@inheritDoc} */
public double getResult() {
return optima[0];
}
/** {@inheritDoc} */
public double getAbsoluteAccuracy() {
return optimizer.getAbsoluteAccuracy();
}
/** {@inheritDoc} */
public int getIterationCount() {
return totalIterations;
}
/** {@inheritDoc} */
public int getMaximalIterationCount() {
return maxIterations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public double getRelativeAccuracy() {
return optimizer.getRelativeAccuracy();
}
/** {@inheritDoc} */
public void resetAbsoluteAccuracy() {
optimizer.resetAbsoluteAccuracy();
}
/** {@inheritDoc} */
public void resetMaximalIterationCount() {
optimizer.resetMaximalIterationCount();
}
/** {@inheritDoc} */
public void resetRelativeAccuracy() {
optimizer.resetRelativeAccuracy();
}
/** {@inheritDoc} */
public void setAbsoluteAccuracy(double accuracy) {
optimizer.setAbsoluteAccuracy(accuracy);
}
/** {@inheritDoc} */
public void setMaximalIterationCount(int count) {
this.maxIterations = count;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public void setRelativeAccuracy(double accuracy) {
optimizer.setRelativeAccuracy(accuracy);
}
/** Get all the optima found during the last call to {@link
* #optimize(UnivariateRealFunction, GoalType, double, double) optimize}.
* <p>The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(UnivariateRealFunction, GoalType,
* double, double) optimize} method returns the best point only. This
* method returns all the points found at the end of each starts,
* including the best one already returned by the {@link
* #optimize(UnivariateRealFunction, GoalType, double, double) optimize}
* method.
* </p>
* <p>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by Double.NaN elements
* corresponding to the runs that did not converge. This means all
* elements will be NaN if the {@link #optimize(UnivariateRealFunction,
* GoalType, double, double) optimize} method did throw a {@link
* ConvergenceException ConvergenceException}). This also means that
* if the first element is not NaN, it is the best point found across
* all starts.</p>
* @return array containing the optima
* @exception IllegalStateException if {@link #optimize(UnivariateRealFunction,
* GoalType, double, double) optimize} has not been called
* @see #getOptimaValues()
*/
public double[] getOptima() throws IllegalStateException {
if (optima == null) {
throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optima.clone();
}
/** Get all the function values at optima found during the last call to {@link
* #optimize(UnivariateRealFunction, GoalType, double, double) optimize}.
* <p>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by Double.NaN elements
* corresponding to the runs that did not converge. This means all
* elements will be NaN if the {@link #optimize(UnivariateRealFunction,
* GoalType, double, double) optimize} method did throw a {@link
* ConvergenceException ConvergenceException}). This also means that
* if the first element is not NaN, it is the best point found across
* all starts.</p>
* @return array containing the optima
* @exception IllegalStateException if {@link #optimize(UnivariateRealFunction,
* GoalType, double, double) optimize} has not been called
* @see #getOptima()
*/
public double[] getOptimaValues() throws IllegalStateException {
if (optimaValues == null) {
throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optimaValues.clone();
}
/** {@inheritDoc} */
public double optimize(final UnivariateRealFunction f, final GoalType goalType,
final double min, final double max)
throws ConvergenceException,
FunctionEvaluationException {
optima = new double[starts];
optimaValues = new double[starts];
totalIterations = 0;
totalEvaluations = 0;
// multi-start loop
for (int i = 0; i < starts; ++i) {
try {
optimizer.setMaximalIterationCount(maxIterations - totalIterations);
optimizer.setMaxEvaluations(maxEvaluations - totalEvaluations);
final double bound1 = (i == 0) ? min : min + generator.nextDouble() * (max - min);
final double bound2 = (i == 0) ? max : min + generator.nextDouble() * (max - min);
optima[i] = optimizer.optimize(f, goalType,
FastMath.min(bound1, bound2),
FastMath.max(bound1, bound2));
optimaValues[i] = optimizer.getFunctionValue();
} catch (FunctionEvaluationException fee) {
optima[i] = Double.NaN;
optimaValues[i] = Double.NaN;
} catch (ConvergenceException ce) {
optima[i] = Double.NaN;
optimaValues[i] = Double.NaN;
}
totalIterations += optimizer.getIterationCount();
totalEvaluations += optimizer.getEvaluations();
}
// sort the optima from best to worst, followed by NaN elements
int lastNaN = optima.length;
for (int i = 0; i < lastNaN; ++i) {
if (Double.isNaN(optima[i])) {
optima[i] = optima[--lastNaN];
optima[lastNaN + 1] = Double.NaN;
optimaValues[i] = optimaValues[--lastNaN];
optimaValues[lastNaN + 1] = Double.NaN;
}
}
double currX = optima[0];
double currY = optimaValues[0];
for (int j = 1; j < lastNaN; ++j) {
final double prevY = currY;
currX = optima[j];
currY = optimaValues[j];
if ((goalType == GoalType.MAXIMIZE) ^ (currY < prevY)) {
// the current element should be inserted closer to the beginning
int i = j - 1;
double mIX = optima[i];
double mIY = optimaValues[i];
while ((i >= 0) && ((goalType == GoalType.MAXIMIZE) ^ (currY < mIY))) {
optima[i + 1] = mIX;
optimaValues[i + 1] = mIY;
if (i-- != 0) {
mIX = optima[i];
mIY = optimaValues[i];
} else {
mIX = Double.NaN;
mIY = Double.NaN;
}
}
optima[i + 1] = currX;
optimaValues[i + 1] = currY;
currX = optima[j];
currY = optimaValues[j];
}
}
if (Double.isNaN(optima[0])) {
throw new OptimizationException(
LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// return the found point given the best objective function value
return optima[0];
}
/** {@inheritDoc} */
public double optimize(final UnivariateRealFunction f, final GoalType goalType,
final double min, final double max, final double startValue)
throws ConvergenceException, FunctionEvaluationException {
return optimize(f, goalType, min, max);
}
}

View File

@ -24,6 +24,7 @@ import org.apache.commons.math.analysis.MultivariateRealFunction;
* scalar objective functions}.
* <p>Optimization algorithms find the input point set that either {@link GoalType
* maximize or minimize} an objective function.</p>
*
* @see DifferentiableMultivariateRealOptimizer
* @see DifferentiableMultivariateVectorialOptimizer
* @version $Revision$ $Date$

View File

@ -32,8 +32,8 @@ package org.apache.commons.math.optimization;
*
* @version $Revision$ $Date$
* @since 2.0
* @deprecated To be removed in 3.0.
*/
public interface RealConvergenceChecker {
/** Check if the optimization algorithm has converged considering the last points.

View File

@ -17,71 +17,81 @@
package org.apache.commons.math.optimization;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.exception.DimensionMismatchException;
/**
* Simple implementation of the {@link RealConvergenceChecker} interface using
* Simple implementation of the {@link ConvergenceChecker} interface using
* only point coordinates.
* <p>
*
* Convergence is considered to have been reached if either the relative
* difference between each point coordinate are smaller than a threshold
* or if either the absolute difference between the point coordinates are
* smaller than another threshold.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
* @since 3.0
*/
public class SimpleRealPointChecker implements RealConvergenceChecker {
/** Default relative threshold. */
private static final double DEFAULT_RELATIVE_THRESHOLD = 100 * MathUtils.EPSILON;
/** Default absolute threshold. */
private static final double DEFAULT_ABSOLUTE_THRESHOLD = 100 * MathUtils.SAFE_MIN;
/** Relative tolerance threshold. */
private final double relativeThreshold;
/** Absolute tolerance threshold. */
private final double absoluteThreshold;
/** Build an instance with default threshold.
public class SimpleRealPointChecker
extends AbstractConvergenceChecker<RealPointValuePair> {
/**
* Build an instance with default threshold.
*/
public SimpleRealPointChecker() {
this.relativeThreshold = DEFAULT_RELATIVE_THRESHOLD;
this.absoluteThreshold = DEFAULT_ABSOLUTE_THRESHOLD;
}
public SimpleRealPointChecker() {}
/** Build an instance with a specified threshold.
* <p>
/**
* Build an instance with specified thresholds.
* In order to perform only relative checks, the absolute tolerance
* must be set to a negative value. In order to perform only absolute
* checks, the relative tolerance must be set to a negative value.
* </p>
*
* @param relativeThreshold relative tolerance threshold
* @param absoluteThreshold absolute tolerance threshold
*/
public SimpleRealPointChecker(final double relativeThreshold,
final double absoluteThreshold) {
this.relativeThreshold = relativeThreshold;
this.absoluteThreshold = absoluteThreshold;
final double absoluteThreshold) {
super(relativeThreshold, absoluteThreshold);
}
/** {@inheritDoc} */
/**
* Check if the optimization algorithm has converged considering the
* last two points.
* This method may be called several time from the same algorithm
* iteration with different points. This can be detected by checking the
* iteration number at each call if needed. Each time this method is
* called, the previous and current point correspond to points with the
* same role at each iteration, so they can be compared. As an example,
* simplex-based algorithms call this method for all points of the simplex,
* not only for the best or worst ones.
*
* @param iteration Index of current iteration
* @param points Points used for checking convergence. The list must
* contain two elements:
* <ul>
* <li>the previous best point,</li>
* <li>the current best point.</li>
* </ul>
* @return {@code true} if the algorithm has converged.
* @throws DimensionMismatchException if the length of the {@code points}
* list is not equal to 2.
*/
public boolean converged(final int iteration,
final RealPointValuePair previous,
final RealPointValuePair current) {
final double[] p = previous.getPoint();
final double[] c = current.getPoint();
final RealPointValuePair ... points) {
if (points.length != 2) {
throw new DimensionMismatchException(points.length, 2);
}
final double[] p = points[0].getPoint();
final double[] c = points[1].getPoint();
for (int i = 0; i < p.length; ++i) {
final double difference = FastMath.abs(p[i] - c[i]);
final double size = FastMath.max(FastMath.abs(p[i]), FastMath.abs(c[i]));
if ((difference > (size * relativeThreshold)) && (difference > absoluteThreshold)) {
final double size = FastMath.max(FastMath.abs(p[i]), FastMath.abs(c[i]));
if (difference > size * getRelativeThreshold() &&
difference > getAbsoluteThreshold()) {
return false;
}
}
return true;
}
}

View File

@ -17,65 +17,76 @@
package org.apache.commons.math.optimization;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.exception.DimensionMismatchException;
/**
* Simple implementation of the {@link RealConvergenceChecker} interface using
* Simple implementation of the {@link ConvergenceChecker} interface using
* only objective function values.
* <p>
*
* Convergence is considered to have been reached if either the relative
* difference between the objective function values is smaller than a
* threshold or if either the absolute difference between the objective
* function values is smaller than another threshold.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
* @since 3.0
*/
public class SimpleScalarValueChecker implements RealConvergenceChecker {
/** Default relative threshold. */
private static final double DEFAULT_RELATIVE_THRESHOLD = 100 * MathUtils.EPSILON;
/** Default absolute threshold. */
private static final double DEFAULT_ABSOLUTE_THRESHOLD = 100 * MathUtils.SAFE_MIN;
/** Relative tolerance threshold. */
private final double relativeThreshold;
/** Absolute tolerance threshold. */
private final double absoluteThreshold;
/** Build an instance with default threshold.
public class SimpleScalarValueChecker
extends AbstractConvergenceChecker<RealPointValuePair> {
/**
* Build an instance with default thresholds.
*/
public SimpleScalarValueChecker() {
this.relativeThreshold = DEFAULT_RELATIVE_THRESHOLD;
this.absoluteThreshold = DEFAULT_ABSOLUTE_THRESHOLD;
}
public SimpleScalarValueChecker() {}
/** Build an instance with a specified threshold.
* <p>
/** Build an instance with specified thresholds.
*
* In order to perform only relative checks, the absolute tolerance
* must be set to a negative value. In order to perform only absolute
* checks, the relative tolerance must be set to a negative value.
* </p>
*
* @param relativeThreshold relative tolerance threshold
* @param absoluteThreshold absolute tolerance threshold
*/
public SimpleScalarValueChecker(final double relativeThreshold,
final double absoluteThreshold) {
this.relativeThreshold = relativeThreshold;
this.absoluteThreshold = absoluteThreshold;
super(relativeThreshold, absoluteThreshold);
}
/** {@inheritDoc} */
/**
* Check if the optimization algorithm has converged considering the
* last two points.
* This method may be called several time from the same algorithm
* iteration with different points. This can be detected by checking the
* iteration number at each call if needed. Each time this method is
* called, the previous and current point correspond to points with the
* same role at each iteration, so they can be compared. As an example,
* simplex-based algorithms call this method for all points of the simplex,
* not only for the best or worst ones.
*
* @param iteration Index of current iteration
* @param points Points used for checking convergence. The list must
* contain two elements:
* <ul>
* <li>the previous best point,</li>
* <li>the current best point.</li>
* </ul>
* @return {@code true} if the algorithm has converged.
* @throws DimensionMismatchException if the length of the {@code points}
* list is not equal to 2.
*/
public boolean converged(final int iteration,
final RealPointValuePair previous,
final RealPointValuePair current) {
final double p = previous.getValue();
final double c = current.getValue();
final RealPointValuePair ... points) {
if (points.length != 2) {
throw new DimensionMismatchException(points.length, 2);
}
final double p = points[0].getValue();
final double c = points[1].getValue();
final double difference = FastMath.abs(p - c);
final double size = FastMath.max(FastMath.abs(p), FastMath.abs(c));
return (difference <= (size * relativeThreshold)) || (difference <= absoluteThreshold);
final double size = FastMath.max(FastMath.abs(p), FastMath.abs(c));
return (difference <= size * getRelativeThreshold() ||
difference <= getAbsoluteThreshold());
}
}

View File

@ -17,74 +17,83 @@
package org.apache.commons.math.optimization;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.exception.DimensionMismatchException;
/**
* Simple implementation of the {@link VectorialConvergenceChecker} interface using
* Simple implementation of the {@link ConvergenceChecker} interface using
* only point coordinates.
* <p>
*
* Convergence is considered to have been reached if either the relative
* difference between each point coordinate are smaller than a threshold
* or if either the absolute difference between the point coordinates are
* smaller than another threshold.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
* @since 3.0
*/
public class SimpleVectorialPointChecker implements VectorialConvergenceChecker {
/** Default relative threshold. */
private static final double DEFAULT_RELATIVE_THRESHOLD = 100 * MathUtils.EPSILON;
/** Default absolute threshold. */
private static final double DEFAULT_ABSOLUTE_THRESHOLD = 100 * MathUtils.SAFE_MIN;
/** Relative tolerance threshold. */
private final double relativeThreshold;
/** Absolute tolerance threshold. */
private final double absoluteThreshold;
/** Build an instance with default threshold.
public class SimpleVectorialPointChecker
extends AbstractConvergenceChecker<VectorialPointValuePair> {
/**
* Build an instance with default threshold.
*/
public SimpleVectorialPointChecker() {
this.relativeThreshold = DEFAULT_RELATIVE_THRESHOLD;
this.absoluteThreshold = DEFAULT_ABSOLUTE_THRESHOLD;
}
public SimpleVectorialPointChecker() {}
/** Build an instance with a specified threshold.
* <p>
/**
* Build an instance with a specified threshold.
*
* In order to perform only relative checks, the absolute tolerance
* must be set to a negative value. In order to perform only absolute
* checks, the relative tolerance must be set to a negative value.
* </p>
*
* @param relativeThreshold relative tolerance threshold
* @param absoluteThreshold absolute tolerance threshold
*/
public SimpleVectorialPointChecker(final double relativeThreshold,
final double absoluteThreshold) {
this.relativeThreshold = relativeThreshold;
this.absoluteThreshold = absoluteThreshold;
super(relativeThreshold, absoluteThreshold);
}
/** {@inheritDoc} */
/**
* Check if the optimization algorithm has converged considering the
* last two points.
* This method may be called several time from the same algorithm
* iteration with different points. This can be detected by checking the
* iteration number at each call if needed. Each time this method is
* called, the previous and current point correspond to points with the
* same role at each iteration, so they can be compared. As an example,
* simplex-based algorithms call this method for all points of the simplex,
* not only for the best or worst ones.
*
* @param iteration Index of current iteration
* @param points Points used for checking convergence. The list must
* contain two elements:
* <ul>
* <li>the previous best point,</li>
* <li>the current best point.</li>
* </ul>
* @return {@code true} if the algorithm has converged.
* @throws DimensionMismatchException if the length of the {@code points}
* list is not equal to 2.
*/
public boolean converged(final int iteration,
final VectorialPointValuePair previous,
final VectorialPointValuePair current) {
final double[] p = previous.getPointRef();
final double[] c = current.getPointRef();
final VectorialPointValuePair ... points) {
if (points.length != 2) {
throw new DimensionMismatchException(points.length, 2);
}
final double[] p = points[0].getPointRef();
final double[] c = points[1].getPointRef();
for (int i = 0; i < p.length; ++i) {
final double pi = p[i];
final double ci = c[i];
final double difference = FastMath.abs(pi - ci);
final double size = FastMath.max(FastMath.abs(pi), FastMath.abs(ci));
if ((difference > (size * relativeThreshold)) &&
(difference > absoluteThreshold)) {
final double pi = p[i];
final double ci = c[i];
final double difference = Math.abs(pi - ci);
final double size = Math.max(Math.abs(pi), Math.abs(ci));
if (difference > size * getRelativeThreshold() &&
difference > getAbsoluteThreshold()) {
return false;
}
}
return true;
}
}

View File

@ -19,72 +19,82 @@ package org.apache.commons.math.optimization;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.exception.DimensionMismatchException;
/**
* Simple implementation of the {@link VectorialConvergenceChecker} interface using
* Simple implementation of the {@link ConvergenceChecker} interface using
* only objective function values.
* <p>
*
* Convergence is considered to have been reached if either the relative
* difference between the objective function values is smaller than a
* threshold or if either the absolute difference between the objective
* function values is smaller than another threshold for all vectors elements.
* </p>
*
* @version $Revision$ $Date$
* @since 2.0
* @since 3.0
*/
public class SimpleVectorialValueChecker implements VectorialConvergenceChecker {
/** Default relative threshold. */
private static final double DEFAULT_RELATIVE_THRESHOLD = 100 * MathUtils.EPSILON;
/** Default absolute threshold. */
private static final double DEFAULT_ABSOLUTE_THRESHOLD = 100 * MathUtils.SAFE_MIN;
/** Relative tolerance threshold. */
private final double relativeThreshold;
/** Absolute tolerance threshold. */
private final double absoluteThreshold;
/** Build an instance with default threshold.
public class SimpleVectorialValueChecker
extends AbstractConvergenceChecker<VectorialPointValuePair> {
/**
* Build an instance with default thresholds.
*/
public SimpleVectorialValueChecker() {
this.relativeThreshold = DEFAULT_RELATIVE_THRESHOLD;
this.absoluteThreshold = DEFAULT_ABSOLUTE_THRESHOLD;
}
public SimpleVectorialValueChecker() {}
/** Build an instance with a specified threshold.
* <p>
/**
* Build an instance with specified thresholds.
*
* In order to perform only relative checks, the absolute tolerance
* must be set to a negative value. In order to perform only absolute
* checks, the relative tolerance must be set to a negative value.
* </p>
*
* @param relativeThreshold relative tolerance threshold
* @param absoluteThreshold absolute tolerance threshold
*/
public SimpleVectorialValueChecker(final double relativeThreshold,
final double absoluteThreshold) {
this.relativeThreshold = relativeThreshold;
this.absoluteThreshold = absoluteThreshold;
super(relativeThreshold, absoluteThreshold);
}
/** {@inheritDoc} */
/**
* Check if the optimization algorithm has converged considering the
* last two points.
* This method may be called several time from the same algorithm
* iteration with different points. This can be detected by checking the
* iteration number at each call if needed. Each time this method is
* called, the previous and current point correspond to points with the
* same role at each iteration, so they can be compared. As an example,
* simplex-based algorithms call this method for all points of the simplex,
* not only for the best or worst ones.
*
* @param iteration Index of current iteration
* @param points Points used for checking convergence. The list must
* contain two elements:
* <ul>
* <li>the previous best point,</li>
* <li>the current best point.</li>
* </ul>
* @return {@code true} if the algorithm has converged.
* @throws DimensionMismatchException if the length of the {@code points}
* list is not equal to 2.
*/
public boolean converged(final int iteration,
final VectorialPointValuePair previous,
final VectorialPointValuePair current) {
final double[] p = previous.getValueRef();
final double[] c = current.getValueRef();
final VectorialPointValuePair ... points) {
if (points.length != 2) {
throw new DimensionMismatchException(points.length, 2);
}
final double[] p = points[0].getValueRef();
final double[] c = points[1].getValueRef();
for (int i = 0; i < p.length; ++i) {
final double pi = p[i];
final double ci = c[i];
final double difference = FastMath.abs(pi - ci);
final double size = FastMath.max(FastMath.abs(pi), FastMath.abs(ci));
if ((difference > (size * relativeThreshold)) &&
(difference > absoluteThreshold)) {
if (difference > size * getRelativeThreshold() &&
difference > getAbsoluteThreshold()) {
return false;
}
}
return true;
}
}

View File

@ -1,115 +0,0 @@
/*
* 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;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.ConvergingAlgorithm;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
/**
* Interface for (univariate real) optimization algorithms.
*
* @version $Revision$ $Date$
* @since 2.0
*/
public interface UnivariateRealOptimizer extends ConvergingAlgorithm {
/** Set the maximal number of functions evaluations.
* @param maxEvaluations maximal number of function evaluations
*/
void setMaxEvaluations(int maxEvaluations);
/** Get the maximal number of functions evaluations.
* @return the maximal number of functions evaluations.
*/
int getMaxEvaluations();
/** Get the number of evaluations of the objective function.
* <p>
* The number of evaluations corresponds to the last call to the
* {@link #optimize(UnivariateRealFunction, GoalType, double, double) optimize}
* method. It is 0 if the method has not been called yet.
* </p>
* @return the number of evaluations of the objective function.
*/
int getEvaluations();
/**
* Find an optimum in the given interval.
* <p>
* An optimizer may require that the interval brackets a single optimum.
* </p>
* @param f the function to optimize.
* @param goalType type of optimization goal: either {@link GoalType#MAXIMIZE}
* or {@link GoalType#MINIMIZE}.
* @param min the lower bound for the interval.
* @param max the upper bound for the interval.
* @return a value where the function is optimum.
* @throws ConvergenceException if the maximum iteration count is exceeded
* or the optimizer detects convergence problems otherwise.
* @throws FunctionEvaluationException if an error occurs evaluating the
* function.
* @throws IllegalArgumentException if min > max or the endpoints do not
* satisfy the requirements specified by the optimizer.
*/
double optimize(UnivariateRealFunction f, GoalType goalType,
double min, double max)
throws ConvergenceException, FunctionEvaluationException;
/**
* Find an optimum in the given interval, start at startValue.
* <p>
* An optimizer may require that the interval brackets a single optimum.
* </p>
* @param f the function to optimize.
* @param goalType type of optimization goal: either {@link GoalType#MAXIMIZE}
* or {@link GoalType#MINIMIZE}.
* @param min the lower bound for the interval.
* @param max the upper bound for the interval.
* @param startValue the start value to use.
* @return a value where the function is optimum.
* @throws ConvergenceException if the maximum iteration count is exceeded
* or the optimizer detects convergence problems otherwise.
* @throws FunctionEvaluationException if an error occurs evaluating the
* function.
* @throws IllegalArgumentException if min > max or the arguments do not
* satisfy the requirements specified by the optimizer.
*/
double optimize(UnivariateRealFunction f, GoalType goalType,
double min, double max, double startValue)
throws ConvergenceException, FunctionEvaluationException;
/**
* Get the result of the last run of the optimizer.
*
* @return the optimum.
* @throws IllegalStateException if there is no result available, either
* because no result was yet computed or the last attempt failed.
*/
double getResult();
/**
* Get the result of the last run of the optimizer.
*
* @return the value of the function at the optimum.
* @throws IllegalStateException if there is no result available, either
* because no result was yet computed or the last attempt failed.
*/
double getFunctionValue();
}

View File

@ -22,16 +22,19 @@ import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.util.Incrementor;
import org.apache.commons.math.analysis.MultivariateRealFunction;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.MultivariateRealOptimizer;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
import org.apache.commons.math.optimization.general.AbstractScalarOptimizer;
/**
* This class implements simplex-based direct search optimization
@ -67,7 +70,7 @@ import org.apache.commons.math.optimization.SimpleScalarValueChecker;
* change, the start configuration will be reset to a default one with the
* appropriate dimensions.</p>
*
* <p>If {@link #setConvergenceChecker(RealConvergenceChecker)} is not called,
* <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
@ -86,41 +89,24 @@ import org.apache.commons.math.optimization.SimpleScalarValueChecker;
* @version $Revision$ $Date$
* @since 1.2
*/
public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer {
public abstract class DirectSearchOptimizer
extends AbstractScalarOptimizer
implements MultivariateRealOptimizer {
/** Simplex. */
protected RealPointValuePair[] simplex;
/** Objective function. */
private MultivariateRealFunction f;
/** Convergence checker. */
private RealConvergenceChecker checker;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed. */
private int iterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed. */
private int evaluations;
/** Start simplex configuration. */
private double[][] startConfiguration;
/** Simple constructor.
/**
* Default constructor.
*/
protected DirectSearchOptimizer() {
setConvergenceChecker(new SimpleScalarValueChecker());
setMaxIterations(Integer.MAX_VALUE);
setMaxEvaluations(Integer.MAX_VALUE);
}
/** Set start configuration for simplex.
/**
* Set start configuration for simplex.
*
* <p>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
@ -132,9 +118,10 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
* 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).</p>
* @param steps steps along the canonical axes representing box edges,
* they may be negative but not null
* @exception IllegalArgumentException if one step is null
*
* @param steps Steps along the canonical axes representing box edges. They
* may be negative but not zero.
* @throws IllegalArgumentException if one step is zero.
*/
public void setStartConfiguration(final double[] steps)
throws IllegalArgumentException {
@ -154,14 +141,16 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
}
}
/** Set start configuration for simplex.
* <p>The real initial simplex will be set up by moving the reference
/**
* Set start configuration for simplex.
* 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.</p>
* @param referenceSimplex reference simplex
* @exception IllegalArgumentException if the reference simplex does not
* optimization.
*
* @param referenceSimplex Reference simplex.
* @throws IllegalArgumentException if the reference simplex does not
* contain at least one point, or if there is a dimension mismatch
* in the reference simplex or if one of its vertices is duplicated
* in the reference simplex or if one of its vertices is duplicated.
*/
public void setStartConfiguration(final double[][] referenceSimplex)
throws IllegalArgumentException {
@ -183,8 +172,7 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
// safety checks
if (refI.length != n) {
throw MathRuntimeException.createIllegalArgumentException(
LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, refI.length, n);
throw new DimensionMismatchException(refI.length, n);
}
for (int j = 0; j < i; ++j) {
final double[] refJ = referenceSimplex[j];
@ -208,92 +196,46 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
confI[k] = refI[k] - ref0[k];
}
}
}
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getIterations() {
return iterations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(RealConvergenceChecker convergenceChecker) {
this.checker = convergenceChecker;
}
/** {@inheritDoc} */
public RealConvergenceChecker getConvergenceChecker() {
return checker;
}
/** {@inheritDoc} */
public RealPointValuePair optimize(final MultivariateRealFunction function,
final GoalType goalType,
final double[] startPoint)
throws FunctionEvaluationException, OptimizationException,
IllegalArgumentException {
protected RealPointValuePair doOptimize()
throws FunctionEvaluationException {
final double[] startPoint = getStartPoint();
if ((startConfiguration == null) ||
(startConfiguration.length != startPoint.length)) {
// no initial configuration has been set up for simplex
// build a default one from a unit hypercube
// No initial configuration has been set up for simplex
// build a default one from a unit hypercube.
final double[] unit = new double[startPoint.length];
Arrays.fill(unit, 1.0);
setStartConfiguration(unit);
}
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);
}
};
this.f = function;
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 (goalType == GoalType.MINIMIZE) ?
Double.compare(v1, v2) : Double.compare(v2, v1);
}
};
// initialize search
iterations = 0;
evaluations = 0;
// Initialize search.
buildSimplex(startPoint);
evaluateSimplex(comparator);
RealPointValuePair[] previous = new RealPointValuePair[simplex.length];
int iteration = 0;
final ConvergenceChecker<RealPointValuePair> checker = getConvergenceChecker();
while (true) {
if (iterations > 0) {
if (iteration > 0) {
boolean converged = true;
for (int i = 0; i < simplex.length; ++i) {
converged &= checker.converged(iterations, previous[i], simplex[i]);
converged &= checker.converged(iteration, previous[i], simplex[i]);
}
if (converged) {
// we have found an optimum
@ -301,65 +243,37 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
}
}
// we still need to search
// We still need to search.
System.arraycopy(simplex, 0, previous, 0, simplex.length);
iterateSimplex(comparator);
}
}
/** 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));
++iteration;
}
}
/** Compute the next simplex of the algorithm.
* @param comparator comparator to use to sort simplex vertices from best to worst
* @exception FunctionEvaluationException if the function cannot be evaluated at
* some point
* @exception OptimizationException if the algorithm fails to converge
* @exception IllegalArgumentException if the start point dimension is wrong
/**
* Compute the next simplex of the algorithm.
*
* @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 TooManyEvaluationsException if the algorithm fails to converge.
* @throws DimensionMismatchException if the start point dimension is wrong.
*/
protected abstract void iterateSimplex(final Comparator<RealPointValuePair> comparator)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException;
throws FunctionEvaluationException;
/** Evaluate the objective function on one point.
* <p>A side effect of this method is to count the number of
* function evaluations</p>
* @param x point on which the objective function should be evaluated
* @return objective function value at the given point
* @exception FunctionEvaluationException if no value can be computed for the
* parameters or if the maximal number of evaluations is exceeded
* @exception IllegalArgumentException if the start point dimension is wrong
/**
* Build an initial simplex.
*
* @param startPoint Start point for optimization.
* @throws DimensionMismatchException if the start point does not match
* simplex dimension.
*/
protected double evaluate(final double[] x)
throws FunctionEvaluationException, IllegalArgumentException {
if (++evaluations > maxEvaluations) {
throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations),
x);
}
return f.value(x);
}
/** Build an initial simplex.
* @param startPoint the start point for optimization
* @exception IllegalArgumentException if the start point does not match
* simplex dimension
*/
private void buildSimplex(final double[] startPoint)
throws IllegalArgumentException {
private void buildSimplex(final double[] startPoint) {
final int n = startPoint.length;
if (n != startConfiguration.length) {
throw MathRuntimeException.createIllegalArgumentException(
LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, n, startConfiguration.length);
throw new DimensionMismatchException(n, startConfiguration.length);
}
// set first vertex
@ -368,41 +282,43 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
// set remaining vertices
for (int i = 0; i < n; ++i) {
final double[] confI = startConfiguration[i];
final double[] confI = startConfiguration[i];
final double[] vertexI = new double[n];
for (int k = 0; k < n; ++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 comparator comparator to use to sort simplex vertices from best to worst
* @exception FunctionEvaluationException if no value can be computed for the parameters
* @exception OptimizationException if the maximal number of evaluations is exceeded
/**
* Evaluate all the non-evaluated points of the simplex.
*
* @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 TooManyEvaluationsException if the maximal number of evaluations is exceeded.
*/
protected void evaluateSimplex(final Comparator<RealPointValuePair> comparator)
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
// evaluate the objective function at all non-evaluated simplex points
// 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, evaluate(point), false);
simplex[i] = new RealPointValuePair(point, computeObjectiveValue(point), false);
}
}
// sort the simplex from best to worst
// 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 to sort simplex vertices from best to worst
/**
* Replace the worst point of the simplex by a new point.
*
* @param pointValuePair Point to insert.
* @param comparator Comparator to use to sort simplex vertices from best to worst.
*/
protected void replaceWorstPoint(RealPointValuePair pointValuePair,
final Comparator<RealPointValuePair> comparator) {
@ -410,11 +326,10 @@ public abstract class DirectSearchOptimizer implements MultivariateRealOptimizer
for (int i = 0; i < n; ++i) {
if (comparator.compare(simplex[i], pointValuePair) > 0) {
RealPointValuePair tmp = simplex[i];
simplex[i] = pointValuePair;
pointValuePair = tmp;
simplex[i] = pointValuePair;
pointValuePair = tmp;
}
}
simplex[n] = pointValuePair;
}
}

View File

@ -20,8 +20,7 @@ package org.apache.commons.math.optimization.direct;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.RealPointValuePair;
/**
@ -59,72 +58,72 @@ public class MultiDirectional extends DirectSearchOptimizer {
/** {@inheritDoc} */
@Override
protected void iterateSimplex(final Comparator<RealPointValuePair> comparator)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
throws FunctionEvaluationException {
final RealConvergenceChecker checker = getConvergenceChecker();
final ConvergenceChecker<RealPointValuePair> checker = getConvergenceChecker();
int iteration = 0;
while (true) {
++iteration;
incrementIterationsCounter();
// save the original vertex
// Save the original vertex.
final RealPointValuePair[] original = simplex;
final RealPointValuePair best = original[0];
// perform a reflection step
// Perform a reflection step.
final RealPointValuePair reflected = evaluateNewSimplex(original, 1.0, comparator);
if (comparator.compare(reflected, best) < 0) {
// compute the expanded simplex
// Compute the expanded simplex.
final RealPointValuePair[] reflectedSimplex = simplex;
final RealPointValuePair expanded = evaluateNewSimplex(original, khi, comparator);
if (comparator.compare(reflected, expanded) <= 0) {
// accept the reflected simplex
// Accept the reflected simplex.
simplex = reflectedSimplex;
}
return;
}
// compute the contracted simplex
// Compute the contracted simplex.
final RealPointValuePair contracted = evaluateNewSimplex(original, gamma, comparator);
if (comparator.compare(contracted, best) < 0) {
// accept the contracted simplex
// Accept the contracted simplex.
return;
}
// check convergence
final int iter = getIterations();
// Check convergence.
boolean converged = true;
for (int i = 0; i < simplex.length; ++i) {
converged &= checker.converged(iter, original[i], simplex[i]);
converged &= checker.converged(iteration, original[i], simplex[i]);
}
if (converged) {
return;
}
}
}
/** Compute and evaluate a new simplex.
* @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 best point in the transformed simplex
* @exception FunctionEvaluationException if the function cannot be evaluated at
* some point
* @exception OptimizationException if the maximal number of evaluations is exceeded
/**
* Compute and evaluate a new simplex.
*
* @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.
* @exception FunctionEvaluationException if the function cannot be
* evaluated at some point.
* @exception TooManyEvaluationsException if the maximal number of
* evaluations is exceeded.
*/
private RealPointValuePair evaluateNewSimplex(final RealPointValuePair[] original,
final double coeff,
final Comparator<RealPointValuePair> comparator)
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
final double[] xSmallest = original[0].getPointRef();
final int n = xSmallest.length;
// create the linearly transformed simplex
// Create the linearly transformed simplex.
simplex = new RealPointValuePair[n + 1];
simplex[0] = original[0];
for (int i = 1; i <= n; ++i) {
@ -136,10 +135,8 @@ public class MultiDirectional extends DirectSearchOptimizer {
simplex[i] = new RealPointValuePair(xTransformed, Double.NaN, false);
}
// evaluate it
// Evaluate the simplex.
evaluateSimplex(comparator);
return simplex[0];
}
}

View File

@ -20,7 +20,6 @@ package org.apache.commons.math.optimization.direct;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair;
/**
@ -72,9 +71,7 @@ public class NelderMead extends DirectSearchOptimizer {
/** {@inheritDoc} */
@Override
protected void iterateSimplex(final Comparator<RealPointValuePair> comparator)
throws FunctionEvaluationException, OptimizationException {
incrementIterationsCounter();
throws FunctionEvaluationException {
// the simplex has n+1 point if dimension is n
final int n = simplex.length - 1;
@ -104,7 +101,8 @@ public class NelderMead extends DirectSearchOptimizer {
for (int j = 0; j < n; ++j) {
xR[j] = centroid[j] + rho * (centroid[j] - xWorst[j]);
}
final RealPointValuePair reflected = new RealPointValuePair(xR, evaluate(xR), false);
final RealPointValuePair reflected
= new RealPointValuePair(xR, computeObjectiveValue(xR), false);
if ((comparator.compare(best, reflected) <= 0) &&
(comparator.compare(reflected, secondBest) < 0)) {
@ -119,7 +117,8 @@ public class NelderMead extends DirectSearchOptimizer {
for (int j = 0; j < n; ++j) {
xE[j] = centroid[j] + khi * (xR[j] - centroid[j]);
}
final RealPointValuePair expanded = new RealPointValuePair(xE, evaluate(xE), false);
final RealPointValuePair expanded
= new RealPointValuePair(xE, computeObjectiveValue(xE), false);
if (comparator.compare(expanded, reflected) < 0) {
// accept the expansion point
@ -138,7 +137,8 @@ public class NelderMead extends DirectSearchOptimizer {
for (int j = 0; j < n; ++j) {
xC[j] = centroid[j] + gamma * (xR[j] - centroid[j]);
}
final RealPointValuePair outContracted = new RealPointValuePair(xC, evaluate(xC), false);
final RealPointValuePair outContracted
= new RealPointValuePair(xC, computeObjectiveValue(xC), false);
if (comparator.compare(outContracted, reflected) <= 0) {
// accept the contraction point
@ -153,7 +153,8 @@ public class NelderMead extends DirectSearchOptimizer {
for (int j = 0; j < n; ++j) {
xC[j] = centroid[j] - gamma * (centroid[j] - xWorst[j]);
}
final RealPointValuePair inContracted = new RealPointValuePair(xC, evaluate(xC), false);
final RealPointValuePair inContracted
= new RealPointValuePair(xC, computeObjectiveValue(xC), false);
if (comparator.compare(inContracted, worst) < 0) {
// accept the contraction point
@ -173,9 +174,6 @@ public class NelderMead extends DirectSearchOptimizer {
simplex[i] = new RealPointValuePair(x, Double.NaN, false);
}
evaluateSimplex(comparator);
}
}
}

View File

@ -24,7 +24,6 @@ import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.VectorialPointValuePair;
/** Fitter for parametric univariate real functions y = f(x).
@ -120,12 +119,12 @@ public class CurveFitter {
* @return fitted parameters
* @exception FunctionEvaluationException if the objective function throws one during
* the search
* @exception OptimizationException if the algorithm failed to converge
* @exception IllegalArgumentException if the start point dimension is wrong
* @exception ConvergenceException if the algorithm failed to converge
* @exception IllegalArgumentException if the start point dimension is wrong.
*/
public double[] fit(final ParametricRealFunction f,
final double[] initialGuess)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
throws FunctionEvaluationException {
// prepare least squares problem
double[] target = new double[observations.size()];
@ -143,7 +142,6 @@ public class CurveFitter {
// extract the coefficients
return optimum.getPointRef();
}
/** Vectorial function computing function theoretical values. */

View File

@ -21,7 +21,7 @@ import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.exception.ConvergenceException;
/** This class implements a curve fitting specialized for polynomials.
* <p>Polynomial fitting is a very simple case of curve fitting. The
@ -69,10 +69,9 @@ public class PolynomialFitter {
/** Get the polynomial fitting the weighted (x, y) points.
* @return polynomial function best fitting the observed points
* @exception OptimizationException if the algorithm failed to converge
* @exception ConvergenceException if the algorithm failed to converge
*/
public PolynomialFunction fit()
throws OptimizationException {
public PolynomialFunction fit() {
try {
return new PolynomialFunction(fitter.fit(new ParametricPolynomial(), new double[degree + 1]));
} catch (FunctionEvaluationException fee) {

View File

@ -18,8 +18,7 @@
package org.apache.commons.math.optimization.general;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.exception.util.LocalizedFormats;
@ -27,155 +26,72 @@ import org.apache.commons.math.linear.InvalidMatrixException;
import org.apache.commons.math.linear.LUDecompositionImpl;
import org.apache.commons.math.linear.MatrixUtils;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.SimpleVectorialValueChecker;
import org.apache.commons.math.optimization.VectorialConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer;
import org.apache.commons.math.optimization.VectorialPointValuePair;
import org.apache.commons.math.util.FastMath;
/**
* Base class for implementing least squares optimizers.
* <p>This base class handles the boilerplate methods associated to thresholds
* settings, jacobian and error estimation.</p>
* It handles the boilerplate methods associated to thresholds settings,
* jacobian and error estimation.
*
* @version $Revision$ $Date$
* @since 1.2
*
*/
public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMultivariateVectorialOptimizer {
/** Default maximal number of iterations allowed. */
public static final int DEFAULT_MAX_ITERATIONS = 100;
/** Convergence checker. */
protected VectorialConvergenceChecker checker;
public abstract class AbstractLeastSquaresOptimizer
extends BaseAbstractVectorialOptimizer<DifferentiableMultivariateVectorialFunction>
implements DifferentiableMultivariateVectorialOptimizer {
/**
* Jacobian matrix of the weighted residuals.
* <p>This matrix is in canonical form just after the calls to
* This matrix is in canonical form just after the calls to
* {@link #updateJacobian()}, but may be modified by the solver
* in the derived class (the {@link LevenbergMarquardtOptimizer
* Levenberg-Marquardt optimizer} does this).</p>
* Levenberg-Marquardt optimizer} does this).
*/
protected double[][] weightedResidualJacobian;
/** Number of columns of the jacobian matrix. */
protected int cols;
/** Number of rows of the jacobian matrix. */
protected int rows;
/**
* Target value for the objective functions at optimum.
* @since 2.1
*/
protected double[] targetValues;
/**
* Weight for the least squares cost computation.
* @since 2.1
*/
protected double[] residualsWeights;
/** Current point. */
protected double[] point;
/** Current objective function value. */
protected double[] objective;
/** Current residuals. */
protected double[] residuals;
/** Weighted residuals */
protected double[] weightedResiduals;
/** Cost value (square root of the sum of the residuals). */
protected double cost;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed. */
private int iterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed. */
private int objectiveEvaluations;
/** Number of jacobian evaluations. */
private int jacobianEvaluations;
/** Objective function. */
private DifferentiableMultivariateVectorialFunction function;
/** Objective function derivatives. */
private MultivariateMatrixFunction jF;
/** Number of evaluations of the Jacobian. */
private int jacobianEvaluations;
/** Simple constructor with default settings.
* <p>The convergence check is set to a {@link SimpleVectorialValueChecker}
* and the maximal number of evaluation is set to its default value.</p>
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link SimpleVectorialValueChecker}.
*/
protected AbstractLeastSquaresOptimizer() {
setConvergenceChecker(new SimpleVectorialValueChecker());
setMaxIterations(DEFAULT_MAX_ITERATIONS);
setMaxEvaluations(Integer.MAX_VALUE);
protected AbstractLeastSquaresOptimizer() {}
/**
* @param checker Convergence checker.
* @param maxEvaluations Maximal number of function evaluations.
*/
protected AbstractLeastSquaresOptimizer(ConvergenceChecker<VectorialPointValuePair> checker,
int maxEvaluations) {
super(checker, maxEvaluations);
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return iterations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return objectiveEvaluations;
}
/** {@inheritDoc} */
/**
* @return the number of evaluations of the Jacobian function.
*/
public int getJacobianEvaluations() {
return jacobianEvaluations;
}
/** {@inheritDoc} */
public void setConvergenceChecker(VectorialConvergenceChecker convergenceChecker) {
this.checker = convergenceChecker;
}
/** {@inheritDoc} */
public VectorialConvergenceChecker getConvergenceChecker() {
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) {
throw new OptimizationException(new MaxIterationsExceededException(maxIterations));
}
}
/**
* Update the jacobian matrix.
* @exception FunctionEvaluationException if the function jacobian
@ -188,6 +104,9 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
throw new FunctionEvaluationException(point, LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE,
weightedResidualJacobian.length, rows);
}
final double[] residualsWeights = getWeightRef();
for (int i = 0; i < rows; i++) {
final double[] ji = weightedResidualJacobian[i];
double wi = FastMath.sqrt(residualsWeights[i]);
@ -204,18 +123,16 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
* or its dimension doesn't match problem dimension or maximal number of
* of evaluations is exceeded
*/
protected void updateResidualsAndCost()
throws FunctionEvaluationException {
if (++objectiveEvaluations > maxEvaluations) {
throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations),
point);
}
objective = function.value(point);
protected void updateResidualsAndCost() throws FunctionEvaluationException {
objective = computeObjectiveValue(point);
if (objective.length != rows) {
throw new FunctionEvaluationException(point, LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE,
objective.length, rows);
}
final double[] targetValues = getTargetRef();
final double[] residualsWeights = getWeightRef();
cost = 0;
int index = 0;
for (int i = 0; i < rows; i++) {
@ -225,7 +142,6 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
index += cols;
}
cost = FastMath.sqrt(cost);
}
/**
@ -249,7 +165,7 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
* @return chi-square value
*/
public double getChiSquare() {
return cost*cost;
return cost * cost;
}
/**
@ -257,11 +173,11 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
* @return covariance matrix
* @exception FunctionEvaluationException if the function jacobian cannot
* be evaluated
* @exception OptimizationException if the covariance matrix
* @exception ConvergenceException if the covariance matrix
* cannot be computed (singular problem)
*/
public double[][] getCovariances()
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
// set up the jacobian
updateJacobian();
@ -285,7 +201,7 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
new LUDecompositionImpl(MatrixUtils.createRealMatrix(jTj)).getSolver().getInverse();
return inverse.getData();
} catch (InvalidMatrixException ime) {
throw new OptimizationException(LocalizedFormats.UNABLE_TO_COMPUTE_COVARIANCE_SINGULAR_PROBLEM);
throw new ConvergenceException(LocalizedFormats.UNABLE_TO_COMPUTE_COVARIANCE_SINGULAR_PROBLEM);
}
}
@ -295,16 +211,15 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
* <p>Guessing is covariance-based, it only gives rough order of magnitude.</p>
* @return errors in optimized parameters
* @exception FunctionEvaluationException if the function jacobian cannot b evaluated
* @exception OptimizationException if the covariances matrix cannot be computed
* @exception ConvergenceException if the covariances matrix cannot be computed
* or the number of degrees of freedom is not positive (number of measurements
* lesser or equal to number of parameters)
*/
public double[] guessParametersErrors()
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
if (rows <= cols) {
throw new OptimizationException(
LocalizedFormats.NO_DEGREES_OF_FREEDOM,
rows, cols);
throw new ConvergenceException(LocalizedFormats.NO_DEGREES_OF_FREEDOM,
rows, cols);
}
double[] errors = new double[cols];
final double c = FastMath.sqrt(getChiSquare() / (rows - cols));
@ -319,46 +234,24 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
public VectorialPointValuePair optimize(final DifferentiableMultivariateVectorialFunction f,
final double[] target, final double[] weights,
final double[] startPoint)
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
throws FunctionEvaluationException {
// Reset counter.
jacobianEvaluations = 0;
if (target.length != weights.length) {
throw new OptimizationException(LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE,
target.length, weights.length);
}
// Store least squares problem characteristics.
jF = f.jacobian();
this.residuals = new double[target.length];
// reset counters
iterations = 0;
objectiveEvaluations = 0;
jacobianEvaluations = 0;
// store least squares problem characteristics
function = f;
jF = f.jacobian();
targetValues = target.clone();
residualsWeights = weights.clone();
this.point = startPoint.clone();
// arrays shared with the other private methods
rows = target.length;
cols = point.length;
// Arrays shared with the other private methods.
point = startPoint.clone();
rows = target.length;
cols = point.length;
weightedResidualJacobian = new double[rows][cols];
this.weightedResiduals = new double[rows];
cost = Double.POSITIVE_INFINITY;
return doOptimize();
return super.optimize(f, target, weights, startPoint);
}
/** Perform the bulk of optimization algorithm.
* @return the point/value pair giving the optimal value for objective function
* @exception FunctionEvaluationException if the objective function throws one during
* the search
* @exception OptimizationException if the algorithm failed to converge
* @exception IllegalArgumentException if the start point dimension is wrong
*/
protected abstract VectorialPointValuePair doOptimize()
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException;
}

View File

@ -22,8 +22,7 @@ import org.apache.commons.math.analysis.DifferentiableMultivariateRealFunction;
import org.apache.commons.math.analysis.MultivariateVectorialFunction;
import org.apache.commons.math.optimization.DifferentiableMultivariateRealOptimizer;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.RealPointValuePair;
/**
@ -37,63 +36,39 @@ import org.apache.commons.math.optimization.RealPointValuePair;
public abstract class AbstractScalarDifferentiableOptimizer
extends BaseAbstractScalarOptimizer<DifferentiableMultivariateRealFunction>
implements DifferentiableMultivariateRealOptimizer {
/** Convergence checker.
* @deprecated in 2.2 (to be removed in 3.0). Please use the accessor
* {@link BaseAbstractScalarOptimizer#getConvergenceChecker()} instead.
*/
protected RealConvergenceChecker checker;
/**
* Type of optimization.
* @since 2.1
* @deprecated in 2.2 (to be removed in 3.0). Please use the accessor
* {@link BaseAbstractScalarOptimizer#getGoalType()} instead.
* Objective function gradient.
*/
protected GoalType goal;
/** Current point set.
* @deprecated in 2.2 (to be removed in 3.0).
*/
protected double[] point;
/** Number of gradient evaluations. */
private int gradientEvaluations;
/** Objective function gradient. */
private MultivariateVectorialFunction gradient;
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link org.apache.commons.math.optimization.SimpleScalarValueChecker},
* the allowed number of iterations and evaluations are set to their
* default values.
* The convergence check is set to a
* {@link org.apache.commons.math.optimization.SimpleScalarValueChecker
* SimpleScalarValueChecker}.
*/
protected AbstractScalarDifferentiableOptimizer() {}
/**
* @param checker Convergence checker.
* @param maxIterations Maximum number of iterations.
* @param maxEvaluations Maximum number of evaluations.
* @param maxEvaluations Maximum number of function evaluations.
*/
protected AbstractScalarDifferentiableOptimizer(RealConvergenceChecker checker,
int maxIterations,
protected AbstractScalarDifferentiableOptimizer(ConvergenceChecker<RealPointValuePair> checker,
int maxEvaluations) {
super(checker, maxIterations, maxEvaluations);
this.checker = checker; // Do not use (deprecated).
}
/** {@inheritDoc} */
public int getGradientEvaluations() {
return gradientEvaluations;
super(checker, maxEvaluations);
}
/**
* Compute the gradient vector.
* @param evaluationPoint point at which the gradient must be evaluated
* @return gradient at the specified point
* @exception FunctionEvaluationException if the function gradient
*
* @param evaluationPoint Point at which the gradient must be evaluated.
* @return the gradient at the specified point.
* @throws FunctionEvaluationException if the function gradient cannot be
* evaluated.
* @throws TooManyEvaluationsException if the allowed number of evaluations
* is exceeded.
*/
protected double[] computeObjectiveGradient(final double[] evaluationPoint)
throws FunctionEvaluationException {
++gradientEvaluations;
return gradient.value(evaluationPoint);
}
@ -101,17 +76,10 @@ public abstract class AbstractScalarDifferentiableOptimizer
public RealPointValuePair optimize(final DifferentiableMultivariateRealFunction f,
final GoalType goalType,
final double[] startPoint)
throws FunctionEvaluationException,
OptimizationException {
// reset counters
gradientEvaluations = 0;
// store optimization problem characteristics
throws FunctionEvaluationException {
// Store optimization problem characteristics.
gradient = f.gradient();
goal = goalType; // Do not use (deprecated).
point = startPoint.clone(); // Do not use (deprecated).
return super.optimize(f, goalType, startPoint);
}
}

View File

@ -19,7 +19,8 @@ package org.apache.commons.math.optimization.general;
import org.apache.commons.math.analysis.MultivariateRealFunction;
import org.apache.commons.math.optimization.MultivariateRealOptimizer;
import org.apache.commons.math.optimization.RealConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.RealPointValuePair;
/**
* Base class for implementing optimizers for multivariate (not necessarily
@ -33,19 +34,16 @@ public abstract class AbstractScalarOptimizer
implements MultivariateRealOptimizer {
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link org.apache.commons.math.optimization.SimpleScalarValueChecker},
* the allowed number of iterations and evaluations are set to their
* default values.
* The convergence check is set to a
* {@link org.apache.commons.math.optimization.SimpleScalarValueChecker}.
*/
protected AbstractScalarOptimizer() {}
/**
* @param checker Convergence checker.
* @param maxIterations Maximum number of iterations.
* @param maxEvaluations Maximum number of evaluations.
* @param maxEvaluations Maximum number of function evaluations.
*/
protected AbstractScalarOptimizer(RealConvergenceChecker checker,
int maxIterations,
protected AbstractScalarOptimizer(ConvergenceChecker<RealPointValuePair> checker,
int maxEvaluations) {
super(checker, maxIterations, maxEvaluations);
super(checker, maxEvaluations);
}
}

View File

@ -18,13 +18,14 @@
package org.apache.commons.math.optimization.general;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.util.Incrementor;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.analysis.MultivariateRealFunction;
import org.apache.commons.math.optimization.BaseMultivariateRealOptimizer;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealConvergenceChecker;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
@ -37,6 +38,7 @@ import org.apache.commons.math.optimization.SimpleScalarValueChecker;
* A class that implements an optimization algorithm should inherit from
* {@link AbstractScalarOptimizer} or from
* {@link AbstractScalarDifferentiableOptimizer}.
*
* @param <T> the type of the objective function to be optimized
*
* @version $Revision$ $Date$
@ -44,136 +46,93 @@ import org.apache.commons.math.optimization.SimpleScalarValueChecker;
*/
public abstract class BaseAbstractScalarOptimizer<T extends MultivariateRealFunction>
implements BaseMultivariateRealOptimizer<T> {
/** Default maximal number of iterations allowed ({@value}). */
public static final int DEFAULT_MAX_ITERATIONS = 1000;
/** Default maximal number of iterations allowed ({@value}). */
public static final int DEFAULT_MAX_EVALUATIONS = 10000;
/** Evaluations counter. */
protected final Incrementor evaluations = new Incrementor();
/** Convergence checker. */
private RealConvergenceChecker checker;
private ConvergenceChecker<RealPointValuePair> checker;
/** Type of optimization. */
private GoalType goal;
/** Initial guess. */
private double[] start;
/** Maximal number of iterations allowed. */
private int maxIterations;
/** Number of iterations already performed. */
private int iterations;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed. */
private int evaluations;
/** Objective function. */
private MultivariateRealFunction function;
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link SimpleScalarValueChecker},
* the allowed number of iterations and evaluations are set to their
* default values.
* The convergence check is set to a {@link SimpleScalarValueChecker} and
* the allowed number of evaluations is set to {@link Integer#MAX_VALUE}.
*/
protected BaseAbstractScalarOptimizer() {
this(new SimpleScalarValueChecker(),
DEFAULT_MAX_ITERATIONS,
DEFAULT_MAX_EVALUATIONS);
this(new SimpleScalarValueChecker(), Integer.MAX_VALUE);
}
/**
* @param checker Convergence checker.
* @param maxIterations Maximum number of iterations.
* @param maxEvaluations Maximum number of evaluations.
* @param maxEvaluations Maximum number of function evaluations.
*/
protected BaseAbstractScalarOptimizer(RealConvergenceChecker checker,
int maxIterations,
protected BaseAbstractScalarOptimizer(ConvergenceChecker<RealPointValuePair> checker,
int maxEvaluations) {
this.checker = checker;
this.maxIterations = maxIterations;
this.maxEvaluations = maxEvaluations;
}
/** {@inheritDoc} */
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
/** {@inheritDoc} */
public int getMaxIterations() {
return maxIterations;
}
/** {@inheritDoc} */
public int getIterations() {
return iterations;
evaluations.setMaximalCount(maxEvaluations);
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
evaluations.setMaximalCount(maxEvaluations);
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
return evaluations.getMaximalCount();
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations;
return evaluations.getCount();
}
/** {@inheritDoc} */
public void setConvergenceChecker(RealConvergenceChecker convergenceChecker) {
public void setConvergenceChecker(ConvergenceChecker<RealPointValuePair> convergenceChecker) {
this.checker = convergenceChecker;
}
/** {@inheritDoc} */
public RealConvergenceChecker getConvergenceChecker() {
public ConvergenceChecker<RealPointValuePair> getConvergenceChecker() {
return checker;
}
/**
* Increment the iterations counter by 1.
* @throws 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 objective function value.
* @param evaluationPoint point at which the objective function must be evaluated
* @return objective function value at specified point
* @throws FunctionEvaluationException if the function cannot be evaluated
* or its dimension doesn't match problem dimension or the maximal number
* of iterations is exceeded
*
* @param point Point at which the objective function must be evaluated.
* @return the objective function value at the specified point.
* @throws FunctionEvaluationException if the function cannot be evaluated.
* @throws TooManyEvaluationsException if the maximal number of evaluations is
* exceeded.
*/
protected double computeObjectiveValue(double[] evaluationPoint)
protected double computeObjectiveValue(double[] point)
throws FunctionEvaluationException {
if (++evaluations > maxEvaluations) {
throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations),
evaluationPoint);
try {
evaluations.incrementCount();
} catch (MaxCountExceededException e) {
throw new TooManyEvaluationsException(e.getMax());
}
return function.value(evaluationPoint);
return function.value(point);
}
/** {@inheritDoc} */
public RealPointValuePair optimize(T f,
GoalType goalType,
double[] startPoint)
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
// Reset.
evaluations.resetCount();
// reset counters
iterations = 0;
evaluations = 0;
// store optimization problem characteristics
// Store optimization problem characteristics.
function = f;
goal = goalType;
start = startPoint.clone();
// Perform computation.
return doOptimize();
}
@ -192,13 +151,12 @@ public abstract class BaseAbstractScalarOptimizer<T extends MultivariateRealFunc
}
/**
* Perform the bulk of optimization algorithm.
* Perform the bulk of the optimization algorithm.
*
* @return the point/value pair giving the optimal value for objective function
* @throws FunctionEvaluationException if the objective function throws one during
* the search
* @throws OptimizationException if the algorithm failed to converge
* @throws IllegalArgumentException if the start point dimension is wrong
*/
protected abstract RealPointValuePair doOptimize()
throws FunctionEvaluationException, OptimizationException;
throws FunctionEvaluationException;
}

View File

@ -0,0 +1,172 @@
/*
* 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.general;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.util.Incrementor;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.analysis.MultivariateVectorialFunction;
import org.apache.commons.math.optimization.BaseMultivariateVectorialOptimizer;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.VectorialPointValuePair;
import org.apache.commons.math.optimization.SimpleVectorialValueChecker;
/**
* Base class for implementing optimizers for multivariate scalar functions.
* This base class handles the boiler-plate methods associated to thresholds
* settings, iterations and evaluations counting.
*
* @param <FUNC> the type of the objective function to be optimized
*
* @version $Revision$ $Date$
* @since 3.0
*/
public abstract class BaseAbstractVectorialOptimizer<FUNC extends MultivariateVectorialFunction>
implements BaseMultivariateVectorialOptimizer<FUNC> {
/** Evaluations counter. */
protected final Incrementor evaluations = new Incrementor();
/** Convergence checker. */
private ConvergenceChecker<VectorialPointValuePair> checker;
/** Target value for the objective functions at optimum. */
private double[] target;
/** Weight for the least squares cost computation. */
private double[] weight;
/** Initial guess. */
private double[] start;
/** Objective function. */
private MultivariateVectorialFunction function;
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link SimpleVectorialValueChecker} and
* the allowed number of evaluations is set to {@link Integer#MAX_VALUE}.
*/
protected BaseAbstractVectorialOptimizer() {
this(new SimpleVectorialValueChecker(), Integer.MAX_VALUE);
}
/**
* @param checker Convergence checker.
* @param maxEvaluations Maximum number of function evaluations.
*/
protected BaseAbstractVectorialOptimizer(ConvergenceChecker<VectorialPointValuePair> checker,
int maxEvaluations) {
this.checker = checker;
evaluations.setMaximalCount(maxEvaluations);
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
evaluations.setMaximalCount(maxEvaluations);
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return evaluations.getMaximalCount();
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations.getCount();
}
/** {@inheritDoc} */
public void setConvergenceChecker(ConvergenceChecker<VectorialPointValuePair> convergenceChecker) {
this.checker = convergenceChecker;
}
/** {@inheritDoc} */
public ConvergenceChecker<VectorialPointValuePair> getConvergenceChecker() {
return checker;
}
/**
* Compute the objective function value.
*
* @param point Point at which the objective function must be evaluated.
* @return the objective function value at the specified point.
* @throws FunctionEvaluationException if the function cannot be evaluated.
* @throws TooManyEvaluationsException if the maximal number of evaluations is
* exceeded.
*/
protected double[] computeObjectiveValue(double[] point)
throws FunctionEvaluationException {
try {
evaluations.incrementCount();
} catch (MaxCountExceededException e) {
throw new TooManyEvaluationsException(e.getMax());
}
return function.value(point);
}
/** {@inheritDoc} */
public VectorialPointValuePair optimize(FUNC f,
double[] target, double[] weight,
double[] startPoint)
throws FunctionEvaluationException {
if (target.length != weight.length) {
throw new DimensionMismatchException(target.length, weight.length);
}
// Reset.
evaluations.resetCount();
// Store optimization problem characteristics.
function = f;
this.target = target.clone();
this.weight = weight.clone();
start = startPoint.clone();
// Perform computation.
return doOptimize();
}
/**
* @return the initial guess.
*/
public double[] getStartPoint() {
return start.clone();
}
/**
* Perform the bulk of the optimization algorithm.
*
* @return the point/value pair giving the optimal value for objective function
* @throws FunctionEvaluationException if the objective function throws one during
* the search
*/
protected abstract VectorialPointValuePair doOptimize()
throws FunctionEvaluationException;
/**
* @return a reference to the {@link #target array}.
*/
protected double[] getTargetRef() {
return target;
}
/**
* @return a reference to the {@link #weight array}.
*/
protected double[] getWeightRef() {
return weight;
}
}

View File

@ -25,7 +25,7 @@ import org.apache.commons.math.linear.InvalidMatrixException;
import org.apache.commons.math.linear.LUDecompositionImpl;
import org.apache.commons.math.linear.QRDecompositionImpl;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.optimization.VectorialPointValuePair;
/**
@ -43,17 +43,17 @@ import org.apache.commons.math.optimization.VectorialPointValuePair;
*/
public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
/** Indicator for using LU decomposition. */
private final boolean useLU;
/** Simple constructor with default settings.
* <p>The convergence check is set to a {@link
* org.apache.commons.math.optimization.SimpleVectorialValueChecker}
* and the maximal number of evaluation is set to
* {@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
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link
* org.apache.commons.math.optimization.SimpleVectorialValueChecker}.
*
* @param useLU if {@code true}, the normal equations will be solved
* using LU decomposition, otherwise they will be solved using QR
* decomposition.
*/
public GaussNewtonOptimizer(final boolean useLU) {
this.useLU = useLU;
@ -62,13 +62,13 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
/** {@inheritDoc} */
@Override
public VectorialPointValuePair doOptimize()
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
throws FunctionEvaluationException {
// iterate until convergence is reached
VectorialPointValuePair current = null;
int iter = 0;
for (boolean converged = false; !converged;) {
incrementIterationsCounter();
++iter;
// evaluate the objective function and its jacobian
VectorialPointValuePair previous = current;
@ -76,6 +76,9 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
updateJacobian();
current = new VectorialPointValuePair(point, objective);
final double[] targetValues = getTargetRef();
final double[] residualsWeights = getWeightRef();
// build the linear problem
final double[] b = new double[cols];
final double[][] a = new double[cols][cols];
@ -99,11 +102,9 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
ak[l] += wgk * grad[l];
}
}
}
try {
// solve the linearized least squares problem
RealMatrix mA = new BlockRealMatrix(a);
DecompositionSolver solver = useLU ?
@ -115,21 +116,16 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
for (int i = 0; i < cols; ++i) {
point[i] += dX[i];
}
} catch(InvalidMatrixException e) {
throw new OptimizationException(LocalizedFormats.UNABLE_TO_SOLVE_SINGULAR_PROBLEM);
} catch (InvalidMatrixException e) {
throw new ConvergenceException(LocalizedFormats.UNABLE_TO_SOLVE_SINGULAR_PROBLEM);
}
// check convergence
if (previous != null) {
converged = checker.converged(getIterations(), previous, current);
converged = getConvergenceChecker().converged(iter, previous, current);
}
}
// we have converged
return current;
}
}

View File

@ -19,9 +19,10 @@ package org.apache.commons.math.optimization.general;
import java.util.Arrays;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.VectorialPointValuePair;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.util.FastMath;
@ -150,9 +151,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
* Build an optimizer for least squares problems.
* <p>The default values for the algorithm settings are:
* <ul>
* <li>{@link #setConvergenceChecker(VectorialConvergenceChecker) vectorial convergence checker}: null</li>
* <li>{@link #setConvergenceChecker(ConvergenceChecker) vectorial convergence checker}: null</li>
* <li>{@link #setInitialStepBoundFactor(double) initial step bound factor}: 100.0</li>
* <li>{@link #setMaxIterations(int) maximal iterations}: 1000</li>
* <li>{@link #setCostRelativeTolerance(double) cost relative tolerance}: 1.0e-10</li>
* <li>{@link #setParRelativeTolerance(double) parameters relative tolerance}: 1.0e-10</li>
* <li>{@link #setOrthoTolerance(double) orthogonality tolerance}: 1.0e-10</li>
@ -165,10 +165,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
* and {@link #setParRelativeTolerance parameters relative tolerance} settings.
*/
public LevenbergMarquardtOptimizer() {
// set up the superclass with a default max cost evaluations setting
setMaxIterations(1000);
// default values for the tuning parameters
setConvergenceChecker(null);
setInitialStepBoundFactor(100.0);
@ -176,7 +172,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
setParRelativeTolerance(1.0e-10);
setOrthoTolerance(1.0e-10);
setQRRankingThreshold(MathUtils.SAFE_MIN);
}
/**
@ -239,8 +234,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
/** {@inheritDoc} */
@Override
protected VectorialPointValuePair doOptimize()
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
protected VectorialPointValuePair doOptimize() throws FunctionEvaluationException {
// arrays shared with the other private methods
solvedCols = FastMath.min(rows, cols);
@ -269,11 +263,14 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
lmPar = 0;
boolean firstIteration = true;
VectorialPointValuePair current = new VectorialPointValuePair(point, objective);
int iter = 0;
final ConvergenceChecker<VectorialPointValuePair> checker = getConvergenceChecker();
while (true) {
++iter;
for (int i=0;i<rows;i++) {
qtf[i]=weightedResiduals[i];
}
incrementIterationsCounter();
// compute the Q.R. decomposition of the jacobian matrix
VectorialPointValuePair previous = current;
@ -290,7 +287,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
}
if (firstIteration) {
// scale the point according to the norms of the columns
// of the initial jacobian
xNorm = 0;
@ -307,7 +303,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// initialize the step bound delta
delta = (xNorm == 0) ? initialStepBoundFactor : (initialStepBoundFactor * xNorm);
}
// check orthogonality between function vector and jacobian columns
@ -425,17 +420,17 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
xNorm = 0;
for (int k = 0; k < cols; ++k) {
double xK = diag[k] * point[k];
xNorm += xK * xK;
xNorm += xK * xK;
}
xNorm = FastMath.sqrt(xNorm);
current = new VectorialPointValuePair(point, objective);
// tests for convergence.
if (checker != null) {
// we use the vectorial convergence checker
if (checker.converged(getIterations(), previous, current)) {
return current;
}
// we use the vectorial convergence checker
if (checker.converged(iter, previous, current)) {
return current;
}
}
} else {
// failed iteration, reset the previous values
@ -462,20 +457,17 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// tests for termination and stringent tolerances
// (2.2204e-16 is the machine epsilon for IEEE754)
if ((FastMath.abs(actRed) <= 2.2204e-16) && (preRed <= 2.2204e-16) && (ratio <= 2.0)) {
throw new OptimizationException(LocalizedFormats.TOO_SMALL_COST_RELATIVE_TOLERANCE,
throw new ConvergenceException(LocalizedFormats.TOO_SMALL_COST_RELATIVE_TOLERANCE,
costRelativeTolerance);
} else if (delta <= 2.2204e-16 * xNorm) {
throw new OptimizationException(LocalizedFormats.TOO_SMALL_PARAMETERS_RELATIVE_TOLERANCE,
throw new ConvergenceException(LocalizedFormats.TOO_SMALL_PARAMETERS_RELATIVE_TOLERANCE,
parRelativeTolerance);
} else if (maxCosine <= 2.2204e-16) {
throw new OptimizationException(LocalizedFormats.TOO_SMALL_ORTHOGONALITY_TOLERANCE,
throw new ConvergenceException(LocalizedFormats.TOO_SMALL_ORTHOGONALITY_TOLERANCE,
orthoTolerance);
}
}
}
}
/**
@ -733,7 +725,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
lmDiag[i] = -sin * rik + cos * lmDiag[i];
weightedResidualJacobian[i][pk] = temp2;
}
}
}
@ -741,7 +732,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// the corresponding diagonal element of R
lmDiag[j] = weightedResidualJacobian[j][permutation[j]];
weightedResidualJacobian[j][permutation[j]] = lmDir[j];
}
// solve the triangular system for z, if the system is
@ -770,7 +760,6 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
for (int j = 0; j < lmDir.length; ++j) {
lmDir[permutation[j]] = work[j];
}
}
/**
@ -793,9 +782,9 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
* are performed in non-increasing columns norms order thanks to columns
* pivoting. The diagonal elements of the R matrix are therefore also in
* non-increasing absolute values order.</p>
* @exception OptimizationException if the decomposition cannot be performed
* @exception ConvergenceException if the decomposition cannot be performed
*/
private void qrDecomposition() throws OptimizationException {
private void qrDecomposition() throws ConvergenceException {
// initializations
for (int k = 0; k < cols; ++k) {
@ -821,7 +810,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
norm2 += aki * aki;
}
if (Double.isInfinite(norm2) || Double.isNaN(norm2)) {
throw new OptimizationException(LocalizedFormats.UNABLE_TO_PERFORM_QR_DECOMPOSITION_ON_JACOBIAN,
throw new ConvergenceException(LocalizedFormats.UNABLE_TO_PERFORM_QR_DECOMPOSITION_ON_JACOBIAN,
rows, cols);
}
if (norm2 > ak2) {
@ -858,11 +847,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
weightedResidualJacobian[j][permutation[k + dk]] -= gamma * weightedResidualJacobian[j][pk];
}
}
}
rank = solvedCols;
}
/**
@ -883,5 +869,4 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
}
}
}
}

View File

@ -17,14 +17,14 @@
package org.apache.commons.math.optimization.general;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.analysis.solvers.BrentSolver;
import org.apache.commons.math.analysis.solvers.UnivariateRealSolver;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.util.FastMath;
@ -54,11 +54,11 @@ public class NonLinearConjugateGradientOptimizer
/** Current point. */
private double[] point;
/** Simple constructor with default settings.
* <p>The convergence check is set to a {@link
* org.apache.commons.math.optimization.SimpleVectorialValueChecker}
* and the maximal number of iterations is set to
* {@link AbstractScalarDifferentiableOptimizer#DEFAULT_MAX_ITERATIONS}.
/**
* Simple constructor with default settings.
* The convergence check is set to a {@link
* org.apache.commons.math.optimization.SimpleVectorialValueChecker}.
*
* @param updateFormula formula to use for updating the &beta; parameter,
* must be one of {@link ConjugateGradientFormula#FLETCHER_REEVES} or {@link
* ConjugateGradientFormula#POLAK_RIBIERE}
@ -110,104 +110,104 @@ public class NonLinearConjugateGradientOptimizer
/** {@inheritDoc} */
@Override
protected RealPointValuePair doOptimize()
throws FunctionEvaluationException, OptimizationException, IllegalArgumentException {
try {
// initialization
if (preconditioner == null) {
preconditioner = new IdentityPreconditioner();
throws FunctionEvaluationException {
// Initialization.
if (preconditioner == null) {
preconditioner = new IdentityPreconditioner();
}
if (solver == null) {
solver = new BrentSolver();
}
point = getStartPoint();
final GoalType goal = getGoalType();
final int n = point.length;
double[] r = computeObjectiveGradient(point);
if (goal == GoalType.MINIMIZE) {
for (int i = 0; i < n; ++i) {
r[i] = -r[i];
}
if (solver == null) {
solver = new BrentSolver();
}
// Initial search direction.
double[] steepestDescent = preconditioner.precondition(point, r);
double[] searchDirection = steepestDescent.clone();
double delta = 0;
for (int i = 0; i < n; ++i) {
delta += r[i] * searchDirection[i];
}
RealPointValuePair current = null;
int iter = 0;
while (true) {
++iter;
final double objective = computeObjectiveValue(point);
RealPointValuePair previous = current;
current = new RealPointValuePair(point, objective);
if (previous != null) {
if (getConvergenceChecker().converged(iter, previous, current)) {
// We have found an optimum.
return current;
}
}
point = getStartPoint();
final GoalType goal = getGoalType();
final int n = point.length;
double[] r = computeObjectiveGradient(point);
double dTd = 0;
for (final double di : searchDirection) {
dTd += di * di;
}
// Find the optimal step in the search direction.
final UnivariateRealFunction lsf = new LineSearchFunction(searchDirection);
try {
final double step = solver.solve(lsf, 0, findUpperBound(lsf, 0, initialStep));
// Validate new point.
for (int i = 0; i < point.length; ++i) {
point[i] += step * searchDirection[i];
}
} catch (org.apache.commons.math.ConvergenceException e) {
throw new ConvergenceException(); // XXX ugly workaround.
}
r = computeObjectiveGradient(point);
if (goal == GoalType.MINIMIZE) {
for (int i = 0; i < n; ++i) {
r[i] = -r[i];
}
}
// initial search direction
double[] steepestDescent = preconditioner.precondition(point, r);
double[] searchDirection = steepestDescent.clone();
double delta = 0;
// Compute beta.
final double deltaOld = delta;
final double[] newSteepestDescent = preconditioner.precondition(point, r);
delta = 0;
for (int i = 0; i < n; ++i) {
delta += r[i] * searchDirection[i];
delta += r[i] * newSteepestDescent[i];
}
RealPointValuePair current = null;
while (true) {
final double objective = computeObjectiveValue(point);
RealPointValuePair previous = current;
current = new RealPointValuePair(point, objective);
if (previous != null) {
if (getConvergenceChecker().converged(getIterations(), previous, current)) {
// we have found an optimum
return current;
}
final double beta;
if (updateFormula == ConjugateGradientFormula.FLETCHER_REEVES) {
beta = delta / deltaOld;
} else {
double deltaMid = 0;
for (int i = 0; i < r.length; ++i) {
deltaMid += r[i] * steepestDescent[i];
}
beta = (delta - deltaMid) / deltaOld;
}
steepestDescent = newSteepestDescent;
incrementIterationsCounter();
double dTd = 0;
for (final double di : searchDirection) {
dTd += di * di;
}
// find the optimal step in the search direction
final UnivariateRealFunction lsf = new LineSearchFunction(searchDirection);
final double step = solver.solve(lsf, 0, findUpperBound(lsf, 0, initialStep));
// validate new point
for (int i = 0; i < point.length; ++i) {
point[i] += step * searchDirection[i];
}
r = computeObjectiveGradient(point);
if (goal == GoalType.MINIMIZE) {
for (int i = 0; i < n; ++i) {
r[i] = -r[i];
}
}
// compute beta
final double deltaOld = delta;
final double[] newSteepestDescent = preconditioner.precondition(point, r);
delta = 0;
// Compute conjugate search direction.
if (iter % n == 0 ||
beta < 0) {
// Break conjugation: reset search direction.
searchDirection = steepestDescent.clone();
} else {
// Compute new conjugate search direction.
for (int i = 0; i < n; ++i) {
delta += r[i] * newSteepestDescent[i];
searchDirection[i] = steepestDescent[i] + beta * searchDirection[i];
}
final double beta;
if (updateFormula == ConjugateGradientFormula.FLETCHER_REEVES) {
beta = delta / deltaOld;
} else {
double deltaMid = 0;
for (int i = 0; i < r.length; ++i) {
deltaMid += r[i] * steepestDescent[i];
}
beta = (delta - deltaMid) / deltaOld;
}
steepestDescent = newSteepestDescent;
// compute conjugate search direction
if ((getIterations() % n == 0) || (beta < 0)) {
// break conjugation: reset search direction
searchDirection = steepestDescent.clone();
} else {
// compute new conjugate search direction
for (int i = 0; i < n; ++i) {
searchDirection[i] = steepestDescent[i] + beta * searchDirection[i];
}
}
}
} catch (ConvergenceException ce) {
throw new OptimizationException(ce);
}
}
@ -218,11 +218,12 @@ public class NonLinearConjugateGradientOptimizer
* @param h initial step to try
* @return b such that f(a) and f(b) have opposite signs
* @exception FunctionEvaluationException if the function cannot be computed
* @exception OptimizationException if no bracket can be found
* @exception MathIllegalStateException if no bracket can be found
* @deprecated in 2.2 (must be replaced with "BracketFinder").
*/
private double findUpperBound(final UnivariateRealFunction f,
final double a, final double h)
throws FunctionEvaluationException, OptimizationException {
throws FunctionEvaluationException {
final double yA = f.value(a);
double yB = yA;
for (double step = h; step < Double.MAX_VALUE; step *= FastMath.max(2, yA / yB)) {
@ -232,7 +233,7 @@ public class NonLinearConjugateGradientOptimizer
return b;
}
}
throw new OptimizationException(LocalizedFormats.UNABLE_TO_BRACKET_OPTIMUM_IN_LINE_SEARCH);
throw new MathIllegalStateException(LocalizedFormats.UNABLE_TO_BRACKET_OPTIMUM_IN_LINE_SEARCH);
}
/** Default identity preconditioner. */

View File

@ -20,77 +20,69 @@ package org.apache.commons.math.optimization.general;
import java.util.Arrays;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.univariate.AbstractUnivariateRealOptimizer;
import org.apache.commons.math.optimization.univariate.BracketFinder;
import org.apache.commons.math.optimization.univariate.BrentOptimizer;
import org.apache.commons.math.optimization.univariate.UnivariateRealPointValuePair;
/**
* Powell algorithm.
* This code is translated and adapted from the Python version of this
* algorithm (as implemented in module {@code optimize.py} v0.5 of
* <em>SciPy</em>).
* <br/>
* The user is responsible for calling {@link
* #setConvergenceChecker(ConvergenceChecker) ConvergenceChecker}
* prior to using the optimizer.
*
* @version $Revision$ $Date$
* @since 2.2
*/
public class PowellOptimizer
extends AbstractScalarOptimizer {
/**
* Default relative tolerance for line search ({@value}).
*/
public static final double DEFAULT_LS_RELATIVE_TOLERANCE = 1e-7;
/**
* Default absolute tolerance for line search ({@value}).
*/
public static final double DEFAULT_LS_ABSOLUTE_TOLERANCE = 1e-11;
/**
* Line search.
*/
private final LineSearch line;
private LineSearch line = new LineSearch();
/**
* Constructor with default line search tolerances (see the
* {@link #PowellOptimizer(double,double) other constructor}).
*/
public PowellOptimizer() {
this(DEFAULT_LS_RELATIVE_TOLERANCE,
DEFAULT_LS_ABSOLUTE_TOLERANCE);
}
/**
* Constructor with default absolute line search tolerances (see
* the {@link #PowellOptimizer(double,double) other constructor}).
* Set the convergence checker.
* It also indirectly sets the line search tolerances to the square-root
* of the correponding tolerances in the checker.
*
* @param lsRelativeTolerance Relative error tolerance for
* the line search algorithm ({@link BrentOptimizer}).
* @param checker Convergence checker.
*/
public PowellOptimizer(double lsRelativeTolerance) {
this(lsRelativeTolerance,
DEFAULT_LS_ABSOLUTE_TOLERANCE);
public void setConvergenceChecker(ConvergenceChecker<RealPointValuePair> checker) {
super.setConvergenceChecker(checker);
// Line search tolerances can be much lower than the tolerances
// required for the optimizer itself.
final double minTol = 1e-4;
final double rel = Math.min(Math.sqrt(checker.getRelativeThreshold()), minTol);
final double abs = Math.min(Math.sqrt(checker.getAbsoluteThreshold()), minTol);
line.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(rel, abs));
}
/**
* @param lsRelativeTolerance Relative error tolerance for
* the line search algorithm ({@link BrentOptimizer}).
* @param lsAbsoluteTolerance Relative error tolerance for
* the line search algorithm ({@link BrentOptimizer}).
*/
public PowellOptimizer(double lsRelativeTolerance,
double lsAbsoluteTolerance) {
line = new LineSearch(lsRelativeTolerance,
lsAbsoluteTolerance);
/** {@inheritDoc} */
@Override
public void setMaxEvaluations(int maxEvaluations) {
super.setMaxEvaluations(maxEvaluations);
// We must allow at least as many iterations to the underlying line
// search optimizer. Because the line search inner class will call
// "computeObjectiveValue" in this class, we ensure that this class
// will be the first to eventually throw "TooManyEvaluationsException".
line.setMaxEvaluations(maxEvaluations);
}
/** {@inheritDoc} */
@Override
protected RealPointValuePair doOptimize()
throws FunctionEvaluationException,
OptimizationException {
throws FunctionEvaluationException {
final GoalType goal = getGoalType();
final double[] guess = getStartPoint();
final int n = guess.length;
@ -103,8 +95,9 @@ public class PowellOptimizer
double[] x = guess;
double fVal = computeObjectiveValue(x);
double[] x1 = x.clone();
int iter = 0;
while (true) {
incrementIterationsCounter();
++iter;
double fX = fVal;
double fX2 = 0;
@ -117,9 +110,9 @@ public class PowellOptimizer
fX2 = fVal;
line.search(x, d);
fVal = line.getValueAtOptimum();
alphaMin = line.getOptimum();
final UnivariateRealPointValuePair optimum = line.search(x, d);
fVal = optimum.getValue();
alphaMin = optimum.getPoint();
final double[][] result = newPointAndDirection(x, d, alphaMin);
x = result[0];
@ -131,7 +124,7 @@ public class PowellOptimizer
final RealPointValuePair previous = new RealPointValuePair(x1, fX);
final RealPointValuePair current = new RealPointValuePair(x, fVal);
if (getConvergenceChecker().converged(getIterations(), previous, current)) {
if (getConvergenceChecker().converged(iter, previous, current)) {
if (goal == GoalType.MINIMIZE) {
return (fVal < fX) ? current : previous;
} else {
@ -157,9 +150,9 @@ public class PowellOptimizer
t -= delta * temp * temp;
if (t < 0.0) {
line.search(x, d);
fVal = line.getValueAtOptimum();
alphaMin = line.getOptimum();
final UnivariateRealPointValuePair optimum = line.search(x, d);
fVal = optimum.getValue();
alphaMin = optimum.getPoint();
final double[][] result = newPointAndDirection(x, d, alphaMin);
x = result[0];
@ -200,11 +193,7 @@ public class PowellOptimizer
* Class for finding the minimum of the objective function along a given
* direction.
*/
private class LineSearch {
/**
* Optimizer.
*/
private final AbstractUnivariateRealOptimizer optim = new BrentOptimizer();
private class LineSearch extends BrentOptimizer {
/**
* Automatic bracketing.
*/
@ -212,78 +201,41 @@ public class PowellOptimizer
/**
* Value of the optimum.
*/
private double optimum = Double.NaN;
/**
* Value of the objective function at the optimum.
*/
private double valueAtOptimum = Double.NaN;
/**
* @param relativeTolerance Relative tolerance.
* @param absoluteTolerance Absolute tolerance.
*/
public LineSearch(double relativeTolerance,
double absoluteTolerance) {
optim.setRelativeAccuracy(relativeTolerance);
optim.setAbsoluteAccuracy(absoluteTolerance);
}
private UnivariateRealPointValuePair optimum;
/**
* Find the minimum of the function {@code f(p + alpha * d)}.
*
* @param p Starting point.
* @param d Search direction.
* @throws OptimizationException if function cannot be evaluated at some test point
* or algorithm fails to converge
*/
public void search(final double[] p,
final double[] d)
throws OptimizationException {
// Reset.
optimum = Double.NaN;
valueAtOptimum = Double.NaN;
try {
final int n = p.length;
final UnivariateRealFunction f = new UnivariateRealFunction() {
public double value(double alpha)
throws FunctionEvaluationException {
final double[] x = new double[n];
for (int i = 0; i < n; i++) {
x[i] = p[i] + alpha * d[i];
}
final double obj = computeObjectiveValue(x);
return obj;
}
};
final GoalType goal = getGoalType();
bracket.search(f, goal, 0, 1);
optimum = optim.optimize(f, goal,
bracket.getLo(),
bracket.getHi(),
bracket.getMid());
valueAtOptimum = optim.getFunctionValue();
} catch (FunctionEvaluationException e) {
throw new OptimizationException(e);
} catch (MaxIterationsExceededException e) {
throw new OptimizationException(e);
}
}
/**
* @return the optimum.
* @throws FunctionEvaluationException if the function evaluation
* fails.
* @throws TooManyEvaluationsException if the number of evaluations is
* exceeded.
*/
public double getOptimum() {
return optimum;
}
/**
* @return the value of the function at the optimum.
*/
public double getValueAtOptimum() {
return valueAtOptimum;
public UnivariateRealPointValuePair search(final double[] p,
final double[] d)
throws FunctionEvaluationException {
final int n = p.length;
final UnivariateRealFunction f = new UnivariateRealFunction() {
public double value(double alpha)
throws FunctionEvaluationException {
final double[] x = new double[n];
for (int i = 0; i < n; i++) {
x[i] = p[i] + alpha * d[i];
}
final double obj = PowellOptimizer.this.computeObjectiveValue(x);
return obj;
}
};
final GoalType goal = PowellOptimizer.this.getGoalType();
bracket.search(f, goal, 0, 1);
return optimize(f, goal, bracket.getLo(), bracket.getHi(),
bracket.getMid());
}
}
}

View File

@ -33,7 +33,7 @@ by changing its input variables set until an optimal set is found. There are onl
interfaces defining the common behavior of optimizers, one for each supported type of objective
function:
<ul>
<li>{@link org.apache.commons.math.optimization.UnivariateRealOptimizer
<li>{@link org.apache.commons.math.optimization.univariate.UnivariateRealOptimizer
UnivariateRealOptimizer} for {@link org.apache.commons.math.analysis.UnivariateRealFunction
univariate real functions}</li>
<li>{@link org.apache.commons.math.optimization.MultivariateRealOptimizer

View File

@ -17,14 +17,13 @@
package org.apache.commons.math.optimization.univariate;
import org.apache.commons.math.ConvergingAlgorithmImpl;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.util.Incrementor;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.exception.NoDataException;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.UnivariateRealOptimizer;
import org.apache.commons.math.optimization.ConvergenceChecker;
/**
* Provide a default implementation for several functions useful to generic
@ -34,19 +33,13 @@ import org.apache.commons.math.optimization.UnivariateRealOptimizer;
* @since 2.0
*/
public abstract class AbstractUnivariateRealOptimizer
extends ConvergingAlgorithmImpl implements UnivariateRealOptimizer {
/** Indicates where a root has been computed. */
private boolean resultComputed;
/** The last computed root. */
private double result;
/** Value of the function at the last computed result. */
private double functionValue;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed. */
private int evaluations;
implements UnivariateRealOptimizer {
/** Convergence checker. */
private ConvergenceChecker<UnivariateRealPointValuePair> checker;
/** Evaluations counter. */
private final Incrementor evaluations = new Incrementor();
/** Optimization type */
private GoalType optimizationGoal;
private GoalType goal;
/** Lower end of search interval. */
private double searchMin;
/** Higher end of search interval. */
@ -56,115 +49,35 @@ public abstract class AbstractUnivariateRealOptimizer
/** Function to optimize. */
private UnivariateRealFunction function;
/**
* Construct a solver with given iteration count and accuracy.
* FunctionEvaluationExceptionFunctionEvaluationException
* @param defaultAbsoluteAccuracy maximum absolute error
* @param defaultMaximalIterationCount maximum number of iterations
* @throws IllegalArgumentException if f is null or the
* defaultAbsoluteAccuracy is not valid
* @deprecated in 2.2. Please use the "setter" methods to assign meaningful
* values to the maximum numbers of iterations and evaluations, and to the
* absolute and relative accuracy thresholds.
*/
protected AbstractUnivariateRealOptimizer(final int defaultMaximalIterationCount,
final double defaultAbsoluteAccuracy) {
super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
resultComputed = false;
setMaxEvaluations(Integer.MAX_VALUE);
}
/**
* Default constructor.
* To be removed once the single non-default one has been removed.
*/
protected AbstractUnivariateRealOptimizer() {}
/**
* Check whether a result has been computed.
* @throws NoDataException if no result has been computed
* @deprecated in 2.2 (no alternative).
*/
protected void checkResultComputed() {
if (!resultComputed) {
throw new NoDataException();
}
}
/** {@inheritDoc} */
public double getResult() {
if (!resultComputed) {
throw new NoDataException();
}
return result;
}
/** {@inheritDoc} */
public double getFunctionValue() {
if (functionValue == Double.NaN) {
final double opt = getResult();
try {
functionValue = function.value(opt);
} catch (FunctionEvaluationException e) {
throw new RuntimeException(e);
}
}
return functionValue;
}
/**
* Convenience function for implementations.
*
* @param x the result to set
* @param fx the result to set
* @param iterationCount the iteration count to set
* @deprecated in 2.2 (no alternative).
*/
protected final void setResult(final double x, final double fx,
final int iterationCount) {
this.result = x;
this.functionValue = fx;
this.iterationCount = iterationCount;
this.resultComputed = true;
}
/**
* Convenience function for implementations.
* @deprecated in 2.2 (no alternative).
*/
protected final void clearResult() {
this.resultComputed = false;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
evaluations.setMaximalCount(maxEvaluations);
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
return evaluations.getMaximalCount();
}
/** {@inheritDoc} */
public int getEvaluations() {
return evaluations;
return evaluations.getCount();
}
/**
* @return the optimization type.
*/
public GoalType getGoalType() {
return optimizationGoal;
return goal;
}
/**
* @return the lower of the search interval.
* @return the lower end of the search interval.
*/
public double getMin() {
return searchMin;
}
/**
* @return the higher of the search interval.
* @return the higher end of the search interval.
*/
public double getMax() {
return searchMax;
@ -176,93 +89,76 @@ public abstract class AbstractUnivariateRealOptimizer
return searchStart;
}
/**
* Compute the objective function value.
* @param f objective function
* @param point point at which the objective function must be evaluated
* @return objective function value at specified point
* @exception FunctionEvaluationException if the function cannot be evaluated
* or the maximal number of iterations is exceeded
* @deprecated in 2.2. Use this {@link #computeObjectiveValue(double)
* replacement} instead.
*/
protected double computeObjectiveValue(final UnivariateRealFunction f,
final double point)
throws FunctionEvaluationException {
if (++evaluations > maxEvaluations) {
throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations),
point);
}
return f.value(point);
}
/**
* Compute the objective function value.
*
* @param point Point at which the objective function must be evaluated.
* @return the objective function value at specified point.
* @exception FunctionEvaluationException if the function cannot be evaluated
* or the maximal number of iterations is exceeded.
* @throws FunctionEvaluationException if the function cannot be
* evaluated.
* @throws TooManyEvaluationsException if the maximal number of evaluations
* is exceeded.
*/
protected double computeObjectiveValue(double point)
throws FunctionEvaluationException {
if (++evaluations > maxEvaluations) {
resultComputed = false;
throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations),
point);
try {
evaluations.incrementCount();
} catch (MaxCountExceededException e) {
throw new TooManyEvaluationsException(e.getMax());
}
return function.value(point);
}
/** {@inheritDoc} */
public double optimize(UnivariateRealFunction f, GoalType goal,
double min, double max, double startValue)
throws MaxIterationsExceededException, FunctionEvaluationException {
// Initialize.
this.searchMin = min;
this.searchMax = max;
this.searchStart = startValue;
this.optimizationGoal = goal;
this.function = f;
public UnivariateRealPointValuePair optimize(UnivariateRealFunction f,
GoalType goalType,
double min, double max,
double startValue)
throws FunctionEvaluationException {
// Reset.
functionValue = Double.NaN;
evaluations = 0;
resetIterationsCounter();
searchMin = min;
searchMax = max;
searchStart = startValue;
goal = goalType;
function = f;
evaluations.resetCount();
// Perform computation.
result = doOptimize();
resultComputed = true;
return result;
}
/**
* Set the value at the optimum.
*
* @param functionValue Value of the objective function at the optimum.
*/
protected void setFunctionValue(double functionValue) {
this.functionValue = functionValue;
return doOptimize();
}
/** {@inheritDoc} */
public double optimize(UnivariateRealFunction f, GoalType goal,
double min, double max)
throws MaxIterationsExceededException, FunctionEvaluationException {
public UnivariateRealPointValuePair optimize(UnivariateRealFunction f,
GoalType goal,
double min, double max)
throws FunctionEvaluationException {
return optimize(f, goal, min, max, min + 0.5 * (max - min));
}
/**
* {@inheritDoc}
*/
public void setConvergenceChecker(ConvergenceChecker<UnivariateRealPointValuePair> checker) {
this.checker = checker;
}
/**
* {@inheritDoc}
*/
public ConvergenceChecker<UnivariateRealPointValuePair> getConvergenceChecker() {
return checker;
}
/**
* Method for implementing actual optimization algorithms in derived
* classes.
*
* @return the optimum.
* @throws MaxIterationsExceededException if the maximum iteration count
* @return the optimum and its corresponding function value.
* @throws TooManyEvaluationsException if the maximal number of evaluations
* is exceeded.
* @throws FunctionEvaluationException if an error occurs evaluating
* the function.
*/
protected abstract double doOptimize()
throws MaxIterationsExceededException, FunctionEvaluationException;
protected abstract UnivariateRealPointValuePair doOptimize()
throws FunctionEvaluationException;
}

View File

@ -0,0 +1,88 @@
/*
* 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.univariate;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.BaseOptimizer;
import org.apache.commons.math.optimization.GoalType;
/**
* This interface is mainly intended to enforce the internal coherence of
* Commons-Math. Users of the API are advised to base their code on
* the following interfaces:
* <ul>
* <li>{@link org.apache.commons.math.optimization.univariate.UnivariateRealOptimizer}</li>
* </ul>
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public interface BaseUnivariateRealOptimizer<FUNC extends UnivariateRealFunction>
extends BaseOptimizer<UnivariateRealPointValuePair> {
/**
* Find an optimum in the given interval.
*
* An optimizer may require that the interval brackets a single optimum.
*
* @param f Function to optimize.
* @param goalType Type of optimization goal: either
* {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}.
* @param min Lower bound for the interval.
* @param max Upper bound for the interval.
* @return a (point, value) pair where the function is optimum.
* @throws {@link org.apache.commons.math.exception.TooManyEvaluationsException}
* if the maximum evaluation count is exceeded.
* @throws {@link org.apache.commons.math.exception.ConvergenceException}
* if the optimizer detects a convergence problem.
* @throws FunctionEvaluationException if an error occurs evaluating the
* function.
* @throws IllegalArgumentException if {@code min > max} or the endpoints
* do not satisfy the requirements specified by the optimizer.
*/
UnivariateRealPointValuePair optimize(FUNC f, GoalType goalType,
double min, double max)
throws FunctionEvaluationException;
/**
* Find an optimum in the given interval, start at startValue.
* An optimizer may require that the interval brackets a single optimum.
*
* @param f Function to optimize.
* @param goalType Type of optimization goal: either
* {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}.
* @param min Lower bound for the interval.
* @param max Upper bound for the interval.
* @param startValue Start value to use.
* @return a (point, value) pair where the function is optimum.
* @throws {@link org.apache.commons.math.exception.TooManyEvaluationsException}
* if the maximum evaluation count is exceeded.
* @throws {@link org.apache.commons.math.exception.ConvergenceException}
* if the optimizer detects a convergence problem.
* @throws FunctionEvaluationException if an error occurs evaluating the
* function.
* @throws IllegalArgumentException if {@code min > max} or the endpoints
* do not satisfy the requirements specified by the optimizer.
*/
UnivariateRealPointValuePair optimize(FUNC f, GoalType goalType,
double min, double max,
double startValue)
throws FunctionEvaluationException;
}

View File

@ -16,9 +16,11 @@
*/
package org.apache.commons.math.optimization.univariate;
import org.apache.commons.math.util.Incrementor;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.GoalType;
@ -26,6 +28,7 @@ import org.apache.commons.math.optimization.GoalType;
* Provide an interval that brackets a local optimum of a function.
* This code is based on a Python implementation (from <em>SciPy</em>,
* module {@code optimize.py} v0.5).
*
* @version $Revision$ $Date$
* @since 2.2
*/
@ -41,17 +44,9 @@ public class BracketFinder {
*/
private final double growLimit;
/**
* Maximum number of iterations.
* Counter for function evaluations.
*/
private final int maxIterations;
/**
* Number of iterations.
*/
private int iterations;
/**
* Number of function evaluations.
*/
private int evaluations;
private final Incrementor evaluations = new Incrementor();
/**
* Lower bound of the bracket.
*/
@ -89,20 +84,20 @@ public class BracketFinder {
* Create a bracketing interval finder.
*
* @param growLimit Expanding factor.
* @param maxIterations Maximum number of iterations allowed for finding
* @param maxEvaluations Maximum number of evaluations allowed for finding
* a bracketing interval.
*/
public BracketFinder(double growLimit,
int maxIterations) {
int maxEvaluations) {
if (growLimit <= 0) {
throw new NotStrictlyPositiveException(growLimit);
}
if (maxIterations <= 0) {
throw new NotStrictlyPositiveException(maxIterations);
if (maxEvaluations <= 0) {
throw new NotStrictlyPositiveException(maxEvaluations);
}
this.growLimit = growLimit;
this.maxIterations = maxIterations;
evaluations.setMaximalCount(maxEvaluations);
}
/**
@ -112,7 +107,7 @@ public class BracketFinder {
* @param goal {@link GoalType Goal type}.
* @param xA Initial point.
* @param xB Initial point.
* @throws MaxIterationsExceededException if the maximum iteration count
* @throws TooManyEvaluationsException if the maximum number of evaluations
* is exceeded.
* @throws FunctionEvaluationException if an error occurs evaluating
* the function.
@ -121,9 +116,8 @@ public class BracketFinder {
GoalType goal,
double xA,
double xB)
throws MaxIterationsExceededException,
FunctionEvaluationException {
reset();
throws FunctionEvaluationException {
evaluations.resetCount();
final boolean isMinim = goal == GoalType.MINIMIZE;
double fA = eval(func, xA);
@ -131,6 +125,7 @@ public class BracketFinder {
if (isMinim ?
fA < fB :
fA > fB) {
double tmp = xA;
xA = xB;
xB = tmp;
@ -144,10 +139,6 @@ public class BracketFinder {
double fC = eval(func, xC);
while (isMinim ? fC < fB : fC > fB) {
if (++iterations > maxIterations) {
throw new MaxIterationsExceededException(maxIterations);
}
double tmp1 = (xB - xA) * (fB - fC);
double tmp2 = (xB - xC) * (fB - fA);
@ -187,7 +178,7 @@ public class BracketFinder {
fW > fC) {
xB = xC;
xC = w;
w = xC + GOLD * (xC -xB);
w = xC + GOLD * (xC - xB);
fB = fC;
fC =fW;
fW = eval(func, w);
@ -198,37 +189,48 @@ public class BracketFinder {
}
xA = xB;
xB = xC;
xC = w;
fA = fB;
xB = xC;
fB = fC;
xC = w;
fC = fW;
}
lo = xA;
mid = xB;
hi = xC;
fLo = fA;
mid = xB;
fMid = fB;
hi = xC;
fHi = fC;
if (lo > hi) {
double tmp = lo;
lo = hi;
hi = tmp;
tmp = fLo;
fLo = fHi;
fHi = tmp;
}
}
/**
* @return the number of iterations.
* @return the number of evalutations.
*/
public int getIterations() {
return iterations;
public int getMaxEvaluations() {
return evaluations.getMaximalCount();
}
/**
* @return the number of evalutations.
*/
public int getEvaluations() {
return evaluations;
return evaluations.getCount();
}
/**
* @return the lower bound of the bracket.
* @see #getFLow()
* @see #getFLo()
*/
public double getLo() {
return lo;
@ -238,7 +240,7 @@ public class BracketFinder {
* Get function value at {@link #getLo()}.
* @return function value at {@link #getLo()}
*/
public double getFLow() {
public double getFLo() {
return fLo;
}
@ -278,21 +280,18 @@ public class BracketFinder {
* @param f Function.
* @param x Argument.
* @return {@code f(x)}
* @throws FunctionEvaluationException if function cannot be evaluated at x
* @throws FunctionEvaluationException if function cannot be evaluated.
* @throws TooManyEvaluationsException if the maximal number of evaluations is
* exceeded.
*/
private double eval(UnivariateRealFunction f,
double x)
throws FunctionEvaluationException {
++evaluations;
try {
evaluations.incrementCount();
} catch (MaxCountExceededException e) {
throw new TooManyEvaluationsException(e.getMax());
}
return f.value(x);
}
/**
* Reset internal state.
*/
private void reset() {
iterations = 0;
evaluations = 0;
}
}

View File

@ -17,16 +17,28 @@
package org.apache.commons.math.optimization.univariate;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.util.MathUtils;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.NumberIsTooSmallException;
import org.apache.commons.math.exception.NotStrictlyPositiveException;
import org.apache.commons.math.exception.MathUnsupportedOperationException;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.optimization.AbstractConvergenceChecker;
import org.apache.commons.math.optimization.GoalType;
/**
* Implements Richard Brent's algorithm (from his book "Algorithms for
* Minimization without Derivatives", p. 79) for finding minima of real
* univariate functions. This implementation is an adaptation partly
* based on the Python code from SciPy (module "optimize.py" v0.5).
* If the function is defined on some interval {@code (lo, hi)}, then
* this method finds an approximation {@code x} to the point at which
* the function attains its minimum.
* <br/>
* The user is responsible for calling {@link
* #setConvergenceChecker(ConvergenceChecker) ConvergenceChecker}
* prior to using the optimizer.
*
* @version $Revision$ $Date$
* @since 2.0
@ -38,57 +50,105 @@ public class BrentOptimizer extends AbstractUnivariateRealOptimizer {
private static final double GOLDEN_SECTION = 0.5 * (3 - FastMath.sqrt(5));
/**
* Construct a solver.
* Convergence checker that implements the original stopping criterion
* of Brent's algorithm.
* {@code abs} and {@code rel} define a tolerance
* {@code tol = rel |x| + abs}. {@code rel} should be no smaller than
* <em>2 macheps</em> and preferably not much less than <em>sqrt(macheps)</em>,
* where <em>macheps</em> is the relative machine precision. {@code abs} must
* be positive.
*
* @since 3.0
*/
public BrentOptimizer() {
setMaxEvaluations(1000);
setMaximalIterationCount(100);
setAbsoluteAccuracy(1e-11);
setRelativeAccuracy(1e-9);
}
public static class BrentConvergenceChecker
extends AbstractConvergenceChecker<UnivariateRealPointValuePair> {
/**
* Minimum relative tolerance.
*/
private static final double MIN_RELATIVE_TOLERANCE = 2 * FastMath.ulp(1d);
/** {@inheritDoc} */
protected double doOptimize()
throws MaxIterationsExceededException, FunctionEvaluationException {
return localMin(getGoalType() == GoalType.MINIMIZE,
getMin(), getStartValue(), getMax(),
getRelativeAccuracy(), getAbsoluteAccuracy());
/**
* Build an instance with specified thresholds.
*
* @param rel Relative tolerance threshold
* @param abs Absolute tolerance threshold
*/
public BrentConvergenceChecker(final double rel,
final double abs) {
super(rel, abs);
if (rel < MIN_RELATIVE_TOLERANCE) {
throw new NumberIsTooSmallException(rel, MIN_RELATIVE_TOLERANCE, true);
}
if (abs <= 0) {
throw new NotStrictlyPositiveException(abs);
}
}
/**
* Convergence criterion.
*
* @param iteration Current iteration.
* @param points Points used for checking the stopping criterion. The list
* must contain 3 points (in the following order):
* <ul>
* <li>the lower end of the current interval</li>
* <li>the current best point</li>
* <li>the higher end of the current interval</li>
* </ul>
* @return {@code true} if the stopping criterion is satisfied.
* @throws DimensionMismatchException if the length of the {@code points}
* list is not equal to 3.
*/
public boolean converged(final int iteration,
final UnivariateRealPointValuePair ... points) {
if (points.length != 3) {
throw new DimensionMismatchException(points.length, 3);
}
final double a = points[0].getPoint();
final double x = points[1].getPoint();
final double b = points[2].getPoint();
final double tol1 = getRelativeThreshold() * FastMath.abs(x) + getAbsoluteThreshold();
final double tol2 = 2 * tol1;
final double m = 0.5 * (a + b);
return FastMath.abs(x - m) <= tol2 - 0.5 * (b - a);
}
}
/**
* Find the minimum of the function within the interval {@code (lo, hi)}.
* Set the convergence checker.
* Since this algorithm requires a specific checker, this method will throw
* an {@code UnsupportedOperationexception} if the argument type is not
* {@link BrentConvergenceChecker}.
*
* If the function is defined on the interval {@code (lo, hi)}, then
* this method finds an approximation {@code x} to the point at which
* the function attains its minimum.<br/>
* {@code t} and {@code eps} define a tolerance {@code tol = eps |x| + t}
* and the function is never evaluated at two points closer together than
* {@code tol}. {@code eps} should be no smaller than <em>2 macheps</em> and
* preferable not much less than <em>sqrt(macheps)</em>, where
* <em>macheps</em> is the relative machine precision. {@code t} should be
* positive.
* @param isMinim {@code true} when minimizing the function.
* @param lo Lower bound of the interval.
* @param mid Point inside the interval {@code [lo, hi]}.
* @param hi Higher bound of the interval.
* @param eps Relative accuracy.
* @param t Absolute accuracy.
* @return the optimum point.
* @throws MaxIterationsExceededException if the maximum iteration count
* is exceeded.
* @throws FunctionEvaluationException if an error occurs evaluating
* the function.
* @throws MathUnsupportedOperationexception if the checker is not an
* instance of {@link BrentConvergenceChecker}.
*/
private double localMin(boolean isMinim,
double lo, double mid, double hi,
double eps, double t)
throws MaxIterationsExceededException, FunctionEvaluationException {
if (eps <= 0) {
throw new NotStrictlyPositiveException(eps);
}
if (t <= 0) {
throw new NotStrictlyPositiveException(t);
@Override
public void setConvergenceChecker(ConvergenceChecker<UnivariateRealPointValuePair> checker) {
if (checker instanceof BrentConvergenceChecker) {
super.setConvergenceChecker(checker);
} else {
throw new MathUnsupportedOperationException();
}
}
/** {@inheritDoc} */
protected UnivariateRealPointValuePair doOptimize()
throws FunctionEvaluationException {
final boolean isMinim = (getGoalType() == GoalType.MINIMIZE);
final double lo = getMin();
final double mid = getStartValue();
final double hi = getMax();
final ConvergenceChecker<UnivariateRealPointValuePair> checker
= getConvergenceChecker();
final double eps = checker.getRelativeThreshold();
final double t = checker.getAbsoluteThreshold();
double a;
double b;
if (lo < hi) {
@ -111,13 +171,19 @@ public class BrentOptimizer extends AbstractUnivariateRealOptimizer {
double fv = fx;
double fw = fx;
int iter = 0;
while (true) {
double m = 0.5 * (a + b);
final double tol1 = eps * FastMath.abs(x) + t;
final double tol2 = 2 * tol1;
// Check stopping criterion.
if (FastMath.abs(x - m) > tol2 - 0.5 * (b - a)) {
// This test will work only if the "checker" is an instance of
// "BrentOptimizer.BrentConvergenceChecker".
if (!getConvergenceChecker().converged(iter,
new UnivariateRealPointValuePair(a, Double.NaN),
new UnivariateRealPointValuePair(x, Double.NaN),
new UnivariateRealPointValuePair(b, Double.NaN))) {
double p = 0;
double q = 0;
double r = 0;
@ -217,11 +283,10 @@ public class BrentOptimizer extends AbstractUnivariateRealOptimizer {
fv = fu;
}
}
} else { // termination
setFunctionValue(isMinim ? fx : -fx);
return x;
} else { // Termination.
return new UnivariateRealPointValuePair(x, (isMinim ? fx : -fx));
}
incrementIterationsCounter();
++iter;
}
}
}

View File

@ -0,0 +1,211 @@
/*
* 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.univariate;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.random.RandomGenerator;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.ConvergenceChecker;
import org.apache.commons.math.util.FastMath;
/**
* Special implementation of the {@link UnivariateRealOptimizer} interface
* adding multi-start features to an existing optimizer.
*
* This class wraps a classical optimizer to use it several times in
* turn with different starting points in order to avoid being trapped
* into a local extremum when looking for a global one.
*
* @param <FUNC> Type of the objective function to be optimized.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public class MultiStartUnivariateRealOptimizer<FUNC extends UnivariateRealFunction>
implements BaseUnivariateRealOptimizer<FUNC> {
/** Underlying classical optimizer. */
private final BaseUnivariateRealOptimizer<FUNC> optimizer;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed for all starts. */
private int totalEvaluations;
/** Number of starts to go. */
private int starts;
/** Random generator for multi-start. */
private RandomGenerator generator;
/** Found optima. */
private UnivariateRealPointValuePair[] optima;
/**
* Create a multi-start optimizer from a single-start optimizer.
*
* @param optimizer Single-start optimizer to wrap.
* @param starts Number of starts to perform (including the
* first one), multi-start is disabled if value is less than or
* equal to 1.
* @param generator Random generator to use for restarts.
*/
public MultiStartUnivariateRealOptimizer(final BaseUnivariateRealOptimizer<FUNC> optimizer,
final int starts,
final RandomGenerator generator) {
this.optimizer = optimizer;
this.starts = starts;
this.generator = generator;
}
/**
* {@inheritDoc}
*/
public void setConvergenceChecker(ConvergenceChecker<UnivariateRealPointValuePair> checker) {
optimizer.setConvergenceChecker(checker);
}
/**
* {@inheritDoc}
*/
public ConvergenceChecker<UnivariateRealPointValuePair> getConvergenceChecker() {
return optimizer.getConvergenceChecker();
}
/** {@inheritDoc} */
public int getMaxEvaluations() {
return maxEvaluations;
}
/** {@inheritDoc} */
public int getEvaluations() {
return totalEvaluations;
}
/** {@inheritDoc} */
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = maxEvaluations;
optimizer.setMaxEvaluations(maxEvaluations);
}
/**
* Get all the optima found during the last call to {@link
* #optimize(FUNC,GoalType,double,double) optimize}.
* The optimizer stores all the optima found during a set of
* restarts. The {@link #optimize(FUNC,GoalType,double,double) optimize}
* method returns the best point only. This method returns all the points
* found at the end of each starts, including the best one already
* returned by the {@link #optimize(FUNC,GoalType,double,double) optimize}
* method.
* <br/>
* The returned array as one element for each start as specified
* in the constructor. It is ordered with the results from the
* runs that did converge first, sorted from best to worst
* objective value (i.e in ascending order if minimizing and in
* descending order if maximizing), followed by {@code null} elements
* corresponding to the runs that did not converge. This means all
* elements will be {@code null} if the {@link
* #optimize(FUNC,GoalType,double,double) optimize} method did throw a
* {@link ConvergenceException}). This also means that if the first
* element is not {@code null}, it is the best point found across all
* starts.
*
* @return an array containing the optima.
* @throws MathIllegalStateException if {@link
* #optimize(FUNC,GoalType,double,double) optimize} has not been called.
*/
public UnivariateRealPointValuePair[] getOptima() {
if (optima == null) {
throw new MathIllegalStateException(LocalizedFormats.NO_OPTIMUM_COMPUTED_YET);
}
return optima.clone();
}
/** {@inheritDoc} */
public UnivariateRealPointValuePair optimize(final FUNC f,
final GoalType goal,
final double min, final double max)
throws FunctionEvaluationException {
optima = new UnivariateRealPointValuePair[starts];
totalEvaluations = 0;
// Multi-start loop.
for (int i = 0; i < starts; ++i) {
try {
final double bound1 = (i == 0) ? min : min + generator.nextDouble() * (max - min);
final double bound2 = (i == 0) ? max : min + generator.nextDouble() * (max - min);
optima[i] = optimizer.optimize(f, goal,
FastMath.min(bound1, bound2),
FastMath.max(bound1, bound2));
} catch (FunctionEvaluationException fee) {
optima[i] = null;
} catch (ConvergenceException ce) {
optima[i] = null;
}
final int usedEvaluations = optimizer.getEvaluations();
optimizer.setMaxEvaluations(optimizer.getMaxEvaluations() - usedEvaluations);
totalEvaluations += usedEvaluations;
}
sortPairs(goal);
if (optima[0] == null) {
throw new ConvergenceException(LocalizedFormats.NO_CONVERGENCE_WITH_ANY_START_POINT,
starts);
}
// Return the point with the best objective function value.
return optima[0];
}
/** {@inheritDoc} */
public UnivariateRealPointValuePair optimize(final FUNC f, final GoalType goalType,
final double min, final double max,
final double startValue)
throws FunctionEvaluationException {
// XXX Main code should be here, using "startValue" for the first start.
// XXX This method should set "startValue" to min + 0.5 * (max - min)
return optimize(f, goalType, min, max);
}
/**
* Sort the optima from best to worst, followed by {@code null} elements.
*
* @param goal Goal type.
*/
private void sortPairs(final GoalType goal) {
Arrays.sort(optima, new Comparator<UnivariateRealPointValuePair>() {
public int compare(final UnivariateRealPointValuePair o1,
final UnivariateRealPointValuePair o2) {
if (o1 == null) {
return (o2 == null) ? 0 : 1;
} else if (o2 == null) {
return -1;
}
final double v1 = o1.getValue();
final double v2 = o2.getValue();
return (goal == GoalType.MINIMIZE) ?
Double.compare(v1, v2) : Double.compare(v2, v1);
}
});
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.univariate;
import org.apache.commons.math.analysis.UnivariateRealFunction;
/**
* Interface for univariate optimization algorithms.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public interface UnivariateRealOptimizer
extends BaseUnivariateRealOptimizer<UnivariateRealFunction> {}

View File

@ -0,0 +1,67 @@
/*
* 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.univariate;
import java.io.Serializable;
/**
* This class holds a point and the value of an objective function at this
* point.
* This is a simple immutable container.
*
* @version $Revision$ $Date$
* @since 3.0
*/
public class UnivariateRealPointValuePair implements Serializable {
/** Serializable version identifier. */
private static final long serialVersionUID = 1003888396256744753L;
/** Point. */
private final double point;
/** Value of the objective function at the point. */
private final double value;
/**
* Build a point/objective function value pair.
*
* @param point Point.
* @param value Value of an objective function at the point
*/
public UnivariateRealPointValuePair(final double point,
final double value) {
this.point = point;
this.value = value;
}
/**
* Get the point.
*
* @return the point.
*/
public double getPoint() {
return point;
}
/**
* Get the value of the objective function.
*
* @return the stored value of the objective function.
*/
public double getValue() {
return value;
}
}

View File

@ -51,6 +51,17 @@ The <action> type attribute can be add,update,fix,remove.
with a new-line in the release notes. (These spaces are ignored when displaying HTML).
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="3.0" date="TBD" description="TBD">
<action dev="erans" type="update" issue="MATH-397">
Removed methods referring to the concept of "iteration".
Removed interface methods to access the number of evaluations of the
gradient and Jacobian.
Added new "Incrementor" utility to be used as a bounded counter for
objective function evaluations.
Removed all references to "OptimizationException" (replaced by
"ConvergenceException").
</action>
</release>
<release version="2.2" date="TBD" description="TBD">
<action dev="luc" type="fix" issue="MATH-375" due-to="Bill Rossi">
Added faster and more accurate version of traditional mathematical functions in a FastMath

View File

@ -39,7 +39,7 @@ import org.junit.Test;
public class MultiStartDifferentiableMultivariateRealOptimizerTest {
@Test
public void testCircleFitting() throws FunctionEvaluationException, OptimizationException {
public void testCircleFitting() throws FunctionEvaluationException {
Circle circle = new Circle();
circle.addPoint( 30.0, 68.0);
circle.addPoint( 50.0, -6.0);
@ -55,14 +55,10 @@ public class MultiStartDifferentiableMultivariateRealOptimizerTest {
new GaussianRandomGenerator(g));
MultiStartDifferentiableMultivariateRealOptimizer optimizer =
new MultiStartDifferentiableMultivariateRealOptimizer(underlying, 10, generator);
optimizer.setMaxIterations(100);
assertEquals(100, optimizer.getMaxIterations());
optimizer.setMaxEvaluations(100);
assertEquals(100, optimizer.getMaxEvaluations());
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-10));
BrentSolver solver = new BrentSolver();
solver.setAbsoluteAccuracy(1.0e-13);
solver.setRelativeAccuracy(1.0e-15);
RealPointValuePair optimum =
optimizer.optimize(circle, GoalType.MINIMIZE, new double[] { 98.680, 47.345 });
RealPointValuePair[] optima = optimizer.getOptima();
@ -72,12 +68,8 @@ public class MultiStartDifferentiableMultivariateRealOptimizerTest {
assertEquals(96.075902096, center.x, 1.0e-8);
assertEquals(48.135167894, center.y, 1.0e-8);
}
assertTrue(optimizer.getGradientEvaluations() > 650);
assertTrue(optimizer.getGradientEvaluations() < 700);
assertTrue(optimizer.getEvaluations() > 70);
assertTrue(optimizer.getEvaluations() < 90);
assertTrue(optimizer.getIterations() > 70);
assertTrue(optimizer.getIterations() < 90);
assertEquals(3.1267527, optimum.getValue(), 1.0e-8);
}
@ -119,7 +111,6 @@ public class MultiStartDifferentiableMultivariateRealOptimizerTest {
dJdY *= 2;
return new double[] { dJdX, dJdY };
}
public double value(double[] variables)
@ -133,9 +124,7 @@ public class MultiStartDifferentiableMultivariateRealOptimizerTest {
double di = point.distance(center) - radius;
sum += di * di;
}
return sum;
}
public MultivariateVectorialFunction gradient() {
@ -153,7 +142,5 @@ public class MultiStartDifferentiableMultivariateRealOptimizerTest {
}
};
}
}
}

View File

@ -24,6 +24,7 @@ import static org.junit.Assert.fail;
import java.io.Serializable;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.linear.BlockRealMatrix;
@ -112,7 +113,7 @@ public class MultiStartDifferentiableMultivariateVectorialOptimizerTest {
MultiStartDifferentiableMultivariateVectorialOptimizer optimizer =
new MultiStartDifferentiableMultivariateVectorialOptimizer(underlyingOptimizer,
10, generator);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
// no optima before first optimization attempt
@ -134,14 +135,10 @@ public class MultiStartDifferentiableMultivariateVectorialOptimizerTest {
}
assertTrue(optimizer.getEvaluations() > 20);
assertTrue(optimizer.getEvaluations() < 50);
assertTrue(optimizer.getIterations() > 20);
assertTrue(optimizer.getIterations() < 50);
assertTrue(optimizer.getJacobianEvaluations() > 20);
assertTrue(optimizer.getJacobianEvaluations() < 50);
assertEquals(100, optimizer.getMaxIterations());
assertEquals(100, optimizer.getMaxEvaluations());
}
@Test(expected = OptimizationException.class)
@Test(expected = ConvergenceException.class)
public void testNoOptimum() throws FunctionEvaluationException, OptimizationException {
DifferentiableMultivariateVectorialOptimizer underlyingOptimizer =
new GaussNewtonOptimizer(true);
@ -152,7 +149,7 @@ public class MultiStartDifferentiableMultivariateVectorialOptimizerTest {
MultiStartDifferentiableMultivariateVectorialOptimizer optimizer =
new MultiStartDifferentiableMultivariateVectorialOptimizer(underlyingOptimizer,
10, generator);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
optimizer.optimize(new DifferentiableMultivariateVectorialFunction() {
public MultivariateMatrixFunction jacobian() {

View File

@ -48,13 +48,13 @@ public class MultiStartMultivariateRealOptimizerTest {
MultiStartMultivariateRealOptimizer optimizer =
new MultiStartMultivariateRealOptimizer(underlying, 10, generator);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(1100);
RealPointValuePair optimum =
optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1.0 });
assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
assertTrue(optimizer.getEvaluations() > 20);
assertTrue(optimizer.getEvaluations() < 250);
assertTrue(optimizer.getEvaluations() > 900);
assertTrue(optimizer.getEvaluations() < 1200);
assertTrue(optimum.getValue() < 8.0e-4);
}

View File

@ -91,7 +91,7 @@ public class MultiDirectionalTest {
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-11, 1.0e-30));
optimizer.setMaxIterations(200);
optimizer.setMaxEvaluations(200);
optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
RealPointValuePair optimum;
@ -146,7 +146,7 @@ public class MultiDirectionalTest {
count = 0;
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setStartConfiguration(new double[][] {
{ -1.2, 1.0 }, { 0.9, 1.2 } , { 3.5, -2.3 }
});
@ -180,7 +180,7 @@ public class MultiDirectionalTest {
count = 0;
MultiDirectional optimizer = new MultiDirectional();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxIterations(1000);
optimizer.setMaxEvaluations(1000);
RealPointValuePair optimum =
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
Assert.assertEquals(count, optimizer.getEvaluations());
@ -196,7 +196,6 @@ public class MultiDirectionalTest {
// fails because MultiDirectional.iterateSimplex is looping forever
// the while(true) should be replaced with a convergence check
MultiDirectional multiDirectional = new MultiDirectional();
multiDirectional.setMaxIterations(100);
multiDirectional.setMaxEvaluations(1000);
final Gaussian2D function = new Gaussian2D(0.0, 0.0, 1.0);

View File

@ -23,315 +23,278 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.MaxIterationsExceededException;
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.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.optimization.SimpleRealPointChecker;
import org.apache.commons.math.optimization.SimpleScalarValueChecker;
import org.apache.commons.math.util.FastMath;
import org.junit.Test;
public class NelderMeadTest {
@Test
public void testFunctionEvaluationExceptions() {
MultivariateRealFunction wrong =
new MultivariateRealFunction() {
private static final long serialVersionUID = 4751314470965489371L;
public double value(double[] x) throws FunctionEvaluationException {
if (x[0] < 0) {
throw new FunctionEvaluationException(x, "{0}", "oops");
} else if (x[0] > 1) {
throw new FunctionEvaluationException(new RuntimeException("oops"), x);
} else {
return x[0] * (1 - x[0]);
@Test
public void testFunctionEvaluationExceptions() {
MultivariateRealFunction wrong =
new MultivariateRealFunction() {
private static final long serialVersionUID = 4751314470965489371L;
public double value(double[] x) throws FunctionEvaluationException {
if (x[0] < 0) {
throw new FunctionEvaluationException(x, "{0}", "oops");
} else if (x[0] > 1) {
throw new FunctionEvaluationException(new RuntimeException("oops"), x);
} else {
return x[0] * (1 - x[0]);
}
}
}
};
try {
NelderMead optimizer = new NelderMead(0.9, 1.9, 0.4, 0.6);
optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { -1.0 });
fail("an exception should have been thrown");
} catch (FunctionEvaluationException ce) {
// expected behavior
assertNull(ce.getCause());
} catch (Exception e) {
fail("wrong exception caught: " + e.getMessage());
}
try {
NelderMead optimizer = new NelderMead(0.9, 1.9, 0.4, 0.6);
optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { +2.0 });
fail("an exception should have been thrown");
} catch (FunctionEvaluationException ce) {
// expected behavior
assertNotNull(ce.getCause());
} catch (Exception e) {
fail("wrong exception caught: " + e.getMessage());
}
}
};
try {
NelderMead optimizer = new NelderMead(0.9, 1.9, 0.4, 0.6);
optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { -1.0 });
fail("an exception should have been thrown");
} catch (FunctionEvaluationException ce) {
// expected behavior
assertNull(ce.getCause());
} catch (Exception e) {
fail("wrong exception caught: " + e.getMessage());
}
try {
NelderMead optimizer = new NelderMead(0.9, 1.9, 0.4, 0.6);
optimizer.optimize(wrong, GoalType.MINIMIZE, new double[] { +2.0 });
fail("an exception should have been thrown");
} catch (FunctionEvaluationException ce) {
// expected behavior
assertNotNull(ce.getCause());
} catch (Exception e) {
fail("wrong exception caught: " + e.getMessage());
}
}
@Test
public void testMinimizeMaximize()
throws FunctionEvaluationException, ConvergenceException {
@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));
}
};
// 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));
}
};
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxIterations(100);
optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
RealPointValuePair optimum;
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-10, 1.0e-30));
optimizer.setMaxEvaluations(100);
optimizer.setStartConfiguration(new double[] { 0.2, 0.2 });
RealPointValuePair optimum;
// minimization
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { -3.0, 0 });
assertEquals(xM, optimum.getPoint()[0], 2.0e-7);
assertEquals(yP, optimum.getPoint()[1], 2.0e-5);
assertEquals(valueXmYp, optimum.getValue(), 6.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
// minimization
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { -3.0, 0 });
assertEquals(xM, optimum.getPoint()[0], 2.0e-7);
assertEquals(yP, optimum.getPoint()[1], 2.0e-5);
assertEquals(valueXmYp, optimum.getValue(), 6.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { +1, 0 });
assertEquals(xP, optimum.getPoint()[0], 5.0e-6);
assertEquals(yM, optimum.getPoint()[1], 6.0e-6);
assertEquals(valueXpYm, optimum.getValue(), 1.0e-11);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
optimum = optimizer.optimize(fourExtrema, GoalType.MINIMIZE, new double[] { +1, 0 });
assertEquals(xP, optimum.getPoint()[0], 5.0e-6);
assertEquals(yM, optimum.getPoint()[1], 6.0e-6);
assertEquals(valueXpYm, optimum.getValue(), 1.0e-11);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
// maximization
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { -3.0, 0.0 });
assertEquals(xM, optimum.getPoint()[0], 1.0e-5);
assertEquals(yM, optimum.getPoint()[1], 3.0e-6);
assertEquals(valueXmYm, optimum.getValue(), 3.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
// maximization
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { -3.0, 0.0 });
assertEquals(xM, optimum.getPoint()[0], 1.0e-5);
assertEquals(yM, optimum.getPoint()[1], 3.0e-6);
assertEquals(valueXmYm, optimum.getValue(), 3.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { +1, 0 });
assertEquals(xP, optimum.getPoint()[0], 4.0e-6);
assertEquals(yP, optimum.getPoint()[1], 5.0e-6);
assertEquals(valueXpYp, optimum.getValue(), 7.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
optimum = optimizer.optimize(fourExtrema, GoalType.MAXIMIZE, new double[] { +1, 0 });
assertEquals(xP, optimum.getPoint()[0], 4.0e-6);
assertEquals(yP, optimum.getPoint()[1], 5.0e-6);
assertEquals(valueXpYp, optimum.getValue(), 7.0e-12);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 90);
}
}
@Test
public void testRosenbrock()
throws FunctionEvaluationException {
@Test
public void testRosenbrock()
throws FunctionEvaluationException, ConvergenceException {
Rosenbrock rosenbrock = new Rosenbrock();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1, 1.0e-3));
optimizer.setMaxEvaluations(100);
optimizer.setStartConfiguration(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.0 });
Rosenbrock rosenbrock = new Rosenbrock();
NelderMead optimizer = new NelderMead();
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 }
});
RealPointValuePair optimum =
optimizer.optimize(rosenbrock, GoalType.MINIMIZE, new double[] { -1.2, 1.0 });
assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
assertTrue(optimizer.getEvaluations() > 40);
assertTrue(optimizer.getEvaluations() < 50);
assertTrue(optimum.getValue() < 8.0e-4);
}
assertEquals(rosenbrock.getCount(), optimizer.getEvaluations());
assertTrue(optimizer.getEvaluations() > 40);
assertTrue(optimizer.getEvaluations() < 50);
assertTrue(optimum.getValue() < 8.0e-4);
@Test
public void testPowell()
throws FunctionEvaluationException {
}
Powell powell = new Powell();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxEvaluations(200);
RealPointValuePair optimum =
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
assertEquals(powell.getCount(), optimizer.getEvaluations());
assertTrue(optimizer.getEvaluations() > 110);
assertTrue(optimizer.getEvaluations() < 130);
assertTrue(optimum.getValue() < 2.0e-3);
}
@Test
public void testPowell()
throws FunctionEvaluationException, ConvergenceException {
@Test
public void testLeastSquares1()
throws FunctionEvaluationException {
Powell powell = new Powell();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxIterations(200);
RealPointValuePair optimum =
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
assertEquals(powell.getCount(), optimizer.getEvaluations());
assertTrue(optimizer.getEvaluations() > 110);
assertTrue(optimizer.getEvaluations() < 130);
assertTrue(optimum.getValue() < 2.0e-3);
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 });
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxEvaluations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 3.0e-5);
assertEquals(-3.0, optimum.getPointRef()[1], 4.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
}
@Test
public void testLeastSquares2()
throws FunctionEvaluationException {
@Test
public void testLeastSquares1()
throws FunctionEvaluationException, ConvergenceException {
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 }, new double[] { 10.0, 0.1 });
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxEvaluations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 5.0e-5);
assertEquals(-3.0, optimum.getPointRef()[1], 8.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 });
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxIterations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 3.0e-5);
assertEquals(-3.0, optimum.getPointRef()[1], 4.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
@Test
public void testLeastSquares3()
throws FunctionEvaluationException {
@Test
public void testLeastSquares2()
throws FunctionEvaluationException, ConvergenceException {
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 }, new Array2DRowRealMatrix(new double [][] {
{ 1.0, 1.2 }, { 1.2, 2.0 }
}));
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxEvaluations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 2.0e-3);
assertEquals(-3.0, optimum.getPointRef()[1], 8.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 }, new double[] { 10.0, 0.1 });
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxIterations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 5.0e-5);
assertEquals(-3.0, optimum.getPointRef()[1], 8.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
@Test(expected = TooManyEvaluationsException.class)
public void testMaxIterations() throws FunctionEvaluationException {
Powell powell = new Powell();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxEvaluations(20);
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
}
@Test
public void testLeastSquares3()
throws FunctionEvaluationException, ConvergenceException {
private static class Rosenbrock implements MultivariateRealFunction {
private int count;
final RealMatrix factors =
new Array2DRowRealMatrix(new double[][] {
{ 1.0, 0.0 },
{ 0.0, 1.0 }
}, false);
LeastSquaresConverter ls = new LeastSquaresConverter(new MultivariateVectorialFunction() {
public double[] value(double[] variables) {
return factors.operate(variables);
}
}, new double[] { 2.0, -3.0 }, new Array2DRowRealMatrix(new double [][] {
{ 1.0, 1.2 }, { 1.2, 2.0 }
}));
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-6));
optimizer.setMaxIterations(200);
RealPointValuePair optimum =
optimizer.optimize(ls, GoalType.MINIMIZE, new double[] { 10.0, 10.0 });
assertEquals( 2.0, optimum.getPointRef()[0], 2.0e-3);
assertEquals(-3.0, optimum.getPointRef()[1], 8.0e-4);
assertTrue(optimizer.getEvaluations() > 60);
assertTrue(optimizer.getEvaluations() < 80);
assertTrue(optimum.getValue() < 1.0e-6);
}
public Rosenbrock() {
count = 0;
}
@Test(expected = MaxIterationsExceededException.class)
public void testMaxIterations() throws MathException {
try {
Powell powell = new Powell();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(-1.0, 1.0e-3));
optimizer.setMaxIterations(20);
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
} catch (OptimizationException oe) {
if (oe.getCause() instanceof ConvergenceException) {
throw (ConvergenceException) oe.getCause();
}
throw oe;
}
}
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;
}
@Test(expected = MaxEvaluationsExceededException.class)
public void testMaxEvaluations() throws MathException {
try {
Powell powell = new Powell();
NelderMead optimizer = new NelderMead();
optimizer.setConvergenceChecker(new SimpleRealPointChecker(-1.0, 1.0e-3));
optimizer.setMaxEvaluations(20);
optimizer.optimize(powell, GoalType.MINIMIZE, new double[] { 3.0, -1.0, 0.0, 1.0 });
} catch (FunctionEvaluationException fee) {
if (fee.getCause() instanceof ConvergenceException) {
throw (ConvergenceException) fee.getCause();
}
throw fee;
}
}
public int getCount() {
return count;
}
}
private static class Rosenbrock implements MultivariateRealFunction {
private static class Powell implements MultivariateRealFunction {
private int count;
private int count;
public Powell() {
count = 0;
}
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;
}
}
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;
}
}
}

View File

@ -23,8 +23,8 @@ import static org.junit.Assert.assertTrue;
import java.util.Random;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;
import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
import org.apache.commons.math.util.FastMath;
@ -33,7 +33,7 @@ import org.junit.Test;
public class PolynomialFitterTest {
@Test
public void testNoError() throws OptimizationException {
public void testNoError() {
Random randomizer = new Random(64925784252l);
for (int degree = 1; degree < 10; ++degree) {
PolynomialFunction p = buildRandomPolynomial(degree, randomizer);
@ -57,7 +57,7 @@ public class PolynomialFitterTest {
}
@Test
public void testSmallError() throws OptimizationException {
public void testSmallError() {
Random randomizer = new Random(53882150042l);
double maxError = 0;
for (int degree = 0; degree < 10; ++degree) {
@ -116,7 +116,7 @@ public class PolynomialFitterTest {
try {
fitter.fit();
assertTrue(solvable || (degree == 0));
} catch(OptimizationException e) {
} catch(ConvergenceException e) {
assertTrue((! solvable) && (degree > 0));
}

View File

@ -25,11 +25,13 @@ import java.util.Arrays;
import junit.framework.TestCase;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.linear.BlockRealMatrix;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.SimpleVectorialPointChecker;
import org.apache.commons.math.optimization.SimpleVectorialValueChecker;
import org.apache.commons.math.optimization.VectorialPointValuePair;
@ -104,11 +106,11 @@ extends TestCase {
super(name);
}
public void testTrivial() throws FunctionEvaluationException, OptimizationException {
public void testTrivial() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 2 } }, new double[] { 3 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1 }, new double[] { 0 });
@ -117,14 +119,14 @@ extends TestCase {
assertEquals(3.0, optimum.getValue()[0], 1.0e-10);
}
public void testColumnsPermutation() throws FunctionEvaluationException, OptimizationException {
public void testColumnsPermutation() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 1.0, -1.0 }, { 0.0, 2.0 }, { 1.0, -2.0 } },
new double[] { 4.0, 6.0, 1.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(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 });
@ -137,7 +139,7 @@ extends TestCase {
}
public void testNoDependency() throws FunctionEvaluationException, OptimizationException {
public void testNoDependency() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 2, 0, 0, 0, 0, 0 },
{ 0, 2, 0, 0, 0, 0 },
@ -147,7 +149,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.setMaxIterations(100);
optimizer.setMaxEvaluations(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 },
@ -158,7 +160,7 @@ extends TestCase {
}
}
public void testOneSet() throws FunctionEvaluationException, OptimizationException {
public void testOneSet() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1, 0, 0 },
@ -166,7 +168,7 @@ extends TestCase {
{ 0, -1, 1 }
}, new double[] { 1, 1, 1});
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(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 });
@ -177,7 +179,7 @@ extends TestCase {
}
public void testTwoSets() throws FunctionEvaluationException, OptimizationException {
public void testTwoSets() throws FunctionEvaluationException {
double epsilon = 1.0e-7;
LinearProblem problem = new LinearProblem(new double[][] {
{ 2, 1, 0, 4, 0, 0 },
@ -189,7 +191,7 @@ extends TestCase {
}, new double[] { 2, -9, 2, 2, 1 + epsilon * epsilon, 2});
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(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 },
@ -212,19 +214,19 @@ extends TestCase {
{ -3, 0, -9 }
}, new double[] { 1, 1, 1 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(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 });
fail("an exception should have been caught");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception type caught");
}
}
public void testIllConditioned() throws FunctionEvaluationException, OptimizationException {
public void testIllConditioned() throws FunctionEvaluationException {
LinearProblem problem1 = new LinearProblem(new double[][] {
{ 10.0, 7.0, 8.0, 7.0 },
{ 7.0, 5.0, 6.0, 5.0 },
@ -232,7 +234,7 @@ extends TestCase {
{ 7.0, 5.0, 9.0, 10.0 }
}, new double[] { 32, 23, 33, 31 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum1 =
optimizer.optimize(problem1, problem1.target, new double[] { 1, 1, 1, 1 },
@ -269,13 +271,13 @@ extends TestCase {
}, new double[] { 7.0, 3.0, 5.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 },
new double[] { 7, 6, 5, 4 });
fail("an exception should have been caught");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception type caught");
@ -292,20 +294,20 @@ 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.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1, 1, 1 },
new double[] { 2, 2, 2, 2, 2, 2 });
fail("an exception should have been caught");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception type caught");
}
}
public void testRedundantEquations() throws FunctionEvaluationException, OptimizationException {
public void testRedundantEquations() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1.0, 1.0 },
{ 1.0, -1.0 },
@ -313,7 +315,7 @@ extends TestCase {
}, new double[] { 3.0, 1.0, 5.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
optimizer.optimize(problem, problem.target, new double[] { 1, 1, 1 },
@ -324,7 +326,7 @@ extends TestCase {
}
public void testInconsistentEquations() throws FunctionEvaluationException, OptimizationException {
public void testInconsistentEquations() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1.0, 1.0 },
{ 1.0, -1.0 },
@ -332,18 +334,18 @@ extends TestCase {
}, new double[] { 3.0, 1.0, 4.0 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(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);
}
public void testInconsistentSizes() throws FunctionEvaluationException, OptimizationException {
public void testInconsistentSizes() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 1, 0 }, { 0, 1 } }, new double[] { -1, 1 });
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
VectorialPointValuePair optimum =
@ -357,7 +359,7 @@ extends TestCase {
new double[] { 1 },
new double[] { 0, 0 });
fail("an exception should have been thrown");
} catch (OptimizationException oe) {
} catch (DimensionMismatchException oe) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
@ -376,7 +378,7 @@ extends TestCase {
}
public void testMaxIterations() {
public void testMaxEvaluations() {
Circle circle = new Circle();
circle.addPoint( 30.0, 68.0);
circle.addPoint( 50.0, -6.0);
@ -384,21 +386,21 @@ extends TestCase {
circle.addPoint( 35.0, 15.0);
circle.addPoint( 45.0, 97.0);
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialPointChecker(1.0e-30, 1.0e-30));
try {
optimizer.optimize(circle, new double[] { 0, 0, 0, 0, 0 },
new double[] { 1, 1, 1, 1, 1 },
new double[] { 98.680, 47.345 });
fail("an exception should have been caught");
} catch (OptimizationException ee) {
} catch (TooManyEvaluationsException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception type caught");
}
}
public void testCircleFitting() throws FunctionEvaluationException, OptimizationException {
public void testCircleFitting() throws FunctionEvaluationException {
Circle circle = new Circle();
circle.addPoint( 30.0, 68.0);
circle.addPoint( 50.0, -6.0);
@ -406,7 +408,7 @@ extends TestCase {
circle.addPoint( 35.0, 15.0);
circle.addPoint( 45.0, 97.0);
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-13, 1.0e-13));
VectorialPointValuePair optimum =
optimizer.optimize(circle, new double[] { 0, 0, 0, 0, 0 },
@ -419,7 +421,7 @@ extends TestCase {
assertEquals(48.135167894714, center.y, 1.0e-10);
}
public void testCircleFittingBadInit() throws FunctionEvaluationException, OptimizationException {
public void testCircleFittingBadInit() throws FunctionEvaluationException {
Circle circle = new Circle();
double[][] points = new double[][] {
{-0.312967, 0.072366}, {-0.339248, 0.132965}, {-0.379780, 0.202724},
@ -460,12 +462,12 @@ extends TestCase {
circle.addPoint(points[i][0], points[i][1]);
}
GaussNewtonOptimizer optimizer = new GaussNewtonOptimizer(true);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleVectorialValueChecker(1.0e-6, 1.0e-6));
try {
optimizer.optimize(circle, target, weights, new double[] { -12, -12 });
fail("an exception should have been caught");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception type caught");

View File

@ -26,11 +26,13 @@ import java.util.List;
import junit.framework.TestCase;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.ConvergenceException;
import org.apache.commons.math.exception.DimensionMismatchException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.linear.BlockRealMatrix;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.SimpleVectorialValueChecker;
import org.apache.commons.math.optimization.VectorialPointValuePair;
import org.apache.commons.math.util.FastMath;
@ -104,7 +106,7 @@ public class LevenbergMarquardtOptimizerTest
super(name);
}
public void testTrivial() throws FunctionEvaluationException, OptimizationException {
public void testTrivial() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 2 } }, new double[] { 3 });
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
@ -114,7 +116,7 @@ public class LevenbergMarquardtOptimizerTest
try {
optimizer.guessParametersErrors();
fail("an exception should have been thrown");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
@ -123,7 +125,7 @@ public class LevenbergMarquardtOptimizerTest
assertEquals(3.0, optimum.getValue()[0], 1.0e-10);
}
public void testQRColumnsPermutation() throws FunctionEvaluationException, OptimizationException {
public void testQRColumnsPermutation() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 1.0, -1.0 }, { 0.0, 2.0 }, { 1.0, -2.0 } },
@ -141,7 +143,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testNoDependency() throws FunctionEvaluationException, OptimizationException {
public void testNoDependency() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 2, 0, 0, 0, 0, 0 },
{ 0, 2, 0, 0, 0, 0 },
@ -160,7 +162,7 @@ public class LevenbergMarquardtOptimizerTest
}
}
public void testOneSet() throws FunctionEvaluationException, OptimizationException {
public void testOneSet() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1, 0, 0 },
@ -177,7 +179,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testTwoSets() throws FunctionEvaluationException, OptimizationException {
public void testTwoSets() throws FunctionEvaluationException {
double epsilon = 1.0e-7;
LinearProblem problem = new LinearProblem(new double[][] {
{ 2, 1, 0, 4, 0, 0 },
@ -202,7 +204,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testNonInversible() throws FunctionEvaluationException, OptimizationException {
public void testNonInversible() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1, 2, -3 },
@ -216,7 +218,7 @@ public class LevenbergMarquardtOptimizerTest
try {
optimizer.getCovariances();
fail("an exception should have been thrown");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
@ -224,7 +226,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testIllConditioned() throws FunctionEvaluationException, OptimizationException {
public void testIllConditioned() throws FunctionEvaluationException {
LinearProblem problem1 = new LinearProblem(new double[][] {
{ 10.0, 7.0, 8.0, 7.0 },
{ 7.0, 5.0, 6.0, 5.0 },
@ -258,7 +260,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testMoreEstimatedParametersSimple() throws FunctionEvaluationException, OptimizationException {
public void testMoreEstimatedParametersSimple() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 3.0, 2.0, 0.0, 0.0 },
@ -273,7 +275,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testMoreEstimatedParametersUnsorted() throws FunctionEvaluationException, OptimizationException {
public void testMoreEstimatedParametersUnsorted() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 1.0, 1.0, 1.0, 0.0 },
@ -294,7 +296,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testRedundantEquations() throws FunctionEvaluationException, OptimizationException {
public void testRedundantEquations() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1.0, 1.0 },
{ 1.0, -1.0 },
@ -311,7 +313,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testInconsistentEquations() throws FunctionEvaluationException, OptimizationException {
public void testInconsistentEquations() throws FunctionEvaluationException {
LinearProblem problem = new LinearProblem(new double[][] {
{ 1.0, 1.0 },
{ 1.0, -1.0 },
@ -324,7 +326,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testInconsistentSizes() throws FunctionEvaluationException, OptimizationException {
public void testInconsistentSizes() throws FunctionEvaluationException {
LinearProblem problem =
new LinearProblem(new double[][] { { 1, 0 }, { 0, 1 } }, new double[] { -1, 1 });
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
@ -340,7 +342,7 @@ public class LevenbergMarquardtOptimizerTest
new double[] { 1 },
new double[] { 0, 0 });
fail("an exception should have been thrown");
} catch (OptimizationException oe) {
} catch (DimensionMismatchException oe) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
@ -380,23 +382,23 @@ public class LevenbergMarquardtOptimizerTest
try {
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
optimizer.setInitialStepBoundFactor(initialStepBoundFactor);
optimizer.setMaxIterations(maxCostEval);
optimizer.setMaxEvaluations(maxCostEval);
optimizer.setCostRelativeTolerance(costRelativeTolerance);
optimizer.setParRelativeTolerance(parRelativeTolerance);
optimizer.setOrthoTolerance(orthoTolerance);
optimizer.optimize(problem, new double[] { 0, 0, 0, 0, 0 }, new double[] { 1, 1, 1, 1, 1 },
new double[] { 98.680, 47.345 });
assertTrue(! shouldFail);
} catch (OptimizationException ee) {
assertTrue(shouldFail);
assertTrue(!shouldFail);
} catch (FunctionEvaluationException ee) {
assertTrue(shouldFail);
} catch (TooManyEvaluationsException ee) {
assertTrue(shouldFail);
} catch (Exception e) {
fail("wrong exception type caught");
}
}
public void testCircleFitting() throws FunctionEvaluationException, OptimizationException {
public void testCircleFitting() throws FunctionEvaluationException {
Circle circle = new Circle();
circle.addPoint( 30.0, 68.0);
circle.addPoint( 50.0, -6.0);
@ -445,7 +447,7 @@ public class LevenbergMarquardtOptimizerTest
}
public void testCircleFittingBadInit() throws FunctionEvaluationException, OptimizationException {
public void testCircleFittingBadInit() throws FunctionEvaluationException {
Circle circle = new Circle();
double[][] points = new double[][] {
{-0.312967, 0.072366}, {-0.339248, 0.132965}, {-0.379780, 0.202724},
@ -513,7 +515,7 @@ public class LevenbergMarquardtOptimizerTest
new double[] { 0.0, 4.4e-323, 1.0, 4.4e-323, 0.0 },
new double[] { 0, 0, 0 });
fail("an exception should have been thrown");
} catch (OptimizationException ee) {
} catch (ConvergenceException ee) {
// expected behavior
}

View File

@ -23,9 +23,9 @@ import java.util.Arrays;
import junit.framework.TestCase;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
import org.apache.commons.math.analysis.MultivariateMatrixFunction;
import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.VectorialPointValuePair;
import org.apache.commons.math.util.FastMath;
@ -490,7 +490,7 @@ public class MinpackTest extends TestCase {
private void minpackTest(MinpackFunction function, boolean exceptionExpected) {
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer();
optimizer.setMaxIterations(100 * (function.getN() + 1));
optimizer.setMaxEvaluations(400 * (function.getN() + 1));
optimizer.setCostRelativeTolerance(FastMath.sqrt(2.22044604926e-16));
optimizer.setParRelativeTolerance(FastMath.sqrt(2.22044604926e-16));
optimizer.setOrthoTolerance(2.22044604926e-16);
@ -503,7 +503,7 @@ public class MinpackTest extends TestCase {
assertFalse(exceptionExpected);
function.checkTheoreticalMinCost(optimizer.getRMS());
function.checkTheoreticalMinParams(optimum);
} catch (OptimizationException lsse) {
} catch (TooManyEvaluationsException e) {
assertTrue(exceptionExpected);
} catch (FunctionEvaluationException fe) {
assertTrue(exceptionExpected);

View File

@ -109,7 +109,7 @@ extends TestCase {
new LinearProblem(new double[][] { { 2 } }, new double[] { 3 });
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 0 });
@ -125,7 +125,7 @@ extends TestCase {
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 0, 0 });
@ -146,7 +146,7 @@ extends TestCase {
}, new double[] { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 });
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 0, 0, 0, 0, 0, 0 });
@ -164,7 +164,7 @@ extends TestCase {
}, new double[] { 1, 1, 1});
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 0, 0, 0 });
@ -187,7 +187,7 @@ extends TestCase {
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setPreconditioner(new Preconditioner() {
public double[] precondition(double[] point, double[] r) {
double[] d = r.clone();
@ -222,7 +222,7 @@ extends TestCase {
}, new double[] { 1, 1, 1 });
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 0, 0, 0 });
@ -238,7 +238,7 @@ extends TestCase {
}, new double[] { 32, 23, 33, 31 });
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-13, 1.0e-13));
BrentSolver solver = new BrentSolver();
solver.setAbsoluteAccuracy(1.0e-15);
@ -277,7 +277,7 @@ extends TestCase {
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 7, 6, 5, 4 });
@ -296,7 +296,7 @@ extends TestCase {
}, new double[] { 3.0, 12.0, -1.0, 7.0, 1.0 });
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 2, 2, 2, 2, 2, 2 });
@ -312,7 +312,7 @@ extends TestCase {
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 1, 1 });
@ -330,7 +330,7 @@ extends TestCase {
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-6, 1.0e-6));
RealPointValuePair optimum =
optimizer.optimize(problem, GoalType.MINIMIZE, new double[] { 1, 1 });
@ -347,7 +347,7 @@ extends TestCase {
circle.addPoint( 45.0, 97.0);
NonLinearConjugateGradientOptimizer optimizer =
new NonLinearConjugateGradientOptimizer(ConjugateGradientFormula.POLAK_RIBIERE);
optimizer.setMaxIterations(100);
optimizer.setMaxEvaluations(100);
optimizer.setConvergenceChecker(new SimpleScalarValueChecker(1.0e-30, 1.0e-30));
BrentSolver solver = new BrentSolver();
solver.setAbsoluteAccuracy(1.0e-13);

View File

@ -48,13 +48,13 @@ public class PowellOptimizerTest {
for (int i = 0; i < dim; i++) {
init[i] = minPoint[i];
}
// doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-5, 1e-9, 1e-7);
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-9, 1e-7);
// Initial is far from minimum.
for (int i = 0; i < dim; i++) {
init[i] = minPoint[i] + 3;
}
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-5, 1e-9, 1e-7);
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-9, 1e-7);
}
@Test
@ -80,13 +80,13 @@ public class PowellOptimizerTest {
for (int i = 0; i < dim; i++) {
init[i] = minPoint[i];
}
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-5, 1e-9, 1e-8);
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-9, 1e-8);
// Initial is far from minimum.
for (int i = 0; i < dim; i++) {
init[i] = minPoint[i] - 20;
}
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-5, 1e-9, 1e-8);
doTest(func, minPoint, init, GoalType.MINIMIZE, 1e-9, 1e-8);
}
@Test
@ -112,13 +112,13 @@ public class PowellOptimizerTest {
for (int i = 0; i < dim; i++) {
init[i] = maxPoint[i];
}
doTest(func, maxPoint, init, GoalType.MAXIMIZE, 1e-5, 1e-9, 1e-8);
doTest(func, maxPoint, init, GoalType.MAXIMIZE, 1e-9, 1e-8);
// Initial is far from minimum.
for (int i = 0; i < dim; i++) {
init[i] = maxPoint[i] - 20;
}
doTest(func, maxPoint, init, GoalType.MAXIMIZE, 1e-5, 1e-9, 1e-8);
doTest(func, maxPoint, init, GoalType.MAXIMIZE, 1e-9, 1e-8);
}
/**
@ -126,8 +126,6 @@ public class PowellOptimizerTest {
* @param optimum Expected optimum.
* @param init Starting point.
* @param goal Minimization or maximization.
* @param xTol Tolerance (relative error on the objective function) for
* "Brent" line search algorithm used by "Powell".
* @param fTol Tolerance (relative error on the objective function) for
* "Powell" algorithm.
* @param pointTol Tolerance for checking that the optimum is correct.
@ -136,12 +134,12 @@ public class PowellOptimizerTest {
double[] optimum,
double[] init,
GoalType goal,
double xTol,
double fTol,
double pointTol)
throws MathException {
final MultivariateRealOptimizer optim = new PowellOptimizer(xTol);
optim.setConvergenceChecker(new SimpleScalarValueChecker(fTol, -1));
final MultivariateRealOptimizer optim = new PowellOptimizer();
optim.setMaxEvaluations(1000);
optim.setConvergenceChecker(new SimpleScalarValueChecker(fTol, Math.ulp(1d)));
final RealPointValuePair result = optim.optimize(func, goal, init);
final double[] found = result.getPoint();

View File

@ -24,6 +24,9 @@ import org.apache.commons.math.optimization.GoalType;
import org.junit.Assert;
import org.junit.Test;
/**
* Test for {@link BracketFinder}.
*/
public class BracketFinderTest {
@Test
@ -70,4 +73,52 @@ public class BracketFinderTest {
Assert.assertEquals(-1, bFind.getMid(), tol);
Assert.assertEquals(0.61803399999999997, bFind.getHi(), tol);
}
@Test
public void testMinimumIsOnIntervalBoundary() throws MathException {
final UnivariateRealFunction func = new UnivariateRealFunction() {
public double value(double x)
throws FunctionEvaluationException {
return x * x;
}
};
final BracketFinder bFind = new BracketFinder();
bFind.search(func, GoalType.MINIMIZE, 0, 1);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
bFind.search(func, GoalType.MINIMIZE, -1, 0);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
}
@Test
public void testIntervalBoundsOrdering() throws MathException {
final UnivariateRealFunction func = new UnivariateRealFunction() {
public double value(double x)
throws FunctionEvaluationException {
return x * x;
}
};
final BracketFinder bFind = new BracketFinder();
bFind.search(func, GoalType.MINIMIZE, -1, 1);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
bFind.search(func, GoalType.MINIMIZE, 1, -1);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
bFind.search(func, GoalType.MINIMIZE, 1, 2);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
bFind.search(func, GoalType.MINIMIZE, 2, 1);
Assert.assertTrue(bFind.getLo() <= 0);
Assert.assertTrue(0 <= bFind.getHi());
}
}

View File

@ -20,17 +20,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.exception.NoDataException;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.exception.TooManyEvaluationsException;
import org.apache.commons.math.analysis.QuinticFunction;
import org.apache.commons.math.analysis.SinFunction;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.UnivariateRealOptimizer;
import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math.util.FastMath;
import org.junit.Test;
/**
@ -41,28 +38,22 @@ public final class BrentOptimizerTest {
@Test
public void testSinMin() throws MathException {
UnivariateRealFunction f = new SinFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
minimizer.setMaxEvaluations(200);
assertEquals(200, minimizer.getMaxEvaluations());
UnivariateRealOptimizer optimizer = new BrentOptimizer();
optimizer.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-10, 1e-14));
optimizer.setMaxEvaluations(200);
assertEquals(200, optimizer.getMaxEvaluations());
assertEquals(3 * Math.PI / 2, optimizer.optimize(f, GoalType.MINIMIZE, 4, 5).getPoint(),
100 * optimizer.getConvergenceChecker().getRelativeThreshold());
assertTrue(optimizer.getEvaluations() <= 50);
assertEquals(3 * Math.PI / 2, optimizer.optimize(f, GoalType.MINIMIZE, 1, 5).getPoint(),
100 * optimizer.getConvergenceChecker().getRelativeThreshold());
assertTrue(optimizer.getEvaluations() <= 100);
assertTrue(optimizer.getEvaluations() >= 15);
optimizer.setMaxEvaluations(10);
try {
minimizer.getResult();
optimizer.optimize(f, GoalType.MINIMIZE, 4, 5);
fail("an exception should have been thrown");
} catch (NoDataException ise) {
// expected
} catch (Exception e) {
fail("wrong exception caught");
}
assertEquals(3 * FastMath.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE, 4, 5), 10 * minimizer.getRelativeAccuracy());
assertTrue(minimizer.getIterationCount() <= 50);
assertEquals(3 * FastMath.PI / 2, minimizer.optimize(f, GoalType.MINIMIZE, 1, 5), 10 * minimizer.getRelativeAccuracy());
assertTrue(minimizer.getIterationCount() <= 50);
assertTrue(minimizer.getEvaluations() <= 100);
assertTrue(minimizer.getEvaluations() >= 15);
minimizer.setMaxEvaluations(10);
try {
minimizer.optimize(f, GoalType.MINIMIZE, 4, 5);
fail("an exception should have been thrown");
} catch (FunctionEvaluationException fee) {
} catch (TooManyEvaluationsException fee) {
// expected
} catch (Exception e) {
fail("wrong exception caught");
@ -73,25 +64,27 @@ public final class BrentOptimizerTest {
public void testQuinticMin() throws MathException {
// The function has local minima at -0.27195613 and 0.82221643.
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
assertEquals(-0.27195613, minimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2), 1.0e-8);
assertEquals( 0.82221643, minimizer.optimize(f, GoalType.MINIMIZE, 0.3, 0.9), 1.0e-8);
assertTrue(minimizer.getIterationCount() <= 50);
UnivariateRealOptimizer optimizer = new BrentOptimizer();
optimizer.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-10, 1e-14));
optimizer.setMaxEvaluations(200);
assertEquals(-0.27195613, optimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2).getPoint(), 1.0e-8);
assertEquals( 0.82221643, optimizer.optimize(f, GoalType.MINIMIZE, 0.3, 0.9).getPoint(), 1.0e-8);
assertTrue(optimizer.getEvaluations() <= 50);
// search in a large interval
assertEquals(-0.27195613, minimizer.optimize(f, GoalType.MINIMIZE, -1.0, 0.2), 1.0e-8);
assertTrue(minimizer.getIterationCount() <= 50);
assertEquals(-0.27195613, optimizer.optimize(f, GoalType.MINIMIZE, -1.0, 0.2).getPoint(), 1.0e-8);
assertTrue(optimizer.getEvaluations() <= 50);
}
@Test
public void testQuinticMinStatistics() throws MathException {
// The function has local minima at -0.27195613 and 0.82221643.
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
minimizer.setRelativeAccuracy(1e-10);
minimizer.setAbsoluteAccuracy(1e-11);
UnivariateRealOptimizer optimizer = new BrentOptimizer();
optimizer.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-12, 1e-14));
optimizer.setMaxEvaluations(40);
final DescriptiveStatistics[] stat = new DescriptiveStatistics[3];
final DescriptiveStatistics[] stat = new DescriptiveStatistics[2];
for (int i = 0; i < stat.length; i++) {
stat[i] = new DescriptiveStatistics();
}
@ -102,31 +95,29 @@ public final class BrentOptimizerTest {
final double delta = (max - min) / nSamples;
for (int i = 0; i < nSamples; i++) {
final double start = min + i * delta;
stat[0].addValue(minimizer.optimize(f, GoalType.MINIMIZE, min, max, start));
stat[1].addValue(minimizer.getIterationCount());
stat[2].addValue(minimizer.getEvaluations());
stat[0].addValue(optimizer.optimize(f, GoalType.MINIMIZE, min, max, start).getPoint());
stat[1].addValue(optimizer.getEvaluations());
}
final double meanOptValue = stat[0].getMean();
final double medianIter = stat[1].getPercentile(50);
final double medianEval = stat[2].getPercentile(50);
assertTrue(meanOptValue > -0.27195612812 && meanOptValue < -0.27195612811);
assertEquals(medianIter, 17, FastMath.ulp(1d));
assertEquals(medianEval, 18, FastMath.ulp(1d));
final double medianEval = stat[1].getPercentile(50);
assertTrue(meanOptValue > -0.2719561281 && meanOptValue < -0.2719561280);
assertEquals((int) medianEval, 27);
}
@Test
@Test(expected = TooManyEvaluationsException.class)
public void testQuinticMax() throws MathException {
// The quintic function has zeros at 0, +-0.5 and +-1.
// The function has a local maximum at 0.27195613.
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer minimizer = new BrentOptimizer();
assertEquals(0.27195613, minimizer.optimize(f, GoalType.MAXIMIZE, 0.2, 0.3), 1.0e-8);
minimizer.setMaximalIterationCount(5);
UnivariateRealOptimizer optimizer = new BrentOptimizer();
optimizer.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-12, 1e-14));
assertEquals(0.27195613, optimizer.optimize(f, GoalType.MAXIMIZE, 0.2, 0.3).getPoint(), 1e-8);
optimizer.setMaxEvaluations(5);
try {
minimizer.optimize(f, GoalType.MAXIMIZE, 0.2, 0.3);
optimizer.optimize(f, GoalType.MAXIMIZE, 0.2, 0.3);
fail("an exception should have been thrown");
} catch (MaxIterationsExceededException miee) {
} catch (TooManyEvaluationsException miee) {
// expected
} catch (Exception e) {
fail("wrong exception caught");
@ -136,15 +127,15 @@ public final class BrentOptimizerTest {
@Test
public void testMinEndpoints() throws Exception {
UnivariateRealFunction f = new SinFunction();
UnivariateRealOptimizer solver = new BrentOptimizer();
solver.setRelativeAccuracy(1e-8);
UnivariateRealOptimizer optimizer = new BrentOptimizer();
optimizer.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-8, 1e-14));
optimizer.setMaxEvaluations(50);
// endpoint is minimum
double result = solver.optimize(f, GoalType.MINIMIZE, 3 * FastMath.PI / 2, 5);
assertEquals(3 * FastMath.PI / 2, result, 10 * solver.getRelativeAccuracy());
double result = optimizer.optimize(f, GoalType.MINIMIZE, 3 * Math.PI / 2, 5).getPoint();
assertEquals(3 * Math.PI / 2, result, 100 * optimizer.getConvergenceChecker().getRelativeThreshold());
result = solver.optimize(f, GoalType.MINIMIZE, 4, 3 * FastMath.PI / 2);
assertEquals(3 * FastMath.PI / 2, result, 10 * solver.getRelativeAccuracy());
result = optimizer.optimize(f, GoalType.MINIMIZE, 4, 3 * Math.PI / 2).getPoint();
assertEquals(3 * Math.PI / 2, result, 100 * optimizer.getConvergenceChecker().getRelativeThreshold());
}
}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.commons.math.optimization;
package org.apache.commons.math.optimization.univariate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -26,6 +26,7 @@ import org.apache.commons.math.analysis.QuinticFunction;
import org.apache.commons.math.analysis.SinFunction;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.univariate.BrentOptimizer;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.random.JDKRandomGenerator;
import org.apache.commons.math.util.FastMath;
import org.junit.Test;
@ -36,21 +37,22 @@ public class MultiStartUnivariateRealOptimizerTest {
public void testSinMin() throws MathException {
UnivariateRealFunction f = new SinFunction();
UnivariateRealOptimizer underlying = new BrentOptimizer();
underlying.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-10, 1e-14));
underlying.setMaxEvaluations(300);
JDKRandomGenerator g = new JDKRandomGenerator();
g.setSeed(44428400075l);
MultiStartUnivariateRealOptimizer minimizer =
MultiStartUnivariateRealOptimizer optimizer =
new MultiStartUnivariateRealOptimizer(underlying, 10, g);
minimizer.optimize(f, GoalType.MINIMIZE, -100.0, 100.0);
double[] optima = minimizer.getOptima();
double[] optimaValues = minimizer.getOptimaValues();
optimizer.optimize(f, GoalType.MINIMIZE, -100.0, 100.0);
UnivariateRealPointValuePair[] optima = optimizer.getOptima();
for (int i = 1; i < optima.length; ++i) {
double d = (optima[i] - optima[i-1]) / (2 * FastMath.PI);
double d = (optima[i].getPoint() - optima[i-1].getPoint()) / (2 * FastMath.PI);
assertTrue (FastMath.abs(d - FastMath.rint(d)) < 1.0e-8);
assertEquals(-1.0, f.value(optima[i]), 1.0e-10);
assertEquals(f.value(optima[i]), optimaValues[i], 1.0e-10);
assertEquals(-1.0, f.value(optima[i].getPoint()), 1.0e-10);
assertEquals(f.value(optima[i].getPoint()), optima[i].getValue(), 1.0e-10);
}
assertTrue(minimizer.getEvaluations() > 150);
assertTrue(minimizer.getEvaluations() < 250);
assertTrue(optimizer.getEvaluations() > 150);
assertTrue(optimizer.getEvaluations() < 250);
}
@Test
@ -59,44 +61,23 @@ public class MultiStartUnivariateRealOptimizerTest {
// The function has extrema (first derivative is zero) at 0.27195613 and 0.82221643,
UnivariateRealFunction f = new QuinticFunction();
UnivariateRealOptimizer underlying = new BrentOptimizer();
underlying.setRelativeAccuracy(1e-15);
underlying.setConvergenceChecker(new BrentOptimizer.BrentConvergenceChecker(1e-9, 1e-14));
underlying.setMaxEvaluations(300);
JDKRandomGenerator g = new JDKRandomGenerator();
g.setSeed(4312000053L);
MultiStartUnivariateRealOptimizer minimizer =
MultiStartUnivariateRealOptimizer optimizer =
new MultiStartUnivariateRealOptimizer(underlying, 5, g);
minimizer.setAbsoluteAccuracy(10 * minimizer.getAbsoluteAccuracy());
minimizer.setRelativeAccuracy(10 * minimizer.getRelativeAccuracy());
try {
minimizer.getOptima();
fail("an exception should have been thrown");
} catch (IllegalStateException ise) {
// expected
} catch (Exception e) {
fail("wrong exception caught");
}
try {
minimizer.getOptimaValues();
fail("an exception should have been thrown");
} catch (IllegalStateException ise) {
// expected
} catch (Exception e) {
fail("wrong exception caught");
}
UnivariateRealPointValuePair optimum
= optimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2);
assertEquals(-0.2719561271, optimum.getPoint(), 1e-9);
assertEquals(-0.0443342695, optimum.getValue(), 1e-9);
double result = minimizer.optimize(f, GoalType.MINIMIZE, -0.3, -0.2);
assertEquals(-0.2719561270319131, result, 1.0e-13);
assertEquals(-0.2719561270319131, minimizer.getResult(), 1.0e-13);
assertEquals(-0.04433426954946637, minimizer.getFunctionValue(), 1.0e-13);
double[] optima = minimizer.getOptima();
double[] optimaValues = minimizer.getOptimaValues();
UnivariateRealPointValuePair[] optima = optimizer.getOptima();
for (int i = 0; i < optima.length; ++i) {
assertEquals(f.value(optima[i]), optimaValues[i], 1.0e-10);
assertEquals(f.value(optima[i].getPoint()), optima[i].getValue(), 1e-9);
}
assertTrue(minimizer.getEvaluations() >= 120);
assertTrue(minimizer.getEvaluations() <= 170);
assertTrue(minimizer.getIterationCount() >= 120);
assertTrue(minimizer.getIterationCount() <= 170);
assertTrue(optimizer.getEvaluations() >= 110);
assertTrue(optimizer.getEvaluations() <= 150);
}
}