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 *
108 * @param optData Optimization data. The following data will be looked for:
109 * <ul>
110 * <li>{@link MaxEval}</li>
111 * <li>{@link MaxIter}</li>
112 * </ul>
113 * @return a point/value pair that satifies the convergence criteria.
114 * @throws TooManyEvaluationsException if the maximal number of
115 * evaluations is exceeded.
116 * @throws TooManyIterationsException if the maximal number of
117 * iterations is exceeded.
118 */
119 public PAIR optimize(OptimizationData... optData)
120 throws TooManyEvaluationsException,
121 TooManyIterationsException {
122 // Retrieve settings.
123 parseOptimizationData(optData);
124 // Reset counters.
125 evaluations.resetCount();
126 iterations.resetCount();
127 // Perform optimization.
128 return doOptimize();
129 }
130
131 /**
132 * Performs the bulk of the optimization algorithm.
133 *
134 * @return the point/value pair giving the optimal value of the
135 * objective function.
136 */
137 protected abstract PAIR doOptimize();
138
139 /**
140 * Increment the evaluation count.
141 *
142 * @throws TooManyEvaluationsException if the allowed evaluations
143 * have been exhausted.
144 */
145 protected void incrementEvaluationCount()
146 throws TooManyEvaluationsException {
147 evaluations.incrementCount();
148 }
149
150 /**
151 * Increment the iteration count.
152 *
153 * @throws TooManyIterationsException if the allowed iterations
154 * have been exhausted.
155 */
156 protected void incrementIterationCount()
157 throws TooManyIterationsException {
158 iterations.incrementCount();
159 }
160
161 /**
162 * Scans the list of (required and optional) optimization data that
163 * characterize the problem.
164 *
165 * @param optData Optimization data.
166 * The following data will be looked for:
167 * <ul>
168 * <li>{@link MaxEval}</li>
169 * <li>{@link MaxIter}</li>
170 * </ul>
171 */
172 private void parseOptimizationData(OptimizationData... optData) {
173 // The existing values (as set by the previous call) are reused if
174 // not provided in the argument list.
175 for (OptimizationData data : optData) {
176 if (data instanceof MaxEval) {
177 evaluations.setMaximalCount(((MaxEval) data).getMaxEval());
178 continue;
179 }
180 if (data instanceof MaxIter) {
181 iterations.setMaximalCount(((MaxIter) data).getMaxIter());
182 continue;
183 }
184 }
185 }
186
187 /**
188 * Defines the action to perform when reaching the maximum number
189 * of evaluations.
190 */
191 private static class MaxEvalCallback
192 implements Incrementor.MaxCountExceededCallback {
193 /**
194 * {@inheritDoc}
195 * @throws TooManyEvaluationsException.
196 */
197 public void trigger(int max) {
198 throw new TooManyEvaluationsException(max);
199 }
200 }
201
202 /**
203 * Defines the action to perform when reaching the maximum number
204 * of evaluations.
205 */
206 private static class MaxIterCallback
207 implements Incrementor.MaxCountExceededCallback {
208 /**
209 * {@inheritDoc}
210 * @throws TooManyIterationsException.
211 */
212 public void trigger(int max) {
213 throw new TooManyIterationsException(max);
214 }
215 }
216 }