Fix a bug in TrustRegionMinimizer. LocalParameterization::Plus is allowed to return false when for some reason the operation cannot be performed. Uptil now, this would cause the TrustRegionMinimizer to terminate with a numerical failure. This is not correct behaviour. Just like CostFunction::Evaluate, returning false from LocalParameterization::Plus should result in the current step to be rejected rather than the entire optimization coming to a halt. LineSearchMinimizer has also been updated to use the same pattern. Thanks to Michael Vitus for reporting this. Change-Id: I1351966bc6db3bf6cd46387b78d4e52a9df51696
diff --git a/internal/ceres/line_search_minimizer.cc b/internal/ceres/line_search_minimizer.cc index 2cc89fa..5533e20 100644 --- a/internal/ceres/line_search_minimizer.cc +++ b/internal/ceres/line_search_minimizer.cc
@@ -69,6 +69,9 @@ // use. const double kEpsilon = 1e-12; +// TODO(sameeragarwal): I think there is a small bug here, in that if +// the evaluation fails, then the state can contain garbage. Look at +// this more carefully. bool Evaluate(Evaluator* evaluator, const Vector& x, LineSearchMinimizer::State* state) { @@ -310,9 +313,10 @@ WallTimeInSeconds() - iteration_start_time; // TODO(sameeragarwal): Collect stats. - if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data()) || - !Evaluate(evaluator, x_plus_delta, ¤t_state)) { - LOG(WARNING) << "Evaluation failed."; + if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { + LOG(WARNING) << "x_plus_delta = Plus(x, delta) failed. "; + } else if (!Evaluate(evaluator, x_plus_delta, ¤t_state)) { + LOG(WARNING) << "Step failed to evaluate. "; } else { x = x_plus_delta; }
diff --git a/internal/ceres/trust_region_minimizer.cc b/internal/ceres/trust_region_minimizer.cc index 03d6c8e..8e2bc67 100644 --- a/internal/ceres/trust_region_minimizer.cc +++ b/internal/ceres/trust_region_minimizer.cc
@@ -287,24 +287,18 @@ // Undo the Jacobian column scaling. delta = (trust_region_step.array() * scale.array()).matrix(); - if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { - summary->termination_type = NUMERICAL_FAILURE; - summary->error = - "Terminating. Failed to compute Plus(x, delta, x_plus_delta)."; - LOG(WARNING) << summary->error; - return; - } - - // Try this step. double new_cost = numeric_limits<double>::max(); - if (!evaluator->Evaluate(x_plus_delta.data(), - &new_cost, - NULL, NULL, NULL)) { - // If the evaluation of the new cost fails, treat it as a step - // with high cost. + if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { + LOG(WARNING) << "x_plus_delta = Plus(x, delta) failed. " + << "Treating it as a step with infinite cost"; + } else if (!evaluator->Evaluate(x_plus_delta.data(), + &new_cost, + NULL, + NULL, + NULL)) { LOG(WARNING) << "Step failed to evaluate. " - << "Treating it as step with infinite cost"; + << "Treating it as a step with infinite cost"; new_cost = numeric_limits<double>::max(); } else { // Check if performing an inner iteration will make it better.