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 klao@369: #include klao@226: #include klao@225: athos@607: #include athos@607: #include klao@493: #include 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@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 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 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@493: /// \todo Implement! klao@369: DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b); 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@493: /// \todo Implement! klao@369: DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b); 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 klao@369: It& first(It &i) const { return i=It(*this); } klao@369: klao@493: /// \brief Initializes node or edge iterator to point to the node or edge klao@493: /// of a given index. klao@369: template klao@493: It& nth(It &i, int n) const { klao@493: // FIXME: this test should be different for NodeIt and EdgeIt: klao@493: if( DM::range_check && (n<0 || n>int(length())) ) klao@493: fault("DirPath::nth: index out of range"); klao@493: return i=It(*this, n); klao@493: } klao@369: klao@493: /// Checks validity of a node or edge iterator. klao@369: template klao@369: bool valid(const It &i) const { return i.valid(); } klao@369: klao@493: /// Steps the given node or edge iterator. klao@369: template klao@493: It& next(It &e) const { 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@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@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= 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@369: operator const GraphEdge& () 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 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@493: * arbitrary order the you can 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@493: ///Sets the first node of the path. alpar@434: klao@493: ///Sets the first node of the path. If the path is empty, this klao@493: ///function or setTo() have to be called before any call to \ref klao@493: ///pushFront() or \ref pushBack() klao@493: void setFrom(const GraphNode &) {} klao@493: klao@493: ///Sets the last node of the path. klao@493: klao@493: ///Sets the last node of the path. If the path is empty, this klao@493: ///function or setFrom() have to be called before any call of \ref klao@493: ///pushFront() or \ref pushBack() klao@493: void setTo(const GraphNode &) {} alpar@434: 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@493: ///\sa setTo 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@493: ///\sa setFrom 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@493: // ///Desctuctor alpar@434: klao@493: // ///The desctuctor. klao@493: // ///It commit also commit the changes. klao@493: // ///\todo Is this what we want? klao@493: // Nope. Let's use commit() explicitly. klao@493: // ~Builder() { commit(); } 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 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 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 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 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 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 klao@369: typename DynamicPath::EdgeIt& klao@369: DynamicPath::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 klao@369: typename DynamicPath::NodeIt& DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: bool DynamicPath::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 klao@369: typename DynamicPath::NodeIt klao@369: DynamicPath::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 klao@369: typename DynamicPath::NodeIt klao@369: DynamicPath::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 klao@369: typename DynamicPath::GraphEdge klao@369: DynamicPath::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 klao@369: typename DynamicPath::GraphNode klao@369: DynamicPath::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 klao@369: typename DynamicPath::EdgeIt& klao@369: DynamicPath::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 klao@369: typename DynamicPath::NodeIt& klao@369: DynamicPath::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(k)); klao@225: return n; klao@225: } klao@225: klao@226: // Reszut konstruktorok: klao@226: klao@226: klao@226: template klao@369: DynamicPath::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 klao@369: DynamicPath::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