o
    yi                     @   sd   d dl mZmZ d dlZd dlmZmZ d dlmZ d dlm	Z	 d dl
mZmZ G dd de	ZdS )	    )AnyOptionalN)Tensortensor)retrieval_fall_out)RetrievalMetric)_flexible_bincountdim_zero_catc                       s   e Zd ZU dZdZeed< dZeed< dZeed< 			dde	d	e
e d
e
e deddf
 fddZdefddZdededefddZ  ZS )RetrievalFallOuta*	  Computes `Fall-out`_.

    Works with binary target data. Accepts float predictions from a model output.

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

    - ``preds`` (:class:`~torch.Tensor`): A float tensor of shape ``(N, ...)``
    - ``target`` (:class:`~torch.Tensor`): A long or bool tensor of shape ``(N, ...)``
    - ``indexes`` (:class:`~torch.Tensor`): A long tensor of shape ``(N, ...)`` which indicate to which query a
      prediction belongs

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

    - ``fo`` (:class:`~torch.Tensor`): A tensor with the computed metric

    All ``indexes``, ``preds`` and ``target`` must have the same dimension and will be flatten at the beginning,
    so that for example, a tensor of shape ``(N, M)`` is treated as ``(N * M, )``. Predictions will be first grouped by
    ``indexes`` and then will be computed as the mean of the metric over each query.

    Args:
        empty_target_action:
            Specify what to do with queries that do not have at least a negative ``target``. Choose from:

            - ``'neg'``: those queries count as ``0.0`` (default)
            - ``'pos'``: those queries count as ``1.0``
            - ``'skip'``: skip those queries; if all queries are skipped, ``0.0`` is returned
            - ``'error'``: raise a ``ValueError``

        ignore_index:
            Ignore predictions where the target is equal to this number.
        k: consider only the top k elements for each query (default: `None`, which considers them all)
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``empty_target_action`` is not one of ``error``, ``skip``, ``neg`` or ``pos``.
        ValueError:
            If ``ignore_index`` is not `None` or an integer.
        ValueError:
            If ``k`` parameter is not `None` or an integer larger than 0.

    Example:
        >>> from torchmetrics import RetrievalFallOut
        >>> indexes = tensor([0, 0, 0, 1, 1, 1, 1])
        >>> preds = tensor([0.2, 0.3, 0.5, 0.1, 0.3, 0.5, 0.2])
        >>> target = tensor([False, False, True, False, True, False, True])
        >>> fo = RetrievalFallOut(k=2)
        >>> fo(preds, target, indexes=indexes)
        tensor(0.5000)
    Fis_differentiablehigher_is_betterfull_state_updateposNempty_target_actionignore_indexkkwargsreturnc                    sD   t  jd||d| |d urt|tr|dkstd|| _d S )N)r   r   r   z(`k` has to be a positive integer or None )super__init__
isinstanceint
ValueErrorr   )selfr   r   r   r   	__class__r   S/home/ubuntu/.local/lib/python3.10/site-packages/torchmetrics/retrieval/fall_out.pyr   P   s   
zRetrievalFallOut.__init__c                    s  t | j}t | j t | j}t|\}} |  || }t|  	 }g }t
tj |ddtj||ddD ]6\}}d|  sh| jdkrNtd| jdkr[|td q;| jdkrg|td	 q;|| || q;|rt fd
d|D  S td	 S )a  First concat state ``indexes``, ``preds`` and ``target`` since they were stored as lists.

        After that, compute list of groups that will help in keeping together predictions about the same query. Finally,
        for each group compute the `_metric` if the number of negative targets is at least 1, otherwise behave as
        specified by `self.empty_target_action`.
        r   )dim   errorzC`compute` method was provided with a query with no negative target.r   g      ?negg        c                    s   g | ]}|  qS r   )to).0xpredsr   r   
<listcomp>   s    z,RetrievalFallOut.compute.<locals>.<listcomp>)r	   indexesr&   targettorchsortr   detachcputolistzipsplitsumr   r   appendr   _metricstackmeanr"   )r   r(   r)   indicessplit_sizesres
mini_predsmini_targetr   r%   r   computea   s*   





.zRetrievalFallOut.computer&   r)   c                 C   s   t ||| jdS )N)r   )r   r   )r   r&   r)   r   r   r   r3      s   zRetrievalFallOut._metric)r   NN)__name__
__module____qualname____doc__r   bool__annotations__r   r   strr   r   r   r   r   r;   r3   __classcell__r   r   r   r   r
      s*   
 3"r
   )typingr   r   r*   r   r   *torchmetrics.functional.retrieval.fall_outr   torchmetrics.retrieval.baser   torchmetrics.utilities.datar   r	   r
   r   r   r   r   <module>   s   