Chris@16
|
1 //=======================================================================
|
Chris@16
|
2 // Copyright 2009 Trustees of Indiana University.
|
Chris@16
|
3 // Authors: Michael Hansen, Andrew Lumsdaine
|
Chris@16
|
4 //
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 //=======================================================================
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP
|
Chris@16
|
11 #define BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #include <algorithm>
|
Chris@16
|
14 #include <vector>
|
Chris@16
|
15 #include <stack>
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/make_shared.hpp>
|
Chris@16
|
18 #include <boost/graph/adjacency_list.hpp>
|
Chris@16
|
19 #include <boost/graph/filtered_graph.hpp>
|
Chris@16
|
20 #include <boost/graph/graph_utility.hpp>
|
Chris@16
|
21 #include <boost/graph/iteration_macros.hpp>
|
Chris@16
|
22 #include <boost/graph/properties.hpp>
|
Chris@16
|
23 #include <boost/property_map/shared_array_property_map.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 namespace boost {
|
Chris@16
|
26
|
Chris@16
|
27 namespace detail {
|
Chris@16
|
28
|
Chris@16
|
29 // Traits associated with common subgraphs, used mainly to keep a
|
Chris@16
|
30 // consistent type for the correspondence maps.
|
Chris@16
|
31 template <typename GraphFirst,
|
Chris@16
|
32 typename GraphSecond,
|
Chris@16
|
33 typename VertexIndexMapFirst,
|
Chris@16
|
34 typename VertexIndexMapSecond>
|
Chris@16
|
35 struct mcgregor_common_subgraph_traits {
|
Chris@16
|
36 typedef typename graph_traits<GraphFirst>::vertex_descriptor vertex_first_type;
|
Chris@16
|
37 typedef typename graph_traits<GraphSecond>::vertex_descriptor vertex_second_type;
|
Chris@16
|
38
|
Chris@16
|
39 typedef shared_array_property_map<vertex_second_type, VertexIndexMapFirst>
|
Chris@16
|
40 correspondence_map_first_to_second_type;
|
Chris@16
|
41
|
Chris@16
|
42 typedef shared_array_property_map<vertex_first_type, VertexIndexMapSecond>
|
Chris@16
|
43 correspondence_map_second_to_first_type;
|
Chris@16
|
44 };
|
Chris@16
|
45
|
Chris@16
|
46 } // namespace detail
|
Chris@16
|
47
|
Chris@16
|
48 // ==========================================================================
|
Chris@16
|
49
|
Chris@16
|
50 // Binary function object that returns true if the values for item1
|
Chris@16
|
51 // in property_map1 and item2 in property_map2 are equivalent.
|
Chris@16
|
52 template <typename PropertyMapFirst,
|
Chris@16
|
53 typename PropertyMapSecond>
|
Chris@16
|
54 struct property_map_equivalent {
|
Chris@16
|
55
|
Chris@16
|
56 property_map_equivalent(const PropertyMapFirst property_map1,
|
Chris@16
|
57 const PropertyMapSecond property_map2) :
|
Chris@16
|
58 m_property_map1(property_map1),
|
Chris@16
|
59 m_property_map2(property_map2) { }
|
Chris@16
|
60
|
Chris@16
|
61 template <typename ItemFirst,
|
Chris@16
|
62 typename ItemSecond>
|
Chris@16
|
63 bool operator()(const ItemFirst item1, const ItemSecond item2) {
|
Chris@16
|
64 return (get(m_property_map1, item1) == get(m_property_map2, item2));
|
Chris@16
|
65 }
|
Chris@16
|
66
|
Chris@16
|
67 private:
|
Chris@16
|
68 const PropertyMapFirst m_property_map1;
|
Chris@16
|
69 const PropertyMapSecond m_property_map2;
|
Chris@16
|
70 };
|
Chris@16
|
71
|
Chris@16
|
72 // Returns a property_map_equivalent object that compares the values
|
Chris@16
|
73 // of property_map1 and property_map2.
|
Chris@16
|
74 template <typename PropertyMapFirst,
|
Chris@16
|
75 typename PropertyMapSecond>
|
Chris@16
|
76 property_map_equivalent<PropertyMapFirst,
|
Chris@16
|
77 PropertyMapSecond>
|
Chris@16
|
78 make_property_map_equivalent
|
Chris@16
|
79 (const PropertyMapFirst property_map1,
|
Chris@16
|
80 const PropertyMapSecond property_map2) {
|
Chris@16
|
81
|
Chris@16
|
82 return (property_map_equivalent<PropertyMapFirst, PropertyMapSecond>
|
Chris@16
|
83 (property_map1, property_map2));
|
Chris@16
|
84 }
|
Chris@16
|
85
|
Chris@16
|
86 // Binary function object that always returns true. Used when
|
Chris@16
|
87 // vertices or edges are always equivalent (i.e. have no labels).
|
Chris@16
|
88 struct always_equivalent {
|
Chris@16
|
89
|
Chris@16
|
90 template <typename ItemFirst,
|
Chris@16
|
91 typename ItemSecond>
|
Chris@16
|
92 bool operator()(const ItemFirst&, const ItemSecond&) {
|
Chris@16
|
93 return (true);
|
Chris@16
|
94 }
|
Chris@16
|
95 };
|
Chris@16
|
96
|
Chris@16
|
97 // ==========================================================================
|
Chris@16
|
98
|
Chris@16
|
99 namespace detail {
|
Chris@16
|
100
|
Chris@16
|
101 // Return true if new_vertex1 and new_vertex2 can extend the
|
Chris@16
|
102 // subgraph represented by correspondence_map_1_to_2 and
|
Chris@16
|
103 // correspondence_map_2_to_1. The vertices_equivalent and
|
Chris@16
|
104 // edges_equivalent predicates are used to test vertex and edge
|
Chris@16
|
105 // equivalency between the two graphs.
|
Chris@16
|
106 template <typename GraphFirst,
|
Chris@16
|
107 typename GraphSecond,
|
Chris@16
|
108 typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
109 typename CorrespondenceMapSecondToFirst,
|
Chris@16
|
110 typename EdgeEquivalencePredicate,
|
Chris@16
|
111 typename VertexEquivalencePredicate>
|
Chris@16
|
112 bool can_extend_graph
|
Chris@16
|
113 (const GraphFirst& graph1,
|
Chris@16
|
114 const GraphSecond& graph2,
|
Chris@16
|
115 CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
116 CorrespondenceMapSecondToFirst /*correspondence_map_2_to_1*/,
|
Chris@16
|
117 typename graph_traits<GraphFirst>::vertices_size_type subgraph_size,
|
Chris@16
|
118 typename graph_traits<GraphFirst>::vertex_descriptor new_vertex1,
|
Chris@16
|
119 typename graph_traits<GraphSecond>::vertex_descriptor new_vertex2,
|
Chris@16
|
120 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
121 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
122 bool only_connected_subgraphs)
|
Chris@16
|
123 {
|
Chris@16
|
124 typedef typename graph_traits<GraphSecond>::vertex_descriptor VertexSecond;
|
Chris@16
|
125
|
Chris@16
|
126 typedef typename graph_traits<GraphFirst>::edge_descriptor EdgeFirst;
|
Chris@16
|
127 typedef typename graph_traits<GraphSecond>::edge_descriptor EdgeSecond;
|
Chris@16
|
128
|
Chris@16
|
129 // Check vertex equality
|
Chris@16
|
130 if (!vertices_equivalent(new_vertex1, new_vertex2)) {
|
Chris@16
|
131 return (false);
|
Chris@16
|
132 }
|
Chris@16
|
133
|
Chris@16
|
134 // Vertices match and graph is empty, so we can extend the subgraph
|
Chris@16
|
135 if (subgraph_size == 0) {
|
Chris@16
|
136 return (true);
|
Chris@16
|
137 }
|
Chris@16
|
138
|
Chris@16
|
139 bool has_one_edge = false;
|
Chris@16
|
140
|
Chris@16
|
141 // Verify edges with existing sub-graph
|
Chris@16
|
142 BGL_FORALL_VERTICES_T(existing_vertex1, graph1, GraphFirst) {
|
Chris@16
|
143
|
Chris@16
|
144 VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, existing_vertex1);
|
Chris@16
|
145
|
Chris@16
|
146 // Skip unassociated vertices
|
Chris@16
|
147 if (existing_vertex2 == graph_traits<GraphSecond>::null_vertex()) {
|
Chris@16
|
148 continue;
|
Chris@16
|
149 }
|
Chris@16
|
150
|
Chris@16
|
151 // NOTE: This will not work with parallel edges, since the
|
Chris@16
|
152 // first matching edge is always chosen.
|
Chris@16
|
153 EdgeFirst edge_to_new1, edge_from_new1;
|
Chris@16
|
154 bool edge_to_new_exists1 = false, edge_from_new_exists1 = false;
|
Chris@16
|
155
|
Chris@16
|
156 EdgeSecond edge_to_new2, edge_from_new2;
|
Chris@16
|
157 bool edge_to_new_exists2 = false, edge_from_new_exists2 = false;
|
Chris@16
|
158
|
Chris@16
|
159 // Search for edge from existing to new vertex (graph1)
|
Chris@16
|
160 BGL_FORALL_OUTEDGES_T(existing_vertex1, edge1, graph1, GraphFirst) {
|
Chris@16
|
161 if (target(edge1, graph1) == new_vertex1) {
|
Chris@16
|
162 edge_to_new1 = edge1;
|
Chris@16
|
163 edge_to_new_exists1 = true;
|
Chris@16
|
164 break;
|
Chris@16
|
165 }
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 // Search for edge from existing to new vertex (graph2)
|
Chris@16
|
169 BGL_FORALL_OUTEDGES_T(existing_vertex2, edge2, graph2, GraphSecond) {
|
Chris@16
|
170 if (target(edge2, graph2) == new_vertex2) {
|
Chris@16
|
171 edge_to_new2 = edge2;
|
Chris@16
|
172 edge_to_new_exists2 = true;
|
Chris@16
|
173 break;
|
Chris@16
|
174 }
|
Chris@16
|
175 }
|
Chris@16
|
176
|
Chris@16
|
177 // Make sure edges from existing to new vertices are equivalent
|
Chris@16
|
178 if ((edge_to_new_exists1 != edge_to_new_exists2) ||
|
Chris@16
|
179 ((edge_to_new_exists1 && edge_to_new_exists2) &&
|
Chris@16
|
180 !edges_equivalent(edge_to_new1, edge_to_new2))) {
|
Chris@16
|
181
|
Chris@16
|
182 return (false);
|
Chris@16
|
183 }
|
Chris@16
|
184
|
Chris@16
|
185 bool is_undirected1 = is_undirected(graph1),
|
Chris@16
|
186 is_undirected2 = is_undirected(graph2);
|
Chris@16
|
187
|
Chris@16
|
188 if (is_undirected1 && is_undirected2) {
|
Chris@16
|
189
|
Chris@16
|
190 // Edge in both graphs exists and both graphs are undirected
|
Chris@16
|
191 if (edge_to_new_exists1 && edge_to_new_exists2) {
|
Chris@16
|
192 has_one_edge = true;
|
Chris@16
|
193 }
|
Chris@16
|
194
|
Chris@16
|
195 continue;
|
Chris@16
|
196 }
|
Chris@16
|
197 else {
|
Chris@16
|
198
|
Chris@16
|
199 if (!is_undirected1) {
|
Chris@16
|
200
|
Chris@16
|
201 // Search for edge from new to existing vertex (graph1)
|
Chris@16
|
202 BGL_FORALL_OUTEDGES_T(new_vertex1, edge1, graph1, GraphFirst) {
|
Chris@16
|
203 if (target(edge1, graph1) == existing_vertex1) {
|
Chris@16
|
204 edge_from_new1 = edge1;
|
Chris@16
|
205 edge_from_new_exists1 = true;
|
Chris@16
|
206 break;
|
Chris@16
|
207 }
|
Chris@16
|
208 }
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 if (!is_undirected2) {
|
Chris@16
|
212
|
Chris@16
|
213 // Search for edge from new to existing vertex (graph2)
|
Chris@16
|
214 BGL_FORALL_OUTEDGES_T(new_vertex2, edge2, graph2, GraphSecond) {
|
Chris@16
|
215 if (target(edge2, graph2) == existing_vertex2) {
|
Chris@16
|
216 edge_from_new2 = edge2;
|
Chris@16
|
217 edge_from_new_exists2 = true;
|
Chris@16
|
218 break;
|
Chris@16
|
219 }
|
Chris@16
|
220 }
|
Chris@16
|
221 }
|
Chris@16
|
222
|
Chris@16
|
223 // Make sure edges from new to existing vertices are equivalent
|
Chris@16
|
224 if ((edge_from_new_exists1 != edge_from_new_exists2) ||
|
Chris@16
|
225 ((edge_from_new_exists1 && edge_from_new_exists2) &&
|
Chris@16
|
226 !edges_equivalent(edge_from_new1, edge_from_new2))) {
|
Chris@16
|
227
|
Chris@16
|
228 return (false);
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 if ((edge_from_new_exists1 && edge_from_new_exists2) ||
|
Chris@16
|
232 (edge_to_new_exists1 && edge_to_new_exists2)) {
|
Chris@16
|
233 has_one_edge = true;
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 } // else
|
Chris@16
|
237
|
Chris@16
|
238 } // BGL_FORALL_VERTICES_T
|
Chris@16
|
239
|
Chris@16
|
240 // Make sure new vertices are connected to the existing subgraph
|
Chris@16
|
241 if (only_connected_subgraphs && !has_one_edge) {
|
Chris@16
|
242 return (false);
|
Chris@16
|
243 }
|
Chris@16
|
244
|
Chris@16
|
245 return (true);
|
Chris@16
|
246 }
|
Chris@16
|
247
|
Chris@16
|
248 // Recursive method that does a depth-first search in the space of
|
Chris@16
|
249 // potential subgraphs. At each level, every new vertex pair from
|
Chris@16
|
250 // both graphs is tested to see if it can extend the current
|
Chris@16
|
251 // subgraph. If so, the subgraph is output to subgraph_callback
|
Chris@16
|
252 // in the form of two correspondence maps (one for each graph).
|
Chris@16
|
253 // Returning false from subgraph_callback will terminate the
|
Chris@16
|
254 // search. Function returns true if the entire search space was
|
Chris@16
|
255 // explored.
|
Chris@16
|
256 template <typename GraphFirst,
|
Chris@16
|
257 typename GraphSecond,
|
Chris@16
|
258 typename VertexIndexMapFirst,
|
Chris@16
|
259 typename VertexIndexMapSecond,
|
Chris@16
|
260 typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
261 typename CorrespondenceMapSecondToFirst,
|
Chris@16
|
262 typename VertexStackFirst,
|
Chris@16
|
263 typename EdgeEquivalencePredicate,
|
Chris@16
|
264 typename VertexEquivalencePredicate,
|
Chris@16
|
265 typename SubGraphInternalCallback>
|
Chris@16
|
266 bool mcgregor_common_subgraphs_internal
|
Chris@16
|
267 (const GraphFirst& graph1,
|
Chris@16
|
268 const GraphSecond& graph2,
|
Chris@16
|
269 const VertexIndexMapFirst& vindex_map1,
|
Chris@16
|
270 const VertexIndexMapSecond& vindex_map2,
|
Chris@16
|
271 CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
272 CorrespondenceMapSecondToFirst correspondence_map_2_to_1,
|
Chris@16
|
273 VertexStackFirst& vertex_stack1,
|
Chris@16
|
274 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
275 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
276 bool only_connected_subgraphs,
|
Chris@16
|
277 SubGraphInternalCallback subgraph_callback)
|
Chris@16
|
278 {
|
Chris@16
|
279 typedef typename graph_traits<GraphFirst>::vertex_descriptor VertexFirst;
|
Chris@16
|
280 typedef typename graph_traits<GraphSecond>::vertex_descriptor VertexSecond;
|
Chris@16
|
281 typedef typename graph_traits<GraphFirst>::vertices_size_type VertexSizeFirst;
|
Chris@16
|
282
|
Chris@16
|
283 // Get iterators for vertices from both graphs
|
Chris@16
|
284 typename graph_traits<GraphFirst>::vertex_iterator
|
Chris@16
|
285 vertex1_iter, vertex1_end;
|
Chris@16
|
286
|
Chris@16
|
287 typename graph_traits<GraphSecond>::vertex_iterator
|
Chris@16
|
288 vertex2_begin, vertex2_end, vertex2_iter;
|
Chris@16
|
289
|
Chris@16
|
290 boost::tie(vertex1_iter, vertex1_end) = vertices(graph1);
|
Chris@16
|
291 boost::tie(vertex2_begin, vertex2_end) = vertices(graph2);
|
Chris@16
|
292 vertex2_iter = vertex2_begin;
|
Chris@16
|
293
|
Chris@16
|
294 // Iterate until all vertices have been visited
|
Chris@16
|
295 BGL_FORALL_VERTICES_T(new_vertex1, graph1, GraphFirst) {
|
Chris@16
|
296
|
Chris@16
|
297 VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, new_vertex1);
|
Chris@16
|
298
|
Chris@16
|
299 // Skip already matched vertices in first graph
|
Chris@16
|
300 if (existing_vertex2 != graph_traits<GraphSecond>::null_vertex()) {
|
Chris@16
|
301 continue;
|
Chris@16
|
302 }
|
Chris@16
|
303
|
Chris@16
|
304 BGL_FORALL_VERTICES_T(new_vertex2, graph2, GraphSecond) {
|
Chris@16
|
305
|
Chris@16
|
306 VertexFirst existing_vertex1 = get(correspondence_map_2_to_1, new_vertex2);
|
Chris@16
|
307
|
Chris@16
|
308 // Skip already matched vertices in second graph
|
Chris@16
|
309 if (existing_vertex1 != graph_traits<GraphFirst>::null_vertex()) {
|
Chris@16
|
310 continue;
|
Chris@16
|
311 }
|
Chris@16
|
312
|
Chris@16
|
313 // Check if current sub-graph can be extended with the matched vertex pair
|
Chris@16
|
314 if (can_extend_graph(graph1, graph2,
|
Chris@16
|
315 correspondence_map_1_to_2, correspondence_map_2_to_1,
|
Chris@16
|
316 (VertexSizeFirst)vertex_stack1.size(),
|
Chris@16
|
317 new_vertex1, new_vertex2,
|
Chris@16
|
318 edges_equivalent, vertices_equivalent,
|
Chris@16
|
319 only_connected_subgraphs)) {
|
Chris@16
|
320
|
Chris@16
|
321 // Keep track of old graph size for restoring later
|
Chris@16
|
322 VertexSizeFirst old_graph_size = (VertexSizeFirst)vertex_stack1.size(),
|
Chris@16
|
323 new_graph_size = old_graph_size + 1;
|
Chris@16
|
324
|
Chris@16
|
325 // Extend subgraph
|
Chris@16
|
326 put(correspondence_map_1_to_2, new_vertex1, new_vertex2);
|
Chris@16
|
327 put(correspondence_map_2_to_1, new_vertex2, new_vertex1);
|
Chris@16
|
328 vertex_stack1.push(new_vertex1);
|
Chris@16
|
329
|
Chris@101
|
330 // Returning false from the callback will cancel iteration
|
Chris@101
|
331 if (!subgraph_callback(correspondence_map_1_to_2,
|
Chris@101
|
332 correspondence_map_2_to_1,
|
Chris@101
|
333 new_graph_size)) {
|
Chris@101
|
334 return (false);
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 // Depth-first search into the state space of possible sub-graphs
|
Chris@16
|
338 bool continue_iteration =
|
Chris@16
|
339 mcgregor_common_subgraphs_internal
|
Chris@16
|
340 (graph1, graph2,
|
Chris@16
|
341 vindex_map1, vindex_map2,
|
Chris@16
|
342 correspondence_map_1_to_2, correspondence_map_2_to_1,
|
Chris@16
|
343 vertex_stack1,
|
Chris@16
|
344 edges_equivalent, vertices_equivalent,
|
Chris@16
|
345 only_connected_subgraphs, subgraph_callback);
|
Chris@16
|
346
|
Chris@16
|
347 if (!continue_iteration) {
|
Chris@16
|
348 return (false);
|
Chris@16
|
349 }
|
Chris@16
|
350
|
Chris@16
|
351 // Restore previous state
|
Chris@16
|
352 if (vertex_stack1.size() > old_graph_size) {
|
Chris@16
|
353
|
Chris@16
|
354 VertexFirst stack_vertex1 = vertex_stack1.top();
|
Chris@16
|
355 VertexSecond stack_vertex2 = get(correspondence_map_1_to_2,
|
Chris@16
|
356 stack_vertex1);
|
Chris@16
|
357
|
Chris@16
|
358 // Contract subgraph
|
Chris@16
|
359 put(correspondence_map_1_to_2, stack_vertex1,
|
Chris@16
|
360 graph_traits<GraphSecond>::null_vertex());
|
Chris@16
|
361
|
Chris@16
|
362 put(correspondence_map_2_to_1, stack_vertex2,
|
Chris@16
|
363 graph_traits<GraphFirst>::null_vertex());
|
Chris@16
|
364
|
Chris@16
|
365 vertex_stack1.pop();
|
Chris@16
|
366 }
|
Chris@16
|
367
|
Chris@16
|
368 } // if can_extend_graph
|
Chris@16
|
369
|
Chris@16
|
370 } // BGL_FORALL_VERTICES_T (graph2)
|
Chris@16
|
371
|
Chris@16
|
372 } // BGL_FORALL_VERTICES_T (graph1)
|
Chris@16
|
373
|
Chris@16
|
374 return (true);
|
Chris@16
|
375 }
|
Chris@16
|
376
|
Chris@16
|
377 // Internal method that initializes blank correspondence maps and
|
Chris@16
|
378 // a vertex stack for use in mcgregor_common_subgraphs_internal.
|
Chris@16
|
379 template <typename GraphFirst,
|
Chris@16
|
380 typename GraphSecond,
|
Chris@16
|
381 typename VertexIndexMapFirst,
|
Chris@16
|
382 typename VertexIndexMapSecond,
|
Chris@16
|
383 typename EdgeEquivalencePredicate,
|
Chris@16
|
384 typename VertexEquivalencePredicate,
|
Chris@16
|
385 typename SubGraphInternalCallback>
|
Chris@16
|
386 inline void mcgregor_common_subgraphs_internal_init
|
Chris@16
|
387 (const GraphFirst& graph1,
|
Chris@16
|
388 const GraphSecond& graph2,
|
Chris@16
|
389 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
390 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
391 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
392 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
393 bool only_connected_subgraphs,
|
Chris@16
|
394 SubGraphInternalCallback subgraph_callback)
|
Chris@16
|
395 {
|
Chris@16
|
396 typedef mcgregor_common_subgraph_traits<GraphFirst,
|
Chris@16
|
397 GraphSecond, VertexIndexMapFirst,
|
Chris@16
|
398 VertexIndexMapSecond> SubGraphTraits;
|
Chris@16
|
399
|
Chris@16
|
400 typename SubGraphTraits::correspondence_map_first_to_second_type
|
Chris@16
|
401 correspondence_map_1_to_2(num_vertices(graph1), vindex_map1);
|
Chris@16
|
402
|
Chris@16
|
403 BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) {
|
Chris@16
|
404 put(correspondence_map_1_to_2, vertex1,
|
Chris@16
|
405 graph_traits<GraphSecond>::null_vertex());
|
Chris@16
|
406 }
|
Chris@16
|
407
|
Chris@16
|
408 typename SubGraphTraits::correspondence_map_second_to_first_type
|
Chris@16
|
409 correspondence_map_2_to_1(num_vertices(graph2), vindex_map2);
|
Chris@16
|
410
|
Chris@16
|
411 BGL_FORALL_VERTICES_T(vertex2, graph2, GraphSecond) {
|
Chris@16
|
412 put(correspondence_map_2_to_1, vertex2,
|
Chris@16
|
413 graph_traits<GraphFirst>::null_vertex());
|
Chris@16
|
414 }
|
Chris@16
|
415
|
Chris@16
|
416 typedef typename graph_traits<GraphFirst>::vertex_descriptor
|
Chris@16
|
417 VertexFirst;
|
Chris@16
|
418
|
Chris@16
|
419 std::stack<VertexFirst> vertex_stack1;
|
Chris@16
|
420
|
Chris@16
|
421 mcgregor_common_subgraphs_internal
|
Chris@16
|
422 (graph1, graph2,
|
Chris@16
|
423 vindex_map1, vindex_map2,
|
Chris@16
|
424 correspondence_map_1_to_2, correspondence_map_2_to_1,
|
Chris@16
|
425 vertex_stack1,
|
Chris@16
|
426 edges_equivalent, vertices_equivalent,
|
Chris@16
|
427 only_connected_subgraphs,
|
Chris@16
|
428 subgraph_callback);
|
Chris@16
|
429 }
|
Chris@16
|
430
|
Chris@16
|
431 } // namespace detail
|
Chris@16
|
432
|
Chris@16
|
433 // ==========================================================================
|
Chris@16
|
434
|
Chris@16
|
435 // Enumerates all common subgraphs present in graph1 and graph2.
|
Chris@16
|
436 // Continues until the search space has been fully explored or false
|
Chris@16
|
437 // is returned from user_callback.
|
Chris@16
|
438 template <typename GraphFirst,
|
Chris@16
|
439 typename GraphSecond,
|
Chris@16
|
440 typename VertexIndexMapFirst,
|
Chris@16
|
441 typename VertexIndexMapSecond,
|
Chris@16
|
442 typename EdgeEquivalencePredicate,
|
Chris@16
|
443 typename VertexEquivalencePredicate,
|
Chris@16
|
444 typename SubGraphCallback>
|
Chris@16
|
445 void mcgregor_common_subgraphs
|
Chris@16
|
446 (const GraphFirst& graph1,
|
Chris@16
|
447 const GraphSecond& graph2,
|
Chris@16
|
448 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
449 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
450 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
451 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
452 bool only_connected_subgraphs,
|
Chris@16
|
453 SubGraphCallback user_callback)
|
Chris@16
|
454 {
|
Chris@16
|
455
|
Chris@16
|
456 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
457 (graph1, graph2,
|
Chris@16
|
458 vindex_map1, vindex_map2,
|
Chris@16
|
459 edges_equivalent, vertices_equivalent,
|
Chris@16
|
460 only_connected_subgraphs,
|
Chris@16
|
461 user_callback);
|
Chris@16
|
462 }
|
Chris@16
|
463
|
Chris@16
|
464 // Variant of mcgregor_common_subgraphs with all default parameters
|
Chris@16
|
465 template <typename GraphFirst,
|
Chris@16
|
466 typename GraphSecond,
|
Chris@16
|
467 typename SubGraphCallback>
|
Chris@16
|
468 void mcgregor_common_subgraphs
|
Chris@16
|
469 (const GraphFirst& graph1,
|
Chris@16
|
470 const GraphSecond& graph2,
|
Chris@16
|
471 bool only_connected_subgraphs,
|
Chris@16
|
472 SubGraphCallback user_callback)
|
Chris@16
|
473 {
|
Chris@16
|
474
|
Chris@16
|
475 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
476 (graph1, graph2,
|
Chris@16
|
477 get(vertex_index, graph1), get(vertex_index, graph2),
|
Chris@16
|
478 always_equivalent(), always_equivalent(),
|
Chris@16
|
479 only_connected_subgraphs, user_callback);
|
Chris@16
|
480 }
|
Chris@16
|
481
|
Chris@16
|
482 // Named parameter variant of mcgregor_common_subgraphs
|
Chris@16
|
483 template <typename GraphFirst,
|
Chris@16
|
484 typename GraphSecond,
|
Chris@16
|
485 typename SubGraphCallback,
|
Chris@16
|
486 typename Param,
|
Chris@16
|
487 typename Tag,
|
Chris@16
|
488 typename Rest>
|
Chris@16
|
489 void mcgregor_common_subgraphs
|
Chris@16
|
490 (const GraphFirst& graph1,
|
Chris@16
|
491 const GraphSecond& graph2,
|
Chris@16
|
492 bool only_connected_subgraphs,
|
Chris@16
|
493 SubGraphCallback user_callback,
|
Chris@16
|
494 const bgl_named_params<Param, Tag, Rest>& params)
|
Chris@16
|
495 {
|
Chris@16
|
496
|
Chris@16
|
497 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
498 (graph1, graph2,
|
Chris@16
|
499 choose_const_pmap(get_param(params, vertex_index1),
|
Chris@16
|
500 graph1, vertex_index),
|
Chris@16
|
501 choose_const_pmap(get_param(params, vertex_index2),
|
Chris@16
|
502 graph2, vertex_index),
|
Chris@16
|
503 choose_param(get_param(params, edges_equivalent_t()),
|
Chris@16
|
504 always_equivalent()),
|
Chris@16
|
505 choose_param(get_param(params, vertices_equivalent_t()),
|
Chris@16
|
506 always_equivalent()),
|
Chris@16
|
507 only_connected_subgraphs, user_callback);
|
Chris@16
|
508 }
|
Chris@16
|
509
|
Chris@16
|
510 // ==========================================================================
|
Chris@16
|
511
|
Chris@16
|
512 namespace detail {
|
Chris@16
|
513
|
Chris@16
|
514 // Binary function object that intercepts subgraphs from
|
Chris@16
|
515 // mcgregor_common_subgraphs_internal and maintains a cache of
|
Chris@16
|
516 // unique subgraphs. The user callback is invoked for each unique
|
Chris@16
|
517 // subgraph.
|
Chris@16
|
518 template <typename GraphFirst,
|
Chris@16
|
519 typename GraphSecond,
|
Chris@16
|
520 typename VertexIndexMapFirst,
|
Chris@16
|
521 typename VertexIndexMapSecond,
|
Chris@16
|
522 typename SubGraphCallback>
|
Chris@16
|
523 struct unique_subgraph_interceptor {
|
Chris@16
|
524
|
Chris@16
|
525 typedef typename graph_traits<GraphFirst>::vertices_size_type
|
Chris@16
|
526 VertexSizeFirst;
|
Chris@16
|
527
|
Chris@16
|
528 typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond,
|
Chris@16
|
529 VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits;
|
Chris@16
|
530
|
Chris@16
|
531 typedef typename SubGraphTraits::correspondence_map_first_to_second_type
|
Chris@16
|
532 CachedCorrespondenceMapFirstToSecond;
|
Chris@16
|
533
|
Chris@16
|
534 typedef typename SubGraphTraits::correspondence_map_second_to_first_type
|
Chris@16
|
535 CachedCorrespondenceMapSecondToFirst;
|
Chris@16
|
536
|
Chris@16
|
537 typedef std::pair<VertexSizeFirst,
|
Chris@16
|
538 std::pair<CachedCorrespondenceMapFirstToSecond,
|
Chris@16
|
539 CachedCorrespondenceMapSecondToFirst> > SubGraph;
|
Chris@16
|
540
|
Chris@16
|
541 typedef std::vector<SubGraph> SubGraphList;
|
Chris@16
|
542
|
Chris@16
|
543 unique_subgraph_interceptor(const GraphFirst& graph1,
|
Chris@16
|
544 const GraphSecond& graph2,
|
Chris@16
|
545 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
546 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
547 SubGraphCallback user_callback) :
|
Chris@16
|
548 m_graph1(graph1), m_graph2(graph2),
|
Chris@16
|
549 m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2),
|
Chris@16
|
550 m_subgraphs(make_shared<SubGraphList>()),
|
Chris@16
|
551 m_user_callback(user_callback) { }
|
Chris@16
|
552
|
Chris@16
|
553 template <typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
554 typename CorrespondenceMapSecondToFirst>
|
Chris@16
|
555 bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
556 CorrespondenceMapSecondToFirst correspondence_map_2_to_1,
|
Chris@16
|
557 VertexSizeFirst subgraph_size) {
|
Chris@16
|
558
|
Chris@16
|
559 for (typename SubGraphList::const_iterator
|
Chris@16
|
560 subgraph_iter = m_subgraphs->begin();
|
Chris@16
|
561 subgraph_iter != m_subgraphs->end();
|
Chris@16
|
562 ++subgraph_iter) {
|
Chris@16
|
563
|
Chris@16
|
564 SubGraph subgraph_cached = *subgraph_iter;
|
Chris@16
|
565
|
Chris@16
|
566 // Compare subgraph sizes
|
Chris@16
|
567 if (subgraph_size != subgraph_cached.first) {
|
Chris@16
|
568 continue;
|
Chris@16
|
569 }
|
Chris@16
|
570
|
Chris@16
|
571 if (!are_property_maps_different(correspondence_map_1_to_2,
|
Chris@16
|
572 subgraph_cached.second.first,
|
Chris@16
|
573 m_graph1)) {
|
Chris@16
|
574
|
Chris@16
|
575 // New subgraph is a duplicate
|
Chris@16
|
576 return (true);
|
Chris@16
|
577 }
|
Chris@16
|
578 }
|
Chris@16
|
579
|
Chris@16
|
580 // Subgraph is unique, so make a cached copy
|
Chris@16
|
581 CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
582 new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
583 (num_vertices(m_graph1), m_vindex_map1);
|
Chris@16
|
584
|
Chris@16
|
585 CachedCorrespondenceMapSecondToFirst
|
Chris@16
|
586 new_subgraph_2_to_1 = CorrespondenceMapSecondToFirst
|
Chris@16
|
587 (num_vertices(m_graph2), m_vindex_map2);
|
Chris@16
|
588
|
Chris@16
|
589 BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) {
|
Chris@16
|
590 put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1));
|
Chris@16
|
591 }
|
Chris@16
|
592
|
Chris@16
|
593 BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) {
|
Chris@16
|
594 put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2));
|
Chris@16
|
595 }
|
Chris@16
|
596
|
Chris@16
|
597 m_subgraphs->push_back(std::make_pair(subgraph_size,
|
Chris@16
|
598 std::make_pair(new_subgraph_1_to_2,
|
Chris@16
|
599 new_subgraph_2_to_1)));
|
Chris@16
|
600
|
Chris@16
|
601 return (m_user_callback(correspondence_map_1_to_2,
|
Chris@16
|
602 correspondence_map_2_to_1,
|
Chris@16
|
603 subgraph_size));
|
Chris@16
|
604 }
|
Chris@16
|
605
|
Chris@16
|
606 private:
|
Chris@16
|
607 const GraphFirst& m_graph1;
|
Chris@16
|
608 const GraphFirst& m_graph2;
|
Chris@16
|
609 const VertexIndexMapFirst m_vindex_map1;
|
Chris@16
|
610 const VertexIndexMapSecond m_vindex_map2;
|
Chris@16
|
611 shared_ptr<SubGraphList> m_subgraphs;
|
Chris@16
|
612 SubGraphCallback m_user_callback;
|
Chris@16
|
613 };
|
Chris@16
|
614
|
Chris@16
|
615 } // namespace detail
|
Chris@16
|
616
|
Chris@16
|
617 // Enumerates all unique common subgraphs between graph1 and graph2.
|
Chris@16
|
618 // The user callback is invoked for each unique subgraph as they are
|
Chris@16
|
619 // discovered.
|
Chris@16
|
620 template <typename GraphFirst,
|
Chris@16
|
621 typename GraphSecond,
|
Chris@16
|
622 typename VertexIndexMapFirst,
|
Chris@16
|
623 typename VertexIndexMapSecond,
|
Chris@16
|
624 typename EdgeEquivalencePredicate,
|
Chris@16
|
625 typename VertexEquivalencePredicate,
|
Chris@16
|
626 typename SubGraphCallback>
|
Chris@16
|
627 void mcgregor_common_subgraphs_unique
|
Chris@16
|
628 (const GraphFirst& graph1,
|
Chris@16
|
629 const GraphSecond& graph2,
|
Chris@16
|
630 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
631 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
632 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
633 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
634 bool only_connected_subgraphs,
|
Chris@16
|
635 SubGraphCallback user_callback)
|
Chris@16
|
636 {
|
Chris@16
|
637 detail::unique_subgraph_interceptor<GraphFirst, GraphSecond,
|
Chris@16
|
638 VertexIndexMapFirst, VertexIndexMapSecond,
|
Chris@16
|
639 SubGraphCallback> unique_callback
|
Chris@16
|
640 (graph1, graph2,
|
Chris@16
|
641 vindex_map1, vindex_map2,
|
Chris@16
|
642 user_callback);
|
Chris@16
|
643
|
Chris@16
|
644 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
645 (graph1, graph2,
|
Chris@16
|
646 vindex_map1, vindex_map2,
|
Chris@16
|
647 edges_equivalent, vertices_equivalent,
|
Chris@16
|
648 only_connected_subgraphs, unique_callback);
|
Chris@16
|
649 }
|
Chris@16
|
650
|
Chris@16
|
651 // Variant of mcgregor_common_subgraphs_unique with all default
|
Chris@16
|
652 // parameters.
|
Chris@16
|
653 template <typename GraphFirst,
|
Chris@16
|
654 typename GraphSecond,
|
Chris@16
|
655 typename SubGraphCallback>
|
Chris@16
|
656 void mcgregor_common_subgraphs_unique
|
Chris@16
|
657 (const GraphFirst& graph1,
|
Chris@16
|
658 const GraphSecond& graph2,
|
Chris@16
|
659 bool only_connected_subgraphs,
|
Chris@16
|
660 SubGraphCallback user_callback)
|
Chris@16
|
661 {
|
Chris@16
|
662 mcgregor_common_subgraphs_unique
|
Chris@16
|
663 (graph1, graph2,
|
Chris@16
|
664 get(vertex_index, graph1), get(vertex_index, graph2),
|
Chris@16
|
665 always_equivalent(), always_equivalent(),
|
Chris@16
|
666 only_connected_subgraphs, user_callback);
|
Chris@16
|
667 }
|
Chris@16
|
668
|
Chris@16
|
669 // Named parameter variant of mcgregor_common_subgraphs_unique
|
Chris@16
|
670 template <typename GraphFirst,
|
Chris@16
|
671 typename GraphSecond,
|
Chris@16
|
672 typename SubGraphCallback,
|
Chris@16
|
673 typename Param,
|
Chris@16
|
674 typename Tag,
|
Chris@16
|
675 typename Rest>
|
Chris@16
|
676 void mcgregor_common_subgraphs_unique
|
Chris@16
|
677 (const GraphFirst& graph1,
|
Chris@16
|
678 const GraphSecond& graph2,
|
Chris@16
|
679 bool only_connected_subgraphs,
|
Chris@16
|
680 SubGraphCallback user_callback,
|
Chris@16
|
681 const bgl_named_params<Param, Tag, Rest>& params)
|
Chris@16
|
682 {
|
Chris@16
|
683 mcgregor_common_subgraphs_unique
|
Chris@16
|
684 (graph1, graph2,
|
Chris@16
|
685 choose_const_pmap(get_param(params, vertex_index1),
|
Chris@16
|
686 graph1, vertex_index),
|
Chris@16
|
687 choose_const_pmap(get_param(params, vertex_index2),
|
Chris@16
|
688 graph2, vertex_index),
|
Chris@16
|
689 choose_param(get_param(params, edges_equivalent_t()),
|
Chris@16
|
690 always_equivalent()),
|
Chris@16
|
691 choose_param(get_param(params, vertices_equivalent_t()),
|
Chris@16
|
692 always_equivalent()),
|
Chris@16
|
693 only_connected_subgraphs, user_callback);
|
Chris@16
|
694 }
|
Chris@16
|
695
|
Chris@16
|
696 // ==========================================================================
|
Chris@16
|
697
|
Chris@16
|
698 namespace detail {
|
Chris@16
|
699
|
Chris@16
|
700 // Binary function object that intercepts subgraphs from
|
Chris@16
|
701 // mcgregor_common_subgraphs_internal and maintains a cache of the
|
Chris@16
|
702 // largest subgraphs.
|
Chris@16
|
703 template <typename GraphFirst,
|
Chris@16
|
704 typename GraphSecond,
|
Chris@16
|
705 typename VertexIndexMapFirst,
|
Chris@16
|
706 typename VertexIndexMapSecond,
|
Chris@16
|
707 typename SubGraphCallback>
|
Chris@16
|
708 struct maximum_subgraph_interceptor {
|
Chris@16
|
709
|
Chris@16
|
710 typedef typename graph_traits<GraphFirst>::vertices_size_type
|
Chris@16
|
711 VertexSizeFirst;
|
Chris@16
|
712
|
Chris@16
|
713 typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond,
|
Chris@16
|
714 VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits;
|
Chris@16
|
715
|
Chris@16
|
716 typedef typename SubGraphTraits::correspondence_map_first_to_second_type
|
Chris@16
|
717 CachedCorrespondenceMapFirstToSecond;
|
Chris@16
|
718
|
Chris@16
|
719 typedef typename SubGraphTraits::correspondence_map_second_to_first_type
|
Chris@16
|
720 CachedCorrespondenceMapSecondToFirst;
|
Chris@16
|
721
|
Chris@16
|
722 typedef std::pair<VertexSizeFirst,
|
Chris@16
|
723 std::pair<CachedCorrespondenceMapFirstToSecond,
|
Chris@16
|
724 CachedCorrespondenceMapSecondToFirst> > SubGraph;
|
Chris@16
|
725
|
Chris@16
|
726 typedef std::vector<SubGraph> SubGraphList;
|
Chris@16
|
727
|
Chris@16
|
728 maximum_subgraph_interceptor(const GraphFirst& graph1,
|
Chris@16
|
729 const GraphSecond& graph2,
|
Chris@16
|
730 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
731 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
732 SubGraphCallback user_callback) :
|
Chris@16
|
733 m_graph1(graph1), m_graph2(graph2),
|
Chris@16
|
734 m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2),
|
Chris@16
|
735 m_subgraphs(make_shared<SubGraphList>()),
|
Chris@16
|
736 m_largest_size_so_far(make_shared<VertexSizeFirst>(0)),
|
Chris@16
|
737 m_user_callback(user_callback) { }
|
Chris@16
|
738
|
Chris@16
|
739 template <typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
740 typename CorrespondenceMapSecondToFirst>
|
Chris@16
|
741 bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
742 CorrespondenceMapSecondToFirst correspondence_map_2_to_1,
|
Chris@16
|
743 VertexSizeFirst subgraph_size) {
|
Chris@16
|
744
|
Chris@16
|
745 if (subgraph_size > *m_largest_size_so_far) {
|
Chris@16
|
746 m_subgraphs->clear();
|
Chris@16
|
747 *m_largest_size_so_far = subgraph_size;
|
Chris@16
|
748 }
|
Chris@16
|
749
|
Chris@16
|
750 if (subgraph_size == *m_largest_size_so_far) {
|
Chris@16
|
751
|
Chris@16
|
752 // Make a cached copy
|
Chris@16
|
753 CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
754 new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
755 (num_vertices(m_graph1), m_vindex_map1);
|
Chris@16
|
756
|
Chris@16
|
757 CachedCorrespondenceMapSecondToFirst
|
Chris@16
|
758 new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst
|
Chris@16
|
759 (num_vertices(m_graph2), m_vindex_map2);
|
Chris@16
|
760
|
Chris@16
|
761 BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) {
|
Chris@16
|
762 put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1));
|
Chris@16
|
763 }
|
Chris@16
|
764
|
Chris@16
|
765 BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) {
|
Chris@16
|
766 put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2));
|
Chris@16
|
767 }
|
Chris@16
|
768
|
Chris@16
|
769 m_subgraphs->push_back(std::make_pair(subgraph_size,
|
Chris@16
|
770 std::make_pair(new_subgraph_1_to_2,
|
Chris@16
|
771 new_subgraph_2_to_1)));
|
Chris@16
|
772 }
|
Chris@16
|
773
|
Chris@16
|
774 return (true);
|
Chris@16
|
775 }
|
Chris@16
|
776
|
Chris@16
|
777 void output_subgraphs() {
|
Chris@16
|
778 for (typename SubGraphList::const_iterator
|
Chris@16
|
779 subgraph_iter = m_subgraphs->begin();
|
Chris@16
|
780 subgraph_iter != m_subgraphs->end();
|
Chris@16
|
781 ++subgraph_iter) {
|
Chris@16
|
782
|
Chris@16
|
783 SubGraph subgraph_cached = *subgraph_iter;
|
Chris@16
|
784 m_user_callback(subgraph_cached.second.first,
|
Chris@16
|
785 subgraph_cached.second.second,
|
Chris@16
|
786 subgraph_cached.first);
|
Chris@16
|
787 }
|
Chris@16
|
788 }
|
Chris@16
|
789
|
Chris@16
|
790 private:
|
Chris@16
|
791 const GraphFirst& m_graph1;
|
Chris@16
|
792 const GraphFirst& m_graph2;
|
Chris@16
|
793 const VertexIndexMapFirst m_vindex_map1;
|
Chris@16
|
794 const VertexIndexMapSecond m_vindex_map2;
|
Chris@16
|
795 shared_ptr<SubGraphList> m_subgraphs;
|
Chris@16
|
796 shared_ptr<VertexSizeFirst> m_largest_size_so_far;
|
Chris@16
|
797 SubGraphCallback m_user_callback;
|
Chris@16
|
798 };
|
Chris@16
|
799
|
Chris@16
|
800 } // namespace detail
|
Chris@16
|
801
|
Chris@16
|
802 // Enumerates the largest common subgraphs found between graph1
|
Chris@16
|
803 // and graph2. Note that the ENTIRE search space is explored before
|
Chris@16
|
804 // user_callback is actually invoked.
|
Chris@16
|
805 template <typename GraphFirst,
|
Chris@16
|
806 typename GraphSecond,
|
Chris@16
|
807 typename VertexIndexMapFirst,
|
Chris@16
|
808 typename VertexIndexMapSecond,
|
Chris@16
|
809 typename EdgeEquivalencePredicate,
|
Chris@16
|
810 typename VertexEquivalencePredicate,
|
Chris@16
|
811 typename SubGraphCallback>
|
Chris@16
|
812 void mcgregor_common_subgraphs_maximum
|
Chris@16
|
813 (const GraphFirst& graph1,
|
Chris@16
|
814 const GraphSecond& graph2,
|
Chris@16
|
815 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
816 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
817 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
818 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
819 bool only_connected_subgraphs,
|
Chris@16
|
820 SubGraphCallback user_callback)
|
Chris@16
|
821 {
|
Chris@16
|
822 detail::maximum_subgraph_interceptor<GraphFirst, GraphSecond,
|
Chris@16
|
823 VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback>
|
Chris@16
|
824 max_interceptor
|
Chris@16
|
825 (graph1, graph2, vindex_map1, vindex_map2, user_callback);
|
Chris@16
|
826
|
Chris@16
|
827 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
828 (graph1, graph2,
|
Chris@16
|
829 vindex_map1, vindex_map2,
|
Chris@16
|
830 edges_equivalent, vertices_equivalent,
|
Chris@16
|
831 only_connected_subgraphs, max_interceptor);
|
Chris@16
|
832
|
Chris@16
|
833 // Only output the largest subgraphs
|
Chris@16
|
834 max_interceptor.output_subgraphs();
|
Chris@16
|
835 }
|
Chris@16
|
836
|
Chris@16
|
837 // Variant of mcgregor_common_subgraphs_maximum with all default
|
Chris@16
|
838 // parameters.
|
Chris@16
|
839 template <typename GraphFirst,
|
Chris@16
|
840 typename GraphSecond,
|
Chris@16
|
841 typename SubGraphCallback>
|
Chris@16
|
842 void mcgregor_common_subgraphs_maximum
|
Chris@16
|
843 (const GraphFirst& graph1,
|
Chris@16
|
844 const GraphSecond& graph2,
|
Chris@16
|
845 bool only_connected_subgraphs,
|
Chris@16
|
846 SubGraphCallback user_callback)
|
Chris@16
|
847 {
|
Chris@16
|
848 mcgregor_common_subgraphs_maximum
|
Chris@16
|
849 (graph1, graph2,
|
Chris@16
|
850 get(vertex_index, graph1), get(vertex_index, graph2),
|
Chris@16
|
851 always_equivalent(), always_equivalent(),
|
Chris@16
|
852 only_connected_subgraphs, user_callback);
|
Chris@16
|
853 }
|
Chris@16
|
854
|
Chris@16
|
855 // Named parameter variant of mcgregor_common_subgraphs_maximum
|
Chris@16
|
856 template <typename GraphFirst,
|
Chris@16
|
857 typename GraphSecond,
|
Chris@16
|
858 typename SubGraphCallback,
|
Chris@16
|
859 typename Param,
|
Chris@16
|
860 typename Tag,
|
Chris@16
|
861 typename Rest>
|
Chris@16
|
862 void mcgregor_common_subgraphs_maximum
|
Chris@16
|
863 (const GraphFirst& graph1,
|
Chris@16
|
864 const GraphSecond& graph2,
|
Chris@16
|
865 bool only_connected_subgraphs,
|
Chris@16
|
866 SubGraphCallback user_callback,
|
Chris@16
|
867 const bgl_named_params<Param, Tag, Rest>& params)
|
Chris@16
|
868 {
|
Chris@16
|
869 mcgregor_common_subgraphs_maximum
|
Chris@16
|
870 (graph1, graph2,
|
Chris@16
|
871 choose_const_pmap(get_param(params, vertex_index1),
|
Chris@16
|
872 graph1, vertex_index),
|
Chris@16
|
873 choose_const_pmap(get_param(params, vertex_index2),
|
Chris@16
|
874 graph2, vertex_index),
|
Chris@16
|
875 choose_param(get_param(params, edges_equivalent_t()),
|
Chris@16
|
876 always_equivalent()),
|
Chris@16
|
877 choose_param(get_param(params, vertices_equivalent_t()),
|
Chris@16
|
878 always_equivalent()),
|
Chris@16
|
879 only_connected_subgraphs, user_callback);
|
Chris@16
|
880 }
|
Chris@16
|
881
|
Chris@16
|
882 // ==========================================================================
|
Chris@16
|
883
|
Chris@16
|
884 namespace detail {
|
Chris@16
|
885
|
Chris@16
|
886 // Binary function object that intercepts subgraphs from
|
Chris@16
|
887 // mcgregor_common_subgraphs_internal and maintains a cache of the
|
Chris@16
|
888 // largest, unique subgraphs.
|
Chris@16
|
889 template <typename GraphFirst,
|
Chris@16
|
890 typename GraphSecond,
|
Chris@16
|
891 typename VertexIndexMapFirst,
|
Chris@16
|
892 typename VertexIndexMapSecond,
|
Chris@16
|
893 typename SubGraphCallback>
|
Chris@16
|
894 struct unique_maximum_subgraph_interceptor {
|
Chris@16
|
895
|
Chris@16
|
896 typedef typename graph_traits<GraphFirst>::vertices_size_type
|
Chris@16
|
897 VertexSizeFirst;
|
Chris@16
|
898
|
Chris@16
|
899 typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond,
|
Chris@16
|
900 VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits;
|
Chris@16
|
901
|
Chris@16
|
902 typedef typename SubGraphTraits::correspondence_map_first_to_second_type
|
Chris@16
|
903 CachedCorrespondenceMapFirstToSecond;
|
Chris@16
|
904
|
Chris@16
|
905 typedef typename SubGraphTraits::correspondence_map_second_to_first_type
|
Chris@16
|
906 CachedCorrespondenceMapSecondToFirst;
|
Chris@16
|
907
|
Chris@16
|
908 typedef std::pair<VertexSizeFirst,
|
Chris@16
|
909 std::pair<CachedCorrespondenceMapFirstToSecond,
|
Chris@16
|
910 CachedCorrespondenceMapSecondToFirst> > SubGraph;
|
Chris@16
|
911
|
Chris@16
|
912 typedef std::vector<SubGraph> SubGraphList;
|
Chris@16
|
913
|
Chris@16
|
914 unique_maximum_subgraph_interceptor(const GraphFirst& graph1,
|
Chris@16
|
915 const GraphSecond& graph2,
|
Chris@16
|
916 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
917 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
918 SubGraphCallback user_callback) :
|
Chris@16
|
919 m_graph1(graph1), m_graph2(graph2),
|
Chris@16
|
920 m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2),
|
Chris@16
|
921 m_subgraphs(make_shared<SubGraphList>()),
|
Chris@16
|
922 m_largest_size_so_far(make_shared<VertexSizeFirst>(0)),
|
Chris@16
|
923 m_user_callback(user_callback) { }
|
Chris@16
|
924
|
Chris@16
|
925 template <typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
926 typename CorrespondenceMapSecondToFirst>
|
Chris@16
|
927 bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
928 CorrespondenceMapSecondToFirst correspondence_map_2_to_1,
|
Chris@16
|
929 VertexSizeFirst subgraph_size) {
|
Chris@16
|
930
|
Chris@16
|
931 if (subgraph_size > *m_largest_size_so_far) {
|
Chris@16
|
932 m_subgraphs->clear();
|
Chris@16
|
933 *m_largest_size_so_far = subgraph_size;
|
Chris@16
|
934 }
|
Chris@16
|
935
|
Chris@16
|
936 if (subgraph_size == *m_largest_size_so_far) {
|
Chris@16
|
937
|
Chris@16
|
938 // Check if subgraph is unique
|
Chris@16
|
939 for (typename SubGraphList::const_iterator
|
Chris@16
|
940 subgraph_iter = m_subgraphs->begin();
|
Chris@16
|
941 subgraph_iter != m_subgraphs->end();
|
Chris@16
|
942 ++subgraph_iter) {
|
Chris@16
|
943
|
Chris@16
|
944 SubGraph subgraph_cached = *subgraph_iter;
|
Chris@16
|
945
|
Chris@16
|
946 if (!are_property_maps_different(correspondence_map_1_to_2,
|
Chris@16
|
947 subgraph_cached.second.first,
|
Chris@16
|
948 m_graph1)) {
|
Chris@16
|
949
|
Chris@16
|
950 // New subgraph is a duplicate
|
Chris@16
|
951 return (true);
|
Chris@16
|
952 }
|
Chris@16
|
953 }
|
Chris@16
|
954
|
Chris@16
|
955 // Subgraph is unique, so make a cached copy
|
Chris@16
|
956 CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
957 new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond
|
Chris@16
|
958 (num_vertices(m_graph1), m_vindex_map1);
|
Chris@16
|
959
|
Chris@16
|
960 CachedCorrespondenceMapSecondToFirst
|
Chris@16
|
961 new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst
|
Chris@16
|
962 (num_vertices(m_graph2), m_vindex_map2);
|
Chris@16
|
963
|
Chris@16
|
964 BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) {
|
Chris@16
|
965 put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1));
|
Chris@16
|
966 }
|
Chris@16
|
967
|
Chris@16
|
968 BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) {
|
Chris@16
|
969 put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2));
|
Chris@16
|
970 }
|
Chris@16
|
971
|
Chris@16
|
972 m_subgraphs->push_back(std::make_pair(subgraph_size,
|
Chris@16
|
973 std::make_pair(new_subgraph_1_to_2,
|
Chris@16
|
974 new_subgraph_2_to_1)));
|
Chris@16
|
975 }
|
Chris@16
|
976
|
Chris@16
|
977 return (true);
|
Chris@16
|
978 }
|
Chris@16
|
979
|
Chris@16
|
980 void output_subgraphs() {
|
Chris@16
|
981 for (typename SubGraphList::const_iterator
|
Chris@16
|
982 subgraph_iter = m_subgraphs->begin();
|
Chris@16
|
983 subgraph_iter != m_subgraphs->end();
|
Chris@16
|
984 ++subgraph_iter) {
|
Chris@16
|
985
|
Chris@16
|
986 SubGraph subgraph_cached = *subgraph_iter;
|
Chris@16
|
987 m_user_callback(subgraph_cached.second.first,
|
Chris@16
|
988 subgraph_cached.second.second,
|
Chris@16
|
989 subgraph_cached.first);
|
Chris@16
|
990 }
|
Chris@16
|
991 }
|
Chris@16
|
992
|
Chris@16
|
993 private:
|
Chris@16
|
994 const GraphFirst& m_graph1;
|
Chris@16
|
995 const GraphFirst& m_graph2;
|
Chris@16
|
996 const VertexIndexMapFirst m_vindex_map1;
|
Chris@16
|
997 const VertexIndexMapSecond m_vindex_map2;
|
Chris@16
|
998 shared_ptr<SubGraphList> m_subgraphs;
|
Chris@16
|
999 shared_ptr<VertexSizeFirst> m_largest_size_so_far;
|
Chris@16
|
1000 SubGraphCallback m_user_callback;
|
Chris@16
|
1001 };
|
Chris@16
|
1002
|
Chris@16
|
1003 } // namespace detail
|
Chris@16
|
1004
|
Chris@16
|
1005 // Enumerates the largest, unique common subgraphs found between
|
Chris@16
|
1006 // graph1 and graph2. Note that the ENTIRE search space is explored
|
Chris@16
|
1007 // before user_callback is actually invoked.
|
Chris@16
|
1008 template <typename GraphFirst,
|
Chris@16
|
1009 typename GraphSecond,
|
Chris@16
|
1010 typename VertexIndexMapFirst,
|
Chris@16
|
1011 typename VertexIndexMapSecond,
|
Chris@16
|
1012 typename EdgeEquivalencePredicate,
|
Chris@16
|
1013 typename VertexEquivalencePredicate,
|
Chris@16
|
1014 typename SubGraphCallback>
|
Chris@16
|
1015 void mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1016 (const GraphFirst& graph1,
|
Chris@16
|
1017 const GraphSecond& graph2,
|
Chris@16
|
1018 const VertexIndexMapFirst vindex_map1,
|
Chris@16
|
1019 const VertexIndexMapSecond vindex_map2,
|
Chris@16
|
1020 EdgeEquivalencePredicate edges_equivalent,
|
Chris@16
|
1021 VertexEquivalencePredicate vertices_equivalent,
|
Chris@16
|
1022 bool only_connected_subgraphs,
|
Chris@16
|
1023 SubGraphCallback user_callback)
|
Chris@16
|
1024 {
|
Chris@16
|
1025 detail::unique_maximum_subgraph_interceptor<GraphFirst, GraphSecond,
|
Chris@16
|
1026 VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback>
|
Chris@16
|
1027 unique_max_interceptor
|
Chris@16
|
1028 (graph1, graph2, vindex_map1, vindex_map2, user_callback);
|
Chris@16
|
1029
|
Chris@16
|
1030 detail::mcgregor_common_subgraphs_internal_init
|
Chris@16
|
1031 (graph1, graph2,
|
Chris@16
|
1032 vindex_map1, vindex_map2,
|
Chris@16
|
1033 edges_equivalent, vertices_equivalent,
|
Chris@16
|
1034 only_connected_subgraphs, unique_max_interceptor);
|
Chris@16
|
1035
|
Chris@16
|
1036 // Only output the largest, unique subgraphs
|
Chris@16
|
1037 unique_max_interceptor.output_subgraphs();
|
Chris@16
|
1038 }
|
Chris@16
|
1039
|
Chris@16
|
1040 // Variant of mcgregor_common_subgraphs_maximum_unique with all default parameters
|
Chris@16
|
1041 template <typename GraphFirst,
|
Chris@16
|
1042 typename GraphSecond,
|
Chris@16
|
1043 typename SubGraphCallback>
|
Chris@16
|
1044 void mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1045 (const GraphFirst& graph1,
|
Chris@16
|
1046 const GraphSecond& graph2,
|
Chris@16
|
1047 bool only_connected_subgraphs,
|
Chris@16
|
1048 SubGraphCallback user_callback)
|
Chris@16
|
1049 {
|
Chris@16
|
1050
|
Chris@16
|
1051 mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1052 (graph1, graph2,
|
Chris@16
|
1053 get(vertex_index, graph1), get(vertex_index, graph2),
|
Chris@16
|
1054 always_equivalent(), always_equivalent(),
|
Chris@16
|
1055 only_connected_subgraphs, user_callback);
|
Chris@16
|
1056 }
|
Chris@16
|
1057
|
Chris@16
|
1058 // Named parameter variant of
|
Chris@16
|
1059 // mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1060 template <typename GraphFirst,
|
Chris@16
|
1061 typename GraphSecond,
|
Chris@16
|
1062 typename SubGraphCallback,
|
Chris@16
|
1063 typename Param,
|
Chris@16
|
1064 typename Tag,
|
Chris@16
|
1065 typename Rest>
|
Chris@16
|
1066 void mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1067 (const GraphFirst& graph1,
|
Chris@16
|
1068 const GraphSecond& graph2,
|
Chris@16
|
1069 bool only_connected_subgraphs,
|
Chris@16
|
1070 SubGraphCallback user_callback,
|
Chris@16
|
1071 const bgl_named_params<Param, Tag, Rest>& params)
|
Chris@16
|
1072 {
|
Chris@16
|
1073 mcgregor_common_subgraphs_maximum_unique
|
Chris@16
|
1074 (graph1, graph2,
|
Chris@16
|
1075 choose_const_pmap(get_param(params, vertex_index1),
|
Chris@16
|
1076 graph1, vertex_index),
|
Chris@16
|
1077 choose_const_pmap(get_param(params, vertex_index2),
|
Chris@16
|
1078 graph2, vertex_index),
|
Chris@16
|
1079 choose_param(get_param(params, edges_equivalent_t()),
|
Chris@16
|
1080 always_equivalent()),
|
Chris@16
|
1081 choose_param(get_param(params, vertices_equivalent_t()),
|
Chris@16
|
1082 always_equivalent()),
|
Chris@16
|
1083 only_connected_subgraphs, user_callback);
|
Chris@16
|
1084 }
|
Chris@16
|
1085
|
Chris@16
|
1086 // ==========================================================================
|
Chris@16
|
1087
|
Chris@16
|
1088 // Fills a membership map (vertex -> bool) using the information
|
Chris@16
|
1089 // present in correspondence_map_1_to_2. Every vertex in a
|
Chris@16
|
1090 // membership map will have a true value only if it is not
|
Chris@16
|
1091 // associated with a null vertex in the correspondence map.
|
Chris@16
|
1092 template <typename GraphSecond,
|
Chris@16
|
1093 typename GraphFirst,
|
Chris@16
|
1094 typename CorrespondenceMapFirstToSecond,
|
Chris@16
|
1095 typename MembershipMapFirst>
|
Chris@16
|
1096 void fill_membership_map
|
Chris@16
|
1097 (const GraphFirst& graph1,
|
Chris@16
|
1098 const CorrespondenceMapFirstToSecond correspondence_map_1_to_2,
|
Chris@16
|
1099 MembershipMapFirst membership_map1) {
|
Chris@16
|
1100
|
Chris@16
|
1101 BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) {
|
Chris@16
|
1102 put(membership_map1, vertex1,
|
Chris@16
|
1103 get(correspondence_map_1_to_2, vertex1) != graph_traits<GraphSecond>::null_vertex());
|
Chris@16
|
1104 }
|
Chris@16
|
1105
|
Chris@16
|
1106 }
|
Chris@16
|
1107
|
Chris@16
|
1108 // Traits associated with a membership map filtered graph. Provided
|
Chris@16
|
1109 // for convenience to access graph and vertex filter types.
|
Chris@16
|
1110 template <typename Graph,
|
Chris@16
|
1111 typename MembershipMap>
|
Chris@16
|
1112 struct membership_filtered_graph_traits {
|
Chris@16
|
1113 typedef property_map_filter<MembershipMap> vertex_filter_type;
|
Chris@16
|
1114 typedef filtered_graph<Graph, keep_all, vertex_filter_type> graph_type;
|
Chris@16
|
1115 };
|
Chris@16
|
1116
|
Chris@16
|
1117 // Returns a filtered sub-graph of graph whose edge and vertex
|
Chris@16
|
1118 // inclusion is dictated by membership_map.
|
Chris@16
|
1119 template <typename Graph,
|
Chris@16
|
1120 typename MembershipMap>
|
Chris@16
|
1121 typename membership_filtered_graph_traits<Graph, MembershipMap>::graph_type
|
Chris@16
|
1122 make_membership_filtered_graph
|
Chris@16
|
1123 (const Graph& graph,
|
Chris@16
|
1124 MembershipMap& membership_map) {
|
Chris@16
|
1125
|
Chris@16
|
1126 typedef membership_filtered_graph_traits<Graph, MembershipMap> MFGTraits;
|
Chris@16
|
1127 typedef typename MFGTraits::graph_type MembershipFilteredGraph;
|
Chris@16
|
1128
|
Chris@16
|
1129 typename MFGTraits::vertex_filter_type v_filter(membership_map);
|
Chris@16
|
1130
|
Chris@16
|
1131 return (MembershipFilteredGraph(graph, keep_all(), v_filter));
|
Chris@16
|
1132
|
Chris@16
|
1133 }
|
Chris@16
|
1134
|
Chris@16
|
1135 } // namespace boost
|
Chris@16
|
1136
|
Chris@16
|
1137 #endif // BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP
|