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 java.util.Comparator; 021 022import org.apache.commons.math3.optimization.PointValuePair; 023import org.apache.commons.math3.analysis.MultivariateFunction; 024 025/** 026 * This class implements the Nelder-Mead simplex algorithm. 027 * 028 * @deprecated As of 3.1 (to be removed in 4.0). 029 * @since 3.0 030 */ 031@Deprecated 032public class NelderMeadSimplex extends AbstractSimplex { 033 /** Default value for {@link #rho}: {@value}. */ 034 private static final double DEFAULT_RHO = 1; 035 /** Default value for {@link #khi}: {@value}. */ 036 private static final double DEFAULT_KHI = 2; 037 /** Default value for {@link #gamma}: {@value}. */ 038 private static final double DEFAULT_GAMMA = 0.5; 039 /** Default value for {@link #sigma}: {@value}. */ 040 private static final double DEFAULT_SIGMA = 0.5; 041 /** Reflection coefficient. */ 042 private final double rho; 043 /** Expansion coefficient. */ 044 private final double khi; 045 /** Contraction coefficient. */ 046 private final double gamma; 047 /** Shrinkage coefficient. */ 048 private final double sigma; 049 050 /** 051 * Build a Nelder-Mead simplex with default coefficients. 052 * The default coefficients are 1.0 for rho, 2.0 for khi and 0.5 053 * for both gamma and sigma. 054 * 055 * @param n Dimension of the simplex. 056 */ 057 public NelderMeadSimplex(final int n) { 058 this(n, 1d); 059 } 060 061 /** 062 * Build a Nelder-Mead simplex with default coefficients. 063 * The default coefficients are 1.0 for rho, 2.0 for khi and 0.5 064 * for both gamma and sigma. 065 * 066 * @param n Dimension of the simplex. 067 * @param sideLength Length of the sides of the default (hypercube) 068 * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}. 069 */ 070 public NelderMeadSimplex(final int n, double sideLength) { 071 this(n, sideLength, 072 DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA); 073 } 074 075 /** 076 * Build a Nelder-Mead simplex with specified coefficients. 077 * 078 * @param n Dimension of the simplex. See 079 * {@link AbstractSimplex#AbstractSimplex(int,double)}. 080 * @param sideLength Length of the sides of the default (hypercube) 081 * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}. 082 * @param rho Reflection coefficient. 083 * @param khi Expansion coefficient. 084 * @param gamma Contraction coefficient. 085 * @param sigma Shrinkage coefficient. 086 */ 087 public NelderMeadSimplex(final int n, double sideLength, 088 final double rho, final double khi, 089 final double gamma, final double sigma) { 090 super(n, sideLength); 091 092 this.rho = rho; 093 this.khi = khi; 094 this.gamma = gamma; 095 this.sigma = sigma; 096 } 097 098 /** 099 * Build a Nelder-Mead simplex with specified coefficients. 100 * 101 * @param n Dimension of the simplex. See 102 * {@link AbstractSimplex#AbstractSimplex(int)}. 103 * @param rho Reflection coefficient. 104 * @param khi Expansion coefficient. 105 * @param gamma Contraction coefficient. 106 * @param sigma Shrinkage coefficient. 107 */ 108 public NelderMeadSimplex(final int n, 109 final double rho, final double khi, 110 final double gamma, final double sigma) { 111 this(n, 1d, rho, khi, gamma, sigma); 112 } 113 114 /** 115 * Build a Nelder-Mead simplex with default coefficients. 116 * The default coefficients are 1.0 for rho, 2.0 for khi and 0.5 117 * for both gamma and sigma. 118 * 119 * @param steps Steps along the canonical axes representing box edges. 120 * They may be negative but not zero. See 121 */ 122 public NelderMeadSimplex(final double[] steps) { 123 this(steps, DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA); 124 } 125 126 /** 127 * Build a Nelder-Mead simplex with specified coefficients. 128 * 129 * @param steps Steps along the canonical axes representing box edges. 130 * They may be negative but not zero. See 131 * {@link AbstractSimplex#AbstractSimplex(double[])}. 132 * @param rho Reflection coefficient. 133 * @param khi Expansion coefficient. 134 * @param gamma Contraction coefficient. 135 * @param sigma Shrinkage coefficient. 136 * @throws IllegalArgumentException if one of the steps is zero. 137 */ 138 public NelderMeadSimplex(final double[] steps, 139 final double rho, final double khi, 140 final double gamma, final double sigma) { 141 super(steps); 142 143 this.rho = rho; 144 this.khi = khi; 145 this.gamma = gamma; 146 this.sigma = sigma; 147 } 148 149 /** 150 * Build a Nelder-Mead simplex with default coefficients. 151 * The default coefficients are 1.0 for rho, 2.0 for khi and 0.5 152 * for both gamma and sigma. 153 * 154 * @param referenceSimplex Reference simplex. See 155 * {@link AbstractSimplex#AbstractSimplex(double[][])}. 156 */ 157 public NelderMeadSimplex(final double[][] referenceSimplex) { 158 this(referenceSimplex, DEFAULT_RHO, DEFAULT_KHI, DEFAULT_GAMMA, DEFAULT_SIGMA); 159 } 160 161 /** 162 * Build a Nelder-Mead simplex with specified coefficients. 163 * 164 * @param referenceSimplex Reference simplex. See 165 * {@link AbstractSimplex#AbstractSimplex(double[][])}. 166 * @param rho Reflection coefficient. 167 * @param khi Expansion coefficient. 168 * @param gamma Contraction coefficient. 169 * @param sigma Shrinkage coefficient. 170 * @throws org.apache.commons.math3.exception.NotStrictlyPositiveException 171 * if the reference simplex does not contain at least one point. 172 * @throws org.apache.commons.math3.exception.DimensionMismatchException 173 * if there is a dimension mismatch in the reference simplex. 174 */ 175 public NelderMeadSimplex(final double[][] referenceSimplex, 176 final double rho, final double khi, 177 final double gamma, final double sigma) { 178 super(referenceSimplex); 179 180 this.rho = rho; 181 this.khi = khi; 182 this.gamma = gamma; 183 this.sigma = sigma; 184 } 185 186 /** {@inheritDoc} */ 187 @Override 188 public void iterate(final MultivariateFunction evaluationFunction, 189 final Comparator<PointValuePair> comparator) { 190 // The simplex has n + 1 points if dimension is n. 191 final int n = getDimension(); 192 193 // Interesting values. 194 final PointValuePair best = getPoint(0); 195 final PointValuePair secondBest = getPoint(n - 1); 196 final PointValuePair worst = getPoint(n); 197 final double[] xWorst = worst.getPointRef(); 198 199 // Compute the centroid of the best vertices (dismissing the worst 200 // point at index n). 201 final double[] centroid = new double[n]; 202 for (int i = 0; i < n; i++) { 203 final double[] x = getPoint(i).getPointRef(); 204 for (int j = 0; j < n; j++) { 205 centroid[j] += x[j]; 206 } 207 } 208 final double scaling = 1.0 / n; 209 for (int j = 0; j < n; j++) { 210 centroid[j] *= scaling; 211 } 212 213 // compute the reflection point 214 final double[] xR = new double[n]; 215 for (int j = 0; j < n; j++) { 216 xR[j] = centroid[j] + rho * (centroid[j] - xWorst[j]); 217 } 218 final PointValuePair reflected 219 = new PointValuePair(xR, evaluationFunction.value(xR), false); 220 221 if (comparator.compare(best, reflected) <= 0 && 222 comparator.compare(reflected, secondBest) < 0) { 223 // Accept the reflected point. 224 replaceWorstPoint(reflected, comparator); 225 } else if (comparator.compare(reflected, best) < 0) { 226 // Compute the expansion point. 227 final double[] xE = new double[n]; 228 for (int j = 0; j < n; j++) { 229 xE[j] = centroid[j] + khi * (xR[j] - centroid[j]); 230 } 231 final PointValuePair expanded 232 = new PointValuePair(xE, evaluationFunction.value(xE), false); 233 234 if (comparator.compare(expanded, reflected) < 0) { 235 // Accept the expansion point. 236 replaceWorstPoint(expanded, comparator); 237 } else { 238 // Accept the reflected point. 239 replaceWorstPoint(reflected, comparator); 240 } 241 } else { 242 if (comparator.compare(reflected, worst) < 0) { 243 // Perform an outside contraction. 244 final double[] xC = new double[n]; 245 for (int j = 0; j < n; j++) { 246 xC[j] = centroid[j] + gamma * (xR[j] - centroid[j]); 247 } 248 final PointValuePair outContracted 249 = new PointValuePair(xC, evaluationFunction.value(xC), false); 250 if (comparator.compare(outContracted, reflected) <= 0) { 251 // Accept the contraction point. 252 replaceWorstPoint(outContracted, comparator); 253 return; 254 } 255 } else { 256 // Perform an inside contraction. 257 final double[] xC = new double[n]; 258 for (int j = 0; j < n; j++) { 259 xC[j] = centroid[j] - gamma * (centroid[j] - xWorst[j]); 260 } 261 final PointValuePair inContracted 262 = new PointValuePair(xC, evaluationFunction.value(xC), false); 263 264 if (comparator.compare(inContracted, worst) < 0) { 265 // Accept the contraction point. 266 replaceWorstPoint(inContracted, comparator); 267 return; 268 } 269 } 270 271 // Perform a shrink. 272 final double[] xSmallest = getPoint(0).getPointRef(); 273 for (int i = 1; i <= n; i++) { 274 final double[] x = getPoint(i).getPoint(); 275 for (int j = 0; j < n; j++) { 276 x[j] = xSmallest[j] + sigma * (x[j] - xSmallest[j]); 277 } 278 setPoint(i, new PointValuePair(x, Double.NaN, false)); 279 } 280 evaluate(evaluationFunction, comparator); 281 } 282 } 283}