BivariateNormalDistribution implements ProbabilityDistribution<double[]> { @Override public double getCDF(final double[] x) { Validate.notNull(x); Validate.isTrue(x.length == 3, "Need a, b and rho values"); Validate.isTrue(x[2] >= -1 && x[2] <= 1, "Correlation must be >= -1 and <= 1"); final double a = x[0]; double b = x[1]; final double rho = x[2]; if (a == Double.POSITIVE_INFINITY || b == Double.POSITIVE_INFINITY) { return 1; } if (a == Double.NEGATIVE_INFINITY || b == Double.NEGATIVE_INFINITY) { return 0; } final double sumSq = (a * a + b * b) / 2.; double rho1, rho2, rho3, ab, absDiff, h5, c, d, mult = 0, rho3Sq, eab, e, result; if (Math.abs(rho) >= 0.7) { rho1 = 1 - rho * rho; rho2 = Math.sqrt(rho1); if (rho < 0) { b *= -1; } ab = a * b; eab = Math.exp(-ab / 2.); if (Math.abs(rho) < 1) { absDiff = Math.abs(a - b); h5 = absDiff * absDiff / 2.; absDiff = absDiff / rho2; c = 0.5 - ab / 8.; d = 3. - 2. * c * h5; mult = 0.13298076 * absDiff * d * (1 - NORMAL.getCDF(absDiff)) - Math.exp(-h5 / rho1) * (d + c * rho1) * 0.053051647; for (int i = 0; i < 5; i++) { rho3 = rho2 * X[i]; rho3Sq = rho3 * rho3; rho1 = Math.sqrt(1 - rho3Sq); if (eab == 0) { e = 0; } else { e = Math.exp(-ab / (1 + rho1)) / rho1 / eab; } mult = mult - Y[i] * Math.exp(-h5 / rho3Sq) * (e - 1 - c * rho3Sq); } } final double corr = Double.isNaN(mult) ? 0. : mult * rho2 * eab; result = corr + NORMAL.getCDF(Math.min(a, b)); if (rho < 0) { result = NORMAL.getCDF(a) - result; } return result; } ab = a * b; if (rho != 0) { for (int i = 0; i < 5; i++) { rho3 = rho * X[i]; rho1 = 1 - rho3 * rho3; mult = mult + Y[i] * Math.exp((rho3 * ab - sumSq) / rho1) / Math.sqrt(rho1); } } final double corr = Double.isNaN(mult) ? 0. : rho * mult; return NORMAL.getCDF(a) * NORMAL.getCDF(b) + corr; }  @Override double getCDF(final double[] x); @Override double getInverseCDF(final double[] p); @Override double getPDF(final double[] x); @Override double nextRandom();  }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullCDF() { DIST.getCDF(null); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testInsufficientLengthCDF() { DIST.getCDF(new double[] {2, 1}); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testExcessiveLengthCDF() { DIST.getCDF(new double[] {2, 1, 4, 5}); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testHighCorrelation() { DIST.getCDF(new double[] {1., 1., 3.}); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testLowCorrelation() { DIST.getCDF(new double[] {1., 1., -3.}); }
@Test public void test() { assertEquals(DIST.getCDF(new double[] {Double.POSITIVE_INFINITY, Math.random(), Math.random()}), 1, 0); assertEquals(DIST.getCDF(new double[] {Math.random(), Double.POSITIVE_INFINITY, Math.random()}), 1, 0); assertEquals(DIST.getCDF(new double[] {Double.NEGATIVE_INFINITY, Math.random(), Math.random()}), 0, 0); assertEquals(DIST.getCDF(new double[] {Math.random(), Double.NEGATIVE_INFINITY, Math.random()}), 0, 0); assertEquals(DIST.getCDF(new double[] {0.0, 0.0, 0.0}), 0.25, EPS); assertEquals(DIST.getCDF(new double[] {0.0, 0.0, -0.5}), 1. / 6, EPS); assertEquals(DIST.getCDF(new double[] {0.0, 0.0, 0.5}), 1. / 3, EPS); assertEquals(DIST.getCDF(new double[] {0.0, -0.5, 0.0}), 0.1542687694, EPS); assertEquals(DIST.getCDF(new double[] {0.0, -0.5, -0.5}), 0.0816597607, EPS); assertEquals(DIST.getCDF(new double[] {0.0, -0.5, 0.5}), 0.2268777781, EPS); assertEquals(DIST.getCDF(new double[] {0.0, 0.5, 0.0}), 0.3457312306, EPS); assertEquals(DIST.getCDF(new double[] {0.0, 0.5, -0.5}), 0.2731222219, EPS); assertEquals(DIST.getCDF(new double[] {0.0, 0.5, 0.5}), 0.4183402393, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.0, 0.0}), 0.1542687694, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.0, -0.5}), 0.0816597607, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.0, 0.5}), 0.2268777781, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, -0.5, 0.0}), 0.0951954128, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, -0.5, -0.5}), 0.0362981865, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, -0.5, 0.5}), 0.1633195213, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.5, 0.0}), 0.2133421259, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.5, -0.5}), 0.1452180174, EPS); assertEquals(DIST.getCDF(new double[] {-0.5, 0.5, 0.5}), 0.2722393522, EPS); assertEquals(DIST.getCDF(new double[] {0.5, 0.0, 0.0}), 0.3457312306, EPS); assertEquals(DIST.getCDF(new double[] {0.5, 0.0, -0.5}), 0.2731222219, EPS); assertEquals(DIST.getCDF(new double[] {0.5, 0.0, 0.5}), 0.4183402393, EPS); assertEquals(DIST.getCDF(new double[] {0.5, -0.5, 0.0}), 0.2133421259, EPS); assertEquals(DIST.getCDF(new double[] {0.5, -0.5, -0.5}), 0.1452180174, EPS); assertEquals(DIST.getCDF(new double[] {0.5, -0.5, 0.5}), 0.2722393522, EPS); assertEquals(DIST.getCDF(new double[] {0.5, 0.5, 0.0}), 0.4781203354, EPS); assertEquals(DIST.getCDF(new double[] {0.5, 0.5, -0.5}), 0.4192231090, EPS); assertEquals(DIST.getCDF(new double[] {0.0, -1.0, -1.0}), 0.00000000, EPS); }