dgl.add_reverse_edges

dgl.add_reverse_edges(g, readonly=None, copy_ndata=True, copy_edata=False, ignore_bipartite=False, exclude_self=True)[source]

Add a reversed edge for each edge in the input graph and return a new graph.

For a graph with edges \((i_1, j_1), \cdots, (i_n, j_n)\), this function creates a new graph with edges \((i_1, j_1), \cdots, (i_n, j_n), (j_1, i_1), \cdots, (j_n, i_n)\).

The returned graph may have duplicate edges. To create a bidirected graph without duplicate edges, use to_bidirected().

The operation only works for edges whose two endpoints belong to the same node type. DGL will raise error if the input graph is heterogeneous and contains edges with different types of endpoints. If ignore_bipartite is true, DGL will ignore those edges instead.

Parameters:
  • g (DGLGraph) – The input graph.

  • readonly (bool, default to be True) – Deprecated. There will be no difference between readonly and non-readonly

  • copy_ndata (bool, optional) –

    If True, the node features of the new graph are copied from the original graph. If False, the new graph will not have any node features.

    (Default: True)

  • copy_edata (bool, optional) –

    If True, the features of the reversed edges will be identical to the original ones.

    If False, the new graph will not have any edge features.

    (Default: False)

  • ignore_bipartite (bool, optional) – If True, unidirectional bipartite graphs are ignored and no error is raised. If False, an error will be raised if an edge type of the input heterogeneous graph is for a unidirectional bipartite graph.

  • exclude_self (bool, optional) – If True, it does not add reverse edges for self-loops, which is likely meaningless in most cases.

Returns:

The graph with reversed edges added.

Return type:

DGLGraph

Notes

If copy_ndata is True, the resulting graph will share the node feature tensors with the input graph. Hence, users should try to avoid in-place operations which will be visible to both graphs. On the contrary, the two graphs do not share the same edge feature storage.

This function discards the batch information. Please use dgl.DGLGraph.set_batch_num_nodes() and dgl.DGLGraph.set_batch_num_edges() on the transformed graph to maintain the information.

Examples

Homogeneous graphs

>>> g = dgl.graph((th.tensor([0, 0]), th.tensor([0, 1])))
>>> bg1 = dgl.add_reverse_edges(g)
>>> bg1.edges()
(tensor([0, 0, 0, 1]), tensor([0, 1, 0, 0]))

Heterogeneous graphs

>>> g = dgl.heterograph({
>>>     ('user', 'wins', 'user'): (th.tensor([0, 2, 0, 2, 2]), th.tensor([1, 1, 2, 1, 0])),
>>>     ('user', 'plays', 'game'): (th.tensor([1, 2, 1]), th.tensor([2, 1, 1])),
>>>     ('user', 'follows', 'user'): (th.tensor([1, 2, 1), th.tensor([0, 0, 0]))
>>> })
>>> g.nodes['game'].data['hv'] = th.ones(3, 1)
>>> g.edges['wins'].data['h'] = th.tensor([0, 1, 2, 3, 4])

The add_reverse_edges() operation is applied to the edge type ('user', 'wins', 'user') and the edge type ('user', 'follows', 'user'). The edge type ('user', 'plays', 'game') is ignored. Both the node features and edge features are shared.

>>> bg = dgl.add_reverse_edges(g, copy_ndata=True,
                           copy_edata=True, ignore_bipartite=True)
>>> bg.edges(('user', 'wins', 'user'))
(tensor([0, 2, 0, 2, 2, 1, 1, 2, 1, 0]), tensor([1, 1, 2, 1, 0, 0, 2, 0, 2, 2]))
>>> bg.edges(('user', 'follows', 'user'))
(tensor([1, 2, 1, 0, 0, 0]), tensor([0, 0, 0, 1, 2, 1]))
>>> bg.edges(('user', 'plays', 'game'))
(th.tensor([1, 2, 1]), th.tensor([2, 1, 1]))
>>> bg.nodes['game'].data['hv']
tensor([0, 0, 0])
>>> bg.edges[('user', 'wins', 'user')].data['h']
th.tensor([0, 1, 2, 3, 4, 0, 1, 2, 3, 4])