1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
6 * EMAXA Kutato-fejleszto Kft. (EMAXA Research Ltd.)
8 * Permission to use, modify and distribute this software is granted
9 * provided that this copyright notice appears in all copies. For
10 * precise terms see the accompanying LICENSE file.
12 * This software is provided "AS IS" with no warranty of any kind,
13 * express or implied, and with no claim as to its suitability for any
21 ///\ingroup graph_properties
23 ///\brief VF2 algorithm \cite cordella2004sub.
25 #include <lemon/core.h>
26 #include <lemon/concepts/graph.h>
27 #include <lemon/dfs.h>
28 #include <lemon/bfs.h>
29 #include <test/test_tools.h>
43 template<class T1, class T2>
44 bool operator()(T1, T2) const
50 template<class M1, class M2>
56 MapEq(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
57 bool operator()(typename M1::Key k1, typename M2::Key k2) const
59 return _m1[k1] == _m2[k2];
64 class DfsLeaveOrder : public DfsVisitor<G>
67 std::vector<typename G::Node> &_order;
70 DfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
71 : i(countNodes(g)), _g(g), _order(order)
73 void leave(const typename G::Node &node)
80 class BfsLeaveOrder : public BfsVisitor<G>
84 std::vector<typename G::Node> &_order;
86 BfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
87 : i(0), _g(g), _order(order)
89 void process(const typename G::Node &node)
97 ///Graph mapping types.
99 ///\ingroup graph_isomorphism
100 ///The \ref Vf2 "VF2" algorithm is capable of finding different kind of
101 ///embeddings, this enum specifies its type.
103 ///See \ref graph_isomorphism for a more detailed description.
104 enum Vf2MappingType {
105 /// Subgraph isomorphism
107 /// Induced subgraph isomorphism
109 /// Graph isomorphism
111 /// If the two graph has the same number of nodes, than it is
112 /// equivalent to \ref INDUCED, and if they also have the same
113 /// number of edges, then it is also equivalent to \ref SUBGRAPH.
115 /// However, using this setting is faster than the other two
120 ///%VF2 algorithm class.
122 ///\ingroup graph_isomorphism This class provides an efficient
123 ///implementation of the %VF2 algorithm \cite cordella2004sub
124 ///for variants of the (Sub)graph Isomorphism problem.
126 ///There is also a \ref vf2() "function-type interface" called \ref vf2()
127 ///for the %VF2 algorithm, which is probably more convenient in most
130 ///\tparam G1 The type of the graph to be embedded.
131 ///The default type is \ref ListDigraph.
132 ///\tparam G2 The type of the graph g1 will be embedded into.
133 ///The default type is \ref ListDigraph.
134 ///\tparam M The type of the NodeMap storing the mapping.
135 ///By default, it is G1::NodeMap<G2::Node>
136 ///\tparam NEQ A bool-valued binary functor determinining whether a node is
137 ///mappable to another. By default it is an always true operator.
141 template<class G1, class G2, class M, class NEQ >
143 template<class G1=ListDigraph,
144 class G2=ListDigraph,
145 class M = typename G1::template NodeMap<G2::Node>,
146 class NEQ = bits::vf2::AlwaysEq >
150 //Current depth in the DFS tree.
152 //Functor with bool operator()(G1::Node,G2::Node), which returns 1
153 //if and only if the 2 nodes are equivalent.
156 typename G2::template NodeMap<int> _conn;
157 //Current mapping. We index it by the nodes of g1, and match[v] is
160 //order[i] is the node of g1, for which we find a pair if depth=i
161 std::vector<typename G1::Node> order;
162 //currEdgeIts[i] is an edge iterator, witch is last used in the ith
163 //depth to find a pair for order[i].
164 std::vector<typename G2::IncEdgeIt> currEdgeIts;
169 //lookup tables for cut the searchtree
170 typename G1::template NodeMap<int> rNew1t,rInOut1t;
172 Vf2MappingType _mapping_type;
174 //cut the search tree
175 template<Vf2MappingType MT>
176 bool cut(const typename G1::Node n1,const typename G2::Node n2) const
178 int rNew2=0,rInOut2=0;
179 for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
181 const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
182 if(_conn[currNode]>0)
184 else if(MT!=SUBGRAPH&&_conn[currNode]==0)
190 return rInOut1t[n1]<=rInOut2&&rNew1t[n1]<=rNew2;
192 return rInOut1t[n1]<=rInOut2;
194 return rInOut1t[n1]==rInOut2&&rNew1t[n1]==rNew2;
200 template<Vf2MappingType MT>
201 bool feas(const typename G1::Node n1,const typename G2::Node n2)
206 for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1)
208 const typename G1::Node currNode=_g1.oppositeNode(n1,e1);
209 if(_mapping[currNode]!=INVALID)
210 --_conn[_mapping[currNode]];
213 for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
215 const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
216 if(_conn[currNode]<-1)
218 else if(MT!=SUBGRAPH&&_conn[currNode]==-1)
225 for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1)
227 const typename G1::Node currNode=_g1.oppositeNode(n1,e1);
228 if(_mapping[currNode]!=INVALID&&_conn[_mapping[currNode]]!=-1)
237 if(_conn[_mapping[currNode]]<-1)
241 _conn[_mapping[currNode]]=-1;
244 return isIso&&cut<MT>(n1,n2);
247 void addPair(const typename G1::Node n1,const typename G2::Node n2)
251 for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
252 if(_conn[_g2.oppositeNode(n2,e2)]!=-1)
253 ++_conn[_g2.oppositeNode(n2,e2)];
256 void subPair(const typename G1::Node n1,const typename G2::Node n2)
259 _mapping.set(n1,INVALID);
260 for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
262 const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
263 if(_conn[currNode]>0)
265 else if(_conn[currNode]==-1)
270 void setOrder()//we will find pairs for the nodes of g1 in this order
272 // bits::vf2::DfsLeaveOrder<G1> v(_g1,order);
273 // DfsVisit<G1,bits::vf2::DfsLeaveOrder<G1> >dfs(_g1, v);
276 //it is more efficient in practice than DFS
277 bits::vf2::BfsLeaveOrder<G1> v(_g1,order);
278 BfsVisit<G1,bits::vf2::BfsLeaveOrder<G1> >bfs(_g1, v);
282 template<Vf2MappingType MT>
287 //there are not nodes in g1, which has not pair in g2.
288 if(_depth==static_cast<int>(order.size()))
293 //the node of g2, which neighbours are the candidates for
294 //the pair of order[_depth]
295 typename G2::Node currPNode;
296 if(currEdgeIts[_depth]==INVALID)
298 typename G1::IncEdgeIt fstMatchedE(_g1,order[_depth]);
299 //if _mapping[order[_depth]]!=INVALID, we dont use
301 if(_mapping[order[_depth]]==INVALID)
302 for(; fstMatchedE!=INVALID &&
303 _mapping[_g1.oppositeNode(order[_depth],
304 fstMatchedE)]==INVALID;
305 ++fstMatchedE) ; //find fstMatchedE
306 if(fstMatchedE==INVALID||_mapping[order[_depth]]!=INVALID)
308 //We did not find an covered neighbour, this means
309 //the graph is not connected(or _depth==0). Every
310 //uncovered(and there are some other properties due
311 //to the spec. problem types) node of g2 is
312 //candidate. We can read the iterator of the last
313 //tryed node from the match if it is not the first
314 //try(match[order[_depth]]!=INVALID)
315 typename G2::NodeIt n2(_g2);
316 //if its not the first try
317 if(_mapping[order[_depth]]!=INVALID)
319 n2=++typename G2::NodeIt(_g2,_mapping[order[_depth]]);
320 subPair(order[_depth],_mapping[order[_depth]]);
322 for(; n2!=INVALID; ++n2)
323 if(MT!=SUBGRAPH&&_conn[n2]==0)
325 if(feas<MT>(order[_depth],n2))
328 else if(MT==SUBGRAPH&&_conn[n2]>=0)
329 if(feas<MT>(order[_depth],n2))
331 // n2 is the next candidate
334 addPair(order[_depth],n2);
337 else // there is no more candidate
343 currPNode=_mapping[_g1.oppositeNode(order[_depth],
345 currEdgeIts[_depth]=typename G2::IncEdgeIt(_g2,currPNode);
350 currPNode=_g2.oppositeNode(_mapping[order[_depth]],
351 currEdgeIts[_depth]);
352 subPair(order[_depth],_mapping[order[_depth]]);
353 ++currEdgeIts[_depth];
355 for(; currEdgeIts[_depth]!=INVALID; ++currEdgeIts[_depth])
357 const typename G2::Node currNode =
358 _g2.oppositeNode(currPNode, currEdgeIts[_depth]);
359 //if currNode is uncovered
360 if(_conn[currNode]>0&&feas<MT>(order[_depth],currNode))
362 addPair(order[_depth],currNode);
366 currEdgeIts[_depth]==INVALID?--_depth:++_depth;
371 //calc. the lookup table for cut the searchtree
372 void setRNew1tRInOut1t()
374 typename G1::template NodeMap<int> tmp(_g1,0);
375 for(unsigned int i=0; i<order.size(); ++i)
378 for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1)
380 const typename G1::Node currNode=_g1.oppositeNode(order[i],e1);
382 ++rInOut1t[order[i]];
383 else if(tmp[currNode]==0)
386 for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1)
388 const typename G1::Node currNode=_g1.oppositeNode(order[i],e1);
389 if(tmp[currNode]!=-1)
399 ///\param g1 The graph to be embedded into \e g2.
400 ///\param g2 The graph \e g1 will be embedded into.
401 ///\param m \ref concepts::ReadWriteMap "read-write" NodeMap
402 ///storing the found mapping.
403 ///\param neq A bool-valued binary functor determinining whether a node is
404 ///mappable to another. By default it is an always true operator.
405 Vf2(const G1 &g1, const G2 &g2,M &m, const NEQ &neq = NEQ() ) :
406 _nEq(neq), _conn(g2,0), _mapping(m), order(countNodes(g1)),
407 currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNew1t(g1,0),
408 rInOut1t(g1,0), _mapping_type(SUBGRAPH)
413 for(typename G1::NodeIt n(g1);n!=INVALID;++n)
417 ///Returns the current mapping type
419 ///Returns the current mapping type
421 Vf2MappingType mappingType() const { return _mapping_type; }
424 ///Sets mapping type.
426 ///The mapping type is set to \ref SUBGRAPH by default.
428 ///\sa See \ref Vf2MappingType for the possible values.
429 void mappingType(Vf2MappingType m_type) { _mapping_type = m_type; }
433 ///It finds a mapping between from g1 into g2 according to the mapping
434 ///type set by \ref mappingType(Vf2MappingType) "mappingType()".
436 ///By subsequent calls, it returns all possible mappings one-by-one.
438 ///\retval true if a mapping is found.
439 ///\retval false if there is no (more) mapping.
442 switch(_mapping_type)
445 return extMatch<SUBGRAPH>();
447 return extMatch<INDUCED>();
449 return extMatch<ISOMORPH>();
456 template<class G1, class G2>
466 Vf2MappingType _mapping_type;
468 typedef typename G1::template NodeMap<typename G2::Node> Mapping;
473 _mapping = new Mapping(_g1);
476 typedef bits::vf2::AlwaysEq NodeEq;
479 Vf2WizardBase(const G1 &g1,const G2 &g2)
480 : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) {}
483 /// Auxiliary class for the function-type interface of %VF2 algorithm.
485 /// This auxiliary class implements the named parameters of
486 /// \ref vf2() "function-type interface" of \ref Vf2 algorithm.
488 /// \warning This class should only be used through the function \ref vf2().
490 /// \tparam TR The traits class that defines various types used by the
493 class Vf2Wizard : public TR
496 typedef typename TR::Graph1 Graph1;
497 typedef typename TR::Graph2 Graph2;
499 typedef typename TR::Mapping Mapping;
500 typedef typename TR::NodeEq NodeEq;
504 using TR::_mapping_type;
510 Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {}
513 Vf2Wizard(const Base &b) : Base(b) {}
517 struct SetMappingBase : public Base {
519 SetMappingBase(const Base &b) : Base(b) {}
522 ///\brief \ref named-templ-param "Named parameter" for setting
525 ///\ref named-templ-param "Named parameter" function for setting
526 ///the map that stores the found embedding.
528 Vf2Wizard< SetMappingBase<T> > mapping(const T &t)
530 Base::_mapping=reinterpret_cast<void*>(const_cast<T*>(&t));
531 Base::_local_mapping = false;
532 return Vf2Wizard<SetMappingBase<T> >(*this);
536 struct SetNodeEqBase : public Base {
539 SetNodeEqBase(const Base &b, const NE &node_eq)
540 : Base(b), _node_eq(node_eq) {}
543 ///\brief \ref named-templ-param "Named parameter" for setting
544 ///the node equivalence relation.
546 ///\ref named-templ-param "Named parameter" function for setting
547 ///the equivalence relation between the nodes.
549 ///\param node_eq A bool-valued binary functor determinining
550 ///whether a node is mappable to another. By default it is an
551 ///always true operator.
553 Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq)
555 return Vf2Wizard<SetNodeEqBase<T> >(SetNodeEqBase<T>(*this,node_eq));
558 ///\brief \ref named-templ-param "Named parameter" for setting
561 ///\ref named-templ-param "Named parameter" function for setting
562 ///the node labels defining equivalence relation between them.
564 ///\param m1 It is arbitrary \ref concepts::ReadMap "readable node map"
566 ///\param m2 It is arbitrary \ref concepts::ReadMap "readable node map"
569 ///The value type of these maps must be equal comparable.
570 template<class M1, class M2>
571 Vf2Wizard< SetNodeEqBase<bits::vf2::MapEq<M1,M2> > >
572 nodeLabels(const M1 &m1,const M2 &m2)
574 return nodeEq(bits::vf2::MapEq<M1,M2>(m1,m2));
577 ///\brief \ref named-templ-param "Named parameter" for setting
580 ///\ref named-templ-param "Named parameter" for setting
583 ///The mapping type is set to \ref SUBGRAPH by default.
585 ///\sa See \ref Vf2MappingType for the possible values.
586 Vf2Wizard<Base> &mappingType(Vf2MappingType m_type)
588 _mapping_type = m_type;
592 ///\brief \ref named-templ-param "Named parameter" for setting
593 ///the mapping type to \ref INDUCED.
595 ///\ref named-templ-param "Named parameter" for setting
596 ///the mapping type to \ref INDUCED.
597 Vf2Wizard<Base> &induced()
599 _mapping_type = INDUCED;
603 ///\brief \ref named-templ-param "Named parameter" for setting
604 ///the mapping type to \ref ISOMORPH.
606 ///\ref named-templ-param "Named parameter" for setting
607 ///the mapping type to \ref ISOMORPH.
608 Vf2Wizard<Base> &iso()
610 _mapping_type = ISOMORPH;
614 ///Runs VF2 algorithm.
616 ///This method runs VF2 algorithm.
618 ///\retval true if a mapping is found.
619 ///\retval false if there is no (more) mapping.
622 if(Base::_local_mapping)
623 Base::createMapping();
625 Vf2<Graph1, Graph2, Mapping, NodeEq >
626 alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
628 alg.mappingType(_mapping_type);
630 bool ret = alg.find();
632 if(Base::_local_mapping)
633 delete reinterpret_cast<Mapping*>(_mapping);
639 ///Function-type interface for VF2 algorithm.
641 /// \ingroup graph_isomorphism
642 ///Function-type interface for VF2 algorithm \cite cordella2004sub.
644 ///This function has several \ref named-func-param "named parameters"
645 ///declared as the members of class \ref Vf2Wizard.
646 ///The following examples show how to use these parameters.
648 /// // Find an embedding of graph g into graph h
649 /// ListGraph::NodeMap<ListGraph::Node> m(g);
650 /// vf2(g,h).mapping(m).run();
652 /// // Check whether graphs g and h are isomorphic
653 /// bool is_iso = vf2(g,h).iso().run();
655 ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()"
656 ///to the end of the expression.
659 template<class G1, class G2>
660 Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2)
662 return Vf2Wizard<Vf2WizardBase<G1,G2> >(g1,g2);