COIN-OR::LEMON - Graph Library

Ticket #597: 3feba0ea1bda.patch

File 3feba0ea1bda.patch, 76.6 KB (added by Alpar Juttner, 2 years ago)
  • new file lemon/bits/vf2_internals.h

    # HG changeset patch
    # User Peter Madarasi <madarasip@caesar.elte.hu>
    # Date 1505822900 -7200
    #      Tue Sep 19 14:08:20 2017 +0200
    # Node ID 3feba0ea1bdac112e99996191ebe7760d5480f1b
    # Parent  bc571f16e1e998989a2d6357b304c78dd27d5fd7
    Vf2 improvements and Vf2pp implementation (#597)
    
    diff --git a/lemon/bits/vf2_internals.h b/lemon/bits/vf2_internals.h
    new file mode 100644
    - +  
     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 VF2_INTERNALS_H
     19#define VF2_INTERNALS_H
     20
     21
     22///\ingroup graph_properties
     23///\file
     24///\brief Mapping types for graph matching algorithms.
     25
     26namespace lemon {
     27  ///\ingroup graph_isomorphism
     28  ///The \ref Vf2 "VF2" algorithm is capable of finding different kind of
     29  ///embeddings, this enum specifies its type.
     30  ///
     31  ///See \ref graph_isomorphism for a more detailed description.
     32  enum MappingType {
     33    /// Subgraph isomorphism
     34    SUBGRAPH = 0,
     35    /// Induced subgraph isomorphism
     36    INDUCED = 1,
     37    /// Graph isomorphism
     38
     39    /// If the two graph has the same number of nodes, than it is
     40    /// equivalent to \ref INDUCED, and if they also have the same
     41    /// number of edges, then it is also equivalent to \ref SUBGRAPH.
     42    ///
     43    /// However, using this setting is faster than the other two
     44    /// options.
     45    ISOMORPH = 2
     46  };
     47}
     48#endif
  • lemon/vf2.h

    diff --git a/lemon/vf2.h b/lemon/vf2.h
    a b  
    22 *
    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 *
    88 * Permission to use, modify and distribute this software is granted
     
    2626#include <lemon/concepts/graph.h>
    2727#include <lemon/dfs.h>
    2828#include <lemon/bfs.h>
     29#include <lemon/bits/vf2_internals.h>
    2930
    3031#include <vector>
    31 #include <set>
    3232
    33 namespace lemon
    34 {
    35   namespace bits
    36   {
    37     namespace vf2
    38     {
    39       class AlwaysEq
    40       {
     33namespace lemon {
     34  namespace bits {
     35    namespace vf2 {
     36
     37      class AlwaysEq {
    4138      public:
    4239        template<class T1, class T2>
    43         bool operator()(T1, T2) const
    44         {
     40        bool operator()(T1&, T2&) const {
    4541          return true;
    4642        }
    4743      };
    4844
    4945      template<class M1, class M2>
    50       class MapEq
    51       {
     46      class MapEq{
    5247        const M1 &_m1;
    5348        const M2 &_m2;
    5449      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         {
     50        MapEq(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) { }
     51        bool operator()(typename M1::Key k1, typename M2::Key k2) const {
    5852          return _m1[k1] == _m2[k2];
    5953        }
    6054      };
    6155
     56
     57
    6258      template <class G>
    63       class DfsLeaveOrder : public DfsVisitor<G>
    64       {
     59      class DfsLeaveOrder : public DfsVisitor<G> {
    6560        const G &_g;
    6661        std::vector<typename G::Node> &_order;
    6762        int i;
    6863      public:
    6964        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         {
     65          : i(countNodes(g)), _g(g), _order(order) { }
     66        void leave(const typename G::Node &node) {
    7467          _order[--i]=node;
    7568        }
    7669      };
    7770
    7871      template <class G>
    79       class BfsLeaveOrder : public BfsVisitor<G>
    80       {
     72      class BfsLeaveOrder : public BfsVisitor<G> {
    8173        int i;
    8274        const G &_g;
    8375        std::vector<typename G::Node> &_order;
    8476      public:
    8577        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         {
     78          : i(0), _g(g), _order(order){
     79        }
     80        void process(const typename G::Node &node) {
    9081          _order[i++]=node;
    9182        }
    9283      };
    9384    }
    9485  }
    9586
    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   };
    11887
    11988  ///%VF2 algorithm class.
    12089
     
    144113           class M = typename G1::template NodeMap<G2::Node>,
    145114           class NEQ = bits::vf2::AlwaysEq >
    146115#endif
    147   class Vf2
    148   {
     116  class Vf2 {
    149117    //Current depth in the DFS tree.
    150118    int _depth;
    151119    //Functor with bool operator()(G1::Node,G2::Node), which returns 1
    152     //if and only if the 2 nodes are equivalent.
     120    //ifff the two nodes are equivalent.
    153121    NEQ _nEq;
    154122
    155123    typename G2::template NodeMap<int> _conn;
    156124    //Current mapping. We index it by the nodes of g1, and match[v] is
    157125    //a node of g2.
    158126    M &_mapping;
    159     //order[i] is the node of g1, for which we find a pair if depth=i
     127    //order[i] is the node of g1, for which we search a pair if depth=i
    160128    std::vector<typename G1::Node> order;
    161129    //currEdgeIts[i] is an edge iterator, witch is last used in the ith
    162130    //depth to find a pair for order[i].
    163131    std::vector<typename G2::IncEdgeIt> currEdgeIts;
    164132    //The small graph.
    165133    const G1 &_g1;
    166     //The big graph.
     134    //The large graph.
    167135    const G2 &_g2;
    168     //lookup tables for cut the searchtree
     136    //lookup tables for cutting the searchtree
    169137    typename G1::template NodeMap<int> rNew1t,rInOut1t;
    170138
    171     Vf2MappingType _mapping_type;
     139    MappingType _mapping_type;
     140
     141    bool _deallocMappingAfterUse;
    172142
    173143    //cut the search tree
    174     template<Vf2MappingType MT>
    175     bool cut(const typename G1::Node n1,const typename G2::Node n2) const
    176     {
     144    template<MappingType MT>
     145    bool cut(const typename G1::Node n1,const typename G2::Node n2) const {
    177146      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         }
     147      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     148        const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
     149        if(_conn[currNode]>0)
     150          ++rInOut2;
     151        else if(MT!=SUBGRAPH&&_conn[currNode]==0)
     152          ++rNew2;
     153      }
     154      switch(MT) {
     155      case INDUCED:
     156        return rInOut1t[n1]<=rInOut2&&rNew1t[n1]<=rNew2;
     157      case SUBGRAPH:
     158        return rInOut1t[n1]<=rInOut2;
     159      case ISOMORPH:
     160        return rInOut1t[n1]==rInOut2&&rNew1t[n1]==rNew2;
     161      default:
     162        return false;
     163      }
    197164    }
    198165
    199     template<Vf2MappingType MT>
    200     bool feas(const typename G1::Node n1,const typename G2::Node n2)
    201     {
     166    template<MappingType MT>
     167    bool feas(const typename G1::Node n1,const typename G2::Node n2) {
    202168      if(!_nEq(n1,n2))
    203169        return 0;
    204170
    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]];
     171      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
     172        const typename G1::Node& currNode=_g1.oppositeNode(n1,e1);
     173        if(_mapping[currNode]!=INVALID)
     174          --_conn[_mapping[currNode]];
     175      }
     176      bool isIso=1;
     177      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     178        int& connCurrNode = _conn[_g2.oppositeNode(n2,e2)];
     179        if(connCurrNode<-1)
     180          ++connCurrNode;
     181        else if(MT!=SUBGRAPH&&connCurrNode==-1) {
     182          isIso=0;
     183          break;
    210184        }
    211       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             {
     185      }
     186
     187      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
     188        const typename G2::Node& currNodePair=_mapping[_g1.oppositeNode(n1,e1)];
     189        int& connCurrNodePair=_conn[currNodePair];
     190        if(currNodePair!=INVALID&&connCurrNodePair!=-1) {
     191          switch(MT) {
     192          case INDUCED:
     193          case ISOMORPH:
     194            isIso=0;
     195            break;
     196          case SUBGRAPH:
     197            if(connCurrNodePair<-1)
    219198              isIso=0;
    220               break;
    221             }
     199            break;
     200          }
     201          connCurrNodePair=-1;
    222202        }
    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         }
     203      }
    243204      return isIso&&cut<MT>(n1,n2);
    244205    }
    245206
    246     void addPair(const typename G1::Node n1,const typename G2::Node n2)
    247     {
     207    void addPair(const typename G1::Node n1,const typename G2::Node n2) {
    248208      _conn[n2]=-1;
    249209      _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)];
     210      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     211        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
     212        if(currConn!=-1)
     213          ++currConn;
     214      }
    253215    }
    254216
    255     void subPair(const typename G1::Node n1,const typename G2::Node n2)
    256     {
     217    void subPair(const typename G1::Node n1,const typename G2::Node n2) {
    257218      _conn[n2]=0;
    258219      _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         }
     220      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
     221        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
     222        if(currConn>0)
     223          --currConn;
     224        else if(currConn==-1)
     225          ++_conn[n2];
     226      }
    267227    }
    268228
    269     void setOrder()//we will find pairs for the nodes of g1 in this order
    270     {
     229    void setOrder() {
     230      // we will find pairs for the nodes of g1 in this order
     231
    271232      // bits::vf2::DfsLeaveOrder<G1> v(_g1,order);
    272233      //   DfsVisit<G1,bits::vf2::DfsLeaveOrder<G1> >dfs(_g1, v);
    273234      //   dfs.run();
     
    278239      bfs.run();
    279240    }
    280241
    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             {
     242    template<MappingType MT>
     243    bool extMatch() {
     244      while(_depth>=0) {
     245        //there are not nodes in g1, which has not pair in g2.
     246        if(_depth==static_cast<int>(order.size())) {
     247          --_depth;
     248          return true;
     249        }
     250        typename G1::Node& nodeOfDepth = order[_depth];
     251        const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth];
     252        typename G2::IncEdgeIt &edgeItOfDepth = currEdgeIts[_depth];
     253        //the node of g2, which neighbours are the candidates for
     254        //the pair of nodeOfDepth
     255        typename G2::Node currPNode;
     256        if(edgeItOfDepth==INVALID) {
     257          typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth);
     258          //if pairOfNodeOfDepth!=INVALID, we dont use
     259          //fstMatchedE
     260          if(pairOfNodeOfDepth==INVALID)
     261            for(; fstMatchedE!=INVALID &&
     262                  _mapping[_g1.oppositeNode(nodeOfDepth,
     263                                            fstMatchedE)]==INVALID;
     264                ++fstMatchedE) ; //find fstMatchedE
     265          if(fstMatchedE==INVALID||pairOfNodeOfDepth!=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
     269            //to the spec. problem types) node of g2 is
     270            //candidate.  We can read the iterator of the last
     271            //tried node from the match if it is not the first
     272            //try(match[nodeOfDepth]!=INVALID)
     273            typename G2::NodeIt n2(_g2);
     274            //if it's not the first try
     275            if(pairOfNodeOfDepth!=INVALID) {
     276              n2=++typename G2::NodeIt(_g2,pairOfNodeOfDepth);
     277              subPair(nodeOfDepth,pairOfNodeOfDepth);
     278            }
     279            for(; n2!=INVALID; ++n2)
     280              if(MT!=SUBGRAPH) {
     281                if(_conn[n2]==0&&feas<MT>(nodeOfDepth,n2))
     282                  break;
     283              }
     284              else if(_conn[n2]>=0&&feas<MT>(nodeOfDepth,n2))
     285                break;
     286            // n2 is the next candidate
     287            if(n2!=INVALID){
     288              addPair(nodeOfDepth,n2);
     289              ++_depth;
     290            }
     291            else // there are no more candidates
    289292              --_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;
     293            continue;
     294          }
     295          else {
     296            currPNode=_mapping[_g1.oppositeNode(nodeOfDepth,
     297                                                fstMatchedE)];
     298            edgeItOfDepth=typename G2::IncEdgeIt(_g2,currPNode);
     299          }
    366300        }
     301        else {
     302          currPNode=_g2.oppositeNode(pairOfNodeOfDepth,
     303                                     edgeItOfDepth);
     304          subPair(nodeOfDepth,pairOfNodeOfDepth);
     305          ++edgeItOfDepth;
     306        }
     307        for(; edgeItOfDepth!=INVALID; ++edgeItOfDepth) {
     308          const typename G2::Node currNode =
     309            _g2.oppositeNode(currPNode, edgeItOfDepth);
     310          if(_conn[currNode]>0&&feas<MT>(nodeOfDepth,currNode)) {
     311            addPair(nodeOfDepth,currNode);
     312            break;
     313          }
     314        }
     315        edgeItOfDepth==INVALID?--_depth:++_depth;
     316      }
    367317      return false;
    368318    }
    369319
    370320    //calc. the lookup table for cut the searchtree
    371     void setRNew1tRInOut1t()
    372     {
     321    void setRNew1tRInOut1t() {
    373322      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             }
     323      for(unsigned int i=0; i<order.size(); ++i) {
     324        const typename G1::Node& orderI = order[i];
     325        tmp[orderI]=-1;
     326        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
     327          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
     328          if(tmp[currNode]>0)
     329            ++rInOut1t[orderI];
     330          else if(tmp[currNode]==0)
     331            ++rNew1t[orderI];
    391332        }
     333        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
     334          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
     335          if(tmp[currNode]!=-1)
     336            ++tmp[currNode];
     337        }
     338      }
    392339    }
    393340  public:
    394341    ///Constructor
     
    399346    ///\param g2 The graph \e g1 will be embedded into.
    400347    ///\param m \ref concepts::ReadWriteMap "read-write" NodeMap
    401348    ///storing the found mapping.
    402     ///\param neq A bool-valued binary functor determinining whether a node is
     349    ///\param neq A bool-valued binary functor determining whether a node is
    403350    ///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() ) :
     351    Vf2(const G1 &g1, const G2 &g2, M &m, const NEQ &neq = NEQ() ) :
    405352      _nEq(neq), _conn(g2,0), _mapping(m), order(countNodes(g1)),
    406353      currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNew1t(g1,0),
    407       rInOut1t(g1,0), _mapping_type(SUBGRAPH)
    408     {
     354      rInOut1t(g1,0), _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0) {
    409355      _depth=0;
    410356      setOrder();
    411357      setRNew1tRInOut1t();
     
    413359        m[n]=INVALID;
    414360    }
    415361
     362    ///Destructor
     363
     364    ///Destructor.
     365    ///
     366
     367    ~Vf2(){
     368      if(_deallocMappingAfterUse)
     369        delete &_mapping;
     370    }
     371
    416372    ///Returns the current mapping type
    417373
    418374    ///Returns the current mapping type
    419375    ///
    420     Vf2MappingType mappingType() const { return _mapping_type; }
     376    MappingType mappingType() const {
     377      return _mapping_type;
     378    }
    421379    ///Sets mapping type
    422380
    423381    ///Sets mapping type.
    424382    ///
    425383    ///The mapping type is set to \ref SUBGRAPH by default.
    426384    ///
    427     ///\sa See \ref Vf2MappingType for the possible values.
    428     void mappingType(Vf2MappingType m_type) { _mapping_type = m_type; }
     385    ///\sa See \ref MappingType for the possible values.
     386    void mappingType(MappingType m_type) {
     387      _mapping_type = m_type;
     388    }
    429389
    430390    ///Finds a mapping
    431391
    432     ///It finds a mapping between from g1 into g2 according to the mapping
    433     ///type set by \ref mappingType(Vf2MappingType) "mappingType()".
     392    ///It finds a mapping from g1 into g2 according to the mapping
     393    ///type set by \ref mappingType(MappingType) "mappingType()".
    434394    ///
    435395    ///By subsequent calls, it returns all possible mappings one-by-one.
    436396    ///
    437397    ///\retval true if a mapping is found.
    438398    ///\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         }
     399    bool find() {
     400      switch(_mapping_type) {
     401      case SUBGRAPH:
     402        return extMatch<SUBGRAPH>();
     403      case INDUCED:
     404        return extMatch<INDUCED>();
     405      case ISOMORPH:
     406        return extMatch<ISOMORPH>();
     407      default:
     408        return false;
     409      }
    452410    }
    453411  };
    454412
    455413  template<class G1, class G2>
    456   class Vf2WizardBase
    457   {
     414  class Vf2WizardBase {
    458415  protected:
    459416    typedef G1 Graph1;
    460417    typedef G2 Graph2;
     
    462419    const G1 &_g1;
    463420    const G2 &_g2;
    464421
    465     Vf2MappingType _mapping_type;
     422    MappingType _mapping_type;
    466423
    467424    typedef typename G1::template NodeMap<typename G2::Node> Mapping;
    468425    bool _local_mapping;
    469426    void *_mapping;
    470     void createMapping()
    471     {
     427    void createMapping() {
    472428      _mapping = new Mapping(_g1);
    473429    }
    474430
     431    void *myVf2; //used in Vf2Wizard::find
     432
     433
    475434    typedef bits::vf2::AlwaysEq NodeEq;
    476435    NodeEq _node_eq;
    477436
    478437    Vf2WizardBase(const G1 &g1,const G2 &g2)
    479       : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) {}
     438      : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) { }
    480439  };
    481440
     441
    482442  /// Auxiliary class for the function-type interface of %VF2 algorithm.
    483443
    484444  /// This auxiliary class implements the named parameters of
     
    489449  /// \tparam TR The traits class that defines various types used by the
    490450  /// algorithm.
    491451  template<class TR>
    492   class Vf2Wizard : public TR
    493   {
     452  class Vf2Wizard : public TR {
    494453    typedef TR Base;
    495454    typedef typename TR::Graph1 Graph1;
    496455    typedef typename TR::Graph2 Graph2;
     
    506465
    507466  public:
    508467    ///Constructor
    509     Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {}
     468    Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {
     469    }
    510470
    511471    ///Copy constructor
    512     Vf2Wizard(const Base &b) : Base(b) {}
     472    Vf2Wizard(const Base &b) : Base(b) { }
     473
     474    ///Copy constructor
     475    Vf2Wizard(const Vf2Wizard &b) : Base(b) {}
    513476
    514477
    515478    template<class T>
    516     struct SetMappingBase : public Base {
     479    struct SetMappingBase : public Base{
    517480      typedef T Mapping;
    518481      SetMappingBase(const Base &b) : Base(b) {}
    519482    };
     
    524487    ///\ref named-templ-param "Named parameter" function for setting
    525488    ///the map that stores the found embedding.
    526489    template<class T>
    527     Vf2Wizard< SetMappingBase<T> > mapping(const T &t)
    528     {
     490    Vf2Wizard< SetMappingBase<T> > mapping(const T &t) {
    529491      Base::_mapping=reinterpret_cast<void*>(const_cast<T*>(&t));
    530492      Base::_local_mapping = false;
    531493      return Vf2Wizard<SetMappingBase<T> >(*this);
     
    536498      typedef NE NodeEq;
    537499      NodeEq _node_eq;
    538500      SetNodeEqBase(const Base &b, const NE &node_eq)
    539         : Base(b), _node_eq(node_eq) {}
     501        : Base(b), _node_eq(node_eq){
     502      }
    540503    };
    541504
    542505    ///\brief \ref named-templ-param "Named parameter" for setting
     
    549512    ///whether a node is mappable to another. By default it is an
    550513    ///always true operator.
    551514    template<class T>
    552     Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq)
    553     {
     515    Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq) {
    554516      return Vf2Wizard<SetNodeEqBase<T> >(SetNodeEqBase<T>(*this,node_eq));
    555517    }
    556518
     
    560522    ///\ref named-templ-param "Named parameter" function for setting
    561523    ///the node labels defining equivalence relation between them.
    562524    ///
    563     ///\param m1 It is arbitrary \ref concepts::ReadMap "readable node map"
     525    ///\param m1 An arbitrary \ref concepts::ReadMap "readable node map"
    564526    ///of g1.
    565     ///\param m2 It is arbitrary \ref concepts::ReadMap "readable node map"
     527    ///\param m2 An arbitrary \ref concepts::ReadMap "readable node map"
    566528    ///of g2.
    567529    ///
    568530    ///The value type of these maps must be equal comparable.
    569531    template<class M1, class M2>
    570532    Vf2Wizard< SetNodeEqBase<bits::vf2::MapEq<M1,M2> > >
    571     nodeLabels(const M1 &m1,const M2 &m2)
    572     {
     533    nodeLabels(const M1 &m1,const M2 &m2){
    573534      return nodeEq(bits::vf2::MapEq<M1,M2>(m1,m2));
    574535    }
    575536
     
    581542    ///
    582543    ///The mapping type is set to \ref SUBGRAPH by default.
    583544    ///
    584     ///\sa See \ref Vf2MappingType for the possible values.
    585     Vf2Wizard<Base> &mappingType(Vf2MappingType m_type)
    586     {
     545    ///\sa See \ref MappingType for the possible values.
     546    Vf2Wizard<Base> &mappingType(MappingType m_type) {
    587547      _mapping_type = m_type;
    588548      return *this;
    589549    }
     
    593553    ///
    594554    ///\ref named-templ-param "Named parameter" for setting
    595555    ///the mapping type to \ref INDUCED.
    596     Vf2Wizard<Base> &induced()
    597     {
     556    Vf2Wizard<Base> &induced() {
    598557      _mapping_type = INDUCED;
    599558      return *this;
    600559    }
     
    604563    ///
    605564    ///\ref named-templ-param "Named parameter" for setting
    606565    ///the mapping type to \ref ISOMORPH.
    607     Vf2Wizard<Base> &iso()
    608     {
     566    Vf2Wizard<Base> &iso() {
    609567      _mapping_type = ISOMORPH;
    610568      return *this;
    611569    }
    612570
     571
    613572    ///Runs VF2 algorithm.
    614573
    615574    ///This method runs VF2 algorithm.
    616575    ///
    617576    ///\retval true if a mapping is found.
    618     ///\retval false if there is no (more) mapping.
    619     bool run()
    620     {
     577    ///\retval false if there is no mapping.
     578    bool run(){
    621579      if(Base::_local_mapping)
    622580        Base::createMapping();
    623581
     
    633591
    634592      return ret;
    635593    }
     594
     595    ///Get a pointer to the generated Vf2 object.
     596
     597    ///Gives a pointer to the generated Vf2 object.
     598    ///
     599    ///\return Pointer to the generated Vf2 object.
     600    ///\warning Don't forget to delete the referred Vf2 object after use.
     601    Vf2<Graph1, Graph2, Mapping, NodeEq >* getPtrToVf2Object() {
     602      if(Base::_local_mapping)
     603        Base::createMapping();
     604      Vf2<Graph1, Graph2, Mapping, NodeEq >* ptr =
     605        new Vf2<Graph1, Graph2, Mapping, NodeEq>
     606        (_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
     607      ptr->mappingType(_mapping_type);
     608      if(Base::_local_mapping)
     609        ptr->_deallocMappingAfterUse = true;
     610      return ptr;
     611    }
     612
     613    ///Counts the number of mappings.
     614
     615    ///This method counts the number of mappings.
     616    ///
     617    /// \return The number of mappings.
     618    int count() {
     619      if(Base::_local_mapping)
     620        Base::createMapping();
     621
     622      Vf2<Graph1, Graph2, Mapping, NodeEq>
     623        alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
     624      if(Base::_local_mapping)
     625        alg._deallocMappingAfterUse = true;
     626      alg.mappingType(_mapping_type);
     627
     628      int ret = 0;
     629      while(alg.find())
     630        ++ret;
     631
     632      return ret;
     633    }
    636634  };
    637635
    638636  ///Function-type interface for VF2 algorithm.
     
    644642  ///declared as the members of class \ref Vf2Wizard.
    645643  ///The following examples show how to use these parameters.
    646644  ///\code
    647   ///  // Find an embedding of graph g into graph h
     645  ///  // Find an embedding of graph g1 into graph g2
    648646  ///  ListGraph::NodeMap<ListGraph::Node> m(g);
    649   ///  vf2(g,h).mapping(m).run();
     647  ///  vf2(g1,g2).mapping(m).run();
    650648  ///
    651   ///  // Check whether graphs g and h are isomorphic
    652   ///  bool is_iso = vf2(g,h).iso().run();
     649  ///  // Check whether graphs g1 and g2 are isomorphic
     650  ///  bool is_iso = vf2(g1,g2).iso().run();
     651  ///
     652  ///  // Count the number of isomorphisms
     653  ///  int num_isos = vf2(g1,g2).iso().count();
     654  ///
     655  ///  // Iterate through all the induced subgraph mappings of graph g1 into g2
     656  ///  auto* myVf2 = vf2(g1,g2).mapping(m).nodeLabels(c1,c2)
     657  ///  .induced().getPtrToVf2Object();
     658  ///  while(myVf2->find()){
     659  ///    //process the current mapping m
     660  ///  }
     661  ///  delete myVf22;
    653662  ///\endcode
    654   ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()"
     663  ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()",
     664  ///\ref Vf2Wizard::count() "count()" or
     665  ///the \ref Vf2Wizard::getPtrToVf2Object() "getPtrToVf2Object()"
    655666  ///to the end of the expression.
    656667  ///\sa Vf2Wizard
    657668  ///\sa Vf2
    658669  template<class G1, class G2>
    659   Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2)
    660   {
     670  Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2) {
    661671    return Vf2Wizard<Vf2WizardBase<G1,G2> >(g1,g2);
    662672  }
    663673
  • new file lemon/vf2pp.h

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

    diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
    a b  
    5555  tsp_test
    5656  unionfind_test
    5757  vf2_test
     58  vf2pp_test
    5859)
    5960
    6061IF(LEMON_HAVE_LP)
  • test/vf2_test.cc

    diff --git a/test/vf2_test.cc b/test/vf2_test.cc
    a b  
    22 *
    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 *
    88 * Permission to use, modify and distribute this software is granted
     
    183183
    184184class EqComparable {
    185185public:
    186   bool operator==(const EqComparable&) { return false; }
     186  bool operator==(const EqComparable&) {
     187    return false;
     188  }
    187189};
    188190
    189191template<class A, class B>
    190192class EqClass {
    191193public:
    192   bool operator()(A, B) { return false; }
     194  bool operator()(A, B){
     195    return false;
     196  }
    193197};
    194198
    195199template<class G1,class G2>
    196 void checkVf2Compile()
    197 {
     200void checkVf2Compile() {
    198201  G1 g;
    199202  G2 h;
    200203  concepts::ReadWriteMap<typename G1::Node, typename G2::Node> r;
     
    205208  succ = vf2(g,h).induced().run();
    206209  succ = vf2(g,h).iso().run();
    207210  succ = vf2(g,h).mapping(r).run();
     211
     212  Vf2<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     213      EqClass<typename G1::Node,typename G2::Node> >
     214    myVf2(g,h,r,EqClass<typename G1::Node,typename G2::Node>());
     215  myVf2.find();
     216
    208217  succ = vf2(g,h).induced().mapping(r).run();
    209218  succ = vf2(g,h).iso().mapping(r).run();
     219
    210220  concepts::ReadMap<typename G1::Node, EqComparable> l1;
    211221  concepts::ReadMap<typename G2::Node, EqComparable> l2;
    212222  succ = vf2(g,h).nodeLabels(l1,l2).mapping(r).run();
     
    214224    .mapping(r).run();
    215225}
    216226
    217 void justCompile()
    218 {
     227void justCompile() {
    219228  checkVf2Compile<concepts::Graph,concepts::Graph>();
    220229  checkVf2Compile<concepts::Graph,SmartGraph>();
    221230  checkVf2Compile<SmartGraph,concepts::Graph>();
    222231}
    223232
    224233template<class G1, class G2, class I>
    225 void checkSub(const G1 &g1, const G2 &g2, const I &i)
    226 {
     234void checkSub(const G1 &g1, const G2 &g2, const I &i) {
    227235  {
    228236    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       }
     237    for(typename G1::NodeIt n(g1);n!=INVALID;++n){
     238      check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
     239      check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
     240      image.insert(i[n]);
     241    }
    235242  }
    236243  for(typename G1::EdgeIt e(g1);e!=INVALID;++e)
    237244    check(findEdge(g2,i[g1.u(e)],i[g1.v(e)])!=INVALID,
     
    239246}
    240247
    241248template<class G1, class G2, class I>
    242 void checkInd(const G1 &g1, const G2 &g2, const I &i)
    243   {
     249void checkInd(const G1 &g1, const G2 &g2, const I &i) {
    244250  std::set<typename G2::Node> image;
    245   for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    246     {
     251  for(typename G1::NodeIt n(g1);n!=INVALID;++n) {
    247252    check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
    248253    check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
    249254    image.insert(i[n]);
    250     }
     255  }
    251256  for(typename G1::NodeIt n(g1); n!=INVALID; ++n)
    252257    for(typename G1::NodeIt m(g1); m!=INVALID; ++m)
    253       if((findEdge(g1,n,m)==INVALID) != (findEdge(g2,i[n],i[m])==INVALID))
    254         {
     258      if((findEdge(g1,n,m)==INVALID) != (findEdge(g2,i[n],i[m])==INVALID)) {
    255259        std::cout << "Wrong isomorphism: edge mismatch";
    256260        exit(1);
    257         }
    258   }
    259 
    260 template<class G1,class G2>
    261 int checkSub(const G1 &g1, const G2 &g2)
    262 {
    263   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;
     261      }
    270262}
    271263
    272264template<class G1,class G2>
    273 int checkInd(const G1 &g1, const G2 &g2)
    274 {
     265int checkSub(const G1 &g1, const G2 &g2) {
    275266  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;
     267  if(vf2(g1,g2).mapping(iso).run()) {
     268    checkSub(g1,g2,iso);
     269    return true;
     270  }
     271  else
     272    return false;
    282273}
    283274
    284275template<class G1,class G2>
    285 int checkIso(const G1 &g1, const G2 &g2)
    286 {
     276int checkInd(const G1 &g1, const G2 &g2) {
    287277  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;
     278  if(vf2(g1,g2).induced().mapping(iso).run()) {
     279    checkInd(g1,g2,iso);
     280    return true;
     281  }
     282  else
     283    return false;
     284}
     285
     286template<class G1,class G2>
     287int checkIso(const G1 &g1, const G2 &g2) {
     288  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     289  if(vf2(g1,g2).iso().mapping(iso).run()) {
     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
     296    return false;
    296297}
    297298
    298299template<class G1, class G2, class L1, class L2, class I>
    299300void checkLabel(const G1 &g1, const G2 &,
    300                 const L1 &l1, const L2 &l2,const I &i)
    301 {
     301                const L1 &l1, const L2 &l2,const I &i) {
    302302  for(typename G1::NodeIt n(g1);n!=INVALID;++n)
    303     {
    304       check(l1[n]==l2[i[n]],"Wrong isomorphism: label mismatch.");
    305     }
     303    check(l1[n]==l2[i[n]],"Wrong isomorphism: label mismatch.");
    306304}
    307305
    308306template<class G1,class G2,class L1,class L2>
    309 int checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2)
    310 {
     307int checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2) {
    311308  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;
     309  if(vf2(g1,g2).nodeLabels(l1,l2).mapping(iso).run()){
     310    checkSub(g1,g2,iso);
     311    checkLabel(g1,g2,l1,l2,iso);
     312    return true;
     313  }
     314  else
     315    return false;
    319316}
    320317
    321318int main() {
    322319  make_graphs();
     320  //   justCompile();
    323321  check(checkSub(c5,petersen), "There should exist a C5->Petersen mapping.");
    324322  check(!checkSub(c7,petersen),
    325323        "There should not exist a C7->Petersen mapping.");
  • new file test/vf2pp_test.cc

    diff --git a/test/vf2pp_test.cc b/test/vf2pp_test.cc
    new file mode 100644
    - +  
     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#include <lemon/vf2pp.h>
     19#include <lemon/concepts/digraph.h>
     20#include <lemon/smart_graph.h>
     21#include <lemon/lgf_reader.h>
     22#include <lemon/concepts/maps.h>
     23#include <lemon/maps.h>
     24#include <lemon/list_graph.h>
     25
     26#include <test/test_tools.h>
     27#include <sstream>
     28
     29using namespace lemon;
     30
     31char petersen_lgf[] =
     32  "@nodes\n"
     33  "label col1 col2\n"
     34  "0 1 1\n"
     35  "1 1 2\n"
     36  "2 1 3\n"
     37  "3 1 4\n"
     38  "4 2 5\n"
     39  "5 2 1\n"
     40  "6 2 2\n"
     41  "7 2 3\n"
     42  "8 2 4\n"
     43  "9 2 5\n"
     44  "@arcs\n"
     45  "     -\n"
     46  "0 1\n"
     47  "1 2\n"
     48  "2 3\n"
     49  "3 4\n"
     50  "4 0\n"
     51  "0 5\n"
     52  "1 6\n"
     53  "2 7\n"
     54  "3 8\n"
     55  "4 9\n"
     56  "5 8\n"
     57  "5 7\n"
     58  "9 6\n"
     59  "9 7\n"
     60  "6 8\n";
     61
     62char c5_lgf[] =
     63  "@nodes\n"
     64  "label col\n"
     65  "0 1\n"
     66  "1 2\n"
     67  "2 3\n"
     68  "3 4\n"
     69  "4 5\n"
     70  "@arcs\n"
     71  "     -\n"
     72  "0 1\n"
     73  "1 2\n"
     74  "2 3\n"
     75  "3 4\n"
     76  "4 0\n";
     77
     78char c7_lgf[] =
     79  "@nodes\n"
     80  "label\n"
     81  "0\n"
     82  "1\n"
     83  "2\n"
     84  "3\n"
     85  "4\n"
     86  "5\n"
     87  "6\n"
     88  "@arcs\n"
     89  "     -\n"
     90  "0 1\n"
     91  "1 2\n"
     92  "2 3\n"
     93  "3 4\n"
     94  "4 5\n"
     95  "5 6\n"
     96  "6 0\n";
     97
     98char c10_lgf[] =
     99  "@nodes\n"
     100  "label\n"
     101  "0\n"
     102  "1\n"
     103  "2\n"
     104  "3\n"
     105  "4\n"
     106  "5\n"
     107  "6\n"
     108  "7\n"
     109  "8\n"
     110  "9\n"
     111  "@arcs\n"
     112  "     -\n"
     113  "0 1\n"
     114  "1 2\n"
     115  "2 3\n"
     116  "3 4\n"
     117  "4 5\n"
     118  "5 6\n"
     119  "6 7\n"
     120  "7 8\n"
     121  "8 9\n"
     122  "9 0\n";
     123
     124char p10_lgf[] =
     125  "@nodes\n"
     126  "label\n"
     127  "0\n"
     128  "1\n"
     129  "2\n"
     130  "3\n"
     131  "4\n"
     132  "5\n"
     133  "6\n"
     134  "7\n"
     135  "8\n"
     136  "9\n"
     137  "@arcs\n"
     138  "     -\n"
     139  "0 1\n"
     140  "1 2\n"
     141  "2 3\n"
     142  "3 4\n"
     143  "4 5\n"
     144  "5 6\n"
     145  "6 7\n"
     146  "7 8\n"
     147  "8 9\n";
     148
     149SmartGraph petersen, c5, c7, c10, p10;
     150SmartGraph::NodeMap<int> petersen_col1(petersen);
     151SmartGraph::NodeMap<int> petersen_col2(petersen);
     152SmartGraph::NodeMap<int> c5_col(c5);
     153
     154void make_graphs(){
     155  std::stringstream ss(petersen_lgf);
     156  graphReader(petersen, ss)
     157    .nodeMap("col1",petersen_col1)
     158    .nodeMap("col2",petersen_col2)
     159    .run();
     160
     161  ss.clear();
     162  ss.str("");
     163  ss<<c5_lgf;
     164
     165  graphReader(c5, ss)
     166    .nodeMap("col",c5_col)
     167    .run();
     168
     169  ss.clear();
     170  ss.str("");
     171  ss<<c7_lgf;
     172  graphReader(c7, ss).run();
     173
     174  ss.clear();
     175  ss.str("");
     176  ss<<c10_lgf;
     177  graphReader(c10, ss).run();
     178
     179  ss.clear();
     180  ss.str("");
     181  ss<<p10_lgf;
     182  graphReader(p10, ss).run();
     183
     184}
     185
     186class IntConvertible1{
     187public:
     188  operator int(){
     189    return 0;
     190  }
     191};
     192
     193class IntConvertible2{
     194public:
     195  operator int(){
     196    return 0;
     197  }
     198};
     199
     200template<class G1,class G2>
     201void checkVf2Compile() {
     202  G1 g;
     203  G2 h;
     204  concepts::ReadWriteMap<typename G1::Node, typename G2::Node> r;
     205  bool succ;
     206  ::lemon::ignore_unused_variable_warning(succ);
     207
     208  succ = vf2pp(g,h).run();
     209  succ = vf2pp(g,h).induced().run();
     210  succ = vf2pp(g,h).iso().run();
     211  succ = vf2pp(g,h).mapping(r).run();
     212  succ = vf2pp(g,h).induced().mapping(r).run();
     213  succ = vf2pp(g,h).iso().mapping(r).run();
     214
     215
     216  concepts::ReadMap<typename G1::Node, int> c1;
     217  concepts::ReadMap<typename G2::Node, int> c2;
     218  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     219        concepts::ReadMap<typename G1::Node, int>,
     220        concepts::ReadMap<typename G2::Node, int> >
     221    myVf2pp(g,h,r,c1,c2);
     222  myVf2pp.find();
     223
     224  succ = vf2pp(g,h).nodeLabels(c1,c2).mapping(r).run();
     225  succ = vf2pp(g,h).nodeLabels(c1,c2)
     226    .mapping(r).run();
     227
     228
     229  concepts::ReadMap<typename G1::Node, char> c1_c;
     230  concepts::ReadMap<typename G2::Node, char> c2_c;
     231  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     232        concepts::ReadMap<typename G1::Node, char>,
     233        concepts::ReadMap<typename G2::Node, char> >
     234    myVf2pp_c(g,h,r,c1_c,c2_c);
     235  myVf2pp_c.find();
     236
     237  succ = vf2pp(g,h).nodeLabels(c1_c,c2_c).mapping(r).run();
     238  succ = vf2pp(g,h).nodeLabels(c1_c,c2_c)
     239    .mapping(r).run();
     240
     241
     242  concepts::ReadMap<typename G1::Node, IntConvertible1> c1_IntConv;
     243  concepts::ReadMap<typename G2::Node, IntConvertible2> c2_IntConv;
     244  Vf2pp<G1,G2,concepts::ReadWriteMap<typename G1::Node, typename G2::Node>,
     245        concepts::ReadMap<typename G1::Node, IntConvertible1>,
     246        concepts::ReadMap<typename G2::Node, IntConvertible2> >
     247    myVf2pp_IntConv(g,h,r,c1_IntConv,c2_IntConv);
     248  myVf2pp_IntConv.find();
     249
     250  succ = vf2pp(g,h).nodeLabels(c1_IntConv,c2_IntConv).mapping(r).run();
     251  succ = vf2pp(g,h).nodeLabels(c1_IntConv,c2_IntConv)
     252    .mapping(r).run();
     253}
     254
     255void justCompile() {
     256  checkVf2Compile<concepts::Graph,concepts::Graph>();
     257  checkVf2Compile<concepts::Graph,SmartGraph>();
     258  checkVf2Compile<SmartGraph,concepts::Graph>();
     259}
     260
     261template<class G1, class G2, class I>
     262void checkSub(const G1 &g1, const G2 &g2, const I &i) {
     263  {
     264    std::set<typename G2::Node> image;
     265    for(typename G1::NodeIt n(g1);n!=INVALID;++n){
     266      check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
     267      check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
     268      image.insert(i[n]);
     269    }
     270  }
     271  for(typename G1::EdgeIt e(g1);e!=INVALID;++e)
     272    check(findEdge(g2,i[g1.u(e)],i[g1.v(e)])!=INVALID,
     273          "Wrong isomorphism: missing edge(checkSub).");
     274}
     275
     276template<class G1, class G2, class I>
     277void checkInd(const G1 &g1, const G2 &g2, const I &i) {
     278  std::set<typename G2::Node> image;
     279  for(typename G1::NodeIt n(g1);n!=INVALID;++n) {
     280    check(i[n]!=INVALID, "Wrong isomorphism: incomplete mapping.");
     281    check(image.count(i[n])==0,"Wrong isomorphism: not injective.");
     282    image.insert(i[n]);
     283  }
     284  for(typename G1::NodeIt n(g1); n!=INVALID; ++n)
     285    for(typename G1::NodeIt m(g1); m!=INVALID; ++m)
     286      if((findEdge(g1,n,m)==INVALID) != (findEdge(g2,i[n],i[m])==INVALID)) {
     287        std::cout << "Wrong isomorphism: edge mismatch";
     288        exit(1);
     289      }
     290}
     291
     292template<class G1,class G2>
     293int checkSub(const G1 &g1, const G2 &g2) {
     294  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     295  if(vf2pp(g1,g2).mapping(iso).run()){
     296    checkSub(g1,g2,iso);
     297    return true;
     298  }
     299  else
     300    return false;
     301}
     302
     303template<class G1,class G2>
     304int checkInd(const G1 &g1, const G2 &g2) {
     305  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     306  if(vf2pp(g1,g2).induced().mapping(iso).run()) {
     307    checkInd(g1,g2,iso);
     308    return true;
     309  }
     310  else
     311    return false;
     312}
     313
     314template<class G1,class G2>
     315int checkIso(const G1 &g1, const G2 &g2) {
     316  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     317  if(vf2pp(g1,g2).iso().mapping(iso).run()) {
     318    check(countNodes(g1)==countNodes(g2),
     319          "Wrong iso alg.: they are not isomophic.");
     320    checkInd(g1,g2,iso);
     321    return true;
     322  }
     323  else
     324    return false;
     325}
     326
     327template<class G1, class G2, class L1, class L2, class I>
     328void checkLabel(const G1 &g1, const G2 &,
     329                const L1 &l1, const L2 &l2,const I &i) {
     330  for(typename G1::NodeIt n(g1);n!=INVALID;++n)
     331    check(l1[n]==l2[i[n]],"Wrong isomorphism: label mismatch.");
     332}
     333
     334template<class G1,class G2,class L1,class L2>
     335int checkSub(const G1 &g1, const G2 &g2, const L1 &l1, const L2 &l2) {
     336  typename G1:: template NodeMap<typename G2::Node> iso(g1,INVALID);
     337  if(vf2pp(g1,g2).nodeLabels(l1,l2).mapping(iso).run()) {
     338    checkSub(g1,g2,iso);
     339    checkLabel(g1,g2,l1,l2,iso);
     340    return true;
     341  }
     342  else
     343    return false;
     344}
     345
     346int main() {
     347  make_graphs();
     348//   justCompile();
     349  check(checkSub(c5,petersen), "There should exist a C5->Petersen mapping.");
     350  check(!checkSub(c7,petersen),
     351        "There should not exist a C7->Petersen mapping.");
     352  check(checkSub(p10,petersen), "There should exist a P10->Petersen mapping.");
     353  check(!checkSub(c10,petersen),
     354        "There should not exist a C10->Petersen mapping.");
     355  check(checkSub(petersen,petersen),
     356        "There should exist a Petersen->Petersen mapping.");
     357
     358  check(checkInd(c5,petersen),
     359        "There should exist a C5->Petersen spanned mapping.");
     360  check(!checkInd(c7,petersen),
     361        "There should exist a C7->Petersen spanned mapping.");
     362  check(!checkInd(p10,petersen),
     363        "There should not exist a P10->Petersen spanned mapping.");
     364  check(!checkInd(c10,petersen),
     365        "There should not exist a C10->Petersen spanned mapping.");
     366  check(checkInd(petersen,petersen),
     367        "There should exist a Petersen->Petersen spanned mapping.");
     368
     369  check(!checkSub(petersen,c10),
     370        "There should not exist a Petersen->C10 mapping.");
     371  check(checkSub(p10,c10),
     372        "There should exist a P10->C10 mapping.");
     373  check(!checkInd(p10,c10),
     374        "There should not exist a P10->C10 spanned mapping.");
     375  check(!checkSub(c10,p10),
     376        "There should not exist a C10->P10 mapping.");
     377
     378  check(!checkIso(p10,c10),
     379        "P10 and C10 are not isomorphic.");
     380  check(checkIso(c10,c10),
     381        "C10 and C10 are isomorphic.");
     382
     383  check(!vf2pp(p10,c10).iso().run(),
     384        "P10 and C10 are not isomorphic.");
     385  check(vf2pp(c10,c10).iso().run(),
     386        "C10 and C10 are isomorphic.");
     387
     388  check(!checkSub(c5,petersen,c5_col,petersen_col1),
     389        "There should exist a C5->Petersen mapping.");
     390  check(checkSub(c5,petersen,c5_col,petersen_col2),
     391        "There should exist a C5->Petersen mapping.");
     392}