class dgl.DGLHeteroGraph(gidx, ntypes, etypes, node_frames=None, edge_frames=None)[source]

Base heterogeneous graph class.

Do NOT instantiate from this class directly; use conversion methods instead.

A Heterogeneous graph is defined as a graph with node types and edge types.

If two edges share the same edge type, then their source nodes, as well as their destination nodes, also have the same type (the source node types don’t have to be the same as the destination node types).


Suppose that we want to construct the following heterogeneous graph:

digraph G {
    Alice -> Bob [label=follows]
    Bob -> Carol [label=follows]
    Alice -> Tetris [label=plays]
    Bob -> Tetris [label=plays]
    Bob -> Minecraft [label=plays]
    Carol -> Minecraft [label=plays]
    Nintendo -> Tetris [label=develops]
    Mojang -> Minecraft [label=develops]
    {rank=source; Alice; Bob; Carol}
    {rank=sink; Nintendo; Mojang}

And suppose that one maps the users, games and developers to the following IDs:

User name Alice Bob Carol
User ID 0 1 2
Game name Tetris Minecraft
Game ID 0 1
Developer name Nintendo Mojang
Developer ID 0 1

One can construct the graph as follows:

>>> follows_g = dgl.graph([(0, 1), (1, 2)], 'user', 'follows')
>>> plays_g = dgl.bipartite([(0, 0), (1, 0), (1, 1), (2, 1)], 'user', 'plays', 'game')
>>> devs_g = dgl.bipartite([(0, 0), (1, 1)], 'developer', 'develops', 'game')
>>> g = dgl.hetero_from_relations([follows_g, plays_g, devs_g])

Or equivalently

>>> g = dgl.heterograph({
...     ('user', 'follows', 'user'): [(0, 1), (1, 2)],
...     ('user', 'plays', 'game'): [(0, 0), (1, 0), (1, 1), (2, 1)],
...     ('developer', 'develops', 'game'): [(0, 0), (1, 1)],
...     })

dgl.graph() and dgl.bipartite() can create a graph from a variety of data types including:

  • edge list
  • edge tuples
  • networkx graph
  • scipy sparse matrix

Click the function names for more details.

Then one can query the graph structure by specifying the ntype or etype arguments:

>>> g.number_of_nodes('user')
>>> g.number_of_edges('plays')
>>> g.out_degrees(etype='develops')  # out-degrees of source nodes of 'develops' relation
tensor([1, 1])
>>> g.in_edges(0, etype='develops')  # in-edges of destination node 0 of 'develops' relation
(tensor([0]), tensor([0]))

Or on the sliced graph for an edge type:

>>> g['plays'].number_of_edges()
>>> g['develops'].out_degrees()
tensor([1, 1])
>>> g['develops'].in_edges(0)
(tensor([0]), tensor([0]))

Node type names must be distinct (no two types have the same name). Edge types could have the same name but they must be distinguishable by the (src_type, edge_type, dst_type) triplet (called canonical edge type).

For example, suppose a graph that has two types of relation “user-watches-movie” and “user-watches-TV” as follows:

>>> g0 = dgl.bipartite([(0, 1), (1, 0), (1, 1)], 'user', 'watches', 'movie')
>>> g1 = dgl.bipartite([(0, 0), (1, 1)], 'user', 'watches', 'TV')
>>> GG = dgl.hetero_from_relations([g0, g1]) # Merge the two graphs

To distinguish between the two “watches” edge type, one must specify a full triplet:

>>> GG.number_of_edges(('user', 'watches', 'movie'))
>>> GG.number_of_edges(('user', 'watches', 'TV'))
>>> GG['user', 'watches', 'movie'].out_degrees()
tensor([1, 2])

Using only one single edge type string “watches” is ambiguous and will cause error:

>>> GG.number_of_edges('watches')  # AMBIGUOUS!!

In many cases, there is only one type of nodes or one type of edges, and the ntype and etype argument could be omitted. This is very common when using the sliced graph, which usually contains only one edge type, and sometimes only one node type:

>>> g['follows'].number_of_nodes()  # OK!! because g['follows'] only has one node type 'user'
>>> g['plays'].number_of_nodes()  # ERROR!! There are two types 'user' and 'game'.
>>> g['plays'].number_of_edges()  # OK!! because there is only one edge type 'plays'

TODO(minjie): docstring about uni-directional bipartite graph

For each heterogeneous graph, one can often infer the metagraph, the template of edge connections showing how many types of nodes and edges exist in the graph, and how each edge type could connect between node types.

One can analyze the example gameplay graph above and figure out the metagraph as follows:

digraph G {
    User -> User [label=follows]
    User -> Game [label=plays]
    Developer -> Game [label=develops]
  • gidx (HeteroGraphIndex) – Graph index object.
  • ntypes (list of str, pair of list of str) – Node type list. ntypes[i] stores the name of node type i. If a pair is given, the graph created is a uni-directional bipartite graph, and its SRC node types and DST node types are given as in the pair.
  • etypes (list of str) – Edge type list. etypes[i] stores the name of edge type i.
  • node_frames (list of FrameRef, optional) – Node feature storage. If None, empty frame is created. Otherwise, node_frames[i] stores the node features of node type i. (default: None)
  • edge_frames (list of FrameRef, optional) – Edge feature storage. If None, empty frame is created. Otherwise, edge_frames[i] stores the edge features of edge type i. (default: None)

Conversion to and from heterogeneous graphs

Module for converting graph from/to other object.

graph(data[, ntype, etype, num_nodes, card, …]) Create a graph with one type of nodes and edges.
bipartite(data[, utype, etype, vtype, …]) Create a bipartite graph.
hetero_from_relations(rel_graphs[, …]) Create a heterograph from graphs representing connections of each relation.
heterograph(data_dict[, num_nodes_dict]) Create a heterogeneous graph from a dictionary between edge types and edge lists.
to_hetero(G, ntypes, etypes[, ntype_field, …]) Convert the given homogeneous graph to a heterogeneous graph.
to_homo(G) Convert the given heterogeneous graph to a homogeneous graph.
to_networkx(g[, node_attrs, edge_attrs]) Convert to networkx graph.
DGLHeteroGraph.adjacency_matrix([transpose, …]) Return the adjacency matrix of edges of the given edge type.
DGLHeteroGraph.incidence_matrix(typestr[, …]) Return the incidence matrix representation of edges with the given edge type.

Querying metagraph structure

DGLHeteroGraph.ntypes Return the list of node types of this graph.
DGLHeteroGraph.etypes Return the list of edge types of this graph.
DGLHeteroGraph.canonical_etypes Return the list of canonical edge types of this graph.
DGLHeteroGraph.metagraph Return the metagraph as networkx.MultiDiGraph.
DGLHeteroGraph.to_canonical_etype(etype) Convert edge type to canonical etype: (srctype, etype, dsttype).
DGLHeteroGraph.get_ntype_id(ntype) Return the id of the given node type.
DGLHeteroGraph.get_etype_id(etype) Return the id of the given edge type.

Querying graph structure

DGLHeteroGraph.number_of_nodes([ntype]) Return the number of nodes of the given type in the heterograph.
DGLHeteroGraph.number_of_edges([etype]) Return the number of edges of the given type in the heterograph.
DGLHeteroGraph.is_multigraph Whether the graph is a multigraph
DGLHeteroGraph.is_readonly Whether the graph is readonly
DGLHeteroGraph.has_node(vid[, ntype]) Whether the graph has a node with a particular id and type.
DGLHeteroGraph.has_nodes(vids[, ntype]) Whether the graph has nodes with ids and a particular type.
DGLHeteroGraph.has_edge_between(u, v[, etype]) Whether the graph has an edge (u, v) of type etype.
DGLHeteroGraph.has_edges_between(u, v[, etype]) Whether the graph has edges of type etype.
DGLHeteroGraph.predecessors(v[, etype]) Return the predecessors of node v in the graph with the specified edge type.
DGLHeteroGraph.successors(v[, etype]) Return the successors of node v in the graph with the specified edge type.
DGLHeteroGraph.edge_id(u, v[, force_multi, …]) Return the edge ID, or an array of edge IDs, between source node u and destination node v, with the specified edge type
DGLHeteroGraph.edge_ids(u, v[, force_multi, …]) Return all edge IDs between source node array u and destination node array v with the specified edge type.
DGLHeteroGraph.find_edges(eid[, etype]) Given an edge ID array with the specified type, return the source and destination node ID array s and d.
DGLHeteroGraph.in_edges(v[, form, etype]) Return the inbound edges of the node(s) with the specified type.
DGLHeteroGraph.out_edges(u[, form, etype]) Return the outbound edges of the node(s) with the specified type.
DGLHeteroGraph.all_edges([form, order, etype]) Return all edges with the specified type.
DGLHeteroGraph.in_degree(v[, etype]) Return the in-degree of node v with edges of type etype.
DGLHeteroGraph.in_degrees([v, etype]) Return the in-degrees of nodes v with edges of type etype.
DGLHeteroGraph.out_degree(u[, etype]) Return the out-degree of node u with edges of type etype.
DGLHeteroGraph.out_degrees([u, etype]) Return the out-degrees of nodes u with edges of type etype.

Using Node/edge features

DGLHeteroGraph.nodes Return a node view that can be used to set/get feature data of a single node type.
DGLHeteroGraph.ndata Return the data view of all the nodes.
DGLHeteroGraph.edges Return an edge view that can be used to set/get feature data of a single edge type.
DGLHeteroGraph.edata Return the data view of all the edges.
DGLHeteroGraph.node_attr_schemes([ntype]) Return the node feature schemes for the specified type.
DGLHeteroGraph.edge_attr_schemes([etype]) Return the edge feature schemes for the specified type.
DGLHeteroGraph.set_n_initializer(initializer) Set the initializer for empty node features.
DGLHeteroGraph.set_e_initializer(initializer) Set the initializer for empty edge features.
DGLHeteroGraph.local_var() Return a heterograph object that can be used in a local function scope.
DGLHeteroGraph.local_scope() Enter a local scope context for this graph.

Transforming graph

DGLHeteroGraph.subgraph(nodes) Return the subgraph induced on given nodes.
DGLHeteroGraph.edge_subgraph(edges[, …]) Return the subgraph induced on given edges.
DGLHeteroGraph.node_type_subgraph(ntypes) Return the subgraph induced on given node types.
DGLHeteroGraph.edge_type_subgraph(etypes) Return the subgraph induced on given edge types.

Computing with DGLHeteroGraph

DGLHeteroGraph.apply_nodes(func[, v, ntype, …]) Apply the function on the nodes with the same type to update their features.
DGLHeteroGraph.apply_edges(func[, edges, …]) Apply the function on the edges with the same type to update their features.
DGLHeteroGraph.group_apply_edges(group_by, func) Group the edges by nodes and apply the function of the grouped edges to update their features.
DGLHeteroGraph.send(edges, message_func[, etype]) Send messages along the given edges with the same edge type.
DGLHeteroGraph.recv(v, reduce_func[, …]) Receive and reduce incoming messages and update the features of node(s) \(v\).
DGLHeteroGraph.multi_recv(v, reducer_dict, …) Receive messages from multiple edge types and perform aggregation.
DGLHeteroGraph.send_and_recv(edges, …[, …]) Send messages along edges of the specified type, and let destinations receive them.
DGLHeteroGraph.multi_send_and_recv(…[, …]) Send and receive messages along multiple edge types and perform aggregation.
DGLHeteroGraph.pull(v, message_func, reduce_func) Pull messages from the node(s)’ predecessors and then update their features.
DGLHeteroGraph.multi_pull(v, etype_dict, …) Pull and receive messages of the given nodes along multiple edge types and perform aggregation.
DGLHeteroGraph.push(u, message_func, reduce_func) Send message from the node(s) to their successors and update them.
DGLHeteroGraph.update_all(message_func, …) Send messages through all edges and update all nodes.
DGLHeteroGraph.multi_update_all(etype_dict, …) Send and receive messages along all edges.
DGLHeteroGraph.prop_nodes(nodes_generator, …) Propagate messages using graph traversal by sequentially triggering pull() on nodes.
DGLHeteroGraph.prop_edges(edges_generator, …) Propagate messages using graph traversal by sequentially triggering send_and_recv() on edges.
DGLHeteroGraph.filter_nodes(predicate[, …]) Return a tensor of node IDs with the given node type that satisfy the given predicate.
DGLHeteroGraph.filter_edges(predicate[, …]) Return a tensor of edge IDs with the given edge type that satisfy the given predicate.
DGLHeteroGraph.to(ctx) Move both ndata and edata to the targeted mode (cpu/gpu) Framework agnostic