o
    .wiEO                     @   s   d dl mZ d dl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 d dlmZmZmZ d dl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 dlm Z m!Z! esfddgZ"G dd deZ#G dd deZ$G dd deZ%dS )    )Sequence)AnyOptionalUnionN)Tensor)Literal)_ClassificationTaskWrapper)_exact_match_reduce_multiclass_exact_match_update_multilabel_exact_match_update)&_multiclass_stat_scores_arg_validation_multiclass_stat_scores_format)_multiclass_stat_scores_tensor_validation&_multilabel_stat_scores_arg_validation_multilabel_stat_scores_format)_multilabel_stat_scores_tensor_validation)Metric)dim_zero_cat)ClassificationTaskNoBinary)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEMulticlassExactMatch.plotMultilabelExactMatch.plotc                       s   e Zd ZU dZeed< dZeed< dZeed< dZ	eed< dZ
eed	< d
Zeed< dZeed< 			d#deded dee dededdf fddZdededdfddZdefddZ	d$deeeee f  d ee defd!d"Z  ZS )%MulticlassExactMatcha]  Compute Exact match (also known as subset accuracy) for multiclass tasks.

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

    As input to ``forward`` and ``update`` the metric accepts the following input:

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

    As output to ``forward`` and ``compute`` the metric returns the following output:

    - ``mcem`` (:class:`~torch.Tensor`): A tensor whose returned shape depends on the ``multidim_average`` argument:

        - If ``multidim_average`` is set to ``global`` the output will be a scalar tensor
        - If ``multidim_average`` is set to ``samplewise`` the output will be a tensor of shape ``(N,)``

    If ``multidim_average`` is set to ``samplewise`` we expect at least one additional dimension ``...`` to be present,
    which the reduction will then be applied over instead of the sample dimension ``N``.

    Args:
        num_classes: Integer specifying the number of labels
        multidim_average:
            Defines how additionally dimensions ``...`` should be handled. Should be one of the following:

            - ``global``: Additional dimensions are flatted along the batch dimension
            - ``samplewise``: Statistic will be calculated independently for each sample on the ``N`` axis.
              The statistics in this case are calculated over the additional dimensions.

        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.

    Example (multidim tensors):
        >>> from torch import tensor
        >>> from torchmetrics.classification import MulticlassExactMatch
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = MulticlassExactMatch(num_classes=3, multidim_average='global')
        >>> metric(preds, target)
        tensor(0.5000)

    Example (multidim tensors):
        >>> from torchmetrics.classification import MulticlassExactMatch
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = MulticlassExactMatch(num_classes=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([1., 0.])

    totalFis_differentiableThigher_is_betterfull_state_update        plot_lower_bound      ?plot_upper_boundClassplot_legend_nameglobalNnum_classesmultidim_averager%   
samplewiseignore_indexvalidate_argskwargsreturnc                    s   t  jdi | d\}}|rt||||| || _|| _|| _|| _| jd| jdkr3tj	dtj
dng | jdkr;dndd | jd	tj	dtj
d| jdkrPdnd
d d S )N)   Ncorrectr%   r.   dtypesumcatdist_reduce_fxr   mean )super__init__r   r&   r'   r*   r+   	add_statetorchzeroslong)selfr&   r'   r*   r+   r,   top_kaverage	__class__r7   d/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/classification/exact_match.pyr9   m   s$   
zMulticlassExactMatch.__init__predstargetc                 C   s   | j rt||| j| j| j t||d\}}t||| j| j\}}| jdkrEt| jt	s0t
d| j| t| jts@t
d|| _dS t| jtsOt
d|  j|7  _t| jts`t
d|  j|7  _dS )z2Update metric states with predictions and targets.r.   r)   8Expected `self.correct` to be a list in samplewise mode.8Expected `self.total` to be a Tensor in samplewise mode.6Expected `self.correct` to be a tensor in global mode.N)r+   r   r&   r'   r*   r   r
   
isinstancer/   list	TypeErrorappendr   r   r>   rD   rE   r/   r   r7   r7   rC   update   s&   

zMulticlassExactMatch.updatec                 C   F   t | jtrt| jn| j}t |trt | jtstdt|| jS zCompute metric.z>Expected `correct` and `total` to be tensors after processing.rI   r/   rJ   r   r   r   rK   r	   r>   r/   r7   r7   rC   compute      zMulticlassExactMatch.computevalaxc                 C      |  ||S )a  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure object and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value per class
            >>> from torch import randint
            >>> from torchmetrics.classification import MulticlassExactMatch
            >>> metric = MulticlassExactMatch(num_classes=3)
            >>> metric.update(randint(3, (20,5)), randint(3, (20,5)))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> from torch import randint
            >>> # Example plotting a multiple values per class
            >>> from torchmetrics.classification import MulticlassExactMatch
            >>> metric = MulticlassExactMatch(num_classes=3)
            >>> values = []
            >>> for _ in range(20):
            ...     values.append(metric(randint(3, (20,5)), randint(3, (20,5))))
            >>> fig_, ax_ = metric.plot(values)

        _plotr>   rU   rV   r7   r7   rC   plot      (r   )r%   NTNN__name__
__module____qualname____doc__r   __annotations__r   boolr   r   r    floatr"   r$   strintr   r   r   r9   rN   rS   r   r   r   r   r[   __classcell__r7   r7   rA   rC   r   -   sF   
 7r   c                       s   e Zd ZU dZeed< dZeed< dZeed< dZ	eed< dZ
eed	< d
Zeed< dZeed< 				d%dededed dee dededdf fddZdededdfddZdefdd Z	d&d!eeeee f  d"ee defd#d$Z  ZS )'MultilabelExactMatcha;  Compute Exact match (also known as subset accuracy) for multilabel tasks.

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

    As input to ``forward`` and ``update`` the metric accepts the following input:

    - ``preds`` (:class:`~torch.Tensor`): An int tensor or float tensor of shape ``(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. Additionally, we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (:class:`~torch.Tensor`): An int tensor of shape ``(N, C, ...)``.

    As output to ``forward`` and ``compute`` the metric returns the following output:

    - ``mlem`` (:class:`~torch.Tensor`): A tensor whose returned shape depends on the ``multidim_average`` argument:

        - If ``multidim_average`` is set to ``global`` the output will be a scalar tensor
        - If ``multidim_average`` is set to ``samplewise`` the output will be a tensor of shape ``(N,)``

    If ``multidim_average`` is set to ``samplewise`` we expect at least one additional dimension ``...`` to be present,
    which the reduction will then be applied over instead of the sample dimension ``N``.

    Args:
        num_labels: Integer specifying the number of labels
        threshold: Threshold for transforming probability to binary (0,1) predictions
        multidim_average:
            Defines how additionally dimensions ``...`` should be handled. Should be one of the following:

            - ``global``: Additional dimensions are flatted along the batch dimension
            - ``samplewise``: Statistic will be calculated independently for each sample on the ``N`` axis.
              The statistics in this case are calculated over the additional dimensions.

        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.

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

    Example (preds is float tensor):
        >>> from torchmetrics.classification import MultilabelExactMatch
        >>> target = tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = tensor([[0.11, 0.22, 0.84], [0.73, 0.33, 0.92]])
        >>> metric = MultilabelExactMatch(num_labels=3)
        >>> metric(preds, target)
        tensor(0.5000)

    Example (multidim tensors):
        >>> from torchmetrics.classification import MultilabelExactMatch
        >>> target = tensor([[[0, 1], [1, 0], [0, 1]], [[1, 1], [0, 0], [1, 0]]])
        >>> preds = tensor([[[0.59, 0.91], [0.91, 0.99], [0.63, 0.04]],
        ...                 [[0.38, 0.04], [0.86, 0.780], [0.45, 0.37]]])
        >>> metric = MultilabelExactMatch(num_labels=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([0., 0.])

    r   Fr   Tr   r   r   r    r!   r"   Labelr$         ?r%   N
num_labels	thresholdr'   r(   r*   r+   r,   r-   c                    s   t  jdi | |rt||d ||d || _|| _|| _|| _|| _| jd| jdkr3t	j
dt	jdng | jdkr;dndd | jd	t	j
dt	jd| jdkrPdnd
d d S )N)r@   r'   r*   r/   r%   r.   r0   r2   r3   r4   r   r6   r7   )r8   r9   r   rl   rm   r'   r*   r+   r:   r;   r<   r=   )r>   rl   rm   r'   r*   r+   r,   rA   r7   rC   r9   "  s(   	

zMultilabelExactMatch.__init__rD   rE   c                 C   s   | j rt||| j| j| j t||| j| j| j\}}t||| j| j| jd\}}| jdkrMt| j	t
s8td| j	| t| jtsHtd|| _dS t| j	tsWtd|  j	|7  _	t| jtshtd|  j|7  _dS )z*Update state with predictions and targets.)rD   rE   rl   r'   r*   r)   rF   rG   rH   N)r+   r   rl   r'   r*   r   rm   r   rI   r/   rJ   rK   rL   r   r   rM   r7   r7   rC   rN   A  s6   


zMultilabelExactMatch.updatec                 C   rO   rP   rQ   rR   r7   r7   rC   rS   c  rT   zMultilabelExactMatch.computerU   rV   c                 C   rW   )a  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value
            >>> from torch import rand, randint
            >>> from torchmetrics.classification import MultilabelExactMatch
            >>> metric = MultilabelExactMatch(num_labels=3)
            >>> metric.update(randint(2, (20, 3, 5)), randint(2, (20, 3, 5)))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torch import rand, randint
            >>> from torchmetrics.classification import MultilabelExactMatch
            >>> metric = MultilabelExactMatch(num_labels=3)
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(randint(2, (20, 3, 5)), randint(2, (20, 3, 5))))
            >>> fig_, ax_ = metric.plot(values)

        rX   rZ   r7   r7   rC   r[   m  r\   r   )rk   r%   NTr]   r^   r7   r7   rA   rC   ri      sL   
 A"ri   c                   @   sh   e Zd ZdZ						dded  ded d	ed
ee dee ded dee de	de
defddZdS )
ExactMatcha  Compute Exact match (also known as subset accuracy).

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

    This module is a simple wrapper to get the task specific versions of this metric, which is done by setting the
    ``task`` argument to either ``'multiclass'`` or ``'multilabel'``. See the documentation of
    :class:`~torchmetrics.classification.MulticlassExactMatch` and
    :class:`~torchmetrics.classification.MultilabelExactMatch` for the specific details of each argument influence and
    examples.

    Legacy Example:
        >>> from torch import tensor
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = ExactMatch(task="multiclass", num_classes=3, multidim_average='global')
        >>> metric(preds, target)
        tensor(0.5000)

        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = ExactMatch(task="multiclass", num_classes=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([1., 0.])

    rk   Nr%   Tclstask)binary
multiclass
multilabelrm   r&   rl   r'   r(   r*   r+   r,   r-   c           	      K   s   t |}||||d |t jkr*t|ts"tdt| dt|fi |S |t j	krGt|ts>tdt| dt
||fi |S td| d)zInitialize task metric.)r'   r*   r+   z+`num_classes` is expected to be `int` but `z was passed.`z*`num_labels` is expected to be `int` but `zTask z not supported!)r   from_strrN   
MULTICLASSrI   rg   
ValueErrortyper   
MULTILABELri   )	ro   rp   rm   r&   rl   r'   r*   r+   r,   r7   r7   rC   __new__  s   




zExactMatch.__new__)rk   NNr%   NT)r_   r`   ra   rb   rw   r   re   r   rg   rd   r   r   ry   r7   r7   r7   rC   rn     s:    	
rn   )&collections.abcr   typingr   r   r   r;   r   typing_extensionsr    torchmetrics.classification.baser   2torchmetrics.functional.classification.exact_matchr	   r
   r   2torchmetrics.functional.classification.stat_scoresr   r   r   r   r   r   torchmetrics.metricr   torchmetrics.utilities.datar   torchmetrics.utilities.enumsr   torchmetrics.utilities.importsr   torchmetrics.utilities.plotr   r   __doctest_skip__r   ri   rn   r7   r7   r7   rC   <module>   s(     , A