o
    Zh'                     @   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   ^/var/www/auris/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   )Zdim1Zdim2)Z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   Z	Wt_Dinv_xZmahalanobis_term1Z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   Zbroadcast_tensorsr(   RuntimeErrorr'   r)   _unbroadcasted_cov_factor_unbroadcasted_cov_diagr   _capacitance_trilsuper__init__)
selfr'   r(   r)   r+   event_shapeloc_Z	cov_diag_ebatch_shape	__class__r   r   r4   `   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   Fr*   )Z_get_checked_instancer
   r   Sizer6   r'   expandr)   r(   r.   r0   r1   r2   r3   r4   _validate_args)r5   r9   Z	_instancenewZ	loc_shaper:   r   r   r=      s   


z LowRankMultivariateNormal.expandreturnc                 C      | j S Nr'   r5   r   r   r   mean      zLowRankMultivariateNormal.meanc                 C   rA   rB   rC   rD   r   r   r   mode   rF   zLowRankMultivariateNormal.modec                 C   s&   | j dd| j | j| j S )Nr   r   )r0   r$   r!   r1   r=   _batch_shape_event_shaperD   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   )rI   r1   sqrtr   r0   r   r   r   r   r   r   r   r=   rH   )r5   nZcov_diag_sqrt_unsqueezeZ
Dinvsqrt_Wr   
scale_trilr   r   r   rM      s   

.z$LowRankMultivariateNormal.scale_trilc                 C   s6   t | j| jjt | j }|| j| j | j S rB   )	r   r   r0   r   
diag_embedr1   r=   rH   rI   )r5   covariance_matrixr   r   r   rO      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)r0   r   r1   r   r   r   Zsolve_triangularr2   rN   Z
reciprocalr=   rH   rI   )r5   r   Aprecision_matrixr   r   r   rR      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)Z_extended_shaper(   r.   r   r'   rT   rU   r   r0   r1   rK   )r5   rS   r.   ZW_shapeZeps_WZ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   )r>   Z_validate_sampler'   r&   r0   r1   r2   r#   rI   mathr    pi)r5   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#   r0   r1   r2   rI   rW   r    rX   lenrH   r=   )r5   r\   Hr   r   r   entropy   s   &z!LowRankMultivariateNormal.entropyrB   )__name__
__module____qualname____doc__r   Zreal_vectorZindependentrealZpositiveZarg_constraintsZsupportZhas_rsampler4   r=   propertyr   rE   rG   r   rJ   rM   rO   rR   r   r<   r	   rV   r]   r`   __classcell__r   r   r:   r   r
   6   s2    "%)rW   r   r   Ztorch.distributionsr   Z torch.distributions.distributionr   Z'torch.distributions.multivariate_normalr   r   Ztorch.distributions.utilsr   r   Ztorch.typesr	   __all__r   r#   r&   r
   r   r   r   r   <module>   s   