U
    yhO&                     @   sz   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l	m
Z
mZ dgZdd Zd	d
 Zdd ZG dd deZdS )    N)constraints)Distribution)_batch_mahalanobis	_batch_mv)_standard_normallazy_property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   a/var/www/html/venv/lib/python3.8/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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 )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.]]), 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           
   
      sB  |  dk rtd|jdd  }|  dk r6td|jdd |kr\td|d  d	|jdd  |kr|td
| |d}|d}zt|||\}| _}W nD tk
r } z&td|j d|j d|j |W 5 d }~X Y nX |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_shapeZloc_Z	cov_diag_ebatch_shape	__class__r   r   r2   Z   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   Sizer4   r%   expandr'   r&   r,   r.   r/   r0   r1   r2   _validate_args)r3   r6   Z	_instancenewZ	loc_shaper7   r   r   r:      s     


  z LowRankMultivariateNormal.expandc                 C   s   | j S Nr%   r3   r   r   r   mean   s    zLowRankMultivariateNormal.meanc                 C   s   | j S r=   r>   r?   r   r   r   mode   s    zLowRankMultivariateNormal.modec                 C   s&   | j dd| j | j| j S )Nr   r	   )r.   r"   r   r/   r:   _batch_shape_event_shaper?   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   )rC   r/   sqrtr   r.   r   r   r   r   r   r   r   r:   rB   )r3   nZcov_diag_sqrt_unsqueezeZ
Dinvsqrt_Wr   
scale_trilr   r   r   rG      s    

.z$LowRankMultivariateNormal.scale_trilc                 C   s6   t | j| jjt | j }|| j| j | j S r=   )	r   r   r.   r   
diag_embedr/   r:   rB   rC   )r3   covariance_matrixr   r   r   rI      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)r.   r   r/   r   r   r   Zsolve_triangularr0   rH   Z
reciprocalr:   rB   rC   )r3   r   Aprecision_matrixr   r   r   rL      s    
z*LowRankMultivariateNormal.precision_matrixc                 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%   rM   rN   r   r.   r/   rE   )r3   Zsample_shaper,   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$   r.   r/   r0   r!   rC   mathr   pi)r3   valuediffMlog_detr   r   r   log_prob   s    

z"LowRankMultivariateNormal.log_probc                 C   sZ   t | j| j| j}d| jd dtdtj   |  }t| j	dkrJ|S |
| j	S d S )Ng      ?r   g      ?r   )r!   r.   r/   r0   rC   rP   r   rQ   lenrB   r:   )r3   rU   Hr   r   r   entropy   s    &z!LowRankMultivariateNormal.entropy)N)N)__name__
__module____qualname____doc__r   Zreal_vectorZindependentrealZpositiveZarg_constraintsZsupportZhas_rsampler2   r:   propertyr@   rA   r   rD   rG   rI   rL   r   r9   rO   rV   rY   __classcell__r   r   r7   r   r   3   s0   %





)rP   r   Ztorch.distributionsr   Z torch.distributions.distributionr   Z'torch.distributions.multivariate_normalr   r   Ztorch.distributions.utilsr   r   __all__r   r!   r$   r   r   r   r   r   <module>   s   