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   * @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 }