You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2018/01/21 14:05:45 UTC

[10/16] commons-statistics git commit: STATISTICS-2: Migrate "o.a.c.math4.distribution" from Commons Math.

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractDiscreteDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractDiscreteDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractDiscreteDistributionTest.java
new file mode 100644
index 0000000..bcf8e7c
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/AbstractDiscreteDistributionTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.statistics.distribution;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for AbstractDiscreteDistribution default implementations.
+ *
+ */
+public class AbstractDiscreteDistributionTest {
+    protected final DiceDistribution diceDistribution = new DiceDistribution();
+    protected final double p = diceDistribution.probability(1);
+
+    @Test
+    public void testInverseCumulativeProbabilityMethod()
+    {
+        double precision = 0.000000000000001;
+        Assert.assertEquals(1, diceDistribution.inverseCumulativeProbability(0));
+        Assert.assertEquals(1, diceDistribution.inverseCumulativeProbability((1d-Double.MIN_VALUE)/6d));
+        Assert.assertEquals(2, diceDistribution.inverseCumulativeProbability((1d+precision)/6d));
+        Assert.assertEquals(2, diceDistribution.inverseCumulativeProbability((2d-Double.MIN_VALUE)/6d));
+        Assert.assertEquals(3, diceDistribution.inverseCumulativeProbability((2d+precision)/6d));
+        Assert.assertEquals(3, diceDistribution.inverseCumulativeProbability((3d-Double.MIN_VALUE)/6d));
+        Assert.assertEquals(4, diceDistribution.inverseCumulativeProbability((3d+precision)/6d));
+        Assert.assertEquals(4, diceDistribution.inverseCumulativeProbability((4d-Double.MIN_VALUE)/6d));
+        Assert.assertEquals(5, diceDistribution.inverseCumulativeProbability((4d+precision)/6d));
+        Assert.assertEquals(5, diceDistribution.inverseCumulativeProbability((5d-precision)/6d));//Can't use Double.MIN
+        Assert.assertEquals(6, diceDistribution.inverseCumulativeProbability((5d+precision)/6d));
+        Assert.assertEquals(6, diceDistribution.inverseCumulativeProbability((6d-precision)/6d));//Can't use Double.MIN
+        Assert.assertEquals(6, diceDistribution.inverseCumulativeProbability((6d)/6d));
+    }
+
+    @Test
+    public void testCumulativeProbabilitiesSingleArguments() {
+        for (int i = 1; i < 7; i++) {
+            Assert.assertEquals(p * i,
+                    diceDistribution.cumulativeProbability(i), Double.MIN_VALUE);
+        }
+        Assert.assertEquals(0.0,
+                diceDistribution.cumulativeProbability(0), Double.MIN_VALUE);
+        Assert.assertEquals(1.0,
+                diceDistribution.cumulativeProbability(7), Double.MIN_VALUE);
+    }
+
+    @Test
+    public void testProbabilitiesRangeArguments() {
+        int lower = 0;
+        int upper = 6;
+        for (int i = 0; i < 2; i++) {
+            // cum(0,6) = p(0 < X <= 6) = 1, cum(1,5) = 4/6, cum(2,4) = 2/6
+            Assert.assertEquals(1 - p * 2 * i,
+                    diceDistribution.probability(lower, upper), 1E-12);
+            lower++;
+            upper--;
+        }
+        for (int i = 0; i < 6; i++) {
+            Assert.assertEquals(p, diceDistribution.probability(i, i+1), 1E-12);
+        }
+    }
+
+    /**
+     * Simple distribution modeling a 6-sided die
+     */
+    class DiceDistribution extends AbstractDiscreteDistribution {
+        public static final long serialVersionUID = 23734213;
+
+        private final double p = 1d/6d;
+
+        @Override
+        public double probability(int x) {
+            if (x < 1 || x > 6) {
+                return 0;
+            } else {
+                return p;
+            }
+        }
+
+        @Override
+        public double cumulativeProbability(int x) {
+            if (x < 1) {
+                return 0;
+            } else if (x >= 6) {
+                return 1;
+            } else {
+                return p * x;
+            }
+        }
+
+        @Override
+        public double getNumericalMean() {
+            return 3.5;
+        }
+
+        @Override
+        public double getNumericalVariance() {
+            return 70/24;  // E(X^2) - E(X)^2
+        }
+
+        @Override
+        public int getSupportLowerBound() {
+            return 1;
+        }
+
+        @Override
+        public int getSupportUpperBound() {
+            return 6;
+        }
+
+        @Override
+        public final boolean isSupportConnected() {
+            return true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
new file mode 100644
index 0000000..f37961c
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
@@ -0,0 +1,381 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.statistics.distribution;
+
+import java.util.Arrays;
+
+import org.apache.commons.rng.simple.RandomSource;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.math3.stat.StatUtils;
+import org.apache.commons.math3.stat.inference.GTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BetaDistributionTest {
+
+    static final double[] alphaBetas = {0.1, 1, 10, 100, 1000};
+    static final double epsilon = StatUtils.min(alphaBetas);
+
+    @Test
+    public void testCumulative() {
+        double[] x = new double[]{-0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1};
+        // all test data computed using R 2.5
+        checkCumulative(0.1, 0.1,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.4063850939, 0.4397091902, 0.4628041861,
+                            0.4821200456, 0.5000000000, 0.5178799544, 0.5371958139, 0.5602908098,
+                            0.5936149061, 1.0000000000, 1.0000000000});
+        checkCumulative(0.1, 0.5,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.7048336221, 0.7593042194, 0.7951765304,
+                            0.8234948385, 0.8480017124, 0.8706034370, 0.8926585878, 0.9156406404,
+                            0.9423662883, 1.0000000000, 1.0000000000});
+        checkCumulative(0.1, 1.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.7943282347, 0.8513399225, 0.8865681506,
+                            0.9124435366, 0.9330329915, 0.9502002165, 0.9649610951, 0.9779327685,
+                            0.9895192582, 1.0000000000, 1.0000000000});
+        checkCumulative(0.1, 2.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.8658177758, 0.9194471163, 0.9486279211,
+                            0.9671901487, 0.9796846411, 0.9882082252, 0.9939099280, 0.9974914239,
+                            0.9994144508, 1.0000000000, 1.0000000000});
+        checkCumulative(0.1, 4.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.9234991121, 0.9661958941, 0.9842285085,
+                            0.9928444112, 0.9970040660, 0.9989112804, 0.9996895625, 0.9999440793,
+                            0.9999967829, 1.0000000000, 1.0000000000});
+        checkCumulative(0.5, 0.1,
+                        x, new double[]{
+                            0.00000000000, 0.00000000000, 0.05763371168, 0.08435935962,
+                            0.10734141216, 0.12939656302, 0.15199828760, 0.17650516146,
+                            0.20482346963, 0.24069578055, 0.29516637795, 1.00000000000, 1.00000000000});
+
+        checkCumulative(0.5, 0.5,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.2048327647, 0.2951672353, 0.3690101196,
+                            0.4359057832, 0.5000000000, 0.5640942168, 0.6309898804, 0.7048327647,
+                            0.7951672353, 1.0000000000, 1.0000000000});
+        checkCumulative(0.5, 1.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.3162277660, 0.4472135955, 0.5477225575,
+                            0.6324555320, 0.7071067812, 0.7745966692, 0.8366600265, 0.8944271910,
+                            0.9486832981, 1.0000000000, 1.0000000000});
+        checkCumulative(0.5, 2.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.4585302607, 0.6260990337, 0.7394254526,
+                            0.8221921916, 0.8838834765, 0.9295160031, 0.9621590305, 0.9838699101,
+                            0.9961174630, 1.0000000000, 1.0000000000});
+        checkCumulative(0.5, 4.0,
+                        x, new double[]{
+                            0.0000000000, 0.0000000000, 0.6266250826, 0.8049844719, 0.8987784842,
+                            0.9502644369, 0.9777960959, 0.9914837366, 0.9974556254, 0.9995223859,
+                            0.9999714889, 1.0000000000, 1.0000000000});
+        checkCumulative(1.0, 0.1,
+                        x, new double[]{
+                            0.00000000000, 0.00000000000, 0.01048074179, 0.02206723146,
+                            0.03503890488, 0.04979978349, 0.06696700846, 0.08755646344,
+                            0.11343184943, 0.14866007748, 0.20567176528, 1.00000000000, 1.00000000000});
+        checkCumulative(1.0, 0.5,
+                        x, new double[]{
+                            0.00000000000, 0.00000000000, 0.05131670195, 0.10557280900,
+                            0.16333997347, 0.22540333076, 0.29289321881, 0.36754446797,
+                            0.45227744249, 0.55278640450, 0.68377223398, 1.00000000000, 1.00000000000});
+        checkCumulative(1, 1,
+                        x, new double[]{
+                            0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.0});
+        checkCumulative(1, 2,
+                        x, new double[]{
+                            0.00, 0.00, 0.19, 0.36, 0.51, 0.64, 0.75, 0.84, 0.91, 0.96, 0.99, 1.00, 1.00});
+        checkCumulative(1, 4,
+                        x, new double[]{
+                            0.0000, 0.0000, 0.3439, 0.5904, 0.7599, 0.8704, 0.9375, 0.9744, 0.9919,
+                            0.9984, 0.9999, 1.0000, 1.0000});
+        checkCumulative(2.0, 0.1,
+                        x, new double[]{
+                            0.0000000000000, 0.0000000000000, 0.0005855492117, 0.0025085760862,
+                            0.0060900720266, 0.0117917748341, 0.0203153588864, 0.0328098512512,
+                            0.0513720788952, 0.0805528836776, 0.1341822241505, 1.0000000000000, 1.0000000000000});
+        checkCumulative(2, 1,
+                        x, new double[]{
+                            0.00, 0.00, 0.01, 0.04, 0.09, 0.16, 0.25, 0.36, 0.49, 0.64, 0.81, 1.00, 1.00});
+        checkCumulative(2.0, 0.5,
+                        x, new double[]{
+                            0.000000000000, 0.000000000000, 0.003882537047, 0.016130089900,
+                            0.037840969486, 0.070483996910, 0.116116523517, 0.177807808356,
+                            0.260574547368, 0.373900966300, 0.541469739276, 1.000000000000, 1.000000000000});
+        checkCumulative(2, 2,
+                        x, new double[]{
+                            0.000, 0.000, 0.028, 0.104, 0.216, 0.352, 0.500, 0.648, 0.784, 0.896, 0.972, 1.000, 1.000});
+        checkCumulative(2, 4,
+                        x, new double[]{
+                            0.00000, 0.00000, 0.08146, 0.26272, 0.47178, 0.66304, 0.81250, 0.91296,
+                            0.96922, 0.99328, 0.99954, 1.00000, 1.00000});
+        checkCumulative(4.0, 0.1,
+                        x, new double[]{
+                            0.000000000e+00, 0.000000000e+00, 3.217128269e-06, 5.592070271e-05,
+                            3.104375474e-04, 1.088719595e-03, 2.995933981e-03, 7.155588777e-03,
+                            1.577149153e-02, 3.380410585e-02, 7.650088789e-02, 1.000000000e+00, 1.000000000e+00});
+        checkCumulative(4.0, 0.5,
+                        x, new double[]{
+                            0.000000000e+00, 0.000000000e+00, 2.851114863e-05, 4.776140576e-04,
+                            2.544374616e-03, 8.516263371e-03, 2.220390414e-02, 4.973556312e-02,
+                            1.012215158e-01, 1.950155281e-01, 3.733749174e-01, 1.000000000e+00, 1.000000000e+00});
+        checkCumulative(4, 1,
+                        x, new double[]{
+                            0.0000, 0.0000, 0.0001, 0.0016, 0.0081, 0.0256, 0.0625, 0.1296, 0.2401,
+                            0.4096, 0.6561, 1.0000, 1.0000});
+        checkCumulative(4, 2,
+                        x, new double[]{
+                            0.00000, 0.00000, 0.00046, 0.00672, 0.03078, 0.08704, 0.18750, 0.33696,
+                            0.52822, 0.73728, 0.91854, 1.00000, 1.00000});
+        checkCumulative(4, 4,
+                        x, new double[]{
+                            0.000000, 0.000000, 0.002728, 0.033344, 0.126036, 0.289792, 0.500000,
+                            0.710208, 0.873964, 0.966656, 0.997272, 1.000000, 1.000000});
+    }
+
+    private void checkCumulative(double alpha, double beta, double[] x, double[] cumes) {
+        BetaDistribution d = new BetaDistribution(alpha, beta);
+        for (int i = 0; i < x.length; i++) {
+            Assert.assertEquals(cumes[i], d.cumulativeProbability(x[i]), 1e-8);
+        }
+
+        for (int i = 1; i < x.length - 1; i++) {
+            Assert.assertEquals(x[i], d.inverseCumulativeProbability(cumes[i]), 1e-5);
+        }
+    }
+
+    @Test
+    public void testDensity() {
+        double[] x = new double[]{1e-6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
+        checkDensity(0.1, 0.1,
+                     x, new double[]{
+                         12741.2357380649, 0.4429889586665234, 2.639378715e-01, 2.066393611e-01,
+                         1.832401831e-01, 1.766302780e-01, 1.832404579e-01, 2.066400696e-01,
+                         2.639396531e-01, 4.429925026e-01});
+        checkDensity(0.1, 0.5,
+                     x, new double[]{
+                         2.218377102e+04, 7.394524202e-01, 4.203020268e-01, 3.119435533e-01,
+                         2.600787829e-01, 2.330648626e-01, 2.211408259e-01, 2.222728708e-01,
+                         2.414013907e-01, 3.070567405e-01});
+        checkDensity(0.1, 1.0,
+                     x, new double[]{
+                         2.511886432e+04, 7.943210858e-01, 4.256680458e-01, 2.955218303e-01,
+                         2.281103709e-01, 1.866062624e-01, 1.583664652e-01, 1.378514078e-01,
+                         1.222414585e-01, 1.099464743e-01});
+        checkDensity(0.1, 2.0,
+                     x, new double[]{
+                         2.763072312e+04, 7.863770012e-01, 3.745874120e-01, 2.275514842e-01,
+                         1.505525939e-01, 1.026332391e-01, 6.968107049e-02, 4.549081293e-02,
+                         2.689298641e-02, 1.209399123e-02});
+        checkDensity(0.1, 4.0,
+                     x, new double[]{
+                         2.997927462e+04, 6.911058917e-01, 2.601128486e-01, 1.209774010e-01,
+                         5.880564714e-02, 2.783915474e-02, 1.209657335e-02, 4.442148268e-03,
+                         1.167143939e-03, 1.312171805e-04});
+        checkDensity(0.5, 0.1,
+                     x, new double[]{
+                         88.3152184726, 0.3070542841, 0.2414007269, 0.2222727015,
+                         0.2211409364, 0.2330652355, 0.2600795198, 0.3119449793,
+                         0.4203052841, 0.7394649088});
+        checkDensity(0.5, 0.5,
+                     x, new double[]{
+                         318.3100453389, 1.0610282383, 0.7957732234, 0.6946084565,
+                         0.6497470636, 0.6366197724, 0.6497476051, 0.6946097796,
+                         0.7957762075, 1.0610376697});
+        checkDensity(0.5, 1.0,
+                     x, new double[]{
+                         500.0000000000, 1.5811309244, 1.1180311937, 0.9128694077,
+                         0.7905684268, 0.7071060741, 0.6454966865, 0.5976138778,
+                         0.5590166450, 0.5270459839});
+        checkDensity(0.5, 2.0,
+                     x, new double[]{
+                         749.99925000000, 2.134537420613655, 1.34163575536, 0.95851150881,
+                         0.71151039830, 0.53032849490, 0.38729704363, 0.26892534859,
+                         0.16770415497, 0.07905610701});
+        checkDensity(0.5, 4.0,
+                     x, new double[]{
+                         1.093746719e+03, 2.52142232809988, 1.252190241e+00, 6.849343920e-01,
+                         3.735417140e-01, 1.933481570e-01, 9.036885833e-02, 3.529621669e-02,
+                         9.782644546e-03, 1.152878503e-03});
+        checkDensity(1.0, 0.1,
+                     x, new double[]{
+                         0.1000000900, 0.1099466942, 0.1222417336, 0.1378517623, 0.1583669403,
+                         0.1866069342, 0.2281113974, 0.2955236034, 0.4256718768,
+                         0.7943353837});
+        checkDensity(1.0, 0.5,
+                     x, new double[]{
+                         0.5000002500, 0.5270465695, 0.5590173438, 0.5976147315, 0.6454977623,
+                         0.7071074883, 0.7905704033, 0.9128724506,
+                         1.1180367838, 1.5811467358});
+        checkDensity(1, 1,
+                     x, new double[]{
+                         1, 1, 1,
+                         1, 1, 1, 1,
+                         1, 1, 1});
+        checkDensity(1, 2,
+                     x, new double[]{
+                         1.999998, 1.799998, 1.599998, 1.399998, 1.199998, 0.999998, 0.799998,
+                         0.599998, 0.399998,
+                         0.199998});
+        checkDensity(1, 4,
+                     x, new double[]{
+                         3.999988000012, 2.915990280011, 2.047992320010, 1.371994120008,
+                         0.863995680007, 0.499997000006, 0.255998080005, 0.107998920004,
+                         0.031999520002, 0.003999880001});
+        checkDensity(2.0, 0.1,
+                     x, new double[]{
+                         1.100000990e-07, 1.209425730e-02, 2.689331586e-02, 4.549123318e-02,
+                         6.968162794e-02, 1.026340191e-01, 1.505537732e-01, 2.275534997e-01,
+                         3.745917198e-01, 7.863929037e-01});
+        checkDensity(2.0, 0.5,
+                     x, new double[]{
+                         7.500003750e-07, 7.905777599e-02, 1.677060417e-01, 2.689275256e-01,
+                         3.872996256e-01, 5.303316769e-01, 7.115145488e-01, 9.585174425e-01,
+                         1.341645818e+00, 2.134537420613655});
+        checkDensity(2, 1,
+                     x, new double[]{
+                         0.000002, 0.200002, 0.400002, 0.600002, 0.800002, 1.000002, 1.200002,
+                         1.400002, 1.600002,
+                         1.800002});
+        checkDensity(2, 2,
+                     x, new double[]{
+                         5.9999940e-06, 5.4000480e-01, 9.6000360e-01, 1.2600024e+00,
+                         1.4400012e+00, 1.5000000e+00, 1.4399988e+00, 1.2599976e+00,
+                         9.5999640e-01, 5.3999520e-01});
+        checkDensity(2, 4,
+                     x, new double[]{
+                         0.00001999994, 1.45800971996, 2.04800255997, 2.05799803998,
+                         1.72799567999, 1.24999500000, 0.76799552000, 0.37799676001,
+                         0.12799824001, 0.01799948000});
+        checkDensity(4.0, 0.1,
+                     x, new double[]{
+                         1.193501074e-19, 1.312253162e-04, 1.167181580e-03, 4.442248535e-03,
+                         1.209679109e-02, 2.783958903e-02, 5.880649983e-02, 1.209791638e-01,
+                         2.601171405e-01, 6.911229392e-01});
+        checkDensity(4.0, 0.5,
+                     x, new double[]{
+                         1.093750547e-18, 1.152948959e-03, 9.782950259e-03, 3.529697305e-02,
+                         9.037036449e-02, 1.933508639e-01, 3.735463833e-01, 6.849425461e-01,
+                         1.252205894e+00, 2.52142232809988});
+        checkDensity(4, 1,
+                     x, new double[]{
+                         4.000000000e-18, 4.000120001e-03, 3.200048000e-02, 1.080010800e-01,
+                         2.560019200e-01, 5.000030000e-01, 8.640043200e-01, 1.372005880e+00,
+                         2.048007680e+00, 2.916009720e+00});
+        checkDensity(4, 2,
+                     x, new double[]{
+                         1.999998000e-17, 1.800052000e-02, 1.280017600e-01, 3.780032400e-01,
+                         7.680044800e-01, 1.250005000e+00, 1.728004320e+00, 2.058001960e+00,
+                         2.047997440e+00, 1.457990280e+00});
+        checkDensity(4, 4,
+                     x, new double[]{
+                         1.399995800e-16, 1.020627216e-01, 5.734464512e-01, 1.296547409e+00,
+                         1.935364838e+00, 2.187500000e+00, 1.935355162e+00, 1.296532591e+00,
+                         5.734335488e-01, 1.020572784e-01});
+    }
+
+    @SuppressWarnings("boxing")
+    private void checkDensity(double alpha, double beta, double[] x, double[] expected) {
+        BetaDistribution d = new BetaDistribution(alpha, beta);
+        for (int i = 0; i < x.length; i++) {
+            Assert.assertEquals(String.format("density at x=%.1f for alpha=%.1f, beta=%.1f", x[i], alpha, beta), expected[i], d.density(x[i]), 1e-5);
+        }
+    }
+
+    @Test
+    public void testMoments() {
+        final double tol = 1e-9;
+        BetaDistribution dist;
+
+        dist = new BetaDistribution(1, 1);
+        Assert.assertEquals(dist.getNumericalMean(), 0.5, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 1.0 / 12.0, tol);
+
+        dist = new BetaDistribution(2, 5);
+        Assert.assertEquals(dist.getNumericalMean(), 2.0 / 7.0, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 10.0 / (49.0 * 8.0), tol);
+    }
+
+    @Test
+    public void testMomentsSampling() {
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.WELL_1024_A,
+                                                              123456789L);
+        final int numSamples = 1000;
+        for (final double alpha : alphaBetas) {
+            for (final double beta : alphaBetas) {
+                final BetaDistribution betaDistribution = new BetaDistribution(alpha, beta);
+                final double[] observed = AbstractContinuousDistribution.sample(numSamples,
+                        betaDistribution.createSampler(rng));
+                Arrays.sort(observed);
+
+                final String distribution = String.format("Beta(%.2f, %.2f)", alpha, beta);
+                Assert.assertEquals(String.format("E[%s]", distribution),
+                                    betaDistribution.getNumericalMean(),
+                                    StatUtils.mean(observed), epsilon);
+                Assert.assertEquals(String.format("Var[%s]", distribution),
+                                    betaDistribution.getNumericalVariance(),
+                                    StatUtils.variance(observed), epsilon);
+            }
+        }
+    }
+
+    @Test
+    public void testGoodnessOfFit() {
+        final UniformRandomProvider rng = RandomSource.create(RandomSource.WELL_19937_A,
+                                                              123456789L);
+
+        final int numSamples = 1000;
+        final double level = 0.01;
+        for (final double alpha : alphaBetas) {
+            for (final double beta : alphaBetas) {
+                final BetaDistribution betaDistribution = new BetaDistribution(alpha, beta);
+
+                final ContinuousDistribution.Sampler sampler = betaDistribution.createSampler(rng);
+                final double[] observed = AbstractContinuousDistribution.sample(numSamples, sampler);
+
+                final double gT = gTest(betaDistribution, observed);
+                Assert.assertFalse("G goodness-of-fit (" + gT + ") test rejected null at alpha = " + level,
+                                   gT < level);
+            }
+        }
+    }
+
+    private double gTest(final ContinuousDistribution expectedDistribution, final double[] values) {
+        final int numBins = values.length / 30;
+        final double[] breaks = new double[numBins];
+        for (int b = 0; b < breaks.length; b++) {
+            breaks[b] = expectedDistribution.inverseCumulativeProbability((double) b / numBins);
+        }
+
+        final long[] observed = new long[numBins];
+        for (final double value : values) {
+            int b = 0;
+            do {
+                b++;
+            } while (b < numBins && value >= breaks[b]);
+
+            observed[b - 1]++;
+        }
+
+        final double[] expected = new double[numBins];
+        Arrays.fill(expected, (double) values.length / numBins);
+
+        return new GTest().gTest(expected, observed);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
new file mode 100644
index 0000000..9d5a97e
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
+ * or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+package org.apache.commons.statistics.distribution;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for BinomialDistribution. Extends DiscreteDistributionAbstractTest.
+ * See class javadoc for DiscreteDistributionAbstractTest for details.
+ *
+ */
+public class BinomialDistributionTest extends DiscreteDistributionAbstractTest {
+
+    /**
+     * Constructor to override default tolerance.
+     */
+    public BinomialDistributionTest() {
+        setTolerance(1e-12);
+    }
+
+    // -------------- Implementations for abstract methods
+    // -----------------------
+
+    /** Creates the default discrete distribution instance to use in tests. */
+    @Override
+    public DiscreteDistribution makeDistribution() {
+        return new BinomialDistribution(10, 0.70);
+    }
+
+    /** Creates the default probability density test input values. */
+    @Override
+    public int[] makeDensityTestPoints() {
+        return new int[] { -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+    }
+
+    /**
+     * Creates the default probability density test expected values.
+     * Reference values are from R, version 2.15.3.
+     */
+    @Override
+    public double[] makeDensityTestValues() {
+        return new double[] { 0d, 0.0000059049d, 0.000137781d, 0.0014467005,
+                              0.009001692, 0.036756909, 0.1029193452, 0.200120949, 0.266827932,
+                              0.2334744405, 0.121060821, 0.0282475249, 0d };
+    }
+
+    /** Creates the default cumulative probability density test input values */
+    @Override
+    public int[] makeCumulativeTestPoints() {
+        return makeDensityTestPoints();
+    }
+
+    /**
+     * Creates the default cumulative probability density test expected values.
+     * Reference values are from R, version 2.15.3.
+     */
+    @Override
+    public double[] makeCumulativeTestValues() {
+        return new double[] { 0d, 5.9049e-06, 0.0001436859, 0.0015903864, 0.0105920784,  0.0473489874,
+                              0.1502683326, 0.3503892816, 0.6172172136, 0.8506916541, 0.9717524751, 1d, 1d };
+    }
+
+    /** Creates the default inverse cumulative probability test input values */
+    @Override
+    public double[] makeInverseCumulativeTestPoints() {
+        return new double[] { 0, 0.001d, 0.010d, 0.025d, 0.050d, 0.100d,
+                              0.999d, 0.990d, 0.975d, 0.950d, 0.900d, 1 };
+    }
+
+    /**
+     * Creates the default inverse cumulative probability density test expected
+     * values
+     */
+    @Override
+    public int[] makeInverseCumulativeTestValues() {
+        return new int[] { 0, 2, 3, 4, 5, 5, 10, 10, 10, 9, 9, 10 };
+    }
+
+    // ----------------- Additional test cases ---------------------------------
+
+    /** Test degenerate case p = 0 */
+    @Test
+    public void testDegenerate0() {
+        BinomialDistribution dist = new BinomialDistribution(5, 0.0d);
+        setDistribution(dist);
+        setCumulativeTestPoints(new int[] { -1, 0, 1, 5, 10 });
+        setCumulativeTestValues(new double[] { 0d, 1d, 1d, 1d, 1d });
+        setDensityTestPoints(new int[] { -1, 0, 1, 10, 11 });
+        setDensityTestValues(new double[] { 0d, 1d, 0d, 0d, 0d });
+        setInverseCumulativeTestPoints(new double[] { 0.1d, 0.5d });
+        setInverseCumulativeTestValues(new int[] { 0, 0 });
+        verifyDensities();
+        verifyCumulativeProbabilities();
+        verifyInverseCumulativeProbabilities();
+        Assert.assertEquals(dist.getSupportLowerBound(), 0);
+        Assert.assertEquals(dist.getSupportUpperBound(), 0);
+    }
+
+    /** Test degenerate case p = 1 */
+    @Test
+    public void testDegenerate1() {
+        BinomialDistribution dist = new BinomialDistribution(5, 1.0d);
+        setDistribution(dist);
+        setCumulativeTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
+        setCumulativeTestValues(new double[] { 0d, 0d, 0d, 0d, 1d, 1d });
+        setDensityTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
+        setDensityTestValues(new double[] { 0d, 0d, 0d, 0d, 1d, 0d });
+        setInverseCumulativeTestPoints(new double[] { 0.1d, 0.5d });
+        setInverseCumulativeTestValues(new int[] { 5, 5 });
+        verifyDensities();
+        verifyCumulativeProbabilities();
+        verifyInverseCumulativeProbabilities();
+        Assert.assertEquals(dist.getSupportLowerBound(), 5);
+        Assert.assertEquals(dist.getSupportUpperBound(), 5);
+    }
+
+    /** Test degenerate case n = 0 */
+    @Test
+    public void testDegenerate2() {
+        BinomialDistribution dist = new BinomialDistribution(0, 0.01d);
+        setDistribution(dist);
+        setCumulativeTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
+        setCumulativeTestValues(new double[] { 0d, 1d, 1d, 1d, 1d, 1d });
+        setDensityTestPoints(new int[] { -1, 0, 1, 2, 5, 10 });
+        setDensityTestValues(new double[] { 0d, 1d, 0d, 0d, 0d, 0d });
+        setInverseCumulativeTestPoints(new double[] { 0.1d, 0.5d });
+        setInverseCumulativeTestValues(new int[] { 0, 0 });
+        verifyDensities();
+        verifyCumulativeProbabilities();
+        verifyInverseCumulativeProbabilities();
+        Assert.assertEquals(dist.getSupportLowerBound(), 0);
+        Assert.assertEquals(dist.getSupportUpperBound(), 0);
+    }
+
+    @Test
+    public void testMoments() {
+        final double tol = 1e-9;
+        BinomialDistribution dist;
+
+        dist = new BinomialDistribution(10, 0.5);
+        Assert.assertEquals(dist.getNumericalMean(), 10d * 0.5d, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 10d * 0.5d * 0.5d, tol);
+
+        dist = new BinomialDistribution(30, 0.3);
+        Assert.assertEquals(dist.getNumericalMean(), 30d * 0.3d, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 30d * 0.3d * (1d - 0.3d), tol);
+    }
+
+    @Test
+    public void testMath718() {
+        // for large trials the evaluation of ContinuedFraction was inaccurate
+        // do a sweep over several large trials to test if the current implementation is
+        // numerically stable.
+
+        for (int trials = 500000; trials < 20000000; trials += 100000) {
+            BinomialDistribution dist = new BinomialDistribution(trials, 0.5);
+            int p = dist.inverseCumulativeProbability(0.5);
+            Assert.assertEquals(trials / 2, p);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
new file mode 100644
index 0000000..4407976
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.statistics.distribution;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for CauchyDistribution.
+ * Extends ContinuousDistributionAbstractTest.  See class javadoc for
+ * ContinuousDistributionAbstractTest for details.
+ *
+ */
+public class CauchyDistributionTest extends ContinuousDistributionAbstractTest {
+
+    // --------------------- Override tolerance  --------------
+    protected double defaultTolerance = 1e-7;
+    @Override
+    public void setUp() {
+        super.setUp();
+        setTolerance(defaultTolerance);
+    }
+
+    //-------------- Implementations for abstract methods -----------------------
+
+    /** Creates the default continuous distribution instance to use in tests. */
+    @Override
+    public CauchyDistribution makeDistribution() {
+        return new CauchyDistribution(1.2, 2.1);
+    }
+
+    /** Creates the default cumulative probability distribution test input values */
+    @Override
+    public double[] makeCumulativeTestPoints() {
+        // quantiles computed using R 2.9.2
+        return new double[] {-667.24856187, -65.6230835029, -25.4830299460, -12.0588781808,
+                             -5.26313542807, 669.64856187, 68.0230835029, 27.8830299460, 14.4588781808, 7.66313542807};
+    }
+
+    /** Creates the default cumulative probability density test expected values */
+    @Override
+    public double[] makeCumulativeTestValues() {
+        return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999,
+                             0.990, 0.975, 0.950, 0.900};
+    }
+
+    /** Creates the default probability density test expected values */
+    @Override
+    public double[] makeDensityTestValues() {
+        return new double[] {1.49599158008e-06, 0.000149550440335, 0.000933076881878, 0.00370933207799, 0.0144742330437,
+                             1.49599158008e-06, 0.000149550440335, 0.000933076881878, 0.00370933207799, 0.0144742330437};
+    }
+
+    //---------------------------- Additional test cases -------------------------
+
+    @Test
+    public void testInverseCumulativeProbabilityExtremes() {
+        setInverseCumulativeTestPoints(new double[] {0.0, 1.0});
+        setInverseCumulativeTestValues(new double[] {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY});
+        verifyInverseCumulativeProbabilities();
+    }
+
+    @Test
+    public void testMedian() {
+        CauchyDistribution distribution = (CauchyDistribution) getDistribution();
+        Assert.assertEquals(1.2, distribution.getMedian(), 0.0);
+    }
+
+    @Test
+    public void testScale() {
+        CauchyDistribution distribution = (CauchyDistribution) getDistribution();
+        Assert.assertEquals(2.1, distribution.getScale(), 0.0);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition1() {
+        new CauchyDistribution(0, 0);
+    }
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition2() {
+        new CauchyDistribution(0, -1);
+    }
+
+    @Test
+    public void testMoments() {
+        CauchyDistribution dist;
+
+        dist = new CauchyDistribution(10.2, 0.15);
+        Assert.assertTrue(Double.isNaN(dist.getNumericalMean()));
+        Assert.assertTrue(Double.isNaN(dist.getNumericalVariance()));
+
+        dist = new CauchyDistribution(23.12, 2.12);
+        Assert.assertTrue(Double.isNaN(dist.getNumericalMean()));
+        Assert.assertTrue(Double.isNaN(dist.getNumericalVariance()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
new file mode 100644
index 0000000..dc97f47
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.statistics.distribution;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link ChiSquaredDistribution}.
+ *
+ * @see ContinuousDistributionAbstractTest
+ */
+public class ChiSquaredDistributionTest extends ContinuousDistributionAbstractTest {
+
+    //-------------- Implementations for abstract methods -----------------------
+
+    /** Creates the default continuous distribution instance to use in tests. */
+    @Override
+    public ChiSquaredDistribution makeDistribution() {
+        return new ChiSquaredDistribution(5.0);
+    }
+
+    /** Creates the default cumulative probability distribution test input values */
+    @Override
+    public double[] makeCumulativeTestPoints() {
+        // quantiles computed using R version 2.9.2
+        return new double[] {0.210212602629, 0.554298076728, 0.831211613487, 1.14547622606, 1.61030798696,
+                             20.5150056524, 15.0862724694, 12.8325019940, 11.0704976935, 9.23635689978};
+    }
+
+    /** Creates the default cumulative probability density test expected values */
+    @Override
+    public double[] makeCumulativeTestValues() {
+        return new double[] {0.001, 0.01, 0.025, 0.05, 0.1, 0.999, 0.990, 0.975, 0.950, 0.900};
+    }
+
+    /** Creates the default inverse cumulative probability test input values */
+    @Override
+    public double[] makeInverseCumulativeTestPoints() {
+        return new double[] {0, 0.001d, 0.01d, 0.025d, 0.05d, 0.1d, 0.999d,
+                             0.990d, 0.975d, 0.950d, 0.900d, 1};
+    }
+
+    /** Creates the default inverse cumulative probability density test expected values */
+    @Override
+    public double[] makeInverseCumulativeTestValues() {
+        return new double[] {0, 0.210212602629, 0.554298076728, 0.831211613487, 1.14547622606, 1.61030798696,
+                             20.5150056524, 15.0862724694, 12.8325019940, 11.0704976935, 9.23635689978,
+                             Double.POSITIVE_INFINITY};
+    }
+
+    /** Creates the default probability density test expected values */
+    @Override
+    public double[] makeDensityTestValues() {
+        return new double[] {0.0115379817652, 0.0415948507811, 0.0665060119842, 0.0919455953114, 0.121472591024,
+                             0.000433630076361, 0.00412780610309, 0.00999340341045, 0.0193246438937, 0.0368460089216};
+    }
+
+    // --------------------- Override tolerance  --------------
+    @Override
+    public void setUp() {
+        super.setUp();
+        setTolerance(1e-9);
+    }
+
+    //---------------------------- Additional test cases -------------------------
+
+    @Test
+    public void testSmallDf() {
+        setDistribution(new ChiSquaredDistribution(0.1d));
+        setTolerance(1E-4);
+        // quantiles computed using R version 1.8.1 (linux version)
+        setCumulativeTestPoints(new double[] {1.168926E-60, 1.168926E-40, 1.063132E-32,
+                                              1.144775E-26, 1.168926E-20, 5.472917, 2.175255, 1.13438,
+                                              0.5318646, 0.1526342});
+        setInverseCumulativeTestValues(getCumulativeTestPoints());
+        setInverseCumulativeTestPoints(getCumulativeTestValues());
+        verifyCumulativeProbabilities();
+        verifyInverseCumulativeProbabilities();
+    }
+
+    @Test
+    public void testDfAccessors() {
+        ChiSquaredDistribution distribution = (ChiSquaredDistribution) getDistribution();
+        Assert.assertEquals(5d, distribution.getDegreesOfFreedom(), Double.MIN_VALUE);
+    }
+
+    @Test
+    public void testDensity() {
+        double[] x = new double[]{-0.1, 1e-6, 0.5, 1, 2, 5};
+        //R 2.5: print(dchisq(x, df=1), digits=10)
+        checkDensity(1, x, new double[]{0.00000000000, 398.94208093034, 0.43939128947, 0.24197072452, 0.10377687436, 0.01464498256});
+        //R 2.5: print(dchisq(x, df=0.1), digits=10)
+        checkDensity(0.1, x, new double[]{0.000000000e+00, 2.486453997e+04, 7.464238732e-02, 3.009077718e-02, 9.447299159e-03, 8.827199396e-04});
+        //R 2.5: print(dchisq(x, df=2), digits=10)
+        checkDensity(2, x, new double[]{0.00000000000, 0.49999975000, 0.38940039154, 0.30326532986, 0.18393972059, 0.04104249931});
+        //R 2.5: print(dchisq(x, df=10), digits=10)
+        checkDensity(10, x, new double[]{0.000000000e+00, 1.302082682e-27, 6.337896998e-05, 7.897534632e-04, 7.664155024e-03, 6.680094289e-02});
+    }
+
+    private void checkDensity(double df, double[] x, double[] expected) {
+        ChiSquaredDistribution d = new ChiSquaredDistribution(df);
+        for (int i = 0; i < x.length; i++) {
+            Assert.assertEquals(expected[i], d.density(x[i]), 1e-5);
+        }
+    }
+
+    @Test
+    public void testMoments() {
+        final double tol = 1e-9;
+        ChiSquaredDistribution dist;
+
+        dist = new ChiSquaredDistribution(1500);
+        Assert.assertEquals(dist.getNumericalMean(), 1500, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 3000, tol);
+
+        dist = new ChiSquaredDistribution(1.12);
+        Assert.assertEquals(dist.getNumericalMean(), 1.12, tol);
+        Assert.assertEquals(dist.getNumericalVariance(), 2.24, tol);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ConstantContinuousDistributionTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ConstantContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ConstantContinuousDistributionTest.java
new file mode 100644
index 0000000..152a6c2
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ConstantContinuousDistributionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.statistics.distribution;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for ConstantContinuousDistribution.
+ */
+public class ConstantContinuousDistributionTest extends ContinuousDistributionAbstractTest {
+
+    // --- Override tolerance -------------------------------------------------
+
+    @Override
+    public void setUp() {
+        super.setUp();
+        setTolerance(0);
+    }
+
+    //--- Implementations for abstract methods --------------------------------
+
+    /** Creates the default uniform real distribution instance to use in tests. */
+    @Override
+    public ConstantContinuousDistribution makeDistribution() {
+        return new ConstantContinuousDistribution(1);
+    }
+
+    /** Creates the default cumulative probability distribution test input values */
+    @Override
+    public double[] makeCumulativeTestPoints() {
+        return new double[] {0, 0.5, 1};
+    }
+
+    /** Creates the default cumulative probability distribution test expected values */
+    @Override
+    public double[] makeCumulativeTestValues() {
+        return new double[] {0, 0, 1};
+    }
+
+    /** Creates the default probability density test expected values */
+    @Override
+    public double[] makeDensityTestValues() {
+        return new double[] {0, 0, 1};
+    }
+
+    /** Override default test, verifying that inverse cum is constant */
+    @Override
+    @Test
+    public void testInverseCumulativeProbabilities() {
+        ContinuousDistribution dist = getDistribution();
+        for (double x : getCumulativeTestValues()) {
+            Assert.assertEquals(1,dist.inverseCumulativeProbability(x), 0);
+        }
+    }
+
+    //--- Additional test cases -----------------------------------------------
+
+    @Test
+    public void testMeanVariance() {
+        ConstantContinuousDistribution dist;
+
+        dist = new ConstantContinuousDistribution(-1);
+        Assert.assertEquals(dist.getNumericalMean(), -1, 0d);
+        Assert.assertEquals(dist.getNumericalVariance(), 0, 0d);
+    }
+
+    @Test
+    @Override
+    public void testSampler() {
+        final double value = 12.345;
+        final ContinuousDistribution.Sampler sampler = new ConstantContinuousDistribution(value).createSampler(null);
+        for (int i = 0; i < 10; i++) {
+            Assert.assertEquals(value, sampler.sample(), 0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java
new file mode 100644
index 0000000..a6176f3
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ContinuousDistributionAbstractTest.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.statistics.distribution;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.commons.math3.analysis.UnivariateFunction;
+import org.apache.commons.math3.analysis.integration.BaseAbstractUnivariateIntegrator;
+import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator;
+import org.apache.commons.rng.simple.RandomSource;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Abstract base class for {@link ContinuousDistribution} tests.
+ * <p>
+ * To create a concrete test class for a continuous distribution
+ * implementation, first implement makeDistribution() to return a distribution
+ * instance to use in tests. Then implement each of the test data generation
+ * methods below.  In each case, the test points and test values arrays
+ * returned represent parallel arrays of inputs and expected values for the
+ * distribution returned by makeDistribution().  Default implementations
+ * are provided for the makeInverseXxx methods that just invert the mapping
+ * defined by the arrays returned by the makeCumulativeXxx methods.
+ * <p>
+ * makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
+ * makeCumulativeTestValues() -- expected cumulative probabilities
+ * makeDensityTestValues() -- expected density values at cumulativeTestPoints
+ * makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf
+ * makeInverseCumulativeTestValues() -- expected inverse cdf values
+ * <p>
+ * To implement additional test cases with different distribution instances and
+ * test data, use the setXxx methods for the instance data in test cases and
+ * call the verifyXxx methods to verify results.
+ * <p>
+ * Error tolerance can be overridden by implementing getTolerance().
+ * <p>
+ * Test data should be validated against reference tables or other packages
+ * where possible, and the source of the reference data and/or validation
+ * should be documented in the test cases.  A framework for validating
+ * distribution data against R is included in the /src/test/R source tree.
+ * <p>
+ * See {@link NormalDistributionTest} and {@link ChiSquaredDistributionTest}
+ * for examples.
+ *
+ */
+public abstract class ContinuousDistributionAbstractTest {
+
+//-------------------- Private test instance data -------------------------
+    /**  Distribution instance used to perform tests */
+    private ContinuousDistribution distribution;
+
+    /** Tolerance used in comparing expected and returned values */
+    private double tolerance = 1e-4;
+
+    /** Arguments used to test cumulative probability density calculations */
+    private double[] cumulativeTestPoints;
+
+    /** Values used to test cumulative probability density calculations */
+    private double[] cumulativeTestValues;
+
+    /** Arguments used to test inverse cumulative probability density calculations */
+    private double[] inverseCumulativeTestPoints;
+
+    /** Values used to test inverse cumulative probability density calculations */
+    private double[] inverseCumulativeTestValues;
+
+    /** Values used to test density calculations */
+    private double[] densityTestValues;
+
+    /** Values used to test logarithmic density calculations */
+    private double[] logDensityTestValues;
+
+    //-------------------- Abstract methods -----------------------------------
+
+    /** Creates the default continuous distribution instance to use in tests. */
+    public abstract ContinuousDistribution makeDistribution();
+
+    /** Creates the default cumulative probability test input values */
+    public abstract double[] makeCumulativeTestPoints();
+
+    /** Creates the default cumulative probability test expected values */
+    public abstract double[] makeCumulativeTestValues();
+
+    /** Creates the default density test expected values */
+    public abstract double[] makeDensityTestValues();
+
+    /** Creates the default logarithmic density test expected values.
+     * The default implementation simply computes the logarithm
+     * of each value returned by {@link #makeDensityTestValues()}.*/
+    public double[] makeLogDensityTestValues() {
+        final double[] densityTestValues = makeDensityTestValues();
+        final double[] logDensityTestValues = new double[densityTestValues.length];
+        for (int i = 0; i < densityTestValues.length; i++) {
+            logDensityTestValues[i] = Math.log(densityTestValues[i]);
+        }
+        return logDensityTestValues;
+    }
+
+    //---- Default implementations of inverse test data generation methods ----
+
+    /** Creates the default inverse cumulative probability test input values */
+    public double[] makeInverseCumulativeTestPoints() {
+        return makeCumulativeTestValues();
+    }
+
+    /** Creates the default inverse cumulative probability density test expected values */
+    public double[] makeInverseCumulativeTestValues() {
+        return makeCumulativeTestPoints();
+    }
+
+    //-------------------- Setup / tear down ----------------------------------
+
+    /**
+     * Setup sets all test instance data to default values
+     */
+    @Before
+    public void setUp() {
+        distribution = makeDistribution();
+        cumulativeTestPoints = makeCumulativeTestPoints();
+        cumulativeTestValues = makeCumulativeTestValues();
+        inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
+        inverseCumulativeTestValues = makeInverseCumulativeTestValues();
+        densityTestValues = makeDensityTestValues();
+        logDensityTestValues = makeLogDensityTestValues();
+    }
+
+    /**
+     * Cleans up test instance data
+     */
+    @After
+    public void tearDown() {
+        distribution = null;
+        cumulativeTestPoints = null;
+        cumulativeTestValues = null;
+        inverseCumulativeTestPoints = null;
+        inverseCumulativeTestValues = null;
+        densityTestValues = null;
+        logDensityTestValues = null;
+    }
+
+    //-------------------- Verification methods -------------------------------
+
+    /**
+     * Verifies that cumulative probability density calculations match expected values
+     * using current test instance data
+     */
+    protected void verifyCumulativeProbabilities() {
+        // verify cumulativeProbability(double)
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            TestUtils.assertEquals("Incorrect cumulative probability value returned for "
+                                   + cumulativeTestPoints[i], cumulativeTestValues[i],
+                                   distribution.cumulativeProbability(cumulativeTestPoints[i]),
+                                   getTolerance());
+        }
+        // verify probability(double, double)
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            for (int j = 0; j < cumulativeTestPoints.length; j++) {
+                if (cumulativeTestPoints[i] <= cumulativeTestPoints[j]) {
+                    TestUtils.assertEquals(cumulativeTestValues[j] - cumulativeTestValues[i],
+                                           distribution.probability(cumulativeTestPoints[i], cumulativeTestPoints[j]),
+                                           getTolerance());
+                } else {
+                    try {
+                        distribution.probability(cumulativeTestPoints[i], cumulativeTestPoints[j]);
+                    } catch (IllegalArgumentException e) {
+                        continue;
+                    }
+                    Assert.fail("distribution.probability(double, double) should have thrown an exception that second argument is too large");
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies that inverse cumulative probability density calculations match expected values
+     * using current test instance data
+     */
+    protected void verifyInverseCumulativeProbabilities() {
+        for (int i = 0; i < inverseCumulativeTestPoints.length; i++) {
+            TestUtils.assertEquals("Incorrect inverse cumulative probability value returned for "
+                                   + inverseCumulativeTestPoints[i], inverseCumulativeTestValues[i],
+                                   distribution.inverseCumulativeProbability(inverseCumulativeTestPoints[i]),
+                                   getTolerance());
+        }
+    }
+
+    /**
+     * Verifies that density calculations match expected values
+     */
+    protected void verifyDensities() {
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            TestUtils.assertEquals("Incorrect probability density value returned for "
+                                   + cumulativeTestPoints[i], densityTestValues[i],
+                                   distribution.density(cumulativeTestPoints[i]),
+                                   getTolerance());
+        }
+    }
+
+    /**
+     * Verifies that logarithmic density calculations match expected values
+     */
+    protected void verifyLogDensities() {
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            TestUtils.assertEquals("Incorrect probability density value returned for "
+                                   + cumulativeTestPoints[i], logDensityTestValues[i],
+                                   distribution.logDensity(cumulativeTestPoints[i]),
+                                   getTolerance());
+        }
+    }
+
+    //------------------------ Default test cases -----------------------------
+
+    /**
+     * Verifies that cumulative probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testCumulativeProbabilities() {
+        verifyCumulativeProbabilities();
+    }
+
+    /**
+     * Verifies that inverse cumulative probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testInverseCumulativeProbabilities() {
+        verifyInverseCumulativeProbabilities();
+    }
+
+    /**
+     * Verifies that density calculations return expected values
+     * for default test instance data
+     */
+    @Test
+    public void testDensities() {
+        verifyDensities();
+    }
+
+    /**
+     * Verifies that logarithmic density calculations return expected values
+     * for default test instance data
+     */
+    @Test
+    public void testLogDensities() {
+        verifyLogDensities();
+    }
+
+    /**
+     * Verifies that probability computations are consistent
+     */
+    @Test
+    public void testConsistency() {
+        for (int i = 1; i < cumulativeTestPoints.length; i++) {
+
+            // check that cdf(x, x) = 0
+            TestUtils.assertEquals(0d,
+                                   distribution.probability
+                                   (cumulativeTestPoints[i], cumulativeTestPoints[i]),
+                                   tolerance);
+
+            // check that P(a < X <= b) = P(X <= b) - P(X <= a)
+            double upper = Math.max(cumulativeTestPoints[i], cumulativeTestPoints[i -1]);
+            double lower = Math.min(cumulativeTestPoints[i], cumulativeTestPoints[i -1]);
+            double diff = distribution.cumulativeProbability(upper) -
+                distribution.cumulativeProbability(lower);
+            double direct = distribution.probability(lower, upper);
+            TestUtils.assertEquals("Inconsistent probability for ("
+                                   + lower + "," + upper + ")", diff, direct, tolerance);
+        }
+    }
+
+    /**
+     * Verifies that illegal arguments are correctly handled
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition1() {
+        distribution.probability(1, 0);
+    }
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition2() {
+        distribution.inverseCumulativeProbability(-1);
+    }
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition3() {
+        distribution.inverseCumulativeProbability(2);
+    }
+
+    /**
+     * Test sampling
+     */
+    @Test
+    public void testSampler() {
+        final int sampleSize = 1000;
+        final ContinuousDistribution.Sampler sampler =
+            distribution.createSampler(RandomSource.create(RandomSource.WELL_19937_C, 123456789L));
+        final double[] sample = AbstractContinuousDistribution.sample(sampleSize, sampler);
+        final double[] quartiles = TestUtils.getDistributionQuartiles(distribution);
+        final double[] expected = {250, 250, 250, 250};
+        final long[] counts = new long[4];
+
+        for (int i = 0; i < sampleSize; i++) {
+            TestUtils.updateCounts(sample[i], counts, quartiles);
+        }
+        TestUtils.assertChiSquareAccept(expected, counts, 0.001);
+    }
+
+    /**
+     * Verify that density integrals match the distribution.
+     * The (filtered, sorted) cumulativeTestPoints array is used to source
+     * integration limits. The integral of the density (estimated using a
+     * Legendre-Gauss integrator) is compared with the cdf over the same
+     * interval. Test points outside of the domain of the density function
+     * are discarded.
+     */
+    @Test
+    public void testDensityIntegrals() {
+        final double tol = 1e-9;
+        final BaseAbstractUnivariateIntegrator integrator =
+            new IterativeLegendreGaussIntegrator(5, 1e-12, 1e-10);
+        final UnivariateFunction d = new UnivariateFunction() {
+                @Override
+                public double value(double x) {
+                    return distribution.density(x);
+                }
+            };
+        final ArrayList<Double> integrationTestPoints = new ArrayList<>();
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            if (Double.isNaN(cumulativeTestValues[i]) ||
+                cumulativeTestValues[i] < 1e-5 ||
+                cumulativeTestValues[i] > 1 - 1e-5) {
+                continue; // exclude integrals outside domain.
+            }
+            integrationTestPoints.add(cumulativeTestPoints[i]);
+        }
+        Collections.sort(integrationTestPoints);
+        for (int i = 1; i < integrationTestPoints.size(); i++) {
+            Assert.assertEquals(distribution.probability(integrationTestPoints.get(0), integrationTestPoints.get(i)),
+                                integrator.integrate(1000000, // Triangle integrals are very slow to converge
+                                                     d, integrationTestPoints.get(0),
+                                                     integrationTestPoints.get(i)), tol);
+        }
+    }
+
+    //------------------ Getters / Setters for test instance data -----------
+    /**
+     * @return Returns the cumulativeTestPoints.
+     */
+    protected double[] getCumulativeTestPoints() {
+        return cumulativeTestPoints;
+    }
+
+    /**
+     * @param cumulativeTestPoints The cumulativeTestPoints to set.
+     */
+    protected void setCumulativeTestPoints(double[] cumulativeTestPoints) {
+        this.cumulativeTestPoints = cumulativeTestPoints;
+    }
+
+    /**
+     * @return Returns the cumulativeTestValues.
+     */
+    protected double[] getCumulativeTestValues() {
+        return cumulativeTestValues;
+    }
+
+    /**
+     * @param cumulativeTestValues The cumulativeTestValues to set.
+     */
+    protected void setCumulativeTestValues(double[] cumulativeTestValues) {
+        this.cumulativeTestValues = cumulativeTestValues;
+    }
+
+    protected double[] getDensityTestValues() {
+        return densityTestValues;
+    }
+
+    protected void setDensityTestValues(double[] densityTestValues) {
+        this.densityTestValues = densityTestValues;
+    }
+
+    /**
+     * @return Returns the distribution.
+     */
+    protected ContinuousDistribution getDistribution() {
+        return distribution;
+    }
+
+    /**
+     * @param distribution The distribution to set.
+     */
+    protected void setDistribution(ContinuousDistribution distribution) {
+        this.distribution = distribution;
+    }
+
+    /**
+     * @return Returns the inverseCumulativeTestPoints.
+     */
+    protected double[] getInverseCumulativeTestPoints() {
+        return inverseCumulativeTestPoints;
+    }
+
+    /**
+     * @param inverseCumulativeTestPoints The inverseCumulativeTestPoints to set.
+     */
+    protected void setInverseCumulativeTestPoints(double[] inverseCumulativeTestPoints) {
+        this.inverseCumulativeTestPoints = inverseCumulativeTestPoints;
+    }
+
+    /**
+     * @return Returns the inverseCumulativeTestValues.
+     */
+    protected double[] getInverseCumulativeTestValues() {
+        return inverseCumulativeTestValues;
+    }
+
+    /**
+     * @param inverseCumulativeTestValues The inverseCumulativeTestValues to set.
+     */
+    protected void setInverseCumulativeTestValues(double[] inverseCumulativeTestValues) {
+        this.inverseCumulativeTestValues = inverseCumulativeTestValues;
+    }
+
+    /**
+     * @return Returns the tolerance.
+     */
+    protected double getTolerance() {
+        return tolerance;
+    }
+
+    /**
+     * @param tolerance The tolerance to set.
+     */
+    protected void setTolerance(double tolerance) {
+        this.tolerance = tolerance;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-statistics/blob/9c794a15/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/DiscreteDistributionAbstractTest.java
----------------------------------------------------------------------
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/DiscreteDistributionAbstractTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/DiscreteDistributionAbstractTest.java
new file mode 100644
index 0000000..ab0e0a1
--- /dev/null
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/DiscreteDistributionAbstractTest.java
@@ -0,0 +1,411 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.statistics.distribution;
+
+import org.apache.commons.rng.simple.RandomSource;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Abstract base class for {@link DiscreteDistribution} tests.
+ * <p>
+ * To create a concrete test class for an integer distribution implementation,
+ *  implement makeDistribution() to return a distribution instance to use in
+ *  tests and each of the test data generation methods below.  In each case, the
+ *  test points and test values arrays returned represent parallel arrays of
+ *  inputs and expected values for the distribution returned by makeDistribution().
+ *  <p>
+ *  makeDensityTestPoints() -- arguments used to test probability density calculation
+ *  makeDensityTestValues() -- expected probability densities
+ *  makeCumulativeTestPoints() -- arguments used to test cumulative probabilities
+ *  makeCumulativeTestValues() -- expected cumulative probabilites
+ *  makeInverseCumulativeTestPoints() -- arguments used to test inverse cdf evaluation
+ *  makeInverseCumulativeTestValues() -- expected inverse cdf values
+ * <p>
+ *  To implement additional test cases with different distribution instances and test data,
+ *  use the setXxx methods for the instance data in test cases and call the verifyXxx methods
+ *  to verify results.
+ *
+ */
+public abstract class DiscreteDistributionAbstractTest {
+
+//-------------------- Private test instance data -------------------------
+    /** Discrete distribution instance used to perform tests */
+    private DiscreteDistribution distribution;
+
+    /** Tolerance used in comparing expected and returned values */
+    private double tolerance = 1e-12;
+
+    /** Arguments used to test probability density calculations */
+    private int[] densityTestPoints;
+
+    /** Values used to test probability density calculations */
+    private double[] densityTestValues;
+
+    /** Values used to test logarithmic probability density calculations */
+    private double[] logDensityTestValues;
+
+    /** Arguments used to test cumulative probability density calculations */
+    private int[] cumulativeTestPoints;
+
+    /** Values used to test cumulative probability density calculations */
+    private double[] cumulativeTestValues;
+
+    /** Arguments used to test inverse cumulative probability density calculations */
+    private double[] inverseCumulativeTestPoints;
+
+    /** Values used to test inverse cumulative probability density calculations */
+    private int[] inverseCumulativeTestValues;
+
+    //-------------------- Abstract methods -----------------------------------
+
+    /** Creates the default discrete distribution instance to use in tests. */
+    public abstract DiscreteDistribution makeDistribution();
+
+    /** Creates the default probability density test input values */
+    public abstract int[] makeDensityTestPoints();
+
+    /** Creates the default probability density test expected values */
+    public abstract double[] makeDensityTestValues();
+
+    /** Creates the default logarithmic probability density test expected values.
+     *
+     * The default implementation simply computes the logarithm of all the values in
+     * {@link #makeDensityTestValues()}.
+     *
+     * @return double[] the default logarithmic probability density test expected values.
+     */
+    public double[] makeLogDensityTestValues() {
+        final double[] densityTestValues = makeDensityTestValues();
+        final double[] logDensityTestValues = new double[densityTestValues.length];
+        for (int i = 0; i < densityTestValues.length; i++) {
+            logDensityTestValues[i] = Math.log(densityTestValues[i]);
+        }
+        return logDensityTestValues;
+    }
+
+    /** Creates the default cumulative probability density test input values */
+    public abstract int[] makeCumulativeTestPoints();
+
+    /** Creates the default cumulative probability density test expected values */
+    public abstract double[] makeCumulativeTestValues();
+
+    /** Creates the default inverse cumulative probability test input values */
+    public abstract double[] makeInverseCumulativeTestPoints();
+
+    /** Creates the default inverse cumulative probability density test expected values */
+    public abstract int[] makeInverseCumulativeTestValues();
+
+    //-------------------- Setup / tear down ----------------------------------
+
+    /**
+     * Setup sets all test instance data to default values
+     */
+    @Before
+    public void setUp() {
+        distribution = makeDistribution();
+        densityTestPoints = makeDensityTestPoints();
+        densityTestValues = makeDensityTestValues();
+        logDensityTestValues = makeLogDensityTestValues();
+        cumulativeTestPoints = makeCumulativeTestPoints();
+        cumulativeTestValues = makeCumulativeTestValues();
+        inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
+        inverseCumulativeTestValues = makeInverseCumulativeTestValues();
+    }
+
+    /**
+     * Cleans up test instance data
+     */
+    @After
+    public void tearDown() {
+        distribution = null;
+        densityTestPoints = null;
+        densityTestValues = null;
+        logDensityTestValues = null;
+        cumulativeTestPoints = null;
+        cumulativeTestValues = null;
+        inverseCumulativeTestPoints = null;
+        inverseCumulativeTestValues = null;
+    }
+
+    //-------------------- Verification methods -------------------------------
+
+    /**
+     * Verifies that probability density calculations match expected values
+     * using current test instance data
+     */
+    protected void verifyDensities() {
+        for (int i = 0; i < densityTestPoints.length; i++) {
+            Assert.assertEquals("Incorrect density value returned for " + densityTestPoints[i],
+                                densityTestValues[i],
+                                distribution.probability(densityTestPoints[i]), getTolerance());
+        }
+    }
+
+    /**
+     * Verifies that logarithmic probability density calculations match expected values
+     * using current test instance data.
+     */
+    protected void verifyLogDensities() {
+        for (int i = 0; i < densityTestPoints.length; i++) {
+            // FIXME: when logProbability methods are added to DiscreteDistribution in 4.0, remove cast below
+            Assert.assertEquals("Incorrect log density value returned for " + densityTestPoints[i],
+                                logDensityTestValues[i],
+                                ((AbstractDiscreteDistribution) distribution).logProbability(densityTestPoints[i]), tolerance);
+        }
+    }
+
+    /**
+     * Verifies that cumulative probability density calculations match expected values
+     * using current test instance data
+     */
+    protected void verifyCumulativeProbabilities() {
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            Assert.assertEquals("Incorrect cumulative probability value returned for " + cumulativeTestPoints[i],
+                                cumulativeTestValues[i],
+                                distribution.cumulativeProbability(cumulativeTestPoints[i]), getTolerance());
+        }
+    }
+
+
+    /**
+     * Verifies that inverse cumulative probability density calculations match expected values
+     * using current test instance data
+     */
+    protected void verifyInverseCumulativeProbabilities() {
+        for (int i = 0; i < inverseCumulativeTestPoints.length; i++) {
+            Assert.assertEquals("Incorrect inverse cumulative probability value returned for "
+                                + inverseCumulativeTestPoints[i], inverseCumulativeTestValues[i],
+                                distribution.inverseCumulativeProbability(inverseCumulativeTestPoints[i]));
+        }
+    }
+
+    //------------------------ Default test cases -----------------------------
+
+    /**
+     * Verifies that probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testDensities() {
+        verifyDensities();
+    }
+
+    /**
+     * Verifies that logarithmic probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testLogDensities() {
+        verifyLogDensities();
+    }
+
+    /**
+     * Verifies that cumulative probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testCumulativeProbabilities() {
+        verifyCumulativeProbabilities();
+    }
+
+    /**
+     * Verifies that inverse cumulative probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testInverseCumulativeProbabilities() {
+        verifyInverseCumulativeProbabilities();
+    }
+
+    @Test
+    public void testConsistencyAtSupportBounds() {
+        final int lower = distribution.getSupportLowerBound();
+        Assert.assertEquals("Cumulative probability mmust be 0 below support lower bound.",
+                            0.0, distribution.cumulativeProbability(lower - 1), 0.0);
+        Assert.assertEquals("Cumulative probability of support lower bound must be equal to probability mass at this point.",
+                            distribution.probability(lower), distribution.cumulativeProbability(lower), getTolerance());
+        Assert.assertEquals("Inverse cumulative probability of 0 must be equal to support lower bound.",
+                            lower, distribution.inverseCumulativeProbability(0.0));
+
+        final int upper = distribution.getSupportUpperBound();
+        if (upper != Integer.MAX_VALUE) {
+            Assert.assertEquals("Cumulative probability of support upper bound must be equal to 1.",
+                                1.0, distribution.cumulativeProbability(upper), 0.0);
+        }
+        Assert.assertEquals("Inverse cumulative probability of 1 must be equal to support upper bound.",
+                            upper, distribution.inverseCumulativeProbability(1.0));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition1() {
+        distribution.probability(1, 0);
+    }
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition2() {
+        distribution.inverseCumulativeProbability(-1);
+    }
+    @Test(expected=IllegalArgumentException.class)
+    public void testPrecondition3() {
+        distribution.inverseCumulativeProbability(2);
+    }
+
+    /**
+     * Test sampling
+     */
+    @Test
+    public void testSampling() {
+        int[] densityPoints = makeDensityTestPoints();
+        double[] densityValues = makeDensityTestValues();
+        int sampleSize = 1000;
+        int length = TestUtils.eliminateZeroMassPoints(densityPoints, densityValues);
+        AbstractDiscreteDistribution distribution = (AbstractDiscreteDistribution) makeDistribution();
+        double[] expectedCounts = new double[length];
+        long[] observedCounts = new long[length];
+        for (int i = 0; i < length; i++) {
+            expectedCounts[i] = sampleSize * densityValues[i];
+        }
+        // Use fixed seed.
+        final DiscreteDistribution.Sampler sampler =
+            distribution.createSampler(RandomSource.create(RandomSource.WELL_512_A,
+                                                           1000));
+        int[] sample = AbstractDiscreteDistribution.sample(sampleSize, sampler);
+        for (int i = 0; i < sampleSize; i++) {
+          for (int j = 0; j < length; j++) {
+              if (sample[i] == densityPoints[j]) {
+                  observedCounts[j]++;
+              }
+          }
+        }
+        TestUtils.assertChiSquareAccept(densityPoints, expectedCounts, observedCounts, .001);
+    }
+
+    //------------------ Getters / Setters for test instance data -----------
+    /**
+     * @return Returns the cumulativeTestPoints.
+     */
+    protected int[] getCumulativeTestPoints() {
+        return cumulativeTestPoints;
+    }
+
+    /**
+     * @param cumulativeTestPoints The cumulativeTestPoints to set.
+     */
+    protected void setCumulativeTestPoints(int[] cumulativeTestPoints) {
+        this.cumulativeTestPoints = cumulativeTestPoints;
+    }
+
+    /**
+     * @return Returns the cumulativeTestValues.
+     */
+    protected double[] getCumulativeTestValues() {
+        return cumulativeTestValues;
+    }
+
+    /**
+     * @param cumulativeTestValues The cumulativeTestValues to set.
+     */
+    protected void setCumulativeTestValues(double[] cumulativeTestValues) {
+        this.cumulativeTestValues = cumulativeTestValues;
+    }
+
+    /**
+     * @return Returns the densityTestPoints.
+     */
+    protected int[] getDensityTestPoints() {
+        return densityTestPoints;
+    }
+
+    /**
+     * @param densityTestPoints The densityTestPoints to set.
+     */
+    protected void setDensityTestPoints(int[] densityTestPoints) {
+        this.densityTestPoints = densityTestPoints;
+    }
+
+    /**
+     * @return Returns the densityTestValues.
+     */
+    protected double[] getDensityTestValues() {
+        return densityTestValues;
+    }
+
+    /**
+     * @param densityTestValues The densityTestValues to set.
+     */
+    protected void setDensityTestValues(double[] densityTestValues) {
+        this.densityTestValues = densityTestValues;
+    }
+
+    /**
+     * @return Returns the distribution.
+     */
+    protected DiscreteDistribution getDistribution() {
+        return distribution;
+    }
+
+    /**
+     * @param distribution The distribution to set.
+     */
+    protected void setDistribution(DiscreteDistribution distribution) {
+        this.distribution = distribution;
+    }
+
+    /**
+     * @return Returns the inverseCumulativeTestPoints.
+     */
+    protected double[] getInverseCumulativeTestPoints() {
+        return inverseCumulativeTestPoints;
+    }
+
+    /**
+     * @param inverseCumulativeTestPoints The inverseCumulativeTestPoints to set.
+     */
+    protected void setInverseCumulativeTestPoints(double[] inverseCumulativeTestPoints) {
+        this.inverseCumulativeTestPoints = inverseCumulativeTestPoints;
+    }
+
+    /**
+     * @return Returns the inverseCumulativeTestValues.
+     */
+    protected int[] getInverseCumulativeTestValues() {
+        return inverseCumulativeTestValues;
+    }
+
+    /**
+     * @param inverseCumulativeTestValues The inverseCumulativeTestValues to set.
+     */
+    protected void setInverseCumulativeTestValues(int[] inverseCumulativeTestValues) {
+        this.inverseCumulativeTestValues = inverseCumulativeTestValues;
+    }
+
+    /**
+     * @return Returns the tolerance.
+     */
+    protected double getTolerance() {
+        return tolerance;
+    }
+
+    /**
+     * @param tolerance The tolerance to set.
+     */
+    protected void setTolerance(double tolerance) {
+        this.tolerance = tolerance;
+    }
+}