blob: da87de19f2cf9f1a5a6aabd751d649b999ad6f5e [file] [log] [blame]
Keir Mierle8ebb0732012-04-30 23:09:08 -07001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2010, 2011, 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: keir@google.com (Keir Mierle)
30// sameeragarwal@google.com (Sameer Agarwal)
31
32#include "ceres/solver.h"
33
34#include <vector>
Keir Mierle6196cba2012-06-18 11:03:40 -070035#include "ceres/problem.h"
36#include "ceres/problem_impl.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070037#include "ceres/program.h"
38#include "ceres/solver_impl.h"
39#include "ceres/stringprintf.h"
Petter Strandmark76533b32012-09-04 22:08:50 -070040#include "ceres/wall_time.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070041
42namespace ceres {
Sameer Agarwal977be7c2013-01-26 16:01:54 -080043namespace {
44
45void StringifyOrdering(const vector<int>& ordering, string* report) {
46 if (ordering.size() == 0) {
47 internal::StringAppendF(report, "AUTOMATIC");
48 return;
49 }
50
51 for (int i = 0; i < ordering.size() - 1; ++i) {
52 internal::StringAppendF(report, "%d, ", ordering[i]);
53 }
54 internal::StringAppendF(report, "%d", ordering.back());
55}
56
57} // namespace
Keir Mierle8ebb0732012-04-30 23:09:08 -070058
Sameer Agarwalba8d9672012-10-02 00:48:57 -070059Solver::Options::~Options() {
Sameer Agarwal68b32a92012-10-06 23:10:51 -070060 delete linear_solver_ordering;
Sameer Agarwalba8d9672012-10-02 00:48:57 -070061 delete inner_iteration_ordering;
62}
63
Keir Mierle8ebb0732012-04-30 23:09:08 -070064Solver::~Solver() {}
65
Keir Mierle8ebb0732012-04-30 23:09:08 -070066void Solver::Solve(const Solver::Options& options,
67 Problem* problem,
68 Solver::Summary* summary) {
Petter Strandmark76533b32012-09-04 22:08:50 -070069 double start_time_seconds = internal::WallTimeInSeconds();
Keir Mierle6196cba2012-06-18 11:03:40 -070070 internal::ProblemImpl* problem_impl =
71 CHECK_NOTNULL(problem)->problem_impl_.get();
72 internal::SolverImpl::Solve(options, problem_impl, summary);
Petter Strandmark76533b32012-09-04 22:08:50 -070073 summary->total_time_in_seconds =
74 internal::WallTimeInSeconds() - start_time_seconds;
Keir Mierle8ebb0732012-04-30 23:09:08 -070075}
76
77void Solve(const Solver::Options& options,
78 Problem* problem,
79 Solver::Summary* summary) {
Keir Mierle6196cba2012-06-18 11:03:40 -070080 Solver solver;
81 solver.Solve(options, problem, summary);
Keir Mierle8ebb0732012-04-30 23:09:08 -070082}
83
84Solver::Summary::Summary()
85 // Invalid values for most fields, to ensure that we are not
86 // accidentally reporting default values.
Sameer Agarwald010de52013-02-15 14:26:56 -080087 : minimizer_type(TRUST_REGION),
Sameer Agarwaldcee1202013-12-07 21:48:56 -080088 termination_type(FAILURE),
89 message("ceres::Solve was not called."),
Keir Mierle8ebb0732012-04-30 23:09:08 -070090 initial_cost(-1.0),
91 final_cost(-1.0),
92 fixed_cost(-1.0),
93 num_successful_steps(-1),
94 num_unsuccessful_steps(-1),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -070095 num_inner_iteration_steps(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -070096 preprocessor_time_in_seconds(-1.0),
97 minimizer_time_in_seconds(-1.0),
Sameer Agarwalfa015192012-06-11 14:21:42 -070098 postprocessor_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070099 total_time_in_seconds(-1.0),
Sameer Agarwal42a84b82013-02-01 12:22:53 -0800100 linear_solver_time_in_seconds(-1.0),
101 residual_evaluation_time_in_seconds(-1.0),
102 jacobian_evaluation_time_in_seconds(-1.0),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700103 inner_iteration_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700104 num_parameter_blocks(-1),
105 num_parameters(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800106 num_effective_parameters(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700107 num_residual_blocks(-1),
108 num_residuals(-1),
109 num_parameter_blocks_reduced(-1),
110 num_parameters_reduced(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800111 num_effective_parameters_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700112 num_residual_blocks_reduced(-1),
113 num_residuals_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700114 num_threads_given(-1),
115 num_threads_used(-1),
116 num_linear_solver_threads_given(-1),
117 num_linear_solver_threads_used(-1),
118 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
119 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700120 inner_iterations_given(false),
121 inner_iterations_used(false),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700122 preconditioner_type(IDENTITY),
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700123 visibility_clustering_type(CANONICAL_VIEWS),
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700124 trust_region_strategy_type(LEVENBERG_MARQUARDT),
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700125 dense_linear_algebra_library_type(EIGEN),
126 sparse_linear_algebra_library_type(SUITE_SPARSE),
Sameer Agarwald010de52013-02-15 14:26:56 -0800127 line_search_direction_type(LBFGS),
Alex Stewart7124c342013-11-07 16:10:02 +0000128 line_search_type(ARMIJO),
129 line_search_interpolation_type(BISECTION),
130 nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
131 max_lbfgs_rank(-1) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700132}
133
Sameer Agarwald010de52013-02-15 14:26:56 -0800134using internal::StringAppendF;
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700135using internal::StringPrintf;
Sameer Agarwald010de52013-02-15 14:26:56 -0800136
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800137string Solver::Summary::BriefReport() const {
138 return StringPrintf("Ceres Solver Report: "
139 "Iterations: %d, "
140 "Initial cost: %e, "
141 "Final cost: %e, "
142 "Termination: %s",
143 num_successful_steps + num_unsuccessful_steps,
144 initial_cost,
145 final_cost,
146 TerminationTypeToString(termination_type));
147};
148
Keir Mierle8ebb0732012-04-30 23:09:08 -0700149string Solver::Summary::FullReport() const {
150 string report =
151 "\n"
152 "Ceres Solver Report\n"
153 "-------------------\n";
154
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800155 StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
156 StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
157 num_parameter_blocks, num_parameter_blocks_reduced);
158 StringAppendF(&report, "Parameters % 25d% 25d\n",
159 num_parameters, num_parameters_reduced);
160 if (num_effective_parameters_reduced != num_parameters_reduced) {
161 StringAppendF(&report, "Effective parameters% 25d% 25d\n",
162 num_effective_parameters, num_effective_parameters_reduced);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700163 }
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800164 StringAppendF(&report, "Residual blocks % 25d% 25d\n",
165 num_residual_blocks, num_residual_blocks_reduced);
166 StringAppendF(&report, "Residual % 25d% 25d\n",
167 num_residuals, num_residuals_reduced);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700168
Sameer Agarwald010de52013-02-15 14:26:56 -0800169 if (minimizer_type == TRUST_REGION) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700170 // TRUST_SEARCH HEADER
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800171 StringAppendF(&report, "\nMinimizer %19s\n",
172 "TRUST_REGION");
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700173
174 if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
175 linear_solver_type_used == DENSE_SCHUR ||
176 linear_solver_type_used == DENSE_QR) {
177 StringAppendF(&report, "\nDense linear algebra library %15s\n",
178 DenseLinearAlgebraLibraryTypeToString(
179 dense_linear_algebra_library_type));
180 }
181
Sameer Agarwald010de52013-02-15 14:26:56 -0800182 if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
183 linear_solver_type_used == SPARSE_SCHUR ||
184 (linear_solver_type_used == ITERATIVE_SCHUR &&
Sameer Agarwal290b9752013-02-17 16:50:37 -0800185 (preconditioner_type == CLUSTER_JACOBI ||
Sameer Agarwald010de52013-02-15 14:26:56 -0800186 preconditioner_type == CLUSTER_TRIDIAGONAL))) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700187 StringAppendF(&report, "\nSparse linear algebra library %15s\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800188 SparseLinearAlgebraLibraryTypeToString(
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700189 sparse_linear_algebra_library_type));
Sameer Agarwal1e289202012-08-21 18:00:54 -0700190 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800191
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700192 StringAppendF(&report, "Trust region strategy %19s",
Sameer Agarwald010de52013-02-15 14:26:56 -0800193 TrustRegionStrategyTypeToString(
194 trust_region_strategy_type));
195 if (trust_region_strategy_type == DOGLEG) {
196 if (dogleg_type == TRADITIONAL_DOGLEG) {
197 StringAppendF(&report, " (TRADITIONAL)");
198 } else {
199 StringAppendF(&report, " (SUBSPACE)");
200 }
201 }
202 StringAppendF(&report, "\n");
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800203 StringAppendF(&report, "\n");
Sameer Agarwal1e289202012-08-21 18:00:54 -0700204
Sameer Agarwal931c3092013-02-25 09:46:21 -0800205 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwald010de52013-02-15 14:26:56 -0800206 StringAppendF(&report, "Linear solver %25s%25s\n",
207 LinearSolverTypeToString(linear_solver_type_given),
208 LinearSolverTypeToString(linear_solver_type_used));
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800209
Sameer Agarwald010de52013-02-15 14:26:56 -0800210 if (linear_solver_type_given == CGNR ||
211 linear_solver_type_given == ITERATIVE_SCHUR) {
212 StringAppendF(&report, "Preconditioner %25s%25s\n",
213 PreconditionerTypeToString(preconditioner_type),
214 PreconditionerTypeToString(preconditioner_type));
Sameer Agarwald010de52013-02-15 14:26:56 -0800215 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800216
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700217 if (preconditioner_type == CLUSTER_JACOBI ||
218 preconditioner_type == CLUSTER_TRIDIAGONAL) {
219 StringAppendF(&report, "Visibility clustering%24s%25s\n",
Sameer Agarwal9ba0b352013-11-05 13:04:56 -0800220 VisibilityClusteringTypeToString(
221 visibility_clustering_type),
222 VisibilityClusteringTypeToString(
223 visibility_clustering_type));
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700224 }
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700225 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800226 num_threads_given, num_threads_used);
227 StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
228 num_linear_solver_threads_given,
229 num_linear_solver_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800230
Sameer Agarwald010de52013-02-15 14:26:56 -0800231 if (IsSchurType(linear_solver_type_used)) {
232 string given;
233 StringifyOrdering(linear_solver_ordering_given, &given);
234 string used;
235 StringifyOrdering(linear_solver_ordering_used, &used);
236 StringAppendF(&report,
237 "Linear solver ordering %22s %24s\n",
238 given.c_str(),
239 used.c_str());
240 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800241
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700242 if (inner_iterations_given) {
243 StringAppendF(&report,
244 "Use inner iterations %20s %20s\n",
245 inner_iterations_given ? "True" : "False",
246 inner_iterations_used ? "True" : "False");
247 }
248
249 if (inner_iterations_used) {
Sameer Agarwald010de52013-02-15 14:26:56 -0800250 string given;
251 StringifyOrdering(inner_iteration_ordering_given, &given);
252 string used;
253 StringifyOrdering(inner_iteration_ordering_used, &used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800254 StringAppendF(&report,
255 "Inner iteration ordering %20s %24s\n",
256 given.c_str(),
257 used.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800258 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800259 } else {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700260 // LINE_SEARCH HEADER
Sameer Agarwald010de52013-02-15 14:26:56 -0800261 StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
Sameer Agarwald010de52013-02-15 14:26:56 -0800262
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700263
264 string line_search_direction_string;
265 if (line_search_direction_type == LBFGS) {
266 line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
267 } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
268 line_search_direction_string =
269 NonlinearConjugateGradientTypeToString(
270 nonlinear_conjugate_gradient_type);
271 } else {
272 line_search_direction_string =
273 LineSearchDirectionTypeToString(line_search_direction_type);
274 }
275
276 StringAppendF(&report, "Line search direction %19s\n",
277 line_search_direction_string.c_str());
278
279 const string line_search_type_string =
280 StringPrintf("%s %s",
Sameer Agarwal7a8f7972013-07-03 09:03:55 -0700281 LineSearchInterpolationTypeToString(
282 line_search_interpolation_type),
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700283 LineSearchTypeToString(line_search_type));
284 StringAppendF(&report, "Line search type %19s\n",
285 line_search_type_string.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800286 StringAppendF(&report, "\n");
287
Sameer Agarwalbeb45052013-02-22 13:37:01 -0800288 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700289 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800290 num_threads_given, num_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800291 }
Keir Mierle8ebb0732012-04-30 23:09:08 -0700292
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700293 StringAppendF(&report, "\nCost:\n");
294 StringAppendF(&report, "Initial % 30e\n", initial_cost);
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800295 if (termination_type != FAILURE &&
296 termination_type != USER_FAILURE) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700297 StringAppendF(&report, "Final % 30e\n", final_cost);
298 StringAppendF(&report, "Change % 30e\n",
299 initial_cost - final_cost);
300 }
301
302 StringAppendF(&report, "\nMinimizer iterations % 16d\n",
303 num_successful_steps + num_unsuccessful_steps);
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700304
305 // Successful/Unsuccessful steps only matter in the case of the
306 // trust region solver. Line search terminates when it encounters
307 // the first unsuccessful step.
308 if (minimizer_type == TRUST_REGION) {
309 StringAppendF(&report, "Successful steps % 14d\n",
310 num_successful_steps);
311 StringAppendF(&report, "Unsuccessful steps % 14d\n",
312 num_unsuccessful_steps);
313 }
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700314 if (inner_iterations_used) {
315 StringAppendF(&report, "Steps with inner iterations % 14d\n",
316 num_inner_iteration_steps);
317 }
318
319 StringAppendF(&report, "\nTime (in seconds):\n");
320 StringAppendF(&report, "Preprocessor %25.3f\n",
321 preprocessor_time_in_seconds);
322
323 StringAppendF(&report, "\n Residual evaluation %23.3f\n",
324 residual_evaluation_time_in_seconds);
325 StringAppendF(&report, " Jacobian evaluation %23.3f\n",
326 jacobian_evaluation_time_in_seconds);
327
328 if (minimizer_type == TRUST_REGION) {
329 StringAppendF(&report, " Linear solver %23.3f\n",
330 linear_solver_time_in_seconds);
331 }
332
333 if (inner_iterations_used) {
334 StringAppendF(&report, " Inner iterations %23.3f\n",
335 inner_iteration_time_in_seconds);
336 }
337
338 StringAppendF(&report, "Minimizer %25.3f\n\n",
339 minimizer_time_in_seconds);
340
341 StringAppendF(&report, "Postprocessor %24.3f\n",
342 postprocessor_time_in_seconds);
343
344 StringAppendF(&report, "Total %25.3f\n\n",
345 total_time_in_seconds);
346
347 StringAppendF(&report, "Termination: %25s\n",
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800348 TerminationTypeToString(termination_type));
Keir Mierle8ebb0732012-04-30 23:09:08 -0700349 return report;
350};
351
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800352bool Solver::Summary::IsSolutionUsable() const {
353 return (termination_type == CONVERGENCE ||
354 termination_type == NO_CONVERGENCE ||
355 termination_type == USER_SUCCESS);
356}
357
Keir Mierle8ebb0732012-04-30 23:09:08 -0700358} // namespace ceres