// $Id$ /* * This is an extensive modification by Greg Landrum of * pieces from several files in the vflib-2.0 distribution * * The initial version of the modifications was completed * in April 2009. * * the original author of the vflib files is: * Author: P. Foggia * http://amalfi.dis.unina.it/graph/db/vflib-2.0/doc/vflib.html * */ #include #include #include #include #ifndef __BGL_VF2_SUB_STATE_H__ #define __BGL_VF2_SUB_STATE_H__ namespace boost{ namespace detail { typedef unsigned short node_id; const node_id NULL_NODE=0xFFFF; struct NodeInfo { node_id id; node_id in; node_id out; }; /** * The ordering by in/out degree */ static bool nodeInfoComp1(const NodeInfo &a, const NodeInfo &b) { if(a.out < b.out) return true; if(a.out > b.out) return false; if(a.in < b.in) return true; if(a.in > b.in) return false; return false; } /** * The ordering by frequency/valence. * The frequency is in the out field, the valence in `in'. */ static int nodeInfoComp2(const NodeInfo &a, const NodeInfo &b) { if (!a.in && b.in ) return 1; if (a.in && !b.in) return -1; if (a.out < b.out) return -1; if (a.out > b.out) return 1; if( a.in < b.in ) return -1; if (a.in > b.in) return 1; return 0; } template VertexDescr getOtherIdx(const Graph &g,const EdgeDescr &edge,const VertexDescr &vertex) { VertexDescr tmp=boost::source(edge,g); if(tmp==vertex){ tmp=boost::target(edge,g); } return tmp; } /*---------------------------------------------------- * Sorts the nodes of a graphs, returning a * heap-allocated vector (using new) with the node ids * in the proper orders. * The sorting criterion takes into account: * 1 - The number of nodes with the same in/out * degree. * 2 - The valence of the nodes. * The nodes at the beginning of the vector are * the most singular, from which the matching should * start. *--------------------------------------------------*/ template node_id* SortNodesByFrequency(const Graph *g) { std::vector vect; vect.reserve(boost::num_vertices(*g)); typename Graph::vertex_iterator bNode,eNode; boost::tie(bNode,eNode) = boost::vertices(*g); while(bNode!=eNode){ NodeInfo t; t.id=vect.size(); t.in=boost::out_degree(*bNode,*g);// <- assuming undirected graph t.out=boost::out_degree(*bNode,*g); vect.push_back(t); ++bNode; } std::sort(vect.begin(),vect.end(),nodeInfoComp1); unsigned int run=1; for(unsigned int i=0; i class VF2SubState { private: Graph *g1, *g2; VertexCompatible &vc; EdgeCompatible &ec; MatchChecking &mc; unsigned int n1, n2; unsigned int core_len, orig_core_len; unsigned int added_node1; unsigned int t1both_len, t2both_len; unsigned int t1in_len, t1out_len; unsigned int t2in_len, t2out_len; // Core nodes are also counted by these... node_id *core_1; node_id *core_2; node_id *in_1; node_id *in_2; node_id *out_1; node_id *out_2; node_id *order; long *share_count; int *vs_compared; public: VF2SubState(Graph *ag1, Graph *ag2, VertexCompatible &avc, EdgeCompatible &aec, MatchChecking &amc, bool sortNodes=false) : g1(ag1), g2(ag2), vc(avc), ec(aec), mc(amc), n1(num_vertices(*ag1)),n2(num_vertices(*ag2)) { if (sortNodes){ order = SortNodesByFrequency(ag1); } else { order = NULL; } core_len=orig_core_len=0; t1both_len=t1in_len=t1out_len=0; t2both_len=t2in_len=t2out_len=0; added_node1=NULL_NODE; core_1=new node_id[n1]; core_2=new node_id[n2]; in_1=new node_id[n1]; in_2=new node_id[n2]; out_1=new node_id[n1]; out_2=new node_id[n2]; share_count = new long; for(unsigned int i=0; i(); *share_count = 1; }; VF2SubState(const VF2SubState &state) : g1(state.g1), g2(state.g2), vc(state.vc), ec(state.ec), mc(state.mc), n1(state.n1),n2(state.n2), order(state.order),vs_compared(state.vs_compared) //es_compared(state.es_compared) { core_len=orig_core_len=state.core_len; t1in_len=state.t1in_len; t1out_len=state.t1out_len; t1both_len=state.t1both_len; t2in_len=state.t2in_len; t2out_len=state.t2out_len; t2both_len=state.t2both_len; added_node1=NULL_NODE; core_1=state.core_1; core_2=state.core_2; in_1=state.in_1; in_2=state.in_2; out_1=state.out_1; out_2=state.out_2; share_count=state.share_count; ++(*share_count); }; ~VF2SubState(){ if (-- *share_count == 0) { delete [] core_1; delete [] core_2; delete [] in_1; delete [] out_1; delete [] in_2; delete [] out_2; delete share_count; delete [] order; //delete [] vs_compared; //delete es_compared; } }; bool IsGoal() { return core_len==n1 ; }; bool MatchChecks(const node_id c1[],const node_id c2[]){ return mc(c1,c2); }; bool IsDead() { return n1>n2 || t1both_len>t2both_len || t1out_len>t2out_len || t1in_len>t2in_len; }; unsigned int CoreLen() { return core_len; } Graph *GetGraph1() { return g1; } Graph *GetGraph2() { return g2; } bool NextPair(node_id *pn1, node_id *pn2, node_id prev_n1=NULL_NODE, node_id prev_n2=NULL_NODE){ if (prev_n1==NULL_NODE) prev_n1=0; if (prev_n2==NULL_NODE) prev_n2=0; else prev_n2++; #if 0 std::cerr<<" **** np: "<< prev_n1<<","<core_len && t2both_len>core_len) { while (prev_n1core_len && t2out_len>core_len) { while (prev_n1core_len && t2in_len>core_len) { while (prev_n1core_len && t2both_len>core_len) { while (prev_n2core_len && t2out_len>core_len) { while (prev_n2core_len && t2in_len>core_len) { while (prev_n2size()< bool match(int *pn, node_id c1[], node_id c2[], SubState &s) { if (s.IsGoal() ) { s.GetCoreSet(c1, c2); if(s.MatchChecks(c1,c2)) { *pn=s.CoreLen(); return true; } } if (s.IsDead()) return false; //std::cerr<<" > match: "<<*pn<<" "<<&s<AddPair(n1, n2); found=match(pn, c1, c2, *s1); s1->BackTrack(); delete s1; } } //std::cerr<<" < returning: "< bool match(node_id c1[], node_id c2[], SubState &s, DoubleBackInsertionSequence &res) { if (s.IsGoal()){ s.GetCoreSet(c1, c2); if(s.MatchChecks(c1,c2)) { typename DoubleBackInsertionSequence::value_type newSeq; for(unsigned int i=0;i(c1[i],c2[i])); } res.push_back(newSeq); } return false; } if (s.IsDead()) return false; node_id n1=NULL_NODE, n2=NULL_NODE; while (s.NextPair(&n1, &n2, n1, n2)) { if (s.IsFeasiblePair(n1, n2)){ SubState *s1=s.Clone(); s1->AddPair(n1, n2); if (match(c1, c2, *s1,res)){ s1->BackTrack(); delete s1; return true; } else { s1->BackTrack(); delete s1; } } } return false; } }; //end of namespace detail template < class Graph , class VertexLabeling // binary predicate , class EdgeLabeling // binary predicate , class MatchChecking // binary predicate , class BackInsertionSequence // contains std::pair > bool vf2(const Graph &g1,const Graph &g2, VertexLabeling& vertex_labeling, EdgeLabeling& edge_labeling, MatchChecking& match_checking, BackInsertionSequence& F){ detail::VF2SubState s0(&g1,&g2,vertex_labeling, edge_labeling,match_checking,false); detail::node_id *ni1 = new detail::node_id[num_vertices(g1)]; detail::node_id *ni2 = new detail::node_id[num_vertices(g2)]; int n=0; F.clear(); F.resize(0); if(match(&n,ni1,ni2,s0)){ for(unsigned int i=0;i(ni1[i],ni2[i])); } } delete [] ni1; delete [] ni2; return !F.empty(); }; template < class Graph , class VertexLabeling // binary predicate , class EdgeLabeling // binary predicate , class MatchChecking // binary predicate , class DoubleBackInsertionSequence // contains a back insertion sequence > bool vf2_all(const Graph& g1, const Graph& g2, VertexLabeling& vertex_labeling, EdgeLabeling& edge_labeling, MatchChecking& match_checking, DoubleBackInsertionSequence& F) { detail::VF2SubState s0(&g1,&g2,vertex_labeling, edge_labeling,match_checking,false); detail::node_id *ni1 = new detail::node_id[num_vertices(g1)]; detail::node_id *ni2 = new detail::node_id[num_vertices(g2)]; F.clear(); F.resize(0); match(ni1,ni2,s0,F); delete [] ni1; delete [] ni2; return !F.empty(); }; } // end of namespace boost #endif