Fix covariance computation for constant blocks
This commit fixes a bug related to the computation of covariance blocks
in the tangent space for constant parameter blocks, causing out of
bounds memory access.
Change-Id: Iaeee7992405fcaaae6086612798e96f2e10ebc5c
diff --git a/internal/ceres/covariance_impl.cc b/internal/ceres/covariance_impl.cc
index 3e8302b..cd823b3 100644
--- a/internal/ceres/covariance_impl.cc
+++ b/internal/ceres/covariance_impl.cc
@@ -120,9 +120,17 @@
ParameterBlock* block2 =
FindOrDie(parameter_map,
const_cast<double*>(original_parameter_block2));
+
const int block1_size = block1->Size();
const int block2_size = block2->Size();
- MatrixRef(covariance_block, block1_size, block2_size).setZero();
+ const int block1_local_size = block1->LocalSize();
+ const int block2_local_size = block2->LocalSize();
+ if (!lift_covariance_to_ambient_space) {
+ MatrixRef(covariance_block, block1_local_size, block2_local_size)
+ .setZero();
+ } else {
+ MatrixRef(covariance_block, block1_size, block2_size).setZero();
+ }
return true;
}
diff --git a/internal/ceres/covariance_test.cc b/internal/ceres/covariance_test.cc
index e47d991..c2b83e3 100644
--- a/internal/ceres/covariance_test.cc
+++ b/internal/ceres/covariance_test.cc
@@ -318,7 +318,7 @@
const double* expected_covariance) {
// Generate all possible combination of block pairs and check if the
// covariance computation is correct.
- for (int i = 1; i <= 64; ++i) {
+ for (int i = 0; i <= 64; ++i) {
vector<pair<const double*, const double*> > covariance_blocks;
if (i & 1) {
covariance_blocks.push_back(all_covariance_blocks_[0]);
@@ -676,6 +676,65 @@
ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
}
+TEST_F(CovarianceTest, LocalParameterizationInTangentSpaceWithConstantBlocks) {
+ double* x = parameters_;
+ double* y = x + 2;
+ double* z = y + 3;
+
+ problem_.SetParameterization(x, new PolynomialParameterization);
+ problem_.SetParameterBlockConstant(x);
+
+ vector<int> subset;
+ subset.push_back(2);
+ problem_.SetParameterization(y, new SubsetParameterization(3, subset));
+ problem_.SetParameterBlockConstant(y);
+
+ local_column_bounds_[x] = make_pair(0, 1);
+ local_column_bounds_[y] = make_pair(1, 3);
+ local_column_bounds_[z] = make_pair(3, 4);
+
+ // Raw Jacobian: J
+ //
+ // 1 0 0 0 0 0
+ // 0 1 0 0 0 0
+ // 0 0 2 0 0 0
+ // 0 0 0 2 0 0
+ // 0 0 0 0 2 0
+ // 0 0 0 0 0 5
+ // -5 -6 1 2 3 0
+ // 3 -2 0 0 0 2
+
+ // Local to global jacobian: A
+ //
+ // 0 0 0 0
+ // 0 0 0 0
+ // 0 0 0 0
+ // 0 0 0 0
+ // 0 0 0 0
+ // 0 0 0 1
+
+ // inv((J*A)'*(J*A))
+ // Computed using octave.
+ double expected_covariance[] = {
+ 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.034482 // NOLINT
+ };
+
+ Covariance::Options options;
+
+#ifndef CERES_NO_SUITESPARSE
+ options.algorithm_type = SUITE_SPARSE_QR;
+ ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
+#endif
+
+ options.algorithm_type = DENSE_SVD;
+ ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
+
+ options.algorithm_type = EIGEN_SPARSE_QR;
+ ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
+}
TEST_F(CovarianceTest, TruncatedRank) {
// J