MultiDirectionalSimplex.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.optim.nonlinear.scalar.noderiv;

  22. import java.util.Comparator;

  23. import org.hipparchus.analysis.MultivariateFunction;
  24. import org.hipparchus.optim.PointValuePair;

  25. /**
  26.  * This class implements the multi-directional direct search method.
  27.  *
  28.  */
  29. public class MultiDirectionalSimplex extends AbstractSimplex {
  30.     /** Default value for {@link #khi}: {@value}. */
  31.     private static final double DEFAULT_KHI = 2;
  32.     /** Default value for {@link #gamma}: {@value}. */
  33.     private static final double DEFAULT_GAMMA = 0.5;
  34.     /** Expansion coefficient. */
  35.     private final double khi;
  36.     /** Contraction coefficient. */
  37.     private final double gamma;

  38.     /**
  39.      * Build a multi-directional simplex with default coefficients.
  40.      * The default values are 2.0 for khi and 0.5 for gamma.
  41.      *
  42.      * @param n Dimension of the simplex.
  43.      */
  44.     public MultiDirectionalSimplex(final int n) {
  45.         this(n, 1d);
  46.     }

  47.     /**
  48.      * Build a multi-directional simplex with default coefficients.
  49.      * The default values are 2.0 for khi and 0.5 for gamma.
  50.      *
  51.      * @param n Dimension of the simplex.
  52.      * @param sideLength Length of the sides of the default (hypercube)
  53.      * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}.
  54.      */
  55.     public MultiDirectionalSimplex(final int n, double sideLength) {
  56.         this(n, sideLength, DEFAULT_KHI, DEFAULT_GAMMA);
  57.     }

  58.     /**
  59.      * Build a multi-directional simplex with specified coefficients.
  60.      *
  61.      * @param n Dimension of the simplex. See
  62.      * {@link AbstractSimplex#AbstractSimplex(int,double)}.
  63.      * @param khi Expansion coefficient.
  64.      * @param gamma Contraction coefficient.
  65.      */
  66.     public MultiDirectionalSimplex(final int n,
  67.                                    final double khi, final double gamma) {
  68.         this(n, 1d, khi, gamma);
  69.     }

  70.     /**
  71.      * Build a multi-directional simplex with specified coefficients.
  72.      *
  73.      * @param n Dimension of the simplex. See
  74.      * {@link AbstractSimplex#AbstractSimplex(int,double)}.
  75.      * @param sideLength Length of the sides of the default (hypercube)
  76.      * simplex. See {@link AbstractSimplex#AbstractSimplex(int,double)}.
  77.      * @param khi Expansion coefficient.
  78.      * @param gamma Contraction coefficient.
  79.      */
  80.     public MultiDirectionalSimplex(final int n, double sideLength,
  81.                                    final double khi, final double gamma) {
  82.         super(n, sideLength);

  83.         this.khi   = khi;
  84.         this.gamma = gamma;
  85.     }

  86.     /**
  87.      * Build a multi-directional simplex with default coefficients.
  88.      * The default values are 2.0 for khi and 0.5 for gamma.
  89.      *
  90.      * @param steps Steps along the canonical axes representing box edges.
  91.      * They may be negative but not zero. See
  92.      */
  93.     public MultiDirectionalSimplex(final double[] steps) {
  94.         this(steps, DEFAULT_KHI, DEFAULT_GAMMA);
  95.     }

  96.     /**
  97.      * Build a multi-directional simplex with specified coefficients.
  98.      *
  99.      * @param steps Steps along the canonical axes representing box edges.
  100.      * They may be negative but not zero. See
  101.      * {@link AbstractSimplex#AbstractSimplex(double[])}.
  102.      * @param khi Expansion coefficient.
  103.      * @param gamma Contraction coefficient.
  104.      */
  105.     public MultiDirectionalSimplex(final double[] steps,
  106.                                    final double khi, final double gamma) {
  107.         super(steps);

  108.         this.khi   = khi;
  109.         this.gamma = gamma;
  110.     }

  111.     /**
  112.      * Build a multi-directional simplex with default coefficients.
  113.      * The default values are 2.0 for khi and 0.5 for gamma.
  114.      *
  115.      * @param referenceSimplex Reference simplex. See
  116.      * {@link AbstractSimplex#AbstractSimplex(double[][])}.
  117.      */
  118.     public MultiDirectionalSimplex(final double[][] referenceSimplex) {
  119.         this(referenceSimplex, DEFAULT_KHI, DEFAULT_GAMMA);
  120.     }

  121.     /**
  122.      * Build a multi-directional simplex with specified coefficients.
  123.      *
  124.      * @param referenceSimplex Reference simplex. See
  125.      * {@link AbstractSimplex#AbstractSimplex(double[][])}.
  126.      * @param khi Expansion coefficient.
  127.      * @param gamma Contraction coefficient.
  128.      * @throws org.hipparchus.exception.MathIllegalArgumentException
  129.      * if the reference simplex does not contain at least one point.
  130.      * @throws org.hipparchus.exception.MathIllegalArgumentException
  131.      * if there is a dimension mismatch in the reference simplex.
  132.      */
  133.     public MultiDirectionalSimplex(final double[][] referenceSimplex,
  134.                                    final double khi, final double gamma) {
  135.         super(referenceSimplex);

  136.         this.khi   = khi;
  137.         this.gamma = gamma;
  138.     }

  139.     /** {@inheritDoc} */
  140.     @Override
  141.     public void iterate(final MultivariateFunction evaluationFunction,
  142.                         final Comparator<PointValuePair> comparator) {
  143.         // Save the original simplex.
  144.         final PointValuePair[] original = getPoints();
  145.         final PointValuePair best = original[0];

  146.         // Perform a reflection step.
  147.         final PointValuePair reflected = evaluateNewSimplex(evaluationFunction,
  148.                                                                 original, 1, comparator);
  149.         if (comparator.compare(reflected, best) < 0) {
  150.             // Compute the expanded simplex.
  151.             final PointValuePair[] reflectedSimplex = getPoints();
  152.             final PointValuePair expanded = evaluateNewSimplex(evaluationFunction,
  153.                                                                    original, khi, comparator);
  154.             if (comparator.compare(reflected, expanded) <= 0) {
  155.                 // Keep the reflected simplex.
  156.                 setPoints(reflectedSimplex);
  157.             }
  158.             // Keep the expanded simplex.
  159.             return;
  160.         }

  161.         // Compute the contracted simplex.
  162.         evaluateNewSimplex(evaluationFunction, original, gamma, comparator);

  163.     }

  164.     /**
  165.      * Compute and evaluate a new simplex.
  166.      *
  167.      * @param evaluationFunction Evaluation function.
  168.      * @param original Original simplex (to be preserved).
  169.      * @param coeff Linear coefficient.
  170.      * @param comparator Comparator to use to sort simplex vertices from best
  171.      * to poorest.
  172.      * @return the best point in the transformed simplex.
  173.      * @throws org.hipparchus.exception.MathIllegalStateException
  174.      * if the maximal number of evaluations is exceeded.
  175.      */
  176.     private PointValuePair evaluateNewSimplex(final MultivariateFunction evaluationFunction,
  177.                                                   final PointValuePair[] original,
  178.                                                   final double coeff,
  179.                                                   final Comparator<PointValuePair> comparator) {
  180.         final double[] xSmallest = original[0].getPointRef();
  181.         // Perform a linear transformation on all the simplex points,
  182.         // except the first one.
  183.         setPoint(0, original[0]);
  184.         final int dim = getDimension();
  185.         for (int i = 1; i < getSize(); i++) {
  186.             final double[] xOriginal = original[i].getPointRef();
  187.             final double[] xTransformed = new double[dim];
  188.             for (int j = 0; j < dim; j++) {
  189.                 xTransformed[j] = xSmallest[j] + coeff * (xSmallest[j] - xOriginal[j]);
  190.             }
  191.             setPoint(i, new PointValuePair(xTransformed, Double.NaN, false));
  192.         }

  193.         // Evaluate the simplex.
  194.         evaluate(evaluationFunction, comparator);

  195.         return getPoint(0);
  196.     }
  197. }