Solver::Summary::FullReport() supports line search now.
Change-Id: Ib08d300198b85d9732cfb5785af4235ca4bd5226
diff --git a/examples/denoising.cc b/examples/denoising.cc
index 086be00..bfd8118 100644
--- a/examples/denoising.cc
+++ b/examples/denoising.cc
@@ -57,6 +57,8 @@
DEFINE_string(output, "", "File to which the output image should be written");
DEFINE_double(sigma, 20.0, "Standard deviation of noise");
DEFINE_bool(verbose, false, "Prints information about the solver progress.");
+DEFINE_bool(line_search, false, "Use a line search instead of trust region "
+ "algorithm.");
namespace ceres {
namespace examples {
@@ -143,7 +145,11 @@
if (FLAGS_verbose) {
options.minimizer_progress_to_stdout = true;
}
- options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
+
+ if (FLAGS_line_search) {
+ options.minimizer_type = ceres::LINE_SEARCH;
+ }
+
options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
options.function_tolerance = 1e-3; // Enough for denoising.
diff --git a/include/ceres/solver.h b/include/ceres/solver.h
index cb858ba..07ce0e4 100644
--- a/include/ceres/solver.h
+++ b/include/ceres/solver.h
@@ -59,7 +59,7 @@
// Default constructor that sets up a generic sparse problem.
Options() {
minimizer_type = TRUST_REGION;
- line_search_direction_type = STEEPEST_DESCENT;
+ line_search_direction_type = LBFGS;
line_search_type = ARMIJO;
nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
max_lbfgs_rank = 20;
@@ -578,6 +578,8 @@
string FullReport() const;
// Minimizer summary -------------------------------------------------
+ MinimizerType minimizer_type;
+
SolverTerminationType termination_type;
// If the solver did not run, or there was a failure, a
@@ -698,9 +700,14 @@
TrustRegionStrategyType trust_region_strategy_type;
DoglegType dogleg_type;
+ bool inner_iterations;
+
SparseLinearAlgebraLibraryType sparse_linear_algebra_library;
- bool inner_iterations;
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ int max_lbfgs_rank;
+
vector<int> inner_iteration_ordering_given;
vector<int> inner_iteration_ordering_used;
};
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index 3004717..e612c26 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -84,7 +84,8 @@
Solver::Summary::Summary()
// Invalid values for most fields, to ensure that we are not
// accidentally reporting default values.
- : termination_type(DID_NOT_RUN),
+ : minimizer_type(TRUST_REGION),
+ termination_type(DID_NOT_RUN),
initial_cost(-1.0),
final_cost(-1.0),
fixed_cost(-1.0),
@@ -113,8 +114,10 @@
linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
preconditioner_type(IDENTITY),
trust_region_strategy_type(LEVENBERG_MARQUARDT),
+ inner_iterations(false),
sparse_linear_algebra_library(SUITE_SPARSE),
- inner_iterations(false) {
+ line_search_direction_type(LBFGS),
+ line_search_type(ARMIJO) {
}
string Solver::Summary::BriefReport() const {
@@ -143,8 +146,10 @@
return report;
};
+using internal::StringAppendF;
+
string Solver::Summary::FullReport() const {
- using internal::StringAppendF;
+
string report =
"\n"
@@ -173,120 +178,185 @@
num_residuals, num_residuals_reduced);
}
- if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
- linear_solver_type_used == SPARSE_SCHUR ||
- (linear_solver_type_used == ITERATIVE_SCHUR &&
- (preconditioner_type == SCHUR_JACOBI ||
- preconditioner_type == CLUSTER_JACOBI ||
- preconditioner_type == CLUSTER_TRIDIAGONAL))) {
- StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
- SparseLinearAlgebraLibraryTypeToString(
- sparse_linear_algebra_library));
- }
+ // TODO(sameeragarwal): Refactor this into separate functions.
- StringAppendF(&report, "Trust Region Strategy %19s",
- TrustRegionStrategyTypeToString(
- trust_region_strategy_type));
- if (trust_region_strategy_type == DOGLEG) {
- if (dogleg_type == TRADITIONAL_DOGLEG) {
- StringAppendF(&report, " (TRADITIONAL)");
- } else {
- StringAppendF(&report, " (SUBSPACE)");
+ if (minimizer_type == TRUST_REGION) {
+ StringAppendF(&report, "\nMinimizer %19s\n", "TRUST_REGION");
+ if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
+ linear_solver_type_used == SPARSE_SCHUR ||
+ (linear_solver_type_used == ITERATIVE_SCHUR &&
+ (preconditioner_type == SCHUR_JACOBI ||
+ preconditioner_type == CLUSTER_JACOBI ||
+ preconditioner_type == CLUSTER_TRIDIAGONAL))) {
+ StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
+ SparseLinearAlgebraLibraryTypeToString(
+ sparse_linear_algebra_library));
}
- }
- StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "Trust Region Strategy %19s",
+ TrustRegionStrategyTypeToString(
+ trust_region_strategy_type));
+ if (trust_region_strategy_type == DOGLEG) {
+ if (dogleg_type == TRADITIONAL_DOGLEG) {
+ StringAppendF(&report, " (TRADITIONAL)");
+ } else {
+ StringAppendF(&report, " (SUBSPACE)");
+ }
+ }
+ StringAppendF(&report, "\n");
StringAppendF(&report, "\n");
- StringAppendF(&report, "%45s %21s\n", "Given", "Used");
- StringAppendF(&report, "Linear solver %25s%25s\n",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(linear_solver_type_used));
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Linear solver %25s%25s\n",
+ LinearSolverTypeToString(linear_solver_type_given),
+ LinearSolverTypeToString(linear_solver_type_used));
- if (linear_solver_type_given == CGNR ||
- linear_solver_type_given == ITERATIVE_SCHUR) {
- StringAppendF(&report, "Preconditioner %25s%25s\n",
- PreconditionerTypeToString(preconditioner_type),
- PreconditionerTypeToString(preconditioner_type));
- } else {
- StringAppendF(&report, "Preconditioner %25s%25s\n",
- "N/A", "N/A");
- }
+ if (linear_solver_type_given == CGNR ||
+ linear_solver_type_given == ITERATIVE_SCHUR) {
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ PreconditionerTypeToString(preconditioner_type),
+ PreconditionerTypeToString(preconditioner_type));
+ } else {
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ "N/A", "N/A");
+ }
- StringAppendF(&report, "Threads: % 25d% 25d\n",
- num_threads_given, num_threads_used);
- StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
- num_linear_solver_threads_given,
- num_linear_solver_threads_used);
+ StringAppendF(&report, "Threads: % 25d% 25d\n",
+ num_threads_given, num_threads_used);
+ StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
+ num_linear_solver_threads_given,
+ num_linear_solver_threads_used);
- if (IsSchurType(linear_solver_type_used)) {
- string given;
- StringifyOrdering(linear_solver_ordering_given, &given);
- string used;
- StringifyOrdering(linear_solver_ordering_used, &used);
- StringAppendF(&report,
- "Linear solver ordering %22s %24s\n",
- given.c_str(),
- used.c_str());
- }
+ if (IsSchurType(linear_solver_type_used)) {
+ string given;
+ StringifyOrdering(linear_solver_ordering_given, &given);
+ string used;
+ StringifyOrdering(linear_solver_ordering_used, &used);
+ StringAppendF(&report,
+ "Linear solver ordering %22s %24s\n",
+ given.c_str(),
+ used.c_str());
+ }
- if (inner_iterations) {
- string given;
- StringifyOrdering(inner_iteration_ordering_given, &given);
- string used;
- StringifyOrdering(inner_iteration_ordering_used, &used);
+ if (inner_iterations) {
+ string given;
+ StringifyOrdering(inner_iteration_ordering_given, &given);
+ string used;
+ StringifyOrdering(inner_iteration_ordering_used, &used);
StringAppendF(&report,
"Inner iteration ordering %20s %24s\n",
given.c_str(),
used.c_str());
+ }
+
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations:\n");
+ StringAppendF(&report, "Successful % 20d\n",
+ num_successful_steps);
+ StringAppendF(&report, "Unsuccessful % 20d\n",
+ num_unsuccessful_steps);
+ StringAppendF(&report, "Total % 20d\n",
+ num_successful_steps + num_unsuccessful_steps);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, " Linear Solver %23.3f\n",
+ linear_solver_time_in_seconds);
+ StringAppendF(&report, "Minimizer %25.3f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.3f\n",
+ postprocessor_time_in_seconds);
+
+ StringAppendF(&report, "Total %25.3f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s\n",
+ SolverTerminationTypeToString(termination_type));
+ } else {
+ // LINE_SEARCH
+ StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
+ if (line_search_direction_type == LBFGS) {
+ StringAppendF(&report, "Line search direction %19s(%d)\n",
+ LineSearchDirectionTypeToString(line_search_direction_type),
+ max_lbfgs_rank);
+ } else {
+ StringAppendF(&report, "Line search direction %19s\n",
+ LineSearchDirectionTypeToString(line_search_direction_type));
+ }
+ StringAppendF(&report, "Line search type %19s\n",
+ LineSearchTypeToString(line_search_type));
+
+ StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Threads: % 25d% 25d\n",
+ num_threads_given, num_threads_used);
+
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations: % 20ld\n", iterations.size() - 1);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, "Minimizer %25.3f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.3f\n",
+ postprocessor_time_in_seconds);
+
+ StringAppendF(&report, "Total %25.3f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s\n",
+ SolverTerminationTypeToString(termination_type));
}
- if (termination_type == DID_NOT_RUN) {
- CHECK(!error.empty())
- << "Solver terminated with DID_NOT_RUN but the solver did not "
- << "return a reason. This is a Ceres error. Please report this "
- << "to the Ceres team";
- StringAppendF(&report, "Termination: %20s\n",
- "DID_NOT_RUN");
- StringAppendF(&report, "Reason: %s\n", error.c_str());
- return report;
- }
-
- StringAppendF(&report, "\nCost:\n");
- StringAppendF(&report, "Initial % 30e\n", initial_cost);
- if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
- StringAppendF(&report, "Final % 30e\n", final_cost);
- StringAppendF(&report, "Change % 30e\n",
- initial_cost - final_cost);
- }
-
- StringAppendF(&report, "\nNumber of iterations:\n");
- StringAppendF(&report, "Successful % 20d\n",
- num_successful_steps);
- StringAppendF(&report, "Unsuccessful % 20d\n",
- num_unsuccessful_steps);
- StringAppendF(&report, "Total % 20d\n",
- num_successful_steps + num_unsuccessful_steps);
-
- StringAppendF(&report, "\nTime (in seconds):\n");
- StringAppendF(&report, "Preprocessor %25.3f\n",
- preprocessor_time_in_seconds);
- StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
- residual_evaluation_time_in_seconds);
- StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
- jacobian_evaluation_time_in_seconds);
- StringAppendF(&report, " Linear Solver %23.3f\n",
- linear_solver_time_in_seconds);
- StringAppendF(&report, "Minimizer %25.3f\n\n",
- minimizer_time_in_seconds);
-
- StringAppendF(&report, "Postprocessor %24.3f\n",
- postprocessor_time_in_seconds);
-
- StringAppendF(&report, "Total %25.3f\n\n",
- total_time_in_seconds);
-
- StringAppendF(&report, "Termination: %25s\n",
- SolverTerminationTypeToString(termination_type));
return report;
};
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index 475e71d..61275fc 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -344,6 +344,7 @@
// Reset the summary object to its default values.
*CHECK_NOTNULL(summary) = Solver::Summary();
+ summary->minimizer_type = TRUST_REGION;
summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
summary->num_parameters = problem_impl->NumParameters();
summary->num_residual_blocks = problem_impl->NumResidualBlocks();
@@ -676,6 +677,10 @@
// Reset the summary object to its default values.
*CHECK_NOTNULL(summary) = Solver::Summary();
+ summary->minimizer_type = LINE_SEARCH;
+ summary->line_search_direction_type = original_options.line_search_direction_type;
+ summary->max_lbfgs_rank = original_options.max_lbfgs_rank;
+ summary->line_search_type = original_options.line_search_type;
summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
summary->num_parameters = problem_impl->NumParameters();
summary->num_residual_blocks = problem_impl->NumResidualBlocks();
@@ -815,9 +820,6 @@
// Ensure the program state is set to the user parameters on the way out.
original_program->SetParameterBlockStatePtrsToUserStatePtrs();
-
- summary->postprocessor_time_in_seconds =
- WallTimeInSeconds() - post_process_start_time;
return;
}
@@ -891,6 +893,17 @@
// Ensure the program state is set to the user parameters on the way out.
original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ const map<string, double>& evaluator_time_statistics =
+ evaluator->TimeStatistics();
+
+ summary->residual_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ summary->jacobian_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+
// Stick a fork in it, we're done.
summary->postprocessor_time_in_seconds =
WallTimeInSeconds() - post_process_start_time;