o
    yik                     @   s  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 dl	m
Z
 d dlmZ 	dAded	eed
  defddZ			dBdedee d	eed
  ddfddZ	dAdededee ddfddZ			dCdedededee dedeeef fddZdededefddZ	dAded	eed
  defddZ				dDdededed	eed
  dee dedefd d!Z		dEd"edee d	eed
  ddfd#d$Z	dAdeded"edee ddf
d%d&Z		dFdededee dedeeef f
d'd(Zdeded"edefd)d*Z	dAded	eed
  defd+d,Z			dGdeded"ed	eed
  dee dedefd-d.Z			dBd/ededee d	eed
  ddf
d0d1Z	dAdeded/edee ddf
d2d3Z			dCdeded/ededee d4edeeef fd5d6Zdeded/edefd7d8Z 	dAded	eed
  defd9d:Z!				dDdeded/eded	eed
  dee dedefd;d<Z"						dHdeded=ed> ded"ee d/ee d	eed
  dee dedefd?d@Z#dS )I    )OptionalTupleN)Tensor)Literal)_check_same_shape)	_bincount)rank_zero_warnconfmat	normalize)truepredallnonereturnc                 C   s   d}||vrt d| |durc|dkrc|  s|  n| } |dkr-| | jddd } n|d	kr;| | jd
dd } n|dkrJ| | jd
dgdd } | t|   }|rcd| t| < t| d | S )a  Reduce an un-normalized confusion matrix
    Args:
        confmat: un-normalized confusion matrix
        normalize: normalization method.
            - `"true"` will divide by the sum of the column dimension.
            - `"pred"` will divide by the sum of the row dimension.
            - `"all"` will divide by the sum of the full matrix
            - `"none"` or `None` will apply no reduction

    Returns:
        Normalized confusion matrix
    r   r   r   r   Nz4Argument `normalize` needs to one of the following: Nr   r   T)axiskeepdimr   r   r   zD NaN values found in confusion matrix have been replaced with zeros.)
ValueErroris_floating_pointfloatsumtorchisnannelementr   )r	   r
   allowed_normalizenan_elements r   k/home/ubuntu/.local/lib/python3.10/site-packages/torchmetrics/functional/classification/confusion_matrix.py_confusion_matrix_reduce   s    r          ?	thresholdignore_indexc                 C   sv   t | trd|   krdksn td|  d|dur(t |ts(td| d}||vr9td| d	| ddS )
zValidate non tensor input.

    - ``threshold`` has to be a float in the [0,1] range
    - ``ignore_index`` has to be None or int
    - ``normalize`` has to be "true" | "pred" | "all" | "none" | None
    r      zHExpected argument `threshold` to be a float in the [0,1] range, but got .NLExpected argument `ignore_index` to either be `None` or an integer, but got r   +Expected argument `normalize` to be one of 
, but got )
isinstancer   r   int)r"   r#   r
   r   r   r   r   '_binary_confusion_matrix_arg_validation;   s    r+   predstargetc                 C   s   t | | t|}|du rt|dk|dk@ }nt|dk|dk@ ||k@ }|rAtd| d|du r:ddgg  n|g d|  s]t| }t|dk|dk@ r_td| ddS dS )	zValidate tensor input.

    - tensors have to be of same shape
    - all values in target tensor that are not ignored have to be in {0, 1}
    - if pred tensor is not floating point, then all values also have to be in {0, 1}
    Nr   r$   +Detected the following values in `target`: ( but expected only the following values r%   *Detected the following values in `preds`: L but expected only the following values [0,1] since preds is a label tensor.)r   r   uniqueanyRuntimeErrorr   )r,   r-   r#   unique_valuescheckr   r   r   *_binary_confusion_matrix_tensor_validationO   s&   




r7   Tconvert_to_labelsc                 C   sj   |   } |  }|dur||k}| | } || }|  r1td| k| dk s+|  } |r1| |k} | |fS )zConvert all input to label format.

    - Remove all datapoints that should be ignored
    - If preds tensor is floating point, applies sigmoid if pred tensor not in [0,1] range
    - If preds tensor is floating point, thresholds afterwards
    Nr   r$   )flattenr   r   r   sigmoid)r,   r-   r"   r#   r8   idxr   r   r   _binary_confusion_matrix_formatq   s   r<   c                 C   s,   |d |   tj}t|dd}|ddS )6Computes the bins to update the confusion matrix with.      	minlengthtor   longr   reshape)r,   r-   unique_mappingbinsr   r   r   _binary_confusion_matrix_update   s   rH   c                 C   
   t | |S zrReduces the confusion matrix to it's final form.

    Normalization technique can be chosen by ``normalize``.
    r    r	   r
   r   r   r    _binary_confusion_matrix_compute      
rM   validate_argsc                 C   sB   |rt ||| t| || t| |||\} }t| |}t||S )a  Computes the `confusion matrix`_ for binary tasks.

    Accepts the following input tensors:

    - ``preds`` (int or float tensor): ``(N, ...)``. If preds is a floating point tensor with values outside
      [0,1] range we consider the input to be logits and will auto apply sigmoid per element. Addtionally,
      we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (int tensor): ``(N, ...)``

    Additional dimension ``...`` will be flattened into the batch dimension.

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        threshold: Threshold for transforming probability to binary (0,1) predictions
        normalize: Normalization mode for confusion matrix. Choose from:

            - ``None`` or ``'none'``: no normalization (default)
            - ``'true'``: normalization over the targets (most commonly used)
            - ``'pred'``: normalization over the predictions
            - ``'all'``: normalization over the whole matrix
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        A ``[2, 2]`` tensor

    Example (preds is int tensor):
        >>> from torchmetrics.functional.classification import binary_confusion_matrix
        >>> target = torch.tensor([1, 1, 0, 0])
        >>> preds = torch.tensor([0, 1, 0, 0])
        >>> binary_confusion_matrix(preds, target)
        tensor([[2, 0],
                [1, 1]])

    Example (preds is float tensor):
        >>> from torchmetrics.functional.classification import binary_confusion_matrix
        >>> target = torch.tensor([1, 1, 0, 0])
        >>> preds = torch.tensor([0.35, 0.85, 0.48, 0.01])
        >>> binary_confusion_matrix(preds, target)
        tensor([[2, 0],
                [1, 1]])
    )r+   r7   r<   rH   rM   )r,   r-   r"   r
   r#   rO   r	   r   r   r   binary_confusion_matrix   s   5

rP   num_classesc                 C   sf   t | tr	| dk rtd|  |dur t |ts td| d}||vr1td| d| ddS )	zValidate non tensor input.

    - ``num_classes`` has to be a int larger than 1
    - ``ignore_index`` has to be None or int
    - ``normalize`` has to be "true" | "pred" | "all" | "none" | None
    r>   zHExpected argument `num_classes` to be an integer larger than 1, but got Nr&   r   r'   r(   r%   )r)   r*   r   )rQ   r#   r
   r   r   r   r   +_multiclass_confusion_matrix_arg_validation   s   rR   c                 C   s,  | j |j d kr.|  std| jd |krtd| jdd |jdd kr-tdn| j |j krI| j|jkrHtdd| j d	|j d
ntdtt|}|du r]||k}n||d k}|rxtd|du rm|n|d  d| d|  stt| }||krtd| d| ddS dS )a  Validate tensor input.

    - if target has one more dimension than preds, then all dimensions except for preds.shape[1] should match
    exactly. preds.shape[1] should have size equal to number of classes
    - if preds and target have same number of dims, then all dimensions should match
    - all values in target tensor that are not ignored have to be {0, ..., num_classes - 1}
    - if pred tensor is not floating point, then all values also have to be in {0, ..., num_classes - 1}
    r$   zSIf `preds` have one dimension more than `target`, `preds` should be a float tensor.zhIf `preds` have one dimension more than `target`, `preds.shape[1]` should be equal to number of classes.r>   NzIf `preds` have one dimension more than `target`, the shape of `preds` should be (N, C, ...), and the shape of `target` should be (N, ...).z4The `preds` and `target` should have the same shape,z got `preds` with shape=z and `target` with shape=r%   zEither `preds` and `target` both should have the (same) shape (N, ...), or `target` should be (N, ...) and `preds` should be (N, C, ...).zJDetected more unique values in `target` than `num_classes`. Expected only z but found z in `target`.zIDetected more unique values in `preds` than `num_classes`. Expected only z in `preds`.)ndimr   r   shapelenr   r2   r4   )r,   r-   rQ   r#   num_unique_valuesr6   r   r   r   ._multiclass_confusion_matrix_tensor_validation   s\   
rW   c                 C   sz   | j |j d kr|r| jdd} |r|  } nt| ddd| jd } | }|dur9||k}| | } || }| |fS )zConvert all input to label format.

    - Applies argmax if preds have one more dimension than target
    - Remove all datapoints that should be ignored
    r$   )dimr   N)rS   argmaxr9   r   movedimrE   rT   )r,   r-   r#   r8   r;   r   r   r   #_multiclass_confusion_matrix_format*  s   
r[   c                 C   s8   | tj| |  tj }t||d d}|||S )z5Compute the bins to update the confusion matrix with.r>   r@   rB   )r,   r-   rQ   rF   rG   r   r   r   #_multiclass_confusion_matrix_updateG  s   r\   c                 C   rI   rJ   rK   rL   r   r   r   $_multiclass_confusion_matrix_computeN  rN   r]   c                 C   sD   |rt ||| t| ||| t| ||\} }t| ||}t||S )a  Computes the `confusion matrix`_ for multiclass tasks.

    Accepts the following input tensors:

    - ``preds``: ``(N, ...)`` (int tensor) or ``(N, C, ..)`` (float tensor). If preds is a floating point
      we apply ``torch.argmax`` along the ``C`` dimension to automatically convert probabilities/logits into
      an int tensor.
    - ``target`` (int tensor): ``(N, ...)``

    Additional dimension ``...`` will be flattened into the batch dimension.

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        num_classes: Integer specifing the number of classes
        normalize: Normalization mode for confusion matrix. Choose from:

            - ``None`` or ``'none'``: no normalization (default)
            - ``'true'``: normalization over the targets (most commonly used)
            - ``'pred'``: normalization over the predictions
            - ``'all'``: normalization over the whole matrix
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        A ``[num_classes, num_classes]`` tensor

    Example (pred is integer tensor):
        >>> from torchmetrics.functional.classification import multiclass_confusion_matrix
        >>> target = torch.tensor([2, 1, 0, 0])
        >>> preds = torch.tensor([2, 1, 0, 1])
        >>> multiclass_confusion_matrix(preds, target, num_classes=3)
        tensor([[1, 1, 0],
                [0, 1, 0],
                [0, 0, 1]])

    Example (pred is float tensor):
        >>> from torchmetrics.functional.classification import multiclass_confusion_matrix
        >>> target = torch.tensor([2, 1, 0, 0])
        >>> preds = torch.tensor([
        ...   [0.16, 0.26, 0.58],
        ...   [0.22, 0.61, 0.17],
        ...   [0.71, 0.09, 0.20],
        ...   [0.05, 0.82, 0.13],
        ... ])
        >>> multiclass_confusion_matrix(preds, target, num_classes=3)
        tensor([[1, 1, 0],
                [0, 1, 0],
                [0, 0, 1]])
    )rR   rW   r[   r\   r]   )r,   r-   rQ   r
   r#   rO   r	   r   r   r   multiclass_confusion_matrixX  s   <
r^   
num_labelsc                 C   s   t | tr	| dk rtd|  t |tr d|  krdks(n td| d|dur8t |ts8td| d	}||vrItd
| d| ddS )a   Validate non tensor input.

    - ``num_labels`` should be an int larger than 1
    - ``threshold`` has to be a float in the [0,1] range
    - ``ignore_index`` has to be None or int
    - ``normalize`` has to be "true" | "pred" | "all" | "none" | None
    r>   zGExpected argument `num_labels` to be an integer larger than 1, but got r   r$   z5Expected argument `threshold` to be a float, but got r%   Nr&   r   r'   r(   )r)   r*   r   r   )r_   r"   r#   r
   r   r   r   r   +_multilabel_confusion_matrix_arg_validation  s    r`   c                 C   s   t | | | jd |krtd| jd  d| t|}|du r.t|dk|dk@ }nt|dk|dk@ ||k@ }|rUtd| d|du rNddgg  n|g d|  sqt| }t|dk|dk@ rstd	| d
dS dS )a9  Validate tensor input.

    - tensors have to be of same shape
    - the second dimension of both tensors need to be equal to the number of labels
    - all values in target tensor that are not ignored have to be in {0, 1}
    - if pred tensor is not floating point, then all values also have to be in {0, 1}
    r$   zaExpected both `target.shape[1]` and `preds.shape[1]` to be equal to the number of labels but got z and expected Nr   r.   r/   r%   r0   r1   )r   rT   r   r   r2   r3   r4   r   )r,   r-   r_   r#   r5   r6   r   r   r   ._multilabel_confusion_matrix_tensor_validation  s6   



ra   should_thresholdc                 C   s   |   rtd| k| dk s|  } |r| |k} t| ddd|} t|ddd|}|durK|  } | }||k}d| | |< d| ||< | |fS )a  Convert all input to label format.

    - If preds tensor is floating point, applies sigmoid if pred tensor not in [0,1] range
    - If preds tensor is floating point, thresholds afterwards
    - Mask all elements that should be ignored with negative numbers for later filtration
    r   r$   r   N)r   r   r   r:   rZ   rE   clone)r,   r-   r_   r"   r#   rb   r;   r   r   r   #_multilabel_confusion_matrix_format  s   re   c                 C   sN   d| |  dt j|| jd   }||dk }t|d| d}||ddS )r=   r>   r?   )devicer   r@   )r   arangerf   r9   r   rE   )r,   r-   r_   rF   rG   r   r   r   #_multilabel_confusion_matrix_update  s   $rh   c                 C   rI   rJ   rK   rL   r   r   r   $_multilabel_confusion_matrix_compute  rN   ri   c                 C   sJ   |rt |||| t| ||| t| ||||\} }t| ||}t||S )a  Computes the `confusion matrix`_ for multilabel tasks.

    Accepts the following input tensors:

    - ``preds`` (int or float tensor): ``(N, C, ...)``. If preds is a floating point tensor with values outside
      [0,1] range we consider the input to be logits and will auto apply sigmoid per element. Addtionally,
      we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (int tensor): ``(N, C, ...)``

    Additional dimension ``...`` will be flattened into the batch dimension.

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        num_labels: Integer specifing the number of labels
        threshold: Threshold for transforming probability to binary (0,1) predictions
        normalize: Normalization mode for confusion matrix. Choose from:

            - ``None`` or ``'none'``: no normalization (default)
            - ``'true'``: normalization over the targets (most commonly used)
            - ``'pred'``: normalization over the predictions
            - ``'all'``: normalization over the whole matrix
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        A ``[num_labels, 2, 2]`` tensor

    Example (preds is int tensor):
        >>> from torchmetrics.functional.classification import multilabel_confusion_matrix
        >>> target = torch.tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = torch.tensor([[0, 0, 1], [1, 0, 1]])
        >>> multilabel_confusion_matrix(preds, target, num_labels=3)
        tensor([[[1, 0], [0, 1]],
                [[1, 0], [1, 0]],
                [[0, 1], [0, 1]]])

    Example (preds is float tensor):
        >>> from torchmetrics.functional.classification import multilabel_confusion_matrix
        >>> target = torch.tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = torch.tensor([[0.11, 0.22, 0.84], [0.73, 0.33, 0.92]])
        >>> multilabel_confusion_matrix(preds, target, num_labels=3)
        tensor([[[1, 0], [0, 1]],
                [[1, 0], [1, 0]],
                [[0, 1], [0, 1]]])
    )r`   ra   re   rh   ri   )r,   r-   r_   r"   r
   r#   rO   r	   r   r   r   multilabel_confusion_matrix  s   9
rj   task)binary
multiclass
multilabelc	           	      C   sz   |dkrt | |||||S |dkr!t|tsJ t| |||||S |dkr6t|ts,J t| ||||||S td| )aR  Computes the `confusion matrix`_.

    This function is a simple wrapper to get the task specific versions of this metric, which is done by setting the
    ``task`` argument to either ``'binary'``, ``'multiclass'`` or ``multilabel``. See the documentation of
    :func:`binary_confusion_matrix`, :func:`multiclass_confusion_matrix` and :func:`multilabel_confusion_matrix` for
    the specific details of each argument influence and examples.

    Legacy Example:
        >>> from torchmetrics import ConfusionMatrix
        >>> target = torch.tensor([1, 1, 0, 0])
        >>> preds = torch.tensor([0, 1, 0, 0])
        >>> confmat = ConfusionMatrix(task="binary")
        >>> confmat(preds, target)
        tensor([[2, 0],
                [1, 1]])

        >>> target = torch.tensor([2, 1, 0, 0])
        >>> preds = torch.tensor([2, 1, 0, 1])
        >>> confmat = ConfusionMatrix(task="multiclass", num_classes=3)
        >>> confmat(preds, target)
        tensor([[1, 1, 0],
                [0, 1, 0],
                [0, 0, 1]])

        >>> target = torch.tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = torch.tensor([[0, 0, 1], [1, 0, 1]])
        >>> confmat = ConfusionMatrix(task="multilabel", num_labels=3)
        >>> confmat(preds, target)
        tensor([[[1, 0], [0, 1]],
                [[1, 0], [1, 0]],
                [[0, 1], [0, 1]]])
    rl   rm   rn   z[Expected argument `task` to either be `'binary'`, `'multiclass'` or `'multilabel'` but got )rP   r)   r*   r^   rj   r   )	r,   r-   rk   r"   rQ   r_   r
   r#   rO   r   r   r   confusion_matrixR  s   +ro   )N)r!   NN)r!   NT)r!   NNT)NN)NT)NNT)r!   NNNNT)$typingr   r   r   r   typing_extensionsr   torchmetrics.utilities.checksr   torchmetrics.utilities.datar   torchmetrics.utilities.printsr   r    r   r*   r+   r7   boolr<   rH   rM   rP   rR   rW   r[   r\   r]   r^   r`   ra   re   rh   ri   rj   ro   r   r   r   r   <module>   s  

#


%





?


<





F


-

"	



E
	
