blob: 426a270497e05727365fa7dffaa3f270bed1f03a [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),
88 termination_type(DID_NOT_RUN),
Keir Mierle8ebb0732012-04-30 23:09:08 -070089 initial_cost(-1.0),
90 final_cost(-1.0),
91 fixed_cost(-1.0),
92 num_successful_steps(-1),
93 num_unsuccessful_steps(-1),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -070094 num_inner_iteration_steps(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -070095 preprocessor_time_in_seconds(-1.0),
96 minimizer_time_in_seconds(-1.0),
Sameer Agarwalfa015192012-06-11 14:21:42 -070097 postprocessor_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070098 total_time_in_seconds(-1.0),
Sameer Agarwal42a84b82013-02-01 12:22:53 -080099 linear_solver_time_in_seconds(-1.0),
100 residual_evaluation_time_in_seconds(-1.0),
101 jacobian_evaluation_time_in_seconds(-1.0),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700102 inner_iteration_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700103 num_parameter_blocks(-1),
104 num_parameters(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800105 num_effective_parameters(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700106 num_residual_blocks(-1),
107 num_residuals(-1),
108 num_parameter_blocks_reduced(-1),
109 num_parameters_reduced(-1),
Keir Mierleba944212013-02-25 12:46:44 -0800110 num_effective_parameters_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700111 num_residual_blocks_reduced(-1),
112 num_residuals_reduced(-1),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700113 num_threads_given(-1),
114 num_threads_used(-1),
115 num_linear_solver_threads_given(-1),
116 num_linear_solver_threads_used(-1),
117 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
118 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700119 inner_iterations_given(false),
120 inner_iterations_used(false),
Keir Mierle8ebb0732012-04-30 23:09:08 -0700121 preconditioner_type(IDENTITY),
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700122 trust_region_strategy_type(LEVENBERG_MARQUARDT),
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800123 sparse_linear_algebra_library(SUITE_SPARSE),
Sameer Agarwald010de52013-02-15 14:26:56 -0800124 line_search_direction_type(LBFGS),
125 line_search_type(ARMIJO) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700126}
127
128string Solver::Summary::BriefReport() const {
129 string report = "Ceres Solver Report: ";
130 if (termination_type == DID_NOT_RUN) {
131 CHECK(!error.empty())
132 << "Solver terminated with DID_NOT_RUN but the solver did not "
133 << "return a reason. This is a Ceres error. Please report this "
134 << "to the Ceres team";
135 return report + "Termination: DID_NOT_RUN, because " + error;
136 }
137
138 internal::StringAppendF(&report, "Iterations: %d",
139 num_successful_steps + num_unsuccessful_steps);
140 internal::StringAppendF(&report, ", Initial cost: %e", initial_cost);
141
142 // If the solver failed or was aborted, then the final_cost has no
143 // meaning.
144 if (termination_type != NUMERICAL_FAILURE &&
145 termination_type != USER_ABORT) {
146 internal::StringAppendF(&report, ", Final cost: %e", final_cost);
147 }
148
149 internal::StringAppendF(&report, ", Termination: %s.",
150 SolverTerminationTypeToString(termination_type));
151 return report;
152};
153
Sameer Agarwald010de52013-02-15 14:26:56 -0800154using internal::StringAppendF;
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700155using internal::StringPrintf;
Sameer Agarwald010de52013-02-15 14:26:56 -0800156
Keir Mierle8ebb0732012-04-30 23:09:08 -0700157string Solver::Summary::FullReport() const {
158 string report =
159 "\n"
160 "Ceres Solver Report\n"
161 "-------------------\n";
162
163 if (termination_type == DID_NOT_RUN) {
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800164 StringAppendF(&report, " Original\n");
Keir Mierleba944212013-02-25 12:46:44 -0800165 StringAppendF(&report, "Parameter blocks % 10d\n", num_parameter_blocks);
166 StringAppendF(&report, "Parameters % 10d\n", num_parameters);
167 if (num_effective_parameters != num_parameters) {
168 StringAppendF(&report, "Effective parameters% 10d\n", num_parameters);
169 }
170
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800171 StringAppendF(&report, "Residual blocks % 10d\n",
172 num_residual_blocks);
173 StringAppendF(&report, "Residuals % 10d\n\n",
174 num_residuals);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700175 } else {
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800176 StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
177 StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
178 num_parameter_blocks, num_parameter_blocks_reduced);
179 StringAppendF(&report, "Parameters % 25d% 25d\n",
180 num_parameters, num_parameters_reduced);
Keir Mierleba944212013-02-25 12:46:44 -0800181 if (num_effective_parameters_reduced != num_parameters_reduced) {
182 StringAppendF(&report, "Effective parameters% 25d% 25d\n",
183 num_effective_parameters, num_effective_parameters_reduced);
184 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800185 StringAppendF(&report, "Residual blocks % 25d% 25d\n",
186 num_residual_blocks, num_residual_blocks_reduced);
187 StringAppendF(&report, "Residual % 25d% 25d\n",
188 num_residuals, num_residuals_reduced);
Keir Mierle8ebb0732012-04-30 23:09:08 -0700189 }
190
Sameer Agarwald010de52013-02-15 14:26:56 -0800191 if (minimizer_type == TRUST_REGION) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700192 // TRUST_SEARCH HEADER
Sameer Agarwal509f68c2013-02-20 01:39:03 -0800193 StringAppendF(&report, "\nMinimizer %19s\n",
194 "TRUST_REGION");
Sameer Agarwald010de52013-02-15 14:26:56 -0800195 if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
196 linear_solver_type_used == SPARSE_SCHUR ||
197 (linear_solver_type_used == ITERATIVE_SCHUR &&
Sameer Agarwal290b9752013-02-17 16:50:37 -0800198 (preconditioner_type == CLUSTER_JACOBI ||
Sameer Agarwald010de52013-02-15 14:26:56 -0800199 preconditioner_type == CLUSTER_TRIDIAGONAL))) {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700200 StringAppendF(&report, "\nSparse linear algebra library %15s\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800201 SparseLinearAlgebraLibraryTypeToString(
202 sparse_linear_algebra_library));
Sameer Agarwal1e289202012-08-21 18:00:54 -0700203 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800204
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700205 StringAppendF(&report, "Trust region strategy %19s",
Sameer Agarwald010de52013-02-15 14:26:56 -0800206 TrustRegionStrategyTypeToString(
207 trust_region_strategy_type));
208 if (trust_region_strategy_type == DOGLEG) {
209 if (dogleg_type == TRADITIONAL_DOGLEG) {
210 StringAppendF(&report, " (TRADITIONAL)");
211 } else {
212 StringAppendF(&report, " (SUBSPACE)");
213 }
214 }
215 StringAppendF(&report, "\n");
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800216 StringAppendF(&report, "\n");
Sameer Agarwal1e289202012-08-21 18:00:54 -0700217
Sameer Agarwal931c3092013-02-25 09:46:21 -0800218 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwald010de52013-02-15 14:26:56 -0800219 StringAppendF(&report, "Linear solver %25s%25s\n",
220 LinearSolverTypeToString(linear_solver_type_given),
221 LinearSolverTypeToString(linear_solver_type_used));
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800222
Sameer Agarwald010de52013-02-15 14:26:56 -0800223 if (linear_solver_type_given == CGNR ||
224 linear_solver_type_given == ITERATIVE_SCHUR) {
225 StringAppendF(&report, "Preconditioner %25s%25s\n",
226 PreconditionerTypeToString(preconditioner_type),
227 PreconditionerTypeToString(preconditioner_type));
Sameer Agarwald010de52013-02-15 14:26:56 -0800228 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800229
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700230 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800231 num_threads_given, num_threads_used);
232 StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
233 num_linear_solver_threads_given,
234 num_linear_solver_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800235
Sameer Agarwald010de52013-02-15 14:26:56 -0800236 if (IsSchurType(linear_solver_type_used)) {
237 string given;
238 StringifyOrdering(linear_solver_ordering_given, &given);
239 string used;
240 StringifyOrdering(linear_solver_ordering_used, &used);
241 StringAppendF(&report,
242 "Linear solver ordering %22s %24s\n",
243 given.c_str(),
244 used.c_str());
245 }
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800246
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700247 if (inner_iterations_given) {
248 StringAppendF(&report,
249 "Use inner iterations %20s %20s\n",
250 inner_iterations_given ? "True" : "False",
251 inner_iterations_used ? "True" : "False");
252 }
253
254 if (inner_iterations_used) {
Sameer Agarwald010de52013-02-15 14:26:56 -0800255 string given;
256 StringifyOrdering(inner_iteration_ordering_given, &given);
257 string used;
258 StringifyOrdering(inner_iteration_ordering_used, &used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800259 StringAppendF(&report,
260 "Inner iteration ordering %20s %24s\n",
261 given.c_str(),
262 used.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800263 }
Sameer Agarwald010de52013-02-15 14:26:56 -0800264 } else {
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700265 // LINE_SEARCH HEADER
Sameer Agarwald010de52013-02-15 14:26:56 -0800266 StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
Sameer Agarwald010de52013-02-15 14:26:56 -0800267
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700268
269 string line_search_direction_string;
270 if (line_search_direction_type == LBFGS) {
271 line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
272 } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
273 line_search_direction_string =
274 NonlinearConjugateGradientTypeToString(
275 nonlinear_conjugate_gradient_type);
276 } else {
277 line_search_direction_string =
278 LineSearchDirectionTypeToString(line_search_direction_type);
279 }
280
281 StringAppendF(&report, "Line search direction %19s\n",
282 line_search_direction_string.c_str());
283
284 const string line_search_type_string =
285 StringPrintf("%s %s",
286 LineSearchInterpolationTypeToString(line_search_interpolation_type),
287 LineSearchTypeToString(line_search_type));
288 StringAppendF(&report, "Line search type %19s\n",
289 line_search_type_string.c_str());
Sameer Agarwald010de52013-02-15 14:26:56 -0800290 StringAppendF(&report, "\n");
291
Sameer Agarwalbeb45052013-02-22 13:37:01 -0800292 StringAppendF(&report, "%45s %21s\n", "Given", "Used");
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700293 StringAppendF(&report, "Threads % 25d% 25d\n",
Sameer Agarwald010de52013-02-15 14:26:56 -0800294 num_threads_given, num_threads_used);
Sameer Agarwal977be7c2013-01-26 16:01:54 -0800295 }
Keir Mierle8ebb0732012-04-30 23:09:08 -0700296
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700297 if (termination_type == DID_NOT_RUN) {
298 CHECK(!error.empty())
299 << "Solver terminated with DID_NOT_RUN but the solver did not "
300 << "return a reason. This is a Ceres error. Please report this "
301 << "to the Ceres team";
302 StringAppendF(&report, "Termination: %20s\n",
303 "DID_NOT_RUN");
304 StringAppendF(&report, "Reason: %s\n", error.c_str());
305 return report;
306 }
307
308 StringAppendF(&report, "\nCost:\n");
309 StringAppendF(&report, "Initial % 30e\n", initial_cost);
310 if (termination_type != NUMERICAL_FAILURE &&
311 termination_type != USER_ABORT) {
312 StringAppendF(&report, "Final % 30e\n", final_cost);
313 StringAppendF(&report, "Change % 30e\n",
314 initial_cost - final_cost);
315 }
316
317 StringAppendF(&report, "\nMinimizer iterations % 16d\n",
318 num_successful_steps + num_unsuccessful_steps);
Sameer Agarwal4f010b22013-07-01 08:01:01 -0700319
320 // Successful/Unsuccessful steps only matter in the case of the
321 // trust region solver. Line search terminates when it encounters
322 // the first unsuccessful step.
323 if (minimizer_type == TRUST_REGION) {
324 StringAppendF(&report, "Successful steps % 14d\n",
325 num_successful_steps);
326 StringAppendF(&report, "Unsuccessful steps % 14d\n",
327 num_unsuccessful_steps);
328 }
Sameer Agarwal9f9488b2013-05-23 09:40:40 -0700329 if (inner_iterations_used) {
330 StringAppendF(&report, "Steps with inner iterations % 14d\n",
331 num_inner_iteration_steps);
332 }
333
334 StringAppendF(&report, "\nTime (in seconds):\n");
335 StringAppendF(&report, "Preprocessor %25.3f\n",
336 preprocessor_time_in_seconds);
337
338 StringAppendF(&report, "\n Residual evaluation %23.3f\n",
339 residual_evaluation_time_in_seconds);
340 StringAppendF(&report, " Jacobian evaluation %23.3f\n",
341 jacobian_evaluation_time_in_seconds);
342
343 if (minimizer_type == TRUST_REGION) {
344 StringAppendF(&report, " Linear solver %23.3f\n",
345 linear_solver_time_in_seconds);
346 }
347
348 if (inner_iterations_used) {
349 StringAppendF(&report, " Inner iterations %23.3f\n",
350 inner_iteration_time_in_seconds);
351 }
352
353 StringAppendF(&report, "Minimizer %25.3f\n\n",
354 minimizer_time_in_seconds);
355
356 StringAppendF(&report, "Postprocessor %24.3f\n",
357 postprocessor_time_in_seconds);
358
359 StringAppendF(&report, "Total %25.3f\n\n",
360 total_time_in_seconds);
361
362 StringAppendF(&report, "Termination: %25s\n",
363 SolverTerminationTypeToString(termination_type));
Keir Mierle8ebb0732012-04-30 23:09:08 -0700364 return report;
365};
366
367} // namespace ceres