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    package org.apache.commons.math3.optim;
018    
019    import org.apache.commons.math3.util.Incrementor;
020    import org.apache.commons.math3.exception.TooManyEvaluationsException;
021    import org.apache.commons.math3.exception.TooManyIterationsException;
022    
023    /**
024     * Base class for implementing optimizers.
025     * It contains the boiler-plate code for counting the number of evaluations
026     * of the objective function and the number of iterations of the algorithm,
027     * and storing the convergence checker.
028     * <em>It is not a "user" class.</em>
029     *
030     * @param <PAIR> Type of the point/value pair returned by the optimization
031     * algorithm.
032     *
033     * @version $Id$
034     * @since 3.1
035     */
036    public abstract class BaseOptimizer<PAIR> {
037        /** Evaluations counter. */
038        protected final Incrementor evaluations;
039        /** Iterations counter. */
040        protected final Incrementor iterations;
041        /** Convergence checker. */
042        private ConvergenceChecker<PAIR> checker;
043    
044        /**
045         * @param checker Convergence checker.
046         */
047        protected BaseOptimizer(ConvergenceChecker<PAIR> checker) {
048            this.checker = checker;
049    
050            evaluations = new Incrementor(0, new MaxEvalCallback());
051            iterations = new Incrementor(0, new MaxIterCallback());
052        }
053    
054        /**
055         * Gets the maximal number of function evaluations.
056         *
057         * @return the maximal number of function evaluations.
058         */
059        public int getMaxEvaluations() {
060            return evaluations.getMaximalCount();
061        }
062    
063        /**
064         * Gets the number of evaluations of the objective function.
065         * The number of evaluations corresponds to the last call to the
066         * {@code optimize} method. It is 0 if the method has not been
067         * called yet.
068         *
069         * @return the number of evaluations of the objective function.
070         */
071        public int getEvaluations() {
072            return evaluations.getCount();
073        }
074    
075        /**
076         * Gets the maximal number of iterations.
077         *
078         * @return the maximal number of iterations.
079         */
080        public int getMaxIterations() {
081            return iterations.getMaximalCount();
082        }
083    
084        /**
085         * Gets the number of iterations performed by the algorithm.
086         * The number iterations corresponds to the last call to the
087         * {@code optimize} method. It is 0 if the method has not been
088         * called yet.
089         *
090         * @return the number of evaluations of the objective function.
091         */
092        public int getIterations() {
093            return iterations.getCount();
094        }
095    
096        /**
097         * Gets the convergence checker.
098         *
099         * @return the object used to check for convergence.
100         */
101        public ConvergenceChecker<PAIR> getConvergenceChecker() {
102            return checker;
103        }
104    
105        /**
106         * Stores data and performs the optimization.
107         * <br/>
108         * The list of parameters is open-ended so that sub-classes can extend it
109         * with arguments specific to their concrete implementations.
110         * <br/>
111         * When the method is called multiple times, instance data is overwritten
112         * only when actually present in the list of arguments: when not specified,
113         * data set in a previous call is retained (and thus is optional in
114         * subsequent calls).
115         *
116         * @param optData Optimization data. The following data will be looked for:
117         * <ul>
118         *  <li>{@link MaxEval}</li>
119         *  <li>{@link MaxIter}</li>
120         * </ul>
121         * @return a point/value pair that satifies the convergence criteria.
122         * @throws TooManyEvaluationsException if the maximal number of
123         * evaluations is exceeded.
124         * @throws TooManyIterationsException if the maximal number of
125         * iterations is exceeded.
126         */
127        public PAIR optimize(OptimizationData... optData)
128            throws TooManyEvaluationsException,
129                   TooManyIterationsException {
130            // Retrieve settings.
131            parseOptimizationData(optData);
132            // Reset counters.
133            evaluations.resetCount();
134            iterations.resetCount();
135            // Perform optimization.
136            return doOptimize();
137        }
138    
139        /**
140         * Performs the bulk of the optimization algorithm.
141         *
142         * @return the point/value pair giving the optimal value of the
143         * objective function.
144         */
145        protected abstract PAIR doOptimize();
146    
147        /**
148         * Increment the evaluation count.
149         *
150         * @throws TooManyEvaluationsException if the allowed evaluations
151         * have been exhausted.
152         */
153        protected void incrementEvaluationCount()
154            throws TooManyEvaluationsException {
155            evaluations.incrementCount();
156        }
157    
158        /**
159         * Increment the iteration count.
160         *
161         * @throws TooManyIterationsException if the allowed iterations
162         * have been exhausted.
163         */
164        protected void incrementIterationCount()
165            throws TooManyIterationsException {
166            iterations.incrementCount();
167        }
168    
169        /**
170         * Scans the list of (required and optional) optimization data that
171         * characterize the problem.
172         *
173         * @param optData Optimization data.
174         * The following data will be looked for:
175         * <ul>
176         *  <li>{@link MaxEval}</li>
177         *  <li>{@link MaxIter}</li>
178         * </ul>
179         */
180        private void parseOptimizationData(OptimizationData... optData) {
181            // The existing values (as set by the previous call) are reused if
182            // not provided in the argument list.
183            for (OptimizationData data : optData) {
184                if (data instanceof MaxEval) {
185                    evaluations.setMaximalCount(((MaxEval) data).getMaxEval());
186                    continue;
187                }
188                if (data instanceof MaxIter) {
189                    iterations.setMaximalCount(((MaxIter) data).getMaxIter());
190                    continue;
191                }
192            }
193        }
194    
195        /**
196         * Defines the action to perform when reaching the maximum number
197         * of evaluations.
198         */
199        private static class MaxEvalCallback
200            implements  Incrementor.MaxCountExceededCallback {
201            /**
202             * {@inheritDoc}
203             * @throws TooManyEvaluationsException.
204             */
205            public void trigger(int max) {
206                throw new TooManyEvaluationsException(max);
207            }
208        }
209    
210        /**
211         * Defines the action to perform when reaching the maximum number
212         * of evaluations.
213         */
214        private static class MaxIterCallback
215            implements Incrementor.MaxCountExceededCallback {
216            /**
217             * {@inheritDoc}
218             * @throws TooManyIterationsException.
219             */
220            public void trigger(int max) {
221                throw new TooManyIterationsException(max);
222            }
223        }
224    }