COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/hugo/path.h @ 900:fc7bc2dacee5

Last change on this file since 900:fc7bc2dacee5 was 900:fc7bc2dacee5, checked in by Alpar Juttner, 20 years ago

'iff' changed to 'if and only if'

File size: 19.3 KB
Line 
1// -*- c++ -*- //
2
3/**
4@defgroup paths Path Structures
5@ingroup datas
6\brief Path structures implemented in Hugo.
7
8Hugolib provides flexible data structures
9to work with paths.
10
11All of them have the same interface, especially they can be built or extended
12using a standard Builder subclass. This make is easy to have e.g. the Dijkstra
13algorithm to store its result in any kind of path structure.
14
15\sa hugo::skeleton::Path
16
17*/
18
19///\ingroup paths
20///\file
21///\brief Classes for representing paths in graphs.
22
23#ifndef HUGO_PATH_H
24#define HUGO_PATH_H
25
26#include <deque>
27#include <vector>
28#include <algorithm>
29
30#include <hugo/invalid.h>
31
32namespace hugo {
33
34  /// \addtogroup paths
35  /// @{
36
37
38  //! \brief A structure for representing directed paths in a graph.
39  //!
40  //! A structure for representing directed path in a graph.
41  //! \param Graph The graph type in which the path is.
42  //! \param DM DebugMode, defaults to DefaultDebugMode.
43  //!
44  //! In a sense, the path can be treated as a graph, for is has \c NodeIt
45  //! and \c EdgeIt with the same usage. These types converts to the \c Node
46  //! and \c Edge of the original graph.
47  //!
48  //! \todo Thoroughfully check all the range and consistency tests.
49  template<typename Graph>
50  class DirPath {
51  public:
52    /// Edge type of the underlying graph.
53    typedef typename Graph::Edge GraphEdge;
54    /// Node type of the underlying graph.
55    typedef typename Graph::Node GraphNode;
56    class NodeIt;
57    class EdgeIt;
58
59  protected:
60    const Graph *gr;
61    typedef std::vector<GraphEdge> Container;
62    Container edges;
63
64  public:
65
66    /// \param _G The graph in which the path is.
67    ///
68    DirPath(const Graph &_G) : gr(&_G) {}
69
70    /// \brief Subpath constructor.
71    ///
72    /// Subpath defined by two nodes.
73    /// \warning It is an error if the two edges are not in order!
74    DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
75      gr = P.gr;
76      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
77    }
78
79    /// \brief Subpath constructor.
80    ///
81    /// Subpath defined by two edges. Contains edges in [a,b)
82    /// \warning It is an error if the two edges are not in order!
83    DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
84      gr = P.gr;
85      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
86    }
87
88    /// Length of the path.
89    size_t length() const { return edges.size(); }
90    /// Returns whether the path is empty.
91    bool empty() const { return edges.empty(); }
92
93    /// Resets the path to an empty path.
94    void clear() { edges.clear(); }
95
96    /// \brief Starting point of the path.
97    ///
98    /// Starting point of the path.
99    /// Returns INVALID if the path is empty.
100    GraphNode tail() const {
101      return empty() ? INVALID : gr->tail(edges[0]);
102    }
103    /// \brief End point of the path.
104    ///
105    /// End point of the path.
106    /// Returns INVALID if the path is empty.
107    GraphNode head() const {
108      return empty() ? INVALID : gr->head(edges[length()-1]);
109    }
110
111    /// \brief Initializes node or edge iterator to point to the first
112    /// node or edge.
113    ///
114    /// \sa nth
115    template<typename It>
116    It& first(It &i) const { return i=It(*this); }
117
118    /// \brief Initializes node iterator to point to the node of a given index.
119    NodeIt& nth(NodeIt &i, int n) const {
120      return i=NodeIt(*this, n);
121    }
122
123    /// \brief Initializes edge iterator to point to the edge of a given index.
124    EdgeIt& nth(EdgeIt &i, int n) const {
125      return i=EdgeIt(*this, n);
126    }
127
128    /// \brief Returns node iterator pointing to the head node of the
129    /// given edge iterator.
130    NodeIt head(const EdgeIt& e) const {
131      return NodeIt(*this, e.idx+1);
132    }
133
134    /// \brief Returns node iterator pointing to the tail node of the
135    /// given edge iterator.
136    NodeIt tail(const EdgeIt& e) const {
137      return NodeIt(*this, e.idx);
138    }
139
140
141    /* Iterator classes */
142
143    /**
144     * \brief Iterator class to iterate on the edges of the paths
145     *
146     * \ingroup paths
147     * This class is used to iterate on the edges of the paths
148     *
149     * Of course it converts to Graph::Edge
150     *
151     */
152    class EdgeIt {
153      friend class DirPath;
154
155      int idx;
156      const DirPath *p;
157    public:
158      /// Default constructor
159      EdgeIt() {}
160      /// Invalid constructor
161      EdgeIt(Invalid) : idx(-1), p(0) {}
162      /// Constructor with starting point
163      EdgeIt(const DirPath &_p, int _idx = 0) :
164        idx(_idx), p(&_p) { validate(); }
165
166      ///Validity check
167      bool valid() const { return idx!=-1; }
168
169      ///Conversion to Graph::Edge
170      operator GraphEdge () const {
171        return valid() ? p->edges[idx] : INVALID;
172      }
173
174      /// Next edge
175      EdgeIt& operator++() { ++idx; validate(); return *this; }
176
177      /// Comparison operator
178      bool operator==(const EdgeIt& e) const { return idx==e.idx; }
179      /// Comparison operator
180      bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
181      /// Comparison operator
182      bool operator<(const EdgeIt& e) const { return idx<e.idx; }
183
184    private:
185      // FIXME: comparison between signed and unsigned...
186      // Jo ez igy? Vagy esetleg legyen a length() int?
187      void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
188    };
189
190    /**
191     * \brief Iterator class to iterate on the nodes of the paths
192     *
193     * \ingroup paths
194     * This class is used to iterate on the nodes of the paths
195     *
196     * Of course it converts to Graph::Node
197     *
198     */
199    class NodeIt {
200      friend class DirPath;
201
202      int idx;
203      const DirPath *p;
204    public:
205      /// Default constructor
206      NodeIt() {}
207      /// Invalid constructor
208      NodeIt(Invalid) : idx(-1), p(0) {}
209      /// Constructor with starting point
210      NodeIt(const DirPath &_p, int _idx = 0) :
211        idx(_idx), p(&_p) { validate(); }
212
213      ///Validity check
214      bool valid() const { return idx!=-1; }
215
216      ///Conversion to Graph::Node
217      operator const GraphNode& () const {
218        if(idx >= p->length())
219          return p->head();
220        else if(idx >= 0)
221          return p->gr->tail(p->edges[idx]);
222        else
223          return INVALID;
224      }
225      /// Next node
226      NodeIt& operator++() { ++idx; validate(); return *this; }
227
228      /// Comparison operator
229      bool operator==(const NodeIt& e) const { return idx==e.idx; }
230      /// Comparison operator
231      bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
232      /// Comparison operator
233      bool operator<(const NodeIt& e) const { return idx<e.idx; }
234
235    private:
236      void validate() { if( size_t(idx) > p->length() ) idx=-1; }
237    };
238
239    friend class Builder;
240
241    /**
242     * \brief Class to build paths
243     *
244     * \ingroup paths
245     * This class is used to fill a path with edges.
246     *
247     * You can push new edges to the front and to the back of the path in
248     * arbitrary order then you should commit these changes to the graph.
249     *
250     * Fundamentally, for most "Paths" (classes fulfilling the
251     * PathConcept) while the builder is active (after the first modifying
252     * operation and until the commit()) the original Path is in a
253     * "transitional" state (operations on it have undefined result). But
254     * in the case of DirPath the original path remains unchanged until the
255     * commit. However we don't recomend that you use this feature.
256     */
257    class Builder {
258      DirPath &P;
259      Container front, back;
260
261    public:
262      ///\param _P the path you want to fill in.
263      ///
264      Builder(DirPath &_P) : P(_P) {}
265
266      /// Sets the starting node of the path.
267
268      /// Sets the starting node of the path. Edge added to the path
269      /// afterwards have to be incident to this node.
270      /// It should be called if and only if
271      /// the path is empty and before any call to
272      /// \ref pushFront() or \ref pushBack()
273      void setStartNode(const GraphNode &) {}
274
275      ///Push a new edge to the front of the path
276
277      ///Push a new edge to the front of the path.
278      ///\sa setStartNode
279      void pushFront(const GraphEdge& e) {
280        front.push_back(e);
281      }
282
283      ///Push a new edge to the back of the path
284
285      ///Push a new edge to the back of the path.
286      ///\sa setStartNode
287      void pushBack(const GraphEdge& e) {
288        back.push_back(e);
289      }
290
291      ///Commit the changes to the path.
292      void commit() {
293        if( !front.empty() || !back.empty() ) {
294          Container tmp;
295          tmp.reserve(front.size()+back.size()+P.length());
296          tmp.insert(tmp.end(), front.rbegin(), front.rend());
297          tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
298          tmp.insert(tmp.end(), back.begin(), back.end());
299          P.edges.swap(tmp);
300          front.clear();
301          back.clear();
302        }
303      }
304
305      ///Reserve storage for the builder in advance.
306
307      ///If you know a reasonable upper bound of the number of the edges
308      ///to add to the front, using this function you can speed up the building.
309
310      void reserveFront(size_t r) {front.reserve(r);}
311
312      ///Reserve storage for the builder in advance.
313
314      ///If you know a reasonable upper bound of the number of the edges
315      ///to add to the back, using this function you can speed up the building.
316
317      void reserveBack(size_t r) {back.reserve(r);}
318
319    private:
320      bool empty() {
321        return front.empty() && back.empty() && P.empty();
322      }
323
324      GraphNode tail() const {
325        if( ! front.empty() )
326          return P.gr->tail(front[front.size()-1]);
327        else if( ! P.empty() )
328          return P.gr->tail(P.edges[0]);
329        else if( ! back.empty() )
330          return P.gr->tail(back[0]);
331        else
332          return INVALID;
333      }
334      GraphNode head() const {
335        if( ! back.empty() )
336          return P.gr->head(back[back.size()-1]);
337        else if( ! P.empty() )
338          return P.gr->head(P.edges[P.length()-1]);
339        else if( ! front.empty() )
340          return P.gr->head(front[0]);
341        else
342          return INVALID;
343      }
344
345    };
346
347  };
348
349
350
351
352
353
354
355
356
357
358  /**********************************************************************/
359
360
361  //! \brief A structure for representing undirected path in a graph.
362  //!
363  //! A structure for representing undirected path in a graph. Ie. this is
364  //! a path in a \e directed graph but the edges should not be directed
365  //! forward.
366  //!
367  //! \param Graph The graph type in which the path is.
368  //! \param DM DebugMode, defaults to DefaultDebugMode.
369  //!
370  //! In a sense, the path can be treated as a graph, for is has \c NodeIt
371  //! and \c EdgeIt with the same usage. These types converts to the \c Node
372  //! and \c Edge of the original graph.
373  //!
374  //! \todo Thoroughfully check all the range and consistency tests.
375  template<typename Graph>
376  class UndirPath {
377  public:
378    /// Edge type of the underlying graph.
379    typedef typename Graph::Edge GraphEdge;
380     /// Node type of the underlying graph.
381   typedef typename Graph::Node GraphNode;
382    class NodeIt;
383    class EdgeIt;
384
385  protected:
386    const Graph *gr;
387    typedef std::vector<GraphEdge> Container;
388    Container edges;
389
390  public:
391
392    /// \param _G The graph in which the path is.
393    ///
394    UndirPath(const Graph &_G) : gr(&_G) {}
395
396    /// \brief Subpath constructor.
397    ///
398    /// Subpath defined by two nodes.
399    /// \warning It is an error if the two edges are not in order!
400    UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
401      gr = P.gr;
402      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
403    }
404
405    /// \brief Subpath constructor.
406    ///
407    /// Subpath defined by two edges. Contains edges in [a,b)
408    /// \warning It is an error if the two edges are not in order!
409    UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
410      gr = P.gr;
411      edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
412    }
413
414    /// Length of the path.
415    size_t length() const { return edges.size(); }
416    /// Returns whether the path is empty.
417    bool empty() const { return edges.empty(); }
418
419    /// Resets the path to an empty path.
420    void clear() { edges.clear(); }
421
422    /// \brief Starting point of the path.
423    ///
424    /// Starting point of the path.
425    /// Returns INVALID if the path is empty.
426    GraphNode tail() const {
427      return empty() ? INVALID : gr->tail(edges[0]);
428    }
429    /// \brief End point of the path.
430    ///
431    /// End point of the path.
432    /// Returns INVALID if the path is empty.
433    GraphNode head() const {
434      return empty() ? INVALID : gr->head(edges[length()-1]);
435    }
436
437    /// \brief Initializes node or edge iterator to point to the first
438    /// node or edge.
439    ///
440    /// \sa nth
441    template<typename It>
442    It& first(It &i) const { return i=It(*this); }
443
444    /// \brief Initializes node iterator to point to the node of a given index.
445    NodeIt& nth(NodeIt &i, int n) const {
446      return i=NodeIt(*this, n);
447    }
448
449    /// \brief Initializes edge iterator to point to the edge of a given index.
450    EdgeIt& nth(EdgeIt &i, int n) const {
451      return i=EdgeIt(*this, n);
452    }
453
454    /// Checks validity of a node or edge iterator.
455    template<typename It>
456    static
457    bool valid(const It &i) { return i.valid(); }
458
459    /// Steps the given node or edge iterator.
460    template<typename It>
461    static
462    It& next(It &e) {
463      return ++e;
464    }
465
466    /// \brief Returns node iterator pointing to the head node of the
467    /// given edge iterator.
468    NodeIt head(const EdgeIt& e) const {
469      return NodeIt(*this, e.idx+1);
470    }
471
472    /// \brief Returns node iterator pointing to the tail node of the
473    /// given edge iterator.
474    NodeIt tail(const EdgeIt& e) const {
475      return NodeIt(*this, e.idx);
476    }
477
478
479
480    /**
481     * \brief Iterator class to iterate on the edges of the paths
482     *
483     * \ingroup paths
484     * This class is used to iterate on the edges of the paths
485     *
486     * Of course it converts to Graph::Edge
487     *
488     * \todo Its interface differs from the standard edge iterator.
489     * Yes, it shouldn't.
490     */
491    class EdgeIt {
492      friend class UndirPath;
493
494      int idx;
495      const UndirPath *p;
496    public:
497      /// Default constructor
498      EdgeIt() {}
499      /// Invalid constructor
500      EdgeIt(Invalid) : idx(-1), p(0) {}
501      /// Constructor with starting point
502      EdgeIt(const UndirPath &_p, int _idx = 0) :
503        idx(_idx), p(&_p) { validate(); }
504
505      ///Validity check
506      bool valid() const { return idx!=-1; }
507
508      ///Conversion to Graph::Edge
509      operator GraphEdge () const {
510        return valid() ? p->edges[idx] : INVALID;
511      }
512      /// Next edge
513     EdgeIt& operator++() { ++idx; validate(); return *this; }
514
515      /// Comparison operator
516      bool operator==(const EdgeIt& e) const { return idx==e.idx; }
517      /// Comparison operator
518      bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
519      /// Comparison operator
520      bool operator<(const EdgeIt& e) const { return idx<e.idx; }
521
522    private:
523      // FIXME: comparison between signed and unsigned...
524      // Jo ez igy? Vagy esetleg legyen a length() int?
525      void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
526    };
527
528    /**
529     * \brief Iterator class to iterate on the nodes of the paths
530     *
531     * \ingroup paths
532     * This class is used to iterate on the nodes of the paths
533     *
534     * Of course it converts to Graph::Node
535     *
536     * \todo Its interface differs from the standard node iterator.
537     * Yes, it shouldn't.
538     */
539    class NodeIt {
540      friend class UndirPath;
541
542      int idx;
543      const UndirPath *p;
544    public:
545      /// Default constructor
546      NodeIt() {}
547      /// Invalid constructor
548      NodeIt(Invalid) : idx(-1), p(0) {}
549      /// Constructor with starting point
550      NodeIt(const UndirPath &_p, int _idx = 0) :
551        idx(_idx), p(&_p) { validate(); }
552
553      ///Validity check
554      bool valid() const { return idx!=-1; }
555
556      ///Conversion to Graph::Node
557      operator const GraphNode& () const {
558        if(idx >= p->length())
559          return p->head();
560        else if(idx >= 0)
561          return p->gr->tail(p->edges[idx]);
562        else
563          return INVALID;
564      }
565      /// Next node
566      NodeIt& operator++() { ++idx; validate(); return *this; }
567
568      /// Comparison operator
569      bool operator==(const NodeIt& e) const { return idx==e.idx; }
570      /// Comparison operator
571      bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
572       /// Comparison operator
573     bool operator<(const NodeIt& e) const { return idx<e.idx; }
574
575    private:
576      void validate() { if( size_t(idx) > p->length() ) idx=-1; }
577    };
578
579    friend class Builder;
580
581    /**
582     * \brief Class to build paths
583     *
584     * \ingroup paths
585     * This class is used to fill a path with edges.
586     *
587     * You can push new edges to the front and to the back of the path in
588     * arbitrary order then you should commit these changes to the graph.
589     *
590     * Fundamentally, for most "Paths" (classes fulfilling the
591     * PathConcept) while the builder is active (after the first modifying
592     * operation and until the commit()) the original Path is in a
593     * "transitional" state (operations ot it have undefined result). But
594     * in the case of UndirPath the original path is unchanged until the
595     * commit. However we don't recomend that you use this feature.
596     */
597    class Builder {
598      UndirPath &P;
599      Container front, back;
600
601    public:
602      ///\param _P the path you want to fill in.
603      ///
604      Builder(UndirPath &_P) : P(_P) {}
605
606      /// Sets the starting node of the path.
607
608      /// Sets the starting node of the path. Edge added to the path
609      /// afterwards have to be incident to this node.
610      /// It should be called if and only if
611      /// the path is empty and before any call to
612      /// \ref pushFront() or \ref pushBack()
613      void setStartNode(const GraphNode &) {}
614
615      ///Push a new edge to the front of the path
616
617      ///Push a new edge to the front of the path.
618      ///\sa setStartNode
619      void pushFront(const GraphEdge& e) {
620        front.push_back(e);
621      }
622
623      ///Push a new edge to the back of the path
624
625      ///Push a new edge to the back of the path.
626      ///\sa setStartNode
627      void pushBack(const GraphEdge& e) {
628        back.push_back(e);
629      }
630
631      ///Commit the changes to the path.
632      void commit() {
633        if( !(front.empty() && back.empty()) ) {
634          Container tmp;
635          tmp.reserve(front.size()+back.size()+P.length());
636          tmp.insert(tmp.end(), front.rbegin(), front.rend());
637          tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
638          tmp.insert(tmp.end(), back.begin(), back.end());
639          P.edges.swap(tmp);
640          front.clear();
641          back.clear();
642        }
643      }
644
645
646      ///Reserve storage for the builder in advance.
647
648      ///If you know a reasonable upper bound of the number of the edges
649      ///to add to the front, using this function you can speed up the building.
650
651      void reserveFront(size_t r) {front.reserve(r);}
652
653      ///Reserve storage for the builder in advance.
654
655      ///If you know a reasonable upper bound of the number of the edges
656      ///to add to the back, using this function you can speed up the building.
657
658      void reserveBack(size_t r) {back.reserve(r);}
659
660    private:
661      bool empty() {
662        return front.empty() && back.empty() && P.empty();
663      }
664
665      GraphNode tail() const {
666        if( ! front.empty() )
667          return P.gr->tail(front[front.size()-1]);
668        else if( ! P.empty() )
669          return P.gr->tail(P.edges[0]);
670        else if( ! back.empty() )
671          return P.gr->tail(back[0]);
672        else
673          return INVALID;
674      }
675      GraphNode head() const {
676        if( ! back.empty() )
677          return P.gr->head(back[back.size()-1]);
678        else if( ! P.empty() )
679          return P.gr->head(P.edges[P.length()-1]);
680        else if( ! front.empty() )
681          return P.gr->head(front[0]);
682        else
683          return INVALID;
684      }
685
686    };
687
688  };
689
690
691  ///@}
692
693} // namespace hugo
694
695#endif // HUGO_PATH_H
Note: See TracBrowser for help on using the repository browser.