blob: 84c275644c5c3345f34fb8177911eef264abf32b [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 {
43
44Solver::~Solver() {}
45
Keir Mierle8ebb0732012-04-30 23:09:08 -070046void Solver::Solve(const Solver::Options& options,
47 Problem* problem,
48 Solver::Summary* summary) {
Petter Strandmark76533b32012-09-04 22:08:50 -070049 double start_time_seconds = internal::WallTimeInSeconds();
Keir Mierle6196cba2012-06-18 11:03:40 -070050 internal::ProblemImpl* problem_impl =
51 CHECK_NOTNULL(problem)->problem_impl_.get();
52 internal::SolverImpl::Solve(options, problem_impl, summary);
Petter Strandmark76533b32012-09-04 22:08:50 -070053 summary->total_time_in_seconds =
54 internal::WallTimeInSeconds() - start_time_seconds;
Keir Mierle8ebb0732012-04-30 23:09:08 -070055}
56
57void Solve(const Solver::Options& options,
58 Problem* problem,
59 Solver::Summary* summary) {
Keir Mierle6196cba2012-06-18 11:03:40 -070060 Solver solver;
61 solver.Solve(options, problem, summary);
Keir Mierle8ebb0732012-04-30 23:09:08 -070062}
63
64Solver::Summary::Summary()
65 // Invalid values for most fields, to ensure that we are not
66 // accidentally reporting default values.
67 : termination_type(DID_NOT_RUN),
68 initial_cost(-1.0),
69 final_cost(-1.0),
70 fixed_cost(-1.0),
71 num_successful_steps(-1),
72 num_unsuccessful_steps(-1),
73 preprocessor_time_in_seconds(-1.0),
74 minimizer_time_in_seconds(-1.0),
Sameer Agarwalfa015192012-06-11 14:21:42 -070075 postprocessor_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070076 total_time_in_seconds(-1.0),
77 num_parameter_blocks(-1),
78 num_parameters(-1),
79 num_residual_blocks(-1),
80 num_residuals(-1),
81 num_parameter_blocks_reduced(-1),
82 num_parameters_reduced(-1),
83 num_residual_blocks_reduced(-1),
84 num_residuals_reduced(-1),
85 num_eliminate_blocks_given(-1),
86 num_eliminate_blocks_used(-1),
87 num_threads_given(-1),
88 num_threads_used(-1),
89 num_linear_solver_threads_given(-1),
90 num_linear_solver_threads_used(-1),
91 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
92 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
93 preconditioner_type(IDENTITY),
Sameer Agarwal97fb6d92012-06-17 10:08:19 -070094 ordering_type(NATURAL),
95 trust_region_strategy_type(LEVENBERG_MARQUARDT),
96 sparse_linear_algebra_library(SUITE_SPARSE) {
Keir Mierle8ebb0732012-04-30 23:09:08 -070097}
98
99string Solver::Summary::BriefReport() const {
100 string report = "Ceres Solver Report: ";
101 if (termination_type == DID_NOT_RUN) {
102 CHECK(!error.empty())
103 << "Solver terminated with DID_NOT_RUN but the solver did not "
104 << "return a reason. This is a Ceres error. Please report this "
105 << "to the Ceres team";
106 return report + "Termination: DID_NOT_RUN, because " + error;
107 }
108
109 internal::StringAppendF(&report, "Iterations: %d",
110 num_successful_steps + num_unsuccessful_steps);
111 internal::StringAppendF(&report, ", Initial cost: %e", initial_cost);
112
113 // If the solver failed or was aborted, then the final_cost has no
114 // meaning.
115 if (termination_type != NUMERICAL_FAILURE &&
116 termination_type != USER_ABORT) {
117 internal::StringAppendF(&report, ", Final cost: %e", final_cost);
118 }
119
120 internal::StringAppendF(&report, ", Termination: %s.",
121 SolverTerminationTypeToString(termination_type));
122 return report;
123};
124
125string Solver::Summary::FullReport() const {
126 string report =
127 "\n"
128 "Ceres Solver Report\n"
129 "-------------------\n";
130
131 if (termination_type == DID_NOT_RUN) {
132 internal::StringAppendF(&report, " Original\n");
133 internal::StringAppendF(&report, "Parameter blocks % 10d\n",
134 num_parameter_blocks);
135 internal::StringAppendF(&report, "Parameters % 10d\n",
136 num_parameters);
137 internal::StringAppendF(&report, "Residual blocks % 10d\n",
138 num_residual_blocks);
Sameer Agarwala7392aa2012-05-11 11:34:50 -0700139 internal::StringAppendF(&report, "Residuals % 10d\n\n",
Keir Mierle8ebb0732012-04-30 23:09:08 -0700140 num_residuals);
141 } else {
142 internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
143 internal::StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
144 num_parameter_blocks, num_parameter_blocks_reduced);
145 internal::StringAppendF(&report, "Parameters % 25d% 25d\n",
146 num_parameters, num_parameters_reduced);
147 internal::StringAppendF(&report, "Residual blocks % 25d% 25d\n",
148 num_residual_blocks, num_residual_blocks_reduced);
149 internal::StringAppendF(&report, "Residual % 25d% 25d\n\n",
150 num_residuals, num_residuals_reduced);
151 }
152
153 internal::StringAppendF(&report, "%45s %21s\n", "Given", "Used");
154 internal::StringAppendF(&report, "Linear solver %25s%25s\n",
155 LinearSolverTypeToString(linear_solver_type_given),
156 LinearSolverTypeToString(linear_solver_type_used));
157
Keir Mierlee2a6cdc2012-05-07 06:39:56 -0700158 if (linear_solver_type_given == CGNR ||
Keir Mierlef7898fb2012-05-05 20:55:08 -0700159 linear_solver_type_given == ITERATIVE_SCHUR) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700160 internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
161 PreconditionerTypeToString(preconditioner_type),
162 PreconditionerTypeToString(preconditioner_type));
163 } else {
164 internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
165 "N/A", "N/A");
166 }
167
168 internal::StringAppendF(&report, "Ordering %25s%25s\n",
169 OrderingTypeToString(ordering_type),
170 OrderingTypeToString(ordering_type));
171
172 if (IsSchurType(linear_solver_type_given)) {
173 if (ordering_type == SCHUR) {
174 internal::StringAppendF(&report, "num_eliminate_blocks%25s% 25d\n",
175 "N/A",
176 num_eliminate_blocks_used);
177 } else {
178 internal::StringAppendF(&report, "num_eliminate_blocks% 25d% 25d\n",
179 num_eliminate_blocks_given,
180 num_eliminate_blocks_used);
181 }
182 }
183
184 internal::StringAppendF(&report, "Threads: % 25d% 25d\n",
185 num_threads_given, num_threads_used);
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700186 internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
Keir Mierle8ebb0732012-04-30 23:09:08 -0700187 num_linear_solver_threads_given,
188 num_linear_solver_threads_used);
189
Sameer Agarwal8b4cb7a2012-08-16 19:26:55 -0700190 if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
191 linear_solver_type_used == SPARSE_SCHUR ||
192 (linear_solver_type_used == ITERATIVE_SCHUR &&
193 (preconditioner_type == SCHUR_JACOBI ||
194 preconditioner_type == CLUSTER_JACOBI ||
195 preconditioner_type == CLUSTER_TRIDIAGONAL))) {
196 internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
197 SparseLinearAlgebraLibraryTypeToString(
198 sparse_linear_algebra_library));
199 }
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700200
Sameer Agarwal1e289202012-08-21 18:00:54 -0700201 internal::StringAppendF(&report, "Trust Region Strategy %19s",
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700202 TrustRegionStrategyTypeToString(
203 trust_region_strategy_type));
Sameer Agarwal1e289202012-08-21 18:00:54 -0700204 if (trust_region_strategy_type == DOGLEG) {
205 if (dogleg_type == TRADITIONAL_DOGLEG) {
206 internal::StringAppendF(&report, " (TRADITIONAL)");
207 } else {
208 internal::StringAppendF(&report, " (SUBSPACE)");
209 }
210 }
211 internal::StringAppendF(&report, "\n");
212
Keir Mierle8ebb0732012-04-30 23:09:08 -0700213
214 if (termination_type == DID_NOT_RUN) {
215 CHECK(!error.empty())
216 << "Solver terminated with DID_NOT_RUN but the solver did not "
217 << "return a reason. This is a Ceres error. Please report this "
218 << "to the Ceres team";
219 internal::StringAppendF(&report, "Termination: %20s\n",
220 "DID_NOT_RUN");
221 internal::StringAppendF(&report, "Reason: %s\n", error.c_str());
222 return report;
223 }
224
225 internal::StringAppendF(&report, "\nCost:\n");
226 internal::StringAppendF(&report, "Initial % 30e\n", initial_cost);
227 if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
228 internal::StringAppendF(&report, "Final % 30e\n", final_cost);
229 internal::StringAppendF(&report, "Change % 30e\n",
230 initial_cost - final_cost);
231 }
232
233 internal::StringAppendF(&report, "\nNumber of iterations:\n");
234 internal::StringAppendF(&report, "Successful % 20d\n",
235 num_successful_steps);
236 internal::StringAppendF(&report, "Unsuccessful % 20d\n",
237 num_unsuccessful_steps);
238 internal::StringAppendF(&report, "Total % 20d\n",
239 num_successful_steps + num_unsuccessful_steps);
240 internal::StringAppendF(&report, "\nTime (in seconds):\n");
241 internal::StringAppendF(&report, "Preprocessor % 25e\n",
242 preprocessor_time_in_seconds);
243 internal::StringAppendF(&report, "Minimizer % 25e\n",
244 minimizer_time_in_seconds);
245 internal::StringAppendF(&report, "Total % 25e\n",
246 total_time_in_seconds);
247
248 internal::StringAppendF(&report, "Termination: %25s\n",
249 SolverTerminationTypeToString(termination_type));
250 return report;
251};
252
253} // namespace ceres