Skip to content

Commit

Permalink
Merge pull request rapidsai#47 from jwyles/bfs_first
Browse files Browse the repository at this point in the history
BFS imported and python bindings added.
  • Loading branch information
BradReesWork authored Feb 4, 2019
2 parents 16a1097 + 248552e commit 2992ac2
Show file tree
Hide file tree
Showing 12 changed files with 2,575 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ endif (NVGRAPH_INCLUDE AND NVGRAPH_LIBRARY)
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/external/cub"
"${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}"
"${CUDF_INCLUDE}"
"${NVGRAPH_INCLUDE}"
Expand All @@ -204,6 +205,7 @@ add_library(cugraph SHARED
src/grmat.cu
src/cugraph.cu
src/pagerank.cu
src/bfs.cu
src/nvgraph_gdf.cu
${CMAKE_CURRENT_BINARY_DIR}/gunrock/gunrock/util/test_utils.cu
${CMAKE_CURRENT_BINARY_DIR}/gunrock/gunrock/util/error_utils.cu
Expand Down
2 changes: 2 additions & 0 deletions include/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ gdf_error gdf_delete_transpose(gdf_graph *graph);
gdf_error gdf_pagerank(gdf_graph *graph, gdf_column *pagerank, float alpha, float tolerance, int max_iter, bool has_guess);

gdf_error gdf_grmat_gen (const char* argv, size_t &vertices, size_t &edges, gdf_column* src, gdf_column* dest, gdf_column* val);

gdf_error gdf_bfs(gdf_graph *graph, gdf_column *distances, gdf_column *predecessors, int start_node, bool directed);
59 changes: 59 additions & 0 deletions python/bfs/bfs_wrapper.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from c_bfs cimport *
from libcpp cimport bool
from libc.stdint cimport uintptr_t
from libc.stdlib cimport calloc, malloc, free
import cudf
from librmm_cffi import librmm as rmm
#from pygdf import Column
import numpy as np

cpdef bfs(G, start, directed=True):
"""
Find the distances and predecessors for a breadth first traversal of a graph.
Parameters
----------
G : cugraph.graph
cuGraph graph descriptor, should contain the connectivity information as an
adjacency list.
start : Integer
The index of the graph vertex from which the traversal begins
directed : bool
Indicates whether the graph in question is a directed graph, or whether
each edge has a corresponding reverse edge. (Allows optimizations if the
graph is undirected)
Returns
-------
df : cudf.DataFrame
df['vertex'][i] gives the vertex id of the i'th vertex
df['distance'][i] gives the path distance for the i'th vertex from the starting vertex
df['predecessor'][i] gives for the i'th vertex the vertex it was reached from in the traversal
Examples
--------
>>> M = ReadMtxFile(graph_file)
>>> sources = cudf.Series(M.row)
>>> destinations = cudf.Series(M.col)
>>> G = cuGraph.Graph()
>>> G.add_edge_list(sources,destinations,none)
>>> dist, pred = cuGraph.bfs(G, 0, false)
"""

cdef uintptr_t graph = G.graph_ptr
cdef gdf_graph* g = <gdf_graph*>graph
num_verts = g.adjList.offsets.size - 1

df = cudf.DataFrame()
df['vertex'] = cudf.Series(np.zeros(num_verts, dtype=np.int32))
cdef uintptr_t vertex_ptr = create_column(df['vertex'])
df['distance'] = cudf.Series(np.zeros(num_verts, dtype=np.int32))
cdef uintptr_t distances_ptr = create_column(df['distance'])
df['predecessor'] = cudf.Series(np.zeros(num_verts, dtype=np.int32))
cdef uintptr_t predecessors_ptr = create_column(df['predecessor'])

err = g.adjList.get_vertex_identifiers(<gdf_column*>vertex_ptr)
cudf.bindings.cudf_cpp.check_gdf_error(err)

gdf_bfs(<gdf_graph*>g, <gdf_column*>distances_ptr, <gdf_column*>predecessors_ptr, <int>start, <bool>directed)
return df
6 changes: 6 additions & 0 deletions python/bfs/c_bfs.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from c_graph cimport *
from libcpp cimport bool

cdef extern from "cugraph.h":

cdef gdf_error gdf_bfs(gdf_graph *graph, gdf_column *distances, gdf_column *predecessors, int start_node, bool directed)
69 changes: 69 additions & 0 deletions python/bfs/test_bfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import cugraph
import cudf
import time
from scipy.io import mmread
import pytest
import numpy as np

def ReadMtxFile(mmFile):
print('Reading ' + str(mmFile) + '...')
return mmread(mmFile).asfptype()


def cugraph_Call(M, start_vertex):

# Device data
M = M.tocsr()
sources = cudf.Series(M.indptr)
destinations = cudf.Series(M.indices)
values = cudf.Series(M.data)

G = cugraph.Graph()
G.add_adj_list(sources, destinations, values)

t1 = time.time()
df = cugraph.bfs(G, start_vertex)
t2 = time.time() - t1
print('Time : '+str(t2))

# Return distances as np.array()
return np.array(df['distance'])


def base_Call(M, start_vertex):
intMax = 2147483647
M = M.tocsr()
offsets = M.indptr
indices = M.indices
num_verts = len(offsets) - 1
dist = np.zeros(num_verts, dtype=np.int32)

for i in range(num_verts):
dist[i] = intMax
import queue
q = queue.Queue()
q.put(start_vertex)
dist[start_vertex] = 0
while(not q.empty()):
u = q.get()
for iCol in range(offsets[u],offsets[u + 1]):
v = indices[iCol]
if (dist[v] == intMax):
dist[v] = dist[u] + 1
q.put(v)
return dist

datasets = ['/datasets/networks/dolphins.mtx',
'/datasets/networks/karate.mtx',
'/datasets/golden_data/graphs/dblp.mtx']

@pytest.mark.parametrize('graph_file', datasets)
def test_bfs(graph_file):

M = ReadMtxFile(graph_file)
base_dist = base_Call(M, 0)
dist = cugraph_Call(M, 0)

assert len(base_dist) == len(dist)
for i in range(len(dist)):
assert base_dist[i] == dist[i]
1 change: 1 addition & 0 deletions python/cugraph.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ include "sssp/sssp_wrapper.pyx"
include "jaccard/jaccard_wrapper.pyx"
include "grmat/grmat_wrapper.pyx"
include "louvain/louvain_wrapper.pyx"
include "bfs/bfs_wrapper.pyx"
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def locate_nvgraph():

# temporary fix. cudf 0.5 will have a cudf.get_include()
cudf_include = os.path.normpath(sys.prefix) + '/include'

cython_files = ['python/cugraph.pyx']

extensions = [
Expand Down
Loading

0 comments on commit 2992ac2

Please sign in to comment.