lemon/vf2pp.h
author Peter Kovacs <kpeter@inf.elte.hu>
Sat, 07 Oct 2017 03:18:49 +0200
changeset 1188 76349d8212d3
parent 1186 3feba0ea1bda
child 1189 b9fad0f9f8ab
permissions -rw-r--r--
Improve and unify comments and API docs of VF2 algorithms (#597)
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2015-2017
     6  * EMAXA Kutato-fejleszto Kft. (EMAXA Research Ltd.)
     7  *
     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.
    11  *
    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
    14  * purpose.
    15  *
    16  */
    17 
    18 #ifndef LEMON_VF2PP_H
    19 #define LEMON_VF2PP_H
    20 
    21 ///\ingroup graph_properties
    22 ///\file
    23 ///\brief VF2 Plus Plus algorithm.
    24 
    25 #include <lemon/core.h>
    26 #include <lemon/concepts/graph.h>
    27 #include <lemon/dfs.h>
    28 #include <lemon/bfs.h>
    29 #include <lemon/bits/vf2_internals.h>
    30 
    31 
    32 #include <vector>
    33 #include <algorithm>
    34 #include <utility>
    35 
    36 
    37 namespace lemon {
    38   namespace bits {
    39     namespace vf2pp {
    40 
    41       template <class G>
    42       class DfsLeaveOrder : public DfsVisitor<G> {
    43         int i;
    44         const G &_g;
    45         std::vector<typename G::Node> &_order;
    46       public:
    47         DfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
    48           : i(countNodes(g)), _g(g), _order(order) {
    49         }
    50         void leave(const typename G::Node &node) {
    51           _order[--i]=node;
    52         }
    53       };
    54 
    55       template <class G>
    56       class BfsLeaveOrder : public BfsVisitor<G> {
    57         int i;
    58         const G &_g;
    59         std::vector<typename G::Node> &_order;
    60       public:
    61         BfsLeaveOrder(const G &g, std::vector<typename G::Node> &order) { }
    62         void process(const typename G::Node &node) {
    63           _order[i++]=node;
    64         }
    65       };
    66     }
    67   }
    68 
    69 
    70   ///%VF2 Plus Plus algorithm class.
    71 
    72   ///\ingroup graph_isomorphism This class provides an efficient
    73   ///implementation of the %VF2 Plus Plus algorithm
    74   ///for variants of the (Sub)graph Isomorphism problem.
    75   ///
    76   ///There is also a \ref vf2pp() "function-type interface" called
    77   ///\ref vf2pp() for the %VF2 Plus Plus algorithm, which is probably
    78   ///more convenient in most use cases.
    79   ///
    80   ///\tparam G1 The type of the graph to be embedded.
    81   ///The default type is \ref ListDigraph.
    82   ///\tparam G2 The type of the graph g1 will be embedded into.
    83   ///The default type is \ref ListDigraph.
    84   ///\tparam M The type of the NodeMap storing the mapping.
    85   ///By default, it is G1::NodeMap<G2::Node>
    86   ///\tparam M1 The type of the NodeMap storing the integer node labels of G1.
    87   ///The labels must be the numbers {0,1,2,..,K-1}, where K is the number of
    88   ///different labels. By default, it is G1::NodeMap<int>.
    89   ///\tparam M2 The type of the NodeMap storing the integer node labels of G2.
    90   ///The labels must be the numbers {0,1,2,..,K-1}, where K is the number of
    91   ///different labels. By default, it is G2::NodeMap<int>.
    92   ///
    93   ///\sa vf2pp()
    94 #ifdef DOXYGEN
    95   template<class G1, class G2, class M, class M1, class M2 >
    96 #else
    97   template<class G1=ListDigraph,
    98            class G2=ListDigraph,
    99            class M = typename G1::template NodeMap<G2::Node>,
   100            class M1 = typename G1::template NodeMap<int>,
   101            class M2 = typename G2::template NodeMap<int> >
   102 #endif
   103   class Vf2pp {
   104     //Current depth in the search tree.
   105     int _depth;
   106 
   107     //_conn[v2] = number of covered neighbours of v2
   108     typename G2::template NodeMap<int> _conn;
   109 
   110     //The current mapping. _mapping[v1]=v2 iff v1 has been mapped to v2,
   111     //where v1 is a node of G1 and v2 is a node of G2
   112     M &_mapping;
   113 
   114     //order[i] is a node of g1 for which a pair is searched if depth=i
   115     std::vector<typename G1::Node> order;
   116 
   117     //currEdgeIts[i] is the last used edge iterator in the i-th
   118     //depth to find a pair for node order[i]
   119     std::vector<typename G2::IncEdgeIt> currEdgeIts;
   120  
   121     //The graph to be embedded
   122     const G1 &_g1;
   123 
   124     //The graph into which g1 is to be embedded
   125     const G2 &_g2;
   126 
   127     //rNewLabels1[v] is a pair of form
   128     //(label; num. of uncov. nodes with such label and no covered neighbours)
   129     typename G1::template NodeMap<std::vector<std::pair<int,int> > >
   130     rNewLabels1;
   131 
   132     //rInOutLabels1[v] is the number of covered neighbours of v for each label
   133     //in form (label,number of such labels)
   134     typename G1::template NodeMap<std::vector<std::pair<int,int> > >
   135     rInOutLabels1;
   136 
   137     //_intLabels1[v]==i means that node v has label i in _g1
   138     //(i is in {0,1,2,..,K-1}, where K is the number of diff. labels)
   139     M1 &_intLabels1;
   140 
   141     //_intLabels2[v]==i means that node v has label i in _g2
   142     //(i is in {0,1,2,..,K-1}, where K is the number of diff. labels)
   143     M2 &_intLabels2;
   144 
   145     //largest label
   146     const int maxLabel;
   147 
   148     //lookup tables for manipulating with label class cardinalities
   149     //(after use they have to be reset to 0..0)
   150     std::vector<int> labelTmp1,labelTmp2;
   151 
   152     MappingType _mapping_type;
   153 
   154     //indicates whether the mapping or the labels must be deleted in the destructor
   155     bool _deallocMappingAfterUse,_deallocLabelsAfterUse;
   156 
   157 
   158     //improved cutting function
   159     template<MappingType MT>
   160     bool cutByLabels(const typename G1::Node n1,const typename G2::Node n2) {
   161       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
   162         const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
   163         if(_conn[currNode]>0)
   164           --labelTmp1[_intLabels2[currNode]];
   165         else if(MT!=SUBGRAPH&&_conn[currNode]==0)
   166           --labelTmp2[_intLabels2[currNode]];
   167       }
   168 
   169       bool ret=1;
   170       if(ret) {
   171         for(unsigned int i = 0; i < rInOutLabels1[n1].size(); ++i)
   172           labelTmp1[rInOutLabels1[n1][i].first]+=rInOutLabels1[n1][i].second;
   173 
   174         if(MT!=SUBGRAPH)
   175           for(unsigned int i = 0; i < rNewLabels1[n1].size(); ++i)
   176             labelTmp2[rNewLabels1[n1][i].first]+=rNewLabels1[n1][i].second;
   177 
   178         switch(MT) {
   179         case INDUCED:
   180           for(unsigned int i = 0; i < rInOutLabels1[n1].size(); ++i)
   181             if(labelTmp1[rInOutLabels1[n1][i].first]>0) {
   182               ret=0;
   183               break;
   184             }
   185           if(ret)
   186             for(unsigned int i = 0; i < rNewLabels1[n1].size(); ++i)
   187               if(labelTmp2[rNewLabels1[n1][i].first]>0) {
   188                 ret=0;
   189                 break;
   190               }
   191           break;
   192         case SUBGRAPH:
   193           for(unsigned int i = 0; i < rInOutLabels1[n1].size(); ++i)
   194             if(labelTmp1[rInOutLabels1[n1][i].first]>0) {
   195               ret=0;
   196               break;
   197             }
   198           break;
   199         case ISOMORPH:
   200           for(unsigned int i = 0; i < rInOutLabels1[n1].size(); ++i)
   201             if(labelTmp1[rInOutLabels1[n1][i].first]!=0) {
   202               ret=0;
   203               break;
   204             }
   205           if(ret)
   206             for(unsigned int i = 0; i < rNewLabels1[n1].size(); ++i)
   207               if(labelTmp2[rNewLabels1[n1][i].first]!=0) {
   208                 ret=0;
   209                 break;
   210               }
   211           break;
   212         default:
   213           return false;
   214         }
   215         for(unsigned int i = 0; i < rInOutLabels1[n1].size(); ++i)
   216           labelTmp1[rInOutLabels1[n1][i].first]=0;
   217 
   218         if(MT!=SUBGRAPH)
   219           for(unsigned int i = 0; i < rNewLabels1[n1].size(); ++i)
   220             labelTmp2[rNewLabels1[n1][i].first]=0;
   221       }
   222 
   223       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
   224         const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
   225         labelTmp1[_intLabels2[currNode]]=0;
   226         if(MT!=SUBGRAPH&&_conn[currNode]==0)
   227           labelTmp2[_intLabels2[currNode]]=0;
   228       }
   229 
   230       return ret;
   231     }
   232 
   233 
   234     //try to exclude the matching of n1 and n2
   235     template<MappingType MT>
   236     bool feas(const typename G1::Node n1,const typename G2::Node n2) {
   237       if(_intLabels1[n1]!=_intLabels2[n2])
   238         return 0;
   239 
   240       for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
   241         const typename G1::Node& currNode=_g1.oppositeNode(n1,e1);
   242         if(_mapping[currNode]!=INVALID)
   243           --_conn[_mapping[currNode]];
   244       }
   245 
   246       bool isIso=1;
   247       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
   248         int& connCurrNode = _conn[_g2.oppositeNode(n2,e2)];
   249         if(connCurrNode<-1)
   250           ++connCurrNode;
   251         else if(MT!=SUBGRAPH&&connCurrNode==-1) {
   252           isIso=0;
   253           break;
   254         }
   255       }
   256 
   257       if(isIso)
   258         for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
   259           const typename G2::Node& currNodePair =
   260             _mapping[_g1.oppositeNode(n1,e1)];
   261           int& connCurrNodePair=_conn[currNodePair];
   262           if(currNodePair!=INVALID&&connCurrNodePair!=-1) {
   263             switch(MT){
   264             case INDUCED:
   265             case ISOMORPH:
   266               isIso=0;
   267               break;
   268             case SUBGRAPH:
   269               if(connCurrNodePair<-1)
   270                 isIso=0;
   271               break;
   272             }
   273             connCurrNodePair=-1;
   274           }
   275         }
   276       else
   277         for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
   278           const typename G2::Node currNode=_mapping[_g1.oppositeNode(n1,e1)];
   279           if(currNode!=INVALID/*&&_conn[currNode]!=-1*/)
   280             _conn[currNode]=-1;
   281         }
   282 
   283       return isIso&&cutByLabels<MT>(n1,n2);
   284     }
   285 
   286     //maps n1 to n2
   287     void addPair(const typename G1::Node n1,const typename G2::Node n2) {
   288       _conn[n2]=-1;
   289       _mapping.set(n1,n2);
   290       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
   291         int& currConn = _conn[_g2.oppositeNode(n2,e2)];
   292         if(currConn!=-1)
   293           ++currConn;
   294       }
   295     }
   296 
   297     //removes mapping of n1 to n2
   298     void subPair(const typename G1::Node n1,const typename G2::Node n2) {
   299       _conn[n2]=0;
   300       _mapping.set(n1,INVALID);
   301       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2){
   302         int& currConn = _conn[_g2.oppositeNode(n2,e2)];
   303         if(currConn>0)
   304           --currConn;
   305         else if(currConn==-1)
   306           ++_conn[n2];
   307       }
   308     }
   309 
   310     void processBFSLevel(typename G1::Node source,unsigned int& orderIndex,
   311                          typename G1::template NodeMap<int>& dm1,
   312                          typename G1::template NodeMap<bool>& added) {
   313       order[orderIndex]=source;
   314       added[source]=1;
   315 
   316       unsigned int endPosOfLevel=orderIndex,
   317         startPosOfLevel=orderIndex,
   318         lastAdded=orderIndex;
   319 
   320       typename G1::template NodeMap<int> currConn(_g1,0);
   321 
   322       while(orderIndex<=lastAdded){
   323         typename G1::Node currNode = order[orderIndex];
   324         for(typename G1::IncEdgeIt e(_g1,currNode); e!=INVALID; ++e) {
   325           typename G1::Node n = _g1.oppositeNode(currNode,e);
   326           if(!added[n]) {
   327             order[++lastAdded]=n;
   328             added[n]=1;
   329           }
   330         }
   331         if(orderIndex>endPosOfLevel){
   332           for(unsigned int j = startPosOfLevel; j <= endPosOfLevel; ++j) {
   333             int minInd=j;
   334             for(unsigned int i = j+1; i <= endPosOfLevel; ++i)
   335               if(currConn[order[i]]>currConn[order[minInd]]||
   336                  (currConn[order[i]]==currConn[order[minInd]]&&
   337                   (dm1[order[i]]>dm1[order[minInd]]||
   338                    (dm1[order[i]]==dm1[order[minInd]]&&
   339                     labelTmp1[_intLabels1[order[minInd]]]>
   340                     labelTmp1[_intLabels1[order[i]]]))))
   341                 minInd=i;
   342 
   343             --labelTmp1[_intLabels1[order[minInd]]];
   344             for(typename G1::IncEdgeIt e(_g1,order[minInd]); e!=INVALID; ++e)
   345               ++currConn[_g1.oppositeNode(order[minInd],e)];
   346             std::swap(order[j],order[minInd]);
   347           }
   348           startPosOfLevel=endPosOfLevel+1;
   349           endPosOfLevel=lastAdded;
   350         }
   351         ++orderIndex;
   352       }
   353     }
   354 
   355 
   356     //we will find pairs for the nodes of g1 in this order
   357     void setOrder(){
   358       for(typename G2::NodeIt n2(_g2); n2!=INVALID; ++n2)
   359         ++labelTmp1[_intLabels2[n2]];
   360 
   361       typename G1::template NodeMap<int> dm1(_g1,0);
   362       for(typename G1::EdgeIt e(_g1); e!=INVALID; ++e) {
   363         ++dm1[_g1.u(e)];
   364         ++dm1[_g1.v(e)];
   365       }
   366 
   367       typename G1::template NodeMap<bool> added(_g1,0);
   368       unsigned int orderIndex=0;
   369 
   370       for(typename G1::NodeIt n(_g1); n!=INVALID;) {
   371         if(!added[n]){
   372           typename G1::Node minNode = n;
   373           for(typename G1::NodeIt n1(_g1,minNode); n1!=INVALID; ++n1)
   374             if(!added[n1] &&
   375                (labelTmp1[_intLabels1[minNode]]>
   376                 labelTmp1[_intLabels1[n1]]||(dm1[minNode]<dm1[n1]&&
   377                                              labelTmp1[_intLabels1[minNode]]==
   378                                              labelTmp1[_intLabels1[n1]])))
   379               minNode=n1;
   380           processBFSLevel(minNode,orderIndex,dm1,added);
   381         }
   382         else
   383           ++n;
   384       }
   385       for(unsigned int i = 0; i < labelTmp1.size(); ++i)
   386         labelTmp1[i]=0;
   387     }
   388 
   389 
   390     template<MappingType MT>
   391     bool extMatch(){
   392       while(_depth>=0) {
   393         if(_depth==static_cast<int>(order.size())) {
   394           //all nodes of g1 are mapped to nodes of g2
   395           --_depth;
   396           return true;
   397         }
   398         typename G1::Node& nodeOfDepth = order[_depth];
   399         const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth];
   400         typename G2::IncEdgeIt &edgeItOfDepth = currEdgeIts[_depth];
   401         //the node of g2 whose neighbours are the candidates for
   402         //the pair of order[_depth]
   403         typename G2::Node currPNode;
   404         if(edgeItOfDepth==INVALID){
   405           typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth);
   406           //if _mapping[order[_depth]]!=INVALID, we don't need fstMatchedE
   407           if(pairOfNodeOfDepth==INVALID) {
   408             for(; fstMatchedE!=INVALID &&
   409                   _mapping[_g1.oppositeNode(nodeOfDepth,
   410                                             fstMatchedE)]==INVALID;
   411                 ++fstMatchedE); //find fstMatchedE, it could be preprocessed
   412           }
   413           if(fstMatchedE==INVALID||pairOfNodeOfDepth!=INVALID) {
   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
   417             //to the spec. problem types) node of g2 is
   418             //candidate. We can read the iterator of the last
   419             //tried node from the match if it is not the first
   420             //try (match[nodeOfDepth]!=INVALID)
   421             typename G2::NodeIt n2(_g2);
   422             //if it's not the first try
   423             if(pairOfNodeOfDepth!=INVALID) {
   424               n2=++typename G2::NodeIt(_g2,pairOfNodeOfDepth);
   425               subPair(nodeOfDepth,pairOfNodeOfDepth);
   426             }
   427             for(; n2!=INVALID; ++n2)
   428               if(MT!=SUBGRAPH) {
   429                 if(_conn[n2]==0&&feas<MT>(nodeOfDepth,n2))
   430                   break;
   431               }
   432               else if(_conn[n2]>=0&&feas<MT>(nodeOfDepth,n2))
   433                 break;
   434             // n2 is the next candidate
   435             if(n2!=INVALID) {
   436               addPair(nodeOfDepth,n2);
   437               ++_depth;
   438             }
   439             else // there are no more candidates
   440               --_depth;
   441             continue;
   442           }
   443           else {
   444             currPNode=_mapping[_g1.oppositeNode(nodeOfDepth,
   445                                                 fstMatchedE)];
   446             edgeItOfDepth=typename G2::IncEdgeIt(_g2,currPNode);
   447           }
   448         }
   449         else {
   450           currPNode=_g2.oppositeNode(pairOfNodeOfDepth,
   451                                      edgeItOfDepth);
   452           subPair(nodeOfDepth,pairOfNodeOfDepth);
   453           ++edgeItOfDepth;
   454         }
   455         for(; edgeItOfDepth!=INVALID; ++edgeItOfDepth) {
   456           const typename G2::Node currNode =
   457             _g2.oppositeNode(currPNode, edgeItOfDepth);
   458           if(_conn[currNode]>0&&feas<MT>(nodeOfDepth,currNode)) {
   459             addPair(nodeOfDepth,currNode);
   460             break;
   461           }
   462         }
   463         edgeItOfDepth==INVALID?--_depth:++_depth;
   464       }
   465       return false;
   466     }
   467 
   468     //calculate the lookup table for cutting the search tree
   469     void setRNew1tRInOut1t(){
   470       typename G1::template NodeMap<int> tmp(_g1,0);
   471       for(unsigned int i=0; i<order.size(); ++i) {
   472         tmp[order[i]]=-1;
   473         for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1) {
   474           const typename G1::Node currNode=_g1.oppositeNode(order[i],e1);
   475           if(tmp[currNode]>0)
   476             ++labelTmp1[_intLabels1[currNode]];
   477           else if(tmp[currNode]==0)
   478             ++labelTmp2[_intLabels1[currNode]];
   479         }
   480         //labelTmp1[i]=number of neightbours with label i in set rInOut
   481         //labelTmp2[i]=number of neightbours with label i in set rNew
   482         for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1) {
   483           const int& currIntLabel = _intLabels1[_g1.oppositeNode(order[i],e1)];
   484           if(labelTmp1[currIntLabel]>0) {
   485             rInOutLabels1[order[i]]
   486               .push_back(std::make_pair(currIntLabel,
   487                                         labelTmp1[currIntLabel]));
   488             labelTmp1[currIntLabel]=0;
   489           }
   490           else if(labelTmp2[currIntLabel]>0) {
   491             rNewLabels1[order[i]].
   492               push_back(std::make_pair(currIntLabel,labelTmp2[currIntLabel]));
   493             labelTmp2[currIntLabel]=0;
   494           }
   495         }
   496 
   497         for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1) {
   498           int& tmpCurrNode=tmp[_g1.oppositeNode(order[i],e1)];
   499           if(tmpCurrNode!=-1)
   500             ++tmpCurrNode;
   501         }
   502       }
   503     }
   504 
   505     int getMaxLabel() const{
   506       int m=-1;
   507       for(typename G1::NodeIt n1(_g1); n1!=INVALID; ++n1) {
   508         const int& currIntLabel = _intLabels1[n1];
   509         if(currIntLabel>m)
   510           m=currIntLabel;
   511       }
   512       for(typename G2::NodeIt n2(_g2); n2!=INVALID; ++n2) {
   513         const int& currIntLabel = _intLabels2[n2];
   514         if(currIntLabel>m)
   515           m=currIntLabel;
   516       }
   517       return m;
   518     }
   519 
   520   public:
   521     ///Constructor
   522 
   523     ///Constructor.
   524     ///\param g1 The graph to be embedded.
   525     ///\param g2 The graph \e g1 will be embedded into.
   526     ///\param m The type of the NodeMap storing the mapping.
   527     ///By default, it is G1::NodeMap<G2::Node>
   528     ///\param intLabel1 The NodeMap storing the integer node labels of G1.
   529     ///The labels must be the numbers {0,1,2,..,K-1}, where K is the number of
   530     ///different labels.
   531     ///\param intLabel1 The NodeMap storing the integer node labels of G2.
   532     ///The labels must be the numbers {0,1,2,..,K-1}, where K is the number of
   533     ///different labels.
   534     Vf2pp(const G1 &g1, const G2 &g2,M &m, M1 &intLabels1, M2 &intLabels2) :
   535       _depth(0), _conn(g2,0), _mapping(m), order(countNodes(g1),INVALID),
   536       currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNewLabels1(_g1),
   537       rInOutLabels1(_g1), _intLabels1(intLabels1) ,_intLabels2(intLabels2),
   538       maxLabel(getMaxLabel()), labelTmp1(maxLabel+1),labelTmp2(maxLabel+1),
   539       _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0),
   540       _deallocLabelsAfterUse(0)
   541     {
   542       setOrder();
   543       setRNew1tRInOut1t();
   544 
   545       //reset mapping
   546       for(typename G1::NodeIt n(g1);n!=INVALID;++n)
   547         m[n]=INVALID;
   548     }
   549 
   550     ///Destructor
   551 
   552     ///Destructor.
   553     ///
   554     ~Vf2pp()
   555     {
   556       if(_deallocMappingAfterUse)
   557         delete &_mapping;
   558       if(_deallocLabelsAfterUse) {
   559         delete &_intLabels1;
   560         delete &_intLabels2;
   561       }
   562     }
   563 
   564     ///Returns the current mapping type.
   565 
   566     ///Returns the current mapping type.
   567     ///
   568     MappingType mappingType() const
   569     {
   570       return _mapping_type;
   571     }
   572 
   573     ///Sets the mapping type
   574 
   575     ///Sets the mapping type.
   576     ///
   577     ///The mapping type is set to \ref SUBGRAPH by default.
   578     ///
   579     ///\sa See \ref MappingType for the possible values.
   580     void mappingType(MappingType m_type)
   581     {
   582       _mapping_type = m_type;
   583     }
   584 
   585     ///Finds a mapping.
   586 
   587     ///This method finds a mapping from g1 into g2 according to the mapping
   588     ///type set by \ref mappingType(MappingType) "mappingType()".
   589     ///
   590     ///By subsequent calls, it returns all possible mappings one-by-one.
   591     ///
   592     ///\retval true if a mapping is found.
   593     ///\retval false if there is no (more) mapping.
   594     bool find()
   595     {
   596       switch(_mapping_type)
   597         {
   598         case SUBGRAPH:
   599           return extMatch<SUBGRAPH>();
   600         case INDUCED:
   601           return extMatch<INDUCED>();
   602         case ISOMORPH:
   603           return extMatch<ISOMORPH>();
   604         default:
   605           return false;
   606         }
   607     }
   608   };
   609 
   610   template<typename G1, typename G2>
   611   class Vf2ppWizardBase {
   612   protected:
   613     typedef G1 Graph1;
   614     typedef G2 Graph2;
   615 
   616     const G1 &_g1;
   617     const G2 &_g2;
   618 
   619     MappingType _mapping_type;
   620 
   621     typedef typename G1::template NodeMap<typename G2::Node> Mapping;
   622     bool _local_mapping;
   623     void *_mapping;
   624     void createMapping() {
   625       _mapping = new Mapping(_g1);
   626     }
   627 
   628     bool _local_nodeLabels;
   629     typedef typename G1::template NodeMap<int> NodeLabels1;
   630     typedef typename G2::template NodeMap<int> NodeLabels2;
   631     void *_nodeLabels1, *_nodeLabels2;
   632     void createNodeLabels() {
   633       _nodeLabels1 = new NodeLabels1(_g1,0);
   634       _nodeLabels2 = new NodeLabels2(_g2,0);
   635     }
   636 
   637     Vf2ppWizardBase(const G1 &g1,const G2 &g2)
   638       : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH),
   639         _local_mapping(1), _local_nodeLabels(1) { }
   640   };
   641 
   642 
   643   /// \brief Auxiliary class for the function-type interface of %VF2
   644   /// Plus Plus algorithm.
   645   ///
   646   /// This auxiliary class implements the named parameters of
   647   /// \ref vf2pp() "function-type interface" of \ref Vf2pp algorithm.
   648   ///
   649   /// \warning This class is not to be used directly.
   650   ///
   651   /// \tparam TR The traits class that defines various types used by the
   652   /// algorithm.
   653   template<typename TR>
   654   class Vf2ppWizard : public TR {
   655     typedef TR Base;
   656     typedef typename TR::Graph1 Graph1;
   657     typedef typename TR::Graph2 Graph2;
   658     typedef typename TR::Mapping Mapping;
   659     typedef typename TR::NodeLabels1 NodeLabels1;
   660     typedef typename TR::NodeLabels2 NodeLabels2;
   661 
   662     using TR::_g1;
   663     using TR::_g2;
   664     using TR::_mapping_type;
   665     using TR::_mapping;
   666     using TR::_nodeLabels1;
   667     using TR::_nodeLabels2;
   668 
   669   public:
   670     ///Constructor
   671     Vf2ppWizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {}
   672 
   673     ///Copy constructor
   674     Vf2ppWizard(const Base &b) : Base(b) {}
   675 
   676 
   677     template<typename T>
   678     struct SetMappingBase : public Base {
   679       typedef T Mapping;
   680       SetMappingBase(const Base &b) : Base(b) {}
   681     };
   682 
   683     ///\brief \ref named-templ-param "Named parameter" for setting
   684     ///the mapping.
   685     ///
   686     ///\ref named-templ-param "Named parameter" function for setting
   687     ///the map that stores the found embedding.
   688     template<typename T>
   689     Vf2ppWizard< SetMappingBase<T> > mapping(const T &t) {
   690       Base::_mapping=reinterpret_cast<void*>(const_cast<T*>(&t));
   691       Base::_local_mapping = 0;
   692       return Vf2ppWizard<SetMappingBase<T> >(*this);
   693     }
   694 
   695     template<typename NL1, typename NL2>
   696     struct SetNodeLabelsBase : public Base {
   697       typedef NL1 NodeLabels1;
   698       typedef NL2 NodeLabels2;
   699       SetNodeLabelsBase(const Base &b) : Base(b) { }
   700     };
   701 
   702     ///\brief \ref named-templ-param "Named parameter" for setting the
   703     ///node labels.
   704     ///
   705     ///\ref named-templ-param "Named parameter" function for setting
   706     ///the node labels.
   707     ///
   708     ///\param nodeLabels1 A \ref concepts::ReadMap "readable node map"
   709     ///of g1 with integer values. In case of K different labels, the labels
   710     ///must be the numbers {0,1,..,K-1}.
   711     ///\param nodeLabels2 A \ref concepts::ReadMap "readable node map"
   712     ///of g2 with integer values. In case of K different labels, the labels
   713     ///must be the numbers {0,1,..,K-1}.
   714     template<typename NL1, typename NL2>
   715     Vf2ppWizard< SetNodeLabelsBase<NL1,NL2> >
   716     nodeLabels(const NL1 &nodeLabels1, const NL2 &nodeLabels2) {
   717       Base::_local_nodeLabels = 0;
   718       Base::_nodeLabels1=
   719         reinterpret_cast<void*>(const_cast<NL1*>(&nodeLabels1));
   720       Base::_nodeLabels2=
   721         reinterpret_cast<void*>(const_cast<NL2*>(&nodeLabels2));
   722       return Vf2ppWizard<SetNodeLabelsBase<NL1,NL2> >
   723         (SetNodeLabelsBase<NL1,NL2>(*this));
   724     }
   725 
   726 
   727     ///\brief \ref named-templ-param "Named parameter" for setting
   728     ///the mapping type.
   729     ///
   730     ///\ref named-templ-param "Named parameter" for setting
   731     ///the mapping type.
   732     ///
   733     ///The mapping type is set to \ref SUBGRAPH by default.
   734     ///
   735     ///\sa See \ref MappingType for the possible values.
   736     Vf2ppWizard<Base> &mappingType(MappingType m_type) {
   737       _mapping_type = m_type;
   738       return *this;
   739     }
   740 
   741     ///\brief \ref named-templ-param "Named parameter" for setting
   742     ///the mapping type to \ref INDUCED.
   743     ///
   744     ///\ref named-templ-param "Named parameter" for setting
   745     ///the mapping type to \ref INDUCED.
   746     Vf2ppWizard<Base> &induced() {
   747       _mapping_type = INDUCED;
   748       return *this;
   749     }
   750 
   751     ///\brief \ref named-templ-param "Named parameter" for setting
   752     ///the mapping type to \ref ISOMORPH.
   753     ///
   754     ///\ref named-templ-param "Named parameter" for setting
   755     ///the mapping type to \ref ISOMORPH.
   756     Vf2ppWizard<Base> &iso() {
   757       _mapping_type = ISOMORPH;
   758       return *this;
   759     }
   760 
   761     ///Runs the %VF2 Plus Plus algorithm.
   762 
   763     ///This method runs the VF2 Plus Plus algorithm.
   764     ///
   765     ///\retval true if a mapping is found.
   766     ///\retval false if there is no mapping.
   767     bool run() {
   768       if(Base::_local_mapping)
   769         Base::createMapping();
   770       if(Base::_local_nodeLabels)
   771         Base::createNodeLabels();
   772 
   773       Vf2pp<Graph1, Graph2, Mapping, NodeLabels1, NodeLabels2 >
   774         alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping),
   775             *reinterpret_cast<NodeLabels1*>(_nodeLabels1),
   776             *reinterpret_cast<NodeLabels2*>(_nodeLabels2));
   777 
   778       alg.mappingType(_mapping_type);
   779 
   780       const bool ret = alg.find();
   781 
   782       if(Base::_local_nodeLabels) {
   783         delete reinterpret_cast<NodeLabels1*>(_nodeLabels1);
   784         delete reinterpret_cast<NodeLabels2*>(_nodeLabels2);
   785       }
   786       if(Base::_local_mapping)
   787         delete reinterpret_cast<Mapping*>(_mapping);
   788 
   789       return ret;
   790     }
   791 
   792     ///Get a pointer to the generated Vf2pp object.
   793 
   794     ///Gives a pointer to the generated Vf2pp object.
   795     ///
   796     ///\return Pointer to the generated Vf2pp object.
   797     ///\warning Don't forget to delete the referred Vf2pp object after use.
   798     Vf2pp<Graph1, Graph2, Mapping, NodeLabels1, NodeLabels2 >*
   799     getPtrToVf2ppObject(){
   800       if(Base::_local_mapping)
   801         Base::createMapping();
   802       if(Base::_local_nodeLabels)
   803         Base::createNodeLabels();
   804 
   805       Vf2pp<Graph1, Graph2, Mapping, NodeLabels1, NodeLabels2 >* ptr =
   806         new Vf2pp<Graph1, Graph2, Mapping, NodeLabels1, NodeLabels2>
   807         (_g1, _g2, *reinterpret_cast<Mapping*>(_mapping),
   808          *reinterpret_cast<NodeLabels1*>(_nodeLabels1),
   809          *reinterpret_cast<NodeLabels2*>(_nodeLabels2));
   810       ptr->mappingType(_mapping_type);
   811       if(Base::_local_mapping)
   812         ptr->_deallocMappingAfterUse=true;
   813       if(Base::_local_nodeLabels)
   814         ptr->_deallocLabelMapsAfterUse=true;
   815 
   816       return ptr;
   817     }
   818 
   819     ///Counts the number of mappings.
   820 
   821     ///This method counts the number of mappings.
   822     ///
   823     /// \return The number of mappings.
   824     int count() {
   825       if(Base::_local_mapping)
   826         Base::createMapping();
   827       if(Base::_local_nodeLabels)
   828         Base::createNodeLabels();
   829 
   830       Vf2pp<Graph1, Graph2, Mapping, NodeLabels1, NodeLabels2>
   831         alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping),
   832             *reinterpret_cast<NodeLabels1*>(_nodeLabels1),
   833             *reinterpret_cast<NodeLabels2*>(_nodeLabels2));
   834 
   835       alg.mappingType(_mapping_type);
   836 
   837       int ret = 0;
   838       while(alg.find())
   839         ++ret;
   840 
   841       if(Base::_local_nodeLabels) {
   842         delete reinterpret_cast<NodeLabels1*>(_nodeLabels1);
   843         delete reinterpret_cast<NodeLabels2*>(_nodeLabels2);
   844       }
   845       if(Base::_local_mapping)
   846         delete reinterpret_cast<Mapping*>(_mapping);
   847 
   848       return ret;
   849     }
   850   };
   851 
   852 
   853   ///Function-type interface for VF2 Plus Plus algorithm.
   854 
   855   /// \ingroup graph_isomorphism
   856   ///Function-type interface for VF2 Plus Plus algorithm.
   857   ///
   858   ///This function has several \ref named-func-param "named parameters"
   859   ///declared as the members of class \ref Vf2ppWizard.
   860   ///The following examples show how to use these parameters.
   861   ///\code
   862   ///  ListGraph::NodeMap<ListGraph::Node> m(g);
   863   ///  // Find an embedding of graph g1 into graph g2
   864   ///  vf2pp(g1,g2).mapping(m).run();
   865   ///
   866   ///  // Check whether graphs g1 and g2 are isomorphic
   867   ///  bool is_iso = vf2pp(g1,g2).iso().run();
   868   ///
   869   ///  // Count the number of isomorphisms
   870   ///  int num_isos = vf2pp(g1,g2).iso().count();
   871   ///
   872   ///  // Iterate through all the induced subgraph mappings
   873   ///  // of graph g1 into g2 using the labels c1 and c2
   874   ///  auto* myVf2pp = vf2pp(g1,g2).mapping(m).nodeLabels(c1,c2)
   875   ///  .induced().getPtrToVf2Object();
   876   ///  while(myVf2pp->find()){
   877   ///    //process the current mapping m
   878   ///  }
   879   ///  delete myVf22pp;
   880   ///\endcode
   881   ///\warning Don't forget to put the \ref Vf2ppWizard::run() "run()",
   882   ///\ref Vf2ppWizard::count() "count()" or
   883   ///the \ref Vf2ppWizard::getPtrToVf2ppObject() "getPtrToVf2ppObject()"
   884   ///to the end of the expression.
   885   ///\sa Vf2ppWizard
   886   ///\sa Vf2pp
   887   template<class G1, class G2>
   888   Vf2ppWizard<Vf2ppWizardBase<G1,G2> > vf2pp(const G1 &g1, const G2 &g2) {
   889     return Vf2ppWizard<Vf2ppWizardBase<G1,G2> >(g1,g2);
   890   }
   891 
   892 }
   893 
   894 #endif
   895