o
    .wi                      @   sr  d dl mZmZ d dlZd dlmZ d dlmZ d dlmZ dededefd	d
Z	dededefddZ
	d3dededeeed f defddZ	d4dedee dedededededefddZdededeeef fddZd5deded!ed"edef
d#d$Zd6deded&edefd'd(Zd6deded&edefd)d*Zded+ededefd,d-Zd.ed/ed0 defd1d2ZdS )7    )OptionalUnionN)Tensor)Literal)rank_zero_warnxyreturnc                 C   s8   | j tjks|j tjkr|  |j   S | |j S )zSafe calculation of matrix multiplication.

    If input is float16, will cast to float32 for computation and back again.

    )dtypetorchfloat16floatThalfr   r    r   [/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/utilities/compute.py_safe_matmul   s   
r   c                 C   s   | t | }d|| dk< |S )zCompute x * log(y). Returns 0 if x=0.

    Example:
        >>> import torch
        >>> x = torch.zeros(1)
        >>> _safe_xlogy(x, 1/x)
        tensor([0.])

            r   )r   log)r   r   resr   r   r   _safe_xlogy"   s   
r   r   numdenomzero_division)warnnanc                 C   s   |   r| n|  } |  r|n| }t|ttfs|dkrS|dkr.t|dkr.td |dkr4dn|}tj|| jdj	| j
| j
jdkd}t|dk| | |S t| |S )a  Safe division, by preventing division by zero.

    Function will cast to float if input is not already to secure backwards compatibility.

    Args:
        num: numerator tensor
        denom: denominator tensor, which may contain zeros
        zero_division: value to replace elements divided by zero

    Example:
        >>> import torch
        >>> num = torch.tensor([1.0, 2.0, 3.0])
        >>> denom = torch.tensor([0.0, 1.0, 2.0])
        >>> _safe_divide(num, denom)
        tensor([0.0000, 2.0000, 1.5000])

    r   r   z:Detected zero division in _safe_divide. Setting 0/0 to 0.0r   )r
   mps)non_blocking)is_floating_pointr   
isinstanceintr   anyr   tensorr
   todevicetypewheretrue_divide)r   r   r   zero_division_tensorr   r   r   _safe_divide1   s   r*      scoreaverage
multilabeltpfpfntop_kc                 C   sz   |d u s|dkr
| S |dkr|| }nt | }|s.d||dkr(|| | dkn|| dk< t||  |jddddS )	Nnoneweightedr   r+   r   T)keepdim)r   	ones_liker*   sum)r,   r-   r.   r/   r0   r1   r2   weightsr   r   r   _adjust_weights_safe_divideU   s   

(r:   c                 C   s   | j dkr	|  n| } |j dkr| n|}| j dks |j dkr,td| j  d|j  |  | krBtd|   d|  | |fS )z Check that auc input is correct.r+   zJExpected both `x` and `y` tensor to be 1d, but got tensors with dimension z and zHExpected the same number of elements in `x` and `y` tensor but received )ndimsqueeze
ValueErrornumelr   r   r   r   _auc_format_inputsc   s   r?   r5   	directionaxisc                 C   sB   t   t j|| |d| }W d   |S 1 sw   Y  |S )zrCompute area under the curve using the trapezoidal rule.

    Assumes increasing or decreasing order of `x`.

    dimN)r   no_gradtrapz)r   r   r@   rA   	auc_scorer   r   r   _auc_compute_without_checks   s   

rG   Freorderc                 C   s   t  > |rt j| dd\} }|| }| dd | dd  }|dk  r3|dk r/d}ntdd	}t| ||W  d   S 1 sEw   Y  dS )
zCompute area under the curve using the trapezoidal rule.

    Example:
        >>> import torch
        >>> x = torch.tensor([1, 2, 3, 4])
        >>> y = torch.tensor([1, 2, 3, 4])
        >>> _auc_compute(x, y)
        tensor(7.5000)

    T)stabler+   Nr5   r   g      z_The `x` tensor is neither increasing or decreasing. Try setting the reorder argument to `True`.g      ?)r   rD   sortr"   allr=   rG   )r   r   rH   x_idxdxr@   r   r   r   _auc_compute~   s   

$rN   c                 C   s   t | |\} }t| ||dS )a8  Compute Area Under the Curve (AUC) using the trapezoidal rule.

    Args:
        x: x-coordinates, must be either increasing or decreasing
        y: y-coordinates
        reorder: if True, will reorder the arrays to make it either increasing or decreasing

    Return:
        Tensor containing AUC score

    )rH   )r?   rN   )r   r   rH   r   r   r   auc   s   rO   xpc              	   C   s   t |dd |dd  |dd |dd  }|dd ||dd   }tt| dddf |dddf dd }t|dt|d }|| |  ||  S )ai  One-dimensional linear interpolation for monotonically increasing sample points.

    Returns the one-dimensional piecewise linear interpolation to a function with
    given discrete data points :math:`(xp, fp)`, evaluated at :math:`x`.

    Adjusted version of this https://github.com/pytorch/pytorch/issues/50334#issuecomment-1000917964

    Args:
        x: the :math:`x`-coordinates at which to evaluate the interpolated values.
        xp: the :math:`x`-coordinates of the data points, must be increasing.
        fp: the :math:`y`-coordinates of the data points, same length as `xp`.

    Returns:
        the interpolated values, same size as `x`.

    Example:
        >>> x = torch.tensor([0.5, 1.5, 2.5])
        >>> xp = torch.tensor([1, 2, 3])
        >>> fp = torch.tensor([1, 2, 3])
        >>> interp(x, xp, fp)
        tensor([0.5000, 1.5000, 2.5000])

    r+   Nr5   r   )r*   r   r8   geclamplen)r   rP   r0   mbindicesr   r   r   interp   s
   20rW   r#   normalization)sigmoidsoftmaxc                 C   s   | j t dkr$t| dk| dk s"|dkr|  ntj| dd} | S | dk | dkB  }t||dkr<t| | S tj| dd| S )a  Normalize logits if needed.

    If input tensor is outside the [0,1] we assume that logits are provided and apply the normalization.
    Use torch.where to prevent device-host sync.

    Args:
        tensor: input tensor that may be logits or probabilities
        normalization: normalization method, either 'sigmoid' or 'softmax'

    Returns:
        normalized tensor if needed

    Example:
        >>> import torch
        >>> tensor = torch.tensor([-1.0, 0.0, 1.0])
        >>> normalize_logits_if_needed(tensor, normalization="sigmoid")
        tensor([0.2689, 0.5000, 0.7311])
        >>> tensor = torch.tensor([[-1.0, 0.0, 1.0], [1.0, 0.0, -1.0]])
        >>> normalize_logits_if_needed(tensor, normalization="softmax")
        tensor([[0.0900, 0.2447, 0.6652],
                [0.6652, 0.2447, 0.0900]])
        >>> tensor = torch.tensor([0.0, 0.5, 1.0])
        >>> normalize_logits_if_needed(tensor, normalization="sigmoid")
        tensor([0.0000, 0.5000, 1.0000])

    cpur   r+   rY   rB   )r%   r   rK   rY   rZ   r"   r'   )r#   rX   	conditionr   r   r   normalize_logits_if_needed   s   r]   )r   )r+   )r5   )F)typingr   r   r   r   typing_extensionsr   torchmetrics.utilitiesr   r   r   r   r*   strboolr!   r:   tupler?   rG   rN   rO   rW   r]   r   r   r   r   <module>   sR   
%
 !