dgl.to_simple(g, return_counts='count', writeback_mapping=False, copy_ndata=True, copy_edata=False, aggregator='arbitrary')[source]

Convert a graph to a simple graph without parallel edges and return.

For a heterogeneous graph with multiple edge types, DGL treats edges with the same edge type and endpoints as parallel edges and removes them. Optionally, one can get the the number of parallel edges by specifying the return_counts argument. To get the a mapping from the edge IDs in the input graph to the edge IDs in the resulting graph, set writeback_mapping to true.

  • g (DGLGraph) – The input graph. Must be on CPU.

  • return_counts (str, optional) –

    If given, the count of each edge in the original graph will be stored as edge features under the name return_counts. The old features with the same name will be replaced.

    (Default: “count”)

  • writeback_mapping (bool, optional) –

    If True, return an extra write-back mapping for each edge type. The write-back mapping is a tensor recording the mapping from the edge IDs in the input graph to the edge IDs in the result graph. If the graph is heterogeneous, DGL returns a dictionary of edge types and such tensors.

    If False, only the simple graph is returned.

    (Default: False)

  • copy_ndata (bool, optional) –

    If True, the node features of the simple graph are copied from the original graph.

    If False, the simple graph will not have any node features.

    (Default: True)

  • copy_edata (bool, optional) –

    If True, the edge features of the simple graph are copied from the original graph. If there exists duplicate edges between two nodes (u, v), the feature of the edge is the aggregation of edge feature of duplicate edges.

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

    (Default: False)

  • aggregator (str, optional) –

    Indicate how to coalesce edge feature of duplicate edges. If arbitrary, select one of the duplicate edges’ feature. If sum, compute the summation of duplicate edges’ feature. If mean, compute the average of duplicate edges’ feature.

    (Default: arbitrary)


  • DGLGraph – The graph.

  • tensor or dict of tensor – The writeback mapping. Only when writeback_mapping is True.


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.

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.


Homogeneous Graphs

Create a graph for demonstrating to_simple API. In the original graph, there are multiple edges between 1 and 2.

>>> import dgl
>>> import torch as th
>>> g = dgl.graph((th.tensor([0, 1, 2, 1]), th.tensor([1, 2, 0, 2])))
>>> g.ndata['h'] = th.tensor([[0.], [1.], [2.]])
>>> g.edata['h'] = th.tensor([[3.], [4.], [5.], [6.]])

Convert the graph to a simple graph. The return counts is stored in the edge feature ‘cnt’ and the writeback mapping is returned in a tensor.

>>> sg, wm = dgl.to_simple(g, return_counts='cnt', writeback_mapping=True)
>>> sg.ndata['h']
>>> u, v, eid = sg.edges(form='all')
>>> u
tensor([0, 1, 2])
>>> v
tensor([1, 2, 0])
>>> eid
tensor([0, 1, 2])
>>> sg.edata['cnt']
tensor([1, 2, 1])
>>> wm
tensor([0, 1, 2, 1])
>>> 'h' in g.edata

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]))
... })
>>> g.nodes['game'].data['hv'] = th.ones(3, 1)
>>> g.edges['plays'].data['he'] = th.zeros(3, 1)

The return counts is stored in the default edge feature ‘count’ for each edge type.

>>> sg, wm = dgl.to_simple(g, copy_ndata=False, writeback_mapping=True)
>>> sg
Graph(num_nodes={'game': 3, 'user': 3},
      num_edges={('user', 'wins', 'user'): 4, ('game', 'plays', 'user'): 3},
      metagraph=[('user', 'user'), ('game', 'user')])
>>> sg.edges(etype='wins')
(tensor([0, 2, 0, 2]), tensor([1, 1, 2, 0]))
>>> wm[('user', 'wins', 'user')]
tensor([0, 1, 2, 1, 3])
>>> sg.edges(etype='plays')
(tensor([2, 1, 1]), tensor([1, 2, 1]))
>>> wm[('user', 'plays', 'game')]
tensor([0, 1, 2])
>>> 'hv' in sg.nodes['game'].data
>>> 'he' in sg.edges['plays'].data
>>> sg.edata['count']
{('user', 'wins', 'user'): tensor([1, 2, 1, 1])
 ('user', 'plays', 'game'): tensor([1, 1, 1])}