o
    yi                     @   sz   d dl mZmZ d dlmZ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eZdS )
    )ABCabstractmethod)AnyListOptionalN)Tensortensor)Metric)_check_retrieval_inputs)_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< e	e
 ed< e	e
 ed< e	e
 ed	< 	
	ddedee deddf fddZde
d	e
de
ddfddZde
fddZede
d	e
de
fddZ  ZS )RetrievalMetrica  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

    .. note:: ``indexes``, ``preds`` and ``target`` must have the same dimension and will be flatten
    to single dimension once provided.

    .. note::
        Predictions will be first grouped by ``indexes`` and then the real metric, defined by overriding
        the `_metric` method, will be computed as the mean of the scores over each query.

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

    - ``metric`` (:class:`~torch.Tensor`): A tensor as computed by ``_metric`` if the number of positive targets is
      at least 1, otherwise behave as specified by ``self.empty_target_action``.

    Args:
        empty_target_action:
            Specify what to do with queries that do not have at least a positive
            or negative (depend on metric) 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.
        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.
    Fis_differentiableThigher_is_betterfull_state_updateindexespredstargetnegNempty_target_actionignore_indexkwargsreturnc                    s   t  jd
i | d| _d}||vrtd| d|| _|d ur*t|ts*td|| _| jdg d d | jdg d d | jd	g d d d S )NF)errorskipr   posz7Argument `empty_target_action` received a wrong value `z`.z3Argument `ignore_index` must be an integer or None.r   )defaultdist_reduce_fxr   r    )	super__init__allow_non_binary_target
ValueErrorr   
isinstanceintr   	add_state)selfr   r   r   empty_target_action_options	__class__r   O/home/ubuntu/.local/lib/python3.10/site-packages/torchmetrics/retrieval/base.pyr    L   s   zRetrievalMetric.__init__c                 C   sT   |du rt dt|||| j| jd\}}}| j| | j| | j| dS )zGCheck shape, check and convert dtypes, flatten and add to accumulators.Nz!Argument `indexes` cannot be None)r!   r   )r"   r
   r!   r   r   appendr   r   )r&   r   r   r   r   r   r*   updated   s   zRetrievalMetric.updatec                    s  t | j}t | j t | j}t|\}} |  || }t|  	 }g }t
tj |ddtj||ddD ]4\}}| sf| jdkrLtd| jdkrY|td q;| jdkre|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 positive targets is at least 1, otherwise behave as
        specified by ``self.empty_target_action``.
        r   )dimr   zC`compute` method was provided with a query with no positive target.r   g      ?r   g        c                    s   g | ]}|  qS r   )to).0xr   r   r*   
<listcomp>   s    z+RetrievalMetric.compute.<locals>.<listcomp>)r   r   r   r   torchsortr   detachcputolistzipsplitsumr   r"   r+   r   _metricstackmeanr.   )r&   r   r   indicessplit_sizesres
mini_predsmini_targetr   r1   r*   computeq   s*   





.zRetrievalMetric.computec                 C   s   dS )zCompute a metric over a predictions and target of a single group.

        This method should be overridden by subclasses.
        Nr   )r&   r   r   r   r   r*   r;      s    zRetrievalMetric._metric)r   N)__name__
__module____qualname____doc__r   bool__annotations__r   r   r   r   strr   r$   r   r    r,   rC   r   r;   __classcell__r   r   r(   r*   r      s.   
 *" r   )abcr   r   typingr   r   r   r3   r   r   torchmetricsr	   torchmetrics.utilities.checksr
   torchmetrics.utilities.datar   r   r   r   r   r   r*   <module>   s   