"...git@developer.sourcefind.cn:renzhc/diffusers_dcu.git" did not exist on "bac8a2412d4cb168116fba2fd8143f5dad44c832"
test_batch-graph.py 10.2 KB
Newer Older
1
import dgl
2
import numpy as np
3
import backend as F
4
import unittest
nv-dlasalle's avatar
nv-dlasalle committed
5
from test_utils import parametrize_idtype
6

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

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

nv-dlasalle's avatar
nv-dlasalle committed
45
@parametrize_idtype
46
47
48
def test_batch_unbatch(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
49
50

    bg = dgl.batch([t1, t2])
Minjie Wang's avatar
Minjie Wang committed
51
52
53
    assert bg.number_of_nodes() == 10
    assert bg.number_of_edges() == 8
    assert bg.batch_size == 2
54
55
    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
56
57

    tt1, tt2 = dgl.unbatch(bg)
58
59
60
61
    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
62

nv-dlasalle's avatar
nv-dlasalle committed
63
@parametrize_idtype
64
65
66
def test_batch_unbatch1(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
Minjie Wang's avatar
Minjie Wang committed
67
68
69
70
71
    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
72
73
    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
74
75

    s1, s2, s3 = dgl.unbatch(b2)
76
77
78
79
80
81
    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'])
82

83
@unittest.skipIf(dgl.backend.backend_name == "tensorflow", reason="TF doesn't support inplace update")
nv-dlasalle's avatar
nv-dlasalle committed
84
@parametrize_idtype
85
def test_batch_unbatch_frame(idtype):
86
87
88
    """Test module of node/edge frames of batched/unbatched DGLGraphs.
    Also address the bug mentioned in https://github.com/dmlc/dgl/issues/1475.
    """
89
90
    t1 = tree1(idtype)
    t2 = tree2(idtype)
91
92
93
94
95
96
97
98
99
100
    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))
    
101
102
103
104
105
106
107
108
109
110
    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)))
111

112
113
114
115
116
117
118
119
    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)))
120

nv-dlasalle's avatar
nv-dlasalle committed
121
@parametrize_idtype
122
def test_batch_unbatch2(idtype):
123
    # test setting/getting features after batch
124
    a = dgl.graph(([], [])).astype(idtype).to(F.ctx())
125
126
    a.add_nodes(4)
    a.add_edges(0, [1, 2, 3])
127
    b = dgl.graph(([], [])).astype(idtype).to(F.ctx())
128
129
130
    b.add_nodes(3)
    b.add_edges(0, [1, 2])
    c = dgl.batch([a, b])
131
132
133
134
    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)))
135

nv-dlasalle's avatar
nv-dlasalle committed
136
@parametrize_idtype
137
138
139
def test_batch_send_and_recv(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
140
141

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

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

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

nv-dlasalle's avatar
nv-dlasalle committed
153
@parametrize_idtype
154
155
156
def test_batch_propagate(idtype):
    t1 = tree1(idtype)
    t2 = tree2(idtype)
157
158

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

    order = []

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

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

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

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

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

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

nv-dlasalle's avatar
nv-dlasalle committed
210
@parametrize_idtype
211
212
213
214
215
216
217
218
219
220
221
def test_batch_keeps_empty_data(idtype):
    g1 = dgl.graph(([], [])).astype(idtype).to(F.ctx())
    g1.ndata["nh"] = F.tensor([])
    g1.edata["eh"] = F.tensor([]) 
    g2 = dgl.graph(([], [])).astype(idtype).to(F.ctx())
    g2.ndata["nh"] = F.tensor([])
    g2.edata["eh"] = F.tensor([]) 
    g = dgl.batch([g1, g2])
    assert "nh" in g.ndata
    assert "eh" in g.edata    

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def _get_subgraph_batch_info(keys, induced_indices_arr, batch_num_objs):
    """Internal function to compute batch information for subgraphs.
    Parameters
    ----------
    keys : List[str]
        The node/edge type keys.
    induced_indices_arr : List[Tensor]
        The induced node/edge index tensor for all node/edge types.
    batch_num_objs : Tensor
        Number of nodes/edges for each graph in the original batch.
    Returns
    -------
    Mapping[str, Tensor]
        A dictionary mapping all node/edge type keys to the ``batch_num_objs``
        array of corresponding graph.
    """
    bucket_offset = np.expand_dims(np.cumsum(F.asnumpy(batch_num_objs), 0), -1)  # (num_bkts, 1)
    ret = {}
    for key, induced_indices in zip(keys, induced_indices_arr):
        # NOTE(Zihao): this implementation is not efficient and we can replace it with
        # binary search in the future.
        induced_indices = np.expand_dims(F.asnumpy(induced_indices), 0)  # (1, num_nodes)
        new_offset = np.sum((induced_indices < bucket_offset), 1)  # (num_bkts,)
        # start_offset = [0] + [new_offset[i-1] for i in range(1, n_bkts)]
        start_offset = np.concatenate([np.zeros((1,)), new_offset[:-1]], 0)
        new_batch_num_objs = new_offset - start_offset
        ret[key] = F.tensor(new_batch_num_objs, dtype=F.dtype(batch_num_objs))
    return ret

nv-dlasalle's avatar
nv-dlasalle committed
251
@parametrize_idtype
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def test_set_batch_info(idtype):
    ctx = F.ctx()

    g1 = dgl.rand_graph(30, 100).astype(idtype).to(F.ctx())
    g2 = dgl.rand_graph(40, 200).astype(idtype).to(F.ctx())
    bg = dgl.batch([g1, g2])
    batch_num_nodes = F.astype(bg.batch_num_nodes(), idtype)
    batch_num_edges = F.astype(bg.batch_num_edges(), idtype)
    
    # test homogeneous node subgraph
    sg_n = dgl.node_subgraph(bg, list(range(10, 20)) + list(range(50, 60)))
    induced_nodes = sg_n.ndata['_ID']
    induced_edges = sg_n.edata['_ID']
    new_batch_num_nodes = _get_subgraph_batch_info(bg.ntypes, [induced_nodes], batch_num_nodes)
    new_batch_num_edges = _get_subgraph_batch_info(bg.canonical_etypes, [induced_edges], batch_num_edges)
    sg_n.set_batch_num_nodes(new_batch_num_nodes)
    sg_n.set_batch_num_edges(new_batch_num_edges)
    subg_n1, subg_n2 = dgl.unbatch(sg_n)
    subg1 = dgl.node_subgraph(g1, list(range(10, 20)))
    subg2 = dgl.node_subgraph(g2, list(range(20, 30)))
    assert subg_n1.num_edges() == subg1.num_edges()
    assert subg_n2.num_edges() == subg2.num_edges()

    # test homogeneous edge subgraph
276
277
    sg_e = dgl.edge_subgraph(bg, list(range(40, 70)) + list(range(150, 200)), relabel_nodes=False)
    induced_nodes = F.arange(0, bg.num_nodes(), idtype)
278
279
280
281
282
283
    induced_edges = sg_e.edata['_ID']
    new_batch_num_nodes = _get_subgraph_batch_info(bg.ntypes, [induced_nodes], batch_num_nodes)
    new_batch_num_edges = _get_subgraph_batch_info(bg.canonical_etypes, [induced_edges], batch_num_edges)
    sg_e.set_batch_num_nodes(new_batch_num_nodes)
    sg_e.set_batch_num_edges(new_batch_num_edges)
    subg_e1, subg_e2 = dgl.unbatch(sg_e)
284
285
    subg1 = dgl.edge_subgraph(g1, list(range(40, 70)), relabel_nodes=False)
    subg2 = dgl.edge_subgraph(g2, list(range(50, 100)), relabel_nodes=False)
286
287
288
289
    assert subg_e1.num_nodes() == subg1.num_nodes()
    assert subg_e2.num_nodes() == subg2.num_nodes()


290
if __name__ == '__main__':
291
292
293
    #test_batch_unbatch()
    #test_batch_unbatch1()
    #test_batch_unbatch_frame()
294
295
296
297
298
299
    #test_batch_unbatch2()
    #test_batched_edge_ordering()
    #test_batch_send_then_recv()
    #test_batch_send_and_recv()
    #test_batch_propagate()
    #test_batch_no_edge()
300
301
    test_set_batch_info(F.int32)