o
    ,hU+                     @   s   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lmZ d dl	m
Z
mZ d dlmZ dgZd	d
 Zdd Zdd ZG dd deZdS )    N)Optional)Tensor)constraints)Distribution)_standard_normallazy_property)_sizeMultivariateNormalc                 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matmul	unsqueezesqueeze)bmatbvec r   b/var/www/html/scripts/venv/lib/python3.10/site-packages/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 }	q:|	|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zipreshapelistrangepermuter   linalgsolve_triangularpowsumt)bLbxnbx_batch_shapebx_batch_dimsbL_batch_dimsouter_batch_dimsold_batch_dimsnew_batch_dimsbx_new_shapesLsxpermute_dimsflat_Lflat_xflat_x_swapM_swapM
permuted_Mpermute_inv_dimsi
reshaped_Mr   r   r   _batch_mahalanobis   sB   
&





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"   choleskyflip	transposeeyer   r?   r@   r#   )PLfL_invIdLr   r   r   _precision_to_scale_trilP   s
   rJ   c                       s  e Zd ZdZejejejejdZejZ	dZ
				d"dedee dee dee d	ee d
df fddZd# fdd	Zed
efddZed
efddZed
efddZed
efddZed
efddZed
efddZe fded
efddZdd Zd d! Z  ZS )$r	   a  
    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:

        >>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_LAPACK)
        >>> # xdoctest: +IGNORE_WANT("non-deterministic")
        >>> 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_trilTNrK   rL   rM   rN   validate_argsreturnc                    s  |  dk r
td|d u|d u |d u dkrtd|d urC|  dk r*tdt|jd d |jd d }||d | _nO|d urj|  dk rQtd	t|jd d |jd d }||d | _n(|d uspJ |  dk rztd
t|jd d |jd d }||d | _||d | _	| j	jdd  }t
 j|||d |d ur|| _d S |d urtj|| _d S 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
   rO   )r   
ValueErrorr   broadcast_shapesr   expandrN   rL   rM   rK   super__init___unbroadcasted_scale_trilr"   rA   rJ   )selfrK   rL   rM   rN   rO   batch_shapeevent_shape	__class__r   r   rV      sV    
zMultivariateNormal.__init__c                    s   |  t|}t|}|| j }|| j | j }| j||_| j|_d| jv r/| j	||_	d| jv r;| j
||_
d| jv rG| j||_tt|j|| jdd | j|_|S )NrL   rN   rM   FrQ   )_get_checked_instancer	   r   SizerZ   rK   rT   rW   __dict__rL   rN   rM   rU   rV   _validate_args)rX   rY   	_instancenew	loc_shape	cov_shaper[   r   r   rT      s"   





zMultivariateNormal.expandc                 C   s   | j | j| j | j S N)rW   rT   _batch_shape_event_shaperX   r   r   r   rN      s   zMultivariateNormal.scale_trilc                 C   s&   t | j| jj| j| j | j S re   )r   r   rW   mTrT   rf   rg   rh   r   r   r   rL      s
   
z$MultivariateNormal.covariance_matrixc                 C   s    t | j| j| j | j S re   )r   cholesky_inverserW   rT   rf   rg   rh   r   r   r   rM      s   z#MultivariateNormal.precision_matrixc                 C      | j S re   rK   rh   r   r   r   mean      zMultivariateNormal.meanc                 C   rk   re   rl   rh   r   r   r   mode   rn   zMultivariateNormal.modec                 C   s    | j dd| j| j S )Nr   r
   )rW   r$   r%   rT   rf   rg   rh   r   r   r   variance   s   
zMultivariateNormal.variancesample_shapec                 C   s2   |  |}t|| jj| jjd}| jt| j| S )Nr>   )_extended_shaper   rK   r?   r@   r   rW   )rX   rq   r   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
   dim1dim2g      r   r   )r`   _validate_samplerK   r=   rW   diagonallogr%   rg   mathpi)rX   valuediffr8   half_log_detr   r   r   log_prob   s   

&zMultivariateNormal.log_probc                 C   s^   | j jddd d}d| jd  dtdtj   | }t| jdkr)|S |	| jS )Nr   r
   ru   g      ?r   g      ?r   )
rW   ry   rz   r%   rg   r{   r|   r   rf   rT   )rX   r   Hr   r   r   entropy  s   &zMultivariateNormal.entropy)NNNNre   )__name__
__module____qualname____doc__r   real_vectorpositive_definitelower_choleskyarg_constraintssupporthas_rsampler   r   boolrV   rT   r   rN   rL   rM   propertyrm   ro   rp   r   r^   r   rt   r   r   __classcell__r   r   r[   r   r	   Y   sT    %:
)r{   typingr   r   r   torch.distributionsr    torch.distributions.distributionr   torch.distributions.utilsr   r   torch.typesr   __all__r   r=   rJ   r	   r   r   r   r   <module>   s   2	