You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
1142 lines
42 KiB
1142 lines
42 KiB
//======================================================================= |
|
// Copyright 2009 Trustees of Indiana University. |
|
// Authors: Michael Hansen, Andrew Lumsdaine |
|
// |
|
// 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) |
|
//======================================================================= |
|
|
|
#ifndef BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP |
|
#define BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP |
|
|
|
#include <algorithm> |
|
#include <vector> |
|
#include <stack> |
|
|
|
#include <boost/make_shared.hpp> |
|
#include <boost/graph/adjacency_list.hpp> |
|
#include <boost/graph/filtered_graph.hpp> |
|
#include <boost/graph/graph_utility.hpp> |
|
#include <boost/graph/iteration_macros.hpp> |
|
#include <boost/graph/properties.hpp> |
|
#include <boost/property_map/shared_array_property_map.hpp> |
|
|
|
namespace boost { |
|
|
|
namespace detail { |
|
|
|
// Traits associated with common subgraphs, used mainly to keep a |
|
// consistent type for the correspondence maps. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond> |
|
struct mcgregor_common_subgraph_traits { |
|
typedef typename graph_traits<GraphFirst>::vertex_descriptor vertex_first_type; |
|
typedef typename graph_traits<GraphSecond>::vertex_descriptor vertex_second_type; |
|
|
|
typedef shared_array_property_map<vertex_second_type, VertexIndexMapFirst> |
|
correspondence_map_first_to_second_type; |
|
|
|
typedef shared_array_property_map<vertex_first_type, VertexIndexMapSecond> |
|
correspondence_map_second_to_first_type; |
|
}; |
|
|
|
} // namespace detail |
|
|
|
// ========================================================================== |
|
|
|
// Binary function object that returns true if the values for item1 |
|
// in property_map1 and item2 in property_map2 are equivalent. |
|
template <typename PropertyMapFirst, |
|
typename PropertyMapSecond> |
|
struct property_map_equivalent { |
|
|
|
property_map_equivalent(const PropertyMapFirst property_map1, |
|
const PropertyMapSecond property_map2) : |
|
m_property_map1(property_map1), |
|
m_property_map2(property_map2) { } |
|
|
|
template <typename ItemFirst, |
|
typename ItemSecond> |
|
bool operator()(const ItemFirst item1, const ItemSecond item2) { |
|
return (get(m_property_map1, item1) == get(m_property_map2, item2)); |
|
} |
|
|
|
private: |
|
const PropertyMapFirst m_property_map1; |
|
const PropertyMapSecond m_property_map2; |
|
}; |
|
|
|
// Returns a property_map_equivalent object that compares the values |
|
// of property_map1 and property_map2. |
|
template <typename PropertyMapFirst, |
|
typename PropertyMapSecond> |
|
property_map_equivalent<PropertyMapFirst, |
|
PropertyMapSecond> |
|
make_property_map_equivalent |
|
(const PropertyMapFirst property_map1, |
|
const PropertyMapSecond property_map2) { |
|
|
|
return (property_map_equivalent<PropertyMapFirst, PropertyMapSecond> |
|
(property_map1, property_map2)); |
|
} |
|
|
|
// Binary function object that always returns true. Used when |
|
// vertices or edges are always equivalent (i.e. have no labels). |
|
struct always_equivalent { |
|
|
|
template <typename ItemFirst, |
|
typename ItemSecond> |
|
bool operator()(const ItemFirst&, const ItemSecond&) { |
|
return (true); |
|
} |
|
}; |
|
|
|
// ========================================================================== |
|
|
|
namespace detail { |
|
|
|
// Return true if new_vertex1 and new_vertex2 can extend the |
|
// subgraph represented by correspondence_map_1_to_2 and |
|
// correspondence_map_2_to_1. The vertices_equivalent and |
|
// edges_equivalent predicates are used to test vertex and edge |
|
// equivalency between the two graphs. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename CorrespondenceMapFirstToSecond, |
|
typename CorrespondenceMapSecondToFirst, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate> |
|
bool can_extend_graph |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
CorrespondenceMapSecondToFirst /*correspondence_map_2_to_1*/, |
|
typename graph_traits<GraphFirst>::vertices_size_type subgraph_size, |
|
typename graph_traits<GraphFirst>::vertex_descriptor new_vertex1, |
|
typename graph_traits<GraphSecond>::vertex_descriptor new_vertex2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs) |
|
{ |
|
typedef typename graph_traits<GraphFirst>::vertex_descriptor VertexFirst; |
|
typedef typename graph_traits<GraphSecond>::vertex_descriptor VertexSecond; |
|
|
|
typedef typename graph_traits<GraphFirst>::edge_descriptor EdgeFirst; |
|
typedef typename graph_traits<GraphSecond>::edge_descriptor EdgeSecond; |
|
|
|
// Check vertex equality |
|
if (!vertices_equivalent(new_vertex1, new_vertex2)) { |
|
return (false); |
|
} |
|
|
|
// Vertices match and graph is empty, so we can extend the subgraph |
|
if (subgraph_size == 0) { |
|
return (true); |
|
} |
|
|
|
bool has_one_edge = false; |
|
|
|
// Verify edges with existing sub-graph |
|
BGL_FORALL_VERTICES_T(existing_vertex1, graph1, GraphFirst) { |
|
|
|
VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, existing_vertex1); |
|
|
|
// Skip unassociated vertices |
|
if (existing_vertex2 == graph_traits<GraphSecond>::null_vertex()) { |
|
continue; |
|
} |
|
|
|
// NOTE: This will not work with parallel edges, since the |
|
// first matching edge is always chosen. |
|
EdgeFirst edge_to_new1, edge_from_new1; |
|
bool edge_to_new_exists1 = false, edge_from_new_exists1 = false; |
|
|
|
EdgeSecond edge_to_new2, edge_from_new2; |
|
bool edge_to_new_exists2 = false, edge_from_new_exists2 = false; |
|
|
|
// Search for edge from existing to new vertex (graph1) |
|
BGL_FORALL_OUTEDGES_T(existing_vertex1, edge1, graph1, GraphFirst) { |
|
if (target(edge1, graph1) == new_vertex1) { |
|
edge_to_new1 = edge1; |
|
edge_to_new_exists1 = true; |
|
break; |
|
} |
|
} |
|
|
|
// Search for edge from existing to new vertex (graph2) |
|
BGL_FORALL_OUTEDGES_T(existing_vertex2, edge2, graph2, GraphSecond) { |
|
if (target(edge2, graph2) == new_vertex2) { |
|
edge_to_new2 = edge2; |
|
edge_to_new_exists2 = true; |
|
break; |
|
} |
|
} |
|
|
|
// Make sure edges from existing to new vertices are equivalent |
|
if ((edge_to_new_exists1 != edge_to_new_exists2) || |
|
((edge_to_new_exists1 && edge_to_new_exists2) && |
|
!edges_equivalent(edge_to_new1, edge_to_new2))) { |
|
|
|
return (false); |
|
} |
|
|
|
bool is_undirected1 = is_undirected(graph1), |
|
is_undirected2 = is_undirected(graph2); |
|
|
|
if (is_undirected1 && is_undirected2) { |
|
|
|
// Edge in both graphs exists and both graphs are undirected |
|
if (edge_to_new_exists1 && edge_to_new_exists2) { |
|
has_one_edge = true; |
|
} |
|
|
|
continue; |
|
} |
|
else { |
|
|
|
if (!is_undirected1) { |
|
|
|
// Search for edge from new to existing vertex (graph1) |
|
BGL_FORALL_OUTEDGES_T(new_vertex1, edge1, graph1, GraphFirst) { |
|
if (target(edge1, graph1) == existing_vertex1) { |
|
edge_from_new1 = edge1; |
|
edge_from_new_exists1 = true; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (!is_undirected2) { |
|
|
|
// Search for edge from new to existing vertex (graph2) |
|
BGL_FORALL_OUTEDGES_T(new_vertex2, edge2, graph2, GraphSecond) { |
|
if (target(edge2, graph2) == existing_vertex2) { |
|
edge_from_new2 = edge2; |
|
edge_from_new_exists2 = true; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
// Make sure edges from new to existing vertices are equivalent |
|
if ((edge_from_new_exists1 != edge_from_new_exists2) || |
|
((edge_from_new_exists1 && edge_from_new_exists2) && |
|
!edges_equivalent(edge_from_new1, edge_from_new2))) { |
|
|
|
return (false); |
|
} |
|
|
|
if ((edge_from_new_exists1 && edge_from_new_exists2) || |
|
(edge_to_new_exists1 && edge_to_new_exists2)) { |
|
has_one_edge = true; |
|
} |
|
|
|
} // else |
|
|
|
} // BGL_FORALL_VERTICES_T |
|
|
|
// Make sure new vertices are connected to the existing subgraph |
|
if (only_connected_subgraphs && !has_one_edge) { |
|
return (false); |
|
} |
|
|
|
return (true); |
|
} |
|
|
|
// Recursive method that does a depth-first search in the space of |
|
// potential subgraphs. At each level, every new vertex pair from |
|
// both graphs is tested to see if it can extend the current |
|
// subgraph. If so, the subgraph is output to subgraph_callback |
|
// in the form of two correspondence maps (one for each graph). |
|
// Returning false from subgraph_callback will terminate the |
|
// search. Function returns true if the entire search space was |
|
// explored. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename CorrespondenceMapFirstToSecond, |
|
typename CorrespondenceMapSecondToFirst, |
|
typename VertexStackFirst, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphInternalCallback> |
|
bool mcgregor_common_subgraphs_internal |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst& vindex_map1, |
|
const VertexIndexMapSecond& vindex_map2, |
|
CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
CorrespondenceMapSecondToFirst correspondence_map_2_to_1, |
|
VertexStackFirst& vertex_stack1, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphInternalCallback subgraph_callback) |
|
{ |
|
typedef typename graph_traits<GraphFirst>::vertex_descriptor VertexFirst; |
|
typedef typename graph_traits<GraphSecond>::vertex_descriptor VertexSecond; |
|
typedef typename graph_traits<GraphFirst>::vertices_size_type VertexSizeFirst; |
|
|
|
// Get iterators for vertices from both graphs |
|
typename graph_traits<GraphFirst>::vertex_iterator |
|
vertex1_iter, vertex1_end; |
|
|
|
typename graph_traits<GraphSecond>::vertex_iterator |
|
vertex2_begin, vertex2_end, vertex2_iter; |
|
|
|
boost::tie(vertex1_iter, vertex1_end) = vertices(graph1); |
|
boost::tie(vertex2_begin, vertex2_end) = vertices(graph2); |
|
vertex2_iter = vertex2_begin; |
|
|
|
// Iterate until all vertices have been visited |
|
BGL_FORALL_VERTICES_T(new_vertex1, graph1, GraphFirst) { |
|
|
|
VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, new_vertex1); |
|
|
|
// Skip already matched vertices in first graph |
|
if (existing_vertex2 != graph_traits<GraphSecond>::null_vertex()) { |
|
continue; |
|
} |
|
|
|
BGL_FORALL_VERTICES_T(new_vertex2, graph2, GraphSecond) { |
|
|
|
VertexFirst existing_vertex1 = get(correspondence_map_2_to_1, new_vertex2); |
|
|
|
// Skip already matched vertices in second graph |
|
if (existing_vertex1 != graph_traits<GraphFirst>::null_vertex()) { |
|
continue; |
|
} |
|
|
|
// Check if current sub-graph can be extended with the matched vertex pair |
|
if (can_extend_graph(graph1, graph2, |
|
correspondence_map_1_to_2, correspondence_map_2_to_1, |
|
(VertexSizeFirst)vertex_stack1.size(), |
|
new_vertex1, new_vertex2, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs)) { |
|
|
|
// Keep track of old graph size for restoring later |
|
VertexSizeFirst old_graph_size = (VertexSizeFirst)vertex_stack1.size(), |
|
new_graph_size = old_graph_size + 1; |
|
|
|
// Extend subgraph |
|
put(correspondence_map_1_to_2, new_vertex1, new_vertex2); |
|
put(correspondence_map_2_to_1, new_vertex2, new_vertex1); |
|
vertex_stack1.push(new_vertex1); |
|
|
|
// Only output sub-graphs larger than a single vertex |
|
if (new_graph_size > 1) { |
|
|
|
// Returning false from the callback will cancel iteration |
|
if (!subgraph_callback(correspondence_map_1_to_2, |
|
correspondence_map_2_to_1, |
|
new_graph_size)) { |
|
return (false); |
|
} |
|
} |
|
|
|
// Depth-first search into the state space of possible sub-graphs |
|
bool continue_iteration = |
|
mcgregor_common_subgraphs_internal |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
correspondence_map_1_to_2, correspondence_map_2_to_1, |
|
vertex_stack1, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, subgraph_callback); |
|
|
|
if (!continue_iteration) { |
|
return (false); |
|
} |
|
|
|
// Restore previous state |
|
if (vertex_stack1.size() > old_graph_size) { |
|
|
|
VertexFirst stack_vertex1 = vertex_stack1.top(); |
|
VertexSecond stack_vertex2 = get(correspondence_map_1_to_2, |
|
stack_vertex1); |
|
|
|
// Contract subgraph |
|
put(correspondence_map_1_to_2, stack_vertex1, |
|
graph_traits<GraphSecond>::null_vertex()); |
|
|
|
put(correspondence_map_2_to_1, stack_vertex2, |
|
graph_traits<GraphFirst>::null_vertex()); |
|
|
|
vertex_stack1.pop(); |
|
} |
|
|
|
} // if can_extend_graph |
|
|
|
} // BGL_FORALL_VERTICES_T (graph2) |
|
|
|
} // BGL_FORALL_VERTICES_T (graph1) |
|
|
|
return (true); |
|
} |
|
|
|
// Internal method that initializes blank correspondence maps and |
|
// a vertex stack for use in mcgregor_common_subgraphs_internal. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphInternalCallback> |
|
inline void mcgregor_common_subgraphs_internal_init |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphInternalCallback subgraph_callback) |
|
{ |
|
typedef mcgregor_common_subgraph_traits<GraphFirst, |
|
GraphSecond, VertexIndexMapFirst, |
|
VertexIndexMapSecond> SubGraphTraits; |
|
|
|
typename SubGraphTraits::correspondence_map_first_to_second_type |
|
correspondence_map_1_to_2(num_vertices(graph1), vindex_map1); |
|
|
|
BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) { |
|
put(correspondence_map_1_to_2, vertex1, |
|
graph_traits<GraphSecond>::null_vertex()); |
|
} |
|
|
|
typename SubGraphTraits::correspondence_map_second_to_first_type |
|
correspondence_map_2_to_1(num_vertices(graph2), vindex_map2); |
|
|
|
BGL_FORALL_VERTICES_T(vertex2, graph2, GraphSecond) { |
|
put(correspondence_map_2_to_1, vertex2, |
|
graph_traits<GraphFirst>::null_vertex()); |
|
} |
|
|
|
typedef typename graph_traits<GraphFirst>::vertex_descriptor |
|
VertexFirst; |
|
|
|
std::stack<VertexFirst> vertex_stack1; |
|
|
|
mcgregor_common_subgraphs_internal |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
correspondence_map_1_to_2, correspondence_map_2_to_1, |
|
vertex_stack1, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, |
|
subgraph_callback); |
|
} |
|
|
|
} // namespace detail |
|
|
|
// ========================================================================== |
|
|
|
// Enumerates all common subgraphs present in graph1 and graph2. |
|
// Continues until the search space has been fully explored or false |
|
// is returned from user_callback. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, |
|
user_callback); |
|
} |
|
|
|
// Variant of mcgregor_common_subgraphs with all default parameters |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
get(vertex_index, graph1), get(vertex_index, graph2), |
|
always_equivalent(), always_equivalent(), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// Named parameter variant of mcgregor_common_subgraphs |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback, |
|
typename Param, |
|
typename Tag, |
|
typename Rest> |
|
void mcgregor_common_subgraphs |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback, |
|
const bgl_named_params<Param, Tag, Rest>& params) |
|
{ |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
choose_const_pmap(get_param(params, vertex_index1), |
|
graph1, vertex_index), |
|
choose_const_pmap(get_param(params, vertex_index2), |
|
graph2, vertex_index), |
|
choose_param(get_param(params, edges_equivalent_t()), |
|
always_equivalent()), |
|
choose_param(get_param(params, vertices_equivalent_t()), |
|
always_equivalent()), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// ========================================================================== |
|
|
|
namespace detail { |
|
|
|
// Binary function object that intercepts subgraphs from |
|
// mcgregor_common_subgraphs_internal and maintains a cache of |
|
// unique subgraphs. The user callback is invoked for each unique |
|
// subgraph. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename SubGraphCallback> |
|
struct unique_subgraph_interceptor { |
|
|
|
typedef typename graph_traits<GraphFirst>::vertices_size_type |
|
VertexSizeFirst; |
|
|
|
typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_first_to_second_type |
|
CachedCorrespondenceMapFirstToSecond; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_second_to_first_type |
|
CachedCorrespondenceMapSecondToFirst; |
|
|
|
typedef std::pair<VertexSizeFirst, |
|
std::pair<CachedCorrespondenceMapFirstToSecond, |
|
CachedCorrespondenceMapSecondToFirst> > SubGraph; |
|
|
|
typedef std::vector<SubGraph> SubGraphList; |
|
|
|
unique_subgraph_interceptor(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
SubGraphCallback user_callback) : |
|
m_graph1(graph1), m_graph2(graph2), |
|
m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2), |
|
m_subgraphs(make_shared<SubGraphList>()), |
|
m_user_callback(user_callback) { } |
|
|
|
template <typename CorrespondenceMapFirstToSecond, |
|
typename CorrespondenceMapSecondToFirst> |
|
bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
CorrespondenceMapSecondToFirst correspondence_map_2_to_1, |
|
VertexSizeFirst subgraph_size) { |
|
|
|
for (typename SubGraphList::const_iterator |
|
subgraph_iter = m_subgraphs->begin(); |
|
subgraph_iter != m_subgraphs->end(); |
|
++subgraph_iter) { |
|
|
|
SubGraph subgraph_cached = *subgraph_iter; |
|
|
|
// Compare subgraph sizes |
|
if (subgraph_size != subgraph_cached.first) { |
|
continue; |
|
} |
|
|
|
if (!are_property_maps_different(correspondence_map_1_to_2, |
|
subgraph_cached.second.first, |
|
m_graph1)) { |
|
|
|
// New subgraph is a duplicate |
|
return (true); |
|
} |
|
} |
|
|
|
// Subgraph is unique, so make a cached copy |
|
CachedCorrespondenceMapFirstToSecond |
|
new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond |
|
(num_vertices(m_graph1), m_vindex_map1); |
|
|
|
CachedCorrespondenceMapSecondToFirst |
|
new_subgraph_2_to_1 = CorrespondenceMapSecondToFirst |
|
(num_vertices(m_graph2), m_vindex_map2); |
|
|
|
BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { |
|
put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); |
|
} |
|
|
|
BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { |
|
put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); |
|
} |
|
|
|
m_subgraphs->push_back(std::make_pair(subgraph_size, |
|
std::make_pair(new_subgraph_1_to_2, |
|
new_subgraph_2_to_1))); |
|
|
|
return (m_user_callback(correspondence_map_1_to_2, |
|
correspondence_map_2_to_1, |
|
subgraph_size)); |
|
} |
|
|
|
private: |
|
const GraphFirst& m_graph1; |
|
const GraphFirst& m_graph2; |
|
const VertexIndexMapFirst m_vindex_map1; |
|
const VertexIndexMapSecond m_vindex_map2; |
|
shared_ptr<SubGraphList> m_subgraphs; |
|
SubGraphCallback m_user_callback; |
|
}; |
|
|
|
} // namespace detail |
|
|
|
// Enumerates all unique common subgraphs between graph1 and graph2. |
|
// The user callback is invoked for each unique subgraph as they are |
|
// discovered. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
detail::unique_subgraph_interceptor<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond, |
|
SubGraphCallback> unique_callback |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
user_callback); |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, unique_callback); |
|
} |
|
|
|
// Variant of mcgregor_common_subgraphs_unique with all default |
|
// parameters. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
mcgregor_common_subgraphs_unique |
|
(graph1, graph2, |
|
get(vertex_index, graph1), get(vertex_index, graph2), |
|
always_equivalent(), always_equivalent(), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// Named parameter variant of mcgregor_common_subgraphs_unique |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback, |
|
typename Param, |
|
typename Tag, |
|
typename Rest> |
|
void mcgregor_common_subgraphs_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback, |
|
const bgl_named_params<Param, Tag, Rest>& params) |
|
{ |
|
mcgregor_common_subgraphs_unique |
|
(graph1, graph2, |
|
choose_const_pmap(get_param(params, vertex_index1), |
|
graph1, vertex_index), |
|
choose_const_pmap(get_param(params, vertex_index2), |
|
graph2, vertex_index), |
|
choose_param(get_param(params, edges_equivalent_t()), |
|
always_equivalent()), |
|
choose_param(get_param(params, vertices_equivalent_t()), |
|
always_equivalent()), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// ========================================================================== |
|
|
|
namespace detail { |
|
|
|
// Binary function object that intercepts subgraphs from |
|
// mcgregor_common_subgraphs_internal and maintains a cache of the |
|
// largest subgraphs. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename SubGraphCallback> |
|
struct maximum_subgraph_interceptor { |
|
|
|
typedef typename graph_traits<GraphFirst>::vertices_size_type |
|
VertexSizeFirst; |
|
|
|
typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_first_to_second_type |
|
CachedCorrespondenceMapFirstToSecond; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_second_to_first_type |
|
CachedCorrespondenceMapSecondToFirst; |
|
|
|
typedef std::pair<VertexSizeFirst, |
|
std::pair<CachedCorrespondenceMapFirstToSecond, |
|
CachedCorrespondenceMapSecondToFirst> > SubGraph; |
|
|
|
typedef std::vector<SubGraph> SubGraphList; |
|
|
|
maximum_subgraph_interceptor(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
SubGraphCallback user_callback) : |
|
m_graph1(graph1), m_graph2(graph2), |
|
m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2), |
|
m_subgraphs(make_shared<SubGraphList>()), |
|
m_largest_size_so_far(make_shared<VertexSizeFirst>(0)), |
|
m_user_callback(user_callback) { } |
|
|
|
template <typename CorrespondenceMapFirstToSecond, |
|
typename CorrespondenceMapSecondToFirst> |
|
bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
CorrespondenceMapSecondToFirst correspondence_map_2_to_1, |
|
VertexSizeFirst subgraph_size) { |
|
|
|
if (subgraph_size > *m_largest_size_so_far) { |
|
m_subgraphs->clear(); |
|
*m_largest_size_so_far = subgraph_size; |
|
} |
|
|
|
if (subgraph_size == *m_largest_size_so_far) { |
|
|
|
// Make a cached copy |
|
CachedCorrespondenceMapFirstToSecond |
|
new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond |
|
(num_vertices(m_graph1), m_vindex_map1); |
|
|
|
CachedCorrespondenceMapSecondToFirst |
|
new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst |
|
(num_vertices(m_graph2), m_vindex_map2); |
|
|
|
BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { |
|
put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); |
|
} |
|
|
|
BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { |
|
put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); |
|
} |
|
|
|
m_subgraphs->push_back(std::make_pair(subgraph_size, |
|
std::make_pair(new_subgraph_1_to_2, |
|
new_subgraph_2_to_1))); |
|
} |
|
|
|
return (true); |
|
} |
|
|
|
void output_subgraphs() { |
|
for (typename SubGraphList::const_iterator |
|
subgraph_iter = m_subgraphs->begin(); |
|
subgraph_iter != m_subgraphs->end(); |
|
++subgraph_iter) { |
|
|
|
SubGraph subgraph_cached = *subgraph_iter; |
|
m_user_callback(subgraph_cached.second.first, |
|
subgraph_cached.second.second, |
|
subgraph_cached.first); |
|
} |
|
} |
|
|
|
private: |
|
const GraphFirst& m_graph1; |
|
const GraphFirst& m_graph2; |
|
const VertexIndexMapFirst m_vindex_map1; |
|
const VertexIndexMapSecond m_vindex_map2; |
|
shared_ptr<SubGraphList> m_subgraphs; |
|
shared_ptr<VertexSizeFirst> m_largest_size_so_far; |
|
SubGraphCallback m_user_callback; |
|
}; |
|
|
|
} // namespace detail |
|
|
|
// Enumerates the largest common subgraphs found between graph1 |
|
// and graph2. Note that the ENTIRE search space is explored before |
|
// user_callback is actually invoked. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_maximum |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
detail::maximum_subgraph_interceptor<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback> |
|
max_interceptor |
|
(graph1, graph2, vindex_map1, vindex_map2, user_callback); |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, max_interceptor); |
|
|
|
// Only output the largest subgraphs |
|
max_interceptor.output_subgraphs(); |
|
} |
|
|
|
// Variant of mcgregor_common_subgraphs_maximum with all default |
|
// parameters. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_maximum |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
mcgregor_common_subgraphs_maximum |
|
(graph1, graph2, |
|
get(vertex_index, graph1), get(vertex_index, graph2), |
|
always_equivalent(), always_equivalent(), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// Named parameter variant of mcgregor_common_subgraphs_maximum |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback, |
|
typename Param, |
|
typename Tag, |
|
typename Rest> |
|
void mcgregor_common_subgraphs_maximum |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback, |
|
const bgl_named_params<Param, Tag, Rest>& params) |
|
{ |
|
mcgregor_common_subgraphs_maximum |
|
(graph1, graph2, |
|
choose_const_pmap(get_param(params, vertex_index1), |
|
graph1, vertex_index), |
|
choose_const_pmap(get_param(params, vertex_index2), |
|
graph2, vertex_index), |
|
choose_param(get_param(params, edges_equivalent_t()), |
|
always_equivalent()), |
|
choose_param(get_param(params, vertices_equivalent_t()), |
|
always_equivalent()), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// ========================================================================== |
|
|
|
namespace detail { |
|
|
|
// Binary function object that intercepts subgraphs from |
|
// mcgregor_common_subgraphs_internal and maintains a cache of the |
|
// largest, unique subgraphs. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename SubGraphCallback> |
|
struct unique_maximum_subgraph_interceptor { |
|
|
|
typedef typename graph_traits<GraphFirst>::vertices_size_type |
|
VertexSizeFirst; |
|
|
|
typedef mcgregor_common_subgraph_traits<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond> SubGraphTraits; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_first_to_second_type |
|
CachedCorrespondenceMapFirstToSecond; |
|
|
|
typedef typename SubGraphTraits::correspondence_map_second_to_first_type |
|
CachedCorrespondenceMapSecondToFirst; |
|
|
|
typedef std::pair<VertexSizeFirst, |
|
std::pair<CachedCorrespondenceMapFirstToSecond, |
|
CachedCorrespondenceMapSecondToFirst> > SubGraph; |
|
|
|
typedef std::vector<SubGraph> SubGraphList; |
|
|
|
unique_maximum_subgraph_interceptor(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
SubGraphCallback user_callback) : |
|
m_graph1(graph1), m_graph2(graph2), |
|
m_vindex_map1(vindex_map1), m_vindex_map2(vindex_map2), |
|
m_subgraphs(make_shared<SubGraphList>()), |
|
m_largest_size_so_far(make_shared<VertexSizeFirst>(0)), |
|
m_user_callback(user_callback) { } |
|
|
|
template <typename CorrespondenceMapFirstToSecond, |
|
typename CorrespondenceMapSecondToFirst> |
|
bool operator()(CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
CorrespondenceMapSecondToFirst correspondence_map_2_to_1, |
|
VertexSizeFirst subgraph_size) { |
|
|
|
if (subgraph_size > *m_largest_size_so_far) { |
|
m_subgraphs->clear(); |
|
*m_largest_size_so_far = subgraph_size; |
|
} |
|
|
|
if (subgraph_size == *m_largest_size_so_far) { |
|
|
|
// Check if subgraph is unique |
|
for (typename SubGraphList::const_iterator |
|
subgraph_iter = m_subgraphs->begin(); |
|
subgraph_iter != m_subgraphs->end(); |
|
++subgraph_iter) { |
|
|
|
SubGraph subgraph_cached = *subgraph_iter; |
|
|
|
if (!are_property_maps_different(correspondence_map_1_to_2, |
|
subgraph_cached.second.first, |
|
m_graph1)) { |
|
|
|
// New subgraph is a duplicate |
|
return (true); |
|
} |
|
} |
|
|
|
// Subgraph is unique, so make a cached copy |
|
CachedCorrespondenceMapFirstToSecond |
|
new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond |
|
(num_vertices(m_graph1), m_vindex_map1); |
|
|
|
CachedCorrespondenceMapSecondToFirst |
|
new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst |
|
(num_vertices(m_graph2), m_vindex_map2); |
|
|
|
BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { |
|
put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); |
|
} |
|
|
|
BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { |
|
put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); |
|
} |
|
|
|
m_subgraphs->push_back(std::make_pair(subgraph_size, |
|
std::make_pair(new_subgraph_1_to_2, |
|
new_subgraph_2_to_1))); |
|
} |
|
|
|
return (true); |
|
} |
|
|
|
void output_subgraphs() { |
|
for (typename SubGraphList::const_iterator |
|
subgraph_iter = m_subgraphs->begin(); |
|
subgraph_iter != m_subgraphs->end(); |
|
++subgraph_iter) { |
|
|
|
SubGraph subgraph_cached = *subgraph_iter; |
|
m_user_callback(subgraph_cached.second.first, |
|
subgraph_cached.second.second, |
|
subgraph_cached.first); |
|
} |
|
} |
|
|
|
private: |
|
const GraphFirst& m_graph1; |
|
const GraphFirst& m_graph2; |
|
const VertexIndexMapFirst m_vindex_map1; |
|
const VertexIndexMapSecond m_vindex_map2; |
|
shared_ptr<SubGraphList> m_subgraphs; |
|
shared_ptr<VertexSizeFirst> m_largest_size_so_far; |
|
SubGraphCallback m_user_callback; |
|
}; |
|
|
|
} // namespace detail |
|
|
|
// Enumerates the largest, unique common subgraphs found between |
|
// graph1 and graph2. Note that the ENTIRE search space is explored |
|
// before user_callback is actually invoked. |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename VertexIndexMapFirst, |
|
typename VertexIndexMapSecond, |
|
typename EdgeEquivalencePredicate, |
|
typename VertexEquivalencePredicate, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_maximum_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
const VertexIndexMapFirst vindex_map1, |
|
const VertexIndexMapSecond vindex_map2, |
|
EdgeEquivalencePredicate edges_equivalent, |
|
VertexEquivalencePredicate vertices_equivalent, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
detail::unique_maximum_subgraph_interceptor<GraphFirst, GraphSecond, |
|
VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback> |
|
unique_max_interceptor |
|
(graph1, graph2, vindex_map1, vindex_map2, user_callback); |
|
|
|
detail::mcgregor_common_subgraphs_internal_init |
|
(graph1, graph2, |
|
vindex_map1, vindex_map2, |
|
edges_equivalent, vertices_equivalent, |
|
only_connected_subgraphs, unique_max_interceptor); |
|
|
|
// Only output the largest, unique subgraphs |
|
unique_max_interceptor.output_subgraphs(); |
|
} |
|
|
|
// Variant of mcgregor_common_subgraphs_maximum_unique with all default parameters |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback> |
|
void mcgregor_common_subgraphs_maximum_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback) |
|
{ |
|
|
|
mcgregor_common_subgraphs_maximum_unique |
|
(graph1, graph2, |
|
get(vertex_index, graph1), get(vertex_index, graph2), |
|
always_equivalent(), always_equivalent(), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// Named parameter variant of |
|
// mcgregor_common_subgraphs_maximum_unique |
|
template <typename GraphFirst, |
|
typename GraphSecond, |
|
typename SubGraphCallback, |
|
typename Param, |
|
typename Tag, |
|
typename Rest> |
|
void mcgregor_common_subgraphs_maximum_unique |
|
(const GraphFirst& graph1, |
|
const GraphSecond& graph2, |
|
bool only_connected_subgraphs, |
|
SubGraphCallback user_callback, |
|
const bgl_named_params<Param, Tag, Rest>& params) |
|
{ |
|
mcgregor_common_subgraphs_maximum_unique |
|
(graph1, graph2, |
|
choose_const_pmap(get_param(params, vertex_index1), |
|
graph1, vertex_index), |
|
choose_const_pmap(get_param(params, vertex_index2), |
|
graph2, vertex_index), |
|
choose_param(get_param(params, edges_equivalent_t()), |
|
always_equivalent()), |
|
choose_param(get_param(params, vertices_equivalent_t()), |
|
always_equivalent()), |
|
only_connected_subgraphs, user_callback); |
|
} |
|
|
|
// ========================================================================== |
|
|
|
// Fills a membership map (vertex -> bool) using the information |
|
// present in correspondence_map_1_to_2. Every vertex in a |
|
// membership map will have a true value only if it is not |
|
// associated with a null vertex in the correspondence map. |
|
template <typename GraphSecond, |
|
typename GraphFirst, |
|
typename CorrespondenceMapFirstToSecond, |
|
typename MembershipMapFirst> |
|
void fill_membership_map |
|
(const GraphFirst& graph1, |
|
const CorrespondenceMapFirstToSecond correspondence_map_1_to_2, |
|
MembershipMapFirst membership_map1) { |
|
|
|
BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) { |
|
put(membership_map1, vertex1, |
|
get(correspondence_map_1_to_2, vertex1) != graph_traits<GraphSecond>::null_vertex()); |
|
} |
|
|
|
} |
|
|
|
// Traits associated with a membership map filtered graph. Provided |
|
// for convenience to access graph and vertex filter types. |
|
template <typename Graph, |
|
typename MembershipMap> |
|
struct membership_filtered_graph_traits { |
|
typedef property_map_filter<MembershipMap> vertex_filter_type; |
|
typedef filtered_graph<Graph, keep_all, vertex_filter_type> graph_type; |
|
}; |
|
|
|
// Returns a filtered sub-graph of graph whose edge and vertex |
|
// inclusion is dictated by membership_map. |
|
template <typename Graph, |
|
typename MembershipMap> |
|
typename membership_filtered_graph_traits<Graph, MembershipMap>::graph_type |
|
make_membership_filtered_graph |
|
(const Graph& graph, |
|
MembershipMap& membership_map) { |
|
|
|
typedef membership_filtered_graph_traits<Graph, MembershipMap> MFGTraits; |
|
typedef typename MFGTraits::graph_type MembershipFilteredGraph; |
|
|
|
typename MFGTraits::vertex_filter_type v_filter(membership_map); |
|
|
|
return (MembershipFilteredGraph(graph, keep_all(), v_filter)); |
|
|
|
} |
|
|
|
} // namespace boost |
|
|
|
#endif // BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP
|
|
|