CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/DetectorDescription/Core/interface/graphwalker.h

Go to the documentation of this file.
00001 #ifndef x_graphwalker_h
00002 #define x_graphwalker_h
00003 
00004 #include "DetectorDescription/Core/interface/adjgraph.h"
00005 
00006 #include <vector>
00007 #include <queue>
00008 
00009 //#include <iostream> // debug
00010 
00012 template <class N, class E>
00013 class graphwalker
00014 {
00015 public:
00016   typedef typename graph<N,E>::index_type index_type;
00017   
00018   typedef typename graph<N,E>::index_result index_result;
00019 
00020   typedef typename graph<N,E>::edge_type edge_type;
00021   
00022   typedef typename graph<N,E>::edge_list edge_list;
00023   
00024   typedef typename graph<N,E>::edge_iterator edge_iterator;
00025   
00026   typedef typename graph<N,E>::const_edge_iterator const_edge_iterator;
00027   
00028   // only a const-edge_range!
00029   typedef typename std::pair<const_edge_iterator, const_edge_iterator> edge_range;
00030   
00031   //typedef std::pair<edge_range,edge_range> stacked_element;
00032   
00033   typedef std::vector<edge_range> stack_type;
00034   typedef std::queue<edge_type> bfs_type;
00035 
00036   typedef bool /*std::pair<const N &, bool>*/ result_type;
00037   
00038   typedef typename graph<N,E>::value_type value_type;
00039   
00040   
00041 public:
00043   graphwalker(const graph<N,E> &);
00044 
00046   graphwalker(const graph<N,E> &, const N & );
00047    
00048   // operations
00049   
00050   result_type firstChild();
00051   
00052   result_type nextSibling();
00053   
00054   result_type parent();
00055   
00056   result_type next();
00057   
00058   inline value_type current() const;
00059   
00060   result_type next_bfs();
00061   value_type current_bfs() const;
00062     
00063   void reset();
00064   
00065   const stack_type & stack() const { return stack_;}
00066   
00067 protected:
00068   // stack_.back().first corresponds to index of the current node!
00069   stack_type stack_; // hierarchical stack used in navigation
00070   bfs_type queue_; // breath first search queue
00071   edge_list root_; // root of the walker
00072   //std::vector<N> rootCandidates_; 
00073   const graph<N,E> & graph_;
00074   //jklsdfjklsdfkljsdfakjl;
00075 private:
00076   graphwalker();
00077 
00078 };
00079 
00080 
00081 
00082 template<class N, class E>
00083 graphwalker<N,E>::graphwalker(const graph<N,E> & g)
00084  : graph_(g)
00085 {  // complexity = (no nodes) * (no edges)
00086    graph_.findRoots(root_);
00087    stack_.push_back(edge_range(root_.begin(),root_.end())); 
00088    if (root_.size()) {
00089      queue_.push(root_[0]);
00090    }
00091 }
00092 
00093 
00094 template<class N, class E>
00095 graphwalker<N,E>::graphwalker(const graph<N,E> & g, const N & root)
00096  : graph_(g)
00097 {
00098    index_result rr = graph_.nodeIndex(root);
00099    if (!rr.second) // no such root node, no walker can be created!
00100      throw root;
00101      
00102    root_.push_back(edge_type(rr.first, 0));
00103    stack_.push_back(edge_range(root_.begin(),root_.end()));   
00104    queue_.push(root_[0]);
00105 }
00106 
00107 
00108 template<class N, class E>
00109 typename graphwalker<N,E>::value_type graphwalker<N,E>::current() const
00110 {
00111    const edge_range & er = stack_.back();
00112 /*
00113    const N & n = graph_.nodeData(er.first->first);
00114    const E & e = er.first->first;
00115    return value_type(n,e);
00116 */   
00117    return value_type(graph_.nodeData(er.first->first), graph_.edgeData(er.first->second)); 
00118 }
00119 
00120 
00121 template<class N, class E>
00122 typename graphwalker<N,E>::value_type graphwalker<N,E>::current_bfs() const
00123 {
00124    const edge_type & e = queue_.front();
00125    return value_type(graph_.nodeData(e.first), graph_.edgeData(e.second)); 
00126 }
00127 
00128 
00129 template<class N, class E>
00130 void graphwalker<N,E>::reset()
00131 {
00132   //std::cout << "graphwalker::reset" << std::endl;
00133   stack_.clear();
00134   stack_.push_back(edge_range(root_.begin(),root_.end()));
00135   queue_.clear();
00136   if (root_.size()) {
00137     queue_.push(root_[0]);   
00138   }
00139 }
00140 
00141 
00142 template<class N, class E>
00143 typename graphwalker<N,E>::result_type graphwalker<N,E>::firstChild()
00144 {
00145    result_type result = false;
00146    const edge_range & adjEdges
00147      = graph_.edges(stack_.back().first->first);
00148    if (adjEdges.first != adjEdges.second) {
00149      stack_.push_back(adjEdges);
00150      result = true;
00151    }
00152    return result;
00153 }
00154 
00155 
00156 template<class N, class E>
00157 typename graphwalker<N,E>::result_type graphwalker<N,E>::nextSibling()
00158 {
00159    result_type result = false;
00160    //if (stack_.size() > 1) { only if single-root should be enforced ...
00161      edge_range & siblings = stack_.back();
00162      if (siblings.first != (siblings.second - 1) ) {
00163        ++siblings.first;
00164        result = true;
00165      }  
00166    //}
00167    return result;
00168 }
00169 
00170 
00171 template<class N, class E>
00172 typename graphwalker<N,E>::result_type graphwalker<N,E>::parent()
00173 {
00174    //std::cout << "graphwalker::parent()" << std::endl;
00175    result_type result = false;
00176    if (stack_.size()>1) {
00177      stack_.pop_back();
00178      result = true;
00179    }
00180    return result;
00181 }
00182 
00183 
00184 template<class N, class E>
00185 typename graphwalker<N,E>::result_type graphwalker<N,E>::next()
00186 {
00187    result_type result = false;
00188    if (firstChild()) {
00189      result = true;
00190    }  
00191    else if(stack_.size()>1 && nextSibling()) {
00192      result = true;
00193    }  
00194    else {  
00195      while(parent()) {
00196        if(stack_.size()>1 && nextSibling()) {
00197          result = true;
00198          break;
00199        }
00200      }
00201    }       
00202    return result;
00203 }   
00204 
00205 template<class N, class E>
00206 typename graphwalker<N,E>::result_type graphwalker<N,E>::next_bfs()
00207 {
00208    result_type result(false);
00209    if (!queue_.empty()) {
00210      const edge_type & e = queue_.front();
00211      const edge_range & er = graph_.edges(e.first);
00212      const_edge_iterator it(er.first), ed(er.second);
00213      for (; it != ed; ++it) {
00214        queue_.push(*it);
00215      }
00216      queue_.pop();
00217      if (!queue_.empty()) {
00218        result=true;
00219      }
00220    }
00221    return result;
00222 }
00223 #endif