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; }