U
    Jºc"'  ã                   @   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   úS/tmp/pip-unpacked-wheel-gikjz4vx/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-determenistic")
        >>> 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           
   
      s<  |  ¡ dk rtdƒ‚|jdd … }|  ¡ dk r6tdƒ‚|jdd… |krZtd |d ¡ƒ‚|jdd … |krztd	 |¡ƒ‚| d¡}| d¡}zt |||¡\}| _}W n< tk
rä } ztd
 |j|j|j¡ƒ|‚W 5 d }~X Y nX |d | _	|d | _
| j	jd d… }	|| _|| _t||ƒ| _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
   z8cov_factor must be a batch of matrices with shape {} x mr   z1cov_diag must be a batch of vectors with shape {}z=Incompatible batch shapes: loc {}, cov_factor {}, cov_diag {}).r   ©Úvalidate_args)ZdimÚ
ValueErrorÚshapeÚformatr   r   Zbroadcast_tensorsr&   ÚRuntimeErrorr%   r'   Ú_unbroadcasted_cov_factorÚ_unbroadcasted_cov_diagr   Ú_capacitance_trilÚsuperr   Ú__init__)
Úselfr%   r&   r'   r)   Úevent_shapeZloc_Z	cov_diag_ÚeÚbatch_shape©Ú	__class__r   r   r2   U   s@    ÿ

  ÿÿ

ÿ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   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   ÚvalueZ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   rT   Ú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   rU   rX   Ú__classcell__r   r   r7   r   r   0   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   
