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 @@
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]