U
    d(                     @   sd   d dl Z d dlZd dlmZ d dlmZ d dlmZmZ dd Z	dd Z
d	d
 ZG dd deZdS )    N)constraints)Distribution)_standard_normallazy_propertyc                 C   s   t | |ddS )a  
    Performs a batched matrix-vector product, with compatible but different batch shapes.

    This function takes as input `bmat`, containing :math:`n \times n` matrices, and
    `bvec`, containing length :math:`n` vectors.

    Both `bmat` and `bvec` may have any number of leading dimensions, which correspond
    to a batch shape. They are not necessarily assumed to have the same batch shape,
    just ones which can be broadcasted.
    )torchmatmulZ	unsqueezeZsqueeze)ZbmatZbvec r	   K/tmp/pip-unpacked-wheel-ua33x9lu/torch/distributions/multivariate_normal.py	_batch_mv	   s    r   c                 C   s  | d}|jdd }t|}|  d }|| }|| }|d|  }|jd| }	t| jdd |j|d D ]\}
}|	||
 |
f7 }	qt|	|f7 }	||	}tt|tt||d tt|d |d |g }||}| d||}|d| d|}|ddd}t	j
j||dddd}| }||jdd }tt|}t|D ]}||| || g7 }q`||}||S )	aK  
    Computes the squared Mahalanobis distance :math:`\mathbf{x}^\top\mathbf{M}^{-1}\mathbf{x}`
    for a factored :math:`\mathbf{M} = \mathbf{L}\mathbf{L}^\top`.

    Accepts batches for both bL and bx. They are not necessarily assumed to have the same batch
    shape, but `bL` one should be able to broadcasted to `bx` one.
    r   N      r   Fupper)sizeshapelendimzipZreshapelistrangeZpermuter   linalgsolve_triangularpowsumt)ZbLZbxnZbx_batch_shapeZbx_batch_dimsZbL_batch_dimsZouter_batch_dimsZold_batch_dimsZnew_batch_dimsZbx_new_shapeZsLZsxZpermute_dimsZflat_LZflat_xZflat_x_swapZM_swapMZ
permuted_MZpermute_inv_dimsiZ
reshaped_Mr	   r	   r
   _batch_mahalanobis   s>    
&




r    c                 C   sZ   t jt | d}t t |ddd}t j| jd | j| jd}t jj	||dd}|S )N)r   r   r   r   dtypedeviceFr   )
r   r   choleskyZflipZ	transposeZeyer   r"   r#   r   )PZLfZL_invZIdLr	   r	   r
   _precision_to_scale_trilE   s
    r'   c                       s   e Zd ZdZejejejejdZejZ	dZ
d fdd	Zd fdd	Zed	d
 Zedd Zedd Zedd Zedd Zedd Ze fddZdd Zdd Z  ZS )MultivariateNormala#  
    Creates a multivariate normal (also called Gaussian) distribution
    parameterized by a mean vector and a covariance matrix.

    The multivariate normal distribution can be parameterized either
    in terms of a positive definite covariance matrix :math:`\mathbf{\Sigma}`
    or a positive definite precision matrix :math:`\mathbf{\Sigma}^{-1}`
    or a lower-triangular matrix :math:`\mathbf{L}` with positive-valued
    diagonal entries, such that
    :math:`\mathbf{\Sigma} = \mathbf{L}\mathbf{L}^\top`. This triangular matrix
    can be obtained via e.g. Cholesky decomposition of the covariance.

    Example:

        >>> m = MultivariateNormal(torch.zeros(2), torch.eye(2))
        >>> m.sample()  # normally distributed with mean=`[0,0]` and covariance_matrix=`I`
        tensor([-0.2102, -0.5429])

    Args:
        loc (Tensor): mean of the distribution
        covariance_matrix (Tensor): positive-definite covariance matrix
        precision_matrix (Tensor): positive-definite precision matrix
        scale_tril (Tensor): lower-triangular factor of covariance, with positive-valued diagonal

    Note:
        Only one of :attr:`covariance_matrix` or :attr:`precision_matrix` or
        :attr:`scale_tril` can be specified.

        Using :attr:`scale_tril` will be more efficient: all computations internally
        are based on :attr:`scale_tril`. If :attr:`covariance_matrix` or
        :attr:`precision_matrix` is passed instead, it is only used to compute
        the corresponding lower triangular matrices using a Cholesky decomposition.
    )loccovariance_matrixprecision_matrix
scale_trilTNc                    s  |  dk rtd|d k	|d k	 |d k	 dkr8td|d k	r|  dk rTtdt|jd d |jd d }||d | _n|d k	r|  dk rtd	t|jd d |jd d }||d | _nD|  dk rtd
t|jd d |jd d }||d | _||d | _	| j	jdd  }t
t| j|||d |d k	r`|| _n$|d k	rztj|| _n
t|| _d S )Nr   z%loc must be at least one-dimensional.zTExactly one of covariance_matrix or precision_matrix or scale_tril may be specified.r   zZscale_tril matrix must be at least two-dimensional, with optional leading batch dimensionsr   r   )r   r   zZcovariance_matrix must be at least two-dimensional, with optional leading batch dimensionszYprecision_matrix must be at least two-dimensional, with optional leading batch dimensions)r   validate_args)r   
ValueErrorr   Zbroadcast_shapesr   expandr,   r*   r+   r)   superr(   __init___unbroadcasted_scale_trilr   r$   r'   )selfr)   r*   r+   r,   r.   batch_shapeevent_shape	__class__r	   r
   r2   w   s4       

zMultivariateNormal.__init__c                    s   |  t|}t|}|| j }|| j | j }| j||_| j|_d| jkr^| j	||_	d| jkrv| j
||_
d| jkr| j||_tt|j|| jdd | j|_|S )Nr*   r,   r+   Fr-   )Z_get_checked_instancer(   r   Sizer6   r)   r0   r3   __dict__r*   r,   r+   r1   r2   _validate_args)r4   r5   Z	_instancenewZ	loc_shapeZ	cov_shaper7   r	   r
   r0      s$    




zMultivariateNormal.expandc                 C   s   | j | j| j | j S N)r3   r0   _batch_shape_event_shaper4   r	   r	   r
   r,      s    zMultivariateNormal.scale_trilc                 C   s&   t | j| jj| j| j | j S r=   )r   r   r3   ZmTr0   r>   r?   r@   r	   r	   r
   r*      s
    z$MultivariateNormal.covariance_matrixc                 C   s    t | j| j| j | j S r=   )r   Zcholesky_inverser3   r0   r>   r?   r@   r	   r	   r
   r+      s    z#MultivariateNormal.precision_matrixc                 C   s   | j S r=   r)   r@   r	   r	   r
   mean   s    zMultivariateNormal.meanc                 C   s   | j S r=   rA   r@   r	   r	   r
   mode   s    zMultivariateNormal.modec                 C   s    | j dd| j| j S )Nr   r   )r3   r   r   r0   r>   r?   r@   r	   r	   r
   variance   s    
zMultivariateNormal.variancec                 C   s2   |  |}t|| jj| jjd}| jt| j| S )Nr!   )Z_extended_shaper   r)   r"   r#   r   r3   )r4   Zsample_shaper   Zepsr	   r	   r
   rsample   s    
zMultivariateNormal.rsamplec                 C   sf   | j r| | || j }t| j|}| jjddd d}d| jd t	dt	j
  |  | S )Nr   r   Zdim1Zdim2g      r   r   )r;   Z_validate_sampler)   r    r3   diagonallogr   r?   mathpi)r4   valueZdiffr   half_log_detr	   r	   r
   log_prob   s    

zMultivariateNormal.log_probc                 C   sb   | j jddd d}d| jd  dtdtj   | }t| jdkrR|S |	| jS d S )Nr   r   rF   g      ?r   g      ?r   )
r3   rG   rH   r   r?   rI   rJ   r   r>   r0   )r4   rL   Hr	   r	   r
   entropy   s
    &zMultivariateNormal.entropy)NNNN)N)__name__
__module____qualname____doc__r   Zreal_vectorZpositive_definiteZlower_choleskyZarg_constraintsZsupportZhas_rsampler2   r0   r   r,   r*   r+   propertyrB   rC   rD   r   r9   rE   rM   rO   __classcell__r	   r	   r7   r
   r(   N   s2   !$





r(   )rI   r   Ztorch.distributionsr   Z torch.distributions.distributionr   Ztorch.distributions.utilsr   r   r   r    r'   r(   r	   r	   r	   r
   <module>   s   .	