// morpho/cdl/bgl_expansions/algorithms/ullmann.hpp header file// // Copyright (c) 2003-2008 Vladimir J. Sykora // Copyright (c) 2007-2008 Vladimir J. Sykora and NCU Studies Ltd // Modifications by Greg Landrum, January 2009 // //***************************************************************************** // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //***************************************************************************** //----------------------------------------------------------------------------- // Algorithm due to JR Ullmann. "An Algorithm for Subgraph // Isomorphism". Journal of the Association for // Computing Machinery, Vol 23, No.1, January 1976, pp 31-42. #ifndef MORPHO_CDL_BGL_EXP_ULLMANN_HPP #define MORPHO_CDL_BGL_EXP_ULLMANN_HPP // -------- boost #include #include // -------- std #include // for std::pair<> #include namespace boost { namespace detail { template bool forward_checking(const Graph& g1, const Graph& g2, UblasMatrix& M, size_t count, BackInsertionSequence& F, size_t num_vert_g1, size_t num_vert_g2, EdgeLabeling& edge_labeling){ typedef std::pair::edge_descriptor,bool> edge_presence; typename BackInsertionSequence::iterator fi, fi_end=F.end(); for (size_t k=count+1; kfirst,g1); if(ep1.second) { flag1_1=true; edge_presence ep2=edge(l,fi->second,g2); if(ep2.second) flag1=edge_labeling(ep1.first,ep2.first); } if(flag1_1 && flag1) { M(k,l)=1; ++fi; continue; } edge_presence ep2=edge(l,fi->second,g2); if(ep2.second) { flag2_1=true; ep1=edge(k,fi->first,g1); if(ep1.second){ flag2=edge_labeling(ep1.first,ep2.first); } else { // ring closed in main structure, not closed in query. This should pass flag2=true; } } if(flag2_1 && flag2) { //if one edge exists, there must be a mapping M(k,l)=1; } else if ( !flag1_1 && !flag2_1 ) { // or both edges are not present M(k,l)=1; } else M(k,l)=0; // if not, there's no mapping ++fi; } } } // TODO: change the data structure of the M matrix to sparse matrix. This wouldn't be neccessary size_t cero_row(0); for (size_t k=0; k bool backtrack(const Graph& g1, const Graph& g2, size_t count, const UblasMatrix& M, BackInsertionSequence& F, const size_t num_vert_g1, const size_t num_vert_g2, EdgeLabeling& edge_labeling){ if(count==num_vert_g1) return true; for (size_t i=0; i void backtrack_all(const Graph& g1, const Graph& g2, size_t count, const UblasMatrix& M, DoubleBackInsertionSequence& FF, const size_t num_vert_g1, const size_t num_vert_g2, EdgeLabeling& edge_labeling) { if(count==num_vert_g1) return; DoubleBackInsertionSequence holdFF; holdFF.insert(holdFF.begin(),FF.begin(),FF.end()); FF.clear(); for (size_t i=0; i void prepareM(const Graph& g1, const Graph& g2, VertexLabeling& vertex_labeling,UblasMatrix &M){ size_t rows(num_vertices(g1)); size_t cols(num_vertices(g2)); M.resize(rows,cols); // initialize the matrix: for (size_t i=0; i=out_degree(i,g1) && vertex_labeling(i,j)) { M(i,j)=1; } else M(i,j)=0; } } } } // namespace detail // test if g1 is a subgraph of g2. mapped vertices are returned in F // Mapping : first: g1 vertices, second : g2 vertices // O( num_vertices(g1)! num_vertices(g1) ^ 3 ) // This function doesnt Work with filtered graphs! // The size of F doesn't indicate match! template < class Graph , class VertexLabeling // binary predicate , class EdgeLabeling // binary predicate , class BackInsertionSequence // contains std::pair > bool ullmann(const Graph& g1, const Graph& g2, VertexLabeling& vertex_labeling, EdgeLabeling& edge_labeling, BackInsertionSequence& F) { typedef ::boost::numeric::ublas::matrix matrix_t; size_t rows(num_vertices(g1)); size_t cols(num_vertices(g2)); matrix_t M; detail::prepareM(g1,g2,vertex_labeling,M); size_t count(0); return detail::backtrack(g1,g2,count,M,F,rows,cols,edge_labeling); } // test if g1 is a subgraph of g2. // F returns all mappings of g1 in g2. mapping in separate containers template < class Graph , class VertexLabeling // binary predicate , class EdgeLabeling // binary predicate , class DoubleBackInsertionSequence // contains a back insertion sequence > bool ullmann_all(const Graph& g1, const Graph& g2, VertexLabeling& vertex_labeling, EdgeLabeling& edge_labeling, DoubleBackInsertionSequence& F) { typedef ::boost::numeric::ublas::matrix matrix_t; size_t rows(num_vertices(g1)); size_t cols(num_vertices(g2)); matrix_t M; detail::prepareM(g1,g2,vertex_labeling,M); size_t count(0); detail::backtrack_all(g1,g2,count,M,F,rows,cols,edge_labeling); return !F.empty(); } } // namespace boost #endif // MORPHO_CDL_BGL_EXP_ULLMANN_HPP