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) {