mirror of
https://github.com/boostorg/graph.git
synced 2026-01-19 04:12:11 +00:00
Merged Boost.Graph changes from trunk for 1.53
[SVN r82061]
This commit is contained in:
@@ -37,10 +37,28 @@ template <typename VertexListGraph,
|
||||
typename P, typename T, typename R>
|
||||
void
|
||||
astar_search_no_init
|
||||
(const IncidenceGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
<a href="AStarHeuristic.html">AStarHeuristic</a> h, const bgl_named_params<P, T, R>& params);
|
||||
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
typename P, typename T, typename R>
|
||||
void
|
||||
astar_search_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
<a href="AStarHeuristic.html">AStarHeuristic</a> h, const bgl_named_params<P, T, R>& params);
|
||||
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
typename P, typename T, typename R>
|
||||
void
|
||||
astar_search_no_init_tree
|
||||
(const IncidenceGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
<a href="AStarHeuristic.html">AStarHeuristic</a> h, const bgl_named_params<P, T, R>& params);
|
||||
|
||||
<i>// Non-named parameter interface</i>
|
||||
template <typename VertexListGraph, typename AStarHeuristic,
|
||||
typename <a href="AStarVisitor.html">AStarVisitor</a>, typename PredecessorMap,
|
||||
@@ -60,7 +78,23 @@ astar_search
|
||||
CompareFunction compare, CombineFunction combine,
|
||||
CostInf inf, CostZero zero);
|
||||
|
||||
<i>// Version that does not initialize property maps (used for implicit graphs)</i>
|
||||
template <typename VertexListGraph, typename AStarHeuristic,
|
||||
typename <a href="AStarVisitor.html">AStarVisitor</a>, typename PredecessorMap,
|
||||
typename CostMap, typename DistanceMap,
|
||||
typename WeightMap,
|
||||
typename <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">CompareFunction</a>, typename <a href="http://www.sgi.com/tech/stl/BinaryFunction.html">CombineFunction</a>,
|
||||
typename CostInf, typename CostZero>
|
||||
inline void
|
||||
astar_search_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, AStarVisitor vis,
|
||||
PredecessorMap predecessor, CostMap cost,
|
||||
DistanceMap distance, WeightMap weight,
|
||||
CompareFunction compare, CombineFunction combine,
|
||||
CostInf inf, CostZero zero);
|
||||
|
||||
<i>// Versions that do not initialize property maps (used for implicit graphs)</i>
|
||||
template <typename IncidenceGraph, typename AStarHeuristic,
|
||||
typename <a href="AStarVisitor.html">AStarVisitor</a>, typename PredecessorMap,
|
||||
typename CostMap, typename DistanceMap,
|
||||
@@ -82,6 +116,22 @@ astar_search_no_init
|
||||
<b>Note that the index_map and color parameters are swapped in
|
||||
astar_search_no_init() relative to astar_search(); the named parameter
|
||||
interfaces are not affected.</b>
|
||||
|
||||
template <typename IncidenceGraph, typename AStarHeuristic,
|
||||
typename <a href="AStarVisitor.html">AStarVisitor</a>, typename PredecessorMap,
|
||||
typename CostMap, typename DistanceMap,
|
||||
typename WeightMap,
|
||||
typename <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">CompareFunction</a>, typename <a href="http://www.sgi.com/tech/stl/BinaryFunction.html">CombineFunction</a>,
|
||||
typename CostInf, typename CostZero>
|
||||
inline void
|
||||
astar_search_no_init_tree
|
||||
(const IncidenceGraph &g,
|
||||
typename graph_traits<IncidenceGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, AStarVisitor vis,
|
||||
PredecessorMap predecessor, CostMap cost,
|
||||
DistanceMap distance, WeightMap weight,
|
||||
CompareFunction compare, CombineFunction combine,
|
||||
CostInf inf, CostZero zero);
|
||||
</PRE>
|
||||
|
||||
<P>
|
||||
@@ -125,7 +175,8 @@ useful for searching large state spaces -- in game-playing scenarios
|
||||
the entire graph. Implicit searches can be performed with this
|
||||
implementation of A* by creating special visitors that generate
|
||||
neighbors of newly-expanded vertices. Please note that
|
||||
<tt>astar_search_no_init()</tt> must be used for implicit graphs; the basic
|
||||
<tt>astar_search_no_init()</tt> or <tt>astar_search_no_init_tree()</tt> must be
|
||||
used for implicit graphs; the basic
|
||||
<tt>astar_search()</tt> function requires a graph that models
|
||||
the <a href="VertexListGraph.html">Vertex List Graph</a> concept. Both
|
||||
versions
|
||||
@@ -134,8 +185,9 @@ href="IncidenceGraph.html">Incidence Graph</a> concept.
|
||||
</P>
|
||||
|
||||
<P>
|
||||
This implementation of A* is based on an OPEN/CLOSED list formulation
|
||||
of the algorithm. Vertices on the OPEN list have been ``discovered''
|
||||
For the non-tree versions of the algorithm,
|
||||
this implementation of A* is based on an OPEN/CLOSED list formulation.
|
||||
Vertices on the OPEN list have been ``discovered''
|
||||
by the algorithm, but not ``expanded'' (we have not discovered their
|
||||
adjacent vertices). Vertices on the CLOSED list have been completely
|
||||
examined by our search (we have expanded them and added their children
|
||||
@@ -146,7 +198,11 @@ avoids ``cycles'' in the state space; the search will not become
|
||||
trapped by loops in the graph. The OPEN/CLOSED lists are implemented
|
||||
using BGL's vertex coloring mechanisms. Vertices in OPEN are colored
|
||||
gray, vertices in CLOSED are colored black, and undiscovered vertices
|
||||
are colored white.
|
||||
are colored white. For the versions of the algorithm whose names end in
|
||||
<tt>_tree</tt>, all vertices are assumed to always be white, leading to
|
||||
checking for repeated vertices being done using the distance map. If a dummy
|
||||
value is used for the distance map and the graph contains cycles, the algorithm
|
||||
will probably enter an infinite loop.
|
||||
</P>
|
||||
|
||||
<P>
|
||||
@@ -292,7 +348,8 @@ IN: <tt>weight_map(WeightMap w_map)</tt>
|
||||
IN: <tt>vertex_index_map(VertexIndexMap i_map)</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
|
||||
num_vertices(g))</tt>. This is necessary in non-tree versions of the
|
||||
algorithm 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/doc/ReadablePropertyMap.html"><tt>Readable
|
||||
@@ -338,7 +395,10 @@ UTIL/OUT: <tt>distance_map(DistanceMap d_map)</tt>
|
||||
<tt>combine</tt> function object and the zero object for the
|
||||
identity element. Also the distance value type must have a <a
|
||||
href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html"><tt>StrictWeakOrdering</tt></a>
|
||||
provided by the <tt>compare</tt> function object.<br>
|
||||
provided by the <tt>compare</tt> function object. A
|
||||
<tt>constant_writable_property_map</tt> returning the infinity value can be
|
||||
used for this parameter in tree versions of the algorithm when the graph does
|
||||
not contain a directed cycle.<br>
|
||||
|
||||
<b>Default:</b> <tt>shared_array_property_map</tt>
|
||||
with the same value type as the
|
||||
@@ -355,7 +415,10 @@ UTIL/OUT: <tt>rank_map(CostMap c_map)</tt>
|
||||
<tt>h</tt>) from the vertex to a goal. The type <tt>CostMap</tt>
|
||||
must be a model of <a
|
||||
href="../../property_map/doc/ReadWritePropertyMap.html"><tt>Read/Write
|
||||
Property Map</tt></a>. The vertex descriptor type of the graph
|
||||
Property Map</tt></a> in non-tree versions of the algorithm, and <a
|
||||
href="../../property_map/doc/WritablePropertyMap.html"><tt>Writable Property
|
||||
Map</tt></a> in tree versions of the algorithm. 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"><tt>Monoid</tt></a> formed with the
|
||||
@@ -364,7 +427,8 @@ UTIL/OUT: <tt>rank_map(CostMap c_map)</tt>
|
||||
href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html"><tt>StrictWeakOrdering</tt></a>
|
||||
provided by the <tt>compare</tt> function object. The value type
|
||||
for this map must be the same as the value type for the distance
|
||||
map.<br>
|
||||
map. In tree versions of the algorithm, <tt>null_property_map</tt> can be
|
||||
used for this parameter.<br>
|
||||
|
||||
<b>Default:</b> <tt>shared_array_property_map</tt>
|
||||
with the same value type as the
|
||||
@@ -375,7 +439,8 @@ UTIL/OUT: <tt>rank_map(CostMap c_map)</tt>
|
||||
UTIL/OUT: <tt>color_map(ColorMap c_map)</tt>
|
||||
<blockquote>
|
||||
|
||||
This is used during the execution of the algorithm to mark the
|
||||
This is used during the execution of non-tree versions of the algorithm to
|
||||
mark the
|
||||
vertices, indicating whether they are on the OPEN or CLOSED lists.
|
||||
The vertices start out white and become gray when they are inserted
|
||||
into the OPEN list. They then turn black when they are examined and
|
||||
|
||||
@@ -396,7 +396,7 @@ disregard the directionality in the function names. The example below
|
||||
demonstrates using the <TT>out_edges()</TT>, <TT>source()</TT>, and
|
||||
<TT>target()</TT> with an undirected graph. The source code for this
|
||||
example and the following one can be found in <a
|
||||
href="../example/undirected.cpp"><TT>examples/undirected.cpp</TT></a>.
|
||||
href="../example/undirected_adjacency_list.cpp"><TT>example/undirected_adjacency_list.cpp</TT></a>.
|
||||
|
||||
<P>
|
||||
<PRE>
|
||||
|
||||
@@ -158,7 +158,7 @@ href="../example/max_flow.cpp"><tt>example/max_flow.cpp</tt></a>.
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/graph/push_relabel_map_flow.hpp>
|
||||
#include <boost/graph/push_relabel_max_flow.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/read_dimacs.hpp>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ http://www.boost.org/LICENSE_1_0.txt)
|
||||
Authors: Tiago de Paula Peixoto -->
|
||||
<pre class="literal-block">
|
||||
void read_graphml(std::istream& in, MutableGraph& graph,
|
||||
dynamic_properties& dp);
|
||||
dynamic_properties& dp, size_t graph_index = 0);
|
||||
</pre>
|
||||
<p>The <tt class="docutils literal"><span class="pre">read_graphml</span></tt> function interprets a graph described using the
|
||||
<a class="reference external" href="http://graphml.graphdrawing.org/">GraphML</a> format and builds a BGL graph that captures that
|
||||
@@ -39,6 +39,10 @@ this object, using the GraphML attribute names as the property names,
|
||||
and with the appropriate C++ value type based on the GraphML attribute type
|
||||
definition. Graph properties are also set with the same
|
||||
<a class="reference external" href="../../property_map/doc/dynamic_property_map.html">dynamic_properties</a> object, where the key type is the type of the graph itself.</p>
|
||||
<p>If the file contains multiple graphs, the <tt class="docutils literal"><span class="pre">graph_index</span></tt> parameter controls
|
||||
which graph will be loaded. It defaults to <tt class="docutils literal"><span class="pre">0</span></tt>, meaning that the first graph
|
||||
in the file will be loaded. If <tt class="docutils literal"><span class="pre">graph_index</span></tt> is greater than or equal to the
|
||||
number of graphs in the file, an empty graph will be returned.</p>
|
||||
<dl class="docutils">
|
||||
<dt>Requirements:</dt>
|
||||
<dd><ul class="first last simple">
|
||||
@@ -156,7 +160,7 @@ graph.</li>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<hr class="footer" />
|
||||
Generated on: 2009-06-12 00:41 UTC.
|
||||
Generated on: 2012-11-12 22:25 UTC.
|
||||
Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
|
||||
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ __ ../../../index.htm
|
||||
::
|
||||
|
||||
void read_graphml(std::istream& in, MutableGraph& graph,
|
||||
dynamic_properties& dp);
|
||||
dynamic_properties& dp, size_t graph_index = 0);
|
||||
|
||||
|
||||
The ``read_graphml`` function interprets a graph described using the
|
||||
@@ -42,6 +42,11 @@ and with the appropriate C++ value type based on the GraphML attribute type
|
||||
definition. Graph properties are also set with the same
|
||||
dynamic_properties_ object, where the key type is the type of the graph itself.
|
||||
|
||||
If the file contains multiple graphs, the ``graph_index`` parameter controls
|
||||
which graph will be loaded. It defaults to ``0``, meaning that the first graph
|
||||
in the file will be loaded. If ``graph_index`` is greater than or equal to the
|
||||
number of graphs in the file, an empty graph will be returned.
|
||||
|
||||
Requirements:
|
||||
- The type of the graph must model the `Mutable Graph`_ concept.
|
||||
- The type of the iterator must model the `Multi-Pass Iterator`_
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
small_world_iterator();
|
||||
small_world_iterator(RandomGenerator& gen, vertices_size_type n,
|
||||
vertices_size_type k, double probability,
|
||||
vertices_size_type k, double probability = 0.,
|
||||
bool allow_self_loops = false);
|
||||
// Iterator operations
|
||||
reference operator*() const;
|
||||
@@ -82,7 +82,7 @@ Constructs a past-the-end iterator.
|
||||
|
||||
<pre>
|
||||
small_world_iterator(RandomGenerator& gen, vertices_size_type n,
|
||||
vertices_size_type k, double probability,
|
||||
vertices_size_type k, double probability = 0.,
|
||||
bool allow_self_loops = false);
|
||||
</pre>
|
||||
<blockquote>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
href="./johnson_all_pairs_shortest.html"><tt>johnson_all_pairs_shortest_paths</tt></A>
|
||||
<li><a href="floyd_warshall_shortest.html"><tt>floyd_warshall_all_pairs_shortest_paths</tt></a></li>
|
||||
<li><a href="r_c_shortest_paths.html"><tt>r_c_shortest_paths</tt> - resource-constrained shortest paths</a></li>
|
||||
<li><a href="astar_search.html"><tt>astar_search</tt></a></li>
|
||||
<li><a href="astar_search.html"><tt>astar_search</tt> (A* search algorithm)</a></li>
|
||||
</OL>
|
||||
<LI>Minimum Spanning Tree Algorithms
|
||||
<OL>
|
||||
@@ -240,6 +240,7 @@
|
||||
<li>Graph Structure Comparisons
|
||||
<ol>
|
||||
<LI><A href="isomorphism.html"><tt>isomorphism</tt></A>
|
||||
<LI><A href="vf2_sub_graph_iso.html"><tt>vf2_sub_graph_iso</tt> (VF2 subgraph isomorphism algorithm)</A>
|
||||
<li><a href="mcgregor_common_subgraphs.html"><tt>mcgregor_common_subgraphs</tt></a></li>
|
||||
</ol>
|
||||
|
||||
|
||||
517
doc/vf2_sub_graph_iso.html
Executable file
517
doc/vf2_sub_graph_iso.html
Executable file
@@ -0,0 +1,517 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!--
|
||||
Copyright (C) Flavio De Lorenzi 2012
|
||||
|
||||
Distributed under 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)
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-15">
|
||||
<title>Boost Graph Library: VF2 (Sub)Graph Isomorphism</title>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
body {
|
||||
color: black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #551A8B;
|
||||
}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p><img src="../../../boost.png" alt="C++ Boost" width="277" height="86"></p>
|
||||
<h1>
|
||||
<tt>vf2_subgraph_iso</tt>
|
||||
</h1>
|
||||
<pre>
|
||||
<em class="comment">// All defaults interface</em>
|
||||
template <typename GraphSmall,
|
||||
typename GraphLarge,
|
||||
typename SubGraphIsoMapCallback>
|
||||
bool vf2_subgraph_iso(const GraphSmall& graph_small,
|
||||
const GraphLarge& graph_large,
|
||||
SubGraphIsoMapCallback user_callback)
|
||||
|
||||
|
||||
<em class="comment">// Named parameter version</em>
|
||||
template <typename GraphSmall,
|
||||
typename GraphLarge,
|
||||
typename VertexOrderSmall,
|
||||
typename SubGraphIsoMapCallback,
|
||||
typename Param,
|
||||
typename Tag,
|
||||
typename Rest>
|
||||
bool vf2_subgraph_iso(const GraphSmall& graph_small,
|
||||
const GraphLarge& graph_large,
|
||||
SubGraphIsoMapCallback user_callback,
|
||||
const VertexOrderSmall& vertex_order_small,
|
||||
const bgl_named_params<Param, Tag, Rest>& params)
|
||||
|
||||
|
||||
<em class="comment">// Non-named parameter version</em>
|
||||
template <typename GraphSmall,
|
||||
typename GraphLarge,
|
||||
typename <a href="../../property_map/doc/ReadablePropertyMap.html">IndexMapSmall</a>,
|
||||
typename <a href="../../property_map/doc/ReadablePropertyMap.html">IndexMapLarge</a>,
|
||||
typename VertexOrderSmall,
|
||||
typename <a href="http://www.sgi.com/tech/stl/BinaryFunction.html">EdgeEquivalencePredicate</a>,
|
||||
typename <a href="http://www.sgi.com/tech/stl/BinaryFunction.html">VertexEquivalencePredicate</a>,
|
||||
typename SubGraphIsoMapCallback>
|
||||
bool vf2_subgraph_iso(const GraphSmall& graph_small,
|
||||
const GraphLarge& graph_large,
|
||||
SubGraphIsoMapCallback user_callback,
|
||||
IndexMapSmall index_map_small,
|
||||
IndexMapLarge index_map_large,
|
||||
const VertexOrderSmall& vertex_order_small,
|
||||
EdgeEquivalencePredicate edge_comp,
|
||||
VertexEquivalencePredicate vertex_comp)
|
||||
</pre>
|
||||
<p>
|
||||
An isomorphism between two graphs <em>G<sub>1</sub>=(V<sub>1</sub>, E<sub>1</sub>)</em>
|
||||
and <em>G<sub>2</sub>=(V<sub>2</sub>, E<sub>2</sub>)</em> is a
|
||||
bijective mapping <em>M</em> of the vertices of one graph to vertices of the other
|
||||
graph that preserves the edge structure of the graphs. <em>M</em> is said to be a
|
||||
graph-subgraph isomorphism if and only if <em>M</em> is an isomorphism between
|
||||
<em>G<sub>1</sub></em> and a subgraph of <em>G<sub>2</sub></em>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This function finds all graph-subgraph isomorphism mappings between
|
||||
graphs <tt>graph_small</tt> and <tt>graph_large</tt> and outputs them to
|
||||
<tt>user_callback</tt>. It continues until <tt>user_callback</tt>
|
||||
returns true or the search space has been fully explored. <tt>vf2_subgraph_iso</tt>
|
||||
returns true if a graph-subgraph isomorphism exists and false otherwise.
|
||||
<tt>EdgeEquivalencePredicate</tt> and
|
||||
<tt>VertexEquivalencePredicate</tt> predicates are used to test whether
|
||||
edges and vertices are equivalent. To use property maps for equivalence,
|
||||
see
|
||||
<tt><a href="./mcgregor_common_subgraphs.html#make_property_map_equivalent">
|
||||
make_property_map_equivalent</a></tt>
|
||||
function. By default <tt><a href="./mcgregor_common_subgraphs.html#always_equivalent">
|
||||
always_equivalent</a></tt> is used, which returns
|
||||
true for any pair of vertices or edges.
|
||||
</p>
|
||||
<p>
|
||||
The current implementation is based on the <em>VF2</em> algorithm,
|
||||
introduced by Cordella et al. An in-depth description of the algorithm is
|
||||
given in [<a href="#cordella2001">1</a>] and [<a href="#cordella2004">2</a>]
|
||||
and references therein. The original code by P. Foggia and collaborators can
|
||||
be found at [<a href="#foggia_etal">3</a>]. In brief, the process of
|
||||
finding a mapping between the two graphs <em>G<sub>1</sub></em> and
|
||||
<em>G<sub>2</sub></em> determines the isomorphism mapping <em>M</em>,
|
||||
which associates vertices <em>G<sub>1</sub></em> with vertices of
|
||||
<em>G<sub>2</sub></em> and vice versa. It can be described by means of a
|
||||
state space representation which is created by the algorithm
|
||||
while exploring the search graph in depth-first fashion.
|
||||
Each state <em>s</em> of the matching process
|
||||
can be associated with a partial mapping <em>M(s)</em>. At each level,
|
||||
the algorithm computes the set of the vertex pairs that are candidates to
|
||||
be added to the current state <em>s</em>. If a pair of vertices
|
||||
(<em>v, w</em>) is feasible, the mapping is extended and the associated
|
||||
successor state <em>s'</em> is computed.
|
||||
The whole procedure is then repeated for state <em>s'</em>.
|
||||
</p>
|
||||
|
||||
<h3>Where Defined</h3>
|
||||
<p>
|
||||
<a href="../../../boost/graph/vf2_sub_graph_iso.hpp">
|
||||
<tt>boost/graph/vf2_sub_graph_iso.hpp</tt></a><br>
|
||||
All functions are defined in the boost namespace.
|
||||
</p>
|
||||
|
||||
<h3>Parameters</h3>
|
||||
|
||||
<p>IN: <tt>const GraphSmall& graph_small</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
The (first) smaller graph (fewer vertices) of the pair to be tested for
|
||||
isomorphism. The type <tt>GraphSmall</tt> must be a
|
||||
model of
|
||||
<a href="./VertexListGraph.html">Vertex List Graph</a>,
|
||||
<a href="./EdgeListGraph.html">Edge List Graph</a>,
|
||||
<a href="./BidirectionalGraph.html">Bidirectional Graph</a> and
|
||||
<a href="./AdjacencyMatrix.html">Adjacency Matrix</a>.
|
||||
The edge descriptors <tt>graph_traits<GraphSmall>::edge_descriptor</tt>
|
||||
must be <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">
|
||||
LessThan Comparable</a>, cf. also the remark <a href="#notes">below</a>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>IN: <tt>const GraphLarge& graph_large</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
The (second) larger graph to be tested.
|
||||
Type <tt>GraphLarge</tt> must be a model of
|
||||
<a href="./VertexListGraph.html">Vertex List Graph</a>,
|
||||
<a href="./EdgeListGraph.html">Edge List Graph</a>,
|
||||
<a href="./BidirectionalGraph.html">Bidirectional Graph</a> and
|
||||
<a href="./AdjacencyMatrix.html">Adjacency Matrix</a>.
|
||||
The edge descriptors <tt>graph_traits<GraphLarge>::edge_descriptor</tt>
|
||||
must be <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">
|
||||
LessThan Comparable</a>, cf. also the remark <a href="#notes">below</a>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>OUT: <tt>SubGraphIsoMapCallback user_callback</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
A function object to be called when a graph-subgraph isomorphism has been discovered. The
|
||||
<tt>operator()</tt> must have following form:
|
||||
</p>
|
||||
<pre>
|
||||
template <typename CorrespondenceMap1To2,
|
||||
typename CorrespondenceMap2To1>
|
||||
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1 g) const
|
||||
</pre>
|
||||
<p>
|
||||
Both the <tt>CorrespondenceMap1To2</tt>
|
||||
and <tt>CorresondenceMap2To1</tt> types are models
|
||||
of <a href="../../property_map/doc/ReadablePropertyMap.html">Readable
|
||||
Property Map</a> and map equivalent vertices across the two
|
||||
graphs given to <tt>vf2_subgraph_iso</tt> (or <tt>vf2_graph_iso</tt>). For
|
||||
instance, if <tt>v</tt> is
|
||||
from <tt>graph_small</tt>, <tt>w</tt> is from <tt>graph_large</tt>,
|
||||
and the vertices can be considered equivalent,
|
||||
then <tt>get(f, v)</tt> will be <tt>w</tt> and <tt>get(g, w)</tt>
|
||||
will be <tt>v</tt>. If any vertex, say <tt>v</tt> in <tt>graph_small</tt>,
|
||||
does not match a vertex in <tt>graph_large</tt> ,
|
||||
then <tt>get(f, v)</tt> will be <tt>graph_traits<GraphLarge>::null_vertex()</tt>.
|
||||
Likewise for any unmatched vertices from <tt>graph_large</tt>,
|
||||
<tt>get(g, w)</tt> will be <tt>graph_traits<GraphSmall>::null_vertex()</tt>.
|
||||
|
||||
Returning false from the callback will abort the search immediately. Otherwise,
|
||||
the entire search space will be explored. A "default" print callback
|
||||
is provided as a <a href="#vf2_callback">utility function</a>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>IN: <tt>const VertexOrderSmall& vertex_order_small</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
The ordered vertices of the smaller (first) graph <tt>graph_small</tt>.
|
||||
During the matching process the vertices are examined in the order given by
|
||||
<tt>vertex_order_small</tt>. Type <tt>VertexOrderSmall</tt> must be a model
|
||||
of <a href="http://www.sgi.com/tech/stl/Container.html">ContainerConcept</a>
|
||||
with value type
|
||||
<tt>graph_traits<GraphSmall>::vertex_descriptor</tt>.
|
||||
<br>
|
||||
<b>Default</b> The vertices are ordered by multiplicity of
|
||||
in/out degrees.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<h3>Named Parameters</h3>
|
||||
|
||||
<p>IN: <tt>vertex_index1(IndexMapSmall index_map_small)</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
This maps each vertex to an integer in the range <tt>[0, num_vertices(graph_small))</tt>.
|
||||
Type <tt>IndexMapSmall</tt> must be a model of
|
||||
<a href="../../property_map/doc/ReadablePropertyMap.html">Readable Property Map</a>.
|
||||
<br>
|
||||
<b>Default:</b> <tt>get(vertex_index, graph_small)</tt>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>IN: <tt>vertex_index2(IndexMapLarge index_map_large)</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
This maps each vertex to an integer in the range <tt>[0, num_vertices(graph_large))</tt>.
|
||||
Type <tt>IndexMapLarge</tt> must be a model of
|
||||
<a href="../../property_map/doc/ReadablePropertyMap.html">Readable Property Map</a>.
|
||||
<br>
|
||||
<b>Default:</b> <tt>get(vertex_index, graph_large)</tt>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>IN: <tt>edges_equivalent(EdgeEquivalencePredicate edge_comp)</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
This function object is used to determine if edges between the two graphs
|
||||
<tt>graph_small</tt> and <tt>graph_large</tt> are equivalent.
|
||||
Type <tt>EdgeEquivalencePredicate</tt> must be a model of
|
||||
<a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">Binary
|
||||
Predicate</a> and have argument types of
|
||||
<tt>graph_traits<GraphSmall>::edge_descriptor</tt> and
|
||||
<tt>graph_traits<GraphLarge>::edge_descriptor</tt>.
|
||||
The edge descriptors must be <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">
|
||||
LessThan Comparable</a>. A return value of true indicates that the edges are equivalent.
|
||||
<br>
|
||||
<b>Default:</b> <tt><a href="./mcgregor_common_subgraphs.html#always_equivalent">
|
||||
always_equivalent</a></tt>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>IN: <tt>vertices_equivalent(VertexEquivalencePredicate vertex_comp)</tt></p>
|
||||
<blockquote>
|
||||
<p>
|
||||
This function object is used to determine if vertices between the two graphs
|
||||
<tt>graph_small</tt> and <tt>graph_large</tt> are equivalent.
|
||||
Type <tt>VertexEquivalencePredicate</tt> must be a model of
|
||||
<a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">Binary Predicate</a>
|
||||
and have argument types of
|
||||
<tt>graph_traits<GraphSmall>::vertex_descriptor</tt> and
|
||||
<tt>graph_traits<GraphLarge>::vertex_descriptor</tt>. A return value of true
|
||||
indicates that the vertices are equivalent.
|
||||
<br>
|
||||
<b>Default:</b> <tt><a href="./mcgregor_common_subgraphs.html#always_equivalent">
|
||||
always_equivalent</a></tt>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<h3>Related Functions</h3>
|
||||
<p>
|
||||
Non-named parameter, named-parameter and all default parameter versions of
|
||||
function
|
||||
</p>
|
||||
<p><tt>vf2_graph_iso(...)</tt></p>
|
||||
<p>
|
||||
for isomorphism testing take the same parameters as the corresponding
|
||||
functions <tt>vf2_subgraph_iso</tt> for subgraph isomorphism testing.
|
||||
The algorithm finds all isomorphism mappings between graphs
|
||||
<tt>graph1</tt> and <tt>graph2</tt> and outputs them to
|
||||
<tt>user_callback</tt>. It continues until <tt>user_callback</tt>
|
||||
returns true or the search space has been fully explored. As before,
|
||||
<tt>EdgeEquivalencePredicate</tt> and
|
||||
<tt>VertexEquivalencePredicate</tt> predicates are used to test
|
||||
whether edges and vertices are equivalent. By default
|
||||
<tt>always_equivalent</tt> is used.
|
||||
</p>
|
||||
|
||||
<h3>Utility Functions and Structs</h3>
|
||||
<p>
|
||||
<tt id="vf2_callback">
|
||||
template<typename Graph1,
|
||||
typename Graph2>
|
||||
struct vf2_print_callback
|
||||
</tt>
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
Callback function object that prints out the correspondences between vertices
|
||||
of <tt>Graph1</tt> and <tt>Graph2</tt>. The constructor takes
|
||||
the two graphs <em>G<sub>1</sub></em> and <em>G<sub>2</sub></em>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>
|
||||
template<typename Graph>
|
||||
std::vector<typename graph_traits<Graph>::vertex_descriptor>
|
||||
vertex_order_by_mult(const Graph& graph)
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
Returns a vector containing the vertices of a graph, sorted
|
||||
by multiplicity of in/out degrees.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>
|
||||
<em class="comment">// Variant of verify_subgraph_iso with all default parameters</em>
|
||||
template<typename Graph1,
|
||||
typename Graph2,
|
||||
typename CorresponenceMap1To2>
|
||||
inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2,
|
||||
const CorresponenceMap1To2 f)
|
||||
|
||||
|
||||
<em class="comment">// Verifies a graph (sub)graph isomorphism map</em>
|
||||
template<typename Graph1,
|
||||
typename Graph2,
|
||||
typename CorresponenceMap1To2,
|
||||
typename EdgeEquivalencePredicate,
|
||||
typename VertexEquivalencePredicate>
|
||||
inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2,
|
||||
const CorresponenceMap1To2 f,
|
||||
EdgeEquivalencePredicate edge_comp,
|
||||
VertexEquivalencePredicate vertex_comp)
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
This function can be used to verify a (sub)graph isomorphism
|
||||
mapping <em>f</em>. The parameters are analogous to
|
||||
function <tt>vf2_subgraph_iso</tt> (<tt>vf2_graph_iso</tt>).
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h3>Complexity</h3>
|
||||
<p>
|
||||
Spatial and time complexity are given in [<a href="#cordella2004">2</a>]. The spatial
|
||||
complexity of VF2 is of order <em>O(V)</em>, where V is the (maximum) number
|
||||
of vertices of the two graphs. Time complexity is <em>O(V<sup>2</sup>)</em> in the best case and
|
||||
<em>O(V!·V)</em> in the worst case.
|
||||
</p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
<h4>Example 1</h4>
|
||||
<p>
|
||||
In the example below, a small graph <tt>graph1</tt> and a larger graph
|
||||
<tt>graph2</tt> are defined. Here small and large refers to the number of
|
||||
vertices of the graphs. <tt>vf2_subgraph_iso</tt> computes all the
|
||||
subgraph isomorphism mappings between the two graphs and outputs them
|
||||
via <tt>callback</tt>.
|
||||
</p>
|
||||
<pre>
|
||||
typedef adjacency_list<setS, vecS, bidirectionalS> graph_type;
|
||||
|
||||
<em class="comment">// Build graph1</em>
|
||||
int num_vertices1 = 8; graph_type graph1(num_vertices1);
|
||||
add_edge(0, 6, graph1); add_edge(0, 7, graph1);
|
||||
add_edge(1, 5, graph1); add_edge(1, 7, graph1);
|
||||
add_edge(2, 4, graph1); add_edge(2, 5, graph1); add_edge(2, 6, graph1);
|
||||
add_edge(3, 4, graph1);
|
||||
|
||||
<em class="comment">// Build graph2</em>
|
||||
int num_vertices2 = 9; graph_type graph2(num_vertices2);
|
||||
add_edge(0, 6, graph2); add_edge(0, 8, graph2);
|
||||
add_edge(1, 5, graph2); add_edge(1, 7, graph2);
|
||||
add_edge(2, 4, graph2); add_edge(2, 7, graph2); add_edge(2, 8, graph2);
|
||||
add_edge(3, 4, graph2); add_edge(3, 5, graph2); add_edge(3, 6, graph2);
|
||||
<em class="comment">
|
||||
// Create callback to print mappings</em>
|
||||
vf2_print_callback<graph_type, graph_type> callback(graph1, graph2);
|
||||
|
||||
<em class="comment">
|
||||
// Print out all subgraph isomorphism mappings between graph1 and graph2.
|
||||
// Vertices and edges are assumed to be always equivalent.</em>
|
||||
vf2_subgraph_iso(graph1, graph2, callback);
|
||||
</pre>
|
||||
<p>
|
||||
The complete example can be found under
|
||||
<a href="../example/vf2_sub_graph_iso_example.cpp"><tt>examples/vf2_sub_graph_iso_example.cpp</tt></a>.
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<h4>Example 2</h4>
|
||||
<p>
|
||||
In this example, the subgraph isomorphism mappings between multi-graphs are computed. The vertices
|
||||
and edges of the multi-graphs are distinguished using property maps.
|
||||
</p>
|
||||
<pre>
|
||||
<em class="comment">// Define edge and vertex properties</em>
|
||||
typedef property<edge_name_t, char> edge_property;
|
||||
typedef property<vertex_name_t, char, property<vertex_index_t, int> > vertex_property;
|
||||
|
||||
<em class="comment">// Using a vecS graphs => the index maps are implicit.</em>
|
||||
typedef adjacency_list<vecS, vecS, bidirectionalS, vertex_property, edge_property> graph_type;
|
||||
|
||||
<em class="comment">// Create graph1</em>
|
||||
graph_type graph1;
|
||||
<em class="comment">// Add vertices... </em>
|
||||
add_vertex(vertex_property('a'), graph1);
|
||||
...
|
||||
<em class="comment">//... and edges </em>
|
||||
add_edge(0, 1, edge_property('b'), graph1);
|
||||
add_edge(0, 1, edge_property('b'), graph1);
|
||||
...
|
||||
|
||||
<em class="comment">// Create graph2 </em>
|
||||
graph_type graph2;
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
...
|
||||
add_edge(0, 1, edge_property('a'), graph2);
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To distinguish vertices and edges with property maps, binary predicates are created using the
|
||||
<tt><a href="./mcgregor_common_subgraphs.html#make_property_map_equivalent">
|
||||
make_property_map_equivalent</a></tt> function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<em class="comment">// Create the vertex binary predicate</em>
|
||||
typedef property_map<graph_type, vertex_name_t>::type vertex_name_map_t;
|
||||
typedef property_map_equivalent<vertex_name_map_t, vertex_name_map_t> vertex_comp_t;
|
||||
vertex_comp_t vertex_comp =
|
||||
make_property_map_equivalent(get(vertex_name, graph1), get(vertex_name, graph2));
|
||||
|
||||
<em class="comment">// Create the vertex binary predicate</em>
|
||||
typedef property_map<graph_type, edge_name_t>::type edge_name_map_t;
|
||||
typedef property_map_equivalent<edge_name_map_t, edge_name_map_t> edge_comp_t;
|
||||
edge_comp_t edge_comp =
|
||||
make_property_map_equivalent(get(edge_name, graph1), get(edge_name, graph2));
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Finally, a callback function object is created and the subgraph isomorphism mappings are
|
||||
computed:
|
||||
</p>
|
||||
<pre>
|
||||
<em class="comment">// Create callback</em>
|
||||
vf2_print_callback<graph_type, graph_type> callback(graph1, graph2);
|
||||
|
||||
<em class="comment">
|
||||
// Print out all subgraph isomorphism mappings between graph1 and graph2.
|
||||
// Function vertex_order_by_mult is used to compute the order of
|
||||
// vertices of graph1. This is the order in which the vertices are examined
|
||||
// during the matching process.</em>
|
||||
vf2_subgraph_iso(graph1, graph2, callback, vertex_order_by_mult(graph1),
|
||||
edges_equivalent(edge_comp).vertices_equivalent(vertex_comp));
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For the complete example, see
|
||||
<a href="../example/vf2_sub_graph_iso_multi_example.cpp">
|
||||
<tt>examples/vf2_sub_graph_iso_multi_example.cpp</tt></a>.
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<h3 id="notes">Notes</h3>
|
||||
<p>
|
||||
If the <tt>EdgeList</tt> allows for parallel edges, e.g. <tt>vecS</tt>, the
|
||||
algorithm does some bookkeeping of already identified edges. Matched edges
|
||||
are temporarily stored using <tt>std::set</tt> as container, requiring that
|
||||
<tt>edge_descriptor</tt> are <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">
|
||||
LessThan Comparable</a>. In contrast, if instead you enforce the absence of
|
||||
parallel edges, e.g. by using <tt>setS</tt>, the lookup function falls back
|
||||
to <tt>edge()</tt> without performing any bookkeeping.
|
||||
</p>
|
||||
|
||||
<h3>Bibliography</h3>
|
||||
|
||||
<dl>
|
||||
<dt><a name="cordella2001">1</a></dt>
|
||||
<dd>
|
||||
L. P. Cordella, P. Foggia, C. Sansone, and M. Vento.
|
||||
<br><em>An improved algorithm for matching large graphs</em>.
|
||||
<br>In: 3rd IAPR-TC15 Workshop on Graph-based Representations in Pattern Recognition, pp. 149-159, Cuen, 2001.
|
||||
<p></p>
|
||||
</dd>
|
||||
<dt><a name="cordella2004">2</a></dt>
|
||||
<dd>
|
||||
L. P. Cordella, P. Foggia, C. Sansone, and M. Vento.
|
||||
<br><em>A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs</em>.
|
||||
<br>IEEE Trans. Pattern Anal. Mach. Intell., vol. 26, no. 10, pp. 1367-1372, 2004.
|
||||
<p></p>
|
||||
</dd>
|
||||
<dt><a name="foggia_etal">3</a></dt>
|
||||
<dd>
|
||||
<a href="http://www.cs.sunysb.edu/~algorith/implement/vflib/implement.shtml">
|
||||
<tt>http://www.cs.sunysb.edu/~algorith/implement/vflib/implement.shtml</tt></a>
|
||||
<p></p>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<p>
|
||||
Copyright © 2012, Flavio De Lorenzi
|
||||
(<a href="mailto:fdlorenzi@gmail.com">fdlorenzi@gmail.com</a>)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -30,6 +30,7 @@ exe ospf-example : ospf-example.cpp ../build//boost_graph ;
|
||||
# exe cc-internet : cc-internet.cpp ../build//boost_graph ;
|
||||
exe implicit_graph : implicit_graph.cpp ;
|
||||
exe astar_maze : astar_maze.cpp ;
|
||||
exe astar-cities : astar-cities.cpp ;
|
||||
exe stoer_wagner : stoer_wagner.cpp ;
|
||||
exe bfs-example : bfs-example.cpp ;
|
||||
exe bfs-example2 : bfs-example2.cpp ;
|
||||
@@ -43,3 +44,6 @@ exe strong_components : strong_components.cpp ../build//boost_graph ;
|
||||
exe strong-components : strong-components.cpp ;
|
||||
exe subgraph : subgraph.cpp ;
|
||||
exe subgraph_properties : subgraph_properties.cpp ;
|
||||
exe vf2_sub_graph_iso_example : vf2_sub_graph_iso_example.cpp ;
|
||||
exe vf2_sub_graph_iso_multi_example : vf2_sub_graph_iso_multi_example.cpp ;
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ int main(int argc, char **argv)
|
||||
vector<cost> d(num_vertices(g));
|
||||
try {
|
||||
// call astar named parameter interface
|
||||
astar_search
|
||||
astar_search_tree
|
||||
(g, start,
|
||||
distance_heuristic<mygraph_t, cost, location*>
|
||||
(locations, goal),
|
||||
|
||||
@@ -26,12 +26,12 @@ undirected_graph_demo1()
|
||||
add_edge(zero, two, undigraph);
|
||||
add_edge(one, two, undigraph);
|
||||
|
||||
std::cout << "out_edges(0): ";
|
||||
std::cout << "out_edges(0):";
|
||||
for (boost::tie(out, out_end) = out_edges(zero, undigraph); out != out_end; ++out)
|
||||
std::cout << *out;
|
||||
std::cout << std::endl << "in_edges(0): ";
|
||||
std::cout << ' ' << *out;
|
||||
std::cout << std::endl << "in_edges(0):";
|
||||
for (boost::tie(in, in_end) = in_edges(zero, undigraph); in != in_end; ++in)
|
||||
std::cout << *in;
|
||||
std::cout << ' ' << *in;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,14 @@ undirected_graph_demo2()
|
||||
#endif
|
||||
std::cout << "weight[(u,v)] = " << get(weight, e1) << std::endl;
|
||||
std::cout << "weight[(v,u)] = " << get(weight, e2) << std::endl;
|
||||
|
||||
std::cout << "the edges incident to v: ";
|
||||
typename boost::graph_traits<UndirectedGraph>::out_edge_iterator e, e_end;
|
||||
typename boost::graph_traits<UndirectedGraph>::vertex_descriptor
|
||||
s = vertex(0, undigraph);
|
||||
for (boost::tie(e, e_end) = out_edges(s, undigraph); e != e_end; ++e)
|
||||
std::cout << "(" << source(*e, undigraph)
|
||||
<< "," << target(*e, undigraph) << ")" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +111,7 @@ main()
|
||||
typedef adjacency_list < vecS, vecS, directedS,
|
||||
no_property, Weight > DirectedGraph;
|
||||
undirected_graph_demo1 < UndirectedGraph > ();
|
||||
undirected_graph_demo2 < UndirectedGraph > ();
|
||||
directed_graph_demo < DirectedGraph > ();
|
||||
undirected_graph_demo2 < UndirectedGraph > ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
out_edges(0): (0,1) (0,2)
|
||||
in_edges(0): (1,0) (2,0)
|
||||
in a directed graph is (u,v) == (v,u) ? 0
|
||||
weight[(u,v)] = 1.2
|
||||
weight[(v,u)] = 2.4
|
||||
|
||||
40
example/vf2_sub_graph_iso_example.cpp
Executable file
40
example/vf2_sub_graph_iso_example.cpp
Executable file
@@ -0,0 +1,40 @@
|
||||
//=======================================================================
|
||||
// Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
|
||||
//
|
||||
// Distributed under 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)
|
||||
//=======================================================================
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/vf2_sub_graph_iso.hpp>
|
||||
using namespace boost;
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
typedef adjacency_list<setS, vecS, bidirectionalS> graph_type;
|
||||
|
||||
// Build graph1
|
||||
int num_vertices1 = 8; graph_type graph1(num_vertices1);
|
||||
add_edge(0, 6, graph1); add_edge(0, 7, graph1);
|
||||
add_edge(1, 5, graph1); add_edge(1, 7, graph1);
|
||||
add_edge(2, 4, graph1); add_edge(2, 5, graph1); add_edge(2, 6, graph1);
|
||||
add_edge(3, 4, graph1);
|
||||
|
||||
// Build graph2
|
||||
int num_vertices2 = 9; graph_type graph2(num_vertices2);
|
||||
add_edge(0, 6, graph2); add_edge(0, 8, graph2);
|
||||
add_edge(1, 5, graph2); add_edge(1, 7, graph2);
|
||||
add_edge(2, 4, graph2); add_edge(2, 7, graph2); add_edge(2, 8, graph2);
|
||||
add_edge(3, 4, graph2); add_edge(3, 5, graph2); add_edge(3, 6, graph2);
|
||||
|
||||
// Create callback to print mappings
|
||||
vf2_print_callback<graph_type, graph_type> callback(graph1, graph2);
|
||||
|
||||
// Print out all subgraph isomorphism mappings between graph1 and graph2.
|
||||
// Vertices and edges are assumed to be always equivalent.
|
||||
vf2_subgraph_iso(graph1, graph2, callback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
example/vf2_sub_graph_iso_multi_example.cpp
Executable file
89
example/vf2_sub_graph_iso_multi_example.cpp
Executable file
@@ -0,0 +1,89 @@
|
||||
//=======================================================================
|
||||
// Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
|
||||
//
|
||||
// Distributed under 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)
|
||||
//=======================================================================
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/vf2_sub_graph_iso.hpp>
|
||||
using namespace boost;
|
||||
|
||||
int main() {
|
||||
typedef property<edge_name_t, char> edge_property;
|
||||
typedef property<vertex_name_t, char, property<vertex_index_t, int> > vertex_property;
|
||||
|
||||
// Using a vecS graphs => the index maps are implicit.
|
||||
typedef adjacency_list<vecS, vecS, bidirectionalS, vertex_property, edge_property> graph_type;
|
||||
|
||||
// Build graph1
|
||||
graph_type graph1;
|
||||
|
||||
add_vertex(vertex_property('a'), graph1);
|
||||
add_vertex(vertex_property('a'), graph1);
|
||||
add_vertex(vertex_property('a'), graph1);
|
||||
|
||||
add_edge(0, 1, edge_property('b'), graph1);
|
||||
add_edge(0, 1, edge_property('b'), graph1);
|
||||
add_edge(0, 1, edge_property('d'), graph1);
|
||||
|
||||
add_edge(1, 2, edge_property('s'), graph1);
|
||||
|
||||
add_edge(2, 2, edge_property('l'), graph1);
|
||||
add_edge(2, 2, edge_property('l'), graph1);
|
||||
|
||||
// Build graph2
|
||||
graph_type graph2;
|
||||
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
add_vertex(vertex_property('a'), graph2);
|
||||
|
||||
add_edge(0, 1, edge_property('a'), graph2);
|
||||
add_edge(0, 1, edge_property('a'), graph2);
|
||||
add_edge(0, 1, edge_property('b'), graph2);
|
||||
|
||||
add_edge(1, 2, edge_property('s'), graph2);
|
||||
|
||||
add_edge(2, 3, edge_property('b'), graph2);
|
||||
add_edge(2, 3, edge_property('d'), graph2);
|
||||
add_edge(2, 3, edge_property('b'), graph2);
|
||||
|
||||
add_edge(3, 4, edge_property('s'), graph2);
|
||||
|
||||
add_edge(4, 4, edge_property('l'), graph2);
|
||||
add_edge(4, 4, edge_property('l'), graph2);
|
||||
|
||||
add_edge(4, 5, edge_property('c'), graph2);
|
||||
add_edge(4, 5, edge_property('c'), graph2);
|
||||
add_edge(4, 5, edge_property('c'), graph2);
|
||||
|
||||
add_edge(5, 0, edge_property('s'), graph2);
|
||||
|
||||
// create predicates
|
||||
typedef property_map<graph_type, vertex_name_t>::type vertex_name_map_t;
|
||||
typedef property_map_equivalent<vertex_name_map_t, vertex_name_map_t> vertex_comp_t;
|
||||
vertex_comp_t vertex_comp =
|
||||
make_property_map_equivalent(get(vertex_name, graph1), get(vertex_name, graph2));
|
||||
|
||||
typedef property_map<graph_type, edge_name_t>::type edge_name_map_t;
|
||||
typedef property_map_equivalent<edge_name_map_t, edge_name_map_t> edge_comp_t;
|
||||
edge_comp_t edge_comp =
|
||||
make_property_map_equivalent(get(edge_name, graph1), get(edge_name, graph2));
|
||||
|
||||
// Create callback
|
||||
vf2_print_callback<graph_type, graph_type> callback(graph1, graph2);
|
||||
|
||||
// Print out all subgraph isomorphism mappings between graph1 and graph2.
|
||||
// Function vertex_order_by_mult is used to compute the order of
|
||||
// vertices of graph1. This is the order in which the vertices are examined
|
||||
// during the matching process.
|
||||
vf2_subgraph_iso(graph1, graph2, callback, vertex_order_by_mult(graph1),
|
||||
edges_equivalent(edge_comp).vertices_equivalent(vertex_comp));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -188,6 +188,7 @@ namespace boost {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Selector> struct is_distributed_selector: mpl::false_ {};
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
#include <boost/graph/relax.hpp>
|
||||
#include <boost/graph/exception.hpp>
|
||||
#include <boost/graph/breadth_first_search.hpp>
|
||||
#include <boost/graph/iteration_macros.hpp>
|
||||
#include <boost/graph/detail/d_ary_heap.hpp>
|
||||
#include <boost/graph/property_maps/constant_property_map.hpp>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <boost/property_map/vector_property_map.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/concept/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
@@ -159,8 +162,9 @@ namespace boost {
|
||||
template <class Edge, class Graph>
|
||||
void tree_edge(Edge e, const Graph& g) {
|
||||
using boost::get;
|
||||
m_decreased = relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
bool m_decreased =
|
||||
relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
|
||||
if(m_decreased) {
|
||||
m_vis.edge_relaxed(e, g);
|
||||
@@ -175,8 +179,9 @@ namespace boost {
|
||||
template <class Edge, class Graph>
|
||||
void gray_target(Edge e, const Graph& g) {
|
||||
using boost::get;
|
||||
m_decreased = relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
bool m_decreased =
|
||||
relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
|
||||
if(m_decreased) {
|
||||
put(m_cost, target(e, g),
|
||||
@@ -192,8 +197,9 @@ namespace boost {
|
||||
template <class Edge, class Graph>
|
||||
void black_target(Edge e, const Graph& g) {
|
||||
using boost::get;
|
||||
m_decreased = relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
bool m_decreased =
|
||||
relax(e, g, m_weight, m_predecessor, m_distance,
|
||||
m_combine, m_compare);
|
||||
|
||||
if(m_decreased) {
|
||||
m_vis.edge_relaxed(e, g);
|
||||
@@ -219,7 +225,6 @@ namespace boost {
|
||||
ColorMap m_color;
|
||||
BinaryFunction m_combine;
|
||||
BinaryPredicate m_compare;
|
||||
bool m_decreased;
|
||||
C m_zero;
|
||||
|
||||
};
|
||||
@@ -263,6 +268,77 @@ namespace boost {
|
||||
breadth_first_visit(g, s, Q, bfs_vis, color);
|
||||
}
|
||||
|
||||
namespace graph_detail {
|
||||
template <typename A, typename B>
|
||||
struct select1st {
|
||||
typedef std::pair<A, B> argument_type;
|
||||
typedef A result_type;
|
||||
A operator()(const std::pair<A, B>& p) const {return p.first;}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename VertexListGraph, typename AStarHeuristic,
|
||||
typename AStarVisitor, typename PredecessorMap,
|
||||
typename CostMap, typename DistanceMap,
|
||||
typename WeightMap,
|
||||
typename CompareFunction, typename CombineFunction,
|
||||
typename CostInf, typename CostZero>
|
||||
inline void
|
||||
astar_search_no_init_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, AStarVisitor vis,
|
||||
PredecessorMap predecessor, CostMap cost,
|
||||
DistanceMap distance, WeightMap weight,
|
||||
CompareFunction compare, CombineFunction combine,
|
||||
CostInf /*inf*/, CostZero zero)
|
||||
{
|
||||
typedef typename graph_traits<VertexListGraph>::vertex_descriptor
|
||||
Vertex;
|
||||
typedef typename property_traits<DistanceMap>::value_type Distance;
|
||||
typedef d_ary_heap_indirect<
|
||||
std::pair<Distance, Vertex>,
|
||||
4,
|
||||
null_property_map<std::pair<Distance, Vertex>, std::size_t>,
|
||||
function_property_map<graph_detail::select1st<Distance, Vertex>, std::pair<Distance, Vertex> >,
|
||||
CompareFunction>
|
||||
MutableQueue;
|
||||
MutableQueue Q(
|
||||
make_function_property_map<std::pair<Distance, Vertex> >(graph_detail::select1st<Distance, Vertex>()),
|
||||
null_property_map<std::pair<Distance, Vertex>, std::size_t>(),
|
||||
compare);
|
||||
|
||||
vis.discover_vertex(s, g);
|
||||
Q.push(std::make_pair(get(cost, s), s));
|
||||
while (!Q.empty()) {
|
||||
Vertex v;
|
||||
Distance v_rank;
|
||||
boost::tie(v_rank, v) = Q.top();
|
||||
Q.pop();
|
||||
vis.examine_vertex(v, g);
|
||||
BGL_FORALL_OUTEDGES_T(v, e, g, VertexListGraph) {
|
||||
Vertex w = target(e, g);
|
||||
vis.examine_edge(e, g);
|
||||
Distance e_weight = get(weight, e);
|
||||
if (compare(e_weight, zero))
|
||||
BOOST_THROW_EXCEPTION(negative_edge());
|
||||
bool decreased =
|
||||
relax(e, g, weight, predecessor, distance,
|
||||
combine, compare);
|
||||
Distance w_d = combine(get(distance, v), e_weight);
|
||||
if (decreased) {
|
||||
vis.edge_relaxed(e, g);
|
||||
Distance w_rank = combine(get(distance, w), h(w));
|
||||
put(cost, w, w_rank);
|
||||
vis.discover_vertex(w, g);
|
||||
Q.push(std::make_pair(w_rank, w));
|
||||
} else {
|
||||
vis.edge_not_relaxed(e, g);
|
||||
}
|
||||
}
|
||||
vis.finish_vertex(v, g);
|
||||
}
|
||||
}
|
||||
|
||||
// Non-named parameter interface
|
||||
template <typename VertexListGraph, typename AStarHeuristic,
|
||||
@@ -303,6 +379,40 @@ namespace boost {
|
||||
|
||||
}
|
||||
|
||||
// Non-named parameter interface
|
||||
template <typename VertexListGraph, typename AStarHeuristic,
|
||||
typename AStarVisitor, typename PredecessorMap,
|
||||
typename CostMap, typename DistanceMap,
|
||||
typename WeightMap,
|
||||
typename CompareFunction, typename CombineFunction,
|
||||
typename CostInf, typename CostZero>
|
||||
inline void
|
||||
astar_search_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, AStarVisitor vis,
|
||||
PredecessorMap predecessor, CostMap cost,
|
||||
DistanceMap distance, WeightMap weight,
|
||||
CompareFunction compare, CombineFunction combine,
|
||||
CostInf inf, CostZero zero)
|
||||
{
|
||||
|
||||
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
|
||||
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
|
||||
put(distance, *ui, inf);
|
||||
put(cost, *ui, inf);
|
||||
put(predecessor, *ui, *ui);
|
||||
vis.initialize_vertex(*ui, g);
|
||||
}
|
||||
put(distance, s, zero);
|
||||
put(cost, s, h(s));
|
||||
|
||||
astar_search_no_init_tree
|
||||
(g, s, h, vis, predecessor, cost, distance, weight,
|
||||
compare, combine, inf, zero);
|
||||
|
||||
}
|
||||
|
||||
// Named parameter interfaces
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
@@ -345,6 +455,46 @@ namespace boost {
|
||||
arg_pack[_distance_zero | D()]);
|
||||
}
|
||||
|
||||
// Named parameter interfaces
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
typename P, typename T, typename R>
|
||||
void
|
||||
astar_search_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
|
||||
{
|
||||
using namespace boost::graph::keywords;
|
||||
typedef bgl_named_params<P, T, R> params_type;
|
||||
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
|
||||
|
||||
// Distance type is the value type of the distance map if there is one,
|
||||
// otherwise the value type of the weight map.
|
||||
typedef
|
||||
typename detail::override_const_property_result<
|
||||
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
|
||||
weight_map_type;
|
||||
typedef typename boost::property_traits<weight_map_type>::value_type W;
|
||||
typedef
|
||||
typename detail::map_maker<VertexListGraph, arg_pack_type, tag::distance_map, W>::map_type
|
||||
distance_map_type;
|
||||
typedef typename boost::property_traits<distance_map_type>::value_type D;
|
||||
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
|
||||
|
||||
astar_search_tree
|
||||
(g, s, h,
|
||||
arg_pack[_visitor | make_astar_visitor(null_visitor())],
|
||||
arg_pack[_predecessor_map | dummy_property_map()],
|
||||
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
|
||||
detail::make_property_map_from_arg_pack_gen<tag::distance_map, W>(W())(g, arg_pack),
|
||||
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
|
||||
arg_pack[_distance_compare | std::less<D>()],
|
||||
arg_pack[_distance_combine | closed_plus<D>(inf)],
|
||||
inf,
|
||||
arg_pack[_distance_zero | D()]);
|
||||
}
|
||||
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
typename P, typename T, typename R>
|
||||
@@ -378,6 +528,37 @@ namespace boost {
|
||||
arg_pack[_distance_zero | D()]);
|
||||
}
|
||||
|
||||
template <typename VertexListGraph,
|
||||
typename AStarHeuristic,
|
||||
typename P, typename T, typename R>
|
||||
void
|
||||
astar_search_no_init_tree
|
||||
(const VertexListGraph &g,
|
||||
typename graph_traits<VertexListGraph>::vertex_descriptor s,
|
||||
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
|
||||
{
|
||||
using namespace boost::graph::keywords;
|
||||
typedef bgl_named_params<P, T, R> params_type;
|
||||
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
|
||||
typedef
|
||||
typename detail::override_const_property_result<
|
||||
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
|
||||
weight_map_type;
|
||||
typedef typename boost::property_traits<weight_map_type>::value_type D;
|
||||
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
|
||||
astar_search_no_init_tree
|
||||
(g, s, h,
|
||||
arg_pack[_visitor | make_astar_visitor(null_visitor())],
|
||||
arg_pack[_predecessor_map | dummy_property_map()],
|
||||
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
|
||||
detail::make_property_map_from_arg_pack_gen<tag::distance_map, D>(D())(g, arg_pack),
|
||||
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
|
||||
arg_pack[_distance_compare | std::less<D>()],
|
||||
arg_pack[_distance_combine | closed_plus<D>(inf)],
|
||||
inf,
|
||||
arg_pack[_distance_zero | D()]);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_GRAPH_ASTAR_SEARCH_HPP
|
||||
|
||||
@@ -442,11 +442,11 @@ class bk_max_flow {
|
||||
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
edge_descriptor in_edge = get(m_rev_edge_map, *ei);
|
||||
vertex_descriptor other_node = source(in_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::black() && has_parent(other_node)){
|
||||
if(get_tree(other_node) == tColorTraits::black() && other_node != m_source){
|
||||
if(get(m_res_cap_map, in_edge) > 0){
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if(source(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
if(has_parent(other_node) && source(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
//we are the parent of that node
|
||||
//it has to find a new parent, too
|
||||
set_no_parent(other_node);
|
||||
@@ -483,11 +483,11 @@ class bk_max_flow {
|
||||
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
|
||||
const edge_descriptor out_edge = *ei;
|
||||
const vertex_descriptor other_node = target(out_edge, m_g);
|
||||
if(get_tree(other_node) == tColorTraits::white() && has_parent(other_node)){
|
||||
if(get_tree(other_node) == tColorTraits::white() && other_node != m_sink){
|
||||
if(get(m_res_cap_map, out_edge) > 0){
|
||||
add_active_node(other_node);
|
||||
}
|
||||
if(target(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
if(has_parent(other_node) && target(get_edge_to_parent(other_node), m_g) == current_node){
|
||||
//we were it's parent, so it has to find a new one, too
|
||||
set_no_parent(other_node);
|
||||
m_child_orphans.push(other_node);
|
||||
@@ -526,6 +526,9 @@ class bk_max_flow {
|
||||
inline void add_active_node(vertex_descriptor v){
|
||||
BOOST_ASSERT(get_tree(v) != tColorTraits::gray());
|
||||
if(get(m_in_active_list_map, v)){
|
||||
if (m_last_grow_vertex == v) {
|
||||
m_last_grow_vertex = graph_traits<Graph>::null_vertex();
|
||||
}
|
||||
return;
|
||||
} else{
|
||||
put(m_in_active_list_map, v, true);
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/graph/graph_selectors.hpp>
|
||||
#include <boost/graph/detail/is_distributed_selector.hpp>
|
||||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
@@ -1322,8 +1324,9 @@ struct csr_property_map_helper<BOOST_CSR_GRAPH_TYPE, Tag, graph_property_tag> {
|
||||
typedef transform_value_property_map<detail::lookup_one_property_f<const plist_type, Tag>, all_const_type> const_type;
|
||||
};
|
||||
|
||||
// disable_if isn't truly necessary but required to avoid ambiguity with specializations below
|
||||
template <BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, Tag>:
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, Tag, typename disable_if<detail::is_distributed_selector<Vertex> >::type>:
|
||||
csr_property_map_helper<
|
||||
BOOST_CSR_GRAPH_TYPE,
|
||||
Tag,
|
||||
@@ -1370,35 +1373,35 @@ put(Tag tag,
|
||||
}
|
||||
|
||||
template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, vertex_index_t>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, vertex_index_t, typename disable_if<detail::is_distributed_selector<Vertex> >::type>
|
||||
{
|
||||
typedef typed_identity_property_map<Vertex> type;
|
||||
typedef type const_type;
|
||||
};
|
||||
|
||||
template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, edge_index_t>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, edge_index_t, typename disable_if<detail::is_distributed_selector<Vertex> >::type>
|
||||
{
|
||||
typedef detail::csr_edge_index_map<Vertex, EdgeIndex> type;
|
||||
typedef type const_type;
|
||||
};
|
||||
|
||||
template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, vertex_all_t>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, vertex_all_t, typename disable_if<detail::is_distributed_selector<Vertex> >::type>
|
||||
{
|
||||
typedef typename BOOST_CSR_GRAPH_TYPE::inherited_vertex_properties::vertex_map_type type;
|
||||
typedef typename BOOST_CSR_GRAPH_TYPE::inherited_vertex_properties::const_vertex_map_type const_type;
|
||||
};
|
||||
|
||||
template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, edge_all_t>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, edge_all_t, typename disable_if<detail::is_distributed_selector<Vertex> >::type>
|
||||
{
|
||||
typedef typename BOOST_CSR_GRAPH_TYPE::forward_type::inherited_edge_properties::edge_map_type type;
|
||||
typedef typename BOOST_CSR_GRAPH_TYPE::forward_type::inherited_edge_properties::const_edge_map_type const_type;
|
||||
};
|
||||
|
||||
template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, graph_all_t>
|
||||
struct property_map<BOOST_CSR_GRAPH_TYPE, graph_all_t, typename disable_if<detail::is_distributed_selector<Vertex> >::type>
|
||||
{
|
||||
typedef boost::ref_property_map<BOOST_CSR_GRAPH_TYPE*, typename BOOST_CSR_GRAPH_TYPE::graph_property_type> type;
|
||||
typedef boost::ref_property_map<BOOST_CSR_GRAPH_TYPE*, const typename BOOST_CSR_GRAPH_TYPE::graph_property_type> const_type;
|
||||
|
||||
@@ -309,14 +309,16 @@ namespace boost {
|
||||
public:
|
||||
typedef Property property_type;
|
||||
inline stored_ra_edge_iter() { }
|
||||
inline stored_ra_edge_iter(Vertex v, Iter i = Iter(),
|
||||
EdgeVec* edge_vec = 0)
|
||||
inline explicit stored_ra_edge_iter(Vertex v) // Only used for comparisons
|
||||
: stored_edge<Vertex>(v), m_i(0), m_vec(0){ }
|
||||
inline stored_ra_edge_iter(Vertex v, Iter i, EdgeVec* edge_vec)
|
||||
: stored_edge<Vertex>(v), m_i(i - edge_vec->begin()), m_vec(edge_vec){ }
|
||||
inline Property& get_property() { return (*m_vec)[m_i].get_property(); }
|
||||
inline Property& get_property() { BOOST_ASSERT ((m_vec != 0)); return (*m_vec)[m_i].get_property(); }
|
||||
inline const Property& get_property() const {
|
||||
BOOST_ASSERT ((m_vec != 0));
|
||||
return (*m_vec)[m_i].get_property();
|
||||
}
|
||||
inline Iter get_iter() const { return m_vec->begin() + m_i; }
|
||||
inline Iter get_iter() const { BOOST_ASSERT ((m_vec != 0)); return m_vec->begin() + m_i; }
|
||||
protected:
|
||||
std::size_t m_i;
|
||||
EdgeVec* m_vec;
|
||||
|
||||
@@ -126,18 +126,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
Value& top() {
|
||||
BOOST_ASSERT (!this->empty());
|
||||
return data[0];
|
||||
}
|
||||
|
||||
const Value& top() const {
|
||||
BOOST_ASSERT (!this->empty());
|
||||
return data[0];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
BOOST_ASSERT (!this->empty());
|
||||
put(index_in_heap, data[0], (size_type)(-1));
|
||||
if (data.size() != 1) {
|
||||
data[0] = data.back();
|
||||
put(index_in_heap, data[0], 0);
|
||||
put(index_in_heap, data[0], (size_type)(0));
|
||||
data.pop_back();
|
||||
preserve_heap_property_down();
|
||||
verify_heap();
|
||||
|
||||
26
include/boost/graph/detail/is_distributed_selector.hpp
Normal file
26
include/boost/graph/detail/is_distributed_selector.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2012 The Trustees of Indiana University.
|
||||
|
||||
// Distributed under 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: Jeremiah Willcock
|
||||
// Andrew Lumsdaine
|
||||
|
||||
// Selector to determine whether a selector is distributedS (can only be true
|
||||
// if <boost/graph/distributed/selector.hpp> has been included) so that we can
|
||||
// disable various sequential-graph-only traits specializations for distributed
|
||||
// graphs.
|
||||
|
||||
#ifndef BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
|
||||
#define BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
template <typename> struct is_distributed_selector: boost::mpl::false_ {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
|
||||
@@ -218,9 +218,9 @@ namespace graph_detail {
|
||||
#define LABELED_GRAPH_PARAMS typename G, typename L, typename S
|
||||
#define LABELED_GRAPH labeled_graph<G,L,S>
|
||||
|
||||
// Specialize mutability traits for for the labeled graph.
|
||||
// Specialize mutability traits for the labeled graph.
|
||||
// This specialization depends on the mutability of the underlying graph type.
|
||||
// If the underlying graph is fully mutable, this this is also fully mutable.
|
||||
// If the underlying graph is fully mutable, this is also fully mutable.
|
||||
// Otherwise, it's different.
|
||||
template <LABELED_GRAPH_PARAMS>
|
||||
struct graph_mutability_traits< LABELED_GRAPH > {
|
||||
|
||||
@@ -113,16 +113,17 @@ namespace boost {
|
||||
distance_weight_combine, distance_compare);
|
||||
|
||||
if (was_edge_relaxed) {
|
||||
vertex_queue.update(neighbor_vertex);
|
||||
visitor.edge_relaxed(current_edge, graph);
|
||||
if (is_neighbor_undiscovered) {
|
||||
visitor.discover_vertex(neighbor_vertex, graph);
|
||||
vertex_queue.push(neighbor_vertex);
|
||||
} else {
|
||||
vertex_queue.update(neighbor_vertex);
|
||||
}
|
||||
} else {
|
||||
visitor.edge_not_relaxed(current_edge, graph);
|
||||
}
|
||||
|
||||
if (is_neighbor_undiscovered) {
|
||||
visitor.discover_vertex(neighbor_vertex, graph);
|
||||
vertex_queue.push(neighbor_vertex);
|
||||
}
|
||||
} // end out edge iteration
|
||||
|
||||
visitor.finish_vertex(min_vertex, graph);
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/pending/property.hpp>
|
||||
#include <boost/property_map/transform_value_property_map.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -27,8 +31,8 @@ struct directed_graph_tag { };
|
||||
*/
|
||||
template <
|
||||
typename VertexProp = no_property,
|
||||
typename EdgeProp= no_property,
|
||||
typename GraphProp= no_property>
|
||||
typename EdgeProp = no_property,
|
||||
typename GraphProp = no_property>
|
||||
class directed_graph
|
||||
{
|
||||
public:
|
||||
@@ -39,15 +43,14 @@ public:
|
||||
typedef typename lookup_one_property<VertexProp, vertex_bundle_t>::type vertex_bundled;
|
||||
typedef typename lookup_one_property<EdgeProp, edge_bundle_t>::type edge_bundled;
|
||||
|
||||
private:
|
||||
// Wrap the user-specified properties with an index.
|
||||
typedef property<vertex_index_t, unsigned, vertex_property_type> vertex_property;
|
||||
typedef property<edge_index_t, unsigned, edge_property_type> edge_property;
|
||||
|
||||
public:
|
||||
// Embed indices into the vertex type.
|
||||
typedef property<vertex_index_t, unsigned, vertex_property_type> internal_vertex_property;
|
||||
typedef property<edge_index_t, unsigned, edge_property_type> internal_edge_property;
|
||||
public:
|
||||
typedef adjacency_list<
|
||||
listS, listS, bidirectionalS,
|
||||
vertex_property, edge_property, GraphProp,
|
||||
internal_vertex_property, internal_edge_property, GraphProp,
|
||||
listS
|
||||
> graph_type;
|
||||
|
||||
@@ -80,8 +83,8 @@ public:
|
||||
typedef typename graph_type::edge_parallel_category edge_parallel_category;
|
||||
typedef typename graph_type::traversal_category traversal_category;
|
||||
|
||||
typedef unsigned vertex_index_type;
|
||||
typedef unsigned edge_index_type;
|
||||
typedef std::size_t vertex_index_type;
|
||||
typedef std::size_t edge_index_type;
|
||||
|
||||
directed_graph(GraphProp const& p = GraphProp())
|
||||
: m_graph(p), m_num_vertices(0), m_num_edges(0), m_max_vertex_index(0)
|
||||
@@ -137,6 +140,7 @@ public:
|
||||
vertices_size_type num_vertices() const
|
||||
{ return m_num_vertices; }
|
||||
|
||||
|
||||
private:
|
||||
// This helper function manages the attribution of vertex indices.
|
||||
vertex_descriptor make_index(vertex_descriptor v) {
|
||||
@@ -150,7 +154,7 @@ public:
|
||||
{ return make_index(boost::add_vertex(m_graph)); }
|
||||
|
||||
vertex_descriptor add_vertex(vertex_property_type const& p)
|
||||
{ return make_index(boost::add_vertex(vertex_property(0u, p), m_graph)); }
|
||||
{ return make_index(boost::add_vertex(internal_vertex_property(0u, p), m_graph)); }
|
||||
|
||||
void clear_vertex(vertex_descriptor v)
|
||||
{
|
||||
@@ -186,7 +190,7 @@ public:
|
||||
|
||||
std::pair<edge_descriptor, bool>
|
||||
add_edge(vertex_descriptor u, vertex_descriptor v, edge_property_type const& p)
|
||||
{ return make_index(boost::add_edge(u, v, edge_property(0u, p), m_graph)); }
|
||||
{ return make_index(boost::add_edge(u, v, internal_edge_property(0u, p), m_graph)); }
|
||||
|
||||
void remove_edge(vertex_descriptor u, vertex_descriptor v)
|
||||
{
|
||||
@@ -516,37 +520,32 @@ remove_in_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v,
|
||||
DIRECTED_GRAPH& g)
|
||||
{ return remove_in_edge_if(v, pred, g.impl()); }
|
||||
|
||||
// Helper code for working with property maps
|
||||
namespace detail
|
||||
{
|
||||
struct directed_graph_vertex_property_selector {
|
||||
template <class DirectedGraph, class Property, class Tag>
|
||||
struct bind_ {
|
||||
typedef typename DirectedGraph::graph_type Graph;
|
||||
typedef property_map<Graph, Tag> PropertyMap;
|
||||
typedef typename PropertyMap::type type;
|
||||
typedef typename PropertyMap::const_type const_type;
|
||||
};
|
||||
};
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Property>
|
||||
struct property_map<DIRECTED_GRAPH, Property>: property_map<typename DIRECTED_GRAPH::graph_type, Property> {};
|
||||
|
||||
struct directed_graph_edge_property_selector {
|
||||
template <class DirectedGraph, class Property, class Tag>
|
||||
struct bind_ {
|
||||
typedef typename DirectedGraph::graph_type Graph;
|
||||
typedef property_map<Graph, Tag> PropertyMap;
|
||||
typedef typename PropertyMap::type type;
|
||||
typedef typename PropertyMap::const_type const_type;
|
||||
};
|
||||
};
|
||||
}
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
struct property_map<DIRECTED_GRAPH, vertex_all_t> {
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename DIRECTED_GRAPH::graph_type, vertex_all_t>::const_type>
|
||||
const_type;
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename DIRECTED_GRAPH::graph_type, vertex_all_t>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct vertex_property_selector<directed_graph_tag>
|
||||
{ typedef detail::directed_graph_vertex_property_selector type; };
|
||||
|
||||
template <>
|
||||
struct edge_property_selector<directed_graph_tag>
|
||||
{ typedef detail::directed_graph_edge_property_selector type; };
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
struct property_map<DIRECTED_GRAPH, edge_all_t> {
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename DIRECTED_GRAPH::graph_type, edge_all_t>::const_type>
|
||||
const_type;
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename DIRECTED_GRAPH::graph_type, edge_all_t>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
// PropertyGraph concepts
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Property>
|
||||
@@ -559,6 +558,26 @@ inline typename property_map<DIRECTED_GRAPH, Property>::const_type
|
||||
get(Property p, DIRECTED_GRAPH const& g)
|
||||
{ return get(p, g.impl()); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<DIRECTED_GRAPH, vertex_all_t>::type
|
||||
get(vertex_all_t, DIRECTED_GRAPH& g)
|
||||
{ return typename property_map<DIRECTED_GRAPH, vertex_all_t>::type(detail::remove_first_property(), get(vertex_all, g.impl())); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<DIRECTED_GRAPH, vertex_all_t>::const_type
|
||||
get(vertex_all_t, DIRECTED_GRAPH const& g)
|
||||
{ return typename property_map<DIRECTED_GRAPH, vertex_all_t>::const_type(detail::remove_first_property(), get(vertex_all, g.impl())); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<DIRECTED_GRAPH, edge_all_t>::type
|
||||
get(edge_all_t, DIRECTED_GRAPH& g)
|
||||
{ return typename property_map<DIRECTED_GRAPH, edge_all_t>::type(detail::remove_first_property(), get(edge_all, g.impl())); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<DIRECTED_GRAPH, edge_all_t>::const_type
|
||||
get(edge_all_t, DIRECTED_GRAPH const& g)
|
||||
{ return typename property_map<DIRECTED_GRAPH, edge_all_t>::const_type(detail::remove_first_property(), get(edge_all, g.impl())); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
@@ -568,10 +587,40 @@ inline typename property_traits<
|
||||
get(Property p, DIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(p, g.impl(), k); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
typename DIRECTED_GRAPH::graph_type, vertex_all_t
|
||||
>::const_type
|
||||
>::value_type
|
||||
get(vertex_all_t, DIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(vertex_all, g.impl(), k).m_base; }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
typename DIRECTED_GRAPH::graph_type, edge_all_t
|
||||
>::const_type
|
||||
>::value_type
|
||||
get(edge_all_t, DIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(edge_all, g.impl(), k).m_base; }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value>
|
||||
inline void put(Property p, DIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(p, g.impl(), k, v); }
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Key, typename Value>
|
||||
inline void put(vertex_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(vertex_all, g.impl(), k,
|
||||
typename DIRECTED_GRAPH::internal_vertex_property(get(vertex_index, g.impl(), k), v));
|
||||
}
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, typename Key, typename Value>
|
||||
inline void put(edge_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(edge_all, g.impl(), k,
|
||||
typename DIRECTED_GRAPH::internal_vertex_property(get(edge_index, g.impl(), k), v));
|
||||
}
|
||||
|
||||
template <DIRECTED_GRAPH_PARAMS, class Property>
|
||||
typename graph_property<DIRECTED_GRAPH, Property>::type&
|
||||
get_property(DIRECTED_GRAPH& g, Property p)
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include <boost/graph/numeric_values.hpp>
|
||||
#include <boost/graph/buffer_concepts.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/concept/assert.hpp>
|
||||
|
||||
@@ -55,12 +58,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
BOOST_concept(Graph,(G))
|
||||
{
|
||||
typedef typename graph_traits<G>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits<G>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<G>::directed_category directed_category;
|
||||
typedef typename graph_traits<G>::edge_parallel_category
|
||||
edge_parallel_category;
|
||||
|
||||
typedef typename graph_traits<G>::traversal_category
|
||||
traversal_category;
|
||||
typedef typename graph_traits<G>::edge_parallel_category edge_parallel_category;
|
||||
typedef typename graph_traits<G>::traversal_category traversal_category;
|
||||
|
||||
BOOST_CONCEPT_USAGE(Graph)
|
||||
{
|
||||
@@ -75,11 +76,12 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
: Graph<G>
|
||||
{
|
||||
typedef typename graph_traits<G>::edge_descriptor edge_descriptor;
|
||||
typedef typename graph_traits<G>::out_edge_iterator
|
||||
out_edge_iterator;
|
||||
typedef typename graph_traits<G>::out_edge_iterator out_edge_iterator;
|
||||
typedef typename graph_traits<G>::degree_size_type degree_size_type;
|
||||
typedef typename graph_traits<G>::traversal_category traversal_category;
|
||||
|
||||
typedef typename graph_traits<G>::traversal_category
|
||||
traversal_category;
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<out_edge_iterator, void> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<degree_size_type, void> >::value));
|
||||
|
||||
BOOST_CONCEPT_USAGE(IncidenceGraph) {
|
||||
BOOST_CONCEPT_ASSERT((MultiPassInputIterator<out_edge_iterator>));
|
||||
@@ -123,6 +125,8 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
|
||||
bidirectional_graph_tag>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<in_edge_iterator, void> >::value));
|
||||
|
||||
p = in_edges(v, g);
|
||||
n = in_degree(v, g);
|
||||
e = *p.first;
|
||||
@@ -153,6 +157,8 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
|
||||
adjacency_graph_tag>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<adjacency_iterator, void> >::value));
|
||||
|
||||
p = adjacent_vertices(v, g);
|
||||
v = *p.first;
|
||||
const_constraints(g);
|
||||
@@ -178,6 +184,9 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
|
||||
vertex_list_graph_tag>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<vertex_iterator, void> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<vertices_size_type, void> >::value));
|
||||
|
||||
#ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK
|
||||
// dwa 2003/7/11 -- This clearly shouldn't be necessary, but if
|
||||
// you want to use vector_as_graph, it is! I'm sure the graph
|
||||
@@ -227,6 +236,9 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&);
|
||||
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
|
||||
edge_list_graph_tag>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<edge_iterator, void> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::mpl::not_<boost::is_same<edges_size_type, void> >::value));
|
||||
|
||||
p = edges(g);
|
||||
e = *p.first;
|
||||
u = source(e, g);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/mpl/void.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
@@ -28,23 +29,47 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail {
|
||||
#define BOOST_GRAPH_MEMBER_OR_VOID(name) \
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(name) \
|
||||
template <typename T> struct BOOST_JOIN(get_member_, name) {typedef typename T::name type;}; \
|
||||
template <typename T> struct BOOST_JOIN(get_opt_member_, name): \
|
||||
boost::mpl::eval_if_c< \
|
||||
BOOST_JOIN(has_, name)<T>::value, \
|
||||
BOOST_JOIN(get_member_, name)<T>, \
|
||||
boost::mpl::identity<void> > \
|
||||
{};
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(adjacency_iterator)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(out_edge_iterator)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(in_edge_iterator)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(vertex_iterator)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(edge_iterator)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(vertices_size_type)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(edges_size_type)
|
||||
BOOST_GRAPH_MEMBER_OR_VOID(degree_size_type)
|
||||
}
|
||||
|
||||
template <typename G>
|
||||
struct graph_traits {
|
||||
#define BOOST_GRAPH_PULL_OPT_MEMBER(name) \
|
||||
typedef typename detail::BOOST_JOIN(get_opt_member_, name)<G>::type name;
|
||||
|
||||
typedef typename G::vertex_descriptor vertex_descriptor;
|
||||
typedef typename G::edge_descriptor edge_descriptor;
|
||||
typedef typename G::adjacency_iterator adjacency_iterator;
|
||||
typedef typename G::out_edge_iterator out_edge_iterator;
|
||||
typedef typename G::in_edge_iterator in_edge_iterator;
|
||||
typedef typename G::vertex_iterator vertex_iterator;
|
||||
typedef typename G::edge_iterator edge_iterator;
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(adjacency_iterator)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(out_edge_iterator)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(in_edge_iterator)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(vertex_iterator)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(edge_iterator)
|
||||
|
||||
typedef typename G::directed_category directed_category;
|
||||
typedef typename G::edge_parallel_category edge_parallel_category;
|
||||
typedef typename G::traversal_category traversal_category;
|
||||
|
||||
typedef typename G::vertices_size_type vertices_size_type;
|
||||
typedef typename G::edges_size_type edges_size_type;
|
||||
typedef typename G::degree_size_type degree_size_type;
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(vertices_size_type)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(edges_size_type)
|
||||
BOOST_GRAPH_PULL_OPT_MEMBER(degree_size_type)
|
||||
#undef BOOST_GRAPH_PULL_OPT_MEMBER
|
||||
|
||||
static inline vertex_descriptor null_vertex();
|
||||
};
|
||||
|
||||
@@ -204,14 +204,14 @@ template<typename MutableGraph>
|
||||
const char* mutate_graph_impl<MutableGraph>::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"};
|
||||
|
||||
void BOOST_GRAPH_DECL
|
||||
read_graphml(std::istream& in, mutate_graph& g);
|
||||
read_graphml(std::istream& in, mutate_graph& g, size_t desired_idx);
|
||||
|
||||
template<typename MutableGraph>
|
||||
void
|
||||
read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp)
|
||||
read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp, size_t desired_idx = 0)
|
||||
{
|
||||
mutate_graph_impl<MutableGraph> mg(g,dp);
|
||||
read_graphml(in, mg);
|
||||
read_graphml(in, mg, desired_idx);
|
||||
}
|
||||
|
||||
template <typename Types>
|
||||
|
||||
@@ -475,12 +475,12 @@ namespace boost {
|
||||
* 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.
|
||||
* weight map. The default is 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
|
||||
* to the value type of the weight map. The default is a vector of
|
||||
* vectors.
|
||||
*
|
||||
* \param partial_derivatives (UTIL) will be used to store the
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
// This file implements a utility for creating mappings from arbitrary
|
||||
// identifers to the vertices of a graph.
|
||||
// identifiers to the vertices of a graph.
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace graph_detail {
|
||||
// Tag dispatch on random access containers (i.e., vectors). This function
|
||||
// basically requires a) that Container is vector<Label> and that Label
|
||||
// is an unsigned integral value. Note that this will resize the vector
|
||||
// to accomodate indices.
|
||||
// to accommodate indices.
|
||||
template <typename Container, typename Graph, typename Label, typename Prop>
|
||||
std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
|
||||
insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p,
|
||||
@@ -112,7 +112,7 @@ namespace graph_detail {
|
||||
{
|
||||
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
||||
|
||||
// If the label is out of bounds, resize the vector to accomodate.
|
||||
// If the label is out of bounds, resize the vector to accommodate.
|
||||
// Resize by 2x the index so we don't cause quadratic insertions over
|
||||
// time.
|
||||
if(l >= c.size()) {
|
||||
@@ -140,7 +140,7 @@ namespace graph_detail {
|
||||
// Tag dispatch on unique associative containers (i.e. maps).
|
||||
template <typename Container, typename Graph, typename Label, typename Prop>
|
||||
std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
|
||||
insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const&,
|
||||
insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p,
|
||||
unique_associative_container_tag)
|
||||
{
|
||||
// Here, we actually have to try the insertion first, and only add
|
||||
@@ -150,6 +150,7 @@ namespace graph_detail {
|
||||
std::pair<Iterator, bool> x = c.insert(std::make_pair(l, Vertex()));
|
||||
if(x.second) {
|
||||
x.first->second = add_vertex(g);
|
||||
put(boost::vertex_all, g, x.first->second, p);
|
||||
}
|
||||
return std::make_pair(x.first->second, x.second);
|
||||
}
|
||||
@@ -246,7 +247,7 @@ struct labeled_graph_types {
|
||||
* vertex labels and vertex descriptors.
|
||||
*
|
||||
* @todo This class is somewhat redundant for adjacency_list<*, vecS> if
|
||||
* the intended label is an unsigned int (and perhpahs some other cases), but
|
||||
* the intended label is an unsigned int (and perhaps some other cases), but
|
||||
* it does avoid some weird ambiguities (i.e. adding a vertex with a label that
|
||||
* does not match its target index).
|
||||
*
|
||||
@@ -310,7 +311,7 @@ public:
|
||||
_map.insert(_map.end(), rng.first, rng.second);
|
||||
}
|
||||
|
||||
// Construct a grpah over n vertices, each of which receives a label from
|
||||
// Construct a graph over n vertices, each of which receives a label from
|
||||
// the range [l, l + n). Note that the graph is not directly constructed
|
||||
// over the n vertices, but added sequentially. This constructor is
|
||||
// necessarily slower than the underlying counterpart.
|
||||
@@ -544,8 +545,9 @@ inline bool label_vertex(typename LABELED_GRAPH::vertex_descriptor v,
|
||||
{ return g.label_vertex(v, l); }
|
||||
|
||||
template <LABELED_GRAPH_PARAMS>
|
||||
inline bool vertex_by_label(typename LABELED_GRAPH::label_type const l,
|
||||
LABELED_GRAPH& g)
|
||||
inline typename LABELED_GRAPH::vertex_descriptor
|
||||
vertex_by_label(typename LABELED_GRAPH::label_type const l,
|
||||
LABELED_GRAPH& g)
|
||||
{ return g.vertex(l); }
|
||||
//@}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace boost
|
||||
// Create tour using a preorder traversal of the mst
|
||||
vector<Node> tour;
|
||||
PreorderTraverser<Node, Tree> tvis(tour);
|
||||
traverse_tree(0, t, tvis);
|
||||
traverse_tree(indexmap[start], t, tvis);
|
||||
|
||||
pair<GVItr, GVItr> g_verts(vertices(g));
|
||||
for(PreorderTraverser<Node, Tree>::const_iterator curr(tvis.begin());
|
||||
@@ -228,7 +228,7 @@ namespace boost
|
||||
}
|
||||
|
||||
// Connect back to the start of the tour
|
||||
vis.visit_vertex(*g_verts.first, g);
|
||||
vis.visit_vertex(start, g);
|
||||
}
|
||||
|
||||
// Default tsp tour visitor that puts the tour in an OutputIterator
|
||||
|
||||
@@ -11,14 +11,23 @@
|
||||
#define BOOST_GRAPH_NAMED_GRAPH_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/pending/property.hpp> // for boost::lookup_one_property
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/tuple/tuple.hpp> // for boost::make_tuple
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <functional> // for std::equal_to
|
||||
#include <stdexcept> // for std::runtime_error
|
||||
#include <utility> // for std::pair
|
||||
|
||||
namespace boost { namespace graph {
|
||||
|
||||
@@ -352,8 +361,15 @@ find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
|
||||
|
||||
/// Retrieve the vertex associated with the given name, or add a new
|
||||
/// vertex with that name if no such vertex is available.
|
||||
/// Note: This is enabled only when the vertex property type is different
|
||||
/// from the vertex name to avoid ambiguous overload problems with
|
||||
/// the add_vertex() function that takes a vertex property.
|
||||
template<BGL_NAMED_GRAPH_PARAMS>
|
||||
Vertex
|
||||
typename disable_if<is_same<
|
||||
typename BGL_NAMED_GRAPH::vertex_name_type,
|
||||
VertexProperty
|
||||
>,
|
||||
Vertex>::type
|
||||
add_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
|
||||
BGL_NAMED_GRAPH& g)
|
||||
{
|
||||
@@ -401,6 +417,35 @@ add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||||
g.derived());
|
||||
}
|
||||
|
||||
// Overloads to support EdgeMutablePropertyGraph graphs
|
||||
template <BGL_NAMED_GRAPH_PARAMS>
|
||||
std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
|
||||
add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
|
||||
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||||
typename edge_property_type<Graph>::type const& p,
|
||||
BGL_NAMED_GRAPH& g) {
|
||||
return add_edge(u, add_vertex(v_name, g.derived()), p, g.derived());
|
||||
}
|
||||
|
||||
template <BGL_NAMED_GRAPH_PARAMS>
|
||||
std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
|
||||
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||||
typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
|
||||
typename edge_property_type<Graph>::type const& p,
|
||||
BGL_NAMED_GRAPH& g) {
|
||||
return add_edge(add_vertex(u_name, g.derived()), v, p, g.derived());
|
||||
}
|
||||
|
||||
template <BGL_NAMED_GRAPH_PARAMS>
|
||||
std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
|
||||
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||||
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||||
typename edge_property_type<Graph>::type const& p,
|
||||
BGL_NAMED_GRAPH& g) {
|
||||
return add_edge(add_vertex(u_name, g.derived()),
|
||||
add_vertex(v_name, g.derived()), p, g.derived());
|
||||
}
|
||||
|
||||
#undef BGL_NAMED_GRAPH
|
||||
#undef BGL_NAMED_GRAPH_PARAMS
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace boost {
|
||||
{};
|
||||
} // namespace detail
|
||||
|
||||
template <class Graph, class Property>
|
||||
template <class Graph, class Property, class Enable = void>
|
||||
struct property_map:
|
||||
mpl::if_<
|
||||
is_same<typename detail::property_kind_from_graph<Graph, Property>::type, edge_property_tag>,
|
||||
@@ -248,8 +248,8 @@ namespace boost {
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class Graph> class vertex_property: vertex_property_type<Graph> {};
|
||||
template <class Graph> class edge_property: edge_property_type<Graph> {};
|
||||
template <typename Graph> struct vertex_property: vertex_property_type<Graph> {};
|
||||
template <typename Graph> struct edge_property: edge_property_type<Graph> {};
|
||||
|
||||
template <typename Graph>
|
||||
class degree_property_map
|
||||
|
||||
@@ -54,6 +54,39 @@ inline constant_property_map<Key, Value>
|
||||
make_constant_property(const Value& value)
|
||||
{ return constant_property_map<Key, Value>(value); }
|
||||
|
||||
/**
|
||||
* Same as above, but pretends to be writable as well.
|
||||
*/
|
||||
template <typename Key, typename Value>
|
||||
struct constant_writable_property_map {
|
||||
typedef Key key_type;
|
||||
typedef Value value_type;
|
||||
typedef Value& reference;
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
|
||||
constant_writable_property_map()
|
||||
: m_value()
|
||||
{ }
|
||||
|
||||
constant_writable_property_map(const value_type &value)
|
||||
: m_value(value)
|
||||
{ }
|
||||
|
||||
constant_writable_property_map(const constant_writable_property_map& copy)
|
||||
: m_value(copy.m_value)
|
||||
{ }
|
||||
|
||||
friend Value get(const constant_writable_property_map& me, Key) {return me.m_value;}
|
||||
friend void put(const constant_writable_property_map&, Key, Value) {}
|
||||
|
||||
value_type m_value;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
inline constant_writable_property_map<Key, Value>
|
||||
make_constant_writable_property(const Value& value)
|
||||
{ return constant_writable_property_map<Key, Value>(value); }
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -433,7 +433,7 @@ namespace detail {
|
||||
{
|
||||
return m[k];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class E>
|
||||
struct property_traits<detail::underlying_edge_desc_map_type<E> > {
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace boost
|
||||
// basically modernized it to use real data structures (no more arrays and matrices).
|
||||
// Oh... and there's explicit control structures - not just gotos.
|
||||
//
|
||||
// The problem is definitely NP-complete, an an unbounded implementation of this
|
||||
// The problem is definitely NP-complete, an unbounded implementation of this
|
||||
// will probably run for quite a while on a large graph. The conclusions
|
||||
// of this paper also reference a Paton algorithm for undirected graphs as being
|
||||
// much more efficient (apparently based on spanning trees). Although not implemented,
|
||||
@@ -85,7 +85,7 @@ namespace boost
|
||||
// }
|
||||
|
||||
/**
|
||||
* The default cycle visitor providse an empty visit function for cycle
|
||||
* The default cycle visitor provides an empty visit function for cycle
|
||||
* visitors.
|
||||
*/
|
||||
struct cycle_visitor
|
||||
@@ -168,7 +168,7 @@ namespace detail
|
||||
|
||||
// conditions for allowing a traversal along this edge are:
|
||||
// 1. the index of v must be greater than that at which the
|
||||
// the path is rooted (p.front()).
|
||||
// path is rooted (p.front()).
|
||||
// 2. the vertex v cannot already be in the path
|
||||
// 3. the vertex v cannot be closed to the vertex u
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/pending/property.hpp>
|
||||
#include <boost/property_map/transform_value_property_map.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -39,16 +43,16 @@ public:
|
||||
typedef typename lookup_one_property<VertexProp, vertex_bundle_t>::type vertex_bundled;
|
||||
typedef typename lookup_one_property<EdgeProp, edge_bundle_t>::type edge_bundled;
|
||||
|
||||
private:
|
||||
public:
|
||||
// Embed indices into the vertex type.
|
||||
typedef property<vertex_index_t, unsigned, vertex_property_type> vertex_property;
|
||||
typedef property<edge_index_t, unsigned, edge_property_type> edge_property;
|
||||
typedef property<vertex_index_t, unsigned, vertex_property_type> internal_vertex_property;
|
||||
typedef property<edge_index_t, unsigned, edge_property_type> internal_edge_property;
|
||||
public:
|
||||
typedef adjacency_list<listS,
|
||||
listS,
|
||||
undirectedS,
|
||||
vertex_property,
|
||||
edge_property,
|
||||
internal_vertex_property,
|
||||
internal_edge_property,
|
||||
GraphProp,
|
||||
listS> graph_type;
|
||||
private:
|
||||
@@ -151,7 +155,7 @@ public:
|
||||
{ return make_index(boost::add_vertex(m_graph)); }
|
||||
|
||||
vertex_descriptor add_vertex(vertex_property_type const& p)
|
||||
{ return make_index(boost::add_vertex(vertex_property(0u, p), m_graph)); }
|
||||
{ return make_index(boost::add_vertex(internal_vertex_property(0u, p), m_graph)); }
|
||||
|
||||
void clear_vertex(vertex_descriptor v) {
|
||||
std::pair<out_edge_iterator, out_edge_iterator>
|
||||
@@ -188,7 +192,7 @@ public:
|
||||
std::pair<edge_descriptor, bool>
|
||||
add_edge(vertex_descriptor u, vertex_descriptor v,
|
||||
edge_property_type const& p)
|
||||
{ return make_index(boost::add_edge(u, v, edge_property(0u, p), m_graph)); }
|
||||
{ return make_index(boost::add_edge(u, v, internal_edge_property(0u, p), m_graph)); }
|
||||
|
||||
void remove_edge(vertex_descriptor u, vertex_descriptor v) {
|
||||
// find all edges, (u, v)
|
||||
@@ -525,6 +529,30 @@ remove_in_edge_if(typename UNDIRECTED_GRAPH::vertex_descriptor v,
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Property>
|
||||
struct property_map<UNDIRECTED_GRAPH, Property>: property_map<typename UNDIRECTED_GRAPH::graph_type, Property> {};
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
struct property_map<UNDIRECTED_GRAPH, vertex_all_t> {
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename UNDIRECTED_GRAPH::graph_type, vertex_all_t>::const_type>
|
||||
const_type;
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename UNDIRECTED_GRAPH::graph_type, vertex_all_t>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
struct property_map<UNDIRECTED_GRAPH, edge_all_t> {
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename UNDIRECTED_GRAPH::graph_type, edge_all_t>::const_type>
|
||||
const_type;
|
||||
typedef transform_value_property_map<
|
||||
detail::remove_first_property,
|
||||
typename property_map<typename UNDIRECTED_GRAPH::graph_type, edge_all_t>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
// PropertyGraph concepts
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Property>
|
||||
inline typename property_map<UNDIRECTED_GRAPH, Property>::type
|
||||
@@ -536,6 +564,26 @@ inline typename property_map<UNDIRECTED_GRAPH, Property>::const_type
|
||||
get(Property p, UNDIRECTED_GRAPH const& g)
|
||||
{ return get(p, g.impl()); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<UNDIRECTED_GRAPH, vertex_all_t>::type
|
||||
get(vertex_all_t, UNDIRECTED_GRAPH& g)
|
||||
{ return typename property_map<UNDIRECTED_GRAPH, vertex_all_t>::type(detail::remove_first_property(), get(vertex_all, g.impl())); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<UNDIRECTED_GRAPH, vertex_all_t>::const_type
|
||||
get(vertex_all_t, UNDIRECTED_GRAPH const& g)
|
||||
{ return typename property_map<UNDIRECTED_GRAPH, vertex_all_t>::const_type(detail::remove_first_property(), get(vertex_all, g.impl())); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<UNDIRECTED_GRAPH, edge_all_t>::type
|
||||
get(edge_all_t, UNDIRECTED_GRAPH& g)
|
||||
{ return typename property_map<UNDIRECTED_GRAPH, edge_all_t>::type(detail::remove_first_property(), get(edge_all, g.impl())); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS>
|
||||
inline typename property_map<UNDIRECTED_GRAPH, edge_all_t>::const_type
|
||||
get(edge_all_t, UNDIRECTED_GRAPH const& g)
|
||||
{ return typename property_map<UNDIRECTED_GRAPH, edge_all_t>::const_type(detail::remove_first_property(), get(edge_all, g.impl())); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Property, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
@@ -545,10 +593,40 @@ inline typename property_traits<
|
||||
get(Property p, UNDIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(p, g.impl(), k); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
typename UNDIRECTED_GRAPH::graph_type, vertex_all_t
|
||||
>::const_type
|
||||
>::value_type
|
||||
get(vertex_all_t, UNDIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(vertex_all, g.impl(), k).m_base; }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Key>
|
||||
inline typename property_traits<
|
||||
typename property_map<
|
||||
typename UNDIRECTED_GRAPH::graph_type, edge_all_t
|
||||
>::const_type
|
||||
>::value_type
|
||||
get(edge_all_t, UNDIRECTED_GRAPH const& g, Key const& k)
|
||||
{ return get(edge_all, g.impl(), k).m_base; }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value>
|
||||
inline void put(Property p, UNDIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(p, g.impl(), k, v); }
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Key, typename Value>
|
||||
inline void put(vertex_all_t, UNDIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(vertex_all, g.impl(), k,
|
||||
typename UNDIRECTED_GRAPH::internal_vertex_property(get(vertex_index, g.impl(), k), v));
|
||||
}
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, typename Key, typename Value>
|
||||
inline void put(edge_all_t, UNDIRECTED_GRAPH& g, Key const& k, Value const& v)
|
||||
{ put(edge_all, g.impl(), k,
|
||||
typename UNDIRECTED_GRAPH::internal_vertex_property(get(edge_index, g.impl(), k), v));
|
||||
}
|
||||
|
||||
template <UNDIRECTED_GRAPH_PARAMS, class Property>
|
||||
inline typename graph_property<UNDIRECTED_GRAPH, Property>::type&
|
||||
get_property(UNDIRECTED_GRAPH& g, Property p)
|
||||
|
||||
1125
include/boost/graph/vf2_sub_graph_iso.hpp
Executable file
1125
include/boost/graph/vf2_sub_graph_iso.hpp
Executable file
File diff suppressed because it is too large
Load Diff
@@ -244,6 +244,27 @@ namespace boost {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace detail {
|
||||
// Stuff for directed_graph and undirected_graph to skip over their first
|
||||
// vertex_index and edge_index properties when providing vertex_all and
|
||||
// edge_all; make sure you know the exact structure of your properties if you
|
||||
// use there.
|
||||
struct remove_first_property {
|
||||
template <typename F>
|
||||
struct result {
|
||||
typedef typename boost::function_traits<F>::arg1_type a1;
|
||||
typedef typename boost::remove_reference<a1>::type non_ref;
|
||||
typedef typename non_ref::next_type nx;
|
||||
typedef typename boost::mpl::if_<boost::is_const<non_ref>, boost::add_const<nx>, nx>::type with_const;
|
||||
typedef typename boost::add_reference<with_const>::type type;
|
||||
};
|
||||
template <typename Prop>
|
||||
typename Prop::next_type& operator()(Prop& p) const {return p.m_base;}
|
||||
template <typename Prop>
|
||||
const typename Prop::next_type& operator()(const Prop& p) const {return p.m_base;}
|
||||
};
|
||||
}
|
||||
|
||||
} // namesapce boost
|
||||
|
||||
#endif /* BOOST_PROPERTY_HPP */
|
||||
|
||||
@@ -34,17 +34,23 @@ public:
|
||||
}
|
||||
|
||||
static void get_graphs(const boost::property_tree::ptree& top,
|
||||
size_t desired_idx /* or -1 for all */,
|
||||
std::vector<const boost::property_tree::ptree*>& result) {
|
||||
using boost::property_tree::ptree;
|
||||
size_t current_idx = 0;
|
||||
BOOST_FOREACH(const ptree::value_type& n, top) {
|
||||
if (n.first == "graph") {
|
||||
result.push_back(&n.second);
|
||||
get_graphs(n.second, result);
|
||||
if (current_idx == desired_idx || desired_idx == (size_t)(-1)) {
|
||||
result.push_back(&n.second);
|
||||
get_graphs(n.second, (size_t)(-1), result);
|
||||
if (desired_idx != (size_t)(-1)) break;
|
||||
}
|
||||
++current_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run(std::istream& in)
|
||||
void run(std::istream& in, size_t desired_idx)
|
||||
{
|
||||
using boost::property_tree::ptree;
|
||||
ptree pt;
|
||||
@@ -74,7 +80,7 @@ public:
|
||||
}
|
||||
// Search for graphs
|
||||
std::vector<const ptree*> graphs;
|
||||
get_graphs(gml, graphs);
|
||||
get_graphs(gml, desired_idx, graphs);
|
||||
BOOST_FOREACH(const ptree* gr, graphs) {
|
||||
// Search for nodes
|
||||
BOOST_FOREACH(const ptree::value_type& node, *gr) {
|
||||
@@ -209,9 +215,9 @@ private:
|
||||
namespace boost
|
||||
{
|
||||
void BOOST_GRAPH_DECL
|
||||
read_graphml(std::istream& in, mutate_graph& g)
|
||||
read_graphml(std::istream& in, mutate_graph& g, size_t desired_idx)
|
||||
{
|
||||
graphml_reader reader(g);
|
||||
reader.run(in);
|
||||
reader.run(in, desired_idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ test-suite graph_test :
|
||||
[ run graphml_test.cpp ../build//boost_graph : : "graphml_test.xml" ]
|
||||
[ run stoer_wagner_test.cpp ../../test/build//boost_unit_test_framework/<link>static : $(TEST_DIR) ]
|
||||
[ compile filtered_graph_properties_dijkstra.cpp ]
|
||||
[ run vf2_sub_graph_iso_test.cpp ]
|
||||
;
|
||||
|
||||
# Run SDB tests only when -sSDB= is set.
|
||||
|
||||
293
test/vf2_sub_graph_iso_test.cpp
Normal file
293
test/vf2_sub_graph_iso_test.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
//=======================================================================
|
||||
// Boost.Graph library vf2_sub_graph_iso test
|
||||
// Adapted from isomorphism.cpp and mcgregor_subgraphs_test.cpp
|
||||
//
|
||||
// Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
|
||||
//
|
||||
// Distributed under 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)
|
||||
//=======================================================================
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <time.h>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/vf2_sub_graph_iso.hpp>
|
||||
#include <boost/graph/random.hpp>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
#include <boost/random/uniform_real.hpp>
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/graph/graphviz.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
|
||||
template <typename Generator>
|
||||
struct random_functor {
|
||||
random_functor(Generator& g) : g(g) { }
|
||||
std::size_t operator()(std::size_t n) {
|
||||
boost::uniform_int<std::size_t> distrib(0, n-1);
|
||||
boost::variate_generator<boost::mt19937&, boost::uniform_int<std::size_t> >
|
||||
x(g, distrib);
|
||||
return x();
|
||||
}
|
||||
Generator& g;
|
||||
};
|
||||
|
||||
|
||||
template<typename Graph1, typename Graph2>
|
||||
void randomly_permute_graph(Graph1& g1, const Graph2& g2) {
|
||||
BOOST_REQUIRE(num_vertices(g1) <= num_vertices(g2));
|
||||
BOOST_REQUIRE(num_edges(g1) == 0);
|
||||
|
||||
typedef typename graph_traits<Graph1>::vertex_descriptor vertex1;
|
||||
typedef typename graph_traits<Graph2>::vertex_descriptor vertex2;
|
||||
typedef typename graph_traits<Graph1>::vertex_iterator vertex_iterator;
|
||||
typedef typename graph_traits<Graph2>::edge_iterator edge_iterator;
|
||||
|
||||
boost::mt19937 gen;
|
||||
random_functor<boost::mt19937> rand_fun(gen);
|
||||
|
||||
// Decide new order
|
||||
std::vector<vertex2> orig_vertices;
|
||||
std::copy(vertices(g2).first, vertices(g2).second, std::back_inserter(orig_vertices));
|
||||
std::random_shuffle(orig_vertices.begin(), orig_vertices.end(), rand_fun);
|
||||
std::map<vertex2, vertex1> vertex_map;
|
||||
|
||||
std::size_t i = 0;
|
||||
for (vertex_iterator vi = vertices(g1).first;
|
||||
vi != vertices(g1).second; ++i, ++vi) {
|
||||
vertex_map[orig_vertices[i]] = *vi;
|
||||
put(vertex_name_t(), g1, *vi, get(vertex_name_t(), g2, orig_vertices[i]));
|
||||
}
|
||||
|
||||
for (edge_iterator ei = edges(g2).first; ei != edges(g2).second; ++ei) {
|
||||
typename std::map<vertex2, vertex1>::iterator si = vertex_map.find(source(*ei, g2)),
|
||||
ti = vertex_map.find(target(*ei, g2));
|
||||
if ((si != vertex_map.end()) && (ti != vertex_map.end()))
|
||||
add_edge(si->second, ti->second, get(edge_name_t(), g2, *ei), g1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Graph>
|
||||
void generate_random_digraph(Graph& g, double edge_probability,
|
||||
int max_parallel_edges, double parallel_edge_probability,
|
||||
int max_edge_name, int max_vertex_name) {
|
||||
|
||||
BOOST_REQUIRE((0 <= edge_probability) && (edge_probability <= 1));
|
||||
BOOST_REQUIRE((0 <= parallel_edge_probability) && (parallel_edge_probability <= 1));
|
||||
BOOST_REQUIRE(0 <= max_parallel_edges);
|
||||
BOOST_REQUIRE(0 <= max_edge_name);
|
||||
BOOST_REQUIRE(0 <= max_vertex_name);
|
||||
|
||||
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
||||
boost::mt19937 random_gen;
|
||||
boost::uniform_real<double> dist_real(0.0, 1.0);
|
||||
boost::variate_generator<boost::mt19937&, boost::uniform_real<double> >
|
||||
random_real_dist(random_gen, dist_real);
|
||||
|
||||
for (vertex_iterator u = vertices(g).first; u != vertices(g).second; ++u) {
|
||||
for (vertex_iterator v = vertices(g).first; v != vertices(g).second; ++v) {
|
||||
if (random_real_dist() <= edge_probability) {
|
||||
add_edge(*u, *v, g);
|
||||
for (int i = 0; i < max_parallel_edges; ++i) {
|
||||
if (random_real_dist() <= parallel_edge_probability)
|
||||
add_edge(*u, *v, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
boost::uniform_int<int> dist_int(0, max_edge_name);
|
||||
boost::variate_generator<boost::mt19937&, boost::uniform_int<int> >
|
||||
random_int_dist(random_gen, dist_int);
|
||||
randomize_property<vertex_name_t>(g, random_int_dist);
|
||||
}
|
||||
|
||||
{
|
||||
boost::uniform_int<int> dist_int(0, max_vertex_name);
|
||||
boost::variate_generator<boost::mt19937&, boost::uniform_int<int> >
|
||||
random_int_dist(random_gen, dist_int);
|
||||
|
||||
randomize_property<edge_name_t>(g, random_int_dist);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename Graph1,
|
||||
typename Graph2,
|
||||
typename EdgeEquivalencePredicate,
|
||||
typename VertexEquivalencePredicate>
|
||||
struct test_callback {
|
||||
|
||||
test_callback(const Graph1& graph1, const Graph2& graph2,
|
||||
EdgeEquivalencePredicate edge_comp,
|
||||
VertexEquivalencePredicate vertex_comp, bool output)
|
||||
: graph1_(graph1), graph2_(graph2), edge_comp_(edge_comp), vertex_comp_(vertex_comp),
|
||||
output_(output) {}
|
||||
|
||||
template <typename CorrespondenceMap1To2,
|
||||
typename CorrespondenceMap2To1>
|
||||
bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) {
|
||||
|
||||
bool verified;
|
||||
BOOST_CHECK(verified = verify_vf2_subgraph_iso(graph1_, graph2_, f, edge_comp_, vertex_comp_));
|
||||
|
||||
// Output (sub)graph isomorphism map
|
||||
if (!verified || output_) {
|
||||
std::cout << "Verfied: " << std::boolalpha << verified << std::endl;
|
||||
std::cout << "Num vertices: " << num_vertices(graph1_) << ' ' << num_vertices(graph2_) << std::endl;
|
||||
BGL_FORALL_VERTICES_T(v, graph1_, Graph1)
|
||||
std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", "
|
||||
<< get(vertex_index_t(), graph2_, get(f, v)) << ") ";
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const Graph1& graph1_;
|
||||
const Graph2& graph2_;
|
||||
EdgeEquivalencePredicate edge_comp_;
|
||||
VertexEquivalencePredicate vertex_comp_;
|
||||
bool output_;
|
||||
};
|
||||
|
||||
|
||||
void test_vf2_sub_graph_iso(int n1, int n2, double edge_probability,
|
||||
int max_parallel_edges, double parallel_edge_probability,
|
||||
int max_edge_name, int max_vertex_name, bool output) {
|
||||
|
||||
typedef property<edge_name_t, int> edge_property;
|
||||
typedef property<vertex_name_t, int, property<vertex_index_t, int> > vertex_property;
|
||||
|
||||
typedef adjacency_list<listS, listS, bidirectionalS, vertex_property, edge_property> graph1;
|
||||
typedef adjacency_list<vecS, vecS, bidirectionalS, vertex_property, edge_property> graph2;
|
||||
|
||||
graph1 g1(n1);
|
||||
graph2 g2(n2);
|
||||
generate_random_digraph(g2, edge_probability, max_parallel_edges, parallel_edge_probability,
|
||||
max_edge_name, max_vertex_name);
|
||||
randomly_permute_graph(g1, g2);
|
||||
|
||||
int v_idx = 0;
|
||||
for (graph_traits<graph1>::vertex_iterator vi = vertices(g1).first;
|
||||
vi != vertices(g1).second; ++vi) {
|
||||
put(vertex_index_t(), g1, *vi, v_idx++);
|
||||
}
|
||||
|
||||
|
||||
// Create vertex and edge predicates
|
||||
typedef property_map<graph1, vertex_name_t>::type vertex_name_map1;
|
||||
typedef property_map<graph2, vertex_name_t>::type vertex_name_map2;
|
||||
|
||||
typedef property_map_equivalent<vertex_name_map1, vertex_name_map2> vertex_predicate;
|
||||
vertex_predicate vertex_comp =
|
||||
make_property_map_equivalent(get(vertex_name, g1), get(vertex_name, g2));
|
||||
|
||||
typedef property_map<graph1, edge_name_t>::type edge_name_map1;
|
||||
typedef property_map<graph2, edge_name_t>::type edge_name_map2;
|
||||
|
||||
typedef property_map_equivalent<edge_name_map1, edge_name_map2> edge_predicate;
|
||||
edge_predicate edge_comp =
|
||||
make_property_map_equivalent(get(edge_name, g1), get(edge_name, g2));
|
||||
|
||||
|
||||
std::clock_t start = std::clock();
|
||||
|
||||
// Create callback
|
||||
test_callback<graph1, graph2, edge_predicate, vertex_predicate>
|
||||
callback(g1, g2, edge_comp, vertex_comp, output);
|
||||
|
||||
std::cout << std::endl;
|
||||
BOOST_CHECK(vf2_subgraph_iso(g1, g2, callback, vertex_order_by_mult(g1),
|
||||
edges_equivalent(edge_comp).vertices_equivalent(vertex_comp)));
|
||||
|
||||
std::clock_t end1 = std::clock();
|
||||
std::cout << "vf2_subgraph_iso: elapsed time (clock cycles): " << (end1 - start) << std::endl;
|
||||
|
||||
if (num_vertices(g1) == num_vertices(g2)) {
|
||||
std::cout << std::endl;
|
||||
BOOST_CHECK(vf2_graph_iso(g1, g2, callback, vertex_order_by_mult(g1),
|
||||
edges_equivalent(edge_comp).vertices_equivalent(vertex_comp)));
|
||||
|
||||
std::clock_t end2 = std::clock();
|
||||
std::cout << "vf2_graph_iso: elapsed time (clock cycles): " << (end2 - end1) << std::endl;
|
||||
}
|
||||
|
||||
if (output) {
|
||||
std::fstream file_graph1("graph1.dot", std::fstream::out);
|
||||
write_graphviz(file_graph1, g1,
|
||||
make_label_writer(get(boost::vertex_name, g1)),
|
||||
make_label_writer(get(boost::edge_name, g1)));
|
||||
|
||||
std::fstream file_graph2("graph2.dot", std::fstream::out);
|
||||
write_graphviz(file_graph2, g2,
|
||||
make_label_writer(get(boost::vertex_name, g2)),
|
||||
make_label_writer(get(boost::edge_name, g2)));
|
||||
}
|
||||
}
|
||||
|
||||
int test_main(int argc, char* argv[]) {
|
||||
|
||||
int num_vertices_g1 = 10;
|
||||
int num_vertices_g2 = 20;
|
||||
double edge_probability = 0.4;
|
||||
int max_parallel_edges = 2;
|
||||
double parallel_edge_probability = 0.4;
|
||||
int max_edge_name = 5;
|
||||
int max_vertex_name = 5;
|
||||
bool output = false;
|
||||
|
||||
if (argc > 1) {
|
||||
num_vertices_g1 = boost::lexical_cast<int>(argv[1]);
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
num_vertices_g2 = boost::lexical_cast<int>(argv[2]);
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
edge_probability = boost::lexical_cast<double>(argv[3]);
|
||||
}
|
||||
|
||||
if (argc > 4) {
|
||||
max_parallel_edges = boost::lexical_cast<int>(argv[4]);
|
||||
}
|
||||
|
||||
if (argc > 5) {
|
||||
parallel_edge_probability = boost::lexical_cast<double>(argv[5]);
|
||||
}
|
||||
|
||||
if (argc > 6) {
|
||||
max_edge_name = boost::lexical_cast<int>(argv[6]);
|
||||
}
|
||||
|
||||
if (argc > 7) {
|
||||
max_vertex_name = boost::lexical_cast<int>(argv[7]);
|
||||
}
|
||||
|
||||
if (argc > 8) {
|
||||
output = boost::lexical_cast<bool>(argv[8]);
|
||||
}
|
||||
|
||||
test_vf2_sub_graph_iso(num_vertices_g1, num_vertices_g2, edge_probability,
|
||||
max_parallel_edges, parallel_edge_probability,
|
||||
max_edge_name, max_vertex_name, output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user