package umontreal.iro.lecuyer.randvar;
   import umontreal.iro.lecuyer.functions.MathFunction;
   import umontreal.iro.lecuyer.rng.RandomStream;
   import umontreal.iro.lecuyer.probdist.ContinuousDistribution;
   import umontreal.iro.lecuyer.probdist.InverseDistFromDensity;



/**
 * Implements a method for generating random variates by numerical inversion of
 * an arbitrary continuous distribution when only the probability density
 * is known.  The cumulative probabilities (cdf) are pre-computed by
 *  numerical quadrature  of the
 * density using Gauss-Lobatto integration over suitably small intervals to
 * satisfy the required precision, and these values are kept in tables. Then the
 *  algorithm uses polynomial interpolation  over the tabulated values to get
 *   the inverse cdf. The user can select the
 *   desired precision and the degree of the interpolating polynomials.
 * 
 * 

* The algorithm may fail for some distributions for which the density * becomes infinite at a point (for ex. the Gamma and the Beta distributions * with * α < 1) if one requires too high a precision * (a too small eps, for ex. * ε∼10-15). * However, it should work also for continuous densities with finite discontinuities. * *

* While the setup time is relatively slow, the generation of random variables * is extremely fast and practically independent of the required precision * and of the specific distribution. The following table shows the time needed * (in seconds) to generate 108 random numbers using inversion * from a given class, then the numerical inversion with Gauss-Lobatto integration * implemented here, and finally the speed ratios between the two methods. * The speed ratio is the speed of the latter over the former. * Thus for the beta distribution with parameters (5, 500), generating random * variables with the Gauss-Lobatto integration implemented in this class is * more than 1700 * times faster than using inversion from the BetaDist class. * These tests were made on a machine with processor AMD Athlon 4000, running * Red Hat Linux, with clock speed at 2403 MHz. * *

*

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
DistributionInversionGauss-Lobattospeed ratio
NormalDist(10.5, 5)9.198.891.03
ExponentialDist(5)17.728.822.0
CauchyDist(10.5, 5)18.308.812.1
BetaSymmetricalDist(10.5)242.808.8527.4
GammaDist(55)899.508.89101
ChiSquareNoncentralDist(10.5, 5)5326.908.85602
BetaDist(5, 500)15469.108.861746
*
* *

* The following table gives the time (in sec.) needed to * create an object (setup time) and to generate one random variable for * this class compared to the same for the inversion method specific to each class, * and the ratios of the times (init + one random variable) of the two methods. * For inversion, we initialized 108 times; for this class, we * initialized 104 times. * *

*

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
DistributionInversionGauss-Lobattotime ratio
 108 init104 initfor 1 init
NormalDist(10.5, 5)5.3038.2926426
ExponentialDist(5)3.9827.0512466
CauchyDist(10.5, 5)5.0558.3925007
BetaSymmetricalDist(10.5)90.6668.332049
GammaDist(55)13.1558.34639
ChiSquareNoncentralDist(10.5, 5)190.48248.98451
BetaDist(5, 500)63.60116.5775
*
* *

* If only a few random variables are needed, then using this class * is not efficient because of the slow set-up. But if one wants to generate * large samples from the same distribution with fixed parameters, then * this class will be very efficient. The following table gives the number of * random variables generated beyond which, using this class will be * worthwhile. * *

*

* * * * * * * * * * * * * * * * * * * * * * * * * *
Distributionnumber of generated variables
NormalDist(10.5, 5)41665
ExponentialDist(5)15266
CauchyDist(10.5, 5)31907
BetaSymmetricalDist(10.5)2814
GammaDist(55)649
ChiSquareNoncentralDist(10.5, 5)467
BetaDist(5, 500)75
*
* *

* Thus, for example, if one needs to generate less than 15266 exponential * random variables, then using the InverseFromDensityGen class * is not wortwhile: it will be faster to use inversion from the * ExponentialGen class. * */ public class InverseFromDensityGen extends RandomVariateGen { /** * Creates a new generator for the continuous distribution * dis, using stream s. dis must have a well-defined * density method; its other methods are unused. For a non-standard distribution * dis, the user may wish to set the left and the right boundaries * between which the density is non-zero by calling methods * {@link umontreal.iro.lecuyer.probdist.ContinuousDistribution#setXinf setXinf} * and * {@link umontreal.iro.lecuyer.probdist.ContinuousDistribution#setXsup setXsup} * of dis, for better efficiency. * Argument xc can be the mean, * the mode or any other x for which the density is relatively large. * The u-resolution eps is the desired absolute error in the CDF, * and order is the degree of the * Newton interpolating polynomial over each interval. * An order of 3 or 5, and an eps of 10-6 to 10-12 * are usually good choices. * Restrictions: * 3 <= order <= 12. * */ public InverseFromDensityGen (RandomStream s, ContinuousDistribution dis, double xc, double eps, int order) { super (s, null); dist = new InverseDistFromDensity (dis, xc, eps, order); } /** * Creates a new generator from the continuous probability density * dens. The left and the right boundaries of the density are * xleft and xright (the density is 0 outside the * interval [xleft, xright]). * See the description of the other constructor. * */ public InverseFromDensityGen (RandomStream s, MathFunction dens, double xc, double eps, int order, double xleft, double xright) { super (s, null); dist = new InverseDistFromDensity (dens, xc, eps, order, xleft, xright); } /** * Generates a new random variate. * */ public double nextDouble() { return dist.inverseF (stream.nextDouble()); } /** * Returns the xc given in the constructor. * */ public double getXc() { return ((InverseDistFromDensity)dist).getXc(); } /** * Returns the u-resolution eps associated with this object. * */ public double getEpsilon() { return ((InverseDistFromDensity)dist).getEpsilon(); } /** * Returns the order associated with this object. * * */ public int getOrder() { return ((InverseDistFromDensity)dist).getOrder(); } }

Ads help maintain this website.