View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.sampling.distribution;
18  
19  import java.util.Arrays;
20  import java.util.List;
21  import java.util.ArrayList;
22  
23  import org.junit.Assert;
24  import org.junit.Test;
25  import org.junit.runner.RunWith;
26  import org.junit.runners.Parameterized;
27  import org.junit.runners.Parameterized.Parameters;
28  
29  /**
30   * Tests for random deviates generators.
31   */
32  @RunWith(value=Parameterized.class)
33  public class ContinuousSamplerParametricTest {
34      /** Sampler under test. */
35      private final ContinuousSamplerTestData sampler;
36  
37      /**
38       * Initializes generator instance.
39       *
40       * @param rng RNG to be tested.
41       */
42      public ContinuousSamplerParametricTest(ContinuousSamplerTestData data) {
43          sampler = data;
44      }
45  
46      @Parameters(name = "{index}: data={0}")
47      public static Iterable<ContinuousSamplerTestData[]> getList() {
48          return ContinuousSamplersList.list();
49      }
50  
51      @Test
52      public void testSampling() {
53          check(20000, sampler.getSampler(), sampler.getDeciles());
54      }
55  
56      /**
57       * Performs a chi-square test of homogeneity of the observed
58       * distribution with the expected distribution.
59       * Tests are performed at the 1% level and an average failure rate
60       * higher than 5% causes the test case to fail.
61       *
62       * @param sampler Sampler.
63       * @param sampleSize Number of random values to generate.
64       * @param deciles Deciles.
65       */
66      private void check(long sampleSize,
67                         ContinuousSampler sampler,
68                         double[] deciles) {
69          final int numTests = 50;
70  
71          // Do not change (statistical test assumes that dof = 9).
72          final int numBins = 10; // dof = numBins - 1
73  
74          // Run the tests.
75          int numFailures = 0;
76  
77          final double[] expected = new double[numBins];
78          for (int k = 0; k < numBins; k++) {
79              expected[k] = sampleSize / (double) numBins;
80          }
81  
82          final long[] observed = new long[numBins];
83          // Chi-square critical value with 9 degrees of freedom
84          // and 1% significance level.
85          final double chi2CriticalValue = 21.67;
86  
87          // For storing chi2 larger than the critical value.
88          final List<Double> failedStat = new ArrayList<Double>();
89          try {
90              final int lastDecileIndex = numBins - 1;
91              for (int i = 0; i < numTests; i++) {
92                  Arrays.fill(observed, 0);
93                  SAMPLE: for (long j = 0; j < sampleSize; j++) {
94                      final double value = sampler.sample();
95  
96                      for (int k = 0; k < lastDecileIndex; k++) {
97                          if (value < deciles[k]) {
98                              ++observed[k];
99                              continue SAMPLE;
100                         }
101                     }
102                     ++observed[lastDecileIndex];
103                 }
104 
105                 // Compute chi-square.
106                 double chi2 = 0;
107                 for (int k = 0; k < numBins; k++) {
108                     final double diff = observed[k] - expected[k];
109                     chi2 += diff * diff / expected[k];
110                     // System.out.println("bin[" + k + "]" +
111                     //                    " obs=" + observed[k] +
112                     //                    " exp=" + expected[k]);
113                 }
114 
115                 // Statistics check.
116                 if (chi2 > chi2CriticalValue) {
117                     failedStat.add(chi2);
118                     ++numFailures;
119                 }
120             }
121         } catch (Exception e) {
122             // Should never happen.
123             throw new RuntimeException("Unexpected", e);
124         }
125 
126         if ((double) numFailures / (double) numTests > 0.05) {
127             Assert.fail(sampler + ": Too many failures for sample size = " + sampleSize +
128                         " (" + numFailures + " out of " + numTests + " tests failed, " +
129                         "chi2=" + Arrays.toString(failedStat.toArray(new Double[0])));
130         }
131     }
132 }