LineSearch.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;

  22. import org.hipparchus.analysis.UnivariateFunction;
  23. import org.hipparchus.optim.MaxEval;
  24. import org.hipparchus.optim.univariate.BracketFinder;
  25. import org.hipparchus.optim.univariate.BrentOptimizer;
  26. import org.hipparchus.optim.univariate.SearchInterval;
  27. import org.hipparchus.optim.univariate.SimpleUnivariateValueChecker;
  28. import org.hipparchus.optim.univariate.UnivariateObjectiveFunction;
  29. import org.hipparchus.optim.univariate.UnivariateOptimizer;
  30. import org.hipparchus.optim.univariate.UnivariatePointValuePair;

  31. /**
  32.  * Class for finding the minimum of the objective function along a given
  33.  * direction.
  34.  *
  35.  */
  36. public class LineSearch {
  37.     /**
  38.      * Value that will pass the precondition check for {@link BrentOptimizer}
  39.      * but will not pass the convergence check, so that the custom checker
  40.      * will always decide when to stop the line search.
  41.      */
  42.     private static final double REL_TOL_UNUSED = 1e-15;
  43.     /**
  44.      * Value that will pass the precondition check for {@link BrentOptimizer}
  45.      * but will not pass the convergence check, so that the custom checker
  46.      * will always decide when to stop the line search.
  47.      */
  48.     private static final double ABS_TOL_UNUSED = Double.MIN_VALUE;
  49.     /**
  50.      * Optimizer used for line search.
  51.      */
  52.     private final UnivariateOptimizer lineOptimizer;
  53.     /**
  54.      * Automatic bracketing.
  55.      */
  56.     private final BracketFinder bracket = new BracketFinder();
  57.     /**
  58.      * Extent of the initial interval used to find an interval that
  59.      * brackets the optimum.
  60.      */
  61.     private final double initialBracketingRange;
  62.     /**
  63.      * Optimizer on behalf of which the line search must be performed.
  64.      */
  65.     private final MultivariateOptimizer mainOptimizer;

  66.     /**
  67.      * The {@code BrentOptimizer} default stopping criterion uses the
  68.      * tolerances to check the domain (point) values, not the function
  69.      * values.
  70.      * The {@code relativeTolerance} and {@code absoluteTolerance}
  71.      * arguments are thus passed to a {@link SimpleUnivariateValueChecker
  72.      * custom checker} that will use the function values.
  73.      *
  74.      * @param optimizer Optimizer on behalf of which the line search
  75.      * be performed.
  76.      * Its {@link MultivariateOptimizer#computeObjectiveValue(double[])
  77.      * computeObjectiveValue} method will be called by the
  78.      * {@link #search(double[],double[]) search} method.
  79.      * @param relativeTolerance Search will stop when the function relative
  80.      * difference between successive iterations is below this value.
  81.      * @param absoluteTolerance Search will stop when the function absolute
  82.      * difference between successive iterations is below this value.
  83.      * @param initialBracketingRange Extent of the initial interval used to
  84.      * find an interval that brackets the optimum.
  85.      * If the optimized function varies a lot in the vicinity of the optimum,
  86.      * it may be necessary to provide a value lower than the distance between
  87.      * successive local minima.
  88.      */
  89.     public LineSearch(MultivariateOptimizer optimizer,
  90.                       double relativeTolerance,
  91.                       double absoluteTolerance,
  92.                       double initialBracketingRange) {
  93.         mainOptimizer = optimizer;
  94.         lineOptimizer = new BrentOptimizer(REL_TOL_UNUSED,
  95.                                            ABS_TOL_UNUSED,
  96.                                            new SimpleUnivariateValueChecker(relativeTolerance,
  97.                                                                             absoluteTolerance));
  98.         this.initialBracketingRange = initialBracketingRange;
  99.     }

  100.     /**
  101.      * Finds the number {@code alpha} that optimizes
  102.      * {@code f(startPoint + alpha * direction)}.
  103.      *
  104.      * @param startPoint Starting point.
  105.      * @param direction Search direction.
  106.      * @return the optimum.
  107.      * @throws org.hipparchus.exception.MathIllegalStateException
  108.      * if the number of evaluations is exceeded.
  109.      */
  110.     public UnivariatePointValuePair search(final double[] startPoint,
  111.                                            final double[] direction) {
  112.         final int n = startPoint.length;
  113.         final UnivariateFunction f = new UnivariateFunction() {
  114.             /** {@inheritDoc} */
  115.             @Override
  116.             public double value(double alpha) {
  117.                 final double[] x = new double[n];
  118.                 for (int i = 0; i < n; i++) {
  119.                     x[i] = startPoint[i] + alpha * direction[i];
  120.                 }
  121.                 return mainOptimizer.computeObjectiveValue(x);
  122.             }
  123.         };

  124.         final GoalType goal = mainOptimizer.getGoalType();
  125.         bracket.search(f, goal, 0, initialBracketingRange);
  126.         // Passing "MAX_VALUE" as a dummy value because it is the enclosing
  127.         // class that counts the number of evaluations (and will eventually
  128.         // generate the exception).
  129.         return lineOptimizer.optimize(new MaxEval(Integer.MAX_VALUE),
  130.                                       new UnivariateObjectiveFunction(f),
  131.                                       goal,
  132.                                       new SearchInterval(bracket.getLo(),
  133.                                                          bracket.getHi(),
  134.                                                          bracket.getMid()));
  135.     }
  136. }