LinearSolver::Options::num_eliminate_blocks is dead.
Replaced with LinearSolver::Options::elimination_groups.
Change-Id: I7c07542ec19279a35ddf6da498d417a79395c77f
diff --git a/internal/ceres/implicit_schur_complement_test.cc b/internal/ceres/implicit_schur_complement_test.cc
index f948403..bd36672 100644
--- a/internal/ceres/implicit_schur_complement_test.cc
+++ b/internal/ceres/implicit_schur_complement_test.cc
@@ -83,7 +83,7 @@
const int num_schur_rows = blhs.num_rows();
LinearSolver::Options options;
- options.num_eliminate_blocks = num_eliminate_blocks_;
+ options.elimination_groups.push_back(num_eliminate_blocks_);
options.type = DENSE_SCHUR;
scoped_ptr<SchurEliminatorBase> eliminator(
diff --git a/internal/ceres/iterative_schur_complement_solver.cc b/internal/ceres/iterative_schur_complement_solver.cc
index 679c41f..376a586 100644
--- a/internal/ceres/iterative_schur_complement_solver.cc
+++ b/internal/ceres/iterative_schur_complement_solver.cc
@@ -67,7 +67,7 @@
// Initialize a ImplicitSchurComplement object.
if (schur_complement_ == NULL) {
schur_complement_.reset(
- new ImplicitSchurComplement(options_.num_eliminate_blocks,
+ new ImplicitSchurComplement(options_.elimination_groups[0],
options_.preconditioner_type == JACOBI));
}
schur_complement_->Init(*A, per_solve_options.D, b);
diff --git a/internal/ceres/iterative_schur_complement_solver_test.cc b/internal/ceres/iterative_schur_complement_solver_test.cc
index d034747..86e7825 100644
--- a/internal/ceres/iterative_schur_complement_solver_test.cc
+++ b/internal/ceres/iterative_schur_complement_solver_test.cc
@@ -89,7 +89,7 @@
Vector reference_solution(num_cols_);
qr->Solve(&dense_A, b_.get(), per_solve_options, reference_solution.data());
- options.num_eliminate_blocks = num_eliminate_blocks_;
+ options.elimination_groups.push_back(num_eliminate_blocks_);
options.max_num_iterations = num_cols_;
IterativeSchurComplementSolver isc(options);
diff --git a/internal/ceres/linear_solver.h b/internal/ceres/linear_solver.h
index 31f8874..ee7fce2 100644
--- a/internal/ceres/linear_solver.h
+++ b/internal/ceres/linear_solver.h
@@ -35,6 +35,7 @@
#define CERES_INTERNAL_LINEAR_SOLVER_H_
#include <cstddef>
+#include <vector>
#include <glog/logging.h>
#include "ceres/block_sparse_matrix.h"
@@ -76,7 +77,6 @@
min_num_iterations(1),
max_num_iterations(1),
num_threads(1),
- num_eliminate_blocks(0),
residual_reset_period(10),
row_block_size(Dynamic),
e_block_size(Dynamic),
@@ -100,15 +100,23 @@
// If possible, how many threads can the solver use.
int num_threads;
- // Eliminate 0 to num_eliminate_blocks - 1 from the Normal
- // equations to form a schur complement. Only used by the Schur
- // complement based solver. The most common use for this parameter
- // is in the case of structure from motion problems where we have
- // camera blocks and point blocks. Then setting the
- // num_eliminate_blocks to the number of points allows the solver
- // to use the Schur complement trick. For more details see the
- // description of this parameter in solver.h.
- int num_eliminate_blocks;
+ // Hints about the order in which the parameter blocks should be
+ // eliminated by the linear solver.
+ //
+ // For example if elimination_groups is a vector of size k, then
+ // the linear solver is informed that it should eliminate the
+ // parameter blocks 0 - elimination_groups[0] - 1 first, and then
+ // elimination_groups[0] - elimination_groups[1] and so on. Within
+ // each elimination group, the linear solver is free to choose how
+ // the parameter blocks are ordered. Different linear solvers have
+ // differing requirements on elimination_groups.
+ //
+ // The most common use is for Schur type solvers, where there
+ // should be at least two elimination groups and the first
+ // elimination group must form an independent set in the normal
+ // equations. The first elimination group corresponds to the
+ // num_eliminate_blocks in the Schur type solvers.
+ vector<int> elimination_groups;
// Iterative solvers, e.g. Preconditioned Conjugate Gradients
// maintain a cheap estimate of the residual which may become
diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc
index b9224d8..54f00dd 100644
--- a/internal/ceres/schur_complement_solver.cc
+++ b/internal/ceres/schur_complement_solver.cc
@@ -66,12 +66,12 @@
if (eliminator_.get() == NULL) {
InitStorage(A->block_structure());
DetectStructure(*A->block_structure(),
- options_.num_eliminate_blocks,
+ options_.elimination_groups[0],
&options_.row_block_size,
&options_.e_block_size,
&options_.f_block_size);
eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
- eliminator_->Init(options_.num_eliminate_blocks, A->block_structure());
+ eliminator_->Init(options_.elimination_groups[0], A->block_structure());
};
const time_t init_time = time(NULL);
fill(x, x + A->num_cols(), 0.0);
@@ -106,7 +106,7 @@
// complement.
void DenseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ const int num_eliminate_blocks = options().elimination_groups[0];
const int num_col_blocks = bs->cols.size();
vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
@@ -178,7 +178,7 @@
// initialize a BlockRandomAccessSparseMatrix object.
void SparseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ const int num_eliminate_blocks = options().elimination_groups[0];
const int num_col_blocks = bs->cols.size();
const int num_row_blocks = bs->rows.size();
diff --git a/internal/ceres/schur_complement_solver.h b/internal/ceres/schur_complement_solver.h
index ea1b318..c382f95 100644
--- a/internal/ceres/schur_complement_solver.h
+++ b/internal/ceres/schur_complement_solver.h
@@ -97,13 +97,14 @@
// The two solvers can be instantiated by calling
// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
// set to DENSE_SCHUR and SPARSE_SCHUR
-// respectively. LinearSolver::Options::num_eliminate_blocks should be
+// respectively. LinearSolver::Options::elimination_groups[0] should be
// at least 1.
class SchurComplementSolver : public BlockSparseMatrixBaseSolver {
public:
explicit SchurComplementSolver(const LinearSolver::Options& options)
: options_(options) {
- CHECK_GT(options.num_eliminate_blocks, 0);
+ CHECK_GT(options.elimination_groups.size(), 1);
+ CHECK_GT(options.elimination_groups[0], 0);
}
// LinearSolver methods
diff --git a/internal/ceres/schur_complement_solver_test.cc b/internal/ceres/schur_complement_solver_test.cc
index 6c31c35..71c6cfd 100644
--- a/internal/ceres/schur_complement_solver_test.cc
+++ b/internal/ceres/schur_complement_solver_test.cc
@@ -98,7 +98,9 @@
ceres::SparseLinearAlgebraLibraryType sparse_linear_algebra_library) {
SetUpFromProblemId(problem_id);
LinearSolver::Options options;
- options.num_eliminate_blocks = num_eliminate_blocks;
+ options.elimination_groups.push_back(num_eliminate_blocks);
+ options.elimination_groups.push_back(
+ A->block_structure()->cols.size() - num_eliminate_blocks);
options.type = linear_solver_type;
options.sparse_linear_algebra_library = sparse_linear_algebra_library;
diff --git a/internal/ceres/schur_eliminator_test.cc b/internal/ceres/schur_eliminator_test.cc
index 0b55a14..56db598 100644
--- a/internal/ceres/schur_eliminator_test.cc
+++ b/internal/ceres/schur_eliminator_test.cc
@@ -149,10 +149,10 @@
Vector rhs(schur_size);
LinearSolver::Options options;
- options.num_eliminate_blocks = num_eliminate_blocks;
+ options.elimination_groups.push_back(num_eliminate_blocks);
if (use_static_structure) {
DetectStructure(*bs,
- options.num_eliminate_blocks,
+ num_eliminate_blocks,
&options.row_block_size,
&options.e_block_size,
&options.f_block_size);
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index 8f2f38b..4bedbe3 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -652,10 +652,19 @@
#endif
linear_solver_options.num_threads = options->num_linear_solver_threads;
- linear_solver_options.num_eliminate_blocks =
- options->num_eliminate_blocks;
+ if (options->num_eliminate_blocks > 0) {
+ linear_solver_options
+ .elimination_groups.push_back(options->num_eliminate_blocks);
+ }
- if ((linear_solver_options.num_eliminate_blocks == 0) &&
+ // TODO(sameeragarwal): Fix this. Right now these are dummy values
+ // and violate the contract that elimination_groups should sum to
+ // the number of parameter blocks, but fixing this requires a bit
+ // more refactoring in solver_impl.cc, which is better done as we
+ // start deprecating the old API.
+ linear_solver_options.elimination_groups.push_back(1);
+
+ if (linear_solver_options.elimination_groups.size() == 1 &&
IsSchurType(linear_solver_options.type)) {
#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
LOG(INFO) << "No elimination block remaining switching to DENSE_QR.";
diff --git a/internal/ceres/visibility_based_preconditioner.cc b/internal/ceres/visibility_based_preconditioner.cc
index 4caad03..ae26d91 100644
--- a/internal/ceres/visibility_based_preconditioner.cc
+++ b/internal/ceres/visibility_based_preconditioner.cc
@@ -70,12 +70,13 @@
num_blocks_(0),
num_clusters_(0),
factor_(NULL) {
- CHECK_GT(options_.num_eliminate_blocks, 0);
+ CHECK_GT(options_.elimination_groups.size(), 1);
+ CHECK_GT(options_.elimination_groups[0], 0);
CHECK(options_.preconditioner_type == SCHUR_JACOBI ||
options_.preconditioner_type == CLUSTER_JACOBI ||
options_.preconditioner_type == CLUSTER_TRIDIAGONAL)
<< "Unknown preconditioner type: " << options_.preconditioner_type;
- num_blocks_ = bs.cols.size() - options_.num_eliminate_blocks;
+ num_blocks_ = bs.cols.size() - options_.elimination_groups[0];
CHECK_GT(num_blocks_, 0)
<< "Jacobian should have atleast 1 f_block for "
<< "visibility based preconditioning.";
@@ -83,7 +84,7 @@
// Vector of camera block sizes
block_size_.resize(num_blocks_);
for (int i = 0; i < num_blocks_; ++i) {
- block_size_[i] = bs.cols[i + options_.num_eliminate_blocks].size;
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
}
const time_t start_time = time(NULL);
@@ -155,7 +156,7 @@
void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
cluster_pairs_.clear();
@@ -173,7 +174,7 @@
void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
@@ -253,7 +254,7 @@
int r = 0;
const int num_row_blocks = bs.rows.size();
- const int num_eliminate_blocks = options_.num_eliminate_blocks;
+ const int num_eliminate_blocks = options_.elimination_groups[0];
// Iterate over each row of the matrix. The block structure of the
// matrix is assumed to be sorted in order of the e_blocks/point
@@ -331,16 +332,17 @@
void VisibilityBasedPreconditioner::InitEliminator(
const CompressedRowBlockStructure& bs) {
LinearSolver::Options eliminator_options;
- eliminator_options.num_eliminate_blocks = options_.num_eliminate_blocks;
+
+ eliminator_options.elimination_groups = options_.elimination_groups;
eliminator_options.num_threads = options_.num_threads;
- DetectStructure(bs, options_.num_eliminate_blocks,
+ DetectStructure(bs, options_.elimination_groups[0],
&eliminator_options.row_block_size,
&eliminator_options.e_block_size,
&eliminator_options.f_block_size);
eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(options_.num_eliminate_blocks, &bs);
+ eliminator_->Init(options_.elimination_groups[0], &bs);
}
// Update the values of the preconditioner matrix and factorize it.
diff --git a/internal/ceres/visibility_based_preconditioner_test.cc b/internal/ceres/visibility_based_preconditioner_test.cc
index 9973d69..8c5378d 100644
--- a/internal/ceres/visibility_based_preconditioner_test.cc
+++ b/internal/ceres/visibility_based_preconditioner_test.cc
@@ -80,7 +80,9 @@
num_rows_ = A_->num_rows();
num_eliminate_blocks_ = problem->num_eliminate_blocks;
num_camera_blocks_ = num_col_blocks - num_eliminate_blocks_;
- options_.num_eliminate_blocks = num_eliminate_blocks_;
+ options_.elimination_groups.push_back(num_eliminate_blocks_);
+ options_.elimination_groups.push_back(
+ A_->block_structure()->cols.size() - num_eliminate_blocks_);
vector<int> blocks(num_col_blocks - num_eliminate_blocks_, 0);
for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {