B
    d"                 @   sd   d Z ddlZddlZddlmZ ddlmZ	 ddl
mZ G dd deZG dd deZddgZdS )z
This modules provides classes for evaluating PDF, logPDF, CDF and inverse CDF
from external arbitrary distributions, and drawing samples from them.
    N)VARARGS_DELIMc               @   sD   e Zd ZdZdZdddZdddZd	d
 Zdd Ze	dd Z
dS )Externala   Distribution defined by external cdfinv and logpdf functions

    To add to an inference configuration file:

    .. code-block:: ini

        [prior-param1+param2]
        name = external
        module = custom_mod
        logpdf = custom_function_name
        cdfinv = custom_function_name2

    Or call `DistributionFunctionFromFile` in the .ini file:

    .. code-block:: ini

        [prior-param]
        name = external_func_fromfile
        module = pycbc.distributions.external
        file_path = path
        column_index = index
        logpdf = _logpdf
        cdfinv = _cdfinv

    Parameters
    ----------
    params : list
        list of parameter names
    custom_mod : module
        module from which logpdf and cdfinv functions can be imported
    logpdf : function
        function which returns the logpdf
    cdfinv : function
        function which applies the invcdf

    Examples
    --------
    To instantate by hand and example of function format. You must provide
    the logpdf function, and you may either provide the rvs or cdfinv function.
    If the cdfinv is provided, but not the rvs, the random values will
    be calculated using the cdfinv function.

    >>> import numpy
    >>> params = ['x', 'y']
    >>> def logpdf(x=None, y=None):
    ...     p = numpy.ones(len(x))
    ...     return p
    >>>
    >>> def cdfinv(**kwds):
    ...     return kwds
    >>> e = External(['x', 'y'], logpdf, cdfinv=cdfinv)
    >>> e.rvs(size=10)
    ZexternalNc             K   s,   || _ || _|| _|| _|s(|s(tdd S )Nz!Must provide either rvs or cdfinv)paramslogpdfcdfinv_rvs
ValueError)selfr   r   rvsr   kwds r   i/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/distributions/external.py__init__S   s    zExternal.__init__   c                s2   | j r| j  dS  fdd| jD }| jf |S )zDraw random value)sizec                s    i | ]}t jjd d d|qS )r   r   )r   )nprandomuniform).0param)r   r   r   
<dictcomp>a   s   z External.rvs.<locals>.<dictcomp>)r   r   r   )r	   r   r   Zsamplesr   )r   r   r
   ]   s
    

zExternal.rvsc             K   s   |S )Nr   )r	   r   r   r   r   apply_boundary_conditionse   s    z"External.apply_boundary_conditionsc             K   s   | j f |S )N)r   )r	   r   r   r   r   __call__h   s    zExternal.__call__c             C   s   |}| t}||d|}|dkrJ||d|}t|||d|d}n
t|}||d|}	t||	}
d  }}||d|r||d|}t||}||d|r||d|}t||}|dkr| |||j||d	S | ||
||d
S )Nmodulezpycbc.distributions.external	file_pathcolumn_index)r   r   r   r   r
   )r   r   r   r
   r   )r   r   r
   r   )	splitr   Zget_opt_tagDistributionFunctionFromFile	importlibimport_modulegetattrZhas_option_tagr   )clscpsectionZvariable_argstagr   Z	modulestrr   modZ	logpdfstrr   r   r
   Z	cdfinvstrZrvsstrr   r   r   from_configk   s,    




zExternal.from_config)NNNN)r   )__name__
__module____qualname____doc__namer   r
   r   r   classmethodr&   r   r   r   r   r      s   5 
	
r   c                   sF   e Zd ZdZdZd fdd	Zdd Zdd	 Zd
d Zdd Z	  Z
S )r   a  Evaluating PDF, logPDF, CDF and inverse CDF from the external
        density function.

    Instances of this class can be called like a distribution in the .ini file,
    when used with `pycbc.distributions.external.External`. Please see the
    example in the `External` class.

    Parameters
    ----------
    parameter : {'file_path', 'column_index'}
        The path of the external density function's .txt file, and the
        column index of the density distribution. By default, the first column
        should be the values of a certain parameter, such as "mass", other
        columns should be the corresponding density values (as a function of
        that parameter). If you add the name of the parameter in the first
        row, please add the '#' at the beginning.
    \**kwargs :
        All other keyword args are passed to `scipy.integrate.quad` to control
        the numerical accuracy of the inverse CDF.
        If not be provided, will use the default values in `self.__init__`.

    Notes
    -----
    This class is different from `pycbc.distributions.arbitrary.FromFile`,
    which needs samples from the hdf file to construct the PDF by using KDE.
    This class reads in any continuous functions of the parameter.
    Zexternal_func_fromfileNc                s   | drt j|d d nt jdd || _tj|ddd| _t|| _|	dd| _
|	dd| _t| jd	 d	 | jd	 d
 d| _tttd| _|stdd S )Nr   )r   T#)fnameunpackcommentsepsabsg
h`?>epsrelr   i  )pdfcdfr   z/Must provide the path to density function file.)__contains__superr   r   r   Zloadtxtdataintr   getr1   r2   Zlinspacex_listcallableinterpr   )r	   r   r   r   kwargs)	__class__r   r   r      s    

$z%DistributionFunctionFromFile.__init__c             K   s   | j d tkrt| jd | j| j }tj|| jd d | jd d f| j| j	dd|d }t| jd | j| j | | j d< t
| j d |}|S )zCalculate and interpolate the PDF by using the given density
        function, then return the corresponding value at the given x.r4   r   r3   i  )r1   r2   limit)r=   r<   scipy_interpolateinterp1dr8   r   scipy_integratequadr1   r2   r   float64)r	   xr>   Zfunc_unnormZ
norm_constZpdf_valr   r   r   _pdf   s     z!DistributionFunctionFromFile._pdfc             K   s   t | j|f|S )z/Calculate the logPDF by calling `pdf` function.)r   logrG   )r	   rF   r>   r   r   r   _logpdf   s    z$DistributionFunctionFromFile._logpdfc             K   s   | j d tkrrg }xJ| jD ]@}tj| j| jd d |f| j| jdd|d }|	| qW t
| j|| j d< t| j d |}|S )z^Calculate and interpolate the CDF, then return the corresponding
        value at the given x.r5   r   i  )r1   r2   r@   )r=   r<   r;   rC   rD   rG   r8   r1   r2   appendrA   rB   r   rE   )r	   rF   r>   cdf_listZx_valZcdf_xZcdf_valr   r   r   _cdf   s    z!DistributionFunctionFromFile._cdfc             K   sz   | j d tkrFg }x| jD ]}|| | qW t|| j| j d< t| d t	
| j d t| d i}|S )zxCalculate and interpolate the inverse CDF, then return the
        corresponding parameter value at the given CDF value.r   r   )r=   r<   r;   rJ   rL   rA   rB   listkeysr   rE   values)r	   r>   rK   Zx_valueZ
cdfinv_valr   r   r   _cdfinv   s    z$DistributionFunctionFromFile._cdfinv)NNN)r'   r(   r)   r*   r+   r   rG   rI   rL   rP   __classcell__r   r   )r?   r   r      s    r   )r*   r   numpyr   Zscipy.integrateZ	integraterC   Zscipy.interpolateZinterpolaterA   Zpycbcr   objectr   r   __all__r   r   r   r   <module>   s   p^