|  | @@ -66,6 +66,46 @@ void ExpectJetsClose(const J &x, const J &y) {
 | 
	
		
			
				|  |  |    ExpectClose(x.v[1], y.v[1], kTolerance);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const double kStep = 1e-8;
 | 
	
		
			
				|  |  | +const double kNumericalTolerance = 1e-6; // Numeric derivation is quite inexact
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Differentiate using Jet and confirm results with numerical derivation.
 | 
	
		
			
				|  |  | +template<typename Function>
 | 
	
		
			
				|  |  | +void NumericalTest(const char* name, const Function& f, const double x) {
 | 
	
		
			
				|  |  | +  const double exact_dx = f(MakeJet(x, 1.0, 0.0)).v[0];
 | 
	
		
			
				|  |  | +  const double estimated_dx =
 | 
	
		
			
				|  |  | +    (f(J(x + kStep)).a - f(J(x - kStep)).a) / (2.0 * kStep);
 | 
	
		
			
				|  |  | +  VL << name << "(" << x << "), exact dx: "
 | 
	
		
			
				|  |  | +     << exact_dx << ", estimated dx: " << estimated_dx;
 | 
	
		
			
				|  |  | +  ExpectClose(exact_dx, estimated_dx, kNumericalTolerance);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Same as NumericalTest, but given a function taking two arguments.
 | 
	
		
			
				|  |  | +template<typename Function>
 | 
	
		
			
				|  |  | +void NumericalTest2(const char* name, const Function& f,
 | 
	
		
			
				|  |  | +                    const double x, const double y) {
 | 
	
		
			
				|  |  | +  const J exact_delta = f(MakeJet(x, 1.0, 0.0), MakeJet(y, 0.0, 1.0));
 | 
	
		
			
				|  |  | +  const double exact_dx = exact_delta.v[0];
 | 
	
		
			
				|  |  | +  const double exact_dy = exact_delta.v[1];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Sanity check – these should be equivalent:
 | 
	
		
			
				|  |  | +  EXPECT_EQ(exact_dx, f(MakeJet(x, 1.0, 0.0), MakeJet(y, 0.0, 0.0)).v[0]);
 | 
	
		
			
				|  |  | +  EXPECT_EQ(exact_dx, f(MakeJet(x, 0.0, 1.0), MakeJet(y, 0.0, 0.0)).v[1]);
 | 
	
		
			
				|  |  | +  EXPECT_EQ(exact_dy, f(MakeJet(x, 0.0, 0.0), MakeJet(y, 1.0, 0.0)).v[0]);
 | 
	
		
			
				|  |  | +  EXPECT_EQ(exact_dy, f(MakeJet(x, 0.0, 0.0), MakeJet(y, 0.0, 1.0)).v[1]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const double estimated_dx =
 | 
	
		
			
				|  |  | +    (f(J(x + kStep), J(y)).a - f(J(x - kStep), J(y)).a) / (2.0 * kStep);
 | 
	
		
			
				|  |  | +  const double estimated_dy =
 | 
	
		
			
				|  |  | +    (f(J(x), J(y + kStep)).a - f(J(x), J(y - kStep)).a) / (2.0 * kStep);
 | 
	
		
			
				|  |  | +  VL << name << "(" << x << ", " << y << "), exact dx: "
 | 
	
		
			
				|  |  | +     << exact_dx << ", estimated dx: " << estimated_dx;
 | 
	
		
			
				|  |  | +  ExpectClose(exact_dx, estimated_dx, kNumericalTolerance);
 | 
	
		
			
				|  |  | +  VL << name << "(" << x << ", " << y << "), exact dy: "
 | 
	
		
			
				|  |  | +     << exact_dy << ", estimated dy: " << estimated_dy;
 | 
	
		
			
				|  |  | +  ExpectClose(exact_dy, estimated_dy, kNumericalTolerance);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  TEST(Jet, Jet) {
 | 
	
		
			
				|  |  |    // Pick arbitrary values for x and y.
 | 
	
		
			
				|  |  |    J x = MakeJet(2.3, -2.7, 1e-3);
 | 
	
	
		
			
				|  | @@ -106,6 +146,9 @@ TEST(Jet, Jet) {
 | 
	
		
			
				|  |  |      ExpectJetsClose(w, y);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  NumericalTest("sqrt", sqrt<double, 2>, 0.00001);
 | 
	
		
			
				|  |  | +  NumericalTest("sqrt", sqrt<double, 2>, 1.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    { // Check that cos(2*x) = cos(x)^2 - sin(x)^2
 | 
	
		
			
				|  |  |      J z = cos(J(2.0) * x);
 | 
	
		
			
				|  |  |      J w = cos(x)*cos(x) - sin(x)*sin(x);
 | 
	
	
		
			
				|  | @@ -523,6 +566,137 @@ TEST(Jet, Jet) {
 | 
	
		
			
				|  |  |      J expected = MakeJet(ceil(a.a), 0.0, 0.0);
 | 
	
		
			
				|  |  |      EXPECT_EQ(expected, b);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  #ifdef CERES_USE_CXX11
 | 
	
		
			
				|  |  | +  { // Check that cbrt(x * x * x) == x.
 | 
	
		
			
				|  |  | +    J z = x * x * x;
 | 
	
		
			
				|  |  | +    J w = cbrt(z);
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    VL << "w = " << w;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(w, x);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that cbrt(y) * cbrt(y) * cbrt(y) == y.
 | 
	
		
			
				|  |  | +    J z = cbrt(y);
 | 
	
		
			
				|  |  | +    J w = z * z * z;
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    VL << "w = " << w;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(w, y);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that cbrt(x) == pow(x, 1/3).
 | 
	
		
			
				|  |  | +    J z = cbrt(x);
 | 
	
		
			
				|  |  | +    J w = pow(x, 1.0 / 3.0);
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    VL << "w = " << w;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(z, w);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  NumericalTest("cbrt", cbrt<double, 2>, -1.0);
 | 
	
		
			
				|  |  | +  NumericalTest("cbrt", cbrt<double, 2>, -1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest("cbrt", cbrt<double, 2>, 1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest("cbrt", cbrt<double, 2>, 1.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that exp2(x) == exp(x * log(2))
 | 
	
		
			
				|  |  | +    J z = exp2(x);
 | 
	
		
			
				|  |  | +    J w = exp(x * log(2.0));
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    VL << "w = " << w;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(z, w);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, -1.0);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, -1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, -1e-200);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, 0.0);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, 1e-200);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, 1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest("exp2", exp2<double, 2>, 1.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that log2(x) == log(x) / log(2)
 | 
	
		
			
				|  |  | +    J z = log2(x);
 | 
	
		
			
				|  |  | +    J w = log(x) / log(2.0);
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    VL << "w = " << w;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(z, w);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  NumericalTest("log2", log2<double, 2>, 1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest("log2", log2<double, 2>, 1.0);
 | 
	
		
			
				|  |  | +  NumericalTest("log2", log2<double, 2>, 100.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(x, y) == sqrt(x^2 + y^2)
 | 
	
		
			
				|  |  | +    J h = hypot(x, y);
 | 
	
		
			
				|  |  | +    J s = sqrt(x*x + y*y);
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    VL << "s = " << s;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(h, s);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(x, x) == sqrt(2) * abs(x)
 | 
	
		
			
				|  |  | +    J h = hypot(x, x);
 | 
	
		
			
				|  |  | +    J s = sqrt(2.0) * abs(x);
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    VL << "s = " << s;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(h, s);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that the derivative is zero tangentially to the circle:
 | 
	
		
			
				|  |  | +    J h = hypot(MakeJet(2.0, 1.0, 1.0), MakeJet(2.0, 1.0, -1.0));
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(h, MakeJet(sqrt(8.0), std::sqrt(2.0), 0.0));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(x, 0) == x
 | 
	
		
			
				|  |  | +    J zero = MakeJet(0.0, 2.0, 3.14);
 | 
	
		
			
				|  |  | +    J h = hypot(x, zero);
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(x, h);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(0, y) == y
 | 
	
		
			
				|  |  | +    J zero = MakeJet(0.0, 2.0, 3.14);
 | 
	
		
			
				|  |  | +    J h = hypot(zero, y);
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(y, h);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(x, 0) == sqrt(x * x) == x, even when x * x underflows:
 | 
	
		
			
				|  |  | +    EXPECT_EQ(DBL_MIN * DBL_MIN, 0.0); // Make sure it underflows
 | 
	
		
			
				|  |  | +    J huge = MakeJet(DBL_MIN, 2.0, 3.14);
 | 
	
		
			
				|  |  | +    J h = hypot(huge, J(0.0));
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(h, huge);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  { // Check that hypot(x, 0) == sqrt(x * x) == x, even when x * x overflows:
 | 
	
		
			
				|  |  | +    EXPECT_EQ(DBL_MAX * DBL_MAX, std::numeric_limits<double>::infinity());
 | 
	
		
			
				|  |  | +    J huge = MakeJet(DBL_MAX, 2.0, 3.14);
 | 
	
		
			
				|  |  | +    J h = hypot(huge, J(0.0));
 | 
	
		
			
				|  |  | +    VL << "h = " << h;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(h, huge);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  0.0,   1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>, -1e-5,  0.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  1e-5,  1e-5);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  0.0,   1.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  1e-3,  1.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  1e-3, -1.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>, -1e-3,  1.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>, -1e-3, -1.0);
 | 
	
		
			
				|  |  | +  NumericalTest2("hypot", hypot<double, 2>,  1.0,   2.0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    J z = fmax(x, y);
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(x, z);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    J z = fmin(x, y);
 | 
	
		
			
				|  |  | +    VL << "z = " << z;
 | 
	
		
			
				|  |  | +    ExpectJetsClose(y, z);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  #endif
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  TEST(Jet, JetsInEigenMatrices) {
 |