klao@225: // -*- c++ -*- // klao@225: alpar@434: ///ingroup datas alpar@434: ///\file alpar@434: ///\brief Class 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: klao@225: #include klao@225: klao@225: namespace hugo { klao@225: alpar@434: /// \addtogroup datas alpar@434: /// @{ alpar@434: alpar@434: ///A container for directed paths alpar@434: alpar@434: ///\param Graph The graph type in which the path is. alpar@434: /// alpar@434: ///In a sense, the path can be treated as a graph, for is has \c NodeIt alpar@434: ///and \c EdgeIt with the same usage. These types converts to the \c Node alpar@434: ///and \c Edge of the original graph. alpar@434: ///\todo How to clear a path? alpar@434: ///\todo Clarify the consistency checks to do. klao@369: 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: /// Constructor alpar@434: alpar@434: /// \param _G The graph in which the path is. alpar@434: /// klao@369: DirPath(const Graph &_G) : gr(&_G) {} klao@369: klao@369: /// Subpath defined by two nodes. alpar@434: /// \warning It is an error if the two edges are not in order! klao@369: DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b); 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@369: DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b); klao@369: klao@369: size_t length() const { return edges.size(); } klao@369: bool empty() const { return edges.empty(); } klao@369: GraphNode from() const { klao@369: return empty() ? INVALID : gr->tail(edges[0]); klao@369: } klao@369: GraphNode to() const { klao@369: return empty() ? INVALID : gr->head(edges[length()-1]); klao@369: } klao@369: klao@369: template klao@369: It& first(It &i) const { return i=It(*this); } klao@369: klao@369: template klao@369: It& nth(It &i, int n) const { return i=It(*this, n); } klao@369: klao@369: template klao@369: bool valid(const It &i) const { return i.valid(); } klao@369: klao@369: template klao@369: It& next(It &e) const { return ++e; } klao@369: klao@369: /// \todo ! klao@369: NodeIt head(const EdgeIt& e) const; klao@369: NodeIt tail(const EdgeIt& e) const; 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: alpar@434: ///Class to build paths alpar@434: alpar@434: ///\ingroup datas alpar@434: ///This class is used to build new paths. alpar@434: ///You can push new edges to the front and to the back of the path in alpar@434: ///arbitrary order the you can commit these changes to the graph. alpar@434: ///\todo We must clarify when the path will be in "transitional" state. klao@369: class Builder { klao@369: DirPath &P; klao@369: Container d; klao@369: klao@369: public: alpar@434: ///Constructor alpar@434: alpar@434: ///\param _P the path you want to build. alpar@434: /// klao@369: Builder(DirPath &_P) : P(_P) {} klao@369: alpar@434: ///Set the first node of the path. alpar@434: alpar@434: ///Set the first node of the path. alpar@434: ///If the path is empty, this must be call before any call of alpar@434: ///\ref pushFront() or \ref pushBack() alpar@434: void setFirst(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. alpar@434: ///\sa setFirst() klao@369: bool pushFront(const GraphEdge& e) { klao@369: if( empty() || P.gr->head(e)==from() ) { klao@369: d.push_back(e); klao@369: return true; klao@369: } klao@369: return false; klao@369: } 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. alpar@434: ///\sa setFirst() klao@369: bool pushBack(const GraphEdge& e) { klao@369: if( empty() || P.gr->tail(e)==to() ) { klao@369: P.edges.push_back(e); klao@369: return true; klao@369: } klao@369: return false; klao@369: } klao@369: alpar@434: ///Commit the changes to the path. klao@369: void commit() { klao@369: if( !d.empty() ) { klao@369: P.edges.insert(P.edges.begin(), d.rbegin(), d.rend()); klao@369: d.clear(); klao@369: } klao@369: } klao@369: alpar@434: ///Desctuctor alpar@434: alpar@434: ///The desctuctor. alpar@434: ///It commit also commit the changes. alpar@434: ///\todo Is this what we want? klao@369: ~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@369: d.reserve(r); klao@369: P.edges.reserve(P.length()+r); klao@369: } klao@369: klao@369: private: klao@369: bool empty() { return d.empty() && P.empty(); } klao@369: klao@369: GraphNode from() const { klao@369: if( ! d.empty() ) klao@369: return P.gr->tail(d[d.size()-1]); klao@369: else if( ! P.empty() ) klao@369: return P.gr->tail(P.edges[0]); klao@369: else klao@369: return INVALID; klao@369: } klao@369: GraphNode to() const { klao@369: if( ! P.empty() ) klao@369: return P.gr->head(P.edges[P.length()-1]); klao@369: else if( ! d.empty() ) klao@369: return P.gr->head(d[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