示例#1
0
        /* The t-distribution has the form

           p(x) dx = (Gamma((nu + 1)/2)/(sqrt(pi nu) Gamma(nu/2))
           * (1 + (x^2)/nu)^-((nu + 1)/2) dx

           The method used here is the one described in Knuth
         */
        public static double Sampler(PZRandomUnivariate random, double nu)
        {
            if (nu <= 2)
            {

                double Y1 = NormalDistribution.SamplerPolar(random, 0.0, 1.0);
                double Y2 = ChiSquareDistribution.Sampler(random, nu);

                double t = Y1 / System.Math.Sqrt(Y2 / nu);

                return t;
            }
            else
            {
                double Y1, Y2, Z, t;
                do
                {
                    Y1 = NormalDistribution.SamplerPolar(random, 0.0, 1.0);
                    Y2 = ExponentialDistribution.Sampler(random, 1 / (nu / 2 - 1));

                    Z = Y1 * Y1 / (nu - 2);
                }
                while (1 - Z < 0 || System.Math.Log(-Y2 - Z) > (1 - Z));

                /* Note that there is a typo in Knuth's formula, the line below
                   is taken from the original paper of Marsaglia, Mathematics of
                   Computation, 34 (1980), p 234-256 */

                t = Y1 / System.Math.Sqrt((1 - 2 / nu) * (1 - Z));
                return t;
            }
        }
示例#2
0
 /// <summary>
 /// </summary>
 /// <returns></returns>
 public static double Sampler(PZRandomUnivariate random, double k)
 {
     double chisq = 2 * GammaDistribution.SampleMarsagliaAndTsang(random, k / 2, 1.0);
     return chisq;
 }
示例#3
0
 public static double Sampler(PZRandomUnivariate random)
 {
     double r = random.Sample();
     return r;
 }
示例#4
0
 /// <summary>
 /// U(0, range], return int value
 /// </summary>
 /// <param name="random"></param>
 /// <param name="range"></param>
 /// <returns></returns>
 public static int SamplerInt(PZRandomUnivariate random, int range)
 {
     return 0;
 }
示例#5
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;
            }
        }
示例#6
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);
        }
示例#7
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 */
        }
示例#8
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;
        }
 /* 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;
 }