Skip to content

Commit 5e024a4

Browse files
authored
Merge pull request #870 from ChuckHastings/fix_louvain
[REVIEW] Fix louvain
2 parents a2d22e3 + 87975fd commit 5e024a4

30 files changed

+857
-3687
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
- PR #852 Fix BFS Notebook
6262
- PR #855 Missed a file in the original SNMG PR
6363
- PR #860 Fix all Notebooks
64+
- PR #870 Fix Louvain
6465
- PR #889 Added missing conftest.py file to benchmarks dir
6566
- PR #896 opg dask infrastructure fixes
6667

cpp/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,9 @@ add_library(cugraph SHARED
316316
src/converters/renumber.cu
317317
src/converters/COOtoCSR.cu
318318
src/community/spectral_clustering.cu
319+
src/community/louvain.cpp
320+
src/community/louvain_kernels.cu
319321
src/community/ktruss.cu
320-
src/community/louvain.cu
321322
src/community/ECG.cu
322323
src/community/triangles_counting.cu
323324
src/community/extract_subgraph_by_vertex.cu

cpp/include/algorithms.hpp

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,62 @@ void bfs(experimental::GraphCSRView<VT, ET, WT> const &graph,
553553
const VT start_vertex,
554554
bool directed = true);
555555

556+
/**
557+
* @brief Louvain implementation
558+
*
559+
* Compute a clustering of the graph by minimizing modularity
560+
*
561+
* @throws cugraph::logic_error when an error occurs.
562+
*
563+
* @tparam VT Type of vertex identifiers.
564+
* Supported value : int (signed, 32-bit)
565+
* @tparam ET Type of edge identifiers.
566+
* Supported value : int (signed, 32-bit)
567+
* @tparam WT Type of edge weights. Supported values : float or double.
568+
*
569+
* @param[in] graph input graph object (CSR)
570+
* @param[out] final_modularity modularity of the returned clustering
571+
* @param[out] num_level number of levels of the returned clustering
572+
* @param[out] clustering Pointer to device array where the clustering should be stored
573+
* @param[in] max_iter (optional) maximum number of iterations to run (default 100)
574+
*/
575+
template <typename VT, typename ET, typename WT>
576+
void louvain(experimental::GraphCSRView<VT, ET, WT> const &graph,
577+
WT *final_modularity,
578+
int *num_level,
579+
VT *louvain_parts,
580+
int max_iter = 100);
581+
582+
/**
583+
* @brief Computes the ecg clustering of the given graph.
584+
*
585+
* ECG runs truncated Louvain on an ensemble of permutations of the input graph,
586+
* then uses the ensemble partitions to determine weights for the input graph.
587+
* The final result is found by running full Louvain on the input graph using
588+
* the determined weights. See https://arxiv.org/abs/1809.05578 for further
589+
* information.
590+
*
591+
* @throws cugraph::logic_error when an error occurs.
592+
*
593+
* @tparam VT Type of vertex identifiers. Supported value : int (signed,
594+
* 32-bit)
595+
* @tparam ET Type of edge identifiers. Supported value : int (signed,
596+
* 32-bit)
597+
* @tparam WT Type of edge weights. Supported values : float or double.
598+
*
599+
* @param[in] graph_coo input graph object (COO)
600+
* @param[in] graph_csr input graph object (CSR)
601+
* @param[in] min_weight The minimum weight parameter
602+
* @param[in] ensemble_size The ensemble size parameter
603+
* @param[out] ecg_parts A device pointer to array where the partitioning should be
604+
* written
605+
*/
606+
template <typename VT, typename ET, typename WT>
607+
void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph_csr,
608+
WT min_weight,
609+
VT ensemble_size,
610+
VT *ecg_parts);
611+
556612
namespace nvgraph {
557613

558614
/**
@@ -725,59 +781,5 @@ void analyzeClustering_ratio_cut(experimental::GraphCSRView<VT, ET, WT> const &g
725781
VT const *clustering,
726782
WT *score);
727783

728-
/**
729-
* @brief Wrapper function for Nvgraph louvain implementation
730-
*
731-
* @throws cugraph::logic_error when an error occurs.
732-
*
733-
* @tparam VT Type of vertex identifiers. Supported value : int (signed,
734-
* 32-bit)
735-
* @tparam ET Type of edge identifiers. Supported value : int (signed,
736-
* 32-bit)
737-
* @tparam WT Type of edge weights. Supported values : float or double.
738-
*
739-
* @param[in] graph input graph object (CSR)
740-
* @param[out] final_modularity modularity of the returned clustering
741-
* @param[out] num_level number of levels of the returned clustering
742-
* @param[out] clustering Pointer to device array where the clustering should be stored
743-
* @param[in] max_iter (optional) maximum number of iterations to run (default 100)
744-
*/
745-
template <typename VT, typename ET, typename WT>
746-
void louvain(experimental::GraphCSRView<VT, ET, WT> const &graph,
747-
WT *final_modularity,
748-
VT *num_level,
749-
VT *louvain_parts,
750-
int max_iter = 100);
751-
752-
/**
753-
* @brief Computes the ecg clustering of the given graph.
754-
*
755-
* ECG runs truncated Louvain on an ensemble of permutations of the input graph,
756-
* then uses the ensemble partitions to determine weights for the input graph.
757-
* The final result is found by running full Louvain on the input graph using
758-
* the determined weights. See https://arxiv.org/abs/1809.05578 for further
759-
* information.
760-
*
761-
* @throws cugraph::logic_error when an error occurs.
762-
*
763-
* @tparam VT Type of vertex identifiers. Supported value : int (signed,
764-
* 32-bit)
765-
* @tparam ET Type of edge identifiers. Supported value : int (signed,
766-
* 32-bit)
767-
* @tparam WT Type of edge weights. Supported values : float or double.
768-
*
769-
* @param[in] graph_coo input graph object (COO)
770-
* @param[in] graph_csr input graph object (CSR)
771-
* @param[in] min_weight The minimum weight parameter
772-
* @param[in] ensemble_size The ensemble size parameter
773-
* @param[out] ecg_parts A device pointer to array where the partitioning should be
774-
* written
775-
*/
776-
template <typename VT, typename ET, typename WT>
777-
void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph_csr,
778-
WT min_weight,
779-
VT ensemble_size,
780-
VT *ecg_parts);
781-
782784
} // namespace nvgraph
783785
} // namespace cugraph

cpp/src/community/ECG.cu

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,21 @@ struct update_functor {
9292
* responsible for freeing the allocated memory using ALLOC_FREE_TRY().
9393
*/
9494
template <typename T>
95-
void get_permutation_vector(T size, T seed, T *permutation)
95+
void get_permutation_vector(T size, T seed, T *permutation, cudaStream_t stream)
9696
{
9797
rmm::device_vector<float> randoms_v(size);
9898

9999
thrust::counting_iterator<uint32_t> index(seed);
100100
thrust::transform(
101-
rmm::exec_policy(nullptr)->on(nullptr), index, index + size, randoms_v.begin(), prg());
102-
thrust::sequence(rmm::exec_policy(nullptr)->on(nullptr), permutation, permutation + size, 0);
101+
rmm::exec_policy(stream)->on(stream), index, index + size, randoms_v.begin(), prg());
102+
thrust::sequence(rmm::exec_policy(stream)->on(stream), permutation, permutation + size, 0);
103103
thrust::sort_by_key(
104-
rmm::exec_policy(nullptr)->on(nullptr), randoms_v.begin(), randoms_v.end(), permutation);
104+
rmm::exec_policy(stream)->on(stream), randoms_v.begin(), randoms_v.end(), permutation);
105105
}
106106

107107
} // anonymous namespace
108108

109109
namespace cugraph {
110-
namespace nvgraph {
111110

112111
template <typename VT, typename ET, typename WT>
113112
void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph,
@@ -118,7 +117,9 @@ void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph,
118117
CUGRAPH_EXPECTS(graph.edge_data != nullptr, "API error, louvain expects a weighted graph");
119118
CUGRAPH_EXPECTS(ecg_parts != nullptr, "Invalid API parameter: ecg_parts is NULL");
120119

121-
rmm::device_vector<WT> ecg_weights_v(graph.number_of_edges, WT{0.0});
120+
cudaStream_t stream{0};
121+
122+
rmm::device_vector<WT> ecg_weights_v(graph.edge_data, graph.edge_data + graph.number_of_edges);
122123

123124
VT size{graph.number_of_vertices};
124125
VT seed{0};
@@ -133,7 +134,7 @@ void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph,
133134
rmm::device_vector<VT> permutation_v(size);
134135
VT *d_permutation = permutation_v.data().get();
135136

136-
get_permutation_vector(size, seed, d_permutation);
137+
get_permutation_vector(size, seed, d_permutation, stream);
137138
seed += size;
138139

139140
detail::permute_graph<VT, ET, WT>(graph, d_permutation, permuted_graph->view());
@@ -145,25 +146,25 @@ void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph,
145146
WT final_modularity;
146147
VT num_level;
147148

148-
cugraph::nvgraph::louvain(permuted_graph->view(), &final_modularity, &num_level, d_parts, 1);
149+
cugraph::louvain(permuted_graph->view(), &final_modularity, &num_level, d_parts, 1);
149150

150151
// For each edge in the graph determine whether the endpoints are in the same partition
151152
// Keep a sum for each edge of the total number of times its endpoints are in the same partition
152153
dim3 grid, block;
153154
block.x = 512;
154155
grid.x = min(VT{CUDA_MAX_BLOCKS}, (graph.number_of_edges / 512 + 1));
155-
match_check_kernel<<<grid, block, 0, nullptr>>>(graph.number_of_edges,
156-
graph.number_of_vertices,
157-
graph.offsets,
158-
graph.indices,
159-
permutation_v.data().get(),
160-
d_parts,
161-
ecg_weights_v.data().get());
156+
match_check_kernel<<<grid, block, 0, stream>>>(graph.number_of_edges,
157+
graph.number_of_vertices,
158+
graph.offsets,
159+
graph.indices,
160+
permutation_v.data().get(),
161+
d_parts,
162+
ecg_weights_v.data().get());
162163
}
163164

164165
// Set weights = min_weight + (1 - min-weight)*sum/ensemble_size
165166
update_functor<WT> uf(min_weight, ensemble_size);
166-
thrust::transform(rmm::exec_policy(nullptr)->on(nullptr),
167+
thrust::transform(rmm::exec_policy(stream)->on(stream),
167168
ecg_weights_v.data().get(),
168169
ecg_weights_v.data().get() + graph.number_of_edges,
169170
ecg_weights_v.data().get(),
@@ -179,7 +180,7 @@ void ecg(experimental::GraphCSRView<VT, ET, WT> const &graph,
179180

180181
WT final_modularity;
181182
VT num_level;
182-
cugraph::nvgraph::louvain(louvain_graph, &final_modularity, &num_level, ecg_parts, 100);
183+
cugraph::louvain(louvain_graph, &final_modularity, &num_level, ecg_parts, 100);
183184
}
184185

185186
// Explicit template instantiations.
@@ -193,5 +194,4 @@ template void ecg<int32_t, int32_t, double>(
193194
double min_weight,
194195
int32_t ensemble_size,
195196
int32_t *ecg_parts);
196-
} // namespace nvgraph
197197
} // namespace cugraph

cpp/src/community/louvain.cu renamed to cpp/src/community/louvain.cpp

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
#include <algorithms.hpp>
1818
#include <graph.hpp>
1919

20-
#include <nvgraph/include/nvlouvain.cuh>
20+
#include <rmm/thrust_rmm_allocator.h>
21+
22+
#include <thrust/sequence.h>
23+
24+
#include <community/louvain_kernels.hpp>
25+
2126
#include "utilities/error_utils.h"
2227

2328
namespace cugraph {
24-
namespace nvgraph {
2529

2630
template <typename VT, typename ET, typename WT>
2731
void louvain(experimental::GraphCSRView<VT, ET, WT> const &graph,
2832
WT *final_modularity,
29-
VT *num_level,
33+
int *num_level,
3034
VT *louvain_parts,
3135
int max_iter)
3236
{
@@ -35,38 +39,12 @@ void louvain(experimental::GraphCSRView<VT, ET, WT> const &graph,
3539
CUGRAPH_EXPECTS(num_level != nullptr, "API error, num_level is null");
3640
CUGRAPH_EXPECTS(louvain_parts != nullptr, "API error, louvain_parts is null");
3741

38-
std::ostream log(0);
39-
40-
bool weighted{true};
41-
42-
WT mod{0.0};
43-
VT n_level{0};
44-
45-
nvlouvain::louvain<VT, WT>(graph.offsets,
46-
graph.indices,
47-
graph.edge_data,
48-
graph.number_of_vertices,
49-
graph.number_of_edges,
50-
weighted,
51-
false,
52-
nullptr,
53-
mod,
54-
louvain_parts,
55-
n_level,
56-
max_iter,
57-
log);
58-
59-
*final_modularity = mod;
60-
*num_level = n_level;
42+
detail::louvain<VT, ET, WT>(graph, final_modularity, num_level, louvain_parts, max_iter);
6143
}
6244

6345
template void louvain(
64-
experimental::GraphCSRView<int32_t, int32_t, float> const &, float *, int32_t *, int32_t *, int);
65-
template void louvain(experimental::GraphCSRView<int32_t, int32_t, double> const &,
66-
double *,
67-
int32_t *,
68-
int32_t *,
69-
int);
46+
experimental::GraphCSRView<int32_t, int32_t, float> const &, float *, int *, int32_t *, int);
47+
template void louvain(
48+
experimental::GraphCSRView<int32_t, int32_t, double> const &, double *, int *, int32_t *, int);
7049

71-
} // namespace nvgraph
7250
} // namespace cugraph

0 commit comments

Comments
 (0)