diff --git a/include/ceres/tiny_solver.h b/include/ceres/tiny_solver.h index 9242cd079..f5cdfd878 100644 --- a/include/ceres/tiny_solver.h +++ b/include/ceres/tiny_solver.h @@ -286,14 +286,13 @@ class TinySolver { // model fits well. x = x_new_; + // TODO(sameeragarwal): Deal with failure. + Update(function, x); if (std::abs(cost_change) < options.function_tolerance) { - cost_ = f_x_new_.squaredNorm() / 2; summary.status = COST_CHANGE_TOO_SMALL; break; } - // TODO(sameeragarwal): Deal with failure. - Update(function, x); if (summary.gradient_max_norm < options.gradient_tolerance) { summary.status = GRADIENT_TOO_SMALL; break; @@ -329,6 +328,16 @@ class TinySolver { return summary; } + Eigen::Matrix Residuals() const { + // Residual updates are stored with the opposite sign. + return -residuals_; + } + + Eigen::Matrix Jacobian() const { + // Undo the scaling applied to the jacobian matrix during Update(). + return jacobian_ * jacobi_scaling_.cwiseInverse().asDiagonal(); + } + Options options; Summary summary; diff --git a/internal/ceres/tiny_solver_test.cc b/internal/ceres/tiny_solver_test.cc index 645ddc5ad..f8b92648f 100644 --- a/internal/ceres/tiny_solver_test.cc +++ b/internal/ceres/tiny_solver_test.cc @@ -121,6 +121,14 @@ void TestHelper(const Function& f, const Vector& x0) { TinySolver solver; solver.Solve(f, &x); EXPECT_NEAR(0.0, solver.summary.final_cost, 1e-10); + + // Getter methods for residuals and jacobian should match the corresponding + // values evaluated at the converged parameter value. + Vec2 expected_residuals; + Eigen::Matrix expected_jacobian; + f(x.data(), expected_residuals.data(), expected_jacobian.data()); + EXPECT_TRUE(expected_residuals.isApprox(solver.Residuals())); + EXPECT_TRUE(expected_jacobian.isApprox(solver.Jacobian())); } // A test case for when the cost function is statically sized.