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