// graph-tool -- a general graph modification and manipulation thingy // // Copyright (C) 2006-2017 Tiago de Paula Peixoto // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 3 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #ifndef GRAPH_CLOSENESS_HH #define GRAPH_CLOSENESS_HH #include #include #include #include #include #include "histogram.hh" #include "hash_map_wrap.hh" namespace graph_tool { using namespace std; struct no_weightS {}; template struct get_val_type { typedef typename boost::property_traits::value_type type; }; template <> struct get_val_type { typedef size_t type; }; struct get_closeness { typedef void result_type; template void operator()(const Graph& g, VertexIndex vertex_index, WeightMap weights, Closeness closeness, bool harmonic, bool norm) const { using namespace boost; // select get_vertex_dists based on the existence of weights typedef typename mpl::if_, get_dists_bfs, get_dists_djk>::type get_vertex_dists_t; // distance type typedef typename get_val_type::type val_type; get_vertex_dists_t get_vertex_dists; size_t HN = HardNumVertices()(g); parallel_vertex_loop (g, [&](auto v) { unchecked_vector_property_map dist_map(vertex_index, num_vertices(g)); for (auto u : vertices_range(g)) dist_map[u] = numeric_limits::max(); dist_map[v] = 0; size_t comp_size = 0; get_vertex_dists(g, v, vertex_index, dist_map, weights, comp_size); closeness[v] = 0; for (auto v2 : vertices_range(g)) { if (v2 != v && dist_map[v2] != numeric_limits::max()) { if (!harmonic) closeness[v] += dist_map[v2]; else closeness[v] += 1. / dist_map[v2]; } } if (!harmonic) closeness[v] = 1 / closeness[v]; if (norm) { if (harmonic) closeness[v] /= HN - 1; else closeness[v] *= comp_size - 1; } }); } class component_djk_visitor: public boost::dijkstra_visitor<> { public: //component_visitor() { } component_djk_visitor(size_t& comp_size) : _comp_size(comp_size) { } template void discover_vertex(Vertex, const Graph&) { ++_comp_size; } private: size_t& _comp_size; }; // weighted version. Use dijkstra_shortest_paths() struct get_dists_djk { template void operator()(const Graph& g, Vertex s, VertexIndex vertex_index, DistanceMap dist_map, WeightMap weights, size_t& comp_size) const { using namespace boost; component_djk_visitor vis(comp_size); dijkstra_shortest_paths(g, s, vertex_index_map(vertex_index). weight_map(weights).distance_map(dist_map).visitor(vis)); } }; template class component_bfs_visitor: public boost::bfs_visitor<> { public: //component_visitor() { } component_bfs_visitor(DistMap dist_map, size_t& comp_size) : _dist_map(dist_map), _comp_size(comp_size) { } template void discover_vertex(Vertex, const Graph&) { ++_comp_size; } template void tree_edge(Edge e, const Graph& g) { _dist_map[target(e, g)] = _dist_map[source(e, g)] + 1; } private: DistMap _dist_map; size_t& _comp_size; }; // unweighted version. Use BFS. struct get_dists_bfs { template void operator()(const Graph& g, Vertex s, VertexIndex vertex_index, DistanceMap dist_map, no_weightS, size_t& comp_size) const { using namespace boost; typedef typename graph_traits::vertex_descriptor vertex_t; typedef gt_hash_map > cmap_t; cmap_t cmap(0, DescriptorHash(vertex_index)); InitializedPropertyMap color_map(cmap, color_traits::white()); component_bfs_visitor vis(dist_map, comp_size); breadth_first_visit(g, s, visitor(vis). color_map(color_map)); } }; }; } // boost namespace #endif // GRAPH_CLOSENESS_HH