line_search.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2023 Google Inc. All rights reserved.
  3. // http://ceres-solver.org/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Google Inc. nor the names of its contributors may be
  14. // used to endorse or promote products derived from this software without
  15. // specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. // POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Author: sameeragarwal@google.com (Sameer Agarwal)
  30. //
  31. // Interface for and implementation of various Line search algorithms.
  32. #ifndef CERES_INTERNAL_LINE_SEARCH_H_
  33. #define CERES_INTERNAL_LINE_SEARCH_H_
  34. #include <memory>
  35. #include <string>
  36. #include <vector>
  37. #include "ceres/function_sample.h"
  38. #include "ceres/internal/eigen.h"
  39. #include "ceres/internal/export.h"
  40. #include "ceres/types.h"
  41. namespace ceres::internal {
  42. class Evaluator;
  43. class LineSearchFunction;
  44. // Line search is another name for a one dimensional optimization
  45. // algorithm. The name "line search" comes from the fact one
  46. // dimensional optimization problems that arise as subproblems of
  47. // general multidimensional optimization problems.
  48. //
  49. // While finding the exact minimum of a one dimensional function is
  50. // hard, instances of LineSearch find a point that satisfies a
  51. // sufficient decrease condition. Depending on the particular
  52. // condition used, we get a variety of different line search
  53. // algorithms, e.g., Armijo, Wolfe etc.
  54. class CERES_NO_EXPORT LineSearch {
  55. public:
  56. struct Summary;
  57. struct CERES_NO_EXPORT Options {
  58. // Degree of the polynomial used to approximate the objective
  59. // function.
  60. LineSearchInterpolationType interpolation_type = CUBIC;
  61. // Armijo and Wolfe line search parameters.
  62. // Solving the line search problem exactly is computationally
  63. // prohibitive. Fortunately, line search based optimization
  64. // algorithms can still guarantee convergence if instead of an
  65. // exact solution, the line search algorithm returns a solution
  66. // which decreases the value of the objective function
  67. // sufficiently. More precisely, we are looking for a step_size
  68. // s.t.
  69. //
  70. // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
  71. double sufficient_decrease = 1e-4;
  72. // In each iteration of the Armijo / Wolfe line search,
  73. //
  74. // new_step_size >= max_step_contraction * step_size
  75. //
  76. // Note that by definition, for contraction:
  77. //
  78. // 0 < max_step_contraction < min_step_contraction < 1
  79. //
  80. double max_step_contraction = 1e-3;
  81. // In each iteration of the Armijo / Wolfe line search,
  82. //
  83. // new_step_size <= min_step_contraction * step_size
  84. // Note that by definition, for contraction:
  85. //
  86. // 0 < max_step_contraction < min_step_contraction < 1
  87. //
  88. double min_step_contraction = 0.9;
  89. // If during the line search, the step_size falls below this
  90. // value, it is truncated to zero.
  91. double min_step_size = 1e-9;
  92. // Maximum number of trial step size iterations during each line search,
  93. // if a step size satisfying the search conditions cannot be found within
  94. // this number of trials, the line search will terminate.
  95. int max_num_iterations = 20;
  96. // Wolfe-specific line search parameters.
  97. // The strong Wolfe conditions consist of the Armijo sufficient
  98. // decrease condition, and an additional requirement that the
  99. // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
  100. // conditions) of the gradient along the search direction
  101. // decreases sufficiently. Precisely, this second condition
  102. // is that we seek a step_size s.t.
  103. //
  104. // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
  105. //
  106. // Where f() is the line search objective and f'() is the derivative
  107. // of f w.r.t step_size (d f / d step_size).
  108. double sufficient_curvature_decrease = 0.9;
  109. // During the bracketing phase of the Wolfe search, the step size is
  110. // increased until either a point satisfying the Wolfe conditions is
  111. // found, or an upper bound for a bracket containing a point satisfying
  112. // the conditions is found. Precisely, at each iteration of the
  113. // expansion:
  114. //
  115. // new_step_size <= max_step_expansion * step_size.
  116. //
  117. // By definition for expansion, max_step_expansion > 1.0.
  118. double max_step_expansion = 10;
  119. bool is_silent = false;
  120. // The one dimensional function that the line search algorithm
  121. // minimizes.
  122. LineSearchFunction* function = nullptr;
  123. };
  124. // Result of the line search.
  125. struct Summary {
  126. bool success = false;
  127. FunctionSample optimal_point;
  128. int num_function_evaluations = 0;
  129. int num_gradient_evaluations = 0;
  130. int num_iterations = 0;
  131. // Cumulative time spent evaluating the value of the cost function across
  132. // all iterations.
  133. double cost_evaluation_time_in_seconds = 0.0;
  134. // Cumulative time spent evaluating the gradient of the cost function across
  135. // all iterations.
  136. double gradient_evaluation_time_in_seconds = 0.0;
  137. // Cumulative time spent minimizing the interpolating polynomial to compute
  138. // the next candidate step size across all iterations.
  139. double polynomial_minimization_time_in_seconds = 0.0;
  140. double total_time_in_seconds = 0.0;
  141. std::string error;
  142. };
  143. explicit LineSearch(const LineSearch::Options& options);
  144. virtual ~LineSearch();
  145. static std::unique_ptr<LineSearch> Create(
  146. const LineSearchType line_search_type,
  147. const LineSearch::Options& options,
  148. std::string* error);
  149. // Perform the line search.
  150. //
  151. // step_size_estimate must be a positive number.
  152. //
  153. // initial_cost and initial_gradient are the values and gradient of
  154. // the function at zero.
  155. // summary must not be null and will contain the result of the line
  156. // search.
  157. //
  158. // Summary::success is true if a non-zero step size is found.
  159. void Search(double step_size_estimate,
  160. double initial_cost,
  161. double initial_gradient,
  162. Summary* summary) const;
  163. double InterpolatingPolynomialMinimizingStepSize(
  164. const LineSearchInterpolationType& interpolation_type,
  165. const FunctionSample& lowerbound_sample,
  166. const FunctionSample& previous_sample,
  167. const FunctionSample& current_sample,
  168. const double min_step_size,
  169. const double max_step_size) const;
  170. protected:
  171. const LineSearch::Options& options() const { return options_; }
  172. private:
  173. virtual void DoSearch(double step_size_estimate,
  174. double initial_cost,
  175. double initial_gradient,
  176. Summary* summary) const = 0;
  177. private:
  178. LineSearch::Options options_;
  179. };
  180. // An object used by the line search to access the function values
  181. // and gradient of the one dimensional function being optimized.
  182. //
  183. // In practice, this object provides access to the objective
  184. // function value and the directional derivative of the underlying
  185. // optimization problem along a specific search direction.
  186. class CERES_NO_EXPORT LineSearchFunction {
  187. public:
  188. explicit LineSearchFunction(Evaluator* evaluator);
  189. void Init(const Vector& position, const Vector& direction);
  190. // Evaluate the line search objective
  191. //
  192. // f(x) = p(position + x * direction)
  193. //
  194. // Where, p is the objective function of the general optimization
  195. // problem.
  196. //
  197. // evaluate_gradient controls whether the gradient will be evaluated
  198. // or not.
  199. //
  200. // On return output->*_is_valid indicate indicate whether the
  201. // corresponding fields have numerically valid values or not.
  202. void Evaluate(double x, bool evaluate_gradient, FunctionSample* output);
  203. double DirectionInfinityNorm() const;
  204. // Resets to now, the start point for the results from TimeStatistics().
  205. void ResetTimeStatistics();
  206. void TimeStatistics(double* cost_evaluation_time_in_seconds,
  207. double* gradient_evaluation_time_in_seconds) const;
  208. const Vector& position() const { return position_; }
  209. const Vector& direction() const { return direction_; }
  210. private:
  211. Evaluator* evaluator_;
  212. Vector position_;
  213. Vector direction_;
  214. // scaled_direction = x * direction_;
  215. Vector scaled_direction_;
  216. // We may not exclusively own the evaluator (e.g. in the Trust Region
  217. // minimizer), hence we need to save the initial evaluation durations for the
  218. // value & gradient to accurately determine the duration of the evaluations
  219. // we invoked. These are reset by a call to ResetTimeStatistics().
  220. double initial_evaluator_residual_time_in_seconds;
  221. double initial_evaluator_jacobian_time_in_seconds;
  222. };
  223. // Backtracking and interpolation based Armijo line search. This
  224. // implementation is based on the Armijo line search that ships in the
  225. // minFunc package by Mark Schmidt.
  226. //
  227. // For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
  228. class CERES_NO_EXPORT ArmijoLineSearch final : public LineSearch {
  229. public:
  230. explicit ArmijoLineSearch(const LineSearch::Options& options);
  231. private:
  232. void DoSearch(double step_size_estimate,
  233. double initial_cost,
  234. double initial_gradient,
  235. Summary* summary) const final;
  236. };
  237. // Bracketing / Zoom Strong Wolfe condition line search. This implementation
  238. // is based on the pseudo-code algorithm presented in Nocedal & Wright [1]
  239. // (p60-61) with inspiration from the WolfeLineSearch which ships with the
  240. // minFunc package by Mark Schmidt [2].
  241. //
  242. // [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed., Springer, 1999.
  243. // [2] http://www.di.ens.fr/~mschmidt/Software/minFunc.html.
  244. class CERES_NO_EXPORT WolfeLineSearch final : public LineSearch {
  245. public:
  246. explicit WolfeLineSearch(const LineSearch::Options& options);
  247. // Returns true iff either a valid point, or valid bracket are found.
  248. bool BracketingPhase(const FunctionSample& initial_position,
  249. const double step_size_estimate,
  250. FunctionSample* bracket_low,
  251. FunctionSample* bracket_high,
  252. bool* perform_zoom_search,
  253. Summary* summary) const;
  254. // Returns true iff final_line_sample satisfies strong Wolfe conditions.
  255. bool ZoomPhase(const FunctionSample& initial_position,
  256. FunctionSample bracket_low,
  257. FunctionSample bracket_high,
  258. FunctionSample* solution,
  259. Summary* summary) const;
  260. private:
  261. void DoSearch(double step_size_estimate,
  262. double initial_cost,
  263. double initial_gradient,
  264. Summary* summary) const final;
  265. };
  266. } // namespace ceres::internal
  267. #endif // CERES_INTERNAL_LINE_SEARCH_H_