View Javadoc
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
70      protected BaseAbstractMultivariateOptimizer() {
71          this(new SimpleValueChecker());
72      }
73      /**
74       * @param checker Convergence checker.
75       */
76      protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) {
77          this.checker = checker;
78      }
79  
80      /** {@inheritDoc} */
81      public int getMaxEvaluations() {
82          return evaluations.getMaximalCount();
83      }
84  
85      /** {@inheritDoc} */
86      public int getEvaluations() {
87          return evaluations.getCount();
88      }
89  
90      /** {@inheritDoc} */
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      */
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
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      */
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
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      */
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      */
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      */
238     public GoalType getGoalType() {
239         return goal;
240     }
241 
242     /**
243      * @return the initial guess.
244      */
245     public double[] getStartPoint() {
246         return start == null ? null : start.clone();
247     }
248     /**
249      * @return the lower bounds.
250      * @since 3.1
251      */
252     public double[] getLowerBound() {
253         return lowerBound == null ? null : lowerBound.clone();
254     }
255     /**
256      * @return the upper bounds.
257      * @since 3.1
258      */
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      */
269     protected abstract PointValuePair doOptimize();
270 
271     /**
272      * Check parameters consistency.
273      */
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 }