4

I am trying to iterate over my boost graph's vertices in parallel using OpenMP. This seems to require having an iterator that supports random access of elements (e.g., itr[i] gets the ith element). However, the iterator that vertices(g) returns (a vertex_iterator) does not seem to support this. Is there an efficient, clean way to accomplish this? Ideally, I just want a standard for loop such as this:

for (int i = 0; i < num_vertices; i++) {
  vertex v = itr[i];
  // Compute on vertex
}

which will cooperate with OpenMP. Thanks!

Sam
  • 2,707
  • 20
  • 25

1 Answers1

5

Using a adjacency_list<..., vecS, ...> or adjacency_matrix would enable this by having integral-type vertex descriptors.

Thinking slightly out of the box, have a look at the Parallel Boost Graph Library (Parallel BGL). It's very likely that it does what you want (and more) but better?

Tiny Demo

Live On Coliru

Sample output (on my system):

Generated 50000000 vertices in 1879ms
Using 8 threads.
Sum of volumes for 50000000 vertices in 94ms: 2.5603e+10

Full listing:

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/random.hpp>
#include <chrono>
#include <iostream>
#include <omp.h>
#include <random>

static std::mt19937 prng { std::random_device{}() };

struct MyVertex {
    uintmax_t volume = [] { static std::uniform_int_distribution<int> pick(0, 1024); return pick(prng); }();
};

using namespace boost;
using G = adjacency_list<vecS, vecS, directedS, MyVertex>;

G generate() {
    using namespace std::chrono;
    auto start = high_resolution_clock::now();

    G g;
    generate_random_graph(g, 50000000, 0, prng);

    auto end = high_resolution_clock::now();
    std::cerr << "Generated " << num_vertices(g) << " vertices " << "in " << duration_cast<milliseconds>(end-start).count() << "ms\n";

    return g;
}

int main() {

    auto const g = generate();

    using namespace std::chrono;
    auto start = high_resolution_clock::now();
    double sum = 0;
#pragma omp parallel
    {
#pragma omp single
        std::cerr << "Using " << omp_get_num_threads() << " threads.\n";

#pragma omp for reduction(+:sum)
        for (G::vertex_descriptor u = 0; u < num_vertices(g); ++u) {
            sum += g[vertex(u, g)].volume;
        }
    }

    auto end = high_resolution_clock::now();
    std::cerr << "Sum of volumes for " << num_vertices(g)                                << " vertices "
              << "in "                 << duration_cast<milliseconds>(end-start).count() << "ms: " << sum << "\n";
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Great answer as usual. It's my understanding that parallel bgl is a distributed multi-node set of tools while openMP is for multi-threading on a single node. – pbible May 11 '15 at 13:05
  • @pbible that is true. However one could perhaps leverage the distributed models and treats each core as a node, so as to benefit from existing distributed algorithms – sehe May 11 '15 at 13:53