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 018package org.apache.commons.math3.optimization.direct; 019 020import org.apache.commons.math3.util.Incrementor; 021import org.apache.commons.math3.exception.MaxCountExceededException; 022import org.apache.commons.math3.exception.TooManyEvaluationsException; 023import org.apache.commons.math3.analysis.MultivariateFunction; 024import org.apache.commons.math3.optimization.BaseMultivariateOptimizer; 025import org.apache.commons.math3.optimization.OptimizationData; 026import org.apache.commons.math3.optimization.GoalType; 027import org.apache.commons.math3.optimization.InitialGuess; 028import org.apache.commons.math3.optimization.SimpleBounds; 029import org.apache.commons.math3.optimization.ConvergenceChecker; 030import org.apache.commons.math3.optimization.PointValuePair; 031import org.apache.commons.math3.optimization.SimpleValueChecker; 032import org.apache.commons.math3.exception.DimensionMismatchException; 033import org.apache.commons.math3.exception.NumberIsTooSmallException; 034import org.apache.commons.math3.exception.NumberIsTooLargeException; 035 036/** 037 * Base class for implementing optimizers for multivariate scalar functions. 038 * This base class handles the boiler-plate methods associated to thresholds, 039 * evaluations counting, initial guess and simple bounds settings. 040 * 041 * @param <FUNC> Type of the objective function to be optimized. 042 * 043 * @deprecated As of 3.1 (to be removed in 4.0). 044 * @since 2.2 045 */ 046@Deprecated 047public abstract class BaseAbstractMultivariateOptimizer<FUNC extends MultivariateFunction> 048 implements BaseMultivariateOptimizer<FUNC> { 049 /** Evaluations counter. */ 050 protected final Incrementor evaluations = new Incrementor(); 051 /** Convergence checker. */ 052 private ConvergenceChecker<PointValuePair> checker; 053 /** Type of optimization. */ 054 private GoalType goal; 055 /** Initial guess. */ 056 private double[] start; 057 /** Lower bounds. */ 058 private double[] lowerBound; 059 /** Upper bounds. */ 060 private double[] upperBound; 061 /** Objective function. */ 062 private MultivariateFunction function; 063 064 /** 065 * Simple constructor with default settings. 066 * The convergence check is set to a {@link SimpleValueChecker}. 067 * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()} 068 */ 069 @Deprecated 070 protected BaseAbstractMultivariateOptimizer() { 071 this(new SimpleValueChecker()); 072 } 073 /** 074 * @param checker Convergence checker. 075 */ 076 protected BaseAbstractMultivariateOptimizer(ConvergenceChecker<PointValuePair> checker) { 077 this.checker = checker; 078 } 079 080 /** {@inheritDoc} */ 081 public int getMaxEvaluations() { 082 return evaluations.getMaximalCount(); 083 } 084 085 /** {@inheritDoc} */ 086 public int getEvaluations() { 087 return evaluations.getCount(); 088 } 089 090 /** {@inheritDoc} */ 091 public ConvergenceChecker<PointValuePair> getConvergenceChecker() { 092 return checker; 093 } 094 095 /** 096 * Compute the objective function value. 097 * 098 * @param point Point at which the objective function must be evaluated. 099 * @return the objective function value at the specified point. 100 * @throws TooManyEvaluationsException if the maximal number of 101 * evaluations is exceeded. 102 */ 103 protected double computeObjectiveValue(double[] point) { 104 try { 105 evaluations.incrementCount(); 106 } catch (MaxCountExceededException e) { 107 throw new TooManyEvaluationsException(e.getMax()); 108 } 109 return function.value(point); 110 } 111 112 /** 113 * {@inheritDoc} 114 * 115 * @deprecated As of 3.1. Please use 116 * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])} 117 * instead. 118 */ 119 @Deprecated 120 public PointValuePair optimize(int maxEval, FUNC f, GoalType goalType, 121 double[] startPoint) { 122 return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint)); 123 } 124 125 /** 126 * Optimize an objective function. 127 * 128 * @param maxEval Allowed number of evaluations of the objective function. 129 * @param f Objective function. 130 * @param goalType Optimization type. 131 * @param optData Optimization data. The following data will be looked for: 132 * <ul> 133 * <li>{@link InitialGuess}</li> 134 * <li>{@link SimpleBounds}</li> 135 * </ul> 136 * @return the point/value pair giving the optimal value of the objective 137 * function. 138 * @since 3.1 139 */ 140 public PointValuePair optimize(int maxEval, 141 FUNC f, 142 GoalType goalType, 143 OptimizationData... optData) { 144 return optimizeInternal(maxEval, f, goalType, optData); 145 } 146 147 /** 148 * Optimize an objective function. 149 * 150 * @param f Objective function. 151 * @param goalType Type of optimization goal: either 152 * {@link GoalType#MAXIMIZE} or {@link GoalType#MINIMIZE}. 153 * @param startPoint Start point for optimization. 154 * @param maxEval Maximum number of function evaluations. 155 * @return the point/value pair giving the optimal value for objective 156 * function. 157 * @throws org.apache.commons.math3.exception.DimensionMismatchException 158 * if the start point dimension is wrong. 159 * @throws org.apache.commons.math3.exception.TooManyEvaluationsException 160 * if the maximal number of evaluations is exceeded. 161 * @throws org.apache.commons.math3.exception.NullArgumentException if 162 * any argument is {@code null}. 163 * @deprecated As of 3.1. Please use 164 * {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])} 165 * instead. 166 */ 167 @Deprecated 168 protected PointValuePair optimizeInternal(int maxEval, FUNC f, GoalType goalType, 169 double[] startPoint) { 170 return optimizeInternal(maxEval, f, goalType, new InitialGuess(startPoint)); 171 } 172 173 /** 174 * Optimize an objective function. 175 * 176 * @param maxEval Allowed number of evaluations of the objective function. 177 * @param f Objective function. 178 * @param goalType Optimization type. 179 * @param optData Optimization data. The following data will be looked for: 180 * <ul> 181 * <li>{@link InitialGuess}</li> 182 * <li>{@link SimpleBounds}</li> 183 * </ul> 184 * @return the point/value pair giving the optimal value of the objective 185 * function. 186 * @throws TooManyEvaluationsException if the maximal number of 187 * evaluations is exceeded. 188 * @since 3.1 189 */ 190 protected PointValuePair optimizeInternal(int maxEval, 191 FUNC f, 192 GoalType goalType, 193 OptimizationData... optData) 194 throws TooManyEvaluationsException { 195 // Set internal state. 196 evaluations.setMaximalCount(maxEval); 197 evaluations.resetCount(); 198 function = f; 199 goal = goalType; 200 // Retrieve other settings. 201 parseOptimizationData(optData); 202 // Check input consistency. 203 checkParameters(); 204 // Perform computation. 205 return doOptimize(); 206 } 207 208 /** 209 * Scans the list of (required and optional) optimization data that 210 * characterize the problem. 211 * 212 * @param optData Optimization data. The following data will be looked for: 213 * <ul> 214 * <li>{@link InitialGuess}</li> 215 * <li>{@link SimpleBounds}</li> 216 * </ul> 217 */ 218 private void parseOptimizationData(OptimizationData... optData) { 219 // The existing values (as set by the previous call) are reused if 220 // not provided in the argument list. 221 for (OptimizationData data : optData) { 222 if (data instanceof InitialGuess) { 223 start = ((InitialGuess) data).getInitialGuess(); 224 continue; 225 } 226 if (data instanceof SimpleBounds) { 227 final SimpleBounds bounds = (SimpleBounds) data; 228 lowerBound = bounds.getLower(); 229 upperBound = bounds.getUpper(); 230 continue; 231 } 232 } 233 } 234 235 /** 236 * @return the optimization type. 237 */ 238 public GoalType getGoalType() { 239 return goal; 240 } 241 242 /** 243 * @return the initial guess. 244 */ 245 public double[] getStartPoint() { 246 return start == null ? null : start.clone(); 247 } 248 /** 249 * @return the lower bounds. 250 * @since 3.1 251 */ 252 public double[] getLowerBound() { 253 return lowerBound == null ? null : lowerBound.clone(); 254 } 255 /** 256 * @return the upper bounds. 257 * @since 3.1 258 */ 259 public double[] getUpperBound() { 260 return upperBound == null ? null : upperBound.clone(); 261 } 262 263 /** 264 * Perform the bulk of the optimization algorithm. 265 * 266 * @return the point/value pair giving the optimal value of the 267 * objective function. 268 */ 269 protected abstract PointValuePair doOptimize(); 270 271 /** 272 * Check parameters consistency. 273 */ 274 private void checkParameters() { 275 if (start != null) { 276 final int dim = start.length; 277 if (lowerBound != null) { 278 if (lowerBound.length != dim) { 279 throw new DimensionMismatchException(lowerBound.length, dim); 280 } 281 for (int i = 0; i < dim; i++) { 282 final double v = start[i]; 283 final double lo = lowerBound[i]; 284 if (v < lo) { 285 throw new NumberIsTooSmallException(v, lo, true); 286 } 287 } 288 } 289 if (upperBound != null) { 290 if (upperBound.length != dim) { 291 throw new DimensionMismatchException(upperBound.length, dim); 292 } 293 for (int i = 0; i < dim; i++) { 294 final double v = start[i]; 295 final double hi = upperBound[i]; 296 if (v > hi) { 297 throw new NumberIsTooLargeException(v, hi, true); 298 } 299 } 300 } 301 302 // If the bounds were not specified, the allowed interval is 303 // assumed to be [-inf, +inf]. 304 if (lowerBound == null) { 305 lowerBound = new double[dim]; 306 for (int i = 0; i < dim; i++) { 307 lowerBound[i] = Double.NEGATIVE_INFINITY; 308 } 309 } 310 if (upperBound == null) { 311 upperBound = new double[dim]; 312 for (int i = 0; i < dim; i++) { 313 upperBound[i] = Double.POSITIVE_INFINITY; 314 } 315 } 316 } 317 } 318}