Commit 54b33836 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

* Initial support for parallel code with openmp from GCC 4.2.0. The following code is now parallel:

  * src/graph/graph_clustering.cc
  * src/graph/graph_distance.cc
  * src/graph/graph_extended_clustering.cc
  * src/graph/graph_distance_sampled.cc
* fixed "jacknife" variance bug in src/graph/graph_clustering.cc



git-svn-id: https://svn.forked.de/graph-tool/trunk@97 d4600afd-f417-0410-95de-beed9576f240
parent df8d400a
...@@ -94,6 +94,24 @@ AC_ARG_ENABLE([range-filtering], [AC_HELP_STRING([--disable-range-filtering], ...@@ -94,6 +94,24 @@ AC_ARG_ENABLE([range-filtering], [AC_HELP_STRING([--disable-range-filtering],
NO_RANGE_FILTERING=no NO_RANGE_FILTERING=no
) )
AC_MSG_CHECKING(whether to enable parallel algorithms with openmp...)
AC_ARG_ENABLE([openmp], [AC_HELP_STRING([--enable-openmp],
[enable openmp [default=no] ])],
if test $enableval = yes; then
[AC_MSG_RESULT(yes)]
[AC_DEFINE([USING_OPENMP], 1, [using openmp])]
USING_OPENMP=yes
[CXXFLAGS="$CXXFLAGS -fopenmp "]
[OPENMP_LDFLAGS=" -lgomp "]
fi
,
[AC_MSG_RESULT(no)]
[AC_DEFINE([USING_OPENMP], 0, [using openmp])]
USING_OPENMP=no
[OPENMP_LDFLAGS=""]
)
AC_SUBST(OPENMP_LDFLAGS)
dnl Checks for programs. dnl Checks for programs.
......
...@@ -155,7 +155,7 @@ class mutate_graph_impl : public mutate_graph ...@@ -155,7 +155,7 @@ class mutate_graph_impl : public mutate_graph
public: public:
put_property(const std::string& name, dynamic_properties& dp, const Key& key, put_property(const std::string& name, dynamic_properties& dp, const Key& key,
const std::string& value, const std::string& value_type, const std::string& value, const std::string& value_type,
char** type_names, bool& type_found) const char** type_names, bool& type_found)
: m_name(name), m_dp(dp), m_key(key), m_value(value), : m_name(name), m_dp(dp), m_key(key), m_value(value),
m_value_type(value_type), m_type_names(type_names), m_value_type(value_type), m_type_names(type_names),
m_type_found(type_found) {} m_type_found(type_found) {}
...@@ -174,7 +174,7 @@ class mutate_graph_impl : public mutate_graph ...@@ -174,7 +174,7 @@ class mutate_graph_impl : public mutate_graph
const Key& m_key; const Key& m_key;
const std::string& m_value; const std::string& m_value;
const std::string& m_value_type; const std::string& m_value_type;
char** m_type_names; const char** m_type_names;
bool& m_type_found; bool& m_type_found;
}; };
...@@ -182,11 +182,11 @@ protected: ...@@ -182,11 +182,11 @@ protected:
MutableGraph& m_g; MutableGraph& m_g;
dynamic_properties& m_dp; dynamic_properties& m_dp;
typedef mpl::vector<bool, int, long, float, double, std::string> value_types; typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
static char* m_type_names[]; static const char* m_type_names[];
}; };
template<typename MutableGraph> template<typename MutableGraph>
char* mutate_graph_impl<MutableGraph>::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"}; const char* mutate_graph_impl<MutableGraph>::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"};
void void
read_graphml(std::istream& in, mutate_graph& g); read_graphml(std::istream& in, mutate_graph& g);
...@@ -203,7 +203,7 @@ template <typename Types> ...@@ -203,7 +203,7 @@ template <typename Types>
class get_type_name class get_type_name
{ {
public: public:
get_type_name(const std::type_info& type, char** type_names, std::string& type_name) get_type_name(const std::type_info& type, const char** type_names, std::string& type_name)
: m_type(type), m_type_names(type_names), m_type_name(type_name) {} : m_type(type), m_type_names(type_names), m_type_name(type_name) {}
template <typename Type> template <typename Type>
void operator()(Type) void operator()(Type)
...@@ -213,7 +213,7 @@ public: ...@@ -213,7 +213,7 @@ public:
} }
private: private:
const std::type_info &m_type; const std::type_info &m_type;
char** m_type_names; const char** m_type_names;
std::string &m_type_name; std::string &m_type_name;
}; };
...@@ -235,7 +235,7 @@ write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index, ...@@ -235,7 +235,7 @@ write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index,
<< "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n"; << "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n";
typedef mpl::vector<bool, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double, std::string> value_types; typedef mpl::vector<bool, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double, std::string> value_types;
char* type_names[] = {"boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string"}; const char* type_names[] = {"boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string"};
std::map<std::string, std::string> graph_key_ids; std::map<std::string, std::string> graph_key_ids;
std::map<std::string, std::string> vertex_key_ids; std::map<std::string, std::string> vertex_key_ids;
std::map<std::string, std::string> edge_key_ids; std::map<std::string, std::string> edge_key_ids;
......
...@@ -49,6 +49,7 @@ libgraph_tool_la_SOURCES = \ ...@@ -49,6 +49,7 @@ libgraph_tool_la_SOURCES = \
libgraph_tool_la_LIBADD = \ libgraph_tool_la_LIBADD = \
$(PYTHON_LDFLAGS) \ $(PYTHON_LDFLAGS) \
$(BOOST_LDFLAGS) \ $(BOOST_LDFLAGS) \
$(OPENMP_LDFLAGS) \
-lboost_python \ -lboost_python \
-lboost_iostreams \ -lboost_iostreams \
-lexpat -lexpat
......
...@@ -41,7 +41,7 @@ using namespace graph_tool; ...@@ -41,7 +41,7 @@ using namespace graph_tool;
template <class Graph> template <class Graph>
pair<int,int> get_triangles(typename graph_traits<Graph>::vertex_descriptor v, const Graph &g) pair<int,int> get_triangles(typename graph_traits<Graph>::vertex_descriptor v, const Graph &g)
{ {
static tr1::unordered_set<typename graph_traits<Graph>::vertex_descriptor> neighbour_set1, neighbour_set2, neighbour_set3; tr1::unordered_set<typename graph_traits<Graph>::vertex_descriptor> neighbour_set1, neighbour_set2, neighbour_set3;
size_t triangles = 0, k = 0; size_t triangles = 0, k = 0;
...@@ -103,23 +103,41 @@ struct get_global_clustering ...@@ -103,23 +103,41 @@ struct get_global_clustering
{ {
size_t triangles = 0, n = 0; size_t triangles = 0, n = 0;
pair<size_t, size_t> temp; pair<size_t, size_t> temp;
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g); int i, N = num_vertices(g);
for(v = v_begin; v != v_end; ++v)
#pragma omp parallel for default(shared) private(i,temp) schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
temp = get_triangles(v, g);
#pragma omp critical
{ {
temp = get_triangles(*v, g);
triangles += temp.first; triangles += temp.first;
n += temp.second; n += temp.second;
} }
}
c = double(triangles)/n; c = double(triangles)/n;
// "jackknife" variance // "jackknife" variance
c_err = 0.0; c_err = 0.0;
for(v = v_begin; v != v_end; ++v)
#pragma omp parallel for default(shared) private(i,temp) schedule(dynamic)
for (i = 0; i < N; ++i)
{ {
temp = get_triangles(*v, g); typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
temp = get_triangles(v, g);
double cl = double(triangles - temp.first)/(n - temp.second); double cl = double(triangles - temp.first)/(n - temp.second);
c_err = (c - cl)*(c - cl);
#pragma omp atomic
c_err += (c - cl)*(c - cl);
} }
c_err = sqrt(c_err); c_err = sqrt(c_err);
} }
...@@ -148,13 +166,22 @@ struct set_clustering_to_property ...@@ -148,13 +166,22 @@ struct set_clustering_to_property
void operator()(const Graph& g, ClustMap& clust_map) const void operator()(const Graph& g, ClustMap& clust_map) const
{ {
typename get_undirected_graph<Graph>::type ug(g); typename get_undirected_graph<Graph>::type ug(g);
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end; int i, N = num_vertices(g);
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v) #pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{ {
pair<size_t,size_t> triangles = get_triangles(*v,ug); // get from ug typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
pair<size_t,size_t> triangles = get_triangles(v,ug); // get from ug
double clustering = (triangles.second > 0)?double(triangles.first)/triangles.second:0.0; double clustering = (triangles.second > 0)?double(triangles.first)/triangles.second:0.0;
clust_map[*v] = clustering;
#pragma omp critical
{
clust_map[v] = clustering;
}
} }
} }
......
...@@ -52,17 +52,25 @@ struct get_distance_histogram ...@@ -52,17 +52,25 @@ struct get_distance_histogram
get_dists_djk>::type get_vertex_dists_t; get_dists_djk>::type get_vertex_dists_t;
get_vertex_dists_t get_vertex_dists; get_vertex_dists_t get_vertex_dists;
typename graph_traits<Graph>::vertex_iterator v, v2, v_end; int i, N = num_vertices(g);
for (tie(v, v_end) = vertices(g); v != v_end; ++v)
#pragma omp parallel for default(shared) private(i)
for (i = 0; i < N; ++i)
{ {
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor,double,DescriptorHash<IndexMap> > dmap_t; typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor,double,DescriptorHash<IndexMap> > dmap_t;
dmap_t dmap(0, DescriptorHash<IndexMap>(index_map)); dmap_t dmap(0, DescriptorHash<IndexMap>(index_map));
InitializedPropertyMap<dmap_t> dist_map(dmap, numeric_limits<double>::max()); InitializedPropertyMap<dmap_t> dist_map(dmap, numeric_limits<double>::max());
dist_map[*v] = 0.0; dist_map[v] = 0.0;
get_vertex_dists(g, *v, index_map, dist_map, weights); get_vertex_dists(g, v, index_map, dist_map, weights);
for (v2 = vertices(g).first; v2 != v_end; ++v2)
if (*v2 != *v && dist_map[*v2] != numeric_limits<double>::max()) typename graph_traits<Graph>::vertex_iterator v2, v_end;
for (tie(v2, v_end) = vertices(g); v2 != v_end; ++v2)
if (*v2 != v && dist_map[*v2] != numeric_limits<double>::max())
#pragma omp atomic
hist[dist_map[*v2]]++; hist[dist_map[*v2]]++;
} }
} }
......
...@@ -48,9 +48,6 @@ struct get_sampled_distances ...@@ -48,9 +48,6 @@ struct get_sampled_distances
template <class Graph, class IndexMap, class WeightMap, class Hist> template <class Graph, class IndexMap, class WeightMap, class Hist>
void operator()(const Graph &g, IndexMap index_map, WeightMap weights, Hist& hist, size_t samples, size_t seed) const void operator()(const Graph &g, IndexMap index_map, WeightMap weights, Hist& hist, size_t samples, size_t seed) const
{ {
typedef HashedDescriptorMap<IndexMap,double> dist_map_t;
dist_map_t dist_map(index_map);
// select get_sum_vertex_dists based on the existence of weights // select get_sum_vertex_dists based on the existence of weights
typedef typename mpl::if_<is_same<WeightMap, no_weightS>, typedef typename mpl::if_<is_same<WeightMap, no_weightS>,
get_dists_bfs, get_dists_bfs,
...@@ -60,7 +57,7 @@ struct get_sampled_distances ...@@ -60,7 +57,7 @@ struct get_sampled_distances
tr1::unordered_map<size_t, typename graph_traits<Graph>::vertex_descriptor> descriptors; tr1::unordered_map<size_t, typename graph_traits<Graph>::vertex_descriptor> descriptors;
typename graph_traits<Graph>::vertex_iterator v, v_end; typename graph_traits<Graph>::vertex_iterator v, v_end;
size_t i = 0, N = 0; int i = 0, N = 0;
for(tie(v, v_end) = vertices(g); v != v_end; ++v,++i) for(tie(v, v_end) = vertices(g); v != v_end; ++v,++i)
{ {
descriptors[i] = *v; descriptors[i] = *v;
...@@ -70,22 +67,34 @@ struct get_sampled_distances ...@@ -70,22 +67,34 @@ struct get_sampled_distances
rng_t rng(static_cast<rng_t::result_type>(seed)); rng_t rng(static_cast<rng_t::result_type>(seed));
uniform_int<size_t> sampler(0,descriptors.size()-1); uniform_int<size_t> sampler(0,descriptors.size()-1);
for(i=0; i < samples; ++i) #pragma omp parallel for default(shared) private(i,v,v_end)
for(i=0; i < int(samples); ++i)
{ {
typedef HashedDescriptorMap<IndexMap,double> dist_map_t;
dist_map_t dist_map(index_map);
for(tie(v, v_end) = vertices(g); v != v_end; ++v) for(tie(v, v_end) = vertices(g); v != v_end; ++v)
dist_map[*v] = numeric_limits<double>::max(); dist_map[*v] = numeric_limits<double>::max();
typename graph_traits<Graph>::vertex_descriptor s = descriptors[sampler(rng)], t; typename graph_traits<Graph>::vertex_descriptor s,t;
#pragma omp critical
{
s = descriptors[sampler(rng)];
do do
{ {
t = descriptors[sampler(rng)]; t = descriptors[sampler(rng)];
} }
while (t == s && N != 1); while (t == s && N != 1);
}
dist_map[s] = 0.0; dist_map[s] = 0.0;
get_vertex_dists(g, s, index_map, dist_map, weights); get_vertex_dists(g, s, index_map, dist_map, weights);
if (dist_map[t] != numeric_limits<double>::max() && dist_map[t] != 0.0) if (dist_map[t] != numeric_limits<double>::max() && dist_map[t] != 0.0)
{
#pragma omp atomic
hist[dist_map[t]]++; hist[dist_map[t]]++;
} }
}
} }
......
...@@ -82,13 +82,20 @@ struct get_extended_clustering ...@@ -82,13 +82,20 @@ struct get_extended_clustering
template <class Graph, class IndexMap, class ClusteringMap> template <class Graph, class IndexMap, class ClusteringMap>
void operator()(Graph& g, IndexMap vertex_index, vector<ClusteringMap>& cmaps) const void operator()(Graph& g, IndexMap vertex_index, vector<ClusteringMap>& cmaps) const
{ {
typename graph_traits<Graph>::vertex_iterator v, v_end;
for (tie(v,v_end) = vertices(g); v != v_end; ++v) int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{ {
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
// We must disconsider paths through the original vertex // We must disconsider paths through the original vertex
typedef single_vertex_filter<typename graph_traits<Graph>::vertex_descriptor> filter_t; typedef single_vertex_filter<typename graph_traits<Graph>::vertex_descriptor> filter_t;
typedef filtered_graph<Graph, keep_all, filter_t> fg_t; typedef filtered_graph<Graph, keep_all, filter_t> fg_t;
fg_t fg(g, keep_all(), filter_t(*v)); fg_t fg(g, keep_all(), filter_t(v));
typedef DescriptorHash<IndexMap> hasher_t; typedef DescriptorHash<IndexMap> hasher_t;
typedef tr1::unordered_set<typename graph_traits<Graph>::vertex_descriptor,hasher_t> neighbour_set_t; typedef tr1::unordered_set<typename graph_traits<Graph>::vertex_descriptor,hasher_t> neighbour_set_t;
...@@ -98,15 +105,15 @@ struct get_extended_clustering ...@@ -98,15 +105,15 @@ struct get_extended_clustering
// collect the targets // collect the targets
typename graph_traits<Graph>::adjacency_iterator a, a_end; typename graph_traits<Graph>::adjacency_iterator a, a_end;
for(tie(a, a_end) = adjacent_vertices(*v, g); a != a_end; ++a) for(tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
if (*a != *v) // no self-loops if (*a != v) // no self-loops
targets.insert(*a); targets.insert(*a);
size_t k = targets.size(); size_t k = targets.size();
// And now we setup and start the BFS bonanza // And now we setup and start the BFS bonanza
for(tie(a, a_end) = adjacent_vertices(*v, g); a != a_end; ++a) for(tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
{ {
if (*a == *v) // no self-loops if (*a == v) // no self-loops
continue; continue;
if (neighbours.find(*a) != neighbours.end()) // avoid parallel edges if (neighbours.find(*a) != neighbours.end()) // avoid parallel edges
continue; continue;
...@@ -133,15 +140,15 @@ struct get_extended_clustering ...@@ -133,15 +140,15 @@ struct get_extended_clustering
neighbours2.clear(); neighbours2.clear();
typename graph_traits<Graph>::adjacency_iterator a2; typename graph_traits<Graph>::adjacency_iterator a2;
for(a2 = adjacent_vertices(*v, g).first ; a2 != a_end ; ++a2) for(a2 = adjacent_vertices(v, g).first ; a2 != a_end ; ++a2)
{ {
if (*a2 == *v || *a2 == *a) // no self-loops if (*a2 == v || *a2 == *a) // no self-loops
continue; continue;
if (neighbours2.find(*a2) != neighbours2.end()) // avoid parallel edges if (neighbours2.find(*a2) != neighbours2.end()) // avoid parallel edges
continue; continue;
neighbours2.insert(*a2); neighbours2.insert(*a2);
if (distance_map[*a2] <= cmaps.size()) if (distance_map[*a2] <= cmaps.size())
cmaps[distance_map[*a2]-1][*v] += 1.0/(k*(k-1)); cmaps[distance_map[*a2]-1][v] += 1.0/(k*(k-1));
} }
} }
} }
......
...@@ -96,6 +96,32 @@ struct SoftNumEdges ...@@ -96,6 +96,32 @@ struct SoftNumEdges
size_t operator()(const Graph &g) const { return num_edges(g); } size_t operator()(const Graph &g) const { return num_edges(g); }
}; };
//==============================================================================
// vertex(i, filtered_graph<G>)
//==============================================================================
template <class Graph, class EdgePredicate, class VertexPredicate>
typename graph_traits<filtered_graph<Graph,EdgePredicate,VertexPredicate> >::vertex_descriptor
vertex(size_t i, const filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g.m_g);
if (g.m_vertex_pred(v))
return v;
else
return graph_traits<Graph>::null_vertex();
}
//==============================================================================
// vertex(i, reverse_graph<G>)
//==============================================================================
template <class Graph>
typename graph_traits<reverse_graph<Graph> >::vertex_descriptor
vertex(size_t i, const reverse_graph<Graph>& g)
{
return vertex(i, g.m_g);
}
//============================================================================== //==============================================================================
// RangeFilter // RangeFilter
//============================================================================== //==============================================================================
......
...@@ -35,7 +35,7 @@ using namespace boost::lambda; ...@@ -35,7 +35,7 @@ using namespace boost::lambda;
using namespace graph_tool; using namespace graph_tool;
typedef mpl::vector<bool, int, long, size_t, float, double, std::string> value_types; typedef mpl::vector<bool, int, long, size_t, float, double, std::string> value_types;
char* type_names[] = {"boolean", "int", "long", "long", "float", "double", "string"}; const char* type_names[] = {"boolean", "int", "long", "long", "float", "double", "string"};
//============================================================================== //==============================================================================
...@@ -191,7 +191,7 @@ template <class ValueTypes, class Descriptor, class IndexMap> ...@@ -191,7 +191,7 @@ template <class ValueTypes, class Descriptor, class IndexMap>
class get_property_map class get_property_map
{ {
public: public:
get_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, char* types[], python::object op, dynamic_property_map*& pmap) get_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, const char* types[], python::object op, dynamic_property_map*& pmap)
: _gi(gi), _dp(dp), _index_map(index_map), _property(property), _type(type), _types(types), _op(op), _pmap(pmap) {} : _gi(gi), _dp(dp), _index_map(index_map), _property(property), _type(type), _types(types), _op(op), _pmap(pmap) {}
template <class ValueType> template <class ValueType>
...@@ -244,7 +244,7 @@ private: ...@@ -244,7 +244,7 @@ private:
IndexMap _index_map; IndexMap _index_map;
string _property; string _property;
string _type; string _type;
char** _types; const char** _types;
python::object _op; python::object _op;
dynamic_property_map*& _pmap; dynamic_property_map*& _pmap;
}; };
...@@ -322,7 +322,7 @@ template <class ValueTypes> ...@@ -322,7 +322,7 @@ template <class ValueTypes>
class print_name class print_name
{ {
public: public:
print_name(const type_info& type, char* types[]): _type(type), _types(types) {} print_name(const type_info& type, const char* types[]): _type(type), _types(types) {}
template <class ValueType> template <class ValueType>
void operator()(ValueType) void operator()(ValueType)
...@@ -332,7 +332,7 @@ public: ...@@ -332,7 +332,7 @@ public:
} }
private: private:
const type_info& _type; const type_info& _type;
char** _types; const char** _types;
}; };
void GraphInterface::ListProperties() const void GraphInterface::ListProperties() const
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment