Allow the LossFunction contained in a LossFunctionWrapper to be NULL.
This is consistent with how NULL LossFunctions are treated everywhere
else.

Change-Id: Ic91e39ccb13137fcad7f85e78613a29ecde30d67
diff --git a/include/ceres/loss_function.h b/include/ceres/loss_function.h
index 78397f0..44c6b87 100644
--- a/include/ceres/loss_function.h
+++ b/include/ceres/loss_function.h
@@ -358,6 +358,9 @@
 // whose scale can be mutated after an optimization problem has been
 // constructed.
 //
+// Since we treat the a NULL Loss function as the Identity loss
+// function, rho = NULL is a valid input.
+//
 // Example usage
 //
 //  Problem problem;
@@ -394,8 +397,14 @@
   }
 
   virtual void Evaluate(double sq_norm, double out[3]) const {
-    CHECK_NOTNULL(rho_.get());
-    rho_->Evaluate(sq_norm, out);
+    if (rho_.get() == NULL) {
+      out[0] = sq_norm;
+      out[1] = 1.0;
+      out[2] = 0.0;
+    }
+    else {
+      rho_->Evaluate(sq_norm, out);
+    }
   }
 
   void Reset(LossFunction* rho, Ownership ownership) {
diff --git a/internal/ceres/loss_function_test.cc b/internal/ceres/loss_function_test.cc
index d06f69e..406ace7 100644
--- a/internal/ceres/loss_function_test.cc
+++ b/internal/ceres/loss_function_test.cc
@@ -228,6 +228,24 @@
   for (int i = 0; i < 3; ++i) {
     EXPECT_NEAR(rho[i], rho_gold[i], 1e-12);
   }
+
+  // Set to NULL
+  TrivialLoss loss_function4;
+  loss_function_wrapper.Reset(NULL, TAKE_OWNERSHIP);
+  loss_function_wrapper.Evaluate(s, rho);
+  loss_function4.Evaluate(s, rho_gold);
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_NEAR(rho[i], rho_gold[i], 1e-12);
+  }
+
+  // Set to NULL, not taking ownership
+  loss_function_wrapper.Reset(NULL, DO_NOT_TAKE_OWNERSHIP);
+  loss_function_wrapper.Evaluate(s, rho);
+  loss_function4.Evaluate(s, rho_gold);
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_NEAR(rho[i], rho_gold[i], 1e-12);
+  }
+
 }
 
 }  // namespace internal