r"""Random Walk Positional Encoding, as introduced in `Graph Neural Networks with Learnable Structural and Positional Representations `__ This function computes the random walk positional encodings as landing probabilities from 1-step to k-step, sta
(g, k, eweight_name=None)
| 3551 | |
| 3552 | |
| 3553 | def random_walk_pe(g, k, eweight_name=None): |
| 3554 | r"""Random Walk Positional Encoding, as introduced in |
| 3555 | `Graph Neural Networks with Learnable Structural and Positional Representations |
| 3556 | <https://arxiv.org/abs/2110.07875>`__ |
| 3557 | |
| 3558 | This function computes the random walk positional encodings as landing probabilities |
| 3559 | from 1-step to k-step, starting from each node to itself. |
| 3560 | |
| 3561 | Parameters |
| 3562 | ---------- |
| 3563 | g : DGLGraph |
| 3564 | The input graph. Must be homogeneous. |
| 3565 | k : int |
| 3566 | The number of random walk steps. The paper found the best value to be 16 and 20 |
| 3567 | for two experiments. |
| 3568 | eweight_name : str, optional |
| 3569 | The name to retrieve the edge weights. Default: None, not using the edge weights. |
| 3570 | |
| 3571 | Returns |
| 3572 | ------- |
| 3573 | Tensor |
| 3574 | The random walk positional encodings of shape :math:`(N, k)`, where :math:`N` is the |
| 3575 | number of nodes in the input graph. |
| 3576 | |
| 3577 | Example |
| 3578 | ------- |
| 3579 | >>> import dgl |
| 3580 | >>> g = dgl.graph(([0,1,1], [1,1,0])) |
| 3581 | >>> dgl.random_walk_pe(g, 2) |
| 3582 | tensor([[0.0000, 0.5000], |
| 3583 | [0.5000, 0.7500]]) |
| 3584 | """ |
| 3585 | N = g.num_nodes() # number of nodes |
| 3586 | M = g.num_edges() # number of edges |
| 3587 | A = g.adj_external(scipy_fmt="csr") # adjacency matrix |
| 3588 | if eweight_name is not None: |
| 3589 | # add edge weights if required |
| 3590 | W = sparse.csr_matrix( |
| 3591 | (g.edata[eweight_name].squeeze(), g.find_edges(list(range(M)))), |
| 3592 | shape=(N, N), |
| 3593 | ) |
| 3594 | A = A.multiply(W) |
| 3595 | # 1-step transition probability |
| 3596 | if version.parse(scipy.__version__) < version.parse("1.11.0"): |
| 3597 | RW = np.array(A / (A.sum(1) + 1e-30)) |
| 3598 | else: |
| 3599 | # Sparse matrix divided by a dense array returns a sparse matrix in |
| 3600 | # scipy since 1.11.0. |
| 3601 | RW = (A / (A.sum(1) + 1e-30)).toarray() |
| 3602 | |
| 3603 | # Iterate for k steps |
| 3604 | PE = [F.astype(F.tensor(np.array(RW.diagonal())), F.float32)] |
| 3605 | RW_power = RW |
| 3606 | for _ in range(k - 1): |
| 3607 | RW_power = RW_power @ RW |
| 3608 | PE.append(F.astype(F.tensor(np.array(RW_power.diagonal())), F.float32)) |
| 3609 | PE = F.stack(PE, dim=-1) |
| 3610 |
nothing calls this directly
no test coverage detected