Beispiel #1
0
def binfreq(n, integer=True):
    """
    Computes all binomial coefficients for n AND the relative frequencies AND 
    the cumulative frequencies and returns them in two lists. Uses fbincoeff  
    (but floats are returned). 
    """

    assert is_posinteger(n), "argument to binFreq must be a positive integer!"

    z      = 0.0     # A float
    farray = []
    np1    = n + 1

    for k in range(0, np1):
        x  = fbincoeff(n, k, integer)
        z  = z + x        # A float
        farray.append(x)

    parray = []
    carray = []

    y = 0.0
    for k in range(0, np1):
        x  = farray[k] / z
        y  = y + x
        parray.append(x)
        carray.append(y)

    return parray, carray
Beispiel #2
0
    def _checkinput(self, cll, t, tnext, tolf, tola, maxitn, imprv):
        """
        Used to check the values of the input parameters to the solver methods. 
        cll is the name of the present method (a string).
        """

        assert tnext > t, "time step must be positive in " + cll + "!"

        wtext1 = "tolerances smaller than machine epsilon are not recommended "
        wtext2 = "in " + cll + ". Machine epsilon is used instead"
        wtext  = wtext1 + wtext2
        if tolf < MACHEPS:
            tolf = MACHEPS
            warn(wtext)
        if tola < MACHEPS:
            tola = MACHEPS
            warn(wtext)
        assert is_posinteger(maxitn), \
                     "maxitn must be a positive integer in " + cll + "!"

        if not is_nonneginteger(imprv):
            imprv = 0
            wtext1  = "imprv must be a non-negative integer in "
            wtext2  = cll + "! imprv=0 is used instead"
            wtext   = wtext1 + wtext2
            warn(wtext)
Beispiel #3
0
def binprob(n, phi, integer=True):
    """
    Computes all binomial terms for n given the Bernoulli probability phi. 
    Returns the relative frequencies AND the cumulative frequencies (two lists). 
    """

    assert is_posinteger(n),  \
                      "first argument to binProb must be a positive integer!"
    assert 0.0 <= phi <= 1.0, \
                    "Bernoulli probability must be in [0.0, 1.0] in binProb!"

    farray = []
    np1 = n + 1
    for k in range(0, np1):
        x = fbincoeff(n, k, integer)
        farray.append(x)

    parray = []
    carray = []

    y = 0.0
    q = 1.0 - phi
    for k in range(0, np1):
        x = farray[k] * phi**k * q**(n - k)
        x = kept_within(0.0, x, 1.0)
        y = y + x
        y = kept_within(0.0, y, 1.0)
        parray.append(x)
        carray.append(y)

    return parray, carray
Beispiel #4
0
    def __init__(self, nseed=2147483647, heir=None):
        """
        Initiates the random stream using the input seed 'nseed' and Python's 
        __init__ constructor method. Unless...
        ...the input seed 'nseed' happens to be a list or tuple of numbers 
        in [0.0, 1.0], in which case this external feed will be used as the 
        basis of all random variate generation for the instance and will be 
        used in place of consecutively sampled numbers from Python's built-in 
        "random" method! 
        """

        if isinstance(nseed, int):
            assert is_posinteger(nseed), \
               "The seed (if not a feed) must be a positive integer in ABCRand!"
            rstream      = Random(nseed)
            self._feed   = False
            self.runif01 = rstream.random
            if heir != "InverseRandomStream":
                self.randrange       = rstream.randrange
                self.randint         = rstream.randint
                self.vonmisesvariate = rstream.vonmisesvariate
                # Random.paretovariate and Random.weibullvariate
                # are used by methods in GeneralRandomStream
                self._paretovariate  = rstream.paretovariate
                self._weibullvariate = rstream.weibullvariate

        else:  # nseed is a list or tuple
            # Check to see beforehand that no numbers 
            # from the feed is outside [0.0, 1.0]
            for x in nseed:
                assert 0.0 <= x <= 1.0, \
                    "number from feed is outside of [0.0, 1.0] in ABCRand!"
            self._feed   = Stack(nseed)  # Creates a Stack object
            self.runif01 = self.__rfeed01
Beispiel #5
0
def cerlang(nshape, phasemean, x):
    """
    The cdf of the Erlang distribution.
    Represents the sum of nshape exponentially distributed random variables, 
    all having "phasemean" as mean
    """

    if nshape == 1:
        cdf = cexpo(phasemean, x)

    else:
        assert is_posinteger(nshape), "shape parameter must be a positive integer in cerlang!"
        assert phasemean >= 0.0, "phase mean must not be negative in cerlang!"
        assert x >= 0.0, "variate must not be negative in cerlang!"
        y = x / float(phasemean)
        cdf = 1.0
        term = 1.0
        cdf = term
        for k in range(1, nshape):
            term = term * y / k
            cdf = cdf + term

        cdf = 1.0 - exp(-y) * cdf

        cdf = kept_within(0.0, cdf, 1.0)

    return cdf
Beispiel #6
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
Beispiel #7
0
def binprob(n, phi, integer=True):
    """
    Computes all binomial terms for n given the Bernoulli probability phi. 
    Returns the relative frequencies AND the cumulative frequencies (two lists). 
    """

    assert is_posinteger(n),  \
                      "first argument to binProb must be a positive integer!"
    assert 0.0 <= phi <= 1.0, \
                    "Bernoulli probability must be in [0.0, 1.0] in binProb!"

    farray = []
    np1    = n + 1
    for k in range(0, np1):
        x = fbincoeff(n, k, integer)
        farray.append(x)

    parray = []
    carray = []

    y = 0.0
    q = 1.0 - phi
    for k in range(0, np1):
        x  = farray[k] * phi**k * q**(n-k)
        x  = kept_within(0.0, x, 1.0)
        y  = y + x
        y  = kept_within(0.0, y, 1.0)
        parray.append(x)
        carray.append(y)

    return parray, carray
Beispiel #8
0
def derlang(nshape, phasemean, x):
    """
    The pdf of the Erlang distribution - represents the sum of 
    nshape exponentially distributed random variables all having 
    the same mean = phasemean. 
    """

    if nshape == 1:
        pdf = dexpo(phasemean, x)

    else:
        # Input check -----------------
        assert is_posinteger(nshape), \
                  "shape parameter must be a positive integer in derlang!"
        assert  phasemean  >  0.0, \
                           "phase mean must be positive in derlang!"
        assert      x      >= 0.0, \
                           "variate must not be negative in derlang!"
        # -----------------------------

        y        =  x / float(phasemean)
        nshapem1 = nshape - 1
        try:
            pdf  =  exp(-y) * y**(nshape-1)
        except OverflowError:
            pdf  =  exp(-y + nshapem1*log(y))
        fact =  1
        for k in range(1, nshape): fact = fact*k  # nshape assumed to be small
        factor = 1.0 / (phasemean*fact)           # Now floats
        pdf    = factor * pdf           # Will always be >= 0.0

    return pdf
Beispiel #9
0
def binfreq(n, integer=True):
    """
    Computes all binomial coefficients for n AND the relative frequencies AND 
    the cumulative frequencies and returns them in two lists. Uses fbincoeff  
    (but floats are returned). 
    """

    assert is_posinteger(n), "argument to binFreq must be a positive integer!"

    z = 0.0  # A float
    farray = []
    np1 = n + 1

    for k in range(0, np1):
        x = fbincoeff(n, k, integer)
        z = z + x  # A float
        farray.append(x)

    parray = []
    carray = []

    y = 0.0
    for k in range(0, np1):
        x = farray[k] / z
        y = y + x
        parray.append(x)
        carray.append(y)

    return parray, carray
Beispiel #10
0
def ibincoeff(n, k, integer=True):
    """
    Computation of a single binomial coefficient n over k, returning an 
    integer (possibly long). For integer=True integer arithmetics is used 
    throughout and there is no risk of overflow. For integer=False a floating- 
    point gamma function approximation is used and the result converted to 
    integer at the end (if an overflow occurs ERRCODE is returned). 
    """

    assert is_posinteger(n), \
               "n in n_over_k in ibincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in ibincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in ibincoeff!"

    if integer:
        ibico = _bicolongint(n, k)

    else:
        try:
            lnbico  =  lngamma(n+1) - lngamma(k+1) - lngamma(n-k+1)
            ibico   =  safeint(round(exp(lnbico)), 'ibincoeff')
        except OverflowError:
            ibico   =  ERRCODE

    return ibico
Beispiel #11
0
def ibinomial(prob, n, phi, normconst=10.0):
    """
    The binomial distribution: p(N=k) = bincoeff * phi**k * (1-phi)**(n-k), 
    n >= 1, k = 0, 1,...., n 
    """

    # Input check -----------
    _assertprob(prob, 'ibinomial')
    assert is_posinteger(n),        "n must be a positive integer in ibinomial!"
    assert 0.0 <= phi and phi <= 1.0, \
                          "success frequency out of support range in ibinomial!"
    assert normconst >= 10.0, \
           "parameter limit for normal approx. in ibinomial must not be < 10.0!"
    # -----------------------

    onemphi = 1.0 - phi

    if phi < 0.5: w = normconst * onemphi / phi
    else:         w = normconst * phi / onemphi

    if n > w:
        k = int(round(inormal(prob, n*phi, sqrt(n*phi*onemphi))))

    else:
        k   = 0
        cdf = binProb(n, phi)[1]
        while True:
            if cdf[k] <= prob:  k = k + 1
            else:               break

    k = kept_within(0, k, n)

    return k
Beispiel #12
0
def ibincoeff(n, k, integer=True):
    """
    Computation of a single binomial coefficient n over k, returning an 
    integer (possibly long). For integer=True integer arithmetics is used 
    throughout and there is no risk of overflow. For integer=False a floating- 
    point gamma function approximation is used and the result converted to 
    integer at the end (if an overflow occurs ERRCODE is returned). 
    """

    assert is_posinteger(n), \
               "n in n_over_k in ibincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in ibincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in ibincoeff!"

    if integer:
        ibico = _bicolongint(n, k)

    else:
        try:
            lnbico = lngamma(n + 1) - lngamma(k + 1) - lngamma(n - k + 1)
            ibico = safeint(round(exp(lnbico)), 'ibincoeff')
        except OverflowError:
            ibico = ERRCODE

    return ibico
Beispiel #13
0
def fbincoeff(n, k, integer=True):
    """
    Computation of a single binomial coefficient n over k, returning a float 
    (an OverflowError returns float('inf'), which would occur for n > 1029 
    for IEEE754 floating-point standard). 
    """

    assert is_posinteger(n), \
               "n in n_over_k in fbincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in fbincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in fbincoeff!"

    if integer:
        bico = _bicolongint(n, k)
        try:
            fbico = round(float(bico))
        except OverflowError:
            fbico = float('inf')

    else:
        try:
            lnbico  =  lngamma(n+1) - lngamma(k+1) - lngamma(n-k+1)
            fbico   =  round(exp(lnbico))
        except OverflowError:
            fbico   =  float('inf')

    return fbico
Beispiel #14
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
Beispiel #15
0
def fbincoeff(n, k, integer=True):
    """
    Computation of a single binomial coefficient n over k, returning a float 
    (an OverflowError returns float('inf'), which would occur for n > 1029 
    for IEEE754 floating-point standard). 
    """

    assert is_posinteger(n), \
               "n in n_over_k in fbincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in fbincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in fbincoeff!"

    if integer:
        bico = _bicolongint(n, k)
        try:
            fbico = round(float(bico))
        except OverflowError:
            fbico = float('inf')

    else:
        try:
            lnbico = lngamma(n + 1) - lngamma(k + 1) - lngamma(n - k + 1)
            fbico = round(exp(lnbico))
        except OverflowError:
            fbico = float('inf')

    return fbico
Beispiel #16
0
def derlang(nshape, phasemean, x):
    """
    The pdf of the Erlang distribution - represents the sum of 
    nshape exponentially distributed random variables all having 
    the same mean = phasemean. 
    """

    if nshape == 1:
        pdf = dexpo(phasemean, x)

    else:
        # Input check -----------------
        assert is_posinteger(nshape), \
                  "shape parameter must be a positive integer in derlang!"
        assert  phasemean  >  0.0, \
                           "phase mean must be positive in derlang!"
        assert      x      >= 0.0, \
                           "variate must not be negative in derlang!"
        # -----------------------------

        y = x / float(phasemean)
        nshapem1 = nshape - 1
        try:
            pdf = exp(-y) * y**(nshape - 1)
        except OverflowError:
            pdf = exp(-y + nshapem1 * log(y))
        fact = 1
        for k in range(1, nshape):
            fact = fact * k  # nshape assumed to be small
        factor = 1.0 / (phasemean * fact)  # Now floats
        pdf = factor * pdf  # Will always be >= 0.0

    return pdf
Beispiel #17
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
Beispiel #18
0
def cerlang(nshape, phasemean, x):
    """
    The cdf of the Erlang distribution.
    Represents the sum of nshape exponentially distributed random variables, 
    all having "phasemean" as mean
    """

    if nshape == 1:
        cdf = cexpo(phasemean, x)

    else:
        assert is_posinteger(nshape), \
                  "shape parameter must be a positive integer in cerlang!"
        assert  phasemean  >= 0.0, \
                           "phase mean must not be negative in cerlang!"
        assert      x      >= 0.0, \
                           "variate must not be negative in cerlang!"
        y = x / float(phasemean)
        cdf = 1.0
        term = 1.0
        cdf = term
        for k in range(1, nshape):
            term = term * y / k
            cdf = cdf + term

        cdf = 1.0 - exp(-y) * cdf

        cdf = kept_within(0.0, cdf, 1.0)

    return cdf
Beispiel #19
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
Beispiel #20
0
    def __init__(self, nseed=2147483647, heir=None):
        """
        Initiates the random stream using the input seed 'nseed' and Python's 
        __init__ constructor method. Unless...
        ...the input seed 'nseed' happens to be a list or tuple of numbers 
        in [0.0, 1.0], in which case this external feed will be used as the 
        basis of all random variate generation for the instance and will be 
        used in place of consecutively sampled numbers from Python's built-in 
        "random" method! 
        """

        if isinstance(nseed, int):
            assert is_posinteger(nseed), \
               "The seed (if not a feed) must be a positive integer in ABCRand!"
            rstream = Random(nseed)
            self._feed = False
            self.runif01 = rstream.random
            if heir != "InverseRandomStream":
                self.randrange = rstream.randrange
                self.randint = rstream.randint
                self.vonmisesvariate = rstream.vonmisesvariate
                # Random.paretovariate and Random.weibullvariate
                # are used by methods in GeneralRandomStream
                self._paretovariate = rstream.paretovariate
                self._weibullvariate = rstream.weibullvariate

        else:  # nseed is a list or tuple
            # Check to see beforehand that no numbers
            # from the feed is outside [0.0, 1.0]
            for x in nseed:
                assert 0.0 <= x <= 1.0, \
                    "number from feed is outside of [0.0, 1.0] in ABCRand!"
            self._feed = Stack(nseed)  # Creates a Stack object
            self.runif01 = self.__rfeed01
Beispiel #21
0
    def runif_int0N(self, number):
        """
        Generator of uniformly distributed integers in [0, number) (also the 
        basis of some other procedures for generating random variates). 
        Numbers returned are 0 through number-1. NB!!!!!!!
        """

        assert is_posinteger(number)

        return int(number*self.runif01())
Beispiel #22
0
    def runif_int0N(self, number):
        """
        Generator of uniformly distributed integers in [0, number) (also the 
        basis of some other procedures for generating random variates). 
        Numbers returned are 0 through number-1. NB!!!!!!!
        """

        assert is_posinteger(number)

        return int(number * self.runif01())
Beispiel #23
0
    def __init__(self, nseed=2147483647):
        """
        Initiates the object and sets the seed.
        """

        errtxt  = "The seed must be a positive integer in GeneralRandomStream\n"
        errtxt += "\t(external feeds cannot be used)"
        assert is_posinteger(nseed), errtxt

        ABCRand.__init__(self, nseed)
        self._feed = False
Beispiel #24
0
    def __init__(self, nseed=2147483647):
        """
        Initiates the object and sets the seed.
        """

        errtxt = "The seed must be a positive integer in GeneralRandomStream\n"
        errtxt += "\t(external feeds cannot be used)"
        assert is_posinteger(nseed), errtxt

        ABCRand.__init__(self, nseed)
        self._feed = False
Beispiel #25
0
    def __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]!
        """

        if isinstance(nseed, int):
            errtxt  = "The seed (if not a feed) must be a positive\n"
            errtxt += "\tinteger in InverseRandomStream!"
            assert is_posinteger(nseed), errtxt

        ABCRand.__init__(self, nseed, 'InverseRandomStream')
Beispiel #26
0
    def __init__(self, nseed=2147483647):
        """
        Initiates the instance object and sets cumulative quantities to zero.
        """

        errtxt  = "The seed must be a positive integer in CumulRandomStream\n"
        errtxt += "\t(external feeds cannot be used)"
        assert is_posinteger(nseed), errtxt

        rstream      = Random(nseed)
        self.runif01 = rstream.random

        self.__tcum   = 0.0   # For all except rpieceexpo_cum and rinhomexpo_cum
        self.__cumul  = 0.0   # For rpieceexpo_cum
        self.__ticum  = 0.0   # For rinhomexpo_cum
Beispiel #27
0
    def __init__(self, nseed=2147483647):
        """
        Initiates the instance object and sets cumulative quantities to zero.
        """

        errtxt = "The seed must be a positive integer in CumulRandomStream\n"
        errtxt += "\t(external feeds cannot be used)"
        assert is_posinteger(nseed), errtxt

        rstream = Random(nseed)
        self.runif01 = rstream.random

        self.__tcum = 0.0  # For all except rpieceexpo_cum and rinhomexpo_cum
        self.__cumul = 0.0  # For rpieceexpo_cum
        self.__ticum = 0.0  # For rinhomexpo_cum
Beispiel #28
0
    def 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.
        """

        pmx = pmax
        if is_posinteger(nmax): pmx = cpoisson(lam, tspan, nmax)

        p  =  pmx * self.runif01()
        n  =  ipoisson(p, lam, tspan)

        return n
Beispiel #29
0
def cgeometric(phi, k):
    """
    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 
    """

    assert 0.0 < phi and phi <= 1.0, "success frequency must be in (0.0, 1.0] in cgeometric!"
    assert is_posinteger(k), "number of trials must be a positive integer in cgeometric!"

    cdf = 1.0 - (1.0 - phi) ** k

    return cdf
Beispiel #30
0
def lusubs_imp(matrix, lower, upper, bvector, permlist, xvector, \
                                     tolf=SQRTMACHEPS, nitermax=4):
    """
    May be used to polish the result from lusubs (some of the necessary 
    checks are made in lusubs). 
    
    tolf is the maximum fractional difference between two consecutive sums
    of absolute values of the output vector, and nitermax is the maximum 
    number of improvements carried out regardless of whether the tolerance 
    is met or not.
    """

    assert tolf >= 0.0, \
            "max fractional tolerance must not be negative in lusubs_imp!"

    assert is_posinteger(nitermax), \
            "max number of iterations must be a positive number in lusubs_imp!"

    ndim = len(bvector)

    sumx = fsum(abs(x) for x in xvector)
    converged = False
    for n in range(0, nitermax):
        resid = array('d', [])  # will get len = ndim
        for k in range(0, ndim):
            sdp = -bvector[k]
            for j in range(0, ndim):
                sdp += matrix[k][j] * xvector[j]
            resid.append(sdp)
        resid = lusubs(lower, upper, resid, permlist)
        for k in range(0, ndim):
            xvector[k] = xvector[k] - resid[k]
        sumn = fsum(abs(x) for x in xvector)
        if abs(sumn - sumx) < sumn * tolf:
            converged = True
            break
        sumx = sumn

    wtext = "lusubs_imp did not converge. Try changing tolerance or nitermax"
    if not converged: warn(wtext)

    return xvector
Beispiel #31
0
def cgeometric(phi, k):
    """
    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 
    """

    assert 0.0 < phi and phi <= 1.0, \
                     "success frequency must be in (0.0, 1.0] in cgeometric!"
    assert is_posinteger(k), \
                 "number of trials must be a positive integer in cgeometric!"

    cdf = 1.0 - (1.0 - phi)**k

    return cdf
Beispiel #32
0
def lnbincoeff(n, k, integer=True):
    """
    Computation of the natural logarithm of a single binomial coefficient 
    n over k
    """

    assert is_posinteger(n), \
               "n in n_over_k in lnbincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in lnbincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in lnbincoeff!"

    if integer:
        bico    =  _bicolongint(n, k)
        lnbico  =  log(bico)

    else:
        lnbico  =  lngamma(n+1) - lngamma(k+1) - lngamma(n-k+1)

    return lnbico
Beispiel #33
0
def lnbincoeff(n, k, integer=True):
    """
    Computation of the natural logarithm of a single binomial coefficient 
    n over k
    """

    assert is_posinteger(n), \
               "n in n_over_k in lnbincoeff must be a positive integer!"
    assert is_nonneginteger(k), \
           "k in n_over_k in lnbincoeff must be a non-negative integer!"
    assert n >= k, "n must be >= k in n_over_k in lnbincoeff!"

    if integer:
        bico = _bicolongint(n, k)
        lnbico = log(bico)

    else:
        lnbico = lngamma(n + 1) - lngamma(k + 1) - lngamma(n - k + 1)

    return lnbico
Beispiel #34
0
def lusubs_imp(matrix, lower, upper, bvector, permlist, xvector, \
                                     tolf=SQRTMACHEPS, nitermax=4):
    """
    May be used to polish the result from lusubs (some of the necessary 
    checks are made in lusubs). 
    
    tolf is the maximum fractional difference between two consecutive sums
    of absolute values of the output vector, and nitermax is the maximum 
    number of improvements carried out regardless of whether the tolerance 
    is met or not.
    """

    assert tolf >= 0.0, \
            "max fractional tolerance must not be negative in lusubs_imp!"
    
    assert is_posinteger(nitermax), \
            "max number of iterations must be a positive number in lusubs_imp!"

    ndim = len(bvector)

    sumx      = fsum(abs(x) for x in xvector)
    converged = False
    for n in range(0, nitermax):
        resid  = array('d', [])   # will get len = ndim
        for k in range(0, ndim):
            sdp = -bvector[k]
            for j in range(0, ndim):
                sdp += matrix[k][j]*xvector[j]
            resid.append(sdp)
        resid = lusubs(lower, upper, resid, permlist)
        for k in range(0, ndim): xvector[k] = xvector[k] - resid[k]
        sumn = fsum(abs(x) for x in xvector)
        if abs(sumn-sumx) < sumn*tolf:
            converged = True
            break
        sumx = sumn

    wtext = "lusubs_imp did not converge. Try changing tolerance or nitermax"
    if not converged: warn(wtext)

    return xvector
Beispiel #35
0
def sercorr(vector, nlag=1):
    """
    sercorr returns the serial correlation coefficient for the sequence of 
    values in the input vector (list/'d' array/tuple) nlag steps apart.
    """

    assert is_posinteger(nlag), \
                      "Lag ('nlag') must be a positive integer in sercorr!"
    nlagp2 = nlag + 2
    assert len(vector) >= nlagp2, "There must be at least " + str(nlagp2) + \
                                  " elements in input sequence to sercorr!"

    vector1 = list(vector)
    vector2 = list(vector)
    for k in range(0, nlag):
        del vector1[-1]
        del vector2[0]

    amean1, amean2, var1, var2, cov12, rho12  =  covar(vector1, vector2)

    return rho12
Beispiel #36
0
def sercorr(vector, nlag=1):
    """
    sercorr returns the serial correlation coefficient for the sequence of 
    values in the input vector (list/'d' array/tuple) nlag steps apart.
    """

    assert is_posinteger(nlag), \
                      "Lag ('nlag') must be a positive integer in sercorr!"
    nlagp2 = nlag + 2
    assert len(vector) >= nlagp2, "There must be at least " + str(nlagp2) + \
                                  " elements in input sequence to sercorr!"

    vector1 = list(vector)
    vector2 = list(vector)
    for k in range(0, nlag):
        del vector1[-1]
        del vector2[0]

    amean1, amean2, var1, var2, cov12, rho12 = covar(vector1, vector2)

    return rho12
Beispiel #37
0
def bracketzero(func,
                x1,
                x2,
                caller='caller',
                factor=GOLDPHI1,
                maxniter=32):  # GOLDPHI1 is approx. 1.6
    """
    Bracket a root by expanding from the input "guesses" x1, x2. 
    NB. It is not required that x2 > x1.
    Designed for use prior to any of the one-variable equation solvers. 
    
    The function carries out a maximum of 'maxniter' iterations, 
    each one expanding the original span by a factor of 'factor', 
    until a span is reached in which there is a zero crossing.
    """

    assert factor > 1.0, "Expansion factor must be > 1.0 in bracketzero!"
    assert is_posinteger(maxniter), \
       "Maximum number of iterations must be a positive integer in bracketzero!"

    lo = min(x1, x2)
    up = max(x1, x2)

    flo = func(lo)
    fup = func(up)

    for k in range(0, maxniter):

        if fsign(flo) != fsign(fup): return lo, up

        if abs(flo) < abs(fup):
            lo += factor * (lo - up)
            flo = func(lo)
        else:
            up += factor * (up - lo)
            fup = func(up)

    errtxt1 = "Root bracketing failed after " + str(maxniter)
    errtxt2 = " iterations in bracketzero " + "(called from " + caller + ")"
    raise Error(errtxt1 + errtxt2)
Beispiel #38
0
    def rpoisson(self, lam, tspan, nmax=False):
        """
        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.
        """

        assert  lam  >= 0.0, "Poisson rate must not be negative in rpoisson!"
        assert tspan >= 0.0, "time span must not be negative in rpoisson!"

        if is_posinteger(nmax): nmaxflag = True
        else:                   nmaxflag = False

        lamtau = lam*tspan

        if lamtau < 64.0:
            while True:
                p = self.runif01()
                n = 0
                r = exp(-lamtau)
                c = r
                f = float(lamtau)
                while c <= p:
                    n  = n + 1
                    r *= f/n
                    c += r
                if not nmaxflag:         break
                if nmaxflag and n<=nmax: break

            n = max(0, n)
            return n

        else:
            while True:
                p = self.runif01()
                n = ipoisson(p, lam, tspan)  # Faster than rej'n vs. the Cauchy
                if not nmaxflag:         break
                if nmaxflag and n<=nmax: break
Beispiel #39
0
    def rpoisson(self, lam, tspan, nmax=False):
        """
        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.
        """

        assert lam >= 0.0, "Poisson rate must not be negative in rpoisson!"
        assert tspan >= 0.0, "time span must not be negative in rpoisson!"

        if is_posinteger(nmax): nmaxflag = True
        else: nmaxflag = False

        lamtau = lam * tspan

        if lamtau < 64.0:
            while True:
                p = self.runif01()
                n = 0
                r = exp(-lamtau)
                c = r
                f = float(lamtau)
                while c <= p:
                    n = n + 1
                    r *= f / n
                    c += r
                if not nmaxflag: break
                if nmaxflag and n <= nmax: break

            n = max(0, n)
            return n

        else:
            while True:
                p = self.runif01()
                n = ipoisson(p, lam, tspan)  # Faster than rej'n vs. the Cauchy
                if not nmaxflag: break
                if nmaxflag and n <= nmax: break
Beispiel #40
0
    def sercorrnormvector(self, n, rho, mu=0.0, sigma=1.0):
        """
        Generates a list of serially correlated normal random 
        variates. Requires that the rstream object is punched 
        out from the GeneralRandomStream class!
        """

        # Input check -----
        assert is_posinteger(n)
        # sigma and rho are checked in rstream.rnormal and rstream.rcorr_normal
        # -----------------

        vector = []
        rstream = self.rstream

        x = rstream.rnormal(mu, sigma)
        vector.append(x)
        for k in range(1, n):
            x = rstream.rcorr_normal(rho, mu, sigma, mu, sigma, x)
            vector.append(x)

        return vector
Beispiel #41
0
    def sercorrnormvector(self, n, rho, mu=0.0, sigma=1.0):
        """
        Generates a list of serially correlated normal random 
        variates. Requires that the rstream object is punched 
        out from the GeneralRandomStream class!
        """

        # Input check -----
        assert is_posinteger(n)
        # sigma and rho are checked in rstream.rnormal and rstream.rcorr_normal
        # -----------------

        vector  = []
        rstream = self.rstream

        x = rstream.rnormal(mu, sigma)
        vector.append(x)
        for k in range(1, n):
            x = rstream.rcorr_normal(rho, mu, sigma, mu, sigma, x)
            vector.append(x)

        return vector
Beispiel #42
0
def cerlang_gen(nshapes, pcumul, phasemean, x):
    """
    The generalized Erlang distribution - the Erlang equivalent of the hyperexpo
    distribution 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 PROBABILITIES ! 
    """

    ln = len(nshapes)
    lp = len(pcumul)

    # Input check -----------------
    assert x >= 0.0, "variate must not be negative in cerlang_gen!"
    assert lp == ln, "number of shapes must be equal to the number of pcumuls in cerlang_gen!"
    if ln == 1:
        return derlang(nshapes[0], phasemean, x)
    errortextn = "all nshapes must be positive integers i cerlang_gen!"
    errortextm = "the mean must be a positive float in cerlang_gen!"
    errortextp = "pcumul list is not in order in cerlang_gen!"
    for n in nshapes:
        assert is_posinteger(n), errortextn
    assert phasemean > 0.0, errortextm
    assert pcumul[-1] == 1.0, errortextp
    assert 0.0 < pcumul[0] and pcumul[0] <= 1.0, errortextp
    # -----------------------------

    summ = pcumul[0] * cerlang(nshapes[0], phasemean, x)
    nvalues = lp
    for k in range(1, nvalues):
        pdiff = pcumul[k] - pcumul[k - 1]
        assert pdiff >= 0.0, errortextp
        summ += pdiff * cerlang(nshapes[k], phasemean, x)
    cdf = summ

    cdf = kept_within(0.0, cdf, 1.0)

    return cdf
Beispiel #43
0
def derlang_gen(nshapes, pcumul, phasemean, x):
    """
    The pdf of the generalized Erlang distribution - the Erlang equivalent 
    of the hyperexpo distribution:
    f = sumk pk * ferlang(m, nk) 
    F = sumk pk * Ferlang(m, nk) 
    with the same mean for all phases.
    
    NB Input to the function is the list of CUMULATIVE PROBABILITIES ! 
    """

    ln = len(nshapes)
    lp = len(pcumul)

    # Input check -----------------
    assert x >= 0.0, "variate must not be negative in derlang_gen!"
    assert lp == ln, \
       "number of shapes must be equal to the number of pcumuls in derlang_gen!"
    if ln == 1: return cerlang(nshapes[0], mean, x)
    errortextn = "all nshapes must be positiva heltal i derlang_gen!"
    errortextm = "the mean must be a positive float in derlang_gen!"
    errortextp = "pcumul list is not in order in derlang_gen!"
    for n in nshapes:
        assert is_posinteger(n), errortextn
    assert phasemean > 0.0, errortextm
    assert pcumul[-1] == 1.0, errortextp
    assert 0.0 < pcumul[0] and pcumul[0] <= 1.0, errortextp
    # -----------------------------

    summ = pcumul[0] * derlang(nshapes[0], phasemean, x)
    nvalues = lp
    for k in range(1, nvalues):
        pdiff = pcumul[k] - pcumul[k - 1]
        assert pdiff >= 0.0, errortextp
        summ += pdiff * derlang(nshapes[k], phasemean, x)
    pdf = summ

    return pdf
Beispiel #44
0
def bracketzero(func, x1, x2, caller='caller', 
                factor=GOLDPHI1, maxniter=32):  # GOLDPHI1 is approx. 1.6
    """
    Bracket a root by expanding from the input "guesses" x1, x2. 
    NB. It is not required that x2 > x1.
    Designed for use prior to any of the one-variable equation solvers. 
    
    The function carries out a maximum of 'maxniter' iterations, 
    each one expanding the original span by a factor of 'factor', 
    until a span is reached in which there is a zero crossing.
    """

    assert factor > 1.0, "Expansion factor must be > 1.0 in bracketzero!"
    assert is_posinteger(maxniter), \
       "Maximum number of iterations must be a positive integer in bracketzero!"

    lo = min(x1, x2)
    up = max(x1, x2)

    flo = func(lo)
    fup = func(up)

    for k in range(0, maxniter):

        if fsign(flo) != fsign(fup): return lo, up

        if abs(flo) < abs(fup):
            lo += factor*(lo-up)
            flo = func(lo)
        else:
            up += factor*(up-lo)
            fup = func(up)

    errtxt1 = "Root bracketing failed after " + str(maxniter)
    errtxt2 = " iterations in bracketzero " + "(called from " + caller + ")"
    raise Error(errtxt1 + errtxt2)
Beispiel #45
0
def cgamma(alpha, lam, x, lngamalpha=False, tolf=FOURMACHEPS, itmax=128):
    """
    The gamma distrib. f = lam * exp(-lam*x) * (lam*x)**(alpha-1) / gamma(alpha)
    F is the integral = the incomplete gamma or the incomplete gamma / complete 
    gamma depending on how the incomplete gamma function is defined.
    x, lam, alpha >= 0
    tolf  =  allowed fractional error in computation of the incomplete function
    itmax =  maximum number of iterations to obtain accuracy 

    NB It is possible to gain efficiency by providing the value of the 
    natural logarithm of the complete gamma function ln(gamma(alpha)) 
    as a pre-computed input (may be computed using numlib.specfunc.lngamma) 
    instead of the default 'False'.
    """

    assert alpha >= 0.0, "alpha must not be negative in cgamma!"
    assert lam >= 0.0, "lambda must not be negative i cgamma!"
    assert x >= 0.0, "variate must not be negative in cgamma!"
    assert tolf >= 0.0, "tolerance must not be negative in cgamma!"
    assert is_posinteger(itmax), "maximum number of iterations must be a positive integer in cgamma!"

    if alpha == 1.0:
        return cexpo(1.0 / lam, x)

    lamx = lam * x
    if lamx == 0.0:
        return 0.0
    if lngamalpha:
        lnga = lngamalpha
    else:
        lnga = lngamma(alpha)

    # -------------------------------------------------------------------------
    def _gamser():
        # A series expansion is used for lamx < alpha + 1.0
        # (cf. Abramowitz & Stegun)
        apn = alpha
        summ = 1.0 / apn
        dela = summ
        converged = False
        for k in range(0, itmax):
            apn += 1.0
            dela = dela * lamx / apn
            summ += dela
            if abs(dela) < abs(summ) * tolf:
                converged = True
                return summ * exp(-lamx + alpha * log(lamx) - lnga), converged
        return summ * exp(-lamx + alpha * log(lamx) - lnga), converged

    # -------------------------------------------------------------------------
    def _gamcf():
        # A continued fraction expansion is used for
        # lamx >= alpha + 1.0 (cf. Abramowitz & Stegun):
        gold = 0.0
        a0 = 1.0
        a1 = lamx
        b0 = 0.0
        b1 = 1.0
        fac = 1.0
        converged = False
        for k in range(0, itmax):
            ak = float(k + 1)
            aka = ak - alpha
            a0 = (a1 + a0 * aka) * fac
            b0 = (b1 + b0 * aka) * fac
            akf = ak * fac
            a1 = lamx * a0 + akf * a1
            b1 = lamx * b0 + akf * b1
            if a1 != 0.0:
                fac = 1.0 / a1
                g = b1 * fac
                if abs(g - gold) < abs(g) * tolf:
                    converged = True
                    return 1.0 - exp(-lamx + alpha * log(lamx) - lnga) * g, converged
                gold = g
        return 1.0 - exp(-lamx + alpha * log(lamx) - lnga) * g, converged

    # -------------------------------------------------------------------------

    if lamx < alpha + 1.0:
        cdf, converged = _gamser()
    else:
        cdf, converged = _gamcf()

    if not converged:
        warn("cgamma has not converged for itmax = " + str(itmax) + " and tolf = " + str(tolf))

    cdf = kept_within(0.0, cdf, 1.0)

    return cdf
Beispiel #46
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
Beispiel #47
0
def zbrent(func, x1, x2, caller='caller', tolf=FOURMACHEPS, \
                         tola=SQRTTINY, maxniter=128, bracket=False):
    """
    Solves the equation func(x) = 0 on [x1, x2] using a variant of Richard 
    Brent's algorithm (more like the "ZEROIN" of Forsythe-Malcolm-Moler). 
    
    NB. The function always returns a value but a warning is printed to stdout 
    if the iteration procedure has not converged! Cf. comment below regarding 
    convergence! 
    
    Arguments:
    ----------
    func      Function having the proposed root as its argument

    x1        Lower search limit (root must be known to be >= x1 unless 
              prior bracketing is used)
    
    x2        Upper search limit (root must be known to be <= x2 unless 
              prior bracketing is used)

    tolf      Desired fractional accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola). tolf 
              should not be < 4.0*machine epsilon since this may inhibit 
              convergence!

    tola      Desired absolute accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)

    maxniter  Maximum number of iterations

    bracket   If True, x1 and x2 are used in an initial bracketing before 
              solving

    Returns:
    ---------
    Final value of root

    This algorithm is claimed to guarantee convergence within about 
    (log2((b-a)/tol))**2 function evaluations, which is more demanding 
    than bisection. For instance: b-a = 1.0 and tol = 1.8e-12 is guaranteed 
    to converge with about 1,500 evaluations. It normally converges with 
    fewer ITERATIONS, however, and for reasonably "smooth and well-behaved" 
    functions it will be on the average more efficient and accurate than 
    bisection. For details on the algorithm see Forsythe-Malcolm-Moler, 
    as well as Brent, R.P.; "An algorithm with guaranteed convergence 
    for finding a zero of a function", The Computer Journal 14(4), 
    pp. 422-425, 1971.
    """

    if tolf < FOURMACHEPS:
        tolf  = FOURMACHEPS
        wtxt1 = "Fractional tol. less than 4.0*machine epsilon may prevent "
        wtxt2 = "convergence in zbrent. 4.0*macheps will be used instead!"
        warn(wtxt1+wtxt2)

    if tola < 0.0:
        tola  = 0.0
        wtxt1 = "Negative absolute tolerance is not a good idea "
        wtxt2 = "in zbrent. 0.0 (zero) will be used instead!"
        warn(wtxt1+wtxt2)

    assert is_posinteger(maxniter), \
            "Maximum number of iterations must be a positive integer in zbrent!"

    if bracket: x1, x2 = bracketzero(func, x1, x2, caller, maxniter)

    assert x2 > x1, "Bounds must be given with the lower bound first in zbrent!"


    a       = x1
    b       = x2
    c       = x2 ###############################  NOT IN REFERENCES !!!!!
    fa      = func(x1)
    if fa == 0.0: return x1
    fb      = func(x2)
    if fb == 0.0: return x2
    if fsign(fa) == fsign(fb):
        x1, x2 = bracketzero(func, x1, x2, caller, maxniter)
        wtxt1 = "Starting points must be on opposite sides of the root in "
        wtxt2 = "zbrent. Bracketing will be used to find an appropriate span!"
        warn(wtxt1+wtxt2)
    fc      = fb

    niter = 0
    while niter <= maxniter:
        niter += 1

        if fsign(fb) == fsign(fc):
            c  = a
            fc = fa
            d  = b - a
            e  = d

        if abs(fc) < abs(fb):
            a  = b
            b  = c
            c  = a
            fa = fb
            fb = fc
            fc = fa

        tol  = tolf*abs(b) + tola
        tol1 = 0.5 * tol
        xm   = 0.5 * (c-b)

        if abs(xm) <= tol1 or fb == 0.0: return b

        if abs(e) >= tol1 and abs(fa) > abs(fb):
            s = fb / fa
            if a == c:
                p = 2.0 * xm * s
                q = 1.0 - s
            else:
                q = fa / fc
                r = fb / fc
                p = s * (2.0*xm*q*(q-r)-(b-a)*(r-1.0))
                q = (q-1.0) * (r-1.0) * (s-1.0)

            if p > 0.0: q = -q
            p = abs(p)
            if 2.0*p < min(3.0*xm*q-abs(tol1*q), abs(e*q)):
                e = d
                d = p / q
            else:
                d = xm
                e = d

        else:
            d = xm
            e = d

        a  = b
        fa = fb

        if abs(d) > tol1:
            b = b + d
        else:
            #b = b + sign(tol1, xm)
            if   xm < 0.0: b = b - tol1
            elif xm > 0.0: b = b + tol1
            else:          b = b

        fb = func(b)

    else:
        numb  = int(math.log((x2-x1)/tol, 2)**2 + 0.5)
        wtxt1 = str(maxniter) + " iterations not sufficient in zbrent called by"
        wtxt2 = " " + caller + ". func(x) = " + str(fb) + " for x = " + str(b)
        warn(wtxt1+wtxt2)
        return b
Beispiel #48
0
def zbisect(func, x1, x2, caller='caller', tolf=FOURMACHEPS, \
                          tola=SQRTTINY, maxniter=256, bracket=False):
    """
    Solves the equation func(x) = 0 on [x1, x2] using a bisection algorithm. 
    zbisect converges slower than zbrent in most cases, but it might be faster 
    in some cases!
    
    NB. The function always returns a value but a warning is printed to stdout 
    if the iteration procedure has not converged! Cf. comment below regarding 
    convergence!

    Arguments:
    ----------
    func      Function having the proposed root as its argument
    
    x1        Lower search limit (root must be known to be >= x1 unless 
              prior bracketing is used)
    
    x2        Upper search limit (root must be known to be <= x2 unless 
              prior bracketing is used)
    
    tolf      Desired fractional accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)

    tola      Desired absolute accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)
              AND
              desired max absolute difference of func(root) from zero

    maxniter  Maximum number of iterations

    bracket   If True, x1 and x2 are used in an initial bracketing before 
              solving 

    Returns:
    ---------
    Final value of root
    
    This algorithm needs on the average log2((b-a)/tol) function evaluations to 
    reach convergence. For instance: b-a = 1.0 and tol = 1.8e-12 will on the 
    average provide convergence in about 40 iterations. Bisection is "dead 
    certain" and will always converge if there is a root. It is likely to pass 
    the tolerances with no extra margin. If there is no root, it will converge 
    to a singularity if there is one...
    """

    if tolf < MACHEPS:
        tolf = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in zbisect. Machine epsilon will be used instead!"
        warn(wtxt1 + wtxt2)

    if tola < 0.0:
        tola = 0.0
        wtxt1 = "Negative absolute tolerance is not a good idea "
        wtxt2 = "in zbisect. 0.0 (zero) will be used instead!"
        warn(wtxt1 + wtxt2)

    assert is_posinteger(maxniter), \
          "Maximum number of iterations must be a positive integer in zbisect!"

    if bracket: x1, x2 = bracketzero(func, x1, x2, caller, maxniter)

    assert x2 > x1, \
                  "Bounds must be given with the lower bound first in zbisect!"

    fmid = func(x2)
    if fmid == 0.0: return x2
    f = func(x1)
    if f == 0.0: return x1
    if fsign(fmid) == fsign(f):
        x1, x2 = bracketzero(func, x1, x2, caller, maxniter)
        wtxt1 = "Starting points must be on opposite sides of the root in "
        wtxt2 = "zbisect. Bracketing will be used to find an appropriate span!"
        warn(wtxt1 + wtxt2)

    if f < 0.0:
        root = x1
        h = x2 - x1
    else:
        root = x2
        h = x1 - x2

    niter = 0
    while niter <= maxniter:
        niter += 1
        h = 0.5 * h
        xmid = root + h
        fmid = func(xmid)
        if abs(fmid) < tola: return xmid
        if fmid <= 0.0: root = xmid
        absh = abs(h)
        if absh < tolf * abs(root) + tola: return root

    else:
        wtxt1 = str(maxniter) + " it'ns not sufficient in zbisect called by "
        wtxt2 = caller + ".\nfunc(x) = " + str(fmid) + " for x = " + str(root)
        warn(wtxt1 + wtxt2)
        return root
Beispiel #49
0
def zbrent(func, x1, x2, caller='caller', tolf=FOURMACHEPS, \
                         tola=SQRTTINY, maxniter=128, bracket=False):
    """
    Solves the equation func(x) = 0 on [x1, x2] using a variant of Richard 
    Brent's algorithm (more like the "ZEROIN" of Forsythe-Malcolm-Moler). 
    
    NB. The function always returns a value but a warning is printed to stdout 
    if the iteration procedure has not converged! Cf. comment below regarding 
    convergence! 
    
    Arguments:
    ----------
    func      Function having the proposed root as its argument

    x1        Lower search limit (root must be known to be >= x1 unless 
              prior bracketing is used)
    
    x2        Upper search limit (root must be known to be <= x2 unless 
              prior bracketing is used)

    tolf      Desired fractional accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola). tolf 
              should not be < 4.0*machine epsilon since this may inhibit 
              convergence!

    tola      Desired absolute accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)

    maxniter  Maximum number of iterations

    bracket   If True, x1 and x2 are used in an initial bracketing before 
              solving

    Returns:
    ---------
    Final value of root

    This algorithm is claimed to guarantee convergence within about 
    (log2((b-a)/tol))**2 function evaluations, which is more demanding 
    than bisection. For instance: b-a = 1.0 and tol = 1.8e-12 is guaranteed 
    to converge with about 1,500 evaluations. It normally converges with 
    fewer ITERATIONS, however, and for reasonably "smooth and well-behaved" 
    functions it will be on the average more efficient and accurate than 
    bisection. For details on the algorithm see Forsythe-Malcolm-Moler, 
    as well as Brent, R.P.; "An algorithm with guaranteed convergence 
    for finding a zero of a function", The Computer Journal 14(4), 
    pp. 422-425, 1971.
    """

    if tolf < FOURMACHEPS:
        tolf = FOURMACHEPS
        wtxt1 = "Fractional tol. less than 4.0*machine epsilon may prevent "
        wtxt2 = "convergence in zbrent. 4.0*macheps will be used instead!"
        warn(wtxt1 + wtxt2)

    if tola < 0.0:
        tola = 0.0
        wtxt1 = "Negative absolute tolerance is not a good idea "
        wtxt2 = "in zbrent. 0.0 (zero) will be used instead!"
        warn(wtxt1 + wtxt2)

    assert is_posinteger(maxniter), \
            "Maximum number of iterations must be a positive integer in zbrent!"

    if bracket: x1, x2 = bracketzero(func, x1, x2, caller, maxniter)

    assert x2 > x1, "Bounds must be given with the lower bound first in zbrent!"

    a = x1
    b = x2
    c = x2  ###############################  NOT IN REFERENCES !!!!!
    fa = func(x1)
    if fa == 0.0: return x1
    fb = func(x2)
    if fb == 0.0: return x2
    if fsign(fa) == fsign(fb):
        x1, x2 = bracketzero(func, x1, x2, caller, maxniter)
        wtxt1 = "Starting points must be on opposite sides of the root in "
        wtxt2 = "zbrent. Bracketing will be used to find an appropriate span!"
        warn(wtxt1 + wtxt2)
    fc = fb

    niter = 0
    while niter <= maxniter:
        niter += 1

        if fsign(fb) == fsign(fc):
            c = a
            fc = fa
            d = b - a
            e = d

        if abs(fc) < abs(fb):
            a = b
            b = c
            c = a
            fa = fb
            fb = fc
            fc = fa

        tol = tolf * abs(b) + tola
        tol1 = 0.5 * tol
        xm = 0.5 * (c - b)

        if abs(xm) <= tol1 or fb == 0.0: return b

        if abs(e) >= tol1 and abs(fa) > abs(fb):
            s = fb / fa
            if a == c:
                p = 2.0 * xm * s
                q = 1.0 - s
            else:
                q = fa / fc
                r = fb / fc
                p = s * (2.0 * xm * q * (q - r) - (b - a) * (r - 1.0))
                q = (q - 1.0) * (r - 1.0) * (s - 1.0)

            if p > 0.0: q = -q
            p = abs(p)
            if 2.0 * p < min(3.0 * xm * q - abs(tol1 * q), abs(e * q)):
                e = d
                d = p / q
            else:
                d = xm
                e = d

        else:
            d = xm
            e = d

        a = b
        fa = fb

        if abs(d) > tol1:
            b = b + d
        else:
            #b = b + sign(tol1, xm)
            if xm < 0.0: b = b - tol1
            elif xm > 0.0: b = b + tol1
            else: b = b

        fb = func(b)

    else:
        numb = int(math.log((x2 - x1) / tol, 2)**2 + 0.5)
        wtxt1 = str(
            maxniter) + " iterations not sufficient in zbrent called by"
        wtxt2 = " " + caller + ". func(x) = " + str(fb) + " for x = " + str(b)
        warn(wtxt1 + wtxt2)
        return b
Beispiel #50
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
Beispiel #51
0
def cgamma(alpha, lam, x, lngamalpha=False, tolf=FOURMACHEPS, itmax=128):
    """
    The gamma distrib. f = lam * exp(-lam*x) * (lam*x)**(alpha-1) / gamma(alpha)
    F is the integral = the incomplete gamma or the incomplete gamma / complete 
    gamma depending on how the incomplete gamma function is defined.
    x, lam, alpha >= 0
    tolf  =  allowed fractional error in computation of the incomplete function
    itmax =  maximum number of iterations to obtain accuracy 

    NB It is possible to gain efficiency by providing the value of the 
    natural logarithm of the complete gamma function ln(gamma(alpha)) 
    as a pre-computed input (may be computed using numlib.specfunc.lngamma) 
    instead of the default 'False'.
    """

    assert alpha >= 0.0, "alpha must not be negative in cgamma!"
    assert lam >= 0.0, "lambda must not be negative i cgamma!"
    assert x >= 0.0, "variate must not be negative in cgamma!"
    assert tolf >= 0.0, "tolerance must not be negative in cgamma!"
    assert is_posinteger(itmax), \
           "maximum number of iterations must be a positive integer in cgamma!"

    if alpha == 1.0: return cexpo(1.0 / lam, x)

    lamx = lam * x
    if lamx == 0.0: return 0.0
    if lngamalpha: lnga = lngamalpha
    else: lnga = lngamma(alpha)

    # -------------------------------------------------------------------------
    def _gamser():
        # A series expansion is used for lamx < alpha + 1.0
        # (cf. Abramowitz & Stegun)
        apn = alpha
        summ = 1.0 / apn
        dela = summ
        converged = False
        for k in range(0, itmax):
            apn += 1.0
            dela = dela * lamx / apn
            summ += dela
            if abs(dela) < abs(summ) * tolf:
                converged = True
                return summ * exp(-lamx + alpha * log(lamx) - lnga), converged
        return summ * exp(-lamx + alpha * log(lamx) - lnga), converged

    # -------------------------------------------------------------------------
    def _gamcf():
        # A continued fraction expansion is used for
        # lamx >= alpha + 1.0 (cf. Abramowitz & Stegun):
        gold = 0.0
        a0 = 1.0
        a1 = lamx
        b0 = 0.0
        b1 = 1.0
        fac = 1.0
        converged = False
        for k in range(0, itmax):
            ak = float(k + 1)
            aka = ak - alpha
            a0 = (a1 + a0 * aka) * fac
            b0 = (b1 + b0 * aka) * fac
            akf = ak * fac
            a1 = lamx * a0 + akf * a1
            b1 = lamx * b0 + akf * b1
            if a1 != 0.0:
                fac = 1.0 / a1
                g = b1 * fac
                if abs(g - gold) < abs(g) * tolf:
                    converged = True
                    return 1.0 - exp(-lamx + alpha * log(lamx) -
                                     lnga) * g, converged
                gold = g
        return 1.0 - exp(-lamx + alpha * log(lamx) - lnga) * g, converged

    # -------------------------------------------------------------------------

    if lamx < alpha + 1.0:
        cdf, converged = _gamser()
    else:
        cdf, converged = _gamcf()

    if not converged:
        warn("cgamma has not converged for itmax = " + \
                     str(itmax) + " and tolf = " + str(tolf))

    cdf = kept_within(0.0, cdf, 1.0)

    return cdf
Beispiel #52
0
def talbot(ftilde, tim, sigma, nu=1.0, tau=3.0, ntrap=32):
    """
    Function: computes the value of the inverse Laplace transform of a
              given complex function for a given time using Talbot's 
              algorithm. It calculates the sum in formula (31) on p. 104 
              in A. Talbot: J Inst Maths Applics 23(1979), 97-120. 
              Besides making sure that the special Talbotian integration 
              contour is to the right of all poles (the algorithm works 
              best when all poles are located on the real axis...), the 
              user also has to make sure that the contour does not coincide 
              with other singularities.

    Inputs:
    Name      Description
    ------    -----------
    ftilde    name of function to be inverted (must be a separate complex 
              function having one complex argument)

    tim       time for which the inversion is to be carried out 
              (float; must be > 0.0)

    sigma     shift parameter of the talbot integration contour; determined 
              by the position of the rightmost pole of ftilde: its value 
              (float) must be located to the right of all singularities but
              should be as close to the rightmost singularity as possible 
              (imprves accuracy and helps reducing the number of steps needed 
              for the integration)

    nu        shape parameter (float; > 0.0)

    tau       scale parameter (float; > 0.0)

    ntrap     number of points in trapezoidal integration (integer; > 0)
              (actually: one more will be used for the first term/point).
              Try using fewer than the default - a good choice of sigma
              will help!

    Outputs:
    Name      Description
    ------    -----------
    fnval     value of inverse (float)
    """

    # --------------------------------

    assert tim > 0.0, "time must be a positive float in talbot!"
    assert nu  > 0.0, "the shape parameter must be a positive float in talbot!"
    assert tau > 0.0, "the scale parameter must be a positive float in talbot!"
    assert is_posinteger(ntrap), \
                    "the number of steps must be a positive integer in talbot!"


    # Compute scaled inverted time
    lam    = tau / tim

    # Initiate lists for subsequent summing (positive and negative 
    # terms are summed separately to prevent cancellation)
    termn  = []
    termp  = []

    # Compute the first term of the series
    thetak =  0.0
    term   =  0.5 * _refthetak(ftilde, sigma, nu, tau, lam, thetak)
    if   term < 0.0: termn.append(term)
    elif term > 0.0: termp.append(term)
    #else: no need to add zeros

    # Compute the rest of the terms
    aux = PI / ntrap
    for k in range(1, ntrap):
        thetak =  k * aux
        term   =  _refthetak(ftilde, sigma, nu, tau, lam, thetak)
        if   term < 0.0:  termn.append(term)
        elif term > 0.0:  termp.append(term)
        #else: no need to add zeros

    # Sort the positive terms in ascending order and sum them up
    termp.sort()
    sump  =  sum(trm for trm in termp)

    # Sort the negative terms in descending order and sum them up
    termn.sort()
    termn.reverse()
    sumn  =  sum(trm for trm in termn)

    # Combine sums and multiply by constant factor to obtain final sum/value
    summ   =  sump + sumn
    ratio  =  lam / ntrap
    fnval  =  summ * exp(sigma*tim) * ratio

    return fnval
Beispiel #53
0
def zbisect(func, x1, x2, caller='caller', tolf=FOURMACHEPS, \
                          tola=SQRTTINY, maxniter=256, bracket=False):
    """
    Solves the equation func(x) = 0 on [x1, x2] using a bisection algorithm. 
    zbisect converges slower than zbrent in most cases, but it might be faster 
    in some cases!
    
    NB. The function always returns a value but a warning is printed to stdout 
    if the iteration procedure has not converged! Cf. comment below regarding 
    convergence!

    Arguments:
    ----------
    func      Function having the proposed root as its argument
    
    x1        Lower search limit (root must be known to be >= x1 unless 
              prior bracketing is used)
    
    x2        Upper search limit (root must be known to be <= x2 unless 
              prior bracketing is used)
    
    tolf      Desired fractional accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)

    tola      Desired absolute accuracy of root (a combination of fractional 
              and absolute will actually be used: tolf*abs(root) + tola)
              AND
              desired max absolute difference of func(root) from zero

    maxniter  Maximum number of iterations

    bracket   If True, x1 and x2 are used in an initial bracketing before 
              solving 

    Returns:
    ---------
    Final value of root
    
    This algorithm needs on the average log2((b-a)/tol) function evaluations to 
    reach convergence. For instance: b-a = 1.0 and tol = 1.8e-12 will on the 
    average provide convergence in about 40 iterations. Bisection is "dead 
    certain" and will always converge if there is a root. It is likely to pass 
    the tolerances with no extra margin. If there is no root, it will converge 
    to a singularity if there is one...
    """

    if tolf < MACHEPS:
        tolf  = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in zbisect. Machine epsilon will be used instead!"
        warn(wtxt1+wtxt2)

    if tola < 0.0:
        tola  = 0.0
        wtxt1 = "Negative absolute tolerance is not a good idea "
        wtxt2 = "in zbisect. 0.0 (zero) will be used instead!"
        warn(wtxt1+wtxt2)

    assert is_posinteger(maxniter), \
          "Maximum number of iterations must be a positive integer in zbisect!"

    if bracket: x1, x2 = bracketzero(func, x1, x2, caller, maxniter)

    assert x2 > x1, \
                  "Bounds must be given with the lower bound first in zbisect!"


    fmid = func(x2)
    if fmid == 0.0: return x2
    f    = func(x1)
    if f   ==  0.0: return x1
    if fsign(fmid) == fsign(f):
        x1, x2 = bracketzero(func, x1, x2, caller, maxniter)
        wtxt1 = "Starting points must be on opposite sides of the root in "
        wtxt2 = "zbisect. Bracketing will be used to find an appropriate span!"
        warn(wtxt1+wtxt2)

    if f < 0.0:
        root = x1
        h    = x2 - x1
    else:
        root = x2
        h    = x1 - x2
    
    niter = 0
    while niter <= maxniter:
        niter += 1
        h      = 0.5 * h
        xmid   = root + h
        fmid   = func(xmid)
        if abs(fmid) < tola: return xmid
        if fmid <= 0.0: root = xmid
        absh = abs(h)
        if absh < tolf*abs(root) + tola: return root
        
    else:
        wtxt1 = str(maxniter) + " it'ns not sufficient in zbisect called by "
        wtxt2 = caller + ".\nfunc(x) = " + str(fmid) + " for x = " + str(root)
        warn(wtxt1+wtxt2)
        return root