Repository: commons-rng
Updated Branches:
  refs/heads/RNG-30__sampling [created] 74be2678f


RNG-30: Unit tests.


Project: http://git-wip-us.apache.org/repos/asf/commons-rng/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-rng/commit/86c64bfb
Tree: http://git-wip-us.apache.org/repos/asf/commons-rng/tree/86c64bfb
Diff: http://git-wip-us.apache.org/repos/asf/commons-rng/diff/86c64bfb

Branch: refs/heads/RNG-30__sampling
Commit: 86c64bfbe9c2d7e77bfd0945e04b9f69c6bfd2cf
Parents: 362789f
Author: Gilles <er...@apache.org>
Authored: Thu Nov 10 16:48:03 2016 +0100
Committer: Gilles <er...@apache.org>
Committed: Thu Nov 10 16:54:08 2016 +0100

----------------------------------------------------------------------
 .../distribution/ContinuousSamplerTestData.java |  48 +++++++
 .../distribution/ContinuousSamplersList.java    | 119 +++++++++++++++
 ...seMethodContinuousSamplerParametricTest.java | 143 +++++++++++++++++++
 3 files changed, 310 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-rng/blob/86c64bfb/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplerTestData.java
----------------------------------------------------------------------
diff --git 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplerTestData.java
 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplerTestData.java
new file mode 100644
index 0000000..a9754b4
--- /dev/null
+++ 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplerTestData.java
@@ -0,0 +1,48 @@
+/*
+ * 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.rng.sampling.distribution;
+
+import java.util.Arrays;
+
+import org.apache.commons.rng.sampling.ContinuousSampler;
+
+/**
+ * Data store for {@link InverseMethodContinuousParametricTest}.
+ */
+class ContinuousSamplerTestData {
+    private final ContinuousSampler sampler;
+    private final double[] deciles;
+
+    public ContinuousSamplerTestData(ContinuousSampler sampler,
+                                     double[] deciles) {
+        this.sampler = sampler;
+        this.deciles = deciles.clone();
+    }
+
+    public ContinuousSampler getSampler() {
+        return sampler;
+    }
+
+    public double[] getDeciles() {
+        return deciles.clone();
+    }
+
+    @Override
+    public String toString() {
+        return sampler.toString() + ": deciles=" + Arrays.toString(deciles);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/86c64bfb/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
----------------------------------------------------------------------
diff --git 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
new file mode 100644
index 0000000..125e9c9
--- /dev/null
+++ 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
@@ -0,0 +1,119 @@
+/*
+ * 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.rng.sampling.distribution;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.sampling.ContinuousSampler;
+import org.apache.commons.rng.simple.RandomSource;
+
+/**
+ * The purpose of this class is to provide a list of samplers
+ * that use the "inverse method" to sampler from distributions.
+ */
+public class ContinuousSamplersList {
+    /** List of all RNGs implemented in the library. */
+    private static final List<ContinuousSamplerTestData[]> LIST =
+        new ArrayList<ContinuousSamplerTestData[]>();
+
+    static {
+        try {
+            // List of distributions to test.
+
+            // 1. Gaussian
+            // 1.a Using the "inverse method".
+            final double mean = -123.45;
+            final double sigma = 6.789;
+            add(LIST, new 
org.apache.commons.math3.distribution.NormalDistribution(mean, sigma),
+                RandomSource.create(RandomSource.KISS));
+            // 1.b Using "Box-Muller".
+            add(LIST, new 
org.apache.commons.math3.distribution.NormalDistribution(mean, sigma),
+                new BoxMullerGaussianSampler(mean, sigma, 
RandomSource.create(RandomSource.MT)));
+
+            // 2. 
+        } catch (Exception e) {
+            System.err.println("Unexpected exception while creating the list 
of samplers: " + e);
+            e.printStackTrace(System.err);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Class contains only static methods.
+     */
+    private ContinuousSamplersList() {}
+
+    /**
+     * @param list List of data (one the "parameters" tested by the Junit 
parametric test).
+     * @param dist Distribution to which the samples are supposed to conform.
+     * @param rng Generator of uniformly distributed sequences.
+     */
+    private static void add(List<ContinuousSamplerTestData[]> list,
+                            final 
org.apache.commons.math3.distribution.RealDistribution dist,
+                            UniformRandomProvider rng) {
+        final ContinuousSampler inverseMethodSampler =
+            new InverseMethodContinuousSampler(rng,
+                                               new 
ContinuousInverseCumulativeProbabilityFunction() {
+                                                   @Override
+                                                   public double 
inverseCumulativeProbability(double p) {
+                                                       return 
dist.inverseCumulativeProbability(p);
+                                                   }
+                                               });
+        list.add(new ContinuousSamplerTestData[] { new 
ContinuousSamplerTestData(inverseMethodSampler,
+                                                                               
  getDeciles(dist)) });
+     }
+
+    /**
+     * @param list List of data (one the "parameters" tested by the Junit 
parametric test).
+     * @param dist Distribution to which the samples are supposed to conform.
+     * @param sampler Sampler.
+     */
+    private static void add(List<ContinuousSamplerTestData[]> list,
+                            final 
org.apache.commons.math3.distribution.RealDistribution dist,
+                            final ContinuousSampler sampler) {
+        list.add(new ContinuousSamplerTestData[] { new 
ContinuousSamplerTestData(sampler,
+                                                                               
  getDeciles(dist)) });
+    }
+
+    /**
+     * Subclasses that are "parametric" tests can forward the call to
+     * the "@Parameters"-annotated method to this method.
+     *
+     * @return the list of all generators.
+     */
+    public static Iterable<ContinuousSamplerTestData[]> list() {
+        return Collections.unmodifiableList(LIST);
+    }
+
+    /**
+     * @param dist Distribution.
+     * @return the deciles of the given distribution. 
+     */
+    private static double[] 
getDeciles(org.apache.commons.math3.distribution.RealDistribution dist) {
+        final int last = 9;
+        final double[] deciles = new double[last];
+        final double ten = 10;
+        for (int i = 0; i < last; i++) {
+            deciles[i] = dist.inverseCumulativeProbability((i + 1) / ten);
+        }
+        return deciles;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/86c64bfb/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/InverseMethodContinuousSamplerParametricTest.java
----------------------------------------------------------------------
diff --git 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/InverseMethodContinuousSamplerParametricTest.java
 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/InverseMethodContinuousSamplerParametricTest.java
new file mode 100644
index 0000000..5296033
--- /dev/null
+++ 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/InverseMethodContinuousSamplerParametricTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.rng.sampling.distribution;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.RandomProviderState;
+import org.apache.commons.rng.RestorableUniformRandomProvider;
+import org.apache.commons.rng.core.RandomProviderDefaultState;
+import org.apache.commons.rng.sampling.ContinuousSampler;
+
+/**
+ * Tests for random deviates generators using the "inverse method".
+ */
+@RunWith(value=Parameterized.class)
+public class InverseMethodContinuousSamplerParametricTest {
+    /** Sampler under test. */
+    private final ContinuousSamplerTestData sampler;
+
+    /**
+     * Initializes generator instance.
+     *
+     * @param rng RNG to be tested.
+     */
+    public 
InverseMethodContinuousSamplerParametricTest(ContinuousSamplerTestData data) {
+        sampler = data;
+    }
+
+    @Parameters(name = "{index}: data={0}")
+    public static Iterable<ContinuousSamplerTestData[]> getList() {
+        return ContinuousSamplersList.list();
+    }
+
+    @Test
+    public void testSampling() {
+        check(10000, sampler.getSampler(), sampler.getDeciles());
+    }
+
+    /**
+     * Performs a chi-square test of homogeneity of the observed
+     * distribution with the expected distribution.
+     * Tests are performed at the 1% level and an average failure rate
+     * higher than 2% (i.e. more than 20 null hypothesis rejections)
+     * causes the test case to fail.
+     *
+     * @param sampler Sampler.
+     * @param sampleSize Number of random values to generate.
+     * @param deciles Deciles.
+     */
+    private void check(long sampleSize,
+                       ContinuousSampler sampler,
+                       double[] deciles) {
+        final int numTests = 500;
+
+        // Do not change (statistical test assumes that dof = 10).
+        final int numBins = 10;
+
+        // Run the tests.
+        int numFailures = 0;
+
+        final double[] expected = new double[numBins];
+        for (int k = 0; k < numBins; k++) {
+            expected[k] = sampleSize / (double) numBins;
+        }
+
+        final long[] observed = new long[numBins];
+        // Chi-square critical value with 10 degrees of freedom
+        // and 1% significance level.
+        final double chi2CriticalValue = 23.209;
+
+        try {
+            final int lastDecileIndex = numBins - 1;
+            for (int i = 0; i < numTests; i++) {
+                Arrays.fill(observed, 0);
+                SAMPLE: for (long j = 0; j < sampleSize; j++) {
+                    final double value = sampler.sample();
+
+                    for (int k = 0; k < lastDecileIndex; k++) {
+                        if (value < deciles[k]) {
+                            ++observed[k];
+                            continue SAMPLE;
+                        }
+                    }
+                    ++observed[lastDecileIndex];
+                }
+
+                // Compute chi-square.
+                double chi2 = 0;
+                for (int k = 0; k < numBins; k++) {
+                    final double diff = observed[k] - expected[k];
+                    chi2 += diff * diff / expected[k];
+                    // System.out.println("bin[" + k + "]" +
+                    //                    " obs=" + observed[k] +
+                    //                    " exp=" + expected[k]);
+                }
+
+                // Statistics check.
+                if (chi2 > chi2CriticalValue) {
+                    ++numFailures;
+                }
+            }
+        } catch (Exception e) {
+            // Should never happen.
+            throw new RuntimeException("Unexpected", e);
+        }
+
+        if ((double) numFailures / (double) numTests > 0.02) {
+            Assert.fail(sampler + ": Too many failures for sample size = " + 
sampleSize +
+                        " (" + numFailures + " out of " + numTests + " tests 
failed)");
+        }
+    }
+}

Reply via email to