B
    d                 @   sF  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 ddlm	Z	 ddlmZ
 ddlmZmZ ddlmZ d	d
lmZmZmZ dddddddddddddgZG dd dZG dd dZG dd dZG dd dZG dd dZd.ddZd/ddZd d! Zd0d$d%Zd&d Zd'd Zd(d Z d)d* Z!d+d Z"d,d Z#d-d Z$dS )1a  
Bounding classes used when proposing new live points, along with a number of
useful helper functions. Bounding objects include:

    UnitCube:
        The unit N-cube (unconstrained draws from the prior).

    Ellipsoid:
        Bounding ellipsoid.

    MultiEllipsoid:
        A set of (possibly overlapping) bounding ellipsoids.

    RadFriends:
        A set of (possibly overlapping) balls centered on each live point.

    SupFriends:
        A set of (possibly overlapping) cubes centered on each live point.

    N)linalg)cov)spatial)cluster)	logsumexpgammaln)kmeans2   )	unitcheckget_seed_sequenceget_random_generatorUnitCube	EllipsoidMultiEllipsoid
RadFriends
SupFriendslogvol_prefactor
randspherebounding_ellipsoidbounding_ellipsoids_bounding_ellipsoids_ellipsoid_bootstrap_expand_friends_bootstrap_radius_friends_leaveoneout_radiusc               @   s>   e Zd ZdZdd Zdd ZdddZdd	d
ZdddZdS )r   z
    An N-dimensional unit cube.

    Parameters
    ----------
    ndim : int
        The number of dimensions of the unit cube.

    c             C   s   || _ d| _d| _d S )Ng        g      ?)nlogvolfunit)selfndim r   ]/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/dynesty/bounding.py__init__7   s    zUnitCube.__init__c             C   s   t |S )z+Checks if unit cube contains the point `x`.)r
   )r   xr   r   r    contains<   s    zUnitCube.containsNc             C   s   |j | jdS )z
        Draw a sample uniformly distributed within the unit cube.

        Returns
        -------
        x : `~numpy.ndarray` with shape (ndim,)
            A coordinate within the unit cube.

        )size)randomr   )r   rstater   r   r    sampleA   s    zUnitCube.samplec             C   s   |j || jfdS )z
        Draw `nsamples` samples randomly distributed within the unit cube.

        Returns
        -------
        x : `~numpy.ndarray` with shape (nsamples, ndim)
            A collection of coordinates within the unit cube.

        )r$   )r%   r   )r   nsamplesr&   r   r   r    samplesN   s    zUnitCube.samplesr   c             C   s   dS )zFiller function.Nr   )r   pointsr&   	bootstrappoolr   r   r    update[   s    zUnitCube.update)N)N)Nr   N)	__name__
__module____qualname____doc__r!   r#   r'   r)   r-   r   r   r   r    r   ,   s   	

c               @   sj   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Zdd Z	dddZ
dddZdddZdddZdS )r   a  
    An N-dimensional ellipsoid defined by::

        (x - v)^T A (x - v) = 1

    where the vector `v` is the center of the ellipsoid and `A` is a
    symmetric, positive-definite `N x N` matrix.

    Parameters
    ----------
    ctr : `~numpy.ndarray` with shape (N,)
        Coordinates of ellipsoid center.

    cov : `~numpy.ndarray` with shape (N, N)
        Covariance matrix describing the axes.

    Nc             C   s   t || _t|| _t|| _tj| jdd\}}t|dkt	|@ rzt
|| _t| jdt|   | _ntd| j d| d| d|d kr|| j | _n|| _|d kr|d	|  |j | _n|| _|| j | _d	| _d
| _d S )NF)check_finiteg        g      ?z2The input precision matrix defining the ellipsoid z is apparently singular with l=z and v=.g      ?r	   )lenr   npZasarrayctrr   lalgeighallisfinitesqrtaxlensr   logsumr   
ValueErroraxesTampaxesexpandr   )r   r6   r   rB   r@   lvr   r   r    r!   s   s$    
 zEllipsoid.__init__c             C   sr  || j  }tt| jd }t| j}| ||| j  k rt|| j }|  j|d 9  _|  j	d|d  9  _	|  j|9  _|  j
|9  _
nt| j}|}| j}tj| jdd\}	}
xPt|	ddd D ]8}tt|||  || d}|||< ||8 }|d8 }qW t|}|	|d  }|
| |
j | _|
d|  |
j | _	|  j|9  _| j
| | _
|| _ dS )	z#Scale ellipsoid to a target volume.   g      ?F)r2   Nr   r	   )r   r5   r=   r;   r   r<   maxexpr   rB   r@   zerosr7   r8   ZargsortminrA   )r   r   ZlogfZmax_log_axlenZ	log_axlenfZlogfaxZcurlogfZcurnrE   rF   Zcurideltafaxl1r   r   r    scale_to_logvol   s4    

zEllipsoid.scale_to_logvolc             C   s2   t | j}| jdd|f }| j| | j| fS )z'Return the endpoints of the major axis.N)r5   Zargmaxr<   rC   r6   )r   irF   r   r   r    major_axis_endpoints   s    zEllipsoid.major_axis_endpointsc             C   s&   || j  }ttt|| j|S )zPCompute the normalized distance to `x` from the center of the
        ellipsoid.)r6   r5   r;   dotrB   )r   r"   dr   r   r    distance   s    
zEllipsoid.distancec             C   s.   || j dddf  }ttd|| j|S )zPCompute the normalized distance to `x` from the center of the
        ellipsoid.Nzij,jk,ik->i)r6   r5   r;   einsumrB   )r   r"   rU   r   r   r    distance_many   s    zEllipsoid.distance_manyc             C   s   |  |dkS )z!Checks if ellipsoid contains `x`.g      ?)rV   )r   r"   r   r   r    r#      s    zEllipsoid.containsc             C   s   | j t| jt| j|d S )z
        Draw a sample uniformly distributed within the ellipsoid.

        Returns
        -------
        x : `~numpy.ndarray` with shape (ndim,)
            A coordinate within the ellipsoid.

        )r&   )r6   r5   rT   r@   r   r   )r   r&   r   r   r    r'      s    zEllipsoid.samplec                s"   t  fddt|D }|S )z
        Draw `nsamples` samples uniformly distributed within the ellipsoid.

        Returns
        -------
        x : `~numpy.ndarray` with shape (nsamples, ndim)
            A collection of coordinates within the ellipsoid.

        c                s   g | ]}j  d qS ))r&   )r'   ).0rR   )r&   r   r   r    
<listcomp>   s    z%Ellipsoid.samples.<locals>.<listcomp>)r5   arrayrange)r   r(   r&   xsr   )r&   r   r    r)      s    zEllipsoid.samples'  c                s6    fddt |D }tdd |D }d| | S )zsUsing `ndraws` Monte Carlo draws, estimate the fraction of
        overlap between the ellipsoid and the unit cube.c                s   g | ]}j  d qS ))r&   )r'   )rY   rR   )r&   r   r   r    rZ      s    z.Ellipsoid.unitcube_overlap.<locals>.<listcomp>c             s   s   | ]}t |V  qd S )N)r
   )rY   r"   r   r   r    	<genexpr>   s    z-Ellipsoid.unitcube_overlap.<locals>.<genexpr>g      ?)r\   r>   )r   ndrawsr&   r)   Zninr   )r&   r   r    unitcube_overlap   s    zEllipsoid.unitcube_overlapr   Fc                s   t  }|j| _|j| _|j| _|j| _|j| _|j| _|j| _|j| _|j	| _	|dkr|dkrft
}n|j
}dd t|D } fddt|D }	t||}
t||	|
}t|t|}t|}|dkr| j| jt|  }| | |r| j|d| _dS )a  
        Update the ellipsoid to bound the collection of points.

        Parameters
        ----------
        points : `~numpy.ndarray` with shape (npoints, ndim)
            The set of points to bound.

        rstate : `~numpy.random.Generator`, optional
            `~numpy.random.Generator` instance.

        bootstrap : int, optional
            The number of bootstrapped realizations of the ellipsoid. The
            maximum distance to the set of points "left out" during each
            iteration is used to enlarge the resulting volumes.
            Default is `0`.

        pool : user-provided pool, optional
            Use this pool of workers to execute operations in parallel.

        mc_integrate : bool, optional
            Whether to use Monte Carlo methods to compute the effective
            overlap of the final ellipsoid with the unit cube.
            Default is `False`.

        r   Nc             S   s   g | ]}d qS )Fr   )rY   itr   r   r    rZ   5  s    z$Ellipsoid.update.<locals>.<listcomp>c                s   g | ]} qS r   r   )rY   rb   )r*   r   r    rZ   6  s    g      ?)r&   )r   r   r6   r   rB   r   r<   r@   rC   rD   mapr\   r   ziplistr   rI   r5   r=   rQ   ra   r   )r   r*   r&   r+   r,   mc_integrateellMmultispsseedsargsexpandsrD   lvr   )r*   r    r-      s2    "

zEllipsoid.update)NN)N)N)r^   N)Nr   NF)r.   r/   r0   r1   r!   rQ   rS   rV   rX   r#   r'   r)   ra   r-   r   r   r   r    r   `   s   
'$


   c               @   sv   e Zd ZdZdddZdd Zdd Zd	d
 ZdddZdddZ	dd Z
d ddZd!ddZd"ddZd#ddZdS )$r   a  
    A collection of M N-dimensional ellipsoids.

    Parameters
    ----------
    ells : list of `Ellipsoid` objects with length M, optional
        A set of `Ellipsoid` objects that make up the collection of
        N-ellipsoids. Used to initialize :class:`MultiEllipsoid` if provided.

    ctrs : `~numpy.ndarray` with shape (M, N), optional
        Collection of coordinates of ellipsoid centers. Used to initialize
        :class:`MultiEllipsoid` if :data:`ams` is also provided.

    covs : `~numpy.ndarray` with shape (M, N, N), optional
        Collection of matrices describing the axes of the ellipsoids. Used to
        initialize :class:`MultiEllipsoid` if :data:`ctrs` also provided.

    Nc                s   |d k	r4d kr* d kr*t || _|| _qttdn@d krN d krNtdn&t | _ fddt| jD | _|   t| j| _t	| j
| _d| _d| _d S )Nz5You cannot specific both `ells` and (`ctrs`, `covs`)!z3You must specify either `ells` or (`ctrs`, `covs`).c                s   g | ]}t |  | qS r   )r   )rY   rR   )covsctrsr   r    rZ   o  s    z+MultiEllipsoid.__init__.<locals>.<listcomp>g      ?r	   )r4   nellsellsr?   r\   _MultiEllipsoid__update_arraysr5   Zonesrm   r   logvols
logvol_tot
expand_totr   )r   rr   rp   ro   r   )ro   rp   r    r!   ^  s    



zMultiEllipsoid.__init__c             C   sd   t dd | jD | _t dd | jD | _t dd | jD | _t dd | jD | _dS )zI
        Update internal arrays to ensure that in sync with ells
        c             S   s   g | ]
}|j qS r   )r6   )rY   rg   r   r   r    rZ   }  s    z2MultiEllipsoid.__update_arrays.<locals>.<listcomp>c             S   s   g | ]
}|j qS r   )r   )rY   rg   r   r   r    rZ   ~  s    c             S   s   g | ]
}|j qS r   )rB   )rY   rg   r   r   r    rZ     s    c             S   s   g | ]
}|j qS r   )r   )rY   rg   r   r   r    rZ     s    N)r5   r[   rr   rp   ro   amsrt   )r   r   r   r    Z__update_arraysy  s    zMultiEllipsoid.__update_arraysc                s|   x&t  jD ]} j| ||  qW    t fddt  jD  _t|}  j	t
| j 9  _	| _dS )zJScale ellipoids to a corresponding set of
        target volumes.
        c                s   g | ]} j | jqS r   )rr   rD   )rY   rR   )r   r   r    rZ     s    z2MultiEllipsoid.scale_to_logvol.<locals>.<listcomp>N)r\   rq   rr   rQ   rs   r5   r[   rm   r   rv   rJ   ru   )r   rt   rR   ru   r   )r   r    rQ     s    zMultiEllipsoid.scale_to_logvolc             C   s   t dd | jD S )z9Return the endpoints of the major axis of each ellipsoid.c             S   s   g | ]}|  qS r   )rS   )rY   rg   r   r   r    rZ     s    z7MultiEllipsoid.major_axis_endpoints.<locals>.<listcomp>)r5   r[   rr   )r   r   r   r    rS     s    z#MultiEllipsoid.major_axis_endpointsc             C   sJ   |dddf | j  }td|| j|dk }|dk	r<d||< t|d S )z]Checks which ellipsoid(s) `x` falls within, skipping the `j`-th
        ellipsoid if need be.Nzai,aij,aj->ar	   Fr   )rp   r5   rW   rw   Znonzero)r   r"   jdeltmaskr   r   r    within  s
    zMultiEllipsoid.withinc             C   s   t | j||d}|S )zUChecks how many ellipsoid(s) `x` falls within, skipping the `j`-th
        ellipsoid.)rx   )r4   r{   )r   r"   rx   qr   r   r    overlap  s    zMultiEllipsoid.overlapc             C   s2   |dddf | j  }ttd|| j|dk S )z-Checks if the set of ellipsoids contains `x`.Nzai,aij,aj->ar	   )rp   r5   anyrW   rw   )r   r"   ry   r   r   r    r#     s    zMultiEllipsoid.containsFc       
      C   s  | j dkr:| jd j|d}d}d}|r2|||fS ||fS t| j| j }xt||}| j| j|d}|dddf | j }t	d|| j
|}|dk  }|dkr|dk }|dkr| }	td|	 |r|||fS |dks| d| k rN||fS qNW dS )a  
        Sample a point uniformly distributed within the *union* of ellipsoids.

        Returns
        -------
        x : `~numpy.ndarray` with shape (ndim,)
            A coordinate within the set of ellipsoids.

        idx : int
            The index of the ellipsoid `x` was sampled from.

        q : int, optional
            The number of ellipsoids `x` falls within.

        r	   r   )r&   Nzai,aij,aj->azEllipsoid check failed q=0, g      ?)rq   rr   r'   r5   rJ   rt   ru   rand_choicerp   rW   rw   r>   rI   RuntimeErrorr%   )
r   r&   return_qr"   idxr|   ZprobsZdeltsZ	ell_masksZmax_maskr   r   r    r'     s0    



zMultiEllipsoid.samplec                s"   t  fddt|D }|S )a  
        Draw `nsamples` samples uniformly distributed within the *union* of
        ellipsoids.

        Returns
        -------
        xs : `~numpy.ndarray` with shape (nsamples, ndim)
            A collection of coordinates within the set of ellipsoids.

        c                s   g | ]}j  d d qS ))r&   r   )r'   )rY   rR   )r&   r   r   r    rZ     s    z*MultiEllipsoid.samples.<locals>.<listcomp>)r5   r[   r\   )r   r(   r&   r]   r   )r&   r   r    r)     s    zMultiEllipsoid.samples'  Tc       	         sl    fddt |D }tdd |D }t|| j }|rdtdd |D }|| }||fS |S dS )zUsing `ndraws` Monte Carlo draws, estimate the log volume of the
        *union* of ellipsoids. If `return_overlap=True`, also returns the
        estimated fractional overlap with the unit cube.c                s   g | ]}j  d dqS )T)r&   r   )r'   )rY   rR   )r&   r   r   r    rZ     s    z5MultiEllipsoid.monte_carlo_logvol.<locals>.<listcomp>c             s   s   | ]\}}}d | V  qdS )g      ?Nr   )rY   r"   r   r|   r   r   r    r_     s    z4MultiEllipsoid.monte_carlo_logvol.<locals>.<genexpr>c             s   s$   | ]\}}}d | t | V  qdS )g      ?N)r
   )rY   r"   r   r|   r   r   r    r_     s    N)r\   r>   r5   r=   ru   )	r   r`   r&   return_overlapr)   qsumr   qinr}   r   )r&   r   r    monte_carlo_logvol  s    
z!MultiEllipsoid.monte_carlo_logvolr   c                sh   j \}}|dkrtdt }t |}	t|	_|	_  tfdd D sbtdt	j
_tdd jD }
j
t|
 }t	|}tj| _|dkrH|d	krt}n|j}d
d t|D } fddt|D }t||}t|||}t|t|}
t|
}|dkrHj
|t|  }| |rdj|dd\__d	S )a  
        Update the set of ellipsoids to bound the collection of points.

        Parameters
        ----------
        points : `~numpy.ndarray` with shape (npoints, ndim)
            The set of points to bound.

        rstate : `~numpy.random.Generator`, optional
            `~numpy.random.Generator` instance.

        bootstrap : int, optional
            The number of bootstrapped realizations of the ellipsoids. The
            maximum distance to the set of points "left out" during each
            iteration is used to enlarge the resulting volumes.
            Default is `0`.

        pool : user-provided pool, optional
            Use this pool of workers to execute operations in parallel.

        mc_integrate : bool, optional
            Whether to use Monte Carlo methods to compute the effective
            volume and fractional overlap of the final union of ellipsoids
            with the unit cube. Default is `False`.

        r	   z8Cannot compute the bounding ellipsoid of a single point.c             3   s   | ]}  |V  qd S )N)r#   )rY   p)r   r   r    r_   D  s    z(MultiEllipsoid.update.<locals>.<genexpr>z'Rejecting invalid MultiEllipsoid regionc             S   s   g | ]
}|j qS r   )rD   )rY   rg   r   r   r    rZ   J  s    z)MultiEllipsoid.update.<locals>.<listcomp>r   Nc             S   s   g | ]}d qS )Tr   )rY   rb   r   r   r    rZ   W  s    c                s   g | ]} qS r   r   )rY   rb   )r*   r   r    rZ   X  s    g      ?T)r&   r   )shaper   r   r   r4   rq   rr   rs   r9   r   rt   ru   r5   r[   r=   rJ   rv   rc   r\   r   rd   re   r   rI   rQ   r   r   )r   r*   r&   r+   r,   rf   npointsr   Zfirstellrr   rm   Zlogvols_origZlogvol_tot_origrh   ri   rj   rk   rl   rD   Zlvsr   )r*   r   r    r-     s>    !






zMultiEllipsoid.update)NNN)N)N)NF)N)r   NT)Nr   NF)r.   r/   r0   r1   r!   rs   rQ   rS   r{   r}   r#   r'   r)   r   r-   r   r   r   r    r   J  s"   
	



<
  
   c               @   sr   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdddZ	dddZ
d ddZd!ddZdd Zdd ZdS )"r   a0  
    A collection of N-balls of identical size centered on each live point.

    Parameters
    ----------
    ndim : int
        The number of dimensions of each ball.

    cov : `~numpy.ndarray` with shape `(ndim, ndim)`, optional
        Covariance structure (correlation and size) of each ball.

    Nc             C   s   || _ |d krt| j }|| _t| j| _t| j| _t| j| _	t
| j\}}|dksftt| j d|  | _d| _d| _d S )Nr   g      ?g      ?r	   )r   r5   identityr   r7   pinvhrB   sqrtmr@   axes_invr   slogdetAssertionErrorr   logvol_ballrD   r   )r   r   r   detsigndetlnr   r   r    r!   {  s    zRadFriends.__init__c             C   sd   t || j d| j  }|  j|d 9  _|  j|d   _|  j|9  _|  j|  _|| _dS )z(Scale ball to encompass a target volume.g      ?rG   N)r5   rJ   r   r   r   rB   r@   r   )r   r   rM   r   r   r    rQ     s    zRadFriends.scale_to_logvolc             C   s.   t tjt || | jdddkd }|S )z#Check which balls `x` falls within.r	   )axisg      ?r   )r5   wherer7   normrT   r   )r   r"   rp   idxsr   r   r    r{     s    &zRadFriends.withinc             C   s   t | ||}|S )z&Check how many balls `x` falls within.)r4   r{   )r   r"   rp   r|   r   r   r    r}     s    zRadFriends.overlapc             C   s   |  ||dkS )z'Check if the set of balls contains `x`.r   )r}   )r   r"   rp   r   r   r    r#     s    zRadFriends.containsFc       
      C   s   t |}xt| j|d}t|| j}|dkr@d}|d | }n"||}	||	 | }| ||}|dks~|s~| d| k r
|r||fS |S q
W dS )a$  
        Sample a point uniformly distributed within the *union* of balls.

        Returns
        -------
        x : `~numpy.ndarray` with shape (ndim,)
            A coordinate within the set of balls.

        q : int, optional
            The number of balls `x` falls within.

        )r&   r	   r   g      ?N)	r4   r   r   r5   rT   r@   integersr}   r%   )
r   rp   r&   r   nctrsdsdxr|   r"   r   r   r   r    r'     s    
zRadFriends.samplec                s$   t  fddt|D }|S )a  
        Draw `nsamples` samples uniformly distributed within the *union* of
        balls.

        Returns
        -------
        xs : `~numpy.ndarray` with shape (nsamples, ndim)
            A collection of coordinates within the set of balls.

        c                s   g | ]}j  d qS ))r&   )r'   )rY   rR   )rp   r&   r   r   r    rZ     s    z&RadFriends.samples.<locals>.<listcomp>)r5   r[   r\   )r   r(   rp   r&   r]   r   )rp   r&   r   r    r)     s    zRadFriends.samples'  Tc                s    fddt |D }tdd |D }td| }td| | t  j }|rtdd |D }	|	| }
||
fS |S dS )zUsing `ndraws` Monte Carlo draws, estimate the log volume of the
        *union* of balls. If `return_overlap=True`, also returns the
        estimated fractional overlap with the unit cube.c                s   g | ]}j  d dqS )T)r&   r   )r'   )rY   rR   )rp   r&   r   r   r    rZ     s   z1RadFriends.monte_carlo_logvol.<locals>.<listcomp>c             S   s   g | ]}|d  qS )r	   r   )rY   _r   r   r    rZ     s    g      ?c             s   s"   | ]\}}d | t | V  qdS )g      ?N)r
   )rY   r"   r|   r   r   r    r_     s    z0RadFriends.monte_carlo_logvol.<locals>.<genexpr>N)r\   r5   r[   r>   r=   r4   r   )r   rp   r`   r&   r   r)   qsr   r   r   r}   r   )rp   r&   r   r    r     s     zRadFriends.monte_carlo_logvolr   c                sj  |dkrt }n|j }|r&| || _n| || _t| j| _t| j| _t| j| _	t
|| j	 |dkr~t d}nL fddt|D }	dd t|D }
t||}t|	|
|}t|t|}t|}|  j|d 9  _|  j|d   _|  j|9  _|  j	|  _	t| j\}}|dks0tt| jd	|  | _d
| _|rf| j|d|dd | _dS )a/  
        Update the radii of our balls.

        Parameters
        ----------
        points : `~numpy.ndarray` with shape (npoints, ndim)
            The set of points to bound.

        rstate : `~numpy.random.Generator`, optional
            `~numpy.random.Generator` instance.

        bootstrap : int, optional
            The number of bootstrapped realizations of the ellipsoids. The
            maximum distance to the set of points "left out" during each
            iteration is used to enlarge the resulting volumes.
            Default is `0`.

        pool : user-provided pool, optional
            Use this pool of workers to execute operations in parallel.

        mc_integrate : bool, optional
            Whether to use Monte Carlo methods to compute the effective
            volume and fractional overlap of the final union of balls
            with the unit cube. Default is `False`.

        use_clustering : bool, optional
            Whether to use clustering to avoid issues with widely-seperated
            modes. Default is `True`.

        Ng        ballsc                s   g | ]} qS r   r   )rY   rb   )points_tr   r    rZ   8  s    z%RadFriends.update.<locals>.<listcomp>c             S   s   g | ]}d qS )r   r   )rY   rb   r   r   r    rZ   9  s    rG   r   g      ?g      ?T)r   r&   r	   )rc   _get_covariance_from_clustersr   _get_covariance_from_all_pointsr7   r   rB   r   r@   r   r5   rT   r   r\   r   rd   re   r   rI   r   r   r   r   r   r   rD   r   r   )r   r*   r&   r+   r,   rf   use_clusteringrh   Zradiirj   ftypesrk   rl   Zrmaxr   r   r   )r   r    r-     s<    '
zRadFriends.updatec             C   s   t j|ddS )z$Compute covariance using all points.F)rowvar)r5   r   )r   r*   r   r   r    r   T  s    z*RadFriends._get_covariance_from_all_pointsc             C   s   t jj|d| jd}tj|}tjj|ddd}t	|}|dkrN| 
|S d}t|}x`t|D ]R}|||kddf }	|	jdd	d
}
|t|	 }|	|
 |||ddf< |}qhW | 
|S dS )z-Compute covariance from re-centered clusters.mahalanobis)metricVIg      ?rV   )	criterionr	   r   N)r   )r	   rH   )r   rV   pdistrB   r   	hierarchysinglefclusterr5   rI   r   
empty_likeuniquemeanreshaper4   )r   r*   	distanceslinkagesclusteridxs	nclustersrR   overlapped_pointsr   group_points
group_meanrx   r   r   r    r   Y  s&    



z(RadFriends._get_covariance_from_clusters)N)NF)N)r   NT)Nr   NFT)r.   r/   r0   r1   r!   rQ   r{   r}   r#   r'   r)   r   r-   r   r   r   r   r   r    r   m  s$   
	
$
  
    
Sc               @   sr   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdddZ	dddZ
d ddZd!ddZdd Zdd ZdS )"r   a/  
    A collection of N-cubes of identical size centered on each live point.

    Parameters
    ----------
    ndim : int
        The number of dimensions of the cube.

    cov : `~numpy.ndarray` with shape `(ndim, ndim)`, optional
        Covariance structure (correlation and size) of each cube.

    Nc             C   s   || _ |d krt| j }|| _t| j| _t| j| _t| j| _	t
| j\}}|dksft| j td d|  | _d| _d| _d S )Nr   g       @g      ?g      ?r	   )r   r5   r   r   r7   r   rB   r   r@   r   r   r   r   r=   logvol_cuberD   r   )r   r   r   r   r   r   r   r    r!     s    zSupFriends.__init__c             C   sd   t || j d| j  }|  j|d 9  _|  j|d   _|  j|9  _|  j|  _|| _dS )z(Scale cube to encompass a target volume.g      ?rG   N)r5   rJ   r   r   r   rB   r@   r   )r   r   rM   r   r   r    rQ     s    zSupFriends.scale_to_logvolc          	   C   s4   t t jt t || | jdddkd }|S )z$Checks which cubes `x` falls within.r	   )r   g      ?r   )r5   r   rI   absrT   r   )r   r"   rp   r   r   r   r    r{     s    ,zSupFriends.withinc             C   s   t | ||}|S )zIChecks how many cubes `x` falls within, skipping the `j`-th
        cube.)r4   r{   )r   r"   rp   r|   r   r   r    r}     s    zSupFriends.overlapc             C   s   |  ||dkS )z(Checks if the set of cubes contains `x`.r   )r}   )r   r"   rp   r   r   r    r#     s    zSupFriends.containsFc       
      C   s   t |}x|jdd| jd}t|| j}|dkrD|d | }d}n"||}	||	 | }| ||}|dks|s| d| k r
|r||fS |S q
W dS )a$  
        Sample a point uniformly distributed within the *union* of cubes.

        Returns
        -------
        x : `~numpy.ndarray` with shape (ndim,)
            A coordinate within the set of cubes.

        q : int, optional
            The number of cubes `x` falls within.

        rH   r	   )r$   r   g      ?N)	r4   uniformr   r5   rT   r@   r   r}   r%   )
r   rp   r&   r   r   r   r   r"   r|   r   r   r   r    r'     s    
zSupFriends.samplec                s$   t  fddt|D }|S )a  
        Draw `nsamples` samples uniformly distributed within the *union* of
        cubes.

        Returns
        -------
        xs : `~numpy.ndarray` with shape (nsamples, ndim)
            A collection of coordinates within the set of cubes.

        c                s   g | ]}j  d qS ))r&   )r'   )rY   rR   )rp   r&   r   r   r    rZ     s    z&SupFriends.samples.<locals>.<listcomp>)r5   r[   r\   )r   r(   rp   r&   r]   r   )rp   r&   r   r    r)     s    zSupFriends.samples'  Tc       
         sz    fddt |D }tdd |D }td| | t  j }|rrtdd |D }|| }	||	fS |S dS )zUsing `ndraws` Monte Carlo draws, estimate the log volume of the
        *union* of cubes. If `return_overlap=True`, also returns the
        estimated fractional overlap with the unit cube.c                s   g | ]}j  d dqS )T)r&   r   )r'   )rY   rR   )rp   r&   r   r   r    rZ     s   z1SupFriends.monte_carlo_logvol.<locals>.<listcomp>c             s   s   | ]\}}d | V  qdS )g      ?Nr   )rY   r"   r|   r   r   r    r_     s    z0SupFriends.monte_carlo_logvol.<locals>.<genexpr>g      ?c             s   s"   | ]\}}d | t | V  qdS )g      ?N)r
   )rY   r"   r|   r   r   r    r_      s    N)r\   r>   r5   r=   r4   r   )
r   rp   r`   r&   r   r)   r   r   r   r}   r   )rp   r&   r   r    r     s     zSupFriends.monte_carlo_logvolr   c                sp  |dkrt }n|j }|r&| || _n| || _t| j| _t| j| _t| j| _	t
|| j	 |dkr~t d}nL fddt|D }	dd t|D }
t||}t|	|
|}t|t|}t|}|  j|d 9  _|  j|d   _|  j|9  _|  j	|  _	t| j\}}|dks0t| jt
d	 d
|  | _d| _|rl| j|d|dd | _dS )a;  
        Update the half-side-lengths of our cubes.

        Parameters
        ----------
        points : `~numpy.ndarray` with shape (npoints, ndim)
            The set of points to bound.

        rstate : `~numpy.random.Generator`, optional
            `~numpy.random.Generator` instance.

        bootstrap : int, optional
            The number of bootstrapped realizations of the ellipsoids. The
            maximum distance to the set of points "left out" during each
            iteration is used to enlarge the resulting volumes.
            Default is `0`.

        pool : user-provided pool, optional
            Use this pool of workers to execute operations in parallel.

        mc_integrate : bool, optional
            Whether to use Monte Carlo methods to compute the effective
            volume and fractional overlap of the final union of cubes
            with the unit cube. Default is `False`.

        use_clustering : bool, optional
            Whether to use clustering to avoid issues with widely-seperated
            modes. Default is `True`.

        Ng        cubesc                s   g | ]} qS r   r   )rY   rb   )r   r   r    rZ   C  s    z%SupFriends.update.<locals>.<listcomp>c             S   s   g | ]}d qS )r   r   )rY   rb   r   r   r    rZ   D  s    rG   r   g       @g      ?g      ?T)r   r&   r	   )rc   r   r   r   r7   r   rB   r   r@   r   r5   rT   r   r\   r   rd   re   r   rI   r   r   r   r   r=   r   rD   r   r   )r   r*   r&   r+   r,   rf   r   rh   Zhsidesrj   r   rk   rl   Zhsmaxr   r   r   )r   r    r-     s<    '
zSupFriends.updatec             C   s   t j|ddS )z$Compute covariance using all points.F)r   )r5   r   )r   r*   r   r   r    r   ^  s    z*SupFriends._get_covariance_from_all_pointsc             C   s   t jj|d| jd}tj|}tjj|ddd}t	|}|dkrN| 
|S d}t|}x`t|D ]R}|||kddf }	|	jdd	d
}
|t|	 }|	|
 |||ddf< |}qhW | 
|S dS )z-Compute covariance from re-centered clusters.r   )r   r   g      ?rV   )r   r	   r   N)r   )r	   rH   )r   rV   r   rB   r   r   r   r   r5   rI   r   r   r   r   r   r4   )r   r*   r   r   r   r   rR   r   r   r   r   rx   r   r   r    r   c  s&    



z(SupFriends._get_covariance_from_clusters)N)NF)N)r   NT)Nr   NFT)r.   r/   r0   r1   r!   rQ   r{   r}   r#   r'   r)   r   r-   r   r   r   r   r   r    r   w  s$   
	
%
  
    
R       @c             C   s>   |d9 }| t d | td| d   t| | d  }|S )a  
    Returns the ln(volume constant) for an `n`-dimensional sphere with an
    :math:`L^p` norm. The constant is defined as::

        lnf = n * ln(2.) + n * LogGamma(1./p + 1) - LogGamma(n/p + 1.)

    By default the `p=2.` norm is used (i.e. the standard Euclidean norm).

    g      ?g       @r	   )r5   r=   r   )r   r   Zlnfr   r   r    r     s    2c             C   s2   |j | d}|| d|   tj|dd  }|S )z=Draw a point uniformly within an `n`-dimensional unit sphere.)r$   g      ?F)r2   )Zstandard_normalr%   r7   r   )r   r&   zZxhatr   r   r    r     s    "c             C   s,   t | }| }tt ||t| d S )z Optimized version of numpy's random.choice
    Return an index of a point selected with the probability pb
    The pb must sum to 1
    r	   )r5   Zcumsumr%   rL   Zsearchsortedr4   )Zpbr&   p1Zxrr   r   r    r     s    
r   d      mBc          	   C   sx  | j d }t| }d}d}xt|D ]}d}yhtj|dd\}	}
|	 }|	 }t|		 r|dkrpd}q||| k rd}q|
|	d  }P nd}W n tj
k
r   d}Y nX |dkr(|dkrt|	|| | }|
| |
j }q(|d	| |d	 |d    }d	| | |t|  }q(W |dkrRtd
 t|}| }| }n|
d	|	  |
j }|dk}||||fS )a7  
    Given the covariance matrix improve it, if it is not invertable
    or eigen values are negative or condition number that is above the limit
    Returns:
    a tuple with three elements
    1) a boolean flag if a matrix is 'good', so it didn't need adjustments
    2) updated matrix
    3) its inverse
    r   g|=
   F)r2   rG   r	   g      ?g      ?zTFailed to guarantee the ellipsoid axes will be non-singular. Defaulting to a sphere.)r   r5   r[   r\   r7   r8   rI   rL   r:   r9   ZLinAlgErrormaximumrA   eyewarningswarncopy)Zcovar0ZntriesZmax_condition_numberr   covarZcoeffminZeig_multZtrialfailedZeigvalZeigvecmaxvalminvalr@   Z
eigval_fixZcoeffrB   good_matr   r   r    improve_covar_mat  sF    







r   c             C   s   | j \}}|dkrtdtj| dd}t| dd}| | }|dkrNt|}d}d| }xtd	D ]|}t|\}	}}
}td
||
|	 }|dkr||kr|| }||9 }|
| }
|t
|9 }|dkr|dkrtd|	rdP qdW t|||
|d}|S )a0  
    Calculate the bounding ellipsoid containing a collection of points.

    Parameters
    ----------
    points : `~numpy.ndarray` with shape (npoints, ndim)
        A set of coordinates.

    Returns
    -------
    ellipsoid : :class:`Ellipsoid`
        The bounding :class:`Ellipsoid` object.

    r	   z6Cannot compute a bounding ellipsoid of a single point.r   )r   F)r   gMbP?g      ?rG   zij,jk,ik->iz<Failed to initialize the ellipsoid to contain all the points)rB   r@   )r   r?   r5   r   mle_covZ
atleast_2dr\   r   rW   rI   r;   r   r   )r*   r   r   r6   r   rN   ZROUND_DELTAZone_minus_a_bitrR   r   rB   r@   ZfmaxZmultrg   r   r   r    r     s2    

c          	      s  j \}}| \}}t||f}t " td t|dddd}W dQ R X |d   fdd	d
D }|d j d d| k s|d j d d| k r|gS dd	 |D }	||d  d }
t|
 t	| | }t
|	d j|	d jt	||j k r(t|d |	d t|d |	d  S t|d |	d t|d |	d  }t|
 t|d  t	| | }tdd	 |D t	||j k r|S |gS )ac  
    Internal method used to compute a set of bounding ellipsoids when a
    bounding ellipsoid for the entire set has already been calculated.

    Parameters
    ----------
    points : `~numpy.ndarray` with shape (npoints, ndim)
        A set of coordinates.

    ell : Ellipsoid
        The bounding ellipsoid containing :data:`points`.

    Returns
    -------
    ells : list of :class:`Ellipsoid` objects
        List of :class:`Ellipsoid` objects used to bound the
        collection of points. Used to initialize the :class:`MultiEllipsoid`
        object returned in :meth:`bounding_ellipsoids`.

    ignorer   matrixF)kiterZminitr2   Nr	   c                s    g | ]} |kd d f qS )Nr   )rY   r   )labelsr*   r   r    rZ   o  s    z(_bounding_ellipsoids.<locals>.<listcomp>)r   r	   r   rG   c             S   s   g | ]}t |qS r   )r   )rY   Zpoints_jr   r   r    rZ   y  s       c             S   s   g | ]
}|j qS r   )r   )rY   er   r   r    rZ     s    )r   rS   r5   Zvstackr   catch_warningssimplefilterr   rJ   r=   Z	logaddexpr   r   r4   r   )r*   rg   r   r   r   p2Z
start_ctrsZk2_resZpoints_krr   ZnparamZvol_dec1outZvol_dec2r   )r   r*   r    r   G  s6    


,&$c             C   s   t | }t| |}t|dS )aa  
    Calculate a set of ellipsoids that bound the collection of points.

    Parameters
    ----------
    points : `~numpy.ndarray` with shape (npoints, ndim)
        A set of coordinates.

    Returns
    -------
    mell : :class:`MultiEllipsoid` object
        The :class:`MultiEllipsoid` object used to bound the
        collection of points.

    )rr   )r   r   r   )r*   rg   rr   r   r   r    r     s    
c       
      C   s   t |}| jd }|j||d}t|}tj|td}d||< | }|dk r\d|dd< ||d krpd|d< | | | |   }}	||	fS )	zl
    Select the bootstrap set from points.
    Return:
    Tuple with selected, and not-selected points
    r   )r$   )ZdtypeTrG   Nr	   F)r   r   r   r5   r   rK   boolr>   )
r*   rseedr&   r   r   Zidx_inZsel_inZn_in	points_in
points_outr   r   r    _bootstrap_points  s    

r   c       	         sp   | \}}}t ||\} t|}|s0| }n,t||}tjt fdd|D dd}tdt|}|S )a8  Internal method used to compute the expansion factor for a bounding
    ellipsoid or ellipsoids based on bootstrapping.
    The argument is a tuple:
    multi: boolean flag if we are doing multiell or single ell decomposition
    points: 2d array of points
    rseed: seed to initialize the random generator
    c                s   g | ]}|  qS r   )rX   )rY   el)r   r   r    rZ     s    z/_ellipsoid_bootstrap_expand.<locals>.<listcomp>r   )r   g      ?)r   r   rX   r   r5   rL   r[   rI   )	rl   multir*   r   r   rg   distsrr   rD   r   )r   r    r     s    


c       	      C   sn   | \}}}t ||\}}t|}|dkrB|j|ddddd }n |dkrb|j|ddtjdd }t|}|S )zInternal method used to compute the radius (half-side-length) for each
    ball (cube) used in :class:`RadFriends` (:class:`SupFriends`) using
    bootstrapping.r   r	   r   rG   )r   epsr   r   )r   r   KDTreequeryr5   infrI   )	rl   r*   ftyper   r   r   kdtreer   distr   r   r    r     s    

c             C   s^   t | }|dkr*|j| ddddd }n |dkrJ|j| ddtjdd }|dddf }|S )zInternal method used to compute the radius (half-side-length) for each
    ball (cube) used in :class:`RadFriends` (:class:`SupFriends`) using
    leave-one-out (LOO) cross-validation.r   rG   r   )r   r   r   r   Nr	   )r   r   r   r5   r   )r*   r   r   r   r   r   r   r    r     s    
)r   )N)r   r   )%r1   r   numpyr5   r   r   r   Zscipyr   r   r7   Zscipy.specialr   r   Zscipy.cluster.vqr   utilsr
   r   r   __all__r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    <module>   sL   
4 k  %    


LMX 