Fix handling of constant blocks when reordering

The reordering code assumed that the parameter_block->index()
field is always set; this is not true. For fixed blocks the index
may have an arbitrary value. This changes the code to ignore fixed
blocks properly.
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index bb59b5f..834ec0d 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -582,10 +582,13 @@
   int min_parameter_block_position = num_eliminate_blocks;
   for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
     ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
-    DCHECK_NE(parameter_block->index(), -1)
-        << "Did you forget to call Program::SetParameterOffsetsAndIndex()?";
-    min_parameter_block_position = std::min(parameter_block->index(),
-                                            min_parameter_block_position);
+    if (!parameter_block->IsConstant()) {
+      CHECK_NE(parameter_block->index(), -1)
+          << "Did you forget to call Program::SetParameterOffsetsAndIndex()? "
+          << "This is a Ceres bug; please contact the developers!";
+      min_parameter_block_position = std::min(parameter_block->index(),
+                                              min_parameter_block_position);
+    }
   }
   return min_parameter_block_position;
 }
diff --git a/internal/ceres/solver_impl_test.cc b/internal/ceres/solver_impl_test.cc
index 99733a2..2abca63 100644
--- a/internal/ceres/solver_impl_test.cc
+++ b/internal/ceres/solver_impl_test.cc
@@ -209,6 +209,7 @@
   EXPECT_TRUE(SolverImpl::MaybeReorderResidualBlocks(options,
                                                      problem.mutable_program(),
                                                      &error));
+  EXPECT_EQ(current_residual_blocks.size(), residual_blocks.size());
   for (int i = 0; i < current_residual_blocks.size(); ++i) {
     EXPECT_EQ(current_residual_blocks[i], residual_blocks[i]);
   }
@@ -281,11 +282,80 @@
   EXPECT_TRUE(SolverImpl::MaybeReorderResidualBlocks(options,
                                                      problem.mutable_program(),
                                                      &error));
+  EXPECT_EQ(residual_blocks.size(), expected_residual_blocks.size());
   for (int i = 0; i < expected_residual_blocks.size(); ++i) {
     EXPECT_EQ(residual_blocks[i], expected_residual_blocks[i]);
   }
 }
 
+TEST(SolverImpl, ReorderResidualBlockNormalFunctionWithFixedBlocks) {
+  ProblemImpl problem;
+  double x;
+  double y;
+  double z;
+
+  problem.AddParameterBlock(&x, 1);
+  problem.AddParameterBlock(&y, 1);
+  problem.AddParameterBlock(&z, 1);
+
+  // Set one parameter block constant.
+  problem.SetParameterBlockConstant(&z);
+
+  // Mark residuals for x's row block with "x" for readability.
+  problem.AddResidualBlock(new UnaryCostFunction(), NULL, &x);       // 0 x
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &x);  // 1 x
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);  // 2
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);  // 3
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &z);  // 4 x
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);  // 5
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &z);  // 6 x
+  problem.AddResidualBlock(new UnaryCostFunction(), NULL, &y);       // 7
+
+  Solver::Options options;
+  options.linear_solver_type = DENSE_SCHUR;
+  options.num_eliminate_blocks = 2;
+
+  // Create the reduced program. This should remove the fixed block "z",
+  // marking the index to -1 at the same time. x and y also get indices.
+  string error;
+  scoped_ptr<Program> reduced_program(
+      SolverImpl::CreateReducedProgram(&options, &problem, &error));
+
+  const vector<ResidualBlock*>& residual_blocks =
+      problem.program().residual_blocks();
+
+  // This is a bit fragile, but it serves the purpose. We know the
+  // bucketing algorithm that the reordering function uses, so we
+  // expect the order for residual blocks for each e_block to be
+  // filled in reverse.
+
+  vector<ResidualBlock*> expected_residual_blocks;
+
+  // Row block for residuals involving "x". These are marked "x" in the block
+  // of code calling AddResidual() above.
+  expected_residual_blocks.push_back(residual_blocks[6]);
+  expected_residual_blocks.push_back(residual_blocks[4]);
+  expected_residual_blocks.push_back(residual_blocks[1]);
+  expected_residual_blocks.push_back(residual_blocks[0]);
+
+  // Row block for residuals involving "y".
+  expected_residual_blocks.push_back(residual_blocks[7]);
+  expected_residual_blocks.push_back(residual_blocks[5]);
+  expected_residual_blocks.push_back(residual_blocks[3]);
+  expected_residual_blocks.push_back(residual_blocks[2]);
+
+  EXPECT_TRUE(SolverImpl::MaybeReorderResidualBlocks(options,
+                                                     reduced_program.get(),
+                                                     &error));
+
+  EXPECT_EQ(reduced_program->residual_blocks().size(),
+            expected_residual_blocks.size());
+  for (int i = 0; i < expected_residual_blocks.size(); ++i) {
+    EXPECT_EQ(reduced_program->residual_blocks()[i],
+              expected_residual_blocks[i]);
+  }
+}
+
 TEST(SolverImpl, ApplyUserOrderingOrderingTooSmall) {
   ProblemImpl problem;
   double x;