Commit e2de443b authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Massive OpenMP reorganization

Now algorithms rely more on parallel_{vertex/edge}_loop() and global
the paralellization threshold is honored.
parent 8783af44
Pipeline #172 passed with stage
......@@ -258,8 +258,8 @@ out_neighbours(typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
}
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator,
typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator>
inline std::pair<typename reverse_graph<BidirectionalGraph,GRef>::in_adjacency_iterator,
typename reverse_graph<BidirectionalGraph,GRef>::in_adjacency_iterator>
in_neighbours(typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
......
......@@ -34,8 +34,8 @@ void normalize_betweenness(const Graph& g,
VertexBetweenness vertex_betweenness,
size_t n)
{
double vfactor = (n > 2) ? 1.0/((n-1)*(n-2)) : 1.0;
double efactor = (n > 1) ? 1.0/(n*(n-1)) : 1.0;
double vfactor = (n > 2) ? 1.0 / ((n - 1) * (n - 2)) : 1.0;
double efactor = (n > 1) ? 1.0 / (n * (n - 1)) : 1.0;
if (std::is_convertible<typename graph_traits<Graph>::directed_category,
undirected_tag>::value)
{
......@@ -43,22 +43,19 @@ void normalize_betweenness(const Graph& g,
efactor *= 2;
}
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
put(vertex_betweenness, v, vfactor * get(vertex_betweenness, v));
}
typename graph_traits<Graph>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(g); e != e_end; ++e)
{
put(edge_betweenness, *e, efactor * get(edge_betweenness, *e));
}
parallel_vertex_loop
(g,
[&](auto v)
{
put(vertex_betweenness, v, vfactor * get(vertex_betweenness, v));
});
parallel_edge_loop
(g,
[&](const auto& e)
{
put(edge_betweenness, e, efactor * get(edge_betweenness, e));
});
}
struct get_betweenness
......
......@@ -83,30 +83,27 @@ struct get_eigentrust
while (delta >= epslon)
{
delta = 0;
size_t i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:delta)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
t_temp[v] = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
if (!is_directed::apply<Graph>::type::value)
t_temp[v] += get(c, e) * t[s] / abs(c_sum[s]);
else
t_temp[v] += get(c, e) * t[s];
}
delta += abs(t_temp[v] - t[v]);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:delta)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
t_temp[v] = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
if (!is_directed::apply<Graph>::type::value)
t_temp[v] += get(c, e) * t[s] / abs(c_sum[s]);
else
t_temp[v] += get(c, e) * t[s];
}
delta += abs(t_temp[v] - t[v]);
});
swap(t_temp, t);
++iter;
......
......@@ -58,31 +58,31 @@ struct get_eigenvector
{
prev_delta = delta;
norm = 0;
size_t i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:norm)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:norm)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
c_temp[v] = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
c_temp[v] += get(w, e) * c[s];
}
norm += power(c_temp[v], 2);
});
c_temp[v] = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
c_temp[v] += get(w, e) * c[s];
}
norm += power(c_temp[v], 2);
}
norm = sqrt(norm);
delta = 0;
parallel_vertex_loop
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:delta)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
......
......@@ -68,52 +68,50 @@ struct get_hits
while (delta >= epsilon)
{
x_norm = 0, y_norm=0;
size_t i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:x_norm, y_norm)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
x_temp[v] = 0;
for (const auto& ie : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(ie, g);
else
s = target(ie, g);
x_temp[v] += get(w, ie) * y[s];
}
x_norm += power(x_temp[v], 2);
y_temp[v] = 0;
for (const auto& e : out_edges_range(v, g))
{
auto s = target(e, g);
y_temp[v] += get(w, e) * x[s];
}
y_norm += power(y_temp[v], 2);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) reduction(+:x_norm, y_norm)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
x_temp[v] = 0;
for (const auto& ie : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(ie, g);
else
s = target(ie, g);
x_temp[v] += get(w, ie) * y[s];
}
x_norm += power(x_temp[v], 2);
y_temp[v] = 0;
for (const auto& e : out_edges_range(v, g))
{
auto s = target(e, g);
y_temp[v] += get(w, e) * x[s];
}
y_norm += power(y_temp[v], 2);
});
x_norm = sqrt(x_norm);
y_norm = sqrt(y_norm);
delta = 0;
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:delta)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
x_temp[v] /= x_norm;
y_temp[v] /= y_norm;
delta += abs(x_temp[v] - x[v]);
delta += abs(y_temp[v] - y[v]);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:delta)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
x_temp[v] /= x_norm;
y_temp[v] /= y_norm;
delta += abs(x_temp[v] - x[v]);
delta += abs(y_temp[v] - y[v]);
});
swap(x_temp, x);
swap(y_temp, y);
......
......@@ -54,7 +54,10 @@ struct get_katz
size_t iter = 0;
while (delta >= epsilon)
{
parallel_vertex_loop
delta = 0;
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:delta)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
......@@ -68,19 +71,8 @@ struct get_katz
s = target(e, g);
c_temp[v] += alpha * get(w, e) * c[s];
}
delta += abs(c_temp[v] - c[v]);
});
delta = 0;
size_t i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:delta)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
delta += abs(c_temp[v] - c[v]);
}
swap(c_temp, c);
++iter;
......
......@@ -45,9 +45,7 @@ struct get_pagerank
(g,
[&](auto v)
{
put(deg, v, 0);
for (auto e : out_edges_range(v, g))
put(deg, v, get(deg, v) + get(weight, e));
put(deg, v, out_degreeS()(v, g, weight));
});
rank_type delta = epsilon + 1;
......@@ -56,29 +54,27 @@ struct get_pagerank
while (delta >= epsilon)
{
delta = 0;
size_t i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) \
schedule(runtime) if (N > 100) reduction(+:delta)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
rank_type r = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
r += (get(rank, s) * get(weight, e)) / get(deg, s);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
reduction(+:delta)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
rank_type r = 0;
for (const auto& e : in_or_out_edges_range(v, g))
{
typename graph_traits<Graph>::vertex_descriptor s;
if (is_directed::apply<Graph>::type::value)
s = source(e, g);
else
s = target(e, g);
r += (get(rank, s) * get(weight, e)) / get(deg, s);
}
put(r_temp, v, (1.0 - d) * get(pers, v) + d * r);
put(r_temp, v, (1.0 - d) * get(pers, v) + d * r);
delta += abs(get(r_temp, v) - get(rank, v));
}
delta += abs(get(r_temp, v) - get(rank, v));
});
swap(r_temp, rank);
++iter;
if (max_iter > 0 && iter == max_iter)
......
......@@ -103,7 +103,7 @@ struct get_trust_transitivity
typedef typename
property_traits<InferredTrustMap>::value_type::value_type t_type;
size_t i, N = (target == -1) ? num_vertices(g) : target + 1;
size_t N = (target == -1) ? num_vertices(g) : target + 1;
parallel_vertex_loop
(g,
......@@ -112,8 +112,8 @@ struct get_trust_transitivity
t[v].resize((source == -1 && target == -1) ? N : 1);
});
#pragma omp parallel for default(shared) private(i) schedule(runtime) if (N > 100)
for (i = (target == -1) ? 0 : target; i < N; ++i)
#pragma omp parallel for if (num_vertices(g) > OPENMP_MIN_THRESH)
for (size_t i = (target == -1) ? 0 : target; i < N; ++i)
{
vertex_t tgt = vertex(i, g);
if (!is_valid_vertex(tgt, g))
......
......@@ -85,42 +85,34 @@ struct get_global_clustering
void operator()(const Graph& g, double& c, double& c_err) const
{
size_t triangles = 0, n = 0;
pair<size_t, size_t> temp;
vector<bool> mask(num_vertices(g), false);
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i,temp) \
firstprivate(mask) schedule(runtime) if (N > OPENMP_MIN_THRESH) \
reduction(+:triangles, n)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
temp = get_triangles(v, mask, g);
triangles += temp.first;
n += temp.second;
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
firstprivate(mask) reduction(+:triangles, n)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
auto temp = get_triangles(v, mask, g);
triangles += temp.first;
n += temp.second;
});
c = double(triangles) / n;
// "jackknife" variance
c_err = 0.0;
double cerr = 0.0;
#pragma omp parallel for default(shared) private(i,temp) \
firstprivate(mask) schedule(runtime) if (N > OPENMP_MIN_THRESH) \
reduction(+:cerr)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
temp = get_triangles(v, mask, g);
double cl = double(triangles - temp.first) / (n - temp.second);
cerr += power(c - cl, 2);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
firstprivate(mask) reduction(+:cerr)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
auto temp = get_triangles(v, mask, g);
double cl = double(triangles - temp.first) /
(n - temp.second);
cerr += power(c - cl, 2);
});
c_err = sqrt(cerr);
}
};
......@@ -133,23 +125,20 @@ struct set_clustering_to_property
{
typedef typename property_traits<ClustMap>::value_type c_type;
typename get_undirected_graph<Graph>::type ug(g);
int i, N = num_vertices(g);
vector<bool> mask(num_vertices(g), false);
#pragma omp parallel for default(shared) private(i) \
firstprivate(mask) schedule(runtime) if (N > OPENMP_MIN_THRESH)
for (i = 0; i < N; ++i)
{
auto v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
auto triangles = get_triangles(v, mask, ug); // get from ug
double clustering = (triangles.second > 0) ?
double(triangles.first)/triangles.second :
0.0;
clust_map[v] = c_type(clustering);
}
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
firstprivate(mask)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
auto triangles = get_triangles(v, mask, ug); // get from ug
double clustering = (triangles.second > 0) ?
double(triangles.first)/triangles.second :
0.0;
clust_map[v] = c_type(clustering);
});
}
template <class Graph>
......
......@@ -80,11 +80,8 @@ struct bfs_max_depth_watcher
template<class Graph, class Vertex, class Targets, class DirectedCategory>
void collect_targets(Vertex v, Graph& g, Targets& t, DirectedCategory)
{
typename graph_traits<Graph>::in_edge_iterator ei, ei_end;
typename graph_traits<Graph>::vertex_descriptor u;
for(tie(ei, ei_end) = in_edges(v, g); ei != ei_end; ++ei)
for (auto u : in_neighbours_range(v, g))
{
u = source(*ei, g);
if (u == v) // no self-loops
continue;
if (t.find(u) != t.end()) // avoid parallel edges
......@@ -96,11 +93,8 @@ void collect_targets(Vertex v, Graph& g, Targets& t, DirectedCategory)
template<class Graph, class Vertex, class Targets>
void collect_targets(Vertex v, Graph& g, Targets& t, undirected_tag)
{
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
typename graph_traits<Graph>::vertex_descriptor u;
for(tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei)
for (auto u : out_neighbours_range(v, g))
{
u = target(*ei, g);
if (u == v) // no self-loops
continue;
if (t.find(u) != t.end()) // avoid parallel edges
......@@ -119,88 +113,83 @@ struct get_extended_clustering
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(runtime) if (N > 100)
for (i = 0; i < N; ++i)
{
vertex_t v = vertex(i, g);
if (!is_valid_vertex(v, g))
continue;
// We must disconsider paths through the original vertex
typedef single_vertex_filter<vertex_t> filter_t;
typedef filtered_graph<Graph, keep_all, filter_t> fg_t;
fg_t fg(g, keep_all(), filter_t(v));
typedef DescriptorHash<IndexMap> hasher_t;
typedef gt_hash_set<vertex_t,hasher_t> neighbour_set_t;
neighbour_set_t neighbours(0, hasher_t(vertex_index));
neighbour_set_t targets(0, hasher_t(vertex_index));
typename neighbour_set_t::iterator ni, ti;
// collect targets, neighbours and calculate normalization factor
collect_targets(v, g, targets,
typename graph_traits<Graph>::directed_category());
size_t k_in = targets.size(), k_out, k_inter=0, z;
typename graph_traits<Graph>::adjacency_iterator a, a_end;
for (tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
{
if (*a == v) // no self-loops
continue;
if (neighbours.find(*a) != neighbours.end()) // avoid parallel
continue; // edges
neighbours.insert(*a);
if (targets.find(*a) != targets.end())
++k_inter;
}
k_out = neighbours.size();
z = (k_in*k_out) - k_inter;
// And now we setup and start the BFS bonanza
for (ni = neighbours.begin(); ni != neighbours.end(); ++ni)
{
typedef gt_hash_map<vertex_t,size_t,
DescriptorHash<IndexMap> > dmap_t;
dmap_t dmap(0, DescriptorHash<IndexMap>(vertex_index));
InitializedPropertyMap<dmap_t>
distance_map(dmap, numeric_limits<size_t>::max());
typedef gt_hash_map<vertex_t,default_color_type,
DescriptorHash<IndexMap> > cmap_t;
cmap_t cmap(0, DescriptorHash<IndexMap>(vertex_index));
InitializedPropertyMap<cmap_t>
color_map(cmap, color_traits<default_color_type>::white());
try
{
distance_map[*ni] = 0;
neighbour_set_t specific_targets = targets;
specific_targets.erase(*ni);
bfs_max_depth_watcher<neighbour_set_t,
InitializedPropertyMap<dmap_t> >
watcher(specific_targets, cmaps.size(), distance_map);
breadth_first_visit(fg, *ni,
visitor
(make_bfs_visitor
(make_pair(record_distances
(distance_map,
boost::on_tree_edge()),
watcher))).
color_map(color_map));
}
catch (bfs_stop_exception) {}
for (ti = targets.begin(); ti != targets.end(); ++ti)
{