Fix broken constant parameter blocks
This fixes the bug introduced in a previous commit,
and adds a test to check that constant parameter
blocks work as expected.
This also refactors the Solver/SolverImpl split so
that SolverImpl is no longer a friend of Problem;
instead, Solver is. This makes it possible to
verify the invariant on parameter block states in
the unit test, and is a more symmetric design
anyway.
Bug: 51
Change-Id: Id503f5b526cfb8bc24aae3aaad2e414b14063d78
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index 982fb40..46c8b1a 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -168,7 +168,7 @@
}
void SolverImpl::Solve(const Solver::Options& original_options,
- Problem* problem,
+ ProblemImpl* problem_impl,
Solver::Summary* summary) {
time_t solver_start_time = time(NULL);
Solver::Options options(original_options);
@@ -199,8 +199,6 @@
original_options.num_linear_solver_threads;
summary->ordering_type = original_options.ordering_type;
- ProblemImpl* problem_impl = CHECK_NOTNULL(problem)->problem_impl_.get();
-
summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
summary->num_parameters = problem_impl->NumParameters();
summary->num_residual_blocks = problem_impl->NumResidualBlocks();
@@ -211,22 +209,18 @@
options.sparse_linear_algebra_library;
summary->trust_region_strategy_type = options.trust_region_strategy_type;
- // Ensure the program state is set to the user parameters.
- Program* program = CHECK_NOTNULL(problem_impl)->mutable_program();
- if (!program->CopyUserStateToParameterBlocks()) {
- // This can only happen if there was a numerical problem updating the local
- // jacobians. Indicate as such and fail out.
- summary->termination_type = NUMERICAL_FAILURE;
- summary->error = "Local parameterization failure.";
- return;
- }
-
// Evaluate the initial cost and residual vector (if needed). The
// initial cost needs to be computed on the original unpreprocessed
// problem, as it is used to determine the value of the "fixed" part
// of the objective function after the problem has undergone
// reduction. Also the initial residuals are in the order in which
// the user added the ResidualBlocks to the optimization problem.
+ //
+ // Note: This assumes the parameter block states are pointing to the
+ // user state at start of Solve(), instead of some other pointer.
+ // The invariant is ensured by the ParameterBlock constructor and by
+ // the call to SetParameterBlockStatePtrsToUserStatePtrs() at the
+ // bottom of this function.
EvaluateCostAndResiduals(problem_impl,
&summary->initial_cost,
options.return_initial_residuals
@@ -238,6 +232,9 @@
// GradientCheckingCostFunction and replacing problem_impl with
// gradient_checking_problem_impl.
scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
+ // Save the original problem impl so we don't use the gradient
+ // checking one when computing the residuals.
+ ProblemImpl* original_problem_impl = problem_impl;
if (options.check_gradients) {
VLOG(1) << "Checking Gradients";
gradient_checking_problem_impl.reset(
@@ -318,8 +315,11 @@
reduced_program->StateVectorToParameterBlocks(parameters.data());
reduced_program->CopyParameterBlockStateToUserState();
+ // Ensure the program state is set to the user parameters on the way out.
+ reduced_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
// Return the final cost and residuals for the original problem.
- EvaluateCostAndResiduals(problem->problem_impl_.get(),
+ EvaluateCostAndResiduals(original_problem_impl,
&summary->final_cost,
options.return_final_residuals
? &summary->final_residuals