//======================================================================= | |
// 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 |