SimplexOptimizer.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.math3.optimization.direct;

  18. import java.util.Comparator;

  19. import org.apache.commons.math3.analysis.MultivariateFunction;
  20. import org.apache.commons.math3.exception.NullArgumentException;
  21. import org.apache.commons.math3.optimization.GoalType;
  22. import org.apache.commons.math3.optimization.ConvergenceChecker;
  23. import org.apache.commons.math3.optimization.PointValuePair;
  24. import org.apache.commons.math3.optimization.SimpleValueChecker;
  25. import org.apache.commons.math3.optimization.MultivariateOptimizer;
  26. import org.apache.commons.math3.optimization.OptimizationData;

  27. /**
  28.  * This class implements simplex-based direct search optimization.
  29.  *
  30.  * <p>
  31.  *  Direct search methods only use objective function values, they do
  32.  *  not need derivatives and don't either try to compute approximation
  33.  *  of the derivatives. According to a 1996 paper by Margaret H. Wright
  34.  *  (<a href="http://cm.bell-labs.com/cm/cs/doc/96/4-02.ps.gz">Direct
  35.  *  Search Methods: Once Scorned, Now Respectable</a>), they are used
  36.  *  when either the computation of the derivative is impossible (noisy
  37.  *  functions, unpredictable discontinuities) or difficult (complexity,
  38.  *  computation cost). In the first cases, rather than an optimum, a
  39.  *  <em>not too bad</em> point is desired. In the latter cases, an
  40.  *  optimum is desired but cannot be reasonably found. In all cases
  41.  *  direct search methods can be useful.
  42.  * </p>
  43.  * <p>
  44.  *  Simplex-based direct search methods are based on comparison of
  45.  *  the objective function values at the vertices of a simplex (which is a
  46.  *  set of n+1 points in dimension n) that is updated by the algorithms
  47.  *  steps.
  48.  * <p>
  49.  * <p>
  50.  *  The {@link #setSimplex(AbstractSimplex) setSimplex} method <em>must</em>
  51.  *  be called prior to calling the {@code optimize} method.
  52.  * </p>
  53.  * <p>
  54.  *  Each call to {@link #optimize(int,MultivariateFunction,GoalType,double[])
  55.  *  optimize} will re-use the start configuration of the current simplex and
  56.  *  move it such that its first vertex is at the provided start point of the
  57.  *  optimization. If the {@code optimize} method is called to solve a different
  58.  *  problem and the number of parameters change, the simplex must be
  59.  *  re-initialized to one with the appropriate dimensions.
  60.  * </p>
  61.  * <p>
  62.  *  Convergence is checked by providing the <em>worst</em> points of
  63.  *  previous and current simplex to the convergence checker, not the best
  64.  *  ones.
  65.  * </p>
  66.  * <p>
  67.  * This simplex optimizer implementation does not directly support constrained
  68.  * optimization with simple bounds, so for such optimizations, either a more
  69.  * dedicated method must be used like {@link CMAESOptimizer} or {@link
  70.  * BOBYQAOptimizer}, or the optimized method must be wrapped in an adapter like
  71.  * {@link MultivariateFunctionMappingAdapter} or {@link
  72.  * MultivariateFunctionPenaltyAdapter}.
  73.  * </p>
  74.  *
  75.  * @see AbstractSimplex
  76.  * @see MultivariateFunctionMappingAdapter
  77.  * @see MultivariateFunctionPenaltyAdapter
  78.  * @see CMAESOptimizer
  79.  * @see BOBYQAOptimizer
  80.  * @deprecated As of 3.1 (to be removed in 4.0).
  81.  * @since 3.0
  82.  */
  83. @SuppressWarnings("boxing") // deprecated anyway
  84. @Deprecated
  85. public class SimplexOptimizer
  86.     extends BaseAbstractMultivariateOptimizer<MultivariateFunction>
  87.     implements MultivariateOptimizer {
  88.     /** Simplex. */
  89.     private AbstractSimplex simplex;

  90.     /**
  91.      * Constructor using a default {@link SimpleValueChecker convergence
  92.      * checker}.
  93.      * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
  94.      */
  95.     @Deprecated
  96.     public SimplexOptimizer() {
  97.         this(new SimpleValueChecker());
  98.     }

  99.     /**
  100.      * @param checker Convergence checker.
  101.      */
  102.     public SimplexOptimizer(ConvergenceChecker<PointValuePair> checker) {
  103.         super(checker);
  104.     }

  105.     /**
  106.      * @param rel Relative threshold.
  107.      * @param abs Absolute threshold.
  108.      */
  109.     public SimplexOptimizer(double rel, double abs) {
  110.         this(new SimpleValueChecker(rel, abs));
  111.     }

  112.     /**
  113.      * Set the simplex algorithm.
  114.      *
  115.      * @param simplex Simplex.
  116.      * @deprecated As of 3.1. The initial simplex can now be passed as an
  117.      * argument of the {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])}
  118.      * method.
  119.      */
  120.     @Deprecated
  121.     public void setSimplex(AbstractSimplex simplex) {
  122.         parseOptimizationData(simplex);
  123.     }

  124.     /**
  125.      * Optimize an objective function.
  126.      *
  127.      * @param maxEval Allowed number of evaluations of the objective function.
  128.      * @param f Objective function.
  129.      * @param goalType Optimization type.
  130.      * @param optData Optimization data. The following data will be looked for:
  131.      * <ul>
  132.      *  <li>{@link org.apache.commons.math3.optimization.InitialGuess InitialGuess}</li>
  133.      *  <li>{@link AbstractSimplex}</li>
  134.      * </ul>
  135.      * @return the point/value pair giving the optimal value for objective
  136.      * function.
  137.      */
  138.     @Override
  139.     protected PointValuePair optimizeInternal(int maxEval, MultivariateFunction f,
  140.                                               GoalType goalType,
  141.                                               OptimizationData... optData) {
  142.         // Scan "optData" for the input specific to this optimizer.
  143.         parseOptimizationData(optData);

  144.         // The parent's method will retrieve the common parameters from
  145.         // "optData" and call "doOptimize".
  146.         return super.optimizeInternal(maxEval, f, goalType, optData);
  147.     }

  148.     /**
  149.      * Scans the list of (required and optional) optimization data that
  150.      * characterize the problem.
  151.      *
  152.      * @param optData Optimization data. The following data will be looked for:
  153.      * <ul>
  154.      *  <li>{@link AbstractSimplex}</li>
  155.      * </ul>
  156.      */
  157.     private void parseOptimizationData(OptimizationData... optData) {
  158.         // The existing values (as set by the previous call) are reused if
  159.         // not provided in the argument list.
  160.         for (OptimizationData data : optData) {
  161.             if (data instanceof AbstractSimplex) {
  162.                 simplex = (AbstractSimplex) data;
  163.                 continue;
  164.             }
  165.         }
  166.     }

  167.     /** {@inheritDoc} */
  168.     @Override
  169.     protected PointValuePair doOptimize() {
  170.         if (simplex == null) {
  171.             throw new NullArgumentException();
  172.         }

  173.         // Indirect call to "computeObjectiveValue" in order to update the
  174.         // evaluations counter.
  175.         final MultivariateFunction evalFunc
  176.             = new MultivariateFunction() {
  177.                 public double value(double[] point) {
  178.                     return computeObjectiveValue(point);
  179.                 }
  180.             };

  181.         final boolean isMinim = getGoalType() == GoalType.MINIMIZE;
  182.         final Comparator<PointValuePair> comparator
  183.             = new Comparator<PointValuePair>() {
  184.             public int compare(final PointValuePair o1,
  185.                                final PointValuePair o2) {
  186.                 final double v1 = o1.getValue();
  187.                 final double v2 = o2.getValue();
  188.                 return isMinim ? Double.compare(v1, v2) : Double.compare(v2, v1);
  189.             }
  190.         };

  191.         // Initialize search.
  192.         simplex.build(getStartPoint());
  193.         simplex.evaluate(evalFunc, comparator);

  194.         PointValuePair[] previous = null;
  195.         int iteration = 0;
  196.         final ConvergenceChecker<PointValuePair> checker = getConvergenceChecker();
  197.         while (true) {
  198.             if (iteration > 0) {
  199.                 boolean converged = true;
  200.                 for (int i = 0; i < simplex.getSize(); i++) {
  201.                     PointValuePair prev = previous[i];
  202.                     converged = converged &&
  203.                         checker.converged(iteration, prev, simplex.getPoint(i));
  204.                 }
  205.                 if (converged) {
  206.                     // We have found an optimum.
  207.                     return simplex.getPoint(0);
  208.                 }
  209.             }

  210.             // We still need to search.
  211.             previous = simplex.getPoints();
  212.             simplex.iterate(evalFunc, comparator);
  213.             ++iteration;
  214.         }
  215.     }
  216. }