You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/02/14 13:59:24 UTC

[commons-rng] 01/17: RNG-68: Add private classes for each algorithm

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git

commit ad8739b2290ae8ea34954b08fd496c6ca07c3b33
Author: aherbert <a....@sussex.ac.uk>
AuthorDate: Mon Jan 28 10:33:09 2019 +0000

    RNG-68: Add private classes for each algorithm
---
 .../AhrensDieterMarsagliaTsangGammaSampler.java    | 174 +++++++++++++++------
 1 file changed, 123 insertions(+), 51 deletions(-)

diff --git a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/AhrensDieterMarsagliaTsangGammaSampler.java b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/AhrensDieterMarsagliaTsangGammaSampler.java
index d34902d..ab2b176 100644
--- a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/AhrensDieterMarsagliaTsangGammaSampler.java
+++ b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/AhrensDieterMarsagliaTsangGammaSampler.java
@@ -44,48 +44,68 @@ import org.apache.commons.rng.UniformRandomProvider;
 public class AhrensDieterMarsagliaTsangGammaSampler
     extends SamplerBase
     implements ContinuousSampler {
-    /** 1/3 */
-    private static final double ONE_THIRD = 1d / 3;
-    /** The shape parameter. */
-    private final double theta;
-    /** The alpha parameter. */
-    private final double alpha;
-    /** Inverse of "theta". */
-    private final double oneOverTheta;
-    /** Optimization (see code). */
-    private final double bGSOptim;
-    /** Optimization (see code). */
-    private final double dOptim;
-    /** Optimization (see code). */
-    private final double cOptim;
-    /** Gaussian sampling. */
-    private final NormalizedGaussianSampler gaussian;
-    /** Underlying source of randomness. */
-    private final UniformRandomProvider rng;
+    /** The appropriate gamma sampler for the parameters. */
+    private final ContinuousSampler delegate;
 
     /**
-     * @param rng Generator of uniformly distributed random numbers.
-     * @param alpha Alpha parameter of the distribution.
-     * @param theta Theta parameter of the distribution.
+     * Base class for a sampler from the Gamma distribution.
      */
-    public AhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng,
-                                                  double alpha,
-                                                  double theta) {
-        super(null);
-        this.rng = rng;
-        this.alpha = alpha;
-        this.theta = theta;
-        gaussian = new ZigguratNormalizedGaussianSampler(rng);
-        oneOverTheta = 1 / theta;
-        bGSOptim = 1 + theta / Math.E;
-        dOptim = theta - ONE_THIRD;
-        cOptim = ONE_THIRD / Math.sqrt(dOptim);
+    private abstract static class BaseAhrensDieterMarsagliaTsangGammaSampler
+        implements ContinuousSampler {
+
+        /** Underlying source of randomness. */
+        protected final UniformRandomProvider rng;
+        /** The shape parameter. */
+        protected final double theta;
+        /** The alpha parameter. */
+        protected final double alpha;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         * @param alpha Alpha shape parameter of the distribution.
+         * @param theta Theta scale parameter of the distribution.
+         */
+        BaseAhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng,
+                                                   double alpha,
+                                                   double theta) {
+            this.rng = rng;
+            this.alpha = alpha;
+            this.theta = theta;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public String toString() {
+            return "Ahrens-Dieter-Marsaglia-Tsang Gamma deviate [" + rng.toString() + "]";
+        }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public double sample() {
-        if (theta < 1) {
+    /**
+     * Class to sample from the Gamma distribution when {@code 0 < theta < 1}.
+     */
+    private static class SmallThetaAhrensDieterMarsagliaTsangGammaSampler
+        extends BaseAhrensDieterMarsagliaTsangGammaSampler {
+
+        /** Inverse of "theta". */
+        private final double oneOverTheta;
+        /** Optimization (see code). */
+        private final double bGSOptim;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         * @param alpha Alpha shape parameter of the distribution.
+         * @param theta Theta scale parameter of the distribution.
+         */
+        SmallThetaAhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng,
+                                                         double alpha,
+                                                         double theta) {
+            super(rng, alpha, theta);
+            oneOverTheta = 1 / theta;
+            bGSOptim = 1 + theta / Math.E;
+        }
+
+        @Override
+        public double sample() {
             // [1]: p. 228, Algorithm GS.
 
             while (true) {
@@ -102,24 +122,56 @@ public class AhrensDieterMarsagliaTsangGammaSampler
                     if (u2 > Math.exp(-x)) {
                         // Reject.
                         continue;
-                    } else {
-                        return alpha * x;
                     }
-                } else {
-                    // Step 3:
+                    return alpha * x;
+                }
 
-                    final double x = -Math.log((bGSOptim - p) * oneOverTheta);
-                    final double u2 = rng.nextDouble();
+                // Step 3:
 
-                    if (u2 > Math.pow(x, theta - 1)) {
-                        // Reject.
-                        continue;
-                    } else {
-                        return alpha * x;
-                    }
+                final double x = -Math.log((bGSOptim - p) * oneOverTheta);
+                final double u2 = rng.nextDouble();
+
+                if (u2 > Math.pow(x, theta - 1)) {
+                    // Reject.
+                    continue;
                 }
+                return alpha * x;
             }
-        } else {
+        }
+    }
+
+    /**
+     * Class to sample from the Gamma distribution when the {@code theta >= 1}.
+     */
+    private static class LargeThetaAhrensDieterMarsagliaTsangGammaSampler
+        extends BaseAhrensDieterMarsagliaTsangGammaSampler {
+
+        /** 1/3 */
+        private static final double ONE_THIRD = 1d / 3;
+
+        /** Optimization (see code). */
+        private final double dOptim;
+        /** Optimization (see code). */
+        private final double cOptim;
+        /** Gaussian sampling. */
+        private final NormalizedGaussianSampler gaussian;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         * @param alpha Alpha shape parameter of the distribution.
+         * @param theta Theta scale parameter of the distribution.
+         */
+        LargeThetaAhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng,
+                                                     double alpha,
+                                                     double theta) {
+            super(rng, alpha, theta);
+            gaussian = new ZigguratNormalizedGaussianSampler(rng);
+            dOptim = theta - ONE_THIRD;
+            cOptim = ONE_THIRD / Math.sqrt(dOptim);
+        }
+
+        @Override
+        public double sample() {
             while (true) {
                 final double x = gaussian.sample();
                 final double oPcTx = 1 + cOptim * x;
@@ -144,9 +196,29 @@ public class AhrensDieterMarsagliaTsangGammaSampler
         }
     }
 
+    /**
+     * @param rng Generator of uniformly distributed random numbers.
+     * @param alpha Alpha shape parameter of the distribution.
+     * @param theta Theta scale parameter of the distribution.
+     */
+    public AhrensDieterMarsagliaTsangGammaSampler(UniformRandomProvider rng,
+                                                  double alpha,
+                                                  double theta) {
+        super(null);
+        delegate = theta < 1 ?
+            new SmallThetaAhrensDieterMarsagliaTsangGammaSampler(rng, alpha, theta) :
+            new LargeThetaAhrensDieterMarsagliaTsangGammaSampler(rng, alpha, theta);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public double sample() {
+        return delegate.sample();
+    }
+
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "Ahrens-Dieter-Marsaglia-Tsang Gamma deviate [" + rng.toString() + "]";
+        return delegate.toString();
     }
 }