1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.math3.optimization.direct;
19
20 import org.apache.commons.math3.util.Incrementor;
21 import org.apache.commons.math3.exception.MaxCountExceededException;
22 import org.apache.commons.math3.exception.TooManyEvaluationsException;
23 import org.apache.commons.math3.analysis.MultivariateFunction;
24 import org.apache.commons.math3.optimization.BaseMultivariateOptimizer;
25 import org.apache.commons.math3.optimization.OptimizationData;
26 import org.apache.commons.math3.optimization.GoalType;
27 import org.apache.commons.math3.optimization.InitialGuess;
28 import org.apache.commons.math3.optimization.SimpleBounds;
29 import org.apache.commons.math3.optimization.ConvergenceChecker;
30 import org.apache.commons.math3.optimization.PointValuePair;
31 import org.apache.commons.math3.optimization.SimpleValueChecker;
32 import org.apache.commons.math3.exception.DimensionMismatchException;
33 import org.apache.commons.math3.exception.NumberIsTooSmallException;
34 import org.apache.commons.math3.exception.NumberIsTooLargeException;
35
36 /**
37 * Base class for implementing optimizers for multivariate scalar functions.
38 * This base class handles the boiler-plate methods associated to thresholds,
39 * evaluations counting, initial guess and simple bounds settings.
40 *
41 * @param <FUNC> Type of the objective function to be optimized.
42 *
43 * @version $Id: BaseAbstractMultivariateOptimizer.java 1422313 2012-12-15 18:53:41Z psteitz $
44 * @deprecated As of 3.1 (to be removed in 4.0).
45 * @since 2.2
46 */
47 @Deprecated
48 public abstract class BaseAbstractMultivariateOptimizer<FUNC extends MultivariateFunction>
49 implements BaseMultivariateOptimizer<FUNC> {
50 /** Evaluations counter. */
51 protected final Incrementor evaluations = new Incrementor();
52 /** Convergence checker. */
53 private ConvergenceChecker<PointValuePair> checker;
54 /** Type of optimization. */
55 private GoalType goal;
56 /** Initial guess. */
57 private double[] start;
58 /** Lower bounds. */
59 private double[] lowerBound;
60 /** Upper bounds. */
61 private double[] upperBound;
62 /** Objective function. */
63 private MultivariateFunction function;
64
65 /**
66 * Simple constructor with default settings.
67 * The convergence check is set to a {@link SimpleValueChecker}.
68 * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
69 */
70 @Deprecated
71 protected BaseAbstractMultivariateOptimizer() {
72 this(new SimpleValueChecker());
73 }
74 /**
75 * @param checker Convergence checker.
76 */
77 protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) {
78 this.checker = checker;
79 }
80
81 /** {@inheritDoc} */
82 public int getMaxEvaluations() {
83 return evaluations.getMaximalCount();
84 }
85
86 /** {@inheritDoc} */
87 public int getEvaluations() {
88 return evaluations.getCount();
89 }
90
91 /** {@inheritDoc} */
92 public ConvergenceChecker<PointValuePair> getConvergenceChecker() {
93 return checker;
94 }
95
96 /**
97 * Compute the objective function value.
98 *
99 * @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 }