Ejemplo n.º 1
0
    def rbinomial(self, n, phi):
        """
        The binomial distribution: p(N=k) = bincoeff * phi**k * (1-phi)**(n-k); 
        n >= 1;  k = 0, 1,...., n  where phi is the frequency or "Bernoulli 
        probability".
        
        Algorithm taken from ORNL-RSIC-38, Vol II (1973). 
        """

        assert is_posinteger(n), \
                          "n must be a positive integer in rbinomial!"
        assert 0.0 < phi and phi < 1.0, \
                   "frequency parameter is out of range in rbinomial!"

        normconst = 10.0
        onemphi = 1.0 - phi
        if phi < 0.5: w = int(round(normconst * onemphi / phi))
        else: w = int(round(normconst * phi / onemphi))

        if n > w:
            #-------------------------------------------------------
            k = int(round(self.rnormal(n * phi, sqrt(n * phi * onemphi))))

        else:
            #-------------------------------------------------------
            if phi < 0.25:
                k = -1
                m = 0
                phi = -safelog(onemphi)
                while m < n:
                    r = self.rexpo(1.0)
                    j = 1 + int(r / phi)
                    m += j
                    k += 1
                if m == n:
                    k += 1

            elif phi > 0.75:
                k = n + 1
                m = 0
                phi = -safelog(phi)
                while m < n:
                    r = self.rexpo(1.0)
                    j = 1 + int(r / phi)
                    m += j
                    k -= 1
                if m == n:
                    k -= 1

            else:  # if 0.25 <= phi and phi <= 0.75:
                k = 0
                m = 0
                while m < n:
                    r = self.runif01()
                    if r < phi: k += 1
                    m += 1

        k = kept_within(0, k, n)

        return k
Ejemplo n.º 2
0
    def 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. 
        """

        assert lam2 > 0.0, \
          "shape parameter lam2 must be a positive float in rtukeylambda_gen!"
        assert 0.0 <= pmin < pmax, \
                             "pmin must be in [0.0, pmax) in rtukeylambda_gen!"
        assert pmin < pmax <= 1.0, \
                             "pmax must be in (pmin, 1.0] in rtukeylambda_gen!"        

        p  =  pmin + (pmax-pmin)*self.runif01()

        if lam3 == 0.0:
            q3 = safelog(p)
        else:
            q3 = (p**lam3-1.0) / lam3

        if lam4 == 0.0:
            q4 = safelog(1.0-p)
        else:
            q4 = ((1.0-p)**lam4 - 1.0) / lam4

        x  =  lam1 + (q3-q4)/lam2

        return x
Ejemplo n.º 3
0
def itukeylambda_gen(prob, lam1, lam2, lam3, lam4):
    """
    The Friemer-Mudholkar-Kollia-Lin generalized Tukey-Lambda distribution.
    lam1 is a location parameter and lam2 is a scale parameter. lam3 and lam4
    are associated with the shape. lam2 must be a positive number. 
    """

    _assertprob(prob, 'itukeylambda_gen')
    # ---
    assert lam2 > 0.0, \
          "shape parameter lam2 must be a positive float in itukeylambda_gen!"

    if lam3 == 0.0:
        q3 = safelog(prob)

    else:
        q3 = (prob**lam3-1.0) / lam3

    if lam4 == 0.0:
        q4 = safelog(1.0-prob)

    else:
        q4 = ((1.0-prob)**lam4 - 1.0) / lam4

    x  =  lam1 + (q3-q4)/lam2

    return x
Ejemplo n.º 4
0
    def rbinomial(self, n, phi):
        """
        The binomial distribution: p(N=k) = bincoeff * phi**k * (1-phi)**(n-k); 
        n >= 1;  k = 0, 1,...., n  where phi is the frequency or "Bernoulli 
        probability".
        
        Algorithm taken from ORNL-RSIC-38, Vol II (1973). 
        """

        assert is_posinteger(n), \
                          "n must be a positive integer in rbinomial!"
        assert 0.0 < phi and phi < 1.0, \
                   "frequency parameter is out of range in rbinomial!"

        normconst = 10.0
        onemphi   = 1.0 - phi
        if phi < 0.5: w = int(round(normconst * onemphi / phi))
        else:         w = int(round(normconst * phi / onemphi))

        if n > w:
            #-------------------------------------------------------
            k = int(round(self.rnormal(n*phi, sqrt(n*phi*onemphi))))

        else:
            #-------------------------------------------------------
            if phi < 0.25:
                k   = -1
                m   =  0
                phi = - safelog(onemphi)
                while m < n:
                    r  = self.rexpo(1.0)
                    j  = 1 + int(r/phi)
                    m += j
                    k += 1
                if m == n:
                    k += 1

            elif phi > 0.75:
                k   =  n + 1
                m   =  0
                phi = - safelog(phi)
                while m < n:
                    r  = self.rexpo(1.0)
                    j  = 1 + int(r/phi)
                    m += j
                    k -= 1
                if m == n:
                    k -= 1

            else: # if 0.25 <= phi and phi <= 0.75:
                k = 0
                m = 0
                while m < n:
                    r  = self.runif01()
                    if r < phi: k += 1
                    m += 1

        k = kept_within(0, k, n)

        return k
Ejemplo n.º 5
0
def iextreme_I(prob, type='max', mu=0.0, scale=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
    """

    _assertprob(prob, 'iextreme_I')
    assert scale >= 0.0, "scale parameter must not be negative in iextreme_I!"

    if    type == 'max':
        x = - scale*safelog(-safelog(prob)) + mu

    elif  type == 'min':
        x =   scale*safelog(-safelog(1.0-prob)) + mu

    else:
        raise Error("iextreme_I: type must be either 'max' or 'min'")

    return x
Ejemplo n.º 6
0
    def 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. 
        """

        assert lam2 > 0.0, \
          "shape parameter lam2 must be a positive float in rtukeylambda_gen!"
        assert 0.0 <= pmin < pmax, \
                             "pmin must be in [0.0, pmax) in rtukeylambda_gen!"
        assert pmin < pmax <= 1.0, \
                             "pmax must be in (pmin, 1.0] in rtukeylambda_gen!"

        p = pmin + (pmax - pmin) * self.runif01()

        if lam3 == 0.0:
            q3 = safelog(p)
        else:
            q3 = (p**lam3 - 1.0) / lam3

        if lam4 == 0.0:
            q4 = safelog(1.0 - p)
        else:
            q4 = ((1.0 - p)**lam4 - 1.0) / lam4

        x = lam1 + (q3 - q4) / lam2

        return x
Ejemplo n.º 7
0
def ikodlin(prob, gam, eta):
    """
    The inverse of 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
    """

    _assertprob(prob, 'ikodlin')
    assert gam >= 0.0, "no parameters in ikodlin must be negative!"
    assert eta >= 0.0, "no parameters in ikodlin must be negative!"

    # (1/2)*eta*x**2 + gam*x + ln(1-F) = 0

    try:
        a  = 0.5*eta
        b  = gam
        c  = safelog(1.0-prob)
        x1, x2 = z2nddeg_real(a, b, c)
        x  = max(x1, x2)

    except ValueError:
        x  =  float('inf')


    x  =  kept_within(0.0, x)

    return x
Ejemplo n.º 8
0
    def rerlang(self, nshape, phasemean, xmax=float('inf')):
        """
        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.
        """

        assert is_posinteger(nshape), \
                       "shape parameter must be a positive integer in rerlang!"
        assert phasemean >= 0.0, "phasemean must not be negative in rerlang!"
        assert xmax >= 0.0, "variate max must be non-negative in rerlang!"

        if nshape < GeneralRandomStream.__ERLANG2GAMMA:
            while True:
                x = 1.0
                for k in range(0, nshape):
                    x *= self.runif01()  # Might turn out to be zero...
                x = -phasemean * safelog(x)
                if x <= xmax: break

        else:  # Gamma is OK
            while True:
                x = phasemean * self.rgamma(float(nshape), 1.0)
                if x <= xmax: break

        x = kept_within(0.0, x)

        return x
Ejemplo n.º 9
0
    def rinhomexpo_cum(self, lamt, suplamt):
        """
        Generates - cumulatively - inhomogeneously exponentially distributed 
        interarrival times (due to an inhomogeneous Poisson process) from 
        clock time = 0.0 (the algorithm is taken from Bratley, Fox & Schrage).

        'lamt' is an externally defined function of clock time that returns 
        the present arrival rate (arrival frequency). 'suplamt' is another 
        externally defined function that returns the supremum of the arrival 
        rate over the REMAINING time from the present clock time.

        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        errtxt1  = "All values from suplamt must be "
        errtxt1 += "non-negative floats in rinhomexpo_cum!"
        errtxt2  = "All values from lamt must be "
        errtxt2 += "non-negative floats in rinhomexpo_cum!"

        ticum = self.__ticum

        while True:
            lamsup =  suplamt(ticum)
            assert lamsup >= 0.0, errortxt1
            u      =  self.runif01()
            ticum -=  safediv(1.0, lamsup) * safelog(self.runif01())
            lam    =  lamt(ticum)
            assert lam >= 0.0, errortxt2
            if u*lamsup <= lam:
                break

        self.__ticum = ticum
        return ticum
Ejemplo n.º 10
0
    def rinhomexpo_cum(self, lamt, suplamt):
        """
        Generates - cumulatively - inhomogeneously exponentially distributed 
        interarrival times (due to an inhomogeneous Poisson process) from 
        clock time = 0.0 (the algorithm is taken from Bratley, Fox & Schrage).

        'lamt' is an externally defined function of clock time that returns 
        the present arrival rate (arrival frequency). 'suplamt' is another 
        externally defined function that returns the supremum of the arrival 
        rate over the REMAINING time from the present clock time.

        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        errtxt1 = "All values from suplamt must be "
        errtxt1 += "non-negative floats in rinhomexpo_cum!"
        errtxt2 = "All values from lamt must be "
        errtxt2 += "non-negative floats in rinhomexpo_cum!"

        ticum = self.__ticum

        while True:
            lamsup = suplamt(ticum)
            assert lamsup >= 0.0, errortxt1
            u = self.runif01()
            ticum -= safediv(1.0, lamsup) * safelog(self.runif01())
            lam = lamt(ticum)
            assert lam >= 0.0, errortxt2
            if u * lamsup <= lam:
                break

        self.__ticum = ticum
        return ticum
Ejemplo n.º 11
0
    def rerlang(self, nshape, phasemean, xmax=float('inf')):
        """
        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.
        """

        assert is_posinteger(nshape), \
                       "shape parameter must be a positive integer in rerlang!"
        assert phasemean >= 0.0,   "phasemean must not be negative in rerlang!"
        assert xmax >= 0.0,      "variate max must be non-negative in rerlang!"


        if nshape < GeneralRandomStream.__ERLANG2GAMMA:
            while True:
                x  =  1.0
                for k in range(0, nshape):
                    x *= self.runif01() # Might turn out to be zero...
                x  = - phasemean * safelog(x)
                if x <= xmax: break

        else:   # Gamma is OK
            while True:
                x  =  phasemean * self.rgamma(float(nshape), 1.0)
                if x <= xmax: break

        x  =  kept_within(0.0, x)

        return x
Ejemplo n.º 12
0
def ilaplace(prob, loc=0.0, scale=1.0):
    """
    The inverse of the Laplace distribution f = [(1/2)/s)]*exp(-abs([x-l]/s))
    F = (1/2)*exp([x-l]/s)  {x <= l},  F = 1 - (1/2)*exp(-[x-l]/s)  {x >= l}
    s >= 0
    """

    _assertprob(prob, 'ilaplace')
    # ---
    assert scale >= 0.0, "scale parameter in ilaplace must not be negative!"

    if prob <= 0.5:
        x =  safelog(2.0*prob)
        x =  scale*x + loc
    else:
        x = - safelog(2.0*(1.0-prob))
        x =  scale*x + loc

    return x
Ejemplo n.º 13
0
def igeometric(prob, 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 
    
    The algorithm is taken from ORNL-RSIC-38, Vol II (1973). 
    """

    _assertprob(prob, 'igeometric')
    assert 0.0 <= phi and phi <= 1.0, \
                      "success frequency must be in [0.0, 1.0] in igeometric!"


    if phi == 1.0: return 1   # Obvious...

    q  =  1.0 - phi

    if phi < 0.25:            # Use the direct inversion formula
        lnq   = - safelog(q)
        ln1mp = - safelog(1.0 - prob)
        kg    =  1 + int(ln1mp/lnq)

    else:             # Looking for the passing point is more efficient for 
        kg = 1        # phi >= 0.25 (it's still inversion)
        u  = prob
        a  = phi
        while True:
            u = u - a
            if u > 0.0:
                kg += 1
                a  *= q
            else:
                break

    return kg
Ejemplo n.º 14
0
def irayleigh(prob, sigma=1.0):
    """
    The inverse of the Rayleigh distribution:
    f = (x/s**2) * exp[-x**2/(2*s**2)]
    F = 1 - exp[-x**2/(2*s**2)]
    x, s >= 0
    """

    _assertprob(prob, 'irayleigh')
    assert sigma >= 0.0, "parameter in irayleigh must not be negative!"

    return sigma * sqrt(2.0*(-safelog(1.0-prob)))  # Will always be >= 0.0
Ejemplo n.º 15
0
def iextreme_gen(prob, type, shape, mu=0.0, scale=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!
    """

    if shape == 0.0:
        x = iextreme_I(prob, type, mu, scale)

    else:
        _assertprob(prob, 'iextreme_gen')
        assert scale >= 0.0

        if   type == 'max':
            x = scale*(1.0-(-safelog(prob))**shape)/shape + mu

        elif type == 'min':
            x = scale*((-safelog(1.0-prob))**shape-1.0)/shape + mu

        else:
            raise Error("iextreme_gen: type must be either 'max' or 'min'")

    return x
Ejemplo n.º 16
0
def ilogistic(prob, mu=0.0, scale=1.0):
    """
    The inverse of the logistic distribution:
    f = exp[-(x-m)/s] / (s*{1 + exp[-(x-m)/s]}**2)
    F = 1 / {1 + exp[-(x-m)/s]}
    x in R
    m is the mean and mode, s is a scale parameter (s >= 0)
    """

    _assertprob(prob, 'ilogistic')
    assert scale >= 0.0, "scale parameter in ilogistic must not be negative!"

    x  =  mu - scale*safelog(safediv(1.0, prob) - 1.0)

    return x
Ejemplo n.º 17
0
def iexpo_gen(prob, a, b, c=0.0):
    """
    The generalized continuous 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 ilaplace!
    """

    _assertprob(prob, 'iexpo_gen')
    assert a > 0.0
    assert b > 0.0

    r = prob*(a+b)/b

    if r <= 1.0:
        x  =  c  +  safelog(r) / a
    else:
        x  =  c  -  safelog((a+b)*(1.0-prob)/a) / b

    return x
Ejemplo n.º 18
0
    def rpiecexpo_cum(self, times, lamt):
        """
        Generates - cumulatively - piecewise exponentially distributed 
        interarrival times from clock time = 0.0 (the algorithm is taken 
        from Bratley, Fox & Schrage).
        
        'times' is a list or tuple containing the points at which the arrival 
        rate (= arrival frequency) changes (the first break time point must 
        be 0.0). 'lamt' is a list or tuple containing the arrival rates between 
        break points. The number of elements in 'times' must be one more than 
        the number of elements in 'lamt'!

        The algorithm cranking out the numbers is cyclic - the procedure 
        starts over from time zero when the last break point is reached. 
        THE PREVENT THE RESTART FROM TAKING PLACE, A (VERY) LARGE NUMBER 
        MUST BE GIVEN AS THE LAST BREAK POINT (the cyclicity is rarely 
        needed or desired in practice).
        
        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES 
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        ntimes = len(times)
        errtxt1 = "No. of arrival rates and no. of break points "
        errtxt2 = "are incompatible in rpiecexpo_cum!"
        errtext = errtxt1 + errtxt2
        assert len(lamt) == ntimes - 1, errtext

        r = ntimes * [0.0]
        for k in range(1, ntimes):
            assert lamt[k-1] >= 0.0, \
                     "All lamt must be non-negative floats in rpiecexpo_cum!"
            r[k] = r[k - 1] + lamt[k - 1] * (times[k] - times[k - 1])

        cumul = self.__cumul
        cumul -= safelog(self.runif01())

        iseg = 0
        while r[iseg + 1] <= cumul:
            iseg = iseg + 1
        tcum = times[iseg] + safediv(cumul - r[iseg], lamt[iseg])

        tcum = kept_within(0.0, tcum)

        self.__cumul = cumul  # NB  THIS IS NOT CUMULATIVE TIME!
        return tcum
Ejemplo n.º 19
0
    def rexpo_cum(self, lam):
        """
        Generates - cumulatively - exponentially distributed interarrival times 
        with arrival rate (arrivale frequency) 'lam' from clock time = 0.0.

        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES 
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        assert lam >= 0.0, \
                    "Arrival rate must be a non-negative float in rexpo_cum!"

        tcum  =  self.__tcum
        tcum -=  safediv(1.0, lam) * safelog(self.runif01())

        self.__tcum = tcum
        return tcum
Ejemplo n.º 20
0
    def rpiecexpo_cum(self, times, lamt):
        """
        Generates - cumulatively - piecewise exponentially distributed 
        interarrival times from clock time = 0.0 (the algorithm is taken 
        from Bratley, Fox & Schrage).
        
        'times' is a list or tuple containing the points at which the arrival 
        rate (= arrival frequency) changes (the first break time point must 
        be 0.0). 'lamt' is a list or tuple containing the arrival rates between 
        break points. The number of elements in 'times' must be one more than 
        the number of elements in 'lamt'!

        The algorithm cranking out the numbers is cyclic - the procedure 
        starts over from time zero when the last break point is reached. 
        THE PREVENT THE RESTART FROM TAKING PLACE, A (VERY) LARGE NUMBER 
        MUST BE GIVEN AS THE LAST BREAK POINT (the cyclicity is rarely 
        needed or desired in practice).
        
        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES 
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        ntimes  = len(times)
        errtxt1 = "No. of arrival rates and no. of break points "
        errtxt2 = "are incompatible in rpiecexpo_cum!"
        errtext = errtxt1 + errtxt2
        assert len(lamt) == ntimes-1, errtext

        r = ntimes*[0.0]
        for k in range(1, ntimes):
            assert lamt[k-1] >= 0.0, \
                     "All lamt must be non-negative floats in rpiecexpo_cum!"
            r[k]  =  r[k-1]  +  lamt[k-1] * (times[k]-times[k-1])

        cumul  = self.__cumul
        cumul -= safelog(self.runif01())
        
        iseg  = 0
        while r[iseg+1] <= cumul:
            iseg = iseg + 1
        tcum  =  times[iseg] + safediv(cumul-r[iseg], lamt[iseg])

        tcum  =  kept_within(0.0, tcum)

        self.__cumul = cumul   # NB  THIS IS NOT CUMULATIVE TIME!
        return tcum
Ejemplo n.º 21
0
    def rexpo(self, mean, xmax=float('inf')):
        """
        Generator of exponentially distributed random variates with 
        mean = 1.0/lambda:
        f = (1/mean) * exp(-x/mean)
        F = 1 - exp(-x/mean).
        mean >= 0.0
        """

        assert mean >= 0.0, "mean must be a non-negative float in rexpo!"
        assert xmax >= 0.0, "variate max must be a non-negative float in rexpo!"

        while True:
            x = - mean * safelog(self.runif01())
            if x <= xmax: break

        return x
Ejemplo n.º 22
0
    def rexpo_cum(self, lam):
        """
        Generates - cumulatively - exponentially distributed interarrival times 
        with arrival rate (arrivale frequency) 'lam' from clock time = 0.0.

        NB. A SEPARATE STREAM MUST BE INSTANTIATED FOR EACH ONE OF THE VARIATES 
        THAT ARE GENERATED USING THIS METHOD, EACH WITH A SEPARATE SEED!! 
        """

        assert lam >= 0.0, \
                    "Arrival rate must be a non-negative float in rexpo_cum!"

        tcum = self.__tcum
        tcum -= safediv(1.0, lam) * safelog(self.runif01())

        self.__tcum = tcum
        return tcum
Ejemplo n.º 23
0
    def rexpo(self, mean, xmax=float('inf')):
        """
        Generator of exponentially distributed random variates with 
        mean = 1.0/lambda:
        f = (1/mean) * exp(-x/mean)
        F = 1 - exp(-x/mean).
        mean >= 0.0
        """

        assert mean >= 0.0, "mean must be a non-negative float in rexpo!"
        assert xmax >= 0.0, "variate max must be a non-negative float in rexpo!"

        while True:
            x = -mean * safelog(self.runif01())
            if x <= xmax: break

        return x
Ejemplo n.º 24
0
def iexpo(prob, mean=1.0):
    """
    The inverse of the exponential distribution with mean = 1/lambda: 
    f = (1/mean) * exp(-x/mean)
    F = 1 - exp(-x/mean)
    
    x >= 0, mean >= 0.0 
    """

    _assertprob(prob, 'iexpo')
    # ---
    assert mean >= 0.0, "mean of variate in iexpo must be a non-negative float!"

    x  =  - mean * safelog(1.0-prob)

    #x  =  kept_within(0.0, x)   # Not really needed

    return x
Ejemplo n.º 25
0
def iweibull(prob, c, scale=1.0):
    """
    The inverse of the Weibull distribution:
    F = 1 - exp[-(x/s)**c]
    x >= 0, s >= 0, c >= 1 
    """

    if c == 1.0:
        x = iexpo(prob, scale)

    else:
        _assertprob(prob, 'iweibull')
        # ---
        assert   c   >= 1.0, \
                   "shape parameter in iweibull must not be smaller than 1.0!"
        assert scale >= 0.0, "scale parameter in iweibull must not be negative!"

        x  =  scale * safepow(-safelog(1.0-prob), 1.0/c)

        #x  =  kept_within(0.0, x)  # Not really needed

    return x
Ejemplo n.º 26
0
    def rstable(self, alpha, beta, location, scale, \
                                    xmin=float('-inf'), xmax=float('inf')):
        """
        rstable generates random variates from any distribution of the stable 
        family. 0 < alpha <= 2 is the tail index (the smaller alpha, the wider 
        the distribution). -1 <= beta <= 1 is the skewness parameter (the 
        greater absolute value, the more skewed the distribution, negative = 
        skewed to the left, positive = skewed to the right). 
        
        For beta = 0 and alpha = 2 the distribution is a Gaussian distribution -
        but scaled with sqrt(2) (the variance of the stable is twice that of the
        Gaussian). For beta = 0 and alpha = 1 the distribution is the Cauchy. 
        For abs(beta) = 1 and alpha = 0.5 the distribution is the Levy.
        
        For alpha < 2.0 the variance and higher moments are infinite, and for 
        alpha <= 1 all moments are infinite. A scale parameter and a location 
        parameter are also applicable so that Y = scale*X + location is still 
        a stable variate with the same alpha as that of X. E{Y} = location for 
        alpha > 1.
        
        The algorithm is taken from Weron but the original version seems to be 
        Chambers, Mallows and Stuck: 
        Weron R. (1996): 'On the Chambers-Mallows-Stuck method for simulating 
        skewed stable random variates', Statist. Probab. Lett. 28, 165-171. 
        Chambers, J.M., Mallows, C.L. and Stuck, B.W. (1976): 'A Method for 
        simulating stable random variables', J. Amer. Statist. Assoc. 71, 
        340-344.
        Weron, R. (1996): 'Correction to: On the Chambers-Mallows-Stuck Method 
        for Simulating Skewed Stable Random Variables', Research Report 
        HSC/96/1, Wroclaw University of Technology. 
        """

        assert  0.0 < alpha and alpha <= 2.0, \
                                      "alpha must be in (0.0, 2.0] in rstable!"
        assert -1.0 <= beta and  beta <= 1.0, \
                                      "beta must be in [-1.0, 1.0] in rstable!"
        assert xmax > xmin, "xmax must be > xmin in rstable!"

        while True:
            v = self.runifab(-PIHALF, PIHALF)
            w = self.rexpo(1.0)

            if beta == 0 or beta == 0.0:
                oneoa = 1.0 / float(alpha)
                av = alpha * v
                x1 = sin(av) / cos(v)**oneoa
                x2 = (cos(v - av) / w)**(oneoa - 1.0)
                x = x1 * x2
                x = scale * x + location

            elif alpha == 1 or alpha == 1.0:
                pihpbv = PIHALF + beta * v
                x1 = pihpbv * tan(v)
                x2 = beta * safelog(PIHALF * w * cos(v) / pihpbv)
                #x      = (x1-x2) / PIHALF
                #x  = scale*x + (1.0/PIHALF)*beta*scale*safelog(scale) + location
                x = 2.0 * PIINV * (x1 - x2) / PIHALF
                x = scale * x + (
                    2.0 * PIINV) * beta * scale * safelog(scale) + location

            else:
                tpiha = tan(PIHALF * alpha)
                oneoa = 1.0 / float(alpha)
                bab = atan(beta * tan(PIHALF * alpha))
                sab = (1.0 + beta * beta * tpiha * tpiha)**(0.5 * oneoa)
                vpbab = v + bab
                av = alpha * vpbab
                x1 = sin(av) / cos(v)**oneoa
                x2 = (cos(v - av) / w)**(oneoa - 1.0)
                x = sab * x1 * x2
                x = scale * x + location

            if xmin <= x and x <= xmax: break

        return x
Ejemplo n.º 27
0
    def rnormal(self, mu, sigma, xmin=float('-inf'), xmax=float('inf')):
        """
        Generator of normally distributed random variates. Based on the 
        Kinderman-Ramage algorithm as modified by Tirler, Dalgaard, Hoermann & 
        Leydold. 
        
        sigma >= 0.0
        """

        assert sigma >= 0.0, \
                 "standard deviation must be a non-negative float in rnormal!"
        assert xmax > xmin, "xmax must be > xmin in rnormal!"

        ksi = 2.2160358671
        ksi2h = 0.5 * ksi * ksi
        p18 = 0.180025191068563
        p48 = 0.479727404222441

        while True:

            u = self.runif01()

            if u < 0.884070402298758:
                v = self.runif01()
                x = ksi * (1.131131635444180 * u + v - 1.0)

            elif u >= 0.973310954173898:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    t = ksi2h - safelog(w)
                    if v * v * t <= ksi2h:
                        break
                if u < 0.986655477086949:
                    x = sqrt(2.0 * t)
                else:
                    x = -sqrt(2.0 * t)

            elif u >= 0.958720824790463:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = ksi - 0.630834801921960 * min(v, w)
                    if max(v, w) <= 0.755591531667601:
                        if z < 0.0: x = t
                        else: x = -t
                        break
                    p = dnormal(0.0, 1.0, t)
                    f = p - p18 * max(ksi - abs(t), 0.0)
                    if 0.034240503750111 * abs(z) <= f:
                        if z < 0.0: x = t
                        else: x = -t
                        break

            elif u >= 0.911312780288703:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = p48 + 1.105473661022070 * min(v, w)
                    if max(v, w) <= 0.872834976671790:
                        if z < 0.0: x = t
                        else: x = -t
                        break
                    p = dnormal(0.0, 1.0, t)
                    f = p - p18 * max(ksi - abs(t), 0.0)
                    if 0.049264496373128 * abs(z) <= f:
                        if z < 0.0: x = t
                        else: x = -t
                        break

            else:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = p48 - 0.595507138015940 * min(v, w)
                    if t >= 0.0:
                        if max(v, w) <= 0.805577924423817:
                            if z < 0.0: x = t
                            else: x = -t
                            break
                        p = dnormal(0.0, 1.0, t)
                        f = p - p18 * max(ksi - abs(t), 0.0)
                        if 0.053377549506886 * abs(z) <= f:
                            if z < 0.0: x = t
                            else: x = -t
                            break

            x = sigma * x + mu
            if xmin <= x <= xmax: break

        return x
Ejemplo n.º 28
0
    def rgamma(self, alpha, lam, xmax=float('inf')):
        """
        The gamma distribution:
        f = lam * exp(-lam*x) * (lam*x)**(alpha-1) / gamma(alpha)
        The cdf is the integral = the incomplete gamma ratio.
        x, alpha >= 0; lam > 0.0
         
        The generator is a slight modification of Python's 
        built-in "gammavariate". 
        """

        assert alpha >= 0.0, "alpha must be non-negative in rgamma!"
        assert lam > 0.0, "lambda must be a positive float in rgamma!"
        assert xmax  >= 0.0, \
                    "variate max must be a non-negative float in rgamma!"

        f, i = modf(alpha)
        if f == 0.0:
            if 1.0 <= i and i <= GeneralRandomStream.__GAMMA2ERLANG:
                return self.rerlang(int(i), 1.0 / lam, xmax)

        if alpha < 1.0:
            # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
            # (according to Python's "gammavariate")
            alphainv = 1.0 / alpha
            alpham1 = alpha - 1.0
            while True:
                while True:
                    u = self.runif01()
                    b = (E + alpha) / E
                    p = b * u
                    if p <= 1.0:
                        w = p**alphainv
                    else:
                        w = -safelog((b - p) * alphainv)
                    u1 = self.runif01()
                    if p > 1.0:
                        if u1 <= w**(alpham1):
                            break
                    elif u1 <= exp(-w):
                        break
                x = w / lam
                if x <= xmax: break

        else:  # elif alpha > 1.0:
            # Uses R.C.H. Cheng, "The generation of Gamma
            # variables with non-integral shape parameters",
            # Applied Statistics, (1977), 26, No. 1, p71-74
            # (according to Python's "gammavariate")

            ainv = sqrt(2.0 * alpha - 1.0)
            beta = 1.0 / ainv
            bbb = alpha - GeneralRandomStream.__LN4
            ccc = alpha + ainv

            while True:
                while True:
                    u1 = self.runif01()
                    u2 = self.runif01()
                    v = beta * safelog(safediv(u1, 1.0 - u1))
                    w = alpha * exp(v)
                    c1 = u1 * u1 * u2
                    r = bbb + ccc * v - w
                    c2 = r + 2.5040773967762742 - 4.5 * c1
                    # 2.5040773967762742 = 1.0 + log(4.5)
                    if c2 >= 0.0 or r >= safelog(c1):
                        break
                x = w / lam
                if x <= xmax: break

        x = kept_within(0.0, x)
        return x
Ejemplo n.º 29
0
    def rexppower(self, loc, scale, alpha, \
                                    xmin=float('-inf'), xmax=float('inf')):
        """
        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.
        
        A modified version of the rejection technique proposed in 
        P.R. Tadikamalla;
        "Random Sampling From the Exponential Power Distribution",
        J. Am. Statistical Association 75(371), 1980, pp 683-686 
        is used (the gamma is used for alpha > 2.0 in place of the rejection 
        procedure proposed by Tadikamalla - for purposes of speed).
        """

        assert xmax > xmin, "xmax must be > xmin in rexppower!"
        assert scale > 0.0, \
                   "scale parameter must be a positive float in rexppower!"
        assert alpha > 0.0, \
                "shape parameter alpha must be a positive float in rexppower!"

        sinv = 1.0 / scale
        ainv = 1.0 / alpha

        while True:
            if alpha < 1.0:  # The gamma distribution
                rgam = self.rgamma(ainv, sinv)
                sign = self.rsign()
                x = loc + sign * rgam**ainv

            elif alpha == 1.0:  # The Laplace distribution is used
                x = self.rlaplace(d, scale)

            elif 1.0 < alpha < 2.0:  # Tadikamalla's rejection procedure
                ayay = ainv**ainv
                ayayi = 1.0 / ayay
                while True:
                    u1 = self.runif01()
                    if u1 > 0.5: x = -ayay * safelog(2.0 * (1.0 - u1))
                    else: x = ayay * safelog(2.0 * u1)
                    ax = abs(x)
                    lnu2 = safelog(self.runif01())
                    if lnu2 <= -ax**alpha + ayayi * ax - 1.0 + ainv:
                        break
                x = loc + sinv * x

            elif alpha == 2.0:  # The normal (Gaussian) distribution
                x = self.rnormal(d, scale)

            else:
                '''while True:   # Tadikamalla is slower than the gamma!!!
                    ayay   = ainv**ainv
                    ayayi2 = 1.0/(ayay*ayay)
                    x      = self.rnormal(0.0, ayay)
                    ax     = abs(x)
                    lnu    = safelog(self.runif01())
                    if lnu  <=  - ax**alpha + 0.5*ayayi2*x*x + ainv - 0.5:
                        break'''
                rgam = self.rgamma(ainv, sinv)  # The gamma distribution
                sign = self.rsign()
                x = loc + sign * rgam**ainv

            if xmin <= x <= xmax: break

        return x
Ejemplo n.º 30
0
    def rbeta(self, a, b, x1, x2):
        """
        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 
        
        The algorithm is due to Berman (1970)/Jonck (1964) (for a and b < 1.0) 
        and Cheng (1978) as described in Bratley, Fox and Schrage.
        """

        assert a  > 0.0, \
                        "shape parameters a and b must both be > 0.0 in rbeta!"
        assert b  > 0.0, \
                        "shape parameters a and b must both be > 0.0 in rbeta!"
        assert x2 >= x1, \
                         "support span must not be negative in rbeta!"

        if x2 == x1: return x1

        if a == 1.0 and b == 1.0:
            y = self.runif01()

        elif is_posinteger(a) and is_posinteger(b):
            nstop = int(a + b - 1.0)
            r = []
            for k in range(0, nstop):
                r.append(self.runif01())
            r.sort()
            y = r[int(a-1.0)]

        elif a < 1.0 and b < 1.0:
            a1 = 1.0 / a
            b1 = 1.0 / b
            while True:
                u = pow(self.runif01(), a1)
                v = pow(self.runif01(), b1)
                if u + v <= 1.0:
                    y = u / (u+v)
                    break

        else:
            alpha = a + b
            if min(a, b) <= 1.0: beta = 1.0 / min(a, b)
            else:                beta = sqrt((alpha-2.0)/(2.0*a*b-alpha))
            gamma = a + 1.0/beta
            while True:
                u1    =  self.runif01()
                u2    =  self.runif01()
                u1    =  kept_within(TINY, u1, ONEMMACHEPS)
                u2    =  kept_within(TINY, u2, HUGE)
                comp1 =  safelog(u1*u1*u2)
                v     =  beta * safelog(safediv(u1, 1.0-u1))
                w     =  a * exp(v)
                comp2 =  alpha*safelog(alpha/(b+w)) + gamma*v - \
                                                     GeneralRandomStream.__LN4
                if comp2 >= comp1:
                    y = w / (b+w)
                    break

        x = y*(x2-x1) + x1
        x = kept_within(x1, x, x2)

        return x
Ejemplo n.º 31
0
    def rexppower(self, loc, scale, alpha, \
                                    xmin=float('-inf'), xmax=float('inf')):
        """
        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.
        
        A modified version of the rejection technique proposed in 
        P.R. Tadikamalla;
        "Random Sampling From the Exponential Power Distribution",
        J. Am. Statistical Association 75(371), 1980, pp 683-686 
        is used (the gamma is used for alpha > 2.0 in place of the rejection 
        procedure proposed by Tadikamalla - for purposes of speed).
        """

        assert xmax > xmin, "xmax must be > xmin in rexppower!"
        assert scale > 0.0, \
                   "scale parameter must be a positive float in rexppower!"
        assert alpha > 0.0, \
                "shape parameter alpha must be a positive float in rexppower!"

        sinv = 1.0/scale
        ainv = 1.0/alpha

        while True:
            if alpha < 1.0:      # The gamma distribution
                rgam =  self.rgamma(ainv, sinv)
                sign =  self.rsign()
                x    =  loc + sign*rgam**ainv

            elif alpha == 1.0:   # The Laplace distribution is used
                x  =  self.rlaplace(d, scale)

            elif 1.0 < alpha < 2.0:   # Tadikamalla's rejection procedure
                ayay  = ainv**ainv
                ayayi = 1.0/ayay
                while True:
                    u1   = self.runif01()
                    if u1 > 0.5: x = - ayay * safelog(2.0*(1.0-u1))
                    else:        x =   ayay * safelog(2.0*u1)
                    ax   = abs(x)
                    lnu2 = safelog(self.runif01())
                    if lnu2  <=  - ax**alpha + ayayi*ax - 1.0 + ainv:
                        break
                x  =  loc + sinv*x
                
            elif alpha == 2.0:   # The normal (Gaussian) distribution
                x  =  self.rnormal(d, scale)

            else:
                '''while True:   # Tadikamalla is slower than the gamma!!!
                    ayay   = ainv**ainv
                    ayayi2 = 1.0/(ayay*ayay)
                    x      = self.rnormal(0.0, ayay)
                    ax     = abs(x)
                    lnu    = safelog(self.runif01())
                    if lnu  <=  - ax**alpha + 0.5*ayayi2*x*x + ainv - 0.5:
                        break'''
                rgam =  self.rgamma(ainv, sinv)   # The gamma distribution
                sign =  self.rsign()
                x    =  loc + sign*rgam**ainv

            if xmin <= x <= xmax: break

        return x
Ejemplo n.º 32
0
    def rbeta(self, a, b, x1, x2):
        """
        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 
        
        The algorithm is due to Berman (1970)/Jonck (1964) (for a and b < 1.0) 
        and Cheng (1978) as described in Bratley, Fox and Schrage.
        """

        assert a  > 0.0, \
                        "shape parameters a and b must both be > 0.0 in rbeta!"
        assert b  > 0.0, \
                        "shape parameters a and b must both be > 0.0 in rbeta!"
        assert x2 >= x1, \
                         "support span must not be negative in rbeta!"

        if x2 == x1: return x1

        if a == 1.0 and b == 1.0:
            y = self.runif01()

        elif is_posinteger(a) and is_posinteger(b):
            nstop = int(a + b - 1.0)
            r = []
            for k in range(0, nstop):
                r.append(self.runif01())
            r.sort()
            y = r[int(a - 1.0)]

        elif a < 1.0 and b < 1.0:
            a1 = 1.0 / a
            b1 = 1.0 / b
            while True:
                u = pow(self.runif01(), a1)
                v = pow(self.runif01(), b1)
                if u + v <= 1.0:
                    y = u / (u + v)
                    break

        else:
            alpha = a + b
            if min(a, b) <= 1.0: beta = 1.0 / min(a, b)
            else: beta = sqrt((alpha - 2.0) / (2.0 * a * b - alpha))
            gamma = a + 1.0 / beta
            while True:
                u1 = self.runif01()
                u2 = self.runif01()
                u1 = kept_within(TINY, u1, ONEMMACHEPS)
                u2 = kept_within(TINY, u2, HUGE)
                comp1 = safelog(u1 * u1 * u2)
                v = beta * safelog(safediv(u1, 1.0 - u1))
                w = a * exp(v)
                comp2 =  alpha*safelog(alpha/(b+w)) + gamma*v - \
                                                     GeneralRandomStream.__LN4
                if comp2 >= comp1:
                    y = w / (b + w)
                    break

        x = y * (x2 - x1) + x1
        x = kept_within(x1, x, x2)

        return x
Ejemplo n.º 33
0
    def rgamma(self, alpha, lam, xmax=float('inf')):
        """
        The gamma distribution:
        f = lam * exp(-lam*x) * (lam*x)**(alpha-1) / gamma(alpha)
        The cdf is the integral = the incomplete gamma ratio.
        x, alpha >= 0; lam > 0.0
         
        The generator is a slight modification of Python's 
        built-in "gammavariate". 
        """

        assert alpha >= 0.0, "alpha must be non-negative in rgamma!"
        assert  lam  >  0.0, "lambda must be a positive float in rgamma!"
        assert xmax  >= 0.0, \
                    "variate max must be a non-negative float in rgamma!"

        f, i = modf(alpha)
        if f == 0.0:
            if 1.0 <= i and i <= GeneralRandomStream.__GAMMA2ERLANG:
                return self.rerlang(int(i), 1.0/lam, xmax)

        if alpha < 1.0:
            # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
            # (according to Python's "gammavariate")
            alphainv = 1.0 / alpha
            alpham1  = alpha - 1.0
            while True:
                while True:
                    u = self.runif01()
                    b = (E+alpha) / E
                    p = b * u
                    if p <= 1.0:
                        w = p ** alphainv
                    else:
                        w = -safelog((b-p)*alphainv)
                    u1 = self.runif01()
                    if p > 1.0:
                        if u1 <= w ** (alpham1):
                            break
                    elif u1 <= exp(-w):
                        break
                x = w / lam
                if x <= xmax: break

        else:   # elif alpha > 1.0:
            # Uses R.C.H. Cheng, "The generation of Gamma
            # variables with non-integral shape parameters",
            # Applied Statistics, (1977), 26, No. 1, p71-74
            # (according to Python's "gammavariate")

            ainv = sqrt(2.0*alpha - 1.0)
            beta = 1.0 / ainv
            bbb  = alpha - GeneralRandomStream.__LN4
            ccc  = alpha + ainv

            while True:
                while True:
                    u1 = self.runif01()
                    u2 = self.runif01()
                    v  = beta * safelog(safediv(u1, 1.0-u1))
                    w  = alpha * exp(v)
                    c1 = u1 * u1 * u2
                    r  = bbb + ccc*v - w
                    c2 = r + 2.5040773967762742 - 4.5*c1
                                        # 2.5040773967762742 = 1.0 + log(4.5)
                    if c2 >= 0.0 or r >= safelog(c1):
                        break
                x = w / lam
                if x <= xmax: break

        x = kept_within(0.0, x)
        return x
Ejemplo n.º 34
0
    def rnormal(self, mu, sigma, xmin=float('-inf'), xmax=float('inf')):
        """
        Generator of normally distributed random variates. Based on the 
        Kinderman-Ramage algorithm as modified by Tirler, Dalgaard, Hoermann & 
        Leydold. 
        
        sigma >= 0.0
        """

        assert sigma >= 0.0, \
                 "standard deviation must be a non-negative float in rnormal!"
        assert xmax > xmin, "xmax must be > xmin in rnormal!"

        ksi   = 2.2160358671
        ksi2h = 0.5*ksi*ksi
        p18   = 0.180025191068563
        p48   = 0.479727404222441

        while True:

            u = self.runif01()

            if u < 0.884070402298758:
                v = self.runif01()
                x = ksi * (1.131131635444180*u + v - 1.0)

            elif u >= 0.973310954173898:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    t = ksi2h - safelog(w)
                    if v*v*t <= ksi2h:
                        break
                if u < 0.986655477086949:
                    x =  sqrt(2.0*t)
                else:
                    x = -sqrt(2.0*t)

            elif u >= 0.958720824790463:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = ksi - 0.630834801921960*min(v, w)
                    if max(v, w) <= 0.755591531667601:
                        if z < 0.0: x =  t
                        else:       x = -t
                        break
                    p = dnormal(0.0, 1.0, t)
                    f = p - p18*max(ksi-abs(t), 0.0)
                    if 0.034240503750111*abs(z) <= f:
                        if z < 0.0: x =  t
                        else:       x = -t
                        break

            elif u >= 0.911312780288703:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = p48 + 1.105473661022070*min(v, w)
                    if max(v, w) <= 0.872834976671790:
                        if z < 0.0: x =  t
                        else:       x = -t
                        break
                    p = dnormal(0.0, 1.0, t)
                    f = p - p18*max(ksi-abs(t), 0.0)
                    if 0.049264496373128*abs(z) <= f:
                        if z < 0.0: x =  t
                        else:       x = -t
                        break

            else:
                while True:
                    v = self.runif01()
                    w = self.runif01()
                    z = v - w
                    t = p48 - 0.595507138015940*min(v, w)
                    if t >= 0.0:
                        if max(v, w) <= 0.805577924423817:
                            if z < 0.0: x =  t
                            else:       x = -t
                            break
                        p = dnormal(0.0, 1.0, t)
                        f = p - p18*max(ksi-abs(t), 0.0)
                        if 0.053377549506886*abs(z) <= f:
                            if z < 0.0: x =  t
                            else:       x = -t
                            break

            x = sigma*x + mu
            if xmin <= x <= xmax: break

        return x
Ejemplo n.º 35
0
def iemp_exp(prob, values, npexp=0, ordered=False):
    """
    The mixed expirical/exponential distribution from Bratley, Fox and Schrage.
    A polygon (piecewise linearly interpolated cdf with equal probability for 
    each interval between the ) is used together with a (shifted) exponential 
    for the tail. The distribution is designed so as to preserve the mean of 
    the input sample.
    
    The input is a tuple/list of observed points and an integer (npexp) 
    corresponding to the number of (the largest) points that will be used 
    to formulate the exponential tail (the default value of npexp will raise 
    an assertion error so something >= 0 must be prescribed).
    
    NB it is assumed that x is in [0.0, inf) !!!!!!!!!!!!
    
    The function may also be used for a piecewise linear cdf without the 
    exponential tail (setting npexp = 0) - corrections are made to maintain 
    the mean in this case as well!!! 
    """

    _assertprob(prob, 'iemp_exp')
    assert is_nonneginteger(npexp), \
        "No. of points for exp. tail in iemp_exp must be a non-neg integer!"

    nvalues = len(values)
    for k in range(0, nvalues):
        assert values[k] >= 0.0, \
                        "All values in list must be non-negative in iemp_exp!"

    if npexp == nvalues:
        mean = sum(values)
        return iexpo(prob, mean)

    vcopy = list(values)
    if not ordered:
        valueskm1 = values[0]
        for k in range(1, nvalues):
            valuesk = values[k]
            if valuesk >= valueskm1:
                valueskm1 = valuesk
            else:
                vcopy.sort()
                break

    if vcopy[0] == 0.0:   # Remove the first zero if any - it will be
        del vcopy[0]      # returned later on!!!!!!!!
        nvalues = nvalues - 1

    errtxt2 = "Number of points for exponential tail in iemp_exp too large!"
    assert npexp <= nvalues, errtxt2

    pcomp = 1.0 - prob
    nred  = pcomp*nvalues
    if npexp > pcomp*nvalues:
        breaki = nvalues - npexp - 1  # The last ix of the piecewise linear part
        breakp = vcopy[breaki]    # The last value of the piecewise linear part
        summ   = 0.0
        k0 = breaki + 1
        for k in range(k0, nvalues):
            summ += vcopy[k] - breakp
        theta  = (0.5*breakp + summ) / npexp
        q  =  npexp / float(nvalues)
        try:
            x  =  breakp - theta*safelog(nred/npexp)
        except ValueError:
            x  =  float('inf')
    else:
        vcopy.insert(0, 0.0)               # A floor value must be inserted
        v  =  nvalues*prob
        i  =  int(v)
        x  =  vcopy[i] + (v-i)*(vcopy[i+1]-vcopy[i])
        if npexp == 0:  # Correction to maintain mean when there is no exp tail
            x  =  (nvalues+1.0) * x / nvalues

    x = kept_within(0.0, x)

    return x
Ejemplo n.º 36
0
    def rstable(self, alpha, beta, location, scale, \
                                    xmin=float('-inf'), xmax=float('inf')):
        """
        rstable generates random variates from any distribution of the stable 
        family. 0 < alpha <= 2 is the tail index (the smaller alpha, the wider 
        the distribution). -1 <= beta <= 1 is the skewness parameter (the 
        greater absolute value, the more skewed the distribution, negative = 
        skewed to the left, positive = skewed to the right). 
        
        For beta = 0 and alpha = 2 the distribution is a Gaussian distribution -
        but scaled with sqrt(2) (the variance of the stable is twice that of the
        Gaussian). For beta = 0 and alpha = 1 the distribution is the Cauchy. 
        For abs(beta) = 1 and alpha = 0.5 the distribution is the Levy.
        
        For alpha < 2.0 the variance and higher moments are infinite, and for 
        alpha <= 1 all moments are infinite. A scale parameter and a location 
        parameter are also applicable so that Y = scale*X + location is still 
        a stable variate with the same alpha as that of X. E{Y} = location for 
        alpha > 1.
        
        The algorithm is taken from Weron but the original version seems to be 
        Chambers, Mallows and Stuck: 
        Weron R. (1996): 'On the Chambers-Mallows-Stuck method for simulating 
        skewed stable random variates', Statist. Probab. Lett. 28, 165-171. 
        Chambers, J.M., Mallows, C.L. and Stuck, B.W. (1976): 'A Method for 
        simulating stable random variables', J. Amer. Statist. Assoc. 71, 
        340-344.
        Weron, R. (1996): 'Correction to: On the Chambers-Mallows-Stuck Method 
        for Simulating Skewed Stable Random Variables', Research Report 
        HSC/96/1, Wroclaw University of Technology. 
        """

        assert  0.0 < alpha and alpha <= 2.0, \
                                      "alpha must be in (0.0, 2.0] in rstable!"
        assert -1.0 <= beta and  beta <= 1.0, \
                                      "beta must be in [-1.0, 1.0] in rstable!"
        assert  xmax > xmin,                  "xmax must be > xmin in rstable!"

        while True:
            v = self.runifab(-PIHALF, PIHALF)
            w = self.rexpo(1.0)

            if beta == 0 or beta == 0.0:
                oneoa =  1.0 / float(alpha)
                av    =  alpha * v
                x1    =  sin(av) / cos(v)**oneoa
                x2    =  (cos(v-av)/w) ** (oneoa-1.0)
                x     =  x1 * x2
                x     =  scale*x + location

            elif alpha == 1 or alpha == 1.0:
                pihpbv = PIHALF + beta*v
                x1     = pihpbv * tan(v)
                x2     = beta * safelog(PIHALF*w*cos(v)/pihpbv)
                #x      = (x1-x2) / PIHALF
                #x  = scale*x + (1.0/PIHALF)*beta*scale*safelog(scale) + location
                x      = 2.0*PIINV * (x1-x2) / PIHALF
                x   = scale*x + (2.0*PIINV)*beta*scale*safelog(scale) + location

            else:
                tpiha =  tan(PIHALF*alpha)
                oneoa =  1.0 / float(alpha)
                bab   =  atan(beta*tan(PIHALF*alpha))
                sab   =  (1.0 + beta*beta*tpiha*tpiha) ** (0.5*oneoa)
                vpbab =  v + bab
                av    =  alpha * vpbab
                x1    =  sin(av) / cos(v)**oneoa
                x2    =  (cos(v-av) / w) ** (oneoa-1.0)
                x     =  sab * x1 * x2
                x     =  scale*x + location

            if xmin <= x and x <= xmax: break

        return x
Ejemplo n.º 37
0
def inormal(prob, mu=0.0, sigma=1.0):
    """
    Returns the inverse of the cumulative normal distribution function.
    Reference: Boris Moro "The Full Monte", Risk Magazine, 8(2) (February): 
    57-58, 1995, where Moro improves on the Beasley-Springer algorithm 
    (J. D. Beasley and S. G. Springer, Applied Statistics, vol. 26, 1977, 
    pp. 118-121). This is further refined by Shaw, c. f. below. 
    Max relative error is claimed to be less than 2.6e-9 
    """

    _assertprob(prob, 'inormal')

    assert sigma >= 0.0, "sigma must not be negative in inormal!"


    #a = ( 2.50662823884, -18.61500062529,  \
    #     41.39119773534, -25.44106049637)   # Moro

    #b = (-8.47351093090,  23.08336743743, \
    #    -21.06224101826,   3.13082909833)   # Moro

    # The a and b below are claimed to be better by William Shaw in a 
    # Mathematica working report: "Refinement of the Normal Quantile - 
    # A benchmark Normal quantile based on recursion, and an appraisal 
    # of the Beasley-Springer-Moro, Acklam, and Wichura (AS241) methods" 
    # (William Shaw, Financial Mathematics Group, King's College, London;  
    # [email protected]).
    # Max RELATIVE error is claimed to be reduced from 1.4e-8 to 2.6e-9
    # over the central region

    a = ( 2.5066282682076065359, -18.515898959450185753, \
         40.864622120467790785,  -24.820209533706798850)      # Moro/Shaw

    b = ( -8.4339736056039657294, 22.831834928541562628, \
         -20.641301545177201274,   3.0154847661978822127)     # Moro/Shaw

    c = (0.3374754822726147, 0.9761690190917186, 0.1607979714918209, \
         0.0276438810333863, 0.0038405729373609, 0.0003951896511919, \
         0.0000321767881768, 0.0000002888167364, 0.0000003960315187)     # Moro

    x = prob - 0.5

    if abs(x) < 0.42:   # A rational approximation for the central region...
        r  =  x * x
        r  =  x * (((a[3]*r+a[2])*r+a[1])*r+a[0]) / ((((b[3]*r+b[2])*r+\
                                                        b[1])*r+b[0])*r+1.0)
        r  =  sigma*r + mu

    else:               # ...and a polynomial for the tails
        r = prob
        if x > 0.0: r = 1.0 - prob
        try:
            r  =  safelog(-safelog(r))
            r  =  c[0] + r*(c[1] + r*(c[2] + r*(c[3] + r*(c[4] + r*(c[5] +\
                                   r*(c[6] + r*(c[7] + r*c[8])))))))
            if x < 0.0: r = -r
            r  =  sigma*r + mu
        except ValueError:
            r  =  fsign(x) * float('inf')

    return r