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.exception.DimensionMismatchException;
020 import org.apache.commons.math3.exception.NumberIsTooSmallException;
021 import org.apache.commons.math3.exception.NumberIsTooLargeException;
022
023 /**
024 * Base class for implementing optimizers for multivariate functions.
025 * It contains the boiler-plate code for initial guess and bounds
026 * specifications.
027 * <em>It is not a "user" class.</em>
028 *
029 * @param <PAIR> Type of the point/value pair returned by the optimization
030 * algorithm.
031 *
032 * @version $Id$
033 * @since 3.1
034 */
035 public abstract class BaseMultivariateOptimizer<PAIR>
036 extends BaseOptimizer<PAIR> {
037 /** Initial guess. */
038 private double[] start;
039 /** Lower bounds. */
040 private double[] lowerBound;
041 /** Upper bounds. */
042 private double[] upperBound;
043
044 /**
045 * @param checker Convergence checker.
046 */
047 protected BaseMultivariateOptimizer(ConvergenceChecker<PAIR> checker) {
048 super(checker);
049 }
050
051 /**
052 * {@inheritDoc}
053 *
054 * @param optData Optimization data.
055 * The following data will be looked for:
056 * <ul>
057 * <li>{@link MaxEval}</li>
058 * <li>{@link InitialGuess}</li>
059 * <li>{@link SimpleBounds}</li>
060 * </ul>
061 * @return {@inheritDoc}
062 */
063 @Override
064 public PAIR optimize(OptimizationData... optData) {
065 // Retrieve settings.
066 parseOptimizationData(optData);
067 // Check input consistency.
068 checkParameters();
069 // Perform optimization.
070 return super.optimize(optData);
071 }
072
073 /**
074 * Scans the list of (required and optional) optimization data that
075 * characterize the problem.
076 *
077 * @param optData Optimization data. The following data will be looked for:
078 * <ul>
079 * <li>{@link InitialGuess}</li>
080 * <li>{@link SimpleBounds}</li>
081 * </ul>
082 */
083 private void parseOptimizationData(OptimizationData... optData) {
084 // The existing values (as set by the previous call) are reused if
085 // not provided in the argument list.
086 for (OptimizationData data : optData) {
087 if (data instanceof InitialGuess) {
088 start = ((InitialGuess) data).getInitialGuess();
089 continue;
090 }
091 if (data instanceof SimpleBounds) {
092 final SimpleBounds bounds = (SimpleBounds) data;
093 lowerBound = bounds.getLower();
094 upperBound = bounds.getUpper();
095 continue;
096 }
097 }
098 }
099
100 /**
101 * Gets the initial guess.
102 *
103 * @return the initial guess, or {@code null} if not set.
104 */
105 public double[] getStartPoint() {
106 return start == null ? null : start.clone();
107 }
108 /**
109 * @return the lower bounds, or {@code null} if not set.
110 */
111 public double[] getLowerBound() {
112 return lowerBound == null ? null : lowerBound.clone();
113 }
114 /**
115 * @return the upper bounds, or {@code null} if not set.
116 */
117 public double[] getUpperBound() {
118 return upperBound == null ? null : upperBound.clone();
119 }
120
121 /**
122 * Check parameters consistency.
123 */
124 private void checkParameters() {
125 if (start != null) {
126 final int dim = start.length;
127 if (lowerBound != null) {
128 if (lowerBound.length != dim) {
129 throw new DimensionMismatchException(lowerBound.length, dim);
130 }
131 for (int i = 0; i < dim; i++) {
132 final double v = start[i];
133 final double lo = lowerBound[i];
134 if (v < lo) {
135 throw new NumberIsTooSmallException(v, lo, true);
136 }
137 }
138 }
139 if (upperBound != null) {
140 if (upperBound.length != dim) {
141 throw new DimensionMismatchException(upperBound.length, dim);
142 }
143 for (int i = 0; i < dim; i++) {
144 final double v = start[i];
145 final double hi = upperBound[i];
146 if (v > hi) {
147 throw new NumberIsTooLargeException(v, hi, true);
148 }
149 }
150 }
151 }
152 }
153 }