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/11/15 16:36:34 UTC

commons-rng git commit: RNG-52: Conservative upper bound to avoid silent truncation.

Repository: commons-rng
Updated Branches:
  refs/heads/master 350fb428e -> 8c927dc65


RNG-52: Conservative upper bound to avoid silent truncation.

Functionality is not limited since the Poisson distribution is already
well approximated by a Gaussian for mean values larger than about 1000.


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

Branch: refs/heads/master
Commit: 8c927dc65dc5d86daa16304a83b033b25c43fd28
Parents: 350fb42
Author: Gilles <er...@apache.org>
Authored: Thu Nov 15 17:33:56 2018 +0100
Committer: Gilles <er...@apache.org>
Committed: Thu Nov 15 17:33:56 2018 +0100

----------------------------------------------------------------------
 .../distribution/LargeMeanPoissonSampler.java   | 12 ++---
 .../distribution/SmallMeanPoissonSampler.java   |  7 ++-
 .../LargeMeanPoissonSamplerTest.java            | 11 ++--
 .../SmallMeanPoissonSamplerTest.java            | 54 ++++++++++++++++++++
 src/changes/changes.xml                         |  3 ++
 5 files changed, 74 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-rng/blob/8c927dc6/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.java
----------------------------------------------------------------------
diff --git a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.java b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.java
index 70cc68b..33675d8 100644
--- a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.java
+++ b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.java
@@ -38,10 +38,10 @@ import org.apache.commons.rng.sampling.distribution.InternalUtils.FactorialLog;
  */
 public class LargeMeanPoissonSampler
     implements DiscreteSampler {
-
+    /** Upper bound to avoid truncation. */
+    private static final double MAX_MEAN = 0.5 * Integer.MAX_VALUE;
     /** Class to compute {@code log(n!)}. This has no cached values. */
     private static final InternalUtils.FactorialLog NO_CACHE_FACTORIAL_LOG;
-
     /** Used when there is no requirement for a small mean Poisson sampler. */
     private static final DiscreteSampler NO_SMALL_MEAN_POISSON_SAMPLER = null;
 
@@ -96,10 +96,10 @@ public class LargeMeanPoissonSampler
     private final DiscreteSampler smallMeanPoissonSampler;
 
     /**
-     * @param rng  Generator of uniformly distributed random numbers.
+     * @param rng Generator of uniformly distributed random numbers.
      * @param mean Mean.
      * @throws IllegalArgumentException if {@code mean <= 0} or
-     * {@code mean >} {@link Integer#MAX_VALUE}.
+     * {@code mean > 0.5 *} {@link Integer#MAX_VALUE}.
      */
     public LargeMeanPoissonSampler(UniformRandomProvider rng,
                                    double mean) {
@@ -107,8 +107,8 @@ public class LargeMeanPoissonSampler
           throw new IllegalArgumentException(mean + " <= " + 0);
         }
         // The algorithm is not valid if Math.floor(mean) is not an integer.
-        if (mean > Integer.MAX_VALUE) {
-            throw new IllegalArgumentException(mean + " > " + Integer.MAX_VALUE);
+        if (mean > MAX_MEAN) {
+            throw new IllegalArgumentException(mean + " > " + MAX_MEAN);
         }
         this.rng = rng;
 

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/8c927dc6/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.java
----------------------------------------------------------------------
diff --git a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.java b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.java
index 170a85b..c8e744e 100644
--- a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.java
+++ b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.java
@@ -32,10 +32,12 @@ import org.apache.commons.rng.UniformRandomProvider;
  * @since 1.1
  *
  * This sampler is suitable for {@code mean < 40}.
+ * For large means, {@link LargePoissonSampler} should be used instead.
  */
 public class SmallMeanPoissonSampler
     implements DiscreteSampler {
-
+    /** Upper bound to avoid truncation. */
+    private static final double MAX_MEAN = 0.5 * Integer.MAX_VALUE;
     /**
      * Pre-compute {@code Math.exp(-mean)}.
      * Note: This is the probability of the Poisson sample {@code P(n=0)}.
@@ -57,6 +59,9 @@ public class SmallMeanPoissonSampler
         if (mean <= 0) {
             throw new IllegalArgumentException(mean + " <= " + 0);
         }
+        if (mean > MAX_MEAN) {
+            throw new IllegalArgumentException(mean + " > " + MAX_MEAN);
+        }
 
         p0 = Math.exp(-mean);
         // The returned sample is bounded by 1000 * mean or Integer.MAX_VALUE

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/8c927dc6/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSamplerTest.java
----------------------------------------------------------------------
diff --git a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSamplerTest.java b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSamplerTest.java
index 480f452..7ee0517 100644
--- a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSamplerTest.java
+++ b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSamplerTest.java
@@ -35,23 +35,22 @@ public class LargeMeanPoissonSamplerTest {
      * Test the constructor with a bad mean.
      */
     @Test(expected=IllegalArgumentException.class)
-    public void testConstructorThrowsWithZeroMean() {
+    public void testConstructorThrowsWithMeanLargerThanUpperBound() {
         final RestorableUniformRandomProvider rng =
                 RandomSource.create(RandomSource.SPLIT_MIX_64);
         @SuppressWarnings("unused")
-        LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, 0);
+        LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, Integer.MAX_VALUE / 2 + 1);
     }
 
     /**
-     * Test the constructor with a mean that is too large.
+     * Test the constructor with a bad mean.
      */
     @Test(expected=IllegalArgumentException.class)
-    public void testConstructorThrowsWithNonIntegerMean() {
+    public void testConstructorThrowsWithZeroMean() {
         final RestorableUniformRandomProvider rng =
                 RandomSource.create(RandomSource.SPLIT_MIX_64);
-        final double mean = Integer.MAX_VALUE + 1.0;
         @SuppressWarnings("unused")
-        LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, mean);
+        LargeMeanPoissonSampler sampler = new LargeMeanPoissonSampler(rng, 0);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/8c927dc6/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java
----------------------------------------------------------------------
diff --git a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java
new file mode 100644
index 0000000..775f326
--- /dev/null
+++ b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSamplerTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.commons.rng.RandomProviderState;
+import org.apache.commons.rng.RestorableUniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * This test checks the {@link SmallMeanPoissonSampler} can be created
+ * from a saved state.
+ */
+public class SmallMeanPoissonSamplerTest {
+
+    // Edge cases for construction
+
+    /**
+     * Test the constructor with a bad mean.
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorThrowsWithMeanLargerThanUpperBound() {
+        final RestorableUniformRandomProvider rng =
+            RandomSource.create(RandomSource.SPLIT_MIX_64);
+        @SuppressWarnings("unused")
+        SmallMeanPoissonSampler sampler = new SmallMeanPoissonSampler(rng, Integer.MAX_VALUE / 2 + 1);
+    }
+
+    /**
+     * Test the constructor with a bad mean.
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorThrowsWithZeroMean() {
+        final RestorableUniformRandomProvider rng =
+            RandomSource.create(RandomSource.SPLIT_MIX_64);
+        @SuppressWarnings("unused")
+        SmallMeanPoissonSampler sampler = new SmallMeanPoissonSampler(rng, 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-rng/blob/8c927dc6/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 62557fe..9e249c5 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -67,6 +67,9 @@ Additional code is provided in the following module:
 It is however not part of the official API and no compatibility
 should be expected in subsequent releases.
 ">
+      <action dev="erans" type="update" issue="RNG-52">
+        Set conservative upper bound in "LargePoissonSampler" to avoid truncation.
+      </action>
       <action dev="erans" type="fix" issue="RNG-59">
         Use JDK's "SecureRandom" to seed the "SeedFactory".
       </action>