src/work/klao/path.h
author marci
Mon, 05 Apr 2004 16:52:46 +0000
changeset 303 1b377a730d02
parent 226 616bc397c83a
child 369 dc9c19f4ca9a
permissions -rw-r--r--
konvergalunk, konvergalunk...
     1 // -*- c++ -*- //
     2 
     3 /**
     4  *
     5  * Class for representing paths in graphs.
     6  *
     7  */
     8 
     9 #ifndef HUGO_PATH_H
    10 #define HUGO_PATH_H
    11 
    12 #include <deque>
    13 #include <algorithm>
    14 
    15 #include <invalid.h>
    16 
    17 namespace hugo {
    18 
    19   /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
    20      elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
    21 
    22   template<typename Graph>
    23   class Path {
    24 
    25   public:
    26     typedef typename Graph::Edge GraphEdge;
    27     typedef typename Graph::Node GraphNode;
    28     class NodeIt;
    29     class EdgeIt;
    30 
    31   protected:
    32     Graph& G;
    33     // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
    34     // iranyitasat:
    35     GraphNode _first, _last;
    36     typedef std::deque<GraphEdge> Container;
    37     Container edges;
    38 
    39   public:
    40 
    41     Path(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
    42 
    43     /// Subpath defined by two nodes.
    44     /// Nodes may be in reversed order, then
    45     /// we contstruct the reversed path.
    46     Path(const Path &P, const NodeIt &a, const NodeIt &b);
    47     /// Subpath defined by two edges. Contains edges in [a,b)
    48     /// It is an error if the two edges are not in order!
    49     Path(const Path &P, const EdgeIt &a, const EdgeIt &b);
    50     
    51     size_t length() const { return edges.size(); }
    52     GraphNode from() const { return _first; }
    53     GraphNode to() const { return _last; }
    54 
    55     NodeIt& first(NodeIt &n) const { return nth(n, 0); }
    56     EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
    57     template<typename It>
    58     It first() const { 
    59       It e;
    60       first(e);
    61       return e; 
    62     }
    63 
    64     NodeIt& nth(NodeIt &, size_t) const;
    65     EdgeIt& nth(EdgeIt &, size_t) const;
    66     template<typename It>
    67     It nth(size_t n) const { 
    68       It e;
    69       nth(e, n);
    70       return e; 
    71     }
    72 
    73     bool valid(const NodeIt &n) const { return n.idx <= length(); }
    74     bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
    75 
    76     bool isForward(const EdgeIt &e) const { return e.forw; }
    77 
    78     /// index of a node on the path. Returns length+2 for the invalid NodeIt
    79     int index(const NodeIt &n) const { return n.idx; }
    80     /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
    81     int index(const EdgeIt &e) const { return e.it - edges.begin(); }
    82 
    83     EdgeIt& next(EdgeIt &e) const;
    84     NodeIt& next(NodeIt &n) const;
    85     template <typename It>
    86     It getNext(It it) const {
    87       It tmp(it); return next(tmp);
    88     }
    89 
    90     // A path is constructed using the following four functions.
    91     // They return false if the requested operation is inconsistent
    92     // with the path constructed so far.
    93     // If your path has only one edge you MUST set either "from" or "to"!
    94     // So you probably SHOULD call it in any case to be safe (and check the
    95     // returned value to check if your path is consistent with your idea).
    96     bool pushFront(const GraphEdge &e);
    97     bool pushBack(const GraphEdge &e);
    98     bool setFrom(const GraphNode &n);
    99     bool setTo(const GraphNode &n);
   100 
   101     // WARNING: these two functions return the head/tail of an edge with
   102     // respect to the direction of the path!
   103     // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if 
   104     // P.forward(e) is true (or the edge is a loop)!
   105     NodeIt head(const EdgeIt& e) const;
   106     NodeIt tail(const EdgeIt& e) const;
   107 
   108     // FIXME: ezeknek valami jobb nev kellene!!!
   109     GraphEdge graphEdge(const EdgeIt& e) const;
   110     GraphNode graphNode(const NodeIt& n) const;
   111 
   112 
   113     /*** Iterator classes ***/
   114     class EdgeIt {
   115       friend class Path;
   116 
   117       typename Container::const_iterator it;
   118       bool forw;
   119     public:
   120       // FIXME: jarna neki ilyen is...
   121       // EdgeIt(Invalid);
   122 
   123       bool forward() const { return forw; }
   124 
   125       bool operator==(const EdgeIt& e) const { return it==e.it; }
   126       bool operator!=(const EdgeIt& e) const { return it!=e.it; }
   127       bool operator<(const EdgeIt& e) const { return it<e.it; }
   128     };
   129 
   130     class NodeIt {
   131       friend class Path;
   132       friend class EdgeIt;
   133 
   134       size_t idx;
   135       bool tail;  // Is this node the tail of the edge with same idx?
   136 
   137     public:
   138       // FIXME: jarna neki ilyen is...
   139       // NodeIt(Invalid);
   140 
   141       bool operator==(const NodeIt& n) const { return idx==n.idx; }
   142       bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
   143       bool operator<(const NodeIt& n) const { return idx<n.idx; }
   144     };
   145 
   146   private:
   147     bool edgeIncident(const GraphEdge &e, const GraphNode &a,
   148 		      GraphNode &b);
   149     bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
   150   };
   151 
   152   template<typename Gr>
   153   typename Path<Gr>::EdgeIt&
   154   Path<Gr>::next(Path::EdgeIt &e) const {
   155     if( e.it == edges.end() ) 
   156       return e;
   157 
   158     GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
   159     ++e.it;
   160 
   161     // Invalid edgeit is always forward :)
   162     if( e.it == edges.end() ) {
   163       e.forw = true;
   164       return e;
   165     }
   166 
   167     e.forw = ( G.tail(*e.it) == common_node );
   168     return e;
   169   }
   170 
   171   template<typename Gr>
   172   typename Path<Gr>::NodeIt& Path<Gr>::next(NodeIt &n) const {
   173     if( n.idx >= length() ) {
   174       // FIXME: invalid
   175       n.idx = length()+1;
   176       return n;
   177     }
   178 
   179     
   180     GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
   181 			      G.tail(edges[n.idx]) );
   182     ++n.idx;
   183     if( n.idx < length() ) {
   184       n.tail = ( next_node == G.tail(edges[n.idx]) );
   185     }
   186     else {
   187       n.tail = true;
   188     }
   189 
   190     return n;
   191   }
   192 
   193   template<typename Gr>
   194   bool Path<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
   195 			  GraphNode &b) {
   196     if( G.tail(e) == a ) {
   197       b=G.head(e);
   198       return true;
   199     }
   200     if( G.head(e) == a ) {
   201       b=G.tail(e);
   202       return true;
   203     }
   204     return false;
   205   }
   206 
   207   template<typename Gr>
   208   bool Path<Gr>::connectTwoEdges(const GraphEdge &e,
   209 			     const GraphEdge &f) {
   210     if( edgeIncident(f, G.tail(e), _last) ) {
   211       _first = G.head(e);
   212       return true;
   213     }
   214     if( edgeIncident(f, G.head(e), _last) ) {
   215       _first = G.tail(e);
   216       return true;
   217     }
   218     return false;
   219   }
   220 
   221   template<typename Gr>
   222   bool Path<Gr>::pushFront(const GraphEdge &e) {
   223     if( G.valid(_first) ) {
   224 	if( edgeIncident(e, _first, _first) ) {
   225 	  edges.push_front(e);
   226 	  return true;
   227 	}
   228 	else
   229 	  return false;
   230     }
   231     else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
   232       edges.push_front(e);
   233       return true;
   234     }
   235     else
   236       return false;
   237   }
   238 
   239   template<typename Gr>
   240   bool Path<Gr>::pushBack(const GraphEdge &e) {
   241     if( G.valid(_last) ) {
   242 	if( edgeIncident(e, _last, _last) ) {
   243 	  edges.push_back(e);
   244 	  return true;
   245 	}
   246 	else
   247 	  return false;
   248     }
   249     else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
   250       edges.push_back(e);
   251       return true;
   252     }
   253     else
   254       return false;
   255   }
   256 
   257 
   258   template<typename Gr>
   259   bool Path<Gr>::setFrom(const GraphNode &n) {
   260     if( G.valid(_first) ) {
   261       return _first == n;
   262     }
   263     else {
   264       if( length() > 0) {
   265 	if( edgeIncident(edges[0], n, _last) ) {
   266 	  _first = n;
   267 	  return true;
   268 	}
   269 	else return false;
   270       }
   271       else {
   272 	_first = _last = n;
   273 	return true;
   274       }
   275     }
   276   }
   277 
   278   template<typename Gr>
   279   bool Path<Gr>::setTo(const GraphNode &n) {
   280     if( G.valid(_last) ) {
   281       return _last == n;
   282     }
   283     else {
   284       if( length() > 0) {
   285 	if( edgeIncident(edges[0], n, _first) ) {
   286 	  _last = n;
   287 	  return true;
   288 	}
   289 	else return false;
   290       }
   291       else {
   292 	_first = _last = n;
   293 	return true;
   294       }
   295     }
   296   }
   297 
   298 
   299   template<typename Gr>
   300   typename Path<Gr>::NodeIt
   301   Path<Gr>::tail(const EdgeIt& e) const {
   302     NodeIt n;
   303 
   304     if( e.it == edges.end() ) {
   305       // FIXME: invalid-> invalid
   306       n.idx = length() + 1;
   307       n.tail = true;
   308       return n;
   309     }
   310 
   311     n.idx = e.it-edges.begin();
   312     n.tail = e.forw;
   313     return n;
   314   }
   315 
   316   template<typename Gr>
   317   typename Path<Gr>::NodeIt
   318   Path<Gr>::head(const EdgeIt& e) const {
   319     if( e.it == edges.end()-1 ) {
   320       return _last;
   321     }
   322 
   323     EdgeIt next_edge = e;
   324     next(next_edge);
   325     return tail(next_edge);
   326   }
   327       
   328   template<typename Gr>
   329   typename Path<Gr>::GraphEdge
   330   Path<Gr>::graphEdge(const EdgeIt& e) const {
   331     if( e.it != edges.end() ) {
   332       return *e.it;
   333     }
   334     else {
   335       return INVALID;
   336     }
   337   }
   338   
   339   template<typename Gr>
   340   typename Path<Gr>::GraphNode
   341   Path<Gr>::graphNode(const NodeIt& n) const {
   342     if( n.idx < length() ) {
   343       return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
   344     }
   345     else if( n.idx == length() ) {
   346       return _last;
   347     }
   348     else {
   349       return INVALID;
   350     }
   351   }
   352 
   353   template<typename Gr>
   354   typename Path<Gr>::EdgeIt& Path<Gr>::nth(EdgeIt &e, size_t k) const {
   355     if( k<0 || k>=length() ) {
   356       // FIXME: invalid EdgeIt
   357       e.it = edges.end();
   358       e.forw = true;
   359       return e;
   360     }
   361 
   362     e.it = edges.begin()+k;
   363     if(k==0) {
   364       e.forw = ( G.tail(*e.it) == _first );
   365     }
   366     else {
   367       e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
   368 		 G.tail(*e.it) == G.head(edges[k-1]) );
   369     }
   370     return e;
   371   }
   372     
   373   template<typename Gr>
   374   typename Path<Gr>::NodeIt& Path<Gr>::nth(NodeIt &n, size_t k) const {
   375     if( k<0 || k>length() ) {
   376       // FIXME: invalid NodeIt
   377       n.idx = length()+1;
   378       n.tail = true;
   379       return n;
   380     }
   381     if( k==length() ) {
   382       n.idx = length();
   383       n.tail = true;
   384       return n;
   385     }
   386     n = tail(nth<EdgeIt>(k));
   387     return n;
   388   }
   389 
   390   // Reszut konstruktorok:
   391 
   392 
   393   template<typename Gr>
   394   Path<Gr>::Path(const Path &P, const EdgeIt &a, const EdgeIt &b) :
   395     G(P.G), edges(a.it, b.it)    // WARNING: if b.it < a.it this will blow up! 
   396   {
   397     if( G.valid(P._first) && a.it < P.edges.end() ) {
   398       _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
   399       if( b.it < P.edges.end() ) {
   400 	_last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
   401       }
   402       else {
   403 	_last = P._last;
   404       }
   405     }
   406   }
   407 
   408   template<typename Gr>
   409   Path<Gr>::Path(const Path &P, const NodeIt &a, const NodeIt &b) :
   410     G(P.G)
   411   {
   412     if( !P.valid(a) || !P.valid(b) )
   413       return;
   414 
   415     int ai = a.idx, bi = b.idx;
   416     if( bi<ai )
   417       swap(ai,bi);
   418     
   419     edges.resize(bi-ai);
   420     copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
   421 
   422     _first = P.graphNode(a);
   423     _last = P.graphNode(b);
   424   }
   425 
   426 
   427 } // namespace hugo
   428 
   429 #endif // HUGO_PATH_H