Fix bug where pow(JetA,JetB) returned wrong result for JetA==0.

Change-Id: Ife7f6f3aca06322fa414ef747008d2b4dc468a57
diff --git a/include/ceres/jet.h b/include/ceres/jet.h
index b476d80..87197ad 100644
--- a/include/ceres/jet.h
+++ b/include/ceres/jet.h
@@ -573,22 +573,57 @@
 }
 
 // pow -- base is a constant, exponent is a differentiable function.
-// (a)^(p+dp) ~= a^p + a^p log(a) dp
+// For a > 0 we have: (a)^(p + dp) ~= a^p + a^p log(a) dp
+// For a == 0 and p > 0 we have: (a)^(p + dp) ~= 0
 template <typename T, int N> inline
 Jet<T, N> pow(double f, const Jet<T, N>& g) {
+  if (f == 0 && g.a > 0) {
+    return Jet<T, N>(T(0.0));
+  }
   T const tmp = pow(f, g.a);
   return Jet<T, N>(tmp, log(f) * tmp * g.v);
 }
 
+// pow -- both base and exponent are differentiable functions. This has a
+// variety of special cases that require careful handling.
+//
+// * For a > 0: (a + da)^(b + db) ~= a^b + a^(b - 1) * (b*da + a*log(a)*db)
+//   The numerical evaluation of a*log(a) for a > 0 is well behaved, even for
+//   extremely small values (e.g. 1e-99).
+//
+// * For a == 0 and b > 1: (a + da)^(b + db) ~= 0
+//   This cases is needed because log(0) can not be evaluated in the a > 0
+//   expression. However the function a*log(a) is well behaved around a == 0
+//   and its limit as a-->0 is zero.
+//
+// * For a == 0 and b == 1: (a + da)^(b + db) ~= 0 + da
+//
+// * For a == 0 and 0 < b < 1: The value is finite but the derivatives are not.
+//
+// * For a == 0 and b < 0: The value and derivatives of a^b are not finite.
+//
+// * For a == 0 and b == 0: The C standard incorrectly defines 0^0 to be 1
+//   "because there are applications that can exploit this definition". We
+//   (arbitrarily) decree that derivatives here will be nonfinite, since that
+//   is consistent with the behavior for b < 0 and 0 < b < 1. Practically any
+//   definition could have been justified because mathematical consistency has
+//   been lost at this point.
 
-// pow -- both base and exponent are differentiable functions.
-// (a+da)^(b+db) ~= a^b + b * a^(b-1) da + a^b log(a) * db
 template <typename T, int N> inline
 Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
+  if (f.a == 0 && g.a >= 1) {
+    // Handle the special cases when f == 0.
+    if (g.a > 1) {
+      return Jet<T, N>(T(0.0));
+    }
+    return Jet<T, N>(T(0.0), f.v);
+  }
+  // Handle the generic case for f != 0. We also handle f == 0, g < 1 here and
+  // allow the log() function to generate -HUGE_VAL, since this results in a
+  // nonfinite derivative.
   T const tmp1 = pow(f.a, g.a);
   T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
   T const tmp3 = tmp1 * log(f.a);
-
   return Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
 }
 
diff --git a/internal/ceres/jet_test.cc b/internal/ceres/jet_test.cc
index 4598099..394dbb8 100644
--- a/internal/ceres/jet_test.cc
+++ b/internal/ceres/jet_test.cc
@@ -244,6 +244,82 @@
     ExpectJetsClose(v, u);
   }
 
+  { // Check that pow(0,y) == 1 for y>1, with both arguments Jets.
+    // This tests special case handling inside pow().
+    J a = MakeJet(0, 1, 2);
+    J b = MakeJet(2, 3, 4);
+    VL << "a = " << a;
+    VL << "b = " << b;
+
+    J c = pow(a, b);
+    VL << "a^b = " << c;
+    ExpectJetsClose(c, MakeJet(0, 0, 0));
+  }
+
+  { // Check that pow(0,y) == 1 for y==1, with both arguments Jets.
+    // This tests special case handling inside pow().
+    J a = MakeJet(0, 1, 2);
+    J b = MakeJet(1, 3, 4);
+    VL << "a = " << a;
+    VL << "b = " << b;
+
+    J c = pow(a, b);
+    VL << "a^b = " << c;
+    ExpectJetsClose(c, MakeJet(0, 1, 2));
+  }
+
+  { // Check that pow(0,<1) is not finite, with both arguments Jets.
+    for (int i = 1; i < 10; i++) {
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(i*0.1, 3, 4);       // b=0.1 ... 0.9
+      VL << "a = " << a;
+      VL << "b = " << b;
+
+      J c = pow(a, b);
+      VL << "a^b = " << c;
+      EXPECT_EQ(c.a, 0.0);
+      EXPECT_FALSE(IsFinite(c.v[0]));
+      EXPECT_FALSE(IsFinite(c.v[1]));
+    }
+    for (int i = -10; i < 0; i++) {
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(i*0.1, 3, 4);       // b=-1,-0.9 ... 0
+      VL << "a = " << a;
+      VL << "b = " << b;
+
+      J c = pow(a, b);
+      VL << "a^b = " << c;
+      EXPECT_FALSE(IsFinite(c.a));
+      EXPECT_FALSE(IsFinite(c.v[0]));
+      EXPECT_FALSE(IsFinite(c.v[1]));
+    }
+    {
+      // The special case of 0^0=1 defined by the C standard.
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(0, 3, 4);
+      VL << "a = " << a;
+      VL << "b = " << b;
+
+      J c = pow(a, b);
+      VL << "a^b = " << c;
+      EXPECT_EQ(c.a, 1.0);
+      EXPECT_FALSE(IsFinite(c.v[0]));
+      EXPECT_FALSE(IsFinite(c.v[1]));
+    }
+  }
+
+  { // Check that pow(0,y) == 1 for y==2, with the second argument a Jets.
+    // This tests special case handling inside pow().
+    double a = 0;
+    J b = MakeJet(2, 3, 4);
+    VL << "a = " << a;
+    VL << "b = " << b;
+
+    J c = pow(a, b);
+    VL << "a^b = " << c;
+    ExpectJetsClose(c, MakeJet(0, 0, 0));
+  }
+
   { // Check that 1 + x == x + 1.
     J a = x + 1.0;
     J b = 1.0 + x;