o
    Hh'                     @   s   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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)Tensor)constraints)Distribution)_batch_mahalanobis	_batch_mv)_standard_normallazy_property)_sizeLowRankMultivariateNormalc                 C   sd   |  d}| j|d }t||  }|d|| dddd|d f  d7  < tj|S )z
    Computes Cholesky of :math:`I + W.T @ inv(D) @ W` for a batch of matrices :math:`W`
    and a batch of vectors :math:`D`.
    N   )	sizemT	unsqueezetorchmatmul
contiguousviewlinalgcholesky)WDmWt_DinvK r   c/var/www/vscode/kcb/lib/python3.10/site-packages/torch/distributions/lowrank_multivariate_normal.py_batch_capacitance_tril   s
   
.r   c                 C   s*   d|j ddd d | d S )z
    Uses "matrix determinant lemma"::
        log|W @ W.T + D| = log|C| + log|D|,
    where :math:`C` is the capacitance matrix :math:`I + W.T @ inv(D) @ W`, to compute
    the log determinant.
       r   r   )dim1dim2)diagonallogsum)r   r   capacitance_trilr   r   r   _batch_lowrank_logdet   s   "r&   c                 C   s@   | j |d }t||}|d| d}t||}|| S )a  
    Uses "Woodbury matrix identity"::
        inv(W @ W.T + D) = inv(D) - inv(D) @ W @ inv(C) @ W.T @ inv(D),
    where :math:`C` is the capacitance matrix :math:`I + W.T @ inv(D) @ W`, to compute the squared
    Mahalanobis distance :math:`x.T @ inv(W @ W.T + D) @ x`.
    r   r   r   )r   r   r   powr$   r   )r   r   xr%   r   	Wt_Dinv_xmahalanobis_term1mahalanobis_term2r   r   r   _batch_lowrank_mahalanobis(   s
   

r,   c                       s   e Zd ZdZejeejdeejddZ	ejZ
dZd 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 distribution with covariance matrix having a low-rank form
    parameterized by :attr:`cov_factor` and :attr:`cov_diag`::

        covariance_matrix = cov_factor @ cov_factor.T + cov_diag

    Example:
        >>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_LAPACK)
        >>> # xdoctest: +IGNORE_WANT("non-deterministic")
        >>> m = LowRankMultivariateNormal(
        ...     torch.zeros(2), torch.tensor([[1.0], [0.0]]), torch.ones(2)
        ... )
        >>> m.sample()  # normally distributed with mean=`[0,0]`, cov_factor=`[[1],[0]]`, cov_diag=`[1,1]`
        tensor([-0.2102, -0.5429])

    Args:
        loc (Tensor): mean of the distribution with shape `batch_shape + event_shape`
        cov_factor (Tensor): factor part of low-rank form of covariance matrix with shape
            `batch_shape + event_shape + (rank,)`
        cov_diag (Tensor): diagonal part of low-rank form of covariance matrix with shape
            `batch_shape + event_shape`

    Note:
        The computation for determinant and inverse of covariance matrix is avoided when
        `cov_factor.shape[1] << cov_factor.shape[0]` thanks to `Woodbury matrix identity
        <https://en.wikipedia.org/wiki/Woodbury_matrix_identity>`_ and
        `matrix determinant lemma <https://en.wikipedia.org/wiki/Matrix_determinant_lemma>`_.
        Thanks to these formulas, we just need to compute the determinant and inverse of
        the small size "capacitance" matrix::

            capacitance = I + cov_factor.T @ inv(cov_diag) @ cov_factor
    r   r   )loc
cov_factorcov_diagTNc           
   
      s8  |  dk r
td|jdd  }|  dk rtd|jdd |kr.td|d  d	|jdd  |kr>td
| |d}|d}zt|||\}| _}W n tyr } ztd|j d|j d|j |d }~ww |d | _|d | _	| jjd d }	|| _
|| _t||| _t j|	||d d S )Nr   z%loc must be at least one-dimensional.r   r   zScov_factor must be at least two-dimensional, with optional leading batch dimensionsr   z2cov_factor must be a batch of matrices with shape r   z x mz/cov_diag must be a batch of vectors with shape zIncompatible batch shapes: loc z, cov_factor z, cov_diag ).r   validate_args)dim
ValueErrorshaper   r   broadcast_tensorsr.   RuntimeErrorr-   r/   _unbroadcasted_cov_factor_unbroadcasted_cov_diagr   _capacitance_trilsuper__init__)
selfr-   r.   r/   r1   event_shapeloc_	cov_diag_ebatch_shape	__class__r   r   r;   `   sH   



z"LowRankMultivariateNormal.__init__c                    s   |  t|}t|}|| j }| j||_| j||_| j|| jj	dd   |_| j
|_
| j|_| j|_tt|j|| jdd | j|_|S )Nr   Fr0   )_get_checked_instancer
   r   Sizer=   r-   expandr/   r.   r4   r7   r8   r9   r:   r;   _validate_args)r<   rA   	_instancenew	loc_shaperB   r   r   rF      s   


z LowRankMultivariateNormal.expandreturnc                 C      | j S Nr-   r<   r   r   r   mean      zLowRankMultivariateNormal.meanc                 C   rL   rM   rN   rO   r   r   r   mode   rQ   zLowRankMultivariateNormal.modec                 C   s&   | j dd| j | j| j S )Nr   r   )r7   r'   r$   r8   rF   _batch_shape_event_shaperO   r   r   r   variance   s   z"LowRankMultivariateNormal.variancec                 C   s   | j d }| j d}| j| }t||j }|	d|| d d d d |d f  d7  < |tj
| }|| j| j  | j  S )Nr   r   r   )rT   r8   sqrtr   r7   r   r   r   r   r   r   r   rF   rS   )r<   ncov_diag_sqrt_unsqueeze
Dinvsqrt_Wr   
scale_trilr   r   r   rZ      s   

.z$LowRankMultivariateNormal.scale_trilc                 C   s6   t | j| jjt | j }|| j| j | j S rM   )	r   r   r7   r   
diag_embedr8   rF   rS   rT   )r<   covariance_matrixr   r   r   r\      s   

z+LowRankMultivariateNormal.covariance_matrixc                 C   sZ   | j j| jd }tjj| j|dd}t| j	 |j|  }|
| j| j | j S )Nr   F)upper)r7   r   r8   r   r   r   solve_triangularr9   r[   
reciprocalrF   rS   rT   )r<   r   Aprecision_matrixr   r   r   ra      s   
z*LowRankMultivariateNormal.precision_matrixsample_shapec                 C   sr   |  |}|d d | jjdd   }t|| jj| jjd}t|| jj| jjd}| jt| j| | j	
 |  S )Nr   )dtypedevice)_extended_shaper.   r4   r   r-   rc   rd   r   r7   r8   rV   )r<   rb   r4   W_shapeeps_Weps_Dr   r   r   rsample   s   

z!LowRankMultivariateNormal.rsamplec                 C   sf   | j r| | || j }t| j| j|| j}t| j| j| j}d| jd t	
dt	j  | |  S )Ng      r   r   )rG   _validate_sampler-   r,   r7   r8   r9   r&   rT   mathr#   pi)r<   valuediffMlog_detr   r   r   log_prob   s   

&z"LowRankMultivariateNormal.log_probc                 C   sV   t | j| j| j}d| jd dtdtj   |  }t| j	dkr%|S |
| j	S )Ng      ?r   g      ?r   )r&   r7   r8   r9   rT   rk   r#   rl   lenrS   rF   )r<   rp   Hr   r   r   entropy   s   &z!LowRankMultivariateNormal.entropyrM   )__name__
__module____qualname____doc__r   real_vectorindependentrealpositivearg_constraintssupporthas_rsampler;   rF   propertyr   rP   rR   r   rU   rZ   r\   ra   r   rE   r	   ri   rq   rt   __classcell__r   r   rB   r   r
   6   s2    "%)rk   r   r   torch.distributionsr    torch.distributions.distributionr   'torch.distributions.multivariate_normalr   r   torch.distributions.utilsr   r   torch.typesr	   __all__r   r&   r,   r
   r   r   r   r   <module>   s   