blob: b8122cd42f0af2963384296fa4eecae623e6dc47 [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"
Keir Mierle8ebb0732012-04-30 23:09:08 -070040
41namespace ceres {
42
43Solver::~Solver() {}
44
Keir Mierle6196cba2012-06-18 11:03:40 -070045// TODO(sameeragarwal): Use subsecond timers.
Keir Mierle8ebb0732012-04-30 23:09:08 -070046void Solver::Solve(const Solver::Options& options,
47 Problem* problem,
48 Solver::Summary* summary) {
49 time_t start_time_seconds = time(NULL);
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);
Keir Mierle8ebb0732012-04-30 23:09:08 -070053 summary->total_time_in_seconds = time(NULL) - start_time_seconds;
Keir Mierle8ebb0732012-04-30 23:09:08 -070054}
55
56void Solve(const Solver::Options& options,
57 Problem* problem,
58 Solver::Summary* summary) {
Keir Mierle6196cba2012-06-18 11:03:40 -070059 Solver solver;
60 solver.Solve(options, problem, summary);
Keir Mierle8ebb0732012-04-30 23:09:08 -070061}
62
63Solver::Summary::Summary()
64 // Invalid values for most fields, to ensure that we are not
65 // accidentally reporting default values.
66 : termination_type(DID_NOT_RUN),
67 initial_cost(-1.0),
68 final_cost(-1.0),
69 fixed_cost(-1.0),
70 num_successful_steps(-1),
71 num_unsuccessful_steps(-1),
72 preprocessor_time_in_seconds(-1.0),
73 minimizer_time_in_seconds(-1.0),
Sameer Agarwalfa015192012-06-11 14:21:42 -070074 postprocessor_time_in_seconds(-1.0),
Keir Mierle8ebb0732012-04-30 23:09:08 -070075 total_time_in_seconds(-1.0),
76 num_parameter_blocks(-1),
77 num_parameters(-1),
78 num_residual_blocks(-1),
79 num_residuals(-1),
80 num_parameter_blocks_reduced(-1),
81 num_parameters_reduced(-1),
82 num_residual_blocks_reduced(-1),
83 num_residuals_reduced(-1),
84 num_eliminate_blocks_given(-1),
85 num_eliminate_blocks_used(-1),
86 num_threads_given(-1),
87 num_threads_used(-1),
88 num_linear_solver_threads_given(-1),
89 num_linear_solver_threads_used(-1),
90 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
91 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
92 preconditioner_type(IDENTITY),
Sameer Agarwal97fb6d92012-06-17 10:08:19 -070093 ordering_type(NATURAL),
94 trust_region_strategy_type(LEVENBERG_MARQUARDT),
95 sparse_linear_algebra_library(SUITE_SPARSE) {
Keir Mierle8ebb0732012-04-30 23:09:08 -070096}
97
98string Solver::Summary::BriefReport() const {
99 string report = "Ceres Solver Report: ";
100 if (termination_type == DID_NOT_RUN) {
101 CHECK(!error.empty())
102 << "Solver terminated with DID_NOT_RUN but the solver did not "
103 << "return a reason. This is a Ceres error. Please report this "
104 << "to the Ceres team";
105 return report + "Termination: DID_NOT_RUN, because " + error;
106 }
107
108 internal::StringAppendF(&report, "Iterations: %d",
109 num_successful_steps + num_unsuccessful_steps);
110 internal::StringAppendF(&report, ", Initial cost: %e", initial_cost);
111
112 // If the solver failed or was aborted, then the final_cost has no
113 // meaning.
114 if (termination_type != NUMERICAL_FAILURE &&
115 termination_type != USER_ABORT) {
116 internal::StringAppendF(&report, ", Final cost: %e", final_cost);
117 }
118
119 internal::StringAppendF(&report, ", Termination: %s.",
120 SolverTerminationTypeToString(termination_type));
121 return report;
122};
123
124string Solver::Summary::FullReport() const {
125 string report =
126 "\n"
127 "Ceres Solver Report\n"
128 "-------------------\n";
129
130 if (termination_type == DID_NOT_RUN) {
131 internal::StringAppendF(&report, " Original\n");
132 internal::StringAppendF(&report, "Parameter blocks % 10d\n",
133 num_parameter_blocks);
134 internal::StringAppendF(&report, "Parameters % 10d\n",
135 num_parameters);
136 internal::StringAppendF(&report, "Residual blocks % 10d\n",
137 num_residual_blocks);
Sameer Agarwala7392aa2012-05-11 11:34:50 -0700138 internal::StringAppendF(&report, "Residuals % 10d\n\n",
Keir Mierle8ebb0732012-04-30 23:09:08 -0700139 num_residuals);
140 } else {
141 internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
142 internal::StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
143 num_parameter_blocks, num_parameter_blocks_reduced);
144 internal::StringAppendF(&report, "Parameters % 25d% 25d\n",
145 num_parameters, num_parameters_reduced);
146 internal::StringAppendF(&report, "Residual blocks % 25d% 25d\n",
147 num_residual_blocks, num_residual_blocks_reduced);
148 internal::StringAppendF(&report, "Residual % 25d% 25d\n\n",
149 num_residuals, num_residuals_reduced);
150 }
151
152 internal::StringAppendF(&report, "%45s %21s\n", "Given", "Used");
153 internal::StringAppendF(&report, "Linear solver %25s%25s\n",
154 LinearSolverTypeToString(linear_solver_type_given),
155 LinearSolverTypeToString(linear_solver_type_used));
156
Keir Mierlee2a6cdc2012-05-07 06:39:56 -0700157 if (linear_solver_type_given == CGNR ||
Keir Mierlef7898fb2012-05-05 20:55:08 -0700158 linear_solver_type_given == ITERATIVE_SCHUR) {
Keir Mierle8ebb0732012-04-30 23:09:08 -0700159 internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
160 PreconditionerTypeToString(preconditioner_type),
161 PreconditionerTypeToString(preconditioner_type));
162 } else {
163 internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
164 "N/A", "N/A");
165 }
166
167 internal::StringAppendF(&report, "Ordering %25s%25s\n",
168 OrderingTypeToString(ordering_type),
169 OrderingTypeToString(ordering_type));
170
171 if (IsSchurType(linear_solver_type_given)) {
172 if (ordering_type == SCHUR) {
173 internal::StringAppendF(&report, "num_eliminate_blocks%25s% 25d\n",
174 "N/A",
175 num_eliminate_blocks_used);
176 } else {
177 internal::StringAppendF(&report, "num_eliminate_blocks% 25d% 25d\n",
178 num_eliminate_blocks_given,
179 num_eliminate_blocks_used);
180 }
181 }
182
183 internal::StringAppendF(&report, "Threads: % 25d% 25d\n",
184 num_threads_given, num_threads_used);
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700185 internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
Keir Mierle8ebb0732012-04-30 23:09:08 -0700186 num_linear_solver_threads_given,
187 num_linear_solver_threads_used);
188
Sameer Agarwal97fb6d92012-06-17 10:08:19 -0700189 internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
190 SparseLinearAlgebraLibraryTypeToString(
191 sparse_linear_algebra_library));
192
193 internal::StringAppendF(&report, "Trust Region Strategy %19s\n",
194 TrustRegionStrategyTypeToString(
195 trust_region_strategy_type));
Keir Mierle8ebb0732012-04-30 23:09:08 -0700196
197 if (termination_type == DID_NOT_RUN) {
198 CHECK(!error.empty())
199 << "Solver terminated with DID_NOT_RUN but the solver did not "
200 << "return a reason. This is a Ceres error. Please report this "
201 << "to the Ceres team";
202 internal::StringAppendF(&report, "Termination: %20s\n",
203 "DID_NOT_RUN");
204 internal::StringAppendF(&report, "Reason: %s\n", error.c_str());
205 return report;
206 }
207
208 internal::StringAppendF(&report, "\nCost:\n");
209 internal::StringAppendF(&report, "Initial % 30e\n", initial_cost);
210 if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
211 internal::StringAppendF(&report, "Final % 30e\n", final_cost);
212 internal::StringAppendF(&report, "Change % 30e\n",
213 initial_cost - final_cost);
214 }
215
216 internal::StringAppendF(&report, "\nNumber of iterations:\n");
217 internal::StringAppendF(&report, "Successful % 20d\n",
218 num_successful_steps);
219 internal::StringAppendF(&report, "Unsuccessful % 20d\n",
220 num_unsuccessful_steps);
221 internal::StringAppendF(&report, "Total % 20d\n",
222 num_successful_steps + num_unsuccessful_steps);
223 internal::StringAppendF(&report, "\nTime (in seconds):\n");
224 internal::StringAppendF(&report, "Preprocessor % 25e\n",
225 preprocessor_time_in_seconds);
226 internal::StringAppendF(&report, "Minimizer % 25e\n",
227 minimizer_time_in_seconds);
228 internal::StringAppendF(&report, "Total % 25e\n",
229 total_time_in_seconds);
230
231 internal::StringAppendF(&report, "Termination: %25s\n",
232 SolverTerminationTypeToString(termination_type));
233 return report;
234};
235
236} // namespace ceres