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
18package org.apache.commons.math.optimization.univariate;
19
20import org.apache.commons.math.ConvergingAlgorithmImpl;
21import org.apache.commons.math.FunctionEvaluationException;
22import org.apache.commons.math.MaxEvaluationsExceededException;
23import org.apache.commons.math.MaxIterationsExceededException;
24import org.apache.commons.math.analysis.UnivariateRealFunction;
25import org.apache.commons.math.exception.MathUnsupportedOperationException;
26import org.apache.commons.math.exception.NoDataException;
27import org.apache.commons.math.exception.util.LocalizedFormats;
28import org.apache.commons.math.optimization.GoalType;
29import org.apache.commons.math.optimization.UnivariateRealOptimizer;
30
31/**
32 * Provide a default implementation for several functions useful to generic
33 * optimizers.
34 *
35 * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
36 * @since 2.0
37 */
38public abstract class AbstractUnivariateRealOptimizer
39    extends ConvergingAlgorithmImpl implements UnivariateRealOptimizer {
40    /** Indicates where a root has been computed. */
41    protected boolean resultComputed;
42    /** The last computed root. */
43    protected double result;
44    /** Value of the function at the last computed result. */
45    protected double functionValue;
46    /** Maximal number of evaluations allowed. */
47    private int maxEvaluations;
48    /** Number of evaluations already performed. */
49    private int evaluations;
50    /** Optimization type */
51    private GoalType optimizationGoal;
52    /** Lower end of search interval. */
53    private double searchMin;
54    /** Higher end of search interval. */
55    private double searchMax;
56    /** Initial guess . */
57    private double searchStart;
58    /** Function to optimize. */
59    private UnivariateRealFunction function;
60
61    /**
62     * Construct a solver with given iteration count and accuracy.
63     * @param defaultAbsoluteAccuracy maximum absolute error
64     * @param defaultMaximalIterationCount maximum number of iterations
65     * @throws IllegalArgumentException if f is null or the
66     * defaultAbsoluteAccuracy is not valid
67     * @deprecated in 2.2. Please use the "setter" methods to assign meaningful
68     * values to the maximum numbers of iterations and evaluations, and to the
69     * absolute and relative accuracy thresholds.
70     */
71    @Deprecated
72    protected AbstractUnivariateRealOptimizer(final int defaultMaximalIterationCount,
73                                              final double defaultAbsoluteAccuracy) {
74        super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
75        resultComputed = false;
76        setMaxEvaluations(Integer.MAX_VALUE);
77    }
78
79    /**
80     * Default constructor.
81     * To be removed once the single non-default one has been removed.
82     */
83    protected AbstractUnivariateRealOptimizer() {}
84
85    /**
86     * Check whether a result has been computed.
87     * @throws NoDataException if no result has been computed
88     * @deprecated in 2.2 (no alternative).
89     */
90    @Deprecated
91    protected void checkResultComputed() {
92        if (!resultComputed) {
93            throw new NoDataException();
94        }
95    }
96
97    /** {@inheritDoc} */
98    public double getResult() {
99        if (!resultComputed) {
100            throw new NoDataException();
101        }
102        return result;
103    }
104
105    /** {@inheritDoc} */
106    public double getFunctionValue() throws FunctionEvaluationException {
107        if (Double.isNaN(functionValue)) {
108            final double opt = getResult();
109            functionValue = function.value(opt);
110        }
111        return functionValue;
112    }
113
114    /**
115     * Convenience function for implementations.
116     *
117     * @param x the result to set
118     * @param fx the result to set
119     * @param iterationCount the iteration count to set
120     * @deprecated in 2.2 (no alternative).
121     */
122    @Deprecated
123    protected final void setResult(final double x, final double fx,
124                                   final int iterationCount) {
125        this.result         = x;
126        this.functionValue  = fx;
127        this.iterationCount = iterationCount;
128        this.resultComputed = true;
129    }
130
131    /**
132     * Convenience function for implementations.
133     * @deprecated in 2.2 (no alternative).
134     */
135    @Deprecated
136    protected final void clearResult() {
137        this.resultComputed = false;
138    }
139
140    /** {@inheritDoc} */
141    public void setMaxEvaluations(int maxEvaluations) {
142        this.maxEvaluations = maxEvaluations;
143    }
144
145    /** {@inheritDoc} */
146    public int getMaxEvaluations() {
147        return maxEvaluations;
148    }
149
150    /** {@inheritDoc} */
151    public int getEvaluations() {
152        return evaluations;
153    }
154
155    /**
156     * @return the optimization type.
157     */
158    public GoalType getGoalType() {
159        return optimizationGoal;
160    }
161    /**
162     * @return the lower of the search interval.
163     */
164    public double getMin() {
165        return searchMin;
166    }
167    /**
168     * @return the higher of the search interval.
169     */
170    public double getMax() {
171        return searchMax;
172    }
173    /**
174     * @return the initial guess.
175     */
176    public double getStartValue() {
177        return searchStart;
178    }
179
180    /**
181     * Compute the objective function value.
182     * @param f objective function
183     * @param point point at which the objective function must be evaluated
184     * @return objective function value at specified point
185     * @exception FunctionEvaluationException if the function cannot be evaluated
186     * or the maximal number of iterations is exceeded
187     * @deprecated in 2.2. Use this {@link #computeObjectiveValue(double)
188     * replacement} instead.
189     */
190    @Deprecated
191    protected double computeObjectiveValue(final UnivariateRealFunction f,
192                                           final double point)
193        throws FunctionEvaluationException {
194        if (++evaluations > maxEvaluations) {
195            throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations), point);
196        }
197        return f.value(point);
198    }
199
200    /**
201     * Compute the objective function value.
202     *
203     * @param point Point at which the objective function must be evaluated.
204     * @return the objective function value at specified point.
205     * @exception FunctionEvaluationException if the function cannot be evaluated
206     * or the maximal number of iterations is exceeded.
207     */
208    protected double computeObjectiveValue(double point)
209        throws FunctionEvaluationException {
210        if (++evaluations > maxEvaluations) {
211            resultComputed = false;
212            throw new FunctionEvaluationException(new MaxEvaluationsExceededException(maxEvaluations), point);
213        }
214        return function.value(point);
215    }
216
217    /** {@inheritDoc} */
218    public double optimize(UnivariateRealFunction f, GoalType goal,
219                           double min, double max, double startValue)
220        throws MaxIterationsExceededException, FunctionEvaluationException {
221        // Initialize.
222        this.searchMin = min;
223        this.searchMax = max;
224        this.searchStart = startValue;
225        this.optimizationGoal = goal;
226        this.function = f;
227
228        // Reset.
229        functionValue = Double.NaN;
230        evaluations = 0;
231        resetIterationsCounter();
232
233        // Perform computation.
234        result = doOptimize();
235        resultComputed = true;
236
237        return result;
238    }
239
240    /**
241     * Set the value at the optimum.
242     *
243     * @param functionValue Value of the objective function at the optimum.
244     */
245    protected void setFunctionValue(double functionValue) {
246        this.functionValue = functionValue;
247    }
248
249    /** {@inheritDoc} */
250    public double optimize(UnivariateRealFunction f, GoalType goal,
251                           double min, double max)
252        throws MaxIterationsExceededException, FunctionEvaluationException {
253        return optimize(f, goal, min, max, min + 0.5 * (max - min));
254    }
255
256    /**
257     * Method for implementing actual optimization algorithms in derived
258     * classes.
259     *
260     * From version 3.0 onwards, this method will be abstract - i.e.
261     * concrete implementations will have to implement it.  If this method
262     * is not implemented, subclasses must override
263     * {@link #optimize(UnivariateRealFunction, GoalType, double, double)}.
264     *
265     * @return the optimum.
266     * @throws MaxIterationsExceededException if the maximum iteration count
267     * is exceeded.
268     * @throws FunctionEvaluationException if an error occurs evaluating
269     * the function.
270     */
271    protected double doOptimize()
272        throws MaxIterationsExceededException, FunctionEvaluationException {
273        throw new MathUnsupportedOperationException(LocalizedFormats.NOT_OVERRIDEN);
274    }
275}
276