Ensure that partial evaluation of residuals triggers an error
ResidualBlock evaluation has logic to ensure that CostFunction
should always fill out the residual and jacobian arrays completely
by using a special value to pre-populate these arrays.
This works for CostFunctions with analytical Jacobians but not for
AutoDiffCostFunction and NumericDiffCostFunction Jacobians.
There is no way to fix this for NumericDiffCostFunctions without
introducing significant performance penalties but the residual
evaluation fails, which should be enough to catch such errors.
For AutoDiffCostFunction the way the Jets are default initialized
was sidestepping this check. So now, the Jet that is used to
capture the output residuals is now initialized with
kImpossibleValue, which will ensure that if the user forgets
to fill all output fields, it triggers an evaluation error.
This change required that ceres::internal::kImpossibleValue be moved
out of array_utils.h/cc to types.h.
Change-Id: I35bb0946cf0785a5d43c7b5459a2272848fb2a9b
diff --git a/internal/ceres/autodiff_cost_function_test.cc b/internal/ceres/autodiff_cost_function_test.cc
index 241fa0f..d14fb82 100644
--- a/internal/ceres/autodiff_cost_function_test.cc
+++ b/internal/ceres/autodiff_cost_function_test.cc
@@ -34,6 +34,7 @@
#include "gtest/gtest.h"
#include "ceres/cost_function.h"
+#include "ceres/array_utils.h"
namespace ceres {
namespace internal {
@@ -142,5 +143,30 @@
delete cost_function;
}
+struct OnlyFillsOneOutputFunctor {
+ template <typename T>
+ bool operator()(const T* x, T* output) const {
+ output[0] = x[0];
+ return true;
+ }
+};
+
+TEST(AutoDiffCostFunction, PartiallyFilledResidualShouldFailEvaluation) {
+ double parameter = 1.0;
+ double jacobian[2];
+ double residuals[2];
+ double* parameters[] = {¶meter};
+ double* jacobians[] = {jacobian};
+
+ scoped_ptr<CostFunction> cost_function(
+ new AutoDiffCostFunction<OnlyFillsOneOutputFunctor, 2, 1>(
+ new OnlyFillsOneOutputFunctor));
+ InvalidateArray(2, jacobian);
+ InvalidateArray(2, residuals);
+ EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, jacobians));
+ EXPECT_FALSE(IsArrayValid(2, jacobian));
+ EXPECT_FALSE(IsArrayValid(2, residuals));
+}
+
} // namespace internal
} // namespace ceres