o
    
jq:                     @   s  d dl mZmZmZmZ d dlZd dlm  mZ	 d dl
mZ d,dejdedejfdd	Z	
		d-deej deeef deeef deeeef  ddf
ddZdededejfddZ								d.dejdejdededeeef deded ed!ed"edeej fd#d$ZG d%d& d&eZ		d/dejdejd'ejd!ed"edeejeejejf f fd(d)Z		d/dejdejd'ejd!ed"edeejeejejf f fd*d+ZdS )0    )ListOptionalTupleUnionN)_Lossmeanx	reductionreturnc                 C   s<   |dkr| S |dkr| j ddS |dkr| jddS td)zReduce input in batch dimension if needed.
    Args:
        x: Tensor with shape (N, *).
        reduction: Specifies the reduction type:
            ``'none'`` | ``'mean'`` | ``'sum'``. Default: ``'mean'``
    noner   r   dimsumz:Unknown reduction. Expected one of {'none', 'mean', 'sum'})r   r   
ValueError)r   r	    r   E/home/kuhnn/.local/lib/python3.10/site-packages/TTS/tts/utils/ssim.py_reduce
   s   r   r   g        g      tensors	dim_range
data_range
size_rangec              	   C   s  	 | d }| D ]}t |sJ dt| |j|jks)J d|j d|j |du rD| | ksCJ d|  d|  n&| |d |d	  | |d |d	  ksjJ d
|  d|  |d |d	 kr| |d ksJ d|d  d|  n,|d |d	 k r|d |   kr|d	 ksn J d|d  d|d	  d|  |d |d	 k r|d | ksJ d|d  d|  | |d	 ksJ d|d	  d|  qdS )a7  Check that input(-s)  satisfies the requirements
    Args:
        tensors: Tensors to check
        dim_range: Allowed number of dimensions. (min, max)
        data_range: Allowed range of values in tensors. (min, max)
        size_range: Dimensions to include in size comparison. (start_dim, end_dim + 1)
    FNr   zExpected torch.Tensor, got zExpected tensors to be on z, got z%Expected tensors with same size, got z and    z9Expected tensors with same size at given dimensions, got z$Expected number of dimensions to be z,Expected number of dimensions to be between z*Expected values to be greater or equal to z(Expected values to be lower or equal to )torch	is_tensortypedevicesizer   minmax)r   r   r   r   r   tr   r   r   _validate_input   s*   $.2.$ ,,r#   kernel_sizesigmac                 C   sd   t j| t jd}|| d d 8 }|d }|d|d  d|d    }||  }|dS )zReturns 2D Gaussian kernel N(0,`sigma`^2)
    Args:
        size: Size of the kernel
        sigma: Std of the distribution
    Returns:
        gaussian_kernel: Tensor with shape (1, kernel_size, kernel_size)
    )dtyper          @   r   )r   arangefloat32	unsqueezeexpr   )r$   r%   coordsgr   r   r   gaussian_filterE   s   &
r/            ?      ?FT{Gz?Q?ykernel_sigmafull
downsamplek1k2c
                 C   s  |d dksJ d| dt | |gdd|fd | t| } |t| }tdtt|  dd	 d
 }
|
dkrJ|rJtj| |
d} tj||
d}t||	| dddd
|}|  dkrctnt}|| ||||	d\}}|d}|d}t||}t||}|r||gS |S )a  Interface of Structural Similarity (SSIM) index.
    Inputs supposed to be in range ``[0, data_range]``.
    To match performance with skimage and tensorflow set ``'downsample' = True``.

    Args:
        x: An input tensor. Shape :math:`(N, C, H, W)` or :math:`(N, C, H, W, 2)`.
        y: A target tensor. Shape :math:`(N, C, H, W)` or :math:`(N, C, H, W, 2)`.
        kernel_size: The side-length of the sliding window used in comparison. Must be an odd value.
        kernel_sigma: Sigma of normal distribution.
        data_range: Maximum value range of images (usually 1.0 or 255).
        reduction: Specifies the reduction type:
            ``'none'`` | ``'mean'`` | ``'sum'``. Default:``'mean'``
        full: Return cs map or not.
        downsample: Perform average pool before SSIM computation. Default: True
        k1: Algorithm parameter, K1 (small constant).
        k2: Algorithm parameter, K2 (small constant).
            Try a larger K2 constant (e.g. 0.4) if you get a negative or NaN results.

    Returns:
        Value of Structural Similarity (SSIM) index. In case of 5D input tensors, complex value is returned
        as a tensor of size 2.

    References:
        Wang, Z., Bovik, A. C., Sheikh, H. R., & Simoncelli, E. P. (2004).
        Image quality assessment: From error visibility to structural similarity.
        IEEE Transactions on Image Processing, 13, 600-612.
        https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf,
        DOI: `10.1109/TIP.2003.819861`
    r(   r   Kernel size must be odd, got [])      r   )r   r   N   )r$   r>   )r   r5   kernelr9   r:   )r#   floatr!   roundr    r   F
avg_pool2dr/   repeattor   _ssim_per_channel_complex_ssim_per_channelr   r   )r   r5   r$   r6   r   r	   r7   r8   r9   r:   frA   _compute_ssim_per_channelssim_mapcs_mapssim_valcsr   r   r   ssimW   s$   )""



rP   c                       s~   e Zd ZdZg dZ								dd
edededededede	eef ddf fddZ
dejdejdejfddZ  ZS )SSIMLossap	  Creates a criterion that measures the structural similarity index error between
    each element in the input :math:`x` and target :math:`y`.

    To match performance with skimage and tensorflow set ``'downsample' = True``.

    The unreduced (i.e. with :attr:`reduction` set to ``'none'``) loss can be described as:

    .. math::
        SSIM = \{ssim_1,\dots,ssim_{N \times C}\}\\
        ssim_{l}(x, y) = \frac{(2 \mu_x \mu_y + c_1) (2 \sigma_{xy} + c_2)}
        {(\mu_x^2 +\mu_y^2 + c_1)(\sigma_x^2 +\sigma_y^2 + c_2)},

    where :math:`N` is the batch size, `C` is the channel size. If :attr:`reduction` is not ``'none'``
    (default ``'mean'``), then:

    .. math::
        SSIMLoss(x, y) =
        \begin{cases}
            \operatorname{mean}(1 - SSIM), &  \text{if reduction} = \text{'mean';}\\
            \operatorname{sum}(1 - SSIM),  &  \text{if reduction} = \text{'sum'.}
        \end{cases}

    :math:`x` and :math:`y` are tensors of arbitrary shapes with a total
    of :math:`n` elements each.

    The sum operation still operates over all the elements, and divides by :math:`n`.
    The division by :math:`n` can be avoided if one sets ``reduction = 'sum'``.
    In case of 5D input tensors, complex value is returned as a tensor of size 2.

    Args:
        kernel_size: By default, the mean and covariance of a pixel is obtained
            by convolution with given filter_size.
        kernel_sigma: Standard deviation for Gaussian kernel.
        k1: Coefficient related to c1 in the above equation.
        k2: Coefficient related to c2 in the above equation.
        downsample: Perform average pool before SSIM computation. Default: True
        reduction: Specifies the reduction type:
            ``'none'`` | ``'mean'`` | ``'sum'``. Default:``'mean'``
        data_range: Maximum value range of images (usually 1.0 or 255).

    Examples:
        >>> loss = SSIMLoss()
        >>> x = torch.rand(3, 3, 256, 256, requires_grad=True)
        >>> y = torch.rand(3, 3, 256, 256)
        >>> output = loss(x, y)
        >>> output.backward()

    References:
        Wang, Z., Bovik, A. C., Sheikh, H. R., & Simoncelli, E. P. (2004).
        Image quality assessment: From error visibility to structural similarity.
        IEEE Transactions on Image Processing, 13, 600-612.
        https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf,
        DOI:`10.1109/TIP.2003.819861`
    )r$   r9   r:   r%   rA   r	   r0   r1   r3   r4   Tr   r2   r$   r6   r9   r:   r8   r	   r   r
   Nc                    sT   t    || _|| _|d dksJ d| d|| _|| _|| _|| _|| _d S )Nr(   r   r;   r<   )	super__init__r	   r$   r6   r9   r:   r8   r   )selfr$   r6   r9   r:   r8   r	   r   	__class__r   r   rS      s   


zSSIMLoss.__init__r   r5   c                 C   s8   t ||| j| j| j| j| jd| j| jd
}t	|| S )a  Computation of Structural Similarity (SSIM) index as a loss function.

        Args:
            x: An input tensor. Shape :math:`(N, C, H, W)` or :math:`(N, C, H, W, 2)`.
            y: A target tensor. Shape :math:`(N, C, H, W)` or :math:`(N, C, H, W, 2)`.

        Returns:
            Value of SSIM loss to be minimized, i.e ``1 - ssim`` in [0, 1] range. In case of 5D input tensors,
            complex value is returned as a tensor of size 2.
        F)
r   r5   r$   r6   r8   r   r	   r7   r9   r:   )
rP   r$   r6   r8   r   r	   r9   r:   r   	ones_like)rT   r   r5   scorer   r   r   forward   s   zSSIMLoss.forward)r0   r1   r3   r4   Tr   r2   )__name__
__module____qualname____doc____constants__intrB   boolstrr   rS   r   TensorrY   __classcell__r   r   rU   r   rQ      s8    6
	$rQ   rA   c                 C   sF  |  d| dk s|  d| dk r"td|    d|   |d }|d }|  d}tj| |dd|d}tj||dd|d}	|d }
|	d }||	 }tj| d |dd|d|
 }tj|d |dd|d| }tj| | |dd|d| }d	| | || |  }d	| | |
| |  | }|jd
d}|jd
d}||fS )a  Calculate Structural Similarity (SSIM) index for X and Y per channel.

    Args:
        x: An input tensor. Shape :math:`(N, C, H, W)`.
        y: A target tensor. Shape :math:`(N, C, H, W)`.
        kernel: 2D Gaussian kernel.
        k1: Algorithm parameter, K1 (small constant, see [1]).
        k2: Algorithm parameter, K2 (small constant, see [1]).
            Try a larger K2 constant (e.g. 0.4) if you get a negative or NaN results.

    Returns:
        Full Value of Structural Similarity (SSIM) index.
    r   r?   AKernel size can't be greater than actual input size. Input size: . Kernel size: r(   r   r   weightstridepaddinggroupsr'   )r   r?   r   )r   r   rD   conv2dr   )r   r5   rA   r9   r:   c1c2
n_channelsmu_xmu_ymu_xxmu_yymu_xysigma_xxsigma_yysigma_xyrO   ssrN   r   r   r   rI   
  s,   (
rI   c           #      C   sf  |  d}|  d| dk s|  d| dk r'td|    d|   |d }|d }| d }| d	 }	|d }
|d	 }tj||dd
|d}tj|	|dd
|d}tj|
|dd
|d}tj||dd
|d}|d|d }|d|d }|| ||  }|| ||  }d}|d|	d }|
d|d }||
 |	|  }|| |	|
  }tj||dd
|d| }tj||dd
|d| }tj||dd
|d| }tj||dd
|d| }tj||fdd}tj||fdd}|d ||  |d|d ||   }|d ||  |d|d ||   } | | } | jdd}!|jdd}"|!|"fS )a  Calculate Structural Similarity (SSIM) index for Complex X and Y per channel.

    Args:
        x: An input tensor. Shape :math:`(N, C, H, W, 2)`.
        y: A target tensor. Shape :math:`(N, C, H, W, 2)`.
        kernel: 2-D gauss kernel.
        k1: Algorithm parameter, K1 (small constant, see [1]).
        k2: Algorithm parameter, K2 (small constant, see [1]).
            Try a larger K2 constant (e.g. 0.4) if you get a negative or NaN results.

    Returns:
        Full Value of Complex Structural Similarity (SSIM) index.
    r   r?   r   rd   re   r(   ).r   ).r   r   rf   r2   r   )r?   rx   )	r   r   rD   rk   powr   stackr+   r   )#r   r5   rA   r9   r:   rn   rl   rm   x_realx_imagy_realy_imagmu1_realmu1_imagmu2_realmu2_imagmu1_sqmu2_sqmu1_mu2_realmu1_mu2_imagcompensationx_sqy_sqx_y_realx_y_imag	sigma1_sq	sigma2_sqsigma12_realsigma12_imagsigma12mu1_mu2rM   rL   rN   rO   r   r   r   rH   =  sL   
(,,rH   )r   )r   r   N)r0   r1   r2   r   FTr3   r4   )r3   r4   )typingr   r   r   r   r   torch.nn.functionalnn
functionalrD   torch.nn.modules.lossr   rb   ra   r   r_   rB   r#   r/   r`   rP   rQ   rI   rH   r   r   r   r   <module>   s   


+
	

Ds
7