Пример #1
0
 public static double Sampler(PZRandomUnivariate random)
 {
     double r = random.Sample();
     return r;
 }
Пример #2
0
        /// <summary>
        /// New version based on Marsaglia and Tsang, "A Simple Method for
        /// generating gamma variables", ACM Transactions on Mathematical
        /// Software, Vol 26, No 3 (2000), p363-372.
        /// Implemented by [email protected], minor modifications for GSL
        /// by Brian Gough
        /// </summary>
        /// <returns></returns>
        public static double SampleMarsagliaAndTsang(PZRandomUnivariate random, double alpha, double beta)
        {
            if (alpha < 1)
            {
                double u = UniformDistribution.Sampler(random);

                return SampleMarsagliaAndTsang(random, 1.0 + alpha, beta) * System.Math.Pow(u, 1.0 / alpha);
            }

            {
                double x, v, u;
                double d = alpha - 1.0 / 3.0;
                double c = (1.0 / 3.0) / System.Math.Sqrt(d);

                while (true)
                {
                    do
                    {
                        x = NormalDistribution.SamplerPolar(random, 0.0, 1.0);
                        v = 1.0 + c * x;
                    }
                    while (v <= 0);

                    v = v * v * v;
                    u = random.Sample();

                    if (u < 1 - 0.0331 * x * x * x * x)
                        break;

                    if (System.Math.Log(u) < 0.5 * x * x + d * (1 - v + System.Math.Log(v)))
                        break;
                }

                return beta * d * v;
            }
        }
Пример #3
0
        /// <summary>
        /// http://en.wikipedia.org/wiki/Gamma_distribution
        /// Knuth
        /// </summary>
        /// <returns></returns>
        public static double SampleKnuth(PZRandomUnivariate random, double k, double theta)
        {
            double integralk = System.Math.Floor(k);
            double fractionalk = k - integralk;
            double xi = 0.0;

            if (fractionalk > 0)
            {
                // Gamma(delta, 1), delta = fractional of k
                // step 1
                int m = 1;
                double delta = fractionalk;
                double v0 = System.Math.E / (System.Math.E + delta);
                double xim = 0.0;
                double etam = 0.0;

                while (true)
                {
                    // step 2
                    double v2mM1 = random.Sample();
                    double v2m = random.Sample();
                    // step 3
                    if (v2mM1 <= v0)
                    {
                        // step 4
                        xim = System.Math.Pow(v2mM1, 1 / delta);
                        etam = v2m * System.Math.Pow(xim, delta - 1.0);
                    }
                    else
                    {
                        // ste 5
                        xim = 1 - System.Math.Log(v2mM1);
                        etam = v2m * System.Math.Exp(-1.0 * xim);
                    }
                    // step 6
                    if (etam > System.Math.Pow(xim, delta - 1) * System.Math.Exp(-1.0 * xim))
                        m++;
                    // return step 2
                    else
                    {
                        // step 7
                        xi = xim; // xi ~ Gamma(delta, 1)
                        break;
                    }
                }
            }

            // Gamma(n, 1), n = integral of k
            double sum = 0.0;
            double ui;
            for (int i = 0; i < integralk; i++)
            {
                ui = random.Sample();
                sum += System.Math.Log(ui);
            }

            return theta * (xi - sum);
        }
Пример #4
0
        /* Ratio method (Kinderman-Monahan); see Knuth v2, 3rd ed, p130.
         * K+M, ACM Trans Math Software 3 (1977) 257-260.
         *
         * [Added by Charles Karney] This is an implementation of Leva's
         * modifications to the original K+M method; see:
         * J. L. Leva, ACM Trans Math Software 18 (1992) 449-453 and 454-455. */
        public static double SamplerRatio(PZRandomUnivariate random, double mu, double sigma)
        {
            double u, v, x, y, Q;
            double s = 0.449871;    /* Constants from Leva */
            double t = -0.386595;
            double a = 0.19600;
            double b = 0.25472;
            double r1 = 0.27597;
            double r2 = 0.27846;

            do  /* This loop is executed 1.369 times on average  */
            {
                /* Generate a point P = (u, v) uniform in a rectangle enclosing
                   the K+M region v^2 <= - 4 u^2 log(u). */

                /* u in (0, 1] to avoid singularity at u = 0 */
                u = 1 - random.Sample();

                /* v is in the asymmetric interval [-0.5, 0.5).  However v = -0.5
                   is rejected in the last part of the while clause.  The
                   resulting normal deviate is strictly symmetric about 0
                   (provided that v is symmetric once v = -0.5 is excluded). */
                v = random.Sample() - 0.5;

                /* Constant 1.7156 > sqrt(8/e) (for accuracy); but not by too
                   much (for efficiency). */
                v *= 1.7156;

                /* Compute Leva's quadratic form Q */
                x = u - s;
                y = System.Math.Abs(v) - t;
                Q = x * x + y * (a * y - b * x);

                /* Accept P if Q < r1 (Leva) */
                /* Reject P if Q > r2 (Leva) */
                /* Accept if v^2 <= -4 u^2 log(u) (K+M) */
                /* This final test is executed 0.012 times on average. */
            }
            while (Q >= r1 && (Q > r2 || v * v > -4 * u * u * System.Math.Log(u)));
            double r = mu + sigma * (v / u);
            return r;       /* Return slope */
        }
Пример #5
0
        /* Of the two methods provided below, I think the Polar method is more
         * efficient, but only when you are actually producing two random
         * deviates.  We don't produce two, because then we'd have to save one
         * in a static variable for the next call, and that would screws up
         * re-entrant or threaded code, so we only produce one.  This makes
         * the Ratio method suddenly more appealing.
         *
         * [Added by Charles Karney] We use Leva's implementation of the Ratio
         * method which avoids calling log() nearly all the time and makes the
         * Ratio method faster than the Polar method (when it produces just one
         * result per call).  Timing per call (gcc -O2 on 866MHz Pentium,
         * average over 10^8 calls)
         *
         *   Polar method: 660 ns
         *   Ratio method: 368 ns
         *
         */
        /* Polar (Box-Mueller) method; See Knuth v2, 3rd ed, p122 */
        public static double SamplerPolar(PZRandomUnivariate random, double mu, double sigma)
        {
            double x, y, r2;
            do
            {
                /* choose x,y in uniform square (-1,-1) to (+1,+1) */
                x = -1 + 2 * random.Sample();
                y = -1 + 2 * random.Sample();

                /* see if it is in the unit circle */
                r2 = x * x + y * y;
            }
            while (r2 > 1.0 || r2 == 0);

            /* Box-Muller transform */
            double r = mu + sigma * y * System.Math.Sqrt(-2.0 * System.Math.Log(r2) / r2);
            return r;
        }
Пример #6
0
 /* The exponential distribution has the form
 p(x) dx = exp(-x/mu) dx/mu
 for x = 0 ... +infty */
 public static double Sampler(PZRandomUnivariate random, double mu)
 {
     double e = random.Sample();
     double r = -mu * System.Math.Log(e);
     return r;
 }