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 */ 017package org.apache.commons.math4.legacy.optim; 018 019import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException; 020import org.apache.commons.math4.legacy.exception.TooManyIterationsException; 021import org.apache.commons.math4.legacy.core.IntegerSequence; 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 * @since 3.1 034 */ 035public abstract class BaseOptimizer<PAIR> { 036 /** Callback to use for the evaluation counter. */ 037 private static final MaxEvalCallback MAX_EVAL_CALLBACK = new MaxEvalCallback(); 038 /** Callback to use for the iteration counter. */ 039 private static final MaxIterCallback MAX_ITER_CALLBACK = new MaxIterCallback(); 040 041 /** Convergence checker. */ 042 private final ConvergenceChecker<PAIR> checker; 043 /** Maximum number of evaluations. */ 044 private int maxEvaluations; 045 /** Maximum number of iterations. */ 046 private int maxIterations; 047 /** Evaluations counter. */ 048 private IntegerSequence.Incrementor evaluations; 049 /** Iterations counter. */ 050 private IntegerSequence.Incrementor iterations; 051 052 /** 053 * @param checker Convergence checker. 054 */ 055 protected BaseOptimizer(ConvergenceChecker<PAIR> checker) { 056 this(checker, 0, Integer.MAX_VALUE); 057 } 058 059 /** 060 * @param checker Convergence checker. 061 * @param maxEval Maximum number of objective function evaluations. 062 * @param maxIter Maximum number of algorithm iterations. 063 */ 064 protected BaseOptimizer(ConvergenceChecker<PAIR> checker, 065 int maxEval, 066 int maxIter) { 067 this.checker = checker; 068 this.maxEvaluations = maxEval; 069 this.maxIterations = maxIter; 070 } 071 072 /** 073 * Gets the maximal number of function evaluations. 074 * 075 * @return the maximal number of function evaluations. 076 */ 077 public int getMaxEvaluations() { 078 return evaluations.getMaximalCount(); 079 } 080 081 /** 082 * Gets the number of evaluations of the objective function. 083 * The number of evaluations corresponds to the last call to the 084 * {@code optimize} method. It is 0 if the method has not been 085 * called yet. 086 * 087 * @return the number of evaluations of the objective function. 088 */ 089 public int getEvaluations() { 090 return evaluations.getCount(); 091 } 092 093 /** 094 * Gets the maximal number of iterations. 095 * 096 * @return the maximal number of iterations. 097 */ 098 public int getMaxIterations() { 099 return iterations.getMaximalCount(); 100 } 101 102 /** 103 * Gets the number of iterations performed by the algorithm. 104 * The number iterations corresponds to the last call to the 105 * {@code optimize} method. It is 0 if the method has not been 106 * called yet. 107 * 108 * @return the number of evaluations of the objective function. 109 */ 110 public int getIterations() { 111 return iterations.getCount(); 112 } 113 114 /** 115 * Gets the convergence checker. 116 * 117 * @return the object used to check for convergence. 118 */ 119 public ConvergenceChecker<PAIR> getConvergenceChecker() { 120 return checker; 121 } 122 123 /** 124 * Stores data and performs the optimization. 125 * <p> 126 * The list of parameters is open-ended so that sub-classes can extend it 127 * with arguments specific to their concrete implementations. 128 * <p> 129 * When the method is called multiple times, instance data is overwritten 130 * only when actually present in the list of arguments: when not specified, 131 * data set in a previous call is retained (and thus is optional in 132 * subsequent calls). 133 * <p> 134 * Important note: Subclasses <em>must</em> override 135 * {@link #parseOptimizationData(OptimizationData[])} if they need to register 136 * their own options; but then, they <em>must</em> also call 137 * {@code super.parseOptimizationData(optData)} within that method. 138 * 139 * @param optData Optimization data. 140 * This method will register the following data: 141 * <ul> 142 * <li>{@link MaxEval}</li> 143 * <li>{@link MaxIter}</li> 144 * </ul> 145 * @return a point/value pair that satisfies the convergence criteria. 146 * @throws TooManyEvaluationsException if the maximal number of 147 * evaluations is exceeded. 148 * @throws TooManyIterationsException if the maximal number of 149 * iterations is exceeded. 150 */ 151 public PAIR optimize(OptimizationData... optData) { 152 // Parse options. 153 parseOptimizationData(optData); 154 // Reset counters. 155 resetCounters(); 156 // Perform optimization. 157 return doOptimize(); 158 } 159 160 /** 161 * Performs the optimization. 162 * 163 * @return a point/value pair that satisfies the convergence criteria. 164 * @throws TooManyEvaluationsException if the maximal number of 165 * evaluations is exceeded. 166 * @throws TooManyIterationsException if the maximal number of 167 * iterations is exceeded. 168 */ 169 public PAIR optimize() { 170 // Reset counters. 171 resetCounters(); 172 // Perform optimization. 173 return doOptimize(); 174 } 175 176 /** 177 * Performs the bulk of the optimization algorithm. 178 * 179 * @return the point/value pair giving the optimal value of the 180 * objective function. 181 */ 182 protected abstract PAIR doOptimize(); 183 184 /** 185 * Increment the evaluation count. 186 * 187 * @throws TooManyEvaluationsException if the allowed evaluations 188 * have been exhausted. 189 */ 190 protected void incrementEvaluationCount() { 191 evaluations.increment(); 192 } 193 194 /** 195 * Increment the iteration count. 196 * 197 * @throws TooManyIterationsException if the allowed iterations 198 * have been exhausted. 199 */ 200 protected void incrementIterationCount() { 201 iterations.increment(); 202 } 203 204 /** 205 * Scans the list of (required and optional) optimization data that 206 * characterize the problem. 207 * 208 * @param optData Optimization data. 209 * The following data will be looked for: 210 * <ul> 211 * <li>{@link MaxEval}</li> 212 * <li>{@link MaxIter}</li> 213 * </ul> 214 */ 215 protected void parseOptimizationData(OptimizationData... optData) { 216 // The existing values (as set by the previous call) are reused if 217 // not provided in the argument list. 218 for (OptimizationData data : optData) { 219 if (data instanceof MaxEval) { 220 maxEvaluations = ((MaxEval) data).getMaxEval(); 221 continue; 222 } 223 if (data instanceof MaxIter) { 224 maxIterations = ((MaxIter) data).getMaxIter(); 225 continue; 226 } 227 } 228 } 229 230 /** Reset counters. */ 231 private void resetCounters() { 232 evaluations = IntegerSequence.Incrementor.create() 233 .withMaximalCount(maxEvaluations) 234 .withCallback(MAX_EVAL_CALLBACK); 235 iterations = IntegerSequence.Incrementor.create() 236 .withMaximalCount(maxIterations) 237 .withCallback(MAX_ITER_CALLBACK); 238 } 239 240 /** 241 * Defines the action to perform when reaching the maximum number 242 * of evaluations. 243 */ 244 private static class MaxEvalCallback 245 implements IntegerSequence.Incrementor.MaxCountExceededCallback { 246 /** 247 * {@inheritDoc} 248 * @throws TooManyEvaluationsException 249 */ 250 @Override 251 public void trigger(int max) { 252 throw new TooManyEvaluationsException(max); 253 } 254 } 255 256 /** 257 * Defines the action to perform when reaching the maximum number 258 * of evaluations. 259 */ 260 private static class MaxIterCallback 261 implements IntegerSequence.Incrementor.MaxCountExceededCallback { 262 /** 263 * {@inheritDoc} 264 * @throws TooManyIterationsException 265 */ 266 @Override 267 public void trigger(int max) { 268 throw new TooManyIterationsException(max); 269 } 270 } 271}