klao@225: // -*- c++ -*- //
klao@225: 
klao@493: ///\ingroup datas
alpar@434: ///\file
klao@493: ///\brief Classes for representing paths in graphs.
klao@225: 
klao@225: #ifndef HUGO_PATH_H
klao@225: #define HUGO_PATH_H
klao@225: 
klao@225: #include <deque>
klao@369: #include <vector>
klao@226: #include <algorithm>
klao@225: 
athos@607: #include <hugo/invalid.h>
athos@607: #include <hugo/error.h>
klao@493: #include <debug.h>
klao@225: 
klao@225: namespace hugo {
klao@225: 
alpar@434:   /// \addtogroup datas
alpar@434:   /// @{
alpar@434: 
alpar@434: 
klao@493:   //! \brief A structure for representing directed path in a graph.
klao@493:   //!
klao@619:   //! A structure for representing directed path in a graph.
klao@493:   //! \param Graph The graph type in which the path is.
klao@493:   //! \param DM DebugMode, defaults to DefaultDebugMode.
klao@493:   //! 
klao@493:   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
klao@493:   //! and \c EdgeIt with the same usage. These types converts to the \c Node
klao@493:   //! and \c Edge of the original graph.
klao@493:   //!
klao@493:   //! \todo Thoroughfully check all the range and consistency tests.
klao@493:   template<typename Graph, typename DM = DefaultDebugMode>
klao@369:   class DirPath {
klao@369:   public:
klao@369:     typedef typename Graph::Edge GraphEdge;
klao@369:     typedef typename Graph::Node GraphNode;
klao@369:     class NodeIt;
klao@369:     class EdgeIt;
klao@369: 
klao@369:   protected:
klao@369:     const Graph *gr;
klao@369:     typedef std::vector<GraphEdge> Container;
klao@369:     Container edges;
klao@369: 
klao@369:   public:
klao@369: 
alpar@434:     /// \param _G The graph in which the path is.
alpar@434:     ///
klao@369:     DirPath(const Graph &_G) : gr(&_G) {}
klao@369: 
klao@493:     /// \brief Subpath constructor.
klao@493:     ///
klao@369:     /// Subpath defined by two nodes.
alpar@434:     /// \warning It is an error if the two edges are not in order!
klao@619:     DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
klao@619:       if( DM::range_check && (!a.valid() || !b.valid) ) {
klao@619: 	// FIXME: this check should be more elaborate...
klao@619: 	fault("DirPath, subpath ctor: invalid bounding nodes");
klao@619:       }
klao@619:       gr = P.gr;
klao@619:       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
klao@619:     }
klao@619: 
klao@493:     /// \brief Subpath constructor.
klao@493:     ///
klao@369:     /// Subpath defined by two edges. Contains edges in [a,b)
alpar@434:     /// \warning It is an error if the two edges are not in order!
klao@619:     DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
klao@619:       if( DM::range_check && (!a.valid() || !b.valid) ) {
klao@619: 	// FIXME: this check should be more elaborate...
klao@619: 	fault("DirPath, subpath ctor: invalid bounding nodes");
klao@619:       }
klao@619:       gr = P.gr;
klao@619:       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
klao@619:     }
klao@369: 
klao@493:     /// Length of the path.
klao@369:     size_t length() const { return edges.size(); }
klao@493:     /// Returns whether the path is empty.
klao@369:     bool empty() const { return edges.empty(); }
klao@493: 
klao@493:     /// Resets the path to an empty path.
klao@493:     void clear() { edges.clear(); }
klao@493: 
klao@493:     /// \brief Starting point of the path.
klao@493:     ///
klao@493:     /// Starting point of the path.
klao@493:     /// Returns INVALID if the path is empty.
klao@369:     GraphNode from() const {
klao@369:       return empty() ? INVALID : gr->tail(edges[0]);
klao@369:     }
klao@493:     /// \brief End point of the path.
klao@493:     ///
klao@493:     /// End point of the path.
klao@493:     /// Returns INVALID if the path is empty.
klao@369:     GraphNode to() const {
klao@369:       return empty() ? INVALID : gr->head(edges[length()-1]);
klao@369:     }
klao@369: 
klao@493:     /// \brief Initializes node or edge iterator to point to the first
klao@493:     /// node or edge.
klao@493:     ///
klao@493:     /// \sa nth
klao@369:     template<typename It>
klao@369:     It& first(It &i) const { return i=It(*this); }
klao@369: 
klao@619:     /// \brief Initializes node iterator to point to the node of a given index.
klao@619:     NodeIt& nth(NodeIt &i, int n) const {
klao@493:       if( DM::range_check && (n<0 || n>int(length())) )
klao@493: 	fault("DirPath::nth: index out of range");
klao@619:       return i=NodeIt(*this, n);
klao@619:     }
klao@619: 
klao@619:     /// \brief Initializes edge iterator to point to the edge of a given index.
klao@619:     EdgeIt& nth(EdgeIt &i, int n) const {
klao@619:       if( DM::range_check && (n<0 || n>=int(length())) )
klao@619: 	fault("DirPath::nth: index out of range");
klao@619:       return i=EdgeIt(*this, n);
klao@493:     }
klao@369: 
klao@493:     /// Checks validity of a node or edge iterator.
klao@369:     template<typename It>
klao@619:     static
klao@619:     bool valid(const It &i) { return i.valid(); }
klao@369: 
klao@493:     /// Steps the given node or edge iterator.
klao@369:     template<typename It>
klao@619:     static
klao@619:     It& next(It &e) {
klao@493:       if( DM::range_check && !e.valid() )
klao@493: 	fault("DirPath::next() on invalid iterator");
klao@493:       return ++e;
klao@493:     }
klao@369: 
klao@493:     /// \brief Returns node iterator pointing to the head node of the
klao@493:     /// given edge iterator.
klao@493:     NodeIt head(const EdgeIt& e) const {
klao@619:       if( DM::range_check && !e.valid() )
klao@619: 	fault("DirPath::head() on invalid iterator");
klao@493:       return NodeIt(*this, e.idx+1);
klao@493:     }
klao@493: 
klao@493:     /// \brief Returns node iterator pointing to the tail node of the
klao@493:     /// given edge iterator.
klao@493:     NodeIt tail(const EdgeIt& e) const {
klao@619:       if( DM::range_check && !e.valid() )
klao@619: 	fault("DirPath::tail() on invalid iterator");
klao@493:       return NodeIt(*this, e.idx);
klao@493:     }
klao@369: 
klao@369: 
klao@369:     /*** Iterator classes ***/
klao@369:     class EdgeIt {
klao@369:       friend class DirPath;
klao@369: 
klao@369:       int idx;
klao@369:       const DirPath *p;
klao@369:     public:
klao@369:       EdgeIt() {}
klao@369:       EdgeIt(Invalid) : idx(-1), p(0) {}
klao@369:       EdgeIt(const DirPath &_p, int _idx = 0) :
klao@369: 	idx(_idx), p(&_p) { validate(); }
klao@369: 
klao@369:       bool valid() const { return idx!=-1; }
klao@369: 
klao@369:       operator GraphEdge () const {
klao@369: 	return valid() ? p->edges[idx] : INVALID;
klao@369:       }
klao@369:       EdgeIt& operator++() { ++idx; validate(); return *this; }
klao@369: 
klao@369:       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
klao@369:       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
klao@369:       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
klao@369: 
klao@369:     private:
klao@369:       // FIXME: comparison between signed and unsigned...
klao@369:       // Jo ez igy? Vagy esetleg legyen a length() int?
klao@369:       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
klao@369:     };
klao@369: 
klao@369:     class NodeIt {
klao@369:       friend class DirPath;
klao@369: 
klao@369:       int idx;
klao@369:       const DirPath *p;
klao@369:     public:
klao@369:       NodeIt() {}
klao@369:       NodeIt(Invalid) : idx(-1), p(0) {}
klao@369:       NodeIt(const DirPath &_p, int _idx = 0) :
klao@369: 	idx(_idx), p(&_p) { validate(); }
klao@369: 
klao@369:       bool valid() const { return idx!=-1; }
klao@369: 
klao@619:       operator const GraphNode& () const {
klao@369: 	if(idx >= p->length())
klao@369: 	  return p->to();
klao@369: 	else if(idx >= 0)
klao@369: 	  return p->gr->tail(p->edges[idx]);
klao@369: 	else
klao@369: 	  return INVALID;
klao@369:       }
klao@369:       NodeIt& operator++() { ++idx; validate(); return *this; }
klao@369: 
klao@369:       bool operator==(const NodeIt& e) const { return idx==e.idx; }
klao@369:       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
klao@369:       bool operator<(const NodeIt& e) const { return idx<e.idx; }
klao@369: 
klao@369:     private:
klao@369:       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
klao@369:     };
klao@369: 
klao@369:     friend class Builder;    
alpar@434: 
klao@493:     /**
klao@493:      * \brief Class to build paths
klao@493:      * 
klao@493:      * \ingroup datas
klao@493:      * This class is used to fill a path with edges.
klao@493:      *
klao@493:      * You can push new edges to the front and to the back of the path in
klao@619:      * arbitrary order then you should commit these changes to the graph.
klao@493:      *
klao@493:      * Fundamentally, for most "Paths" (classes fulfilling the
klao@493:      * PathConcept) while the builder is active (after the first modifying
klao@493:      * operation and until the commit()) the original Path is in a
klao@493:      * "transitional" state (operations ot it have undefined result). But
klao@493:      * in the case of DirPath the original path is unchanged until the
klao@493:      * commit. However we don't recomend that you use this feature.
klao@493:      */
klao@369:     class Builder {
klao@369:       DirPath &P;
klao@493:       Container front, back;
klao@369: 
klao@369:     public:
klao@493:       ///\param _P the path you want to fill in.
alpar@434:       ///
klao@369:       Builder(DirPath &_P) : P(_P) {}
klao@369: 
klao@619:       /// Sets the starting node of the path.
alpar@434:       
klao@619:       /// Sets the starting node of the path. Edge added to the path
klao@619:       /// afterwards have to be incident to this node.
klao@619:       /// It should be called iff the path is empty and before any call to
klao@619:       /// \ref pushFront() or \ref pushBack()
klao@619:       void setStart(const GraphNode &) {}
klao@619: 
alpar@434:       ///Push a new edge to the front of the path
alpar@434: 
alpar@434:       ///Push a new edge to the front of the path.
klao@619:       ///\sa setStart
klao@493:       void pushFront(const GraphEdge& e) {
klao@493: 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
klao@493: 	  fault("DirPath::Builder::pushFront: nonincident edge");
klao@369: 	}
klao@493: 	front.push_back(e);
klao@369:       }
klao@493: 
alpar@434:       ///Push a new edge to the back of the path
alpar@434: 
alpar@434:       ///Push a new edge to the back of the path.
klao@619:       ///\sa setStart
klao@493:       void pushBack(const GraphEdge& e) {
klao@493: 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
klao@493: 	  fault("DirPath::Builder::pushBack: nonincident edge");
klao@369: 	}
klao@493: 	back.push_back(e);
klao@369:       }
klao@369: 
alpar@434:       ///Commit the changes to the path.
klao@369:       void commit() {
klao@493: 	if( !(front.empty() && back.empty()) ) {
klao@493: 	  Container tmp;
klao@493: 	  tmp.reserve(front.size()+back.size()+P.length());
klao@493: 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
klao@493: 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
klao@493: 	  tmp.insert(tmp.end(), back.begin(), back.end());
klao@493: 	  P.edges.swap(tmp);
klao@493: 	  front.clear();
klao@493: 	  back.clear();
klao@369: 	}
klao@369:       }
klao@369: 
klao@619:       // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
klao@619:       // Hogy kenyelmes egy ilyet hasznalni?
klao@619:       void reserve(size_t r) {
klao@619: 	front.reserve(r);
klao@619: 	back.reserve(r);
klao@619:       }
alpar@434: 
klao@619:     private:
klao@619:       bool empty() {
klao@619: 	return front.empty() && back.empty() && P.empty();
klao@619:       }
klao@619: 
klao@619:       GraphNode from() const {
klao@619: 	if( ! front.empty() )
klao@619: 	  return P.gr->tail(front[front.size()-1]);
klao@619: 	else if( ! P.empty() )
klao@619: 	  return P.gr->tail(P.edges[0]);
klao@619: 	else if( ! back.empty() )
klao@619: 	  return P.gr->tail(back[0]);
klao@619: 	else
klao@619: 	  return INVALID;
klao@619:       }
klao@619:       GraphNode to() const {
klao@619: 	if( ! back.empty() )
klao@619: 	  return P.gr->head(back[back.size()-1]);
klao@619: 	else if( ! P.empty() )
klao@619: 	  return P.gr->head(P.edges[P.length()-1]);
klao@619: 	else if( ! front.empty() )
klao@619: 	  return P.gr->head(front[0]);
klao@619: 	else
klao@619: 	  return INVALID;
klao@619:       }
klao@619: 
klao@619:     };
klao@619: 
klao@619:   };
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619: 
klao@619:   /**********************************************************************/
klao@619: 
klao@619: 
klao@619:   //! \brief A structure for representing undirected path in a graph.
klao@619:   //!
klao@619:   //! A structure for representing undirected path in a graph. Ie. this is
klao@619:   //! a path in a \e directed graph but the edges should not be directed
klao@619:   //! forward.
klao@619:   //!
klao@619:   //! \param Graph The graph type in which the path is.
klao@619:   //! \param DM DebugMode, defaults to DefaultDebugMode.
klao@619:   //! 
klao@619:   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
klao@619:   //! and \c EdgeIt with the same usage. These types converts to the \c Node
klao@619:   //! and \c Edge of the original graph.
klao@619:   //!
klao@619:   //! \todo Thoroughfully check all the range and consistency tests.
klao@619:   template<typename Graph, typename DM = DefaultDebugMode>
klao@619:   class UndirPath {
klao@619:   public:
klao@619:     typedef typename Graph::Edge GraphEdge;
klao@619:     typedef typename Graph::Node GraphNode;
klao@619:     class NodeIt;
klao@619:     class EdgeIt;
klao@619: 
klao@619:   protected:
klao@619:     const Graph *gr;
klao@619:     typedef std::vector<GraphEdge> Container;
klao@619:     Container edges;
klao@619: 
klao@619:   public:
klao@619: 
klao@619:     /// \param _G The graph in which the path is.
klao@619:     ///
klao@619:     UndirPath(const Graph &_G) : gr(&_G) {}
klao@619: 
klao@619:     /// \brief Subpath constructor.
klao@619:     ///
klao@619:     /// Subpath defined by two nodes.
klao@619:     /// \warning It is an error if the two edges are not in order!
klao@619:     UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
klao@619:       if( DM::range_check && (!a.valid() || !b.valid) ) {
klao@619: 	// FIXME: this check should be more elaborate...
klao@619: 	fault("UndirPath, subpath ctor: invalid bounding nodes");
klao@619:       }
klao@619:       gr = P.gr;
klao@619:       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
klao@619:     }
klao@619: 
klao@619:     /// \brief Subpath constructor.
klao@619:     ///
klao@619:     /// Subpath defined by two edges. Contains edges in [a,b)
klao@619:     /// \warning It is an error if the two edges are not in order!
klao@619:     UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
klao@619:       if( DM::range_check && (!a.valid() || !b.valid) ) {
klao@619: 	// FIXME: this check should be more elaborate...
klao@619: 	fault("UndirPath, subpath ctor: invalid bounding nodes");
klao@619:       }
klao@619:       gr = P.gr;
klao@619:       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
klao@619:     }
klao@619: 
klao@619:     /// Length of the path.
klao@619:     size_t length() const { return edges.size(); }
klao@619:     /// Returns whether the path is empty.
klao@619:     bool empty() const { return edges.empty(); }
klao@619: 
klao@619:     /// Resets the path to an empty path.
klao@619:     void clear() { edges.clear(); }
klao@619: 
klao@619:     /// \brief Starting point of the path.
klao@619:     ///
klao@619:     /// Starting point of the path.
klao@619:     /// Returns INVALID if the path is empty.
klao@619:     GraphNode from() const {
klao@619:       return empty() ? INVALID : gr->tail(edges[0]);
klao@619:     }
klao@619:     /// \brief End point of the path.
klao@619:     ///
klao@619:     /// End point of the path.
klao@619:     /// Returns INVALID if the path is empty.
klao@619:     GraphNode to() const {
klao@619:       return empty() ? INVALID : gr->head(edges[length()-1]);
klao@619:     }
klao@619: 
klao@619:     /// \brief Initializes node or edge iterator to point to the first
klao@619:     /// node or edge.
klao@619:     ///
klao@619:     /// \sa nth
klao@619:     template<typename It>
klao@619:     It& first(It &i) const { return i=It(*this); }
klao@619: 
klao@619:     /// \brief Initializes node iterator to point to the node of a given index.
klao@619:     NodeIt& nth(NodeIt &i, int n) const {
klao@619:       if( DM::range_check && (n<0 || n>int(length())) )
klao@619: 	fault("UndirPath::nth: index out of range");
klao@619:       return i=NodeIt(*this, n);
klao@619:     }
klao@619: 
klao@619:     /// \brief Initializes edge iterator to point to the edge of a given index.
klao@619:     EdgeIt& nth(EdgeIt &i, int n) const {
klao@619:       if( DM::range_check && (n<0 || n>=int(length())) )
klao@619: 	fault("UndirPath::nth: index out of range");
klao@619:       return i=EdgeIt(*this, n);
klao@619:     }
klao@619: 
klao@619:     /// Checks validity of a node or edge iterator.
klao@619:     template<typename It>
klao@619:     static
klao@619:     bool valid(const It &i) { return i.valid(); }
klao@619: 
klao@619:     /// Steps the given node or edge iterator.
klao@619:     template<typename It>
klao@619:     static
klao@619:     It& next(It &e) {
klao@619:       if( DM::range_check && !e.valid() )
klao@619: 	fault("UndirPath::next() on invalid iterator");
klao@619:       return ++e;
klao@619:     }
klao@619: 
klao@619:     /// \brief Returns node iterator pointing to the head node of the
klao@619:     /// given edge iterator.
klao@619:     NodeIt head(const EdgeIt& e) const {
klao@619:       if( DM::range_check && !e.valid() )
klao@619: 	fault("UndirPath::head() on invalid iterator");
klao@619:       return NodeIt(*this, e.idx+1);
klao@619:     }
klao@619: 
klao@619:     /// \brief Returns node iterator pointing to the tail node of the
klao@619:     /// given edge iterator.
klao@619:     NodeIt tail(const EdgeIt& e) const {
klao@619:       if( DM::range_check && !e.valid() )
klao@619: 	fault("UndirPath::tail() on invalid iterator");
klao@619:       return NodeIt(*this, e.idx);
klao@619:     }
klao@619: 
klao@619: 
klao@619:     /*** Iterator classes ***/
klao@619:     class EdgeIt {
klao@619:       friend class UndirPath;
klao@619: 
klao@619:       int idx;
klao@619:       const UndirPath *p;
klao@619:     public:
klao@619:       EdgeIt() {}
klao@619:       EdgeIt(Invalid) : idx(-1), p(0) {}
klao@619:       EdgeIt(const UndirPath &_p, int _idx = 0) :
klao@619: 	idx(_idx), p(&_p) { validate(); }
klao@619: 
klao@619:       bool valid() const { return idx!=-1; }
klao@619: 
klao@619:       operator GraphEdge () const {
klao@619: 	return valid() ? p->edges[idx] : INVALID;
klao@619:       }
klao@619:       EdgeIt& operator++() { ++idx; validate(); return *this; }
klao@619: 
klao@619:       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
klao@619:       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
klao@619:       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
klao@619: 
klao@619:     private:
klao@619:       // FIXME: comparison between signed and unsigned...
klao@619:       // Jo ez igy? Vagy esetleg legyen a length() int?
klao@619:       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
klao@619:     };
klao@619: 
klao@619:     class NodeIt {
klao@619:       friend class UndirPath;
klao@619: 
klao@619:       int idx;
klao@619:       const UndirPath *p;
klao@619:     public:
klao@619:       NodeIt() {}
klao@619:       NodeIt(Invalid) : idx(-1), p(0) {}
klao@619:       NodeIt(const UndirPath &_p, int _idx = 0) :
klao@619: 	idx(_idx), p(&_p) { validate(); }
klao@619: 
klao@619:       bool valid() const { return idx!=-1; }
klao@619: 
klao@619:       operator const GraphNode& () const {
klao@619: 	if(idx >= p->length())
klao@619: 	  return p->to();
klao@619: 	else if(idx >= 0)
klao@619: 	  return p->gr->tail(p->edges[idx]);
klao@619: 	else
klao@619: 	  return INVALID;
klao@619:       }
klao@619:       NodeIt& operator++() { ++idx; validate(); return *this; }
klao@619: 
klao@619:       bool operator==(const NodeIt& e) const { return idx==e.idx; }
klao@619:       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
klao@619:       bool operator<(const NodeIt& e) const { return idx<e.idx; }
klao@619: 
klao@619:     private:
klao@619:       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
klao@619:     };
klao@619: 
klao@619:     friend class Builder;    
klao@619: 
klao@619:     /**
klao@619:      * \brief Class to build paths
klao@619:      * 
klao@619:      * \ingroup datas
klao@619:      * This class is used to fill a path with edges.
klao@619:      *
klao@619:      * You can push new edges to the front and to the back of the path in
klao@619:      * arbitrary order then you should commit these changes to the graph.
klao@619:      *
klao@619:      * Fundamentally, for most "Paths" (classes fulfilling the
klao@619:      * PathConcept) while the builder is active (after the first modifying
klao@619:      * operation and until the commit()) the original Path is in a
klao@619:      * "transitional" state (operations ot it have undefined result). But
klao@619:      * in the case of UndirPath the original path is unchanged until the
klao@619:      * commit. However we don't recomend that you use this feature.
klao@619:      */
klao@619:     class Builder {
klao@619:       UndirPath &P;
klao@619:       Container front, back;
klao@619: 
klao@619:     public:
klao@619:       ///\param _P the path you want to fill in.
klao@619:       ///
klao@619:       Builder(UndirPath &_P) : P(_P) {}
klao@619: 
klao@619:       /// Sets the starting node of the path.
klao@619:       
klao@619:       /// Sets the starting node of the path. Edge added to the path
klao@619:       /// afterwards have to be incident to this node.
klao@619:       /// It should be called iff the path is empty and before any call to
klao@619:       /// \ref pushFront() or \ref pushBack()
klao@619:       void setStart(const GraphNode &) {}
klao@619: 
klao@619:       ///Push a new edge to the front of the path
klao@619: 
klao@619:       ///Push a new edge to the front of the path.
klao@619:       ///\sa setStart
klao@619:       void pushFront(const GraphEdge& e) {
klao@619: 	if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
klao@619: 	  fault("UndirPath::Builder::pushFront: nonincident edge");
klao@619: 	}
klao@619: 	front.push_back(e);
klao@619:       }
klao@619: 
klao@619:       ///Push a new edge to the back of the path
klao@619: 
klao@619:       ///Push a new edge to the back of the path.
klao@619:       ///\sa setStart
klao@619:       void pushBack(const GraphEdge& e) {
klao@619: 	if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
klao@619: 	  fault("UndirPath::Builder::pushBack: nonincident edge");
klao@619: 	}
klao@619: 	back.push_back(e);
klao@619:       }
klao@619: 
klao@619:       ///Commit the changes to the path.
klao@619:       void commit() {
klao@619: 	if( !(front.empty() && back.empty()) ) {
klao@619: 	  Container tmp;
klao@619: 	  tmp.reserve(front.size()+back.size()+P.length());
klao@619: 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
klao@619: 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
klao@619: 	  tmp.insert(tmp.end(), back.begin(), back.end());
klao@619: 	  P.edges.swap(tmp);
klao@619: 	  front.clear();
klao@619: 	  back.clear();
klao@619: 	}
klao@619:       }
klao@369: 
klao@369:       // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
klao@369:       // Hogy kenyelmes egy ilyet hasznalni?
klao@369:       void reserve(size_t r) {
klao@493: 	front.reserve(r);
klao@493: 	back.reserve(r);
klao@369:       }
klao@369: 
klao@369:     private:
klao@493:       bool empty() {
klao@493: 	return front.empty() && back.empty() && P.empty();
klao@493:       }
klao@369: 
klao@369:       GraphNode from() const {
klao@493: 	if( ! front.empty() )
klao@493: 	  return P.gr->tail(front[front.size()-1]);
klao@369: 	else if( ! P.empty() )
klao@369: 	  return P.gr->tail(P.edges[0]);
klao@493: 	else if( ! back.empty() )
klao@493: 	  return P.gr->tail(back[0]);
klao@369: 	else
klao@369: 	  return INVALID;
klao@369:       }
klao@369:       GraphNode to() const {
klao@493: 	if( ! back.empty() )
klao@493: 	  return P.gr->head(back[back.size()-1]);
klao@493: 	else if( ! P.empty() )
klao@369: 	  return P.gr->head(P.edges[P.length()-1]);
klao@493: 	else if( ! front.empty() )
klao@493: 	  return P.gr->head(front[0]);
klao@369: 	else
klao@369: 	  return INVALID;
klao@369:       }
klao@369: 
klao@369:     };
klao@369: 
klao@369:   };
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369: 
klao@369:   /**********************************************************************/
klao@369: 
klao@369: 
klao@225:   /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
klao@225:      elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
klao@225: 
klao@225:   template<typename Graph>
klao@369:   class DynamicPath {
klao@225: 
klao@225:   public:
klao@225:     typedef typename Graph::Edge GraphEdge;
klao@225:     typedef typename Graph::Node GraphNode;
klao@225:     class NodeIt;
klao@225:     class EdgeIt;
klao@225: 
klao@225:   protected:
klao@225:     Graph& G;
klao@225:     // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
klao@225:     // iranyitasat:
klao@225:     GraphNode _first, _last;
klao@225:     typedef std::deque<GraphEdge> Container;
klao@225:     Container edges;
klao@225: 
klao@225:   public:
klao@225: 
klao@369:     DynamicPath(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
klao@225: 
klao@226:     /// Subpath defined by two nodes.
klao@226:     /// Nodes may be in reversed order, then
klao@226:     /// we contstruct the reversed path.
klao@369:     DynamicPath(const DynamicPath &P, const NodeIt &a, const NodeIt &b);
klao@226:     /// Subpath defined by two edges. Contains edges in [a,b)
klao@226:     /// It is an error if the two edges are not in order!
klao@369:     DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
klao@225:     
klao@225:     size_t length() const { return edges.size(); }
klao@225:     GraphNode from() const { return _first; }
klao@225:     GraphNode to() const { return _last; }
klao@225: 
klao@225:     NodeIt& first(NodeIt &n) const { return nth(n, 0); }
klao@225:     EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
klao@225:     template<typename It>
klao@225:     It first() const { 
klao@225:       It e;
klao@225:       first(e);
klao@225:       return e; 
klao@225:     }
klao@225: 
klao@225:     NodeIt& nth(NodeIt &, size_t) const;
klao@225:     EdgeIt& nth(EdgeIt &, size_t) const;
klao@225:     template<typename It>
klao@225:     It nth(size_t n) const { 
klao@225:       It e;
klao@225:       nth(e, n);
klao@225:       return e; 
klao@225:     }
klao@225: 
klao@225:     bool valid(const NodeIt &n) const { return n.idx <= length(); }
klao@225:     bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
klao@225: 
klao@225:     bool isForward(const EdgeIt &e) const { return e.forw; }
klao@225: 
klao@226:     /// index of a node on the path. Returns length+2 for the invalid NodeIt
klao@226:     int index(const NodeIt &n) const { return n.idx; }
klao@226:     /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
klao@226:     int index(const EdgeIt &e) const { return e.it - edges.begin(); }
klao@226: 
klao@225:     EdgeIt& next(EdgeIt &e) const;
klao@225:     NodeIt& next(NodeIt &n) const;
klao@225:     template <typename It>
klao@225:     It getNext(It it) const {
klao@225:       It tmp(it); return next(tmp);
klao@225:     }
klao@225: 
klao@225:     // A path is constructed using the following four functions.
klao@225:     // They return false if the requested operation is inconsistent
klao@225:     // with the path constructed so far.
klao@225:     // If your path has only one edge you MUST set either "from" or "to"!
klao@225:     // So you probably SHOULD call it in any case to be safe (and check the
klao@225:     // returned value to check if your path is consistent with your idea).
klao@225:     bool pushFront(const GraphEdge &e);
klao@225:     bool pushBack(const GraphEdge &e);
klao@225:     bool setFrom(const GraphNode &n);
klao@225:     bool setTo(const GraphNode &n);
klao@225: 
klao@225:     // WARNING: these two functions return the head/tail of an edge with
klao@225:     // respect to the direction of the path!
klao@225:     // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if 
klao@225:     // P.forward(e) is true (or the edge is a loop)!
klao@225:     NodeIt head(const EdgeIt& e) const;
klao@225:     NodeIt tail(const EdgeIt& e) const;
klao@225: 
klao@225:     // FIXME: ezeknek valami jobb nev kellene!!!
klao@225:     GraphEdge graphEdge(const EdgeIt& e) const;
klao@225:     GraphNode graphNode(const NodeIt& n) const;
klao@225: 
klao@225: 
klao@225:     /*** Iterator classes ***/
klao@225:     class EdgeIt {
klao@369:       friend class DynamicPath;
klao@225: 
klao@225:       typename Container::const_iterator it;
klao@225:       bool forw;
klao@225:     public:
klao@225:       // FIXME: jarna neki ilyen is...
klao@225:       // EdgeIt(Invalid);
klao@225: 
klao@225:       bool forward() const { return forw; }
klao@225: 
klao@225:       bool operator==(const EdgeIt& e) const { return it==e.it; }
klao@225:       bool operator!=(const EdgeIt& e) const { return it!=e.it; }
klao@225:       bool operator<(const EdgeIt& e) const { return it<e.it; }
klao@225:     };
klao@225: 
klao@225:     class NodeIt {
klao@369:       friend class DynamicPath;
klao@225: 
klao@226:       size_t idx;
klao@225:       bool tail;  // Is this node the tail of the edge with same idx?
klao@225: 
klao@225:     public:
klao@225:       // FIXME: jarna neki ilyen is...
klao@225:       // NodeIt(Invalid);
klao@225: 
klao@225:       bool operator==(const NodeIt& n) const { return idx==n.idx; }
klao@225:       bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
klao@225:       bool operator<(const NodeIt& n) const { return idx<n.idx; }
klao@225:     };
klao@225: 
klao@225:   private:
klao@225:     bool edgeIncident(const GraphEdge &e, const GraphNode &a,
klao@225: 		      GraphNode &b);
klao@225:     bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
klao@225:   };
klao@225: 
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::EdgeIt&
klao@369:   DynamicPath<Gr>::next(DynamicPath::EdgeIt &e) const {
klao@225:     if( e.it == edges.end() ) 
klao@225:       return e;
klao@225: 
klao@225:     GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
klao@225:     ++e.it;
klao@225: 
klao@225:     // Invalid edgeit is always forward :)
klao@225:     if( e.it == edges.end() ) {
klao@225:       e.forw = true;
klao@225:       return e;
klao@225:     }
klao@225: 
klao@225:     e.forw = ( G.tail(*e.it) == common_node );
klao@225:     return e;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::NodeIt& DynamicPath<Gr>::next(NodeIt &n) const {
klao@225:     if( n.idx >= length() ) {
klao@225:       // FIXME: invalid
klao@225:       n.idx = length()+1;
klao@225:       return n;
klao@225:     }
klao@225: 
klao@225:     
klao@225:     GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
klao@225: 			      G.tail(edges[n.idx]) );
klao@225:     ++n.idx;
klao@225:     if( n.idx < length() ) {
klao@225:       n.tail = ( next_node == G.tail(edges[n.idx]) );
klao@225:     }
klao@225:     else {
klao@225:       n.tail = true;
klao@225:     }
klao@225: 
klao@225:     return n;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
klao@225: 			  GraphNode &b) {
klao@225:     if( G.tail(e) == a ) {
klao@225:       b=G.head(e);
klao@225:       return true;
klao@225:     }
klao@225:     if( G.head(e) == a ) {
klao@225:       b=G.tail(e);
klao@225:       return true;
klao@225:     }
klao@225:     return false;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::connectTwoEdges(const GraphEdge &e,
klao@225: 			     const GraphEdge &f) {
klao@225:     if( edgeIncident(f, G.tail(e), _last) ) {
klao@225:       _first = G.head(e);
klao@225:       return true;
klao@225:     }
klao@225:     if( edgeIncident(f, G.head(e), _last) ) {
klao@225:       _first = G.tail(e);
klao@225:       return true;
klao@225:     }
klao@225:     return false;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::pushFront(const GraphEdge &e) {
klao@225:     if( G.valid(_first) ) {
klao@225: 	if( edgeIncident(e, _first, _first) ) {
klao@225: 	  edges.push_front(e);
klao@225: 	  return true;
klao@225: 	}
klao@225: 	else
klao@225: 	  return false;
klao@225:     }
klao@225:     else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
klao@225:       edges.push_front(e);
klao@225:       return true;
klao@225:     }
klao@225:     else
klao@225:       return false;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::pushBack(const GraphEdge &e) {
klao@225:     if( G.valid(_last) ) {
klao@225: 	if( edgeIncident(e, _last, _last) ) {
klao@225: 	  edges.push_back(e);
klao@225: 	  return true;
klao@225: 	}
klao@225: 	else
klao@225: 	  return false;
klao@225:     }
klao@225:     else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
klao@225:       edges.push_back(e);
klao@225:       return true;
klao@225:     }
klao@225:     else
klao@225:       return false;
klao@225:   }
klao@225: 
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::setFrom(const GraphNode &n) {
klao@225:     if( G.valid(_first) ) {
klao@225:       return _first == n;
klao@225:     }
klao@225:     else {
klao@225:       if( length() > 0) {
klao@225: 	if( edgeIncident(edges[0], n, _last) ) {
klao@225: 	  _first = n;
klao@225: 	  return true;
klao@225: 	}
klao@225: 	else return false;
klao@225:       }
klao@225:       else {
klao@225: 	_first = _last = n;
klao@225: 	return true;
klao@225:       }
klao@225:     }
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   bool DynamicPath<Gr>::setTo(const GraphNode &n) {
klao@225:     if( G.valid(_last) ) {
klao@225:       return _last == n;
klao@225:     }
klao@225:     else {
klao@225:       if( length() > 0) {
klao@225: 	if( edgeIncident(edges[0], n, _first) ) {
klao@225: 	  _last = n;
klao@225: 	  return true;
klao@225: 	}
klao@225: 	else return false;
klao@225:       }
klao@225:       else {
klao@225: 	_first = _last = n;
klao@225: 	return true;
klao@225:       }
klao@225:     }
klao@225:   }
klao@225: 
klao@225: 
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::NodeIt
klao@369:   DynamicPath<Gr>::tail(const EdgeIt& e) const {
klao@225:     NodeIt n;
klao@225: 
klao@225:     if( e.it == edges.end() ) {
klao@225:       // FIXME: invalid-> invalid
klao@225:       n.idx = length() + 1;
klao@225:       n.tail = true;
klao@225:       return n;
klao@225:     }
klao@225: 
klao@225:     n.idx = e.it-edges.begin();
klao@225:     n.tail = e.forw;
klao@226:     return n;
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::NodeIt
klao@369:   DynamicPath<Gr>::head(const EdgeIt& e) const {
klao@225:     if( e.it == edges.end()-1 ) {
klao@225:       return _last;
klao@225:     }
klao@225: 
klao@225:     EdgeIt next_edge = e;
klao@225:     next(next_edge);
klao@225:     return tail(next_edge);
klao@225:   }
klao@225:       
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::GraphEdge
klao@369:   DynamicPath<Gr>::graphEdge(const EdgeIt& e) const {
klao@225:     if( e.it != edges.end() ) {
klao@225:       return *e.it;
klao@225:     }
klao@225:     else {
klao@225:       return INVALID;
klao@225:     }
klao@225:   }
klao@225:   
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::GraphNode
klao@369:   DynamicPath<Gr>::graphNode(const NodeIt& n) const {
klao@225:     if( n.idx < length() ) {
klao@225:       return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
klao@225:     }
klao@225:     else if( n.idx == length() ) {
klao@225:       return _last;
klao@225:     }
klao@225:     else {
klao@225:       return INVALID;
klao@225:     }
klao@225:   }
klao@225: 
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::EdgeIt&
klao@369:   DynamicPath<Gr>::nth(EdgeIt &e, size_t k) const {
klao@450:     if( k>=length() ) {
klao@225:       // FIXME: invalid EdgeIt
klao@225:       e.it = edges.end();
klao@225:       e.forw = true;
klao@225:       return e;
klao@225:     }
klao@225: 
klao@225:     e.it = edges.begin()+k;
klao@225:     if(k==0) {
klao@225:       e.forw = ( G.tail(*e.it) == _first );
klao@225:     }
klao@225:     else {
klao@225:       e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
klao@225: 		 G.tail(*e.it) == G.head(edges[k-1]) );
klao@225:     }
klao@225:     return e;
klao@225:   }
klao@225:     
klao@225:   template<typename Gr>
klao@369:   typename DynamicPath<Gr>::NodeIt&
klao@369:   DynamicPath<Gr>::nth(NodeIt &n, size_t k) const {
klao@450:     if( k>length() ) {
klao@225:       // FIXME: invalid NodeIt
klao@225:       n.idx = length()+1;
klao@225:       n.tail = true;
klao@225:       return n;
klao@225:     }
klao@225:     if( k==length() ) {
klao@225:       n.idx = length();
klao@225:       n.tail = true;
klao@225:       return n;
klao@225:     }
klao@225:     n = tail(nth<EdgeIt>(k));
klao@225:     return n;
klao@225:   }
klao@225: 
klao@226:   // Reszut konstruktorok:
klao@226: 
klao@226: 
klao@226:   template<typename Gr>
klao@369:   DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const EdgeIt &a,
klao@369: 			       const EdgeIt &b) :
klao@226:     G(P.G), edges(a.it, b.it)    // WARNING: if b.it < a.it this will blow up! 
klao@226:   {
klao@226:     if( G.valid(P._first) && a.it < P.edges.end() ) {
klao@226:       _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
klao@226:       if( b.it < P.edges.end() ) {
klao@226: 	_last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
klao@226:       }
klao@226:       else {
klao@226: 	_last = P._last;
klao@226:       }
klao@226:     }
klao@226:   }
klao@226: 
klao@226:   template<typename Gr>
klao@369:   DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const NodeIt &a,
klao@369: 			       const NodeIt &b) : G(P.G)
klao@226:   {
klao@226:     if( !P.valid(a) || !P.valid(b) )
klao@226:       return;
klao@226: 
klao@226:     int ai = a.idx, bi = b.idx;
klao@226:     if( bi<ai )
klao@450:       std::swap(ai,bi);
klao@226:     
klao@226:     edges.resize(bi-ai);
klao@226:     copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
klao@226: 
klao@226:     _first = P.graphNode(a);
klao@226:     _last = P.graphNode(b);
klao@226:   }
klao@226: 
alpar@434:   ///@}
klao@225: 
klao@225: } // namespace hugo
klao@225: 
klao@225: #endif // HUGO_PATH_H