test_batched_graph.py 6.42 KB
Newer Older
1
import dgl
2
import backend as F
3
import unittest
4
from test_utils import parametrize_dtype
5

6
def tree1(idtype):
7
8
9
10
11
12
13
14
    """Generate a tree
         0
        / \
       1   2
      / \
     3   4
    Edges are from leaves to root.
    """
15
    g = dgl.DGLGraph().astype(idtype).to(F.ctx())
Minjie Wang's avatar
Minjie Wang committed
16
    g.add_nodes(5)
17
18
19
20
    g.add_edge(3, 1)
    g.add_edge(4, 1)
    g.add_edge(1, 0)
    g.add_edge(2, 0)
21
22
    g.ndata['h'] = F.tensor([0, 1, 2, 3, 4])
    g.edata['h'] = F.randn((4, 10))
23
24
    return g

25
def tree2(idtype):
26
27
28
29
30
31
32
33
    """Generate a tree
         1
        / \
       4   3
      / \
     2   0
    Edges are from leaves to root.
    """
34
    g = dgl.DGLGraph().astype(idtype).to(F.ctx())
Minjie Wang's avatar
Minjie Wang committed
35
    g.add_nodes(5)
36
37
38
39
    g.add_edge(2, 4)
    g.add_edge(0, 4)
    g.add_edge(4, 1)
    g.add_edge(3, 1)
40
41
    g.ndata['h'] = F.tensor([0, 1, 2, 3, 4])
    g.edata['h'] = F.randn((4, 10))
42
43
    return g

44
45
46
47
@parametrize_dtype
def test_batch_unbatch(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
48
49

    bg = dgl.batch([t1, t2])
Minjie Wang's avatar
Minjie Wang committed
50
51
52
    assert bg.number_of_nodes() == 10
    assert bg.number_of_edges() == 8
    assert bg.batch_size == 2
53
54
    assert F.allclose(bg.batch_num_nodes(), F.tensor([5, 5]))
    assert F.allclose(bg.batch_num_edges(), F.tensor([4, 4]))
Minjie Wang's avatar
Minjie Wang committed
55
56

    tt1, tt2 = dgl.unbatch(bg)
57
58
59
60
    assert F.allclose(t1.ndata['h'], tt1.ndata['h'])
    assert F.allclose(t1.edata['h'], tt1.edata['h'])
    assert F.allclose(t2.ndata['h'], tt2.ndata['h'])
    assert F.allclose(t2.edata['h'], tt2.edata['h'])
Minjie Wang's avatar
Minjie Wang committed
61

62
63
64
65
@parametrize_dtype
def test_batch_unbatch1(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
Minjie Wang's avatar
Minjie Wang committed
66
67
68
69
70
    b1 = dgl.batch([t1, t2])
    b2 = dgl.batch([t2, b1])
    assert b2.number_of_nodes() == 15
    assert b2.number_of_edges() == 12
    assert b2.batch_size == 3
71
72
    assert F.allclose(b2.batch_num_nodes(), F.tensor([5, 5, 5]))
    assert F.allclose(b2.batch_num_edges(), F.tensor([4, 4, 4]))
Minjie Wang's avatar
Minjie Wang committed
73
74

    s1, s2, s3 = dgl.unbatch(b2)
75
76
77
78
79
80
    assert F.allclose(t2.ndata['h'], s1.ndata['h'])
    assert F.allclose(t2.edata['h'], s1.edata['h'])
    assert F.allclose(t1.ndata['h'], s2.ndata['h'])
    assert F.allclose(t1.edata['h'], s2.edata['h'])
    assert F.allclose(t2.ndata['h'], s3.ndata['h'])
    assert F.allclose(t2.edata['h'], s3.edata['h'])
81

82
@unittest.skipIf(dgl.backend.backend_name == "tensorflow", reason="TF doesn't support inplace update")
83
84
@parametrize_dtype
def test_batch_unbatch_frame(idtype):
85
86
87
    """Test module of node/edge frames of batched/unbatched DGLGraphs.
    Also address the bug mentioned in https://github.com/dmlc/dgl/issues/1475.
    """
88
89
    t1 = tree1(idtype)
    t2 = tree2(idtype)
90
91
92
93
94
95
96
97
98
99
    N1 = t1.number_of_nodes()
    E1 = t1.number_of_edges()
    N2 = t2.number_of_nodes()
    E2 = t2.number_of_edges()
    D = 10
    t1.ndata['h'] = F.randn((N1, D))
    t1.edata['h'] = F.randn((E1, D))
    t2.ndata['h'] = F.randn((N2, D))
    t2.edata['h'] = F.randn((E2, D))
    
100
101
102
103
104
105
106
107
108
109
    b1 = dgl.batch([t1, t2])
    b2 = dgl.batch([t2])
    b1.ndata['h'][:N1] = F.zeros((N1, D))
    b1.edata['h'][:E1] = F.zeros((E1, D))
    b2.ndata['h'][:N2] = F.zeros((N2, D))
    b2.edata['h'][:E2] = F.zeros((E2, D))
    assert not F.allclose(t1.ndata['h'], F.zeros((N1, D)))
    assert not F.allclose(t1.edata['h'], F.zeros((E1, D)))
    assert not F.allclose(t2.ndata['h'], F.zeros((N2, D)))
    assert not F.allclose(t2.edata['h'], F.zeros((E2, D)))
110

111
112
113
114
115
116
117
118
    g1, g2 = dgl.unbatch(b1)
    _g2, = dgl.unbatch(b2)
    assert F.allclose(g1.ndata['h'], F.zeros((N1, D)))
    assert F.allclose(g1.edata['h'], F.zeros((E1, D)))
    assert F.allclose(g2.ndata['h'], t2.ndata['h'])
    assert F.allclose(g2.edata['h'], t2.edata['h'])
    assert F.allclose(_g2.ndata['h'], F.zeros((N2, D)))
    assert F.allclose(_g2.edata['h'], F.zeros((E2, D)))
119

120
121
@parametrize_dtype
def test_batch_unbatch2(idtype):
122
    # test setting/getting features after batch
123
    a = dgl.DGLGraph().astype(idtype).to(F.ctx())
124
125
    a.add_nodes(4)
    a.add_edges(0, [1, 2, 3])
126
    b = dgl.DGLGraph().astype(idtype).to(F.ctx())
127
128
129
    b.add_nodes(3)
    b.add_edges(0, [1, 2])
    c = dgl.batch([a, b])
130
131
132
133
    c.ndata['h'] = F.ones((7, 1))
    c.edata['w'] = F.ones((5, 1))
    assert F.allclose(c.ndata['h'], F.ones((7, 1)))
    assert F.allclose(c.edata['w'], F.ones((5, 1)))
134

135
136
137
138
@parametrize_dtype
def test_batch_send_and_recv(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
139
140

    bg = dgl.batch([t1, t2])
141
142
    _mfunc = lambda edges: {'m' : edges.src['h']}
    _rfunc = lambda nodes: {'h' : F.sum(nodes.mailbox['m'], 1)}
143
144
145
    u = [3, 4, 2 + 5, 0 + 5]
    v = [1, 1, 4 + 5, 4 + 5]

146
    bg.send_and_recv((u, v), _mfunc, _rfunc)
147
148

    t1, t2 = dgl.unbatch(bg)
149
150
    assert F.asnumpy(t1.ndata['h'][1]) == 7
    assert F.asnumpy(t2.ndata['h'][4]) == 2
151

152
153
154
155
@parametrize_dtype
def test_batch_propagate(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
156
157

    bg = dgl.batch([t1, t2])
158
159
    _mfunc = lambda edges: {'m' : edges.src['h']}
    _rfunc = lambda nodes: {'h' : F.sum(nodes.mailbox['m'], 1)}
160
161
162
163
164
    # get leaves.

    order = []

    # step 1
Lingfan Yu's avatar
Lingfan Yu committed
165
166
    u = [3, 4, 2 + 5, 0 + 5]
    v = [1, 1, 4 + 5, 4 + 5]
167
168
169
    order.append((u, v))

    # step 2
Lingfan Yu's avatar
Lingfan Yu committed
170
171
    u = [1, 2, 4 + 5, 3 + 5]
    v = [0, 0, 1 + 5, 1 + 5]
172
173
    order.append((u, v))

174
    bg.prop_edges(order, _mfunc, _rfunc)
Lingfan Yu's avatar
Lingfan Yu committed
175
    t1, t2 = dgl.unbatch(bg)
176

177
178
    assert F.asnumpy(t1.ndata['h'][0]) == 9
    assert F.asnumpy(t2.ndata['h'][1]) == 5
179

180
181
182
@parametrize_dtype
def test_batched_edge_ordering(idtype):
    g1 = dgl.DGLGraph().astype(idtype).to(F.ctx())
Lingfan Yu's avatar
Lingfan Yu committed
183
184
    g1.add_nodes(6)
    g1.add_edges([4, 4, 2, 2, 0], [5, 3, 3, 1, 1])
185
    e1 = F.randn((5, 10))
186
    g1.edata['h'] = e1
187
    g2 = dgl.DGLGraph().astype(idtype).to(F.ctx())
Lingfan Yu's avatar
Lingfan Yu committed
188
189
    g2.add_nodes(6)
    g2.add_edges([0, 1 ,2 ,5, 4 ,5], [1, 2, 3, 4, 3, 0])
190
    e2 = F.randn((6, 10))
191
    g2.edata['h'] = e2
192
    g = dgl.batch([g1, g2])
193
194
    r1 = g.edata['h'][g.edge_id(4, 5)]
    r2 = g1.edata['h'][g1.edge_id(4, 5)]
195
    assert F.array_equal(r1, r2)
196

197
198
199
@parametrize_dtype
def test_batch_no_edge(idtype):
    g1 = dgl.DGLGraph().astype(idtype).to(F.ctx())
Lingfan Yu's avatar
Lingfan Yu committed
200
201
    g1.add_nodes(6)
    g1.add_edges([4, 4, 2, 2, 0], [5, 3, 3, 1, 1])
202
    g2 = dgl.DGLGraph().astype(idtype).to(F.ctx())
Lingfan Yu's avatar
Lingfan Yu committed
203
204
    g2.add_nodes(6)
    g2.add_edges([0, 1, 2, 5, 4, 5], [1 ,2 ,3, 4, 3, 0])
205
    g3 = dgl.DGLGraph().astype(idtype).to(F.ctx())
Lingfan Yu's avatar
Lingfan Yu committed
206
207
208
    g3.add_nodes(1)  # no edges
    g = dgl.batch([g1, g3, g2]) # should not throw an error

209
210
if __name__ == '__main__':
    test_batch_unbatch()
Minjie Wang's avatar
Minjie Wang committed
211
    test_batch_unbatch1()
212
    test_batch_unbatch_frame()
213
214
215
216
217
218
    #test_batch_unbatch2()
    #test_batched_edge_ordering()
    #test_batch_send_then_recv()
    #test_batch_send_and_recv()
    #test_batch_propagate()
    #test_batch_no_edge()