;ς
e‘Fc           @   sq   d  Z  d k l Z d k l Z d k Z d k Z d e e f d     YZ [ [ [ [ d e f d     YZ d S(   s  Gamma distributions.

Any time your data are of some kind guaranteed positive (e.g. how tall human
beings are), a suitable gamma distribution is more apt than a gaussian - though
a lognormal distribution may be more apt (see gauss.py).  This module provides
implementations of suitable interfaces for the gamma distribution.

Gamma distributions have the general form

 p = (: exp(-beta*x)*(beta*x)**(alpha-1) &larr;x :{positives})*beta/gamma(alpha)

for some positive beta and alpha.  The normalisation factor gamma(alpha)
generalises factorial; gamma(1+n) = n! for natural n.  It is defined by

  gamma(alpha) = integral(: exp(-t) * t**(alpha-1) &larr;t :{positives})

for which one can show that gamma(1+a) = a*gamma(a), corresponding to
   (1+n)! = gamma(2+n) = (1+n).gamma(1+n) = (1+n).n!

Various tweaks (see stirling.lngamma) are available to enable accurate
calculation of gamma().  One might plausibly hope to be able to do a bit of
trickery with the integrals to determine gamma's derivative; but all this
actually ends up yielding is what could be inferred from:
   d((x+1)!)/dx = d(x!.(x+1))/dx = x! +(x+1).d(x!)/dx
(If I could integrate log(t), log(t)*t**n or exp(-t)*log(t), I could do the
partial differentiation the other way and maybe something interesting would drop
out ...)

For alpha < 1, the distribution has a pole at 0; for sufficiently small beta*X,

 integral(: p(x) &larr;x; 0<x<X :)

has exp(-beta*x) always close enough to 1 that the difference is ignorable;
then

 integral(: (beta*x)**(alpha-1) &larr;x; 0<x<X :)

is the increase in (beta*x)**alpha / (beta*alpha) between x=0 and x=X;
which, for alpha > 0, is just (beta*X)**alpha / (beta * alpha), making
our integral of p up to X pretty close to

 (beta*X)**alpha / alpha / gamma(alpha)

$Id: gamma.py,v 1.4 2007/03/24 15:14:20 eddy Exp $
(   s
   Integrator(   s   LazyNs   Gammac           B   s‘   t  Z e i Z d   Z d  k Z e i d  Z [ e d  Z [ e	 i
 e	 i e i d  Z e	 i d  Z e i d  Z e i Z d   Z d   Z d	   Z RS(
   Nc         C   sΥ   y | d Wn" t j
 o t | d   n X| | f \ |  _  |  _ | d j o d |  _ n; | d j o d |  _ n! | d j o t | d   n |  i |  i d |  |  i | |  d | |  _	 d  S(   Ni   s<   Gamma distribution's order parameter should be dimensionlessi    s2   Gamma function cannot be normalised for this alpha(
   s   alphas	   TypeErrors   betas   selfs   _Gamma__atzeros
   ValueErrors   _Gamma__upinits	   _Gamma__ps   _Gamma__setups   _Gamma__zero(   s   selfs   alphas   beta(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __init__5   s       c         C   s   | |  d d  Sd  S(   Ni   (   s   gs   a(   s   as   g(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __genH   s    c         C   s   | |  i  |  i Sd  S(   N(   s   gs   selfs   alphas   beta(   s   selfs   g(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   sampleK   s    c   	      C   sχ   d } y | i |  } Wn t j
 o | |  } n Xt } y/ | i | i	 f t
 | i  o
 t  n Wn, t j
 o  | | d | | d  } n! Xt } | | d | | d  } | o | | | d  |  _ n | | | d  |  _ d S(   sΜ  Fiddly bits of setup dealing with whether alpha, beta are Quantity()s.

        Overall goal is to set self.__ep to the function
          (: (beta * x)**(alpha-1) * exp(-beta * x) &larr; x :) * beta / gamma(alpha)
        i.e. the density function for our Gamma variate.  However, assorted
        complications raise their heads: we only have gamma as log&on;gamma,
        evaluation of which, along with that of log and gamma, should be done
        via .evaluate() if pertinent values are Quantity()s (in which case we
        need a scalar to apply .evaluate() to).

        Note that self.__ep() should not be used directly, only via self.__p(),
        which performs necessary checks against invalid input. i   c         C   s$   | |  } | | |  | | Sd  S(   N(   s   bs   xs   bxs   as   lns   n(   s   xs   bs   as   lns   ns   bx(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   logpj   s    
c         C   s'   | |  } | | i |  | | Sd  S(   N(   s   bs   xs   bxs   as   evaluates   lns   n(   s   xs   bs   as   lns   ns   bx(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   logpo   s    
c         C   s   | | |    | S(   N(   s   es   lps   xs   b(   s   xs   es   lps   b(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   <lambda>s   s    c         C   s   | |   i |  | S(   N(   s   lps   xs   evaluates   es   b(   s   xs   es   lps   b(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   <lambda>t   s    N(   s   scalars   alphas   evaluates   lngams   lognorms   AttributeErrors   Nones   betas   widths   bests   callables   logs   logps   exps   selfs
   _Gamma__ep(	   s   selfs   alphas   betas   logs   exps   lngams   lognorms   logps   scalar(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __setupQ   s$         c         C   sr   | |  i j o. y |  i SWq> t j
 o t d  q> Xn | |  i j  o t | d   n |  i |  Sd S(   s   The probability distributions*   Gamma, with alpha < 1, is infinite at zeros-   Gamma distribution only defined on positives.N(   s   xs   selfs   _Gamma__zeros   _Gamma__atzeros   AttributeErrors   OverflowErrors
   ValueErrors
   _Gamma__ep(   s   selfs   xs   exp(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __pv   s      c         C   s   | |  i d j o d |  i } n | d } y | i } Wn t j
 o n X|  i | |  i |  i | |  i  | f Sd S(   s  Approximates integration from zero to some small value < end.

	This involves chosing an X < end for which exp(beta*X) differs
	negligibly from 1 = exp(0), then using 

	    eps = (beta*X)**alpha / alpha / gamma(alpha)

	as estimate of the integral.  Returns a twople, (eps, X). i   f1.0f9.9999999999999995e-07N(   s   ends   selfs   betas   bests   AttributeErrors   alphas   gam(   s   selfs   ends   gam(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __sliver   s      
  c         O   sO  | | j  o d | } n | | j  o d | } n | | j o d |  i Sn | | j  o" t |  i | | f | |  Sn |  i d j  o
 | d j o | d j p t	  |  i
 |  \ } } y | d } Wn t j
 o | | d <n X| | | d <| t |  i | | | f | |  Sn t |  i | | f | |  Sd  S(   Ni    i   s   offset(   s   starts   stops   selfs   betas   applys   betweens   argss   whats   alphas   AssertionErrors   _Gamma__slivers   epss   cuts   offs   KeyErrors   _Gamma__between(   s   selfs   starts   stops   argss   whats   cuts   offs   eps(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   between   s$        "  )c         C   s   |  i |  i Sd S(   s  Mean of the gamma distribution.

        This is
            integrate(: (beta * x)**alpha * exp(-beta * x) &larr; x; x > 0 :) / gamma(alpha)
            = integrate(: u**alpha * exp(-u) &larr; u; u > 0 :) / beta / gamma(alpha)
        whose integrand is
            d(-exp(-u) * u**alpha) +alpha * u**(alpha-1) * exp(-u)
        the differential term in which is zero at both 0 and infinity, for alpha > 0,
        so we can integrate by parts to obtain the mean as:
            integrate(: u**(alpha-1) * exp(-u) &larr; u; u > 0
                       :) * alpha / beta / gamma(alpha)
        which is just alpha / beta, since the ingegral is gamma(alpha). N(   s   selfs   alphas   beta(   s   selfs   ignored(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   _lazy_get_mean_¦   s     c         C   s   |  i |  i d Sd S(   s  Variance of the gamma distribution.

        This is the expected value of the variate's square, minus the square of
        the mean.  The first term is:
            integrate(: (beta * x)**(alpha+1) * exp(-beta * x) &larr; x; x > 0
                       :) / beta / gamma(alpha)
            = integrate(: u**(alpha+1) * exp(-u) &larr; u; u > 0
                         :) / beta**2 / gamma(alpha)
        whose integrand is
            d(-exp(-u) * u**(alpha+1)) + (alpha+1) * u**alpha * exp(-u)
            = d(-exp(-u) * (u**(alpha+1) + (alpha+1) * u**alpha))
              + (alpha+1) * alpha * u**(alpha-1) * exp(-u)
        again with its differential terms zero at 0 and infinity, for alpha > 0,
        enabling us to integrate by parts, as for the mean, to get the expected
        square as
            alpha * (alpha+1) / beta**2
        from which we subtract (alpha/beta)**2 to get alpha / beta**2. i   N(   s   selfs   alphas   beta(   s   selfs   ignored(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   _lazy_get_variance_Ά   s     (   s   __name__s
   __module__s
   Integrators   __init__s   _Gamma__upinits   randoms   gammavariates   _Gamma__gens   samples   maths   logs   exps   stirlings   lngammas   _Gamma__setups	   _Gamma__ps   gammas   _Gamma__slivers   betweens   _Gamma__betweens   _lazy_get_mean_s   _lazy_get_variance_(    (    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   Gamma3   s   			%			s   GammaByMeanVarc           B   s   t  Z e i Z d   Z RS(   Nc         C   s   y | d | Wn= t j
 o t | | d   n t t f j
 o n X| | f \ |  _  |  _ | | } |  i | | |  d S(   sΒ   Initialises a Gamma using mean and variance as inputs.

        This simply infers alpha and beta from the formulae used, above, to
        compute mean and variance lazily from alpha and beta. i   s?   Incompatible quantities for mean and variance of a distributionN(   s   means   variances	   TypeErrors   OverflowErrors   OverflowWarnings   selfs   betas   _GammaByMeanVar__upinit(   s   selfs   means   variances   beta(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   __init__Ο   s      	 
(   s   __name__s
   __module__s   Gammas   __init__s   _GammaByMeanVar__upinit(    (    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   GammaByMeanVarΝ   s   	(	   s   __doc__s	   integrates
   Integrators   study.value.lazys   Lazys   maths   stirlings   Gammas   GammaByMeanVar(   s   GammaByMeanVars   Lazys
   Integrators   stirlings   maths   Gamma(    (    s'   /home/eddy/.sys/py/study/maths/gamma.pys   ?-   s   