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
018package org.apache.commons.math3.optimization.direct;
019
020import org.apache.commons.math3.util.Incrementor;
021import org.apache.commons.math3.exception.MaxCountExceededException;
022import org.apache.commons.math3.exception.TooManyEvaluationsException;
023import org.apache.commons.math3.analysis.MultivariateFunction;
024import org.apache.commons.math3.optimization.BaseMultivariateOptimizer;
025import org.apache.commons.math3.optimization.OptimizationData;
026import org.apache.commons.math3.optimization.GoalType;
027import org.apache.commons.math3.optimization.InitialGuess;
028import org.apache.commons.math3.optimization.SimpleBounds;
029import org.apache.commons.math3.optimization.ConvergenceChecker;
030import org.apache.commons.math3.optimization.PointValuePair;
031import org.apache.commons.math3.optimization.SimpleValueChecker;
032import org.apache.commons.math3.exception.DimensionMismatchException;
033import org.apache.commons.math3.exception.NumberIsTooSmallException;
034import 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 * @deprecated As of 3.1 (to be removed in 4.0).
044 * @since 2.2
045 */
046@Deprecated
047public abstract class BaseAbstractMultivariateOptimizer<FUNC extends MultivariateFunction>
048    implements BaseMultivariateOptimizer<FUNC> {
049    /** Evaluations counter. */
050    protected final Incrementor evaluations = new Incrementor();
051    /** Convergence checker. */
052    private ConvergenceChecker<PointValuePair> checker;
053    /** Type of optimization. */
054    private GoalType goal;
055    /** Initial guess. */
056    private double[] start;
057    /** Lower bounds. */
058    private double[] lowerBound;
059    /** Upper bounds. */
060    private double[] upperBound;
061    /** Objective function. */
062    private MultivariateFunction function;
063
064    /**
065     * Simple constructor with default settings.
066     * The convergence check is set to a {@link SimpleValueChecker}.
067     * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
068     */
069    @Deprecated
070    protected BaseAbstractMultivariateOptimizer() {
071        this(new SimpleValueChecker());
072    }
073    /**
074     * @param checker Convergence checker.
075     */
076    protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) {
077        this.checker = checker;
078    }
079
080    /** {@inheritDoc} */
081    public int getMaxEvaluations() {
082        return evaluations.getMaximalCount();
083    }
084
085    /** {@inheritDoc} */
086    public int getEvaluations() {
087        return evaluations.getCount();
088    }
089
090    /** {@inheritDoc} */
091    public ConvergenceChecker<PointValuePair> getConvergenceChecker() {
092        return checker;
093    }
094
095    /**
096     * Compute the objective function value.
097     *
098     * @param point Point at which the objective function must be evaluated.
099     * @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}