/* Copyright (C) 2009-2010 The Trustees of Indiana University. *//* *//* Use, modification and distribution is subject to the Boost Software *//* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at *//* http://www.boost.org/LICENSE_1_0.txt) *//* *//* Authors: Jeremiah Willcock *//* Andrew Lumsdaine */ #include <stdlib.h>#include <stdint.h>#include <stdio.h>#include <string.h>#include <limits.h>#include <assert.h>#include <math.h>#ifdef __MTA__#include <sys/mta_task.h>#endif#ifdef GRAPH_GENERATOR_MPI#include <mpi.h>#endif#ifdef GRAPH_GENERATOR_OMP#include <omp.h>#endif /* Simplified interface to build graphs with scrambled vertices. */ #include "graph_generator.h"#include "permutation_gen.h"#include "apply_permutation_mpi.h"#include "scramble_edges.h"#include "utils.h" #ifdef GRAPH_GENERATOR_SEQvoid make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) { int64_t N, M; N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts); M = desired_nedges; /* Spread the two 64-bit numbers into five nonzero values in the correct * range. */ uint_fast32_t seed[5]; make_mrg_seed(userseed1, userseed2, seed); int64_t nedges = compute_edge_array_size(0, 1, M); *nedges_ptr = nedges;#ifdef GRAPHGEN_KEEP_MULTIPLICITIES generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */#else int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#endif generate_kronecker(0, 1, seed, log_numverts, M, initiator, edges); int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t)); int64_t* result;#ifdef GRAPHGEN_KEEP_MULTIPLICITIES result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#else result = edges;#endif *result_ptr = result; mrg_state state; mrg_seed(&state, seed); rand_sort_shared(&state, N, vertex_perm); int64_t i; /* Apply vertex permutation to graph, optionally copying into user's result * array. */#ifdef GRAPHGEN_KEEP_MULTIPLICITIES for (i = 0; i < nedges; ++i) { if (edges[i].multiplicity != 0) { int64_t v1 = vertex_perm[edges[i].src]; int64_t v2 = vertex_perm[edges[i].tgt]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ result[i * 2] = (v1 < v2) ? v1 : v2; result[i * 2 + 1] = (v1 < v2) ? v2 : v1; } else { result[i * 2] = result[i * 2 + 1] = (int64_t)(-1); } } free(edges);#else for (i = 0; i < 2 * nedges; i += 2) { if (edges[i] != (int64_t)(-1)) { int64_t v1 = vertex_perm[edges[i]]; int64_t v2 = vertex_perm[edges[i + 1]]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ edges[i] = (v1 < v2) ? v1 : v2; edges[i + 1] = (v1 < v2) ? v2 : v1; } }#endif free(vertex_perm); /* Randomly mix up the order of the edges. */ scramble_edges_shared(userseed1, userseed2, nedges, edges);}#endif /* GRAPH_GENERATOR_SEQ */ #ifdef __MTA__void make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) { int64_t N, M; N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts); M = (int64_t)desired_nedges; /* Spread the two 64-bit numbers into five nonzero values in the correct * range. */ uint_fast32_t seed[5]; make_mrg_seed(userseed1, userseed2, seed); int64_t nedges = compute_edge_array_size(0, 1, M); *nedges_ptr = nedges;#ifdef GRAPHGEN_KEEP_MULTIPLICITIES generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */#else int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#endif int rank, size; /* The "for all streams" here is in compiler versions >= 6.4 */#pragma mta use 100 streams#pragma mta for all streams rank of size { double my_initiator[GRAPHGEN_INITIATOR_SIZE * GRAPHGEN_INITIATOR_SIZE]; /* Local copy */ int i; for (i = 0; i < GRAPHGEN_INITIATOR_SIZE * GRAPHGEN_INITIATOR_SIZE; ++i) { my_initiator[i] = initiator[i]; } generate_kronecker(rank, size, seed, log_numverts, M, my_initiator, edges); } int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t)); int64_t* result; #ifdef GRAPHGEN_KEEP_MULTIPLICITIES result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#else result = edges;#endif *result_ptr = result; mrg_state state; mrg_seed(&state, seed); rand_sort_shared(&state, N, vertex_perm); int64_t i; /* Apply vertex permutation to graph, optionally copying into user's result * array. */#ifdef GRAPHGEN_KEEP_MULTIPLICITIES#pragma mta assert parallel#pragma mta block schedule for (i = 0; i < nedges; ++i) { if (edges[i].multiplicity != 0) { int64_t v1 = vertex_perm[edges[i].src]; int64_t v2 = vertex_perm[edges[i].tgt]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ result[i * 2] = MTA_INT_MIN(v1, v2); result[i * 2 + 1] = MTA_INT_MAX(v1, v2); } else { result[i * 2] = result[i * 2 + 1] = (int64_t)(-1); } } free(edges);#else#pragma mta assert parallel#pragma mta block schedule for (i = 0; i < 2 * nedges; i += 2) { if (edges[i] != (int64_t)(-1)) { int64_t v1 = vertex_perm[edges[i]]; int64_t v2 = vertex_perm[edges[i + 1]]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ edges[i] = MTA_INT_MIN(v1, v2); edges[i + 1] = MTA_INT_MAX(v1, v2); } }#endif free(vertex_perm); /* Randomly mix up the order of the edges. */ scramble_edges_shared(userseed1, userseed2, nedges, edges);}#endif /* __MTA__ */ #ifdef GRAPH_GENERATOR_OMPvoid make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) { int64_t N, M; N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts); M = desired_nedges; /* Spread the two 64-bit numbers into five nonzero values in the correct * range. */ uint_fast32_t seed[5]; make_mrg_seed(userseed1, userseed2, seed); int64_t nedges = compute_edge_array_size(0, 1, M); *nedges_ptr = nedges;#ifdef GRAPHGEN_KEEP_MULTIPLICITIES generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */#else int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#endif #pragma omp parallel { int rank = omp_get_thread_num(), size = omp_get_num_threads(); generate_kronecker(rank, size, seed, log_numverts, M, initiator, edges); } int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t)); int64_t* result; #ifdef GRAPHGEN_KEEP_MULTIPLICITIES result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#else result = edges;#endif *result_ptr = result; mrg_state state; mrg_seed(&state, seed); rand_sort_shared(&state, N, vertex_perm); int64_t i; /* Apply vertex permutation to graph, optionally copying into user's result * array. */#ifdef GRAPHGEN_KEEP_MULTIPLICITIES#pragma omp parallel for for (i = 0; i < nedges; ++i) { if (edges[i].multiplicity != 0) { int64_t v1 = vertex_perm[edges[i].src]; int64_t v2 = vertex_perm[edges[i].tgt]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ result[i * 2] = (v1 < v2) ? v1 : v2; result[i * 2 + 1] = (v1 < v2) ? v2 : v1; } else { result[i * 2] = result[i * 2 + 1] = (int64_t)(-1); } } free(edges);#else#pragma omp parallel for for (i = 0; i < 2 * nedges; i += 2) { if (edges[i] != (int64_t)(-1)) { int64_t v1 = vertex_perm[edges[i]]; int64_t v2 = vertex_perm[edges[i + 1]]; /* Sort these since otherwise the directions of the permuted edges would * give away the unscrambled vertex order. */ edges[i] = (v1 < v2) ? v1 : v2; edges[i + 1] = (v1 < v2) ? v2 : v1; } }#endif free(vertex_perm); /* Randomly mix up the order of the edges. */ scramble_edges_shared(userseed1, userseed2, nedges, edges);}#endif /* GRAPH_GENERATOR_OMP */ #ifdef GRAPH_GENERATOR_MPIvoid make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) { int64_t N, M; int rank, size; N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts); M = desired_nedges; /* Spread the two 64-bit numbers into five nonzero values in the correct * range. */ uint_fast32_t seed[5]; make_mrg_seed(userseed1, userseed2, seed); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); int64_t nedges = compute_edge_array_size(rank, size, M);#ifdef GRAPHGEN_KEEP_MULTIPLICITIES generated_edge* local_edges = (generated_edge*)xmalloc(nedges * sizeof(generated_edge));#else int64_t* local_edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));#endif double start = MPI_Wtime(); generate_kronecker(rank, size, seed, log_numverts, M, initiator, local_edges); double gen_time = MPI_Wtime() - start; int64_t* local_vertex_perm = NULL; mrg_state state; mrg_seed(&state, seed); start = MPI_Wtime(); int64_t perm_local_size; rand_sort_mpi(MPI_COMM_WORLD, &state, N, &perm_local_size, &local_vertex_perm); double perm_gen_time = MPI_Wtime() - start; /* Copy the edge endpoints into the result array if necessary. */ int64_t* result;#ifdef GRAPHGEN_KEEP_MULTIPLICITIES result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t)); for (i = 0; i < nedges; ++i) { if (local_edges[i].multiplicity != 0) { result[i * 2] = local_edges[i].src; result[i * 2 + 1] = local_edges[i].tgt; } else { result[i * 2] = result[i * 2 + 1] = (int64_t)(-1); } } free(local_edges); local_edges = NULL;#else result = local_edges; *result_ptr = result; local_edges = NULL; /* Freed by caller */#endif /* Apply vertex permutation to graph. */ start = MPI_Wtime(); apply_permutation_mpi(MPI_COMM_WORLD, perm_local_size, local_vertex_perm, N, nedges, result); double perm_apply_time = MPI_Wtime() - start; free(local_vertex_perm); local_vertex_perm = NULL; /* Randomly mix up the order of the edges. */ start = MPI_Wtime(); int64_t* new_result; int64_t nedges_out; scramble_edges_mpi(MPI_COMM_WORLD, userseed1, userseed2, nedges, result, &nedges_out, &new_result); double edge_scramble_time = MPI_Wtime() - start; free(result); result = NULL; *result_ptr = new_result; *nedges_ptr = nedges_out; if (rank == 0) { fprintf(stdout, "unpermuted_graph_generation: %f s\n", gen_time); fprintf(stdout, "vertex_permutation_generation: %f s\n", perm_gen_time); fprintf(stdout, "vertex_permutation_application: %f s\n", perm_apply_time); fprintf(stdout, "edge_scrambling: %f s\n", edge_scramble_time); }}#endif /* PRNG interface for implementations; takes seed in same format as given by * users, and creates a vector of doubles in a reproducible (and * random-access) way. */void make_random_numbers( /* in */ int64_t nvalues /* Number of values to generate */, /* in */ uint64_t userseed1 /* Arbitrary 64-bit seed value */, /* in */ uint64_t userseed2 /* Arbitrary 64-bit seed value */, /* in */ int64_t position /* Start index in random number stream */, /* out */ double* result /* Returned array of values */) { int64_t i; uint_fast32_t seed[5]; make_mrg_seed(userseed1, userseed2, seed); mrg_state st; mrg_seed(&st, seed); mrg_skip(&st, 2, 0, 2 * position); /* Each double takes two PRNG outputs */ for (i = 0; i < nvalues; ++i) { result[i] = mrg_get_double_orig(&st); }}
/* Copyright (C) 2009-2010 The Trustees of Indiana University. */
/* */
/* Use, modification and distribution is subject to the Boost Software */
/* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at */
/* http://www.boost.org/LICENSE_1_0.txt) */
/* */
/* Authors: Jeremiah Willcock */
/* Andrew Lumsdaine */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <math.h>
#ifdef __MTA__
#include <sys/mta_task.h>
#endif
#ifdef GRAPH_GENERATOR_MPI
#include <mpi.h>
#endif
#ifdef GRAPH_GENERATOR_OMP
#include <omp.h>
#endif
/* Simplified interface to build graphs with scrambled vertices. */
#include "graph_generator.h"
#include "permutation_gen.h"
#include "apply_permutation_mpi.h"
#include "scramble_edges.h"
#include "utils.h"
#ifdef GRAPH_GENERATOR_SEQ
void make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) {
int64_t N, M;
N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts);
M = desired_nedges;
/* Spread the two 64-bit numbers into five nonzero values in the correct
* range. */
uint_fast32_t seed[5];
make_mrg_seed(userseed1, userseed2, seed);
int64_t nedges = compute_edge_array_size(0, 1, M);
*nedges_ptr = nedges;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */
#else
int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#endif
generate_kronecker(0, 1, seed, log_numverts, M, initiator, edges);
int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t));
int64_t* result;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#else
result = edges;
#endif
*result_ptr = result;
mrg_state state;
mrg_seed(&state, seed);
rand_sort_shared(&state, N, vertex_perm);
int64_t i;
/* Apply vertex permutation to graph, optionally copying into user's result
* array. */
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
for (i = 0; i < nedges; ++i) {
if (edges[i].multiplicity != 0) {
int64_t v1 = vertex_perm[edges[i].src];
int64_t v2 = vertex_perm[edges[i].tgt];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
result[i * 2] = (v1 < v2) ? v1 : v2;
result[i * 2 + 1] = (v1 < v2) ? v2 : v1;
} else {
result[i * 2] = result[i * 2 + 1] = (int64_t)(-1);
}
}
free(edges);
#else
for (i = 0; i < 2 * nedges; i += 2) {
if (edges[i] != (int64_t)(-1)) {
int64_t v1 = vertex_perm[edges[i]];
int64_t v2 = vertex_perm[edges[i + 1]];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
edges[i] = (v1 < v2) ? v1 : v2;
edges[i + 1] = (v1 < v2) ? v2 : v1;
}
}
#endif
free(vertex_perm);
/* Randomly mix up the order of the edges. */
scramble_edges_shared(userseed1, userseed2, nedges, edges);
}
#endif /* GRAPH_GENERATOR_SEQ */
#ifdef __MTA__
void make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) {
int64_t N, M;
N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts);
M = (int64_t)desired_nedges;
/* Spread the two 64-bit numbers into five nonzero values in the correct
* range. */
uint_fast32_t seed[5];
make_mrg_seed(userseed1, userseed2, seed);
int64_t nedges = compute_edge_array_size(0, 1, M);
*nedges_ptr = nedges;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */
#else
int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#endif
int rank, size;
/* The "for all streams" here is in compiler versions >= 6.4 */
#pragma mta use 100 streams
#pragma mta for all streams rank of size
{
double my_initiator[GRAPHGEN_INITIATOR_SIZE * GRAPHGEN_INITIATOR_SIZE]; /* Local copy */
int i;
for (i = 0; i < GRAPHGEN_INITIATOR_SIZE * GRAPHGEN_INITIATOR_SIZE; ++i) {
my_initiator[i] = initiator[i];
}
generate_kronecker(rank, size, seed, log_numverts, M, my_initiator, edges);
}
int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t));
int64_t* result;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#else
result = edges;
#endif
*result_ptr = result;
mrg_state state;
mrg_seed(&state, seed);
rand_sort_shared(&state, N, vertex_perm);
int64_t i;
/* Apply vertex permutation to graph, optionally copying into user's result
* array. */
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
#pragma mta assert parallel
#pragma mta block schedule
for (i = 0; i < nedges; ++i) {
if (edges[i].multiplicity != 0) {
int64_t v1 = vertex_perm[edges[i].src];
int64_t v2 = vertex_perm[edges[i].tgt];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
result[i * 2] = MTA_INT_MIN(v1, v2);
result[i * 2 + 1] = MTA_INT_MAX(v1, v2);
} else {
result[i * 2] = result[i * 2 + 1] = (int64_t)(-1);
}
}
free(edges);
#else
#pragma mta assert parallel
#pragma mta block schedule
for (i = 0; i < 2 * nedges; i += 2) {
if (edges[i] != (int64_t)(-1)) {
int64_t v1 = vertex_perm[edges[i]];
int64_t v2 = vertex_perm[edges[i + 1]];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
edges[i] = MTA_INT_MIN(v1, v2);
edges[i + 1] = MTA_INT_MAX(v1, v2);
}
}
#endif
free(vertex_perm);
/* Randomly mix up the order of the edges. */
scramble_edges_shared(userseed1, userseed2, nedges, edges);
}
#endif /* __MTA__ */
#ifdef GRAPH_GENERATOR_OMP
void make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) {
int64_t N, M;
N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts);
M = desired_nedges;
/* Spread the two 64-bit numbers into five nonzero values in the correct
* range. */
uint_fast32_t seed[5];
make_mrg_seed(userseed1, userseed2, seed);
int64_t nedges = compute_edge_array_size(0, 1, M);
*nedges_ptr = nedges;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
generated_edge* edges = (generated_edge*)xcalloc(nedges, sizeof(generated_edge)); /* multiplicity set to 0 for unused edges */
#else
int64_t* edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#endif
#pragma omp parallel
{
int rank = omp_get_thread_num(), size = omp_get_num_threads();
generate_kronecker(rank, size, seed, log_numverts, M, initiator, edges);
}
int64_t* vertex_perm = (int64_t*)xmalloc(N * sizeof(int64_t));
int64_t* result;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#else
result = edges;
#endif
*result_ptr = result;
mrg_state state;
mrg_seed(&state, seed);
rand_sort_shared(&state, N, vertex_perm);
int64_t i;
/* Apply vertex permutation to graph, optionally copying into user's result
* array. */
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
#pragma omp parallel for
for (i = 0; i < nedges; ++i) {
if (edges[i].multiplicity != 0) {
int64_t v1 = vertex_perm[edges[i].src];
int64_t v2 = vertex_perm[edges[i].tgt];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
result[i * 2] = (v1 < v2) ? v1 : v2;
result[i * 2 + 1] = (v1 < v2) ? v2 : v1;
} else {
result[i * 2] = result[i * 2 + 1] = (int64_t)(-1);
}
}
free(edges);
#else
#pragma omp parallel for
for (i = 0; i < 2 * nedges; i += 2) {
if (edges[i] != (int64_t)(-1)) {
int64_t v1 = vertex_perm[edges[i]];
int64_t v2 = vertex_perm[edges[i + 1]];
/* Sort these since otherwise the directions of the permuted edges would
* give away the unscrambled vertex order. */
edges[i] = (v1 < v2) ? v1 : v2;
edges[i + 1] = (v1 < v2) ? v2 : v1;
}
}
#endif
free(vertex_perm);
/* Randomly mix up the order of the edges. */
scramble_edges_shared(userseed1, userseed2, nedges, edges);
}
#endif /* GRAPH_GENERATOR_OMP */
#ifdef GRAPH_GENERATOR_MPI
void make_graph(int log_numverts, int64_t desired_nedges, uint64_t userseed1, uint64_t userseed2, const double initiator[4], int64_t* nedges_ptr, int64_t** result_ptr) {
int64_t N, M;
int rank, size;
N = (int64_t)pow(GRAPHGEN_INITIATOR_SIZE, log_numverts);
M = desired_nedges;
/* Spread the two 64-bit numbers into five nonzero values in the correct
* range. */
uint_fast32_t seed[5];
make_mrg_seed(userseed1, userseed2, seed);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int64_t nedges = compute_edge_array_size(rank, size, M);
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
generated_edge* local_edges = (generated_edge*)xmalloc(nedges * sizeof(generated_edge));
#else
int64_t* local_edges = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
#endif
double start = MPI_Wtime();
generate_kronecker(rank, size, seed, log_numverts, M, initiator, local_edges);
double gen_time = MPI_Wtime() - start;
int64_t* local_vertex_perm = NULL;
mrg_state state;
mrg_seed(&state, seed);
start = MPI_Wtime();
int64_t perm_local_size;
rand_sort_mpi(MPI_COMM_WORLD, &state, N, &perm_local_size, &local_vertex_perm);
double perm_gen_time = MPI_Wtime() - start;
/* Copy the edge endpoints into the result array if necessary. */
int64_t* result;
#ifdef GRAPHGEN_KEEP_MULTIPLICITIES
result = (int64_t*)xmalloc(2 * nedges * sizeof(int64_t));
for (i = 0; i < nedges; ++i) {
if (local_edges[i].multiplicity != 0) {
result[i * 2] = local_edges[i].src;
result[i * 2 + 1] = local_edges[i].tgt;
} else {
result[i * 2] = result[i * 2 + 1] = (int64_t)(-1);
}
}
free(local_edges); local_edges = NULL;
#else
result = local_edges;
*result_ptr = result;
local_edges = NULL; /* Freed by caller */
#endif
/* Apply vertex permutation to graph. */
start = MPI_Wtime();
apply_permutation_mpi(MPI_COMM_WORLD, perm_local_size, local_vertex_perm, N, nedges, result);
double perm_apply_time = MPI_Wtime() - start;
free(local_vertex_perm); local_vertex_perm = NULL;
/* Randomly mix up the order of the edges. */
start = MPI_Wtime();
int64_t* new_result;
int64_t nedges_out;
scramble_edges_mpi(MPI_COMM_WORLD, userseed1, userseed2, nedges, result, &nedges_out, &new_result);
double edge_scramble_time = MPI_Wtime() - start;
free(result); result = NULL;
*result_ptr = new_result;
*nedges_ptr = nedges_out;
if (rank == 0) {
fprintf(stdout, "unpermuted_graph_generation: %f s\n", gen_time);
fprintf(stdout, "vertex_permutation_generation: %f s\n", perm_gen_time);
fprintf(stdout, "vertex_permutation_application: %f s\n", perm_apply_time);
fprintf(stdout, "edge_scrambling: %f s\n", edge_scramble_time);
}
}
#endif
/* PRNG interface for implementations; takes seed in same format as given by
* users, and creates a vector of doubles in a reproducible (and
* random-access) way. */
void make_random_numbers(
/* in */ int64_t nvalues /* Number of values to generate */,
/* in */ uint64_t userseed1 /* Arbitrary 64-bit seed value */,
/* in */ uint64_t userseed2 /* Arbitrary 64-bit seed value */,
/* in */ int64_t position /* Start index in random number stream */,
/* out */ double* result /* Returned array of values */
) {
int64_t i;
uint_fast32_t seed[5];
make_mrg_seed(userseed1, userseed2, seed);
mrg_state st;
mrg_seed(&st, seed);
mrg_skip(&st, 2, 0, 2 * position); /* Each double takes two PRNG outputs */
for (i = 0; i < nvalues; ++i) {
result[i] = mrg_get_double_orig(&st);
}
}