lemon/vf2.h
author Peter Madarasi <madarasip@caesar.elte.hu>
Tue, 19 Sep 2017 14:08:20 +0200
changeset 1405 3feba0ea1bda
parent 1370 f51c01a1b88e
child 1407 76349d8212d3
permissions -rw-r--r--
Vf2 improvements and Vf2pp implementation (#597)
madarasip@1350
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
madarasip@1350
     2
 *
madarasip@1350
     3
 * This file is a part of LEMON, a generic C++ optimization library.
madarasip@1350
     4
 *
madarasip@1405
     5
 * Copyright (C) 2015-2017
madarasip@1350
     6
 * EMAXA Kutato-fejleszto Kft. (EMAXA Research Ltd.)
madarasip@1350
     7
 *
madarasip@1350
     8
 * Permission to use, modify and distribute this software is granted
madarasip@1350
     9
 * provided that this copyright notice appears in all copies. For
madarasip@1350
    10
 * precise terms see the accompanying LICENSE file.
madarasip@1350
    11
 *
madarasip@1350
    12
 * This software is provided "AS IS" with no warranty of any kind,
madarasip@1350
    13
 * express or implied, and with no claim as to its suitability for any
madarasip@1350
    14
 * purpose.
madarasip@1350
    15
 *
madarasip@1350
    16
 */
madarasip@1350
    17
madarasip@1350
    18
#ifndef LEMON_VF2_H
madarasip@1350
    19
#define LEMON_VF2_H
madarasip@1350
    20
alpar@1351
    21
///\ingroup graph_properties
alpar@1351
    22
///\file
alpar@1351
    23
///\brief VF2 algorithm \cite cordella2004sub.
alpar@1351
    24
madarasip@1350
    25
#include <lemon/core.h>
madarasip@1350
    26
#include <lemon/concepts/graph.h>
madarasip@1350
    27
#include <lemon/dfs.h>
madarasip@1350
    28
#include <lemon/bfs.h>
madarasip@1405
    29
#include <lemon/bits/vf2_internals.h>
madarasip@1350
    30
madarasip@1350
    31
#include <vector>
madarasip@1350
    32
madarasip@1405
    33
namespace lemon {
madarasip@1405
    34
  namespace bits {
madarasip@1405
    35
    namespace vf2 {
madarasip@1405
    36
madarasip@1405
    37
      class AlwaysEq {
madarasip@1350
    38
      public:
madarasip@1350
    39
        template<class T1, class T2>
madarasip@1405
    40
        bool operator()(T1&, T2&) const {
madarasip@1350
    41
          return true;
madarasip@1350
    42
        }
madarasip@1350
    43
      };
madarasip@1350
    44
madarasip@1350
    45
      template<class M1, class M2>
madarasip@1405
    46
      class MapEq{
madarasip@1350
    47
        const M1 &_m1;
madarasip@1350
    48
        const M2 &_m2;
madarasip@1350
    49
      public:
madarasip@1405
    50
        MapEq(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) { }
madarasip@1405
    51
        bool operator()(typename M1::Key k1, typename M2::Key k2) const {
madarasip@1350
    52
          return _m1[k1] == _m2[k2];
madarasip@1350
    53
        }
madarasip@1350
    54
      };
madarasip@1350
    55
madarasip@1405
    56
madarasip@1405
    57
madarasip@1350
    58
      template <class G>
madarasip@1405
    59
      class DfsLeaveOrder : public DfsVisitor<G> {
madarasip@1350
    60
        const G &_g;
madarasip@1350
    61
        std::vector<typename G::Node> &_order;
madarasip@1350
    62
        int i;
madarasip@1350
    63
      public:
madarasip@1350
    64
        DfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
madarasip@1405
    65
          : i(countNodes(g)), _g(g), _order(order) { }
madarasip@1405
    66
        void leave(const typename G::Node &node) {
madarasip@1350
    67
          _order[--i]=node;
madarasip@1350
    68
        }
madarasip@1350
    69
      };
madarasip@1350
    70
madarasip@1350
    71
      template <class G>
madarasip@1405
    72
      class BfsLeaveOrder : public BfsVisitor<G> {
madarasip@1350
    73
        int i;
madarasip@1350
    74
        const G &_g;
madarasip@1350
    75
        std::vector<typename G::Node> &_order;
madarasip@1350
    76
      public:
madarasip@1350
    77
        BfsLeaveOrder(const G &g, std::vector<typename G::Node> &order)
madarasip@1405
    78
          : i(0), _g(g), _order(order){
madarasip@1405
    79
        }
madarasip@1405
    80
        void process(const typename G::Node &node) {
madarasip@1350
    81
          _order[i++]=node;
madarasip@1350
    82
        }
madarasip@1350
    83
      };
madarasip@1350
    84
    }
madarasip@1350
    85
  }
madarasip@1350
    86
madarasip@1350
    87
alpar@1351
    88
  ///%VF2 algorithm class.
alpar@1351
    89
alpar@1351
    90
  ///\ingroup graph_isomorphism This class provides an efficient
alpar@1351
    91
  ///implementation of the %VF2 algorithm \cite cordella2004sub
alpar@1351
    92
  ///for variants of the (Sub)graph Isomorphism problem.
alpar@1351
    93
  ///
alpar@1351
    94
  ///There is also a \ref vf2() "function-type interface" called \ref vf2()
alpar@1351
    95
  ///for the %VF2 algorithm, which is probably more convenient in most
alpar@1351
    96
  ///use-cases.
alpar@1351
    97
  ///
alpar@1351
    98
  ///\tparam G1 The type of the graph to be embedded.
alpar@1351
    99
  ///The default type is \ref ListDigraph.
alpar@1351
   100
  ///\tparam G2 The type of the graph g1 will be embedded into.
alpar@1351
   101
  ///The default type is \ref ListDigraph.
alpar@1351
   102
  ///\tparam M The type of the NodeMap storing the mapping.
alpar@1351
   103
  ///By default, it is G1::NodeMap<G2::Node>
alpar@1351
   104
  ///\tparam NEQ A bool-valued binary functor determinining whether a node is
alpar@1351
   105
  ///mappable to another. By default it is an always true operator.
alpar@1351
   106
  ///
alpar@1351
   107
  ///\sa vf2()
alpar@1351
   108
#ifdef DOXYGEN
alpar@1351
   109
  template<class G1, class G2, class M, class NEQ >
alpar@1351
   110
#else
alpar@1351
   111
  template<class G1=ListDigraph,
alpar@1351
   112
           class G2=ListDigraph,
alpar@1351
   113
           class M = typename G1::template NodeMap<G2::Node>,
alpar@1351
   114
           class NEQ = bits::vf2::AlwaysEq >
alpar@1351
   115
#endif
madarasip@1405
   116
  class Vf2 {
madarasip@1350
   117
    //Current depth in the DFS tree.
madarasip@1350
   118
    int _depth;
madarasip@1350
   119
    //Functor with bool operator()(G1::Node,G2::Node), which returns 1
madarasip@1405
   120
    //ifff the two nodes are equivalent.
alpar@1351
   121
    NEQ _nEq;
madarasip@1350
   122
madarasip@1350
   123
    typename G2::template NodeMap<int> _conn;
alpar@1351
   124
    //Current mapping. We index it by the nodes of g1, and match[v] is
madarasip@1350
   125
    //a node of g2.
alpar@1351
   126
    M &_mapping;
madarasip@1405
   127
    //order[i] is the node of g1, for which we search a pair if depth=i
madarasip@1350
   128
    std::vector<typename G1::Node> order;
madarasip@1350
   129
    //currEdgeIts[i] is an edge iterator, witch is last used in the ith
madarasip@1350
   130
    //depth to find a pair for order[i].
madarasip@1350
   131
    std::vector<typename G2::IncEdgeIt> currEdgeIts;
madarasip@1350
   132
    //The small graph.
madarasip@1350
   133
    const G1 &_g1;
madarasip@1405
   134
    //The large graph.
madarasip@1350
   135
    const G2 &_g2;
madarasip@1405
   136
    //lookup tables for cutting the searchtree
madarasip@1350
   137
    typename G1::template NodeMap<int> rNew1t,rInOut1t;
madarasip@1350
   138
madarasip@1405
   139
    MappingType _mapping_type;
madarasip@1405
   140
madarasip@1405
   141
    bool _deallocMappingAfterUse;
madarasip@1350
   142
madarasip@1350
   143
    //cut the search tree
madarasip@1405
   144
    template<MappingType MT>
madarasip@1405
   145
    bool cut(const typename G1::Node n1,const typename G2::Node n2) const {
madarasip@1350
   146
      int rNew2=0,rInOut2=0;
madarasip@1405
   147
      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
madarasip@1405
   148
        const typename G2::Node currNode=_g2.oppositeNode(n2,e2);
madarasip@1405
   149
        if(_conn[currNode]>0)
madarasip@1405
   150
          ++rInOut2;
madarasip@1405
   151
        else if(MT!=SUBGRAPH&&_conn[currNode]==0)
madarasip@1405
   152
          ++rNew2;
madarasip@1405
   153
      }
madarasip@1405
   154
      switch(MT) {
madarasip@1405
   155
      case INDUCED:
madarasip@1405
   156
        return rInOut1t[n1]<=rInOut2&&rNew1t[n1]<=rNew2;
madarasip@1405
   157
      case SUBGRAPH:
madarasip@1405
   158
        return rInOut1t[n1]<=rInOut2;
madarasip@1405
   159
      case ISOMORPH:
madarasip@1405
   160
        return rInOut1t[n1]==rInOut2&&rNew1t[n1]==rNew2;
madarasip@1405
   161
      default:
madarasip@1405
   162
        return false;
madarasip@1405
   163
      }
madarasip@1350
   164
    }
madarasip@1350
   165
madarasip@1405
   166
    template<MappingType MT>
madarasip@1405
   167
    bool feas(const typename G1::Node n1,const typename G2::Node n2) {
madarasip@1350
   168
      if(!_nEq(n1,n2))
madarasip@1350
   169
        return 0;
madarasip@1350
   170
madarasip@1405
   171
      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
madarasip@1405
   172
        const typename G1::Node& currNode=_g1.oppositeNode(n1,e1);
madarasip@1405
   173
        if(_mapping[currNode]!=INVALID)
madarasip@1405
   174
          --_conn[_mapping[currNode]];
madarasip@1405
   175
      }
madarasip@1405
   176
      bool isIso=1;
madarasip@1405
   177
      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
madarasip@1405
   178
        int& connCurrNode = _conn[_g2.oppositeNode(n2,e2)];
madarasip@1405
   179
        if(connCurrNode<-1)
madarasip@1405
   180
          ++connCurrNode;
madarasip@1405
   181
        else if(MT!=SUBGRAPH&&connCurrNode==-1) {
madarasip@1405
   182
          isIso=0;
madarasip@1405
   183
          break;
madarasip@1350
   184
        }
madarasip@1405
   185
      }
madarasip@1405
   186
madarasip@1405
   187
      for(typename G1::IncEdgeIt e1(_g1,n1); e1!=INVALID; ++e1) {
madarasip@1405
   188
        const typename G2::Node& currNodePair=_mapping[_g1.oppositeNode(n1,e1)];
madarasip@1405
   189
        int& connCurrNodePair=_conn[currNodePair];
madarasip@1405
   190
        if(currNodePair!=INVALID&&connCurrNodePair!=-1) {
madarasip@1405
   191
          switch(MT) {
madarasip@1405
   192
          case INDUCED:
madarasip@1405
   193
          case ISOMORPH:
madarasip@1405
   194
            isIso=0;
madarasip@1405
   195
            break;
madarasip@1405
   196
          case SUBGRAPH:
madarasip@1405
   197
            if(connCurrNodePair<-1)
madarasip@1350
   198
              isIso=0;
madarasip@1405
   199
            break;
madarasip@1405
   200
          }
madarasip@1405
   201
          connCurrNodePair=-1;
madarasip@1350
   202
        }
madarasip@1405
   203
      }
madarasip@1350
   204
      return isIso&&cut<MT>(n1,n2);
madarasip@1350
   205
    }
madarasip@1350
   206
madarasip@1405
   207
    void addPair(const typename G1::Node n1,const typename G2::Node n2) {
madarasip@1350
   208
      _conn[n2]=-1;
alpar@1351
   209
      _mapping.set(n1,n2);
madarasip@1405
   210
      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
madarasip@1405
   211
        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
madarasip@1405
   212
        if(currConn!=-1)
madarasip@1405
   213
          ++currConn;
madarasip@1405
   214
      }
madarasip@1350
   215
    }
madarasip@1350
   216
madarasip@1405
   217
    void subPair(const typename G1::Node n1,const typename G2::Node n2) {
madarasip@1350
   218
      _conn[n2]=0;
alpar@1351
   219
      _mapping.set(n1,INVALID);
madarasip@1405
   220
      for(typename G2::IncEdgeIt e2(_g2,n2); e2!=INVALID; ++e2) {
madarasip@1405
   221
        int& currConn = _conn[_g2.oppositeNode(n2,e2)];
madarasip@1405
   222
        if(currConn>0)
madarasip@1405
   223
          --currConn;
madarasip@1405
   224
        else if(currConn==-1)
madarasip@1405
   225
          ++_conn[n2];
madarasip@1405
   226
      }
madarasip@1350
   227
    }
madarasip@1350
   228
madarasip@1405
   229
    void setOrder() {
madarasip@1405
   230
      // we will find pairs for the nodes of g1 in this order
madarasip@1405
   231
madarasip@1350
   232
      // bits::vf2::DfsLeaveOrder<G1> v(_g1,order);
madarasip@1350
   233
      //   DfsVisit<G1,bits::vf2::DfsLeaveOrder<G1> >dfs(_g1, v);
madarasip@1350
   234
      //   dfs.run();
madarasip@1350
   235
madarasip@1350
   236
      //it is more efficient in practice than DFS
madarasip@1350
   237
      bits::vf2::BfsLeaveOrder<G1> v(_g1,order);
madarasip@1350
   238
      BfsVisit<G1,bits::vf2::BfsLeaveOrder<G1> >bfs(_g1, v);
madarasip@1350
   239
      bfs.run();
madarasip@1350
   240
    }
madarasip@1350
   241
madarasip@1405
   242
    template<MappingType MT>
madarasip@1405
   243
    bool extMatch() {
madarasip@1405
   244
      while(_depth>=0) {
madarasip@1405
   245
        //there are not nodes in g1, which has not pair in g2.
madarasip@1405
   246
        if(_depth==static_cast<int>(order.size())) {
madarasip@1405
   247
          --_depth;
madarasip@1405
   248
          return true;
madarasip@1405
   249
        }
madarasip@1405
   250
        typename G1::Node& nodeOfDepth = order[_depth];
madarasip@1405
   251
        const typename G2::Node& pairOfNodeOfDepth = _mapping[nodeOfDepth];
madarasip@1405
   252
        typename G2::IncEdgeIt &edgeItOfDepth = currEdgeIts[_depth];
madarasip@1405
   253
        //the node of g2, which neighbours are the candidates for
madarasip@1405
   254
        //the pair of nodeOfDepth
madarasip@1405
   255
        typename G2::Node currPNode;
madarasip@1405
   256
        if(edgeItOfDepth==INVALID) {
madarasip@1405
   257
          typename G1::IncEdgeIt fstMatchedE(_g1,nodeOfDepth);
madarasip@1405
   258
          //if pairOfNodeOfDepth!=INVALID, we dont use
madarasip@1405
   259
          //fstMatchedE
madarasip@1405
   260
          if(pairOfNodeOfDepth==INVALID)
madarasip@1405
   261
            for(; fstMatchedE!=INVALID &&
madarasip@1405
   262
                  _mapping[_g1.oppositeNode(nodeOfDepth,
madarasip@1405
   263
                                            fstMatchedE)]==INVALID;
madarasip@1405
   264
                ++fstMatchedE) ; //find fstMatchedE
madarasip@1405
   265
          if(fstMatchedE==INVALID||pairOfNodeOfDepth!=INVALID) {
madarasip@1405
   266
            //We found no covered neighbours, this means
madarasip@1405
   267
            //the graph is not connected(or _depth==0).  Each
madarasip@1405
   268
            //uncovered(and there are some other properties due
madarasip@1405
   269
            //to the spec. problem types) node of g2 is
madarasip@1405
   270
            //candidate.  We can read the iterator of the last
madarasip@1405
   271
            //tried node from the match if it is not the first
madarasip@1405
   272
            //try(match[nodeOfDepth]!=INVALID)
madarasip@1405
   273
            typename G2::NodeIt n2(_g2);
madarasip@1405
   274
            //if it's not the first try
madarasip@1405
   275
            if(pairOfNodeOfDepth!=INVALID) {
madarasip@1405
   276
              n2=++typename G2::NodeIt(_g2,pairOfNodeOfDepth);
madarasip@1405
   277
              subPair(nodeOfDepth,pairOfNodeOfDepth);
madarasip@1405
   278
            }
madarasip@1405
   279
            for(; n2!=INVALID; ++n2)
madarasip@1405
   280
              if(MT!=SUBGRAPH) {
madarasip@1405
   281
                if(_conn[n2]==0&&feas<MT>(nodeOfDepth,n2))
madarasip@1405
   282
                  break;
madarasip@1405
   283
              }
madarasip@1405
   284
              else if(_conn[n2]>=0&&feas<MT>(nodeOfDepth,n2))
madarasip@1405
   285
                break;
madarasip@1405
   286
            // n2 is the next candidate
madarasip@1405
   287
            if(n2!=INVALID){
madarasip@1405
   288
              addPair(nodeOfDepth,n2);
madarasip@1405
   289
              ++_depth;
madarasip@1405
   290
            }
madarasip@1405
   291
            else // there are no more candidates
madarasip@1350
   292
              --_depth;
madarasip@1405
   293
            continue;
madarasip@1405
   294
          }
madarasip@1405
   295
          else {
madarasip@1405
   296
            currPNode=_mapping[_g1.oppositeNode(nodeOfDepth,
madarasip@1405
   297
                                                fstMatchedE)];
madarasip@1405
   298
            edgeItOfDepth=typename G2::IncEdgeIt(_g2,currPNode);
madarasip@1405
   299
          }
madarasip@1350
   300
        }
madarasip@1405
   301
        else {
madarasip@1405
   302
          currPNode=_g2.oppositeNode(pairOfNodeOfDepth,
madarasip@1405
   303
                                     edgeItOfDepth);
madarasip@1405
   304
          subPair(nodeOfDepth,pairOfNodeOfDepth);
madarasip@1405
   305
          ++edgeItOfDepth;
madarasip@1405
   306
        }
madarasip@1405
   307
        for(; edgeItOfDepth!=INVALID; ++edgeItOfDepth) {
madarasip@1405
   308
          const typename G2::Node currNode =
madarasip@1405
   309
            _g2.oppositeNode(currPNode, edgeItOfDepth);
madarasip@1405
   310
          if(_conn[currNode]>0&&feas<MT>(nodeOfDepth,currNode)) {
madarasip@1405
   311
            addPair(nodeOfDepth,currNode);
madarasip@1405
   312
            break;
madarasip@1405
   313
          }
madarasip@1405
   314
        }
madarasip@1405
   315
        edgeItOfDepth==INVALID?--_depth:++_depth;
madarasip@1405
   316
      }
madarasip@1350
   317
      return false;
madarasip@1350
   318
    }
madarasip@1350
   319
madarasip@1350
   320
    //calc. the lookup table for cut the searchtree
madarasip@1405
   321
    void setRNew1tRInOut1t() {
madarasip@1350
   322
      typename G1::template NodeMap<int> tmp(_g1,0);
madarasip@1405
   323
      for(unsigned int i=0; i<order.size(); ++i) {
madarasip@1405
   324
        const typename G1::Node& orderI = order[i];
madarasip@1405
   325
        tmp[orderI]=-1;
madarasip@1405
   326
        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
madarasip@1405
   327
          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
madarasip@1405
   328
          if(tmp[currNode]>0)
madarasip@1405
   329
            ++rInOut1t[orderI];
madarasip@1405
   330
          else if(tmp[currNode]==0)
madarasip@1405
   331
            ++rNew1t[orderI];
madarasip@1350
   332
        }
madarasip@1405
   333
        for(typename G1::IncEdgeIt e1(_g1,orderI); e1!=INVALID; ++e1) {
madarasip@1405
   334
          const typename G1::Node currNode=_g1.oppositeNode(orderI,e1);
madarasip@1405
   335
          if(tmp[currNode]!=-1)
madarasip@1405
   336
            ++tmp[currNode];
madarasip@1405
   337
        }
madarasip@1405
   338
      }
madarasip@1350
   339
    }
madarasip@1350
   340
  public:
alpar@1351
   341
    ///Constructor
alpar@1351
   342
alpar@1351
   343
    ///Constructor
alpar@1351
   344
alpar@1351
   345
    ///\param g1 The graph to be embedded into \e g2.
alpar@1351
   346
    ///\param g2 The graph \e g1 will be embedded into.
alpar@1351
   347
    ///\param m \ref concepts::ReadWriteMap "read-write" NodeMap
alpar@1351
   348
    ///storing the found mapping.
madarasip@1405
   349
    ///\param neq A bool-valued binary functor determining whether a node is
alpar@1351
   350
    ///mappable to another. By default it is an always true operator.
madarasip@1405
   351
    Vf2(const G1 &g1, const G2 &g2, M &m, const NEQ &neq = NEQ() ) :
alpar@1351
   352
      _nEq(neq), _conn(g2,0), _mapping(m), order(countNodes(g1)),
madarasip@1350
   353
      currEdgeIts(countNodes(g1),INVALID), _g1(g1), _g2(g2), rNew1t(g1,0),
madarasip@1405
   354
      rInOut1t(g1,0), _mapping_type(SUBGRAPH), _deallocMappingAfterUse(0) {
madarasip@1350
   355
      _depth=0;
madarasip@1350
   356
      setOrder();
madarasip@1350
   357
      setRNew1tRInOut1t();
alpar@1352
   358
      for(typename G1::NodeIt n(g1);n!=INVALID;++n)
alpar@1352
   359
        m[n]=INVALID;
madarasip@1350
   360
    }
madarasip@1350
   361
madarasip@1405
   362
    ///Destructor
madarasip@1405
   363
madarasip@1405
   364
    ///Destructor.
madarasip@1405
   365
    ///
madarasip@1405
   366
madarasip@1405
   367
    ~Vf2(){
madarasip@1405
   368
      if(_deallocMappingAfterUse)
madarasip@1405
   369
        delete &_mapping;
madarasip@1405
   370
    }
madarasip@1405
   371
alpar@1351
   372
    ///Returns the current mapping type
madarasip@1350
   373
alpar@1351
   374
    ///Returns the current mapping type
alpar@1351
   375
    ///
madarasip@1405
   376
    MappingType mappingType() const {
madarasip@1405
   377
      return _mapping_type;
madarasip@1405
   378
    }
alpar@1351
   379
    ///Sets mapping type
alpar@1351
   380
alpar@1351
   381
    ///Sets mapping type.
alpar@1351
   382
    ///
alpar@1351
   383
    ///The mapping type is set to \ref SUBGRAPH by default.
alpar@1351
   384
    ///
madarasip@1405
   385
    ///\sa See \ref MappingType for the possible values.
madarasip@1405
   386
    void mappingType(MappingType m_type) {
madarasip@1405
   387
      _mapping_type = m_type;
madarasip@1405
   388
    }
alpar@1351
   389
kpeter@1366
   390
    ///Finds a mapping
alpar@1351
   391
madarasip@1405
   392
    ///It finds a mapping from g1 into g2 according to the mapping
madarasip@1405
   393
    ///type set by \ref mappingType(MappingType) "mappingType()".
alpar@1351
   394
    ///
alpar@1351
   395
    ///By subsequent calls, it returns all possible mappings one-by-one.
alpar@1351
   396
    ///
alpar@1351
   397
    ///\retval true if a mapping is found.
alpar@1351
   398
    ///\retval false if there is no (more) mapping.
madarasip@1405
   399
    bool find() {
madarasip@1405
   400
      switch(_mapping_type) {
madarasip@1405
   401
      case SUBGRAPH:
madarasip@1405
   402
        return extMatch<SUBGRAPH>();
madarasip@1405
   403
      case INDUCED:
madarasip@1405
   404
        return extMatch<INDUCED>();
madarasip@1405
   405
      case ISOMORPH:
madarasip@1405
   406
        return extMatch<ISOMORPH>();
madarasip@1405
   407
      default:
madarasip@1405
   408
        return false;
madarasip@1405
   409
      }
madarasip@1350
   410
    }
madarasip@1350
   411
  };
madarasip@1350
   412
madarasip@1350
   413
  template<class G1, class G2>
madarasip@1405
   414
  class Vf2WizardBase {
madarasip@1350
   415
  protected:
madarasip@1350
   416
    typedef G1 Graph1;
madarasip@1350
   417
    typedef G2 Graph2;
madarasip@1350
   418
madarasip@1350
   419
    const G1 &_g1;
madarasip@1350
   420
    const G2 &_g2;
madarasip@1350
   421
madarasip@1405
   422
    MappingType _mapping_type;
madarasip@1350
   423
madarasip@1350
   424
    typedef typename G1::template NodeMap<typename G2::Node> Mapping;
madarasip@1350
   425
    bool _local_mapping;
madarasip@1350
   426
    void *_mapping;
madarasip@1405
   427
    void createMapping() {
madarasip@1350
   428
      _mapping = new Mapping(_g1);
madarasip@1350
   429
    }
madarasip@1350
   430
madarasip@1405
   431
    void *myVf2; //used in Vf2Wizard::find
madarasip@1405
   432
madarasip@1405
   433
madarasip@1350
   434
    typedef bits::vf2::AlwaysEq NodeEq;
madarasip@1350
   435
    NodeEq _node_eq;
madarasip@1350
   436
madarasip@1350
   437
    Vf2WizardBase(const G1 &g1,const G2 &g2)
madarasip@1405
   438
      : _g1(g1), _g2(g2), _mapping_type(SUBGRAPH), _local_mapping(true) { }
madarasip@1350
   439
  };
madarasip@1350
   440
madarasip@1405
   441
alpar@1351
   442
  /// Auxiliary class for the function-type interface of %VF2 algorithm.
alpar@1351
   443
alpar@1351
   444
  /// This auxiliary class implements the named parameters of
alpar@1351
   445
  /// \ref vf2() "function-type interface" of \ref Vf2 algorithm.
alpar@1351
   446
  ///
alpar@1351
   447
  /// \warning This class should only be used through the function \ref vf2().
alpar@1351
   448
  ///
alpar@1351
   449
  /// \tparam TR The traits class that defines various types used by the
alpar@1351
   450
  /// algorithm.
madarasip@1350
   451
  template<class TR>
madarasip@1405
   452
  class Vf2Wizard : public TR {
madarasip@1350
   453
    typedef TR Base;
madarasip@1350
   454
    typedef typename TR::Graph1 Graph1;
madarasip@1350
   455
    typedef typename TR::Graph2 Graph2;
madarasip@1350
   456
madarasip@1350
   457
    typedef typename TR::Mapping Mapping;
madarasip@1350
   458
    typedef typename TR::NodeEq NodeEq;
madarasip@1350
   459
madarasip@1350
   460
    using TR::_g1;
madarasip@1350
   461
    using TR::_g2;
madarasip@1350
   462
    using TR::_mapping_type;
madarasip@1350
   463
    using TR::_mapping;
madarasip@1350
   464
    using TR::_node_eq;
madarasip@1350
   465
madarasip@1350
   466
  public:
alpar@1351
   467
    ///Constructor
madarasip@1405
   468
    Vf2Wizard(const Graph1 &g1,const Graph2 &g2) : Base(g1,g2) {
madarasip@1405
   469
    }
madarasip@1350
   470
madarasip@1350
   471
    ///Copy constructor
madarasip@1405
   472
    Vf2Wizard(const Base &b) : Base(b) { }
madarasip@1405
   473
madarasip@1405
   474
    ///Copy constructor
madarasip@1405
   475
    Vf2Wizard(const Vf2Wizard &b) : Base(b) {}
madarasip@1350
   476
madarasip@1350
   477
madarasip@1350
   478
    template<class T>
madarasip@1405
   479
    struct SetMappingBase : public Base{
madarasip@1350
   480
      typedef T Mapping;
madarasip@1350
   481
      SetMappingBase(const Base &b) : Base(b) {}
madarasip@1350
   482
    };
madarasip@1350
   483
madarasip@1350
   484
    ///\brief \ref named-templ-param "Named parameter" for setting
madarasip@1350
   485
    ///the mapping.
madarasip@1350
   486
    ///
madarasip@1350
   487
    ///\ref named-templ-param "Named parameter" function for setting
madarasip@1350
   488
    ///the map that stores the found embedding.
madarasip@1350
   489
    template<class T>
madarasip@1405
   490
    Vf2Wizard< SetMappingBase<T> > mapping(const T &t) {
madarasip@1350
   491
      Base::_mapping=reinterpret_cast<void*>(const_cast<T*>(&t));
madarasip@1350
   492
      Base::_local_mapping = false;
madarasip@1350
   493
      return Vf2Wizard<SetMappingBase<T> >(*this);
madarasip@1350
   494
    }
madarasip@1350
   495
madarasip@1350
   496
    template<class NE>
madarasip@1350
   497
    struct SetNodeEqBase : public Base {
madarasip@1350
   498
      typedef NE NodeEq;
madarasip@1350
   499
      NodeEq _node_eq;
madarasip@1350
   500
      SetNodeEqBase(const Base &b, const NE &node_eq)
madarasip@1405
   501
        : Base(b), _node_eq(node_eq){
madarasip@1405
   502
      }
madarasip@1350
   503
    };
madarasip@1350
   504
madarasip@1350
   505
    ///\brief \ref named-templ-param "Named parameter" for setting
madarasip@1350
   506
    ///the node equivalence relation.
madarasip@1350
   507
    ///
madarasip@1350
   508
    ///\ref named-templ-param "Named parameter" function for setting
madarasip@1350
   509
    ///the equivalence relation between the nodes.
alpar@1351
   510
    ///
alpar@1351
   511
    ///\param node_eq A bool-valued binary functor determinining
alpar@1351
   512
    ///whether a node is mappable to another. By default it is an
alpar@1351
   513
    ///always true operator.
madarasip@1350
   514
    template<class T>
madarasip@1405
   515
    Vf2Wizard< SetNodeEqBase<T> > nodeEq(const T &node_eq) {
madarasip@1350
   516
      return Vf2Wizard<SetNodeEqBase<T> >(SetNodeEqBase<T>(*this,node_eq));
madarasip@1350
   517
    }
madarasip@1350
   518
madarasip@1350
   519
    ///\brief \ref named-templ-param "Named parameter" for setting
madarasip@1350
   520
    ///the node labels.
madarasip@1350
   521
    ///
madarasip@1350
   522
    ///\ref named-templ-param "Named parameter" function for setting
madarasip@1350
   523
    ///the node labels defining equivalence relation between them.
alpar@1351
   524
    ///
madarasip@1405
   525
    ///\param m1 An arbitrary \ref concepts::ReadMap "readable node map"
alpar@1353
   526
    ///of g1.
madarasip@1405
   527
    ///\param m2 An arbitrary \ref concepts::ReadMap "readable node map"
alpar@1353
   528
    ///of g2.
alpar@1351
   529
    ///
alpar@1351
   530
    ///The value type of these maps must be equal comparable.
madarasip@1350
   531
    template<class M1, class M2>
madarasip@1350
   532
    Vf2Wizard< SetNodeEqBase<bits::vf2::MapEq<M1,M2> > >
madarasip@1405
   533
    nodeLabels(const M1 &m1,const M2 &m2){
madarasip@1350
   534
      return nodeEq(bits::vf2::MapEq<M1,M2>(m1,m2));
madarasip@1350
   535
    }
madarasip@1350
   536
alpar@1351
   537
    ///\brief \ref named-templ-param "Named parameter" for setting
alpar@1351
   538
    ///the mapping type.
alpar@1351
   539
    ///
alpar@1351
   540
    ///\ref named-templ-param "Named parameter" for setting
alpar@1351
   541
    ///the mapping type.
alpar@1351
   542
    ///
alpar@1351
   543
    ///The mapping type is set to \ref SUBGRAPH by default.
alpar@1351
   544
    ///
madarasip@1405
   545
    ///\sa See \ref MappingType for the possible values.
madarasip@1405
   546
    Vf2Wizard<Base> &mappingType(MappingType m_type) {
madarasip@1350
   547
      _mapping_type = m_type;
madarasip@1350
   548
      return *this;
madarasip@1350
   549
    }
madarasip@1350
   550
alpar@1351
   551
    ///\brief \ref named-templ-param "Named parameter" for setting
alpar@1351
   552
    ///the mapping type to \ref INDUCED.
alpar@1351
   553
    ///
alpar@1351
   554
    ///\ref named-templ-param "Named parameter" for setting
alpar@1351
   555
    ///the mapping type to \ref INDUCED.
madarasip@1405
   556
    Vf2Wizard<Base> &induced() {
madarasip@1350
   557
      _mapping_type = INDUCED;
madarasip@1350
   558
      return *this;
madarasip@1350
   559
    }
madarasip@1350
   560
alpar@1351
   561
    ///\brief \ref named-templ-param "Named parameter" for setting
alpar@1351
   562
    ///the mapping type to \ref ISOMORPH.
alpar@1351
   563
    ///
alpar@1351
   564
    ///\ref named-templ-param "Named parameter" for setting
alpar@1351
   565
    ///the mapping type to \ref ISOMORPH.
madarasip@1405
   566
    Vf2Wizard<Base> &iso() {
madarasip@1350
   567
      _mapping_type = ISOMORPH;
madarasip@1350
   568
      return *this;
madarasip@1350
   569
    }
madarasip@1350
   570
madarasip@1405
   571
alpar@1351
   572
    ///Runs VF2 algorithm.
alpar@1351
   573
alpar@1351
   574
    ///This method runs VF2 algorithm.
alpar@1351
   575
    ///
alpar@1351
   576
    ///\retval true if a mapping is found.
madarasip@1405
   577
    ///\retval false if there is no mapping.
madarasip@1405
   578
    bool run(){
madarasip@1350
   579
      if(Base::_local_mapping)
madarasip@1350
   580
        Base::createMapping();
madarasip@1350
   581
madarasip@1350
   582
      Vf2<Graph1, Graph2, Mapping, NodeEq >
madarasip@1350
   583
        alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
madarasip@1350
   584
madarasip@1350
   585
      alg.mappingType(_mapping_type);
madarasip@1350
   586
madarasip@1350
   587
      bool ret = alg.find();
madarasip@1350
   588
madarasip@1350
   589
      if(Base::_local_mapping)
madarasip@1350
   590
        delete reinterpret_cast<Mapping*>(_mapping);
madarasip@1350
   591
madarasip@1350
   592
      return ret;
madarasip@1350
   593
    }
madarasip@1405
   594
madarasip@1405
   595
    ///Get a pointer to the generated Vf2 object.
madarasip@1405
   596
madarasip@1405
   597
    ///Gives a pointer to the generated Vf2 object.
madarasip@1405
   598
    ///
madarasip@1405
   599
    ///\return Pointer to the generated Vf2 object.
madarasip@1405
   600
    ///\warning Don't forget to delete the referred Vf2 object after use.
madarasip@1405
   601
    Vf2<Graph1, Graph2, Mapping, NodeEq >* getPtrToVf2Object() {
madarasip@1405
   602
      if(Base::_local_mapping)
madarasip@1405
   603
        Base::createMapping();
madarasip@1405
   604
      Vf2<Graph1, Graph2, Mapping, NodeEq >* ptr =
madarasip@1405
   605
        new Vf2<Graph1, Graph2, Mapping, NodeEq>
madarasip@1405
   606
        (_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
madarasip@1405
   607
      ptr->mappingType(_mapping_type);
madarasip@1405
   608
      if(Base::_local_mapping)
madarasip@1405
   609
        ptr->_deallocMappingAfterUse = true;
madarasip@1405
   610
      return ptr;
madarasip@1405
   611
    }
madarasip@1405
   612
madarasip@1405
   613
    ///Counts the number of mappings.
madarasip@1405
   614
madarasip@1405
   615
    ///This method counts the number of mappings.
madarasip@1405
   616
    ///
madarasip@1405
   617
    /// \return The number of mappings.
madarasip@1405
   618
    int count() {
madarasip@1405
   619
      if(Base::_local_mapping)
madarasip@1405
   620
        Base::createMapping();
madarasip@1405
   621
madarasip@1405
   622
      Vf2<Graph1, Graph2, Mapping, NodeEq>
madarasip@1405
   623
        alg(_g1, _g2, *reinterpret_cast<Mapping*>(_mapping), _node_eq);
madarasip@1405
   624
      if(Base::_local_mapping)
madarasip@1405
   625
        alg._deallocMappingAfterUse = true;
madarasip@1405
   626
      alg.mappingType(_mapping_type);
madarasip@1405
   627
madarasip@1405
   628
      int ret = 0;
madarasip@1405
   629
      while(alg.find())
madarasip@1405
   630
        ++ret;
madarasip@1405
   631
madarasip@1405
   632
      return ret;
madarasip@1405
   633
    }
madarasip@1350
   634
  };
madarasip@1350
   635
alpar@1351
   636
  ///Function-type interface for VF2 algorithm.
alpar@1351
   637
alpar@1351
   638
  /// \ingroup graph_isomorphism
alpar@1351
   639
  ///Function-type interface for VF2 algorithm \cite cordella2004sub.
alpar@1351
   640
  ///
alpar@1351
   641
  ///This function has several \ref named-func-param "named parameters"
alpar@1351
   642
  ///declared as the members of class \ref Vf2Wizard.
alpar@1351
   643
  ///The following examples show how to use these parameters.
alpar@1351
   644
  ///\code
madarasip@1405
   645
  ///  // Find an embedding of graph g1 into graph g2
alpar@1351
   646
  ///  ListGraph::NodeMap<ListGraph::Node> m(g);
madarasip@1405
   647
  ///  vf2(g1,g2).mapping(m).run();
alpar@1351
   648
  ///
madarasip@1405
   649
  ///  // Check whether graphs g1 and g2 are isomorphic
madarasip@1405
   650
  ///  bool is_iso = vf2(g1,g2).iso().run();
madarasip@1405
   651
  ///
madarasip@1405
   652
  ///  // Count the number of isomorphisms
madarasip@1405
   653
  ///  int num_isos = vf2(g1,g2).iso().count();
madarasip@1405
   654
  ///
madarasip@1405
   655
  ///  // Iterate through all the induced subgraph mappings of graph g1 into g2
madarasip@1405
   656
  ///  auto* myVf2 = vf2(g1,g2).mapping(m).nodeLabels(c1,c2)
madarasip@1405
   657
  ///  .induced().getPtrToVf2Object();
madarasip@1405
   658
  ///  while(myVf2->find()){
madarasip@1405
   659
  ///    //process the current mapping m
madarasip@1405
   660
  ///  }
madarasip@1405
   661
  ///  delete myVf22;
alpar@1351
   662
  ///\endcode
madarasip@1405
   663
  ///\warning Don't forget to put the \ref Vf2Wizard::run() "run()",
madarasip@1405
   664
  ///\ref Vf2Wizard::count() "count()" or
madarasip@1405
   665
  ///the \ref Vf2Wizard::getPtrToVf2Object() "getPtrToVf2Object()"
alpar@1351
   666
  ///to the end of the expression.
alpar@1351
   667
  ///\sa Vf2Wizard
alpar@1351
   668
  ///\sa Vf2
madarasip@1350
   669
  template<class G1, class G2>
madarasip@1405
   670
  Vf2Wizard<Vf2WizardBase<G1,G2> > vf2(const G1 &g1, const G2 &g2) {
madarasip@1350
   671
    return Vf2Wizard<Vf2WizardBase<G1,G2> >(g1,g2);
madarasip@1350
   672
  }
madarasip@1350
   673
madarasip@1350
   674
}
madarasip@1350
   675
madarasip@1350
   676
#endif