Blame internal/ceres/covariance_test.cc

Packit ea1746
// Ceres Solver - A fast non-linear least squares minimizer
Packit ea1746
// Copyright 2015 Google Inc. All rights reserved.
Packit ea1746
// http://ceres-solver.org/
Packit ea1746
//
Packit ea1746
// Redistribution and use in source and binary forms, with or without
Packit ea1746
// modification, are permitted provided that the following conditions are met:
Packit ea1746
//
Packit ea1746
// * Redistributions of source code must retain the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer.
Packit ea1746
// * Redistributions in binary form must reproduce the above copyright notice,
Packit ea1746
//   this list of conditions and the following disclaimer in the documentation
Packit ea1746
//   and/or other materials provided with the distribution.
Packit ea1746
// * Neither the name of Google Inc. nor the names of its contributors may be
Packit ea1746
//   used to endorse or promote products derived from this software without
Packit ea1746
//   specific prior written permission.
Packit ea1746
//
Packit ea1746
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit ea1746
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit ea1746
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit ea1746
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit ea1746
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit ea1746
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit ea1746
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit ea1746
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit ea1746
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit ea1746
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit ea1746
// POSSIBILITY OF SUCH DAMAGE.
Packit ea1746
//
Packit ea1746
// Author: sameeragarwal@google.com (Sameer Agarwal)
Packit ea1746
Packit ea1746
#include "ceres/covariance.h"
Packit ea1746
Packit ea1746
#include <algorithm>
Packit ea1746
#include <cmath>
Packit ea1746
#include <map>
Packit ea1746
#include <utility>
Packit ea1746
#include "ceres/compressed_row_sparse_matrix.h"
Packit ea1746
#include "ceres/cost_function.h"
Packit ea1746
#include "ceres/covariance_impl.h"
Packit ea1746
#include "ceres/local_parameterization.h"
Packit ea1746
#include "ceres/map_util.h"
Packit ea1746
#include "ceres/problem_impl.h"
Packit ea1746
#include "gtest/gtest.h"
Packit ea1746
Packit ea1746
namespace ceres {
Packit ea1746
namespace internal {
Packit ea1746
Packit ea1746
using std::make_pair;
Packit ea1746
using std::map;
Packit ea1746
using std::pair;
Packit ea1746
using std::vector;
Packit ea1746
Packit ea1746
class UnaryCostFunction: public CostFunction {
Packit ea1746
 public:
Packit ea1746
  UnaryCostFunction(const int num_residuals,
Packit ea1746
                    const int32 parameter_block_size,
Packit ea1746
                    const double* jacobian)
Packit ea1746
      : jacobian_(jacobian, jacobian + num_residuals * parameter_block_size) {
Packit ea1746
    set_num_residuals(num_residuals);
Packit ea1746
    mutable_parameter_block_sizes()->push_back(parameter_block_size);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    for (int i = 0; i < num_residuals(); ++i) {
Packit ea1746
      residuals[i] = 1;
Packit ea1746
    }
Packit ea1746
Packit ea1746
    if (jacobians == NULL) {
Packit ea1746
      return true;
Packit ea1746
    }
Packit ea1746
Packit ea1746
    if (jacobians[0] != NULL) {
Packit ea1746
      copy(jacobian_.begin(), jacobian_.end(), jacobians[0]);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
 private:
Packit ea1746
  vector<double> jacobian_;
Packit ea1746
};
Packit ea1746
Packit ea1746
Packit ea1746
class BinaryCostFunction: public CostFunction {
Packit ea1746
 public:
Packit ea1746
  BinaryCostFunction(const int num_residuals,
Packit ea1746
                     const int32 parameter_block1_size,
Packit ea1746
                     const int32 parameter_block2_size,
Packit ea1746
                     const double* jacobian1,
Packit ea1746
                     const double* jacobian2)
Packit ea1746
      : jacobian1_(jacobian1,
Packit ea1746
                   jacobian1 + num_residuals * parameter_block1_size),
Packit ea1746
        jacobian2_(jacobian2,
Packit ea1746
                   jacobian2 + num_residuals * parameter_block2_size) {
Packit ea1746
    set_num_residuals(num_residuals);
Packit ea1746
    mutable_parameter_block_sizes()->push_back(parameter_block1_size);
Packit ea1746
    mutable_parameter_block_sizes()->push_back(parameter_block2_size);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  virtual bool Evaluate(double const* const* parameters,
Packit ea1746
                        double* residuals,
Packit ea1746
                        double** jacobians) const {
Packit ea1746
    for (int i = 0; i < num_residuals(); ++i) {
Packit ea1746
      residuals[i] = 2;
Packit ea1746
    }
Packit ea1746
Packit ea1746
    if (jacobians == NULL) {
Packit ea1746
      return true;
Packit ea1746
    }
Packit ea1746
Packit ea1746
    if (jacobians[0] != NULL) {
Packit ea1746
      copy(jacobian1_.begin(), jacobian1_.end(), jacobians[0]);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    if (jacobians[1] != NULL) {
Packit ea1746
      copy(jacobian2_.begin(), jacobian2_.end(), jacobians[1]);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
 private:
Packit ea1746
  vector<double> jacobian1_;
Packit ea1746
  vector<double> jacobian2_;
Packit ea1746
};
Packit ea1746
Packit ea1746
// x_plus_delta = delta * x;
Packit ea1746
class PolynomialParameterization : public LocalParameterization {
Packit ea1746
 public:
Packit ea1746
  virtual ~PolynomialParameterization() {}
Packit ea1746
Packit ea1746
  virtual bool Plus(const double* x,
Packit ea1746
                    const double* delta,
Packit ea1746
                    double* x_plus_delta) const {
Packit ea1746
    x_plus_delta[0] = delta[0] * x[0];
Packit ea1746
    x_plus_delta[1] = delta[0] * x[1];
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  virtual bool ComputeJacobian(const double* x, double* jacobian) const {
Packit ea1746
    jacobian[0] = x[0];
Packit ea1746
    jacobian[1] = x[1];
Packit ea1746
    return true;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  virtual int GlobalSize() const { return 2; }
Packit ea1746
  virtual int LocalSize() const { return 1; }
Packit ea1746
};
Packit ea1746
Packit ea1746
TEST(CovarianceImpl, ComputeCovarianceSparsity) {
Packit ea1746
  double parameters[10];
Packit ea1746
Packit ea1746
  double* block1 = parameters;
Packit ea1746
  double* block2 = block1 + 1;
Packit ea1746
  double* block3 = block2 + 2;
Packit ea1746
  double* block4 = block3 + 3;
Packit ea1746
Packit ea1746
  ProblemImpl problem;
Packit ea1746
Packit ea1746
  // Add in random order
Packit ea1746
  Vector junk_jacobian = Vector::Zero(10);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 3, junk_jacobian.data()), NULL, block3);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
Packit ea1746
Packit ea1746
  // Sparsity pattern
Packit ea1746
  //
Packit ea1746
  // Note that the problem structure does not imply this sparsity
Packit ea1746
  // pattern since all the residual blocks are unary. But the
Packit ea1746
  // ComputeCovarianceSparsity function in its current incarnation
Packit ea1746
  // does not pay attention to this fact and only looks at the
Packit ea1746
  // parameter block pairs that the user provides.
Packit ea1746
  //
Packit ea1746
  //  X . . . . . X X X X
Packit ea1746
  //  . X X X X X . . . .
Packit ea1746
  //  . X X X X X . . . .
Packit ea1746
  //  . . . X X X . . . .
Packit ea1746
  //  . . . X X X . . . .
Packit ea1746
  //  . . . X X X . . . .
Packit ea1746
  //  . . . . . . X X X X
Packit ea1746
  //  . . . . . . X X X X
Packit ea1746
  //  . . . . . . X X X X
Packit ea1746
  //  . . . . . . X X X X
Packit ea1746
Packit ea1746
  int expected_rows[] = {0, 5, 10, 15, 18, 21, 24, 28, 32, 36, 40};
Packit ea1746
  int expected_cols[] = {0, 6, 7, 8, 9,
Packit ea1746
                         1, 2, 3, 4, 5,
Packit ea1746
                         1, 2, 3, 4, 5,
Packit ea1746
                         3, 4, 5,
Packit ea1746
                         3, 4, 5,
Packit ea1746
                         3, 4, 5,
Packit ea1746
                         6, 7, 8, 9,
Packit ea1746
                         6, 7, 8, 9,
Packit ea1746
                         6, 7, 8, 9,
Packit ea1746
                         6, 7, 8, 9};
Packit ea1746
Packit ea1746
Packit ea1746
  vector<pair<const double*, const double*> > covariance_blocks;
Packit ea1746
  covariance_blocks.push_back(make_pair(block1, block1));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block4));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block2));
Packit ea1746
  covariance_blocks.push_back(make_pair(block3, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
  CovarianceImpl covariance_impl(options);
Packit ea1746
  EXPECT_TRUE(covariance_impl
Packit ea1746
              .ComputeCovarianceSparsity(covariance_blocks, &problem));
Packit ea1746
Packit ea1746
  const CompressedRowSparseMatrix* crsm = covariance_impl.covariance_matrix();
Packit ea1746
Packit ea1746
  EXPECT_EQ(crsm->num_rows(), 10);
Packit ea1746
  EXPECT_EQ(crsm->num_cols(), 10);
Packit ea1746
  EXPECT_EQ(crsm->num_nonzeros(), 40);
Packit ea1746
Packit ea1746
  const int* rows = crsm->rows();
Packit ea1746
  for (int r = 0; r < crsm->num_rows() + 1; ++r) {
Packit ea1746
    EXPECT_EQ(rows[r], expected_rows[r])
Packit ea1746
        << r << " "
Packit ea1746
        << rows[r] << " "
Packit ea1746
        << expected_rows[r];
Packit ea1746
  }
Packit ea1746
Packit ea1746
  const int* cols = crsm->cols();
Packit ea1746
  for (int c = 0; c < crsm->num_nonzeros(); ++c) {
Packit ea1746
    EXPECT_EQ(cols[c], expected_cols[c])
Packit ea1746
        << c << " "
Packit ea1746
        << cols[c] << " "
Packit ea1746
        << expected_cols[c];
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST(CovarianceImpl, ComputeCovarianceSparsityWithConstantParameterBlock) {
Packit ea1746
  double parameters[10];
Packit ea1746
Packit ea1746
  double* block1 = parameters;
Packit ea1746
  double* block2 = block1 + 1;
Packit ea1746
  double* block3 = block2 + 2;
Packit ea1746
  double* block4 = block3 + 3;
Packit ea1746
Packit ea1746
  ProblemImpl problem;
Packit ea1746
Packit ea1746
  // Add in random order
Packit ea1746
  Vector junk_jacobian = Vector::Zero(10);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 3, junk_jacobian.data()), NULL, block3);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
Packit ea1746
  problem.SetParameterBlockConstant(block3);
Packit ea1746
Packit ea1746
  // Sparsity pattern
Packit ea1746
  //
Packit ea1746
  // Note that the problem structure does not imply this sparsity
Packit ea1746
  // pattern since all the residual blocks are unary. But the
Packit ea1746
  // ComputeCovarianceSparsity function in its current incarnation
Packit ea1746
  // does not pay attention to this fact and only looks at the
Packit ea1746
  // parameter block pairs that the user provides.
Packit ea1746
  //
Packit ea1746
  //  X . . X X X X
Packit ea1746
  //  . X X . . . .
Packit ea1746
  //  . X X . . . .
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
Packit ea1746
  int expected_rows[] = {0, 5, 7, 9, 13, 17, 21, 25};
Packit ea1746
  int expected_cols[] = {0, 3, 4, 5, 6,
Packit ea1746
                         1, 2,
Packit ea1746
                         1, 2,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6};
Packit ea1746
Packit ea1746
  vector<pair<const double*, const double*> > covariance_blocks;
Packit ea1746
  covariance_blocks.push_back(make_pair(block1, block1));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block4));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block2));
Packit ea1746
  covariance_blocks.push_back(make_pair(block3, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
  CovarianceImpl covariance_impl(options);
Packit ea1746
  EXPECT_TRUE(covariance_impl
Packit ea1746
              .ComputeCovarianceSparsity(covariance_blocks, &problem));
Packit ea1746
Packit ea1746
  const CompressedRowSparseMatrix* crsm = covariance_impl.covariance_matrix();
Packit ea1746
Packit ea1746
  EXPECT_EQ(crsm->num_rows(), 7);
Packit ea1746
  EXPECT_EQ(crsm->num_cols(), 7);
Packit ea1746
  EXPECT_EQ(crsm->num_nonzeros(), 25);
Packit ea1746
Packit ea1746
  const int* rows = crsm->rows();
Packit ea1746
  for (int r = 0; r < crsm->num_rows() + 1; ++r) {
Packit ea1746
    EXPECT_EQ(rows[r], expected_rows[r])
Packit ea1746
        << r << " "
Packit ea1746
        << rows[r] << " "
Packit ea1746
        << expected_rows[r];
Packit ea1746
  }
Packit ea1746
Packit ea1746
  const int* cols = crsm->cols();
Packit ea1746
  for (int c = 0; c < crsm->num_nonzeros(); ++c) {
Packit ea1746
    EXPECT_EQ(cols[c], expected_cols[c])
Packit ea1746
        << c << " "
Packit ea1746
        << cols[c] << " "
Packit ea1746
        << expected_cols[c];
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST(CovarianceImpl, ComputeCovarianceSparsityWithFreeParameterBlock) {
Packit ea1746
  double parameters[10];
Packit ea1746
Packit ea1746
  double* block1 = parameters;
Packit ea1746
  double* block2 = block1 + 1;
Packit ea1746
  double* block3 = block2 + 2;
Packit ea1746
  double* block4 = block3 + 3;
Packit ea1746
Packit ea1746
  ProblemImpl problem;
Packit ea1746
Packit ea1746
  // Add in random order
Packit ea1746
  Vector junk_jacobian = Vector::Zero(10);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
Packit ea1746
  problem.AddParameterBlock(block3, 3);
Packit ea1746
  problem.AddResidualBlock(
Packit ea1746
      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
Packit ea1746
Packit ea1746
  // Sparsity pattern
Packit ea1746
  //
Packit ea1746
  // Note that the problem structure does not imply this sparsity
Packit ea1746
  // pattern since all the residual blocks are unary. But the
Packit ea1746
  // ComputeCovarianceSparsity function in its current incarnation
Packit ea1746
  // does not pay attention to this fact and only looks at the
Packit ea1746
  // parameter block pairs that the user provides.
Packit ea1746
  //
Packit ea1746
  //  X . . X X X X
Packit ea1746
  //  . X X . . . .
Packit ea1746
  //  . X X . . . .
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
  //  . . . X X X X
Packit ea1746
Packit ea1746
  int expected_rows[] = {0, 5, 7, 9, 13, 17, 21, 25};
Packit ea1746
  int expected_cols[] = {0, 3, 4, 5, 6,
Packit ea1746
                         1, 2,
Packit ea1746
                         1, 2,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6,
Packit ea1746
                         3, 4, 5, 6};
Packit ea1746
Packit ea1746
  vector<pair<const double*, const double*> > covariance_blocks;
Packit ea1746
  covariance_blocks.push_back(make_pair(block1, block1));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block4));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block2));
Packit ea1746
  covariance_blocks.push_back(make_pair(block3, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block2, block3));
Packit ea1746
  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
  CovarianceImpl covariance_impl(options);
Packit ea1746
  EXPECT_TRUE(covariance_impl
Packit ea1746
              .ComputeCovarianceSparsity(covariance_blocks, &problem));
Packit ea1746
Packit ea1746
  const CompressedRowSparseMatrix* crsm = covariance_impl.covariance_matrix();
Packit ea1746
Packit ea1746
  EXPECT_EQ(crsm->num_rows(), 7);
Packit ea1746
  EXPECT_EQ(crsm->num_cols(), 7);
Packit ea1746
  EXPECT_EQ(crsm->num_nonzeros(), 25);
Packit ea1746
Packit ea1746
  const int* rows = crsm->rows();
Packit ea1746
  for (int r = 0; r < crsm->num_rows() + 1; ++r) {
Packit ea1746
    EXPECT_EQ(rows[r], expected_rows[r])
Packit ea1746
        << r << " "
Packit ea1746
        << rows[r] << " "
Packit ea1746
        << expected_rows[r];
Packit ea1746
  }
Packit ea1746
Packit ea1746
  const int* cols = crsm->cols();
Packit ea1746
  for (int c = 0; c < crsm->num_nonzeros(); ++c) {
Packit ea1746
    EXPECT_EQ(cols[c], expected_cols[c])
Packit ea1746
        << c << " "
Packit ea1746
        << cols[c] << " "
Packit ea1746
        << expected_cols[c];
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
class CovarianceTest : public ::testing::Test {
Packit ea1746
 protected:
Packit ea1746
  typedef map<const double*, pair<int, int> > BoundsMap;
Packit ea1746
Packit ea1746
  virtual void SetUp() {
Packit ea1746
    double* x = parameters_;
Packit ea1746
    double* y = x + 2;
Packit ea1746
    double* z = y + 3;
Packit ea1746
Packit ea1746
    x[0] = 1;
Packit ea1746
    x[1] = 1;
Packit ea1746
    y[0] = 2;
Packit ea1746
    y[1] = 2;
Packit ea1746
    y[2] = 2;
Packit ea1746
    z[0] = 3;
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian[] = { 1.0, 0.0, 0.0, 1.0};
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(2, 2, jacobian), NULL, x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian[] = { 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0 };
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(3, 3, jacobian), NULL, y);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian = 5.0;
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(1, 1, &jacobian),
Packit ea1746
                                NULL,
Packit ea1746
                                z);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian1[] = { 1.0, 2.0, 3.0 };
Packit ea1746
      double jacobian2[] = { -5.0, -6.0 };
Packit ea1746
      problem_.AddResidualBlock(
Packit ea1746
          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2),
Packit ea1746
          NULL,
Packit ea1746
          y,
Packit ea1746
          x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian1[] = {2.0 };
Packit ea1746
      double jacobian2[] = { 3.0, -2.0 };
Packit ea1746
      problem_.AddResidualBlock(
Packit ea1746
          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2),
Packit ea1746
          NULL,
Packit ea1746
          z,
Packit ea1746
          x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, x));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(y, y));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(z, z));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, y));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, z));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(y, z));
Packit ea1746
Packit ea1746
    column_bounds_[x] = make_pair(0, 2);
Packit ea1746
    column_bounds_[y] = make_pair(2, 5);
Packit ea1746
    column_bounds_[z] = make_pair(5, 6);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Computes covariance in ambient space.
Packit ea1746
  void ComputeAndCompareCovarianceBlocks(const Covariance::Options& options,
Packit ea1746
                                         const double* expected_covariance) {
Packit ea1746
    ComputeAndCompareCovarianceBlocksInTangentOrAmbientSpace(
Packit ea1746
        options,
Packit ea1746
        true,  // ambient
Packit ea1746
        expected_covariance);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  // Computes covariance in tangent space.
Packit ea1746
  void ComputeAndCompareCovarianceBlocksInTangentSpace(
Packit ea1746
                                         const Covariance::Options& options,
Packit ea1746
                                         const double* expected_covariance) {
Packit ea1746
    ComputeAndCompareCovarianceBlocksInTangentOrAmbientSpace(
Packit ea1746
        options,
Packit ea1746
        false,  // tangent
Packit ea1746
        expected_covariance);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  void ComputeAndCompareCovarianceBlocksInTangentOrAmbientSpace(
Packit ea1746
      const Covariance::Options& options,
Packit ea1746
      bool lift_covariance_to_ambient_space,
Packit ea1746
      const double* expected_covariance) {
Packit ea1746
    // Generate all possible combination of block pairs and check if the
Packit ea1746
    // covariance computation is correct.
Packit ea1746
    for (int i = 0; i <= 64; ++i) {
Packit ea1746
      vector<pair<const double*, const double*> > covariance_blocks;
Packit ea1746
      if (i & 1) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[0]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      if (i & 2) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[1]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      if (i & 4) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[2]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      if (i & 8) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[3]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      if (i & 16) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[4]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      if (i & 32) {
Packit ea1746
        covariance_blocks.push_back(all_covariance_blocks_[5]);
Packit ea1746
      }
Packit ea1746
Packit ea1746
      Covariance covariance(options);
Packit ea1746
      EXPECT_TRUE(covariance.Compute(covariance_blocks, &problem_));
Packit ea1746
Packit ea1746
      for (int i = 0; i < covariance_blocks.size(); ++i) {
Packit ea1746
        const double* block1 = covariance_blocks[i].first;
Packit ea1746
        const double* block2 = covariance_blocks[i].second;
Packit ea1746
        // block1, block2
Packit ea1746
        GetCovarianceBlockAndCompare(block1,
Packit ea1746
                                     block2,
Packit ea1746
                                     lift_covariance_to_ambient_space,
Packit ea1746
                                     covariance,
Packit ea1746
                                     expected_covariance);
Packit ea1746
        // block2, block1
Packit ea1746
        GetCovarianceBlockAndCompare(block2,
Packit ea1746
                                     block1,
Packit ea1746
                                     lift_covariance_to_ambient_space,
Packit ea1746
                                     covariance,
Packit ea1746
                                     expected_covariance);
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  void GetCovarianceBlockAndCompare(const double* block1,
Packit ea1746
                                    const double* block2,
Packit ea1746
                                    bool lift_covariance_to_ambient_space,
Packit ea1746
                                    const Covariance& covariance,
Packit ea1746
                                    const double* expected_covariance) {
Packit ea1746
    const BoundsMap& column_bounds = lift_covariance_to_ambient_space ?
Packit ea1746
        column_bounds_ : local_column_bounds_;
Packit ea1746
    const int row_begin = FindOrDie(column_bounds, block1).first;
Packit ea1746
    const int row_end = FindOrDie(column_bounds, block1).second;
Packit ea1746
    const int col_begin = FindOrDie(column_bounds, block2).first;
Packit ea1746
    const int col_end = FindOrDie(column_bounds, block2).second;
Packit ea1746
Packit ea1746
    Matrix actual(row_end - row_begin, col_end - col_begin);
Packit ea1746
    if (lift_covariance_to_ambient_space) {
Packit ea1746
      EXPECT_TRUE(covariance.GetCovarianceBlock(block1,
Packit ea1746
                                                block2,
Packit ea1746
                                                actual.data()));
Packit ea1746
    } else {
Packit ea1746
      EXPECT_TRUE(covariance.GetCovarianceBlockInTangentSpace(block1,
Packit ea1746
                                                              block2,
Packit ea1746
                                                              actual.data()));
Packit ea1746
    }
Packit ea1746
Packit ea1746
    int dof = 0;  // degrees of freedom = sum of LocalSize()s
Packit ea1746
    for (BoundsMap::const_iterator iter = column_bounds.begin();
Packit ea1746
         iter != column_bounds.end(); ++iter) {
Packit ea1746
      dof = std::max(dof, iter->second.second);
Packit ea1746
    }
Packit ea1746
    ConstMatrixRef expected(expected_covariance, dof, dof);
Packit ea1746
    double diff_norm = (expected.block(row_begin,
Packit ea1746
                                       col_begin,
Packit ea1746
                                       row_end - row_begin,
Packit ea1746
                                       col_end - col_begin) - actual).norm();
Packit ea1746
    diff_norm /= (row_end - row_begin) * (col_end - col_begin);
Packit ea1746
Packit ea1746
    const double kTolerance = 1e-5;
Packit ea1746
    EXPECT_NEAR(diff_norm, 0.0, kTolerance)
Packit ea1746
        << "rows: " << row_begin << " " << row_end << "  "
Packit ea1746
        << "cols: " << col_begin << " " << col_end << "  "
Packit ea1746
        << "\n\n expected: \n " << expected.block(row_begin,
Packit ea1746
                                                  col_begin,
Packit ea1746
                                                  row_end - row_begin,
Packit ea1746
                                                  col_end - col_begin)
Packit ea1746
        << "\n\n actual: \n " << actual
Packit ea1746
        << "\n\n full expected: \n" << expected;
Packit ea1746
  }
Packit ea1746
Packit ea1746
  double parameters_[6];
Packit ea1746
  Problem problem_;
Packit ea1746
  vector<pair<const double*, const double*> > all_covariance_blocks_;
Packit ea1746
  BoundsMap column_bounds_;
Packit ea1746
  BoundsMap local_column_bounds_;
Packit ea1746
};
Packit ea1746
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, NormalBehavior) {
Packit ea1746
  // J
Packit ea1746
  //
Packit ea1746
  //   1  0  0  0  0  0
Packit ea1746
  //   0  1  0  0  0  0
Packit ea1746
  //   0  0  2  0  0  0
Packit ea1746
  //   0  0  0  2  0  0
Packit ea1746
  //   0  0  0  0  2  0
Packit ea1746
  //   0  0  0  0  0  5
Packit ea1746
  //  -5 -6  1  2  3  0
Packit ea1746
  //   3 -2  0  0  0  2
Packit ea1746
Packit ea1746
  // J'J
Packit ea1746
  //
Packit ea1746
  //   35  24 -5 -10 -15  6
Packit ea1746
  //   24  41 -6 -12 -18 -4
Packit ea1746
  //   -5  -6  5   2   3  0
Packit ea1746
  //  -10 -12  2   8   6  0
Packit ea1746
  //  -15 -18  3   6  13  0
Packit ea1746
  //    6  -4  0   0   0 29
Packit ea1746
Packit ea1746
  // inv(J'J) computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
     7.0747e-02,  -8.4923e-03,   1.6821e-02,   3.3643e-02,   5.0464e-02,  -1.5809e-02,  // NOLINT
Packit ea1746
    -8.4923e-03,   8.1352e-02,   2.4758e-02,   4.9517e-02,   7.4275e-02,   1.2978e-02,  // NOLINT
Packit ea1746
     1.6821e-02,   2.4758e-02,   2.4904e-01,  -1.9271e-03,  -2.8906e-03,  -6.5325e-05,  // NOLINT
Packit ea1746
     3.3643e-02,   4.9517e-02,  -1.9271e-03,   2.4615e-01,  -5.7813e-03,  -1.3065e-04,  // NOLINT
Packit ea1746
     5.0464e-02,   7.4275e-02,  -2.8906e-03,  -5.7813e-03,   2.4133e-01,  -1.9598e-04,  // NOLINT
Packit ea1746
    -1.5809e-02,   1.2978e-02,  -6.5325e-05,  -1.3065e-04,  -1.9598e-04,   3.9544e-02,  // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
#ifdef CERES_USE_OPENMP
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, ThreadedNormalBehavior) {
Packit ea1746
  // J
Packit ea1746
  //
Packit ea1746
  //   1  0  0  0  0  0
Packit ea1746
  //   0  1  0  0  0  0
Packit ea1746
  //   0  0  2  0  0  0
Packit ea1746
  //   0  0  0  2  0  0
Packit ea1746
  //   0  0  0  0  2  0
Packit ea1746
  //   0  0  0  0  0  5
Packit ea1746
  //  -5 -6  1  2  3  0
Packit ea1746
  //   3 -2  0  0  0  2
Packit ea1746
Packit ea1746
  // J'J
Packit ea1746
  //
Packit ea1746
  //   35  24 -5 -10 -15  6
Packit ea1746
  //   24  41 -6 -12 -18 -4
Packit ea1746
  //   -5  -6  5   2   3  0
Packit ea1746
  //  -10 -12  2   8   6  0
Packit ea1746
  //  -15 -18  3   6  13  0
Packit ea1746
  //    6  -4  0   0   0 29
Packit ea1746
Packit ea1746
  // inv(J'J) computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
     7.0747e-02,  -8.4923e-03,   1.6821e-02,   3.3643e-02,   5.0464e-02,  -1.5809e-02,  // NOLINT
Packit ea1746
    -8.4923e-03,   8.1352e-02,   2.4758e-02,   4.9517e-02,   7.4275e-02,   1.2978e-02,  // NOLINT
Packit ea1746
     1.6821e-02,   2.4758e-02,   2.4904e-01,  -1.9271e-03,  -2.8906e-03,  -6.5325e-05,  // NOLINT
Packit ea1746
     3.3643e-02,   4.9517e-02,  -1.9271e-03,   2.4615e-01,  -5.7813e-03,  -1.3065e-04,  // NOLINT
Packit ea1746
     5.0464e-02,   7.4275e-02,  -2.8906e-03,  -5.7813e-03,   2.4133e-01,  -1.9598e-04,  // NOLINT
Packit ea1746
    -1.5809e-02,   1.2978e-02,  -6.5325e-05,  -1.3065e-04,  -1.9598e-04,   3.9544e-02,  // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
  options.num_threads = 4;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
#endif  // CERES_USE_OPENMP
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, ConstantParameterBlock) {
Packit ea1746
  problem_.SetParameterBlockConstant(parameters_);
Packit ea1746
Packit ea1746
  // J
Packit ea1746
  //
Packit ea1746
  //  0  0  0  0  0  0
Packit ea1746
  //  0  0  0  0  0  0
Packit ea1746
  //  0  0  2  0  0  0
Packit ea1746
  //  0  0  0  2  0  0
Packit ea1746
  //  0  0  0  0  2  0
Packit ea1746
  //  0  0  0  0  0  5
Packit ea1746
  //  0  0  1  2  3  0
Packit ea1746
  //  0  0  0  0  0  2
Packit ea1746
Packit ea1746
  // J'J
Packit ea1746
  //
Packit ea1746
  //  0  0  0  0  0  0
Packit ea1746
  //  0  0  0  0  0  0
Packit ea1746
  //  0  0  5  2  3  0
Packit ea1746
  //  0  0  2  8  6  0
Packit ea1746
  //  0  0  3  6 13  0
Packit ea1746
  //  0  0  0  0  0 29
Packit ea1746
Packit ea1746
  // pinv(J'J) computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
              0,            0,            0,            0,            0,            0,  // NOLINT
Packit ea1746
              0,            0,            0,            0,            0,            0,  // NOLINT
Packit ea1746
              0,            0,      0.23611,     -0.02778,     -0.04167,     -0.00000,  // NOLINT
Packit ea1746
              0,            0,     -0.02778,      0.19444,     -0.08333,     -0.00000,  // NOLINT
Packit ea1746
              0,            0,     -0.04167,     -0.08333,      0.12500,     -0.00000,  // NOLINT
Packit ea1746
              0,            0,     -0.00000,     -0.00000,     -0.00000,      0.03448   // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, LocalParameterization) {
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
Packit ea1746
  problem_.SetParameterization(x, new PolynomialParameterization);
Packit ea1746
Packit ea1746
  vector<int> subset;
Packit ea1746
  subset.push_back(2);
Packit ea1746
  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
Packit ea1746
Packit ea1746
  // Raw Jacobian: J
Packit ea1746
  //
Packit ea1746
  //   1   0  0  0  0  0
Packit ea1746
  //   0   1  0  0  0  0
Packit ea1746
  //   0   0  2  0  0  0
Packit ea1746
  //   0   0  0  2  0  0
Packit ea1746
  //   0   0  0  0  2  0
Packit ea1746
  //   0   0  0  0  0  5
Packit ea1746
  //  -5  -6  1  2  3  0
Packit ea1746
  //   3  -2  0  0  0  2
Packit ea1746
Packit ea1746
  // Local to global jacobian: A
Packit ea1746
  //
Packit ea1746
  //  1   0   0   0
Packit ea1746
  //  1   0   0   0
Packit ea1746
  //  0   1   0   0
Packit ea1746
  //  0   0   1   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   1
Packit ea1746
Packit ea1746
  // A * inv((J*A)'*(J*A)) * A'
Packit ea1746
  // Computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
    0.01766,   0.01766,   0.02158,   0.04316,   0.00000,  -0.00122,
Packit ea1746
    0.01766,   0.01766,   0.02158,   0.04316,   0.00000,  -0.00122,
Packit ea1746
    0.02158,   0.02158,   0.24860,  -0.00281,   0.00000,  -0.00149,
Packit ea1746
    0.04316,   0.04316,  -0.00281,   0.24439,   0.00000,  -0.00298,
Packit ea1746
    0.00000,   0.00000,   0.00000,   0.00000,   0.00000,   0.00000,
Packit ea1746
   -0.00122,  -0.00122,  -0.00149,  -0.00298,   0.00000,   0.03457
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, LocalParameterizationInTangentSpace) {
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  double* z = y + 3;
Packit ea1746
Packit ea1746
  problem_.SetParameterization(x, new PolynomialParameterization);
Packit ea1746
Packit ea1746
  vector<int> subset;
Packit ea1746
  subset.push_back(2);
Packit ea1746
  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
Packit ea1746
Packit ea1746
  local_column_bounds_[x] = make_pair(0, 1);
Packit ea1746
  local_column_bounds_[y] = make_pair(1, 3);
Packit ea1746
  local_column_bounds_[z] = make_pair(3, 4);
Packit ea1746
Packit ea1746
  // Raw Jacobian: J
Packit ea1746
  //
Packit ea1746
  //   1   0  0  0  0  0
Packit ea1746
  //   0   1  0  0  0  0
Packit ea1746
  //   0   0  2  0  0  0
Packit ea1746
  //   0   0  0  2  0  0
Packit ea1746
  //   0   0  0  0  2  0
Packit ea1746
  //   0   0  0  0  0  5
Packit ea1746
  //  -5  -6  1  2  3  0
Packit ea1746
  //   3  -2  0  0  0  2
Packit ea1746
Packit ea1746
  // Local to global jacobian: A
Packit ea1746
  //
Packit ea1746
  //  1   0   0   0
Packit ea1746
  //  1   0   0   0
Packit ea1746
  //  0   1   0   0
Packit ea1746
  //  0   0   1   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   1
Packit ea1746
Packit ea1746
  // inv((J*A)'*(J*A))
Packit ea1746
  // Computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
    0.01766,   0.02158,   0.04316,   -0.00122,
Packit ea1746
    0.02158,   0.24860,  -0.00281,   -0.00149,
Packit ea1746
    0.04316,  -0.00281,   0.24439,   -0.00298,
Packit ea1746
   -0.00122,  -0.00149,  -0.00298,    0.03457  // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, LocalParameterizationInTangentSpaceWithConstantBlocks) {
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  double* z = y + 3;
Packit ea1746
Packit ea1746
  problem_.SetParameterization(x, new PolynomialParameterization);
Packit ea1746
  problem_.SetParameterBlockConstant(x);
Packit ea1746
Packit ea1746
  vector<int> subset;
Packit ea1746
  subset.push_back(2);
Packit ea1746
  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
Packit ea1746
  problem_.SetParameterBlockConstant(y);
Packit ea1746
Packit ea1746
  local_column_bounds_[x] = make_pair(0, 1);
Packit ea1746
  local_column_bounds_[y] = make_pair(1, 3);
Packit ea1746
  local_column_bounds_[z] = make_pair(3, 4);
Packit ea1746
Packit ea1746
  // Raw Jacobian: J
Packit ea1746
  //
Packit ea1746
  //   1   0  0  0  0  0
Packit ea1746
  //   0   1  0  0  0  0
Packit ea1746
  //   0   0  2  0  0  0
Packit ea1746
  //   0   0  0  2  0  0
Packit ea1746
  //   0   0  0  0  2  0
Packit ea1746
  //   0   0  0  0  0  5
Packit ea1746
  //  -5  -6  1  2  3  0
Packit ea1746
  //   3  -2  0  0  0  2
Packit ea1746
Packit ea1746
  // Local to global jacobian: A
Packit ea1746
  //
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   0
Packit ea1746
  //  0   0   0   1
Packit ea1746
Packit ea1746
  // pinv((J*A)'*(J*A))
Packit ea1746
  // Computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
    0.0, 0.0, 0.0, 0.0,
Packit ea1746
    0.0, 0.0, 0.0, 0.0,
Packit ea1746
    0.0, 0.0, 0.0, 0.0,
Packit ea1746
    0.0, 0.0, 0.0, 0.034482 // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, TruncatedRank) {
Packit ea1746
  // J
Packit ea1746
  //
Packit ea1746
  //   1  0  0  0  0  0
Packit ea1746
  //   0  1  0  0  0  0
Packit ea1746
  //   0  0  2  0  0  0
Packit ea1746
  //   0  0  0  2  0  0
Packit ea1746
  //   0  0  0  0  2  0
Packit ea1746
  //   0  0  0  0  0  5
Packit ea1746
  //  -5 -6  1  2  3  0
Packit ea1746
  //   3 -2  0  0  0  2
Packit ea1746
Packit ea1746
  // J'J
Packit ea1746
  //
Packit ea1746
  //   35  24 -5 -10 -15  6
Packit ea1746
  //   24  41 -6 -12 -18 -4
Packit ea1746
  //   -5  -6  5   2   3  0
Packit ea1746
  //  -10 -12  2   8   6  0
Packit ea1746
  //  -15 -18  3   6  13  0
Packit ea1746
  //    6  -4  0   0   0 29
Packit ea1746
Packit ea1746
  // 3.4142 is the smallest eigen value of J'J. The following matrix
Packit ea1746
  // was obtained by dropping the eigenvector corresponding to this
Packit ea1746
  // eigenvalue.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
     5.4135e-02,  -3.5121e-02,   1.7257e-04,   3.4514e-04,   5.1771e-04,  -1.6076e-02,  // NOLINT
Packit ea1746
    -3.5121e-02,   3.8667e-02,  -1.9288e-03,  -3.8576e-03,  -5.7864e-03,   1.2549e-02,  // NOLINT
Packit ea1746
     1.7257e-04,  -1.9288e-03,   2.3235e-01,  -3.5297e-02,  -5.2946e-02,  -3.3329e-04,  // NOLINT
Packit ea1746
     3.4514e-04,  -3.8576e-03,  -3.5297e-02,   1.7941e-01,  -1.0589e-01,  -6.6659e-04,  // NOLINT
Packit ea1746
     5.1771e-04,  -5.7864e-03,  -5.2946e-02,  -1.0589e-01,   9.1162e-02,  -9.9988e-04,  // NOLINT
Packit ea1746
    -1.6076e-02,   1.2549e-02,  -3.3329e-04,  -6.6659e-04,  -9.9988e-04,   3.9539e-02   // NOLINT
Packit ea1746
  };
Packit ea1746
Packit ea1746
Packit ea1746
  {
Packit ea1746
    Covariance::Options options;
Packit ea1746
    options.algorithm_type = DENSE_SVD;
Packit ea1746
    // Force dropping of the smallest eigenvector.
Packit ea1746
    options.null_space_rank = 1;
Packit ea1746
    ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
  }
Packit ea1746
Packit ea1746
  {
Packit ea1746
    Covariance::Options options;
Packit ea1746
    options.algorithm_type = DENSE_SVD;
Packit ea1746
    // Force dropping of the smallest eigenvector via the ratio but
Packit ea1746
    // automatic truncation.
Packit ea1746
    options.min_reciprocal_condition_number = 0.044494;
Packit ea1746
    options.null_space_rank = -1;
Packit ea1746
    ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
  }
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, DenseCovarianceMatrixFromSetOfParameters) {
Packit ea1746
  Covariance::Options options;
Packit ea1746
  Covariance covariance(options);
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  double* z = y + 3;
Packit ea1746
  vector<const double*> parameter_blocks;
Packit ea1746
  parameter_blocks.push_back(x);
Packit ea1746
  parameter_blocks.push_back(y);
Packit ea1746
  parameter_blocks.push_back(z);
Packit ea1746
  covariance.Compute(parameter_blocks, &problem_);
Packit ea1746
  double expected_covariance[36];
Packit ea1746
  covariance.GetCovarianceMatrix(parameter_blocks, expected_covariance);
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, DenseCovarianceMatrixFromSetOfParametersThreaded) {
Packit ea1746
  Covariance::Options options;
Packit ea1746
  options.num_threads = 4;
Packit ea1746
  Covariance covariance(options);
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  double* z = y + 3;
Packit ea1746
  vector<const double*> parameter_blocks;
Packit ea1746
  parameter_blocks.push_back(x);
Packit ea1746
  parameter_blocks.push_back(y);
Packit ea1746
  parameter_blocks.push_back(z);
Packit ea1746
  covariance.Compute(parameter_blocks, &problem_);
Packit ea1746
  double expected_covariance[36];
Packit ea1746
  covariance.GetCovarianceMatrix(parameter_blocks, expected_covariance);
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, DenseCovarianceMatrixFromSetOfParametersInTangentSpace) {
Packit ea1746
  Covariance::Options options;
Packit ea1746
  Covariance covariance(options);
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  double* z = y + 3;
Packit ea1746
Packit ea1746
  problem_.SetParameterization(x, new PolynomialParameterization);
Packit ea1746
Packit ea1746
  vector<int> subset;
Packit ea1746
  subset.push_back(2);
Packit ea1746
  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
Packit ea1746
Packit ea1746
  local_column_bounds_[x] = make_pair(0, 1);
Packit ea1746
  local_column_bounds_[y] = make_pair(1, 3);
Packit ea1746
  local_column_bounds_[z] = make_pair(3, 4);
Packit ea1746
Packit ea1746
  vector<const double*> parameter_blocks;
Packit ea1746
  parameter_blocks.push_back(x);
Packit ea1746
  parameter_blocks.push_back(y);
Packit ea1746
  parameter_blocks.push_back(z);
Packit ea1746
  covariance.Compute(parameter_blocks, &problem_);
Packit ea1746
  double expected_covariance[16];
Packit ea1746
  covariance.GetCovarianceMatrixInTangentSpace(parameter_blocks,
Packit ea1746
                                               expected_covariance);
Packit ea1746
Packit ea1746
#ifndef CERES_NO_SUITESPARSE
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
Packit ea1746
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
#endif
Packit ea1746
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
Packit ea1746
  options.algorithm_type = SPARSE_QR;
Packit ea1746
  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
Packit ea1746
  ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
TEST_F(CovarianceTest, ComputeCovarianceFailure) {
Packit ea1746
  Covariance::Options options;
Packit ea1746
  Covariance covariance(options);
Packit ea1746
  double* x = parameters_;
Packit ea1746
  double* y = x + 2;
Packit ea1746
  vector<const double*> parameter_blocks;
Packit ea1746
  parameter_blocks.push_back(x);
Packit ea1746
  parameter_blocks.push_back(x);
Packit ea1746
  parameter_blocks.push_back(y);
Packit ea1746
  parameter_blocks.push_back(y);
Packit ea1746
  EXPECT_DEATH_IF_SUPPORTED(covariance.Compute(parameter_blocks, &problem_),
Packit ea1746
                            "Covariance::Compute called with duplicate blocks "
Packit ea1746
                            "at indices \\(0, 1\\) and \\(2, 3\\)");
Packit ea1746
  vector<pair<const double*, const double*> > covariance_blocks;
Packit ea1746
  covariance_blocks.push_back(make_pair(x, x));
Packit ea1746
  covariance_blocks.push_back(make_pair(x, x));
Packit ea1746
  covariance_blocks.push_back(make_pair(y, y));
Packit ea1746
  covariance_blocks.push_back(make_pair(y, y));
Packit ea1746
  EXPECT_DEATH_IF_SUPPORTED(covariance.Compute(covariance_blocks, &problem_),
Packit ea1746
                            "Covariance::Compute called with duplicate blocks "
Packit ea1746
                            "at indices \\(0, 1\\) and \\(2, 3\\)");
Packit ea1746
}
Packit ea1746
Packit ea1746
class RankDeficientCovarianceTest : public CovarianceTest {
Packit ea1746
 protected:
Packit ea1746
  virtual void SetUp() {
Packit ea1746
    double* x = parameters_;
Packit ea1746
    double* y = x + 2;
Packit ea1746
    double* z = y + 3;
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian[] = { 1.0, 0.0, 0.0, 1.0};
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(2, 2, jacobian), NULL, x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(3, 3, jacobian), NULL, y);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian = 5.0;
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(1, 1, &jacobian),
Packit ea1746
                                NULL,
Packit ea1746
                                z);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian1[] = { 0.0, 0.0, 0.0 };
Packit ea1746
      double jacobian2[] = { -5.0, -6.0 };
Packit ea1746
      problem_.AddResidualBlock(
Packit ea1746
          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2),
Packit ea1746
          NULL,
Packit ea1746
          y,
Packit ea1746
          x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    {
Packit ea1746
      double jacobian1[] = {2.0 };
Packit ea1746
      double jacobian2[] = { 3.0, -2.0 };
Packit ea1746
      problem_.AddResidualBlock(
Packit ea1746
          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2),
Packit ea1746
          NULL,
Packit ea1746
          z,
Packit ea1746
          x);
Packit ea1746
    }
Packit ea1746
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, x));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(y, y));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(z, z));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, y));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(x, z));
Packit ea1746
    all_covariance_blocks_.push_back(make_pair(y, z));
Packit ea1746
Packit ea1746
    column_bounds_[x] = make_pair(0, 2);
Packit ea1746
    column_bounds_[y] = make_pair(2, 5);
Packit ea1746
    column_bounds_[z] = make_pair(5, 6);
Packit ea1746
  }
Packit ea1746
};
Packit ea1746
Packit ea1746
TEST_F(RankDeficientCovarianceTest, AutomaticTruncation) {
Packit ea1746
  // J
Packit ea1746
  //
Packit ea1746
  //   1  0  0  0  0  0
Packit ea1746
  //   0  1  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  5
Packit ea1746
  //  -5 -6  0  0  0  0
Packit ea1746
  //   3 -2  0  0  0  2
Packit ea1746
Packit ea1746
  // J'J
Packit ea1746
  //
Packit ea1746
  //  35 24  0  0  0  6
Packit ea1746
  //  24 41  0  0  0 -4
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   0  0  0  0  0  0
Packit ea1746
  //   6 -4  0  0  0 29
Packit ea1746
Packit ea1746
  // pinv(J'J) computed using octave.
Packit ea1746
  double expected_covariance[] = {
Packit ea1746
     0.053998,  -0.033145,   0.000000,   0.000000,   0.000000,  -0.015744,
Packit ea1746
    -0.033145,   0.045067,   0.000000,   0.000000,   0.000000,   0.013074,
Packit ea1746
     0.000000,   0.000000,   0.000000,   0.000000,   0.000000,   0.000000,
Packit ea1746
     0.000000,   0.000000,   0.000000,   0.000000,   0.000000,   0.000000,
Packit ea1746
     0.000000,   0.000000,   0.000000,   0.000000,   0.000000,   0.000000,
Packit ea1746
    -0.015744,   0.013074,   0.000000,   0.000000,   0.000000,   0.039543
Packit ea1746
  };
Packit ea1746
Packit ea1746
  Covariance::Options options;
Packit ea1746
  options.algorithm_type = DENSE_SVD;
Packit ea1746
  options.null_space_rank = -1;
Packit ea1746
  ComputeAndCompareCovarianceBlocks(options, expected_covariance);
Packit ea1746
}
Packit ea1746
Packit ea1746
class LargeScaleCovarianceTest : public ::testing::Test {
Packit ea1746
 protected:
Packit ea1746
  virtual void SetUp() {
Packit ea1746
    num_parameter_blocks_ = 2000;
Packit ea1746
    parameter_block_size_ = 5;
Packit ea1746
    parameters_.reset(
Packit ea1746
        new double[parameter_block_size_ * num_parameter_blocks_]);
Packit ea1746
Packit ea1746
    Matrix jacobian(parameter_block_size_, parameter_block_size_);
Packit ea1746
    for (int i = 0; i < num_parameter_blocks_; ++i) {
Packit ea1746
      jacobian.setIdentity();
Packit ea1746
      jacobian *= (i + 1);
Packit ea1746
Packit ea1746
      double* block_i = parameters_.get() + i * parameter_block_size_;
Packit ea1746
      problem_.AddResidualBlock(new UnaryCostFunction(parameter_block_size_,
Packit ea1746
                                                      parameter_block_size_,
Packit ea1746
                                                      jacobian.data()),
Packit ea1746
                                NULL,
Packit ea1746
                                block_i);
Packit ea1746
      for (int j = i; j < num_parameter_blocks_; ++j) {
Packit ea1746
        double* block_j = parameters_.get() + j * parameter_block_size_;
Packit ea1746
        all_covariance_blocks_.push_back(make_pair(block_i, block_j));
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  void ComputeAndCompare(
Packit ea1746
      CovarianceAlgorithmType algorithm_type,
Packit ea1746
      SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
Packit ea1746
      int num_threads) {
Packit ea1746
    Covariance::Options options;
Packit ea1746
    options.algorithm_type = algorithm_type;
Packit ea1746
    options.sparse_linear_algebra_library_type =
Packit ea1746
        sparse_linear_algebra_library_type;
Packit ea1746
    options.num_threads = num_threads;
Packit ea1746
    Covariance covariance(options);
Packit ea1746
    EXPECT_TRUE(covariance.Compute(all_covariance_blocks_, &problem_));
Packit ea1746
Packit ea1746
    Matrix expected(parameter_block_size_, parameter_block_size_);
Packit ea1746
    Matrix actual(parameter_block_size_, parameter_block_size_);
Packit ea1746
    const double kTolerance = 1e-16;
Packit ea1746
Packit ea1746
    for (int i = 0; i < num_parameter_blocks_; ++i) {
Packit ea1746
      expected.setIdentity();
Packit ea1746
      expected /= (i + 1.0) * (i + 1.0);
Packit ea1746
Packit ea1746
      double* block_i = parameters_.get() + i * parameter_block_size_;
Packit ea1746
      covariance.GetCovarianceBlock(block_i, block_i, actual.data());
Packit ea1746
      EXPECT_NEAR((expected - actual).norm(), 0.0, kTolerance)
Packit ea1746
          << "block: " << i << ", " << i << "\n"
Packit ea1746
          << "expected: \n" << expected << "\n"
Packit ea1746
          << "actual: \n" << actual;
Packit ea1746
Packit ea1746
      expected.setZero();
Packit ea1746
      for (int j = i + 1; j < num_parameter_blocks_; ++j) {
Packit ea1746
        double* block_j = parameters_.get() + j * parameter_block_size_;
Packit ea1746
        covariance.GetCovarianceBlock(block_i, block_j, actual.data());
Packit ea1746
        EXPECT_NEAR((expected - actual).norm(), 0.0, kTolerance)
Packit ea1746
            << "block: " << i << ", " << j << "\n"
Packit ea1746
            << "expected: \n" << expected << "\n"
Packit ea1746
            << "actual: \n" << actual;
Packit ea1746
      }
Packit ea1746
    }
Packit ea1746
  }
Packit ea1746
Packit ea1746
  scoped_array<double> parameters_;
Packit ea1746
  int parameter_block_size_;
Packit ea1746
  int num_parameter_blocks_;
Packit ea1746
Packit ea1746
  Problem problem_;
Packit ea1746
  vector<pair<const double*, const double*> > all_covariance_blocks_;
Packit ea1746
};
Packit ea1746
Packit ea1746
#if !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
Packit ea1746
Packit ea1746
TEST_F(LargeScaleCovarianceTest, Parallel) {
Packit ea1746
  ComputeAndCompare(SPARSE_QR, SUITE_SPARSE, 4);
Packit ea1746
}
Packit ea1746
Packit ea1746
#endif  // !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
Packit ea1746
Packit ea1746
}  // namespace internal
Packit ea1746
}  // namespace ceres