Comparison { @SuppressWarnings("WeakerAccess") public static double compareChi2(TDigest dist1, TDigest dist2, double[] qCuts) { double[][] count = new double[2][]; count[0] = new double[qCuts.length + 1]; count[1] = new double[qCuts.length + 1]; double oldQ = 0; double oldQ2 = 0; for (int i = 0; i <= qCuts.length; i++) { double newQ; double x; if (i == qCuts.length) { newQ = 1; x = Math.max(dist1.getMax(), dist2.getMax()) + 1; } else { newQ = qCuts[i]; x = dist1.quantile(newQ); } count[0][i] = dist1.size() * (newQ - oldQ); double q2 = dist2.cdf(x); count[1][i] = dist2.size() * (q2 - oldQ2); oldQ = newQ; oldQ2 = q2; } return llr(count); }  @SuppressWarnings("WeakerAccess") static double compareChi2(TDigest dist1, TDigest dist2, double[] qCuts); @SuppressWarnings("WeakerAccess") static double compareChi2(Histogram dist1, Histogram dist2); @SuppressWarnings("WeakerAccess") static double llr(double[][] count); static double ks(TDigest d1, TDigest d2);  }
@Test public void compareMergingDigests() { TDigest d1 = new MergingDigest(100); TDigest d2 = new MergingDigest(100); d1.add(1); d2.add(3); assertEquals(2.77, Comparison.compareChi2(d1, d2, new double[]{1}), 0.01); Random r = new Random(); int failed = 0; for (int i = 0; i < 1000; i++) { d1 = new MergingDigest(100); d2 = new MergingDigest(100); MergingDigest d3 = new MergingDigest(100); for (int j = 0; j < 10000; j++) { d1.add(r.nextGaussian()); d2.add(r.nextGaussian()); d3.add(r.nextGaussian() + 0.3); } if (Comparison.compareChi2(d1, d2, new double[]{0.1, 0.3, 0.5, 0.8, 0.9}) > 25) { failed++; } if (Comparison.compareChi2(d1, d2, new double[]{0.1}) > 20) { failed++; } if (Comparison.compareChi2(d1, d2, new double[]{0.5}) > 20) { failed++; } if (Comparison.compareChi2(d1, d3, new double[]{0.1, 0.5, 0.9}) < 90) { failed++; } } assertEquals(0, failed, 5); System.out.printf("Failed %d times (up to 5 acceptable)", failed); }
@Test public void compareLogHistograms() { Random r = new Random(); int failed = 0; try { Comparison.compareChi2(new LogHistogram(10e-6, 10), new LogHistogram(1e-6, 1)); fail("Should have detected incompatible histograms (lower bound)"); } catch (IllegalArgumentException e) { assertEquals("Incompatible histograms in terms of size or bounds", e.getMessage()); } try { Comparison.compareChi2(new LogHistogram(10e-6, 10), new LogHistogram(10e-6, 1)); fail("Should have detected incompatible histograms (size)"); } catch (IllegalArgumentException e) { assertEquals("Incompatible histograms in terms of size or bounds", e.getMessage()); } for (int i = 0; i < 1000; i++) { LogHistogram d1 = new LogHistogram(10e-6, 10); LogHistogram d2 = new LogHistogram(10e-6, 10); LogHistogram d3 = new LogHistogram(10e-6, 10); for (int j = 0; j < 10000; j++) { d1.add(Math.exp(r.nextGaussian())); d2.add(Math.exp(r.nextGaussian())); d3.add(Math.exp(r.nextGaussian() + 0.5)); } if (Comparison.compareChi2(d1, d2) > 250) { failed++; } if (Comparison.compareChi2(d1, d3) < 1000) { failed++; } } assertEquals(0, failed, 5); }