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  * @deprecated As of 3.1 (to be removed in 4.0).
44  * @since 2.2
45  */
46 @Deprecated
47 public abstract class BaseAbstractMultivariateOptimizer<FUNC extends MultivariateFunction>
48     implements BaseMultivariateOptimizer<FUNC> {
49     /** Evaluations counter. */
50     protected final Incrementor evaluations = new Incrementor();
51     /** Convergence checker. */
52     private ConvergenceChecker<PointValuePair> checker;
53     /** Type of optimization. */
54     private GoalType goal;
55     /** Initial guess. */
56     private double[] start;
57     /** Lower bounds. */
58     private double[] lowerBound;
59     /** Upper bounds. */
60     private double[] upperBound;
61     /** Objective function. */
62     private MultivariateFunction function;
63 
64     /**
65      * Simple constructor with default settings.
66      * The convergence check is set to a {@link SimpleValueChecker}.
67      * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
68      */
69     @Deprecated
BaseAbstractMultivariateOptimizer()70     protected BaseAbstractMultivariateOptimizer() {
71         this(new SimpleValueChecker());
72     }
73     /**
74      * @param checker Convergence checker.
75      */
BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker)76     protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) {
77         this.checker = checker;
78     }
79 
80     /** {@inheritDoc} */
getMaxEvaluations()81     public int getMaxEvaluations() {
82         return evaluations.getMaximalCount();
83     }
84 
85     /** {@inheritDoc} */
getEvaluations()86     public int getEvaluations() {
87         return evaluations.getCount();
88     }
89 
90     /** {@inheritDoc} */
getConvergenceChecker()91     public ConvergenceChecker<PointValuePair> getConvergenceChecker() {
92         return checker;
93     }
94 
95     /**
96      * Compute the objective function value.
97      *
98      * @param point Point at which the objective function must be evaluated.
99      * @return the objective function value at the specified point.
100      * @throws TooManyEvaluationsException if the maximal number of
101      * evaluations is exceeded.
102      */
computeObjectiveValue(double[] point)103     protected double computeObjectiveValue(double[] point) {
104         try {
105             evaluations.incrementCount();
106         } catch (MaxCountExceededException e) {
107             throw new TooManyEvaluationsException(e.getMax());
108         }
109         return function.value(point);
110     }
111 
112     /**
113      * {@inheritDoc}
114      *
115      * @deprecated As of 3.1. Please use
116      * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])}
117      * instead.
118      */
119     @Deprecated
optimize(int maxEval, FUNC f, GoalType goalType, double[] startPoint)120     public PointValuePair optimize(int maxEval, FUNC f, GoalType goalType,
121                                    double[] startPoint) {
122         return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint));
123     }
124 
125     /**
126      * Optimize an objective function.
127      *
128      * @param maxEval Allowed number of evaluations of the objective function.
129      * @param f Objective function.
130      * @param goalType Optimization type.
131      * @param optData Optimization data. The following data will be looked for:
132      * <ul>
133      *  <li>{@link InitialGuess}</li>
134      *  <li>{@link SimpleBounds}</li>
135      * </ul>
136      * @return the point/value pair giving the optimal value of the objective
137      * function.
138      * @since 3.1
139      */
optimize(int maxEval, FUNC f, GoalType goalType, OptimizationData... optData)140     public PointValuePair optimize(int maxEval,
141                                    FUNC f,
142                                    GoalType goalType,
143                                    OptimizationData... optData) {
144         return optimizeInternal(maxEval, f, goalType, optData);
145     }
146 
147     /**
148      * Optimize an objective function.
149      *
150      * @param f Objective function.
151      * @param goalType Type of optimization goal: either
152      * {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}.
153      * @param startPoint Start point for optimization.
154      * @param maxEval Maximum number of function evaluations.
155      * @return the point/value pair giving the optimal value for objective
156      * function.
157      * @throws org.apache.commons.math3.exception.DimensionMismatchException
158      * if the start point dimension is wrong.
159      * @throws org.apache.commons.math3.exception.TooManyEvaluationsException
160      * if the maximal number of evaluations is exceeded.
161      * @throws org.apache.commons.math3.exception.NullArgumentException if
162      * any argument is {@code null}.
163      * @deprecated As of 3.1. Please use
164      * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])}
165      * instead.
166      */
167     @Deprecated
optimizeInternal(int maxEval, FUNC f, GoalType goalType, double[] startPoint)168     protected PointValuePair optimizeInternal(int maxEval, FUNC f, GoalType goalType,
169                                               double[] startPoint) {
170         return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint));
171     }
172 
173     /**
174      * Optimize an objective function.
175      *
176      * @param maxEval Allowed number of evaluations of the objective function.
177      * @param f Objective function.
178      * @param goalType Optimization type.
179      * @param optData Optimization data. The following data will be looked for:
180      * <ul>
181      *  <li>{@link InitialGuess}</li>
182      *  <li>{@link SimpleBounds}</li>
183      * </ul>
184      * @return the point/value pair giving the optimal value of the objective
185      * function.
186      * @throws TooManyEvaluationsException if the maximal number of
187      * evaluations is exceeded.
188      * @since 3.1
189      */
optimizeInternal(int maxEval, FUNC f, GoalType goalType, OptimizationData... optData)190     protected PointValuePair optimizeInternal(int maxEval,
191                                               FUNC f,
192                                               GoalType goalType,
193                                               OptimizationData... optData)
194         throws TooManyEvaluationsException {
195         // Set internal state.
196         evaluations.setMaximalCount(maxEval);
197         evaluations.resetCount();
198         function = f;
199         goal = goalType;
200         // Retrieve other settings.
201         parseOptimizationData(optData);
202         // Check input consistency.
203         checkParameters();
204         // Perform computation.
205         return doOptimize();
206     }
207 
208     /**
209      * Scans the list of (required and optional) optimization data that
210      * characterize the problem.
211      *
212      * @param optData Optimization data. The following data will be looked for:
213      * <ul>
214      *  <li>{@link InitialGuess}</li>
215      *  <li>{@link SimpleBounds}</li>
216      * </ul>
217      */
parseOptimizationData(OptimizationData... optData)218     private void parseOptimizationData(OptimizationData... optData) {
219         // The existing values (as set by the previous call) are reused if
220         // not provided in the argument list.
221         for (OptimizationData data : optData) {
222             if (data instanceof InitialGuess) {
223                 start = ((InitialGuess) data).getInitialGuess();
224                 continue;
225             }
226             if (data instanceof SimpleBounds) {
227                 final SimpleBounds bounds = (SimpleBounds) data;
228                 lowerBound = bounds.getLower();
229                 upperBound = bounds.getUpper();
230                 continue;
231             }
232         }
233     }
234 
235     /**
236      * @return the optimization type.
237      */
getGoalType()238     public GoalType getGoalType() {
239         return goal;
240     }
241 
242     /**
243      * @return the initial guess.
244      */
getStartPoint()245     public double[] getStartPoint() {
246         return start == null ? null : start.clone();
247     }
248     /**
249      * @return the lower bounds.
250      * @since 3.1
251      */
getLowerBound()252     public double[] getLowerBound() {
253         return lowerBound == null ? null : lowerBound.clone();
254     }
255     /**
256      * @return the upper bounds.
257      * @since 3.1
258      */
getUpperBound()259     public double[] getUpperBound() {
260         return upperBound == null ? null : upperBound.clone();
261     }
262 
263     /**
264      * Perform the bulk of the optimization algorithm.
265      *
266      * @return the point/value pair giving the optimal value of the
267      * objective function.
268      */
doOptimize()269     protected abstract PointValuePair doOptimize();
270 
271     /**
272      * Check parameters consistency.
273      */
checkParameters()274     private void checkParameters() {
275         if (start != null) {
276             final int dim = start.length;
277             if (lowerBound != null) {
278                 if (lowerBound.length != dim) {
279                     throw new DimensionMismatchException(lowerBound.length, dim);
280                 }
281                 for (int i = 0; i < dim; i++) {
282                     final double v = start[i];
283                     final double lo = lowerBound[i];
284                     if (v < lo) {
285                         throw new NumberIsTooSmallException(v, lo, true);
286                     }
287                 }
288             }
289             if (upperBound != null) {
290                 if (upperBound.length != dim) {
291                     throw new DimensionMismatchException(upperBound.length, dim);
292                 }
293                 for (int i = 0; i < dim; i++) {
294                     final double v = start[i];
295                     final double hi = upperBound[i];
296                     if (v > hi) {
297                         throw new NumberIsTooLargeException(v, hi, true);
298                     }
299                 }
300             }
301 
302             // If the bounds were not specified, the allowed interval is
303             // assumed to be [-inf, +inf].
304             if (lowerBound == null) {
305                 lowerBound = new double[dim];
306                 for (int i = 0; i < dim; i++) {
307                     lowerBound[i] = Double.NEGATIVE_INFINITY;
308                 }
309             }
310             if (upperBound == null) {
311                 upperBound = new double[dim];
312                 for (int i = 0; i < dim; i++) {
313                     upperBound[i] = Double.POSITIVE_INFINITY;
314                 }
315             }
316         }
317     }
318 }
319