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()

```

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`)

{"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"}]}