示例#1
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
示例#2
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
示例#3
0
def ffactorial(n, integer=True):
    """
    Computation of a factorial, returning a float. If integer=True a rounded 
    float obtained from integer arithmetics is returned. If integer=False a 
    rounded float obtained from floating-point arithmetics based on the 
    function lngamma is returned. 
    
    Rounding may cause the return of an approximate result rather than an 
    exact. 
    
    float('inf') is returned if an OverflowError occurs.
    """

    assert is_nonneginteger(n), \
              "the argument to ffactorial must be a non-negative integer!"

    if integer:
        fact = factorial(n)
        try:
            ffact = round(float(fact))
        except OverflowError:
            ffact = float('inf')

    else:
        try:
            ffact = round(exp(lngamma(n + 1.0)))
        except OverflowError:
            ffact = float('inf')

    return ffact
示例#4
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
示例#5
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
示例#6
0
def ffactorial(n, integer=True):
    """
    Computation of a factorial, returning a float. If integer=True a rounded 
    float obtained from integer arithmetics is returned. If integer=False a 
    rounded float obtained from floating-point arithmetics based on the 
    function lngamma is returned. 
    
    Rounding may cause the return of an approximate result rather than an 
    exact. 
    
    float('inf') is returned if an OverflowError occurs.
    """

    assert is_nonneginteger(n), \
              "the argument to ffactorial must be a non-negative integer!"

    if integer:
        fact = factorial(n)
        try:
            ffact = round(float(fact))
        except OverflowError:
            ffact = float('inf')

    else:
        try:
            ffact = round(exp(lngamma(n+1.0)))
        except OverflowError:
            ffact = float('inf')

    return ffact
示例#7
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)
示例#8
0
def qromberg(func, a, b, caller='caller', tolf=TWOMACHEPS, maxnsplits=16):
    """
    Romberg integration of a function of one variable over the interval [a, b]. 
    'caller' is the name of the program, method or function calling qromberg.
    'tolf' is the maximum allowed fractional difference between the two last 
    "tail" integrals on the "T table diagonal". 'maxnsplits' is the maximum 
    number of consecutive splits of the subintervals into halves.
    (cf. Davis-Rabinowitz and Dahlquist-Bjorck-Anderson).
    """

    span  =  b - a
    assert span >= 0.0, \
               "Integration limits must be in increasing order in qromberg!"
    assert is_nonneginteger(maxnsplits), \
           "Max number of splits must be a nonnegative integer in qromberg!"

    m  = 1; n  =  1
    summ       =  0.5 * (func(a)+func(b))
    intgrl     =  span * summ
    ttable     =  [[intgrl]]    # First entry into T table (a nested list)
    previntgrl =  (1.0 + 2.0*tolf)*intgrl  # Ascertains intgrl != previntgrl...
    adiff      = abs(intgrl-previntgrl)

    while (adiff > tolf*abs(intgrl)) and (m <= maxnsplits):
        n *= 2
        # We have made a computation for all lower powers-of-2 starting with 1. 
        # The below procedure sums up the new ordinates and then multiplies the 
        # sum with the width of the trapezoids.
        nhalved = n // 2   # Integer division
        h       = span / float(nhalved)
        x       = a + 0.5*h
        subsum  = 0.0
        for k in range(0, nhalved):
            subsum += func(x + k*h)
        summ += subsum
        ttable.append([])
        ttable[m].append(span * summ / n)

        # Interpolation Richardson style:
        for k in range(0, m):    
            aux = float(4**(k+1))
            y   = (aux*ttable[m][k] - ttable[m-1][k]) / (aux - 1.0)
            ttable[m].append(y)
        intgrl     = ttable[m][m]
        previntgrl = ttable[m-1][m-1]
        adiff      = abs(intgrl-previntgrl)
        m += 1

    if m > maxnsplits:
        wtxt1 = "qromberg called by " + caller + " failed to converge.\n"
        wtxt2 = "abs(intgrl-previntgrl) = " + str(adiff)
        wtxt3 = " for " + str(maxnsplits) + " splits"
        warn(wtxt1+wtxt2+wtxt3)

    return intgrl
示例#9
0
def cpoisson(lam, tspan, n):
    """
    The Poisson distribution: p(N=n) = exp(-lam*tspan) * (lam*tspan)**n / n!
    n = 0, 1,...., inf
    """

    # Input check -----------
    assert lam >= 0.0, "Poisson rate must not be negative in cpoisson!"
    assert tspan >= 0.0, "time span must not be negative in cpoisson!"
    assert is_nonneginteger(n), "variate must be a non-negative integer in cpoisson!"
    # -----------------------

    cdf = 1.0 - cgamma(n + 1.0, lam, tspan)

    return cdf
示例#10
0
def cpoisson(lam, tspan, n):
    """
    The Poisson distribution: p(N=n) = exp(-lam*tspan) * (lam*tspan)**n / n!
    n = 0, 1,...., inf
    """

    # Input check -----------
    assert lam >= 0.0, "Poisson rate must not be negative in cpoisson!"
    assert tspan >= 0.0, "time span must not be negative in cpoisson!"
    assert is_nonneginteger(n), \
                "variate must be a non-negative integer in cpoisson!"
    # -----------------------

    cdf = 1.0 - cgamma(n + 1.0, lam, tspan)

    return cdf
示例#11
0
def dpoisson(lam, tspan, n):
    """
    The Poisson distribution: p(N=n) = exp(-lam*tspan) * (lam*tspan)**n / n!
    n = 0, 1,...., inf
    """

    # Input check -----------
    assert lam >= 0.0, "Poisson rate must not be negative in dpoisson!"
    assert tspan >= 0.0, "time span must not be negative in dpoisson!"
    assert is_nonneginteger(n), \
                " must be a non-negative integer in dpoisson!"
    # -----------------------

    lamtau = lam * tspan
    ln = lamtau + lngamma(n + 1) - n * log(lamtau)
    ln = kept_within(0.0, ln)
    pdf = exp(-ln)  # Will always be >= 0.0

    return pdf
示例#12
0
def lnfactorial(n, integer=True):
    """
    Computation of the natural logarithm of a factorial using integer 
    arithmetics (integer=True) or floating point arithmetics using lngamma 
    (integer=False). In both cases a floating-point number is returned, of 
    course...
    """

    assert is_nonneginteger(n), \
               "the argument to lnfactorial must be a non-negative integer!"

    if integer:
        fact   = factorial(n)
        lnfact = log(fact)

    else:
        lnfact = lngamma(n+1.0)

    return lnfact
示例#13
0
def dpoisson(lam, tspan, n):
    """
    The Poisson distribution: p(N=n) = exp(-lam*tspan) * (lam*tspan)**n / n!
    n = 0, 1,...., inf
    """

    # Input check -----------
    assert  lam  >= 0.0, "Poisson rate must not be negative in dpoisson!"
    assert tspan >= 0.0, "time span must not be negative in dpoisson!"
    assert is_nonneginteger(n), \
                " must be a non-negative integer in dpoisson!"
    # -----------------------

    lamtau = lam*tspan
    ln  =  lamtau + lngamma(n+1) - n*log(lamtau)
    ln  =  kept_within(0.0, ln)
    pdf =  exp(-ln)    # Will always be >= 0.0

    return pdf
示例#14
0
def lnfactorial(n, integer=True):
    """
    Computation of the natural logarithm of a factorial using integer 
    arithmetics (integer=True) or floating point arithmetics using lngamma 
    (integer=False). In both cases a floating-point number is returned, of 
    course...
    """

    assert is_nonneginteger(n), \
               "the argument to lnfactorial must be a non-negative integer!"

    if integer:
        fact = factorial(n)
        lnfact = log(fact)

    else:
        lnfact = lngamma(n + 1.0)

    return lnfact
示例#15
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
示例#16
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
示例#17
0
def ifactorial(n, integer=True):
    """
    Computation of a factorial, returning an integer. For integer=True a long, 
    exact integer is returned. For integer=False an integer obtained from 
    floating-point arithmetics based on the function lngamma is returned - 
    it is approximate and may not be exact but faster for large n. ERRCODE 
    (cf. misclib.numbers) is returned if a floating-point OverflowError occurs 
    and a warning is sent to stdout (no error can occur when integer=True).
    """

    assert is_nonneginteger(n), \
                 "the argument to ifactorial must be a non-negative integer!"

    if integer:
        fact = factorial(n)

    else:
        try:
            fact = safeint(round(exp(lngamma(n + 1.0))), 'ifactorial')
        except OverflowError:
            fact = ERRCODE
            warn("OverflowError in ifactorial - ERRCODE is returned")

    return fact
示例#18
0
def ifactorial(n, integer=True):
    """
    Computation of a factorial, returning an integer. For integer=True a long, 
    exact integer is returned. For integer=False an integer obtained from 
    floating-point arithmetics based on the function lngamma is returned - 
    it is approximate and may not be exact but faster for large n. ERRCODE 
    (cf. misclib.numbers) is returned if a floating-point OverflowError occurs 
    and a warning is sent to stdout (no error can occur when integer=True).
    """

    assert is_nonneginteger(n), \
                 "the argument to ifactorial must be a non-negative integer!"

    if integer:
        fact = factorial(n)

    else:
        try:
            fact = safeint(round(exp(lngamma(n+1.0))), 'ifactorial')
        except OverflowError:
            fact = ERRCODE
            warn("OverflowError in ifactorial - ERRCODE is returned")

    return fact
示例#19
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
示例#20
0
def znewton(fifi2fid, x0, caller='caller', tolf=FOURMACHEPS, \
                            tola=SQRTTINY, maxniter=64):
    """
    Solves the equation fi(x) = 0 using the Newton-Raphson algorithm. 
    
    NB. The function always returns a value but a warning is printed 
    to stdout if the iteration procedure has not converged!
    
    Convergence is fast for the Newton algorithm - at the price of having to 
    compute the derivative of the function. Convergence cannot be guaranteed 
    for all functions and/or initial guesses, either...

    Arguments:
    ----------
    fifi2fid    Function having the desired root as its argument and 
                1: the value of fi, AND
                2: the value of the ratio of its value to the 
                value of its derivative given that root as its 
                outputs, in that order

    x0          Initial guess as to the value of the root
   
    tolf        Desired fractional accuracy of root (a combination of absolute 
                and fractional will actually be used: tolf*abs(root) + tola)

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

    Additional feature:
    -------------------
    For maxniter == 0 the solution will be taken beyond tolf and tola (if 
    possible) to the limit where either abs(fi(x)) or abs(fi(x)/fid(x)) has 
    stopped shrinking. If convergence is not reached after 2048 iterations, 
    the procedure is halted and the present estimate is returned anyway (a 
    minimum of 8 iterations will be carried out anyhow).

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

    if tolf < MACHEPS:
        tolf = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in znewton. 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 znewton. 0.0 (zero) will be used instead!"
        warn(wtxt1 + wtxt2)

    assert is_nonneginteger(maxniter), \
       "Maximum number of iterations must be a non-negative integer in znewton!"

    MAXMAX = 2048
    MINNITER = 8

    if maxniter == 0:
        limit = True
        maxnit = MAXMAX
    else:
        limit = False
        maxnit = maxniter

    x = x0
    fi, fi2fid = fifi2fid(x)
    if fi == 0.0: return x
    af = abs(fi)
    if not limit:
        if af < tola: return x
    x -= fi2fid
    ah = abs(fi2fid)
    if not limit:
        if ah < tolf * abs(x) + tola: return x

    niter = 0
    while True:
        niter += 1
        afprev = af
        ahprev = ah
        fi, fi2fid = fifi2fid(x)
        if fi == 0.0: return x
        af = abs(fi)
        if limit:
            if af < tola and niter >= MINNITER and af >= afprev: return x
        else:
            if af < tola: return x
        x -= fi2fid
        ah = abs(fi2fid)
        if limit:
            if ah < tolf * abs(x) + tola and niter >= MINNITER and ah >= ahprev:                 \
                                                        return x
        else:
            if ah < tolf * abs(x) + tola: return x
        if niter >= maxnit:
            break

    wtxt1 = str(maxnit) + " iterations not sufficient in znewton called by "
    wtxt2 = caller + ". fi(x) = " + str(fi) + " for x = " + str(x)
    warn(wtxt1 + wtxt2)
    return x
示例#21
0
def cemp_exp(values, npexp, x, ordered=False, check=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!!! 
    """

    nvalues = len(values)
    if check:
        assert is_nonneginteger(npexp), \
            "No. of points for exp tail in cemp_exp must be a non-neg integer!"
        assert npexp <= nvalues, \
                "Number of points for exponential tail in cemp_exp too large!"
        for v in values:
            assert value >= 0.0, \
                      "All inputs must be non-negative in cemp_exp!"

    if npexp == nvalues:
        mean = sum(values) / float(nvalues)
        return cexpo(mean, x)

    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:
        vcopy.insert(0, 0.0)
        nindex = nvalues
    else:
        nindex = nvalues - 1

    breaki = nindex - npexp  # The last index of the piecewise linear part
    vcopyb = vcopy[breaki]
    if x > vcopyb:  # Compute the mean of the shifted exponential
        theta = 0.0
        k0 = breaki + 1
        nip1 = nindex + 1
        for k in range(k0, nip1):
            theta += vcopy[k]
        theta += vcopyb * (0.5 - npexp)
        theta /= npexp
        cdf = 1.0 - npexp * exp(-(x - vcopyb) / theta) / nindex

    else:
        # Find the right interval using a binary search
        left = bisect(vcopy, x) - 1
        vcopyl = vcopy[left]
        try:
            cdf = left + (x - vcopyl) / (vcopy[left + 1] - vcopyl)
        except ZeroDivisionError:
            cdf = left
        cdf /= nindex

    cdf = kept_within(0.0, cdf, 1.0)
    return cdf
示例#22
0
def zsteffen(func, x0, caller='caller', tolf=FOURMACHEPS, \
                         tola=SQRTTINY, maxniter=512):
    """
    Solves the equation func(x) = 0 using Steffensen's method. Steffensen's 
    method is a method with second order convergence (like Newton's method) 
    at the price of two function evaluations per iteration. It does NOT 
    require that the derivative be computed, as opposed to Newton's method.
        In practice zsteffen seems to require a rather clever initial guess 
    as to the root and/or a lot of iterations since it starts slowly when the 
    initial guess is too far away from the actual root, but it might anyway 
    converge in the end. It is clearly inferior to znewton and should be 
    avoided unless the derivative offers problems with numerics or speed. 
        If computation of the derivative is slow, a good idea is to use 
    znewton for a very small number of iterations to produce an initial guess 
    that can be used as an input to zsteffen (may at times be very efficient).
        And/or: Try the additional feature of taking the solution to the 
    practical limit (cf. below) rather than trying to guess the required 
    number of iterations! 

    For the theory behind Steffensen's method, consult Dahlquist-Bjorck-
    Anderson. 
    
    NB. The function always returns a value but a warning is printed 
    to stdout if the iteration procedure has not converged!

    Arguments:
    ----------
    func        Function having the proposed root as its argument

    x0          Initial guess as to the value of the root
   
    tolf        Desired fractional accuracy of root (a combination of absolute 
                and fractional will actually be used: tolf*abs(root) + tola)

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

    Additional feature: 
    -------------------
    For maxniter == 0 the solution will be taken beyond tolf and tola (if 
    possible) to the limit where either abs(func(x)) or abs(h) - where h is 
    the increment of the root estimate - has stopped shrinking. If convergence 
    is not reached after 2**16 (= 65,536) iterations, the procedure is halted 
    and the present estimate is returned anyway (a minimum of 16 iterations 
    will be carried out anyhow).
    
    Returns:
    ---------
    Final value of root
    """

    if tolf < MACHEPS:
        tolf = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in zsteffen. 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 zsteffen. 0.0 (zero) will be used instead!"
        warn(wtxt1 + wtxt2)

    assert is_nonneginteger(maxniter), \
      "Maximum number of iterations must be a non-negative integer in zsteffen!"

    MAXMAX = 2**16
    MINNITER = 16

    if maxniter == 0:
        limit = True
        maxnit = MAXMAX
    else:
        limit = False
        maxnit = maxniter

    x = x0
    f = func(x)
    if f == 0.0: return x
    af = abs(f)
    if not limit:
        if af < tola: return x
    g = (func(x + f) - f) / f
    h = f / g
    x -= h
    ah = abs(h)
    if not limit:
        if ah < tolf * abs(x) + tola: return x

    niter = 0
    while True:
        niter += 1
        afprev = af
        ahprev = ah
        f = func(x)
        if f == 0.0: return x
        af = abs(f)
        if limit:
            if af < tola and niter >= MINNITER and af >= afprev: return x
        else:
            if af < tola: return x
        g = (func(x + f) - f) / f
        h = f / g
        x -= h
        ah = abs(h)
        if limit:
            if ah < tolf * abs(x) + tola and niter >= MINNITER and ah >= ahprev:                 \
                                                        return x
        else:
            if ah < tolf * abs(x) + tola: return x
        if niter >= maxnit:
            break

    wtxt1 = str(maxnit) + " iterations not sufficient in zsteffen called by "
    wtxt2 = caller + ". func(x) = " + str(f) + " for x = " + str(x)
    warn(wtxt1 + wtxt2)
    return x
示例#23
0
def zsteffen(func, x0, caller='caller', tolf=FOURMACHEPS, \
                         tola=SQRTTINY, maxniter=512):
    """
    Solves the equation func(x) = 0 using Steffensen's method. Steffensen's 
    method is a method with second order convergence (like Newton's method) 
    at the price of two function evaluations per iteration. It does NOT 
    require that the derivative be computed, as opposed to Newton's method.
        In practice zsteffen seems to require a rather clever initial guess 
    as to the root and/or a lot of iterations since it starts slowly when the 
    initial guess is too far away from the actual root, but it might anyway 
    converge in the end. It is clearly inferior to znewton and should be 
    avoided unless the derivative offers problems with numerics or speed. 
        If computation of the derivative is slow, a good idea is to use 
    znewton for a very small number of iterations to produce an initial guess 
    that can be used as an input to zsteffen (may at times be very efficient).
        And/or: Try the additional feature of taking the solution to the 
    practical limit (cf. below) rather than trying to guess the required 
    number of iterations! 

    For the theory behind Steffensen's method, consult Dahlquist-Bjorck-
    Anderson. 
    
    NB. The function always returns a value but a warning is printed 
    to stdout if the iteration procedure has not converged!

    Arguments:
    ----------
    func        Function having the proposed root as its argument

    x0          Initial guess as to the value of the root
   
    tolf        Desired fractional accuracy of root (a combination of absolute 
                and fractional will actually be used: tolf*abs(root) + tola)

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

    Additional feature: 
    -------------------
    For maxniter == 0 the solution will be taken beyond tolf and tola (if 
    possible) to the limit where either abs(func(x)) or abs(h) - where h is 
    the increment of the root estimate - has stopped shrinking. If convergence 
    is not reached after 2**16 (= 65,536) iterations, the procedure is halted 
    and the present estimate is returned anyway (a minimum of 16 iterations 
    will be carried out anyhow).
    
    Returns:
    ---------
    Final value of root
    """

    if tolf < MACHEPS:
        tolf  = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in zsteffen. 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 zsteffen. 0.0 (zero) will be used instead!"
        warn(wtxt1+wtxt2)

    assert is_nonneginteger(maxniter), \
      "Maximum number of iterations must be a non-negative integer in zsteffen!"

    MAXMAX   = 2**16
    MINNITER = 16

    if maxniter == 0:
        limit  = True
        maxnit = MAXMAX
    else:
        limit  = False
        maxnit = maxniter

    x  = x0
    f  = func(x)
    if f == 0.0: return x
    af = abs(f)
    if not limit:
        if af < tola: return x
    g  = (func(x+f) - f) / f
    h  = f/g
    x -= h
    ah = abs(h)
    if not limit:
        if ah < tolf*abs(x) + tola: return x

    niter = 0
    while True:
        niter +=  1
        afprev = af
        ahprev = ah
        f  = func(x)
        if f == 0.0: return x
        af = abs(f)
        if limit:
            if af < tola and niter >= MINNITER and af >= afprev: return x
        else:
            if af < tola: return x
        g  = (func(x+f) - f) / f
        h  = f/g
        x -= h
        ah = abs(h)
        if limit:
            if ah < tolf*abs(x) + tola and niter >= MINNITER and ah >= ahprev: \
                                        return x
        else:
            if ah < tolf*abs(x) + tola: return x
        if niter >= maxnit:
            break
            

    wtxt1 = str(maxnit) + " iterations not sufficient in zsteffen called by "
    wtxt2 = caller + ". func(x) = " + str(f) + " for x = " + str(x)
    warn(wtxt1+wtxt2)
    return x
示例#24
0
def znewton(fifi2fid, x0, caller='caller', tolf=FOURMACHEPS, \
                            tola=SQRTTINY, maxniter=64):
    """
    Solves the equation fi(x) = 0 using the Newton-Raphson algorithm. 
    
    NB. The function always returns a value but a warning is printed 
    to stdout if the iteration procedure has not converged!
    
    Convergence is fast for the Newton algorithm - at the price of having to 
    compute the derivative of the function. Convergence cannot be guaranteed 
    for all functions and/or initial guesses, either...

    Arguments:
    ----------
    fifi2fid    Function having the desired root as its argument and 
                1: the value of fi, AND
                2: the value of the ratio of its value to the 
                value of its derivative given that root as its 
                outputs, in that order

    x0          Initial guess as to the value of the root
   
    tolf        Desired fractional accuracy of root (a combination of absolute 
                and fractional will actually be used: tolf*abs(root) + tola)

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

    Additional feature:
    -------------------
    For maxniter == 0 the solution will be taken beyond tolf and tola (if 
    possible) to the limit where either abs(fi(x)) or abs(fi(x)/fid(x)) has 
    stopped shrinking. If convergence is not reached after 2048 iterations, 
    the procedure is halted and the present estimate is returned anyway (a 
    minimum of 8 iterations will be carried out anyhow).

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

    if tolf < MACHEPS:
        tolf  = MACHEPS
        wtxt1 = "Fractional tolerance less than machine epsilon is not a "
        wtxt2 = "good idea in znewton. 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 znewton. 0.0 (zero) will be used instead!"
        warn(wtxt1+wtxt2)

    assert is_nonneginteger(maxniter), \
       "Maximum number of iterations must be a non-negative integer in znewton!"

    MAXMAX   = 2048
    MINNITER =    8

    if maxniter == 0:
        limit  = True
        maxnit = MAXMAX
    else:
        limit  = False
        maxnit = maxniter

    x  = x0
    fi, fi2fid  = fifi2fid(x)
    if fi == 0.0: return x
    af = abs(fi)
    if not limit: 
        if af < tola: return x
    x -= fi2fid
    ah = abs(fi2fid)
    if not limit:
        if ah < tolf*abs(x) + tola: return x

    niter = 0
    while True:
        niter +=  1
        afprev = af
        ahprev = ah
        fi, fi2fid  = fifi2fid(x)
        if fi == 0.0: return x
        af = abs(fi)
        if limit:
            if af < tola and niter >= MINNITER and af >= afprev: return x
        else:
            if af < tola: return x
        x -= fi2fid
        ah = abs(fi2fid)
        if limit:
            if ah < tolf*abs(x) + tola and niter >= MINNITER and ah >= ahprev: \
                                        return x
        else:
            if ah < tolf*abs(x) + tola: return x
        if niter >= maxnit:
            break

    wtxt1 = str(maxnit) + " iterations not sufficient in znewton called by "
    wtxt2 = caller + ". fi(x) = " + str(fi) + " for x = " + str(x)
    warn(wtxt1+wtxt2)
    return x
示例#25
0
def nelder_mead(objfunc, point0, spans, \
                trace=False, tolf=SQRTMACHEPS, tola=SQRTTINY, maxniter=256, \
                rho=1.0, xsi=2.0, gamma=0.5, sigma=0.5):
    """
    The Nelder & Mead downhill simplex method is designed to find the minimum 
    of an objective function that has a multi-dimensional input, (see for 
    instance Lagarias et al. (1998), "Convergence Properties of the Nelder-Mead 
    Simplex in Low Dimensions", SIAM J. Optim., Society for Industrial and 
    Applied Mathematics Vol. 9, No. 1, pp. 112-147 for details). The algorithm 
    is said to first have been presented by Nelder and Mead in Computer Journal,
    Vol. 7, pp. 308-313 (1965).

    The initial simplex must be entered by entering an initial point (an 
    array of coordinates), plus an array of spans for the corresponding 
    point coordinates.

    For trace=True a trace is printed to stdout consisting of the present 
    number of iterations, the present low value of the objective function, 
    the present value of the absolute value of difference between the high and
    the low value of the objective function, and the present list of vertices 
    of the low value of the objective function = the present "best" point.
    
    tolf is the fractional tolerance and tola is the absolute tolerance of 
    the absolute value of difference between the high and the low value of 
    the objective function.

    maxniter is the maximum allowed number of iterations.

    rho, xsi, gamma and sigma are the parameters for reflection, expansion,
    contraction and shrinkage, respectively (cf. the references above).
    """

    # Check the input parameters
    assert is_nonneginteger(maxniter), \
       "max number of iterations must be a non-negative integer in nelder_mead!"
    if tolf < MACHEPS:
        tolf = MACHEPS
        wtext  = "fractional tolerance smaller than machine epsilon is not "
        wtext += "recommended in nelder_mead. Machine epsilon is used instead"
        warn(wtext)
    assert rho > 0.0, "rho must be positive in nelder_mead!"
    assert xsi > 1.0, "xsi must be > 1.0 in nelder_mead!"
    assert xsi > rho, "xsi must be > rho in nelder_mead!"
    assert 0.0 < gamma < 1.0, "gamma must be in (0.0, 1.0) in nelder_mead!"
    assert 0.0 < sigma < 1.0, "sigma be in (0.0, 1.0) in nelder_mead!"
    assert tola >= 0.0, "absolute tolerance must be positive in nelder_mead!"

    # Prepare matrix of vertices
    ndim     = len(point0)
    assert len(spans) == ndim
    vertices = Matrix()
    vertices.append(array('d', list(point0)))
    ndimp1   = ndim + 1
    fndim    = float(ndim)
    for j in range(0, ndim): vertices.append(array('d', list(point0)))
    for j in range(0, ndim): vertices[j+1][j] += spans[j]

    # Prepare a few variants of parameters
    oneprho = 1.0 + rho

    # LOOP!!!!!!!!
    niter = 0
    while True:
        niter += 1
        if niter > maxniter:
            txt1 = "nelder_mead did not converge. Absolute error = "
            txt2 = str(abs(high-low)) + " for " + str(niter-1)
            txt3 = " iterations. Consider new tols or maxniter!"
            raise Error(txt1+txt2+txt3)
        # Compute the objective function values for the vertices
        flist = array('d', [])
        for k in range(0, ndimp1):
            fk = objfunc(vertices[k])
            flist.append(fk)

        # Establish the highest point, the next highest point and the lowest
        low   = flist[0]
        high  = nxhi = low
        ilow  = 0
        ihigh = 0
        for k in range(1, ndimp1):
            fk = flist[k]
            if fk > high:
                nxhi   = high
                high   = fk
                ihigh  = k
            elif fk < low:
                low  = fk
                ilow = k

        if trace: print(niter, low, abs(high-low), list(vertices[ilow]))
        if low < tola: tol = tola
        else:          tol = abs(low)*tolf
        if abs(high-low) < tol: return low, list(vertices[ilow])

        # Reflect the high point
        # First find a new vertix = the centroid of the non-max vertices
        cntr  = array('d', ndim*[float('nan')])
        newr  = array('d', ndim*[float('nan')])
        for j in range(0, ndim):
            xsum = 0.0
            for k in range(0, ndimp1):
                if k != ihigh:
                    xsum += vertices[k][j]
            cntr[j] = xsum/fndim
        # Then move from the centroid in an away-from-max direction
        for j in range(0, ndim):
            newr[j] = oneprho*cntr[j] - rho*vertices[ihigh][j]

        # Check the new vertix
        accepted = False
        phir = objfunc(newr)
        if low <= phir < nxhi:
            # Everything is OK!
            if trace: print("Reflection sufficient")
            vertices[ihigh] = newr
            phi             = phir
            accepted        = True
        elif phir < low:
            # Expand:
            if trace: print("Expansion")
            newe = array('d', ndim*[float('nan')])
            for j in range(0, ndim):
                newe[j] = cntr[j] + xsi*(newr[j]-cntr[j])
            phie = objfunc(newe)
            if phie < phir:
                vertices[ihigh] = newe
                phi             = phie
            else:
                vertices[ihigh] = newr
                phi             = phir
            accepted = True
        elif phir >= nxhi:
            # Contract
            if phir < high:
                # -outside:
                if trace: print("Outside contraction")
                newo = array('d', ndim*[float('nan')])
                for j in range(0, ndim):
                    newo[j] = cntr[j] + gamma*(newr[j]-cntr[j])
                phio = objfunc(newo)
                if phio <= phir:
                    vertices[ihigh] = newo
                    phi             = phio
                    accepted        = True
            else:
                # -inside:
                if trace: print("Inside contraction")
                newi = array('d', ndim*[float('nan')])
                for j in range(0, ndim):
                    newi[j] = cntr[j] - gamma*(cntr[j]-vertices[ihigh][j])
                phii = objfunc(newi)
                if phii <= high:
                    vertices[ihigh] = newi
                    phi             = phii
                    accepted        = True
        if not accepted:
            # Shrink:
            if trace: print("Shrinkage")
            for k in range(0, ndimp1):
                for j in range(j, ndim):
                    vertices[k][j] = vertices[ilow][j] + sigma*(vertices[k][j] -
                                                             vertices[ilow][j])

# end of nelder_mead

# ------------------------------------------------------------------------------
示例#26
0
def cemp_exp(values, npexp, x, ordered=False, check=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!!! 
    """

    nvalues = len(values)
    if check:
        assert is_nonneginteger(npexp), "No. of points for exp tail in cemp_exp must be a non-neg integer!"
        assert npexp <= nvalues, "Number of points for exponential tail in cemp_exp too large!"
        for v in values:
            assert value >= 0.0, "All inputs must be non-negative in cemp_exp!"

    if npexp == nvalues:
        mean = sum(values) / float(nvalues)
        return cexpo(mean, x)

    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:
        vcopy.insert(0, 0.0)
        nindex = nvalues
    else:
        nindex = nvalues - 1

    breaki = nindex - npexp  # The last index of the piecewise linear part
    vcopyb = vcopy[breaki]
    if x > vcopyb:  # Compute the mean of the shifted exponential
        theta = 0.0
        k0 = breaki + 1
        nip1 = nindex + 1
        for k in range(k0, nip1):
            theta += vcopy[k]
        theta += vcopyb * (0.5 - npexp)
        theta /= npexp
        cdf = 1.0 - npexp * exp(-(x - vcopyb) / theta) / nindex

    else:
        # Find the right interval using a binary search
        left = bisect(vcopy, x) - 1
        vcopyl = vcopy[left]
        try:
            cdf = left + (x - vcopyl) / (vcopy[left + 1] - vcopyl)
        except ZeroDivisionError:
            cdf = left
        cdf /= nindex

    cdf = kept_within(0.0, cdf, 1.0)
    return cdf