a
    dZ                     @   s  d dl mZmZmZmZ d dlZd dlmZ d dlmZ d dl	m
Z
mZmZmZmZmZmZmZmZmZmZmZmZmZmZ d dlmZ d dlmZ d dlmZ d d	lm Z  d-eeee f eeee f eed  ee edddZ!eeeeef f ee edddZ"d.eeeee#ee$ ef  ee# e%edddZ&d/e#eed  eee#ee$ ef  ee# ddddZ'd0eeeeef f e#eed  ee edddZ(d1eee#eed  eee#ee$ ef  ee# e%edddZ)d2e#eed  eee#ee$ ef  ee# dd d!d"Z*d3eeeeef f e#eed  ee ee# ed#d$d%Z+d4eee#eed  eee#ee$ ef  ee# e%ed&d'd(Z,d5eeed) eee#ee$ ef  ee# ee# eed  ee# e%ee d*
d+d,Z-dS )6    )ListOptionalTupleUnionN)Tensor)Literal)-_binary_precision_recall_curve_arg_validation&_binary_precision_recall_curve_compute%_binary_precision_recall_curve_format0_binary_precision_recall_curve_tensor_validation%_binary_precision_recall_curve_update1_multiclass_precision_recall_curve_arg_validation*_multiclass_precision_recall_curve_compute)_multiclass_precision_recall_curve_format4_multiclass_precision_recall_curve_tensor_validation)_multiclass_precision_recall_curve_update1_multilabel_precision_recall_curve_arg_validation*_multilabel_precision_recall_curve_compute)_multilabel_precision_recall_curve_format4_multilabel_precision_recall_curve_tensor_validation)_multilabel_precision_recall_curve_update)_safe_divide)	_bincount)ClassificationTask)rank_zero_warnmacro)r   weightednone)	precisionrecallaverageweightsreturnc                 C   s  t | tr\t |tr\t|ddddf |ddddf  | ddddf  d }ntdd t| |D }|du s|dkr|S t| rtd| dt	 t| }|d	kr|| 
 S |d
kr|durt|| ||  }|| |  S tddS )z8Reduce multiple average precision score into one number.N   c                 S   s<   g | ]4\}}t |d d |dd  |dd   qS )r#   Nr$   )torchsum).0pr r*   /var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/functional/classification/average_precision.py
<listcomp>5       z-_reduce_average_precision.<locals>.<listcomp>r   zUAverage precision score for one or more classes was `nan`. Ignoring these classes in z-averager   r   zBReceived an incompatible combinations of inputs to make reduction.)
isinstancer   r%   r&   stackzipisnananyr   UserWarningmeanr   
ValueError)r   r   r    r!   residxr*   r*   r+   _reduce_average_precision+   s"    H
r8   )state
thresholdsr"   c                 C   s<   t | |\}}}t|dd  |d d  |d d   S )Nr#   r$   )r	   r%   r&   )r9   r:   r   r   _r*   r*   r+   !_binary_average_precision_computeF   s    r<   T)predstargetr:   ignore_indexvalidate_argsr"   c                 C   sD   |rt || t| || t| |||\} }}t| ||}t||S )a  Compute the average precision (AP) score for binary tasks.

    The AP score summarizes a precision-recall curve as an weighted mean of precisions at each threshold, with the
    difference in recall from the previous threshold as weight:

    .. math::
        AP = \sum{n} (R_n - R_{n-1}) P_n

    where :math:`P_n, R_n` is the respective precision and recall at threshold index :math:`n`. This value is
    equivalent to the area under the precision-recall curve (AUPRC).

    Accepts the following input tensors:

    - ``preds`` (float tensor): ``(N, ...)``. Preds should be a tensor containing probabilities or logits for each
      observation. If preds has values outside [0,1] range we consider the input to be logits and will auto apply
      sigmoid per element.
    - ``target`` (int tensor): ``(N, ...)``. Target should be a tensor containing ground truth labels, and therefore
      only contain {0,1} values (except if `ignore_index` is specified). The value 1 always encodes the positive class.

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

    The implementation both supports calculating the metric in a non-binned but accurate version and a binned version
    that is less accurate but more memory efficient. Setting the `thresholds` argument to `None` will activate the
    non-binned  version that uses memory of size :math:`\mathcal{O}(n_{samples})` whereas setting the `thresholds`
    argument to either an integer, list or a 1d tensor will use a binned version that uses memory of
    size :math:`\mathcal{O}(n_{thresholds})` (constant memory).

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        thresholds:
            Can be one of:

            - If set to `None`, will use a non-binned approach where thresholds are dynamically calculated from
              all the data. Most accurate but also most memory consuming approach.
            - If set to an `int` (larger than 1), will use that number of thresholds linearly spaced from
              0 to 1 as bins for the calculation.
            - If set to an `list` of floats, will use the indicated thresholds in the list as bins for the calculation
            - If set to an 1d `tensor` of floats, will use the indicated thresholds in the tensor as
              bins for the calculation.

        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 single scalar with the average precision score

    Example:
        >>> from torchmetrics.functional.classification import binary_average_precision
        >>> preds = torch.tensor([0, 0.5, 0.7, 0.8])
        >>> target = torch.tensor([0, 1, 1, 0])
        >>> binary_average_precision(preds, target, thresholds=None)
        tensor(0.5833)
        >>> binary_average_precision(preds, target, thresholds=5)
        tensor(0.6667)

    )r   r   r
   r   r<   )r=   r>   r:   r?   r@   r9   r*   r*   r+   binary_average_precisionN   s    B
rA   )num_classesr    r:   r?   r"   c                 C   s0   t | || d}||vr,td| d| d S )N)r   r   r   N)Expected argument `average` to be one of 	 but got )r   r5   )rB   r    r:   r?   allowed_averager*   r*   r+   ,_multiclass_average_precision_arg_validation   s    rF   )r9   rB   r    r:   r"   c              	   C   sZ   t | ||\}}}t||||d u r6t| d |d n| d d d dd d f ddS )Nr#   )Z	minlengthr   r$   r!   )r   r8   r   floatr&   )r9   rB   r    r:   r   r   r;   r*   r*   r+   %_multiclass_average_precision_compute   s    :rI   )r=   r>   rB   r    r:   r?   r@   r"   c                 C   sR   |r t |||| t| ||| t| ||||\} }}t| |||}t||||S )a  Compute the average precision (AP) score for multiclass tasks.

    The AP score summarizes a precision-recall curve as an weighted mean of precisions at each threshold, with the
    difference in recall from the previous threshold as weight:

    .. math::
        AP = \sum{n} (R_n - R_{n-1}) P_n

    where :math:`P_n, R_n` is the respective precision and recall at threshold index :math:`n`. This value is
    equivalent to the area under the precision-recall curve (AUPRC).

    Accepts the following input tensors:

    - ``preds`` (float tensor): ``(N, C, ...)``. Preds should be a tensor containing probabilities or logits for each
      observation. If preds has values outside [0,1] range we consider the input to be logits and will auto apply
      softmax per sample.
    - ``target`` (int tensor): ``(N, ...)``. Target should be a tensor containing ground truth labels, and therefore
      only contain values in the [0, n_classes-1] range (except if `ignore_index` is specified).

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

    The implementation both supports calculating the metric in a non-binned but accurate version and a binned version
    that is less accurate but more memory efficient. Setting the `thresholds` argument to `None` will activate the
    non-binned  version that uses memory of size :math:`\mathcal{O}(n_{samples})` whereas setting the `thresholds`
    argument to either an integer, list or a 1d tensor will use a binned version that uses memory of
    size :math:`\mathcal{O}(n_{thresholds} \times n_{classes})` (constant memory).

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        num_classes: Integer specifing the number of classes
        average:
            Defines the reduction that is applied over classes. Should be one of the following:

            - ``macro``: Calculate score for each class and average them
            - ``weighted``: calculates score for each class and computes weighted average using their support
            - ``"none"`` or ``None``: calculates score for each class and applies no reduction
        thresholds:
            Can be one of:

            - If set to `None`, will use a non-binned approach where thresholds are dynamically calculated from
              all the data. Most accurate but also most memory consuming approach.
            - If set to an `int` (larger than 1), will use that number of thresholds linearly spaced from
              0 to 1 as bins for the calculation.
            - If set to an `list` of floats, will use the indicated thresholds in the list as bins for the calculation
            - If set to an 1d `tensor` of floats, will use the indicated thresholds in the tensor as
              bins for the calculation.

        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:
        If `average=None|"none"` then a 1d tensor of shape (n_classes, ) will be returned with AP score per class.
        If `average="macro"|"weighted"` then a single scalar is returned.

    Example:
        >>> from torchmetrics.functional.classification import multiclass_average_precision
        >>> preds = torch.tensor([[0.75, 0.05, 0.05, 0.05, 0.05],
        ...                       [0.05, 0.75, 0.05, 0.05, 0.05],
        ...                       [0.05, 0.05, 0.75, 0.05, 0.05],
        ...                       [0.05, 0.05, 0.05, 0.75, 0.05]])
        >>> target = torch.tensor([0, 1, 3, 2])
        >>> multiclass_average_precision(preds, target, num_classes=5, average="macro", thresholds=None)
        tensor(0.6250)
        >>> multiclass_average_precision(preds, target, num_classes=5, average=None, thresholds=None)
        tensor([1.0000, 1.0000, 0.2500, 0.2500,    nan])
        >>> multiclass_average_precision(preds, target, num_classes=5, average="macro", thresholds=5)
        tensor(0.5000)
        >>> multiclass_average_precision(preds, target, num_classes=5, average=None, thresholds=5)
        tensor([1.0000, 1.0000, 0.2500, 0.2500, -0.0000])

    )rF   r   r   r   rI   )r=   r>   rB   r    r:   r?   r@   r9   r*   r*   r+   multiclass_average_precision   s    S

rJ   )micror   r   r   )
num_labelsr    r:   r?   r"   c                 C   s0   t | || d}||vr,td| d| d S )N)rK   r   r   r   NrC   rD   )r   r5   )rL   r    r:   r?   rE   r*   r*   r+   ,_multilabel_average_precision_arg_validation  s    rM   )r9   rL   r    r:   r?   r"   c              	   C   s   |dkrvt | tr&|d ur&| d} nF| d  | d   }}|d urd||k}||  }||  }||f} t| |S t| |||\}}	}
t||	||d u r| d dkjdd n| d d d dd d f ddS )NrK   r#   r   )Zdimr$   rG   )r.   r   r&   flattenr<   r   r8   rH   )r9   rL   r    r:   r?   r=   r>   r7   r   r   r;   r*   r*   r+   %_multilabel_average_precision_compute  s"    


>rO   )r=   r>   rL   r    r:   r?   r@   r"   c                 C   sT   |r t |||| t| ||| t| ||||\} }}t| |||}t|||||S )a  Compute the average precision (AP) score for multilabel tasks.

    The AP score summarizes a precision-recall curve as an weighted mean of precisions at each threshold, with the
    difference in recall from the previous threshold as weight:

    .. math::
        AP = \sum{n} (R_n - R_{n-1}) P_n

    where :math:`P_n, R_n` is the respective precision and recall at threshold index :math:`n`. This value is
    equivalent to the area under the precision-recall curve (AUPRC).

    Accepts the following input tensors:

    - ``preds`` (float tensor): ``(N, C, ...)``. Preds should be a tensor containing probabilities or logits for each
      observation. If preds has values outside [0,1] range we consider the input to be logits and will auto apply
      sigmoid per element.
    - ``target`` (int tensor): ``(N, C, ...)``. Target should be a tensor containing ground truth labels, and therefore
      only contain {0,1} values (except if `ignore_index` is specified).

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

    The implementation both supports calculating the metric in a non-binned but accurate version and a binned version
    that is less accurate but more memory efficient. Setting the `thresholds` argument to `None` will activate the
    non-binned  version that uses memory of size :math:`\mathcal{O}(n_{samples})` whereas setting the `thresholds`
    argument to either an integer, list or a 1d tensor will use a binned version that uses memory of
    size :math:`\mathcal{O}(n_{thresholds} \times n_{labels})` (constant memory).

    Args:
        preds: Tensor with predictions
        target: Tensor with true labels
        num_labels: Integer specifing the number of labels
        average:
            Defines the reduction that is applied over labels. Should be one of the following:

            - ``micro``: Sum score over all labels
            - ``macro``: Calculate score for each label and average them
            - ``weighted``: calculates score for each label and computes weighted average using their support
            - ``"none"`` or ``None``: calculates score for each label and applies no reduction
        thresholds:
            Can be one of:

            - If set to `None`, will use a non-binned approach where thresholds are dynamically calculated from
              all the data. Most accurate but also most memory consuming approach.
            - If set to an `int` (larger than 1), will use that number of thresholds linearly spaced from
              0 to 1 as bins for the calculation.
            - If set to an `list` of floats, will use the indicated thresholds in the list as bins for the calculation
            - If set to an 1d `tensor` of floats, will use the indicated thresholds in the tensor as
              bins for the calculation.

        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:
        If `average=None|"none"` then a 1d tensor of shape (n_classes, ) will be returned with AP score per class.
        If `average="micro|macro"|"weighted"` then a single scalar is returned.

    Example:
        >>> from torchmetrics.functional.classification import multilabel_average_precision
        >>> preds = torch.tensor([[0.75, 0.05, 0.35],
        ...                       [0.45, 0.75, 0.05],
        ...                       [0.05, 0.55, 0.75],
        ...                       [0.05, 0.65, 0.05]])
        >>> target = torch.tensor([[1, 0, 1],
        ...                        [0, 0, 0],
        ...                        [0, 1, 1],
        ...                        [1, 1, 1]])
        >>> multilabel_average_precision(preds, target, num_labels=3, average="macro", thresholds=None)
        tensor(0.7500)
        >>> multilabel_average_precision(preds, target, num_labels=3, average=None, thresholds=None)
        tensor([0.7500, 0.5833, 0.9167])
        >>> multilabel_average_precision(preds, target, num_labels=3, average="macro", thresholds=5)
        tensor(0.7778)
        >>> multilabel_average_precision(preds, target, num_labels=3, average=None, thresholds=5)
        tensor([0.7500, 0.6667, 0.9167])

    )rM   r   r   r   rO   )r=   r>   rL   r    r:   r?   r@   r9   r*   r*   r+   multilabel_average_precision8  s    W

rP   )binaryZ
multiclassZ
multilabel)
r=   r>   taskr:   rB   rL   r    r?   r@   r"   c	           	      C   s   t |}|t jkr$t| ||||S |t jkr`t|tsLtdt| dt	| ||||||S |t j
krt|tstdt| dt| ||||||S dS )a  Compute the average precision (AP) score.

    The AP score summarizes a precision-recall curve as an weighted mean of precisions at each threshold, with the
    difference in recall from the previous threshold as weight:

    .. math::
        AP = \sum{n} (R_n - R_{n-1}) P_n

    where :math:`P_n, R_n` is the respective precision and recall at threshold index :math:`n`. This value is
    equivalent to the area under the precision-recall curve (AUPRC).

    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:`~torchmetrics.functional.classification.binary_average_precision`,
    :func:`~torchmetrics.functional.classification.multiclass_average_precision` and
    :func:`~torchmetrics.functional.classification.multilabel_average_precision`
    for the specific details of each argument influence and examples.

    Legacy Example:
        >>> from torchmetrics.functional.classification import average_precision
        >>> pred = torch.tensor([0.0, 1.0, 2.0, 3.0])
        >>> target = torch.tensor([0, 1, 1, 1])
        >>> average_precision(pred, target, task="binary")
        tensor(1.)

        >>> pred = torch.tensor([[0.75, 0.05, 0.05, 0.05, 0.05],
        ...                      [0.05, 0.75, 0.05, 0.05, 0.05],
        ...                      [0.05, 0.05, 0.75, 0.05, 0.05],
        ...                      [0.05, 0.05, 0.05, 0.75, 0.05]])
        >>> target = torch.tensor([0, 1, 3, 2])
        >>> average_precision(pred, target, task="multiclass", num_classes=5, average=None)
        tensor([1.0000, 1.0000, 0.2500, 0.2500,    nan])

    z+`num_classes` is expected to be `int` but `z was passed.`z*`num_labels` is expected to be `int` but `N)r   Zfrom_strBINARYrA   Z
MULTICLASSr.   intr5   typerJ   Z
MULTILABELrP   )	r=   r>   rR   r:   rB   rL   r    r?   r@   r*   r*   r+   average_precision  s    -





rV   )r   N)NNT)r   NN)r   N)r   NNT)NN)N)r   NNT)NNNr   NT).typingr   r   r   r   r%   r   Ztyping_extensionsr   Z=torchmetrics.functional.classification.precision_recall_curver   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   Ztorchmetrics.utilities.computer   Ztorchmetrics.utilities.datar   Ztorchmetrics.utilities.enumsr   Ztorchmetrics.utilities.printsr   r8   r<   rT   rH   boolrA   rF   rI   rJ   rM   rO   rP   rV   r*   r*   r*   r+   <module>   s   D  
   L   
  
    
`  
 
     
e      
