src/hugo/path.h
changeset 831 b6ae3446098a
parent 819 3623e8dbce49
child 834 1dd3167db044
equal deleted inserted replaced
0:ded16296d331 1:f9c0374a9f54
    27 #include <vector>
    27 #include <vector>
    28 #include <algorithm>
    28 #include <algorithm>
    29 
    29 
    30 #include <hugo/invalid.h>
    30 #include <hugo/invalid.h>
    31 #include <hugo/error.h>
    31 #include <hugo/error.h>
    32 #include <hugo/debug.h>
    32 //#include <hugo/debug.h>
    33 
    33 
    34 namespace hugo {
    34 namespace hugo {
    35 
    35 
    36   /// \addtogroup paths
    36   /// \addtogroup paths
    37   /// @{
    37   /// @{
    46   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
    46   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
    47   //! and \c EdgeIt with the same usage. These types converts to the \c Node
    47   //! and \c EdgeIt with the same usage. These types converts to the \c Node
    48   //! and \c Edge of the original graph.
    48   //! and \c Edge of the original graph.
    49   //!
    49   //!
    50   //! \todo Thoroughfully check all the range and consistency tests.
    50   //! \todo Thoroughfully check all the range and consistency tests.
    51   template<typename Graph, typename DM = DefaultDebugMode>
    51   template<typename Graph>
    52   class DirPath {
    52   class DirPath {
    53   public:
    53   public:
    54     /// Edge type of the underlying graph.
    54     /// Edge type of the underlying graph.
    55     typedef typename Graph::Edge GraphEdge; 
    55     typedef typename Graph::Edge GraphEdge; 
    56     /// Node type of the underlying graph.
    56     /// Node type of the underlying graph.
    72     /// \brief Subpath constructor.
    72     /// \brief Subpath constructor.
    73     ///
    73     ///
    74     /// Subpath defined by two nodes.
    74     /// Subpath defined by two nodes.
    75     /// \warning It is an error if the two edges are not in order!
    75     /// \warning It is an error if the two edges are not in order!
    76     DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
    76     DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
    77       if( DM::range_check && (!a.valid() || !b.valid) ) {
    77       if(!a.valid() || !b.valid) {
    78 	// FIXME: this check should be more elaborate...
    78 	// FIXME: this check should be more elaborate...
    79 	fault("DirPath, subpath ctor: invalid bounding nodes");
    79 	fault("DirPath, subpath ctor: invalid bounding nodes");
    80       }
    80       }
    81       gr = P.gr;
    81       gr = P.gr;
    82       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    82       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    85     /// \brief Subpath constructor.
    85     /// \brief Subpath constructor.
    86     ///
    86     ///
    87     /// Subpath defined by two edges. Contains edges in [a,b)
    87     /// Subpath defined by two edges. Contains edges in [a,b)
    88     /// \warning It is an error if the two edges are not in order!
    88     /// \warning It is an error if the two edges are not in order!
    89     DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
    89     DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
    90       if( DM::range_check && (!a.valid() || !b.valid) ) {
    90       if (!a.valid() || !b.valid) {
    91 	// FIXME: this check should be more elaborate...
    91 	// FIXME: this check should be more elaborate...
    92 	fault("DirPath, subpath ctor: invalid bounding nodes");
    92 	fault("DirPath, subpath ctor: invalid bounding nodes");
    93       }
    93       }
    94       gr = P.gr;
    94       gr = P.gr;
    95       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    95       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   105 
   105 
   106     /// \brief Starting point of the path.
   106     /// \brief Starting point of the path.
   107     ///
   107     ///
   108     /// Starting point of the path.
   108     /// Starting point of the path.
   109     /// Returns INVALID if the path is empty.
   109     /// Returns INVALID if the path is empty.
   110     GraphNode from() const {
   110     GraphNode tail() const {
   111       return empty() ? INVALID : gr->tail(edges[0]);
   111       return empty() ? INVALID : gr->tail(edges[0]);
   112     }
   112     }
   113     /// \brief End point of the path.
   113     /// \brief End point of the path.
   114     ///
   114     ///
   115     /// End point of the path.
   115     /// End point of the path.
   116     /// Returns INVALID if the path is empty.
   116     /// Returns INVALID if the path is empty.
   117     GraphNode to() const {
   117     GraphNode head() const {
   118       return empty() ? INVALID : gr->head(edges[length()-1]);
   118       return empty() ? INVALID : gr->head(edges[length()-1]);
   119     }
   119     }
   120 
   120 
   121     /// \brief Initializes node or edge iterator to point to the first
   121     /// \brief Initializes node or edge iterator to point to the first
   122     /// node or edge.
   122     /// node or edge.
   125     template<typename It>
   125     template<typename It>
   126     It& first(It &i) const { return i=It(*this); }
   126     It& first(It &i) const { return i=It(*this); }
   127 
   127 
   128     /// \brief Initializes node iterator to point to the node of a given index.
   128     /// \brief Initializes node iterator to point to the node of a given index.
   129     NodeIt& nth(NodeIt &i, int n) const {
   129     NodeIt& nth(NodeIt &i, int n) const {
   130       if( DM::range_check && (n<0 || n>int(length())) )
   130       if(n<0 || n>int(length())) 
   131 	fault("DirPath::nth: index out of range");
   131 	fault("DirPath::nth: index out of range");
   132       return i=NodeIt(*this, n);
   132       return i=NodeIt(*this, n);
   133     }
   133     }
   134 
   134 
   135     /// \brief Initializes edge iterator to point to the edge of a given index.
   135     /// \brief Initializes edge iterator to point to the edge of a given index.
   136     EdgeIt& nth(EdgeIt &i, int n) const {
   136     EdgeIt& nth(EdgeIt &i, int n) const {
   137       if( DM::range_check && (n<0 || n>=int(length())) )
   137       if(n<0 || n>=int(length())) 
   138 	fault("DirPath::nth: index out of range");
   138 	fault("DirPath::nth: index out of range");
   139       return i=EdgeIt(*this, n);
   139       return i=EdgeIt(*this, n);
   140     }
   140     }
   141 
   141 
   142     /// Checks validity of a node or edge iterator.
   142     /// Checks validity of a node or edge iterator.
   146 
   146 
   147     /// Steps the given node or edge iterator.
   147     /// Steps the given node or edge iterator.
   148     template<typename It>
   148     template<typename It>
   149     static
   149     static
   150     It& next(It &e) {
   150     It& next(It &e) {
   151       if( DM::range_check && !e.valid() )
   151       if( !e.valid() )
   152 	fault("DirPath::next() on invalid iterator");
   152 	fault("DirPath::next() on invalid iterator");
   153       return ++e;
   153       return ++e;
   154     }
   154     }
   155 
   155 
   156     /// \brief Returns node iterator pointing to the head node of the
   156     /// \brief Returns node iterator pointing to the head node of the
   157     /// given edge iterator.
   157     /// given edge iterator.
   158     NodeIt head(const EdgeIt& e) const {
   158     NodeIt head(const EdgeIt& e) const {
   159       if( DM::range_check && !e.valid() )
   159       if( !e.valid() )
   160 	fault("DirPath::head() on invalid iterator");
   160 	fault("DirPath::head() on invalid iterator");
   161       return NodeIt(*this, e.idx+1);
   161       return NodeIt(*this, e.idx+1);
   162     }
   162     }
   163 
   163 
   164     /// \brief Returns node iterator pointing to the tail node of the
   164     /// \brief Returns node iterator pointing to the tail node of the
   165     /// given edge iterator.
   165     /// given edge iterator.
   166     NodeIt tail(const EdgeIt& e) const {
   166     NodeIt tail(const EdgeIt& e) const {
   167       if( DM::range_check && !e.valid() )
   167       if( !e.valid() )
   168 	fault("DirPath::tail() on invalid iterator");
   168 	fault("DirPath::tail() on invalid iterator");
   169       return NodeIt(*this, e.idx);
   169       return NodeIt(*this, e.idx);
   170     }
   170     }
   171 
   171 
   172 
   172 
   250       bool valid() const { return idx!=-1; }
   250       bool valid() const { return idx!=-1; }
   251 
   251 
   252       ///Conversion to Graph::Node
   252       ///Conversion to Graph::Node
   253       operator const GraphNode& () const {
   253       operator const GraphNode& () const {
   254 	if(idx >= p->length())
   254 	if(idx >= p->length())
   255 	  return p->to();
   255 	  return p->head();
   256 	else if(idx >= 0)
   256 	else if(idx >= 0)
   257 	  return p->gr->tail(p->edges[idx]);
   257 	  return p->gr->tail(p->edges[idx]);
   258 	else
   258 	else
   259 	  return INVALID;
   259 	  return INVALID;
   260       }
   260       }
   310       ///Push a new edge to the front of the path
   310       ///Push a new edge to the front of the path
   311 
   311 
   312       ///Push a new edge to the front of the path.
   312       ///Push a new edge to the front of the path.
   313       ///\sa setStartNode
   313       ///\sa setStartNode
   314       void pushFront(const GraphEdge& e) {
   314       void pushFront(const GraphEdge& e) {
   315 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
   315 	if( !empty() && P.gr->head(e)!=tail() ) {
   316 	  fault("DirPath::Builder::pushFront: nonincident edge");
   316 	  fault("DirPath::Builder::pushFront: nonincident edge");
   317 	}
   317 	}
   318 	front.push_back(e);
   318 	front.push_back(e);
   319       }
   319       }
   320 
   320 
   321       ///Push a new edge to the back of the path
   321       ///Push a new edge to the back of the path
   322 
   322 
   323       ///Push a new edge to the back of the path.
   323       ///Push a new edge to the back of the path.
   324       ///\sa setStartNode
   324       ///\sa setStartNode
   325       void pushBack(const GraphEdge& e) {
   325       void pushBack(const GraphEdge& e) {
   326 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
   326 	if( !empty() && P.gr->tail(e)!=head() ) {
   327 	  fault("DirPath::Builder::pushBack: nonincident edge");
   327 	  fault("DirPath::Builder::pushBack: nonincident edge");
   328 	}
   328 	}
   329 	back.push_back(e);
   329 	back.push_back(e);
   330       }
   330       }
   331 
   331 
   353       void reserve(size_t r) {
   353       void reserve(size_t r) {
   354 	front.reserve(r);
   354 	front.reserve(r);
   355 	back.reserve(r);
   355 	back.reserve(r);
   356       }
   356       }
   357 
   357 
       
   358       void reserveFront(size_t r) {}
       
   359       void reserveBack(size_t r) {}
       
   360 
   358     private:
   361     private:
   359       bool empty() {
   362       bool empty() {
   360 	return front.empty() && back.empty() && P.empty();
   363 	return front.empty() && back.empty() && P.empty();
   361       }
   364       }
   362 
   365 
   363       GraphNode from() const {
   366       GraphNode tail() const {
   364 	if( ! front.empty() )
   367 	if( ! front.empty() )
   365 	  return P.gr->tail(front[front.size()-1]);
   368 	  return P.gr->tail(front[front.size()-1]);
   366 	else if( ! P.empty() )
   369 	else if( ! P.empty() )
   367 	  return P.gr->tail(P.edges[0]);
   370 	  return P.gr->tail(P.edges[0]);
   368 	else if( ! back.empty() )
   371 	else if( ! back.empty() )
   369 	  return P.gr->tail(back[0]);
   372 	  return P.gr->tail(back[0]);
   370 	else
   373 	else
   371 	  return INVALID;
   374 	  return INVALID;
   372       }
   375       }
   373       GraphNode to() const {
   376       GraphNode head() const {
   374 	if( ! back.empty() )
   377 	if( ! back.empty() )
   375 	  return P.gr->head(back[back.size()-1]);
   378 	  return P.gr->head(back[back.size()-1]);
   376 	else if( ! P.empty() )
   379 	else if( ! P.empty() )
   377 	  return P.gr->head(P.edges[P.length()-1]);
   380 	  return P.gr->head(P.edges[P.length()-1]);
   378 	else if( ! front.empty() )
   381 	else if( ! front.empty() )
   409   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
   412   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
   410   //! and \c EdgeIt with the same usage. These types converts to the \c Node
   413   //! and \c EdgeIt with the same usage. These types converts to the \c Node
   411   //! and \c Edge of the original graph.
   414   //! and \c Edge of the original graph.
   412   //!
   415   //!
   413   //! \todo Thoroughfully check all the range and consistency tests.
   416   //! \todo Thoroughfully check all the range and consistency tests.
   414   template<typename Graph, typename DM = DefaultDebugMode>
   417   template<typename Graph>
   415   class UndirPath {
   418   class UndirPath {
   416   public:
   419   public:
   417     /// Edge type of the underlying graph.
   420     /// Edge type of the underlying graph.
   418     typedef typename Graph::Edge GraphEdge;
   421     typedef typename Graph::Edge GraphEdge;
   419      /// Node type of the underlying graph.
   422      /// Node type of the underlying graph.
   435     /// \brief Subpath constructor.
   438     /// \brief Subpath constructor.
   436     ///
   439     ///
   437     /// Subpath defined by two nodes.
   440     /// Subpath defined by two nodes.
   438     /// \warning It is an error if the two edges are not in order!
   441     /// \warning It is an error if the two edges are not in order!
   439     UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
   442     UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
   440       if( DM::range_check && (!a.valid() || !b.valid) ) {
   443       if(!a.valid() || !b.valid) {
   441 	// FIXME: this check should be more elaborate...
   444 	// FIXME: this check should be more elaborate...
   442 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   445 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   443       }
   446       }
   444       gr = P.gr;
   447       gr = P.gr;
   445       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   448       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   448     /// \brief Subpath constructor.
   451     /// \brief Subpath constructor.
   449     ///
   452     ///
   450     /// Subpath defined by two edges. Contains edges in [a,b)
   453     /// Subpath defined by two edges. Contains edges in [a,b)
   451     /// \warning It is an error if the two edges are not in order!
   454     /// \warning It is an error if the two edges are not in order!
   452     UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
   455     UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
   453       if( DM::range_check && (!a.valid() || !b.valid) ) {
   456       if(!a.valid() || !b.valid) {
   454 	// FIXME: this check should be more elaborate...
   457 	// FIXME: this check should be more elaborate...
   455 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   458 	fault("UndirPath, subpath ctor: invalid bounding nodes");
   456       }
   459       }
   457       gr = P.gr;
   460       gr = P.gr;
   458       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   461       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   468 
   471 
   469     /// \brief Starting point of the path.
   472     /// \brief Starting point of the path.
   470     ///
   473     ///
   471     /// Starting point of the path.
   474     /// Starting point of the path.
   472     /// Returns INVALID if the path is empty.
   475     /// Returns INVALID if the path is empty.
   473     GraphNode from() const {
   476     GraphNode tail() const {
   474       return empty() ? INVALID : gr->tail(edges[0]);
   477       return empty() ? INVALID : gr->tail(edges[0]);
   475     }
   478     }
   476     /// \brief End point of the path.
   479     /// \brief End point of the path.
   477     ///
   480     ///
   478     /// End point of the path.
   481     /// End point of the path.
   479     /// Returns INVALID if the path is empty.
   482     /// Returns INVALID if the path is empty.
   480     GraphNode to() const {
   483     GraphNode head() const {
   481       return empty() ? INVALID : gr->head(edges[length()-1]);
   484       return empty() ? INVALID : gr->head(edges[length()-1]);
   482     }
   485     }
   483 
   486 
   484     /// \brief Initializes node or edge iterator to point to the first
   487     /// \brief Initializes node or edge iterator to point to the first
   485     /// node or edge.
   488     /// node or edge.
   488     template<typename It>
   491     template<typename It>
   489     It& first(It &i) const { return i=It(*this); }
   492     It& first(It &i) const { return i=It(*this); }
   490 
   493 
   491     /// \brief Initializes node iterator to point to the node of a given index.
   494     /// \brief Initializes node iterator to point to the node of a given index.
   492     NodeIt& nth(NodeIt &i, int n) const {
   495     NodeIt& nth(NodeIt &i, int n) const {
   493       if( DM::range_check && (n<0 || n>int(length())) )
   496       if(n<0 || n>int(length()))
   494 	fault("UndirPath::nth: index out of range");
   497 	fault("UndirPath::nth: index out of range");
   495       return i=NodeIt(*this, n);
   498       return i=NodeIt(*this, n);
   496     }
   499     }
   497 
   500 
   498     /// \brief Initializes edge iterator to point to the edge of a given index.
   501     /// \brief Initializes edge iterator to point to the edge of a given index.
   499     EdgeIt& nth(EdgeIt &i, int n) const {
   502     EdgeIt& nth(EdgeIt &i, int n) const {
   500       if( DM::range_check && (n<0 || n>=int(length())) )
   503       if(n<0 || n>=int(length()))
   501 	fault("UndirPath::nth: index out of range");
   504 	fault("UndirPath::nth: index out of range");
   502       return i=EdgeIt(*this, n);
   505       return i=EdgeIt(*this, n);
   503     }
   506     }
   504 
   507 
   505     /// Checks validity of a node or edge iterator.
   508     /// Checks validity of a node or edge iterator.
   509 
   512 
   510     /// Steps the given node or edge iterator.
   513     /// Steps the given node or edge iterator.
   511     template<typename It>
   514     template<typename It>
   512     static
   515     static
   513     It& next(It &e) {
   516     It& next(It &e) {
   514       if( DM::range_check && !e.valid() )
   517       if( !e.valid() )
   515 	fault("UndirPath::next() on invalid iterator");
   518 	fault("UndirPath::next() on invalid iterator");
   516       return ++e;
   519       return ++e;
   517     }
   520     }
   518 
   521 
   519     /// \brief Returns node iterator pointing to the head node of the
   522     /// \brief Returns node iterator pointing to the head node of the
   520     /// given edge iterator.
   523     /// given edge iterator.
   521     NodeIt head(const EdgeIt& e) const {
   524     NodeIt head(const EdgeIt& e) const {
   522       if( DM::range_check && !e.valid() )
   525       if( !e.valid() )
   523 	fault("UndirPath::head() on invalid iterator");
   526 	fault("UndirPath::head() on invalid iterator");
   524       return NodeIt(*this, e.idx+1);
   527       return NodeIt(*this, e.idx+1);
   525     }
   528     }
   526 
   529 
   527     /// \brief Returns node iterator pointing to the tail node of the
   530     /// \brief Returns node iterator pointing to the tail node of the
   528     /// given edge iterator.
   531     /// given edge iterator.
   529     NodeIt tail(const EdgeIt& e) const {
   532     NodeIt tail(const EdgeIt& e) const {
   530       if( DM::range_check && !e.valid() )
   533       if( !e.valid() )
   531 	fault("UndirPath::tail() on invalid iterator");
   534 	fault("UndirPath::tail() on invalid iterator");
   532       return NodeIt(*this, e.idx);
   535       return NodeIt(*this, e.idx);
   533     }
   536     }
   534 
   537 
   535 
   538 
   611       bool valid() const { return idx!=-1; }
   614       bool valid() const { return idx!=-1; }
   612 
   615 
   613       ///Conversion to Graph::Node
   616       ///Conversion to Graph::Node
   614       operator const GraphNode& () const {
   617       operator const GraphNode& () const {
   615 	if(idx >= p->length())
   618 	if(idx >= p->length())
   616 	  return p->to();
   619 	  return p->head();
   617 	else if(idx >= 0)
   620 	else if(idx >= 0)
   618 	  return p->gr->tail(p->edges[idx]);
   621 	  return p->gr->tail(p->edges[idx]);
   619 	else
   622 	else
   620 	  return INVALID;
   623 	  return INVALID;
   621       }
   624       }
   671       ///Push a new edge to the front of the path
   674       ///Push a new edge to the front of the path
   672 
   675 
   673       ///Push a new edge to the front of the path.
   676       ///Push a new edge to the front of the path.
   674       ///\sa setStartNode
   677       ///\sa setStartNode
   675       void pushFront(const GraphEdge& e) {
   678       void pushFront(const GraphEdge& e) {
   676 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
   679 	if( !empty() && P.gr->head(e)!=tail() ) {
   677 	  fault("UndirPath::Builder::pushFront: nonincident edge");
   680 	  fault("UndirPath::Builder::pushFront: nonincident edge");
   678 	}
   681 	}
   679 	front.push_back(e);
   682 	front.push_back(e);
   680       }
   683       }
   681 
   684 
   682       ///Push a new edge to the back of the path
   685       ///Push a new edge to the back of the path
   683 
   686 
   684       ///Push a new edge to the back of the path.
   687       ///Push a new edge to the back of the path.
   685       ///\sa setStartNode
   688       ///\sa setStartNode
   686       void pushBack(const GraphEdge& e) {
   689       void pushBack(const GraphEdge& e) {
   687 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
   690 	if( !empty() && P.gr->tail(e)!=head() ) {
   688 	  fault("UndirPath::Builder::pushBack: nonincident edge");
   691 	  fault("UndirPath::Builder::pushBack: nonincident edge");
   689 	}
   692 	}
   690 	back.push_back(e);
   693 	back.push_back(e);
   691       }
   694       }
   692 
   695 
   714        void reserve(size_t r) {
   717        void reserve(size_t r) {
   715 	front.reserve(r);
   718 	front.reserve(r);
   716 	back.reserve(r);
   719 	back.reserve(r);
   717       }
   720       }
   718 
   721 
       
   722       void reserveFront(size_t r) {}
       
   723       void reserveBack(size_t r) {}
       
   724 
   719     private:
   725     private:
   720       bool empty() {
   726       bool empty() {
   721 	return front.empty() && back.empty() && P.empty();
   727 	return front.empty() && back.empty() && P.empty();
   722       }
   728       }
   723 
   729 
   724       GraphNode from() const {
   730       GraphNode tail() const {
   725 	if( ! front.empty() )
   731 	if( ! front.empty() )
   726 	  return P.gr->tail(front[front.size()-1]);
   732 	  return P.gr->tail(front[front.size()-1]);
   727 	else if( ! P.empty() )
   733 	else if( ! P.empty() )
   728 	  return P.gr->tail(P.edges[0]);
   734 	  return P.gr->tail(P.edges[0]);
   729 	else if( ! back.empty() )
   735 	else if( ! back.empty() )
   730 	  return P.gr->tail(back[0]);
   736 	  return P.gr->tail(back[0]);
   731 	else
   737 	else
   732 	  return INVALID;
   738 	  return INVALID;
   733       }
   739       }
   734       GraphNode to() const {
   740       GraphNode head() const {
   735 	if( ! back.empty() )
   741 	if( ! back.empty() )
   736 	  return P.gr->head(back[back.size()-1]);
   742 	  return P.gr->head(back[back.size()-1]);
   737 	else if( ! P.empty() )
   743 	else if( ! P.empty() )
   738 	  return P.gr->head(P.edges[P.length()-1]);
   744 	  return P.gr->head(P.edges[P.length()-1]);
   739 	else if( ! front.empty() )
   745 	else if( ! front.empty() )
   789     /// Subpath defined by two edges. Contains edges in [a,b)
   795     /// Subpath defined by two edges. Contains edges in [a,b)
   790     /// It is an error if the two edges are not in order!
   796     /// It is an error if the two edges are not in order!
   791     DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
   797     DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
   792     
   798     
   793     size_t length() const { return edges.size(); }
   799     size_t length() const { return edges.size(); }
   794     GraphNode from() const { return _first; }
   800     GraphNode tail() const { return _first; }
   795     GraphNode to() const { return _last; }
   801     GraphNode head() const { return _last; }
   796 
   802 
   797     NodeIt& first(NodeIt &n) const { return nth(n, 0); }
   803     NodeIt& first(NodeIt &n) const { return nth(n, 0); }
   798     EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
   804     EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
   799     template<typename It>
   805     template<typename It>
   800     It first() const { 
   806     It first() const {