52 #ifndef HAVOQGT_MPI_GEN_PREFERENTIAL_ATTACHMENT_EDGE_LIST_HPP_INCLUDED
53 #define HAVOQGT_MPI_GEN_PREFERENTIAL_ATTACHMENT_EDGE_LIST_HPP_INCLUDED
58 #include <boost/random.hpp>
61 namespace havoqgt {
namespace mpi {
64 template <
typename EdgeType>
66 uint64_t in_base_seed,
67 uint64_t in_node_scale,
68 uint64_t in_edge_scale,
70 double in_prob_rewire,
74 int mpi_rank, mpi_size;
75 CHK_MPI( MPI_Comm_rank(in_comm, &mpi_rank) );
76 CHK_MPI( MPI_Comm_size(in_comm, &mpi_size) );
80 uint64_t global_num_nodes = uint64_t(1) << in_node_scale;
81 uint64_t global_num_edges = uint64_t(1) << in_edge_scale;
82 uint64_t k = global_num_edges / global_num_nodes;
83 uint64_t edges_per_rank = global_num_edges / mpi_size;
85 ad::preferential_attachment_helper<uint64_t> pa(k, global_num_edges, in_beta,
86 in_base_seed*mpi_rank + mpi_rank);
90 double init_time_start = MPI_Wtime();
91 local_edges.resize(edges_per_rank);
92 for(uint64_t i=0; i<edges_per_rank; ++i) {
93 uint64_t edge_index = uint64_t(mpi_rank) + i*uint64_t(mpi_size);
94 local_edges[i] = pa.gen_edge(edge_index);
96 double init_time_end = MPI_Wtime();
98 std::cout <<
"Initial rng for edges took " << init_time_end - init_time_start
99 <<
" seconds. " << std::endl;
104 uint64_t iteration_count(1), count_missing(0), count_total_mising(0);
108 for(uint64_t i=0; i<edges_per_rank; ++i) {
109 if(pa.is_pointer(local_edges[i].second)) {
110 ++count_total_mising;
115 double time_start = MPI_Wtime();
118 std::vector<std::vector<uint64_t> > tmp_send_to_rank(mpi_size);
119 std::vector<std::vector<uint64_t> > tmp_mark_send_to_rank(mpi_size);
120 uint64_t count_to_send(0);
121 for(uint64_t i=0; i<local_edges.size(); ++i) {
122 if(pa.is_pointer(local_edges[i].second)) {
123 int owner = pa.value_of_pointer(local_edges[i].second) % mpi_size;
124 tmp_mark_send_to_rank[owner].push_back(i);
125 tmp_send_to_rank[owner].push_back(pa.value_of_pointer(local_edges[i].second));
131 std::vector<uint64_t> to_send(count_to_send); to_send.reserve(1);
132 std::vector<uint64_t> mark_to_send(count_to_send);
133 std::vector<int> sendcnts(mpi_size,0); sendcnts.reserve(1);
134 to_send.clear(); mark_to_send.clear();
135 for(
int i = 0; i < mpi_size; ++i) {
136 for(
size_t j = 0; j < tmp_send_to_rank[i].size(); ++j) {
137 to_send.push_back(tmp_send_to_rank[i][j]);
138 mark_to_send.push_back(tmp_mark_send_to_rank[i][j]);
140 sendcnts[i] = tmp_send_to_rank[i].size();
145 std::vector<std::vector<uint64_t> > empty;
146 tmp_send_to_rank.swap(empty);
149 std::vector<std::vector<uint64_t> > empty;
150 tmp_mark_send_to_rank.swap(empty);
154 std::vector<uint64_t> to_recv;
155 std::vector<int> recvcnts;
159 for(
size_t i=0; i<to_recv.size(); ++i) {
160 uint64_t local_index = to_recv[i]/mpi_size;
161 to_recv[i] = local_edges[local_index].second;
168 for(
size_t i=0; i<to_send.size(); ++i) {
169 local_edges[ mark_to_send[i] ].second = to_send[i];;
173 for(uint64_t i=0; i<edges_per_rank; ++i) {
174 if(pa.is_pointer(local_edges[i].second)) {
182 double time_end = MPI_Wtime();
184 std::cout <<
"Iteration " << iteration_count <<
" took "
185 << time_end - time_start <<
" seconds. "
186 << count_missing <<
" still missing. " << std::endl;
189 }
while(count_missing > 0);
194 std::cout <<
"Total missing (how much data globally exchanged) = " << count_total_mising << std::endl;
200 if(in_prob_rewire >
double(0)) {
201 boost::mt19937 rng(in_base_seed + uint64_t(mpi_rank) * 3ULL);
202 boost::random::uniform_int_distribution<> rand_node(0,global_num_nodes-1);
203 boost::random::uniform_01<> rand_real;
204 for(
size_t i=0; i<local_edges.size(); ++i) {
205 if(rand_real(rng) < in_prob_rewire) {
206 EdgeType rand_edge(rand_node(rng), rand_node(rng));
207 local_edges[i] = rand_edge;
214 for(
size_t i=0; i<local_edges.size(); ++i) {
217 local_edges[i].first %= global_num_nodes;
218 local_edges[i].second %= global_num_nodes;
219 local_edges[i].first =
ad::hash_nbits(local_edges[i].first, in_node_scale);
220 local_edges[i].second =
ad::hash_nbits(local_edges[i].second, in_node_scale);
242 #endif //end HAVOQGT_MPI_GEN_PREFERENTIAL_ATTACHMENT_EDGE_LIST_HPP_INCLUDED
uint64_t hash_nbits(uint64_t input, int n)
T mpi_all_reduce(T in_d, Op in_op, MPI_Comm mpi_comm)
void gen_preferential_attachment_edge_list(std::vector< EdgeType > &local_edges, uint64_t in_base_seed, uint64_t in_node_scale, uint64_t in_edge_scale, double in_beta, double in_prob_rewire, MPI_Comm in_comm)
void mpi_all_to_all(std::vector< T > &in_vec, std::vector< int > &in_sendcnts, std::vector< T > &out_vec, std::vector< int > &out_recvcnts, MPI_Comm mpi_comm)