| // Ceres Solver - A fast non-linear least squares minimizer | 
 | // Copyright 2012 Google Inc. All rights reserved. | 
 | // http://code.google.com/p/ceres-solver/ | 
 | // | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are met: | 
 | // | 
 | // * Redistributions of source code must retain the above copyright notice, | 
 | //   this list of conditions and the following disclaimer. | 
 | // * Redistributions in binary form must reproduce the above copyright notice, | 
 | //   this list of conditions and the following disclaimer in the documentation | 
 | //   and/or other materials provided with the distribution. | 
 | // * Neither the name of Google Inc. nor the names of its contributors may be | 
 | //   used to endorse or promote products derived from this software without | 
 | //   specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 
 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
 | // POSSIBILITY OF SUCH DAMAGE. | 
 | // | 
 | // Author: sameeragarwal@google.com (Sameer Agarwal) | 
 |  | 
 | #ifndef CERES_NO_LINE_SEARCH_MINIMIZER | 
 | #include "ceres/line_search.h" | 
 |  | 
 | #include "ceres/fpclassify.h" | 
 | #include "ceres/evaluator.h" | 
 | #include "ceres/internal/eigen.h" | 
 | #include "ceres/polynomial.h" | 
 | #include "glog/logging.h" | 
 |  | 
 | namespace ceres { | 
 | namespace internal { | 
 | namespace { | 
 |  | 
 | FunctionSample ValueSample(const double x, const double value) { | 
 |   FunctionSample sample; | 
 |   sample.x = x; | 
 |   sample.value = value; | 
 |   sample.value_is_valid = true; | 
 |   return sample; | 
 | }; | 
 |  | 
 | FunctionSample ValueAndGradientSample(const double x, | 
 |                                       const double value, | 
 |                                       const double gradient) { | 
 |   FunctionSample sample; | 
 |   sample.x = x; | 
 |   sample.value = value; | 
 |   sample.gradient = gradient; | 
 |   sample.value_is_valid = true; | 
 |   sample.gradient_is_valid = true; | 
 |   return sample; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | LineSearchFunction::LineSearchFunction(Evaluator* evaluator) | 
 |     : evaluator_(evaluator), | 
 |       position_(evaluator->NumParameters()), | 
 |       direction_(evaluator->NumEffectiveParameters()), | 
 |       evaluation_point_(evaluator->NumParameters()), | 
 |       scaled_direction_(evaluator->NumEffectiveParameters()), | 
 |       gradient_(evaluator->NumEffectiveParameters()) { | 
 | } | 
 |  | 
 | void LineSearchFunction::Init(const Vector& position, | 
 |                               const Vector& direction) { | 
 |   position_ = position; | 
 |   direction_ = direction; | 
 | } | 
 |  | 
 | bool LineSearchFunction::Evaluate(const double x, double* f, double* g) { | 
 |   scaled_direction_ = x * direction_; | 
 |   if (!evaluator_->Plus(position_.data(), | 
 |                         scaled_direction_.data(), | 
 |                         evaluation_point_.data())) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (g == NULL) { | 
 |     return (evaluator_->Evaluate(evaluation_point_.data(), | 
 |                                   f, NULL, NULL, NULL) && | 
 |             IsFinite(*f)); | 
 |   } | 
 |  | 
 |   if (!evaluator_->Evaluate(evaluation_point_.data(), | 
 |                             f, | 
 |                             NULL, | 
 |                             gradient_.data(), NULL)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   *g = direction_.dot(gradient_); | 
 |   return IsFinite(*f) && IsFinite(*g); | 
 | } | 
 |  | 
 | void ArmijoLineSearch::Search(const LineSearch::Options& options, | 
 |                               const double initial_step_size, | 
 |                               const double initial_cost, | 
 |                               const double initial_gradient, | 
 |                               Summary* summary) { | 
 |   *CHECK_NOTNULL(summary) = LineSearch::Summary(); | 
 |   Function* function = options.function; | 
 |  | 
 |   double previous_step_size = 0.0; | 
 |   double previous_cost = 0.0; | 
 |   double previous_gradient = 0.0; | 
 |   bool previous_step_size_is_valid = false; | 
 |  | 
 |   double step_size = initial_step_size; | 
 |   double cost = 0.0; | 
 |   double gradient = 0.0; | 
 |   bool step_size_is_valid = false; | 
 |  | 
 |   ++summary->num_evaluations; | 
 |   step_size_is_valid = | 
 |       function->Evaluate(step_size, | 
 |                          &cost, | 
 |                          options.interpolation_degree < 2 ? NULL : &gradient); | 
 |   while (!step_size_is_valid || cost > (initial_cost | 
 |                                         + options.sufficient_decrease | 
 |                                         * initial_gradient | 
 |                                         * step_size)) { | 
 |     // If step_size_is_valid is not true we treat it as if the cost at | 
 |     // that point is not large enough to satisfy the sufficient | 
 |     // decrease condition. | 
 |  | 
 |     const double current_step_size = step_size; | 
 |     // Backtracking search. Each iteration of this loop finds a new point | 
 |  | 
 |     if ((options.interpolation_degree == 0) || !step_size_is_valid) { | 
 |       // Backtrack by halving the step_size; | 
 |       step_size *= 0.5; | 
 |     } else { | 
 |       // Backtrack by interpolating the function and gradient values | 
 |       // and minimizing the corresponding polynomial. | 
 |  | 
 |       vector<FunctionSample> samples; | 
 |       samples.push_back(ValueAndGradientSample(0.0, | 
 |                                                initial_cost, | 
 |                                                initial_gradient)); | 
 |  | 
 |       if (options.interpolation_degree == 1) { | 
 |         // Two point interpolation using function values and the | 
 |         // initial gradient. | 
 |         samples.push_back(ValueSample(step_size, cost)); | 
 |  | 
 |         if (options.use_higher_degree_interpolation_when_possible && | 
 |             summary->num_evaluations > 1 && | 
 |             previous_step_size_is_valid) { | 
 |           // Three point interpolation, using function values and the | 
 |           // initial gradient. | 
 |           samples.push_back(ValueSample(previous_step_size, previous_cost)); | 
 |         } | 
 |       } else { | 
 |         // Two point interpolation using the function values and the gradients. | 
 |         samples.push_back(ValueAndGradientSample(step_size, | 
 |                                                  cost, | 
 |                                                  gradient)); | 
 |  | 
 |         if (options.use_higher_degree_interpolation_when_possible && | 
 |             summary->num_evaluations > 1 && | 
 |             previous_step_size_is_valid) { | 
 |           // Three point interpolation using the function values and | 
 |           // the gradients. | 
 |           samples.push_back(ValueAndGradientSample(previous_step_size, | 
 |                                                    previous_cost, | 
 |                                                    previous_gradient)); | 
 |         } | 
 |       } | 
 |  | 
 |       double min_value; | 
 |       MinimizeInterpolatingPolynomial(samples, 0.0, current_step_size, | 
 |                                       &step_size, &min_value); | 
 |       step_size = | 
 |           min(max(step_size, | 
 |                   options.min_relative_step_size_change * current_step_size), | 
 |               options.max_relative_step_size_change * current_step_size); | 
 |     } | 
 |  | 
 |     previous_step_size = current_step_size; | 
 |     previous_cost = cost; | 
 |     previous_gradient = gradient; | 
 |  | 
 |     if (fabs(initial_gradient) * step_size < options.step_size_threshold) { | 
 |       LOG(WARNING) << "Line search failed: step_size too small: " << step_size; | 
 |       return; | 
 |     } | 
 |  | 
 |     ++summary->num_evaluations; | 
 |     step_size_is_valid = | 
 |         function->Evaluate(step_size, | 
 |                            &cost, | 
 |                            options.interpolation_degree < 2 ? NULL : &gradient); | 
 |   } | 
 |  | 
 |   summary->optimal_step_size = step_size; | 
 |   summary->success = true; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace ceres | 
 |  | 
 | #endif  // CERES_NO_LINE_SEARCH_MINIMIZER |