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

* 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],
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.
......
......@@ -155,7 +155,7 @@ class mutate_graph_impl : public mutate_graph
public:
put_property(const std::string& name, dynamic_properties& dp, const Key& key,
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_value_type(value_type), m_type_names(type_names),
m_type_found(type_found) {}
......@@ -174,7 +174,7 @@ class mutate_graph_impl : public mutate_graph
const Key& m_key;
const std::string& m_value;
const std::string& m_value_type;
char** m_type_names;
const char** m_type_names;
bool& m_type_found;
};
......@@ -182,11 +182,11 @@ protected:
MutableGraph& m_g;
dynamic_properties& m_dp;
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>
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
read_graphml(std::istream& in, mutate_graph& g);
......@@ -203,7 +203,7 @@ template <typename Types>
class get_type_name
{
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) {}
template <typename Type>
void operator()(Type)
......@@ -213,7 +213,7 @@ public:
}
private:
const std::type_info &m_type;
char** m_type_names;
const char** m_type_names;
std::string &m_type_name;
};
......@@ -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";
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> vertex_key_ids;
std::map<std::string, std::string> edge_key_ids;
......
......@@ -49,6 +49,7 @@ libgraph_tool_la_SOURCES = \
libgraph_tool_la_LIBADD = \
$(PYTHON_LDFLAGS) \
$(BOOST_LDFLAGS) \
$(OPENMP_LDFLAGS) \
-lboost_python \
-lboost_iostreams \
-lexpat
......
......@@ -41,7 +41,7 @@ using namespace graph_tool;
template <class Graph>
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;
......@@ -103,23 +103,41 @@ struct get_global_clustering
{
size_t triangles = 0, n = 0;
pair<size_t, size_t> temp;
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v)
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i,temp) schedule(dynamic)
for (i = 0; i < N; ++i)
{
temp = get_triangles(*v, g);
triangles += temp.first;
n += temp.second;
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
{
triangles += temp.first;
n += temp.second;
}
}
c = double(triangles)/n;
// "jackknife" variance
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);
c_err = (c - cl)*(c - cl);
#pragma omp atomic
c_err += (c - cl)*(c - cl);
}
c_err = sqrt(c_err);
}
......@@ -148,13 +166,22 @@ struct set_clustering_to_property
void operator()(const Graph& g, ClustMap& clust_map) const
{
typename get_undirected_graph<Graph>::type ug(g);
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; 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)
{
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;
clust_map[*v] = clustering;
#pragma omp critical
{
clust_map[v] = clustering;
}
}
}
......
......@@ -52,18 +52,26 @@ struct get_distance_histogram
get_dists_djk>::type get_vertex_dists_t;
get_vertex_dists_t get_vertex_dists;
typename graph_traits<Graph>::vertex_iterator v, v2, 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)
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;
dmap_t dmap(0, DescriptorHash<IndexMap>(index_map));
InitializedPropertyMap<dmap_t> dist_map(dmap, numeric_limits<double>::max());
dist_map[*v] = 0.0;
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())
hist[dist_map[*v2]]++;
dist_map[v] = 0.0;
get_vertex_dists(g, v, index_map, dist_map, weights);
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]]++;
}
}
......
......@@ -48,9 +48,6 @@ struct get_sampled_distances
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
{
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
typedef typename mpl::if_<is_same<WeightMap, no_weightS>,
get_dists_bfs,
......@@ -60,7 +57,7 @@ struct get_sampled_distances
tr1::unordered_map<size_t, typename graph_traits<Graph>::vertex_descriptor> descriptors;
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)
{
descriptors[i] = *v;
......@@ -70,21 +67,33 @@ struct get_sampled_distances
rng_t rng(static_cast<rng_t::result_type>(seed));
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)
dist_map[*v] = numeric_limits<double>::max();
typename graph_traits<Graph>::vertex_descriptor s = descriptors[sampler(rng)], t;
do
typename graph_traits<Graph>::vertex_descriptor s,t;
#pragma omp critical
{
t = descriptors[sampler(rng)];
s = descriptors[sampler(rng)];
do
{
t = descriptors[sampler(rng)];
}
while (t == s && N != 1);
}
while (t == s && N != 1);
dist_map[s] = 0.0;
get_vertex_dists(g, s, index_map, dist_map, weights);
if (dist_map[t] != numeric_limits<double>::max() && dist_map[t] != 0.0)
{
#pragma omp atomic
hist[dist_map[t]]++;
}
}
}
......
......@@ -82,13 +82,20 @@ struct get_extended_clustering
template <class Graph, class IndexMap, class ClusteringMap>
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
typedef single_vertex_filter<typename graph_traits<Graph>::vertex_descriptor> filter_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 tr1::unordered_set<typename graph_traits<Graph>::vertex_descriptor,hasher_t> neighbour_set_t;
......@@ -98,15 +105,15 @@ struct get_extended_clustering
// collect the targets
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
for(tie(a, a_end) = adjacent_vertices(v, g); a != a_end; ++a)
if (*a != v) // no self-loops
targets.insert(*a);
size_t k = targets.size();
// 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;
if (neighbours.find(*a) != neighbours.end()) // avoid parallel edges
continue;
......@@ -133,15 +140,15 @@ struct get_extended_clustering
neighbours2.clear();
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;
if (neighbours2.find(*a2) != neighbours2.end()) // avoid parallel edges
continue;
neighbours2.insert(*a2);
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
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
//==============================================================================
......
......@@ -35,7 +35,7 @@ using namespace boost::lambda;
using namespace graph_tool;
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>
class get_property_map
{
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) {}
template <class ValueType>
......@@ -244,7 +244,7 @@ private:
IndexMap _index_map;
string _property;
string _type;
char** _types;
const char** _types;
python::object _op;
dynamic_property_map*& _pmap;
};
......@@ -322,7 +322,7 @@ template <class ValueTypes>
class print_name
{
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>
void operator()(ValueType)
......@@ -332,7 +332,7 @@ public:
}
private:
const type_info& _type;
char** _types;
const char** _types;
};
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