2
0
mirror of https://github.com/boostorg/graph.git synced 2026-01-19 04:12:11 +00:00

This commit was manufactured by cvs2svn to create tag

'merged_to_graph_devel'.

[SVN r24507]
This commit is contained in:
nobody
2004-08-16 14:12:16 +00:00
parent 487d1b3dc5
commit 0c3f9bb479
19 changed files with 2619 additions and 0 deletions

View 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 &#8212; 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>&lt;<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&gt;
  <span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph &amp; g, Done done,
                                         EdgeCentralityMap edge_centrality,
                                         VertexIndexMap vertex_index);
<span class="bold"><b>template</b></span>&lt;<span class="bold"><b>typename</b></span> MutableGraph, <span class="bold"><b>typename</b></span> Done, <span class="bold"><b>typename</b></span> EdgeCentralityMap&gt;
  <span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph &amp; g, Done done,
                                         EdgeCentralityMap edge_centrality);
<span class="bold"><b>template</b></span>&lt;<span class="bold"><b>typename</b></span> MutableGraph, <span class="bold"><b>typename</b></span> Done&gt;
  <span class="type"><span class="bold"><b>void</b></span></span> betweenness_centrality_clustering(MutableGraph &amp; 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 &copy 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>

View 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&lt;typename Graph, typename Param, typename Tag, typename Rest&gt;
void
brandes_betweenness_centrality(const Graph&amp; g,
const bgl_named_params&lt;Param,Tag,Rest&gt;&amp; params);
template&lt;typename Graph, typename CentralityMap&gt;
void
brandes_betweenness_centrality(const Graph&amp; g, CentralityMap centrality_map);
template&lt;typename Graph, typename CentralityMap, typename EdgeCentralityMap&gt;
void
brandes_betweenness_centrality(const Graph&amp; g, CentralityMap centrality_map,
EdgeCentralityMap edge_centrality);
<em>// non-named parameter versions</em>
template&lt;typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename IncomingMap, typename DistanceMap, typename DependencyMap,
typename PathCountMap, typename VertexIndexMap&gt;
void
brandes_betweenness_centrality(const Graph&amp; g, CentralityMap centrality_map,
EdgeCentralityMap edge_centrality,
IncomingMap incoming,
DistanceMap distance, DependencyMap dependency,
PathCountMap path_count,
VertexIndexMap vertex_index);
template&lt;typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename IncomingMap, typename DistanceMap, typename DependencyMap,
typename PathCountMap, typename VertexIndexMap, typename WeightMap&gt;
void
brandes_betweenness_centrality(const Graph&amp; 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&lt;typename Graph, typename CentralityMap&gt;
void
relative_betweenness_centrality(const Graph&amp; g, CentralityMap centrality_map);
template&lt;typename Graph, typename CentralityMap&gt;
typename property_traits&lt;CentralityMap&gt;::value_type
central_point_dominance(const Graph&amp; g, CentralityMap centrality_map);
</pre>
<p>This algorithm&nbsp;[<a href="bibliography.html#brandes01">54</a>]
computes the <em>betweenness centrality</em>&nbsp;[<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>&nbsp;[<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&amp; 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&lt;Edge&gt;</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 &copy 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
View 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 &#8212; 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>&lt;<span class="bold"><b>typename</b></span> VertexListGraph, <span class="bold"><b>typename</b></span> PositionMap, <span class="bold"><b>typename</b></span> Radius&gt;
  <span class="type"><span class="bold"><b>void</b></span></span> circle_graph_layout(<span class="bold"><b>const</b></span> VertexListGraph &amp; 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 &copy 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

BIN
doc/figs/sigma_st.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

BIN
doc/figs/sigma_stv.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

BIN
doc/figs/v_star.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 B

BIN
doc/figs/wheel_graph.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View 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 &#8212; 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>&lt;<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&gt;
  <span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph &amp; 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&lt; WeightMap &gt;::value_type spring_constant,
                                  VertexIndexMap index,
                                  DistanceMatrix distance,
                                  SpringStrengthMatrix spring_strength,
                                  PartialDerivativeMap partial_derivatives);
<span class="bold"><b>template</b></span>&lt;<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&gt;
  <span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph &amp; 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&lt; WeightMap &gt;::value_type spring_constant,
                                  VertexIndexMap index);
<span class="bold"><b>template</b></span>&lt;<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&gt;
  <span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph &amp; 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&lt; WeightMap &gt;::value_type spring_constant = typename property_traits&lt; WeightMap &gt;::value_type(1));
<span class="bold"><b>template</b></span>&lt;<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&gt;
  <span class="type"><span class="bold"><b>bool</b></span></span> kamada_kawai_spring_layout(<span class="bold"><b>const</b></span> Graph &amp; 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&nbsp;[<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 &copy 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
View 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 &#8212; 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>&lt;<span class="bold"><b>typename</b></span> T = double&gt;
<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 &amp; = 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>&lt;<span class="bold"><b>typename</b></span> Graph&gt;
    <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&lt; Graph &gt;::vertex_descriptor,
                    <span class="bold"><b>const</b></span> Graph &amp;, <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 &amp; 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>&lt;<span class="bold"><b>typename</b></span> Graph&gt;
  <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&lt; Graph &gt;::vertex_descriptor p,
                  <span class="bold"><b>const</b></span> Graph &amp; 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>

View 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;
}

View 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

View 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

View 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

View 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

View 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
View 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;
}