blob: c62cda7825a347aff092990b3bee743d0347d79f [file] [log] [blame]
Sameer Agarwal1d11be92012-11-25 19:28:06 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2012 Google Inc. All rights reserved.
3// http://code.google.com/p/ceres-solver/
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
Sameer Agarwal8140f0f2013-03-12 09:45:08 -070031#ifndef CERES_NO_LINE_SEARCH_MINIMIZER
Alex Stewart7124c342013-11-07 16:10:02 +000032#include <iomanip> // For std::setprecision.
33#include <iostream> // For std::scientific.
34
Sameer Agarwal1d11be92012-11-25 19:28:06 -080035#include "ceres/line_search.h"
36
Sameer Agarwal1d11be92012-11-25 19:28:06 -080037#include "ceres/fpclassify.h"
38#include "ceres/evaluator.h"
39#include "ceres/internal/eigen.h"
40#include "ceres/polynomial.h"
Alex Stewart9aa0e3c2013-07-05 20:22:37 +010041#include "ceres/stringprintf.h"
Sameer Agarwala1eaa262013-05-09 10:02:24 -070042#include "glog/logging.h"
Sameer Agarwal1d11be92012-11-25 19:28:06 -080043
44namespace ceres {
45namespace internal {
46namespace {
Alex Stewart7124c342013-11-07 16:10:02 +000047// Precision used for floating point values in error message output.
48const int kErrorMessageNumericPrecision = 8;
Sameer Agarwal1d11be92012-11-25 19:28:06 -080049
50FunctionSample ValueSample(const double x, const double value) {
51 FunctionSample sample;
52 sample.x = x;
53 sample.value = value;
54 sample.value_is_valid = true;
55 return sample;
56};
57
58FunctionSample ValueAndGradientSample(const double x,
59 const double value,
60 const double gradient) {
61 FunctionSample sample;
62 sample.x = x;
63 sample.value = value;
64 sample.gradient = gradient;
65 sample.value_is_valid = true;
66 sample.gradient_is_valid = true;
67 return sample;
68};
69
Sameer Agarwal719889b2013-07-17 11:31:08 -070070} // namespace
71
Alex Stewart9aa0e3c2013-07-05 20:22:37 +010072// Convenience stream operator for pushing FunctionSamples into log messages.
73std::ostream& operator<<(std::ostream &os,
74 const FunctionSample& sample) {
Alex Stewart7124c342013-11-07 16:10:02 +000075 os << sample.ToDebugString();
Alex Stewart9aa0e3c2013-07-05 20:22:37 +010076 return os;
Sameer Agarwalc5bcfc02013-07-19 15:50:27 -070077}
Alex Stewart9aa0e3c2013-07-05 20:22:37 +010078
Alex Stewart9aa0e3c2013-07-05 20:22:37 +010079LineSearch::LineSearch(const LineSearch::Options& options)
80 : options_(options) {}
81
82LineSearch* LineSearch::Create(const LineSearchType line_search_type,
83 const LineSearch::Options& options,
84 string* error) {
85 LineSearch* line_search = NULL;
86 switch (line_search_type) {
87 case ceres::ARMIJO:
88 line_search = new ArmijoLineSearch(options);
89 break;
90 case ceres::WOLFE:
91 line_search = new WolfeLineSearch(options);
92 break;
93 default:
94 *error = string("Invalid line search algorithm type: ") +
95 LineSearchTypeToString(line_search_type) +
96 string(", unable to create line search.");
97 return NULL;
98 }
99 return line_search;
100}
101
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800102LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
103 : evaluator_(evaluator),
104 position_(evaluator->NumParameters()),
105 direction_(evaluator->NumEffectiveParameters()),
106 evaluation_point_(evaluator->NumParameters()),
107 scaled_direction_(evaluator->NumEffectiveParameters()),
108 gradient_(evaluator->NumEffectiveParameters()) {
109}
110
111void LineSearchFunction::Init(const Vector& position,
Sameer Agarwal3e8d1922012-11-28 17:20:22 -0800112 const Vector& direction) {
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800113 position_ = position;
114 direction_ = direction;
115}
116
Petter Strandmark880cba02013-08-16 20:05:30 +0200117bool LineSearchFunction::Evaluate(double x, double* f, double* g) {
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800118 scaled_direction_ = x * direction_;
Sameer Agarwalf4d01642012-11-26 12:55:58 -0800119 if (!evaluator_->Plus(position_.data(),
120 scaled_direction_.data(),
121 evaluation_point_.data())) {
122 return false;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800123 }
Sameer Agarwalf4d01642012-11-26 12:55:58 -0800124
125 if (g == NULL) {
126 return (evaluator_->Evaluate(evaluation_point_.data(),
127 f, NULL, NULL, NULL) &&
128 IsFinite(*f));
129 }
130
131 if (!evaluator_->Evaluate(evaluation_point_.data(),
132 f,
133 NULL,
134 gradient_.data(), NULL)) {
135 return false;
136 }
137
138 *g = direction_.dot(gradient_);
139 return IsFinite(*f) && IsFinite(*g);
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800140}
141
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100142double LineSearchFunction::DirectionInfinityNorm() const {
143 return direction_.lpNorm<Eigen::Infinity>();
144}
145
146// Returns step_size \in [min_step_size, max_step_size] which minimizes the
147// polynomial of degree defined by interpolation_type which interpolates all
148// of the provided samples with valid values.
149double LineSearch::InterpolatingPolynomialMinimizingStepSize(
150 const LineSearchInterpolationType& interpolation_type,
151 const FunctionSample& lowerbound,
152 const FunctionSample& previous,
153 const FunctionSample& current,
154 const double min_step_size,
155 const double max_step_size) const {
156 if (!current.value_is_valid ||
157 (interpolation_type == BISECTION &&
158 max_step_size <= current.x)) {
159 // Either: sample is invalid; or we are using BISECTION and contracting
160 // the step size.
161 return min(max(current.x * 0.5, min_step_size), max_step_size);
162 } else if (interpolation_type == BISECTION) {
163 CHECK_GT(max_step_size, current.x);
164 // We are expanding the search (during a Wolfe bracketing phase) using
165 // BISECTION interpolation. Using BISECTION when trying to expand is
166 // strictly speaking an oxymoron, but we define this to mean always taking
167 // the maximum step size so that the Armijo & Wolfe implementations are
168 // agnostic to the interpolation type.
169 return max_step_size;
170 }
171 // Only check if lower-bound is valid here, where it is required
172 // to avoid replicating current.value_is_valid == false
173 // behaviour in WolfeLineSearch.
174 CHECK(lowerbound.value_is_valid)
Alex Stewart7124c342013-11-07 16:10:02 +0000175 << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100176 << "Ceres bug: lower-bound sample for interpolation is invalid, "
177 << "please contact the developers!, interpolation_type: "
178 << LineSearchInterpolationTypeToString(interpolation_type)
179 << ", lowerbound: " << lowerbound << ", previous: " << previous
180 << ", current: " << current;
181
182 // Select step size by interpolating the function and gradient values
183 // and minimizing the corresponding polynomial.
184 vector<FunctionSample> samples;
185 samples.push_back(lowerbound);
186
187 if (interpolation_type == QUADRATIC) {
188 // Two point interpolation using function values and the
189 // gradient at the lower bound.
190 samples.push_back(ValueSample(current.x, current.value));
191
192 if (previous.value_is_valid) {
193 // Three point interpolation, using function values and the
194 // gradient at the lower bound.
195 samples.push_back(ValueSample(previous.x, previous.value));
196 }
197 } else if (interpolation_type == CUBIC) {
198 // Two point interpolation using the function values and the gradients.
199 samples.push_back(current);
200
201 if (previous.value_is_valid) {
202 // Three point interpolation using the function values and
203 // the gradients.
204 samples.push_back(previous);
205 }
206 } else {
207 LOG(FATAL) << "Ceres bug: No handler for interpolation_type: "
208 << LineSearchInterpolationTypeToString(interpolation_type)
209 << ", please contact the developers!";
210 }
211
212 double step_size = 0.0, unused_min_value = 0.0;
213 MinimizeInterpolatingPolynomial(samples, min_step_size, max_step_size,
214 &step_size, &unused_min_value);
215 return step_size;
216}
217
218ArmijoLineSearch::ArmijoLineSearch(const LineSearch::Options& options)
219 : LineSearch(options) {}
220
221void ArmijoLineSearch::Search(const double step_size_estimate,
Sameer Agarwalf4d01642012-11-26 12:55:58 -0800222 const double initial_cost,
223 const double initial_gradient,
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800224 Summary* summary) {
225 *CHECK_NOTNULL(summary) = LineSearch::Summary();
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100226 CHECK_GE(step_size_estimate, 0.0);
227 CHECK_GT(options().sufficient_decrease, 0.0);
228 CHECK_LT(options().sufficient_decrease, 1.0);
229 CHECK_GT(options().max_num_iterations, 0);
230 Function* function = options().function;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800231
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100232 // Note initial_cost & initial_gradient are evaluated at step_size = 0,
233 // not step_size_estimate, which is our starting guess.
234 const FunctionSample initial_position =
235 ValueAndGradientSample(0.0, initial_cost, initial_gradient);
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800236
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100237 FunctionSample previous = ValueAndGradientSample(0.0, 0.0, 0.0);
238 previous.value_is_valid = false;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800239
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100240 FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
241 current.value_is_valid = false;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800242
Alex Stewart7124c342013-11-07 16:10:02 +0000243 // As the Armijo line search algorithm always uses the initial point, for
244 // which both the function value and derivative are known, when fitting a
245 // minimizing polynomial, we can fit up to a quadratic without requiring the
246 // gradient at the current query point.
247 const bool interpolation_uses_gradient_at_current_sample =
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100248 options().interpolation_type == CUBIC;
249 const double descent_direction_max_norm =
250 static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800251
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100252 ++summary->num_function_evaluations;
Alex Stewart7124c342013-11-07 16:10:02 +0000253 if (interpolation_uses_gradient_at_current_sample) {
254 ++summary->num_gradient_evaluations;
255 }
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100256 current.value_is_valid =
257 function->Evaluate(current.x,
258 &current.value,
Alex Stewart7124c342013-11-07 16:10:02 +0000259 interpolation_uses_gradient_at_current_sample
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100260 ? &current.gradient : NULL);
261 current.gradient_is_valid =
Alex Stewart7124c342013-11-07 16:10:02 +0000262 interpolation_uses_gradient_at_current_sample && current.value_is_valid;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100263 while (!current.value_is_valid ||
264 current.value > (initial_cost
265 + options().sufficient_decrease
266 * initial_gradient
267 * current.x)) {
268 // If current.value_is_valid is false, we treat it as if the cost at that
269 // point is not large enough to satisfy the sufficient decrease condition.
270 ++summary->num_iterations;
271 if (summary->num_iterations >= options().max_num_iterations) {
272 summary->error =
273 StringPrintf("Line search failed: Armijo failed to find a point "
274 "satisfying the sufficient decrease condition within "
275 "specified max_num_iterations: %d.",
276 options().max_num_iterations);
277 LOG(WARNING) << summary->error;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800278 return;
279 }
280
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100281 const double step_size =
282 this->InterpolatingPolynomialMinimizingStepSize(
283 options().interpolation_type,
284 initial_position,
285 previous,
286 current,
287 (options().max_step_contraction * current.x),
288 (options().min_step_contraction * current.x));
289
290 if (step_size * descent_direction_max_norm < options().min_step_size) {
291 summary->error =
292 StringPrintf("Line search failed: step_size too small: %.5e "
293 "with descent_direction_max_norm: %.5e.", step_size,
294 descent_direction_max_norm);
295 LOG(WARNING) << summary->error;
296 return;
297 }
298
299 previous = current;
300 current.x = step_size;
301
302 ++summary->num_function_evaluations;
Alex Stewart7124c342013-11-07 16:10:02 +0000303 if (interpolation_uses_gradient_at_current_sample) {
304 ++summary->num_gradient_evaluations;
305 }
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100306 current.value_is_valid =
307 function->Evaluate(current.x,
308 &current.value,
Alex Stewart7124c342013-11-07 16:10:02 +0000309 interpolation_uses_gradient_at_current_sample
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100310 ? &current.gradient : NULL);
311 current.gradient_is_valid =
Alex Stewart7124c342013-11-07 16:10:02 +0000312 interpolation_uses_gradient_at_current_sample && current.value_is_valid;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800313 }
314
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100315 summary->optimal_step_size = current.x;
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800316 summary->success = true;
317}
318
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100319WolfeLineSearch::WolfeLineSearch(const LineSearch::Options& options)
320 : LineSearch(options) {}
321
322void WolfeLineSearch::Search(const double step_size_estimate,
323 const double initial_cost,
324 const double initial_gradient,
325 Summary* summary) {
326 *CHECK_NOTNULL(summary) = LineSearch::Summary();
327 // All parameters should have been validated by the Solver, but as
328 // invalid values would produce crazy nonsense, hard check them here.
329 CHECK_GE(step_size_estimate, 0.0);
330 CHECK_GT(options().sufficient_decrease, 0.0);
331 CHECK_GT(options().sufficient_curvature_decrease,
332 options().sufficient_decrease);
333 CHECK_LT(options().sufficient_curvature_decrease, 1.0);
334 CHECK_GT(options().max_step_expansion, 1.0);
335
336 // Note initial_cost & initial_gradient are evaluated at step_size = 0,
337 // not step_size_estimate, which is our starting guess.
338 const FunctionSample initial_position =
339 ValueAndGradientSample(0.0, initial_cost, initial_gradient);
340
341 bool do_zoom_search = false;
342 // Important: The high/low in bracket_high & bracket_low refer to their
343 // _function_ values, not their step sizes i.e. it is _not_ required that
344 // bracket_low.x < bracket_high.x.
345 FunctionSample solution, bracket_low, bracket_high;
346
347 // Wolfe bracketing phase: Increases step_size until either it finds a point
348 // that satisfies the (strong) Wolfe conditions, or an interval that brackets
349 // step sizes which satisfy the conditions. From Nocedal & Wright [1] p61 the
350 // interval: (step_size_{k-1}, step_size_{k}) contains step lengths satisfying
351 // the strong Wolfe conditions if one of the following conditions are met:
352 //
353 // 1. step_size_{k} violates the sufficient decrease (Armijo) condition.
354 // 2. f(step_size_{k}) >= f(step_size_{k-1}).
355 // 3. f'(step_size_{k}) >= 0.
356 //
357 // Caveat: If f(step_size_{k}) is invalid, then step_size is reduced, ignoring
358 // this special case, step_size monotonically increases during bracketing.
359 if (!this->BracketingPhase(initial_position,
360 step_size_estimate,
361 &bracket_low,
362 &bracket_high,
363 &do_zoom_search,
Alex Stewart7124c342013-11-07 16:10:02 +0000364 summary)) {
365 // Failed to find either a valid point, a valid bracket satisfying the Wolfe
366 // conditions, or even a step size > minimum tolerance satisfying the Armijo
367 // condition.
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100368 return;
369 }
Alex Stewart7124c342013-11-07 16:10:02 +0000370
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100371 if (!do_zoom_search) {
372 // Either: Bracketing phase already found a point satisfying the strong
373 // Wolfe conditions, thus no Zoom required.
374 //
375 // Or: Bracketing failed to find a valid bracket or a point satisfying the
Alex Stewart7124c342013-11-07 16:10:02 +0000376 // strong Wolfe conditions within max_num_iterations, or whilst searching
377 // shrank the bracket width until it was below our minimum tolerance.
378 // As these are 'artificial' constraints, and we would otherwise fail to
379 // produce a valid point when ArmijoLineSearch would succeed, we return the
380 // point with the lowest cost found thus far which satsifies the Armijo
381 // condition (but not the Wolfe conditions).
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100382 summary->optimal_step_size = bracket_low.x;
383 summary->success = true;
384 return;
385 }
386
Alex Stewart40ef9032013-11-25 16:36:40 +0000387 VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
388 << "Starting line search zoom phase with bracket_low: "
389 << bracket_low << ", bracket_high: " << bracket_high
390 << ", bracket width: " << fabs(bracket_low.x - bracket_high.x)
391 << ", bracket abs delta cost: "
392 << fabs(bracket_low.value - bracket_high.value);
393
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100394 // Wolfe Zoom phase: Called when the Bracketing phase finds an interval of
395 // non-zero, finite width that should bracket step sizes which satisfy the
396 // (strong) Wolfe conditions (before finding a step size that satisfies the
397 // conditions). Zoom successively decreases the size of the interval until a
398 // step size which satisfies the Wolfe conditions is found. The interval is
399 // defined by bracket_low & bracket_high, which satisfy:
400 //
401 // 1. The interval bounded by step sizes: bracket_low.x & bracket_high.x
402 // contains step sizes that satsify the strong Wolfe conditions.
403 // 2. bracket_low.x is of all the step sizes evaluated *which satisifed the
404 // Armijo sufficient decrease condition*, the one which generated the
405 // smallest function value, i.e. bracket_low.value <
406 // f(all other steps satisfying Armijo).
407 // - Note that this does _not_ (necessarily) mean that initially
408 // bracket_low.value < bracket_high.value (although this is typical)
409 // e.g. when bracket_low = initial_position, and bracket_high is the
410 // first sample, and which does not satisfy the Armijo condition,
411 // but still has bracket_high.value < initial_position.value.
412 // 3. bracket_high is chosen after bracket_low, s.t.
413 // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
414 if (!this->ZoomPhase(initial_position,
415 bracket_low,
416 bracket_high,
417 &solution,
418 summary) && !solution.value_is_valid) {
419 // Failed to find a valid point (given the specified decrease parameters)
420 // within the specified bracket.
421 return;
422 }
423 // Ensure that if we ran out of iterations whilst zooming the bracket, or
424 // shrank the bracket width to < tolerance and failed to find a point which
425 // satisfies the strong Wolfe curvature condition, that we return the point
426 // amongst those found thus far, which minimizes f() and satisfies the Armijo
427 // condition.
428 solution =
429 solution.value_is_valid && solution.value <= bracket_low.value
430 ? solution : bracket_low;
431
432 summary->optimal_step_size = solution.x;
433 summary->success = true;
434}
435
Alex Stewart7124c342013-11-07 16:10:02 +0000436// Returns true if either:
437//
438// A termination condition satisfying the (strong) Wolfe bracketing conditions
439// is found:
440//
441// - A valid point, defined as a bracket of zero width [zoom not required].
442// - A valid bracket (of width > tolerance), [zoom required].
443//
444// Or, searching was stopped due to an 'artificial' constraint, i.e. not
445// a condition imposed / required by the underlying algorithm, but instead an
446// engineering / implementation consideration. But a step which exceeds the
447// minimum step size, and satsifies the Armijo condition was still found,
448// and should thus be used [zoom not required].
449//
450// Returns false if no step size > minimum step size was found which
451// satisfies at least the Armijo condition.
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100452bool WolfeLineSearch::BracketingPhase(
453 const FunctionSample& initial_position,
454 const double step_size_estimate,
455 FunctionSample* bracket_low,
456 FunctionSample* bracket_high,
457 bool* do_zoom_search,
458 Summary* summary) {
459 Function* function = options().function;
460
461 FunctionSample previous = initial_position;
462 FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
463 current.value_is_valid = false;
464
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100465 const double descent_direction_max_norm =
466 static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
467
468 *do_zoom_search = false;
469 *bracket_low = initial_position;
470
Alex Stewart7124c342013-11-07 16:10:02 +0000471 // As we require the gradient to evaluate the Wolfe condition, we always
472 // calculate it together with the value, irrespective of the interpolation
473 // type. As opposed to only calculating the gradient after the Armijo
474 // condition is satisifed, as the computational saving from this approach
475 // would be slight (perhaps even negative due to the extra call). Also,
476 // always calculating the value & gradient together protects against us
477 // reporting invalid solutions if the cost function returns slightly different
478 // function values when evaluated with / without gradients (due to numerical
479 // issues).
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100480 ++summary->num_function_evaluations;
Alex Stewart7124c342013-11-07 16:10:02 +0000481 ++summary->num_gradient_evaluations;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100482 current.value_is_valid =
483 function->Evaluate(current.x,
484 &current.value,
Alex Stewart7124c342013-11-07 16:10:02 +0000485 &current.gradient);
486 current.gradient_is_valid = current.value_is_valid;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100487
488 while (true) {
489 ++summary->num_iterations;
490
491 if (current.value_is_valid &&
492 (current.value > (initial_position.value
493 + options().sufficient_decrease
494 * initial_position.gradient
495 * current.x) ||
496 (previous.value_is_valid && current.value > previous.value))) {
497 // Bracket found: current step size violates Armijo sufficient decrease
498 // condition, or has stepped past an inflection point of f() relative to
499 // previous step size.
500 *do_zoom_search = true;
501 *bracket_low = previous;
502 *bracket_high = current;
Alex Stewart40ef9032013-11-25 16:36:40 +0000503 VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
504 << "Bracket found: current step (" << current.x
505 << ") violates Armijo sufficient condition, or has passed an "
506 << "inflection point of f() based on value.";
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100507 break;
508 }
509
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100510 if (current.value_is_valid &&
511 fabs(current.gradient) <=
512 -options().sufficient_curvature_decrease * initial_position.gradient) {
513 // Current step size satisfies the strong Wolfe conditions, and is thus a
514 // valid termination point, therefore a Zoom not required.
515 *bracket_low = current;
516 *bracket_high = current;
Alex Stewart40ef9032013-11-25 16:36:40 +0000517 VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
518 << "Bracketing phase found step size: " << current.x
519 << ", satisfying strong Wolfe conditions, initial_position: "
520 << initial_position << ", current: " << current;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100521 break;
522
523 } else if (current.value_is_valid && current.gradient >= 0) {
524 // Bracket found: current step size has stepped past an inflection point
525 // of f(), but Armijo sufficient decrease is still satisfied and
526 // f(current) is our best minimum thus far. Remember step size
527 // monotonically increases, thus previous_step_size < current_step_size
528 // even though f(previous) > f(current).
529 *do_zoom_search = true;
530 // Note inverse ordering from first bracket case.
531 *bracket_low = current;
532 *bracket_high = previous;
Alex Stewart40ef9032013-11-25 16:36:40 +0000533 VLOG(3) << "Bracket found: current step (" << current.x
534 << ") satisfies Armijo, but has gradient >= 0, thus have passed "
535 << "an inflection point of f().";
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100536 break;
537
Alex Stewart7124c342013-11-07 16:10:02 +0000538 } else if (current.value_is_valid &&
539 fabs(current.x - previous.x) * descent_direction_max_norm
540 < options().min_step_size) {
541 // We have shrunk the search bracket to a width less than our tolerance,
542 // and still not found either a point satisfying the strong Wolfe
543 // conditions, or a valid bracket containing such a point. Stop searching
544 // and set bracket_low to the size size amongst all those tested which
545 // minimizes f() and satisfies the Armijo condition.
546 LOG(WARNING) << "Line search failed: Wolfe bracketing phase shrank "
547 << "bracket width: " << fabs(current.x - previous.x)
548 << ", to < tolerance: " << options().min_step_size
549 << ", with descent_direction_max_norm: "
550 << descent_direction_max_norm << ", and failed to find "
551 << "a point satisfying the strong Wolfe conditions or a "
552 << "bracketing containing such a point. Accepting "
553 << "point found satisfying Armijo condition only, to "
554 << "allow continuation.";
555 *bracket_low = current;
556 break;
557
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100558 } else if (summary->num_iterations >= options().max_num_iterations) {
559 // Check num iterations bound here so that we always evaluate the
560 // max_num_iterations-th iteration against all conditions, and
561 // then perform no additional (unused) evaluations.
562 summary->error =
563 StringPrintf("Line search failed: Wolfe bracketing phase failed to "
564 "find a point satisfying strong Wolfe conditions, or a "
565 "bracket containing such a point within specified "
566 "max_num_iterations: %d", options().max_num_iterations);
567 LOG(WARNING) << summary->error;
568 // Ensure that bracket_low is always set to the step size amongst all
569 // those tested which minimizes f() and satisfies the Armijo condition
570 // when we terminate due to the 'artificial' max_num_iterations condition.
571 *bracket_low =
572 current.value_is_valid && current.value < bracket_low->value
573 ? current : *bracket_low;
Alex Stewart7124c342013-11-07 16:10:02 +0000574 break;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100575 }
576 // Either: f(current) is invalid; or, f(current) is valid, but does not
577 // satisfy the strong Wolfe conditions itself, or the conditions for
578 // being a boundary of a bracket.
579
580 // If f(current) is valid, (but meets no criteria) expand the search by
581 // increasing the step size.
582 const double max_step_size =
583 current.value_is_valid
584 ? (current.x * options().max_step_expansion) : current.x;
585
586 // We are performing 2-point interpolation only here, but the API of
587 // InterpolatingPolynomialMinimizingStepSize() allows for up to
588 // 3-point interpolation, so pad call with a sample with an invalid
589 // value that will therefore be ignored.
590 const FunctionSample unused_previous;
591 DCHECK(!unused_previous.value_is_valid);
592 // Contracts step size if f(current) is not valid.
593 const double step_size =
594 this->InterpolatingPolynomialMinimizingStepSize(
595 options().interpolation_type,
596 previous,
597 unused_previous,
598 current,
599 previous.x,
600 max_step_size);
601 if (step_size * descent_direction_max_norm < options().min_step_size) {
602 summary->error =
603 StringPrintf("Line search failed: step_size too small: %.5e "
604 "with descent_direction_max_norm: %.5e", step_size,
605 descent_direction_max_norm);
606 LOG(WARNING) << summary->error;
607 return false;
608 }
609
610 previous = current.value_is_valid ? current : previous;
611 current.x = step_size;
612
613 ++summary->num_function_evaluations;
Alex Stewart7124c342013-11-07 16:10:02 +0000614 ++summary->num_gradient_evaluations;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100615 current.value_is_valid =
616 function->Evaluate(current.x,
617 &current.value,
Alex Stewart7124c342013-11-07 16:10:02 +0000618 &current.gradient);
619 current.gradient_is_valid = current.value_is_valid;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100620 }
Alex Stewart7124c342013-11-07 16:10:02 +0000621
622 // Ensure that even if a valid bracket was found, we will only mark a zoom
623 // as required if the bracket's width is greater than our minimum tolerance.
624 if (*do_zoom_search &&
625 fabs(bracket_high->x - bracket_low->x) * descent_direction_max_norm
626 < options().min_step_size) {
627 *do_zoom_search = false;
628 }
629
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100630 return true;
631}
632
633// Returns true iff solution satisfies the strong Wolfe conditions. Otherwise,
634// on return false, if we stopped searching due to the 'artificial' condition of
635// reaching max_num_iterations, solution is the step size amongst all those
636// tested, which satisfied the Armijo decrease condition and minimized f().
637bool WolfeLineSearch::ZoomPhase(const FunctionSample& initial_position,
638 FunctionSample bracket_low,
639 FunctionSample bracket_high,
640 FunctionSample* solution,
641 Summary* summary) {
642 Function* function = options().function;
643
644 CHECK(bracket_low.value_is_valid && bracket_low.gradient_is_valid)
Alex Stewart7124c342013-11-07 16:10:02 +0000645 << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100646 << "Ceres bug: f_low input to Wolfe Zoom invalid, please contact "
647 << "the developers!, initial_position: " << initial_position
648 << ", bracket_low: " << bracket_low
649 << ", bracket_high: "<< bracket_high;
650 // We do not require bracket_high.gradient_is_valid as the gradient condition
651 // for a valid bracket is only dependent upon bracket_low.gradient, and
652 // in order to minimize jacobian evaluations, bracket_high.gradient may
653 // not have been calculated (if bracket_high.value does not satisfy the
654 // Armijo sufficient decrease condition and interpolation method does not
655 // require it).
Alex Stewart7124c342013-11-07 16:10:02 +0000656 //
657 // We also do not require that: bracket_low.value < bracket_high.value,
658 // although this is typical. This is to deal with the case when
659 // bracket_low = initial_position, bracket_high is the first sample,
660 // and bracket_high does not satisfy the Armijo condition, but still has
661 // bracket_high.value < initial_position.value.
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100662 CHECK(bracket_high.value_is_valid)
Alex Stewart7124c342013-11-07 16:10:02 +0000663 << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100664 << "Ceres bug: f_high input to Wolfe Zoom invalid, please "
665 << "contact the developers!, initial_position: " << initial_position
666 << ", bracket_low: " << bracket_low
667 << ", bracket_high: "<< bracket_high;
Alex Stewart7124c342013-11-07 16:10:02 +0000668
669 if (bracket_low.gradient * (bracket_high.x - bracket_low.x) >= 0) {
670 // The third condition for a valid initial bracket:
671 //
672 // 3. bracket_high is chosen after bracket_low, s.t.
673 // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
674 //
675 // is not satisfied. As this can happen when the users' cost function
676 // returns inconsistent gradient values relative to the function values,
677 // we do not CHECK_LT(), but we do stop processing and return an invalid
678 // value.
679 summary->error =
680 StringPrintf("Line search failed: Wolfe zoom phase passed a bracket "
681 "which does not satisfy: bracket_low.gradient * "
682 "(bracket_high.x - bracket_low.x) < 0 [%.8e !< 0] "
683 "with initial_position: %s, bracket_low: %s, bracket_high:"
684 " %s, the most likely cause of which is the cost function "
685 "returning inconsistent gradient & function values.",
686 bracket_low.gradient * (bracket_high.x - bracket_low.x),
687 initial_position.ToDebugString().c_str(),
688 bracket_low.ToDebugString().c_str(),
689 bracket_high.ToDebugString().c_str());
690 LOG(WARNING) << summary->error;
691 solution->value_is_valid = false;
692 return false;
693 }
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100694
695 const int num_bracketing_iterations = summary->num_iterations;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100696 const double descent_direction_max_norm =
697 static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
698
699 while (true) {
700 // Set solution to bracket_low, as it is our best step size (smallest f())
701 // found thus far and satisfies the Armijo condition, even though it does
702 // not satisfy the Wolfe condition.
703 *solution = bracket_low;
704 if (summary->num_iterations >= options().max_num_iterations) {
705 summary->error =
706 StringPrintf("Line search failed: Wolfe zoom phase failed to "
707 "find a point satisfying strong Wolfe conditions "
708 "within specified max_num_iterations: %d, "
709 "(num iterations taken for bracketing: %d).",
710 options().max_num_iterations, num_bracketing_iterations);
711 LOG(WARNING) << summary->error;
712 return false;
713 }
714 if (fabs(bracket_high.x - bracket_low.x) * descent_direction_max_norm
715 < options().min_step_size) {
716 // Bracket width has been reduced below tolerance, and no point satisfying
717 // the strong Wolfe conditions has been found.
718 summary->error =
719 StringPrintf("Line search failed: Wolfe zoom bracket width: %.5e "
720 "too small with descent_direction_max_norm: %.5e.",
721 fabs(bracket_high.x - bracket_low.x),
722 descent_direction_max_norm);
723 LOG(WARNING) << summary->error;
724 return false;
725 }
726
727 ++summary->num_iterations;
728 // Polynomial interpolation requires inputs ordered according to step size,
729 // not f(step size).
730 const FunctionSample& lower_bound_step =
731 bracket_low.x < bracket_high.x ? bracket_low : bracket_high;
732 const FunctionSample& upper_bound_step =
733 bracket_low.x < bracket_high.x ? bracket_high : bracket_low;
734 // We are performing 2-point interpolation only here, but the API of
735 // InterpolatingPolynomialMinimizingStepSize() allows for up to
736 // 3-point interpolation, so pad call with a sample with an invalid
737 // value that will therefore be ignored.
738 const FunctionSample unused_previous;
739 DCHECK(!unused_previous.value_is_valid);
740 solution->x =
741 this->InterpolatingPolynomialMinimizingStepSize(
742 options().interpolation_type,
743 lower_bound_step,
744 unused_previous,
745 upper_bound_step,
746 lower_bound_step.x,
747 upper_bound_step.x);
748 // No check on magnitude of step size being too small here as it is
749 // lower-bounded by the initial bracket start point, which was valid.
Alex Stewart7124c342013-11-07 16:10:02 +0000750 //
751 // As we require the gradient to evaluate the Wolfe condition, we always
752 // calculate it together with the value, irrespective of the interpolation
753 // type. As opposed to only calculating the gradient after the Armijo
754 // condition is satisifed, as the computational saving from this approach
755 // would be slight (perhaps even negative due to the extra call). Also,
756 // always calculating the value & gradient together protects against us
757 // reporting invalid solutions if the cost function returns slightly
758 // different function values when evaluated with / without gradients (due
759 // to numerical issues).
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100760 ++summary->num_function_evaluations;
Alex Stewart7124c342013-11-07 16:10:02 +0000761 ++summary->num_gradient_evaluations;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100762 solution->value_is_valid =
763 function->Evaluate(solution->x,
764 &solution->value,
Alex Stewart7124c342013-11-07 16:10:02 +0000765 &solution->gradient);
766 solution->gradient_is_valid = solution->value_is_valid;
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100767 if (!solution->value_is_valid) {
768 summary->error =
769 StringPrintf("Line search failed: Wolfe Zoom phase found "
770 "step_size: %.5e, for which function is invalid, "
771 "between low_step: %.5e and high_step: %.5e "
772 "at which function is valid.",
773 solution->x, bracket_low.x, bracket_high.x);
774 LOG(WARNING) << summary->error;
775 return false;
776 }
777
Alex Stewart40ef9032013-11-25 16:36:40 +0000778 VLOG(3) << "Zoom iteration: "
779 << summary->num_iterations - num_bracketing_iterations
780 << ", bracket_low: " << bracket_low
781 << ", bracket_high: " << bracket_high
782 << ", minimizing solution: " << *solution;
783
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100784 if ((solution->value > (initial_position.value
785 + options().sufficient_decrease
786 * initial_position.gradient
787 * solution->x)) ||
788 (solution->value >= bracket_low.value)) {
789 // Armijo sufficient decrease not satisfied, or not better
790 // than current lowest sample, use as new upper bound.
791 bracket_high = *solution;
792 continue;
793 }
794
795 // Armijo sufficient decrease satisfied, check strong Wolfe condition.
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100796 if (fabs(solution->gradient) <=
797 -options().sufficient_curvature_decrease * initial_position.gradient) {
798 // Found a valid termination point satisfying strong Wolfe conditions.
Alex Stewart40ef9032013-11-25 16:36:40 +0000799 VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
800 << "Zoom phase found step size: " << solution->x
801 << ", satisfying strong Wolfe conditions.";
Alex Stewart9aa0e3c2013-07-05 20:22:37 +0100802 break;
803
804 } else if (solution->gradient * (bracket_high.x - bracket_low.x) >= 0) {
805 bracket_high = bracket_low;
806 }
807
808 bracket_low = *solution;
809 }
810 // Solution contains a valid point which satisfies the strong Wolfe
811 // conditions.
812 return true;
813}
814
Sameer Agarwal1d11be92012-11-25 19:28:06 -0800815} // namespace internal
816} // namespace ceres
Sameer Agarwal8140f0f2013-03-12 09:45:08 -0700817
818#endif // CERES_NO_LINE_SEARCH_MINIMIZER