Compute the gradient if requested in the evaluator

This extends the Evaluator interface to support evaluating the
gradient in addition to the residuals and jacobian, if requested.

   bool Evaluate(const double* state,
                 double* cost,
                 double* residuals,
                 double* gradient,  <----------- NEW
                 SparseMatrix* jacobian) = 0;

The ProgramEvaluator is extended to support the new gradient
evaluation. This required some gymnastics around the block
evaluate preparer, which now contains a scratch evaluate preparer
for the case that no jacobian is requested but the gradient is.

Gradient evaluation is a prerequisite for the planned suite of
first order methods, including nonlinear conjugate gradient,
CG_DESCENT, L-BFGS, trust region with line search, and more.

This also considerably refactors the evaluator_test to make it
shorter and check the results for all combinations of the optional
parameters [residuals, gradient, jacobian].

Change-Id: Ic7d0fec028dc5ffebc08ee079ad04eeaf6e02582
diff --git a/internal/ceres/evaluator_test.cc b/internal/ceres/evaluator_test.cc
index b7381a4..6fbb759 100644
--- a/internal/ceres/evaluator_test.cc
+++ b/internal/ceres/evaluator_test.cc
@@ -88,6 +88,15 @@
   }
 };
 
+struct ExpectedEvaluation {
+  int num_rows;
+  int num_cols;
+  double cost;
+  const double residuals[50];
+  const double gradient[50];
+  const double jacobian[200];
+};
+
 struct EvaluatorTest
     : public ::testing::TestWithParam<pair<LinearSolverType, int> > {
   Evaluator* CreateEvaluator(Program* program) {
@@ -103,6 +112,93 @@
     string error;
     return Evaluator::Create(options, program, &error);
   }
+
+  void CheckEvaluation(ProblemImpl *problem,
+                       int expected_num_rows,
+                       int expected_num_cols,
+                       double expected_cost,
+                       const double* expected_residuals,
+                       const double* expected_gradient,
+                       const double* expected_jacobian) {
+    scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem->mutable_program()));
+    int num_residuals = expected_num_rows;
+    int num_parameters = expected_num_cols;
+
+    double cost = -1;
+
+    Vector residuals(num_residuals);
+    residuals.setConstant(-2000);
+
+    Vector gradient(num_parameters);
+    gradient.setConstant(-3000);
+
+    scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
+
+    ASSERT_EQ(expected_num_rows, evaluator->NumResiduals());
+    ASSERT_EQ(expected_num_cols, evaluator->NumEffectiveParameters());
+    ASSERT_EQ(expected_num_rows, jacobian->num_rows());
+    ASSERT_EQ(expected_num_cols, jacobian->num_cols());
+
+    vector<double> state(evaluator->NumParameters());
+
+    ASSERT_TRUE(evaluator->Evaluate(
+          &state[0],
+          &cost,
+          expected_residuals != NULL ? &residuals[0]  : NULL,
+          expected_gradient  != NULL ? &gradient[0]   : NULL,
+          expected_jacobian  != NULL ? jacobian.get() : NULL));
+
+    EXPECT_EQ(expected_cost, cost);
+
+    if (expected_residuals != NULL) {
+      for (int i = 0; i < num_residuals; ++i) {
+        EXPECT_EQ(expected_residuals[i], residuals[i]) << i;
+      }
+    }
+
+    if (expected_gradient != NULL) {
+      ConstVectorRef expected_gradient_vector(expected_gradient,
+                                              expected_num_cols);
+
+      EXPECT_TRUE((gradient.array() ==
+                   expected_gradient_vector.array()).all())
+          << "Actual:\n" << gradient.transpose()
+          << "\nExpected:\n" << expected_gradient_vector.transpose();
+    }
+
+    if (expected_jacobian != NULL) {
+      ConstMatrixRef expected_jacobian_matrix(expected_jacobian,
+                                              expected_num_rows,
+                                              expected_num_cols);
+      Matrix actual_jacobian;
+      jacobian->ToDenseMatrix(&actual_jacobian);
+
+      EXPECT_TRUE((actual_jacobian.array() ==
+                   expected_jacobian_matrix.array()).all())
+          << "Actual:\n" << actual_jacobian
+          << "\nExpected:\n" << expected_jacobian;
+    }
+  }
+
+  // Try all combinations of parameters for the evaluator.
+  void CheckAllEvaluationCombinations(const ExpectedEvaluation &expected) {
+    for (int i = 0; i < 8; ++i) {
+      CheckEvaluation(&problem,
+                      expected.num_rows,
+                      expected.num_cols,
+                      expected.cost,
+                      (i & 1) ? expected.residuals : NULL,
+                      (i & 2) ? expected.gradient  : NULL,
+                      (i & 4) ? expected.jacobian  : NULL);
+    }
+  }
+
+  // The values are ignored completely by the cost function.
+  double x[2];
+  double y[3];
+  double z[4];
+
+  ProblemImpl problem;
 };
 
 void SetSparseMatrixConstant(SparseMatrix* sparse_matrix, double value) {
@@ -111,77 +207,32 @@
 }
 
 TEST_P(EvaluatorTest, SingleResidualProblem) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   problem.AddResidualBlock(new ParameterIgnoringCostFunction<1, 3, 2, 3, 4>,
                            NULL,
                            x, y, z);
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(3, jacobian->num_rows());
-  ASSERT_EQ(9, jacobian->num_cols());
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(7.0, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    Matrix expected_jacobian(3, 9);
-    expected_jacobian
-        // x       y          z
-        << 1, 2,   1, 2, 3,   1, 2, 3, 4,
-           1, 2,   1, 2, 3,   1, 2, 3, 4,
-           1, 2,   1, 2, 3,   1, 2, 3, 4;
-
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    3, 9,
+    // Cost
+    7.0,
+    // Residuals
+    { 1.0, 2.0, 3.0 },
+    // Gradient
+    { 6.0, 12.0,              // x
+      6.0, 12.0, 18.0,        // y
+      6.0, 12.0, 18.0, 24.0,  // z
+    },
+    // Jacobian
+    //   x          y             z
+    { 1, 2,   1, 2, 3,   1, 2, 3, 4,
+      1, 2,   1, 2, 3,   1, 2, 3, 4,
+      1, 2,   1, 2, 3,   1, 2, 3, 4
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 }
-
 TEST_P(EvaluatorTest, SingleResidualProblemWithPermutedParameters) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   // Add the parameters in explicit order to force the ordering in the program.
   problem.AddParameterBlock(x,  2);
   problem.AddParameterBlock(y,  3);
@@ -197,143 +248,76 @@
                            NULL,
                            z, y, x);
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(3, jacobian->num_rows());
-  ASSERT_EQ(9, jacobian->num_cols());
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(7.0, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    Matrix expected_jacobian(3, 9);
-    expected_jacobian
-        // x       y          z
-        << 1, 2,   1, 2, 3,   1, 2, 3, 4,
-           1, 2,   1, 2, 3,   1, 2, 3, 4,
-           1, 2,   1, 2, 3,   1, 2, 3, 4;
-
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    3, 9,
+    // Cost
+    7.0,
+    // Residuals
+    { 1.0, 2.0, 3.0 },
+    // Gradient
+    { 6.0, 12.0,              // x
+      6.0, 12.0, 18.0,        // y
+      6.0, 12.0, 18.0, 24.0,  // z
+    },
+    // Jacobian
+    //   x          y             z
+    { 1, 2,   1, 2, 3,   1, 2, 3, 4,
+      1, 2,   1, 2, 3,   1, 2, 3, 4,
+      1, 2,   1, 2, 3,   1, 2, 3, 4
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 }
+
 TEST_P(EvaluatorTest, SingleResidualProblemWithNuisanceParameters) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   // These parameters are not used.
-  double w1[2];
-  double w2[1];
-  double w3[1];
-  double w4[3];
+  double a[2];
+  double b[1];
+  double c[1];
+  double d[3];
 
   // Add the parameters in a mixed order so the Jacobian is "checkered" with the
   // values from the other parameters.
-  problem.AddParameterBlock(w1, 2);
-  problem.AddParameterBlock(x,  2);
-  problem.AddParameterBlock(w2, 1);
-  problem.AddParameterBlock(y,  3);
-  problem.AddParameterBlock(w3, 1);
-  problem.AddParameterBlock(z,  4);
-  problem.AddParameterBlock(w4, 3);
+  problem.AddParameterBlock(a, 2);
+  problem.AddParameterBlock(x, 2);
+  problem.AddParameterBlock(b, 1);
+  problem.AddParameterBlock(y, 3);
+  problem.AddParameterBlock(c, 1);
+  problem.AddParameterBlock(z, 4);
+  problem.AddParameterBlock(d, 3);
 
   problem.AddResidualBlock(new ParameterIgnoringCostFunction<1, 3, 2, 3, 4>,
                            NULL,
                            x, y, z);
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(3, jacobian->num_rows());
-  ASSERT_EQ(16, jacobian->num_cols());
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(7.0, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[3] = { -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(7.0, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(3.0, residuals[2]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    Matrix expected_jacobian(3, 16);
-    expected_jacobian
-        // w1       x        w2    y           w2    z              w3
-        << 0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0,
-           0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0,
-           0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0;
-
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    3, 16,
+    // Cost
+    7.0,
+    // Residuals
+    { 1.0, 2.0, 3.0 },
+    // Gradient
+    { 0.0, 0.0,               // a
+      6.0, 12.0,              // x
+      0.0,                    // b
+      6.0, 12.0, 18.0,        // y
+      0.0,                    // c
+      6.0, 12.0, 18.0, 24.0,  // z
+      0.0, 0.0, 0.0,          // d
+    },
+    // Jacobian
+    //   a        x     b           y     c              z           d
+    { 0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0,
+      0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0,
+      0, 0,    1, 2,    0,    1, 2, 3,    0,    1, 2, 3, 4,    0, 0, 0
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 }
 
 TEST_P(EvaluatorTest, MultipleResidualProblem) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   // Add the parameters in explicit order to force the ordering in the program.
   problem.AddParameterBlock(x,  2);
   problem.AddParameterBlock(y,  3);
@@ -354,63 +338,22 @@
                            NULL,
                            y, z);
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(9, jacobian->num_rows());
-  ASSERT_EQ(9, jacobian->num_cols());
-
-  //                      f       g           h
-  double expected_cost = (1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0;
-
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(expected_cost, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    Matrix expected_jacobian(9, 9);
-    expected_jacobian <<
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    9, 9,
+    // Cost
+    // f       g           h
+    (  1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0,
+    // Residuals
+    { 1.0, 2.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 4.0 },
+    // Gradient
+    { 15.0, 30.0,               // x
+      33.0, 66.0, 99.0,         // y
+      42.0, 84.0, 126.0, 168.0  // z
+    },
+    // Jacobian
     //                x        y           z
-        /* f(x, y) */ 1, 2,    1, 2, 3,    0, 0, 0, 0,
+    {   /* f(x, y) */ 1, 2,    1, 2, 3,    0, 0, 0, 0,
                       1, 2,    1, 2, 3,    0, 0, 0, 0,
 
         /* g(x, z) */ 2, 4,    0, 0, 0,    2, 4, 6, 8,
@@ -420,23 +363,13 @@
         /* h(y, z) */ 0, 0,    3, 6, 9,    3, 6, 9, 12,
                       0, 0,    3, 6, 9,    3, 6, 9, 12,
                       0, 0,    3, 6, 9,    3, 6, 9, 12,
-                      0, 0,    3, 6, 9,    3, 6, 9, 12;
-
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+                      0, 0,    3, 6, 9,    3, 6, 9, 12 
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 }
 
 TEST_P(EvaluatorTest, MultipleResidualsWithLocalParameterizations) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   // Add the parameters in explicit order to force the ordering in the program.
   problem.AddParameterBlock(x,  2);
 
@@ -465,64 +398,22 @@
                            NULL,
                            y, z);
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(9, jacobian->num_rows());
-  ASSERT_EQ(7, jacobian->num_cols());
-
-  //                      f       g           h
-  double expected_cost = (1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0;
-
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(expected_cost, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    // Note y and z are missing columns due to the subset parameterization.
-    Matrix expected_jacobian(9, 7);
-    expected_jacobian <<
-    //                x        y        z
-        /* f(x, y) */ 1, 2,    2, 3,    0, 0, 0,
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    9, 7,
+    // Cost
+    // f       g           h
+    (  1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0,
+    // Residuals
+    { 1.0, 2.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 4.0 },
+    // Gradient
+    { 15.0, 30.0,         // x
+      66.0, 99.0,         // y
+      42.0, 126.0, 168.0  // z
+    },
+    // Jacobian
+    //                x        y           z
+    {   /* f(x, y) */ 1, 2,    2, 3,    0, 0, 0,
                       1, 2,    2, 3,    0, 0, 0,
 
         /* g(x, z) */ 2, 4,    0, 0,    2, 6, 8,
@@ -532,17 +423,13 @@
         /* h(y, z) */ 0, 0,    6, 9,    3, 9, 12,
                       0, 0,    6, 9,    3, 9, 12,
                       0, 0,    6, 9,    3, 9, 12,
-                      0, 0,    6, 9,    3, 9, 12;
-
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+                      0, 0,    6, 9,    3, 9, 12 
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 }
 
 TEST_P(EvaluatorTest, MultipleResidualProblemWithSomeConstantParameters) {
-  ProblemImpl problem;
-
   // The values are ignored completely by the cost function.
   double x[2];
   double y[3];
@@ -576,71 +463,30 @@
   // Normally, the preprocessing of the program that happens in solver_impl
   // takes care of this, but we don't want to invoke the solver here.
   Program reduced_program;
-  *reduced_program.mutable_residual_blocks() =
-      problem.program().residual_blocks();
-  *reduced_program.mutable_parameter_blocks() =
-      problem.program().parameter_blocks();
+  vector<ParameterBlock*>* parameter_blocks =
+      problem.mutable_program()->mutable_parameter_blocks();
 
-  // "z" is the last parameter; pop it off.
-  reduced_program.mutable_parameter_blocks()->pop_back();
+  // "z" is the last parameter; save it for later and pop it off temporarily.
+  // Note that "z" will still get read during evaluation, so it cannot be
+  // deleted at this point.
+  ParameterBlock* parameter_block_z = parameter_blocks->back();
+  parameter_blocks->pop_back();
 
-  scoped_ptr<Evaluator> evaluator(CreateEvaluator(&reduced_program));
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  ASSERT_EQ(9, jacobian->num_rows());
-  ASSERT_EQ(5, jacobian->num_cols());
-
-  //                      f       g           h
-  double expected_cost = (1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0;
-
-
-  // Cost only; no residuals and no jacobian.
-  {
-    double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
-    EXPECT_EQ(expected_cost, cost);
-  }
-
-  // Cost and residuals, no jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-  }
-
-  // Cost, residuals, and jacobian.
-  {
-    double cost = -1;
-    double residuals[9] = { -2, -2, -2, -2, -2, -2, -2, -2, -2 };
-    SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
-    EXPECT_EQ(expected_cost, cost);
-    EXPECT_EQ(1.0, residuals[0]);
-    EXPECT_EQ(2.0, residuals[1]);
-    EXPECT_EQ(1.0, residuals[2]);
-    EXPECT_EQ(2.0, residuals[3]);
-    EXPECT_EQ(3.0, residuals[4]);
-    EXPECT_EQ(1.0, residuals[5]);
-    EXPECT_EQ(2.0, residuals[6]);
-    EXPECT_EQ(3.0, residuals[7]);
-    EXPECT_EQ(4.0, residuals[8]);
-
-    Matrix actual_jacobian;
-    jacobian->ToDenseMatrix(&actual_jacobian);
-
-    Matrix expected_jacobian(9, 5);
-    expected_jacobian <<
-    //                x        y
-        /* f(x, y) */ 1, 2,    1, 2, 3,
+  ExpectedEvaluation expected = {
+    // Rows/columns
+    9, 5,
+    // Cost
+    // f       g           h
+    (  1 + 4 + 1 + 4 + 9 + 1 + 4 + 9 + 16) / 2.0,
+    // Residuals
+    { 1.0, 2.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 4.0 },
+    // Gradient
+    { 15.0, 30.0,        // x
+      33.0, 66.0, 99.0,  // y
+    },
+    // Jacobian
+    //                x        y    
+    {   /* f(x, y) */ 1, 2,    1, 2, 3,
                       1, 2,    1, 2, 3,
 
         /* g(x, z) */ 2, 4,    0, 0, 0,
@@ -650,31 +496,27 @@
         /* h(y, z) */ 0, 0,    3, 6, 9,
                       0, 0,    3, 6, 9,
                       0, 0,    3, 6, 9,
-                      0, 0,    3, 6, 9;
+                      0, 0,    3, 6, 9
+    }
+  };
+  CheckAllEvaluationCombinations(expected);
 
-    EXPECT_TRUE((actual_jacobian.array() == expected_jacobian.array()).all())
-        << "Actual:\n" << actual_jacobian
-        << "\nExpected:\n" << expected_jacobian;
-  }
+  // Restore parameter block z, so it will get freed in a consistent way.
+  parameter_blocks->push_back(parameter_block_z);
 }
 
 TEST_P(EvaluatorTest, EvaluatorAbortsForResidualsThatFailToEvaluate) {
-  ProblemImpl problem;
-
-  // The values are ignored completely by the cost function.
-  double x[2];
-  double y[3];
-  double z[4];
-  double state[9];
-
   // Switch the return value to failure.
   problem.AddResidualBlock(
       new ParameterIgnoringCostFunction<20, 3, 2, 3, 4, false>, NULL, x, y, z);
 
+  // The values are ignored.
+  double state[9];
+
   scoped_ptr<Evaluator> evaluator(CreateEvaluator(problem.mutable_program()));
   scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
   double cost;
-  EXPECT_FALSE(evaluator->Evaluate(state, &cost, NULL, NULL));
+  EXPECT_FALSE(evaluator->Evaluate(state, &cost, NULL, NULL, NULL));
 }
 
 // In the pairs, the first argument is the linear solver type, and the second
@@ -762,7 +604,7 @@
   // Cost only; no residuals and no jacobian.
   {
     double cost = -1;
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL));
+    ASSERT_TRUE(evaluator->Evaluate(state, &cost, NULL, NULL, NULL));
     EXPECT_EQ(48.5, cost);
   }
 
@@ -770,7 +612,7 @@
   {
     double cost = -1;
     double residuals[2] = { -2, -2 };
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL));
+    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL, NULL));
     EXPECT_EQ(48.5, cost);
     EXPECT_EQ(4, residuals[0]);
     EXPECT_EQ(9, residuals[1]);
@@ -781,7 +623,7 @@
     double cost = -1;
     double residuals[2] = { -2, -2};
     SetSparseMatrixConstant(jacobian.get(), -1);
-    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, jacobian.get()));
+    ASSERT_TRUE(evaluator->Evaluate(state, &cost, residuals, NULL, jacobian.get()));
     EXPECT_EQ(48.5, cost);
     EXPECT_EQ(4, residuals[0]);
     EXPECT_EQ(9, residuals[1]);