blob: 53a9b4b7220d3633c3417fd7a72ed74b08b9c5b3 [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
59Solver::~Solver() {}
60
Keir Mierle8ebb0732012-04-30 23:09:08 -070061void Solver::Solve(const Solver::Options& options,
62 Problem* problem,
63 Solver::Summary* summary) {
Petter Strandmark76533b32012-09-04 22:08:50 -070064 double start_time_seconds = internal::WallTimeInSeconds();
Keir Mierle6196cba2012-06-18 11:03:40 -070065 internal::ProblemImpl* problem_impl =
66 CHECK_NOTNULL(problem)->problem_impl_.get();
67 internal::SolverImpl::Solve(options, problem_impl, summary);
Petter Strandmark76533b32012-09-04 22:08:50 -070068 summary->total_time_in_seconds =
69 internal::WallTimeInSeconds() - start_time_seconds;
Keir Mierle8ebb0732012-04-30 23:09:08 -070070}
71
72void Solve(const Solver::Options& options,
73 Problem* problem,
74 Solver::Summary* summary) {
Keir Mierle6196cba2012-06-18 11:03:40 -070075 Solver solver;
76 solver.Solve(options, problem, summary);
Keir Mierle8ebb0732012-04-30 23:09:08 -070077}
78
79Solver::Summary::Summary()
80 // Invalid values for most fields, to ensure that we are not
81 // accidentally reporting default values.
Sameer Agarwald010de52013-02-15 14:26:56 -080082 : minimizer_type(TRUST_REGION),
Sameer Agarwaldcee1202013-12-07 21:48:56 -080083 termination_type(FAILURE),
84 message("ceres::Solve was not called."),
Keir Mierle8ebb0732012-04-30 23:09:08 -070085 initial_cost(-1.0),
86 final_cost(-1.0),
87 fixed_cost(-1.0),
88 num_successful_steps(-1),
89 num_unsuccessful_steps(-1),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -070090 num_inner_iteration_steps(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -070091 preprocessor_time_in_seconds(-1.0),
92 minimizer_time_in_seconds(-1.0),
Sameer Agarwalfa015192012-06-11 14:21:42 -070093 postprocessor_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070094 total_time_in_seconds(-1.0),
Sameer Agarwal42a84b82013-02-01 12:22:53 -080095 linear_solver_time_in_seconds(-1.0),
96 residual_evaluation_time_in_seconds(-1.0),
97 jacobian_evaluation_time_in_seconds(-1.0),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -070098 inner_iteration_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070099 num_parameter_blocks(-1),
100 num_parameters(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800101 num_effective_parameters(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700102 num_residual_blocks(-1),
103 num_residuals(-1),
104 num_parameter_blocks_reduced(-1),
105 num_parameters_reduced(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800106 num_effective_parameters_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700107 num_residual_blocks_reduced(-1),
108 num_residuals_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700109 num_threads_given(-1),
110 num_threads_used(-1),
111 num_linear_solver_threads_given(-1),
112 num_linear_solver_threads_used(-1),
113 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
114 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700115 inner_iterations_given(false),
116 inner_iterations_used(false),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700117 preconditioner_type(IDENTITY),
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700118 visibility_clustering_type(CANONICAL_VIEWS),
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700119 trust_region_strategy_type(LEVENBERG_MARQUARDT),
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700120 dense_linear_algebra_library_type(EIGEN),
121 sparse_linear_algebra_library_type(SUITE_SPARSE),
Sameer Agarwald010de52013-02-15 14:26:56 -0800122 line_search_direction_type(LBFGS),
Alex Stewart7124c342013-11-07 16:10:02 +0000123 line_search_type(ARMIJO),
124 line_search_interpolation_type(BISECTION),
125 nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
126 max_lbfgs_rank(-1) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700127}
128
Sameer Agarwald010de52013-02-15 14:26:56 -0800129using internal::StringAppendF;
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700130using internal::StringPrintf;
Sameer Agarwald010de52013-02-15 14:26:56 -0800131
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800132string Solver::Summary::BriefReport() const {
133 return StringPrintf("Ceres Solver Report: "
134 "Iterations: %d, "
135 "Initial cost: %e, "
136 "Final cost: %e, "
137 "Termination: %s",
138 num_successful_steps + num_unsuccessful_steps,
139 initial_cost,
140 final_cost,
141 TerminationTypeToString(termination_type));
142};
143
Keir Mierle8ebb0732012-04-30 23:09:08 -0700144string Solver::Summary::FullReport() const {
145 string report =
146 "\n"
147 "Ceres Solver Report\n"
148 "-------------------\n";
149
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800150 StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
151 StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
152 num_parameter_blocks, num_parameter_blocks_reduced);
153 StringAppendF(&report, "Parameters % 25d% 25d\n",
154 num_parameters, num_parameters_reduced);
155 if (num_effective_parameters_reduced != num_parameters_reduced) {
156 StringAppendF(&report, "Effective parameters% 25d% 25d\n",
157 num_effective_parameters, num_effective_parameters_reduced);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700158 }
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800159 StringAppendF(&report, "Residual blocks % 25d% 25d\n",
160 num_residual_blocks, num_residual_blocks_reduced);
161 StringAppendF(&report, "Residual % 25d% 25d\n",
162 num_residuals, num_residuals_reduced);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700163
Sameer Agarwald010de52013-02-15 14:26:56 -0800164 if (minimizer_type == TRUST_REGION) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700165 // TRUST_SEARCH HEADER
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800166 StringAppendF(&report, "\nMinimizer %19s\n",
167 "TRUST_REGION");
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700168
169 if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
170 linear_solver_type_used == DENSE_SCHUR ||
171 linear_solver_type_used == DENSE_QR) {
172 StringAppendF(&report, "\nDense linear algebra library %15s\n",
173 DenseLinearAlgebraLibraryTypeToString(
174 dense_linear_algebra_library_type));
175 }
176
Sameer Agarwald010de52013-02-15 14:26:56 -0800177 if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
178 linear_solver_type_used == SPARSE_SCHUR ||
179 (linear_solver_type_used == ITERATIVE_SCHUR &&
Sameer Agarwal290b9752013-02-17 16:50:37 -0800180 (preconditioner_type == CLUSTER_JACOBI ||
Sameer Agarwald010de52013-02-15 14:26:56 -0800181 preconditioner_type == CLUSTER_TRIDIAGONAL))) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700182 StringAppendF(&report, "\nSparse linear algebra library %15s\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800183 SparseLinearAlgebraLibraryTypeToString(
Sameer Agarwal367b65e2013-08-09 10:35:37 -0700184 sparse_linear_algebra_library_type));
Sameer Agarwal1e289202012-08-21 18:00:54 -0700185 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800186
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700187 StringAppendF(&report, "Trust region strategy %19s",
Sameer Agarwald010de52013-02-15 14:26:56 -0800188 TrustRegionStrategyTypeToString(
189 trust_region_strategy_type));
190 if (trust_region_strategy_type == DOGLEG) {
191 if (dogleg_type == TRADITIONAL_DOGLEG) {
192 StringAppendF(&report, " (TRADITIONAL)");
193 } else {
194 StringAppendF(&report, " (SUBSPACE)");
195 }
196 }
197 StringAppendF(&report, "\n");
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800198 StringAppendF(&report, "\n");
Sameer Agarwal1e289202012-08-21 18:00:54 -0700199
Sameer Agarwal931c3092013-02-25 09:46:21 -0800200 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwald010de52013-02-15 14:26:56 -0800201 StringAppendF(&report, "Linear solver %25s%25s\n",
202 LinearSolverTypeToString(linear_solver_type_given),
203 LinearSolverTypeToString(linear_solver_type_used));
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800204
Sameer Agarwald010de52013-02-15 14:26:56 -0800205 if (linear_solver_type_given == CGNR ||
206 linear_solver_type_given == ITERATIVE_SCHUR) {
207 StringAppendF(&report, "Preconditioner %25s%25s\n",
208 PreconditionerTypeToString(preconditioner_type),
209 PreconditionerTypeToString(preconditioner_type));
Sameer Agarwald010de52013-02-15 14:26:56 -0800210 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800211
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700212 if (preconditioner_type == CLUSTER_JACOBI ||
213 preconditioner_type == CLUSTER_TRIDIAGONAL) {
214 StringAppendF(&report, "Visibility clustering%24s%25s\n",
Sameer Agarwal9ba0b352013-11-05 13:04:56 -0800215 VisibilityClusteringTypeToString(
216 visibility_clustering_type),
217 VisibilityClusteringTypeToString(
218 visibility_clustering_type));
Sameer Agarwalf06b9fa2013-10-27 21:38:13 -0700219 }
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700220 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800221 num_threads_given, num_threads_used);
222 StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
223 num_linear_solver_threads_given,
224 num_linear_solver_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800225
Sameer Agarwald010de52013-02-15 14:26:56 -0800226 if (IsSchurType(linear_solver_type_used)) {
227 string given;
228 StringifyOrdering(linear_solver_ordering_given, &given);
229 string used;
230 StringifyOrdering(linear_solver_ordering_used, &used);
231 StringAppendF(&report,
232 "Linear solver ordering %22s %24s\n",
233 given.c_str(),
234 used.c_str());
235 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800236
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700237 if (inner_iterations_given) {
238 StringAppendF(&report,
239 "Use inner iterations %20s %20s\n",
240 inner_iterations_given ? "True" : "False",
241 inner_iterations_used ? "True" : "False");
242 }
243
244 if (inner_iterations_used) {
Sameer Agarwald010de52013-02-15 14:26:56 -0800245 string given;
246 StringifyOrdering(inner_iteration_ordering_given, &given);
247 string used;
248 StringifyOrdering(inner_iteration_ordering_used, &used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800249 StringAppendF(&report,
250 "Inner iteration ordering %20s %24s\n",
251 given.c_str(),
252 used.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800253 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800254 } else {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700255 // LINE_SEARCH HEADER
Sameer Agarwald010de52013-02-15 14:26:56 -0800256 StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
Sameer Agarwald010de52013-02-15 14:26:56 -0800257
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700258
259 string line_search_direction_string;
260 if (line_search_direction_type == LBFGS) {
261 line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
262 } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
263 line_search_direction_string =
264 NonlinearConjugateGradientTypeToString(
265 nonlinear_conjugate_gradient_type);
266 } else {
267 line_search_direction_string =
268 LineSearchDirectionTypeToString(line_search_direction_type);
269 }
270
271 StringAppendF(&report, "Line search direction %19s\n",
272 line_search_direction_string.c_str());
273
274 const string line_search_type_string =
275 StringPrintf("%s %s",
Sameer Agarwal7a8f7972013-07-03 09:03:55 -0700276 LineSearchInterpolationTypeToString(
277 line_search_interpolation_type),
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700278 LineSearchTypeToString(line_search_type));
279 StringAppendF(&report, "Line search type %19s\n",
280 line_search_type_string.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800281 StringAppendF(&report, "\n");
282
Sameer Agarwalbeb45052013-02-22 13:37:01 -0800283 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700284 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800285 num_threads_given, num_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800286 }
Keir Mierle8ebb0732012-04-30 23:09:08 -0700287
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700288 StringAppendF(&report, "\nCost:\n");
289 StringAppendF(&report, "Initial % 30e\n", initial_cost);
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800290 if (termination_type != FAILURE &&
291 termination_type != USER_FAILURE) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700292 StringAppendF(&report, "Final % 30e\n", final_cost);
293 StringAppendF(&report, "Change % 30e\n",
294 initial_cost - final_cost);
295 }
296
297 StringAppendF(&report, "\nMinimizer iterations % 16d\n",
298 num_successful_steps + num_unsuccessful_steps);
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700299
300 // Successful/Unsuccessful steps only matter in the case of the
301 // trust region solver. Line search terminates when it encounters
302 // the first unsuccessful step.
303 if (minimizer_type == TRUST_REGION) {
304 StringAppendF(&report, "Successful steps % 14d\n",
305 num_successful_steps);
306 StringAppendF(&report, "Unsuccessful steps % 14d\n",
307 num_unsuccessful_steps);
308 }
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700309 if (inner_iterations_used) {
310 StringAppendF(&report, "Steps with inner iterations % 14d\n",
311 num_inner_iteration_steps);
312 }
313
314 StringAppendF(&report, "\nTime (in seconds):\n");
315 StringAppendF(&report, "Preprocessor %25.3f\n",
316 preprocessor_time_in_seconds);
317
318 StringAppendF(&report, "\n Residual evaluation %23.3f\n",
319 residual_evaluation_time_in_seconds);
320 StringAppendF(&report, " Jacobian evaluation %23.3f\n",
321 jacobian_evaluation_time_in_seconds);
322
323 if (minimizer_type == TRUST_REGION) {
324 StringAppendF(&report, " Linear solver %23.3f\n",
325 linear_solver_time_in_seconds);
326 }
327
328 if (inner_iterations_used) {
329 StringAppendF(&report, " Inner iterations %23.3f\n",
330 inner_iteration_time_in_seconds);
331 }
332
333 StringAppendF(&report, "Minimizer %25.3f\n\n",
334 minimizer_time_in_seconds);
335
336 StringAppendF(&report, "Postprocessor %24.3f\n",
337 postprocessor_time_in_seconds);
338
339 StringAppendF(&report, "Total %25.3f\n\n",
340 total_time_in_seconds);
341
Sameer Agarwal1da92922014-02-23 16:10:33 -0800342 StringAppendF(&report, "Termination: %25s (%s)\n",
343 TerminationTypeToString(termination_type), message.c_str());
Keir Mierle8ebb0732012-04-30 23:09:08 -0700344 return report;
345};
346
Sameer Agarwaldcee1202013-12-07 21:48:56 -0800347bool Solver::Summary::IsSolutionUsable() const {
348 return (termination_type == CONVERGENCE ||
349 termination_type == NO_CONVERGENCE ||
350 termination_type == USER_SUCCESS);
351}
352
Keir Mierle8ebb0732012-04-30 23:09:08 -0700353} // namespace ceres