;ς
ρFc           @   s   d  Z  d f  d     YZ d S(   sO   Integration made easy.

$Id: integrate.py,v 1.4 2007/03/24 15:19:18 eddy Exp $
s
   Integratorc           B   s  t  Z d  Z e d  Z e d  Z e e d  Z e e d  Z e e d  Z d k	 l
 Z
 e
 d  Z [
 d   d	   d
  Z d   d  Z e e e d  Z [ e e d  Z [ [ d   Z d k Z d e i d e i  e i d  d e i d e i g d  Z [ RS(   sB	  Base class for integrators.

    Provides crude trapezium rule integrator, which derived classes might wish
    to over-ride.  More importantly, defines an API for integrators:
        measure(func) -- integrator scaling self.integrand by func
        between(start, stop) -- integrates over an interval
        before(stop) -- as between, but with minus infinity as start
        beyond(start) -- as between, but with plus infinity as stop

    Both before() and beyond() presume that they're integrating a `tail' of a
    distribution: to compute an integral between one side of a distribution's
    mode and infinity on the other side, it is probably wisest to call between()
    on the given bound and a more-or-less arbitrary position on the same side of
    the mode as the infinity in question, then to use before() or beyond() to
    compute the remainder, using between()'s output as offset (see below).

    All three integrator methods take an optional argument, test, following the
    given required arguments; and an optional keyword argument, offset, after
    that.  These are used in deciding when the integral has been determined
    accurately enough: after each iteration, the integrator calls test with the
    change in its estimate of the integral as first argument and, as second
    argument, the new estimate, optionally with offset added to it.  If the
    change is small enough that further refinement is a waste of time, test
    should return true.  The integrator will then return the given estimate
    added to an error bar whose width is the last change.

    By default, the code is geared up to deal with values of class Quantity (see
    basEddy.quantity) and, indeed, the integrators return Quantity()s.  If the
    first estimate at the integral (plus optional offset) has a positive .width
    attribute, it is presumed to be a Quantity() and the default test simply
    compares the change in estimate with the .width of the new estimate; if the
    change is within this existing error bar, it is taken to be small enough.
    In the absence of .width, or if the .width is not positive, the default test
    simply looks to see whether the change in estimate is smaller than 1e-6
    times the estimate (plus optional offset); in the absence of an offset, this
    last test will work poorly if the integral should yield zero. c         C   s-   | |  _ | t j	 o t |  |  _ n d S(   s  Initialises an integrator.

	Required first argument is the function to be integrated.
	This will be stored as self.integrand.

	Optional second argument, width - only needed if .beyond() or .before()
	is liable to be called with bound zero - is a `unit' change in input.
	It should ideally be approximately the difference between highest and
	lowest inputs for which the integrand differs significantly from 0;
	e.g. if func describes a Gaussian distribution with variance 1, a width
	of about 5 would be prudent. N(   s   funcs   selfs	   integrands   widths   Nones   abss   _Integrator__unit(   s   selfs   funcs   width(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   __init__+   s     	 c         C   sQ   | t j o' y |  i } Wq4 t j
 o q4 Xn t | |  i d  |  Sd S(   s°  New integrator scaling self.integrand pointwise by a given function.

        Required argument, func, is a function accepting the same inputs as
        self.integrand().  Optional argument, width, is as for the Integrator
        constructor; if omitted, the value used when self was constructed (if
        any) is used.

        Returns an Integrator whose integrand is (: func(x) * self.integrand(x)
        &larr;x :) which can be construed as integrating func using self as
        measure; or as integrating self using func as measure.  If self is a
        probability distribution, its moments can be computed using func()s of
        form (: x**i &larr;x :) for i = 1, 2, 3 ...c         C   s   | |   | |   S(   N(   s   fs   xs   i(   s   xs   fs   i(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>L   s    N(   s   widths   Nones   selfs   _Integrator__units   AttributeErrors
   Integrators   funcs	   integrand(   s   selfs   funcs   width(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   measure;   s       	c         C   s?   |  i | | | d |  i |  |  i |  d | |  Sd S(   sΡ   Integral over a range.

	Two required arguments, start and stop, give the bounds of the range.
        Also accepts the usual optional tolerance specifiers, test and offset:
        see class doc for details. f1.0f0.5N(   s   selfs   _Integrator__betweens   starts   stops	   integrands   tests   offset(   s   selfs   starts   stops   tests   offset(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   betweenN   s
     	c         C   s%   |  i | |  i |  | |  Sd S(   sV  Integration from minus infinity.

        Equivalent to between() with start set to a value less than any at which
        self's distribution is distinguishable from zero.  Required argument is
        the upper bound of the integral; also accepts the usual optional
        tolerance specifiers, test and offset: see class doc for details. N(   s   selfs   _Integrator__outwardss   stops   _Integrator__steps   tests   offset(   s   selfs   stops   tests   offset(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   beforeZ   s     c         C   s#   |  i | |  i |  | |  Sd S(   sδ   Integration to plus infinity.

        As before() but required argument is the lower bound of integration, the
        upper bound being greater than any value at which self's distribution is
        distinguishable from zero. N(   s   selfs   _Integrator__outwardss   starts   _Integrator__steps   tests   offset(   s   selfs   starts   tests   offset(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   beyondd   s     (   s   tophatc         C   s   |  | | Sd  S(   N(   s   mids   Hs   spread(   s   mids   spreads   H(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   __bluro   s    c         C   s   t  |   d t  |  j S(   Nf9.9999999999999995e-07(   s   abss   ds   n(   s   ds   n(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>s   s    c         C   s   t  |  i  | i j S(   N(   s   abss   ds   bests   ns   width(   s   ds   n(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>t   s    c         C   sΊ   y |  i } y` d } x+ | d j o |  i | d f \ }  } q Wx% |  i d |  i j o |  i }  qF WWn t j
 o n X| d |  j o | Sn Wn t j
 o n X| Sd S(   s  Returns a sensible tolerance test.

        Where between, below and beyond are not given a tolerance test function,
        this determines one given an example value kindred to the final output
        (plus optional offset) relative to which the tolerance is computed. i
   i    i   N(   s   egs   widths   ws   counts   bests   AttributeErrors   bywidths
   microclose(   s   egs
   microcloses   bywidths   counts   w(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys	   __gettestr   s$     	       c         C   s   |  | S(   N(   s   as   b(   s   as   b(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>   s    c         C   s   t  | |   Sd  S(   N(   s   reduces   pluss   row(   s   rows   plus(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   __sum   s    c	         C   s
  | | }
 | t j o5 y |
 |
 i } WqL t j
 o |
 d } qL Xn | t j o | | |
  } n d } x n o d | |
 f \ } } | | }	 | t | |	 |  i d  t d |    | |	 }
 |
 | } | | |
 |  o | |
 |  Sqv q} Wd  S(   Ni    i   i   c         C   s   | | |  |  S(   N(   s   fs   bs   is   s(   s   is   bs   ss   f(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>   s    (   s   edges   gaps   nows   offsets   Nones   bests   AttributeErrors   tests   gettests   ns   wass   hs   sums   maps   starts   selfs	   integrands   ranges   difs   blur(   s   selfs   starts   gaps   edges   tests   offsets   blurs   gettests   sums   hs   nows   wass   difs   n(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys	   __between   s$    
    

 c         C   s  t  |  i |   d } x( |  i | |  | j  o | d } q Wx( |  i | |  | j o | d } qG W| t j o | | |  } n | | }	 |  i | |	 | d | |	 f \ } } | t j o5 y | | i } Wqt j
 o d | } qXn xz n or | d } | | }	 |  i | |	 | d | | }
 | |
 |	 f \ } } | |
 | |  o | | |
  SqqWd  S(   Nf1000.0f7.0i   s   offseti    i   i   (   s   abss   selfs	   integrands   bounds   smalls   _Integrator__probes   steps   tests   Nones   gettests   nexts   betweens   offsets   totals   bests   AttributeErrors   mores   blur(   s   selfs   bounds   steps   tests   offsets   blurs   gettests   totals   smalls   nexts   more(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys
   __outwards₯   s0         
'   

 c         C   s   y |  i SWn t j
 o n Xy t | i d     } Wn% t t f j
 o t |  } n X| o | |  _ n
 t d  | Sd  S(   Nc         C   s   d S(   Ni   (    (   s   x(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>Ώ   s    s?   Integrator needs a width parameter for .before(0) or .beyond(0)(	   s   selfs   _Integrator__units   AttributeErrors   abss   bounds   copys   anss	   TypeErrors
   ValueError(   s   selfs   bounds   ans(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   __stepΌ   s         	Ni   f2.0i   i   c         C   s&   t  t |  i | | d  |   Sd S(   s>   Scale of integrand's values for inputs base + of order scale. c         C   s   t  | | |  |   S(   N(   s   abss   fs   bs   xs   s(   s   xs   fs   ss   b(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   <lambda>Κ   s    N(   s   maxs   maps   selfs	   integrands   scales   bases   samples(   s   selfs   bases   scales   samples(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   __probeΗ   s     (   s   __name__s
   __module__s   __doc__s   Nones   __init__s   measures   betweens   befores   beyonds   study.value.quantitys   tophats   _Integrator__blurs   _Integrator__gettests   _Integrator__sums   _Integrator__betweens   _Integrator__outwardss   _Integrator__steps   maths   exps   pis   sqrts   es   _Integrator__probe(    (    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys
   Integrator   s&   $ 

	
	@N(   s   __doc__s
   Integrator(   s
   Integrator(    (    s+   /home/eddy/.sys/py/study/maths/integrate.pys   ?   s   