diff --git a/bkj_install.sh b/bkj_install.sh new file mode 100644 index 00000000000..3f760410c66 --- /dev/null +++ b/bkj_install.sh @@ -0,0 +1,21 @@ +conda env create --name cugraph_dev --file conda/environments/cugraph_dev_cuda11.0.yml +conda activate cugraph_dev + +# fix version of gcc +sudo apt install gcc-8 g++-8 gcc-9 g++-9 gcc-10 g++-10 +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 --slave /usr/bin/g++ g++ /usr/bin/g++-9 --slave /usr/bin/gcov gcov /usr/bin/gcov-9 + +PARALLEL_LEVEL=12 ./build.sh clean + +# libcugraph +cd cpp +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX +make -j +make install + +cd ../../ +cd python +python setup.py build_ext --inplace +python setup.py install \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index b0e52ba73b6..739a9304f59 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -72,7 +72,7 @@ option(BUILD_CUGRAPH_MG_TESTS "Build cuGraph multigpu algorithm tests" OFF) set(BLAS_LIBRARIES "" CACHE STRING "Location of BLAS library for FAISS build.") option(BUILD_STATIC_FAISS "Build the FAISS library for nearest neighbors search on GPU" OFF) option(CMAKE_CUDA_LINEINFO "Enable the -lineinfo option for nvcc (useful for cuda-memcheck / profiler" OFF) -option(BUILD_TESTS "Configure CMake to build tests" ON) +option(BUILD_TESTS "Configure CMake to build tests" OFF) ################################################################################################### # - compiler options ------------------------------------------------------------------------------ @@ -146,6 +146,7 @@ include(cmake/thirdparty/get_cuco.cmake) include(cmake/thirdparty/get_cuhornet.cmake) include(cmake/thirdparty/get_gunrock.cmake) +include(cmake/thirdparty/get_essentials.cmake) if(BUILD_TESTS) include(cmake/thirdparty/get_gtest.cmake) @@ -164,6 +165,7 @@ add_library(cugraph SHARED src/link_analysis/gunrock_hits.cpp src/traversal/bfs.cu src/traversal/sssp.cu + src/traversal/gunrock_sssp.cu src/traversal/tsp.cu src/link_prediction/jaccard.cu src/link_prediction/overlap.cu @@ -175,7 +177,7 @@ add_library(cugraph SHARED src/community/leiden.cu src/community/ktruss.cu src/community/ecg.cu - src/community/triangles_counting.cu + # src/community/triangles_counting.cu src/community/extract_subgraph_by_vertex.cu src/community/egonet.cu src/sampling/random_walks.cu @@ -197,7 +199,7 @@ add_library(cugraph SHARED src/experimental/pagerank.cu src/experimental/katz_centrality.cu src/tree/mst.cu - src/components/weakly_connected_components.cu + # src/components/weakly_connected_components.cu src/structure/create_graph_from_edgelist.cu src/utilities/host_barrier.cpp ) @@ -263,6 +265,7 @@ target_link_libraries(cugraph FAISS::FAISS gunrock NCCL::NCCL + essentials ) if(OpenMP_CXX_FOUND) diff --git a/cpp/cmake/thirdparty/get_essentials.cmake b/cpp/cmake/thirdparty/get_essentials.cmake new file mode 100644 index 00000000000..adce20e67b8 --- /dev/null +++ b/cpp/cmake/thirdparty/get_essentials.cmake @@ -0,0 +1,19 @@ +function(find_and_configure_essentials) + rapids_cpm_find( + essentials 0.0 + GLOBAL_TARGETS essentials + CPM_ARGS + GIT_REPOSITORY https://github.com/gunrock/essentials/ + GIT_TAG 52ea059b1d824778e15fe3c240ffaf8f02e8a105 + OPTIONS "ESSENTIALS_BUILD_EXAMPLES OFF" + ) + + if(NOT TARGET essentials) + add_library(essentials IMPORTED INTERFACE GLOBAL) + target_include_directories(essentials INTERFACE + "${essentials_SOURCE_DIR}/include" + ) + endif() +endfunction() + +find_and_configure_essentials() \ No newline at end of file diff --git a/cpp/include/cugraph/algorithms.hpp b/cpp/include/cugraph/algorithms.hpp index 0b0dd88ce29..25716f37949 100644 --- a/cpp/include/cugraph/algorithms.hpp +++ b/cpp/include/cugraph/algorithms.hpp @@ -530,6 +530,13 @@ void sssp(GraphCSRView const &graph, VT *predecessors, const VT source_vertex); +// essentials SSSP test +template +void gunrock_sssp(GraphCSRView const &graph, + WT *distances, + VT *predecessors, + VT source_vertex); + // FIXME: Internally distances is of int (signed 32-bit) data type, but current // template uses data from VT, ET, WT from he GraphCSR View even if weights // are not considered diff --git a/cpp/include/cugraph/utilities/cython.hpp b/cpp/include/cugraph/utilities/cython.hpp index 1e246b7255a..b679ec6f2e4 100644 --- a/cpp/include/cugraph/utilities/cython.hpp +++ b/cpp/include/cugraph/utilities/cython.hpp @@ -490,6 +490,15 @@ void call_sssp(raft::handle_t const& handle, vertex_t* predecessors, const vertex_t source_vertex); +// Wrapper for calling gunrock_sssp through a graph container +template +void call_gunrock_sssp(raft::handle_t const& handle, + graph_container_t const& graph_container, + vertex_t* identifiers, + weight_t* distances, + vertex_t* predecessors, + const vertex_t source_vertex); + // Wrapper for calling egonet through a graph container template std::unique_ptr call_egonet(raft::handle_t const& handle, diff --git a/cpp/src/traversal/gunrock_sssp.cu b/cpp/src/traversal/gunrock_sssp.cu new file mode 100644 index 00000000000..f9bc8e40fbd --- /dev/null +++ b/cpp/src/traversal/gunrock_sssp.cu @@ -0,0 +1,39 @@ +#include +#include + +#include + +#include + +namespace cugraph { + +namespace E = ::gunrock; // gunrock/essentials + +template +void gunrock_sssp(GraphCSRView const &graph, + WT *distances, + VT *predecessors, + VT source_vertex) +{ + + printf("gunrock_sssp: ok\n"); + + auto G = E::graph::build::from_csr( + graph.number_of_vertices, + graph.number_of_vertices, + graph.number_of_edges, + graph.offsets, + graph.indices, + graph.edge_data + ); + + E::sssp::run(G, source_vertex, distances, predecessors); +} + +// explicit instantiation +template void gunrock_sssp(GraphCSRView const &graph, + float *distances, + int *predecessors, + int source_vertex); + +} // namespace cugraph diff --git a/cpp/src/utilities/cython.cu b/cpp/src/utilities/cython.cu index 989de166699..bbd1ec1aeb1 100644 --- a/cpp/src/utilities/cython.cu +++ b/cpp/src/utilities/cython.cu @@ -981,6 +981,30 @@ void call_sssp(raft::handle_t const& handle, } } +// Wrapper for calling SSSP through a graph container +template +void call_gunrock_sssp(raft::handle_t const& handle, + graph_container_t const& graph_container, + vertex_t* identifiers, + weight_t* distances, + vertex_t* predecessors, + const vertex_t source_vertex) +{ + if (graph_container.graph_type == graphTypeEnum::GraphCSRViewFloat) { + graph_container.graph_ptr_union.GraphCSRViewFloatPtr->get_vertex_identifiers( + reinterpret_cast(identifiers)); + + gunrock_sssp( // handle, TODO: clarify: no raft_handle_t? why? + *(graph_container.graph_ptr_union.GraphCSRViewFloatPtr), + reinterpret_cast(distances), + reinterpret_cast(predecessors), + static_cast(source_vertex)); + } else { + CUGRAPH_FAIL("vertexType/edgeType combination unsupported"); + } +} + + // wrapper for shuffling: // template @@ -1360,6 +1384,13 @@ template void call_sssp(raft::handle_t const& handle, int64_t* predecessors, const int64_t source_vertex); +template void call_gunrock_sssp(raft::handle_t const& handle, + graph_container_t const& graph_container, + int32_t* identifiers, + float* distances, + int32_t* predecessors, + const int32_t source_vertex); + template std::unique_ptr> call_shuffle( raft::handle_t const& handle, int32_t* edgelist_major_vertices, diff --git a/python/cugraph/__init__.py b/python/cugraph/__init__.py index 1a113b93d8d..50b0a5d220f 100644 --- a/python/cugraph/__init__.py +++ b/python/cugraph/__init__.py @@ -15,7 +15,7 @@ ecg, ktruss_subgraph, k_truss, - louvain, + # louvain, leiden, spectralBalancedCutClustering, spectralModularityMaximizationClustering, @@ -23,7 +23,7 @@ analyzeClustering_edge_cut, analyzeClustering_ratio_cut, subgraph, - triangles, + # triangles, ego_graph, batched_ego_graphs, ) @@ -85,6 +85,7 @@ bfs, bfs_edges, sssp, + gunrock_sssp, shortest_path, filter_unreachable, shortest_path_length, diff --git a/python/cugraph/community/__init__.py b/python/cugraph/community/__init__.py index 9cc92637e20..76e116154dc 100644 --- a/python/cugraph/community/__init__.py +++ b/python/cugraph/community/__init__.py @@ -22,7 +22,7 @@ analyzeClustering_ratio_cut, ) from cugraph.community.subgraph_extraction import subgraph -from cugraph.community.triangle_count import triangles +# from cugraph.community.triangle_count import triangles from cugraph.community.ktruss_subgraph import ktruss_subgraph from cugraph.community.ktruss_subgraph import k_truss from cugraph.community.egonet import ego_graph diff --git a/python/cugraph/traversal/__init__.py b/python/cugraph/traversal/__init__.py index e74266d29fc..0b3c27835d6 100644 --- a/python/cugraph/traversal/__init__.py +++ b/python/cugraph/traversal/__init__.py @@ -22,3 +22,5 @@ from cugraph.traversal.traveling_salesperson import traveling_salesperson from cugraph.traversal.ms_bfs import concurrent_bfs, multi_source_bfs + +from cugraph.traversal.gunrock_sssp import gunrock_sssp \ No newline at end of file diff --git a/python/cugraph/traversal/gunrock_sssp.pxd b/python/cugraph/traversal/gunrock_sssp.pxd new file mode 100644 index 00000000000..33db3b51fe0 --- /dev/null +++ b/python/cugraph/traversal/gunrock_sssp.pxd @@ -0,0 +1,11 @@ +from cugraph.structure.graph_utilities cimport * + +cdef extern from "cugraph/utilities/cython.hpp" namespace "cugraph::cython": + + cdef void call_gunrock_sssp[vertex_t, weight_t]( + const handle_t &handle, + const graph_container_t &g, + vertex_t *identifiers, + weight_t *distances, + vertex_t *predecessors, + vertex_t start_vertex) except + diff --git a/python/cugraph/traversal/gunrock_sssp.py b/python/cugraph/traversal/gunrock_sssp.py new file mode 100644 index 00000000000..372a5c73159 --- /dev/null +++ b/python/cugraph/traversal/gunrock_sssp.py @@ -0,0 +1,4 @@ +from cugraph.traversal import gunrock_sssp_wrapper + +def gunrock_sssp(G, source=0): + return gunrock_sssp_wrapper.gunrock_sssp(G, source) \ No newline at end of file diff --git a/python/cugraph/traversal/gunrock_sssp_wrapper.pyx b/python/cugraph/traversal/gunrock_sssp_wrapper.pyx new file mode 100644 index 00000000000..65abdcdfbd1 --- /dev/null +++ b/python/cugraph/traversal/gunrock_sssp_wrapper.pyx @@ -0,0 +1,120 @@ +# Copyright (c) 2019-2021, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# cython: profile=False +# distutils: language = c++ +# cython: embedsignature = True +# cython: language_level = 3 + +cimport cugraph.traversal.gunrock_sssp as c_sssp +from cugraph.structure.graph_utilities cimport * +from cugraph.structure import graph_primtypes_wrapper +from libcpp cimport bool +from libc.stdint cimport uintptr_t +import cudf +import numpy as np + + +def gunrock_sssp(input_graph, source): + """ + Call sssp + """ + # Step 1: Declare the different variables + cdef graph_container_t graph_container + # FIXME: Offsets and indices are currently hardcoded to int, but this may + # not be acceptable in the future. + numberTypeMap = {np.dtype("int32") : numberTypeEnum.int32Type, + np.dtype("float32") : numberTypeEnum.floatType} + + # Pointers required for CSR Graph + cdef uintptr_t c_offsets_ptr = NULL # Pointer to the CSR offsets + cdef uintptr_t c_indices_ptr = NULL # Pointer to the CSR indices + cdef uintptr_t c_weights_ptr = NULL # Pointer to the CSR weights + cdef uintptr_t c_local_verts = NULL; + cdef uintptr_t c_local_edges = NULL; + cdef uintptr_t c_local_offsets = NULL; + weight_t = np.dtype("float32") + + # Pointers for SSSP / BFS + cdef uintptr_t c_identifier_ptr = NULL # Pointer to the DataFrame 'vertex' Series + cdef uintptr_t c_distance_ptr = NULL # Pointer to the DataFrame 'distance' Series + cdef uintptr_t c_predecessor_ptr = NULL # Pointer to the DataFrame 'predecessor' Series + + cdef unique_ptr[handle_t] handle_ptr + handle_ptr.reset(new handle_t()) + handle_ = handle_ptr.get(); + + # Step 2: Verify that input_graph has the expected format + # the SSSP implementation expects CSR format + if not input_graph.adjlist: + input_graph.view_adj_list() + + # Step 3: Extract CSR offsets, indices and indices + # - offsets: int (signed, 32-bit) + # - indices: int (signed, 32-bit) + # - weights: float / double + # Extract data_type from weights (not None: float / double, None: signed int 32-bit) + [offsets, indices] = graph_primtypes_wrapper.datatype_cast([input_graph.adjlist.offsets, input_graph.adjlist.indices], [np.int32]) + [weights] = graph_primtypes_wrapper.datatype_cast([input_graph.adjlist.weights], [np.float32, np.float64]) + c_offsets_ptr = offsets.__cuda_array_interface__['data'][0] + c_indices_ptr = indices.__cuda_array_interface__['data'][0] + + if weights is not None: + weight_t = weights.dtype + c_weights_ptr = weights.__cuda_array_interface__['data'][0] + + # Step 4: Setup number of vertices and number of edges + num_verts = input_graph.number_of_vertices() + num_edges = input_graph.number_of_edges(directed_edges=True) + + # Step 5: Check if source index is valid + if not 0 <= source < num_verts: + raise ValueError("Starting vertex should be between 0 to number of vertices") + + # Step 6: Generation of the result cudf.DataFrame + # Distances depends on data_type (c.f. Step 3) + df = cudf.DataFrame() + + df['vertex'] = cudf.Series(np.zeros(num_verts, dtype=np.int32)) + df['distance'] = cudf.Series(np.zeros(num_verts, dtype=weight_t)) + df['predecessor'] = cudf.Series(np.zeros(num_verts, dtype=np.int32)) + + # Step 7: Associate to cudf Series + c_identifier_ptr = df['vertex'].__cuda_array_interface__['data'][0] + c_distance_ptr = df['distance'].__cuda_array_interface__['data'][0] + c_predecessor_ptr = df['predecessor'].__cuda_array_interface__['data'][0] + + # Step 8: Dispatch to SSSP / BFS Based on weights + # - weights is not None: SSSP float or SSSP double + # - weights is None: BFS + populate_graph_container_legacy(graph_container, + ((graphTypeEnum.LegacyCSR)), + handle_[0], + c_offsets_ptr, c_indices_ptr, c_weights_ptr, + ((numberTypeEnum.int32Type)), + ((numberTypeEnum.int32Type)), + ((numberTypeMap[weight_t])), + num_verts, num_edges, + c_local_verts, c_local_edges, c_local_offsets) + + if weight_t == np.float32: + c_sssp.call_gunrock_sssp[int, float](handle_[0], + graph_container, + c_identifier_ptr, + c_distance_ptr, + c_predecessor_ptr, + source) + else: # This case should not happen + raise NotImplementedError + + return df