diff --git a/doc/betweenness_centrality.html b/doc/betweenness_centrality.html index 9b1a27d01..f5a9e9b1e 100644 --- a/doc/betweenness_centrality.html +++ b/doc/betweenness_centrality.html @@ -57,6 +57,20 @@

(Python)brandes_betweenness_centralit VertexIndexMap vertex_index, WeightMap weight_map); +template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, + typename IncomingMap, typename DistanceMap, typename DependencyMap, + typename PathCountMap, typename VertexIndexMap, typename WeightMap, + typename MultiplicityMap> +void +brandes_betweenness_centrality(const Graph& g, CentralityMap centrality_map, + EdgeCentralityMap edge_centrality, + IncomingMap incoming, + DistanceMap distance, DependencyMap dependency, + PathCountMap path_count, + VertexIndexMap vertex_index, + WeightMap weight_map, + MultiplicityMap multiplicity_map); + // helper functions template<typename Graph, typename CentralityMap> void @@ -271,12 +285,12 @@

Named parameters

Python: Unsupported parameter. -IN: weight_map(WeightMap w_map) +IN: weight_map(WeightMap weight_map)
The weight or ``length'' of each edge in the graph. The weights must all be non-negative, and the algorithm will throw a negative_edge - exception is one of the edges is negative. + exception if one of the edges is negative. The type WeightMap must be a model of Readable Property Map. The edge descriptor type of the graph needs to be usable as the key type for the weight @@ -286,6 +300,21 @@

Named parameters

Python: If supplied, must be an edge_double_map for the graph.
+IN: multiplicity_map(MultiplicityMap multiplicity_map) +
+ The multiplicity of each edge in the graph. The multiplicities + must all be positive, and the algorithm will throw a + nonpositive_edge + exception if one of the edges is non-positive. + The type MultiplicityMap must be a model of + Readable Property Map. The edge descriptor type of + the graph needs to be usable as the key type for the multiplicity + map. The value type for this map must be + the same as the value type of the distance map.
+ Default: All edge multiplicities are assumed to be one. + Python: Unsupported parameter. +
+

Complexity

The time complexity is O(VE) for unweighted graphs and O(VE + V(V+E) log V) for weighted graphs. The space complexity diff --git a/doc/exception.html b/doc/exception.html index def19cefd..f5f611bd8 100644 --- a/doc/exception.html +++ b/doc/exception.html @@ -34,7 +34,10 @@

Synopsis

struct not_a_dag : public bad_graph { not_a_dag(); }; - struct negative_edge : public bad_graph { + struct nonpositive_edge : public bad_graph { + negative_edge(); + }; + struct negative_edge : public nonpositive_edge { negative_edge(); }; struct negative_cycle : public bad_graph { diff --git a/include/boost/graph/betweenness_centrality.hpp b/include/boost/graph/betweenness_centrality.hpp index d596d5a28..6ae782a71 100644 --- a/include/boost/graph/betweenness_centrality.hpp +++ b/include/boost/graph/betweenness_centrality.hpp @@ -28,6 +28,23 @@ namespace boost { namespace detail { namespace graph { + + /** + * Check if an edge property is positive and throw an exception + * if it is not. + */ + template + void check_edge_positive(Edge e, Property property) { + // copied from dijkstra_shortest_paths + typedef typename property_traits::value_type property_type; + std::less_equal compare; + closed_plus combine; + property_type zero = property_type(); + if (compare(combine(zero, get(property, e)), zero)) { + boost::throw_exception(nonpositive_edge()); + } + } + /** * Customized visitor passed to Dijkstra's algorithm by Brandes' * betweenness centrality algorithm. This visitor is responsible for @@ -36,20 +53,22 @@ namespace detail { namespace graph { * of shortest paths. */ template + typename DistanceMap, typename PathCountMap, typename MultiplicityMap> struct brandes_dijkstra_visitor : public bfs_visitor<> { typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor; + typedef typename property_traits::value_type multiplicity_type; brandes_dijkstra_visitor(std::stack& ordered_vertices, WeightMap weight, IncomingMap incoming, DistanceMap distance, - PathCountMap path_count) - : ordered_vertices(ordered_vertices), weight(weight), + PathCountMap path_count, + MultiplicityMap multiplicity) + : ordered_vertices(ordered_vertices), weight(weight), incoming(incoming), distance(distance), - path_count(path_count) + path_count(path_count), multiplicity(multiplicity) { } /** @@ -59,10 +78,12 @@ namespace detail { namespace graph { */ void edge_relaxed(edge_descriptor e, const Graph& g) { + check_edge_positive(e, multiplicity); + vertex_descriptor v = source(e, g), w = target(e, g); incoming[w].clear(); incoming[w].push_back(e); - put(path_count, w, get(path_count, v)); + put(path_count, w, get(multiplicity, e) * get(path_count, v)); } /** @@ -73,6 +94,8 @@ namespace detail { namespace graph { */ void edge_not_relaxed(edge_descriptor e, const Graph& g) { + check_edge_positive(e, multiplicity); + typedef typename property_traits::value_type weight_type; typedef typename property_traits::value_type distance_type; vertex_descriptor v = source(e, g), w = target(e, g); @@ -81,7 +104,8 @@ namespace detail { namespace graph { closed_plus combine; if (d_w == combine(d_v, w_e)) { - put(path_count, w, get(path_count, w) + get(path_count, v)); + put(path_count, w, + get(path_count, w) + get(multiplicity, e) * get(path_count, v)); incoming[w].push_back(e); } } @@ -98,6 +122,7 @@ namespace detail { namespace graph { IncomingMap incoming; DistanceMap distance; PathCountMap path_count; + MultiplicityMap multiplicity; }; /** @@ -105,11 +130,11 @@ namespace detail { namespace graph { * using the Dijkstra visitor for the Brandes betweenness centrality * algorithm. */ - template + template struct brandes_dijkstra_shortest_paths { - brandes_dijkstra_shortest_paths(WeightMap weight_map) - : weight_map(weight_map) { } + brandes_dijkstra_shortest_paths(WeightMap weight_map, MultiplicityMap multiplicity_map) + : weight_map(weight_map), multiplicity_map(multiplicity_map) { } template @@ -123,8 +148,10 @@ namespace detail { namespace graph { VertexIndexMap vertex_index) { typedef brandes_dijkstra_visitor visitor_type; - visitor_type visitor(ov, weight_map, incoming, distance, path_count); + DistanceMap, PathCountMap, + MultiplicityMap> visitor_type; + visitor_type visitor(ov, weight_map, incoming, distance, path_count, + multiplicity_map); dijkstra_shortest_paths(g, s, boost::weight_map(weight_map) @@ -135,14 +162,21 @@ namespace detail { namespace graph { private: WeightMap weight_map; + MultiplicityMap multiplicity_map; }; /** * Function object that invokes breadth-first search for the * unweighted form of the Brandes betweenness centrality algorithm. */ + template struct brandes_unweighted_shortest_paths { + + brandes_unweighted_shortest_paths(MultiplicityMap multiplicity_map) + : multiplicity_map(multiplicity_map) + { } + /** * Customized visitor passed to breadth-first search, which * records predecessor and the number of shortest paths to each @@ -158,9 +192,11 @@ namespace detail { namespace graph { visitor_type(IncomingMap incoming, DistanceMap distance, PathCountMap path_count, - std::stack& ordered_vertices) + std::stack& ordered_vertices, + MultiplicityMap multiplicity) : incoming(incoming), distance(distance), - path_count(path_count), ordered_vertices(ordered_vertices) { } + path_count(path_count), ordered_vertices(ordered_vertices), + multiplicity(multiplicity) { } /// Keep track of vertices as they are reached void examine_vertex(vertex_descriptor v, Graph&) @@ -175,11 +211,13 @@ namespace detail { namespace graph { */ void tree_edge(edge_descriptor e, Graph& g) { + check_edge_positive(e, multiplicity); + vertex_descriptor v = source(e, g); vertex_descriptor w = target(e, g); put(distance, w, get(distance, v) + 1); - put(path_count, w, get(path_count, v)); + put(path_count, w, get(multiplicity, e) * get(path_count, v)); incoming[w].push_back(e); } @@ -191,10 +229,13 @@ namespace detail { namespace graph { */ void non_tree_edge(edge_descriptor e, Graph& g) { + check_edge_positive(e, multiplicity); + vertex_descriptor v = source(e, g); vertex_descriptor w = target(e, g); if (get(distance, w) == get(distance, v) + 1) { - put(path_count, w, get(path_count, w) + get(path_count, v)); + put(path_count, w, + get(path_count, w) + get(multiplicity, e) * get(path_count, v)); incoming[w].push_back(e); } } @@ -204,6 +245,7 @@ namespace detail { namespace graph { DistanceMap distance; PathCountMap path_count; std::stack& ordered_vertices; + MultiplicityMap multiplicity; }; template - visitor(incoming, distance, path_count, ov); + visitor(incoming, distance, path_count, ov, multiplicity_map); std::vector colors(num_vertices(g), color_traits::white()); @@ -230,6 +272,30 @@ namespace detail { namespace graph { make_iterator_property_map(colors.begin(), vertex_index)); } + + private: + MultiplicityMap multiplicity_map; + }; + + template + struct make_shortest_paths + { + typedef brandes_dijkstra_shortest_paths type; + type operator()(WeightMap weight_map, MultiplicityMap multiplicity_map) + { + return brandes_dijkstra_shortest_paths + (weight_map, multiplicity_map); + } + }; + + template + struct make_shortest_paths + { + typedef brandes_unweighted_shortest_paths type; + type operator()(dummy_property_map weight_map, MultiplicityMap multiplicity_map) + { + return brandes_unweighted_shortest_paths(multiplicity_map); + } }; // When the edge centrality map is a dummy property map, no @@ -294,6 +360,34 @@ namespace detail { namespace graph { PathCountMap path_count, // sigma VertexIndexMap vertex_index, ShortestPaths shortest_paths) + { + // default constant multiplicity of one + typedef typename property_traits::value_type multiplicity_type; + typedef static_property_map MultiplicityMap; + MultiplicityMap multiplicity_map(multiplicity_type(1)); + + brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, + incoming, distance, dependency, + path_count, vertex_index, shortest_paths, + multiplicity_map); + } + + template + void + brandes_betweenness_centrality_impl(const Graph& g, + CentralityMap centrality, // C_B + EdgeCentralityMap edge_centrality_map, + IncomingMap incoming, // P + DistanceMap distance, // d + DependencyMap dependency, // delta + PathCountMap path_count, // sigma + VertexIndexMap vertex_index, + ShortestPaths shortest_paths, + MultiplicityMap multiplicity_map) { typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename graph_traits::vertex_descriptor vertex_descriptor; @@ -335,6 +429,7 @@ namespace detail { namespace graph { vertex_descriptor v = source(*vw, g); dependency_type factor = dependency_type(get(path_count, v)) / dependency_type(get(path_count, w)); + factor *= dependency_type(get(multiplicity_map, *vw)); factor *= (dependency_type(1) + get(dependency, w)); put(dependency, v, get(dependency, v) + factor); update_centrality(edge_centrality_map, *vw, factor); @@ -372,7 +467,13 @@ brandes_betweenness_centrality(const Graph& g, VertexIndexMap vertex_index BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) { - detail::graph::brandes_unweighted_shortest_paths shortest_paths; + // default constant multiplicity of one + typedef typename property_traits::value_type multiplicity_type; + typedef static_property_map MultiplicityMap; + MultiplicityMap multiplicity_map(multiplicity_type(1)); + + detail::graph::brandes_unweighted_shortest_paths + shortest_paths(multiplicity_map); detail::graph::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, @@ -398,26 +499,56 @@ brandes_betweenness_centrality(const Graph& g, WeightMap weight_map BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) { - detail::graph::brandes_dijkstra_shortest_paths - shortest_paths(weight_map); + // default constant multiplicity of one + typedef typename property_traits::value_type multiplicity_type; + typedef static_property_map MultiplicityMap; + MultiplicityMap multiplicity_map(multiplicity_type(1)); + + brandes_betweenness_centrality(g, centrality, edge_centrality_map, + incoming, distance, dependency, path_count, + vertex_index, weight_map, multiplicity_map); +} + +template +void +brandes_betweenness_centrality(const Graph& g, + CentralityMap centrality, // C_B + EdgeCentralityMap edge_centrality_map, + IncomingMap incoming, // P + DistanceMap distance, // d + DependencyMap dependency, // delta + PathCountMap path_count, // sigma + VertexIndexMap vertex_index, + WeightMap weight_map, + MultiplicityMap multiplicity_map + BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) +{ + typedef detail::graph::make_shortest_paths make; + typedef typename make::type ShortestPaths; + ShortestPaths shortest_paths = make()(weight_map, multiplicity_map); detail::graph::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, - shortest_paths); + shortest_paths, + multiplicity_map); } namespace detail { namespace graph { template + typename WeightMap, typename VertexIndexMap, typename MultiplicityMap> void brandes_betweenness_centrality_dispatch2(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, WeightMap weight_map, - VertexIndexMap vertex_index) + VertexIndexMap vertex_index, + MultiplicityMap multiplicity_map) { typedef typename graph_traits::degree_size_type degree_size_type; typedef typename graph_traits::edge_descriptor edge_descriptor; @@ -442,7 +573,8 @@ namespace detail { namespace graph { make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, - weight_map); + weight_map, + multiplicity_map); } @@ -479,7 +611,7 @@ namespace detail { namespace graph { vertex_index); } - template + template struct brandes_betweenness_centrality_dispatch1 { template + struct brandes_betweenness_centrality_dispatch1 + { + template + static void + run(const Graph& g, CentralityMap centrality, + EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, + WeightMap weight_map, param_not_found) + { + // default constant multiplicity of one + typedef typename mpl::if_, + EdgeCentralityMap, CentralityMap>::type + a_centrality_map; + typedef typename property_traits::value_type multiplicity_type; + typedef static_property_map MultiplicityMap; + MultiplicityMap multiplicity_map(multiplicity_type(1)); + + brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map, + weight_map, vertex_index, + multiplicity_map); + } + }; + + template + struct brandes_betweenness_centrality_dispatch1 + { + template + static void + run(const Graph& g, CentralityMap centrality, + EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, + param_not_found, MultiplicityMap multiplicity_map) { + // default weight to dummy property map brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map, - weight_map, vertex_index); + dummy_property_map(), vertex_index, + multiplicity_map); } }; template<> - struct brandes_betweenness_centrality_dispatch1 + struct brandes_betweenness_centrality_dispatch1 { template static void run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, - param_not_found) + param_not_found, param_not_found) { brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map, vertex_index); @@ -530,14 +704,16 @@ brandes_betweenness_centrality(const Graph& g, typedef bgl_named_params named_params; typedef typename get_param_type::type ew; - detail::graph::brandes_betweenness_centrality_dispatch1::run( + typedef typename get_param_type::type em; + detail::graph::brandes_betweenness_centrality_dispatch1::run( g, choose_param(get_param(params, vertex_centrality), dummy_property_map()), choose_param(get_param(params, edge_centrality), dummy_property_map()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), - get_param(params, edge_weight)); + get_param(params, edge_weight), + get_param(params, edge_multiplicity_t())); } // disable_if is required to work around problem with MSVC 7.1 (it seems to not diff --git a/include/boost/graph/exception.hpp b/include/boost/graph/exception.hpp index 382d67192..3a28af26e 100644 --- a/include/boost/graph/exception.hpp +++ b/include/boost/graph/exception.hpp @@ -26,9 +26,18 @@ namespace boost { { } }; - struct negative_edge : public bad_graph { + struct nonpositive_edge : public bad_graph { + nonpositive_edge() + : bad_graph("The graph may not contain an edge with non-positive weight.") + { } + protected: + nonpositive_edge(const std::string& what_arg) + : bad_graph(what_arg) { } + }; + + struct negative_edge : public nonpositive_edge { negative_edge() - : bad_graph("The graph may not contain an edge with negative weight.") + : nonpositive_edge("The graph may not contain an edge with negative weight.") { } }; diff --git a/include/boost/graph/named_function_params.hpp b/include/boost/graph/named_function_params.hpp index 26d3d5e40..b3dda72d4 100644 --- a/include/boost/graph/named_function_params.hpp +++ b/include/boost/graph/named_function_params.hpp @@ -28,6 +28,7 @@ namespace boost { struct parity_map_t { }; + struct edge_multiplicity_t { }; struct vertex_assignment_map_t { }; struct distance_compare_t { }; struct distance_combine_t { }; @@ -76,6 +77,7 @@ namespace boost { BOOST_BGL_ONE_PARAM_CREF(edge_color_map, edge_color) \ BOOST_BGL_ONE_PARAM_CREF(capacity_map, edge_capacity) \ BOOST_BGL_ONE_PARAM_CREF(residual_capacity_map, edge_residual_capacity) \ + BOOST_BGL_ONE_PARAM_CREF(multiplicity_map, edge_multiplicity) \ BOOST_BGL_ONE_PARAM_CREF(reverse_edge_map, edge_reverse) \ BOOST_BGL_ONE_PARAM_CREF(discover_time_map, vertex_discover_time) \ BOOST_BGL_ONE_PARAM_CREF(lowpoint_map, vertex_lowpoint) \ diff --git a/quickbook/reference/betweenness_centrality.qbk b/quickbook/reference/betweenness_centrality.qbk index 3c65610a4..93c25a0d3 100644 --- a/quickbook/reference/betweenness_centrality.qbk +++ b/quickbook/reference/betweenness_centrality.qbk @@ -182,4 +182,20 @@ interface. VertexIndexMap vertex_index, WeightMap weight_map) + template + void + brandes_betweenness_centrality(const Graph& g, + CentralityMap centrality, + EdgeCentralityMap edge_centrality, + IncomingMap incoming, + DistanceMap distance, + DependencyMap dependency, + PathCountMap path_count, + VertexIndexMap vertex_index, + WeightMap weight_map, + MultiplicityMap multiplicity_map) + [endsect]