1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.optim.nonlinear.scalar.noderiv; 23 24 import java.util.Comparator; 25 26 import org.hipparchus.analysis.MultivariateFunction; 27 import org.hipparchus.optim.PointValuePair; 28 29 /** 30 * This class implements the multi-directional direct search method. 31 * 32 */ 33 public class MultiDirectionalSimplex extends AbstractSimplex { 34 /** Default value for {@link #khi}: {@value}. */ 35 private static final double DEFAULT_KHI = 2; 36 /** Default value for {@link #gamma}: {@value}. */ 37 private static final double DEFAULT_GAMMA = 0.5; 38 /** Expansion coefficient. */ 39 private final double khi; 40 /** Contraction coefficient. */ 41 private final double gamma; 42 43 /** 44 * Build a multi-directional simplex with default coefficients. 45 * The default values are 2.0 for khi and 0.5 for gamma. 46 * 47 * @param n Dimension of the simplex. 48 */ 49 public MultiDirectionalSimplex(final int n) { 50 this(n, 1d); 51 } 52 53 /** 54 * Build a multi-directional simplex with default coefficients. 55 * The default values are 2.0 for khi and 0.5 for gamma. 56 * 57 * @param n Dimension of the simplex. 58 * @param sideLength Length of the sides of the default (hypercube) 59 * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}. 60 */ 61 public MultiDirectionalSimplex(final int n, double sideLength) { 62 this(n, sideLength, DEFAULT_KHI, DEFAULT_GAMMA); 63 } 64 65 /** 66 * Build a multi-directional simplex with specified coefficients. 67 * 68 * @param n Dimension of the simplex. See 69 * {@link AbstractSimplex#AbstractSimplex(int,double)}. 70 * @param khi Expansion coefficient. 71 * @param gamma Contraction coefficient. 72 */ 73 public MultiDirectionalSimplex(final int n, 74 final double khi, final double gamma) { 75 this(n, 1d, khi, gamma); 76 } 77 78 /** 79 * Build a multi-directional simplex with specified coefficients. 80 * 81 * @param n Dimension of the simplex. See 82 * {@link AbstractSimplex#AbstractSimplex(int,double)}. 83 * @param sideLength Length of the sides of the default (hypercube) 84 * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}. 85 * @param khi Expansion coefficient. 86 * @param gamma Contraction coefficient. 87 */ 88 public MultiDirectionalSimplex(final int n, double sideLength, 89 final double khi, final double gamma) { 90 super(n, sideLength); 91 92 this.khi = khi; 93 this.gamma = gamma; 94 } 95 96 /** 97 * Build a multi-directional simplex with default coefficients. 98 * The default values are 2.0 for khi and 0.5 for gamma. 99 * 100 * @param steps Steps along the canonical axes representing box edges. 101 * They may be negative but not zero. See 102 */ 103 public MultiDirectionalSimplex(final double[] steps) { 104 this(steps, DEFAULT_KHI, DEFAULT_GAMMA); 105 } 106 107 /** 108 * Build a multi-directional simplex with specified coefficients. 109 * 110 * @param steps Steps along the canonical axes representing box edges. 111 * They may be negative but not zero. See 112 * {@link AbstractSimplex#AbstractSimplex(double[])}. 113 * @param khi Expansion coefficient. 114 * @param gamma Contraction coefficient. 115 */ 116 public MultiDirectionalSimplex(final double[] steps, 117 final double khi, final double gamma) { 118 super(steps); 119 120 this.khi = khi; 121 this.gamma = gamma; 122 } 123 124 /** 125 * Build a multi-directional simplex with default coefficients. 126 * The default values are 2.0 for khi and 0.5 for gamma. 127 * 128 * @param referenceSimplex Reference simplex. See 129 * {@link AbstractSimplex#AbstractSimplex(double[][])}. 130 */ 131 public MultiDirectionalSimplex(final double[][] referenceSimplex) { 132 this(referenceSimplex, DEFAULT_KHI, DEFAULT_GAMMA); 133 } 134 135 /** 136 * Build a multi-directional simplex with specified coefficients. 137 * 138 * @param referenceSimplex Reference simplex. See 139 * {@link AbstractSimplex#AbstractSimplex(double[][])}. 140 * @param khi Expansion coefficient. 141 * @param gamma Contraction coefficient. 142 * @throws org.hipparchus.exception.MathIllegalArgumentException 143 * if the reference simplex does not contain at least one point. 144 * @throws org.hipparchus.exception.MathIllegalArgumentException 145 * if there is a dimension mismatch in the reference simplex. 146 */ 147 public MultiDirectionalSimplex(final double[][] referenceSimplex, 148 final double khi, final double gamma) { 149 super(referenceSimplex); 150 151 this.khi = khi; 152 this.gamma = gamma; 153 } 154 155 /** {@inheritDoc} */ 156 @Override 157 public void iterate(final MultivariateFunction evaluationFunction, 158 final Comparator<PointValuePair> comparator) { 159 // Save the original simplex. 160 final PointValuePair[] original = getPoints(); 161 final PointValuePair best = original[0]; 162 163 // Perform a reflection step. 164 final PointValuePair reflected = evaluateNewSimplex(evaluationFunction, 165 original, 1, comparator); 166 if (comparator.compare(reflected, best) < 0) { 167 // Compute the expanded simplex. 168 final PointValuePair[] reflectedSimplex = getPoints(); 169 final PointValuePair expanded = evaluateNewSimplex(evaluationFunction, 170 original, khi, comparator); 171 if (comparator.compare(reflected, expanded) <= 0) { 172 // Keep the reflected simplex. 173 setPoints(reflectedSimplex); 174 } 175 // Keep the expanded simplex. 176 return; 177 } 178 179 // Compute the contracted simplex. 180 evaluateNewSimplex(evaluationFunction, original, gamma, comparator); 181 182 } 183 184 /** 185 * Compute and evaluate a new simplex. 186 * 187 * @param evaluationFunction Evaluation function. 188 * @param original Original simplex (to be preserved). 189 * @param coeff Linear coefficient. 190 * @param comparator Comparator to use to sort simplex vertices from best 191 * to poorest. 192 * @return the best point in the transformed simplex. 193 * @throws org.hipparchus.exception.MathIllegalStateException 194 * if the maximal number of evaluations is exceeded. 195 */ 196 private PointValuePair evaluateNewSimplex(final MultivariateFunction evaluationFunction, 197 final PointValuePair[] original, 198 final double coeff, 199 final Comparator<PointValuePair> comparator) { 200 final double[] xSmallest = original[0].getPointRef(); 201 // Perform a linear transformation on all the simplex points, 202 // except the first one. 203 setPoint(0, original[0]); 204 final int dim = getDimension(); 205 for (int i = 1; i < getSize(); i++) { 206 final double[] xOriginal = original[i].getPointRef(); 207 final double[] xTransformed = new double[dim]; 208 for (int j = 0; j < dim; j++) { 209 xTransformed[j] = xSmallest[j] + coeff * (xSmallest[j] - xOriginal[j]); 210 } 211 setPoint(i, new PointValuePair(xTransformed, Double.NaN, false)); 212 } 213 214 // Evaluate the simplex. 215 evaluate(evaluationFunction, comparator); 216 217 return getPoint(0); 218 } 219 }