MultiDirectionalTransform.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.  *      http://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. package org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv;

  18. import java.util.List;
  19. import java.util.ArrayList;
  20. import java.util.Comparator;
  21. import java.util.function.UnaryOperator;
  22. import java.util.function.DoublePredicate;

  23. import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
  24. import org.apache.commons.math4.legacy.optim.PointValuePair;

  25. /**
  26.  * <a href="https://scholarship.rice.edu/handle/1911/16304">Multi-directional</a> search method.
  27.  */
  28. public class MultiDirectionalTransform
  29.     implements Simplex.TransformFactory {
  30.     /** Reflection coefficient. */
  31.     private static final double ALPHA = 1;
  32.     /** Default value for {@link #gamma}: {@value}. */
  33.     private static final double DEFAULT_GAMMA = 2;
  34.     /** Default value for {@link #sigma}: {@value}. */
  35.     private static final double DEFAULT_SIGMA = 0.5;
  36.     /** Expansion coefficient. */
  37.     private final double gamma;
  38.     /** Contraction coefficient. */
  39.     private final double sigma;

  40.     /**
  41.      * @param gamma Expansion coefficient.
  42.      * @param sigma Shrinkage coefficient.
  43.      */
  44.     public MultiDirectionalTransform(double gamma,
  45.                                      double sigma) {
  46.         if (gamma < 1) {
  47.             throw new IllegalArgumentException("gamma: " + gamma);
  48.         }
  49.         if (sigma < 0 ||
  50.             sigma > 1) {
  51.             throw new IllegalArgumentException("sigma: " + sigma);
  52.         }

  53.         this.gamma = gamma;
  54.         this.sigma = sigma;
  55.     }

  56.     /**
  57.      * Transform with default values.
  58.      */
  59.     public MultiDirectionalTransform() {
  60.         this(DEFAULT_GAMMA,
  61.              DEFAULT_SIGMA);
  62.     }

  63.     /** {@inheritDoc} */
  64.     @Override
  65.     public UnaryOperator<Simplex> create(final MultivariateFunction evaluationFunction,
  66.                                          final Comparator<PointValuePair> comparator,
  67.                                          final DoublePredicate sa) {
  68.         return original -> {
  69.             final PointValuePair best = original.get(0);

  70.             // Perform a reflection step.
  71.             final Simplex reflectedSimplex = transform(original,
  72.                                                        ALPHA,
  73.                                                        comparator,
  74.                                                        evaluationFunction);
  75.             final PointValuePair reflectedBest = reflectedSimplex.get(0);

  76.             if (comparator.compare(reflectedBest, best) < 0) {
  77.                 // Compute the expanded simplex.
  78.                 final Simplex expandedSimplex = transform(original,
  79.                                                           gamma,
  80.                                                           comparator,
  81.                                                           evaluationFunction);
  82.                 final PointValuePair expandedBest = expandedSimplex.get(0);

  83.                 if (comparator.compare(expandedBest, reflectedBest) <= 0 ||
  84.                     (sa != null &&
  85.                      sa.test(expandedBest.getValue() - reflectedBest.getValue()))) {
  86.                     return expandedSimplex;
  87.                 } else {
  88.                     return reflectedSimplex;
  89.                 }
  90.             } else {
  91.                 // Compute the contracted simplex.
  92.                 return original.shrink(sigma, evaluationFunction);
  93.             }
  94.         };
  95.     }

  96.     /**
  97.      * Computes and evaluates a new simplex.
  98.      *
  99.      * @param original Original simplex.
  100.      * @param coeff Linear coefficient.
  101.      * @param comp Fitness comparator.
  102.      * @param evalFunc Objective function.
  103.      * @return the transformed simplex.
  104.      * @throws org.apache.commons.math4.legacy.exception.TooManyEvaluationsException
  105.      * if the maximal number of evaluations is exceeded.
  106.      */
  107.     private Simplex transform(Simplex original,
  108.                               double coeff,
  109.                               Comparator<PointValuePair> comp,
  110.                               MultivariateFunction evalFunc) {
  111.         // Transformed simplex is the result a linear transformation on all
  112.         // points except the first one.
  113.         final int replSize = original.getSize() - 1;
  114.         final List<PointValuePair> replacement = new ArrayList<>();
  115.         final double[] bestPoint = original.get(0).getPoint();
  116.         for (int i = 0; i < replSize; i++) {
  117.             replacement.add(Simplex.newPoint(bestPoint,
  118.                                              -coeff,
  119.                                              original.get(i + 1).getPoint(),
  120.                                              evalFunc));
  121.         }

  122.         return original.replaceLast(replacement).evaluate(evalFunc, comp);
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     public String toString() {
  127.         return "Multidirectional [g=" + gamma +
  128.             " s=" + sigma + "]";
  129.     }
  130. }