test_traversal.py 4.04 KB
Newer Older
1
import itertools
GaiYu0's avatar
GaiYu0 committed
2
3
4
import random
import sys
import time
5
import unittest
GaiYu0's avatar
GaiYu0 committed
6

7
import backend as F
8
9

import dgl
GaiYu0's avatar
GaiYu0 committed
10
11
12
import networkx as nx
import numpy as np
import scipy.sparse as sp
13
from pytests_utils import parametrize_idtype
Gan Quan's avatar
Gan Quan committed
14

GaiYu0's avatar
GaiYu0 committed
15
16
np.random.seed(42)

17

Gan Quan's avatar
Gan Quan committed
18
def toset(x):
VoVAllen's avatar
VoVAllen committed
19
    # F.zerocopy_to_numpy may return a int
20
    return set(F.zerocopy_to_numpy(x).tolist())
Gan Quan's avatar
Gan Quan committed
21

22

nv-dlasalle's avatar
nv-dlasalle committed
23
@parametrize_idtype
24
def test_bfs(idtype, n=100):
Minjie Wang's avatar
Minjie Wang committed
25
26
27
28
29
30
31
32
33
    def _bfs_nx(g_nx, src):
        edges = nx.bfs_edges(g_nx, src)
        layers_nx = [set([src])]
        edges_nx = []
        frontier = set()
        edge_frontier = set()
        for u, v in edges:
            if u in layers_nx[-1]:
                frontier.add(v)
34
                edge_frontier.add(g.edge_ids(int(u), int(v)))
Minjie Wang's avatar
Minjie Wang committed
35
36
37
38
            else:
                layers_nx.append(frontier)
                edges_nx.append(edge_frontier)
                frontier = set([v])
39
                edge_frontier = set([g.edge_ids(u, v)])
40
41
42
43
        # avoids empty successors
        if len(frontier) > 0 and len(edge_frontier) > 0:
            layers_nx.append(frontier)
            edges_nx.append(edge_frontier)
Minjie Wang's avatar
Minjie Wang committed
44
        return layers_nx, edges_nx
GaiYu0's avatar
GaiYu0 committed
45

46
    a = sp.random(n, n, 3 / n, data_rvs=lambda n: np.ones(n))
47
    g = dgl.from_scipy(a).astype(idtype)
48

Minjie Wang's avatar
Minjie Wang committed
49
    g_nx = g.to_networkx()
GaiYu0's avatar
GaiYu0 committed
50
    src = random.choice(range(n))
Minjie Wang's avatar
Minjie Wang committed
51
    layers_nx, _ = _bfs_nx(g_nx, src)
52
    layers_dgl = dgl.bfs_nodes_generator(g, src)
GaiYu0's avatar
GaiYu0 committed
53
54
55
    assert len(layers_dgl) == len(layers_nx)
    assert all(toset(x) == y for x, y in zip(layers_dgl, layers_nx))

Minjie Wang's avatar
Minjie Wang committed
56
    g_nx = nx.random_tree(n, seed=42)
57
    g = dgl.from_networkx(g_nx).astype(idtype)
Minjie Wang's avatar
Minjie Wang committed
58
59
    src = 0
    _, edges_nx = _bfs_nx(g_nx, src)
Gan Quan's avatar
Gan Quan committed
60
61
62
63
    edges_dgl = dgl.bfs_edges_generator(g, src)
    assert len(edges_dgl) == len(edges_nx)
    assert all(toset(x) == y for x, y in zip(edges_dgl, edges_nx))

64

nv-dlasalle's avatar
nv-dlasalle committed
65
@parametrize_idtype
66
def test_topological_nodes(idtype, n=100):
67
    a = sp.random(n, n, 3 / n, data_rvs=lambda n: np.ones(n))
GaiYu0's avatar
GaiYu0 committed
68
    b = sp.tril(a, -1).tocoo()
69
    g = dgl.from_scipy(b).astype(idtype)
GaiYu0's avatar
GaiYu0 committed
70
71
72

    layers_dgl = dgl.topological_nodes_generator(g)

73
    adjmat = g.adjacency_matrix(transpose=True)
74

GaiYu0's avatar
GaiYu0 committed
75
76
    def tensor_topo_traverse():
        n = g.number_of_nodes()
77
        mask = F.copy_to(F.ones((n, 1)), F.cpu())
78
        degree = F.spmm(adjmat, mask)
79
80
        while F.reduce_sum(mask) != 0.0:
            v = F.astype((degree == 0.0), F.float32)
GaiYu0's avatar
GaiYu0 committed
81
82
            v = v * mask
            mask = mask - v
83
            frontier = F.copy_to(F.nonzero_1d(F.squeeze(v, 1)), F.cpu())
GaiYu0's avatar
GaiYu0 committed
84
            yield frontier
85
            degree -= F.spmm(adjmat, v)
GaiYu0's avatar
GaiYu0 committed
86
87
88
89
90
91

    layers_spmv = list(tensor_topo_traverse())

    assert len(layers_dgl) == len(layers_spmv)
    assert all(toset(x) == toset(y) for x, y in zip(layers_dgl, layers_spmv))

92
93
94
95

DFS_LABEL_NAMES = ["forward", "reverse", "nontree"]


nv-dlasalle's avatar
nv-dlasalle committed
96
@parametrize_idtype
97
98
def test_dfs_labeled_edges(idtype, example=False):
    dgl_g = dgl.DGLGraph().astype(idtype)
Gan Quan's avatar
Gan Quan committed
99
100
    dgl_g.add_nodes(6)
    dgl_g.add_edges([0, 1, 0, 3, 3], [1, 2, 2, 4, 5])
GaiYu0's avatar
GaiYu0 committed
101
    dgl_edges, dgl_labels = dgl.dfs_labeled_edges_generator(
102
103
        dgl_g, [0, 3], has_reverse_edge=True, has_nontree_edge=True
    )
Gan Quan's avatar
Gan Quan committed
104
105
106
    dgl_edges = [toset(t) for t in dgl_edges]
    dgl_labels = [toset(t) for t in dgl_labels]
    g1_solutions = [
107
108
109
        # edges           labels
        [[0, 1, 1, 0, 2], [0, 0, 1, 1, 2]],
        [[2, 2, 0, 1, 0], [0, 1, 0, 2, 1]],
Gan Quan's avatar
Gan Quan committed
110
111
    ]
    g2_solutions = [
112
113
114
        # edges        labels
        [[3, 3, 4, 4], [0, 1, 0, 1]],
        [[4, 4, 3, 3], [0, 1, 0, 1]],
Gan Quan's avatar
Gan Quan committed
115
116
117
118
    ]

    def combine_frontiers(sol):
        es, ls = zip(*sol)
119
120
121
122
123
124
125
126
        es = [
            set(i for i in t if i is not None)
            for t in itertools.zip_longest(*es)
        ]
        ls = [
            set(i for i in t if i is not None)
            for t in itertools.zip_longest(*ls)
        ]
Gan Quan's avatar
Gan Quan committed
127
128
129
130
131
132
133
134
135
        return es, ls

    for sol_set in itertools.product(g1_solutions, g2_solutions):
        es, ls = combine_frontiers(sol_set)
        if es == dgl_edges and ls == dgl_labels:
            break
    else:
        assert False

136
137
138
139
140

if __name__ == "__main__":
    test_bfs(idtype="int32")
    test_topological_nodes(idtype="int32")
    test_dfs_labeled_edges(idtype="int32")