Commit e7679cf2 authored by GaiYu0's avatar GaiYu0
Browse files

implement requested changes

parent eb46dc00
...@@ -29,8 +29,6 @@ tensor = th.tensor ...@@ -29,8 +29,6 @@ tensor = th.tensor
sparse_tensor = th.sparse.FloatTensor sparse_tensor = th.sparse.FloatTensor
sum = th.sum sum = th.sum
max = th.max max = th.max
abs = th.abs
all = lambda x: x.byte().all()
stack = th.stack stack = th.stack
def astype(a, ty): def astype(a, ty):
...@@ -42,23 +40,6 @@ def asnumpy(a): ...@@ -42,23 +40,6 @@ def asnumpy(a):
def from_numpy(np_data): def from_numpy(np_data):
return th.from_numpy(np_data) return th.from_numpy(np_data)
def from_scipy_sparse(x):
x_coo = x.tocoo()
row = th.LongTensor(x_coo.row)
col = th.LongTensor(x_coo.col)
idx = th.stack([row, col])
dat = th.FloatTensor(x_coo.data)
return th.sparse.FloatTensor(idx, dat, x_coo.shape)
def to_scipy_sparse(x):
x_cpu = x.cpu()
idx = x._indices()
row, col = idx.chunk(2, 0)
row = row.squeeze(0).numpy()
col = col.squeeze(0).numpy()
dat = x._values().numpy()
return sp.sparse.coo_matrix((dat, (row, col)), shape=x.shape)
def pack(tensors, dim=0): def pack(tensors, dim=0):
return th.cat(tensors, dim) return th.cat(tensors, dim)
...@@ -71,9 +52,6 @@ def shape(x): ...@@ -71,9 +52,6 @@ def shape(x):
def dtype(x): def dtype(x):
return x.dtype return x.dtype
def item(x):
return x.item()
unique = th.unique unique = th.unique
def gather_row(data, row_index): def gather_row(data, row_index):
......
...@@ -18,10 +18,19 @@ def sbm(n_blocks, block_size, p, q, rng=None): ...@@ -18,10 +18,19 @@ def sbm(n_blocks, block_size, p, q, rng=None):
Parameters Parameters
---------- ----------
n_blocks : number of blocks n_blocks : int
block_size : block size Number of blocks.
p : probability for intra-community edge block_size : int
q : probability for inter-community edge Block size.
p : float
Probability for intra-community edge.
q : float
Probability for inter-community edge.
Returns
-------
scipy sparse matrix
The adjacency matrix of generated graph.
""" """
n = n_blocks * block_size n = n_blocks * block_size
p /= n p /= n
...@@ -45,17 +54,28 @@ def sbm(n_blocks, block_size, p, q, rng=None): ...@@ -45,17 +54,28 @@ def sbm(n_blocks, block_size, p, q, rng=None):
return adj return adj
class SBMMixture(Dataset): class SBMMixture(Dataset):
""" Symmetric Stochastic Block Model Mixture
Please refer to Appendix C of "Supervised Community Detection with Hierarchical Graph Neural Networks" (https://arxiv.org/abs/1705.08415) for details.
Parameters
----------
n_graphs : int
Number of graphs.
n_nodes : int
Number of nodes.
n_communities : int
Number of communities.
k : int, optional
Multiplier.
avg_deg : int, optional
Average degree.
p : callable or str, optional
Random density generator.
rng : numpy.random.RandomState, optional
Random number generator.
"""
def __init__(self, n_graphs, n_nodes, n_communities, def __init__(self, n_graphs, n_nodes, n_communities,
k=2, avg_deg=3, p='Appendix C', rng=None): k=2, avg_deg=3, p='Appendix C', rng=None):
""" Symmetric Stochastic Block Model Mixture
n_graphs : number of graphs
n_nodes : number of nodes
n_communities : number of communities
k : multiplier, optional
avg_deg : average degree, optional
p : random density generator, optional
rng : random number generator, optional
"""
super(SBMMixture, self).__init__() super(SBMMixture, self).__init__()
self._n_nodes = n_nodes self._n_nodes = n_nodes
assert n_nodes % n_communities == 0 assert n_nodes % n_communities == 0
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
from __future__ import absolute_import from __future__ import absolute_import
import networkx as nx import networkx as nx
import scipy as sp
import dgl import dgl
from .base import ALL, is_all, __MSG__, __REPR__ from .base import ALL, is_all, __MSG__, __REPR__
...@@ -472,7 +471,8 @@ class DGLGraph(object): ...@@ -472,7 +471,8 @@ class DGLGraph(object):
Parameters Parameters
---------- ----------
a : a : scipy sparse matrix
The graph's adjacency matrix
""" """
self.clear() self.clear()
self._graph.from_scipy_sparse_matrix(a) self._graph.from_scipy_sparse_matrix(a)
...@@ -1233,44 +1233,55 @@ class DGLGraph(object): ...@@ -1233,44 +1233,55 @@ class DGLGraph(object):
self._edge_frame.num_rows, self._edge_frame.num_rows,
reduce_func) reduce_func)
def adjacency_matrix(self): def adjacency_matrix(self, ctx=None):
"""Return the adjacency matrix representation of this graph. """Return the adjacency matrix representation of this graph.
Parameters
----------
ctx : optional
The context of returned adjacency matrix.
Returns Returns
------- -------
utils.CtxCachedObject sparse_tensor
An object that returns tensor given context. The adjacency matrix.
""" """
return self._graph.adjacency_matrix() return self._graph.adjacency_matrix().get(ctx)
def incidence_matrix(self, oriented=False, sorted=False): def incidence_matrix(self, oriented=False, ctx=None):
"""Return the incidence matrix representation of this graph. """Return the incidence matrix representation of this graph.
Parameters
----------
oriented : bool, optional
Whether the returned incidence matrix is oriented.
ctx : optional
The context of returned incidence matrix.
Returns Returns
------- -------
utils.CtxCachedObject sparse_tensor
An object that returns tensor given context. The incidence matrix.
""" """
return self._graph.incidence_matrix(oriented, sorted) return self._graph.incidence_matrix(oriented).get(ctx)
def line_graph(self, backtracking=True, sorted=False): def line_graph(self, backtracking=True, shared=False):
"""Return the line graph of this graph. """Return the line graph of this graph.
Parameters
----------
backtracking : bool, optional
Whether the returned line graph is backtracking.
shared : bool, optional
Whether the returned line graph shares representations with `self`.
Returns Returns
------- -------
DGLGraph DGLGraph
The line graph of this graph. The line graph of this graph.
""" """
return DGLGraph(self._graph.line_graph(backtracking, sorted)) graph_data = self._graph.line_graph(backtracking)
node_frame = self._edge_frame if shared else None
def _get_repr(attr_dict): return DGLGraph(graph_data, node_frame)
if len(attr_dict) == 1 and __REPR__ in attr_dict:
return attr_dict[__REPR__]
else:
return attr_dict
def _set_repr(attr_dict, attr):
if utils.is_dict_like(attr):
attr_dict.update(attr)
else:
attr_dict[__REPR__] = attr
...@@ -408,26 +408,22 @@ class GraphIndex(object): ...@@ -408,26 +408,22 @@ class GraphIndex(object):
self._cache['adj'] = utils.CtxCachedObject(lambda ctx: F.to_context(mat, ctx)) self._cache['adj'] = utils.CtxCachedObject(lambda ctx: F.to_context(mat, ctx))
return self._cache['adj'] return self._cache['adj']
def incidence_matrix(self, oriented=False, sorted=False): def incidence_matrix(self, oriented=False):
"""Return the incidence matrix representation of this graph. """Return the incidence matrix representation of this graph.
Parameters Parameters
---------- ----------
oriented : bool, optional (default=False) oriented : bool, optional (default=False)
Whether the returned incidence matrix is oriented. Whether the returned incidence matrix is oriented.
sorted : bool, optional (default=False)
If true, nodes in L(G) are sorted as pairs.
If False, nodes in L(G) are ordered by their edge id's in G.
Returns Returns
------- -------
utils.CtxCachedObject utils.CtxCachedObject
An object that returns tensor given context. An object that returns tensor given context.
""" """
key = ('oriented ' if oriented else '') + \ key = ('oriented ' if oriented else '') + 'incidence matrix'
('sorted ' if sorted else '') + 'incidence matrix'
if not key in self._cache: if not key in self._cache:
src, dst, _ = self.edges(sorted=sorted) src, dst, _ = self.edges(sorted=False)
src = src.tousertensor() src = src.tousertensor()
dst = dst.tousertensor() dst = dst.tousertensor()
m = self.number_of_edges() m = self.number_of_edges()
...@@ -519,7 +515,7 @@ class GraphIndex(object): ...@@ -519,7 +515,7 @@ class GraphIndex(object):
dst = utils.toindex(adj_coo.col) dst = utils.toindex(adj_coo.col)
self.add_edges(src, dst) self.add_edges(src, dst)
def line_graph(self, backtracking=True, sorted=False): def line_graph(self, backtracking=True):
"""Return the line graph of this graph. """Return the line graph of this graph.
Parameters Parameters
...@@ -527,9 +523,6 @@ class GraphIndex(object): ...@@ -527,9 +523,6 @@ class GraphIndex(object):
backtracking : bool, optional (default=False) backtracking : bool, optional (default=False)
Whether (i, j) ~ (j, i) in L(G). Whether (i, j) ~ (j, i) in L(G).
(i, j) ~ (j, i) is the behavior of networkx.line_graph. (i, j) ~ (j, i) is the behavior of networkx.line_graph.
sorted : bool, optional (default=False)
If true, nodes in L(G) are sorted as pairs.
If False, nodes in L(G) are ordered by their edge id's in G.
Returns Returns
------- -------
......
// Graph operation implementation // Graph operation implementation
#include <dgl/graph_op.h> #include <dgl/graph_op.h>
#include <algorithm> #include <algorithm>
#include <stdio.h>
namespace dgl { namespace dgl {
......
...@@ -9,20 +9,18 @@ def check_eq(a, b): ...@@ -9,20 +9,18 @@ def check_eq(a, b):
return a.shape == b.shape and np.allclose(a.numpy(), b.numpy()) return a.shape == b.shape and np.allclose(a.numpy(), b.numpy())
def test_line_graph(): def test_line_graph():
# FIXME
return
"""
N = 5 N = 5
G = dgl.DGLGraph(nx.star_graph(N)) G = dgl.DGLGraph(nx.star_graph(N))
G.set_e_repr(th.randn((2*N, D))) G.set_e_repr(th.randn((2 * N, D)))
n_edges = G.number_of_edges() n_edges = G.number_of_edges()
L = dgl.line_graph(G) L = G.line_graph(shared=True)
assert L.number_of_nodes() == 2*N assert L.number_of_nodes() == 2 * N
L.set_n_repr(th.randn((2 * N, D)))
# update node features on line graph should reflect to edge features on # update node features on line graph should reflect to edge features on
# original graph. # original graph.
u = [0, 0, 2, 3] u = [0, 0, 2, 3]
v = [1, 2, 0, 0] v = [1, 2, 0, 0]
eid = G.get_edge_id(u, v) eid = G.edge_ids(u, v)
L.set_n_repr(th.zeros((4, D)), eid) L.set_n_repr(th.zeros((4, D)), eid)
assert check_eq(G.get_e_repr(u, v), th.zeros((4, D))) assert check_eq(G.get_e_repr(u, v), th.zeros((4, D)))
...@@ -31,23 +29,18 @@ def test_line_graph(): ...@@ -31,23 +29,18 @@ def test_line_graph():
data = th.randn(n_edges, D) data = th.randn(n_edges, D)
L.set_n_repr({'w': data}) L.set_n_repr({'w': data})
assert check_eq(G.get_e_repr()['w'], data) assert check_eq(G.get_e_repr()['w'], data)
"""
def test_no_backtracking(): def test_no_backtracking():
# FIXME
return
"""
N = 5 N = 5
G = dgl.DGLGraph(nx.star_graph(N)) G = dgl.DGLGraph(nx.star_graph(N))
G.set_e_repr(th.randn((2*N, D))) G.set_e_repr(th.randn((2 * N, D)))
L = dgl.line_graph(G, no_backtracking=True) L = G.line_graph(backtracking=False)
assert L.number_of_nodes() == 2*N assert L.number_of_nodes() == 2 * N
for i in range(1, N): for i in range(1, N):
e1 = G.get_edge_id(0, i) e1 = G.edge_id(0, i)
e2 = G.get_edge_id(i, 0) e2 = G.edge_id(i, 0)
assert not L.has_edge(e1, e2) assert not L.has_edge(e1, e2)
assert not L.has_edge(e2, e1) assert not L.has_edge(e2, e1)
"""
if __name__ == '__main__': if __name__ == '__main__':
test_line_graph() test_line_graph()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment