001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math3.optimization.direct;
019
020 import org.apache.commons.math3.util.Incrementor;
021 import org.apache.commons.math3.exception.MaxCountExceededException;
022 import org.apache.commons.math3.exception.TooManyEvaluationsException;
023 import org.apache.commons.math3.analysis.MultivariateFunction;
024 import org.apache.commons.math3.optimization.BaseMultivariateOptimizer;
025 import org.apache.commons.math3.optimization.OptimizationData;
026 import org.apache.commons.math3.optimization.GoalType;
027 import org.apache.commons.math3.optimization.InitialGuess;
028 import org.apache.commons.math3.optimization.SimpleBounds;
029 import org.apache.commons.math3.optimization.ConvergenceChecker;
030 import org.apache.commons.math3.optimization.PointValuePair;
031 import org.apache.commons.math3.optimization.SimpleValueChecker;
032 import org.apache.commons.math3.exception.DimensionMismatchException;
033 import org.apache.commons.math3.exception.NumberIsTooSmallException;
034 import org.apache.commons.math3.exception.NumberIsTooLargeException;
035
036 /**
037 * Base class for implementing optimizers for multivariate scalar functions.
038 * This base class handles the boiler-plate methods associated to thresholds,
039 * evaluations counting, initial guess and simple bounds settings.
040 *
041 * @param <FUNC> Type of the objective function to be optimized.
042 *
043 * @version $Id: BaseAbstractMultivariateOptimizer.java 1422313 2012-12-15 18:53:41Z psteitz $
044 * @deprecated As of 3.1 (to be removed in 4.0).
045 * @since 2.2
046 */
047 @Deprecated
048 public abstract class BaseAbstractMultivariateOptimizer<FUNC extends MultivariateFunction>
049 implements BaseMultivariateOptimizer<FUNC> {
050 /** Evaluations counter. */
051 protected final Incrementor evaluations = new Incrementor();
052 /** Convergence checker. */
053 private ConvergenceChecker<PointValuePair> checker;
054 /** Type of optimization. */
055 private GoalType goal;
056 /** Initial guess. */
057 private double[] start;
058 /** Lower bounds. */
059 private double[] lowerBound;
060 /** Upper bounds. */
061 private double[] upperBound;
062 /** Objective function. */
063 private MultivariateFunction function;
064
065 /**
066 * Simple constructor with default settings.
067 * The convergence check is set to a {@link SimpleValueChecker}.
068 * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
069 */
070 @Deprecated
071 protected BaseAbstractMultivariateOptimizer() {
072 this(new SimpleValueChecker());
073 }
074 /**
075 * @param checker Convergence checker.
076 */
077 protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) {
078 this.checker = checker;
079 }
080
081 /** {@inheritDoc} */
082 public int getMaxEvaluations() {
083 return evaluations.getMaximalCount();
084 }
085
086 /** {@inheritDoc} */
087 public int getEvaluations() {
088 return evaluations.getCount();
089 }
090
091 /** {@inheritDoc} */
092 public ConvergenceChecker<PointValuePair> getConvergenceChecker() {
093 return checker;
094 }
095
096 /**
097 * Compute the objective function value.
098 *
099 * @param point Point at which the objective function must be evaluated.
100 * @return the objective function value at the specified point.
101 * @throws TooManyEvaluationsException if the maximal number of
102 * evaluations is exceeded.
103 */
104 protected double computeObjectiveValue(double[] point) {
105 try {
106 evaluations.incrementCount();
107 } catch (MaxCountExceededException e) {
108 throw new TooManyEvaluationsException(e.getMax());
109 }
110 return function.value(point);
111 }
112
113 /**
114 * {@inheritDoc}
115 *
116 * @deprecated As of 3.1. Please use
117 * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])}
118 * instead.
119 */
120 @Deprecated
121 public PointValuePair optimize(int maxEval, FUNC f, GoalType goalType,
122 double[] startPoint) {
123 return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint));
124 }
125
126 /**
127 * Optimize an objective function.
128 *
129 * @param maxEval Allowed number of evaluations of the objective function.
130 * @param f Objective function.
131 * @param goalType Optimization type.
132 * @param optData Optimization data. The following data will be looked for:
133 * <ul>
134 * <li>{@link InitialGuess}</li>
135 * <li>{@link SimpleBounds}</li>
136 * </ul>
137 * @return the point/value pair giving the optimal value of the objective
138 * function.
139 * @since 3.1
140 */
141 public PointValuePair optimize(int maxEval,
142 FUNC f,
143 GoalType goalType,
144 OptimizationData... optData) {
145 return optimizeInternal(maxEval, f, goalType, optData);
146 }
147
148 /**
149 * Optimize an objective function.
150 *
151 * @param f Objective function.
152 * @param goalType Type of optimization goal: either
153 * {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}.
154 * @param startPoint Start point for optimization.
155 * @param maxEval Maximum number of function evaluations.
156 * @return the point/value pair giving the optimal value for objective
157 * function.
158 * @throws org.apache.commons.math3.exception.DimensionMismatchException
159 * if the start point dimension is wrong.
160 * @throws org.apache.commons.math3.exception.TooManyEvaluationsException
161 * if the maximal number of evaluations is exceeded.
162 * @throws org.apache.commons.math3.exception.NullArgumentException if
163 * any argument is {@code null}.
164 * @deprecated As of 3.1. Please use
165 * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])}
166 * instead.
167 */
168 @Deprecated
169 protected PointValuePair optimizeInternal(int maxEval, FUNC f, GoalType goalType,
170 double[] startPoint) {
171 return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint));
172 }
173
174 /**
175 * Optimize an objective function.
176 *
177 * @param maxEval Allowed number of evaluations of the objective function.
178 * @param f Objective function.
179 * @param goalType Optimization type.
180 * @param optData Optimization data. The following data will be looked for:
181 * <ul>
182 * <li>{@link InitialGuess}</li>
183 * <li>{@link SimpleBounds}</li>
184 * </ul>
185 * @return the point/value pair giving the optimal value of the objective
186 * function.
187 * @throws TooManyEvaluationsException if the maximal number of
188 * evaluations is exceeded.
189 * @since 3.1
190 */
191 protected PointValuePair optimizeInternal(int maxEval,
192 FUNC f,
193 GoalType goalType,
194 OptimizationData... optData)
195 throws TooManyEvaluationsException {
196 // Set internal state.
197 evaluations.setMaximalCount(maxEval);
198 evaluations.resetCount();
199 function = f;
200 goal = goalType;
201 // Retrieve other settings.
202 parseOptimizationData(optData);
203 // Check input consistency.
204 checkParameters();
205 // Perform computation.
206 return doOptimize();
207 }
208
209 /**
210 * Scans the list of (required and optional) optimization data that
211 * characterize the problem.
212 *
213 * @param optData Optimization data. The following data will be looked for:
214 * <ul>
215 * <li>{@link InitialGuess}</li>
216 * <li>{@link SimpleBounds}</li>
217 * </ul>
218 */
219 private void parseOptimizationData(OptimizationData... optData) {
220 // The existing values (as set by the previous call) are reused if
221 // not provided in the argument list.
222 for (OptimizationData data : optData) {
223 if (data instanceof InitialGuess) {
224 start = ((InitialGuess) data).getInitialGuess();
225 continue;
226 }
227 if (data instanceof SimpleBounds) {
228 final SimpleBounds bounds = (SimpleBounds) data;
229 lowerBound = bounds.getLower();
230 upperBound = bounds.getUpper();
231 continue;
232 }
233 }
234 }
235
236 /**
237 * @return the optimization type.
238 */
239 public GoalType getGoalType() {
240 return goal;
241 }
242
243 /**
244 * @return the initial guess.
245 */
246 public double[] getStartPoint() {
247 return start == null ? null : start.clone();
248 }
249 /**
250 * @return the lower bounds.
251 * @since 3.1
252 */
253 public double[] getLowerBound() {
254 return lowerBound == null ? null : lowerBound.clone();
255 }
256 /**
257 * @return the upper bounds.
258 * @since 3.1
259 */
260 public double[] getUpperBound() {
261 return upperBound == null ? null : upperBound.clone();
262 }
263
264 /**
265 * Perform the bulk of the optimization algorithm.
266 *
267 * @return the point/value pair giving the optimal value of the
268 * objective function.
269 */
270 protected abstract PointValuePair doOptimize();
271
272 /**
273 * Check parameters consistency.
274 */
275 private void checkParameters() {
276 if (start != null) {
277 final int dim = start.length;
278 if (lowerBound != null) {
279 if (lowerBound.length != dim) {
280 throw new DimensionMismatchException(lowerBound.length, dim);
281 }
282 for (int i = 0; i < dim; i++) {
283 final double v = start[i];
284 final double lo = lowerBound[i];
285 if (v < lo) {
286 throw new NumberIsTooSmallException(v, lo, true);
287 }
288 }
289 }
290 if (upperBound != null) {
291 if (upperBound.length != dim) {
292 throw new DimensionMismatchException(upperBound.length, dim);
293 }
294 for (int i = 0; i < dim; i++) {
295 final double v = start[i];
296 final double hi = upperBound[i];
297 if (v > hi) {
298 throw new NumberIsTooLargeException(v, hi, true);
299 }
300 }
301 }
302
303 // If the bounds were not specified, the allowed interval is
304 // assumed to be [-inf, +inf].
305 if (lowerBound == null) {
306 lowerBound = new double[dim];
307 for (int i = 0; i < dim; i++) {
308 lowerBound[i] = Double.NEGATIVE_INFINITY;
309 }
310 }
311 if (upperBound == null) {
312 upperBound = new double[dim];
313 for (int i = 0; i < dim; i++) {
314 upperBound[i] = Double.POSITIVE_INFINITY;
315 }
316 }
317 }
318 }
319 }