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 org.apache.commons.rng.RandomProviderState;
20  import org.apache.commons.rng.RestorableUniformRandomProvider;
21  import org.apache.commons.rng.UniformRandomProvider;
22  import org.apache.commons.rng.sampling.RandomAssert;
23  import org.apache.commons.rng.sampling.distribution.LargeMeanPoissonSampler.LargeMeanPoissonSamplerState;
24  import org.apache.commons.rng.simple.RandomSource;
25  import org.junit.Assert;
26  import org.junit.Test;
27  
28  /**
29   * This test checks the {@link LargeMeanPoissonSampler} can be created
30   * from a saved state.
31   */
32  public class LargeMeanPoissonSamplerTest {
33  
34      // Edge cases for construction
35  
36      /**
37       * Test the constructor with a bad mean.
38       */
39      @Test(expected = IllegalArgumentException.class)
40      public void testConstructorThrowsWithMeanLargerThanUpperBound() {
41          final RestorableUniformRandomProvider rng =
42                  RandomSource.create(RandomSource.SPLIT_MIX_64);
43          final double mean = Integer.MAX_VALUE / 2 + 1;
44          LargeMeanPoissonSampler.of(rng, mean);
45      }
46  
47      /**
48       * Test the constructor with a mean below 1.
49       */
50      @Test(expected = IllegalArgumentException.class)
51      public void testConstructorThrowsWithMeanBelow1() {
52          final RestorableUniformRandomProvider rng =
53                  RandomSource.create(RandomSource.SPLIT_MIX_64);
54          final double mean = Math.nextAfter(1, -1);
55          LargeMeanPoissonSampler.of(rng, mean);
56      }
57  
58      /**
59       * Test the constructor using the state with a negative fractional mean.
60       */
61      @Test(expected = IllegalArgumentException.class)
62      public void testConstructorThrowsWithStateAndNegativeFractionalMean() {
63          final RestorableUniformRandomProvider rng =
64                  RandomSource.create(RandomSource.SPLIT_MIX_64);
65          final LargeMeanPoissonSamplerState state = new LargeMeanPoissonSampler(rng, 1).getState();
66          @SuppressWarnings("unused")
67          LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, state, -0.1);
68      }
69  
70      /**
71       * Test the constructor with a non-fractional mean.
72       */
73      @Test(expected = IllegalArgumentException.class)
74      public void testConstructorThrowsWithStateAndNonFractionalMean() {
75          final RestorableUniformRandomProvider rng =
76                  RandomSource.create(RandomSource.SPLIT_MIX_64);
77          final LargeMeanPoissonSamplerState state = new LargeMeanPoissonSampler(rng, 1).getState();
78          @SuppressWarnings("unused")
79          LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, state, 1.1);
80      }
81  
82      /**
83       * Test the constructor with fractional mean of 1.
84       */
85      @Test(expected = IllegalArgumentException.class)
86      public void testConstructorThrowsWithStateAndFractionalMeanOne() {
87          final RestorableUniformRandomProvider rng =
88                  RandomSource.create(RandomSource.SPLIT_MIX_64);
89          final LargeMeanPoissonSamplerState state = new LargeMeanPoissonSampler(rng, 1).getState();
90          @SuppressWarnings("unused")
91          LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, state, 1);
92      }
93  
94      // Sampling tests
95  
96      /**
97       * Test the {@link LargeMeanPoissonSampler} returns the same samples when it
98       * is created using the saved state.
99       */
100     @Test
101     public void testCanComputeSameSamplesWhenConstructedWithState() {
102         // Two identical RNGs
103         final RestorableUniformRandomProvider rng1 =
104                 RandomSource.create(RandomSource.MWC_256);
105         final RandomProviderState state = rng1.saveState();
106         final RestorableUniformRandomProvider rng2 =
107                 RandomSource.create(RandomSource.MWC_256);
108         rng2.restoreState(state);
109 
110         // The sampler is suitable for mean > 40
111         for (int i = 40; i < 44; i++) {
112             // Test integer mean (no SmallMeanPoissonSampler required)
113             testPoissonSamples(rng1, rng2, i);
114             // Test non-integer mean (SmallMeanPoissonSampler required)
115             testPoissonSamples(rng1, rng2, i + 0.5);
116         }
117     }
118 
119     /**
120      * Test the {@link LargeMeanPoissonSampler} returns the same samples when it
121      * is created using the saved state. The random providers must be
122      * identical (including state).
123      *
124      * @param rng1  the first random provider
125      * @param rng2  the second random provider
126      * @param mean  the mean
127      */
128     private static void testPoissonSamples(
129             final RestorableUniformRandomProvider rng1,
130             final RestorableUniformRandomProvider rng2,
131             double mean) {
132         final LargeMeanPoissonSampler s1 = new LargeMeanPoissonSampler(rng1, mean);
133         final int n = (int) Math.floor(mean);
134         final double lambdaFractional = mean - n;
135         final LargeMeanPoissonSamplerState state1 = s1.getState();
136         final LargeMeanPoissonSampler s2 = new LargeMeanPoissonSampler(rng2, state1, lambdaFractional);
137         final LargeMeanPoissonSamplerState state2 = s2.getState();
138         Assert.assertEquals("State lambdas are not equal", state1.getLambda(), state2.getLambda());
139         Assert.assertNotSame("States are the same object", state1, state2);
140         RandomAssert.assertProduceSameSequence(s1, s2);
141     }
142 
143     /**
144      * Test the SharedStateSampler implementation.
145      */
146     @Test
147     public void testSharedStateSamplerWithFractionalMean() {
148         testSharedStateSampler(34.5);
149     }
150 
151     /**
152      * Test the SharedStateSampler implementation with the edge case when there is no
153      * small mean sampler (i.e. no fraction part to the mean).
154      */
155     @Test
156     public void testSharedStateSamplerWithIntegerMean() {
157         testSharedStateSampler(34.0);
158     }
159 
160     /**
161      * Test the SharedStateSampler implementation.
162      *
163      * @param mean Mean.
164      */
165     private static void testSharedStateSampler(double mean) {
166         final UniformRandomProvider rng1 = RandomSource.create(RandomSource.SPLIT_MIX_64, 0L);
167         final UniformRandomProvider rng2 = RandomSource.create(RandomSource.SPLIT_MIX_64, 0L);
168         final SharedStateDiscreteSampler sampler1 =
169             LargeMeanPoissonSampler.of(rng1, mean);
170         final SharedStateDiscreteSampler sampler2 = sampler1.withUniformRandomProvider(rng2);
171         RandomAssert.assertProduceSameSequence(sampler1, sampler2);
172     }
173 }