Cleanup reorder_program.cc

Program::SetParameterOffsetsAndIndex() was being called willy nilly.
Now the invariant is that any function that actually reorders the
program, updates the offsets and indices.

Also the logic around handling EIGEN_SPARSE has been simplified in
anticipation of the block AMD code that is forthcoming.

Last but not the least, num_eliminate_blocks, which is a rather
cryptic name to begin with has been replaced by the more meaningful
size_of_first_elimination_group.

Change-Id: I77e684f699a93b53e76aa406d64f40f8704df813
diff --git a/internal/ceres/reorder_program.cc b/internal/ceres/reorder_program.cc
index 9b40885..4caa01f 100644
--- a/internal/ceres/reorder_program.cc
+++ b/internal/ceres/reorder_program.cc
@@ -41,7 +41,6 @@
 #include "ceres/parameter_block_ordering.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
-#include "ceres/program.h"
 #include "ceres/residual_block.h"
 #include "ceres/solver.h"
 #include "ceres/suitesparse.h"
@@ -53,12 +52,13 @@
 namespace internal {
 namespace {
 
-// Find the minimum index of any parameter block to the given residual.
-// Parameter blocks that have indices greater than num_eliminate_blocks are
-// considered to have an index equal to num_eliminate_blocks.
+// Find the minimum index of any parameter block to the given
+// residual.  Parameter blocks that have indices greater than
+// size_of_first_elimination_group are considered to have an index
+// equal to size_of_first_elimination_group.
 static int MinParameterBlock(const ResidualBlock* residual_block,
-                             int num_eliminate_blocks) {
-  int min_parameter_block_position = num_eliminate_blocks;
+                             int size_of_first_elimination_group) {
+  int min_parameter_block_position = size_of_first_elimination_group;
   for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
     ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
     if (!parameter_block->IsConstant()) {
@@ -178,30 +178,32 @@
   return true;
 }
 
-bool LexicographicallyOrderResidualBlocks(const int num_eliminate_blocks,
-                                          Program* program,
-                                          string* error) {
-  CHECK_GE(num_eliminate_blocks, 1)
+bool LexicographicallyOrderResidualBlocks(
+    const int size_of_first_elimination_group,
+    Program* program,
+    string* error) {
+  CHECK_GE(size_of_first_elimination_group, 1)
       << "Congratulations, you found a Ceres bug! Please report this error "
       << "to the developers.";
 
   // Create a histogram of the number of residuals for each E block. There is an
   // extra bucket at the end to catch all non-eliminated F blocks.
-  vector<int> residual_blocks_per_e_block(num_eliminate_blocks + 1);
+  vector<int> residual_blocks_per_e_block(size_of_first_elimination_group + 1);
   vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
   vector<int> min_position_per_residual(residual_blocks->size());
   for (int i = 0; i < residual_blocks->size(); ++i) {
     ResidualBlock* residual_block = (*residual_blocks)[i];
-    int position = MinParameterBlock(residual_block, num_eliminate_blocks);
+    int position = MinParameterBlock(residual_block,
+                                     size_of_first_elimination_group);
     min_position_per_residual[i] = position;
-    DCHECK_LE(position, num_eliminate_blocks);
+    DCHECK_LE(position, size_of_first_elimination_group);
     residual_blocks_per_e_block[position]++;
   }
 
   // Run a cumulative sum on the histogram, to obtain offsets to the start of
   // each histogram bucket (where each bucket is for the residuals for that
   // E-block).
-  vector<int> offsets(num_eliminate_blocks + 1);
+  vector<int> offsets(size_of_first_elimination_group + 1);
   std::partial_sum(residual_blocks_per_e_block.begin(),
                    residual_blocks_per_e_block.end(),
                    offsets.begin());
@@ -240,7 +242,7 @@
 
   // Sanity check #1: The difference in bucket offsets should match the
   // histogram sizes.
-  for (int i = 0; i < num_eliminate_blocks; ++i) {
+  for (int i = 0; i < size_of_first_elimination_group; ++i) {
     CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i])
         << "Congratulations, you found a Ceres bug! Please report this error "
         << "to the developers.";
@@ -257,11 +259,11 @@
   return true;
 }
 
+// Pre-order the columns corresponding to the schur complement if
+// possible.
 void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
     const ParameterBlockOrdering& parameter_block_ordering,
     Program* program) {
-  // Pre-order the columns corresponding to the schur complement if
-  // possible.
 #ifndef CERES_NO_SUITESPARSE
   SuiteSparse ss;
   if (!SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
@@ -283,13 +285,10 @@
   // parameter_blocks.size() - 1].
   MapValuesToContiguousRange(constraints.size(), &constraints[0]);
 
-  // Set the offsets and index for CreateJacobianSparsityTranspose.
-  program->SetParameterOffsetsAndIndex();
   // Compute a block sparse presentation of J'.
   scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
       program->CreateJacobianBlockSparsityTranspose());
 
-
   cholmod_sparse* block_jacobian_transpose =
       ss.CreateSparseMatrix(tsm_block_jacobian_transpose.get());
 
@@ -303,6 +302,8 @@
   for (int i = 0; i < program->NumParameterBlocks(); ++i) {
     parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
   }
+
+  program->SetParameterOffsetsAndIndex();
 #endif
 }
 
@@ -313,7 +314,8 @@
     ParameterBlockOrdering* parameter_block_ordering,
     Program* program,
     string* error) {
-  if (parameter_block_ordering->NumElements() != program->NumParameterBlocks()) {
+  if (parameter_block_ordering->NumElements() !=
+      program->NumParameterBlocks()) {
     *error = StringPrintf(
         "The program has %d parameter blocks, but the parameter block "
         "ordering has %d parameter blocks.",
@@ -330,7 +332,7 @@
     // this means that the user wishes for Ceres to identify the
     // e_blocks, which we do by computing a maximal independent set.
     vector<ParameterBlock*> schur_ordering;
-    const int num_eliminate_blocks =
+    const int size_of_first_elimination_group =
         ComputeStableSchurOrdering(*program, &schur_ordering);
 
     CHECK_EQ(schur_ordering.size(), program->NumParameterBlocks())
@@ -340,7 +342,7 @@
     // Update the parameter_block_ordering object.
     for (int i = 0; i < schur_ordering.size(); ++i) {
       double* parameter_block = schur_ordering[i]->mutable_user_state();
-      const int group_id = (i < num_eliminate_blocks) ? 0 : 1;
+      const int group_id = (i < size_of_first_elimination_group) ? 0 : 1;
       parameter_block_ordering->AddElementToGroup(parameter_block, group_id);
     }
 
@@ -373,6 +375,8 @@
     }
   }
 
+  program->SetParameterOffsetsAndIndex();
+
   if (linear_solver_type == SPARSE_SCHUR &&
       sparse_linear_algebra_library_type == SUITE_SPARSE) {
     MaybeReorderSchurComplementColumnsUsingSuiteSparse(
@@ -380,18 +384,18 @@
         program);
   }
 
-  program->SetParameterOffsetsAndIndex();
+
+
   // Schur type solvers also require that their residual blocks be
   // lexicographically ordered.
-  const int num_eliminate_blocks =
+  const int size_of_first_elimination_group =
       parameter_block_ordering->group_to_elements().begin()->second.size();
-  if (!LexicographicallyOrderResidualBlocks(num_eliminate_blocks,
+  if (!LexicographicallyOrderResidualBlocks(size_of_first_elimination_group,
                                             program,
                                             error)) {
     return false;
   }
 
-  program->SetParameterOffsetsAndIndex();
   return true;
 }
 
@@ -400,30 +404,6 @@
     const ParameterBlockOrdering& parameter_block_ordering,
     Program* program,
     string* error) {
-
-  if (sparse_linear_algebra_library_type != SUITE_SPARSE &&
-      sparse_linear_algebra_library_type != CX_SPARSE &&
-      sparse_linear_algebra_library_type != EIGEN_SPARSE) {
-    *error = "Unknown sparse linear algebra library.";
-    return false;
-  }
-
-  // For Eigen, there is nothing to do. This is because Eigen in its
-  // current stable version does not expose a method for doing
-  // symbolic analysis on pre-ordered matrices, so a block
-  // pre-ordering is a bit pointless.
-  //
-  // The dev version as recently as July 20, 2014 has support for
-  // pre-ordering. Once this becomes more widespread, or we add
-  // support for detecting Eigen versions, we can add support for this
-  // along the lines of CXSparse.
-  if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
-    program->SetParameterOffsetsAndIndex();
-    return true;
-  }
-
-  // Set the offsets and index for CreateJacobianSparsityTranspose.
-  program->SetParameterOffsetsAndIndex();
   // Compute a block sparse presentation of J'.
   scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
       program->CreateJacobianBlockSparsityTranspose());
@@ -438,10 +418,16 @@
         parameter_blocks,
         parameter_block_ordering,
         &ordering[0]);
-  } else if (sparse_linear_algebra_library_type == CX_SPARSE){
+  } else if (sparse_linear_algebra_library_type == CX_SPARSE) {
     OrderingForSparseNormalCholeskyUsingCXSparse(
         *tsm_block_jacobian_transpose,
         &ordering[0]);
+  } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+    // Starting with v3.2.2 Eigen has support for symbolic analysis on
+    // pre-ordered matrices.
+    //
+    // TODO(sameeragarwal): Apply block amd for eigen.
+    return true;
   }
 
   // Apply ordering.
diff --git a/internal/ceres/reorder_program.h b/internal/ceres/reorder_program.h
index d3962f9..0474c1f 100644
--- a/internal/ceres/reorder_program.h
+++ b/internal/ceres/reorder_program.h
@@ -51,7 +51,7 @@
 // Reorder the residuals for program, if necessary, so that the residuals
 // involving each E block occur together. This is a necessary condition for the
 // Schur eliminator, which works on these "row blocks" in the jacobian.
-bool LexicographicallyOrderResidualBlocks(int num_eliminate_blocks,
+bool LexicographicallyOrderResidualBlocks(int size_of_first_elimination_group,
                                           Program* program,
                                           string* error);