B
    dL                 @   s   d Z ddlmZ ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 G dd	 d	e	j
ZG d
d deZG dd deZG dd dejZd	dddgZdS )zE
This modules provides classes for evaluating angular distributions.
    )ErrorN)VARARGS_DELIM)
boundaries)bounded)uniformc                   sX   e Zd ZdZdZddej fZd fdd	Ze	dd	 Z
 fd
dZedd Z  ZS )UniformAnglea  A uniform distribution in which the dependent variable is between
    `[0,2pi)`.

    The domain of the distribution may optionally be made cyclic using the
    `cyclic_domain` parameter.

    Bounds may be provided to limit the range for which the pdf has support.
    If provided, the parameter bounds are in radians.

    Parameters
    ----------
    cyclic_domain : {False, bool}
        If True, cyclic bounds on [0, 2pi) are applied to all values when
        evaluating the pdf. This is done prior to any additional bounds
        specified for a parameter are applied. Default is False.
    \**params :
        The keyword arguments should provide the names of parameters and
        (optionally) their corresponding bounds, as either
        `boundaries.Bounds` instances or tuples. The bounds must be
        in [0,2PI). These are converted to radians for storage. None may also
        be passed; in that case, the domain bounds will be used.

    Notes
    ------
    For more information, see Uniform.
    Zuniform_angler      Fc                s   t j| jd | jd |d| _x| D ]\}}|d kr@| j}nBt|t jrn|j|j|_|j|j|_nt |d |d }|j	| jj	k s|j
| jj
krtdj| jj	| jj
|j	|j
d|||< q(W tt| jf | d S )Nr      )cyclicz*bounds must be in [{x},{y}); got [{a},{b}))xyab)r   Bounds_domainbounds_domainitems
isinstance_min	__class___maxminmax
ValueErrorformatsuperr   __init__)selfcyclic_domainparamspZbnds)r    h/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/pycbc/distributions/angular.pyr   :   s     
zUniformAngle.__init__c             C   s   | j S )z'Returns the domain of the distribution.)r   )r   r!   r!   r"   domainV   s    zUniformAngle.domainc                s,   t  fdd| D }tt jf |S )a  Maps values to be in [0, 2pi) (the domain) first, before applying
        any additional boundary conditions.

        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.

        Returns
        -------
        dict
            A dictionary of the parameter names and the conditioned values.
        c                s*   g | ]"\}}| j kr| j|gqS r!   )_boundsr   apply_conditions).0r    val)r   r!   r"   
<listcomp>l   s   z:UniformAngle.apply_boundary_conditions.<locals>.<listcomp>)dictr   r   r   apply_boundary_conditions)r   kwargs)r   )r   r"   r*   [   s    z&UniformAngle.apply_boundary_conditionsc             C   s(   d| |d|i}tj| |||d|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. By default,
        only the name of the distribution (`uniform_angle`) needs to be
        specified. This will results in a uniform prior on `[0, 2pi)`. To
        make the domain cyclic, add `cyclic_domain =`. To specify boundaries
        that are not `[0, 2pi)`, add `(min|max)-var` arguments, where `var`
        is the name of the variable.

        For example, this will initialize a variable called `theta` with a
        uniform distribution on `[0, 2pi)` without cyclic boundaries:

        .. code-block:: ini

            [{section}-theta]
            name = uniform_angle

        This will make the domain cyclic on `[0, 2pi)`:

        .. code-block:: ini

            [{section}-theta]
            name = uniform_angle
            cyclic_domain =

        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
            ``VARARGS_DELIM``. These must appear in the "tag" part
            of the section header.

        Returns
        -------
        UniformAngle
            A distribution instance from the pycbc.inference.prior module.
        r   F)Zbounds_requiredadditional_opts)has_option_tagr   Zbounded_from_config)clscpsectionvariable_argsr,   r!   r!   r"   from_configq   s
    .
zUniformAngle.from_config)F)__name__
__module____qualname____doc__namenumpypir   r   propertyr#   r*   classmethodr2   __classcell__r!   r!   )r   r"   r      s   r   c                   sX   e Zd ZdZdZejZejZ	ej
ZdejfZ fddZdd Zdd	 Zd
d Z  ZS )SinAnglea  A sine distribution; the pdf of each parameter `\theta` is given by:

    ..math::
        p(\theta) = \frac{\sin \theta}{\cos\theta_0 - \cos\theta_1}, \theta_0 \leq \theta < \theta_1,

    and 0 otherwise. Here, :math:`\theta_0, \theta_1` are the bounds of the
    parameter.

    The domain of this distribution is `[0, pi]`. This is accomplished by
    putting hard boundaries at `[0, pi]`. Bounds may be provided to further
    limit the range for which the pdf has support.  As with `UniformAngle`,
    these are initialized in radians.

    Parameters
    ----------
    \**params :
        The keyword arguments should provide the names of parameters and
        (optionally) their corresponding bounds, as either
        `boundaries.Bounds` instances or tuples. The bounds must be
        in [0,PI]. These are converted to radians for storage. None may also
        be passed; in that case, the domain bounds will be used.
    Z	sin_angler   c                sf   t t jf | tj jd  jd dddd _t fdd j	 D   _
t j
 _d S )Nr   r	   closedF)Z	btype_minZ	btype_maxr
   c          
      s2   g | ]*}t t |d   |d  qS )r	   r   )r8   logabs_func)r&   Zbnd)r   r!   r"   r(      s   z%SinAngle.__init__.<locals>.<listcomp>)r   r=   r   r   r   r   r   sumr$   values_lognormr8   exp_norm)r   r   )r   )r   r"   r      s    
zSinAngle.__init__c             C   s\   t | j| d t | j| d  }dt | j| d |  }t | ||  }|S )zMReturn inverse of cdf for mapping unit interval to parameter bounds.
        r   r	   g      ?)r8   cosr$   arccos)r   argvaluescaleoffset	new_valuer!   r!   r"   _cdfinv_param   s
    zSinAngle._cdfinv_paramc                s6    | krdS | j | t fdd| jD   S )zReturns the pdf at the given values. The keyword arguments must
        contain all of parameters in self's params. Unrecognized arguments are
        ignored.
        g        c                s   g | ]} | qS r!   r!   )r&   r    )r+   r!   r"   r(      s    z!SinAngle._pdf.<locals>.<listcomp>)rF   _dfuncr8   array_paramsprod)r   r+   r!   )r+   r"   _pdf   s    zSinAngle._pdfc          
      s@    | krt j S | jt | t  fdd| jD   S )zReturns 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.
        c                s   g | ]} | qS r!   r!   )r&   r    )r+   r!   r"   r(      s    z$SinAngle._logpdf.<locals>.<listcomp>)r8   infrD   r?   rO   rP   rQ   rB   )r   r+   r!   )r+   r"   _logpdf   s
    zSinAngle._logpdf)r3   r4   r5   r6   r7   r8   rG   rA   sinrO   rH   _arcfuncr9   r   r   rN   rS   rU   r<   r!   r!   )r   r"   r=      s   
	r=   c               @   sD   e Zd ZdZdZejZejZ	ej
Zej d ejd fZdd ZdS )CosAnglea  A cosine distribution. This is the same thing as a sine distribution,
    but with the domain shifted to `[-pi/2, pi/2]`. See SinAngle for more
    details.

    Parameters
    ----------
    \**params :
        The keyword arguments should provide the names of parameters and
        (optionally) their corresponding bounds, as either
        `boundaries.Bounds` instances or tuples. The bounds must be
        in [-PI/2, PI/2].
    Z	cos_angler   c             C   sh   | j | d }| j | d }t|t| }dt|t|t|   }t|| | }|S )Nr   r	   g      ?)r$   r8   rV   arcsin)r   paramrJ   r   r   rK   rL   rM   r!   r!   r"   rN     s    "zCosAngle._cdfinv_paramN)r3   r4   r5   r6   r7   r8   rV   rA   rG   rO   rY   rW   r9   r   rN   r!   r!   r!   r"   rX      s   rX   c               @   s~   e Zd ZdZdZeZeZdZ	dZ
dddZed	d
 Zedd Zedd Zdd Zdd Zdd Zdd Zedd ZdS )UniformSolidAnglea  A distribution that is uniform in the solid angle of a sphere. The names
    of the two angluar parameters can be specified on initalization.

    Parameters
    ----------
    polar_angle : {'theta', str}
        The name of the polar angle.
    azimuthal_angle : {'phi', str}
        The name of the azimuthal angle.
    polar_bounds : {None, tuple}
        Limit the polar angle to the given bounds. If None provided, the polar
        angle will vary from 0 (the north pole) to pi (the south pole). The
        bounds should be specified as factors of pi. For example, to limit
        the distribution to the northern hemisphere, set
        `polar_bounds=(0,0.5)`.
    azimuthal_bounds : {None, tuple}
        Limit the azimuthal angle to the given bounds. If None provided, the
        azimuthal angle will vary from 0 to 2pi. The
        bounds should be specified as factors of pi. For example, to limit
        the distribution to the one hemisphere, set `azimuthal_bounds=(0,1)`.
    azimuthal_cyclic_domain : {False, bool}
        Make the domain of the azimuthal angle be cyclic; i.e., azimuthal
        values are constrained to be in [0, 2pi) using cyclic boundaries prior
        to applying any other boundary conditions and prior to evaluating the
        pdf. Default is False.
    Zuniform_solidanglethetaphiNFc             C   s   |d kr| j }|d kr| j}| jf ||i| _| jf ||d|i| _|| _|| _| jj	 | _
| j
| jj t| j
 | _d S )Nr   )_default_polar_angle_default_azimuthal_angle_polardistcls
_polardist_azimuthaldistcls_azimuthaldist_polar_angle_azimuthal_angleboundscopyr$   updatesortedkeysrQ   )r   polar_angleazimuthal_anglepolar_boundsazimuthal_boundsazimuthal_cyclic_domainr!   r!   r"   r   +  s    zUniformSolidAngle.__init__c             C   s   | j S )a_  dict: The bounds on each angle. The keys are the names of the polar
        and azimuthal angles, the values are the minimum and maximum of each,
        in radians. For example, if the distribution was initialized with
        `polar_angle='theta', polar_bounds=(0,0.5)` then the bounds will have
        `'theta': 0, 1.5707963267948966` as an entry.)r$   )r   r!   r!   r"   rf   =  s    zUniformSolidAngle.boundsc             C   s   | j S )z!str: The name of the polar angle.)rd   )r   r!   r!   r"   rk   F  s    zUniformSolidAngle.polar_anglec             C   s   | j S )z%str: The name of the azimuthal angle.)re   )r   r!   r!   r"   rl   K  s    z!UniformSolidAngle.azimuthal_anglec             C   s4   || j kr| j||S || jkr0| j||S dS )z0 Return the cdfinv for a single given parameter N)rk   ra   rN   rl   rc   )r   rZ   rJ   r!   r!   r"   rN   P  s    

zUniformSolidAngle._cdfinv_paramc             K   sd   || j  }|| j }| jj|}| jj|}| j| j  |}| j| j |}| j || j|iS )al  Maps the given values to be within the domain of the azimuthal and
        polar angles, before applying any other boundary conditions.

        Parameters
        ----------
        \**kwargs :
            The keyword args must include values for both the azimuthal and
            polar angle, using the names they were initilialized with. For
            example, if `polar_angle='theta'` and `azimuthal_angle=`phi`, then
            the keyword args must be `theta={val1}, phi={val2}`.

        Returns
        -------
        dict
            A dictionary of the parameter names and the conditioned values.
        )rd   re   ra   r   r%   rc   r$   )r   r+   ZpolarvalZazvalr!   r!   r"   r*   W  s    

z+UniformSolidAngle.apply_boundary_conditionsc             K   s   | j jf || jjf | S )a  
        Returns the pdf at the given angles.

        Parameters
        ----------
        \**kwargs:
            The keyword arguments should specify the value for each angle,
            using the names of the polar and azimuthal angles as the keywords.
            Unrecognized arguments are ignored.

        Returns
        -------
        float
            The value of the pdf at the given values.
        )ra   rS   rc   )r   r+   r!   r!   r"   rS   s  s    zUniformSolidAngle._pdfc             K   s   | j jf || jjf | S )a  
        Returns the logpdf at the given angles.

        Parameters
        ----------
        \**kwargs:
            The keyword arguments should specify the value for each angle,
            using the names of the polar and azimuthal angles as the keywords.
            Unrecognized arguments are ignored.

        Returns
        -------
        float
            The value of the pdf at the given values.
        )ra   rU   rc   )r   r+   r!   r!   r"   rU     s    zUniformSolidAngle._logpdfc       
      C   s   |}| t}y||d|}W n tk
r:   | j}Y nX y||d|}W n tk
rh   | j}Y nX ||krtd|d|f ||krtd| dd|  t||||}t||||}|	|d|}	| |||||	dS )	aE  Returns a distribution based on a configuration file.

        The section must have the names of the polar and azimuthal angles in
        the tag part of the section header. For example:

        .. code-block:: ini

            [prior-theta+phi]
            name = uniform_solidangle

        If nothing else is provided, the default names and bounds of the polar
        and azimuthal angles will be used. To specify a different name for
        each angle, set the `polar-angle` and `azimuthal-angle` attributes. For
        example:

        .. code-block:: ini

            [prior-foo+bar]
            name = uniform_solidangle
            polar-angle = foo
            azimuthal-angle = bar

        Note that the names of the variable args in the tag part of the section
        name must match the names of the polar and azimuthal angles.

        Bounds may also be specified for each angle, as factors of pi. For
        example:

        .. code-block:: ini

            [prior-theta+phi]
            polar-angle = theta
            azimuthal-angle = phi
            min-theta = 0
            max-theta = 0.5

        This will return a distribution that is uniform in the upper
        hemisphere.

        By default, the domain of the azimuthal angle is `[0, 2pi)`. To make
        this domain cyclic, add `azimuthal_cyclic_domain =`.

        Parameters
        ----------
        cp : ConfigParser instance
            The config file.
        section : str
            The name of the section.
        variable_args : str
            The names of the parameters for this distribution, separated by
            ``VARARGS_DELIM``. These must appear in the "tag" part
            of the section header.

        Returns
        -------
        UniformSolidAngle
            A distribution instance from the pycbc.inference.prior module.
        zpolar-anglezazimuthal-anglez3polar-angle %s is not one of the variable args (%s)z, z3azimuthal-angle %s is not one of the variable args z(%s)ro   )rk   rl   rm   rn   ro   )
splitr   Zget_opt_tagr   r^   r_   joinr   Zget_param_bounds_from_configr-   )
r.   r/   r0   r1   tagrk   rl   rm   rn   ro   r!   r!   r"   r2     s8    <
zUniformSolidAngle.from_config)NNNNF)r3   r4   r5   r6   r7   r=   r`   r   rb   r^   r_   r   r:   rf   rk   rl   rN   r*   rS   rU   r;   r2   r!   r!   r!   r"   r[   
  s"     
	r[   )r6   configparserr   r8   Zpycbcr   r   Zpycbc.distributionsr   r   ZUniformr   r=   rX   ZBoundedDistr[   __all__r!   r!   r!   r"   <module>   s    H s