blob: 7d4c093220d90b3d757a4867a86a6ac54611c480 [file] [log] [blame]
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -07001// 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
31#include "ceres/trust_region_minimizer.h"
32
33#include <algorithm>
34#include <cstdlib>
35#include <cmath>
36#include <cstring>
Sameer Agarwal552f9f82012-08-31 07:27:22 -070037#include <limits>
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070038#include <string>
39#include <vector>
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070040
41#include "Eigen/Core"
42#include "ceres/array_utils.h"
43#include "ceres/evaluator.h"
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070044#include "ceres/internal/eigen.h"
45#include "ceres/internal/scoped_ptr.h"
Sameer Agarwal0beab862012-08-13 15:12:01 -070046#include "ceres/linear_least_squares_problems.h"
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070047#include "ceres/sparse_matrix.h"
Sameer Agarwal9123e2f2012-09-18 21:49:06 -070048#include "ceres/stringprintf.h"
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070049#include "ceres/trust_region_strategy.h"
50#include "ceres/types.h"
Petter Strandmark76533b32012-09-04 22:08:50 -070051#include "ceres/wall_time.h"
Sameer Agarwal0beab862012-08-13 15:12:01 -070052#include "glog/logging.h"
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070053
54namespace ceres {
55namespace internal {
56namespace {
57// Small constant for various floating point issues.
58const double kEpsilon = 1e-12;
59} // namespace
60
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070061// Compute a scaling vector that is used to improve the conditioning
62// of the Jacobian.
63void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian,
64 double* scale) const {
65 jacobian.SquaredColumnNorm(scale);
66 for (int i = 0; i < jacobian.num_cols(); ++i) {
Sameer Agarwala406b172012-08-18 15:28:49 -070067 scale[i] = 1.0 / (1.0 + sqrt(scale[i]));
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070068 }
69}
70
71void TrustRegionMinimizer::Init(const Minimizer::Options& options) {
72 options_ = options;
73 sort(options_.lsqp_iterations_to_dump.begin(),
74 options_.lsqp_iterations_to_dump.end());
75}
76
77bool TrustRegionMinimizer::MaybeDumpLinearLeastSquaresProblem(
78 const int iteration,
79 const SparseMatrix* jacobian,
80 const double* residuals,
81 const double* step) const {
82 // TODO(sameeragarwal): Since the use of trust_region_radius has
83 // moved inside TrustRegionStrategy, its not clear how we dump the
84 // regularization vector/matrix anymore.
85 //
Sameer Agarwal65625f72012-09-17 12:06:57 -070086 // Also num_eliminate_blocks is not visible to the trust region
87 // minimizer either.
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070088 //
Sameer Agarwal65625f72012-09-17 12:06:57 -070089 // Both of these indicate that this is the wrong place for this
90 // code, and going forward this should needs fixing/refactoring.
Sameer Agarwal65625f72012-09-17 12:06:57 -070091 return true;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070092}
93
94void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
95 double* parameters,
96 Solver::Summary* summary) {
Petter Strandmark76533b32012-09-04 22:08:50 -070097 double start_time = WallTimeInSeconds();
98 double iteration_start_time = start_time;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -070099 Init(options);
100
101 summary->termination_type = NO_CONVERGENCE;
102 summary->num_successful_steps = 0;
103 summary->num_unsuccessful_steps = 0;
104
105 Evaluator* evaluator = CHECK_NOTNULL(options_.evaluator);
106 SparseMatrix* jacobian = CHECK_NOTNULL(options_.jacobian);
107 TrustRegionStrategy* strategy = CHECK_NOTNULL(options_.trust_region_strategy);
108
109 const int num_parameters = evaluator->NumParameters();
110 const int num_effective_parameters = evaluator->NumEffectiveParameters();
111 const int num_residuals = evaluator->NumResiduals();
112
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700113 VectorRef x_min(parameters, num_parameters);
114 Vector x = x_min;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700115 double x_norm = x.norm();
116
117 Vector residuals(num_residuals);
118 Vector trust_region_step(num_effective_parameters);
119 Vector delta(num_effective_parameters);
120 Vector x_plus_delta(num_parameters);
121 Vector gradient(num_effective_parameters);
122 Vector model_residuals(num_residuals);
123 Vector scale(num_effective_parameters);
124
125 IterationSummary iteration_summary;
126 iteration_summary.iteration = 0;
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700127 iteration_summary.step_is_valid = false;
128 iteration_summary.step_is_successful = false;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700129 iteration_summary.cost_change = 0.0;
130 iteration_summary.gradient_max_norm = 0.0;
131 iteration_summary.step_norm = 0.0;
132 iteration_summary.relative_decrease = 0.0;
133 iteration_summary.trust_region_radius = strategy->Radius();
134 // TODO(sameeragarwal): Rename eta to linear_solver_accuracy or
135 // something similar across the board.
136 iteration_summary.eta = options_.eta;
137 iteration_summary.linear_solver_iterations = 0;
Sameer Agarwalfa015192012-06-11 14:21:42 -0700138 iteration_summary.step_solver_time_in_seconds = 0;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700139
140 // Do initial cost and Jacobian evaluation.
141 double cost = 0.0;
Sameer Agarwalc3c3dd82013-04-25 07:49:24 -0700142 if (!evaluator->Evaluate(x.data(),
143 &cost,
144 residuals.data(),
145 gradient.data(),
146 jacobian)) {
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700147 LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed.";
148 summary->termination_type = NUMERICAL_FAILURE;
149 return;
150 }
151
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700152 int num_consecutive_nonmonotonic_steps = 0;
153 double minimum_cost = cost;
154 double reference_cost = cost;
155 double accumulated_reference_model_cost_change = 0.0;
156 double candidate_cost = cost;
157 double accumulated_candidate_model_cost_change = 0.0;
158
Sameer Agarwalc3c3dd82013-04-25 07:49:24 -0700159 summary->initial_cost = cost + summary->fixed_cost;
160 iteration_summary.cost = cost + summary->fixed_cost;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700161 iteration_summary.gradient_max_norm = gradient.lpNorm<Eigen::Infinity>();
162
Sameer Agarwal4441b5b2012-06-12 18:01:11 -0700163 // The initial gradient max_norm is bounded from below so that we do
164 // not divide by zero.
Sameer Agarwal9883fc32012-11-30 12:32:43 -0800165 const double initial_gradient_max_norm =
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700166 max(iteration_summary.gradient_max_norm, kEpsilon);
Sameer Agarwal4441b5b2012-06-12 18:01:11 -0700167 const double absolute_gradient_tolerance =
Sameer Agarwal9883fc32012-11-30 12:32:43 -0800168 options_.gradient_tolerance * initial_gradient_max_norm;
Sameer Agarwal4441b5b2012-06-12 18:01:11 -0700169
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700170 if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
171 summary->termination_type = GRADIENT_TOLERANCE;
172 VLOG(1) << "Terminating: Gradient tolerance reached."
173 << "Relative gradient max norm: "
Sameer Agarwal9883fc32012-11-30 12:32:43 -0800174 << iteration_summary.gradient_max_norm / initial_gradient_max_norm
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700175 << " <= " << options_.gradient_tolerance;
176 return;
177 }
178
Sameer Agarwalfa015192012-06-11 14:21:42 -0700179 iteration_summary.iteration_time_in_seconds =
Petter Strandmark76533b32012-09-04 22:08:50 -0700180 WallTimeInSeconds() - iteration_start_time;
181 iteration_summary.cumulative_time_in_seconds =
182 WallTimeInSeconds() - start_time
183 + summary->preprocessor_time_in_seconds;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700184 summary->iterations.push_back(iteration_summary);
Sameer Agarwalfa015192012-06-11 14:21:42 -0700185
Sameer Agarwalc3c3dd82013-04-25 07:49:24 -0700186 if (options_.jacobi_scaling) {
187 EstimateScale(*jacobian, scale.data());
188 jacobian->ScaleColumns(scale.data());
189 } else {
190 scale.setOnes();
191 }
192
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800193 int num_consecutive_invalid_steps = 0;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700194 while (true) {
Sameer Agarwal9883fc32012-11-30 12:32:43 -0800195 if (!RunCallbacks(options.callbacks, iteration_summary, summary)) {
196 return;
197 }
198
Petter Strandmark76533b32012-09-04 22:08:50 -0700199 iteration_start_time = WallTimeInSeconds();
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700200 if (iteration_summary.iteration >= options_.max_num_iterations) {
201 summary->termination_type = NO_CONVERGENCE;
202 VLOG(1) << "Terminating: Maximum number of iterations reached.";
203 break;
204 }
205
Sameer Agarwalfa015192012-06-11 14:21:42 -0700206 const double total_solver_time = iteration_start_time - start_time +
207 summary->preprocessor_time_in_seconds;
208 if (total_solver_time >= options_.max_solver_time_in_seconds) {
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700209 summary->termination_type = NO_CONVERGENCE;
210 VLOG(1) << "Terminating: Maximum solver time reached.";
211 break;
212 }
213
214 iteration_summary = IterationSummary();
215 iteration_summary = summary->iterations.back();
216 iteration_summary.iteration = summary->iterations.back().iteration + 1;
217 iteration_summary.step_is_valid = false;
218 iteration_summary.step_is_successful = false;
219
Petter Strandmark76533b32012-09-04 22:08:50 -0700220 const double strategy_start_time = WallTimeInSeconds();
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700221 TrustRegionStrategy::PerSolveOptions per_solve_options;
222 per_solve_options.eta = options_.eta;
Sameer Agarwal05292bf2012-08-20 07:40:45 -0700223 TrustRegionStrategy::Summary strategy_summary =
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700224 strategy->ComputeStep(per_solve_options,
225 jacobian,
226 residuals.data(),
227 trust_region_step.data());
228
Sameer Agarwalfa015192012-06-11 14:21:42 -0700229 iteration_summary.step_solver_time_in_seconds =
Petter Strandmark76533b32012-09-04 22:08:50 -0700230 WallTimeInSeconds() - strategy_start_time;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700231 iteration_summary.linear_solver_iterations =
232 strategy_summary.num_iterations;
233
234 if (!MaybeDumpLinearLeastSquaresProblem(iteration_summary.iteration,
235 jacobian,
236 residuals.data(),
237 trust_region_step.data())) {
238 LOG(FATAL) << "Tried writing linear least squares problem: "
239 << options.lsqp_dump_directory << "but failed.";
240 }
241
Sameer Agarwalb329e582012-09-05 10:45:17 -0700242 double model_cost_change = 0.0;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700243 if (strategy_summary.termination_type != FAILURE) {
Sameer Agarwalb329e582012-09-05 10:45:17 -0700244 // new_model_cost
245 // = 1/2 [f + J * step]^2
246 // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ]
247 // model_cost_change
248 // = cost - new_model_cost
249 // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step]
250 // = -f'J * step - step' * J' * J * step / 2
251 model_residuals.setZero();
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700252 jacobian->RightMultiply(trust_region_step.data(), model_residuals.data());
Sameer Agarwalb329e582012-09-05 10:45:17 -0700253 model_cost_change = -(residuals.dot(model_residuals) +
254 model_residuals.squaredNorm() / 2.0);
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700255
Sameer Agarwalb329e582012-09-05 10:45:17 -0700256 if (model_cost_change < 0.0) {
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700257 VLOG(1) << "Invalid step: current_cost: " << cost
Sameer Agarwalb329e582012-09-05 10:45:17 -0700258 << " absolute difference " << model_cost_change
259 << " relative difference " << (model_cost_change / cost);
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700260 } else {
261 iteration_summary.step_is_valid = true;
262 }
263 }
264
265 if (!iteration_summary.step_is_valid) {
266 // Invalid steps can happen due to a number of reasons, and we
267 // allow a limited number of successive failures, and return with
268 // NUMERICAL_FAILURE if this limit is exceeded.
269 if (++num_consecutive_invalid_steps >=
270 options_.max_num_consecutive_invalid_steps) {
271 summary->termination_type = NUMERICAL_FAILURE;
Sameer Agarwal9123e2f2012-09-18 21:49:06 -0700272 summary->error = StringPrintf(
273 "Terminating. Number of successive invalid steps more "
274 "than Solver::Options::max_num_consecutive_invalid_steps: %d",
275 options_.max_num_consecutive_invalid_steps);
276
277 LOG(WARNING) << summary->error;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700278 return;
279 }
280
281 // We are going to try and reduce the trust region radius and
282 // solve again. To do this, we are going to treat this iteration
283 // as an unsuccessful iteration. Since the various callbacks are
284 // still executed, we are going to fill the iteration summary
285 // with data that assumes a step of length zero and no progress.
Sameer Agarwal9123e2f2012-09-18 21:49:06 -0700286 iteration_summary.cost = cost + summary->fixed_cost;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700287 iteration_summary.cost_change = 0.0;
288 iteration_summary.gradient_max_norm =
289 summary->iterations.back().gradient_max_norm;
290 iteration_summary.step_norm = 0.0;
291 iteration_summary.relative_decrease = 0.0;
292 iteration_summary.eta = options_.eta;
293 } else {
294 // The step is numerically valid, so now we can judge its quality.
295 num_consecutive_invalid_steps = 0;
296
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700297 // Undo the Jacobian column scaling.
Markus Moll47d26bc2012-08-16 00:23:38 +0200298 delta = (trust_region_step.array() * scale.array()).matrix();
Sameer Agarwal9123e2f2012-09-18 21:49:06 -0700299 if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
300 summary->termination_type = NUMERICAL_FAILURE;
301 summary->error =
302 "Terminating. Failed to compute Plus(x, delta, x_plus_delta).";
303
304 LOG(WARNING) << summary->error;
305 return;
306 }
307
308 // Try this step.
309 double new_cost = numeric_limits<double>::max();
310 if (!evaluator->Evaluate(x_plus_delta.data(),
311 &new_cost,
312 NULL, NULL, NULL)) {
313 // If the evaluation of the new cost fails, treat it as a step
314 // with high cost.
315 LOG(WARNING) << "Step failed to evaluate. "
316 << "Treating it as step with infinite cost";
317 new_cost = numeric_limits<double>::max();
Sameer Agarwalba8d9672012-10-02 00:48:57 -0700318 } else {
319 // Check if performing an inner iteration will make it better.
320 if (options.inner_iteration_minimizer != NULL) {
321 const double x_plus_delta_cost = new_cost;
322 Vector inner_iteration_x = x_plus_delta;
323 Solver::Summary inner_iteration_summary;
324 options.inner_iteration_minimizer->Minimize(options,
325 inner_iteration_x.data(),
326 &inner_iteration_summary);
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800327 if (!evaluator->Evaluate(inner_iteration_x.data(),
328 &new_cost,
329 NULL, NULL, NULL)) {
Sameer Agarwalba8d9672012-10-02 00:48:57 -0700330 VLOG(2) << "Inner iteration failed.";
331 new_cost = x_plus_delta_cost;
332 } else {
333 x_plus_delta = inner_iteration_x;
Sameer Agarwal9883fc32012-11-30 12:32:43 -0800334 // Boost the model_cost_change, since the inner iteration
Sameer Agarwalba8d9672012-10-02 00:48:57 -0700335 // improvements are not accounted for by the trust region.
336 model_cost_change += x_plus_delta_cost - new_cost;
337 VLOG(2) << "Inner iteration succeeded; current cost: " << cost
338 << " x_plus_delta_cost: " << x_plus_delta_cost
339 << " new_cost: " << new_cost;
340 }
341 }
Sameer Agarwal9123e2f2012-09-18 21:49:06 -0700342 }
343
344 iteration_summary.step_norm = (x - x_plus_delta).norm();
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700345
346 // Convergence based on parameter_tolerance.
347 const double step_size_tolerance = options_.parameter_tolerance *
348 (x_norm + options_.parameter_tolerance);
349 if (iteration_summary.step_norm <= step_size_tolerance) {
350 VLOG(1) << "Terminating. Parameter tolerance reached. "
351 << "relative step_norm: "
352 << iteration_summary.step_norm /
353 (x_norm + options_.parameter_tolerance)
354 << " <= " << options_.parameter_tolerance;
355 summary->termination_type = PARAMETER_TOLERANCE;
356 return;
357 }
358
Sameer Agarwald28b3c82012-06-05 21:50:31 -0700359 VLOG(2) << "old cost: " << cost << " new cost: " << new_cost;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700360 iteration_summary.cost_change = cost - new_cost;
361 const double absolute_function_tolerance =
362 options_.function_tolerance * cost;
363 if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
364 VLOG(1) << "Terminating. Function tolerance reached. "
Sameer Agarwalfa015192012-06-11 14:21:42 -0700365 << "|cost_change|/cost: "
366 << fabs(iteration_summary.cost_change) / cost
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700367 << " <= " << options_.function_tolerance;
368 summary->termination_type = FUNCTION_TOLERANCE;
369 return;
370 }
371
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700372 const double relative_decrease =
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700373 iteration_summary.cost_change / model_cost_change;
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700374
375 const double historical_relative_decrease =
376 (reference_cost - new_cost) /
377 (accumulated_reference_model_cost_change + model_cost_change);
378
379 // If monotonic steps are being used, then the relative_decrease
380 // is the usual ratio of the change in objective function value
381 // divided by the change in model cost.
382 //
383 // If non-monotonic steps are allowed, then we take the maximum
384 // of the relative_decrease and the
385 // historical_relative_decrease, which measures the increase
386 // from a reference iteration. The model cost change is
387 // estimated by accumulating the model cost changes since the
388 // reference iteration. The historical relative_decrease offers
389 // a boost to a step which is not too bad compared to the
390 // reference iteration, allowing for non-monotonic steps.
391 iteration_summary.relative_decrease =
392 options.use_nonmonotonic_steps
393 ? max(relative_decrease, historical_relative_decrease)
394 : relative_decrease;
395
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700396 iteration_summary.step_is_successful =
397 iteration_summary.relative_decrease > options_.min_relative_decrease;
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700398
399 if (iteration_summary.step_is_successful) {
400 accumulated_candidate_model_cost_change += model_cost_change;
401 accumulated_reference_model_cost_change += model_cost_change;
402 if (relative_decrease <= options_.min_relative_decrease) {
Sameer Agarwalb23fd4e2012-09-25 09:04:41 -0700403 iteration_summary.step_is_nonmonotonic = true;
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700404 VLOG(2) << "Non-monotonic step! "
405 << " relative_decrease: " << relative_decrease
406 << " historical_relative_decrease: "
407 << historical_relative_decrease;
408 }
409 }
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700410 }
411
412 if (iteration_summary.step_is_successful) {
413 ++summary->num_successful_steps;
414 strategy->StepAccepted(iteration_summary.relative_decrease);
415 x = x_plus_delta;
416 x_norm = x.norm();
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700417
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700418 // Step looks good, evaluate the residuals and Jacobian at this
419 // point.
Keir Mierlef44907f2012-07-06 13:52:32 -0700420 if (!evaluator->Evaluate(x.data(),
421 &cost,
422 residuals.data(),
Sameer Agarwalc3c3dd82013-04-25 07:49:24 -0700423 gradient.data(),
Keir Mierlef44907f2012-07-06 13:52:32 -0700424 jacobian)) {
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700425 summary->termination_type = NUMERICAL_FAILURE;
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800426 summary->error =
427 "Terminating: Residual and Jacobian evaluation failed.";
Sameer Agarwal9123e2f2012-09-18 21:49:06 -0700428 LOG(WARNING) << summary->error;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700429 return;
430 }
431
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700432 iteration_summary.gradient_max_norm = gradient.lpNorm<Eigen::Infinity>();
433
434 if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
435 summary->termination_type = GRADIENT_TOLERANCE;
436 VLOG(1) << "Terminating: Gradient tolerance reached."
437 << "Relative gradient max norm: "
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800438 << (iteration_summary.gradient_max_norm /
439 initial_gradient_max_norm)
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700440 << " <= " << options_.gradient_tolerance;
441 return;
442 }
443
444 if (options_.jacobi_scaling) {
445 jacobian->ScaleColumns(scale.data());
446 }
Sameer Agarwala8f87d72012-08-08 10:38:31 -0700447
448 // Update the best, reference and candidate iterates.
449 //
450 // Based on algorithm 10.1.2 (page 357) of "Trust Region
451 // Methods" by Conn Gould & Toint, or equations 33-40 of
452 // "Non-monotone trust-region algorithms for nonlinear
453 // optimization subject to convex constraints" by Phil Toint,
454 // Mathematical Programming, 77, 1997.
455 if (cost < minimum_cost) {
456 // A step that improves solution quality was found.
457 x_min = x;
458 minimum_cost = cost;
459 // Set the candidate iterate to the current point.
460 candidate_cost = cost;
461 num_consecutive_nonmonotonic_steps = 0;
462 accumulated_candidate_model_cost_change = 0.0;
463 } else {
464 ++num_consecutive_nonmonotonic_steps;
465 if (cost > candidate_cost) {
466 // The current iterate is has a higher cost than the
467 // candidate iterate. Set the candidate to this point.
468 VLOG(2) << "Updating the candidate iterate to the current point.";
469 candidate_cost = cost;
470 accumulated_candidate_model_cost_change = 0.0;
471 }
472
473 // At this point we have made too many non-monotonic steps and
474 // we are going to reset the value of the reference iterate so
475 // as to force the algorithm to descend.
476 //
477 // This is the case because the candidate iterate has a value
478 // greater than minimum_cost but smaller than the reference
479 // iterate.
480 if (num_consecutive_nonmonotonic_steps ==
481 options.max_consecutive_nonmonotonic_steps) {
482 VLOG(2) << "Resetting the reference point to the candidate point";
483 reference_cost = candidate_cost;
484 accumulated_reference_model_cost_change =
485 accumulated_candidate_model_cost_change;
486 }
487 }
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700488 } else {
489 ++summary->num_unsuccessful_steps;
Sameer Agarwalfa015192012-06-11 14:21:42 -0700490 if (iteration_summary.step_is_valid) {
491 strategy->StepRejected(iteration_summary.relative_decrease);
492 } else {
493 strategy->StepIsInvalid();
494 }
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700495 }
496
497 iteration_summary.cost = cost + summary->fixed_cost;
498 iteration_summary.trust_region_radius = strategy->Radius();
499 if (iteration_summary.trust_region_radius <
500 options_.min_trust_region_radius) {
501 summary->termination_type = PARAMETER_TOLERANCE;
502 VLOG(1) << "Termination. Minimum trust region radius reached.";
503 return;
504 }
505
Sameer Agarwalfa015192012-06-11 14:21:42 -0700506 iteration_summary.iteration_time_in_seconds =
Petter Strandmark76533b32012-09-04 22:08:50 -0700507 WallTimeInSeconds() - iteration_start_time;
508 iteration_summary.cumulative_time_in_seconds =
509 WallTimeInSeconds() - start_time
510 + summary->preprocessor_time_in_seconds;
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700511 summary->iterations.push_back(iteration_summary);
Sameer Agarwalaa9a83c2012-05-29 17:40:17 -0700512 }
513}
514
515
516} // namespace internal
517} // namespace ceres