invrandstrm

# invrandstrm.py
# ------------------------------------------------------------------------------

 
Classes
       
abcrand.ABCRand()
InverseRandomStream

 
class InverseRandomStream(abcrand.ABCRand)
    GENERAL CLASS FOR INITIATING RANDOM NUMBER STREAMS AND CREATING RANDOM 
VARIATES FROM DIFFERENT PROBABILITY DISTRIBUTIONS 
 
NB. All methods return a single random number on each call. 
 
The class inherits the methods explicitly available from the abstract base 
class ABCRand. The methods of Python's built-in Random class inherited via 
ABCRand can not be guaranteed to be inverse-based. They are killed off 
here and NOT available in InverseRandomStream! Please consult the docstrings
of the methods of the ABCRand class for information on how to use the 
methods that ARE inherited.
 
The class is normally used like this:
    rstream = InverseRandomStream()
    meanx   = 2.5
    x       = rstream.rexpo(meanx)
    muy     = -1.5
    sigmay  = 3.0
    y       = rstream.rnormal(muy, sigmay)  # or whatever....
 
If another seed than the default seed is desired, then the class can be 
instantiated using rstream = InverseRandomStream(nseed) where nseed is 
an integer (preferably a large one).
 
A generating method of this class is in many cases much slower than the 
corresponding method provided by the GeneralRandomStream class. The Latin 
Hypercube and antithetic variance reduction methods provided by the 
RandomStructure class only work with the methods in InverseRandomStream
on the other hand. So speed is based on the generating methods as well as 
the possibility of using variance reduction. Tests should be made when 
speed is crucial.
 
InverseRandomStream makes it possible to use the RandomStructure class 
to enter rank correlations between random parameters regardless of 
distribution type, as well as correlated multinormal distributions.
 
It might be desirable at times to bound the output from a variate 
generator for practical or physical reasons, for instance (some output 
values might be unrealistic). A majority of the methods in this class 
allow that. The actual bounds can be given (xmin and xmax), or the 
corresponding cdf values of the unbound distribution can be specified 
(pmin and pmax), a faster alternative since the method will otherwise 
compute the corresponding cdf values every time the method is used. 
Prior cdf value bounds may be computed by calling the corresponding 
function in the statlib.cdf module.
BUT: 
prescribing limits alters the distribution so the outputs will not truly 
adhere to the theoretical one. The input parameters (mean, standard 
deviation etc) are, anyhow, for the corresponding full-span theoretical 
distribution! 
 
NB The reason for using a generator not based on inversion is that a 
particular generator not using inversion is faster. Bounding the range 
of the output variate may alter this however, particularly for tight 
bounds, so "ten mucho cuidado!". AND prescribing limits alters the 
distribution so the outputs will not truly adhere to the theoretical 
one. The input parameters (mean, std dev etc) are, however, for the
corresponding full-span theoretical distribution! 
 
An externally generated input [0.0, 1.0] stream or "feed" can also be 
used instead of letting the object instance pick the random variates 
on its own. Cf. the docstrings of the ABCRand class for details!
 
NB. Some methods may return float('inf') or float('-inf') !
 
 
Method resolution order:
InverseRandomStream
abcrand.ABCRand

Methods defined here:
__init__(self, nseed=2147483647)
The seed 'nseed' must be a positive integer or a feed (a list or 
a tuple) of numbers in [0.0, 1.0]!
rNexpo(self, means, xmax=inf, pmax=1.0)
Generator of random variates from a distribution of the sum of 
exponentially distributed random variables. means[k] = 1.0/lambda[k].
NB Numbers in the means vector can be exactly equal! This generator 
is slow, however...
rNexpo2(self, means, xmax=inf, pmax=1.0)
Generator of random variates from a distribution of the sum of 
exponentially distributed random variables. means[k] = 1.0/lambda[k].
NB No two numbers in the means vector can be exactly equal! If this 
is desired, use rNexpo !
rbeta(self, a, b, x1, x2, betaab=False)
The beta distribution f = x**(a-1) * (1-x)**(b-1) / beta(a, b)
The cdf is the integral = the incomplete beta or the incomplete 
beta/complete beta depending on how the incomplete beta function 
is defined.
 
x, a, b >= 0; x2 > x1 
 
NB It is possible to provide the value of the complete beta 
function beta(a, b) as a pre-computed input (may be computed 
using numlib.specfunc.beta) instead of the default "False", a 
feature that will make rbeta 30 % faster!
rbootstrap(self, values)
Picks elements from the input sequence (list, tuple etc) at random 
(could be any sequence). The input sequence is sorted to assure 
inverse properties.
rconst(self, const)
Returns the input constant. Use it to keep up the synchronization 
even when a parameter has no spread (a dummy random number is sampled 
each time the method is called)!
rcoxian(self, means, probs, xmax=inf, pmax=1.0)
Generates a random number from the Coxian phased distribution, which is 
based on the exponential.
probs is a list of probabilities for GOING ON TO THE NEXT PHASE rather 
than reaching the absorbing state prematurely. The number of means must 
(of course) be one more than the number of probabilities!
 
NB means are allowed to be equal!
 
NB It is better to use rNexpo when all probs=1.0 !
rcoxian2(self, means, probs, xmax=inf, pmax=1.0)
Generates a random number from the Coxian phased distribution, which is 
based on the exponential.
probs is a list of probabilities for GOING ON TO THE NEXT PHASE rather 
than 
reaching the absorbing state prematurely. The number of means must (of 
course) be one more than the number of probabilities!
 
NB No two means must be equal - if this is desired, use rcoxian instead! 
 
NB It is better to use rNexpo2 when all probs=1.0 !
rdiscrete(self, values, qumul)
Generates random variates from a user-defined discrete cdf. 
 
'values' is a list/tuple with numbers, and 'qumul' are the corresponding 
CUMULATIVE FREQUENCIES such that qumul[k] = P(x<=values[k]). The number 
of values must be equal to the number of cumulative frequencies.
 
The cumulative frequencies must of course obey qumul[k+1] >= qumul[k],
otherwise an exception will be raised!
 
The 'values' sequence is sorted to assure inverse properties.
rerlang(self, nshape, phasemean, xmax=inf, pmax=1.0)
Generator of Erlang-distributed random variates.
Represents the sum of nshape exponentially distributed random variables, 
each having the same mean value = phasemean. For nshape = 1 it works as 
a generator of exponentially distributed random numbers.
rerlang_gen(self, nshapes, qumul, phasemean, xmax=inf, pmax=1.0)
The generalized Erlang distribution - the Erlang equivalent of the 
rhyperexpo generator 
f = sumk pk * ferlang(m, nk), F = sumk pk * Ferlang(m, nk), the same
mean for all phases.
 
NB Input to the function is the list of CUMULATIVE FREQUENCIES !
rexpo(self, mean, xmax=inf, pmax=1.0)
Generator of exponentially distributed random variates with 
mean = 1.0/lambda
F = 1 - exp(-x/mean) 
mean >= 0.0
rexppower(self, loc, scale, alpha, lngam1oalpha=False, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0, tolf=8.8817841970012523e-16, itmax=128)
The exponential power distribution 
f  =  (a/s) * exp(-abs([x-l]/s)**a) / [2*gamma(1/a)]
F  =  1/2 * [1 + sgn(x-l) * Fgamma(1/a, abs([x-l]/s)**a)],  x in R
s, a > 0
where Fgamma is the gamma distribution cdf.
 
NB It is possible to gain efficiency by providing the value of the 
natural logarithm of the complete gamma function ln(gamma(1.0/alpha)) 
as a pre-computed input (may be computed using numlib.specfunc.lngamma) 
instead of the default 'False'.
 
tolf and itmax are the numerical control parameters of iexppower 
and cexppower.
rfoldednormal(self, muunfold, sigmaunfold, xmax=inf, pmax=1.0)
The distribution of a random variable that is the absolute value
of a variate drawn from the normal distribution (i. e. the distribution 
of a variate that is the absolute value of a normal variate, the latter 
having muunfold as its mean and sigmaunfold as its standard deviation). 
 
sigmaunfold >= 0.0
rgamma(self, alpha, lam, lngamalpha=False, xmax=inf, pmax=1.0, tolf=8.8817841970012523e-16, itmax=128)
The gamma distribution
f = lam * exp(-lam*x) * (lam*x)**(alpha-1) / gamma(alpha)
The cdf is the integral = the incomplete gamma ratio.
x, lam, alpha >= 0 
 
NB It is possible to provide the value of the natural logarithm of the 
complete gamma function lngamma(alpha) as a pre-computed input (may be 
computed using numlib.specfunc.lngamma) instead of the default "False", 
a feature that will make rgamma 50 % faster! 
 
tolf and itmax are the numerical control parameters of igamma 
and cgamma.
rhyperexpo(self, means, qumul, xmax=inf, pmax=1.0)
Generates a random number from the hyperexponential distribution 
f = sumk pk * exp(x/mk) / mk, F = sumk pk * (1-exp(x/mk)) 
NB Input to the function is the list of CUMULATIVE FREQUENCIES !
rlevy(self, scale, xmax=inf, pmax=1.0)
The Levy distribution: f = sqrt(s/2pi) * (1/x)**(3/2) * exp(-s/2x)
                       F = erfc(sqrt(s/2x)); x >= 0
(stable distribution with alpha = 1/2, and beta = 1, aka the Cournot 
distribution or the right-skewed Levy).
rlognormal(self, mulg, sigmalg, xmax=inf, pmax=1.0)
Generator of lognormally distributed random variates, inverse variant.
The log10-converted form is assumed for mulg and sigmalg: 
mulg is the mean of the log10 (and the log10 of the median) of 
the random variate, NOT the log10 of the mean of the non-logged 
variate!, and sigmalg is the standard deviation of the log10 of 
the random variate, NOT the log10 of the standard deviation of 
the non-logged variate!!
 
sigmalg > 0.0
rnormal(self, mu, sigma, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
Generator of normally distributed random variates using an inverse 
method, claimed to give a maximum relative error less than 2.6e-9 
(cf. statlib.invcdf.inormal for details).
rpareto(self, lam, xm, xmax=inf, pmax=1.0)
The Pareto distribution:
f = lam * xm**lam / x**(lam+1)
F = 1 - (xm/x)**lam 
x >= xm,  lam > 0 
For lam < 1 all moments are infinite
For lam < 2 all moments are infinite except for the mean
rpoisson(self, lam, tspan, nmax=False, pmax=1.0)
The Poisson distribution: p(N=n) = exp(-lam*tspan) * (lam*tspan)**n / n!
n = 0, 1, ...., infinity
 
A maximum number for the output may be given in nmax - then it must be 
a positive integer.
rstable_sym(self, alpha, location, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
The SYMMETRICAL stable distribution where alpha is the tail exponent. 
For numerical reasons alpha is restricted to [0.25, 0.9] and 
[1.125, 1.9] - but alpha = 1.0 (the Cauchy) and alpha = 2.0 (scaled 
normal) are also allowed!
 
Numerics are somewhat crude but the fractional error is mostly < 0.001 -
sometimes much less - and the absolute error is almost always < 0.001 - 
sometimes much less... 
 
NB This generator is slow - particularly for small alpha  !!!!!
ruser_defined(self, ifunc, *args, pmin=0.0, pmax=1.0)
Random deviate generation based on a user-defined inverse cdf placed in 
a function ('ifunc') with arguments p in [0.0, 1.0] and sequence *args.
 
NB 1  *args is optional in that it is OK for ifunc to have no arguments.
 
NB 2  THE VALUES OF pmin AND pmax MUST - AND CAN ONLY - BE PASSED 
BY KEYWORD: pmin=??, pmax=?? MUST ALWAYS BE WRITTEN OUT EXPLICITLY 
UNLESS DEFAULTS ARE USED ('pmin' may be entered without explicit 
keywording of pmax if the default is accepted for pmax).
rweibull(self, c, scale, xmax=inf, pmax=1.0)
Generator of random variates from the Weibull distribution.
F = 1 - exp[-(x/s)**c]
s >= 0.0, c >= 1.0
For c = 1.0 it is equivalent to a generator of exponential variates 
with mean = scale
rwiener(self, tau, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
Generates random numbers corrsponding to a Wiener process (the 
intergral of white noise (Langevin's function)), inverse variant. 
The Wiener process is W(t+tau) - W (t) = N(0, sqrt(tau)) 
where tau is the time increment and N(0, sqrt(tau)) is a  
normally distributed random variable having zero mean and 
sqrt(tau) as its standard deviation.
 
This method returns W(t+tau) - W(t) given tau and allows 
tau to be negative.

Data and other attributes defined here:
__abstractmethods__ = frozenset([])

Methods inherited from abcrand.ABCRand:
rcauchy(self, location, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
Generator of random variates from the Cauchy distribution: 
f = 1 / [s*pi*(1 + [(x-l)/s]**2)]
F = (1/pi)*arctan((x-l)/s) + 1/2
(also known as the Lorentzian or Lorentz distribution)
 
scale must be >= 0
rchistogram(self, values, qumul)
Generates random variates from an input CUMULATIVE histogram.
'values' is a list/tuple with FLOATS in ascending order - A MUST! 
These values represent bin end points and must be one more than 
the number of cumulative frequencies, and where...
...'qumul' are the corresponding CUMULATIVE FREQUENCIES such that 
qumul[k] = P(x<=values[k+1]).
 
The cumulative frequencies must of course obey qumul[k+1] >= qumul[k],
otherwise an exception will be raised!
 
The values of the random variate are assumed to be uniformly 
distributed within each bin.
rchistogram_int(self, values, qumul)
Generates random variates from an input CUMULATIVE histogram.
'values' is a list/tuple with INTEGERS in ascending order - A MUST! 
These values represent bin end points and must be one more than 
the number of cumulative frequencies, and where...
...'qumul' are the corresponding CUMULATIVE FREQUENCIES such that 
qumul[k] = P(x<=values[k+1]).
 
NB The first element of the values list is will never be returned!
The first integer to be returned is values[0] + 1   !!!!
 
The cumulative frequencies must of course obey qumul[k+1] >= qumul[k],
otherwise an exception will be raised!
 
The integer values of the random variate are assumed to be uniformly 
distributed within each bin.
remp_exp(self, values, npexp=0, ordered=False, xmax=inf, pmax=1.0)
The mixed expirical/exponential distribution from Bratley, Fox and 
Schrage. A polygon (piecewise linearly interpolated cdf) is used 
together with a (shifted) exponential for the tail. The procedure 
is designed so as to preserve the mean of the input sample.
 
The input is a set of observed points (vector) and an integer 
representing the npexp largest points that will be used to formulate 
the exponential tail.
 
NB it is assumed that x is in [0, inf) (with the usual cutoff 
provisions)  !!!!!
 
The function may also be used for a piecewise linear cdf without the 
exponential tail - corrections are made to preserve the mean in this 
case as well !!!
rexpo_gen(self, a, b, c, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
The generalized continuous double-sided exponential 
distribution (x in R):
x <= c: f  =  [a*b/(a+b)] * exp(+a*[x-c])
        F  =   [b/(a+b)]  * exp(+a*[x-c])
x >= c: f  =  [a*b/(a+b)] * exp(-b*[x-c])
        F  =  1 - [a/(a+b)]*exp(-b*[x-c])
a > 0, b > 0
 
NB The symmetrical double-sided exponential sits in rlaplace!
rextreme_I(self, type, mu, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
Extreme value distribution type I (aka the Gumbel distribution or 
Gumbel distribution type I):
F = exp{-exp[-(x-mu)/scale]}       (max variant)
f = exp[-(x-mu)/scale] * exp{-exp[-(x-mu)/scale]} / scale
F = 1 - exp{-exp[+(x-mu)/scale]}   (min variant)
f = exp[+(x-mu)/scale] * exp{-exp[+(x-mu)/scale]} / scale
 
type must be 'max' or 'min'
scale must be > 0.0
rextreme_gen(self, type, shape, mu, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
Generalized extreme value distribution:
F = exp{-[1-shape*(x-mu)/scale]**(1/shape)}       (max version)
f = [1-shape*(x-mu)/scale]**(1/shape-1) * 
                         exp{-[1-shape*(x-mu)/scale]**(1/shape)} / scale
F = 1 - exp{-[1+shape*(x-mu)/scale]**(1/shape)}   (min version)
f = [1+shape*(x-mu)/scale]**(1/shape-1) * 
                         exp{-[1+shape*(x-mu)/scale]**(1/shape)} / scale
shape  < 0 => Type II
shape  > 0 => Type III
shape -> 0 => Type I - Gumbel
 
type must be 'max' or 'min'
scale must be > 0.0
 
A REASONABLE SCHEME SEEMS TO BE mu = scale WHICH SEEMS TO LIMIT THE
DISTRIBUTION TO EITHER SIDE OF THE Y-AXIS!
rgeometric(self, phi)
The geometric distribution with p(K=k) = phi * (1-phi)**(k-1)  and 
P(K>=k) = sum phi * (1-phi)**k = 1 - q**k, where q = 1 - phi and  
0 < phi <= 1 is the success frequency or "Bernoulli probability" 
and K >= 1 is the number of  trials to the first success in a series 
of Bernoulli trials. It is easy to prove that P(k) = 1 - (1-phi)**k: 
let q = 1 - phi. p(k) = (1-q) * q**(k-1) = q**(k-1) - q**k. Then P(1) = 
p(1) = 1 - q. P(2) = p(1) + p(2) = 1 - q + q - q**2 = 1 - q**2. 
Induction can be used to show that P(k) = 1 - q**k = 1 - (1-phi)**k
rkodlin(self, gam, eta, xmax=inf, pmax=1.0)
The Kodlin distribution, aka the linear hazard rate distribution:
f = (gam + eta*x) * exp{-[gam*x + (1/2)*eta*x**2]},
F = 1 - exp{-[gam*x + (1/2)*eta*x**2]};  x, gam, eta >= 0
rkumaraswamy(self, a, b, x1, x2)
The Kumaraswamy distribution f = a*b*x**(a-1) * (1-x**a)**(b-1)
                             F = 1 - (1-x**a)**b
                             a, b >= 0; 0 <= x <= 1
The Kumaraswamy is very similar to the beta distribution !!!
 
x2 >= x1 !!!!
rlaplace(self, loc, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
The Laplace aka the symmetrical double-sided exponential distribution 
f = ((1/2)/s)) * exp(-abs([x-l]/s))
F = (1/2)*exp([x-l]/s)  {x <= 0},  F = 1 - (1/2)*exp(-[x-l]/s)  {x >= 0}
s >= 0
rlogistic(self, mu, scale, xmin=-inf, xmax=inf, pmin=0.0, pmax=1.0)
The logistic distribution: F = 1 / {1 + exp[-(x-m)/s]}; x on R
m is the mean and mode, and s is a scale parameter (s >= 0)
rpareto_zero(self, lam, xm, xmax=inf, pmax=1.0)
The Pareto distribution with the support shifted to [0, inf):
f = lam * xm**lam / (x+xm)**(lam+1)
F = 1 - [xm/(x+xm)]**lam
x in [0, inf)
lam > 0
For lam < 1 all moments are infinite
For lam < 2 all moments are infinite except for the mean
rrayleigh(self, sigma, xmax=inf, pmax=1.0)
The Rayleigh distribution:
f = (x/s**2) * exp[-x**2/(2*s**2)]
F = 1 - exp[-x**2/(2*s**2)]
x, s >= 0
rsign(self)
Returns -1.0 or 1.0 with probability 0.5 for each.
rsinus(self, left, right)
The "sinus distribution".
rtri_unif_tri(self, a, b, c, d)
Triangular-uniform-triangular distribution with support on [a, d] and 
with breakpoints in b and c.
rtriang(self, left, mode, right)
Generator of triangularly distributed random numbers on [left, right] 
with the peak of the pdf at mode.
rtukeylambda_gen(self, lam1, lam2, lam3, lam4, pmin=0.0, pmax=1.0)
The Friemer-Mudholkar-Kollia-Lin generalized Tukey lambda distribution.
lam1 is a location parameter and lam2 a scale parameter. lam3 and lam4
are associated with the shape of the distribution.
runif_int0N(self, number)
Generator of uniformly distributed integers in [0, n) (also the basis 
of some other procedures for generating random variates). 
Numbers returned are 0 through n-1.
runifab(self, left, right)
Generator of uniformly distributed floats between 'left' and 'right'.

Data descriptors inherited from abcrand.ABCRand:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Data
        FOURMACHEPS = 8.8817841970012523e-16
MAXFLOAT = 1.7976931348623157e+308