o
    oi                     @  sp   d dl mZ d dlmZ d dlZd dlm  mZ d dlmZ d dl	m
Z
 		ddddZG dd dejZdS )    )annotations)OptionalN)nn)mask_ignore_pixels:0yE>predtorch.Tensortargetalphafloatbetaepsignore_indexOptional[int]returnc                 C  sd  t | tjstdt|  t| jdkstd| j | jdd |jdd ks8td| j d|j | j|jksJtd| j d|j t	j
| d	d
}t||\}}|d	|d	}|dury|d	j| jd}	||	 }|	d}
n| j\}}}}tj|f|| | j| jd}
|d}tj||
| t|
|| dd|}||}d|  S )u  Criterion that computes Tversky Coefficient loss.

    According to :cite:`salehi2017tversky`, we compute the Tversky Coefficient as follows:

    .. math::

        \text{S}(P, G, \alpha; \beta) =
          \frac{|PG|}{|PG| + \alpha |P \setminus G| + \beta |G \setminus P|}

    Where:
       - :math:`P` and :math:`G` are the predicted and ground truth binary
         labels.
       - :math:`\alpha` and :math:`\beta` control the magnitude of the
         penalties for FPs and FNs, respectively.

    Note:
       - :math:`\alpha = \beta = 0.5` => dice coeff
       - :math:`\alpha = \beta = 1` => tanimoto coeff
       - :math:`\alpha + \beta = 1` => F beta coeff

    Args:
        pred: logits tensor with shape :math:`(N, C, H, W)` where C = number of classes.
        target: labels tensor with shape :math:`(N, H, W)` where each value
          is :math:`0 ≤ targets[i] ≤ C-1`.
        alpha: the first coefficient in the denominator.
        beta: the second coefficient in the denominator.
        eps: scalar for numerical stability.
        ignore_index: labels with this value are ignored in the loss computation.

    Return:
        the computed loss.

    Example:
        >>> N = 5  # num_classes
        >>> pred = torch.randn(1, N, 3, 5, requires_grad=True)
        >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N)
        >>> output = tversky_loss(pred, target, alpha=0.5, beta=0.5)
        >>> output.backward()

    z%pred type is not a torch.Tensor. Got    z,Invalid pred shape, we expect BxNxHxW. Got: Nz.pred and target shapes must be the same. Got: z and z1pred and target must be in the same device. Got:    )dim)dtype)r         )r   deviceg      ?)value)
isinstancetorchTensor	TypeErrortypelenshape
ValueErrorr   Fsoftmaxr   gather	unsqueezetor   sumfulladdcmul	full_likeadd_divmean)r   r
   r   r   r   r   	pred_softtarget_maskp_truemtotalB_HWintersectiondenominatorscore r;   I/home/ubuntu/.local/lib/python3.10/site-packages/kornia/losses/tversky.pytversky_loss    s8   0

r=   c                      s.   e Zd ZdZdd fddZdddZ  ZS )TverskyLossu  Criterion that computes Tversky Coefficient loss.

    According to :cite:`salehi2017tversky`, we compute the Tversky Coefficient as follows:

    .. math::

        \text{S}(P, G, \alpha; \beta) =
          \frac{|PG|}{|PG| + \alpha |P \setminus G| + \beta |G \setminus P|}

    Where:
       - :math:`P` and :math:`G` are the predicted and ground truth binary
         labels.
       - :math:`\alpha` and :math:`\beta` control the magnitude of the
         penalties for FPs and FNs, respectively.

    Note:
       - :math:`\alpha = \beta = 0.5` => dice coeff
       - :math:`\alpha = \beta = 1` => tanimoto coeff
       - :math:`\alpha + \beta = 1` => F beta coeff

    Args:
        alpha: the first coefficient in the denominator.
        beta: the second coefficient in the denominator.
        eps: scalar for numerical stability.
        ignore_index: labels with this value are ignored in the loss computation.

    Shape:
        - Pred: :math:`(N, C, H, W)` where C = number of classes.
        - Target: :math:`(N, H, W)` where each value is
          :math:`0 ≤ targets[i] ≤ C-1`.

    Examples:
        >>> N = 5  # num_classes
        >>> criterion = TverskyLoss(alpha=0.5, beta=0.5)
        >>> pred = torch.randn(1, N, 3, 5, requires_grad=True)
        >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N)
        >>> output = criterion(pred, target)
        >>> output.backward()

    r   r   r   r   r   r   r   r   r   Nonec                   s&   t    || _|| _|| _|| _d S N)super__init__r   r   r   r   )selfr   r   r   r   	__class__r;   r<   rB      s
   

zTverskyLoss.__init__r   r	   r
   c                 C  s   t ||| j| j| j| jS r@   )r=   r   r   r   r   )rC   r   r
   r;   r;   r<   forward   s   zTverskyLoss.forwardr   r   )
r   r   r   r   r   r   r   r   r   r?   )r   r	   r
   r	   r   r	   )__name__
__module____qualname____doc__rB   rF   __classcell__r;   r;   rD   r<   r>   x   s    )r>   rG   )r   r	   r
   r	   r   r   r   r   r   r   r   r   r   r	   )
__future__r   typingr   r   torch.nn.functionalr   
functionalr#   kornia.losses._utilsr   r=   Moduler>   r;   r;   r;   r<   <module>   s   X