COIN-OR::LEMON - Graph Library

Ignore:
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • doc/references.bib

    r1367 r1414  
    4343  pages =        {67--118}
    4444}
     45
     46@article{VF2PP,
     47  author =       {Alp\'ar J\"uttner and  P\'eter Madarasi},
     48  title =        {{VF2++} — An improved subgraph isomorphism algorithm},
     49  journal =      {Discrete Applied Mathematics},
     50  year =         {2018},
     51  volume =       {242},
     52  pages =        {69--81},
     53  url =          {https://doi.org/10.1016/j.dam.2018.02.018}
     54}
     55
    4556
    4657
  • lemon/vf2.h

    r1370 r1413  
    33 * This file is a part of LEMON, a generic C++ optimization library.
    44 *
    5  * Copyright (C) 2015
     5 * Copyright (C) 2015-2017
    66 * EMAXA Kutato-fejleszto Kft. (EMAXA Research Ltd.)
    77 *
     
    2525#include <lemon/core.h>
    2626#include <lemon/concepts/graph.h>
    27 #include <lemon/dfs.h>
    2827#include <lemon/bfs.h>
     28#include <lemon/bits/vf2_internals.h>
    2929
    3030#include <vector>
    31 #include <set>
    32 
    33 namespace lemon
    34 {
    35   namespace bits
    36   {
    37     namespace vf2
    38     {
    39       class AlwaysEq
    40       {
     31
     32namespace lemon {
     33  namespace bits {
     34    namespace vf2 {
     35
     36      class AlwaysEq {
    4137      public:
    4238        template<class T1, class T2>
    43         bool operator()(T1, T2) const
    44         {
     39        bool operator()(T1&, T2&) const {
    4540          return true;
    4641        }
     
    4843
    4944      template<class M1, class M2>
    50       class MapEq
    51       {
     45      class MapEq{
    5246        const M1 &_m1;
    5347        const M2 &_m2;
    5448      public:
    55         MapEq(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {}
    56         bool operator()(typename M1::Key k1, typename M2::Key k2) const
    57         {
     49        MapEq(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) { }
     50        bool operator()(typename M1::Key k1, typename M2::Key k2) const {
    5851          return _m1[k1] == _m2[k2];
    5952        }
     
    6154
    6255      template <class G>
    63       class DfsLeaveOrder : public DfsVisitor<G>
    64       {
    65         const G &_g;
    66         std::vector<typename G::Node> &_order;
    67         int i;
    68       public:
    69         DfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
    70           : i(countNodes(g)), _g(g), _order(order)
    71         {}
    72         void leave(const typename G::Node &node)
    73         {
    74           _order[--i]=node;
    75         }
    76       };
    77 
    78       template <class G>
    79       class BfsLeaveOrder : public BfsVisitor<G>
    80       {
     56      class BfsLeaveOrder : public BfsVisitor<G> {
    8157        int i;
    8258        const G &_g;
     
    8460      public:
    8561        BfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
    86           : i(0), _g(g), _order(order)
    87         {}
    88         void process(const typename G::Node &node)
    89         {
     62          : i(0), _g(g), _order(order){
     63        }
     64        void process(const typename G::Node &node) {
    9065          _order[i++]=node;
    9166        }
     
    9469  }
    9570
    96   ///Graph mapping types.
    97 
    98   ///\ingroup graph_isomorphism
    99   ///The \ref Vf2 "VF2" algorithm is capable of finding different kind of
    100   ///embeddings, this enum specifies its type.
    101   ///
    102   ///See \ref graph_isomorphism for a more detailed description.
    103   enum Vf2MappingType {
    104     /// Subgraph isomorphism
    105     SUBGRAPH = 0,
    106     /// Induced subgraph isomorphism
    107     INDUCED = 1,
    108     /// Graph isomorphism
    109 
    110     /// If the two graph has the same number of nodes, than it is
    111     /// equivalent to \ref INDUCED, and if they also have the same
    112     /// number of edges, then it is also equivalent to \ref SUBGRAPH.
    113     ///
    114     /// However, using this setting is faster than the other two
    115     /// options.
    116     ISOMORPH = 2
    117   };
    11871
    11972  ///%VF2 algorithm class.
     
    12578  ///There is also a \ref vf2() "function-type interface" called \ref vf2()
    12679  ///for the %VF2 algorithm, which is probably more convenient in most
    127   ///use-cases.
     80  ///use cases.
    12881  ///
    12982  ///\tparam G1 The type of the graph to be embedded.
    130   ///The default type is \ref ListDigraph.
     83  ///The default type is \ref ListGraph.
    13184  ///\tparam G2 The type of the graph g1 will be embedded into.
    132   ///The default type is \ref ListDigraph.
     85  ///The default type is \ref ListGraph.
    13386  ///\tparam M The type of the NodeMap storing the mapping.
    13487  ///By default, it is G1::NodeMap<G2::Node>
    13588  ///\tparam NEQ A bool-valued binary functor determinining whether a node is
    136   ///mappable to another. By default it is an always true operator.
     89  ///mappable to another. By default, it is an always-true operator.
    13790  ///
    13891  ///\sa vf2()
     
    14093  template<class G1, class G2, class M, class NEQ >
    14194#else
    142   template<class G1=ListDigraph,
    143            class G2=ListDigraph,
     95  template<class G1 = ListGraph,
     96           class G2 = ListGraph,
    14497           class M = typename G1::template NodeMap<G2::Node>,
    14598           class NEQ = bits::vf2::AlwaysEq >
    14699#endif
    147   class Vf2
    148   {
    149     //Current depth in the DFS tree.
     100  class Vf2 {
     101    //The graph to be embedded
     102    const G1 &_g1;
     103
     104    //The graph into which g1 is to be embedded
     105    const G2 &_g2;
     106
     107    //Functor with bool operator()(G1::Node,G2::Node), which returns 1
     108    //if and only if the two nodes are equivalent
     109    NEQ _nEq;
     110
     111    //Current depth in the search tree
    150112    int _depth;
    151     //Functor with bool operator()(G1::Node,G2::Node), which returns 1
    152     //if and only if the 2 nodes are equivalent.
    153     NEQ _nEq;
    154 
     113
     114    //The current mapping. _mapping[v1]=v2 iff v1 has been mapped to v2,
     115    //where v1 is a node of G1 and v2 is a node of G2
     116    M &_mapping;
     117
     118    //_order[i] is the node of g1 for which a pair is searched if depth=i
     119    std::vector<typename G1::Node> _order;
     120 
     121    //_conn[v2] = number of covered neighbours of v2
    155122    typename G2::template NodeMap<int> _conn;
    156     //Current mapping. We index it by the nodes of g1, and match[v] is
    157     //a node of g2.
    158     M &_mapping;
    159     //order[i] is the node of g1, for which we find a pair if depth=i
    160     std::vector<typename G1::Node> order;
    161     //currEdgeIts[i] is an edge iterator, witch is last used in the ith
    162     //depth to find a pair for order[i].
    163     std::vector<typename G2::IncEdgeIt> currEdgeIts;
    164     //The small graph.
    165     const G1 &_g1;
    166     //The big graph.
    167     const G2 &_g2;
    168     //lookup tables for cut the searchtree
    169     typename G1::template NodeMap<int> rNew1t,rInOut1t;
    170 
    171     Vf2MappingType _mapping_type;
     123
     124    //_currEdgeIts[i] is the last used edge iterator in the i-th
     125    //depth to find a pair for node _order[i]
     126    std::vector<typename G2::IncEdgeIt> _currEdgeIts;
     127
     128    //lookup tables for cutting the searchtree
     129    typename G1::template NodeMap<int> _rNew1t, _rInOut1t;
     130
     131    MappingType _mapping_type;
     132
     133    bool _deallocMappingAfterUse;
    172134
    173135    //cut the search tree
    174     template<Vf2MappingType MT>
    175     bool cut(const typename G1::Node n1,const typename G2::Node n2) const
    176     {
     136    template<MappingType MT>
     137    bool cut(const typename G1::Node n1,const typename G2::Node n2) const {
    177138      int rNew2=0,rInOut2=0;
    178       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
    179         {
    180           const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
    181           if(_conn[currNode]>0)
    182             ++rInOut2;
    183           else if(MT!=SUBGRAPH&&_conn[currNode]==0)
    184             ++rNew2;
    185         }
    186       switch(MT)
    187         {
    188         case INDUCED:
    189           return rInOut1t[n1]<=rInOut2&&rNew1t[n1]<=rNew2;
    190         case SUBGRAPH:
    191           return rInOut1t[n1]<=rInOut2;
    192         case ISOMORPH:
    193           return rInOut1t[n1]==rInOut2&&rNew1t[n1]==rNew2;
    194         default:
    195           return false;
    196         }
    197     }
    198 
    199     template<Vf2MappingType MT>
    200     bool feas(const typename G1::Node n1,const typename G2::Node n2)
    201     {
     139      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     140        const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
     141        if(_conn[currNode]>0)
     142          ++rInOut2;
     143        else if(MT!=SUBGRAPH&&_conn[currNode]==0)
     144          ++rNew2;
     145      }
     146      switch(MT) {
     147      case INDUCED:
     148        return _rInOut1t[n1]<=rInOut2&&_rNew1t[n1]<=rNew2;
     149      case SUBGRAPH:
     150        return _rInOut1t[n1]<=rInOut2;
     151      case ISOMORPH:
     152        return _rInOut1t[n1]==rInOut2&&_rNew1t[n1]==rNew2;
     153      default:
     154        return false;
     155      }
     156    }
     157
     158    template<MappingType MT>
     159    bool feas(const typename G1::Node n1,const typename G2::Node n2) {
    202160      if(!_nEq(n1,n2))
    203161        return 0;
    204162
    205       for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1)
    206         {
    207           const typename G1::Node currNode=_g1.oppositeNode(n1,e1);
    208           if(_mapping[currNode]!=INVALID)
    209             --_conn[_mapping[currNode]];
    210         }
     163      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
     164        const typename G1::Node& currNode=_g1.oppositeNode(n1,e1);
     165        if(_mapping[currNode]!=INVALID)
     166          --_conn[_mapping[currNode]];
     167      }
    211168      bool isIso=1;
    212       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
    213         {
    214           const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
    215           if(_conn[currNode]<-1)
    216             ++_conn[currNode];
    217           else if(MT!=SUBGRAPH&&_conn[currNode]==-1)
    218             {
     169      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     170        int& connCurrNode = _conn[_g2.oppositeNode(n2,e2)];
     171        if(connCurrNode<-1)
     172          ++connCurrNode;
     173        else if(MT!=SUBGRAPH&&connCurrNode==-1) {
     174          isIso=0;
     175          break;
     176        }
     177      }
     178
     179      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
     180        const typename G2::Node& currNodePair=_mapping[_g1.oppositeNode(n1,e1)];
     181        int& connCurrNodePair=_conn[currNodePair];
     182        if(currNodePair!=INVALID&&connCurrNodePair!=-1) {
     183          switch(MT) {
     184          case INDUCED:
     185          case ISOMORPH:
     186            isIso=0;
     187            break;
     188          case SUBGRAPH:
     189            if(connCurrNodePair<-1)
    219190              isIso=0;
    220               break;
    221             }
    222         }
    223 
    224       for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1)
    225         {
    226           const typename G1::Node currNode=_g1.oppositeNode(n1,e1);
    227           if(_mapping[currNode]!=INVALID&&_conn[_mapping[currNode]]!=-1)
    228             {
    229               switch(MT)
    230                 {
    231                 case INDUCED:
    232                 case ISOMORPH:
    233                   isIso=0;
    234                   break;
    235                 case SUBGRAPH:
    236                   if(_conn[_mapping[currNode]]<-1)
    237                     isIso=0;
    238                   break;
    239                 }
    240               _conn[_mapping[currNode]]=-1;
    241             }
    242         }
     191            break;
     192          }
     193          connCurrNodePair=-1;
     194        }
     195      }
    243196      return isIso&&cut<MT>(n1,n2);
    244197    }
    245198
    246     void addPair(const typename G1::Node n1,const typename G2::Node n2)
    247     {
     199    void addPair(const typename G1::Node n1,const typename G2::Node n2) {
    248200      _conn[n2]=-1;
    249201      _mapping.set(n1,n2);
    250       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
    251         if(_conn[_g2.oppositeNode(n2,e2)]!=-1)
    252           ++_conn[_g2.oppositeNode(n2,e2)];
    253     }
    254 
    255     void subPair(const typename G1::Node n1,const typename G2::Node n2)
    256     {
     202      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     203        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
     204        if(currConn!=-1)
     205          ++currConn;
     206      }
     207    }
     208
     209    void subPair(const typename G1::Node n1,const typename G2::Node n2) {
    257210      _conn[n2]=0;
    258211      _mapping.set(n1,INVALID);
    259       for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2)
    260         {
    261           const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
    262           if(_conn[currNode]>0)
    263             --_conn[currNode];
    264           else if(_conn[currNode]==-1)
    265             ++_conn[n2];
    266         }
    267     }
    268 
    269     void setOrder()//we will find pairs for the nodes of g1 in this order
    270     {
    271       // bits::vf2::DfsLeaveOrder<G1> v(_g1,order);
    272       //   DfsVisit<G1,bits::vf2::DfsLeaveOrder<G1> >dfs(_g1, v);
    273       //   dfs.run();
    274 
    275       //it is more efficient in practice than DFS
    276       bits::vf2::BfsLeaveOrder<G1> v(_g1,order);
    277       BfsVisit<G1,bits::vf2::BfsLeaveOrder<G1> >bfs(_g1, v);
     212      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     213        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
     214        if(currConn>0)
     215          --currConn;
     216        else if(currConn==-1)
     217          ++_conn[n2];
     218      }
     219    }
     220
     221    void initOrder() {
     222      //determine the order in which we will find pairs for the nodes of g1
     223      //BFS order is more efficient in practice than DFS
     224      bits::vf2::BfsLeaveOrder<G1> v(_g1,_order);
     225      BfsVisit<G1,bits::vf2::BfsLeaveOrder<G1> > bfs(_g1, v);
    278226      bfs.run();
    279227    }
    280228
    281     template<Vf2MappingType MT>
    282     bool extMatch()
    283     {
    284       while(_depth>=0)
    285         {
    286           //there are not nodes in g1, which has not pair in g2.
    287           if(_depth==static_cast<int>(order.size()))
    288             {
     229    template<MappingType MT>
     230    bool extMatch() {
     231      while(_depth>=0) {
     232        if(_depth==static_cast<int>(_order.size())) {
     233          //all nodes of g1 are mapped to nodes of g2
     234          --_depth;
     235          return true;
     236        }
     237        typename G1::Node& nodeOfDepth = _order[_depth];
     238        const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth];
     239        typename G2::IncEdgeIt &edgeItOfDepth = _currEdgeIts[_depth];
     240        //the node of g2 whose neighbours are the candidates for
     241        //the pair of nodeOfDepth
     242        typename G2::Node currPNode;
     243        if(edgeItOfDepth==INVALID) {
     244          typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth);
     245          //if pairOfNodeOfDepth!=INVALID, we don't use fstMatchedE
     246          if(pairOfNodeOfDepth==INVALID) {
     247            for(; fstMatchedE!=INVALID &&
     248                  _mapping[_g1.oppositeNode(nodeOfDepth,
     249                                            fstMatchedE)]==INVALID;
     250                ++fstMatchedE) ; //find fstMatchedE
     251          }
     252          if(fstMatchedE==INVALID||pairOfNodeOfDepth!=INVALID) {
     253            //We found no covered neighbours, this means that
     254            //the graph is not connected (or _depth==0). Each
     255            //uncovered (and there are some other properties due
     256            //to the spec. problem types) node of g2 is
     257            //candidate. We can read the iterator of the last
     258            //tried node from the match if it is not the first
     259            //try (match[nodeOfDepth]!=INVALID)
     260            typename G2::NodeIt n2(_g2);
     261            //if it's not the first try
     262            if(pairOfNodeOfDepth!=INVALID) {
     263              n2=++typename G2::NodeIt(_g2,pairOfNodeOfDepth);
     264              subPair(nodeOfDepth,pairOfNodeOfDepth);
     265            }
     266            for(; n2!=INVALID; ++n2)
     267              if(MT!=SUBGRAPH) {
     268                if(_conn[n2]==0&&feas<MT>(nodeOfDepth,n2))
     269                  break;
     270              }
     271              else if(_conn[n2]>=0&&feas<MT>(nodeOfDepth,n2))
     272                break;
     273            // n2 is the next candidate
     274            if(n2!=INVALID){
     275              addPair(nodeOfDepth,n2);
     276              ++_depth;
     277            }
     278            else // there are no more candidates
    289279              --_depth;
    290               return true;
    291             }
    292           //the node of g2, which neighbours are the candidates for
    293           //the pair of order[_depth]
    294           typename G2::Node currPNode;
    295           if(currEdgeIts[_depth]==INVALID)
    296             {
    297               typename G1::IncEdgeIt fstMatchedE(_g1,order[_depth]);
    298               //if _mapping[order[_depth]]!=INVALID, we dont use
    299               //fstMatchedE
    300               if(_mapping[order[_depth]]==INVALID)
    301                 for(; fstMatchedE!=INVALID &&
    302                       _mapping[_g1.oppositeNode(order[_depth],
    303                                               fstMatchedE)]==INVALID;
    304                     ++fstMatchedE) ; //find fstMatchedE
    305               if(fstMatchedE==INVALID||_mapping[order[_depth]]!=INVALID)
    306                 {
    307                   //We did not find an covered neighbour, this means
    308                   //the graph is not connected(or _depth==0).  Every
    309                   //uncovered(and there are some other properties due
    310                   //to the spec. problem types) node of g2 is
    311                   //candidate.  We can read the iterator of the last
    312                   //tryed node from the match if it is not the first
    313                   //try(match[order[_depth]]!=INVALID)
    314                   typename G2::NodeIt n2(_g2);
    315                   //if its not the first try
    316                   if(_mapping[order[_depth]]!=INVALID)
    317                     {
    318                       n2=++typename G2::NodeIt(_g2,_mapping[order[_depth]]);
    319                       subPair(order[_depth],_mapping[order[_depth]]);
    320                     }
    321                   for(; n2!=INVALID; ++n2)
    322                     if(MT!=SUBGRAPH&&_conn[n2]==0)
    323                       {
    324                         if(feas<MT>(order[_depth],n2))
    325                           break;
    326                       }
    327                     else if(MT==SUBGRAPH&&_conn[n2]>=0)
    328                       if(feas<MT>(order[_depth],n2))
    329                         break;
    330                   // n2 is the next candidate
    331                   if(n2!=INVALID)
    332                     {
    333                       addPair(order[_depth],n2);
    334                       ++_depth;
    335                     }
    336                   else // there is no more candidate
    337                     --_depth;
    338                   continue;
    339                 }
    340               else
    341                 {
    342                   currPNode=_mapping[_g1.oppositeNode(order[_depth],
    343                                                       fstMatchedE)];
    344                   currEdgeIts[_depth]=typename G2::IncEdgeIt(_g2,currPNode);
    345                 }
    346             }
    347           else
    348             {
    349               currPNode=_g2.oppositeNode(_mapping[order[_depth]],
    350                                          currEdgeIts[_depth]);
    351               subPair(order[_depth],_mapping[order[_depth]]);
    352               ++currEdgeIts[_depth];
    353             }
    354           for(; currEdgeIts[_depth]!=INVALID; ++currEdgeIts[_depth])
    355             {
    356               const typename G2::Node currNode =
    357                 _g2.oppositeNode(currPNode, currEdgeIts[_depth]);
    358               //if currNode is uncovered
    359               if(_conn[currNode]>0&&feas<MT>(order[_depth],currNode))
    360                 {
    361                   addPair(order[_depth],currNode);
    362                   break;
    363                 }
    364             }
    365           currEdgeIts[_depth]==INVALID?--_depth:++_depth;
    366         }
     280            continue;
     281          }
     282          else {
     283            currPNode=_mapping[_g1.oppositeNode(nodeOfDepth,
     284                                                fstMatchedE)];
     285            edgeItOfDepth=typename G2::IncEdgeIt(_g2,currPNode);
     286          }
     287        }
     288        else {
     289          currPNode=_g2.oppositeNode(pairOfNodeOfDepth,
     290                                     edgeItOfDepth);
     291          subPair(nodeOfDepth,pairOfNodeOfDepth);
     292          ++edgeItOfDepth;
     293        }
     294        for(; edgeItOfDepth!=INVALID; ++edgeItOfDepth) {
     295          const typename G2::Node currNode =
     296            _g2.oppositeNode(currPNode, edgeItOfDepth);
     297          if(_conn[currNode]>0&&feas<MT>(nodeOfDepth,currNode)) {
     298            addPair(nodeOfDepth,currNode);
     299            break;
     300          }
     301        }
     302        edgeItOfDepth==INVALID?--_depth:++_depth;
     303      }
    367304      return false;
    368305    }
    369306
    370     //calc. the lookup table for cut the searchtree
    371     void setRNew1tRInOut1t()
    372     {
     307    //calculate the lookup table for cutting the search tree
     308    void initRNew1tRInOut1t() {
    373309      typename G1::template NodeMap<int> tmp(_g1,0);
    374       for(unsigned int i=0; i<order.size(); ++i)
    375         {
    376           tmp[order[i]]=-1;
    377           for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1)
    378             {
    379               const typename G1::Node currNode=_g1.oppositeNode(order[i],e1);
    380               if(tmp[currNode]>0)
    381                 ++rInOut1t[order[i]];
    382               else if(tmp[currNode]==0)
    383                 ++rNew1t[order[i]];
    384             }
    385           for(typename G1::IncEdgeIt e1(_g1,order[i]); e1!=INVALID; ++e1)
    386             {
    387               const typename G1::Node currNode=_g1.oppositeNode(order[i],e1);
    388               if(tmp[currNode]!=-1)
    389                 ++tmp[currNode];
    390             }
    391         }
     310      for(unsigned int i=0; i<_order.size(); ++i) {
     311        const typename G1::Node& orderI = _order[i];
     312        tmp[orderI]=-1;
     313        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
     314          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
     315          if(tmp[currNode]>0)
     316            ++_rInOut1t[orderI];
     317          else if(tmp[currNode]==0)
     318            ++_rNew1t[orderI];
     319        }
     320        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
     321          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
     322          if(tmp[currNode]!=-1)
     323            ++tmp[currNode];
     324        }
     325      }
    392326    }
    393327  public:
     
    400334    ///\param m \ref concepts::ReadWriteMap "read-write" NodeMap
    401335    ///storing the found mapping.
    402     ///\param neq A bool-valued binary functor determinining whether a node is
     336    ///\param neq A bool-valued binary functor determining whether a node is
    403337    ///mappable to another. By default it is an always true operator.
    404     Vf2(const G1 &g1, const G2 &g2,M &m, const NEQ &neq = NEQ() ) :
    405       _nEq(neq), _conn(g2,0), _mapping(m), order(countNodes(g1)),
    406       currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNew1t(g1,0),
    407       rInOut1t(g1,0), _mapping_type(SUBGRAPH)
     338    Vf2(const G1 &g1, const G2 &g2, M &m, const NEQ &neq = NEQ() ) :
     339      _g1(g1), _g2(g2), _nEq(neq), _depth(0), _mapping(m),
     340      _order(countNodes(g1)), _conn(g2,0),
     341      _currEdgeIts(countNodes(g1),INVALID), _rNew1t(g1,0), _rInOut1t(g1,0),
     342      _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0)
    408343    {
    409       _depth=0;
    410       setOrder();
    411       setRNew1tRInOut1t();
     344      initOrder();
     345      initRNew1tRInOut1t();
    412346      for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    413347        m[n]=INVALID;
    414348    }
    415349
     350    ///Destructor
     351
     352    ///Destructor.
     353    ///
     354
     355    ~Vf2(){
     356      if(_deallocMappingAfterUse)
     357        delete &_mapping;
     358    }
     359
    416360    ///Returns the current mapping type
    417361
    418362    ///Returns the current mapping type
    419363    ///
    420     Vf2MappingType mappingType() const { return _mapping_type; }
     364    MappingType mappingType() const {
     365      return _mapping_type;
     366    }
    421367    ///Sets mapping type
    422368
     
    425371    ///The mapping type is set to \ref SUBGRAPH by default.
    426372    ///
    427     ///\sa See \ref Vf2MappingType for the possible values.
    428     void mappingType(Vf2MappingType m_type) { _mapping_type = m_type; }
     373    ///\sa See \ref MappingType for the possible values.
     374    void mappingType(MappingType m_type) {
     375      _mapping_type = m_type;
     376    }
    429377
    430378    ///Finds a mapping
    431379
    432     ///It finds a mapping between from g1 into g2 according to the mapping
    433     ///type set by \ref mappingType(Vf2MappingType) "mappingType()".
     380    ///It finds a mapping from g1 into g2 according to the mapping
     381    ///type set by \ref mappingType(MappingType) "mappingType()".
    434382    ///
    435383    ///By subsequent calls, it returns all possible mappings one-by-one.
     
    437385    ///\retval true if a mapping is found.
    438386    ///\retval false if there is no (more) mapping.
    439     bool find()
    440     {
    441       switch(_mapping_type)
    442         {
    443         case SUBGRAPH:
    444           return extMatch<SUBGRAPH>();
    445         case INDUCED:
    446           return extMatch<INDUCED>();
    447         case ISOMORPH:
    448           return extMatch<ISOMORPH>();
    449         default:
    450           return false;
    451         }
     387    bool find() {
     388      switch(_mapping_type) {
     389      case SUBGRAPH:
     390        return extMatch<SUBGRAPH>();
     391      case INDUCED:
     392        return extMatch<INDUCED>();
     393      case ISOMORPH:
     394        return extMatch<ISOMORPH>();
     395      default:
     396        return false;
     397      }
    452398    }
    453399  };
    454400
    455401  template<class G1, class G2>
    456   class Vf2WizardBase
    457   {
     402  class Vf2WizardBase {
    458403  protected:
    459404    typedef G1 Graph1;
     
    463408    const G2 &_g2;
    464409
    465     Vf2MappingType _mapping_type;
     410    MappingType _mapping_type;
    466411
    467412    typedef typename G1::template NodeMap<typename G2::Node> Mapping;
    468413    bool _local_mapping;
    469414    void *_mapping;
    470     void createMapping()
    471     {
     415    void createMapping() {
    472416      _mapping = new Mapping(_g1);
    473417    }
     418
     419    void *myVf2; //used in Vf2Wizard::find
     420
    474421
    475422    typedef bits::vf2::AlwaysEq NodeEq;
     
    477424
    478425    Vf2WizardBase(const G1 &g1,const G2 &g2)
    479       : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) {}
     426      : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) { }
    480427  };
    481428
     429
    482430  /// Auxiliary class for the function-type interface of %VF2 algorithm.
    483 
     431  ///
    484432  /// This auxiliary class implements the named parameters of
    485433  /// \ref vf2() "function-type interface" of \ref Vf2 algorithm.
    486434  ///
    487   /// \warning This class should only be used through the function \ref vf2().
     435  /// \warning This class is not to be used directly.
    488436  ///
    489437  /// \tparam TR The traits class that defines various types used by the
    490438  /// algorithm.
    491439  template<class TR>
    492   class Vf2Wizard : public TR
    493   {
     440  class Vf2Wizard : public TR {
    494441    typedef TR Base;
    495442    typedef typename TR::Graph1 Graph1;
     
    512459    Vf2Wizard(const Base &b) : Base(b) {}
    513460
     461    ///Copy constructor
     462    Vf2Wizard(const Vf2Wizard &b) : Base(b) {}
     463
    514464
    515465    template<class T>
    516     struct SetMappingBase : public Base {
     466    struct SetMappingBase : public Base{
    517467      typedef T Mapping;
    518468      SetMappingBase(const Base &b) : Base(b) {}
     
    525475    ///the map that stores the found embedding.
    526476    template<class T>
    527     Vf2Wizard< SetMappingBase<T> > mapping(const T &t)
    528     {
     477    Vf2Wizard< SetMappingBase<T> > mapping(const T &t) {
    529478      Base::_mapping=reinterpret_cast<void*>(const_cast<T*>(&t));
    530479      Base::_local_mapping = false;
     
    537486      NodeEq _node_eq;
    538487      SetNodeEqBase(const Base &b, const NE &node_eq)
    539         : Base(b), _node_eq(node_eq) {}
     488        : Base(b), _node_eq(node_eq){
     489      }
    540490    };
    541491
     
    550500    ///always true operator.
    551501    template<class T>
    552     Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq)
    553     {
     502    Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq) {
    554503      return Vf2Wizard<SetNodeEqBase<T> >(SetNodeEqBase<T>(*this,node_eq));
    555504    }
     
    561510    ///the node labels defining equivalence relation between them.
    562511    ///
    563     ///\param m1 It is arbitrary \ref concepts::ReadMap "readable node map"
     512    ///\param m1 An arbitrary \ref concepts::ReadMap "readable node map"
    564513    ///of g1.
    565     ///\param m2 It is arbitrary \ref concepts::ReadMap "readable node map"
     514    ///\param m2 An arbitrary \ref concepts::ReadMap "readable node map"
    566515    ///of g2.
    567516    ///
     
    569518    template<class M1, class M2>
    570519    Vf2Wizard< SetNodeEqBase<bits::vf2::MapEq<M1,M2> > >
    571     nodeLabels(const M1 &m1,const M2 &m2)
    572     {
     520    nodeLabels(const M1 &m1,const M2 &m2){
    573521      return nodeEq(bits::vf2::MapEq<M1,M2>(m1,m2));
    574522    }
     
    582530    ///The mapping type is set to \ref SUBGRAPH by default.
    583531    ///
    584     ///\sa See \ref Vf2MappingType for the possible values.
    585     Vf2Wizard<Base> &mappingType(Vf2MappingType m_type)
    586     {
     532    ///\sa See \ref MappingType for the possible values.
     533    Vf2Wizard<Base> &mappingType(MappingType m_type) {
    587534      _mapping_type = m_type;
    588535      return *this;
     
    594541    ///\ref named-templ-param "Named parameter" for setting
    595542    ///the mapping type to \ref INDUCED.
    596     Vf2Wizard<Base> &induced()
    597     {
     543    Vf2Wizard<Base> &induced() {
    598544      _mapping_type = INDUCED;
    599545      return *this;
     
    605551    ///\ref named-templ-param "Named parameter" for setting
    606552    ///the mapping type to \ref ISOMORPH.
    607     Vf2Wizard<Base> &iso()
    608     {
     553    Vf2Wizard<Base> &iso() {
    609554      _mapping_type = ISOMORPH;
    610555      return *this;
    611556    }
    612557
     558
    613559    ///Runs VF2 algorithm.
    614560
     
    616562    ///
    617563    ///\retval true if a mapping is found.
    618     ///\retval false if there is no (more) mapping.
    619     bool run()
    620     {
     564    ///\retval false if there is no mapping.
     565    bool run(){
    621566      if(Base::_local_mapping)
    622567        Base::createMapping();
     
    631576      if(Base::_local_mapping)
    632577        delete reinterpret_cast<Mapping*>(_mapping);
     578
     579      return ret;
     580    }
     581
     582    ///Get a pointer to the generated Vf2 object.
     583
     584    ///Gives a pointer to the generated Vf2 object.
     585    ///
     586    ///\return Pointer to the generated Vf2 object.
     587    ///\warning Don't forget to delete the referred Vf2 object after use.
     588    Vf2<Graph1, Graph2, Mapping, NodeEq >* getPtrToVf2Object() {
     589      if(Base::_local_mapping)
     590        Base::createMapping();
     591      Vf2<Graph1, Graph2, Mapping, NodeEq >* ptr =
     592        new Vf2<Graph1, Graph2, Mapping, NodeEq>
     593        (_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
     594      ptr->mappingType(_mapping_type);
     595      if(Base::_local_mapping)
     596        ptr->_deallocMappingAfterUse = true;
     597      return ptr;
     598    }
     599
     600    ///Counts the number of mappings.
     601
     602    ///This method counts the number of mappings.
     603    ///
     604    /// \return The number of mappings.
     605    int count() {
     606      if(Base::_local_mapping)
     607        Base::createMapping();
     608
     609      Vf2<Graph1, Graph2, Mapping, NodeEq>
     610        alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
     611      if(Base::_local_mapping)
     612        alg._deallocMappingAfterUse = true;
     613      alg.mappingType(_mapping_type);
     614
     615      int ret = 0;
     616      while(alg.find())
     617        ++ret;
    633618
    634619      return ret;
     
    645630  ///The following examples show how to use these parameters.
    646631  ///\code
    647   ///  // Find an embedding of graph g into graph h
     632  ///  // Find an embedding of graph g1 into graph g2
    648633  ///  ListGraph::NodeMap<ListGraph::Node> m(g);
    649   ///  vf2(g,h).mapping(m).run();
    650   ///
    651   ///  // Check whether graphs g and h are isomorphic
    652   ///  bool is_iso = vf2(g,h).iso().run();
     634  ///  vf2(g1,g2).mapping(m).run();
     635  ///
     636  ///  // Check whether graphs g1 and g2 are isomorphic
     637  ///  bool is_iso = vf2(g1,g2).iso().run();
     638  ///
     639  ///  // Count the number of isomorphisms
     640  ///  int num_isos = vf2(g1,g2).iso().count();
     641  ///
     642  ///  // Iterate through all the induced subgraph mappings of graph g1 into g2
     643  ///  auto* myVf2 = vf2(g1,g2).mapping(m).nodeLabels(c1,c2)
     644  ///  .induced().getPtrToVf2Object();
     645  ///  while(myVf2->find()){
     646  ///    //process the current mapping m
     647  ///  }
     648  ///  delete myVf22;
    653649  ///\endcode
    654   ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()"
     650  ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()",
     651  ///\ref Vf2Wizard::count() "count()" or
     652  ///the \ref Vf2Wizard::getPtrToVf2Object() "getPtrToVf2Object()"
    655653  ///to the end of the expression.
    656654  ///\sa Vf2Wizard
    657655  ///\sa Vf2
    658656  template<class G1, class G2>
    659   Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2)
    660   {
     657  Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2) {
    661658    return Vf2Wizard<Vf2WizardBase<G1,G2> >(g1,g2);
    662659  }
  • test/vf2_test.cc

    r1352 r1406  
    33 * This file is a part of LEMON, a generic C++ optimization library.
    44 *
    5  * Copyright (C) 2015
     5 * Copyright (C) 2015-2017
    66 * EMAXA Kutato-fejleszto Kft. (EMAXA Research Ltd.)
    77 *
     
    1717
    1818#include <lemon/vf2.h>
     19#include <lemon/vf2pp.h>
    1920#include <lemon/concepts/digraph.h>
    2021#include <lemon/smart_graph.h>
     
    153154  std::stringstream ss(petersen_lgf);
    154155  graphReader(petersen, ss)
    155     .nodeMap("col1",petersen_col1)
    156     .nodeMap("col2",petersen_col2)
     156    .nodeMap("col1", petersen_col1)
     157    .nodeMap("col2", petersen_col2)
    157158    .run();
    158159
    159160  ss.clear();
    160161  ss.str("");
    161   ss<<c5_lgf;
     162  ss << c5_lgf;
    162163  //std::stringstream ss2(c5_lgf);
    163164  graphReader(c5, ss)
    164     .nodeMap("col",c5_col)
     165    .nodeMap("col", c5_col)
    165166    .run();
    166167
    167168  ss.clear();
    168169  ss.str("");
    169   ss<<c7_lgf;
     170  ss << c7_lgf;
    170171  graphReader(c7, ss).run();
    171172
    172173  ss.clear();
    173174  ss.str("");
    174   ss<<c10_lgf;
     175  ss << c10_lgf;
    175176  graphReader(c10, ss).run();
    176177
    177178  ss.clear();
    178179  ss.str("");
    179   ss<<p10_lgf;
     180  ss << p10_lgf;
    180181  graphReader(p10, ss).run();
    181182
     
    184185class EqComparable {
    185186public:
    186   bool operator==(const EqComparable&) { return false; }
     187  bool operator==(const EqComparable&) {
     188    return false;
     189  }
    187190};
    188191
     
    190193class EqClass {
    191194public:
    192   bool operator()(A, B) { return false; }
     195  bool operator()(A, B){
     196    return false;
     197  }
    193198};
    194199
     200class IntConvertible1 {
     201public:
     202  operator int() {
     203    return 0;
     204  }
     205};
     206
     207class IntConvertible2 {
     208public:
     209  operator int() {
     210    return 0;
     211  }
     212};
     213
    195214template<class G1,class G2>
    196 void checkVf2Compile()
    197 {
     215void checkVf2Compile() {
    198216  G1 g;
    199217  G2 h;
     
    206224  succ = vf2(g,h).iso().run();
    207225  succ = vf2(g,h).mapping(r).run();
     226
     227  Vf2<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     228      EqClass<typename G1::Node,typename G2::Node> >
     229    myVf2(g,h,r,EqClass<typename G1::Node,typename G2::Node>());
     230  myVf2.find();
     231
    208232  succ = vf2(g,h).induced().mapping(r).run();
    209233  succ = vf2(g,h).iso().mapping(r).run();
     234
    210235  concepts::ReadMap<typename G1::Node, EqComparable> l1;
    211236  concepts::ReadMap<typename G2::Node, EqComparable> l2;
     
    215240}
    216241
    217 void justCompile()
    218 {
     242void vf2Compile() {
    219243  checkVf2Compile<concepts::Graph,concepts::Graph>();
    220244  checkVf2Compile<concepts::Graph,SmartGraph>();
     
    222246}
    223247
     248template<class G1,class G2>
     249void checkVf2ppCompile() {
     250  G1 g;
     251  G2 h;
     252  concepts::ReadWriteMap<typename G1::Node, typename G2::Node> r;
     253  bool succ;
     254  ::lemon::ignore_unused_variable_warning(succ);
     255
     256  succ = vf2pp(g,h).run();
     257  succ = vf2pp(g,h).induced().run();
     258  succ = vf2pp(g,h).iso().run();
     259  succ = vf2pp(g,h).mapping(r).run();
     260  succ = vf2pp(g,h).induced().mapping(r).run();
     261  succ = vf2pp(g,h).iso().mapping(r).run();
     262
     263  concepts::ReadMap<typename G1::Node, int> c1;
     264  concepts::ReadMap<typename G2::Node, int> c2;
     265  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     266        concepts::ReadMap<typename G1::Node, int>,
     267        concepts::ReadMap<typename G2::Node, int> >
     268    myVf2pp(g,h,r,c1,c2);
     269  myVf2pp.find();
     270
     271  succ = vf2pp(g,h).nodeLabels(c1,c2).mapping(r).run();
     272  succ = vf2pp(g,h).nodeLabels(c1,c2).mapping(r).run();
     273
     274  concepts::ReadMap<typename G1::Node, char> c1_c;
     275  concepts::ReadMap<typename G2::Node, char> c2_c;
     276  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     277        concepts::ReadMap<typename G1::Node, char>,
     278        concepts::ReadMap<typename G2::Node, char> >
     279    myVf2pp_c(g,h,r,c1_c,c2_c);
     280  myVf2pp_c.find();
     281
     282  succ = vf2pp(g,h).nodeLabels(c1_c,c2_c).mapping(r).run();
     283  succ = vf2pp(g,h).nodeLabels(c1_c,c2_c).mapping(r).run();
     284
     285  concepts::ReadMap<typename G1::Node, IntConvertible1> c1_IntConv;
     286  concepts::ReadMap<typename G2::Node, IntConvertible2> c2_IntConv;
     287  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     288        concepts::ReadMap<typename G1::Node, IntConvertible1>,
     289        concepts::ReadMap<typename G2::Node, IntConvertible2> >
     290    myVf2pp_IntConv(g,h,r,c1_IntConv,c2_IntConv);
     291  myVf2pp_IntConv.find();
     292
     293  succ = vf2pp(g,h).nodeLabels(c1_IntConv,c2_IntConv).mapping(r).run();
     294  succ = vf2pp(g,h).nodeLabels(c1_IntConv,c2_IntConv).mapping(r).run();
     295}
     296
     297void vf2ppCompile() {
     298  checkVf2ppCompile<concepts::Graph,concepts::Graph>();
     299  checkVf2ppCompile<concepts::Graph,SmartGraph>();
     300  checkVf2ppCompile<SmartGraph,concepts::Graph>();
     301}
     302
    224303template<class G1, class G2, class I>
    225 void checkSub(const G1 &g1, const G2 &g2, const I &i)
    226 {
    227   {
    228     std::set<typename G2::Node> image;
    229     for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    230       {
    231           check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
    232           check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
    233           image.insert(i[n]);
    234       }
    235   }
    236   for(typename G1::EdgeIt e(g1);e!=INVALID;++e)
    237     check(findEdge(g2,i[g1.u(e)],i[g1.v(e)])!=INVALID,
    238           "Wrong isomorphism: missing edge(checkSub).");
    239 }
    240 
    241 template<class G1, class G2, class I>
    242 void checkInd(const G1 &g1, const G2 &g2, const I &i)
    243   {
     304void checkSubIso(const G1 &g1, const G2 &g2, const I &i) {
    244305  std::set<typename G2::Node> image;
    245   for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    246     {
     306  for (typename G1::NodeIt n(g1);n!=INVALID;++n){
    247307    check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
    248308    check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
    249309    image.insert(i[n]);
    250     }
    251   for(typename G1::NodeIt n(g1); n!=INVALID; ++n)
    252     for(typename G1::NodeIt m(g1); m!=INVALID; ++m)
    253       if((findEdge(g1,n,m)==INVALID) != (findEdge(g2,i[n],i[m])==INVALID))
    254         {
     310  }
     311  for (typename G1::EdgeIt e(g1);e!=INVALID;++e) {
     312    check(findEdge(g2,i[g1.u(e)],i[g1.v(e)])!=INVALID,
     313          "Wrong isomorphism: missing edge(checkSub).");
     314  }
     315}
     316
     317template<class G1, class G2, class I>
     318void checkIndIso(const G1 &g1, const G2 &g2, const I &i) {
     319  std::set<typename G2::Node> image;
     320  for (typename G1::NodeIt n(g1);n!=INVALID;++n) {
     321    check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
     322    check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
     323    image.insert(i[n]);
     324  }
     325  for (typename G1::NodeIt n(g1); n!=INVALID; ++n) {
     326    for (typename G1::NodeIt m(g1); m!=INVALID; ++m) {
     327      if((findEdge(g1,n,m)==INVALID) != (findEdge(g2,i[n],i[m])==INVALID)) {
    255328        std::cout << "Wrong isomorphism: edge mismatch";
    256329        exit(1);
    257         }
    258   }
    259 
    260 template<class G1,class G2>
    261 int checkSub(const G1 &g1, const G2 &g2)
    262 {
     330      }
     331    }
     332  }
     333}
     334
     335template<class G1,class G2,class T>
     336bool checkSub(const G1 &g1, const G2 &g2, const T &vf2) {
    263337  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
    264   if(vf2(g1,g2).mapping(iso).run())
    265     {
    266       checkSub(g1,g2,iso);
    267       return true;
    268     }
    269   else return false;
    270 }
    271 
    272 template<class G1,class G2>
    273 int checkInd(const G1 &g1, const G2 &g2)
    274 {
     338  if (const_cast<T&>(vf2).mapping(iso).run()) {
     339    checkSubIso(g1,g2,iso);
     340    return true;
     341  }
     342  return false;
     343}
     344
     345template<class G1,class G2,class T>
     346bool checkInd(const G1 &g1, const G2 &g2, const T &vf2) {
    275347  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
    276   if(vf2(g1,g2).induced().mapping(iso).run())
    277     {
    278       checkInd(g1,g2,iso);
    279       return true;
    280     }
    281   else return false;
    282 }
    283 
    284 template<class G1,class G2>
    285 int checkIso(const G1 &g1, const G2 &g2)
    286 {
     348  if (const_cast<T&>(vf2).induced().mapping(iso).run()) {
     349    checkIndIso(g1,g2,iso);
     350    return true;
     351  }
     352  return false;
     353}
     354
     355template<class G1,class G2,class T>
     356bool checkIso(const G1 &g1, const G2 &g2, const T &vf2) {
    287357  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
    288   if(vf2(g1,g2).iso().mapping(iso).run())
    289     {
    290       check(countNodes(g1)==countNodes(g2),
    291             "Wrong iso alg.: they are not isomophic.");
    292       checkInd(g1,g2,iso);
    293       return true;
    294     }
    295   else return false;
     358  if (const_cast<T&>(vf2).iso().mapping(iso).run()) {
     359    check(countNodes(g1)==countNodes(g2),
     360          "Wrong iso alg.: they are not isomophic.");
     361    checkIndIso(g1,g2,iso);
     362    return true;
     363  }
     364  return false;
    296365}
    297366
    298367template<class G1, class G2, class L1, class L2, class I>
    299368void checkLabel(const G1 &g1, const G2 &,
    300                 const L1 &l1, const L2 &l2,const I &i)
    301 {
    302   for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    303     {
    304       check(l1[n]==l2[i[n]],"Wrong isomorphism: label mismatch.");
    305     }
     369                const L1 &l1, const L2 &l2, const I &i) {
     370  for (typename G1::NodeIt n(g1);n!=INVALID;++n) {
     371    check(l1[n]==l2[i[n]],"Wrong isomorphism: label mismatch.");
     372  }
     373}
     374
     375template<class G1,class G2,class L1,class L2,class T>
     376bool checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2, const T &vf2) {
     377  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     378  if (const_cast<T&>(vf2).nodeLabels(l1,l2).mapping(iso).run()){
     379    checkSubIso(g1,g2,iso);
     380    checkLabel(g1,g2,l1,l2,iso);
     381    return true;
     382  }
     383  return false;
     384}
     385
     386template<class G1,class G2>
     387void checkSub(const G1 &g1, const G2 &g2, bool expected, const char* msg) {
     388  check(checkSub(g1,g2,vf2(g1,g2)) == expected, msg);
     389  check(checkSub(g1,g2,vf2pp(g1,g2)) == expected, msg);
     390}
     391
     392template<class G1,class G2>
     393void checkInd(const G1 &g1, const G2 &g2, bool expected, const char* msg) {
     394  check(checkInd(g1,g2,vf2(g1,g2)) == expected, msg);
     395  check(checkInd(g1,g2,vf2pp(g1,g2)) == expected, msg);
     396}
     397
     398template<class G1,class G2>
     399void checkIso(const G1 &g1, const G2 &g2, bool expected, const char* msg) {
     400  check(checkIso(g1,g2,vf2(g1,g2)) == expected, msg);
     401  check(checkIso(g1,g2,vf2pp(g1,g2)) == expected, msg);
    306402}
    307403
    308404template<class G1,class G2,class L1,class L2>
    309 int checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2)
    310 {
    311   typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
    312   if(vf2(g1,g2).nodeLabels(l1,l2).mapping(iso).run())
    313     {
    314       checkSub(g1,g2,iso);
    315       checkLabel(g1,g2,l1,l2,iso);
    316       return true;
    317     }
    318   else return false;
     405void checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2, bool expected, const char* msg) {
     406  check(checkSub(g1,g2,l1,l2,vf2(g1,g2)) == expected, msg);
     407  check(checkSub(g1,g2,l1,l2,vf2pp(g1,g2)) == expected, msg);
    319408}
    320409
    321410int main() {
    322411  make_graphs();
    323   check(checkSub(c5,petersen), "There should exist a C5->Petersen mapping.");
    324   check(!checkSub(c7,petersen),
    325         "There should not exist a C7->Petersen mapping.");
    326   check(checkSub(p10,petersen), "There should exist a P10->Petersen mapping.");
    327   check(!checkSub(c10,petersen),
    328         "There should not exist a C10->Petersen mapping.");
    329   check(checkSub(petersen,petersen),
    330         "There should exist a Petersen->Petersen mapping.");
    331 
    332   check(checkInd(c5,petersen),
    333         "There should exist a C5->Petersen spanned mapping.");
    334   check(!checkInd(c7,petersen),
    335         "There should exist a C7->Petersen spanned mapping.");
    336   check(!checkInd(p10,petersen),
    337         "There should not exist a P10->Petersen spanned mapping.");
    338   check(!checkInd(c10,petersen),
    339         "There should not exist a C10->Petersen spanned mapping.");
    340   check(checkInd(petersen,petersen),
     412
     413  checkSub(c5,petersen,true,
     414      "There should exist a C5->Petersen mapping.");
     415  checkSub(c7,petersen,false,
     416      "There should not exist a C7->Petersen mapping.");
     417  checkSub(p10,petersen,true,
     418      "There should exist a P10->Petersen mapping.");
     419  checkSub(c10,petersen,false,
     420      "There should not exist a C10->Petersen mapping.");
     421  checkSub(petersen,petersen,true,
     422      "There should exist a Petersen->Petersen mapping.");
     423
     424  checkInd(c5,petersen,true,
     425      "There should exist a C5->Petersen spanned mapping.");
     426  checkInd(c7,petersen,false,
     427      "There should exist a C7->Petersen spanned mapping.");
     428  checkInd(p10,petersen,false,
     429      "There should not exist a P10->Petersen spanned mapping.");
     430  checkInd(c10,petersen,false,
     431      "There should not exist a C10->Petersen spanned mapping.");
     432  checkInd(petersen,petersen,true,
    341433        "There should exist a Petersen->Petersen spanned mapping.");
    342434
    343   check(!checkSub(petersen,c10),
    344         "There should not exist a Petersen->C10 mapping.");
    345   check(checkSub(p10,c10),
    346         "There should exist a P10->C10 mapping.");
    347   check(!checkInd(p10,c10),
    348         "There should not exist a P10->C10 spanned mapping.");
    349   check(!checkSub(c10,p10),
    350         "There should not exist a C10->P10 mapping.");
    351 
    352   check(!checkIso(p10,c10),
    353         "P10 and C10 are not isomorphic.");
    354   check(checkIso(c10,c10),
    355         "C10 and C10 are isomorphic.");
    356 
    357   check(!vf2(p10,c10).iso().run(),
    358         "P10 and C10 are not isomorphic.");
    359   check(vf2(c10,c10).iso().run(),
    360         "C10 and C10 are isomorphic.");
    361 
    362   check(!checkSub(c5,petersen,c5_col,petersen_col1),
    363         "There should exist a C5->Petersen mapping.");
    364   check(checkSub(c5,petersen,c5_col,petersen_col2),
    365         "There should exist a C5->Petersen mapping.");
    366 }
     435  checkSub(petersen,c10,false,
     436      "There should not exist a Petersen->C10 mapping.");
     437  checkSub(p10,c10,true,
     438      "There should exist a P10->C10 mapping.");
     439  checkInd(p10,c10,false,
     440      "There should not exist a P10->C10 spanned mapping.");
     441  checkSub(c10,p10,false,
     442      "There should not exist a C10->P10 mapping.");
     443
     444  checkIso(p10,c10,false,
     445      "P10 and C10 are not isomorphic.");
     446  checkIso(c10,c10,true,
     447      "C10 and C10 are isomorphic.");
     448
     449  checkSub(c5,petersen,c5_col,petersen_col1,false,
     450      "There should exist a C5->Petersen mapping.");
     451  checkSub(c5,petersen,c5_col,petersen_col2,true,
     452      "There should exist a C5->Petersen mapping.");
     453
     454  check(!vf2(p10,c10).iso().run(), "P10 and C10 are not isomorphic.");
     455  check(!vf2pp(p10,c10).iso().run(), "P10 and C10 are not isomorphic.");
     456
     457  check(vf2(c10,c10).iso().run(), "C10 and C10 are isomorphic.");
     458  check(vf2pp(c10,c10).iso().run(), "C10 and C10 are isomorphic.");
     459}
Note: See TracChangeset for help on using the changeset viewer.