diff --git a/rugnux/RigidBodyRefine.cpp b/rugnux/RigidBodyRefine.cpp index 8b36f44d5..e60339c57 100644 --- a/rugnux/RigidBodyRefine.cpp +++ b/rugnux/RigidBodyRefine.cpp @@ -214,8 +214,17 @@ public: bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override { const int n = num_residuals(); - if (!ev_.Residuals(parameters[0], residuals)) - return false; + // Ceres evaluates every step it accepts twice: the residuals alone to decide whether to take + // it, then residuals and Jacobian together at the same point. The residuals are a function of + // the placement alone, so the second time they are the first time's, copied. + if (!last_residuals_.empty() && std::equal(parameters[0], parameters[0] + 6, last_q_.begin())) { + std::copy(last_residuals_.begin(), last_residuals_.end(), residuals); + } else { + if (!ev_.Residuals(parameters[0], residuals)) + return false; + std::copy(parameters[0], parameters[0] + 6, last_q_.begin()); + last_residuals_.assign(residuals, residuals + n); + } if (jacobians != nullptr && jacobians[0] != nullptr) { const double step = ev_.JacobianStep(); std::vector> shifted(6, std::vector(n)); @@ -244,6 +253,8 @@ private: Evaluator &ev_; std::vector &columns_; size_t nthreads_; + mutable std::array last_q_{}; + mutable std::vector last_residuals_; // at last_q_; empty until an evaluation succeeds }; // The directions in which this space group's origin is free. Translating the whole cell content along