lemon/vf2.h
author Alpar Juttner <alpar@cs.elte.hu>
Fri, 15 May 2015 10:16:48 +0200
changeset 1145 1de908281369
parent 1143 f85ee41c84bc
child 1152 abc24245d276
permissions -rw-r--r--
Update Doxyfile.in

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