src/work/klao/path.h
author marci
Fri, 21 May 2004 10:57:30 +0000
changeset 655 a9878222d5c8
parent 607 327f7cf13843
child 682 1ea8162ce638
permissions -rw-r--r--
bug correction in BidirGraphWrapper<Graph> default constructor
     1 // -*- c++ -*- //
     2 
     3 ///\ingroup datas
     4 ///\file
     5 ///\brief Classes for representing paths in graphs.
     6 
     7 #ifndef HUGO_PATH_H
     8 #define HUGO_PATH_H
     9 
    10 #include <deque>
    11 #include <vector>
    12 #include <algorithm>
    13 
    14 #include <hugo/invalid.h>
    15 #include <hugo/error.h>
    16 #include <debug.h>
    17 
    18 namespace hugo {
    19 
    20   /// \addtogroup datas
    21   /// @{
    22 
    23 
    24   //! \brief A structure for representing directed path in a graph.
    25   //!
    26   //! A structure for representing directed path in a graph.
    27   //! \param Graph The graph type in which the path is.
    28   //! \param DM DebugMode, defaults to DefaultDebugMode.
    29   //! 
    30   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
    31   //! and \c EdgeIt with the same usage. These types converts to the \c Node
    32   //! and \c Edge of the original graph.
    33   //!
    34   //! \todo Thoroughfully check all the range and consistency tests.
    35   template<typename Graph, typename DM = DefaultDebugMode>
    36   class DirPath {
    37   public:
    38     typedef typename Graph::Edge GraphEdge;
    39     typedef typename Graph::Node GraphNode;
    40     class NodeIt;
    41     class EdgeIt;
    42 
    43   protected:
    44     const Graph *gr;
    45     typedef std::vector<GraphEdge> Container;
    46     Container edges;
    47 
    48   public:
    49 
    50     /// \param _G The graph in which the path is.
    51     ///
    52     DirPath(const Graph &_G) : gr(&_G) {}
    53 
    54     /// \brief Subpath constructor.
    55     ///
    56     /// Subpath defined by two nodes.
    57     /// \warning It is an error if the two edges are not in order!
    58     DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
    59       if( DM::range_check && (!a.valid() || !b.valid) ) {
    60 	// FIXME: this check should be more elaborate...
    61 	fault("DirPath, subpath ctor: invalid bounding nodes");
    62       }
    63       gr = P.gr;
    64       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    65     }
    66 
    67     /// \brief Subpath constructor.
    68     ///
    69     /// Subpath defined by two edges. Contains edges in [a,b)
    70     /// \warning It is an error if the two edges are not in order!
    71     DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
    72       if( DM::range_check && (!a.valid() || !b.valid) ) {
    73 	// FIXME: this check should be more elaborate...
    74 	fault("DirPath, subpath ctor: invalid bounding nodes");
    75       }
    76       gr = P.gr;
    77       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    78     }
    79 
    80     /// Length of the path.
    81     size_t length() const { return edges.size(); }
    82     /// Returns whether the path is empty.
    83     bool empty() const { return edges.empty(); }
    84 
    85     /// Resets the path to an empty path.
    86     void clear() { edges.clear(); }
    87 
    88     /// \brief Starting point of the path.
    89     ///
    90     /// Starting point of the path.
    91     /// Returns INVALID if the path is empty.
    92     GraphNode from() const {
    93       return empty() ? INVALID : gr->tail(edges[0]);
    94     }
    95     /// \brief End point of the path.
    96     ///
    97     /// End point of the path.
    98     /// Returns INVALID if the path is empty.
    99     GraphNode to() const {
   100       return empty() ? INVALID : gr->head(edges[length()-1]);
   101     }
   102 
   103     /// \brief Initializes node or edge iterator to point to the first
   104     /// node or edge.
   105     ///
   106     /// \sa nth
   107     template<typename It>
   108     It& first(It &i) const { return i=It(*this); }
   109 
   110     /// \brief Initializes node iterator to point to the node of a given index.
   111     NodeIt& nth(NodeIt &i, int n) const {
   112       if( DM::range_check && (n<0 || n>int(length())) )
   113 	fault("DirPath::nth: index out of range");
   114       return i=NodeIt(*this, n);
   115     }
   116 
   117     /// \brief Initializes edge iterator to point to the edge of a given index.
   118     EdgeIt& nth(EdgeIt &i, int n) const {
   119       if( DM::range_check && (n<0 || n>=int(length())) )
   120 	fault("DirPath::nth: index out of range");
   121       return i=EdgeIt(*this, n);
   122     }
   123 
   124     /// Checks validity of a node or edge iterator.
   125     template<typename It>
   126     static
   127     bool valid(const It &i) { return i.valid(); }
   128 
   129     /// Steps the given node or edge iterator.
   130     template<typename It>
   131     static
   132     It& next(It &e) {
   133       if( DM::range_check && !e.valid() )
   134 	fault("DirPath::next() on invalid iterator");
   135       return ++e;
   136     }
   137 
   138     /// \brief Returns node iterator pointing to the head node of the
   139     /// given edge iterator.
   140     NodeIt head(const EdgeIt& e) const {
   141       if( DM::range_check && !e.valid() )
   142 	fault("DirPath::head() on invalid iterator");
   143       return NodeIt(*this, e.idx+1);
   144     }
   145 
   146     /// \brief Returns node iterator pointing to the tail node of the
   147     /// given edge iterator.
   148     NodeIt tail(const EdgeIt& e) const {
   149       if( DM::range_check && !e.valid() )
   150 	fault("DirPath::tail() on invalid iterator");
   151       return NodeIt(*this, e.idx);
   152     }
   153 
   154 
   155     /*** Iterator classes ***/
   156     class EdgeIt {
   157       friend class DirPath;
   158 
   159       int idx;
   160       const DirPath *p;
   161     public:
   162       EdgeIt() {}
   163       EdgeIt(Invalid) : idx(-1), p(0) {}
   164       EdgeIt(const DirPath &_p, int _idx = 0) :
   165 	idx(_idx), p(&_p) { validate(); }
   166 
   167       bool valid() const { return idx!=-1; }
   168 
   169       operator GraphEdge () const {
   170 	return valid() ? p->edges[idx] : INVALID;
   171       }
   172       EdgeIt& operator++() { ++idx; validate(); return *this; }
   173 
   174       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
   175       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
   176       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
   177 
   178     private:
   179       // FIXME: comparison between signed and unsigned...
   180       // Jo ez igy? Vagy esetleg legyen a length() int?
   181       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
   182     };
   183 
   184     class NodeIt {
   185       friend class DirPath;
   186 
   187       int idx;
   188       const DirPath *p;
   189     public:
   190       NodeIt() {}
   191       NodeIt(Invalid) : idx(-1), p(0) {}
   192       NodeIt(const DirPath &_p, int _idx = 0) :
   193 	idx(_idx), p(&_p) { validate(); }
   194 
   195       bool valid() const { return idx!=-1; }
   196 
   197       operator const GraphNode& () const {
   198 	if(idx >= p->length())
   199 	  return p->to();
   200 	else if(idx >= 0)
   201 	  return p->gr->tail(p->edges[idx]);
   202 	else
   203 	  return INVALID;
   204       }
   205       NodeIt& operator++() { ++idx; validate(); return *this; }
   206 
   207       bool operator==(const NodeIt& e) const { return idx==e.idx; }
   208       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
   209       bool operator<(const NodeIt& e) const { return idx<e.idx; }
   210 
   211     private:
   212       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
   213     };
   214 
   215     friend class Builder;    
   216 
   217     /**
   218      * \brief Class to build paths
   219      * 
   220      * \ingroup datas
   221      * This class is used to fill a path with edges.
   222      *
   223      * You can push new edges to the front and to the back of the path in
   224      * arbitrary order then you should commit these changes to the graph.
   225      *
   226      * Fundamentally, for most "Paths" (classes fulfilling the
   227      * PathConcept) while the builder is active (after the first modifying
   228      * operation and until the commit()) the original Path is in a
   229      * "transitional" state (operations ot it have undefined result). But
   230      * in the case of DirPath the original path is unchanged until the
   231      * commit. However we don't recomend that you use this feature.
   232      */
   233     class Builder {
   234       DirPath &P;
   235       Container front, back;
   236 
   237     public:
   238       ///\param _P the path you want to fill in.
   239       ///
   240       Builder(DirPath &_P) : P(_P) {}
   241 
   242       /// Sets the starting node of the path.
   243       
   244       /// Sets the starting node of the path. Edge added to the path
   245       /// afterwards have to be incident to this node.
   246       /// It should be called iff the path is empty and before any call to
   247       /// \ref pushFront() or \ref pushBack()
   248       void setStart(const GraphNode &) {}
   249 
   250       ///Push a new edge to the front of the path
   251 
   252       ///Push a new edge to the front of the path.
   253       ///\sa setStart
   254       void pushFront(const GraphEdge& e) {
   255 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
   256 	  fault("DirPath::Builder::pushFront: nonincident edge");
   257 	}
   258 	front.push_back(e);
   259       }
   260 
   261       ///Push a new edge to the back of the path
   262 
   263       ///Push a new edge to the back of the path.
   264       ///\sa setStart
   265       void pushBack(const GraphEdge& e) {
   266 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
   267 	  fault("DirPath::Builder::pushBack: nonincident edge");
   268 	}
   269 	back.push_back(e);
   270       }
   271 
   272       ///Commit the changes to the path.
   273       void commit() {
   274 	if( !(front.empty() && back.empty()) ) {
   275 	  Container tmp;
   276 	  tmp.reserve(front.size()+back.size()+P.length());
   277 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
   278 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
   279 	  tmp.insert(tmp.end(), back.begin(), back.end());
   280 	  P.edges.swap(tmp);
   281 	  front.clear();
   282 	  back.clear();
   283 	}
   284       }
   285 
   286       // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
   287       // Hogy kenyelmes egy ilyet hasznalni?
   288       void reserve(size_t r) {
   289 	front.reserve(r);
   290 	back.reserve(r);
   291       }
   292 
   293     private:
   294       bool empty() {
   295 	return front.empty() && back.empty() && P.empty();
   296       }
   297 
   298       GraphNode from() const {
   299 	if( ! front.empty() )
   300 	  return P.gr->tail(front[front.size()-1]);
   301 	else if( ! P.empty() )
   302 	  return P.gr->tail(P.edges[0]);
   303 	else if( ! back.empty() )
   304 	  return P.gr->tail(back[0]);
   305 	else
   306 	  return INVALID;
   307       }
   308       GraphNode to() const {
   309 	if( ! back.empty() )
   310 	  return P.gr->head(back[back.size()-1]);
   311 	else if( ! P.empty() )
   312 	  return P.gr->head(P.edges[P.length()-1]);
   313 	else if( ! front.empty() )
   314 	  return P.gr->head(front[0]);
   315 	else
   316 	  return INVALID;
   317       }
   318 
   319     };
   320 
   321   };
   322 
   323 
   324 
   325 
   326 
   327 
   328 
   329 
   330 
   331 
   332   /**********************************************************************/
   333 
   334 
   335   //! \brief A structure for representing undirected path in a graph.
   336   //!
   337   //! A structure for representing undirected path in a graph. Ie. this is
   338   //! a path in a \e directed graph but the edges should not be directed
   339   //! forward.
   340   //!
   341   //! \param Graph The graph type in which the path is.
   342   //! \param DM DebugMode, defaults to DefaultDebugMode.
   343   //! 
   344   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
   345   //! and \c EdgeIt with the same usage. These types converts to the \c Node
   346   //! and \c Edge of the original graph.
   347   //!
   348   //! \todo Thoroughfully check all the range and consistency tests.
   349   template<typename Graph, typename DM = DefaultDebugMode>
   350   class UndirPath {
   351   public:
   352     typedef typename Graph::Edge GraphEdge;
   353     typedef typename Graph::Node GraphNode;
   354     class NodeIt;
   355     class EdgeIt;
   356 
   357   protected:
   358     const Graph *gr;
   359     typedef std::vector<GraphEdge> Container;
   360     Container edges;
   361 
   362   public:
   363 
   364     /// \param _G The graph in which the path is.
   365     ///
   366     UndirPath(const Graph &_G) : gr(&_G) {}
   367 
   368     /// \brief Subpath constructor.
   369     ///
   370     /// Subpath defined by two nodes.
   371     /// \warning It is an error if the two edges are not in order!
   372     UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
   373       if( DM::range_check && (!a.valid() || !b.valid) ) {
   374 	// FIXME: this check should be more elaborate...
   375 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   376       }
   377       gr = P.gr;
   378       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   379     }
   380 
   381     /// \brief Subpath constructor.
   382     ///
   383     /// Subpath defined by two edges. Contains edges in [a,b)
   384     /// \warning It is an error if the two edges are not in order!
   385     UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
   386       if( DM::range_check && (!a.valid() || !b.valid) ) {
   387 	// FIXME: this check should be more elaborate...
   388 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   389       }
   390       gr = P.gr;
   391       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   392     }
   393 
   394     /// Length of the path.
   395     size_t length() const { return edges.size(); }
   396     /// Returns whether the path is empty.
   397     bool empty() const { return edges.empty(); }
   398 
   399     /// Resets the path to an empty path.
   400     void clear() { edges.clear(); }
   401 
   402     /// \brief Starting point of the path.
   403     ///
   404     /// Starting point of the path.
   405     /// Returns INVALID if the path is empty.
   406     GraphNode from() const {
   407       return empty() ? INVALID : gr->tail(edges[0]);
   408     }
   409     /// \brief End point of the path.
   410     ///
   411     /// End point of the path.
   412     /// Returns INVALID if the path is empty.
   413     GraphNode to() const {
   414       return empty() ? INVALID : gr->head(edges[length()-1]);
   415     }
   416 
   417     /// \brief Initializes node or edge iterator to point to the first
   418     /// node or edge.
   419     ///
   420     /// \sa nth
   421     template<typename It>
   422     It& first(It &i) const { return i=It(*this); }
   423 
   424     /// \brief Initializes node iterator to point to the node of a given index.
   425     NodeIt& nth(NodeIt &i, int n) const {
   426       if( DM::range_check && (n<0 || n>int(length())) )
   427 	fault("UndirPath::nth: index out of range");
   428       return i=NodeIt(*this, n);
   429     }
   430 
   431     /// \brief Initializes edge iterator to point to the edge of a given index.
   432     EdgeIt& nth(EdgeIt &i, int n) const {
   433       if( DM::range_check && (n<0 || n>=int(length())) )
   434 	fault("UndirPath::nth: index out of range");
   435       return i=EdgeIt(*this, n);
   436     }
   437 
   438     /// Checks validity of a node or edge iterator.
   439     template<typename It>
   440     static
   441     bool valid(const It &i) { return i.valid(); }
   442 
   443     /// Steps the given node or edge iterator.
   444     template<typename It>
   445     static
   446     It& next(It &e) {
   447       if( DM::range_check && !e.valid() )
   448 	fault("UndirPath::next() on invalid iterator");
   449       return ++e;
   450     }
   451 
   452     /// \brief Returns node iterator pointing to the head node of the
   453     /// given edge iterator.
   454     NodeIt head(const EdgeIt& e) const {
   455       if( DM::range_check && !e.valid() )
   456 	fault("UndirPath::head() on invalid iterator");
   457       return NodeIt(*this, e.idx+1);
   458     }
   459 
   460     /// \brief Returns node iterator pointing to the tail node of the
   461     /// given edge iterator.
   462     NodeIt tail(const EdgeIt& e) const {
   463       if( DM::range_check && !e.valid() )
   464 	fault("UndirPath::tail() on invalid iterator");
   465       return NodeIt(*this, e.idx);
   466     }
   467 
   468 
   469     /*** Iterator classes ***/
   470     class EdgeIt {
   471       friend class UndirPath;
   472 
   473       int idx;
   474       const UndirPath *p;
   475     public:
   476       EdgeIt() {}
   477       EdgeIt(Invalid) : idx(-1), p(0) {}
   478       EdgeIt(const UndirPath &_p, int _idx = 0) :
   479 	idx(_idx), p(&_p) { validate(); }
   480 
   481       bool valid() const { return idx!=-1; }
   482 
   483       operator GraphEdge () const {
   484 	return valid() ? p->edges[idx] : INVALID;
   485       }
   486       EdgeIt& operator++() { ++idx; validate(); return *this; }
   487 
   488       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
   489       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
   490       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
   491 
   492     private:
   493       // FIXME: comparison between signed and unsigned...
   494       // Jo ez igy? Vagy esetleg legyen a length() int?
   495       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
   496     };
   497 
   498     class NodeIt {
   499       friend class UndirPath;
   500 
   501       int idx;
   502       const UndirPath *p;
   503     public:
   504       NodeIt() {}
   505       NodeIt(Invalid) : idx(-1), p(0) {}
   506       NodeIt(const UndirPath &_p, int _idx = 0) :
   507 	idx(_idx), p(&_p) { validate(); }
   508 
   509       bool valid() const { return idx!=-1; }
   510 
   511       operator const GraphNode& () const {
   512 	if(idx >= p->length())
   513 	  return p->to();
   514 	else if(idx >= 0)
   515 	  return p->gr->tail(p->edges[idx]);
   516 	else
   517 	  return INVALID;
   518       }
   519       NodeIt& operator++() { ++idx; validate(); return *this; }
   520 
   521       bool operator==(const NodeIt& e) const { return idx==e.idx; }
   522       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
   523       bool operator<(const NodeIt& e) const { return idx<e.idx; }
   524 
   525     private:
   526       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
   527     };
   528 
   529     friend class Builder;    
   530 
   531     /**
   532      * \brief Class to build paths
   533      * 
   534      * \ingroup datas
   535      * This class is used to fill a path with edges.
   536      *
   537      * You can push new edges to the front and to the back of the path in
   538      * arbitrary order then you should commit these changes to the graph.
   539      *
   540      * Fundamentally, for most "Paths" (classes fulfilling the
   541      * PathConcept) while the builder is active (after the first modifying
   542      * operation and until the commit()) the original Path is in a
   543      * "transitional" state (operations ot it have undefined result). But
   544      * in the case of UndirPath the original path is unchanged until the
   545      * commit. However we don't recomend that you use this feature.
   546      */
   547     class Builder {
   548       UndirPath &P;
   549       Container front, back;
   550 
   551     public:
   552       ///\param _P the path you want to fill in.
   553       ///
   554       Builder(UndirPath &_P) : P(_P) {}
   555 
   556       /// Sets the starting node of the path.
   557       
   558       /// Sets the starting node of the path. Edge added to the path
   559       /// afterwards have to be incident to this node.
   560       /// It should be called iff the path is empty and before any call to
   561       /// \ref pushFront() or \ref pushBack()
   562       void setStart(const GraphNode &) {}
   563 
   564       ///Push a new edge to the front of the path
   565 
   566       ///Push a new edge to the front of the path.
   567       ///\sa setStart
   568       void pushFront(const GraphEdge& e) {
   569 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
   570 	  fault("UndirPath::Builder::pushFront: nonincident edge");
   571 	}
   572 	front.push_back(e);
   573       }
   574 
   575       ///Push a new edge to the back of the path
   576 
   577       ///Push a new edge to the back of the path.
   578       ///\sa setStart
   579       void pushBack(const GraphEdge& e) {
   580 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
   581 	  fault("UndirPath::Builder::pushBack: nonincident edge");
   582 	}
   583 	back.push_back(e);
   584       }
   585 
   586       ///Commit the changes to the path.
   587       void commit() {
   588 	if( !(front.empty() && back.empty()) ) {
   589 	  Container tmp;
   590 	  tmp.reserve(front.size()+back.size()+P.length());
   591 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
   592 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
   593 	  tmp.insert(tmp.end(), back.begin(), back.end());
   594 	  P.edges.swap(tmp);
   595 	  front.clear();
   596 	  back.clear();
   597 	}
   598       }
   599 
   600       // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
   601       // Hogy kenyelmes egy ilyet hasznalni?
   602       void reserve(size_t r) {
   603 	front.reserve(r);
   604 	back.reserve(r);
   605       }
   606 
   607     private:
   608       bool empty() {
   609 	return front.empty() && back.empty() && P.empty();
   610       }
   611 
   612       GraphNode from() const {
   613 	if( ! front.empty() )
   614 	  return P.gr->tail(front[front.size()-1]);
   615 	else if( ! P.empty() )
   616 	  return P.gr->tail(P.edges[0]);
   617 	else if( ! back.empty() )
   618 	  return P.gr->tail(back[0]);
   619 	else
   620 	  return INVALID;
   621       }
   622       GraphNode to() const {
   623 	if( ! back.empty() )
   624 	  return P.gr->head(back[back.size()-1]);
   625 	else if( ! P.empty() )
   626 	  return P.gr->head(P.edges[P.length()-1]);
   627 	else if( ! front.empty() )
   628 	  return P.gr->head(front[0]);
   629 	else
   630 	  return INVALID;
   631       }
   632 
   633     };
   634 
   635   };
   636 
   637 
   638 
   639 
   640 
   641 
   642 
   643 
   644 
   645 
   646   /**********************************************************************/
   647 
   648 
   649   /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
   650      elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
   651 
   652   template<typename Graph>
   653   class DynamicPath {
   654 
   655   public:
   656     typedef typename Graph::Edge GraphEdge;
   657     typedef typename Graph::Node GraphNode;
   658     class NodeIt;
   659     class EdgeIt;
   660 
   661   protected:
   662     Graph& G;
   663     // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
   664     // iranyitasat:
   665     GraphNode _first, _last;
   666     typedef std::deque<GraphEdge> Container;
   667     Container edges;
   668 
   669   public:
   670 
   671     DynamicPath(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
   672 
   673     /// Subpath defined by two nodes.
   674     /// Nodes may be in reversed order, then
   675     /// we contstruct the reversed path.
   676     DynamicPath(const DynamicPath &P, const NodeIt &a, const NodeIt &b);
   677     /// Subpath defined by two edges. Contains edges in [a,b)
   678     /// It is an error if the two edges are not in order!
   679     DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
   680     
   681     size_t length() const { return edges.size(); }
   682     GraphNode from() const { return _first; }
   683     GraphNode to() const { return _last; }
   684 
   685     NodeIt& first(NodeIt &n) const { return nth(n, 0); }
   686     EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
   687     template<typename It>
   688     It first() const { 
   689       It e;
   690       first(e);
   691       return e; 
   692     }
   693 
   694     NodeIt& nth(NodeIt &, size_t) const;
   695     EdgeIt& nth(EdgeIt &, size_t) const;
   696     template<typename It>
   697     It nth(size_t n) const { 
   698       It e;
   699       nth(e, n);
   700       return e; 
   701     }
   702 
   703     bool valid(const NodeIt &n) const { return n.idx <= length(); }
   704     bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
   705 
   706     bool isForward(const EdgeIt &e) const { return e.forw; }
   707 
   708     /// index of a node on the path. Returns length+2 for the invalid NodeIt
   709     int index(const NodeIt &n) const { return n.idx; }
   710     /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
   711     int index(const EdgeIt &e) const { return e.it - edges.begin(); }
   712 
   713     EdgeIt& next(EdgeIt &e) const;
   714     NodeIt& next(NodeIt &n) const;
   715     template <typename It>
   716     It getNext(It it) const {
   717       It tmp(it); return next(tmp);
   718     }
   719 
   720     // A path is constructed using the following four functions.
   721     // They return false if the requested operation is inconsistent
   722     // with the path constructed so far.
   723     // If your path has only one edge you MUST set either "from" or "to"!
   724     // So you probably SHOULD call it in any case to be safe (and check the
   725     // returned value to check if your path is consistent with your idea).
   726     bool pushFront(const GraphEdge &e);
   727     bool pushBack(const GraphEdge &e);
   728     bool setFrom(const GraphNode &n);
   729     bool setTo(const GraphNode &n);
   730 
   731     // WARNING: these two functions return the head/tail of an edge with
   732     // respect to the direction of the path!
   733     // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if 
   734     // P.forward(e) is true (or the edge is a loop)!
   735     NodeIt head(const EdgeIt& e) const;
   736     NodeIt tail(const EdgeIt& e) const;
   737 
   738     // FIXME: ezeknek valami jobb nev kellene!!!
   739     GraphEdge graphEdge(const EdgeIt& e) const;
   740     GraphNode graphNode(const NodeIt& n) const;
   741 
   742 
   743     /*** Iterator classes ***/
   744     class EdgeIt {
   745       friend class DynamicPath;
   746 
   747       typename Container::const_iterator it;
   748       bool forw;
   749     public:
   750       // FIXME: jarna neki ilyen is...
   751       // EdgeIt(Invalid);
   752 
   753       bool forward() const { return forw; }
   754 
   755       bool operator==(const EdgeIt& e) const { return it==e.it; }
   756       bool operator!=(const EdgeIt& e) const { return it!=e.it; }
   757       bool operator<(const EdgeIt& e) const { return it<e.it; }
   758     };
   759 
   760     class NodeIt {
   761       friend class DynamicPath;
   762 
   763       size_t idx;
   764       bool tail;  // Is this node the tail of the edge with same idx?
   765 
   766     public:
   767       // FIXME: jarna neki ilyen is...
   768       // NodeIt(Invalid);
   769 
   770       bool operator==(const NodeIt& n) const { return idx==n.idx; }
   771       bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
   772       bool operator<(const NodeIt& n) const { return idx<n.idx; }
   773     };
   774 
   775   private:
   776     bool edgeIncident(const GraphEdge &e, const GraphNode &a,
   777 		      GraphNode &b);
   778     bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
   779   };
   780 
   781   template<typename Gr>
   782   typename DynamicPath<Gr>::EdgeIt&
   783   DynamicPath<Gr>::next(DynamicPath::EdgeIt &e) const {
   784     if( e.it == edges.end() ) 
   785       return e;
   786 
   787     GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
   788     ++e.it;
   789 
   790     // Invalid edgeit is always forward :)
   791     if( e.it == edges.end() ) {
   792       e.forw = true;
   793       return e;
   794     }
   795 
   796     e.forw = ( G.tail(*e.it) == common_node );
   797     return e;
   798   }
   799 
   800   template<typename Gr>
   801   typename DynamicPath<Gr>::NodeIt& DynamicPath<Gr>::next(NodeIt &n) const {
   802     if( n.idx >= length() ) {
   803       // FIXME: invalid
   804       n.idx = length()+1;
   805       return n;
   806     }
   807 
   808     
   809     GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
   810 			      G.tail(edges[n.idx]) );
   811     ++n.idx;
   812     if( n.idx < length() ) {
   813       n.tail = ( next_node == G.tail(edges[n.idx]) );
   814     }
   815     else {
   816       n.tail = true;
   817     }
   818 
   819     return n;
   820   }
   821 
   822   template<typename Gr>
   823   bool DynamicPath<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
   824 			  GraphNode &b) {
   825     if( G.tail(e) == a ) {
   826       b=G.head(e);
   827       return true;
   828     }
   829     if( G.head(e) == a ) {
   830       b=G.tail(e);
   831       return true;
   832     }
   833     return false;
   834   }
   835 
   836   template<typename Gr>
   837   bool DynamicPath<Gr>::connectTwoEdges(const GraphEdge &e,
   838 			     const GraphEdge &f) {
   839     if( edgeIncident(f, G.tail(e), _last) ) {
   840       _first = G.head(e);
   841       return true;
   842     }
   843     if( edgeIncident(f, G.head(e), _last) ) {
   844       _first = G.tail(e);
   845       return true;
   846     }
   847     return false;
   848   }
   849 
   850   template<typename Gr>
   851   bool DynamicPath<Gr>::pushFront(const GraphEdge &e) {
   852     if( G.valid(_first) ) {
   853 	if( edgeIncident(e, _first, _first) ) {
   854 	  edges.push_front(e);
   855 	  return true;
   856 	}
   857 	else
   858 	  return false;
   859     }
   860     else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
   861       edges.push_front(e);
   862       return true;
   863     }
   864     else
   865       return false;
   866   }
   867 
   868   template<typename Gr>
   869   bool DynamicPath<Gr>::pushBack(const GraphEdge &e) {
   870     if( G.valid(_last) ) {
   871 	if( edgeIncident(e, _last, _last) ) {
   872 	  edges.push_back(e);
   873 	  return true;
   874 	}
   875 	else
   876 	  return false;
   877     }
   878     else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
   879       edges.push_back(e);
   880       return true;
   881     }
   882     else
   883       return false;
   884   }
   885 
   886 
   887   template<typename Gr>
   888   bool DynamicPath<Gr>::setFrom(const GraphNode &n) {
   889     if( G.valid(_first) ) {
   890       return _first == n;
   891     }
   892     else {
   893       if( length() > 0) {
   894 	if( edgeIncident(edges[0], n, _last) ) {
   895 	  _first = n;
   896 	  return true;
   897 	}
   898 	else return false;
   899       }
   900       else {
   901 	_first = _last = n;
   902 	return true;
   903       }
   904     }
   905   }
   906 
   907   template<typename Gr>
   908   bool DynamicPath<Gr>::setTo(const GraphNode &n) {
   909     if( G.valid(_last) ) {
   910       return _last == n;
   911     }
   912     else {
   913       if( length() > 0) {
   914 	if( edgeIncident(edges[0], n, _first) ) {
   915 	  _last = n;
   916 	  return true;
   917 	}
   918 	else return false;
   919       }
   920       else {
   921 	_first = _last = n;
   922 	return true;
   923       }
   924     }
   925   }
   926 
   927 
   928   template<typename Gr>
   929   typename DynamicPath<Gr>::NodeIt
   930   DynamicPath<Gr>::tail(const EdgeIt& e) const {
   931     NodeIt n;
   932 
   933     if( e.it == edges.end() ) {
   934       // FIXME: invalid-> invalid
   935       n.idx = length() + 1;
   936       n.tail = true;
   937       return n;
   938     }
   939 
   940     n.idx = e.it-edges.begin();
   941     n.tail = e.forw;
   942     return n;
   943   }
   944 
   945   template<typename Gr>
   946   typename DynamicPath<Gr>::NodeIt
   947   DynamicPath<Gr>::head(const EdgeIt& e) const {
   948     if( e.it == edges.end()-1 ) {
   949       return _last;
   950     }
   951 
   952     EdgeIt next_edge = e;
   953     next(next_edge);
   954     return tail(next_edge);
   955   }
   956       
   957   template<typename Gr>
   958   typename DynamicPath<Gr>::GraphEdge
   959   DynamicPath<Gr>::graphEdge(const EdgeIt& e) const {
   960     if( e.it != edges.end() ) {
   961       return *e.it;
   962     }
   963     else {
   964       return INVALID;
   965     }
   966   }
   967   
   968   template<typename Gr>
   969   typename DynamicPath<Gr>::GraphNode
   970   DynamicPath<Gr>::graphNode(const NodeIt& n) const {
   971     if( n.idx < length() ) {
   972       return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
   973     }
   974     else if( n.idx == length() ) {
   975       return _last;
   976     }
   977     else {
   978       return INVALID;
   979     }
   980   }
   981 
   982   template<typename Gr>
   983   typename DynamicPath<Gr>::EdgeIt&
   984   DynamicPath<Gr>::nth(EdgeIt &e, size_t k) const {
   985     if( k>=length() ) {
   986       // FIXME: invalid EdgeIt
   987       e.it = edges.end();
   988       e.forw = true;
   989       return e;
   990     }
   991 
   992     e.it = edges.begin()+k;
   993     if(k==0) {
   994       e.forw = ( G.tail(*e.it) == _first );
   995     }
   996     else {
   997       e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
   998 		 G.tail(*e.it) == G.head(edges[k-1]) );
   999     }
  1000     return e;
  1001   }
  1002     
  1003   template<typename Gr>
  1004   typename DynamicPath<Gr>::NodeIt&
  1005   DynamicPath<Gr>::nth(NodeIt &n, size_t k) const {
  1006     if( k>length() ) {
  1007       // FIXME: invalid NodeIt
  1008       n.idx = length()+1;
  1009       n.tail = true;
  1010       return n;
  1011     }
  1012     if( k==length() ) {
  1013       n.idx = length();
  1014       n.tail = true;
  1015       return n;
  1016     }
  1017     n = tail(nth<EdgeIt>(k));
  1018     return n;
  1019   }
  1020 
  1021   // Reszut konstruktorok:
  1022 
  1023 
  1024   template<typename Gr>
  1025   DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const EdgeIt &a,
  1026 			       const EdgeIt &b) :
  1027     G(P.G), edges(a.it, b.it)    // WARNING: if b.it < a.it this will blow up! 
  1028   {
  1029     if( G.valid(P._first) && a.it < P.edges.end() ) {
  1030       _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
  1031       if( b.it < P.edges.end() ) {
  1032 	_last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
  1033       }
  1034       else {
  1035 	_last = P._last;
  1036       }
  1037     }
  1038   }
  1039 
  1040   template<typename Gr>
  1041   DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const NodeIt &a,
  1042 			       const NodeIt &b) : G(P.G)
  1043   {
  1044     if( !P.valid(a) || !P.valid(b) )
  1045       return;
  1046 
  1047     int ai = a.idx, bi = b.idx;
  1048     if( bi<ai )
  1049       std::swap(ai,bi);
  1050     
  1051     edges.resize(bi-ai);
  1052     copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
  1053 
  1054     _first = P.graphNode(a);
  1055     _last = P.graphNode(b);
  1056   }
  1057 
  1058   ///@}
  1059 
  1060 } // namespace hugo
  1061 
  1062 #endif // HUGO_PATH_H