This commit was manufactured by cvs2svn to create tag
'merged_to_graph_devel'. [SVN r24507]
22
doc/betweenness_centrality_clustering.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Function betweenness_centrality_clustering</title><div class="titlepage"><div></div><div></div></div><div class="refnamediv"><h2><span class="refentrytitle">Function betweenness_centrality_clustering</span></h2><p>boost::betweenness_centrality_clustering — Graph clustering based on edge betweenness centrality.</p></div><h2 xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv-title">Synopsis</h2><div xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv"><pre class="synopsis">
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> MutableGraph, <span class="bold"><b>typename</b></span> Done, <span class="bold"><b>typename</b></span> EdgeCentralityMap,
|
||||
<span class="bold"><b>typename</b></span> VertexIndexMap>
|
||||
<span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph & g, Done done,
|
||||
EdgeCentralityMap edge_centrality,
|
||||
VertexIndexMap vertex_index);
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> MutableGraph, <span class="bold"><b>typename</b></span> Done, <span class="bold"><b>typename</b></span> EdgeCentralityMap>
|
||||
<span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph & g, Done done,
|
||||
EdgeCentralityMap edge_centrality);
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> MutableGraph, <span class="bold"><b>typename</b></span> Done>
|
||||
<span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph & g, Done done);</pre></div><div class="refsect1" lang="en"><a name="id822306"></a><h2>Description</h2><div class="variablelist"><p class="title"><b>Parameters</b></p><dl><dt><span class="term">done</span></dt><dd><p>The function object that indicates termination of the algorithm. It must be a ternary function object thats accepts the maximum centrality, the descriptor of the edge that will be removed, and the graph <tt class="computeroutput">g</tt> .</p></dd><dt><span class="term">edge_centrality</span></dt><dd><p>(UTIL/OUT) The property map that will store the betweenness centrality for each edge. When the algorithm terminates, it will contain the edge centralities for the graph. The type of this property map must model the ReadWritePropertyMap concept. Defaults to an <tt class="computeroutput">iterator_property_map</tt> whose value type is <tt class="computeroutput">Done::centrality_type</tt> and using <tt class="computeroutput">get(edge_index, g)</tt> for the index map.</p></dd><dt><span class="term">g</span></dt><dd><p>The graph on which clustering will be performed. The type of this parameter (<tt class="computeroutput">MutableGraph</tt> ) must be a model of the VertexListGraph, IncidenceGraph, EdgeListGraph, and Mutable Graph concepts.</p></dd><dt><span class="term">vertex_index</span></dt><dd><p>(IN) The property map that maps vertices to indices in the range <tt class="computeroutput"></tt> [0, num_vertices(g)). This type of this property map must model the ReadablePropertyMap concept and its value type must be an integral type. Defaults to <tt class="computeroutput">get(vertex_index, g)</tt> . </p></dd></dl></div><p>This algorithm implements graph clustering based on edge betweenness centrality. It is an iterative algorithm, where in each step it compute the edge betweenness centrality (via <a href="brandes_betweenness_centrality.html"/>brandes_betweenness_centrality</a>) and removes the edge with the maximum betweenness centrality. The <tt class="computeroutput">done</tt> function object determines when the algorithm terminates (the edge found when the algorithm terminates will not be removed).</p><p></p></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small></small></td></tr></table><hr>
|
||||
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2004</TD><TD>
|
||||
<A HREF="../../../people/doug_gregor.html">Douglas Gregor</A>, Indiana University (dgregor@cs.indiana.edu</A>)<br>
|
||||
<A HREF=http://www.osl.iu.edu/~lums>Andrew Lumsdaine</A>,
|
||||
Indiana University (<A
|
||||
HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</body></html>
|
||||
278
doc/brandes_betweenness_centrality.html
Normal file
@@ -0,0 +1,278 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Boost Graph Library: Brandes' Betweenness Centrality</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<IMG SRC="../../../c++boost.gif"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
<h1><tt>brandes_betweenness_centrality</tt></h1>
|
||||
|
||||
<p>
|
||||
<pre>
|
||||
<em>// named parameter versions</em>
|
||||
template<typename Graph, typename Param, typename Tag, typename Rest>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g,
|
||||
const bgl_named_params<Param,Tag,Rest>& params);
|
||||
|
||||
template<typename Graph, typename CentralityMap>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality_map);
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality_map,
|
||||
EdgeCentralityMap edge_centrality);
|
||||
|
||||
<em>// non-named parameter versions</em>
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename IncomingMap, typename DistanceMap, typename DependencyMap,
|
||||
typename PathCountMap, typename VertexIndexMap>
|
||||
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);
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename IncomingMap, typename DistanceMap, typename DependencyMap,
|
||||
typename PathCountMap, typename VertexIndexMap, typename WeightMap>
|
||||
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);
|
||||
|
||||
<em>// helper functions</em>
|
||||
template<typename Graph, typename CentralityMap>
|
||||
void
|
||||
relative_betweenness_centrality(const Graph& g, CentralityMap centrality_map);
|
||||
|
||||
template<typename Graph, typename CentralityMap>
|
||||
typename property_traits<CentralityMap>::value_type
|
||||
central_point_dominance(const Graph& g, CentralityMap centrality_map);
|
||||
</pre>
|
||||
|
||||
<p>This algorithm [<a href="bibliography.html#brandes01">54</a>]
|
||||
computes the <em>betweenness centrality</em> [<a
|
||||
href="bibliography.html#freeman77">55</a>,<a
|
||||
href="bibliography.html#anthonisse71">56</a>] of each vertex or each
|
||||
edge in the graph. The betweenness centrality of a vertex <em>v</em>
|
||||
is defined by
|
||||
|
||||
<p><img src="figs/betweenness_centrality.gif">,
|
||||
|
||||
<p>where <img src="figs/sigma_st.gif"> is the number of shortest paths from
|
||||
vertex <em>s</em> to vertex <em>t</em> and <img src="figs/sigma_stv.gif">
|
||||
is the number of shortest paths from vertex <em>s</em> to vertex
|
||||
<em>t</em> that pass through vertex <em>v</em>.
|
||||
|
||||
<!-- \sum_{s \neq v \neq t}\frac{\sigma_{st}(v)}{\sigma_{st}} -->
|
||||
|
||||
<p>The edge betweenness centrality indicates for each edge the
|
||||
betweenness centrality that was contributed to the target(s) of the
|
||||
edge (plural for undirected graphs). Similar to (vertex) betweenness
|
||||
centrality, edge betweenness centrality can be used to determine the
|
||||
edges through which most shortest paths must pass. A single invocation
|
||||
of this algorithm can compute either the vertex or edge centrality (or
|
||||
both).</p>
|
||||
|
||||
<p>This algorithm can operate either on weighted graphs (if a suitable
|
||||
edge weight map is supplied) or unweighted graphs (if no edge weight
|
||||
map is supplied). The result is the absolute betweenness centrality;
|
||||
to convert to the relative betweenness centrality, which scales each
|
||||
absolute centrality by <img src="figs/relative_betweenness_centrality.gif">
|
||||
(where <em>n</em> is the number of vertices in the graph), use
|
||||
<tt>relative_betweenness_centrality</tt>. Given the relative
|
||||
betweenness centrality, one can compute the <em>central point
|
||||
dominance</em> [<a href="bibliography.html#freeman77">55</a>], which is a measure of the maximum "betweenness" of any
|
||||
point in the graph: it will be 0 for complete graphs and
|
||||
1 for "wheel" graphs (in which there is a central vertex that all
|
||||
paths include; see <a href="#Fig1">Fig. 1</a>). Let <img src="figs/v_star.gif"> be the vertex with the largest relative betweenness centrality; then, the central point dominance is defined as:
|
||||
|
||||
<p><img src="figs/central_point_dominance.gif">
|
||||
|
||||
<!-- C_B' = \frac{\sum_{v \in V} C_B(v^*) - C_B'(v)}{n-1} -->
|
||||
|
||||
<p><a name="Fig1">
|
||||
<table border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fig. 1: A wheel graph, where every path travels through the central node. <br>The central point dominance of this graph is 1.</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center"><img src="figs/wheel_graph.gif"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Where Defined</h3>
|
||||
<a href="../../../boost/graph/brandes_betweenness_centrality.hpp"><tt>boost/graph/brandes_betweenness_centrality.hpp</tt></a>
|
||||
|
||||
<h3>Parameters</h3>
|
||||
IN: <tt>const Graph& g</tt>
|
||||
<blockquote>
|
||||
The graph object on which the algorithm will be applied. The type
|
||||
<tt>Graph</tt> must be a model of <a
|
||||
href="VertexListGraph.html">Vertex List Graph</a> and <a
|
||||
href="IncidenceGraph.html">Incidence Graph</a>. When an edge
|
||||
centrality map is supplied, it must also model <a
|
||||
href="EdgeListGraph.html">Edge List Graph</a>.
|
||||
</blockquote>
|
||||
|
||||
UTIL: <tt>IncomingMap incoming</tt>
|
||||
<blockquote>
|
||||
This property map records the set of edges incoming to each vertex that comprise a shortest path from a particular source vertex through this vertex, and is used internally by the algorithm.The <tt>IncomingMap</tt> type must be a <a
|
||||
href="../../property_map/LvaluePropertyMap.html">Lvalue Property
|
||||
Map</a> whose key type is the same as the vertex descriptor type of
|
||||
the graph and whose value type is a Sequence (e.g., an
|
||||
<tt>std::vector</tt>) containing edge descriptors.<br>
|
||||
|
||||
<b>Default:</b> <a
|
||||
href="../../property_map/iterator_property_map.html">
|
||||
<tt>iterator_property_map</tt></a> created from a
|
||||
<tt>std::vector</tt> of <tt>std::vector<Edge></tt>, where
|
||||
<tt>Edge</tt> is the edge descriptor type of the graph.
|
||||
</blockquote>
|
||||
|
||||
UTIL: <tt>DistanceMap distance_map</tt>
|
||||
<blockquote>
|
||||
The shortest path weight from each source vertex <tt>s</tt> to each
|
||||
vertex in the graph <tt>g</tt> is recorded in this property map, but
|
||||
the result is only used internally. The type <tt>DistanceMap</tt>
|
||||
must be a model of <a
|
||||
href="../../property_map/ReadWritePropertyMap.html">Read/Write
|
||||
Property Map</a>. The vertex descriptor type of the graph needs to
|
||||
be usable as the key type of the distance map. The value type of the
|
||||
distance map is the element type of a <a
|
||||
href="./Monoid.html">Monoid</a>.<br>
|
||||
|
||||
<b>Default:</b> <a
|
||||
href="../../property_map/iterator_property_map.html">
|
||||
<tt>iterator_property_map</tt></a> created from a
|
||||
<tt>std::vector</tt> of the <tt>WeightMap</tt>'s value type (or the
|
||||
<tt>vertices_size_type</tt> of the graph when no weight map exists)
|
||||
of size <tt>num_vertices(g)</tt> and using the <tt>vertex_index</tt> for
|
||||
the index map.
|
||||
</blockquote>
|
||||
|
||||
UTIL: <tt>DependencyMap dependency</tt>
|
||||
<blockquote>
|
||||
Property map used internally to accumulate partial betweenness
|
||||
centrality results. The type <tt>DependencyMap</tt> must be a model
|
||||
of <a href="../../property_map/ReadWritePropertyMap.html">Read/Write
|
||||
Property Map</a>. The vertex descriptor type of the graph needs to
|
||||
be usable as the key type of the dependency map. The value type of
|
||||
the dependency map must be compatible with the value type of the
|
||||
centrality map.<br>
|
||||
|
||||
<b>Default:</b> <a
|
||||
href="../../property_map/iterator_property_map.html">
|
||||
<tt>iterator_property_map</tt></a> created from a
|
||||
<tt>std::vector</tt> of the <tt>CentralityMap</tt>'s value type of
|
||||
size <tt>num_vertices(g)</tt> and using the <tt>vertex_index</tt>
|
||||
for the index map.
|
||||
</blockquote>
|
||||
|
||||
UTIL: <tt>PathCountMap path_count</tt>
|
||||
<blockquote>
|
||||
Property map used internally to accumulate the number of paths that
|
||||
pass through each particular vertex. The type <tt>PathCountMap</tt>
|
||||
must be a model of <a
|
||||
href="../../property_map/ReadWritePropertyMap.html">Read/Write
|
||||
Property Map</a>. The vertex descriptor type of the graph needs to
|
||||
be usable as the key type of the dependency map. The value type of
|
||||
the dependency map must be an integral type large enough to store
|
||||
the number of paths in the graph.<br>
|
||||
|
||||
<b>Default:</b> <a
|
||||
href="../../property_map/iterator_property_map.html">
|
||||
<tt>iterator_property_map</tt></a> created from a
|
||||
<tt>std::vector</tt> of the <tt>degree_size_type</tt> of the graph of
|
||||
size <tt>num_vertices(g)</tt> and using the <tt>vertex_index</tt>
|
||||
for the index map.
|
||||
</blockquote>
|
||||
|
||||
<h3>Named parameters</h3>
|
||||
OUT/UTIL: <tt>CentralityMap centrality_map</tt>
|
||||
<blockquote>
|
||||
This property map is used to accumulate the betweenness centrality
|
||||
of each vertex, and is the primary output of the algorithm. The type
|
||||
<tt>CentralityMap</tt> must be a model of <a
|
||||
href="../../property_map/ReadWritePropertyMap.html">Read/Write
|
||||
Property Map</a>, with the graph's vertex descriptor type as its key
|
||||
type. The value type of this property map should be a floating-point
|
||||
or rational type.<br>
|
||||
|
||||
<b>Default:</b> a <tt>dummy_property_map</tt>, which requires no
|
||||
work to compute and returns no answer.
|
||||
</blockquote>
|
||||
|
||||
OUT/UTIL: <tt>EdgeCentralityMap edge_centrality</tt>
|
||||
<blockquote>
|
||||
This property map is used to accumulate the betweenness centrality
|
||||
of each edge, and is a secondary form of output for the
|
||||
algorithm. The type <tt>EdgeCentralityMap</tt> must be a model of <a
|
||||
href="../../property_map/ReadWritePropertyMap.html">Read/Write
|
||||
Property Map</a>, with the graph's edge descriptor type as its key
|
||||
type. The value type of this property map should be the same as the
|
||||
value type of the <tt>CentralityMap</tt> property map.<br>
|
||||
|
||||
<b>Default:</b> a <tt>dummy_property_map</tt>, which requires no
|
||||
work to compute and returns no answer.
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>vertex_index_map(VertexIndexMap vertex_index)</tt>
|
||||
<blockquote>
|
||||
This maps each vertex to an integer in the range <tt>[0,
|
||||
num_vertices(g))</tt>. This is necessary for efficient updates of the
|
||||
heap data structure when an edge is relaxed. The type
|
||||
<tt>VertexIndexMap</tt> must be a model of
|
||||
<a href="../../property_map/ReadablePropertyMap.html">Readable Property Map</a>. The value type of the map must be an
|
||||
integer type. The vertex descriptor type of the graph needs to be
|
||||
usable as the key type of the map.<br>
|
||||
<b>Default:</b> <tt>get(vertex_index, g)</tt>
|
||||
</blockquote>
|
||||
|
||||
IN: <tt>weight_map(WeightMap w_map)</tt>
|
||||
<blockquote>
|
||||
The weight or ``length'' of each edge in the graph. The weights
|
||||
must all be non-negative, and the algorithm will throw a
|
||||
<a href="./exception.html#negative_edge"><tt>negative_edge</tt></a>
|
||||
exception is one of the edges is negative.
|
||||
The type <tt>WeightMap</tt> must be a model of
|
||||
<a href="../../property_map/ReadablePropertyMap.html">Readable Property Map</a>. The edge descriptor type of
|
||||
the graph needs to be usable as the key type for the weight
|
||||
map. The value type for this map must be
|
||||
the same as the value type of the distance map.<br>
|
||||
<b>Default:</b> All edge weights are assumed to be equivalent.
|
||||
</blockquote>
|
||||
|
||||
<h3>Complexity</h3>
|
||||
The time complexity is <em>O(VE)</em> for unweighted graphs and
|
||||
<em>O(VE + V(V+E) log V)</em> for weighted graphs. The space complexity
|
||||
is <em>O(VE)</em>.
|
||||
|
||||
<hr>
|
||||
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2004</TD><TD>
|
||||
<A HREF="../../../people/doug_gregor.html">Douglas Gregor</A>, Indiana University (dgregor@cs.indiana.edu</A>)<br>
|
||||
<A HREF=http://www.osl.iu.edu/~lums>Andrew Lumsdaine</A>,
|
||||
Indiana University (<A
|
||||
HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
<!-- Created: Fri Jun 4 16:42:50 EST 2004 -->
|
||||
<!-- hhmts start -->Last modified: Wed Aug 4 17:41:44 EST 2004 <!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
||||
14
doc/circle_layout.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Function template circle_graph_layout</title></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td><td align="center"><a href="../../../index.htm">Home</a></td><td align="center"><a href="../../../doc/html/libraries.html">Libraries</a></td><td align="center"><a href="../../../people/people.htm">People</a></td><td align="center"><a href="../../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../../more/index.htm">More</a></td></table><hr><div class="refentry" lang="en"><a name="id103562-bb"></a><div class="titlepage"><div></div><div></div></div><div class="refnamediv"><h2><span class="refentrytitle">Function template circle_graph_layout</span></h2><p>boost::circle_graph_layout — Layout the graph with the vertices at the points of a regular n-polygon. </p></div><h2 xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv-title">Synopsis</h2><div xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv"><pre class="synopsis">
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> VertexListGraph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> Radius>
|
||||
<span class="type"><span class="bold"><b>void</b></span></span> circle_graph_layout(<span class="bold"><b>const</b></span> VertexListGraph & g, PositionMap position,
|
||||
Radius radius);</pre></div><div class="refsect1" lang="en"><a name="id821794"></a><h2>Where Defined</h2><a href="../../../boost/graph/circle_layout.hpp">boost/graph/circle_layout.hpp</a><h2>Description</h2><p>The distance from the center of the polygon to each point is determined by the <tt class="computeroutput">radius</tt> parameter. The <tt class="computeroutput">position</tt> parameter must be an Lvalue Property Map whose value type is a class type containing <tt class="computeroutput">x</tt> and <tt class="computeroutput">y</tt> members that will be set to the <tt class="computeroutput">x</tt> and <tt class="computeroutput">y</tt> coordinates. </p></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small></small></td></tr></table><hr>
|
||||
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2004</TD><TD>
|
||||
<A HREF="../../../people/doug_gregor.html">Douglas Gregor</A>, Indiana University (dgregor@cs.indiana.edu</A>)<br>
|
||||
<A HREF=http://www.osl.iu.edu/~lums>Andrew Lumsdaine</A>,
|
||||
Indiana University (<A
|
||||
HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
</body></html>
|
||||
BIN
doc/figs/betweenness_centrality.gif
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
doc/figs/central_point_dominance.gif
Normal file
|
After Width: | Height: | Size: 786 B |
BIN
doc/figs/relative_betweenness_centrality.gif
Normal file
|
After Width: | Height: | Size: 224 B |
BIN
doc/figs/sigma_st.gif
Normal file
|
After Width: | Height: | Size: 73 B |
BIN
doc/figs/sigma_stv.gif
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
doc/figs/v_star.gif
Normal file
|
After Width: | Height: | Size: 71 B |
BIN
doc/figs/wheel_graph.gif
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
44
doc/kamada_kawai_spring_layout.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Function kamada_kawai_spring_layout</title></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td><td align="center"><a href="../../../index.htm">Home</a></td><td align="center"><a href="../../../doc/html/libraries.html">Libraries</a></td><td align="center"><a href="../../../people/people.htm">People</a></td><td align="center"><a href="../../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../../more/index.htm">More</a></td></table><hr><div class="refentry" lang="en"><a name="id103831-bb"></a><div class="titlepage"><div></div><div></div></div><div class="refnamediv"><h2><span class="refentrytitle">Function kamada_kawai_spring_layout</span></h2><p>boost::kamada_kawai_spring_layout — Kamada-Kawai spring layout for undirected graphs. </p></div><h2 xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv-title">Synopsis</h2><div xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv"><pre class="synopsis">
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> WeightMap, <span class="bold"><b>typename</b></span> T,
|
||||
<span class="bold"><b>bool</b></span> EdgeOrSideLength, <span class="bold"><b>typename</b></span> Done, <span class="bold"><b>typename</b></span> VertexIndexMap,
|
||||
<span class="bold"><b>typename</b></span> DistanceMatrix, <span class="bold"><b>typename</b></span> SpringStrengthMatrix,
|
||||
<span class="bold"><b>typename</b></span> PartialDerivativeMap>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph & g, PositionMap position,
|
||||
WeightMap weight,
|
||||
<span class="emphasis"><em>unspecified</em></span> edge_or_side_length, Done done,
|
||||
<span class="bold"><b>typename</b></span> property_traits< WeightMap >::value_type spring_constant,
|
||||
VertexIndexMap index,
|
||||
DistanceMatrix distance,
|
||||
SpringStrengthMatrix spring_strength,
|
||||
PartialDerivativeMap partial_derivatives);
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> WeightMap, <span class="bold"><b>typename</b></span> T,
|
||||
<span class="bold"><b>bool</b></span> EdgeOrSideLength, <span class="bold"><b>typename</b></span> Done, <span class="bold"><b>typename</b></span> VertexIndexMap>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph & g, PositionMap position,
|
||||
WeightMap weight,
|
||||
<span class="emphasis"><em>unspecified</em></span> edge_or_side_length, Done done,
|
||||
<span class="bold"><b>typename</b></span> property_traits< WeightMap >::value_type spring_constant,
|
||||
VertexIndexMap index);
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> WeightMap, <span class="bold"><b>typename</b></span> T,
|
||||
<span class="bold"><b>bool</b></span> EdgeOrSideLength, <span class="bold"><b>typename</b></span> Done>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph & g, PositionMap position,
|
||||
WeightMap weight,
|
||||
<span class="emphasis"><em>unspecified</em></span> edge_or_side_length, Done done,
|
||||
<span class="bold"><b>typename</b></span> property_traits< WeightMap >::value_type spring_constant = typename property_traits< WeightMap >::value_type(1));
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> WeightMap, <span class="bold"><b>typename</b></span> T,
|
||||
<span class="bold"><b>bool</b></span> EdgeOrSideLength>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph & g, PositionMap position,
|
||||
WeightMap weight,
|
||||
<span class="emphasis"><em>unspecified</em></span> edge_or_side_length);</pre></div><div class="refsect1" lang="en"><a name="id822881"></a><h2>Where Defined</h2><a href="../../../boost/graph/kamada_kawai_spring_layout.hpp">boost/graph/kamada_kawai_spring_layout.hpp</a><h2>Description</h2><div class="variablelist"><p class="title"><b>Parameters</b></p><dl><dt><span class="term">distance</span></dt><dd><p>(UTIL/OUT) will be used to store the distance from every vertex to every other vertex, which is computed in the first stages of the algorithm. This value's type must be a model of BasicMatrix with value type equal to the value type of the weight map. The default is a a vector of vectors.</p></dd><dt><span class="term">done</span></dt><dd><p>(IN) is a 4-argument function object that is passed the current value of delta_p (i.e., the energy of vertex <tt class="computeroutput">p</tt> ), the vertex <tt class="computeroutput">p</tt> , the graph <tt class="computeroutput">g</tt> , and a boolean flag indicating whether <tt class="computeroutput">delta_p</tt> is the maximum energy in the system (when <tt class="computeroutput">true</tt> ) or the energy of the vertex being moved. Defaults to <a href="layout_tolerance.html"><tt class="computeroutput">layout_tolerance</tt></a> instantiated over the value type of the weight map.</p></dd><dt><span class="term">edge_or_side_length</span></dt><dd><p>(IN) provides either the unit length <tt class="computeroutput">e</tt> of an edge in the layout or the length of a side <tt class="computeroutput">s</tt> of the display area, and must be either <tt class="computeroutput">boost::edge_length(e)</tt> or <tt class="computeroutput">boost::side_length(s)</tt> , respectively.</p></dd><dt><span class="term">g</span></dt><dd><p>(IN) must be a model of Vertex List Graph, Edge List Graph, and Incidence Graph and must be undirected.</p></dd><dt><span class="term">index</span></dt><dd><p>(IN) is a mapping from vertices to index values between 0 and <tt class="computeroutput">num_vertices(g)</tt> . The default is <tt class="computeroutput">get(vertex_index,g)</tt> .</p></dd><dt><span class="term">partial_derivatives</span></dt><dd><p>(UTIL) will be used to store the partial derivates of each vertex with respect to the <tt class="computeroutput">x</tt> and <tt class="computeroutput">y</tt> coordinates. This must be a Read/Write Property Map whose value type is a pair with both types equivalent to the value type of the weight map. The default is an iterator property map.</p></dd><dt><span class="term">position</span></dt><dd><p>(OUT) must be a model of Lvalue Property Map, where the value type is a class containing fields <tt class="computeroutput">x</tt> and <tt class="computeroutput">y</tt> that will be set to the <tt class="computeroutput">x</tt> and <tt class="computeroutput">y</tt> coordinates of each vertex.</p></dd><dt><span class="term">spring_constant</span></dt><dd><p>(IN) is the constant multiplied by each spring's strength. Larger values create systems with more energy that can take longer to stabilize; smaller values create systems with less energy that stabilize quickly but do not necessarily result in pleasing layouts. The default value is 1.</p></dd><dt><span class="term">spring_strength</span></dt><dd><p>(UTIL/OUT) will be used to store the strength of the spring between every pair of vertices. This value's type must be a model of BasicMatrix with value type equal to the value type of the weight map. The default is a a vector of vectors.</p></dd><dt><span class="term">weight</span></dt><dd><p>(IN) must be a model of Readable Property Map, which provides the weight of each edge in the graph <tt class="computeroutput">g</tt> .</p></dd></dl></div><p>This algorithm [<a href="bibliography.html#kamada89">57</a>] performs graph layout (in two dimensions) for connected, undirected graphs. It operates by relating the layout of graphs to a dynamic spring system and minimizing the energy within that system. The strength of a spring between two vertices is inversely proportional to the square of the shortest distance (in graph terms) between those two vertices. Essentially, vertices that are closer in the graph-theoretic sense (i.e., by following edges) will have stronger springs and will therefore be placed closer together.</p><p>Prior to invoking this algorithm, it is recommended that the vertices be placed along the vertices of a regular n-sided polygon via <a href="circle_layout.html"><tt>circle_layout</tt></a>.</p><p></p><p><b xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision"><span class="term">Returns</span></b>:
|
||||
|
||||
<tt class="computeroutput">true</tt> if layout was successful or <tt class="computeroutput">false</tt> if a negative weight cycle was detected. </p></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small></small></td></tr></table><hr>
|
||||
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2004</TD><TD>
|
||||
<A HREF="../../../people/doug_gregor.html">Douglas Gregor</A>, Indiana University (dgregor@cs.indiana.edu</A>)<br>
|
||||
<A HREF=http://www.osl.iu.edu/~lums>Andrew Lumsdaine</A>,
|
||||
Indiana University (<A
|
||||
HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</body></html>
|
||||
14
doc/layout_tolerance.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Struct template layout_tolerance</title></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td><td align="center"><a href="../../../index.htm">Home</a></td><td align="center"><a href="../../../doc/html/libraries.html">Libraries</a></td><td align="center"><a href="../../../people/people.htm">People</a></td><td align="center"><a href="../../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../../more/index.htm">More</a></td></table><hr><div class="refentry" lang="en"><a name="struct.boost.layout_tolerance"></a><div class="titlepage"><div></div><div></div></div><div class="refnamediv"><h2><span class="refentrytitle">Struct template layout_tolerance</span></h2><p>boost::layout_tolerance — Determines when to terminate layout of a particular graph based on a given tolerance. </p></div><h2 xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv-title">Synopsis</h2><div xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="refsynopsisdiv"><pre class="synopsis"><span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> T = double>
|
||||
<span class="bold"><b>struct</b></span> layout_tolerance {
|
||||
<span class="emphasis"><em>// <a href="struct.boost.layout_tolerance.html#struct.boost.layout_toleranceconstruct-copy-destruct">construct/copy/destruct</a></em></span>
|
||||
<a href="struct.boost.layout_tolerance.html#id103752-bb">layout_tolerance</a>(<span class="bold"><b>const</b></span> T & = T(0.01));
|
||||
|
||||
<span class="emphasis"><em>// <a href="struct.boost.layout_tolerance.html#id103692-bb">public member functions</a></em></span>
|
||||
<span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> <a href="struct.boost.layout_tolerance.html#id103697-bb"><span class="bold"><b>operator</b></span>()</a>(T,
|
||||
<span class="bold"><b>typename</b></span> boost::graph_traits< Graph >::vertex_descriptor,
|
||||
<span class="bold"><b>const</b></span> Graph &, <span class="bold"><b>bool</b></span>) ;
|
||||
};</pre></div><div class="refsect1" lang="en"><a name="id822409"></a><h2>Where Defined</h2><a href="../../../boost/graph/kamada_kawai_spring_layout.hpp">boost/graph/kamada_kawai_spring_layout.hpp</a><h2>Description</h2><p>For local movements, where a single vertex is being moved toward a local minima the tolerance is taken as an absolute tolerance; for global movements, layout terminates when moving individual particles results in changes in the maximum vertex energy less than the tolerance. </p><div class="refsect2" lang="en"><a name="id822420"></a><h3><a name="struct.boost.layout_toleranceconstruct-copy-destruct"></a><tt class="computeroutput">layout_tolerance</tt> construct/copy/destruct</h3><div class="orderedlist"><ol type="1"><li><pre class="literallayout"><a name="id103752-bb"></a>layout_tolerance(<span class="bold"><b>const</b></span> T & tolerance = T(0.01));</pre></li></ol></div></div><div class="refsect2" lang="en"><a name="id822461"></a><h3><a name="id103692-bb"></a><tt class="computeroutput">layout_tolerance</tt> public member functions</h3><div class="orderedlist"><ol type="1"><li><pre class="literallayout"><span class="bold"><b>template</b></span><<span class="bold"><b>typename</b></span> Graph>
|
||||
<span class="type"><span class="bold"><b>bool</b></span></span> <a name="id103697-bb"></a><span class="bold"><b>operator</b></span>()(T delta_p,
|
||||
<span class="bold"><b>typename</b></span> boost::graph_traits< Graph >::vertex_descriptor p,
|
||||
<span class="bold"><b>const</b></span> Graph & g, <span class="bold"><b>bool</b></span> global) ;</pre></li></ol></div></div></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small></small></td></tr></table><hr></body></html>
|
||||
187
example/actor_clustering.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
|
||||
// This program performs betweenness centrality (BC) clustering on the
|
||||
// actor collaboration graph available at
|
||||
// http://www.nd.edu/~networks/database/index.html and outputs the
|
||||
// result of clustering in Pajek format.
|
||||
//
|
||||
// This program mimics the BC clustering algorithm program implemented
|
||||
// by Shashikant Penumarthy for JUNG, so that we may compare results
|
||||
// and timings.
|
||||
#include <boost/graph/betweenness_centrality_clustering.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <map>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
struct Actor
|
||||
{
|
||||
Actor(int id = -1) : id(id) {}
|
||||
|
||||
int id;
|
||||
};
|
||||
|
||||
typedef adjacency_list<vecS, vecS, undirectedS, Actor,
|
||||
property<edge_centrality_t, double> > ActorGraph;
|
||||
typedef graph_traits<ActorGraph>::vertex_descriptor Vertex;
|
||||
typedef graph_traits<ActorGraph>::edge_descriptor Edge;
|
||||
|
||||
void load_actor_graph(std::istream& in, ActorGraph& g)
|
||||
{
|
||||
std::map<int, Vertex> actors;
|
||||
|
||||
std::string line;
|
||||
while (getline(in, line)) {
|
||||
std::vector<Vertex> actors_in_movie;
|
||||
|
||||
// Map from the actor numbers on this line to the actor vertices
|
||||
typedef tokenizer<char_separator<char> > Tok;
|
||||
Tok tok(line, char_separator<char>(" "));
|
||||
for (Tok::iterator id = tok.begin(); id != tok.end(); ++id) {
|
||||
int actor_id = lexical_cast<int>(*id);
|
||||
std::map<int, Vertex>::iterator v = actors.find(actor_id);
|
||||
if (v == actors.end()) {
|
||||
Vertex new_vertex = add_vertex(Actor(actor_id), g);
|
||||
actors[actor_id] = new_vertex;
|
||||
actors_in_movie.push_back(new_vertex);
|
||||
} else {
|
||||
actors_in_movie.push_back(v->second);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<Vertex>::iterator i = actors_in_movie.begin();
|
||||
i != actors_in_movie.end(); ++i) {
|
||||
for (std::vector<Vertex>::iterator j = i + 1;
|
||||
j != actors_in_movie.end(); ++j) {
|
||||
if (!edge(*i, *j, g).second) add_edge(*i, *j, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Graph, typename VertexIndexMap, typename VertexNameMap>
|
||||
std::ostream&
|
||||
write_pajek_graph(std::ostream& out, const Graph& g,
|
||||
VertexIndexMap vertex_index, VertexNameMap vertex_name)
|
||||
{
|
||||
out << "*Vertices " << num_vertices(g) << '\n';
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
for (vertex_iterator v = vertices(g).first; v != vertices(g).second; ++v) {
|
||||
out << get(vertex_index, *v)+1 << " \"" << get(vertex_name, *v) << "\"\n";
|
||||
}
|
||||
|
||||
out << "*Edges\n";
|
||||
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
||||
for (edge_iterator e = edges(g).first; e != edges(g).second; ++e) {
|
||||
out << get(vertex_index, source(*e, g))+1 << ' '
|
||||
<< get(vertex_index, target(*e, g))+1 << " 1.0\n"; // HACK!
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
class actor_clustering_threshold : public bc_clustering_threshold<double>
|
||||
{
|
||||
typedef bc_clustering_threshold<double> inherited;
|
||||
|
||||
public:
|
||||
actor_clustering_threshold(double threshold, const ActorGraph& g,
|
||||
bool normalize)
|
||||
: inherited(threshold, g, normalize), iter(1) { }
|
||||
|
||||
bool operator()(double max_centrality, Edge e, const ActorGraph& g)
|
||||
{
|
||||
std::cout << "Iter: " << iter << " Max Centrality: "
|
||||
<< (max_centrality / dividend) << std::endl;
|
||||
++iter;
|
||||
return inherited::operator()(max_centrality, e, g);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int iter;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::string in_file;
|
||||
std::string out_file;
|
||||
double threshold = -1.0;
|
||||
bool normalize = false;
|
||||
|
||||
// Parse command-line options
|
||||
{
|
||||
int on_arg = 1;
|
||||
while (on_arg < argc) {
|
||||
std::string arg(argv[on_arg]);
|
||||
if (arg == "-in") {
|
||||
++on_arg; assert(on_arg < argc);
|
||||
in_file = argv[on_arg];
|
||||
} else if (arg == "-out") {
|
||||
++on_arg; assert(on_arg < argc);
|
||||
out_file = argv[on_arg];
|
||||
} else if (arg == "-threshold") {
|
||||
++on_arg; assert(on_arg < argc);
|
||||
threshold = lexical_cast<double>(argv[on_arg]);
|
||||
} else if (arg == "-normalize") {
|
||||
normalize = true;
|
||||
} else {
|
||||
std::cerr << "Unrecognized parameter \"" << arg << "\".\n";
|
||||
return -1;
|
||||
}
|
||||
++on_arg;
|
||||
}
|
||||
|
||||
if (in_file.empty() || out_file.empty() || threshold < 0) {
|
||||
std::cerr << "error: syntax is actor_clustering [options]\n\n"
|
||||
<< "options are:\n"
|
||||
<< "\t-in <infile>\tInput file\n"
|
||||
<< "\t-out <outfile>\tOutput file\n"
|
||||
<< "\t-threshold <value>\tA threshold value\n"
|
||||
<< "\t-normalize\tNormalize edge centrality scores\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ActorGraph g;
|
||||
|
||||
// Load the actor graph
|
||||
{
|
||||
std::cout << "Building graph." << std::endl;
|
||||
std::ifstream in(in_file.c_str());
|
||||
if (!in) {
|
||||
std::cerr << "Unable to open file \"" << in_file << "\" for input.\n";
|
||||
return -2;
|
||||
}
|
||||
load_actor_graph(in, g);
|
||||
}
|
||||
|
||||
// Run the algorithm
|
||||
std::cout << "Clusting..." << std::endl;
|
||||
betweenness_centrality_clustering(g,
|
||||
actor_clustering_threshold(threshold, g, normalize),
|
||||
get(edge_centrality, g));
|
||||
|
||||
// Output the graph
|
||||
{
|
||||
std::cout << "Writing graph to file: " << out_file << std::endl;
|
||||
std::ofstream out(out_file.c_str());
|
||||
if (!out) {
|
||||
std::cerr << "Unable to open file \"" << out_file << "\" for output.\n";
|
||||
return -3;
|
||||
}
|
||||
write_pajek_graph(out, g, get(vertex_index, g), get(&Actor::id, g));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
165
include/boost/graph/betweenness_centrality_clustering.hpp
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#ifndef BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
|
||||
#define BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
|
||||
|
||||
#include <boost/graph/brandes_betweenness_centrality.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/pending/indirect_cmp.hpp>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <boost/property_map.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
/** Threshold termination function for the betweenness centrality
|
||||
* clustering algorithm.
|
||||
*/
|
||||
template<typename T>
|
||||
struct bc_clustering_threshold
|
||||
{
|
||||
typedef T centrality_type;
|
||||
|
||||
/// Terminate clustering when maximum absolute edge centrality is
|
||||
/// below the given threshold.
|
||||
explicit bc_clustering_threshold(T threshold)
|
||||
: threshold(threshold), dividend(1.0) {}
|
||||
|
||||
/**
|
||||
* Terminate clustering when the maximum edge centrality is below
|
||||
* the given threshold.
|
||||
*
|
||||
* @param threshold the threshold value
|
||||
*
|
||||
* @param g the graph on which the threshold will be calculated
|
||||
*
|
||||
* @param normalize when true, the threshold is compared against the
|
||||
* normalized edge centrality based on the input graph; otherwise,
|
||||
* the threshold is compared against the absolute edge centrality.
|
||||
*/
|
||||
template<typename Graph>
|
||||
bc_clustering_threshold(T threshold, const Graph& g, bool normalize = true)
|
||||
: threshold(threshold), dividend(1.0)
|
||||
{
|
||||
if (normalize) {
|
||||
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
|
||||
dividend = T((n - 1) * (n - 2)) / T(2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true when the given maximum edge centrality (potentially
|
||||
* normalized) falls below the threshold.
|
||||
*/
|
||||
template<typename Graph, typename Edge>
|
||||
bool operator()(T max_centrality, Edge, const Graph&)
|
||||
{
|
||||
return (max_centrality / dividend) < threshold;
|
||||
}
|
||||
|
||||
protected:
|
||||
T threshold;
|
||||
T dividend;
|
||||
};
|
||||
|
||||
/** Graph clustering based on edge betweenness centrality.
|
||||
*
|
||||
* This algorithm implements graph clustering based on edge
|
||||
* betweenness centrality. It is an iterative algorithm, where in each
|
||||
* step it compute the edge betweenness centrality (via @ref
|
||||
* brandes_betweenness_centrality) and removes the edge with the
|
||||
* maximum betweenness centrality. The @p done function object
|
||||
* determines when the algorithm terminates (the edge found when the
|
||||
* algorithm terminates will not be removed).
|
||||
*
|
||||
* @param g The graph on which clustering will be performed. The type
|
||||
* of this parameter (@c MutableGraph) must be a model of the
|
||||
* VertexListGraph, IncidenceGraph, EdgeListGraph, and Mutable Graph
|
||||
* concepts.
|
||||
*
|
||||
* @param done The function object that indicates termination of the
|
||||
* algorithm. It must be a ternary function object thats accepts the
|
||||
* maximum centrality, the descriptor of the edge that will be
|
||||
* removed, and the graph @p g.
|
||||
*
|
||||
* @param edge_centrality (UTIL/OUT) The property map that will store
|
||||
* the betweenness centrality for each edge. When the algorithm
|
||||
* terminates, it will contain the edge centralities for the
|
||||
* graph. The type of this property map must model the
|
||||
* ReadWritePropertyMap concept. Defaults to an @c
|
||||
* iterator_property_map whose value type is
|
||||
* @c Done::centrality_type and using @c get(edge_index, g) for the
|
||||
* index map.
|
||||
*
|
||||
* @param vertex_index (IN) The property map that maps vertices to
|
||||
* indices in the range @c [0, num_vertices(g)). This type of this
|
||||
* property map must model the ReadablePropertyMap concept and its
|
||||
* value type must be an integral type. Defaults to
|
||||
* @c get(vertex_index, g).
|
||||
*/
|
||||
template<typename MutableGraph, typename Done, typename EdgeCentralityMap,
|
||||
typename VertexIndexMap>
|
||||
void
|
||||
betweenness_centrality_clustering(MutableGraph& g, Done done,
|
||||
EdgeCentralityMap edge_centrality,
|
||||
VertexIndexMap vertex_index)
|
||||
{
|
||||
typedef typename property_traits<EdgeCentralityMap>::value_type
|
||||
centrality_type;
|
||||
typedef typename graph_traits<MutableGraph>::edge_iterator edge_iterator;
|
||||
typedef typename graph_traits<MutableGraph>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<MutableGraph>::vertices_size_type
|
||||
vertices_size_type;
|
||||
|
||||
if (edges(g).first == edges(g).second) return;
|
||||
|
||||
// Function object that compares the centrality of edges
|
||||
indirect_cmp<EdgeCentralityMap, std::less<centrality_type> >
|
||||
cmp(edge_centrality);
|
||||
|
||||
bool is_done;
|
||||
do {
|
||||
brandes_betweenness_centrality(g,
|
||||
edge_centrality_map(edge_centrality)
|
||||
.vertex_index_map(vertex_index));
|
||||
edge_descriptor e = *max_element(edges(g).first, edges(g).second, cmp);
|
||||
centrality_type max_centrality = get(edge_centrality, e);
|
||||
is_done = done(get(edge_centrality, e), e, g);
|
||||
if (!is_done) remove_edge(e, g);
|
||||
} while (!is_done && edges(g).first != edges(g).second);
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
template<typename MutableGraph, typename Done, typename EdgeCentralityMap>
|
||||
void
|
||||
betweenness_centrality_clustering(MutableGraph& g, Done done,
|
||||
EdgeCentralityMap edge_centrality)
|
||||
{
|
||||
betweenness_centrality_clustering(g, done, edge_centrality,
|
||||
get(vertex_index, g));
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
template<typename MutableGraph, typename Done>
|
||||
void
|
||||
betweenness_centrality_clustering(MutableGraph& g, Done done)
|
||||
{
|
||||
typedef typename Done::centrality_type centrality_type;
|
||||
std::vector<centrality_type> edge_centrality(num_edges(g));
|
||||
betweenness_centrality_clustering(g, done,
|
||||
make_iterator_property_map(edge_centrality.begin(), get(edge_index, g)),
|
||||
get(vertex_index, g));
|
||||
}
|
||||
|
||||
} // end namespace boost
|
||||
|
||||
#endif // BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
|
||||
599
include/boost/graph/brandes_betweenness_centrality.hpp
Normal file
@@ -0,0 +1,599 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#ifndef BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
|
||||
#define BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
||||
#include <boost/graph/breadth_first_search.hpp>
|
||||
#include <boost/graph/relax.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/graph/named_function_params.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail { namespace graph {
|
||||
|
||||
/**
|
||||
* Customized visitor passed to Dijkstra's algorithm by Brandes'
|
||||
* betweenness centrality algorithm. This visitor is responsible for
|
||||
* keeping track of the order in which vertices are discovered, the
|
||||
* predecessors on the shortest path(s) to a vertex, and the number
|
||||
* of shortest paths.
|
||||
*/
|
||||
template<typename Graph, typename WeightMap, typename IncomingMap,
|
||||
typename DistanceMap, typename PathCountMap>
|
||||
struct brandes_dijkstra_visitor : public bfs_visitor<>
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
|
||||
brandes_dijkstra_visitor(std::stack<vertex_descriptor>& ordered_vertices,
|
||||
WeightMap weight,
|
||||
IncomingMap incoming,
|
||||
DistanceMap distance,
|
||||
PathCountMap path_count)
|
||||
: ordered_vertices(ordered_vertices), weight(weight),
|
||||
incoming(incoming), distance(distance),
|
||||
path_count(path_count)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Whenever an edge e = (v, w) is relaxed, the incoming edge list
|
||||
* for w is set to {(v, w)} and the shortest path count of w is set to
|
||||
* the number of paths that reach {v}.
|
||||
*/
|
||||
void edge_relaxed(edge_descriptor e, const Graph& g)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* If an edge e = (v, w) was not relaxed, it may still be the case
|
||||
* that we've found more equally-short paths, so include {(v, w)} in the
|
||||
* incoming edges of w and add all of the shortest paths to v to the
|
||||
* shortest path count of w.
|
||||
*/
|
||||
void edge_not_relaxed(edge_descriptor e, const Graph& g)
|
||||
{
|
||||
typedef typename property_traits<WeightMap>::value_type weight_type;
|
||||
typedef typename property_traits<DistanceMap>::value_type distance_type;
|
||||
vertex_descriptor v = source(e, g), w = target(e, g);
|
||||
distance_type d_v = get(distance, v), d_w = get(distance, w);
|
||||
weight_type w_e = get(weight, e);
|
||||
|
||||
closed_plus<distance_type> combine;
|
||||
if (d_w == combine(d_v, w_e)) {
|
||||
put(path_count, w, get(path_count, w) + get(path_count, v));
|
||||
incoming[w].push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep track of vertices as they are reached
|
||||
void examine_vertex(vertex_descriptor w, const Graph&)
|
||||
{
|
||||
ordered_vertices.push(w);
|
||||
}
|
||||
|
||||
private:
|
||||
std::stack<vertex_descriptor>& ordered_vertices;
|
||||
WeightMap weight;
|
||||
IncomingMap incoming;
|
||||
DistanceMap distance;
|
||||
PathCountMap path_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function object that calls Dijkstra's shortest paths algorithm
|
||||
* using the Dijkstra visitor for the Brandes betweenness centrality
|
||||
* algorithm.
|
||||
*/
|
||||
template<typename WeightMap>
|
||||
struct brandes_dijkstra_shortest_paths
|
||||
{
|
||||
brandes_dijkstra_shortest_paths(WeightMap weight_map)
|
||||
: weight_map(weight_map) { }
|
||||
|
||||
template<typename Graph, typename IncomingMap, typename DistanceMap,
|
||||
typename PathCountMap, typename VertexIndexMap>
|
||||
void
|
||||
operator()(Graph& g,
|
||||
typename graph_traits<Graph>::vertex_descriptor s,
|
||||
std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
|
||||
IncomingMap incoming,
|
||||
DistanceMap distance,
|
||||
PathCountMap path_count,
|
||||
VertexIndexMap vertex_index)
|
||||
{
|
||||
typedef brandes_dijkstra_visitor<Graph, WeightMap, IncomingMap,
|
||||
DistanceMap, PathCountMap> visitor_type;
|
||||
visitor_type visitor(ov, weight_map, incoming, distance, path_count);
|
||||
|
||||
dijkstra_shortest_paths(g, s,
|
||||
boost::weight_map(weight_map)
|
||||
.vertex_index_map(vertex_index)
|
||||
.distance_map(distance)
|
||||
.visitor(visitor));
|
||||
}
|
||||
|
||||
private:
|
||||
WeightMap weight_map;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function object that invokes breadth-first search for the
|
||||
* unweighted form of the Brandes betweenness centrality algorithm.
|
||||
*/
|
||||
struct brandes_unweighted_shortest_paths
|
||||
{
|
||||
/**
|
||||
* Customized visitor passed to breadth-first search, which
|
||||
* records predecessor and the number of shortest paths to each
|
||||
* vertex.
|
||||
*/
|
||||
template<typename Graph, typename IncomingMap, typename DistanceMap,
|
||||
typename PathCountMap>
|
||||
struct visitor_type : public bfs_visitor<>
|
||||
{
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor
|
||||
vertex_descriptor;
|
||||
|
||||
visitor_type(IncomingMap incoming, DistanceMap distance,
|
||||
PathCountMap path_count,
|
||||
std::stack<vertex_descriptor>& ordered_vertices)
|
||||
: incoming(incoming), distance(distance),
|
||||
path_count(path_count), ordered_vertices(ordered_vertices) { }
|
||||
|
||||
/// Keep track of vertices as they are reached
|
||||
void examine_vertex(vertex_descriptor v, Graph&)
|
||||
{
|
||||
ordered_vertices.push(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever an edge e = (v, w) is labelled a tree edge, the
|
||||
* incoming edge list for w is set to {(v, w)} and the shortest
|
||||
* path count of w is set to the number of paths that reach {v}.
|
||||
*/
|
||||
void tree_edge(edge_descriptor e, Graph& g)
|
||||
{
|
||||
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));
|
||||
incoming[w].push_back(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* If an edge e = (v, w) is not a tree edge, it may still be the
|
||||
* case that we've found more equally-short paths, so include (v, w)
|
||||
* in the incoming edge list of w and add all of the shortest
|
||||
* paths to v to the shortest path count of w.
|
||||
*/
|
||||
void non_tree_edge(edge_descriptor e, Graph& g)
|
||||
{
|
||||
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));
|
||||
incoming[w].push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
IncomingMap incoming;
|
||||
DistanceMap distance;
|
||||
PathCountMap path_count;
|
||||
std::stack<vertex_descriptor>& ordered_vertices;
|
||||
};
|
||||
|
||||
template<typename Graph, typename IncomingMap, typename DistanceMap,
|
||||
typename PathCountMap, typename VertexIndexMap>
|
||||
void
|
||||
operator()(Graph& g,
|
||||
typename graph_traits<Graph>::vertex_descriptor s,
|
||||
std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
|
||||
IncomingMap incoming,
|
||||
DistanceMap distance,
|
||||
PathCountMap path_count,
|
||||
VertexIndexMap vertex_index)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor
|
||||
vertex_descriptor;
|
||||
|
||||
visitor_type<Graph, IncomingMap, DistanceMap, PathCountMap>
|
||||
visitor(incoming, distance, path_count, ov);
|
||||
|
||||
std::vector<default_color_type>
|
||||
colors(num_vertices(g), color_traits<default_color_type>::white());
|
||||
boost::queue<vertex_descriptor> Q;
|
||||
breadth_first_visit(g, s, Q, visitor,
|
||||
make_iterator_property_map(colors.begin(),
|
||||
vertex_index));
|
||||
}
|
||||
};
|
||||
|
||||
// When the edge centrality map is a dummy property map, no
|
||||
// initialization is needed.
|
||||
template<typename Iter>
|
||||
inline void
|
||||
init_centrality_map(std::pair<Iter, Iter>, dummy_property_map) { }
|
||||
|
||||
// When we have a real edge centrality map, initialize all of the
|
||||
// centralities to zero.
|
||||
template<typename Iter, typename Centrality>
|
||||
void
|
||||
init_centrality_map(std::pair<Iter, Iter> keys, Centrality centrality_map)
|
||||
{
|
||||
typedef typename property_traits<Centrality>::value_type
|
||||
centrality_type;
|
||||
while (keys.first != keys.second) {
|
||||
put(centrality_map, *keys.first, centrality_type(0));
|
||||
++keys.first;
|
||||
}
|
||||
}
|
||||
|
||||
// When the edge centrality map is a dummy property map, no update
|
||||
// is performed.
|
||||
template<typename Key, typename T>
|
||||
inline void
|
||||
update_centrality(dummy_property_map, const Key&, const T&) { }
|
||||
|
||||
// When we have a real edge centrality map, add the value to the map
|
||||
template<typename CentralityMap, typename Key, typename T>
|
||||
inline void
|
||||
update_centrality(CentralityMap centrality_map, Key k, const T& x)
|
||||
{ put(centrality_map, k, get(centrality_map, k) + x); }
|
||||
|
||||
template<typename Iter>
|
||||
inline void
|
||||
divide_centrality_by_two(std::pair<Iter, Iter>, dummy_property_map) {}
|
||||
|
||||
template<typename Iter, typename CentralityMap>
|
||||
inline void
|
||||
divide_centrality_by_two(std::pair<Iter, Iter> keys,
|
||||
CentralityMap centrality_map)
|
||||
{
|
||||
typename property_traits<CentralityMap>::value_type two(2);
|
||||
while (keys.first != keys.second) {
|
||||
put(centrality_map, *keys.first, get(centrality_map, *keys.first) / two);
|
||||
++keys.first;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename IncomingMap, typename DistanceMap,
|
||||
typename DependencyMap, typename PathCountMap,
|
||||
typename VertexIndexMap, typename ShortestPaths>
|
||||
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)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
// Initialize centrality
|
||||
init_centrality_map(vertices(g), centrality);
|
||||
init_centrality_map(edges(g), edge_centrality_map);
|
||||
|
||||
std::stack<vertex_descriptor> ordered_vertices;
|
||||
vertex_iterator s, s_end;
|
||||
for (tie(s, s_end) = vertices(g); s != s_end; ++s) {
|
||||
// Initialize for this iteration
|
||||
vertex_iterator w, w_end;
|
||||
for (tie(w, w_end) = vertices(g); w != w_end; ++w) {
|
||||
incoming[*w].clear();
|
||||
put(path_count, *w, 0);
|
||||
put(dependency, *w, 0);
|
||||
}
|
||||
put(path_count, *s, 1);
|
||||
|
||||
// Execute the shortest paths algorithm. This will be either
|
||||
// Dijkstra's algorithm or a customized breadth-first search,
|
||||
// depending on whether the graph is weighted or unweighted.
|
||||
shortest_paths(g, *s, ordered_vertices, incoming, distance,
|
||||
path_count, vertex_index);
|
||||
|
||||
while (!ordered_vertices.empty()) {
|
||||
vertex_descriptor w = ordered_vertices.top();
|
||||
ordered_vertices.pop();
|
||||
|
||||
typedef typename property_traits<IncomingMap>::value_type
|
||||
incoming_type;
|
||||
typedef typename incoming_type::iterator incoming_iterator;
|
||||
typedef typename property_traits<DependencyMap>::value_type
|
||||
dependency_type;
|
||||
|
||||
for (incoming_iterator vw = incoming[w].begin();
|
||||
vw != incoming[w].end(); ++vw) {
|
||||
vertex_descriptor v = source(*vw, g);
|
||||
dependency_type factor = dependency_type(get(path_count, v))
|
||||
/ dependency_type(get(path_count, w));
|
||||
factor *= (dependency_type(1) + get(dependency, w));
|
||||
put(dependency, v, get(dependency, v) + factor);
|
||||
update_centrality(edge_centrality_map, *vw, factor);
|
||||
}
|
||||
|
||||
if (w != *s) {
|
||||
update_centrality(centrality, w, get(dependency, w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef typename graph_traits<Graph>::directed_category directed_category;
|
||||
const bool is_undirected =
|
||||
is_convertible<directed_category*, undirected_tag*>::value;
|
||||
if (is_undirected) {
|
||||
divide_centrality_by_two(vertices(g), centrality);
|
||||
divide_centrality_by_two(edges(g), edge_centrality_map);
|
||||
}
|
||||
}
|
||||
|
||||
} } // end namespace detail::graph
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename IncomingMap, typename DistanceMap,
|
||||
typename DependencyMap, typename PathCountMap,
|
||||
typename VertexIndexMap>
|
||||
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)
|
||||
{
|
||||
detail::graph::brandes_unweighted_shortest_paths shortest_paths;
|
||||
|
||||
detail::graph::brandes_betweenness_centrality_impl(g, centrality,
|
||||
edge_centrality_map,
|
||||
incoming, distance,
|
||||
dependency, path_count,
|
||||
vertex_index,
|
||||
shortest_paths);
|
||||
}
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename IncomingMap, typename DistanceMap,
|
||||
typename DependencyMap, typename PathCountMap,
|
||||
typename VertexIndexMap, typename WeightMap>
|
||||
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)
|
||||
{
|
||||
detail::graph::brandes_dijkstra_shortest_paths<WeightMap>
|
||||
shortest_paths(weight_map);
|
||||
|
||||
detail::graph::brandes_betweenness_centrality_impl(g, centrality,
|
||||
edge_centrality_map,
|
||||
incoming, distance,
|
||||
dependency, path_count,
|
||||
vertex_index,
|
||||
shortest_paths);
|
||||
}
|
||||
|
||||
namespace detail { namespace graph {
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename WeightMap, typename VertexIndexMap>
|
||||
void
|
||||
brandes_betweenness_centrality_dispatch2(const Graph& g,
|
||||
CentralityMap centrality,
|
||||
EdgeCentralityMap edge_centrality_map,
|
||||
WeightMap weight_map,
|
||||
VertexIndexMap vertex_index)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename mpl::if_c<(is_same<CentralityMap,
|
||||
dummy_property_map>::value),
|
||||
EdgeCentralityMap,
|
||||
CentralityMap>::type a_centrality_map;
|
||||
typedef typename property_traits<a_centrality_map>::value_type
|
||||
centrality_type;
|
||||
|
||||
typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
|
||||
|
||||
std::vector<std::vector<edge_descriptor> > incoming(V);
|
||||
std::vector<centrality_type> distance(V);
|
||||
std::vector<centrality_type> dependency(V);
|
||||
std::vector<degree_size_type> path_count(V);
|
||||
|
||||
brandes_betweenness_centrality(
|
||||
g, centrality, edge_centrality_map,
|
||||
make_iterator_property_map(incoming.begin(), vertex_index),
|
||||
make_iterator_property_map(distance.begin(), vertex_index),
|
||||
make_iterator_property_map(dependency.begin(), vertex_index),
|
||||
make_iterator_property_map(path_count.begin(), vertex_index),
|
||||
vertex_index,
|
||||
weight_map);
|
||||
}
|
||||
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
|
||||
typename VertexIndexMap>
|
||||
void
|
||||
brandes_betweenness_centrality_dispatch2(const Graph& g,
|
||||
CentralityMap centrality,
|
||||
EdgeCentralityMap edge_centrality_map,
|
||||
VertexIndexMap vertex_index)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
typedef typename mpl::if_c<(is_same<CentralityMap,
|
||||
dummy_property_map>::value),
|
||||
EdgeCentralityMap,
|
||||
CentralityMap>::type a_centrality_map;
|
||||
typedef typename property_traits<a_centrality_map>::value_type
|
||||
centrality_type;
|
||||
|
||||
typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
|
||||
|
||||
std::vector<std::vector<edge_descriptor> > incoming(V);
|
||||
std::vector<centrality_type> distance(V);
|
||||
std::vector<centrality_type> dependency(V);
|
||||
std::vector<degree_size_type> path_count(V);
|
||||
|
||||
brandes_betweenness_centrality(
|
||||
g, centrality, edge_centrality_map,
|
||||
make_iterator_property_map(incoming.begin(), vertex_index),
|
||||
make_iterator_property_map(distance.begin(), vertex_index),
|
||||
make_iterator_property_map(dependency.begin(), vertex_index),
|
||||
make_iterator_property_map(path_count.begin(), vertex_index),
|
||||
vertex_index);
|
||||
}
|
||||
|
||||
template<typename WeightMap>
|
||||
struct brandes_betweenness_centrality_dispatch1
|
||||
{
|
||||
template<typename Graph, typename CentralityMap,
|
||||
typename EdgeCentralityMap, typename VertexIndexMap>
|
||||
static void
|
||||
run(const Graph& g, CentralityMap centrality,
|
||||
EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
|
||||
WeightMap weight_map)
|
||||
{
|
||||
brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
|
||||
weight_map, vertex_index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct brandes_betweenness_centrality_dispatch1<error_property_not_found>
|
||||
{
|
||||
template<typename Graph, typename CentralityMap,
|
||||
typename EdgeCentralityMap, typename VertexIndexMap>
|
||||
static void
|
||||
run(const Graph& g, CentralityMap centrality,
|
||||
EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
|
||||
error_property_not_found)
|
||||
{
|
||||
brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
|
||||
vertex_index);
|
||||
}
|
||||
};
|
||||
|
||||
} } // end namespace detail::graph
|
||||
|
||||
template<typename Graph, typename Param, typename Tag, typename Rest>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g,
|
||||
const bgl_named_params<Param,Tag,Rest>& params)
|
||||
{
|
||||
typedef bgl_named_params<Param,Tag,Rest> named_params;
|
||||
|
||||
typedef typename property_value<named_params, edge_weight_t>::type ew;
|
||||
detail::graph::brandes_betweenness_centrality_dispatch1<ew>::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));
|
||||
}
|
||||
|
||||
template<typename Graph, typename CentralityMap>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality)
|
||||
{
|
||||
detail::graph::brandes_betweenness_centrality_dispatch2(
|
||||
g, centrality, dummy_property_map(), get(vertex_index, g));
|
||||
}
|
||||
|
||||
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
|
||||
void
|
||||
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality,
|
||||
EdgeCentralityMap edge_centrality_map)
|
||||
{
|
||||
detail::graph::brandes_betweenness_centrality_dispatch2(
|
||||
g, centrality, edge_centrality_map, get(vertex_index, g));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts "absolute" betweenness centrality (as computed by the
|
||||
* brandes_betweenness_centrality algorithm) in the centrality map
|
||||
* into "relative" centrality. The result is placed back into the
|
||||
* given centrality map.
|
||||
*/
|
||||
template<typename Graph, typename CentralityMap>
|
||||
void
|
||||
relative_betweenness_centrality(const Graph& g, CentralityMap centrality)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename property_traits<CentralityMap>::value_type centrality_type;
|
||||
|
||||
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
|
||||
centrality_type factor = centrality_type(2)/centrality_type(n*n - 3*n + 2);
|
||||
vertex_iterator v, v_end;
|
||||
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
|
||||
put(centrality, *v, factor * get(centrality, *v));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the central point dominance of a graph.
|
||||
template<typename Graph, typename CentralityMap>
|
||||
typename property_traits<CentralityMap>::value_type
|
||||
central_point_dominance(const Graph& g, CentralityMap centrality)
|
||||
{
|
||||
using std::max;
|
||||
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename property_traits<CentralityMap>::value_type centrality_type;
|
||||
|
||||
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
|
||||
|
||||
// Find max centrality
|
||||
centrality_type max_centrality(0);
|
||||
vertex_iterator v, v_end;
|
||||
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
|
||||
max_centrality = max(max_centrality, get(centrality, *v));
|
||||
}
|
||||
|
||||
// Compute central point dominance
|
||||
centrality_type sum(0);
|
||||
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
|
||||
sum += (max_centrality - get(centrality, *v));
|
||||
}
|
||||
return sum/(n-1);
|
||||
}
|
||||
|
||||
} // end namespace boost
|
||||
|
||||
#endif // BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
|
||||
53
include/boost/graph/circle_layout.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#ifndef BOOST_GRAPH_CIRCLE_LAYOUT_HPP
|
||||
#define BOOST_GRAPH_CIRCLE_LAYOUT_HPP
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
/**
|
||||
* \brief Layout the graph with the vertices at the points of a regular
|
||||
* n-polygon.
|
||||
*
|
||||
* The distance from the center of the polygon to each point is
|
||||
* determined by the @p radius parameter. The @p position parameter
|
||||
* must be an Lvalue Property Map whose value type is a class type
|
||||
* containing @c x and @c y members that will be set to the @c x and
|
||||
* @c y coordinates.
|
||||
*/
|
||||
template<typename VertexListGraph, typename PositionMap, typename Radius>
|
||||
void
|
||||
circle_graph_layout(const VertexListGraph& g, PositionMap position,
|
||||
Radius radius)
|
||||
{
|
||||
const double pi = 3.14159;
|
||||
|
||||
using std::sin;
|
||||
using std::cos;
|
||||
|
||||
typedef typename graph_traits<VertexListGraph>::vertices_size_type
|
||||
vertices_size_type;
|
||||
|
||||
vertices_size_type n = num_vertices(g);
|
||||
|
||||
typedef typename graph_traits<VertexListGraph>::vertex_iterator
|
||||
vertex_iterator;
|
||||
|
||||
vertices_size_type i = 0;
|
||||
for(std::pair<vertex_iterator, vertex_iterator> v = vertices(g);
|
||||
v.first != v.second; ++v.first, ++i) {
|
||||
position[*v.first].x = radius * cos(i * 2 * pi / n);
|
||||
position[*v.first].y = radius * sin(i * 2 * pi / n);
|
||||
}
|
||||
}
|
||||
} // end namespace boost
|
||||
|
||||
#endif // BOOST_GRAPH_CIRCLE_LAYOUT_HPP
|
||||
506
include/boost/graph/kamada_kawai_spring_layout.hpp
Normal file
@@ -0,0 +1,506 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#ifndef BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
|
||||
#define BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/johnson_all_pairs_shortest.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
namespace boost {
|
||||
namespace detail { namespace graph {
|
||||
/**
|
||||
* Denotes an edge or display area side length used to scale a
|
||||
* Kamada-Kawai drawing.
|
||||
*/
|
||||
template<bool Edge, typename T>
|
||||
struct edge_or_side
|
||||
{
|
||||
explicit edge_or_side(T value) : value(value) {}
|
||||
|
||||
T value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the edge length from an edge length. This is trivial.
|
||||
*/
|
||||
template<typename Graph, typename DistanceMap, typename IndexMap,
|
||||
typename T>
|
||||
T compute_edge_length(const Graph&, DistanceMap, IndexMap,
|
||||
edge_or_side<true, T> length)
|
||||
{ return length.value; }
|
||||
|
||||
/**
|
||||
* Compute the edge length based on the display area side
|
||||
length. We do this by dividing the side length by the largest
|
||||
shortest distance between any two vertices in the graph.
|
||||
*/
|
||||
template<typename Graph, typename DistanceMap, typename IndexMap,
|
||||
typename T>
|
||||
T
|
||||
compute_edge_length(const Graph& g, DistanceMap distance, IndexMap index,
|
||||
edge_or_side<false, T> length)
|
||||
{
|
||||
T result(0);
|
||||
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
|
||||
for (vertex_iterator ui = vertices(g).first, end = vertices(g).second;
|
||||
ui != end; ++ui) {
|
||||
vertex_iterator vi = ui;
|
||||
for (++vi; vi != end; ++vi) {
|
||||
T dij = distance[get(index, *ui)][get(index, *vi)];
|
||||
if (dij > result) result = dij;
|
||||
}
|
||||
}
|
||||
return length.value / result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the Kamada-Kawai spring layout algorithm.
|
||||
*/
|
||||
template<typename Graph, typename PositionMap, typename WeightMap,
|
||||
typename EdgeOrSideLength, typename Done,
|
||||
typename VertexIndexMap, typename DistanceMatrix,
|
||||
typename SpringStrengthMatrix, typename PartialDerivativeMap>
|
||||
struct kamada_kawai_spring_layout_impl
|
||||
{
|
||||
typedef typename property_traits<WeightMap>::value_type weight_type;
|
||||
typedef std::pair<weight_type, weight_type> deriv_type;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor
|
||||
vertex_descriptor;
|
||||
|
||||
kamada_kawai_spring_layout_impl(
|
||||
const Graph& g,
|
||||
PositionMap position,
|
||||
WeightMap weight,
|
||||
EdgeOrSideLength edge_or_side_length,
|
||||
Done done,
|
||||
weight_type spring_constant,
|
||||
VertexIndexMap index,
|
||||
DistanceMatrix distance,
|
||||
SpringStrengthMatrix spring_strength,
|
||||
PartialDerivativeMap partial_derivatives)
|
||||
: g(g), position(position), weight(weight),
|
||||
edge_or_side_length(edge_or_side_length), done(done),
|
||||
spring_constant(spring_constant), index(index), distance(distance),
|
||||
spring_strength(spring_strength),
|
||||
partial_derivatives(partial_derivatives) {}
|
||||
|
||||
// Compute contribution of vertex i to the first partial
|
||||
// derivatives (dE/dx_m, dE/dy_m) (for vertex m)
|
||||
deriv_type
|
||||
compute_partial_derivative(vertex_descriptor m, vertex_descriptor i)
|
||||
{
|
||||
using std::sqrt;
|
||||
|
||||
deriv_type result(0, 0);
|
||||
if (i != m) {
|
||||
weight_type x_diff = position[m].x - position[i].x;
|
||||
weight_type y_diff = position[m].y - position[i].y;
|
||||
weight_type dist = sqrt(x_diff * x_diff + y_diff * y_diff);
|
||||
result.first = spring_strength[get(index, m)][get(index, i)]
|
||||
* (x_diff - distance[get(index, m)][get(index, i)]*x_diff/dist);
|
||||
result.second = spring_strength[get(index, m)][get(index, i)]
|
||||
* (y_diff - distance[get(index, m)][get(index, i)]*y_diff/dist);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compute partial derivatives dE/dx_m and dE/dy_m
|
||||
deriv_type
|
||||
compute_partial_derivatives(vertex_descriptor m)
|
||||
{
|
||||
using std::sqrt;
|
||||
|
||||
deriv_type result(0, 0);
|
||||
|
||||
// TBD: looks like an accumulate to me
|
||||
std::pair<vertex_iterator, vertex_iterator> verts = vertices(g);
|
||||
for (/* no init */; verts.first != verts.second; ++verts.first) {
|
||||
vertex_descriptor i = *verts.first;
|
||||
deriv_type deriv = compute_partial_derivative(m, i);
|
||||
result.first += deriv.first;
|
||||
result.second += deriv.second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The actual Kamada-Kawai spring layout algorithm implementation
|
||||
bool run()
|
||||
{
|
||||
using std::sqrt;
|
||||
|
||||
// Compute d_{ij} and place it in the distance matrix
|
||||
if (!johnson_all_pairs_shortest_paths(g, distance, index, weight,
|
||||
weight_type(0)))
|
||||
return false;
|
||||
|
||||
// Compute L based on side length (if needed), or retrieve L
|
||||
weight_type edge_length =
|
||||
detail::graph::compute_edge_length(g, distance, index,
|
||||
edge_or_side_length);
|
||||
|
||||
// Compute l_{ij} and k_{ij}
|
||||
const weight_type K = spring_constant;
|
||||
vertex_iterator ui, end = vertices(g).second;
|
||||
for (ui = vertices(g).first; ui != end; ++ui) {
|
||||
vertex_iterator vi = ui;
|
||||
for (++vi; vi != end; ++vi) {
|
||||
weight_type dij = distance[get(index, *ui)][get(index, *vi)];
|
||||
distance[get(index, *ui)][get(index, *vi)] = edge_length * dij;
|
||||
distance[get(index, *vi)][get(index, *ui)] = edge_length * dij;
|
||||
spring_strength[get(index, *ui)][get(index, *vi)] = K/(dij*dij);
|
||||
spring_strength[get(index, *vi)][get(index, *ui)] = K/(dij*dij);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute Delta_i and find max
|
||||
vertex_descriptor p = *vertices(g).first;
|
||||
weight_type delta_p(0);
|
||||
|
||||
for (ui = vertices(g).first; ui != end; ++ui) {
|
||||
deriv_type deriv = compute_partial_derivatives(*ui);
|
||||
put(partial_derivatives, *ui, deriv);
|
||||
|
||||
weight_type delta =
|
||||
sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
|
||||
|
||||
if (delta > delta_p) {
|
||||
p = *ui;
|
||||
delta_p = delta;
|
||||
}
|
||||
}
|
||||
|
||||
while (!done(delta_p, p, g, true)) {
|
||||
// The contribution p makes to the partial derivatives of
|
||||
// each vertex. Computing this (at O(n) cost) allows us to
|
||||
// update the delta_i values in O(n) time instead of O(n^2)
|
||||
// time.
|
||||
std::vector<deriv_type> p_partials(num_vertices(g));
|
||||
for (ui = vertices(g).first; ui != end; ++ui) {
|
||||
vertex_descriptor i = *ui;
|
||||
p_partials[get(index, i)] = compute_partial_derivative(i, p);
|
||||
}
|
||||
|
||||
do {
|
||||
// Compute the 4 elements of the Jacobian
|
||||
weight_type dE_dx_dx = 0, dE_dx_dy = 0, dE_dy_dx = 0, dE_dy_dy = 0;
|
||||
for (ui = vertices(g).first; ui != end; ++ui) {
|
||||
vertex_descriptor i = *ui;
|
||||
if (i != p) {
|
||||
weight_type x_diff = position[p].x - position[i].x;
|
||||
weight_type y_diff = position[p].y - position[i].y;
|
||||
weight_type dist = sqrt(x_diff * x_diff + y_diff * y_diff);
|
||||
weight_type dist_cubed = dist * dist * dist;
|
||||
weight_type k_mi = spring_strength[get(index,p)][get(index,i)];
|
||||
weight_type l_mi = distance[get(index, p)][get(index, i)];
|
||||
dE_dx_dx += k_mi * (1 - (l_mi * y_diff * y_diff)/dist_cubed);
|
||||
dE_dx_dy += k_mi * l_mi * x_diff * y_diff / dist_cubed;
|
||||
dE_dy_dx += k_mi * l_mi * x_diff * y_diff / dist_cubed;
|
||||
dE_dy_dy += k_mi * (1 - (l_mi * x_diff * x_diff)/dist_cubed);
|
||||
}
|
||||
}
|
||||
|
||||
// Solve for delta_x and delta_y
|
||||
weight_type dE_dx = get(partial_derivatives, p).first;
|
||||
weight_type dE_dy = get(partial_derivatives, p).second;
|
||||
|
||||
weight_type delta_x =
|
||||
(dE_dx_dy * dE_dy - dE_dy_dy * dE_dx)
|
||||
/ (dE_dx_dx * dE_dy_dy - dE_dx_dy * dE_dy_dx);
|
||||
|
||||
weight_type delta_y =
|
||||
(dE_dx_dx * dE_dy - dE_dy_dx * dE_dx)
|
||||
/ (dE_dy_dx * dE_dx_dy - dE_dx_dx * dE_dy_dy);
|
||||
|
||||
|
||||
// Move p by (delta_x, delta_y)
|
||||
position[p].x += delta_x;
|
||||
position[p].y += delta_y;
|
||||
|
||||
// Recompute partial derivatives and delta_p
|
||||
deriv_type deriv = compute_partial_derivatives(p);
|
||||
put(partial_derivatives, p, deriv);
|
||||
|
||||
delta_p =
|
||||
sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
|
||||
} while (!done(delta_p, p, g, false));
|
||||
|
||||
// Select new p by updating each partial derivative and delta
|
||||
vertex_descriptor old_p;
|
||||
for (ui = vertices(g).first; ui != end; ++ui) {
|
||||
deriv_type old_deriv_p = p_partials[get(index, *ui)];
|
||||
deriv_type old_p_partial =
|
||||
compute_partial_derivative(*ui, old_p);
|
||||
deriv_type deriv = get(partial_derivatives, *ui);
|
||||
|
||||
deriv.first += old_p_partial.first - old_deriv_p.first;
|
||||
deriv.second += old_p_partial.second - old_deriv_p.second;
|
||||
|
||||
put(partial_derivatives, *ui, deriv);
|
||||
weight_type delta =
|
||||
sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
|
||||
|
||||
if (delta > delta_p) {
|
||||
p = *ui;
|
||||
delta_p = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Graph& g;
|
||||
PositionMap position;
|
||||
WeightMap weight;
|
||||
EdgeOrSideLength edge_or_side_length;
|
||||
Done done;
|
||||
weight_type spring_constant;
|
||||
VertexIndexMap index;
|
||||
DistanceMatrix distance;
|
||||
SpringStrengthMatrix spring_strength;
|
||||
PartialDerivativeMap partial_derivatives;
|
||||
};
|
||||
} } // end namespace detail::graph
|
||||
|
||||
/// States that the given quantity is an edge length.
|
||||
template<typename T>
|
||||
inline detail::graph::edge_or_side<true, T>
|
||||
edge_length(T x)
|
||||
{ return detail::graph::edge_or_side<true, T>(x); }
|
||||
|
||||
/// States that the given quantity is a display area side length.
|
||||
template<typename T>
|
||||
inline detail::graph::edge_or_side<false, T>
|
||||
side_length(T x)
|
||||
{ return detail::graph::edge_or_side<false, T>(x); }
|
||||
|
||||
/**
|
||||
* \brief Determines when to terminate layout of a particular graph based
|
||||
* on a given tolerance.
|
||||
*
|
||||
* For local movements, where a single vertex is being moved toward
|
||||
* a local minima the tolerance is taken as an absolute tolerance;
|
||||
* for global movements, layout terminates when moving individual
|
||||
* particles results in changes in the maximum vertex energy less
|
||||
* than the tolerance.
|
||||
*/
|
||||
template<typename T = double>
|
||||
struct layout_tolerance
|
||||
{
|
||||
layout_tolerance(const T& tolerance = T(0.01))
|
||||
: tolerance(tolerance), last_energy(std::numeric_limits<T>::max()) { }
|
||||
|
||||
template<typename Graph>
|
||||
bool
|
||||
operator()(T delta_p,
|
||||
typename boost::graph_traits<Graph>::vertex_descriptor p,
|
||||
const Graph& g,
|
||||
bool global)
|
||||
{
|
||||
if (global) {
|
||||
double diff = fabs(last_energy - delta_p);
|
||||
if (diff < T(0)) diff = -diff;
|
||||
last_energy = delta_p;
|
||||
return diff < tolerance;
|
||||
} else {
|
||||
return delta_p < tolerance;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T tolerance;
|
||||
T last_energy;
|
||||
};
|
||||
|
||||
/** \brief Kamada-Kawai spring layout for undirected graphs.
|
||||
*
|
||||
* This algorithm performs graph layout (in two dimensions) for
|
||||
* connected, undirected graphs. It operates by relating the layout
|
||||
* of graphs to a dynamic spring system and minimizing the energy
|
||||
* within that system. The strength of a spring between two vertices
|
||||
* is inversely proportional to the square of the shortest distance
|
||||
* (in graph terms) between those two vertices. Essentially,
|
||||
* vertices that are closer in the graph-theoretic sense (i.e., by
|
||||
* following edges) will have stronger springs and will therefore be
|
||||
* placed closer together.
|
||||
*
|
||||
* Prior to invoking this algorithm, it is recommended that the
|
||||
* vertices be placed along the vertices of a regular n-sided
|
||||
* polygon.
|
||||
*
|
||||
* \param g (IN) must be a model of Vertex List Graph, Edge List
|
||||
* Graph, and Incidence Graph and must be undirected.
|
||||
*
|
||||
* \param position (OUT) must be a model of Lvalue Property Map,
|
||||
* where the value type is a class containing fields @c x and @c y
|
||||
* that will be set to the @c x and @c y coordinates of each vertex.
|
||||
*
|
||||
* \param weight (IN) must be a model of Readable Property Map,
|
||||
* which provides the weight of each edge in the graph @p g.
|
||||
*
|
||||
* \param edge_or_side_length (IN) provides either the unit length
|
||||
* @c e of an edge in the layout or the length of a side @c s of the
|
||||
* display area, and must be either @c boost::edge_length(e) or @c
|
||||
* boost::side_length(s), respectively.
|
||||
*
|
||||
* \param done (IN) is a 4-argument function object that is passed
|
||||
* the current value of delta_p (i.e., the energy of vertex @p p),
|
||||
* the vertex @p p, the graph @p g, and a boolean flag indicating
|
||||
* whether @p delta_p is the maximum energy in the system (when @c
|
||||
* true) or the energy of the vertex being moved. Defaults to @c
|
||||
* layout_tolerance instantiated over the value type of the weight
|
||||
* map.
|
||||
*
|
||||
* \param spring_constant (IN) is the constant multiplied by each
|
||||
* spring's strength. Larger values create systems with more energy
|
||||
* that can take longer to stabilize; smaller values create systems
|
||||
* with less energy that stabilize quickly but do not necessarily
|
||||
* result in pleasing layouts. The default value is 1.
|
||||
*
|
||||
* \param index (IN) is a mapping from vertices to index values
|
||||
* between 0 and @c num_vertices(g). The default is @c
|
||||
* get(vertex_index,g).
|
||||
*
|
||||
* \param distance (UTIL/OUT) will be used to store the distance
|
||||
* from every vertex to every other vertex, which is computed in the
|
||||
* first stages of the algorithm. This value's type must be a model
|
||||
* of BasicMatrix with value type equal to the value type of the
|
||||
* weight map. The default is a a vector of vectors.
|
||||
*
|
||||
* \param spring_strength (UTIL/OUT) will be used to store the
|
||||
* strength of the spring between every pair of vertices. This
|
||||
* value's type must be a model of BasicMatrix with value type equal
|
||||
* to the value type of the weight map. The default is a a vector of
|
||||
* vectors.
|
||||
*
|
||||
* \param partial_derivatives (UTIL) will be used to store the
|
||||
* partial derivates of each vertex with respect to the @c x and @c
|
||||
* y coordinates. This must be a Read/Write Property Map whose value
|
||||
* type is a pair with both types equivalent to the value type of
|
||||
* the weight map. The default is an iterator property map.
|
||||
*
|
||||
* \returns @c true if layout was successful or @c false if a
|
||||
* negative weight cycle was detected.
|
||||
*/
|
||||
template<typename Graph, typename PositionMap, typename WeightMap,
|
||||
typename T, bool EdgeOrSideLength, typename Done,
|
||||
typename VertexIndexMap, typename DistanceMatrix,
|
||||
typename SpringStrengthMatrix, typename PartialDerivativeMap>
|
||||
bool
|
||||
kamada_kawai_spring_layout(
|
||||
const Graph& g,
|
||||
PositionMap position,
|
||||
WeightMap weight,
|
||||
detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
|
||||
Done done,
|
||||
typename property_traits<WeightMap>::value_type spring_constant,
|
||||
VertexIndexMap index,
|
||||
DistanceMatrix distance,
|
||||
SpringStrengthMatrix spring_strength,
|
||||
PartialDerivativeMap partial_derivatives)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((is_convertible<
|
||||
typename graph_traits<Graph>::directed_category*,
|
||||
undirected_tag*
|
||||
>::value));
|
||||
|
||||
detail::graph::kamada_kawai_spring_layout_impl<
|
||||
Graph, PositionMap, WeightMap,
|
||||
detail::graph::edge_or_side<EdgeOrSideLength, T>, Done, VertexIndexMap,
|
||||
DistanceMatrix, SpringStrengthMatrix, PartialDerivativeMap>
|
||||
alg(g, position, weight, edge_or_side_length, done, spring_constant,
|
||||
index, distance, spring_strength, partial_derivatives);
|
||||
return alg.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
template<typename Graph, typename PositionMap, typename WeightMap,
|
||||
typename T, bool EdgeOrSideLength, typename Done,
|
||||
typename VertexIndexMap>
|
||||
bool
|
||||
kamada_kawai_spring_layout(
|
||||
const Graph& g,
|
||||
PositionMap position,
|
||||
WeightMap weight,
|
||||
detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
|
||||
Done done,
|
||||
typename property_traits<WeightMap>::value_type spring_constant,
|
||||
VertexIndexMap index)
|
||||
{
|
||||
typedef typename property_traits<WeightMap>::value_type weight_type;
|
||||
|
||||
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
|
||||
typedef std::vector<weight_type> weight_vec;
|
||||
|
||||
std::vector<weight_vec> distance(n, weight_vec(n));
|
||||
std::vector<weight_vec> spring_strength(n, weight_vec(n));
|
||||
std::vector<std::pair<weight_type, weight_type> > partial_derivatives(n);
|
||||
|
||||
return
|
||||
kamada_kawai_spring_layout(
|
||||
g, position, weight, edge_or_side_length, done, spring_constant, index,
|
||||
distance.begin(),
|
||||
spring_strength.begin(),
|
||||
make_iterator_property_map(partial_derivatives.begin(), index));
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
template<typename Graph, typename PositionMap, typename WeightMap,
|
||||
typename T, bool EdgeOrSideLength, typename Done>
|
||||
bool
|
||||
kamada_kawai_spring_layout(
|
||||
const Graph& g,
|
||||
PositionMap position,
|
||||
WeightMap weight,
|
||||
detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
|
||||
Done done,
|
||||
typename property_traits<WeightMap>::value_type spring_constant =
|
||||
typename property_traits<WeightMap>::value_type(1))
|
||||
{
|
||||
return kamada_kawai_spring_layout(g, position, weight, edge_or_side_length,
|
||||
done, spring_constant,
|
||||
get(vertex_index, g));
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
template<typename Graph, typename PositionMap, typename WeightMap,
|
||||
typename T, bool EdgeOrSideLength>
|
||||
bool
|
||||
kamada_kawai_spring_layout(
|
||||
const Graph& g,
|
||||
PositionMap position,
|
||||
WeightMap weight,
|
||||
detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length)
|
||||
{
|
||||
typedef typename property_traits<WeightMap>::value_type weight_type;
|
||||
return kamada_kawai_spring_layout(g, position, weight, edge_or_side_length,
|
||||
layout_tolerance<weight_type>(),
|
||||
weight_type(1.0),
|
||||
get(vertex_index, g));
|
||||
}
|
||||
} // end namespace boost
|
||||
|
||||
#endif // BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
|
||||
479
test/brandes_betweenness_centrality_test.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#include <boost/graph/brandes_betweenness_centrality.hpp>
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <queue>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/random/uniform_01.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
const double error_tolerance = 0.001;
|
||||
|
||||
typedef property<edge_weight_t, double,
|
||||
property<edge_index_t, std::size_t> > EdgeProperties;
|
||||
|
||||
struct weighted_edge
|
||||
{
|
||||
int source, target;
|
||||
double weight;
|
||||
};
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
run_weighted_test(Graph*, int V, weighted_edge edge_init[], int E,
|
||||
double correct_centrality[])
|
||||
{
|
||||
Graph g(V);
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor Edge;
|
||||
|
||||
std::vector<Vertex> vertices(V);
|
||||
{
|
||||
vertex_iterator v, v_end;
|
||||
int index = 0;
|
||||
for (tie(v, v_end) = boost::vertices(g); v != v_end; ++v, ++index) {
|
||||
put(vertex_index, g, *v, index);
|
||||
vertices[index] = *v;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Edge> edges(E);
|
||||
for (int e = 0; e < E; ++e) {
|
||||
edges[e] = add_edge(vertices[edge_init[e].source],
|
||||
vertices[edge_init[e].target],
|
||||
g).first;
|
||||
put(edge_weight, g, edges[e], 1.0);
|
||||
}
|
||||
|
||||
std::vector<double> centrality(V);
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
centrality_map(
|
||||
make_iterator_property_map(centrality.begin(), get(vertex_index, g)))
|
||||
.vertex_index_map(get(vertex_index, g)).weight_map(get(edge_weight, g)));
|
||||
|
||||
|
||||
for (int v = 0; v < V; ++v) {
|
||||
BOOST_TEST(centrality[v] == correct_centrality[v]);
|
||||
}
|
||||
}
|
||||
|
||||
struct unweighted_edge
|
||||
{
|
||||
int source, target;
|
||||
};
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
run_unweighted_test(Graph*, int V, unweighted_edge edge_init[], int E,
|
||||
double correct_centrality[],
|
||||
double* correct_edge_centrality = 0)
|
||||
{
|
||||
Graph g(V);
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor Edge;
|
||||
|
||||
std::vector<Vertex> vertices(V);
|
||||
{
|
||||
vertex_iterator v, v_end;
|
||||
int index = 0;
|
||||
for (tie(v, v_end) = boost::vertices(g); v != v_end; ++v, ++index) {
|
||||
put(vertex_index, g, *v, index);
|
||||
vertices[index] = *v;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Edge> edges(E);
|
||||
for (int e = 0; e < E; ++e) {
|
||||
edges[e] = add_edge(vertices[edge_init[e].source],
|
||||
vertices[edge_init[e].target],
|
||||
g).first;
|
||||
put(edge_weight, g, edges[e], 1.0);
|
||||
put(edge_index, g, edges[e], e);
|
||||
}
|
||||
|
||||
std::vector<double> centrality(V);
|
||||
std::vector<double> edge_centrality1(E);
|
||||
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
centrality_map(
|
||||
make_iterator_property_map(centrality.begin(), get(vertex_index, g)))
|
||||
.edge_centrality_map(
|
||||
make_iterator_property_map(edge_centrality1.begin(),
|
||||
get(edge_index, g)))
|
||||
.vertex_index_map(get(vertex_index, g)));
|
||||
|
||||
std::vector<double> centrality2(V);
|
||||
std::vector<double> edge_centrality2(E);
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
vertex_index_map(get(vertex_index, g)).weight_map(get(edge_weight, g))
|
||||
.centrality_map(
|
||||
make_iterator_property_map(centrality2.begin(), get(vertex_index, g)))
|
||||
.edge_centrality_map(
|
||||
make_iterator_property_map(edge_centrality2.begin(),
|
||||
get(edge_index, g))));
|
||||
|
||||
std::vector<double> edge_centrality3(E);
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
edge_centrality_map(
|
||||
make_iterator_property_map(edge_centrality3.begin(),
|
||||
get(edge_index, g))));
|
||||
|
||||
for (int v = 0; v < V; ++v) {
|
||||
BOOST_TEST(centrality[v] == centrality2[v]);
|
||||
|
||||
double relative_error =
|
||||
correct_centrality[v] == 0.0? centrality[v]
|
||||
: (centrality[v] - correct_centrality[v]) / correct_centrality[v];
|
||||
if (relative_error < 0) relative_error = -relative_error;
|
||||
BOOST_TEST(relative_error < error_tolerance);
|
||||
}
|
||||
|
||||
for (int e = 0; e < E; ++e) {
|
||||
BOOST_TEST(edge_centrality1[e] == edge_centrality2[e]);
|
||||
BOOST_TEST(edge_centrality1[e] == edge_centrality3[e]);
|
||||
|
||||
if (correct_edge_centrality) {
|
||||
double relative_error =
|
||||
correct_edge_centrality[e] == 0.0? edge_centrality1[e]
|
||||
: (edge_centrality1[e] - correct_edge_centrality[e])
|
||||
/ correct_edge_centrality[e];
|
||||
if (relative_error < 0) relative_error = -relative_error;
|
||||
BOOST_TEST(relative_error < error_tolerance);
|
||||
|
||||
if (relative_error >= error_tolerance) {
|
||||
std::cerr << "Edge " << e << " has edge centrality "
|
||||
<< edge_centrality1[e] << ", should be "
|
||||
<< correct_edge_centrality[e] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
run_wheel_test(Graph*, int V)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
|
||||
Graph g(V);
|
||||
Vertex center = *boost::vertices(g).first;
|
||||
|
||||
std::vector<Vertex> vertices(V);
|
||||
{
|
||||
vertex_iterator v, v_end;
|
||||
int index = 0;
|
||||
for (tie(v, v_end) = boost::vertices(g); v != v_end; ++v, ++index) {
|
||||
put(vertex_index, g, *v, index);
|
||||
vertices[index] = *v;
|
||||
if (*v != center) add_edge(*v, center, g);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> centrality(V);
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
make_iterator_property_map(centrality.begin(), get(vertex_index, g)));
|
||||
|
||||
std::vector<double> centrality2(V);
|
||||
brandes_betweenness_centrality(
|
||||
g,
|
||||
centrality_map(
|
||||
make_iterator_property_map(centrality2.begin(), get(vertex_index, g)))
|
||||
.vertex_index_map(get(vertex_index, g)).weight_map(get(edge_weight, g)));
|
||||
|
||||
relative_betweenness_centrality(
|
||||
g,
|
||||
make_iterator_property_map(centrality.begin(), get(vertex_index, g)));
|
||||
|
||||
relative_betweenness_centrality(
|
||||
g,
|
||||
make_iterator_property_map(centrality2.begin(), get(vertex_index, g)));
|
||||
|
||||
for (int v = 0; v < V; ++v) {
|
||||
BOOST_TEST(centrality[v] == centrality2[v]);
|
||||
BOOST_TEST((v == 0 && centrality[v] == 1)
|
||||
|| (v != 0 && centrality[v] == 0));
|
||||
}
|
||||
|
||||
double dominance =
|
||||
central_point_dominance(
|
||||
g,
|
||||
make_iterator_property_map(centrality2.begin(), get(vertex_index, g)));
|
||||
BOOST_TEST(dominance == 1.0);
|
||||
}
|
||||
|
||||
template<typename MutableGraph>
|
||||
void randomly_add_edges(MutableGraph& g, double edge_probability)
|
||||
{
|
||||
typedef typename graph_traits<MutableGraph>::directed_category
|
||||
directed_category;
|
||||
const bool is_undirected =
|
||||
is_same<directed_category, undirected_tag>::value;
|
||||
|
||||
minstd_rand gen;
|
||||
uniform_01<minstd_rand, double> rand_gen(gen);
|
||||
|
||||
typedef typename graph_traits<MutableGraph>::vertex_descriptor vertex;
|
||||
typename graph_traits<MutableGraph>::vertex_iterator vi, vi_end;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
|
||||
vertex v = *vi;
|
||||
typename graph_traits<MutableGraph>::vertex_iterator wi
|
||||
= is_undirected? vi : vertices(g).first;
|
||||
while (wi != vi_end) {
|
||||
vertex w = *wi++;
|
||||
if (v != w) {
|
||||
if (rand_gen() < edge_probability) add_edge(v, w, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Graph, typename VertexIndexMap, typename CentralityMap>
|
||||
void
|
||||
simple_unweighted_betweenness_centrality(const Graph& g, VertexIndexMap index,
|
||||
CentralityMap centrality)
|
||||
{
|
||||
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex;
|
||||
typedef typename boost::graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename boost::graph_traits<Graph>::adjacency_iterator adjacency_iterator;
|
||||
typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
|
||||
typedef typename boost::property_traits<CentralityMap>::value_type centrality_type;
|
||||
|
||||
vertex_iterator vi, vi_end;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
|
||||
put(centrality, *vi, 0);
|
||||
|
||||
vertex_iterator si, si_end;
|
||||
for (tie(si, si_end) = vertices(g); si != si_end; ++si) {
|
||||
vertex s = *si;
|
||||
|
||||
// S <-- empty stack
|
||||
std::stack<vertex> S;
|
||||
|
||||
// P[w] <-- empty list, w \in V
|
||||
typedef std::vector<vertex> Predecessors;
|
||||
std::vector<Predecessors> predecessors(num_vertices(g));
|
||||
|
||||
// sigma[t] <-- 0, t \in V
|
||||
std::vector<vertices_size_type> sigma(num_vertices(g), 0);
|
||||
|
||||
// sigma[s] <-- 1
|
||||
sigma[get(index, s)] = 1;
|
||||
|
||||
// d[t] <-- -1, t \in V
|
||||
std::vector<int> d(num_vertices(g), -1);
|
||||
|
||||
// d[s] <-- 0
|
||||
d[get(index, s)] = 0;
|
||||
|
||||
// Q <-- empty queue
|
||||
std::queue<vertex> Q;
|
||||
|
||||
// enqueue s --> Q
|
||||
Q.push(s);
|
||||
|
||||
while (!Q.empty()) {
|
||||
// dequeue v <-- Q
|
||||
vertex v = Q.front(); Q.pop();
|
||||
|
||||
// push v --> S
|
||||
S.push(v);
|
||||
|
||||
adjacency_iterator wi, wi_end;
|
||||
for (tie(wi, wi_end) = adjacent_vertices(v, g); wi != wi_end; ++wi) {
|
||||
vertex w = *wi;
|
||||
|
||||
// w found for the first time?
|
||||
if (d[get(index, w)] < 0) {
|
||||
// enqueue w --> Q
|
||||
Q.push(w);
|
||||
|
||||
// d[w] <-- d[v] + 1
|
||||
d[get(index, w)] = d[get(index, v)] + 1;
|
||||
}
|
||||
|
||||
// shortest path to w via v?
|
||||
if (d[get(index, w)] == d[get(index, v)] + 1) {
|
||||
// sigma[w] = sigma[w] + sigma[v]
|
||||
sigma[get(index, w)] += sigma[get(index, v)];
|
||||
|
||||
// append v --> P[w]
|
||||
predecessors[get(index, w)].push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delta[v] <-- 0, v \in V
|
||||
std::vector<centrality_type> delta(num_vertices(g), 0);
|
||||
|
||||
// S returns vertices in order of non-increasing distance from s
|
||||
while (!S.empty()) {
|
||||
// pop w <-- S
|
||||
vertex w = S.top(); S.pop();
|
||||
|
||||
const Predecessors& w_preds = predecessors[get(index, w)];
|
||||
for (typename Predecessors::const_iterator vi = w_preds.begin();
|
||||
vi != w_preds.end(); ++vi) {
|
||||
vertex v = *vi;
|
||||
// delta[v] <-- delta[v] + (sigma[v]/sigma[w])*(1 + delta[w])
|
||||
delta[get(index, v)] +=
|
||||
((centrality_type)sigma[get(index, v)]/sigma[get(index, w)])
|
||||
* (1 + delta[get(index, w)]);
|
||||
}
|
||||
|
||||
if (w != s) {
|
||||
// C_B[w] <-- C_B[w] + delta[w]
|
||||
centrality[w] += delta[get(index, w)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef typename graph_traits<Graph>::directed_category directed_category;
|
||||
const bool is_undirected =
|
||||
is_same<directed_category, undirected_tag>::value;
|
||||
if (is_undirected) {
|
||||
vertex_iterator v, v_end;
|
||||
for(tie(v, v_end) = vertices(g); v != v_end; ++v) {
|
||||
put(centrality, *v, get(centrality, *v) / centrality_type(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Graph>
|
||||
void random_unweighted_test(Graph*, int n)
|
||||
{
|
||||
Graph g(n);
|
||||
randomly_add_edges(g, 0.20);
|
||||
std::cout << "Random graph with " << n << " vertices and "
|
||||
<< num_edges(g) << " edges.\n";
|
||||
|
||||
std::cout << " Direct translation of Brandes' algorithm...";
|
||||
std::vector<double> centrality(n);
|
||||
simple_unweighted_betweenness_centrality(g, get(vertex_index, g),
|
||||
make_iterator_property_map(centrality.begin(), get(vertex_index, g)));
|
||||
std::cout << "DONE.\n";
|
||||
|
||||
std::cout << " Real version, unweighted...";
|
||||
std::vector<double> centrality2(n);
|
||||
brandes_betweenness_centrality(g,
|
||||
make_iterator_property_map(centrality2.begin(), get(vertex_index, g)));
|
||||
std::cout << "DONE.\n";
|
||||
|
||||
BOOST_TEST(std::equal(centrality.begin(), centrality.end(),
|
||||
centrality2.begin()));
|
||||
|
||||
std::cout << " Real version, weighted...";
|
||||
std::vector<double> centrality3(n);
|
||||
|
||||
for (typename graph_traits<Graph>::edge_iterator ei = edges(g).first;
|
||||
ei != edges(g).second; ++ei)
|
||||
put(edge_weight, g, *ei, 1);
|
||||
|
||||
brandes_betweenness_centrality(g,
|
||||
weight_map(get(edge_weight, g))
|
||||
.centrality_map(
|
||||
make_iterator_property_map(centrality3.begin(), get(vertex_index, g))));
|
||||
std::cout << "DONE.\n";
|
||||
|
||||
BOOST_TEST(std::equal(centrality.begin(), centrality.end(),
|
||||
centrality3.begin()));
|
||||
|
||||
}
|
||||
|
||||
int test_main(int, char*[])
|
||||
{
|
||||
typedef adjacency_list<listS, listS, undirectedS,
|
||||
property<vertex_index_t, int>, EdgeProperties>
|
||||
Graph;
|
||||
typedef adjacency_list<listS, listS, directedS,
|
||||
property<vertex_index_t, int>, EdgeProperties>
|
||||
Digraph;
|
||||
|
||||
struct unweighted_edge ud_edge_init1[5] = {
|
||||
{ 0, 1 },
|
||||
{ 0, 3 },
|
||||
{ 1, 2 },
|
||||
{ 3, 2 },
|
||||
{ 2, 4 }
|
||||
};
|
||||
double ud_centrality1[5] = { 0.5, 1.0, 3.5, 1.0, 0.0 };
|
||||
run_unweighted_test((Graph*)0, 5, ud_edge_init1, 5, ud_centrality1);
|
||||
|
||||
// Example borrowed from the JUNG test suite
|
||||
struct unweighted_edge ud_edge_init2[10] = {
|
||||
{ 0, 1 },
|
||||
{ 0, 6 },
|
||||
{ 1, 2 },
|
||||
{ 1, 3 },
|
||||
{ 2, 4 },
|
||||
{ 3, 4 },
|
||||
{ 4, 5 },
|
||||
{ 5, 8 },
|
||||
{ 7, 8 },
|
||||
{ 6, 7 },
|
||||
};
|
||||
double ud_centrality2[9] = {
|
||||
0.2142 * 28,
|
||||
0.2797 * 28,
|
||||
0.0892 * 28,
|
||||
0.0892 * 28,
|
||||
0.2797 * 28,
|
||||
0.2142 * 28,
|
||||
0.1666 * 28,
|
||||
0.1428 * 28,
|
||||
0.1666 * 28
|
||||
};
|
||||
double ud_edge_centrality2[10] = {
|
||||
10.66666,
|
||||
9.33333,
|
||||
6.5,
|
||||
6.5,
|
||||
6.5,
|
||||
6.5,
|
||||
10.66666,
|
||||
9.33333,
|
||||
8.0,
|
||||
8.0
|
||||
};
|
||||
|
||||
run_unweighted_test((Graph*)0, 9, ud_edge_init2, 10, ud_centrality2,
|
||||
ud_edge_centrality2);
|
||||
|
||||
weighted_edge dw_edge_init1[6] = {
|
||||
{ 0, 1, 1.0 },
|
||||
{ 0, 3, 1.0 },
|
||||
{ 1, 2, 0.5 },
|
||||
{ 3, 1, 1.0 },
|
||||
{ 3, 4, 1.0 },
|
||||
{ 4, 2, 0.5 }
|
||||
};
|
||||
double dw_centrality1[5] = { 0.0, 1.5, 0.0, 1.0, 0.5 };
|
||||
run_weighted_test((Digraph*)0, 5, dw_edge_init1, 6, dw_centrality1);
|
||||
|
||||
run_wheel_test((Graph*)0, 15);
|
||||
|
||||
random_unweighted_test((Graph*)0, 500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
258
test/layout_test.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
// Copyright 2004 The Trustees of Indiana University.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Douglas Gregor
|
||||
// Andrew Lumsdaine
|
||||
#include <boost/graph/kamada_kawai_spring_layout.hpp>
|
||||
#include <boost/graph/circle_layout.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
using namespace boost;
|
||||
|
||||
enum vertex_position_t { vertex_position };
|
||||
namespace boost { BOOST_INSTALL_PROPERTY(vertex, position); }
|
||||
|
||||
struct point
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
template<typename Graph, typename PositionMap>
|
||||
void print_graph_layout(const Graph& g, PositionMap position)
|
||||
{
|
||||
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
|
||||
int xmin = 0, xmax = 0, ymin = 0, ymax = 0;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
|
||||
if ((int)position[*vi].x < xmin) xmin = (int)position[*vi].x;
|
||||
if ((int)position[*vi].x > xmax) xmax = (int)position[*vi].x;
|
||||
if ((int)position[*vi].y < ymin) ymin = (int)position[*vi].y;
|
||||
if ((int)position[*vi].y > ymax) ymax = (int)position[*vi].y;
|
||||
}
|
||||
|
||||
for (int y = ymin; y <= ymax; ++y) {
|
||||
for (int x = xmin; x <= xmax; ++x) {
|
||||
// Find vertex at this position
|
||||
typename graph_traits<Graph>::vertices_size_type index = 0;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi, ++index) {
|
||||
if ((int)position[*vi].x == x && (int)position[*vi].y == y)
|
||||
break;
|
||||
}
|
||||
|
||||
if (vi == vi_end) std::cout << ' ';
|
||||
else std::cout << (char)(index + 'A');
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Graph, typename PositionMap>
|
||||
void dump_graph_layout(std::string name, const Graph& g, PositionMap position)
|
||||
{
|
||||
std::ofstream out((name + ".dot").c_str());
|
||||
out << "graph " << name << " {" << std::endl;
|
||||
|
||||
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
|
||||
out << " n" << get(vertex_index, g, *vi) << "[ pos=\""
|
||||
<< (int)position[*vi].x + 25 << ", " << (int)position[*vi].y + 25
|
||||
<< "\" ];\n";
|
||||
}
|
||||
|
||||
typename graph_traits<Graph>::edge_iterator ei, ei_end;
|
||||
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
|
||||
out << " n" << get(vertex_index, g, source(*ei, g)) << " -- n"
|
||||
<< get(vertex_index, g, target(*ei, g)) << ";\n";
|
||||
}
|
||||
out << "}\n";
|
||||
}
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
test_circle_layout(Graph*, typename graph_traits<Graph>::vertices_size_type n)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
|
||||
typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
|
||||
|
||||
Graph g(n);
|
||||
|
||||
// Initialize vertex indices
|
||||
vertex_iterator vi = vertices(g).first;
|
||||
for (vertices_size_type i = 0; i < n; ++i, ++vi)
|
||||
put(vertex_index, g, *vi, i);
|
||||
|
||||
circle_graph_layout(g, get(vertex_position, g), 10.0);
|
||||
|
||||
std::cout << "Regular polygon layout with " << n << " points.\n";
|
||||
print_graph_layout(g, get(vertex_position, g));
|
||||
}
|
||||
|
||||
struct simple_edge
|
||||
{
|
||||
int first, second;
|
||||
};
|
||||
|
||||
struct kamada_kawai_done
|
||||
{
|
||||
kamada_kawai_done() : last_delta() {}
|
||||
|
||||
template<typename Graph>
|
||||
bool operator()(double delta_p,
|
||||
typename boost::graph_traits<Graph>::vertex_descriptor p,
|
||||
const Graph& g,
|
||||
bool global)
|
||||
{
|
||||
if (global) {
|
||||
double diff = last_delta - delta_p;
|
||||
if (diff < 0) diff = -diff;
|
||||
last_delta = delta_p;
|
||||
return diff < 0.01;
|
||||
} else {
|
||||
return delta_p < 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
double last_delta;
|
||||
};
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
test_triangle(Graph*)
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||||
|
||||
Graph g;
|
||||
|
||||
vertex_descriptor u = add_vertex(g); put(vertex_index, g, u, 0);
|
||||
vertex_descriptor v = add_vertex(g); put(vertex_index, g, v, 1);
|
||||
vertex_descriptor w = add_vertex(g); put(vertex_index, g, w, 2);
|
||||
|
||||
edge_descriptor e1 = add_edge(u, v, g).first; put(edge_weight, g, e1, 1.0);
|
||||
edge_descriptor e2 = add_edge(v, w, g).first; put(edge_weight, g, e2, 1.0);
|
||||
edge_descriptor e3 = add_edge(w, u, g).first; put(edge_weight, g, e3, 1.0);
|
||||
|
||||
circle_graph_layout(g, get(vertex_position, g), 25.0);
|
||||
|
||||
bool ok = kamada_kawai_spring_layout(g,
|
||||
get(vertex_position, g),
|
||||
get(edge_weight, g),
|
||||
side_length(50.0));
|
||||
BOOST_TEST(ok);
|
||||
|
||||
std::cout << "Triangle layout.\n";
|
||||
print_graph_layout(g, get(vertex_position, g));
|
||||
}
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
test_cube(Graph*)
|
||||
{
|
||||
enum {A, B, C, D, E, F, G, H};
|
||||
simple_edge cube_edges[12] = {
|
||||
{A, E}, {A, B}, {A, D}, {B, F}, {B, C}, {C, D}, {C, G}, {D, H},
|
||||
{E, H}, {E, F}, {F, G}, {G, H}
|
||||
};
|
||||
|
||||
Graph g(&cube_edges[0], &cube_edges[12], 8);
|
||||
|
||||
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
|
||||
vertex_iterator vi, vi_end;
|
||||
int i = 0;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
|
||||
put(vertex_index, g, *vi, i++);
|
||||
|
||||
edge_iterator ei, ei_end;
|
||||
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
|
||||
put(edge_weight, g, *ei, 1.0);
|
||||
std::cerr << "(" << (char)(get(vertex_index, g, source(*ei, g)) + 'A')
|
||||
<< ", " << (char)(get(vertex_index, g, target(*ei, g)) + 'A')
|
||||
<< ") ";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
circle_graph_layout(g, get(vertex_position, g), 25.0);
|
||||
|
||||
bool ok = kamada_kawai_spring_layout(g,
|
||||
get(vertex_position, g),
|
||||
get(edge_weight, g),
|
||||
side_length(50.0),
|
||||
kamada_kawai_done());
|
||||
BOOST_TEST(ok);
|
||||
|
||||
std::cout << "Cube layout.\n";
|
||||
print_graph_layout(g, get(vertex_position, g));
|
||||
|
||||
dump_graph_layout("cube", g, get(vertex_position, g));
|
||||
}
|
||||
|
||||
template<typename Graph>
|
||||
void
|
||||
test_triangular(Graph*)
|
||||
{
|
||||
enum {A, B, C, D, E, F, G, H, I, J};
|
||||
simple_edge triangular_edges[18] = {
|
||||
{A, B}, {A, C}, {B, C}, {B, D}, {B, E}, {C, E}, {C, F}, {D, E}, {D, G},
|
||||
{D, H}, {E, F}, {E, H}, {E, I}, {F, I}, {F, J}, {G, H}, {H, I}, {I, J}
|
||||
};
|
||||
|
||||
Graph g(&triangular_edges[0], &triangular_edges[18], 10);
|
||||
|
||||
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
|
||||
vertex_iterator vi, vi_end;
|
||||
int i = 0;
|
||||
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
|
||||
put(vertex_index, g, *vi, i++);
|
||||
|
||||
edge_iterator ei, ei_end;
|
||||
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
|
||||
put(edge_weight, g, *ei, 1.0);
|
||||
std::cerr << "(" << (char)(get(vertex_index, g, source(*ei, g)) + 'A')
|
||||
<< ", " << (char)(get(vertex_index, g, target(*ei, g)) + 'A')
|
||||
<< ") ";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
circle_graph_layout(g, get(vertex_position, g), 25.0);
|
||||
|
||||
bool ok = kamada_kawai_spring_layout(g,
|
||||
get(vertex_position, g),
|
||||
get(edge_weight, g),
|
||||
side_length(50.0),
|
||||
kamada_kawai_done());
|
||||
BOOST_TEST(ok);
|
||||
|
||||
std::cout << "Triangular layout.\n";
|
||||
print_graph_layout(g, get(vertex_position, g));
|
||||
|
||||
dump_graph_layout("triangular", g, get(vertex_position, g));
|
||||
}
|
||||
|
||||
int test_main(int, char*[])
|
||||
{
|
||||
typedef adjacency_list<listS, listS, undirectedS,
|
||||
// Vertex properties
|
||||
property<vertex_index_t, int,
|
||||
property<vertex_position_t, point> >,
|
||||
// Edge properties
|
||||
property<edge_weight_t, double> > Graph;
|
||||
|
||||
test_circle_layout((Graph*)0, 5);
|
||||
test_cube((Graph*)0);
|
||||
test_triangular((Graph*)0);
|
||||
|
||||
return 0;
|
||||
}
|
||||