2_basics.py 5.78 KB
Newer Older
1
2
3
"""
.. currentmodule:: dgl

4
5
DGLGraph and Node/edge Features
===============================
6
7
8
9

**Author**: `Minjie Wang <https://jermainewang.github.io/>`_, Quan Gan, Yu Gai,
Zheng Zhang

10
In this tutorial, you learn how to create a graph and how to read and write node and edge representations.
11
12
13
"""

###############################################################################
14
# Creating a graph
15
# ----------------
16
17
18
# The design of :class:`DGLGraph` was influenced by other graph libraries. You 
# can create a graph from networkx and convert it into a :class:`DGLGraph` and 
# vice versa.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

import networkx as nx
import dgl

g_nx = nx.petersen_graph()
g_dgl = dgl.DGLGraph(g_nx)

import matplotlib.pyplot as plt
plt.subplot(121)
nx.draw(g_nx, with_labels=True)
plt.subplot(122)
nx.draw(g_dgl.to_networkx(), with_labels=True)

plt.show()


###############################################################################
36
# The examples here show the same graph, except that :class:`DGLGraph` is always directional.
37
#
38
# You can also create a graph by calling the DGL interface.
39
# 
40
# In the next example, you build a star graph. :class:`DGLGraph` nodes are a consecutive range of
41
42
43
# integers between 0 and :func:`number_of_nodes() <DGLGraph.number_of_nodes>`
# and can grow by calling :func:`add_nodes <DGLGraph.add_nodes>`.
# :class:`DGLGraph` edges are in order of their additions. Note that
44
# edges are accessed in much the same way as nodes, with one extra feature: *edge broadcasting*.
45
46
47
48
49
50

import dgl
import torch as th

g = dgl.DGLGraph()
g.add_nodes(10)
51
# A couple edges one-by-one
52
53
for i in range(1, 4):
    g.add_edge(i, 0)
54
# A few more with a paired list
55
56
57
58
59
60
src = list(range(5, 8)); dst = [0]*3
g.add_edges(src, dst)
# finish with a pair of tensors
src = th.tensor([8, 9]); dst = th.tensor([0, 0])
g.add_edges(src, dst)

61
# Edge broadcasting will do star graph in one go!
62
63
64
65
66
67
68
69
70
71
72
g.clear(); g.add_nodes(10)
src = th.tensor(list(range(1, 10)));
g.add_edges(src, 0)

import networkx as nx
import matplotlib.pyplot as plt
nx.draw(g.to_networkx(), with_labels=True)
plt.show()


###############################################################################
73
# Assigning a feature
74
# -------------------
75
# You can also assign features to nodes and edges of a :class:`DGLGraph`.  The
76
77
78
79
80
81
82
83
# features are represented as dictionary of names (strings) and tensors,
# called **fields**.
#
# The following code snippet assigns each node a vector (len=3).
#
# .. note::
#
#    DGL aims to be framework-agnostic, and currently it supports PyTorch and
84
#    MXNet tensors. The following examples use PyTorch only.
85
86
87
88
89
90
91
92
93

import dgl
import torch as th

x = th.randn(10, 3)
g.ndata['x'] = x


###############################################################################
94
95
96
# :func:`ndata <DGLGraph.ndata>` is a syntax sugar to access the state of all nodes. 
# States are stored
# in a container ``data`` that hosts a user-defined dictionary.
97
98
99

print(g.ndata['x'] == g.nodes[:].data['x'])

100
# Access node set with integer, list, or integer tensor
101
102
103
104
105
106
g.nodes[0].data['x'] = th.zeros(1, 3)
g.nodes[[0, 1, 2]].data['x'] = th.zeros(3, 3)
g.nodes[th.tensor([0, 1, 2])].data['x'] = th.zeros(3, 3)


###############################################################################
107
108
# Assigning edge features is similar to that of node features,
# except that you can also do it by specifying endpoints of the edges.
109
110
111

g.edata['w'] = th.randn(9, 2)

112
# Access edge set with IDs in integer, list, or integer tensor
113
114
115
116
g.edges[1].data['w'] = th.randn(1, 2)
g.edges[[0, 1, 2]].data['w'] = th.zeros(3, 2)
g.edges[th.tensor([0, 1, 2])].data['w'] = th.zeros(3, 2)

117
# You can also access the edges by giving endpoints
118
119
120
121
122
g.edges[1, 0].data['w'] = th.ones(1, 2)                 # edge 1 -> 0
g.edges[[1, 2, 3], [0, 0, 0]].data['w'] = th.ones(3, 2) # edges [1, 2, 3] -> 0


###############################################################################
123
# After assignments, each node or edge field will be associated with a scheme
124
125
126
127
128
129
130
131
# containing the shape and data type (dtype) of its field value.

print(g.node_attr_schemes())
g.ndata['x'] = th.zeros((10, 4))
print(g.node_attr_schemes())


###############################################################################
132
# You can also remove node or edge states from the graph. This is particularly
133
134
135
136
137
138
139
# useful to save memory during inference.

g.ndata.pop('x')
g.edata.pop('w')


###############################################################################
140
# Working with multigraphs
141
# ~~~~~~~~~~~~~~~~~~~~~~~~
142
# Many graph applications need parallel edges. To enable this, construct :class:`DGLGraph`
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# with ``multigraph=True``.

g_multi = dgl.DGLGraph(multigraph=True)
g_multi.add_nodes(10)
g_multi.ndata['x'] = th.randn(10, 2)

g_multi.add_edges(list(range(1, 10)), 0)
g_multi.add_edge(1, 0) # two edges on 1->0

g_multi.edata['w'] = th.randn(10, 2)
g_multi.edges[1].data['w'] = th.zeros(1, 2)
print(g_multi.edges())


###############################################################################
158
159
# An edge in multigraph cannot be uniquely identified by using its incident nodes
# :math:`u` and :math:`v`; query their edge IDs use ``edge_id`` interface.
160
161
162
163
164
165
166
167
168

eid_10 = g_multi.edge_id(1, 0)
g_multi.edges[eid_10].data['w'] = th.ones(len(eid_10), 2)
print(g_multi.edata['w'])


###############################################################################
# .. note::
#
169
170
#    * Nodes and edges can be added but not removed.
#    * Updating a feature of different schemes raises the risk of error on individual nodes (or
171
172
173
174
175
176
#      node subset).


###############################################################################
# Next steps
# ----------
177
# In the :doc:`next tutorial <3_pagerank>` you learn the
178
# DGL message passing interface by implementing PageRank.