# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1507339129 7200
# Node ID 76349d8212d3953003885aabcef528a29de3d42d
# Parent 120b9031eadac340f6078b85d9bcb43c9342bc93
Improve and unify comments and API docs of VF2 algorithms (#597)
diff git a/lemon/bits/vf2_internals.h b/lemon/bits/vf2_internals.h
a

b


26  26  namespace lemon { 
27  27  ///\ingroup graph_isomorphism 
28  28  ///The \ref Vf2 "VF2" algorithm is capable of finding different kind of 
29   ///embeddings, this enum specifies its type. 
 29  ///graph embeddings, this enum specifies their types. 
30  30  /// 
31  31  ///See \ref graph_isomorphism for a more detailed description. 
32  32  enum MappingType { 
… 
… 

35  35  /// Induced subgraph isomorphism 
36  36  INDUCED = 1, 
37  37  /// Graph isomorphism 
38   
39   /// If the two graph has the same number of nodes, than it is 
 38  /// 
 39  /// If the two graphs have the same number of nodes, than it is 
40  40  /// equivalent to \ref INDUCED, and if they also have the same 
41  41  /// number of edges, then it is also equivalent to \ref SUBGRAPH. 
42  42  /// 
43   /// However, using this setting is faster than the other two 
44   /// options. 
 43  /// However, using this setting is faster than the other two options. 
45  44  ISOMORPH = 2 
46  45  }; 
47  46  } 
diff git a/lemon/vf2.h b/lemon/vf2.h
a

b


53  53  } 
54  54  }; 
55  55  
56   
57   
58  56  template <class G> 
59  57  class DfsLeaveOrder : public DfsVisitor<G> { 
60  58  const G &_g; 
… 
… 

93  91  /// 
94  92  ///There is also a \ref vf2() "functiontype interface" called \ref vf2() 
95  93  ///for the %VF2 algorithm, which is probably more convenient in most 
96   ///usecases. 
 94  ///use cases. 
97  95  /// 
98  96  ///\tparam G1 The type of the graph to be embedded. 
99  97  ///The default type is \ref ListDigraph. 
… 
… 

102  100  ///\tparam M The type of the NodeMap storing the mapping. 
103  101  ///By default, it is G1::NodeMap<G2::Node> 
104  102  ///\tparam NEQ A boolvalued binary functor determinining whether a node is 
105   ///mappable to another. By default it is an always true operator. 
 103  ///mappable to another. By default, it is an alwaystrue operator. 
106  104  /// 
107  105  ///\sa vf2() 
108  106  #ifdef DOXYGEN 
… 
… 

116  114  class Vf2 { 
117  115  //Current depth in the DFS tree. 
118  116  int _depth; 
 117  
119  118  //Functor with bool operator()(G1::Node,G2::Node), which returns 1 
120   //ifff the two nodes are equivalent. 
 119  //if and only if the two nodes are equivalent 
121  120  NEQ _nEq; 
122  121  
 122  //_conn[v2] = number of covered neighbours of v2 
123  123  typename G2::template NodeMap<int> _conn; 
124   //Current mapping. We index it by the nodes of g1, and match[v] is 
125   //a node of g2. 
 124  
 125  //The current mapping. _mapping[v1]=v2 iff v1 has been mapped to v2, 
 126  //where v1 is a node of G1 and v2 is a node of G2 
126  127  M &_mapping; 
127   //order[i] is the node of g1, for which we search a pair if depth=i 
 128  
 129  //order[i] is the node of g1 for which a pair is searched if depth=i 
128  130  std::vector<typename G1::Node> order; 
129   //currEdgeIts[i] is an edge iterator, witch is last used in the ith 
130   //depth to find a pair for order[i]. 
 131  
 132  //currEdgeIts[i] is the last used edge iterator in the ith 
 133  //depth to find a pair for node order[i] 
131  134  std::vector<typename G2::IncEdgeIt> currEdgeIts; 
132   //The small graph. 
 135  
 136  //The graph to be embedded 
133  137  const G1 &_g1; 
134   //The large graph. 
 138  
 139  //The graph into which g1 is to be embedded 
135  140  const G2 &_g2; 
 141  
136  142  //lookup tables for cutting the searchtree 
137  143  typename G1::template NodeMap<int> rNew1t,rInOut1t; 
138  144  
… 
… 

242  248  template<MappingType MT> 
243  249  bool extMatch() { 
244  250  while(_depth>=0) { 
245   //there are not nodes in g1, which has not pair in g2. 
246  251  if(_depth==static_cast<int>(order.size())) { 
 252  //all nodes of g1 are mapped to nodes of g2 
247  253  _depth; 
248  254  return true; 
249  255  } 
250  256  typename G1::Node& nodeOfDepth = order[_depth]; 
251  257  const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth]; 
252  258  typename G2::IncEdgeIt &edgeItOfDepth = currEdgeIts[_depth]; 
253   //the node of g2, which neighbours are the candidates for 
 259  //the node of g2 whose neighbours are the candidates for 
254  260  //the pair of nodeOfDepth 
255  261  typename G2::Node currPNode; 
256  262  if(edgeItOfDepth==INVALID) { 
257  263  typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth); 
258   //if pairOfNodeOfDepth!=INVALID, we dont use 
259   //fstMatchedE 
260   if(pairOfNodeOfDepth==INVALID) 
 264  //if pairOfNodeOfDepth!=INVALID, we don't use fstMatchedE 
 265  if(pairOfNodeOfDepth==INVALID) { 
261  266  for(; fstMatchedE!=INVALID && 
262  267  _mapping[_g1.oppositeNode(nodeOfDepth, 
263  268  fstMatchedE)]==INVALID; 
264  269  ++fstMatchedE) ; //find fstMatchedE 
 270  } 
265  271  if(fstMatchedE==INVALIDpairOfNodeOfDepth!=INVALID) { 
266   //We found no covered neighbours, this means 
267   //the graph is not connected(or _depth==0). Each 
268   //uncovered(and there are some other properties due 
 272  //We found no covered neighbours, this means that 
 273  //the graph is not connected (or _depth==0). Each 
 274  //uncovered (and there are some other properties due 
269  275  //to the spec. problem types) node of g2 is 
270   //candidate. We can read the iterator of the last 
 276  //candidate. We can read the iterator of the last 
271  277  //tried node from the match if it is not the first 
272   //try(match[nodeOfDepth]!=INVALID) 
 278  //try (match[nodeOfDepth]!=INVALID) 
273  279  typename G2::NodeIt n2(_g2); 
274  280  //if it's not the first try 
275  281  if(pairOfNodeOfDepth!=INVALID) { 
… 
… 

317  323  return false; 
318  324  } 
319  325  
320   //calc. the lookup table for cut the searchtree 
 326  //calculate the lookup table for cutting the search tree 
321  327  void setRNew1tRInOut1t() { 
322  328  typename G1::template NodeMap<int> tmp(_g1,0); 
323  329  for(unsigned int i=0; i<order.size(); ++i) { 
… 
… 

351  357  Vf2(const G1 &g1, const G2 &g2, M &m, const NEQ &neq = NEQ() ) : 
352  358  _nEq(neq), _conn(g2,0), _mapping(m), order(countNodes(g1)), 
353  359  currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNew1t(g1,0), 
354   rInOut1t(g1,0), _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0) { 
 360  rInOut1t(g1,0), _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0) 
 361  { 
355  362  _depth=0; 
356  363  setOrder(); 
357  364  setRNew1tRInOut1t(); 
… 
… 

440  447  
441  448  
442  449  /// Auxiliary class for the functiontype interface of %VF2 algorithm. 
443   
 450  /// 
444  451  /// This auxiliary class implements the named parameters of 
445  452  /// \ref vf2() "functiontype interface" of \ref Vf2 algorithm. 
446  453  /// 
447   /// \warning This class should only be used through the function \ref vf2(). 
 454  /// \warning This class is not to be used directly. 
448  455  /// 
449  456  /// \tparam TR The traits class that defines various types used by the 
450  457  /// algorithm. 
… 
… 

465  472  
466  473  public: 
467  474  ///Constructor 
468   Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) { 
469   } 
 475  Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {} 
470  476  
471  477  ///Copy constructor 
472   Vf2Wizard(const Base &b) : Base(b) { } 
 478  Vf2Wizard(const Base &b) : Base(b) {} 
473  479  
474  480  ///Copy constructor 
475  481  Vf2Wizard(const Vf2Wizard &b) : Base(b) {} 
diff git a/lemon/vf2pp.h b/lemon/vf2pp.h
a

b


75  75  /// 
76  76  ///There is also a \ref vf2pp() "functiontype interface" called 
77  77  ///\ref vf2pp() for the %VF2 Plus Plus algorithm, which is probably 
78   ///more convenient in most usecases. 
 78  ///more convenient in most use cases. 
79  79  /// 
80  80  ///\tparam G1 The type of the graph to be embedded. 
81  81  ///The default type is \ref ListDigraph. 
… 
… 

96  96  #else 
97  97  template<class G1=ListDigraph, 
98  98  class G2=ListDigraph, 
99   class M = typename G1::template NodeMap<G2::Node>,//the mapping 
100   //labels of G1,the labels are the numbers {0,1,2,..,K1}, 
101   //where K is the number of different labels 
 99  class M = typename G1::template NodeMap<G2::Node>, 
102  100  class M1 = typename G1::template NodeMap<int>, 
103   //labels of G2, ... 
104  101  class M2 = typename G2::template NodeMap<int> > 
105  102  #endif 
106  103  class Vf2pp { 
… 
… 

114  111  //where v1 is a node of G1 and v2 is a node of G2 
115  112  M &_mapping; 
116  113  
117   //order[i] is a node of g1, for which a pair is searched if depth=i 
 114  //order[i] is a node of g1 for which a pair is searched if depth=i 
118  115  std::vector<typename G1::Node> order; 
119  116  
120   //currEdgeIts[i] is the last used edge iterator in the ith 
 117  //currEdgeIts[i] is the last used edge iterator in the ith 
121  118  //depth to find a pair for node order[i] 
122  119  std::vector<typename G2::IncEdgeIt> currEdgeIts; 
123   
124   //The small graph. 
 120  
 121  //The graph to be embedded 
125  122  const G1 &_g1; 
126  123  
127   //The large graph. 
 124  //The graph into which g1 is to be embedded 
128  125  const G2 &_g2; 
129  126  
130  127  //rNewLabels1[v] is a pair of form 
… 
… 

137  134  typename G1::template NodeMap<std::vector<std::pair<int,int> > > 
138  135  rInOutLabels1; 
139  136  
140   //_intLabels1[v]==i means that vertex v has the i label in 
141   //_g1 (i is in {0,1,2,..,K1}, where K is the number of diff. labels) 
 137  //_intLabels1[v]==i means that node v has label i in _g1 
 138  //(i is in {0,1,2,..,K1}, where K is the number of diff. labels) 
142  139  M1 &_intLabels1; 
143  140  
144   //_intLabels2[v]==i means that vertex v has the i label in 
145   //_g2 (i is in {0,1,2,..,K1}, where K is the number of diff. labels) 
 141  //_intLabels2[v]==i means that node v has label i in _g2 
 142  //(i is in {0,1,2,..,K1}, where K is the number of diff. labels) 
146  143  M2 &_intLabels2; 
147  144  
148  145  //largest label 
149  146  const int maxLabel; 
150  147  
151  148  //lookup tables for manipulating with label class cardinalities 
152   //after use they have to be reset to 0..0 
 149  //(after use they have to be reset to 0..0) 
153  150  std::vector<int> labelTmp1,labelTmp2; 
154  151  
155  152  MappingType _mapping_type; 
156  153  
157   //indicates whether the mapping or the labels must be deleted in the ctor 
 154  //indicates whether the mapping or the labels must be deleted in the destructor 
158  155  bool _deallocMappingAfterUse,_deallocLabelsAfterUse; 
159  156  
160  157  
… 
… 

286  283  return isIso&&cutByLabels<MT>(n1,n2); 
287  284  } 
288  285  
289   
290   //matches n1 and n2 
 286  //maps n1 to n2 
291  287  void addPair(const typename G1::Node n1,const typename G2::Node n2) { 
292  288  _conn[n2]=1; 
293  289  _mapping.set(n1,n2); 
… 
… 

298  294  } 
299  295  } 
300  296  
301   
302   //dematches n1 and n2 
 297  //removes mapping of n1 to n2 
303  298  void subPair(const typename G1::Node n1,const typename G2::Node n2) { 
304  299  _conn[n2]=0; 
305  300  _mapping.set(n1,INVALID); 
… 
… 

312  307  } 
313  308  } 
314  309  
315   
316  310  void processBFSLevel(typename G1::Node source,unsigned int& orderIndex, 
317  311  typename G1::template NodeMap<int>& dm1, 
318  312  typename G1::template NodeMap<bool>& added) { 
… 
… 

364  358  for(typename G2::NodeIt n2(_g2); n2!=INVALID; ++n2) 
365  359  ++labelTmp1[_intLabels2[n2]]; 
366  360  
367   // OutDegMap<G1> dm1(_g1); 
368  361  typename G1::template NodeMap<int> dm1(_g1,0); 
369  362  for(typename G1::EdgeIt e(_g1); e!=INVALID; ++e) { 
370  363  ++dm1[_g1.u(e)]; 
… 
… 

397  390  template<MappingType MT> 
398  391  bool extMatch(){ 
399  392  while(_depth>=0) { 
400   //there is no node in g1, which has not pair in g2. 
401  393  if(_depth==static_cast<int>(order.size())) { 
 394  //all nodes of g1 are mapped to nodes of g2 
402  395  _depth; 
403  396  return true; 
404  397  } 
405  398  typename G1::Node& nodeOfDepth = order[_depth]; 
406  399  const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth]; 
407  400  typename G2::IncEdgeIt &edgeItOfDepth = currEdgeIts[_depth]; 
408   //the node of g2, which neighbours are the candidates for 
 401  //the node of g2 whose neighbours are the candidates for 
409  402  //the pair of order[_depth] 
410  403  typename G2::Node currPNode; 
411  404  if(edgeItOfDepth==INVALID){ 
412  405  typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth); 
413   //if _mapping[order[_depth]]!=INVALID, we dont need 
414   //fstMatchedE 
415   if(pairOfNodeOfDepth==INVALID) 
 406  //if _mapping[order[_depth]]!=INVALID, we don't need fstMatchedE 
 407  if(pairOfNodeOfDepth==INVALID) { 
416  408  for(; fstMatchedE!=INVALID && 
417  409  _mapping[_g1.oppositeNode(nodeOfDepth, 
418  410  fstMatchedE)]==INVALID; 
419  411  ++fstMatchedE); //find fstMatchedE, it could be preprocessed 
 412  } 
420  413  if(fstMatchedE==INVALIDpairOfNodeOfDepth!=INVALID) { 
421   //We found no covered neighbours, this means 
422   //the graph is not connected(or _depth==0). Each 
423   //uncovered(and there are some other properties due 
 414  //We found no covered neighbours, this means that 
 415  //the graph is not connected (or _depth==0). Each 
 416  //uncovered (and there are some other properties due 
424  417  //to the spec. problem types) node of g2 is 
425   //candidate. We can read the iterator of the last 
 418  //candidate. We can read the iterator of the last 
426  419  //tried node from the match if it is not the first 
427   //try(match[nodeOfDepth]!=INVALID) 
 420  //try (match[nodeOfDepth]!=INVALID) 
428  421  typename G2::NodeIt n2(_g2); 
429  422  //if it's not the first try 
430  423  if(pairOfNodeOfDepth!=INVALID) { 
… 
… 

447  440  _depth; 
448  441  continue; 
449  442  } 
450   else{ 
 443  else { 
451  444  currPNode=_mapping[_g1.oppositeNode(nodeOfDepth, 
452  445  fstMatchedE)]; 
453  446  edgeItOfDepth=typename G2::IncEdgeIt(_g2,currPNode); 
454  447  } 
455  448  } 
456   else{ 
 449  else { 
457  450  currPNode=_g2.oppositeNode(pairOfNodeOfDepth, 
458  451  edgeItOfDepth); 
459  452  subPair(nodeOfDepth,pairOfNodeOfDepth); 
… 
… 

472  465  return false; 
473  466  } 
474  467  
475   //calc. the lookup table for cutting the searchtree 
 468  //calculate the lookup table for cutting the search tree 
476  469  void setRNew1tRInOut1t(){ 
477  470  typename G1::template NodeMap<int> tmp(_g1,0); 
478  471  for(unsigned int i=0; i<order.size(); ++i) { 
… 
… 

675  668  
676  669  public: 
677  670  ///Constructor 
678   Vf2ppWizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) { } 
 671  Vf2ppWizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {} 
679  672  
680  673  ///Copy constructor 
681  674  Vf2ppWizard(const Base &b) : Base(b) {} 
… 
… 

684  677  template<typename T> 
685  678  struct SetMappingBase : public Base { 
686  679  typedef T Mapping; 
687   SetMappingBase(const Base &b) : Base(b) { } 
 680  SetMappingBase(const Base &b) : Base(b) {} 
688  681  }; 
689  682  
690  683  ///\brief \ref namedtemplparam "Named parameter" for setting 
… 
… 

713  706  ///the node labels. 
714  707  /// 
715  708  ///\param nodeLabels1 A \ref concepts::ReadMap "readable node map" 
716   ///of g1 with integer value. In case of K different labels, the labels 
717   ///must be the {0,1,..,K1} numbers. 
 709  ///of g1 with integer values. In case of K different labels, the labels 
 710  ///must be the numbers {0,1,..,K1}. 
718  711  ///\param nodeLabels2 A \ref concepts::ReadMap "readable node map" 
719   ///of g2 with integer value. In case of K different labels, the labels 
720   ///must be the {0,1,..,K1} numbers. 
 712  ///of g2 with integer values. In case of K different labels, the labels 
 713  ///must be the numbers {0,1,..,K1}. 
721  714  template<typename NL1, typename NL2> 
722  715  Vf2ppWizard< SetNodeLabelsBase<NL1,NL2> > 
723  716  nodeLabels(const NL1 &nodeLabels1, const NL2 &nodeLabels2) { 
… 
… 

877  870  /// int num_isos = vf2pp(g1,g2).iso().count(); 
878  871  /// 
879  872  /// // Iterate through all the induced subgraph mappings 
880   /// //of graph g1 into g2 using the labels c1 and c2 
 873  /// // of graph g1 into g2 using the labels c1 and c2 
881  874  /// auto* myVf2pp = vf2pp(g1,g2).mapping(m).nodeLabels(c1,c2) 
882  875  /// .induced().getPtrToVf2Object(); 
883  876  /// while(myVf2pp>find()){ 