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 }