blob: f5f5d91e6d5282fcd40c6fdf5e6c4b734647d712 [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 Mierle8ebb0732012-04-30 23:09:08 -070035#include "ceres/program.h"
36#include "ceres/solver_impl.h"
37#include "ceres/stringprintf.h"
38#include "ceres/problem.h"
39
40namespace ceres {
41
42Solver::~Solver() {}
43
44// TODO(sameeragarwal): The timing code here should use a sub-second
45// timer.
46void Solver::Solve(const Solver::Options& options,
47 Problem* problem,
48 Solver::Summary* summary) {
49 time_t start_time_seconds = time(NULL);
50 internal::SolverImpl::Solve(options, problem, summary);
51 summary->total_time_in_seconds = time(NULL) - start_time_seconds;
52 summary->preprocessor_time_in_seconds =
53 summary->total_time_in_seconds - summary->minimizer_time_in_seconds;
54}
55
56void Solve(const Solver::Options& options,
57 Problem* problem,
58 Solver::Summary* summary) {
59 time_t start_time_seconds = time(NULL);
60 internal::SolverImpl::Solve(options, problem, summary);
61 summary->total_time_in_seconds = time(NULL) - start_time_seconds;
62 summary->preprocessor_time_in_seconds =
63 summary->total_time_in_seconds - summary->minimizer_time_in_seconds;
64}
65
66Solver::Summary::Summary()
67 // Invalid values for most fields, to ensure that we are not
68 // accidentally reporting default values.
69 : termination_type(DID_NOT_RUN),
70 initial_cost(-1.0),
71 final_cost(-1.0),
72 fixed_cost(-1.0),
73 num_successful_steps(-1),
74 num_unsuccessful_steps(-1),
75 preprocessor_time_in_seconds(-1.0),
76 minimizer_time_in_seconds(-1.0),
77 total_time_in_seconds(-1.0),
78 num_parameter_blocks(-1),
79 num_parameters(-1),
80 num_residual_blocks(-1),
81 num_residuals(-1),
82 num_parameter_blocks_reduced(-1),
83 num_parameters_reduced(-1),
84 num_residual_blocks_reduced(-1),
85 num_residuals_reduced(-1),
86 num_eliminate_blocks_given(-1),
87 num_eliminate_blocks_used(-1),
88 num_threads_given(-1),
89 num_threads_used(-1),
90 num_linear_solver_threads_given(-1),
91 num_linear_solver_threads_used(-1),
92 linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
93 linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
94 preconditioner_type(IDENTITY),
95 ordering_type(NATURAL) {
96}
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 Agarwal7f974672012-05-11 11:35:31 -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
189
190 if (termination_type == DID_NOT_RUN) {
191 CHECK(!error.empty())
192 << "Solver terminated with DID_NOT_RUN but the solver did not "
193 << "return a reason. This is a Ceres error. Please report this "
194 << "to the Ceres team";
195 internal::StringAppendF(&report, "Termination: %20s\n",
196 "DID_NOT_RUN");
197 internal::StringAppendF(&report, "Reason: %s\n", error.c_str());
198 return report;
199 }
200
201 internal::StringAppendF(&report, "\nCost:\n");
202 internal::StringAppendF(&report, "Initial % 30e\n", initial_cost);
203 if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
204 internal::StringAppendF(&report, "Final % 30e\n", final_cost);
205 internal::StringAppendF(&report, "Change % 30e\n",
206 initial_cost - final_cost);
207 }
208
209 internal::StringAppendF(&report, "\nNumber of iterations:\n");
210 internal::StringAppendF(&report, "Successful % 20d\n",
211 num_successful_steps);
212 internal::StringAppendF(&report, "Unsuccessful % 20d\n",
213 num_unsuccessful_steps);
214 internal::StringAppendF(&report, "Total % 20d\n",
215 num_successful_steps + num_unsuccessful_steps);
216 internal::StringAppendF(&report, "\nTime (in seconds):\n");
217 internal::StringAppendF(&report, "Preprocessor % 25e\n",
218 preprocessor_time_in_seconds);
219 internal::StringAppendF(&report, "Minimizer % 25e\n",
220 minimizer_time_in_seconds);
221 internal::StringAppendF(&report, "Total % 25e\n",
222 total_time_in_seconds);
223
224 internal::StringAppendF(&report, "Termination: %25s\n",
225 SolverTerminationTypeToString(termination_type));
226 return report;
227};
228
229} // namespace ceres