⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graph_iso_check.h

📁 这是一个用于数据挖掘的常用算法的模板库(数据挖掘的C++模板库for UNIX)
💻 H
字号:
/* *  Copyright (C) 2005 M.J. Zaki <zaki@cs.rpi.edu> Rensselaer Polytechnic Institute *  Written by parimi@cs.rpi.edu *  Updated by chaojv@cs.rpi.edu, alhasan@cs.rpi.edu, salems@cs.rpi.edu * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  as published by the Free Software Foundation; either version 2 *  of the License, or (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. *//** author: parimi@cs.rpi.edu    The functions in this file are based on the canonical code class.     A new canonical code class would require a new set of isomorphism     functions */#ifndef _GRAPH_ISO_CHECK_H#define _GRAPH_ISO_CHECK_H#include<vector>#include<iostream>#include "typedefs.h"#include "time_tracker.h"using namespace std;#include "element_parser.h"#define INF_LABEL "99999999" // max label initializer for edge & vertex labelstemplate<class PP, class MP, class ST, template<class, typename, typename, template <typename> class > class CC,         template <typename> class ALLOC >class pattern;class undirected;template<class prop, class next_property>class proplist;int  num_startup=0;  int  num_urmp=0;  time_tracker tt_iso_chk;time_tracker tt_iso_startup;time_tracker tt_update_rmp;time_tracker tt_minimal;time_tracker  tt_rest;void print_rmp(const vector<int>& rmp) {  cout<<"rmp is:"<<endl;  for(unsigned int i=0; i<rmp.size(); i++)    cout<<rmp[i]<<" ";  cout<<endl;}/** Updates the right most path of candidate for last vertex added;    Also updates its canonical code for new added edge */// Note: it is assumed that this function is called for graphs of atleast // size=2template<class PP, class MP, class PAT_ST, template<class, typename, typename, template <typename> class > class CC,          template <typename> class ALLOC >void update_rmost_path(GRAPH_PATTERN*const& cand_pat) {  // How it works: no change in rmost-path (rmp) if last edge added was back-  // edge - only append to canonical code.   // In case of fwd edge, rmp is modified as well  num_urmp++;    tt_update_rmp.start();  int new_vid=cand_pat->rmost_vid(); // vertex added to generate this candidate  typename GRAPH_PATTERN::RMP_T& rmost_path=cand_pat->_rmost_path;  // no change to rmp if this candidate was formed by back extension  // but canonical code must be updated  if(new_vid==*(rmost_path.end()-1)) {    typename GRAPH_PATTERN::CONST_EIT_PAIR eit_p=cand_pat->out_edges(new_vid);    eit_p.second--;    int back_vid=eit_p.second->first; // vid at back vertex of edge    typename GRAPH_PATTERN::CAN_CODE::FIVE_TUPLE new_tuple(new_vid, back_vid, cand_pat->label(new_vid), eit_p.second->second, cand_pat->label(back_vid));    cand_pat->_canonical_code.push_back(new_tuple);    return;  }  /// new edge is a fwd edge ///  int pvid=(cand_pat->out_edges(new_vid)).first->first; // parent of new_vid  typename GRAPH_PATTERN::RMP_T::iterator it=rmost_path.end()-1;  while(it!=rmost_path.begin()) {    if(*it==pvid)    break;    it=rmost_path.erase(it);    it--;  }  rmost_path.push_back(new_vid);  // update canonical code  typename GRAPH_PATTERN::CONST_EIT_PAIR eit_p=cand_pat->out_edges(new_vid);  typename GRAPH_PATTERN::CAN_CODE::FIVE_TUPLE new_tuple(pvid, new_vid, cand_pat->label(pvid), eit_p.first->second, cand_pat->label(new_vid));  cand_pat->_canonical_code.push_back(new_tuple);  tt_update_rmp.stop();}//end update_rmost_path()/** Returns true if given candidate is isomorphic;     correspondingly sets the bool flag in cand_pat as well */template<class PP, class MP, class PAT_ST, template<class, typename, typename, template <typename> class> class CC,         template <typename> class ALLOC >bool check_isomorphism(GRAPH_PATTERN*const& cand_pat) {  // How it works: it is a recursive test. At each recursive call, the   // minimal edge according to DFS ordering (gSpan) is determined. If this   // minimal edge is what cand_pat has at that level, then cand_pat passes   // test at that call and further recursive calls have to be made. This   // recursion continues till i) test failed at some level or ii) all edges   // are exhausted, when cand_pat is declared to have passes isomorphsim test  tt_iso_chk.start();  typedef CC<GRAPH_PROP, typename GRAPH_PATTERN::VERTEX_T, typename GRAPH_PATTERN::EDGE_T, ALLOC > CAN_CODE;  // first step is get rmp updated  update_rmost_path(cand_pat);#ifdef PRINT  cout<<"checking isomorphism for: "<<endl<<cand_pat->canonical_code()<<endl;#endif  typename GRAPH_PATTERN::EDGE_T e; // least label of edge  typename GRAPH_PATTERN::VERTEX_T src_v, dest_v; // least labelled vertices of an edge  vector<pair<int, int> > ids; // ids with least labelled edges  vector<CAN_CODE> new_codes;  tt_rest.start();  // default startup values  src_v=cand_pat->label(0);  dest_v=cand_pat->label(1);  if(!cand_pat->get_out_edge(0, 1, e)) {    cerr<<"check_iso(graph): get_out_edge failed in startup"<<endl;    tt_iso_chk.stop();    return false;  }  tt_rest.stop();  iso_startup(cand_pat, src_v, dest_v, e, ids);  // create separate codes for each pair in ids  // each such pair shall have to be tested for isomorphism    tt_rest.start();  for(unsigned int i=0; i<ids.size(); i++) {    CAN_CODE new_cc(typename CAN_CODE::FIVE_TUPLE(0, 1, cand_pat->label(ids[i].first), e, cand_pat->label(ids[i].second)), ids[i].first, ids[i].second);    new_cc.init_rmp();    new_codes.push_back(new_cc);  }  // codes in new_codes are all equivalent  // check if any one is < current one  if(new_codes[0][0]<cand_pat->_canonical_code[0]) {#ifdef PRINT      cout<<"Isomorphism decision made at first level: new_tuple="<<new_codes[0][0]<<endl;      cout<<"current_code="<<cand_pat->_canonical_code[0]<<endl;#endif      cand_pat->_is_canonical=false;      tt_iso_chk.stop();      return false;    }  tt_rest.stop();  for(unsigned int i=0; i<new_codes.size(); i++) {    tt_minimal.start();    bool r = minimal(cand_pat, new_codes[i]);    if(!r) {      cand_pat->_is_canonical=false;      tt_iso_chk.stop();      return false;    }    tt_minimal.stop();  }  // execution reaches here iff all codes were found to be >= current one  cand_pat->_is_canonical=true;  tt_iso_chk.stop();  return true;}//end check_isomorphism()// find minimal pair, acc to DFS orderingtemplate<typename PATTERN>void iso_startup(const PATTERN* cand_pat, typename PATTERN::VERTEX_T& src_v, typename PATTERN::VERTEX_T& dest_v, typename PATTERN::EDGE_T& e, vector<pair<int, int> >& ids) {    num_startup++;    tt_iso_startup.start();  // find minimal pair, acc to DFS ordering  typename PATTERN::CONST_IT it;  typename PATTERN::CONST_EIT_PAIR eit_p;  for(it=cand_pat->begin(); it!=cand_pat->end(); it++) {    if(it->v>src_v)    continue;    eit_p=cand_pat->out_edges(it->id);          if(it->v<src_v) {      // new minimal src label found        // find edge with least label            ids.clear();      e=eit_p.first->second;      src_v=it->v;      dest_v=cand_pat->label(eit_p.first->first);      ids.push_back(make_pair(it->id, eit_p.first->first));      eit_p.first++;    }          while(eit_p.first!=eit_p.second) {      if(eit_p.first->second<=e) {        if(eit_p.first->second<e) {          // new minimal edge found          ids.clear();          e=eit_p.first->second;          dest_v=cand_pat->label(eit_p.first->first);          ids.push_back(make_pair(it->id, eit_p.first->first));          eit_p.first++;          continue;        }        if(cand_pat->label(eit_p.first->first)<=dest_v) {          if(cand_pat->label(eit_p.first->first)<dest_v) {            // new least dest label found            ids.clear();            dest_v=cand_pat->label(eit_p.first->first);          }          ids.push_back(make_pair(it->id, eit_p.first->first));        }      }//end if eit_p.first->second<=e      eit_p.first++;    }    }//end for  tt_iso_startup.stop();}//end iso_startup()/** Returns true if cand_pat's can_code is <= the one generated from new_code;    calls itself recursively to accomplish this task */template<typename PATTERN, typename CAN_CODE>bool minimal(const PATTERN* cand_pat, CAN_CODE& new_code) {  element_parser<typename PATTERN::EDGE_T> ed_prsr;  element_parser<typename PATTERN::VERTEX_T> vt_prsr;  // starts by checking if a back-edge can be added  // else, the minimal fwd edge is added and minimality checked again  //// quick check on the status of minimality test ////  // if all edges have been added to new_code, then no new edges can be added  // hence cand_pat is minimal  if(cand_pat->canonical_code().size()==new_code.size())    return true;  const CAN_CODE& current_code=cand_pat->canonical_code();  typename CAN_CODE::CONST_IT cc_it=new_code.end()-1;  bool is_last_fwd=(cc_it->_i<cc_it->_j); // denotes if last edge in new_code was a fwd edge  int last_vid=(is_last_fwd)? cc_it->_j: cc_it->_i; // vid to which edge shall be added    int last_vid_g=new_code.gid(last_vid);  typename PATTERN::CONST_EIT_PAIR eit_p=cand_pat->out_edges(last_vid_g);  int code_index=new_code.size();  typename CAN_CODE::RMP_T& rmp=new_code.rmost_path();  typename CAN_CODE::RMP_T::iterator rmp_it;  ///// first try to add BACK EDGE /////////  int back_vid, last_back_vid;  back_vid=last_vid;  typename PATTERN::EDGE_T e=typename PATTERN::EDGE_T();  if(is_last_fwd)    // relatively straight forward - add the farthest back edge you find    last_back_vid=-1;  else    // add a back edge only if it's after the last back edge present    last_back_vid=cc_it->_j;    while(eit_p.first!=eit_p.second) {    rmp_it=rmp.end()-3;      // check if this vid occurs on the rmp of can code    while(rmp_it>=rmp.begin()) {      if(*rmp_it==new_code.cid(eit_p.first->first))        break;      if(*rmp_it<new_code.cid(eit_p.first->first))        rmp_it=rmp.begin();        rmp_it--;    }    if(rmp_it<rmp.begin()) {      eit_p.first++;      continue;    }    // atleast 2 nodes prior to last one    if(new_code.cid(eit_p.first->first)<back_vid // this vertex is farthest one seen so far       && new_code.cid(eit_p.first->first)>last_back_vid) { // a valid back edge must end                                                                // at a vertex after last_back_vid       back_vid=new_code.cid(eit_p.first->first);       e=eit_p.first->second;    }    eit_p.first++;  }        if(back_vid!=last_vid) {    // valid back edge found    typename PATTERN::VERTEX_T lbl1=cand_pat->label(new_code.gid(last_vid));    typename PATTERN::VERTEX_T lbl2=cand_pat->label(new_code.gid(back_vid));    typename CAN_CODE::FIVE_TUPLE new_tuple(last_vid, back_vid, lbl1, e, lbl2);    if(new_tuple<current_code[code_index]) {#ifdef PRINT      cout<<"decision at back-edge: new tuple is more minimal"<<endl;      cout<<"new_tuple="<<new_tuple<<endl;      cout<<"curent_tuple="<<current_code[code_index]<<endl;      cout<<"current_code"<<current_code<<endl;#endif      return false;    }    if(current_code[code_index]<new_tuple) {#ifdef PRINT      cout<<"decision at back-edge: current tuple is more minimal"<<endl;      cout<<"new_tuple="<<new_tuple<<endl;      cout<<"curent_tuple="<<current_code[code_index]<<endl;      cout<<"current_code"<<current_code<<endl;#endif      return true;    }    else {      new_code.append(new_tuple);      // no changes to new_code's rmp, nor to the cid-gid mappings since      // back edge implies both vertices were already present in it      return minimal(cand_pat, new_code);    }  }    // execution gets here iff back-edge add failed  ///// try to add a FWD EDGE /////  // how to: find the deepest outgoing edge, and among all such edges find the   // minimal one, i.e. least edge-label + least dest-label  bool fwd_found=false;  rmp_it=rmp.end()-1;  last_vid=*rmp_it;  vector<int> new_vids; // equivalent minimal vertices whose minimality has to be checked recursively  e=ed_prsr.parse_element(INF_LABEL);  typename PATTERN::VERTEX_T dest_v=vt_prsr.parse_element(INF_LABEL);  while(rmp_it>=rmp.begin()) {    // get neighbors of current vertex    eit_p=cand_pat->out_edges(new_code.gid(*rmp_it));    // try to find minimal fwd edge    while(eit_p.first!=eit_p.second) {      if(new_code.cid(eit_p.first->first)!=-1) {        // this vertex is already part of minimal code (CHECK THIS ??)        eit_p.first++;        continue;      }      if(eit_p.first->second<=e) {        // minimal edge        typename PATTERN::VERTEX_T curr_lbl=cand_pat->label(eit_p.first->first);        if(eit_p.first->second<e) {          // new minimal edge found          new_vids.clear();          e=eit_p.first->second;          dest_v=curr_lbl;        }        if(curr_lbl<=dest_v) {          // minimal dest label          if(curr_lbl<dest_v) {            new_vids.clear();            dest_v=curr_lbl;          }          new_vids.push_back(eit_p.first->first);        }      }      eit_p.first++;    }//end while eit_p.first..    if(!new_vids.empty()) {      // fwd extension found at this level      fwd_found=true;      break;    }    rmp_it--;    rmp.pop_back();  }//end while !fwd_found..  if(!fwd_found || rmp_it<rmp.begin()) {    // no fwd edge extension could be found i.e. all fwd edges have been added    // so this code is minimal    //cout<<"Isomorphism decision at fwd-edge: all edges exhausted"<<endl;    return true;  }  typename CAN_CODE::FIVE_TUPLE new_tuple(*rmp_it, last_vid+1, cand_pat->label(new_code.gid(*rmp_it)), e, cand_pat->label(new_vids[0]));  if(new_tuple<current_code[code_index]) {    // new edge is more minimal#ifdef PRINT    cout<<"decision at fwd-edge: new_edge is more minimal"<<endl;    cout<<"new_tuple: "<<new_tuple<<endl;    cout<<"current_tuple: "<<current_code[code_index]<<endl;    cout<<"current_code="<<current_code<<endl;#endif    return false;  }  if(current_code[code_index]<new_tuple) {    // current tuple is more minimal#ifdef PRINT    cout<<"decision at fwd-edge: current tuple is more minimal"<<endl;    cout<<"new_tuple: "<<new_tuple<<endl;    cout<<"current_tuple: "<<current_code[code_index]<<endl;    cout<<"current_code="<<current_code<<endl;#endif    return true;  }  // check minimality against each new code  for(unsigned int i=0; i<new_vids.size(); i++) {    CAN_CODE next_code=new_code;    next_code.append(new_tuple, new_code.gid(*rmp_it), new_vids[i]);    next_code.append_rmp(last_vid+1);    if(!minimal(cand_pat, next_code))      return false;  }  // all codes were greater than cand_pat's code#ifdef PRINT  cout<<"decision at fwd-edge: this code more minimal than all codes"<<endl;#endif  return true;}//end minimal()#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -