We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Custom callable is ignored in retrieval metric aggregation
## 🐛 Bug

When passing a custom aggregation to any `RetrievalMetric`, the callable is ignored. There is a bug in the retrieval aggregation function that defaults to using the maximum of the values by default https://github.com/Lightning-AI/torchmetrics/blob/1a2f406da17a01c13ce1add83835e097460cbce3/src/torchmetrics/retrieval/base.py#L38

### To Reproduce

The following custom aggregation should output the tensor of values without aggregation but returns 1, the max of the values.

```
>>> from torchmetrics.retrieval import RetrievalNormalizedDCG
>>> 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])
>>> ndcg = RetrievalNormalizedDCG(aggregation=lambda x, dim: x)
>>> print(ndcg(preds, target, indexes=indexes))
tensor(1.)
>>> ndcg = RetrievalNormalizedDCG(aggregation="max")
>>> print(ndcg(preds, target, indexes=indexes))
tensor(1.)
>>> ndcg = RetrievalNormalizedDCG()
>>> print(ndcg(preds, target, indexes=indexes))
tensor(0.8467)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/torchmetrics/retrieval/base.py`
Content:
```
1 # Copyright The Lightning team.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from abc import ABC, abstractmethod
15 from typing import Any, Callable, List, Optional, Union
16 
17 import torch
18 from torch import Tensor, tensor
19 from typing_extensions import Literal
20 
21 from torchmetrics import Metric
22 from torchmetrics.utilities.checks import _check_retrieval_inputs
23 from torchmetrics.utilities.data import _flexible_bincount, dim_zero_cat
24 
25 
26 def _retrieval_aggregate(
27     values: Tensor,
28     aggregation: Union[Literal["mean", "median", "min", "max"], Callable] = "mean",
29     dim: Optional[int] = None,
30 ) -> Tensor:
31     """Aggregate the final retrieval values into a single value."""
32     if aggregation == "mean":
33         return values.mean() if dim is None else values.mean(dim=dim)
34     if aggregation == "median":
35         return values.median() if dim is None else values.median(dim=dim).values
36     if aggregation == "min":
37         return values.min() if dim is None else values.min(dim=dim).values
38     if aggregation:
39         return values.max() if dim is None else values.max(dim=dim).values
40     return aggregation(values, dim=dim)
41 
42 
43 class RetrievalMetric(Metric, ABC):
44     """Works with binary target data. Accepts float predictions from a model output.
45 
46     As input to ``forward`` and ``update`` the metric accepts the following input:
47 
48     - ``preds`` (:class:`~torch.Tensor`): A float tensor of shape ``(N, ...)``
49     - ``target`` (:class:`~torch.Tensor`): A long or bool tensor of shape ``(N, ...)``
50     - ``indexes`` (:class:`~torch.Tensor`): A long tensor of shape ``(N, ...)`` which indicate to which query a
51       prediction belongs
52 
53     .. note:: ``indexes``, ``preds`` and ``target`` must have the same dimension and will be flatten
54     to single dimension once provided.
55 
56     .. note::
57         Predictions will be first grouped by ``indexes`` and then the real metric, defined by overriding
58         the `_metric` method, will be computed as the mean of the scores over each query.
59 
60     As output to ``forward`` and ``compute`` the metric returns the following output:
61 
62     - ``metric`` (:class:`~torch.Tensor`): A tensor as computed by ``_metric`` if the number of positive targets is
63       at least 1, otherwise behave as specified by ``self.empty_target_action``.
64 
65     Args:
66         empty_target_action:
67             Specify what to do with queries that do not have at least a positive
68             or negative (depend on metric) target. Choose from:
69 
70             - ``'neg'``: those queries count as ``0.0`` (default)
71             - ``'pos'``: those queries count as ``1.0``
72             - ``'skip'``: skip those queries; if all queries are skipped, ``0.0`` is returned
73             - ``'error'``: raise a ``ValueError``
74 
75         ignore_index:
76             Ignore predictions where the target is equal to this number.
77         aggregation:
78             Specify how to aggregate over indexes. Can either a custom callable function that takes in a single tensor
79             and returns a scalar value or one of the following strings:
80 
81             - ``'mean'``: average value is returned
82             - ``'median'``: median value is returned
83             - ``'max'``: max value is returned
84             - ``'min'``: min value is returned
85 
86         kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.
87 
88     Raises:
89         ValueError:
90             If ``empty_target_action`` is not one of ``error``, ``skip``, ``neg`` or ``pos``.
91         ValueError:
92             If ``ignore_index`` is not `None` or an integer.
93 
94     """
95 
96     is_differentiable: bool = False
97     higher_is_better: bool = True
98     full_state_update: bool = False
99 
100     indexes: List[Tensor]
101     preds: List[Tensor]
102     target: List[Tensor]
103 
104     def __init__(
105         self,
106         empty_target_action: str = "neg",
107         ignore_index: Optional[int] = None,
108         aggregation: Union[Literal["mean", "median", "min", "max"], Callable] = "mean",
109         **kwargs: Any,
110     ) -> None:
111         super().__init__(**kwargs)
112         self.allow_non_binary_target = False
113 
114         empty_target_action_options = ("error", "skip", "neg", "pos")
115         if empty_target_action not in empty_target_action_options:
116             raise ValueError(f"Argument `empty_target_action` received a wrong value `{empty_target_action}`.")
117         self.empty_target_action = empty_target_action
118 
119         if ignore_index is not None and not isinstance(ignore_index, int):
120             raise ValueError("Argument `ignore_index` must be an integer or None.")
121         self.ignore_index = ignore_index
122 
123         if not (aggregation in ("mean", "median", "min", "max") or callable(aggregation)):
124             raise ValueError(
125                 "Argument `aggregation` must be one of `mean`, `median`, `min`, `max` or a custom callable function"
126                 f"which takes tensor of values, but got {aggregation}."
127             )
128         self.aggregation = aggregation
129 
130         self.add_state("indexes", default=[], dist_reduce_fx=None)
131         self.add_state("preds", default=[], dist_reduce_fx=None)
132         self.add_state("target", default=[], dist_reduce_fx=None)
133 
134     def update(self, preds: Tensor, target: Tensor, indexes: Tensor) -> None:
135         """Check shape, check and convert dtypes, flatten and add to accumulators."""
136         if indexes is None:
137             raise ValueError("Argument `indexes` cannot be None")
138 
139         indexes, preds, target = _check_retrieval_inputs(
140             indexes, preds, target, allow_non_binary_target=self.allow_non_binary_target, ignore_index=self.ignore_index
141         )
142 
143         self.indexes.append(indexes)
144         self.preds.append(preds)
145         self.target.append(target)
146 
147     def compute(self) -> Tensor:
148         """First concat state ``indexes``, ``preds`` and ``target`` since they were stored as lists.
149 
150         After that, compute list of groups that will help in keeping together predictions about the same query. Finally,
151         for each group compute the ``_metric`` if the number of positive targets is at least 1, otherwise behave as
152         specified by ``self.empty_target_action``.
153 
154         """
155         indexes = dim_zero_cat(self.indexes)
156         preds = dim_zero_cat(self.preds)
157         target = dim_zero_cat(self.target)
158 
159         indexes, indices = torch.sort(indexes)
160         preds = preds[indices]
161         target = target[indices]
162 
163         split_sizes = _flexible_bincount(indexes).detach().cpu().tolist()
164 
165         res = []
166         for mini_preds, mini_target in zip(
167             torch.split(preds, split_sizes, dim=0), torch.split(target, split_sizes, dim=0)
168         ):
169             if not mini_target.sum():
170                 if self.empty_target_action == "error":
171                     raise ValueError("`compute` method was provided with a query with no positive target.")
172                 if self.empty_target_action == "pos":
173                     res.append(tensor(1.0))
174                 elif self.empty_target_action == "neg":
175                     res.append(tensor(0.0))
176             else:
177                 # ensure list contains only float tensors
178                 res.append(self._metric(mini_preds, mini_target))
179 
180         if res:
181             return _retrieval_aggregate(torch.stack([x.to(preds) for x in res]), self.aggregation)
182         return tensor(0.0).to(preds)
183 
184     @abstractmethod
185     def _metric(self, preds: Tensor, target: Tensor) -> Tensor:
186         """Compute a metric over a predictions and target of a single group.
187 
188         This method should be overridden by subclasses.
189 
190         """
191
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/torchmetrics/retrieval/base.py b/src/torchmetrics/retrieval/base.py
--- a/src/torchmetrics/retrieval/base.py
+++ b/src/torchmetrics/retrieval/base.py
@@ -35,7 +35,7 @@
         return values.median() if dim is None else values.median(dim=dim).values
     if aggregation == "min":
         return values.min() if dim is None else values.min(dim=dim).values
-    if aggregation:
+    if aggregation == "max":
         return values.max() if dim is None else values.max(dim=dim).values
     return aggregation(values, dim=dim)

{"golden_diff": "diff --git a/src/torchmetrics/retrieval/base.py b/src/torchmetrics/retrieval/base.py\n--- a/src/torchmetrics/retrieval/base.py\n+++ b/src/torchmetrics/retrieval/base.py\n@@ -35,7 +35,7 @@\n         return values.median() if dim is None else values.median(dim=dim).values\n     if aggregation == \"min\":\n         return values.min() if dim is None else values.min(dim=dim).values\n-    if aggregation:\n+    if aggregation == \"max\":\n         return values.max() if dim is None else values.max(dim=dim).values\n     return aggregation(values, dim=dim)\n", "issue": "Custom callable is ignored in retrieval metric aggregation\n## \ud83d\udc1b Bug\r\n\r\nWhen passing a custom aggregation to any `RetrievalMetric`, the callable is ignored. There is a bug in the retrieval aggregation function that defaults to using the maximum of the values by default https://github.com/Lightning-AI/torchmetrics/blob/1a2f406da17a01c13ce1add83835e097460cbce3/src/torchmetrics/retrieval/base.py#L38\r\n\r\n### To Reproduce\r\n\r\nThe following custom aggregation should output the tensor of values without aggregation but returns 1, the max of the values.\r\n\r\n```\r\n>>> from torchmetrics.retrieval import RetrievalNormalizedDCG\r\n>>> indexes = tensor([0, 0, 0, 1, 1, 1, 1])\r\n>>> preds = tensor([0.2, 0.3, 0.5, 0.1, 0.3, 0.5, 0.2])\r\n>>> target = tensor([False, False, True, False, True, False, True])\r\n>>> ndcg = RetrievalNormalizedDCG(aggregation=lambda x, dim: x)\r\n>>> print(ndcg(preds, target, indexes=indexes))\r\ntensor(1.)\r\n>>> ndcg = RetrievalNormalizedDCG(aggregation=\"max\")\r\n>>> print(ndcg(preds, target, indexes=indexes))\r\ntensor(1.)\r\n>>> ndcg = RetrievalNormalizedDCG()\r\n>>> print(ndcg(preds, target, indexes=indexes))\r\ntensor(0.8467)\r\n```\n", "before_files": [{"content": "# Copyright The Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Callable, List, Optional, Union\n\nimport torch\nfrom torch import Tensor, tensor\nfrom typing_extensions import Literal\n\nfrom torchmetrics import Metric\nfrom torchmetrics.utilities.checks import _check_retrieval_inputs\nfrom torchmetrics.utilities.data import _flexible_bincount, dim_zero_cat\n\n\ndef _retrieval_aggregate(\n    values: Tensor,\n    aggregation: Union[Literal[\"mean\", \"median\", \"min\", \"max\"], Callable] = \"mean\",\n    dim: Optional[int] = None,\n) -> Tensor:\n    \"\"\"Aggregate the final retrieval values into a single value.\"\"\"\n    if aggregation == \"mean\":\n        return values.mean() if dim is None else values.mean(dim=dim)\n    if aggregation == \"median\":\n        return values.median() if dim is None else values.median(dim=dim).values\n    if aggregation == \"min\":\n        return values.min() if dim is None else values.min(dim=dim).values\n    if aggregation:\n        return values.max() if dim is None else values.max(dim=dim).values\n    return aggregation(values, dim=dim)\n\n\nclass RetrievalMetric(Metric, ABC):\n    \"\"\"Works with binary target data. Accepts float predictions from a model output.\n\n    As input to ``forward`` and ``update`` the metric accepts the following input:\n\n    - ``preds`` (:class:`~torch.Tensor`): A float tensor of shape ``(N, ...)``\n    - ``target`` (:class:`~torch.Tensor`): A long or bool tensor of shape ``(N, ...)``\n    - ``indexes`` (:class:`~torch.Tensor`): A long tensor of shape ``(N, ...)`` which indicate to which query a\n      prediction belongs\n\n    .. note:: ``indexes``, ``preds`` and ``target`` must have the same dimension and will be flatten\n    to single dimension once provided.\n\n    .. note::\n        Predictions will be first grouped by ``indexes`` and then the real metric, defined by overriding\n        the `_metric` method, will be computed as the mean of the scores over each query.\n\n    As output to ``forward`` and ``compute`` the metric returns the following output:\n\n    - ``metric`` (:class:`~torch.Tensor`): A tensor as computed by ``_metric`` if the number of positive targets is\n      at least 1, otherwise behave as specified by ``self.empty_target_action``.\n\n    Args:\n        empty_target_action:\n            Specify what to do with queries that do not have at least a positive\n            or negative (depend on metric) target. Choose from:\n\n            - ``'neg'``: those queries count as ``0.0`` (default)\n            - ``'pos'``: those queries count as ``1.0``\n            - ``'skip'``: skip those queries; if all queries are skipped, ``0.0`` is returned\n            - ``'error'``: raise a ``ValueError``\n\n        ignore_index:\n            Ignore predictions where the target is equal to this number.\n        aggregation:\n            Specify how to aggregate over indexes. Can either a custom callable function that takes in a single tensor\n            and returns a scalar value or one of the following strings:\n\n            - ``'mean'``: average value is returned\n            - ``'median'``: median value is returned\n            - ``'max'``: max value is returned\n            - ``'min'``: min value is returned\n\n        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.\n\n    Raises:\n        ValueError:\n            If ``empty_target_action`` is not one of ``error``, ``skip``, ``neg`` or ``pos``.\n        ValueError:\n            If ``ignore_index`` is not `None` or an integer.\n\n    \"\"\"\n\n    is_differentiable: bool = False\n    higher_is_better: bool = True\n    full_state_update: bool = False\n\n    indexes: List[Tensor]\n    preds: List[Tensor]\n    target: List[Tensor]\n\n    def __init__(\n        self,\n        empty_target_action: str = \"neg\",\n        ignore_index: Optional[int] = None,\n        aggregation: Union[Literal[\"mean\", \"median\", \"min\", \"max\"], Callable] = \"mean\",\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n        self.allow_non_binary_target = False\n\n        empty_target_action_options = (\"error\", \"skip\", \"neg\", \"pos\")\n        if empty_target_action not in empty_target_action_options:\n            raise ValueError(f\"Argument `empty_target_action` received a wrong value `{empty_target_action}`.\")\n        self.empty_target_action = empty_target_action\n\n        if ignore_index is not None and not isinstance(ignore_index, int):\n            raise ValueError(\"Argument `ignore_index` must be an integer or None.\")\n        self.ignore_index = ignore_index\n\n        if not (aggregation in (\"mean\", \"median\", \"min\", \"max\") or callable(aggregation)):\n            raise ValueError(\n                \"Argument `aggregation` must be one of `mean`, `median`, `min`, `max` or a custom callable function\"\n                f\"which takes tensor of values, but got {aggregation}.\"\n            )\n        self.aggregation = aggregation\n\n        self.add_state(\"indexes\", default=[], dist_reduce_fx=None)\n        self.add_state(\"preds\", default=[], dist_reduce_fx=None)\n        self.add_state(\"target\", default=[], dist_reduce_fx=None)\n\n    def update(self, preds: Tensor, target: Tensor, indexes: Tensor) -> None:\n        \"\"\"Check shape, check and convert dtypes, flatten and add to accumulators.\"\"\"\n        if indexes is None:\n            raise ValueError(\"Argument `indexes` cannot be None\")\n\n        indexes, preds, target = _check_retrieval_inputs(\n            indexes, preds, target, allow_non_binary_target=self.allow_non_binary_target, ignore_index=self.ignore_index\n        )\n\n        self.indexes.append(indexes)\n        self.preds.append(preds)\n        self.target.append(target)\n\n    def compute(self) -> Tensor:\n        \"\"\"First concat state ``indexes``, ``preds`` and ``target`` since they were stored as lists.\n\n        After that, compute list of groups that will help in keeping together predictions about the same query. Finally,\n        for each group compute the ``_metric`` if the number of positive targets is at least 1, otherwise behave as\n        specified by ``self.empty_target_action``.\n\n        \"\"\"\n        indexes = dim_zero_cat(self.indexes)\n        preds = dim_zero_cat(self.preds)\n        target = dim_zero_cat(self.target)\n\n        indexes, indices = torch.sort(indexes)\n        preds = preds[indices]\n        target = target[indices]\n\n        split_sizes = _flexible_bincount(indexes).detach().cpu().tolist()\n\n        res = []\n        for mini_preds, mini_target in zip(\n            torch.split(preds, split_sizes, dim=0), torch.split(target, split_sizes, dim=0)\n        ):\n            if not mini_target.sum():\n                if self.empty_target_action == \"error\":\n                    raise ValueError(\"`compute` method was provided with a query with no positive target.\")\n                if self.empty_target_action == \"pos\":\n                    res.append(tensor(1.0))\n                elif self.empty_target_action == \"neg\":\n                    res.append(tensor(0.0))\n            else:\n                # ensure list contains only float tensors\n                res.append(self._metric(mini_preds, mini_target))\n\n        if res:\n            return _retrieval_aggregate(torch.stack([x.to(preds) for x in res]), self.aggregation)\n        return tensor(0.0).to(preds)\n\n    @abstractmethod\n    def _metric(self, preds: Tensor, target: Tensor) -> Tensor:\n        \"\"\"Compute a metric over a predictions and target of a single group.\n\n        This method should be overridden by subclasses.\n\n        \"\"\"\n", "path": "src/torchmetrics/retrieval/base.py"}], "after_files": [{"content": "# Copyright The Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Callable, List, Optional, Union\n\nimport torch\nfrom torch import Tensor, tensor\nfrom typing_extensions import Literal\n\nfrom torchmetrics import Metric\nfrom torchmetrics.utilities.checks import _check_retrieval_inputs\nfrom torchmetrics.utilities.data import _flexible_bincount, dim_zero_cat\n\n\ndef _retrieval_aggregate(\n    values: Tensor,\n    aggregation: Union[Literal[\"mean\", \"median\", \"min\", \"max\"], Callable] = \"mean\",\n    dim: Optional[int] = None,\n) -> Tensor:\n    \"\"\"Aggregate the final retrieval values into a single value.\"\"\"\n    if aggregation == \"mean\":\n        return values.mean() if dim is None else values.mean(dim=dim)\n    if aggregation == \"median\":\n        return values.median() if dim is None else values.median(dim=dim).values\n    if aggregation == \"min\":\n        return values.min() if dim is None else values.min(dim=dim).values\n    if aggregation == \"max\":\n        return values.max() if dim is None else values.max(dim=dim).values\n    return aggregation(values, dim=dim)\n\n\nclass RetrievalMetric(Metric, ABC):\n    \"\"\"Works with binary target data. Accepts float predictions from a model output.\n\n    As input to ``forward`` and ``update`` the metric accepts the following input:\n\n    - ``preds`` (:class:`~torch.Tensor`): A float tensor of shape ``(N, ...)``\n    - ``target`` (:class:`~torch.Tensor`): A long or bool tensor of shape ``(N, ...)``\n    - ``indexes`` (:class:`~torch.Tensor`): A long tensor of shape ``(N, ...)`` which indicate to which query a\n      prediction belongs\n\n    .. note:: ``indexes``, ``preds`` and ``target`` must have the same dimension and will be flatten\n    to single dimension once provided.\n\n    .. note::\n        Predictions will be first grouped by ``indexes`` and then the real metric, defined by overriding\n        the `_metric` method, will be computed as the mean of the scores over each query.\n\n    As output to ``forward`` and ``compute`` the metric returns the following output:\n\n    - ``metric`` (:class:`~torch.Tensor`): A tensor as computed by ``_metric`` if the number of positive targets is\n      at least 1, otherwise behave as specified by ``self.empty_target_action``.\n\n    Args:\n        empty_target_action:\n            Specify what to do with queries that do not have at least a positive\n            or negative (depend on metric) target. Choose from:\n\n            - ``'neg'``: those queries count as ``0.0`` (default)\n            - ``'pos'``: those queries count as ``1.0``\n            - ``'skip'``: skip those queries; if all queries are skipped, ``0.0`` is returned\n            - ``'error'``: raise a ``ValueError``\n\n        ignore_index:\n            Ignore predictions where the target is equal to this number.\n        aggregation:\n            Specify how to aggregate over indexes. Can either a custom callable function that takes in a single tensor\n            and returns a scalar value or one of the following strings:\n\n            - ``'mean'``: average value is returned\n            - ``'median'``: median value is returned\n            - ``'max'``: max value is returned\n            - ``'min'``: min value is returned\n\n        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.\n\n    Raises:\n        ValueError:\n            If ``empty_target_action`` is not one of ``error``, ``skip``, ``neg`` or ``pos``.\n        ValueError:\n            If ``ignore_index`` is not `None` or an integer.\n\n    \"\"\"\n\n    is_differentiable: bool = False\n    higher_is_better: bool = True\n    full_state_update: bool = False\n\n    indexes: List[Tensor]\n    preds: List[Tensor]\n    target: List[Tensor]\n\n    def __init__(\n        self,\n        empty_target_action: str = \"neg\",\n        ignore_index: Optional[int] = None,\n        aggregation: Union[Literal[\"mean\", \"median\", \"min\", \"max\"], Callable] = \"mean\",\n        **kwargs: Any,\n    ) -> None:\n        super().__init__(**kwargs)\n        self.allow_non_binary_target = False\n\n        empty_target_action_options = (\"error\", \"skip\", \"neg\", \"pos\")\n        if empty_target_action not in empty_target_action_options:\n            raise ValueError(f\"Argument `empty_target_action` received a wrong value `{empty_target_action}`.\")\n        self.empty_target_action = empty_target_action\n\n        if ignore_index is not None and not isinstance(ignore_index, int):\n            raise ValueError(\"Argument `ignore_index` must be an integer or None.\")\n        self.ignore_index = ignore_index\n\n        if not (aggregation in (\"mean\", \"median\", \"min\", \"max\") or callable(aggregation)):\n            raise ValueError(\n                \"Argument `aggregation` must be one of `mean`, `median`, `min`, `max` or a custom callable function\"\n                f\"which takes tensor of values, but got {aggregation}.\"\n            )\n        self.aggregation = aggregation\n\n        self.add_state(\"indexes\", default=[], dist_reduce_fx=None)\n        self.add_state(\"preds\", default=[], dist_reduce_fx=None)\n        self.add_state(\"target\", default=[], dist_reduce_fx=None)\n\n    def update(self, preds: Tensor, target: Tensor, indexes: Tensor) -> None:\n        \"\"\"Check shape, check and convert dtypes, flatten and add to accumulators.\"\"\"\n        if indexes is None:\n            raise ValueError(\"Argument `indexes` cannot be None\")\n\n        indexes, preds, target = _check_retrieval_inputs(\n            indexes, preds, target, allow_non_binary_target=self.allow_non_binary_target, ignore_index=self.ignore_index\n        )\n\n        self.indexes.append(indexes)\n        self.preds.append(preds)\n        self.target.append(target)\n\n    def compute(self) -> Tensor:\n        \"\"\"First concat state ``indexes``, ``preds`` and ``target`` since they were stored as lists.\n\n        After that, compute list of groups that will help in keeping together predictions about the same query. Finally,\n        for each group compute the ``_metric`` if the number of positive targets is at least 1, otherwise behave as\n        specified by ``self.empty_target_action``.\n\n        \"\"\"\n        indexes = dim_zero_cat(self.indexes)\n        preds = dim_zero_cat(self.preds)\n        target = dim_zero_cat(self.target)\n\n        indexes, indices = torch.sort(indexes)\n        preds = preds[indices]\n        target = target[indices]\n\n        split_sizes = _flexible_bincount(indexes).detach().cpu().tolist()\n\n        res = []\n        for mini_preds, mini_target in zip(\n            torch.split(preds, split_sizes, dim=0), torch.split(target, split_sizes, dim=0)\n        ):\n            if not mini_target.sum():\n                if self.empty_target_action == \"error\":\n                    raise ValueError(\"`compute` method was provided with a query with no positive target.\")\n                if self.empty_target_action == \"pos\":\n                    res.append(tensor(1.0))\n                elif self.empty_target_action == \"neg\":\n                    res.append(tensor(0.0))\n            else:\n                # ensure list contains only float tensors\n                res.append(self._metric(mini_preds, mini_target))\n\n        if res:\n            return _retrieval_aggregate(torch.stack([x.to(preds) for x in res]), self.aggregation)\n        return tensor(0.0).to(preds)\n\n    @abstractmethod\n    def _metric(self, preds: Tensor, target: Tensor) -> Tensor:\n        \"\"\"Compute a metric over a predictions and target of a single group.\n\n        This method should be overridden by subclasses.\n\n        \"\"\"\n", "path": "src/torchmetrics/retrieval/base.py"}]}