We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`test/transforms/test_add_positional_encoding.py::test_eigenvector_permutation_invariance` fails with AMD CPU
### 🐛 Describe the bug

The unit test added in #8087 fails with the error bellow on AMD CPU based systems.


```
NVIDIA_TF32_OVERRIDE=0 pytest -s --cov --cov-report=xml test/transforms/test_add_positional_encoding.py::test_eigenvector_permutation_invariance
```

Traceback:
```
======================================================================== FAILURES ========================================================================$
_________________________________________________________ test_eigenvector_permutation_invariance ________________________________________________________$

    def test_eigenvector_permutation_invariance():
        edge_index = torch.tensor([[0, 1, 0, 4, 1, 4, 2, 3, 3, 5],
                                   [1, 0, 4, 0, 4, 1, 3, 2, 5, 3]])
        data = Data(edge_index=edge_index, num_nodes=6)

        perm = torch.tensor([5, 4, 3, 2, 1, 0])
        transform = AddLaplacianEigenvectorPE(
            k=1,
            is_undirected=True,
            attr_name='x',
            v0=torch.arange(data.num_nodes),
        )
        out1 = transform(data)

        transform = AddLaplacianEigenvectorPE(
            k=1,
            is_undirected=True,
            attr_name='x',
            v0=perm,
        )
        out2 = transform(data.subgraph(perm))

        print(out1.x[perm].abs())
        print(out2.x.abs())

>       assert torch.allclose(out1.x[perm].abs(), out2.x.abs(), atol=1e-1)
E       assert False
E        +  where False = <built-in method allclose of type object at 0x7f2f94b318a0>(tensor([[0.1360],\n        [0.5556],\n        [0.1924],\n        [0.1
360],\n        [0.5556],\n        [0.5556]]), tensor([[0.2091],\n        [0.5245],\n        [0.2957],\n        [0.2091],\n        [0.5245],\n        [0.524
5]]), atol=0.1)
E        +    where <built-in method allclose of type object at 0x7f2f94b318a0> = torch.allclose
E        +    and   tensor([[0.1360],\n        [0.5556],\n        [0.1924],\n        [0.1360],\n        [0.5556],\n        [0.5556]]) = <built-in method ab
s of Tensor object at 0x7f2bc6e1e160>()
E        +      where <built-in method abs of Tensor object at 0x7f2bc6e1e160> = tensor([[ 0.1360],\n        [-0.5556],\n        [ 0.1924],\n        [ 0.13
60],\n        [-0.5556],\n        [-0.5556]]).abs
E        +    and   tensor([[0.2091],\n        [0.5245],\n        [0.2957],\n        [0.2091],\n        [0.5245],\n        [0.5245]]) = <built-in method ab
s of Tensor object at 0x7f2bc89d3470>()
E        +      where <built-in method abs of Tensor object at 0x7f2bc89d3470> = tensor([[ 0.2091],\n        [-0.5245],\n        [ 0.2957],\n        [ 0.20
91],\n        [-0.5245],\n        [-0.5245]]).abs
E        +        where tensor([[ 0.2091],\n        [-0.5245],\n        [ 0.2957],\n        [ 0.2091],\n        [-0.5245],\n        [-0.5245]]) = Data(edge
_index=[2, 10], num_nodes=6, x=[6, 1]).x
```

### Environment

* PyG version: 2.4.0 (built from source)
* PyTorch version: 2.1.0
* OS:  Ubuntu 22.04.3 LTS
* Python version: 3.10.12
* CUDA/cuDNN version: 12.2
* How you installed PyTorch and PyG (`conda`, `pip`, source): source

--- 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/transforms/add_positional_encoding.py`
Content:
```
1 from typing import Any, Optional
2 
3 import numpy as np
4 import torch
5 
6 from torch_geometric.data import Data
7 from torch_geometric.data.datapipes import functional_transform
8 from torch_geometric.transforms import BaseTransform
9 from torch_geometric.utils import (
10     get_laplacian,
11     get_self_loop_attr,
12     scatter,
13     to_edge_index,
14     to_scipy_sparse_matrix,
15     to_torch_csr_tensor,
16 )
17 
18 
19 def add_node_attr(data: Data, value: Any,
20                   attr_name: Optional[str] = None) -> Data:
21     # TODO Move to `BaseTransform`.
22     if attr_name is None:
23         if 'x' in data:
24             x = data.x.view(-1, 1) if data.x.dim() == 1 else data.x
25             data.x = torch.cat([x, value.to(x.device, x.dtype)], dim=-1)
26         else:
27             data.x = value
28     else:
29         data[attr_name] = value
30 
31     return data
32 
33 
34 @functional_transform('add_laplacian_eigenvector_pe')
35 class AddLaplacianEigenvectorPE(BaseTransform):
36     r"""Adds the Laplacian eigenvector positional encoding from the
37     `"Benchmarking Graph Neural Networks" <https://arxiv.org/abs/2003.00982>`_
38     paper to the given graph
39     (functional name: :obj:`add_laplacian_eigenvector_pe`).
40 
41     Args:
42         k (int): The number of non-trivial eigenvectors to consider.
43         attr_name (str, optional): The attribute name of the data object to add
44             positional encodings to. If set to :obj:`None`, will be
45             concatenated to :obj:`data.x`.
46             (default: :obj:`"laplacian_eigenvector_pe"`)
47         is_undirected (bool, optional): If set to :obj:`True`, this transform
48             expects undirected graphs as input, and can hence speed up the
49             computation of eigenvectors. (default: :obj:`False`)
50         **kwargs (optional): Additional arguments of
51             :meth:`scipy.sparse.linalg.eigs` (when :attr:`is_undirected` is
52             :obj:`False`) or :meth:`scipy.sparse.linalg.eigsh` (when
53             :attr:`is_undirected` is :obj:`True`).
54     """
55     def __init__(
56         self,
57         k: int,
58         attr_name: Optional[str] = 'laplacian_eigenvector_pe',
59         is_undirected: bool = False,
60         **kwargs,
61     ):
62         self.k = k
63         self.attr_name = attr_name
64         self.is_undirected = is_undirected
65         self.kwargs = kwargs
66 
67     def forward(self, data: Data) -> Data:
68         from scipy.sparse.linalg import eigs, eigsh
69         eig_fn = eigs if not self.is_undirected else eigsh
70 
71         num_nodes = data.num_nodes
72         edge_index, edge_weight = get_laplacian(
73             data.edge_index,
74             data.edge_weight,
75             normalization='sym',
76             num_nodes=num_nodes,
77         )
78 
79         L = to_scipy_sparse_matrix(edge_index, edge_weight, num_nodes)
80         L = L.tocsr()
81 
82         eig_vals, eig_vecs = eig_fn(
83             L,
84             k=self.k + 1,
85             which='SR' if not self.is_undirected else 'SA',
86             return_eigenvectors=True,
87             **self.kwargs,
88         )
89 
90         eig_vecs = np.real(eig_vecs[:, eig_vals.argsort()])
91         pe = torch.from_numpy(eig_vecs[:, 1:self.k + 1])
92         sign = -1 + 2 * torch.randint(0, 2, (self.k, ))
93         pe *= sign
94 
95         data = add_node_attr(data, pe, attr_name=self.attr_name)
96         return data
97 
98 
99 @functional_transform('add_random_walk_pe')
100 class AddRandomWalkPE(BaseTransform):
101     r"""Adds the random walk positional encoding from the `"Graph Neural
102     Networks with Learnable Structural and Positional Representations"
103     <https://arxiv.org/abs/2110.07875>`_ paper to the given graph
104     (functional name: :obj:`add_random_walk_pe`).
105 
106     Args:
107         walk_length (int): The number of random walk steps.
108         attr_name (str, optional): The attribute name of the data object to add
109             positional encodings to. If set to :obj:`None`, will be
110             concatenated to :obj:`data.x`.
111             (default: :obj:`"random_walk_pe"`)
112     """
113     def __init__(
114         self,
115         walk_length: int,
116         attr_name: Optional[str] = 'random_walk_pe',
117     ):
118         self.walk_length = walk_length
119         self.attr_name = attr_name
120 
121     def forward(self, data: Data) -> Data:
122         row, col = data.edge_index
123         N = data.num_nodes
124 
125         value = data.edge_weight
126         if value is None:
127             value = torch.ones(data.num_edges, device=row.device)
128         value = scatter(value, row, dim_size=N, reduce='sum').clamp(min=1)[row]
129         value = 1.0 / value
130 
131         adj = to_torch_csr_tensor(data.edge_index, value, size=data.size())
132 
133         out = adj
134         pe_list = [get_self_loop_attr(*to_edge_index(out), num_nodes=N)]
135         for _ in range(self.walk_length - 1):
136             out = out @ adj
137             pe_list.append(get_self_loop_attr(*to_edge_index(out), N))
138         pe = torch.stack(pe_list, dim=-1)
139 
140         data = add_node_attr(data, pe, attr_name=self.attr_name)
141         return data
142
```
--- 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/transforms/add_positional_encoding.py b/torch_geometric/transforms/add_positional_encoding.py
--- a/torch_geometric/transforms/add_positional_encoding.py
+++ b/torch_geometric/transforms/add_positional_encoding.py
@@ -52,6 +52,9 @@
             :obj:`False`) or :meth:`scipy.sparse.linalg.eigsh` (when
             :attr:`is_undirected` is :obj:`True`).
     """
+    # Number of nodes from which to use sparse eigenvector computation:
+    SPARSE_THRESHOLD: int = 100
+
     def __init__(
         self,
         k: int,
@@ -65,9 +68,6 @@
         self.kwargs = kwargs
 
     def forward(self, data: Data) -> Data:
-        from scipy.sparse.linalg import eigs, eigsh
-        eig_fn = eigs if not self.is_undirected else eigsh
-
         num_nodes = data.num_nodes
         edge_index, edge_weight = get_laplacian(
             data.edge_index,
@@ -77,15 +77,23 @@
         )
 
         L = to_scipy_sparse_matrix(edge_index, edge_weight, num_nodes)
-        L = L.tocsr()
-
-        eig_vals, eig_vecs = eig_fn(
-            L,
-            k=self.k + 1,
-            which='SR' if not self.is_undirected else 'SA',
-            return_eigenvectors=True,
-            **self.kwargs,
-        )
+
+        if num_nodes < self.SPARSE_THRESHOLD:
+            from numpy.linalg import eig, eigh
+            eig_fn = eig if not self.is_undirected else eigh
+
+            eig_vals, eig_vecs = eig_fn(L.todense())
+        else:
+            from scipy.sparse.linalg import eigs, eigsh
+            eig_fn = eigs if not self.is_undirected else eigsh
+
+            eig_vals, eig_vecs = eig_fn(
+                L,
+                k=self.k + 1,
+                which='SR' if not self.is_undirected else 'SA',
+                return_eigenvectors=True,
+                **self.kwargs,
+            )
 
         eig_vecs = np.real(eig_vecs[:, eig_vals.argsort()])
         pe = torch.from_numpy(eig_vecs[:, 1:self.k + 1])

{"golden_diff": "diff --git a/torch_geometric/transforms/add_positional_encoding.py b/torch_geometric/transforms/add_positional_encoding.py\n--- a/torch_geometric/transforms/add_positional_encoding.py\n+++ b/torch_geometric/transforms/add_positional_encoding.py\n@@ -52,6 +52,9 @@\n             :obj:`False`) or :meth:`scipy.sparse.linalg.eigsh` (when\n             :attr:`is_undirected` is :obj:`True`).\n     \"\"\"\n+    # Number of nodes from which to use sparse eigenvector computation:\n+    SPARSE_THRESHOLD: int = 100\n+\n     def __init__(\n         self,\n         k: int,\n@@ -65,9 +68,6 @@\n         self.kwargs = kwargs\n \n     def forward(self, data: Data) -> Data:\n-        from scipy.sparse.linalg import eigs, eigsh\n-        eig_fn = eigs if not self.is_undirected else eigsh\n-\n         num_nodes = data.num_nodes\n         edge_index, edge_weight = get_laplacian(\n             data.edge_index,\n@@ -77,15 +77,23 @@\n         )\n \n         L = to_scipy_sparse_matrix(edge_index, edge_weight, num_nodes)\n-        L = L.tocsr()\n-\n-        eig_vals, eig_vecs = eig_fn(\n-            L,\n-            k=self.k + 1,\n-            which='SR' if not self.is_undirected else 'SA',\n-            return_eigenvectors=True,\n-            **self.kwargs,\n-        )\n+\n+        if num_nodes < self.SPARSE_THRESHOLD:\n+            from numpy.linalg import eig, eigh\n+            eig_fn = eig if not self.is_undirected else eigh\n+\n+            eig_vals, eig_vecs = eig_fn(L.todense())\n+        else:\n+            from scipy.sparse.linalg import eigs, eigsh\n+            eig_fn = eigs if not self.is_undirected else eigsh\n+\n+            eig_vals, eig_vecs = eig_fn(\n+                L,\n+                k=self.k + 1,\n+                which='SR' if not self.is_undirected else 'SA',\n+                return_eigenvectors=True,\n+                **self.kwargs,\n+            )\n \n         eig_vecs = np.real(eig_vecs[:, eig_vals.argsort()])\n         pe = torch.from_numpy(eig_vecs[:, 1:self.k + 1])\n", "issue": "`test/transforms/test_add_positional_encoding.py::test_eigenvector_permutation_invariance` fails with AMD CPU\n### \ud83d\udc1b Describe the bug\r\n\r\nThe unit test added in #8087 fails with the error bellow on AMD CPU based systems.\r\n\r\n\r\n```\r\nNVIDIA_TF32_OVERRIDE=0 pytest -s --cov --cov-report=xml test/transforms/test_add_positional_encoding.py::test_eigenvector_permutation_invariance\r\n```\r\n\r\nTraceback:\r\n```\r\n======================================================================== FAILURES ========================================================================$\r\n_________________________________________________________ test_eigenvector_permutation_invariance ________________________________________________________$\r\n\r\n    def test_eigenvector_permutation_invariance():\r\n        edge_index = torch.tensor([[0, 1, 0, 4, 1, 4, 2, 3, 3, 5],\r\n                                   [1, 0, 4, 0, 4, 1, 3, 2, 5, 3]])\r\n        data = Data(edge_index=edge_index, num_nodes=6)\r\n\r\n        perm = torch.tensor([5, 4, 3, 2, 1, 0])\r\n        transform = AddLaplacianEigenvectorPE(\r\n            k=1,\r\n            is_undirected=True,\r\n            attr_name='x',\r\n            v0=torch.arange(data.num_nodes),\r\n        )\r\n        out1 = transform(data)\r\n\r\n        transform = AddLaplacianEigenvectorPE(\r\n            k=1,\r\n            is_undirected=True,\r\n            attr_name='x',\r\n            v0=perm,\r\n        )\r\n        out2 = transform(data.subgraph(perm))\r\n\r\n        print(out1.x[perm].abs())\r\n        print(out2.x.abs())\r\n\r\n>       assert torch.allclose(out1.x[perm].abs(), out2.x.abs(), atol=1e-1)\r\nE       assert False\r\nE        +  where False = <built-in method allclose of type object at 0x7f2f94b318a0>(tensor([[0.1360],\\n        [0.5556],\\n        [0.1924],\\n        [0.1\r\n360],\\n        [0.5556],\\n        [0.5556]]), tensor([[0.2091],\\n        [0.5245],\\n        [0.2957],\\n        [0.2091],\\n        [0.5245],\\n        [0.524\r\n5]]), atol=0.1)\r\nE        +    where <built-in method allclose of type object at 0x7f2f94b318a0> = torch.allclose\r\nE        +    and   tensor([[0.1360],\\n        [0.5556],\\n        [0.1924],\\n        [0.1360],\\n        [0.5556],\\n        [0.5556]]) = <built-in method ab\r\ns of Tensor object at 0x7f2bc6e1e160>()\r\nE        +      where <built-in method abs of Tensor object at 0x7f2bc6e1e160> = tensor([[ 0.1360],\\n        [-0.5556],\\n        [ 0.1924],\\n        [ 0.13\r\n60],\\n        [-0.5556],\\n        [-0.5556]]).abs\r\nE        +    and   tensor([[0.2091],\\n        [0.5245],\\n        [0.2957],\\n        [0.2091],\\n        [0.5245],\\n        [0.5245]]) = <built-in method ab\r\ns of Tensor object at 0x7f2bc89d3470>()\r\nE        +      where <built-in method abs of Tensor object at 0x7f2bc89d3470> = tensor([[ 0.2091],\\n        [-0.5245],\\n        [ 0.2957],\\n        [ 0.20\r\n91],\\n        [-0.5245],\\n        [-0.5245]]).abs\r\nE        +        where tensor([[ 0.2091],\\n        [-0.5245],\\n        [ 0.2957],\\n        [ 0.2091],\\n        [-0.5245],\\n        [-0.5245]]) = Data(edge\r\n_index=[2, 10], num_nodes=6, x=[6, 1]).x\r\n```\r\n\r\n### Environment\r\n\r\n* PyG version: 2.4.0 (built from source)\r\n* PyTorch version: 2.1.0\r\n* OS:  Ubuntu 22.04.3 LTS\r\n* Python version: 3.10.12\r\n* CUDA/cuDNN version: 12.2\r\n* How you installed PyTorch and PyG (`conda`, `pip`, source): source\n", "before_files": [{"content": "from typing import Any, Optional\n\nimport numpy as np\nimport torch\n\nfrom torch_geometric.data import Data\nfrom torch_geometric.data.datapipes import functional_transform\nfrom torch_geometric.transforms import BaseTransform\nfrom torch_geometric.utils import (\n    get_laplacian,\n    get_self_loop_attr,\n    scatter,\n    to_edge_index,\n    to_scipy_sparse_matrix,\n    to_torch_csr_tensor,\n)\n\n\ndef add_node_attr(data: Data, value: Any,\n                  attr_name: Optional[str] = None) -> Data:\n    # TODO Move to `BaseTransform`.\n    if attr_name is None:\n        if 'x' in data:\n            x = data.x.view(-1, 1) if data.x.dim() == 1 else data.x\n            data.x = torch.cat([x, value.to(x.device, x.dtype)], dim=-1)\n        else:\n            data.x = value\n    else:\n        data[attr_name] = value\n\n    return data\n\n\n@functional_transform('add_laplacian_eigenvector_pe')\nclass AddLaplacianEigenvectorPE(BaseTransform):\n    r\"\"\"Adds the Laplacian eigenvector positional encoding from the\n    `\"Benchmarking Graph Neural Networks\" <https://arxiv.org/abs/2003.00982>`_\n    paper to the given graph\n    (functional name: :obj:`add_laplacian_eigenvector_pe`).\n\n    Args:\n        k (int): The number of non-trivial eigenvectors to consider.\n        attr_name (str, optional): The attribute name of the data object to add\n            positional encodings to. If set to :obj:`None`, will be\n            concatenated to :obj:`data.x`.\n            (default: :obj:`\"laplacian_eigenvector_pe\"`)\n        is_undirected (bool, optional): If set to :obj:`True`, this transform\n            expects undirected graphs as input, and can hence speed up the\n            computation of eigenvectors. (default: :obj:`False`)\n        **kwargs (optional): Additional arguments of\n            :meth:`scipy.sparse.linalg.eigs` (when :attr:`is_undirected` is\n            :obj:`False`) or :meth:`scipy.sparse.linalg.eigsh` (when\n            :attr:`is_undirected` is :obj:`True`).\n    \"\"\"\n    def __init__(\n        self,\n        k: int,\n        attr_name: Optional[str] = 'laplacian_eigenvector_pe',\n        is_undirected: bool = False,\n        **kwargs,\n    ):\n        self.k = k\n        self.attr_name = attr_name\n        self.is_undirected = is_undirected\n        self.kwargs = kwargs\n\n    def forward(self, data: Data) -> Data:\n        from scipy.sparse.linalg import eigs, eigsh\n        eig_fn = eigs if not self.is_undirected else eigsh\n\n        num_nodes = data.num_nodes\n        edge_index, edge_weight = get_laplacian(\n            data.edge_index,\n            data.edge_weight,\n            normalization='sym',\n            num_nodes=num_nodes,\n        )\n\n        L = to_scipy_sparse_matrix(edge_index, edge_weight, num_nodes)\n        L = L.tocsr()\n\n        eig_vals, eig_vecs = eig_fn(\n            L,\n            k=self.k + 1,\n            which='SR' if not self.is_undirected else 'SA',\n            return_eigenvectors=True,\n            **self.kwargs,\n        )\n\n        eig_vecs = np.real(eig_vecs[:, eig_vals.argsort()])\n        pe = torch.from_numpy(eig_vecs[:, 1:self.k + 1])\n        sign = -1 + 2 * torch.randint(0, 2, (self.k, ))\n        pe *= sign\n\n        data = add_node_attr(data, pe, attr_name=self.attr_name)\n        return data\n\n\n@functional_transform('add_random_walk_pe')\nclass AddRandomWalkPE(BaseTransform):\n    r\"\"\"Adds the random walk positional encoding from the `\"Graph Neural\n    Networks with Learnable Structural and Positional Representations\"\n    <https://arxiv.org/abs/2110.07875>`_ paper to the given graph\n    (functional name: :obj:`add_random_walk_pe`).\n\n    Args:\n        walk_length (int): The number of random walk steps.\n        attr_name (str, optional): The attribute name of the data object to add\n            positional encodings to. If set to :obj:`None`, will be\n            concatenated to :obj:`data.x`.\n            (default: :obj:`\"random_walk_pe\"`)\n    \"\"\"\n    def __init__(\n        self,\n        walk_length: int,\n        attr_name: Optional[str] = 'random_walk_pe',\n    ):\n        self.walk_length = walk_length\n        self.attr_name = attr_name\n\n    def forward(self, data: Data) -> Data:\n        row, col = data.edge_index\n        N = data.num_nodes\n\n        value = data.edge_weight\n        if value is None:\n            value = torch.ones(data.num_edges, device=row.device)\n        value = scatter(value, row, dim_size=N, reduce='sum').clamp(min=1)[row]\n        value = 1.0 / value\n\n        adj = to_torch_csr_tensor(data.edge_index, value, size=data.size())\n\n        out = adj\n        pe_list = [get_self_loop_attr(*to_edge_index(out), num_nodes=N)]\n        for _ in range(self.walk_length - 1):\n            out = out @ adj\n            pe_list.append(get_self_loop_attr(*to_edge_index(out), N))\n        pe = torch.stack(pe_list, dim=-1)\n\n        data = add_node_attr(data, pe, attr_name=self.attr_name)\n        return data\n", "path": "torch_geometric/transforms/add_positional_encoding.py"}], "after_files": [{"content": "from typing import Any, Optional\n\nimport numpy as np\nimport torch\n\nfrom torch_geometric.data import Data\nfrom torch_geometric.data.datapipes import functional_transform\nfrom torch_geometric.transforms import BaseTransform\nfrom torch_geometric.utils import (\n    get_laplacian,\n    get_self_loop_attr,\n    scatter,\n    to_edge_index,\n    to_scipy_sparse_matrix,\n    to_torch_csr_tensor,\n)\n\n\ndef add_node_attr(data: Data, value: Any,\n                  attr_name: Optional[str] = None) -> Data:\n    # TODO Move to `BaseTransform`.\n    if attr_name is None:\n        if 'x' in data:\n            x = data.x.view(-1, 1) if data.x.dim() == 1 else data.x\n            data.x = torch.cat([x, value.to(x.device, x.dtype)], dim=-1)\n        else:\n            data.x = value\n    else:\n        data[attr_name] = value\n\n    return data\n\n\n@functional_transform('add_laplacian_eigenvector_pe')\nclass AddLaplacianEigenvectorPE(BaseTransform):\n    r\"\"\"Adds the Laplacian eigenvector positional encoding from the\n    `\"Benchmarking Graph Neural Networks\" <https://arxiv.org/abs/2003.00982>`_\n    paper to the given graph\n    (functional name: :obj:`add_laplacian_eigenvector_pe`).\n\n    Args:\n        k (int): The number of non-trivial eigenvectors to consider.\n        attr_name (str, optional): The attribute name of the data object to add\n            positional encodings to. If set to :obj:`None`, will be\n            concatenated to :obj:`data.x`.\n            (default: :obj:`\"laplacian_eigenvector_pe\"`)\n        is_undirected (bool, optional): If set to :obj:`True`, this transform\n            expects undirected graphs as input, and can hence speed up the\n            computation of eigenvectors. (default: :obj:`False`)\n        **kwargs (optional): Additional arguments of\n            :meth:`scipy.sparse.linalg.eigs` (when :attr:`is_undirected` is\n            :obj:`False`) or :meth:`scipy.sparse.linalg.eigsh` (when\n            :attr:`is_undirected` is :obj:`True`).\n    \"\"\"\n    # Number of nodes from which to use sparse eigenvector computation:\n    SPARSE_THRESHOLD: int = 100\n\n    def __init__(\n        self,\n        k: int,\n        attr_name: Optional[str] = 'laplacian_eigenvector_pe',\n        is_undirected: bool = False,\n        **kwargs,\n    ):\n        self.k = k\n        self.attr_name = attr_name\n        self.is_undirected = is_undirected\n        self.kwargs = kwargs\n\n    def forward(self, data: Data) -> Data:\n        num_nodes = data.num_nodes\n        edge_index, edge_weight = get_laplacian(\n            data.edge_index,\n            data.edge_weight,\n            normalization='sym',\n            num_nodes=num_nodes,\n        )\n\n        L = to_scipy_sparse_matrix(edge_index, edge_weight, num_nodes)\n\n        if num_nodes < self.SPARSE_THRESHOLD:\n            from numpy.linalg import eig, eigh\n            eig_fn = eig if not self.is_undirected else eigh\n\n            eig_vals, eig_vecs = eig_fn(L.todense())\n        else:\n            from scipy.sparse.linalg import eigs, eigsh\n            eig_fn = eigs if not self.is_undirected else eigsh\n\n            eig_vals, eig_vecs = eig_fn(\n                L,\n                k=self.k + 1,\n                which='SR' if not self.is_undirected else 'SA',\n                return_eigenvectors=True,\n                **self.kwargs,\n            )\n\n        eig_vecs = np.real(eig_vecs[:, eig_vals.argsort()])\n        pe = torch.from_numpy(eig_vecs[:, 1:self.k + 1])\n        sign = -1 + 2 * torch.randint(0, 2, (self.k, ))\n        pe *= sign\n\n        data = add_node_attr(data, pe, attr_name=self.attr_name)\n        return data\n\n\n@functional_transform('add_random_walk_pe')\nclass AddRandomWalkPE(BaseTransform):\n    r\"\"\"Adds the random walk positional encoding from the `\"Graph Neural\n    Networks with Learnable Structural and Positional Representations\"\n    <https://arxiv.org/abs/2110.07875>`_ paper to the given graph\n    (functional name: :obj:`add_random_walk_pe`).\n\n    Args:\n        walk_length (int): The number of random walk steps.\n        attr_name (str, optional): The attribute name of the data object to add\n            positional encodings to. If set to :obj:`None`, will be\n            concatenated to :obj:`data.x`.\n            (default: :obj:`\"random_walk_pe\"`)\n    \"\"\"\n    def __init__(\n        self,\n        walk_length: int,\n        attr_name: Optional[str] = 'random_walk_pe',\n    ):\n        self.walk_length = walk_length\n        self.attr_name = attr_name\n\n    def forward(self, data: Data) -> Data:\n        row, col = data.edge_index\n        N = data.num_nodes\n\n        value = data.edge_weight\n        if value is None:\n            value = torch.ones(data.num_edges, device=row.device)\n        value = scatter(value, row, dim_size=N, reduce='sum').clamp(min=1)[row]\n        value = 1.0 / value\n\n        adj = to_torch_csr_tensor(data.edge_index, value, size=data.size())\n\n        out = adj\n        pe_list = [get_self_loop_attr(*to_edge_index(out), num_nodes=N)]\n        for _ in range(self.walk_length - 1):\n            out = out @ adj\n            pe_list.append(get_self_loop_attr(*to_edge_index(out), N))\n        pe = torch.stack(pe_list, dim=-1)\n\n        data = add_node_attr(data, pe, attr_name=self.attr_name)\n        return data\n", "path": "torch_geometric/transforms/add_positional_encoding.py"}]}