Schur ordering was operating on the original program.

Thanks to Ricardo Martin for reporting this.

Change-Id: Iacf44f672287e4d76633878c7051694a39b3056f
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index 062577e..03fe921 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -627,7 +627,7 @@
   // maximal independent set.
   if (original_num_groups == 1 && IsSchurType(options->linear_solver_type)) {
     vector<ParameterBlock*> schur_ordering;
-    const int num_eliminate_blocks = ComputeSchurOrdering(*original_program,
+    const int num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
                                                           &schur_ordering);
     CHECK_EQ(schur_ordering.size(), transformed_program->NumParameterBlocks())
         << "Congratulations, you found a Ceres bug! Please report this error "
diff --git a/internal/ceres/solver_impl_test.cc b/internal/ceres/solver_impl_test.cc
index 5f4a82c..9b01766 100644
--- a/internal/ceres/solver_impl_test.cc
+++ b/internal/ceres/solver_impl_test.cc
@@ -386,6 +386,63 @@
   }
 }
 
+TEST(SolverImpl, AutomaticSchurReorderingRespectsConstantBlocks) {
+  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);
+
+  problem.AddResidualBlock(new UnaryCostFunction(), NULL, &x);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &x);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &z);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &z, &y);
+  problem.AddResidualBlock(new BinaryCostFunction(), NULL, &x, &z);
+  problem.AddResidualBlock(new UnaryCostFunction(), NULL, &y);
+  problem.AddResidualBlock(new UnaryCostFunction(), NULL, &z);
+
+  ParameterBlockOrdering* ordering = new ParameterBlockOrdering;
+  ordering->AddElementToGroup(&x, 0);
+  ordering->AddElementToGroup(&z, 0);
+  ordering->AddElementToGroup(&y, 0);
+
+  Solver::Options options;
+  options.linear_solver_type = DENSE_SCHUR;
+  options.ordering = ordering;
+
+  string error;
+  scoped_ptr<Program> reduced_program(
+      SolverImpl::CreateReducedProgram(&options, &problem, NULL, &error));
+
+  const vector<ResidualBlock*>& residual_blocks =
+      reduced_program->residual_blocks();
+  const vector<ParameterBlock*>& parameter_blocks =
+      reduced_program->parameter_blocks();
+
+  const vector<ResidualBlock*>& original_residual_blocks =
+      problem.program().residual_blocks();
+
+  EXPECT_EQ(residual_blocks.size(), 8);
+  EXPECT_EQ(reduced_program->parameter_blocks().size(), 2);
+
+  // Verify that right parmeter block and the residual blocks have
+  // been removed.
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_NE(residual_blocks[i], original_residual_blocks.back());
+  }
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_NE(parameter_blocks[i]->mutable_user_state(), &z);
+  }
+}
+
 TEST(SolverImpl, ApplyUserOrderingOrderingTooSmall) {
   ProblemImpl problem;
   double x;