Minor changes: Section labels fixed.
5 ///\brief Classes for representing paths in graphs.
14 #include <hugo/invalid.h>
15 #include <hugo/error.h>
24 //! \brief A structure for representing directed path in a graph.
26 //! \param Graph The graph type in which the path is.
27 //! \param DM DebugMode, defaults to DefaultDebugMode.
29 //! In a sense, the path can be treated as a graph, for is has \c NodeIt
30 //! and \c EdgeIt with the same usage. These types converts to the \c Node
31 //! and \c Edge of the original graph.
33 //! \todo Thoroughfully check all the range and consistency tests.
34 template<typename Graph, typename DM = DefaultDebugMode>
37 typedef typename Graph::Edge GraphEdge;
38 typedef typename Graph::Node GraphNode;
44 typedef std::vector<GraphEdge> Container;
49 /// \param _G The graph in which the path is.
51 DirPath(const Graph &_G) : gr(&_G) {}
53 /// \brief Subpath constructor.
55 /// Subpath defined by two nodes.
56 /// \warning It is an error if the two edges are not in order!
58 DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b);
59 /// \brief Subpath constructor.
61 /// Subpath defined by two edges. Contains edges in [a,b)
62 /// \warning It is an error if the two edges are not in order!
64 DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b);
66 /// Length of the path.
67 size_t length() const { return edges.size(); }
68 /// Returns whether the path is empty.
69 bool empty() const { return edges.empty(); }
71 /// Resets the path to an empty path.
72 void clear() { edges.clear(); }
74 /// \brief Starting point of the path.
76 /// Starting point of the path.
77 /// Returns INVALID if the path is empty.
78 GraphNode from() const {
79 return empty() ? INVALID : gr->tail(edges[0]);
81 /// \brief End point of the path.
83 /// End point of the path.
84 /// Returns INVALID if the path is empty.
85 GraphNode to() const {
86 return empty() ? INVALID : gr->head(edges[length()-1]);
89 /// \brief Initializes node or edge iterator to point to the first
94 It& first(It &i) const { return i=It(*this); }
96 /// \brief Initializes node or edge iterator to point to the node or edge
99 It& nth(It &i, int n) const {
100 // FIXME: this test should be different for NodeIt and EdgeIt:
101 if( DM::range_check && (n<0 || n>int(length())) )
102 fault("DirPath::nth: index out of range");
103 return i=It(*this, n);
106 /// Checks validity of a node or edge iterator.
107 template<typename It>
108 bool valid(const It &i) const { return i.valid(); }
110 /// Steps the given node or edge iterator.
111 template<typename It>
112 It& next(It &e) const {
113 if( DM::range_check && !e.valid() )
114 fault("DirPath::next() on invalid iterator");
118 /// \brief Returns node iterator pointing to the head node of the
119 /// given edge iterator.
120 NodeIt head(const EdgeIt& e) const {
121 return NodeIt(*this, e.idx+1);
124 /// \brief Returns node iterator pointing to the tail node of the
125 /// given edge iterator.
126 NodeIt tail(const EdgeIt& e) const {
127 return NodeIt(*this, e.idx);
131 /*** Iterator classes ***/
133 friend class DirPath;
139 EdgeIt(Invalid) : idx(-1), p(0) {}
140 EdgeIt(const DirPath &_p, int _idx = 0) :
141 idx(_idx), p(&_p) { validate(); }
143 bool valid() const { return idx!=-1; }
145 operator GraphEdge () const {
146 return valid() ? p->edges[idx] : INVALID;
148 EdgeIt& operator++() { ++idx; validate(); return *this; }
150 bool operator==(const EdgeIt& e) const { return idx==e.idx; }
151 bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
152 bool operator<(const EdgeIt& e) const { return idx<e.idx; }
155 // FIXME: comparison between signed and unsigned...
156 // Jo ez igy? Vagy esetleg legyen a length() int?
157 void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
161 friend class DirPath;
167 NodeIt(Invalid) : idx(-1), p(0) {}
168 NodeIt(const DirPath &_p, int _idx = 0) :
169 idx(_idx), p(&_p) { validate(); }
171 bool valid() const { return idx!=-1; }
173 operator const GraphEdge& () const {
174 if(idx >= p->length())
177 return p->gr->tail(p->edges[idx]);
181 NodeIt& operator++() { ++idx; validate(); return *this; }
183 bool operator==(const NodeIt& e) const { return idx==e.idx; }
184 bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
185 bool operator<(const NodeIt& e) const { return idx<e.idx; }
188 void validate() { if( size_t(idx) > p->length() ) idx=-1; }
191 friend class Builder;
194 * \brief Class to build paths
197 * This class is used to fill a path with edges.
199 * You can push new edges to the front and to the back of the path in
200 * arbitrary order the you can commit these changes to the graph.
202 * Fundamentally, for most "Paths" (classes fulfilling the
203 * PathConcept) while the builder is active (after the first modifying
204 * operation and until the commit()) the original Path is in a
205 * "transitional" state (operations ot it have undefined result). But
206 * in the case of DirPath the original path is unchanged until the
207 * commit. However we don't recomend that you use this feature.
211 Container front, back;
214 ///\param _P the path you want to fill in.
216 Builder(DirPath &_P) : P(_P) {}
218 ///Sets the first node of the path.
220 ///Sets the first node of the path. If the path is empty, this
221 ///function or setTo() have to be called before any call to \ref
222 ///pushFront() or \ref pushBack()
223 void setFrom(const GraphNode &) {}
225 ///Sets the last node of the path.
227 ///Sets the last node of the path. If the path is empty, this
228 ///function or setFrom() have to be called before any call of \ref
229 ///pushFront() or \ref pushBack()
230 void setTo(const GraphNode &) {}
232 ///Push a new edge to the front of the path
234 ///Push a new edge to the front of the path.
236 void pushFront(const GraphEdge& e) {
237 if( DM::consistensy_check && !empty() && P.gr->head(e)!=from() ) {
238 fault("DirPath::Builder::pushFront: nonincident edge");
243 ///Push a new edge to the back of the path
245 ///Push a new edge to the back of the path.
247 void pushBack(const GraphEdge& e) {
248 if( DM::consistensy_check && !empty() && P.gr->tail(e)!=to() ) {
249 fault("DirPath::Builder::pushBack: nonincident edge");
254 ///Commit the changes to the path.
256 if( !(front.empty() && back.empty()) ) {
258 tmp.reserve(front.size()+back.size()+P.length());
259 tmp.insert(tmp.end(), front.rbegin(), front.rend());
260 tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
261 tmp.insert(tmp.end(), back.begin(), back.end());
270 // ///The desctuctor.
271 // ///It commit also commit the changes.
272 // ///\todo Is this what we want?
273 // Nope. Let's use commit() explicitly.
274 // ~Builder() { commit(); }
276 // FIXME: Hmm, pontosan hogy is kene ezt csinalni?
277 // Hogy kenyelmes egy ilyet hasznalni?
278 void reserve(size_t r) {
285 return front.empty() && back.empty() && P.empty();
288 GraphNode from() const {
289 if( ! front.empty() )
290 return P.gr->tail(front[front.size()-1]);
291 else if( ! P.empty() )
292 return P.gr->tail(P.edges[0]);
293 else if( ! back.empty() )
294 return P.gr->tail(back[0]);
298 GraphNode to() const {
300 return P.gr->head(back[back.size()-1]);
301 else if( ! P.empty() )
302 return P.gr->head(P.edges[P.length()-1]);
303 else if( ! front.empty() )
304 return P.gr->head(front[0]);
322 /**********************************************************************/
325 /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata
326 elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */
328 template<typename Graph>
332 typedef typename Graph::Edge GraphEdge;
333 typedef typename Graph::Node GraphNode;
339 // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el
341 GraphNode _first, _last;
342 typedef std::deque<GraphEdge> Container;
347 DynamicPath(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {}
349 /// Subpath defined by two nodes.
350 /// Nodes may be in reversed order, then
351 /// we contstruct the reversed path.
352 DynamicPath(const DynamicPath &P, const NodeIt &a, const NodeIt &b);
353 /// Subpath defined by two edges. Contains edges in [a,b)
354 /// It is an error if the two edges are not in order!
355 DynamicPath(const DynamicPath &P, const EdgeIt &a, const EdgeIt &b);
357 size_t length() const { return edges.size(); }
358 GraphNode from() const { return _first; }
359 GraphNode to() const { return _last; }
361 NodeIt& first(NodeIt &n) const { return nth(n, 0); }
362 EdgeIt& first(EdgeIt &e) const { return nth(e, 0); }
363 template<typename It>
370 NodeIt& nth(NodeIt &, size_t) const;
371 EdgeIt& nth(EdgeIt &, size_t) const;
372 template<typename It>
373 It nth(size_t n) const {
379 bool valid(const NodeIt &n) const { return n.idx <= length(); }
380 bool valid(const EdgeIt &e) const { return e.it < edges.end(); }
382 bool isForward(const EdgeIt &e) const { return e.forw; }
384 /// index of a node on the path. Returns length+2 for the invalid NodeIt
385 int index(const NodeIt &n) const { return n.idx; }
386 /// index of an edge on the path. Returns length+1 for the invalid EdgeIt
387 int index(const EdgeIt &e) const { return e.it - edges.begin(); }
389 EdgeIt& next(EdgeIt &e) const;
390 NodeIt& next(NodeIt &n) const;
391 template <typename It>
392 It getNext(It it) const {
393 It tmp(it); return next(tmp);
396 // A path is constructed using the following four functions.
397 // They return false if the requested operation is inconsistent
398 // with the path constructed so far.
399 // If your path has only one edge you MUST set either "from" or "to"!
400 // So you probably SHOULD call it in any case to be safe (and check the
401 // returned value to check if your path is consistent with your idea).
402 bool pushFront(const GraphEdge &e);
403 bool pushBack(const GraphEdge &e);
404 bool setFrom(const GraphNode &n);
405 bool setTo(const GraphNode &n);
407 // WARNING: these two functions return the head/tail of an edge with
408 // respect to the direction of the path!
409 // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if
410 // P.forward(e) is true (or the edge is a loop)!
411 NodeIt head(const EdgeIt& e) const;
412 NodeIt tail(const EdgeIt& e) const;
414 // FIXME: ezeknek valami jobb nev kellene!!!
415 GraphEdge graphEdge(const EdgeIt& e) const;
416 GraphNode graphNode(const NodeIt& n) const;
419 /*** Iterator classes ***/
421 friend class DynamicPath;
423 typename Container::const_iterator it;
426 // FIXME: jarna neki ilyen is...
429 bool forward() const { return forw; }
431 bool operator==(const EdgeIt& e) const { return it==e.it; }
432 bool operator!=(const EdgeIt& e) const { return it!=e.it; }
433 bool operator<(const EdgeIt& e) const { return it<e.it; }
437 friend class DynamicPath;
440 bool tail; // Is this node the tail of the edge with same idx?
443 // FIXME: jarna neki ilyen is...
446 bool operator==(const NodeIt& n) const { return idx==n.idx; }
447 bool operator!=(const NodeIt& n) const { return idx!=n.idx; }
448 bool operator<(const NodeIt& n) const { return idx<n.idx; }
452 bool edgeIncident(const GraphEdge &e, const GraphNode &a,
454 bool connectTwoEdges(const GraphEdge &e, const GraphEdge &f);
457 template<typename Gr>
458 typename DynamicPath<Gr>::EdgeIt&
459 DynamicPath<Gr>::next(DynamicPath::EdgeIt &e) const {
460 if( e.it == edges.end() )
463 GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) );
466 // Invalid edgeit is always forward :)
467 if( e.it == edges.end() ) {
472 e.forw = ( G.tail(*e.it) == common_node );
476 template<typename Gr>
477 typename DynamicPath<Gr>::NodeIt& DynamicPath<Gr>::next(NodeIt &n) const {
478 if( n.idx >= length() ) {
485 GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) :
486 G.tail(edges[n.idx]) );
488 if( n.idx < length() ) {
489 n.tail = ( next_node == G.tail(edges[n.idx]) );
498 template<typename Gr>
499 bool DynamicPath<Gr>::edgeIncident(const GraphEdge &e, const GraphNode &a,
501 if( G.tail(e) == a ) {
505 if( G.head(e) == a ) {
512 template<typename Gr>
513 bool DynamicPath<Gr>::connectTwoEdges(const GraphEdge &e,
514 const GraphEdge &f) {
515 if( edgeIncident(f, G.tail(e), _last) ) {
519 if( edgeIncident(f, G.head(e), _last) ) {
526 template<typename Gr>
527 bool DynamicPath<Gr>::pushFront(const GraphEdge &e) {
528 if( G.valid(_first) ) {
529 if( edgeIncident(e, _first, _first) ) {
536 else if( length() < 1 || connectTwoEdges(e, edges[0]) ) {
544 template<typename Gr>
545 bool DynamicPath<Gr>::pushBack(const GraphEdge &e) {
546 if( G.valid(_last) ) {
547 if( edgeIncident(e, _last, _last) ) {
554 else if( length() < 1 || connectTwoEdges(edges[0], e) ) {
563 template<typename Gr>
564 bool DynamicPath<Gr>::setFrom(const GraphNode &n) {
565 if( G.valid(_first) ) {
570 if( edgeIncident(edges[0], n, _last) ) {
583 template<typename Gr>
584 bool DynamicPath<Gr>::setTo(const GraphNode &n) {
585 if( G.valid(_last) ) {
590 if( edgeIncident(edges[0], n, _first) ) {
604 template<typename Gr>
605 typename DynamicPath<Gr>::NodeIt
606 DynamicPath<Gr>::tail(const EdgeIt& e) const {
609 if( e.it == edges.end() ) {
610 // FIXME: invalid-> invalid
611 n.idx = length() + 1;
616 n.idx = e.it-edges.begin();
621 template<typename Gr>
622 typename DynamicPath<Gr>::NodeIt
623 DynamicPath<Gr>::head(const EdgeIt& e) const {
624 if( e.it == edges.end()-1 ) {
628 EdgeIt next_edge = e;
630 return tail(next_edge);
633 template<typename Gr>
634 typename DynamicPath<Gr>::GraphEdge
635 DynamicPath<Gr>::graphEdge(const EdgeIt& e) const {
636 if( e.it != edges.end() ) {
644 template<typename Gr>
645 typename DynamicPath<Gr>::GraphNode
646 DynamicPath<Gr>::graphNode(const NodeIt& n) const {
647 if( n.idx < length() ) {
648 return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]);
650 else if( n.idx == length() ) {
658 template<typename Gr>
659 typename DynamicPath<Gr>::EdgeIt&
660 DynamicPath<Gr>::nth(EdgeIt &e, size_t k) const {
662 // FIXME: invalid EdgeIt
668 e.it = edges.begin()+k;
670 e.forw = ( G.tail(*e.it) == _first );
673 e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) ||
674 G.tail(*e.it) == G.head(edges[k-1]) );
679 template<typename Gr>
680 typename DynamicPath<Gr>::NodeIt&
681 DynamicPath<Gr>::nth(NodeIt &n, size_t k) const {
683 // FIXME: invalid NodeIt
693 n = tail(nth<EdgeIt>(k));
697 // Reszut konstruktorok:
700 template<typename Gr>
701 DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const EdgeIt &a,
703 G(P.G), edges(a.it, b.it) // WARNING: if b.it < a.it this will blow up!
705 if( G.valid(P._first) && a.it < P.edges.end() ) {
706 _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) );
707 if( b.it < P.edges.end() ) {
708 _last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) );
716 template<typename Gr>
717 DynamicPath<Gr>::DynamicPath(const DynamicPath &P, const NodeIt &a,
718 const NodeIt &b) : G(P.G)
720 if( !P.valid(a) || !P.valid(b) )
723 int ai = a.idx, bi = b.idx;
728 copy(P.edges.begin()+ai, P.edges.begin()+bi, edges.begin());
730 _first = P.graphNode(a);
731 _last = P.graphNode(b);
738 #endif // HUGO_PATH_H