blob: a162979f5fcf7910eda1629b7608ee044da0370d [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2015 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
33#ifndef CERES_INTERNAL_LINE_SEARCH_H_
34#define CERES_INTERNAL_LINE_SEARCH_H_
35
36#include <string>
37#include <vector>
38#include "ceres/function_sample.h"
39#include "ceres/internal/eigen.h"
40#include "ceres/internal/port.h"
41#include "ceres/types.h"
42
43namespace ceres {
44namespace internal {
45
46class Evaluator;
47class LineSearchFunction;
48
49// Line search is another name for a one dimensional optimization
50// algorithm. The name "line search" comes from the fact one
51// dimensional optimization problems that arise as subproblems of
52// general multidimensional optimization problems.
53//
54// While finding the exact minimum of a one dimensional function is
55// hard, instances of LineSearch find a point that satisfies a
56// sufficient decrease condition. Depending on the particular
57// condition used, we get a variety of different line search
58// algorithms, e.g., Armijo, Wolfe etc.
59class LineSearch {
60 public:
61 struct Summary;
62
63 struct Options {
64 // Degree of the polynomial used to approximate the objective
65 // function.
66 LineSearchInterpolationType interpolation_type = CUBIC;
67
68 // Armijo and Wolfe line search parameters.
69
70 // Solving the line search problem exactly is computationally
71 // prohibitive. Fortunately, line search based optimization
72 // algorithms can still guarantee convergence if instead of an
73 // exact solution, the line search algorithm returns a solution
74 // which decreases the value of the objective function
75 // sufficiently. More precisely, we are looking for a step_size
76 // s.t.
77 //
78 // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
79 double sufficient_decrease = 1e-4;
80
81 // In each iteration of the Armijo / Wolfe line search,
82 //
83 // new_step_size >= max_step_contraction * step_size
84 //
85 // Note that by definition, for contraction:
86 //
87 // 0 < max_step_contraction < min_step_contraction < 1
88 //
89 double max_step_contraction = 1e-3;
90
91 // In each iteration of the Armijo / Wolfe line search,
92 //
93 // new_step_size <= min_step_contraction * step_size
94 // Note that by definition, for contraction:
95 //
96 // 0 < max_step_contraction < min_step_contraction < 1
97 //
98 double min_step_contraction = 0.9;
99
100 // If during the line search, the step_size falls below this
101 // value, it is truncated to zero.
102 double min_step_size = 1e-9;
103
104 // Maximum number of trial step size iterations during each line search,
105 // if a step size satisfying the search conditions cannot be found within
106 // this number of trials, the line search will terminate.
107 int max_num_iterations = 20;
108
109 // Wolfe-specific line search parameters.
110
111 // The strong Wolfe conditions consist of the Armijo sufficient
112 // decrease condition, and an additional requirement that the
113 // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
114 // conditions) of the gradient along the search direction
115 // decreases sufficiently. Precisely, this second condition
116 // is that we seek a step_size s.t.
117 //
118 // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
119 //
120 // Where f() is the line search objective and f'() is the derivative
121 // of f w.r.t step_size (d f / d step_size).
122 double sufficient_curvature_decrease = 0.9;
123
124 // During the bracketing phase of the Wolfe search, the step size is
125 // increased until either a point satisfying the Wolfe conditions is
126 // found, or an upper bound for a bracket containing a point satisfying
127 // the conditions is found. Precisely, at each iteration of the
128 // expansion:
129 //
130 // new_step_size <= max_step_expansion * step_size.
131 //
132 // By definition for expansion, max_step_expansion > 1.0.
133 double max_step_expansion = 10;
134
135 bool is_silent = false;
136
137 // The one dimensional function that the line search algorithm
138 // minimizes.
139 LineSearchFunction* function = nullptr;
140 };
141
142 // Result of the line search.
143 struct Summary {
144 bool success = false;
145 FunctionSample optimal_point;
146 int num_function_evaluations = 0;
147 int num_gradient_evaluations = 0;
148 int num_iterations = 0;
149 // Cumulative time spent evaluating the value of the cost function across
150 // all iterations.
151 double cost_evaluation_time_in_seconds = 0.0;
152 // Cumulative time spent evaluating the gradient of the cost function across
153 // all iterations.
154 double gradient_evaluation_time_in_seconds = 0.0;
155 // Cumulative time spent minimizing the interpolating polynomial to compute
156 // the next candidate step size across all iterations.
157 double polynomial_minimization_time_in_seconds = 0.0;
158 double total_time_in_seconds = 0.0;
159 std::string error;
160 };
161
162 explicit LineSearch(const LineSearch::Options& options);
163 virtual ~LineSearch() {}
164
165 static LineSearch* Create(const LineSearchType line_search_type,
166 const LineSearch::Options& options,
167 std::string* error);
168
169 // Perform the line search.
170 //
171 // step_size_estimate must be a positive number.
172 //
173 // initial_cost and initial_gradient are the values and gradient of
174 // the function at zero.
175 // summary must not be null and will contain the result of the line
176 // search.
177 //
178 // Summary::success is true if a non-zero step size is found.
179 void Search(double step_size_estimate,
180 double initial_cost,
181 double initial_gradient,
182 Summary* summary) const;
183 double InterpolatingPolynomialMinimizingStepSize(
184 const LineSearchInterpolationType& interpolation_type,
185 const FunctionSample& lowerbound_sample,
186 const FunctionSample& previous_sample,
187 const FunctionSample& current_sample,
188 const double min_step_size,
189 const double max_step_size) const;
190
191 protected:
192 const LineSearch::Options& options() const { return options_; }
193
194 private:
195 virtual void DoSearch(double step_size_estimate,
196 double initial_cost,
197 double initial_gradient,
198 Summary* summary) const = 0;
199
200 private:
201 LineSearch::Options options_;
202};
203
204// An object used by the line search to access the function values
205// and gradient of the one dimensional function being optimized.
206//
207// In practice, this object provides access to the objective
208// function value and the directional derivative of the underlying
209// optimization problem along a specific search direction.
210class LineSearchFunction {
211 public:
212 explicit LineSearchFunction(Evaluator* evaluator);
213 void Init(const Vector& position, const Vector& direction);
214
215 // Evaluate the line search objective
216 //
217 // f(x) = p(position + x * direction)
218 //
219 // Where, p is the objective function of the general optimization
220 // problem.
221 //
222 // evaluate_gradient controls whether the gradient will be evaluated
223 // or not.
224 //
225 // On return output->*_is_valid indicate indicate whether the
226 // corresponding fields have numerically valid values or not.
227 void Evaluate(double x, bool evaluate_gradient, FunctionSample* output);
228
229 double DirectionInfinityNorm() const;
230
231 // Resets to now, the start point for the results from TimeStatistics().
232 void ResetTimeStatistics();
233 void TimeStatistics(double* cost_evaluation_time_in_seconds,
234 double* gradient_evaluation_time_in_seconds) const;
235 const Vector& position() const { return position_; }
236 const Vector& direction() const { return direction_; }
237
238 private:
239 Evaluator* evaluator_;
240 Vector position_;
241 Vector direction_;
242
243 // scaled_direction = x * direction_;
244 Vector scaled_direction_;
245
246 // We may not exclusively own the evaluator (e.g. in the Trust Region
247 // minimizer), hence we need to save the initial evaluation durations for the
248 // value & gradient to accurately determine the duration of the evaluations
249 // we invoked. These are reset by a call to ResetTimeStatistics().
250 double initial_evaluator_residual_time_in_seconds;
251 double initial_evaluator_jacobian_time_in_seconds;
252};
253
254// Backtracking and interpolation based Armijo line search. This
255// implementation is based on the Armijo line search that ships in the
256// minFunc package by Mark Schmidt.
257//
258// For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
259class ArmijoLineSearch : public LineSearch {
260 public:
261 explicit ArmijoLineSearch(const LineSearch::Options& options);
262 virtual ~ArmijoLineSearch() {}
263
264 private:
265 virtual void DoSearch(double step_size_estimate,
266 double initial_cost,
267 double initial_gradient,
268 Summary* summary) const;
269};
270
271// Bracketing / Zoom Strong Wolfe condition line search. This implementation
272// is based on the pseudo-code algorithm presented in Nocedal & Wright [1]
273// (p60-61) with inspiration from the WolfeLineSearch which ships with the
274// minFunc package by Mark Schmidt [2].
275//
276// [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed., Springer, 1999.
277// [2] http://www.di.ens.fr/~mschmidt/Software/minFunc.html.
278class WolfeLineSearch : public LineSearch {
279 public:
280 explicit WolfeLineSearch(const LineSearch::Options& options);
281 virtual ~WolfeLineSearch() {}
282
283 // Returns true iff either a valid point, or valid bracket are found.
284 bool BracketingPhase(const FunctionSample& initial_position,
285 const double step_size_estimate,
286 FunctionSample* bracket_low,
287 FunctionSample* bracket_high,
288 bool* perform_zoom_search,
289 Summary* summary) const;
290 // Returns true iff final_line_sample satisfies strong Wolfe conditions.
291 bool ZoomPhase(const FunctionSample& initial_position,
292 FunctionSample bracket_low,
293 FunctionSample bracket_high,
294 FunctionSample* solution,
295 Summary* summary) const;
296
297 private:
298 virtual void DoSearch(double step_size_estimate,
299 double initial_cost,
300 double initial_gradient,
301 Summary* summary) const;
302};
303
304} // namespace internal
305} // namespace ceres
306
307#endif // CERES_INTERNAL_LINE_SEARCH_H_