prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Strange behaviour with the to_dense_adj function
  ### 🐛 Describe the bug
  
  While using to_dense_adj with edge attributes, I observed that the `idx` values generated are not unique ((line 94 in to_dense_adj.py). As such, the scatter_add function sums up overlapping values and generating an output greater than the original range of edge_attr values.
  
  ![image](https://github.com/pyg-team/pytorch_geometric/assets/16525717/be9029d6-f104-4577-bb5a-62c097c1ed9a)
  
  The required tensors can be downloaded from [here](https://filesender.switch.ch/filesender2/download.php?token=d4b1599a-6eee-4b06-8640-be16fb784ab5&files_ids=490595)
  
  Any help or insights are highly appreciated. 
  
  Thanks,
  Chinmay
  
  ### Environment
  
  * PyG version:2.3.1
  * PyTorch version: 2.0.1+cu117
  * OS: Ubuntu 20.04
  * Python version:3.8.10
  * CUDA/cuDNN version:11.7
  * How you installed PyTorch and PyG (`conda`, `pip`, source):pip
  * Any other relevant information (*e.g.*, version of `torch-scatter`):
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `torch_geometric/utils/to_dense_adj.py`
  Content:
  ```
  1 from typing import Optional
  2 
  3 import torch
  4 from torch import Tensor
  5 
  6 from torch_geometric.typing import OptTensor
  7 from torch_geometric.utils import cumsum, scatter
  8 
  9 
  10 def to_dense_adj(
  11     edge_index: Tensor,
  12     batch: OptTensor = None,
  13     edge_attr: OptTensor = None,
  14     max_num_nodes: Optional[int] = None,
  15     batch_size: Optional[int] = None,
  16 ) -> Tensor:
  17     r"""Converts batched sparse adjacency matrices given by edge indices and
  18     edge attributes to a single dense batched adjacency matrix.
  19 
  20     Args:
  21         edge_index (LongTensor): The edge indices.
  22         batch (LongTensor, optional): Batch vector
  23             :math:`\mathbf{b} \in {\{ 0, \ldots, B-1\}}^N`, which assigns each
  24             node to a specific example. (default: :obj:`None`)
  25         edge_attr (Tensor, optional): Edge weights or multi-dimensional edge
  26             features. (default: :obj:`None`)
  27         max_num_nodes (int, optional): The size of the output node dimension.
  28             (default: :obj:`None`)
  29         batch_size (int, optional) The batch size. (default: :obj:`None`)
  30 
  31     :rtype: :class:`Tensor`
  32 
  33     Examples:
  34 
  35         >>> edge_index = torch.tensor([[0, 0, 1, 2, 3],
  36         ...                            [0, 1, 0, 3, 0]])
  37         >>> batch = torch.tensor([0, 0, 1, 1])
  38         >>> to_dense_adj(edge_index, batch)
  39         tensor([[[1., 1.],
  40                 [1., 0.]],
  41                 [[0., 1.],
  42                 [1., 0.]]])
  43 
  44         >>> to_dense_adj(edge_index, batch, max_num_nodes=4)
  45         tensor([[[1., 1., 0., 0.],
  46                 [1., 0., 0., 0.],
  47                 [0., 0., 0., 0.],
  48                 [0., 0., 0., 0.]],
  49                 [[0., 1., 0., 0.],
  50                 [1., 0., 0., 0.],
  51                 [0., 0., 0., 0.],
  52                 [0., 0., 0., 0.]]])
  53 
  54         >>> edge_attr = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])
  55         >>> to_dense_adj(edge_index, batch, edge_attr)
  56         tensor([[[1., 2.],
  57                 [3., 0.]],
  58                 [[0., 4.],
  59                 [5., 0.]]])
  60     """
  61     if batch is None:
  62         num_nodes = int(edge_index.max()) + 1 if edge_index.numel() > 0 else 0
  63         batch = edge_index.new_zeros(num_nodes)
  64 
  65     if batch_size is None:
  66         batch_size = int(batch.max()) + 1 if batch.numel() > 0 else 1
  67 
  68     one = batch.new_ones(batch.size(0))
  69     num_nodes = scatter(one, batch, dim=0, dim_size=batch_size, reduce='sum')
  70     cum_nodes = cumsum(num_nodes)
  71 
  72     idx0 = batch[edge_index[0]]
  73     idx1 = edge_index[0] - cum_nodes[batch][edge_index[0]]
  74     idx2 = edge_index[1] - cum_nodes[batch][edge_index[1]]
  75 
  76     if max_num_nodes is None:
  77         max_num_nodes = int(num_nodes.max())
  78 
  79     elif ((idx1.numel() > 0 and idx1.max() >= max_num_nodes)
  80           or (idx2.numel() > 0 and idx2.max() >= max_num_nodes)):
  81         mask = (idx1 < max_num_nodes) & (idx2 < max_num_nodes)
  82         idx0 = idx0[mask]
  83         idx1 = idx1[mask]
  84         idx2 = idx2[mask]
  85         edge_attr = None if edge_attr is None else edge_attr[mask]
  86 
  87     if edge_attr is None:
  88         edge_attr = torch.ones(idx0.numel(), device=edge_index.device)
  89 
  90     size = [batch_size, max_num_nodes, max_num_nodes]
  91     size += list(edge_attr.size())[1:]
  92     flattened_size = batch_size * max_num_nodes * max_num_nodes
  93 
  94     idx = idx0 * max_num_nodes * max_num_nodes + idx1 * max_num_nodes + idx2
  95     adj = scatter(edge_attr, idx, dim=0, dim_size=flattened_size, reduce='sum')
  96     adj = adj.view(size)
  97 
  98     return adj
  99
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/torch_geometric/utils/to_dense_adj.py b/torch_geometric/utils/to_dense_adj.py
  --- a/torch_geometric/utils/to_dense_adj.py
  +++ b/torch_geometric/utils/to_dense_adj.py
  @@ -23,7 +23,10 @@
               :math:`\mathbf{b} \in {\{ 0, \ldots, B-1\}}^N`, which assigns each
               node to a specific example. (default: :obj:`None`)
           edge_attr (Tensor, optional): Edge weights or multi-dimensional edge
  -            features. (default: :obj:`None`)
  +            features.
  +            If :obj:`edge_index` contains duplicated edges, the dense adjacency
  +            matrix output holds the summed up entries of :obj:`edge_attr` for
  +            duplicated edges. (default: :obj:`None`)
           max_num_nodes (int, optional): The size of the output node dimension.
               (default: :obj:`None`)
           batch_size (int, optional) The batch size. (default: :obj:`None`)
  
verification_info: {"golden_diff": "diff --git a/torch_geometric/utils/to_dense_adj.py b/torch_geometric/utils/to_dense_adj.py\n--- a/torch_geometric/utils/to_dense_adj.py\n+++ b/torch_geometric/utils/to_dense_adj.py\n@@ -23,7 +23,10 @@\n             :math:`\\mathbf{b} \\in {\\{ 0, \\ldots, B-1\\}}^N`, which assigns each\n             node to a specific example. (default: :obj:`None`)\n         edge_attr (Tensor, optional): Edge weights or multi-dimensional edge\n-            features. (default: :obj:`None`)\n+            features.\n+            If :obj:`edge_index` contains duplicated edges, the dense adjacency\n+            matrix output holds the summed up entries of :obj:`edge_attr` for\n+            duplicated edges. (default: :obj:`None`)\n         max_num_nodes (int, optional): The size of the output node dimension.\n             (default: :obj:`None`)\n         batch_size (int, optional) The batch size. (default: :obj:`None`)\n", "issue": "Strange behaviour with the to_dense_adj function\n### \ud83d\udc1b Describe the bug\n\nWhile using to_dense_adj with edge attributes, I observed that the `idx` values generated are not unique ((line 94 in to_dense_adj.py). As such, the scatter_add function sums up overlapping values and generating an output greater than the original range of edge_attr values.\r\n\r\n![image](https://github.com/pyg-team/pytorch_geometric/assets/16525717/be9029d6-f104-4577-bb5a-62c097c1ed9a)\r\n\r\nThe required tensors can be downloaded from [here](https://filesender.switch.ch/filesender2/download.php?token=d4b1599a-6eee-4b06-8640-be16fb784ab5&files_ids=490595)\r\n\r\nAny help or insights are highly appreciated. \r\n\r\nThanks,\r\nChinmay\n\n### Environment\n\n* PyG version:2.3.1\r\n* PyTorch version: 2.0.1+cu117\r\n* OS: Ubuntu 20.04\r\n* Python version:3.8.10\r\n* CUDA/cuDNN version:11.7\r\n* How you installed PyTorch and PyG (`conda`, `pip`, source):pip\r\n* Any other relevant information (*e.g.*, version of `torch-scatter`):\r\n\n", "before_files": [{"content": "from typing import Optional\n\nimport torch\nfrom torch import Tensor\n\nfrom torch_geometric.typing import OptTensor\nfrom torch_geometric.utils import cumsum, scatter\n\n\ndef to_dense_adj(\n    edge_index: Tensor,\n    batch: OptTensor = None,\n    edge_attr: OptTensor = None,\n    max_num_nodes: Optional[int] = None,\n    batch_size: Optional[int] = None,\n) -> Tensor:\n    r\"\"\"Converts batched sparse adjacency matrices given by edge indices and\n    edge attributes to a single dense batched adjacency matrix.\n\n    Args:\n        edge_index (LongTensor): The edge indices.\n        batch (LongTensor, optional): Batch vector\n            :math:`\\mathbf{b} \\in {\\{ 0, \\ldots, B-1\\}}^N`, which assigns each\n            node to a specific example. (default: :obj:`None`)\n        edge_attr (Tensor, optional): Edge weights or multi-dimensional edge\n            features. (default: :obj:`None`)\n        max_num_nodes (int, optional): The size of the output node dimension.\n            (default: :obj:`None`)\n        batch_size (int, optional) The batch size. (default: :obj:`None`)\n\n    :rtype: :class:`Tensor`\n\n    Examples:\n\n        >>> edge_index = torch.tensor([[0, 0, 1, 2, 3],\n        ...                            [0, 1, 0, 3, 0]])\n        >>> batch = torch.tensor([0, 0, 1, 1])\n        >>> to_dense_adj(edge_index, batch)\n        tensor([[[1., 1.],\n                [1., 0.]],\n                [[0., 1.],\n                [1., 0.]]])\n\n        >>> to_dense_adj(edge_index, batch, max_num_nodes=4)\n        tensor([[[1., 1., 0., 0.],\n                [1., 0., 0., 0.],\n                [0., 0., 0., 0.],\n                [0., 0., 0., 0.]],\n                [[0., 1., 0., 0.],\n                [1., 0., 0., 0.],\n                [0., 0., 0., 0.],\n                [0., 0., 0., 0.]]])\n\n        >>> edge_attr = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])\n        >>> to_dense_adj(edge_index, batch, edge_attr)\n        tensor([[[1., 2.],\n                [3., 0.]],\n                [[0., 4.],\n                [5., 0.]]])\n    \"\"\"\n    if batch is None:\n        num_nodes = int(edge_index.max()) + 1 if edge_index.numel() > 0 else 0\n        batch = edge_index.new_zeros(num_nodes)\n\n    if batch_size is None:\n        batch_size = int(batch.max()) + 1 if batch.numel() > 0 else 1\n\n    one = batch.new_ones(batch.size(0))\n    num_nodes = scatter(one, batch, dim=0, dim_size=batch_size, reduce='sum')\n    cum_nodes = cumsum(num_nodes)\n\n    idx0 = batch[edge_index[0]]\n    idx1 = edge_index[0] - cum_nodes[batch][edge_index[0]]\n    idx2 = edge_index[1] - cum_nodes[batch][edge_index[1]]\n\n    if max_num_nodes is None:\n        max_num_nodes = int(num_nodes.max())\n\n    elif ((idx1.numel() > 0 and idx1.max() >= max_num_nodes)\n          or (idx2.numel() > 0 and idx2.max() >= max_num_nodes)):\n        mask = (idx1 < max_num_nodes) & (idx2 < max_num_nodes)\n        idx0 = idx0[mask]\n        idx1 = idx1[mask]\n        idx2 = idx2[mask]\n        edge_attr = None if edge_attr is None else edge_attr[mask]\n\n    if edge_attr is None:\n        edge_attr = torch.ones(idx0.numel(), device=edge_index.device)\n\n    size = [batch_size, max_num_nodes, max_num_nodes]\n    size += list(edge_attr.size())[1:]\n    flattened_size = batch_size * max_num_nodes * max_num_nodes\n\n    idx = idx0 * max_num_nodes * max_num_nodes + idx1 * max_num_nodes + idx2\n    adj = scatter(edge_attr, idx, dim=0, dim_size=flattened_size, reduce='sum')\n    adj = adj.view(size)\n\n    return adj\n", "path": "torch_geometric/utils/to_dense_adj.py"}], "after_files": [{"content": "from typing import Optional\n\nimport torch\nfrom torch import Tensor\n\nfrom torch_geometric.typing import OptTensor\nfrom torch_geometric.utils import cumsum, scatter\n\n\ndef to_dense_adj(\n    edge_index: Tensor,\n    batch: OptTensor = None,\n    edge_attr: OptTensor = None,\n    max_num_nodes: Optional[int] = None,\n    batch_size: Optional[int] = None,\n) -> Tensor:\n    r\"\"\"Converts batched sparse adjacency matrices given by edge indices and\n    edge attributes to a single dense batched adjacency matrix.\n\n    Args:\n        edge_index (LongTensor): The edge indices.\n        batch (LongTensor, optional): Batch vector\n            :math:`\\mathbf{b} \\in {\\{ 0, \\ldots, B-1\\}}^N`, which assigns each\n            node to a specific example. (default: :obj:`None`)\n        edge_attr (Tensor, optional): Edge weights or multi-dimensional edge\n            features.\n            If :obj:`edge_index` contains duplicated edges, the dense adjacency\n            matrix output holds the summed up entries of :obj:`edge_attr` for\n            duplicated edges. (default: :obj:`None`)\n        max_num_nodes (int, optional): The size of the output node dimension.\n            (default: :obj:`None`)\n        batch_size (int, optional) The batch size. (default: :obj:`None`)\n\n    :rtype: :class:`Tensor`\n\n    Examples:\n\n        >>> edge_index = torch.tensor([[0, 0, 1, 2, 3],\n        ...                            [0, 1, 0, 3, 0]])\n        >>> batch = torch.tensor([0, 0, 1, 1])\n        >>> to_dense_adj(edge_index, batch)\n        tensor([[[1., 1.],\n                [1., 0.]],\n                [[0., 1.],\n                [1., 0.]]])\n\n        >>> to_dense_adj(edge_index, batch, max_num_nodes=4)\n        tensor([[[1., 1., 0., 0.],\n                [1., 0., 0., 0.],\n                [0., 0., 0., 0.],\n                [0., 0., 0., 0.]],\n                [[0., 1., 0., 0.],\n                [1., 0., 0., 0.],\n                [0., 0., 0., 0.],\n                [0., 0., 0., 0.]]])\n\n        >>> edge_attr = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])\n        >>> to_dense_adj(edge_index, batch, edge_attr)\n        tensor([[[1., 2.],\n                [3., 0.]],\n                [[0., 4.],\n                [5., 0.]]])\n    \"\"\"\n    if batch is None:\n        num_nodes = int(edge_index.max()) + 1 if edge_index.numel() > 0 else 0\n        batch = edge_index.new_zeros(num_nodes)\n\n    if batch_size is None:\n        batch_size = int(batch.max()) + 1 if batch.numel() > 0 else 1\n\n    one = batch.new_ones(batch.size(0))\n    num_nodes = scatter(one, batch, dim=0, dim_size=batch_size, reduce='sum')\n    cum_nodes = cumsum(num_nodes)\n\n    idx0 = batch[edge_index[0]]\n    idx1 = edge_index[0] - cum_nodes[batch][edge_index[0]]\n    idx2 = edge_index[1] - cum_nodes[batch][edge_index[1]]\n\n    if max_num_nodes is None:\n        max_num_nodes = int(num_nodes.max())\n\n    elif ((idx1.numel() > 0 and idx1.max() >= max_num_nodes)\n          or (idx2.numel() > 0 and idx2.max() >= max_num_nodes)):\n        mask = (idx1 < max_num_nodes) & (idx2 < max_num_nodes)\n        idx0 = idx0[mask]\n        idx1 = idx1[mask]\n        idx2 = idx2[mask]\n        edge_attr = None if edge_attr is None else edge_attr[mask]\n\n    if edge_attr is None:\n        edge_attr = torch.ones(idx0.numel(), device=edge_index.device)\n\n    size = [batch_size, max_num_nodes, max_num_nodes]\n    size += list(edge_attr.size())[1:]\n    flattened_size = batch_size * max_num_nodes * max_num_nodes\n\n    idx = idx0 * max_num_nodes * max_num_nodes + idx1 * max_num_nodes + idx2\n    adj = scatter(edge_attr, idx, dim=0, dim_size=flattened_size, reduce='sum')\n    adj = adj.view(size)\n\n    return adj\n", "path": "torch_geometric/utils/to_dense_adj.py"}]}