B
    d&5                 @   s^   d Z ddlZddlmZ ddlZddlmZ ddlmZ dd Zdd	d
Z	G dd de
ZdS )zI
This modules provides classes for evaluating distributions with bounds.
    N)Error)
boundaries)VARARGS_DELIMc             C   sR  yt | |d| |}W n tk
r2   d}Y nX yt | |d| |}W n tk
rf   d}Y nX |dkr~|dkr~d}n|dks|dkrtd| d n||d}y| |d||}W n tk
r   d}Y nX y| |d	||}	W n tk
r   d
}	Y nX |||	d | |d||}
|d|
i tjf |}|S )a  Gets bounds for the given parameter from a section in a config file.

    Minimum and maximum values for bounds are specified by adding
    `min-{param}` and `max-{param}` options, where `{param}` is the name of
    the parameter. The types of boundary (open, closed, or reflected) to create
    may also be specified by adding options `btype-min-{param}` and
    `btype-max-{param}`. Cyclic conditions can be adding option
    `cyclic-{param}`. If no `btype` arguments are provided, the
    left bound will be closed and the right open.

    For example, the following will create right-open bounds for parameter
    `foo`:

    .. code-block:: ini

        [{section}-{tag}]
        min-foo = -1
        max-foo = 1

    This would make the boundaries cyclic:

    .. code-block:: ini

        [{section}-{tag}]
        min-foo = -1
        max-foo = 1
        cyclic-foo =

    For more details on boundary types and their meaning, see
    `boundaries.Bounds`.

    If the parameter is not found in the section will just return None (in
    this case, all `btype` and `cyclic` arguments are ignored for that
    parameter).  If bounds are specified, both a minimum and maximum must be
    provided, else a Value or Type Error will be raised.

    Parameters
    ----------
    cp : ConfigParser instance
        The config file.
    section : str
        The name of the section.
    tag : str
        Any tag in the section name. The full section name searched for in
        the config file is `{section}(-{tag})`.
    param : str
        The name of the parameter to retrieve bounds for.

    Returns
    -------
    bounds : {Bounds instance | None}
        If bounds were provided, a `boundaries.Bounds` instance
        representing the bounds. Otherwise, `None`.
    zmin-Nzmax-zif specifying bounds for %s, z-you must provide both a minimum and a maximum)Z	min_boundZ	max_boundzbtype-min-{}closedzbtype-max-{}open)Z	btype_minZ	btype_maxz	cyclic-{}cyclic)	floatget_opt_tagr   
ValueErrorformatupdateZhas_option_tagr   Bounds)cpsectiontagparamZminbndZmaxbndbndsZbndargsZminbtypeZmaxbtyper    r   h/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/distributions/bounded.pyget_param_bounds_from_config   s:    7







r   Fc          	   C   s.  |}| t}|dkri }dgdd |D  dd |D  dd |D  dd |D  dd |D  t|  }i }x:|D ]2}	t||||	}
|r|
dkrtd	|	 |
||	< q|W xf|d
||gD ]N}||krq||||}yt	|}W n tk
r   Y nX |
||i qW |
| | f |S )a  Returns a bounded distribution based on a configuration file. The
    parameters for the distribution are retrieved from the section titled
    "[`section`-`variable_args`]" in the config file.

    Parameters
    ----------
    cls : pycbc.prior class
        The class to initialize with.
    cp : pycbc.workflow.WorkflowConfigParser
        A parsed configuration file that contains the distribution
        options.
    section : str
        Name of the section in the configuration file.
    variable_args : str
        The names of the parameters for this distribution, separated by
        `prior.VARARGS_DELIM`. These must appear in the "tag" part
        of the section header.
    bounds_required : {False, bool}
       If True, raise a ValueError if a min and max are not provided for
       every parameter. Otherwise, the prior will be initialized with the
       parameter set to None. Even if bounds are not required, a
       ValueError will be raised if only one bound is provided; i.e.,
       either both bounds need to provided or no bounds.
    additional_opts : {None, dict}
        Provide additional options to be passed to the distribution class;
        should be a dictionary specifying option -> value. If an option is
        provided that also exists in the config file, the value provided will
        be used instead of being read from the file.

    Returns
    -------
    cls
        An instance of the given class.
    Nnamec             S   s   g | ]}d  |qS )zmin-{})r   ).0argr   r   r   
<listcomp>   s    z'bounded_from_config.<locals>.<listcomp>c             S   s   g | ]}d  |qS )zmax-{})r   )r   r   r   r   r   r      s    c             S   s   g | ]}d  |qS )zbtype-min-{})r   )r   r   r   r   r   r      s    c             S   s   g | ]}d  |qS )zbtype-max-{})r   )r   r   r   r   r   r      s    c             S   s   g | ]}d  |qS )z	cyclic-{})r   )r   r   r   r   r   r      s    z'min and/or max missing for parameter %s-)splitr   listkeysr   r
   optionsjoinr	   r   r   )clsr   r   variable_argsbounds_requiredZadditional_optsr   Zspecial_args	dist_argsr   boundskeyvalr   r   r   bounded_from_configu   s0    $
J

r'   c               @   s   e Zd ZdZdd Zedd Zedd Zdd	 Zd
d Z	dd Z
dd Zdd Zdd ZeZdd Zdd ZdddZed ddZdS )!BoundedDista]  
    A generic class for storing common properties of distributions in which
    each parameter has a minimum and maximum value.

    Parameters
    ----------
    \**params :
        The keyword arguments should provide the names of parameters and their
        corresponding bounds, as either tuples or a `boundaries.Bounds`
        instance.
    c             K   s   x|  D ]z\}}|d kr(t ||< n$t|tjsLt|d |d ||< t|tjr
|jjdksp|jjdkr
td	|d  q
W || _
tt| | _d S )Nr      Z	reflectedzParam {} has one or more zQreflected boundaries. Reflected boundaries can cause issues when used in an MCMC.)itemsr   r   
isinstanceminr   maxwarningswarnr   _boundssortedr   r   _params)selfparamsr   r   r   r   r   __init__   s    zBoundedDist.__init__c             C   s   | j S )z-list of strings: The list of parameter names.)r2   )r3   r   r   r   r4      s    zBoundedDist.paramsc             C   s   | j S )z;dict: A dictionary of the parameter names and their bounds.)r0   )r3   r   r   r   r$      s    zBoundedDist.boundsc                sH   yt  fddjD S  tk
rB   tddj Y nX d S )Nc             3   s"   | ]}j |  | V  qd S )N)r0   Zcontains_conditioned)r   p)r4   r3   r   r   	<genexpr>   s   z+BoundedDist.__contains__.<locals>.<genexpr>z must provide all parameters [%s]z, )allr2   KeyErrorr
   r   )r3   r4   r   )r4   r3   r   __contains__   s    zBoundedDist.__contains__c                s   t  fdd| D S )a  Applies any boundary conditions to the given values (e.g., applying
        cyclic conditions, and/or reflecting values off of boundaries). This
        is done by running `apply_conditions` of each bounds in self on the
        corresponding value. See `boundaries.Bounds.apply_conditions` for
        details.

        Parameters
        ----------
        \**kwargs :
            The keyword args should be the name of a parameter and value to
            apply its boundary conditions to. The arguments need not include
            all of the parameters in self. Any unrecognized arguments are
            ignored.

        Returns
        -------
        dict
            A dictionary of the parameter names and the conditioned values.
        c                s.   g | ]&\}}| j kr| j | |gqS r   )r0   Zapply_conditions)r   r6   r&   )r3   r   r   r     s   z9BoundedDist.apply_boundary_conditions.<locals>.<listcomp>)dictr*   )r3   kwargsr   )r3   r   apply_boundary_conditions   s    z%BoundedDist.apply_boundary_conditionsc             K   s   | j f | jf |S )zReturns the pdf at the given values. The keyword arguments must
        contain all of parameters in self's params. Unrecognized arguments are
        ignored. Any boundary conditions are applied to the values before the
        pdf is evaluated.
        )_pdfr=   )r3   r<   r   r   r   pdf  s    zBoundedDist.pdfc             K   s   t ddS )zThe underlying pdf function called by `self.pdf`. This must be set
        by any class that inherits from this class. Otherwise, a
        `NotImplementedError` is raised.
        zpdf function not setN)NotImplementedError)r3   r<   r   r   r   r>     s    zBoundedDist._pdfc             K   s   | j f | jf |S )a
  Returns the log of the pdf at the given values. The keyword
        arguments must contain all of parameters in self's params.
        Unrecognized arguments are ignored. Any boundary conditions are
        applied to the values before the pdf is evaluated.
        )_logpdfr=   )r3   r<   r   r   r   logpdf  s    zBoundedDist.logpdfc             K   s   t ddS )zThe underlying log pdf function called by `self.logpdf`. This must
        be set by any class that inherits from this class. Otherwise, a
        `NotImplementedError` is raised.
        zpdf function not setN)r@   )r3   r<   r   r   r   rA   %  s    zBoundedDist._logpdfc             C   s   t ddS )z/Return the cdfinv for a single given parameter zinverse cdf not setN)r@   )r3   r   valuer   r   r   _cdfinv_param.  s    zBoundedDist._cdfinv_paramc             K   s,   i }x"| j D ]}| ||| ||< qW |S )zReturn the inverse cdf to map the unit interval to parameter bounds.
        You must provide a keyword for every parameter.
        )r4   rD   )r3   kwdsupdatedr   r   r   r   cdfinv2  s    zBoundedDist.cdfinvr)   c             K   st   dd | j D }tj||d}i }x$| j D ]}tjjdd|d||< q*W | jf |}x| j D ]}|| ||< q\W |S )zDraw random valuec             S   s   g | ]}|t fqS r   )r   )r   r6   r   r   r   r   =  s    z#BoundedDist.rvs.<locals>.<listcomp>)dtyper   r)   )size)r4   numpyZzerosrandomuniformrG   )r3   rI   rE   rH   ZarrZdrawr   expr   r   r   rvs;  s    zBoundedDist.rvsFc             C   s   t | ||||dS )a  Returns a distribution based on a configuration file. The parameters
        for the distribution are retrieved from the section titled
        "[`section`-`variable_args`]" in the config file.

        Parameters
        ----------
        cp : pycbc.workflow.WorkflowConfigParser
            A parsed configuration file that contains the distribution
            options.
        section : str
            Name of the section in the configuration file.
        variable_args : str
            The names of the parameters for this distribution, separated by
            `prior.VARARGS_DELIM`. These must appear in the "tag" part
            of the section header.
        bounds_required : {False, bool}
           If True, raise a ValueError if a min and max are not provided for
           every parameter. Otherwise, the prior will be initialized with the
           parameter set to None. Even if bounds are not required, a
           ValueError will be raised if only one bound is provided; i.e.,
           either both bounds need to provided or no bounds.

        Returns
        -------
        BoundedDist
            A distribution instance from the pycbc.distribution subpackage.
        )r"   )r'   )r    r   r   r!   r"   r   r   r   from_configG  s    
zBoundedDist.from_configN)r)   )F)__name__
__module____qualname____doc__r5   propertyr4   r$   r:   r=   r?   r>   rB   rA   __call__rD   rG   rN   classmethodrO   r   r   r   r   r(      s    	
r(   )FN)rS   r.   configparserr   rJ   Zpycbcr   r   r   r'   objectr(   r   r   r   r   <module>   s   Y
R