3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
22 ///\brief Classes for representing paths in graphs.
31 #include <lemon/error.h>
32 #include <lemon/bits/invalid.h>
40 //! \brief A structure for representing directed paths in a graph.
42 //! A structure for representing directed path in a graph.
43 //! \param Graph The graph type in which the path is.
45 //! In a sense, the path can be treated as a graph, for is has \c NodeIt
46 //! and \c EdgeIt with the same usage. These types converts to the \c Node
47 //! and \c Edge of the original graph.
49 //! \todo Thoroughfully check all the range and consistency tests.
50 template<typename Graph>
53 /// Edge type of the underlying graph.
54 typedef typename Graph::Edge Edge;
55 /// Node type of the underlying graph.
56 typedef typename Graph::Node Node;
61 struct PathError : public LogicError {
62 virtual const char* what() const throw() {
63 return "lemon::PathError";
69 /// \brief Constructor
72 /// \param _G The graph in which the path is.
73 Path(const Graph &_graph) : graph(&_graph), start(INVALID) {}
75 /// \brief Subpath constructor.
77 /// Subpath defined by two nodes.
78 /// \warning It is an error if the two edges are not in order!
79 Path(const Path &other, const NodeIt &a, const NodeIt &b) {
82 edges.insert(edges.end(),
83 other.edges.begin() + a.id, other.edges.begin() + b.id);
86 /// \brief Subpath constructor.
88 /// Subpath defined by two edges. Contains edges in [a,b)
89 /// \warning It is an error if the two edges are not in order!
90 Path(const Path &other, const EdgeIt &a, const EdgeIt &b) {
92 start = graph->source(a);
93 edges.insert(edges.end(),
94 other.edges.begin() + a.id, other.edges.begin() + b.id);
97 /// \brief Length of the path.
99 /// The number of the edges in the path. It can be zero if the
100 /// path has only one node or it is empty.
101 int length() const { return edges.size(); }
103 /// \brief Returns whether the path is empty.
105 /// Returns true when the path does not contain neither edge nor
107 bool empty() const { return start == INVALID; }
109 /// \brief Resets the path to an empty path.
111 /// Resets the path to an empty path.
112 void clear() { edges.clear(); start = INVALID; }
114 /// \brief Starting point of the path.
116 /// Starting point of the path.
117 /// Returns INVALID if the path is empty.
118 Node source() const {
121 /// \brief End point of the path.
123 /// End point of the path.
124 /// Returns INVALID if the path is empty.
125 Node target() const {
126 return length() == 0 ? start : graph->target(edges[length()-1]);
129 /// \brief Gives back a node iterator to point to the node of a
132 /// Gives back a node iterator to point to the node of a given
134 /// \pre n should less or equal to \c length()
135 NodeIt nthNode(int n) const {
136 return NodeIt(*this, n);
139 /// \brief Gives back an edge iterator to point to the edge of a
142 /// Gives back an edge iterator to point to the node of a given
144 /// \pre n should less than \c length()
145 EdgeIt nthEdge(int n) const {
146 return EdgeIt(*this, n);
149 /// \brief Returns node iterator pointing to the source node of the
150 /// given edge iterator.
152 /// Returns node iterator pointing to the source node of the given
154 NodeIt source(const EdgeIt& e) const {
155 return NodeIt(*this, e.id);
158 /// \brief Returns node iterator pointing to the target node of the
159 /// given edge iterator.
161 /// Returns node iterator pointing to the target node of the given
163 NodeIt target(const EdgeIt& e) const {
164 return NodeIt(*this, e.id + 1);
168 /// \brief Iterator class to iterate on the nodes of the paths
170 /// This class is used to iterate on the nodes of the paths
172 /// Of course it converts to Graph::Node
177 /// \brief Default constructor
179 /// Default constructor
182 /// \brief Invalid constructor
184 /// Invalid constructor
185 NodeIt(Invalid) : id(-1), path(0) {}
187 /// \brief Constructor with starting point
189 /// Constructor with starting point
190 NodeIt(const Path &_path, int _id = 0) : id(_id), path(&_path) {
191 if (id > path->length()) id = -1;
194 /// \brief Conversion to Graph::Node
196 /// Conversion to Graph::Node
197 operator Node() const {
199 return path->graph->target(path->edges[id - 1]);
200 } else if (id == 0) {
207 /// \brief Steps to the next node
209 /// Steps to the next node
210 NodeIt& operator++() {
212 if (id > path->length()) id = -1;
216 /// \brief Comparison operator
218 /// Comparison operator
219 bool operator==(const NodeIt& n) const { return id == n.id; }
221 /// \brief Comparison operator
223 /// Comparison operator
224 bool operator!=(const NodeIt& n) const { return id != n.id; }
226 /// \brief Comparison operator
228 /// Comparison operator
229 bool operator<(const NodeIt& n) const { return id < n.id; }
236 /// \brief Iterator class to iterate on the edges of the paths
238 /// This class is used to iterate on the edges of the paths
239 /// Of course it converts to Graph::Edge
244 /// \brief Default constructor
246 /// Default constructor
249 /// \brief Invalid constructor
251 /// Invalid constructor
252 EdgeIt(Invalid) : id(-1), path(0) {}
254 /// \brief Constructor with starting point
256 /// Constructor with starting point
257 EdgeIt(const Path &_path, int _id = 0) : id(_id), path(&_path) {
258 if (id >= path->length()) id = -1;
261 /// \brief Conversion to Graph::Edge
263 /// Conversion to Graph::Edge
264 operator Edge() const {
265 return id != -1 ? path->edges[id] : INVALID;
268 /// \brief Steps to the next edge
270 /// Steps to the next edge
271 EdgeIt& operator++() {
273 if (id >= path->length()) id = -1;
277 /// \brief Comparison operator
279 /// Comparison operator
280 bool operator==(const EdgeIt& e) const { return id == e.id; }
282 /// \brief Comparison operator
284 /// Comparison operator
285 bool operator!=(const EdgeIt& e) const { return id != e.id; }
287 /// \brief Comparison operator
289 /// Comparison operator
290 bool operator<(const EdgeIt& e) const { return id < e.id; }
302 typedef std::vector<Edge> Container;
308 friend class Builder;
310 /// \brief Class to build paths
312 /// This class is used to fill a path with edges.
314 /// You can push new edges to the front and to the back of the
315 /// path in arbitrary order then you should commit these changes
318 /// Fundamentally, for most "Paths" (classes fulfilling the
319 /// PathConcept) while the builder is active (after the first
320 /// modifying operation and until the commit()) the original Path
321 /// is in a "transitional" state (operations on it have undefined
322 /// result). But in the case of Path the original path remains
323 /// unchanged until the commit. However we don't recomend that you
324 /// use this feature.
327 /// \brief Constructor
330 /// \param _path the path you want to fill in.
331 Builder(Path &_path) : path(_path), start(INVALID) {}
333 /// \brief Destructor
337 LEMON_ASSERT(front.empty() && back.empty() && start == INVALID,
341 /// \brief Sets the starting node of the path.
343 /// Sets the starting node of the path. Edge added to the path
344 /// afterwards have to be incident to this node. It should be
345 /// called if and only if the path is empty and before any call
346 /// to \ref pushFront() or \ref pushBack()
347 void setStartNode(const Node &_start) {
348 LEMON_ASSERT(path.empty() && start == INVALID, PathError());
352 /// \brief Push a new edge to the front of the path
354 /// Push a new edge to the front of the path.
356 void pushFront(const Edge& e) {
357 LEMON_ASSERT(front.empty() ||
358 (path.graph->source(front.back()) ==
359 path.graph->target(e)), PathError());
360 LEMON_ASSERT(path.empty() ||
361 (path.source() == path.graph->target(e)), PathError());
362 LEMON_ASSERT(!path.empty() || !front.empty() ||
363 (start == path.graph->target(e)), PathError());
367 /// \brief Push a new edge to the back of the path
369 /// Push a new edge to the back of the path.
371 void pushBack(const Edge& e) {
372 LEMON_ASSERT(back.empty() ||
373 (path.graph->target(back.back()) ==
374 path.graph->source(e)), PathError());
375 LEMON_ASSERT(path.empty() ||
376 (path.target() == path.graph->source(e)), PathError());
377 LEMON_ASSERT(!path.empty() || !back.empty() ||
378 (start == path.graph->source(e)), PathError());
382 /// \brief Commit the changes to the path.
384 /// Commit the changes to the path.
386 if( !front.empty() || !back.empty() || start != INVALID) {
388 tmp.reserve(front.size() + back.size() + path.length());
389 tmp.insert(tmp.end(), front.rbegin(), front.rend());
390 tmp.insert(tmp.end(), path.edges.begin(), path.edges.end());
391 tmp.insert(tmp.end(), back.begin(), back.end());
392 path.edges.swap(tmp);
393 if (!front.empty()) {
394 path.start = path.graph->source(front.back());
404 /// \brief Reserve storage for the builder in advance.
406 /// If you know a reasonable upper bound of the number of the
407 /// edges to add to the front, using this function you can speed
409 void reserveFront(size_t r) {front.reserve(r);}
411 /// \brief Reserve storage for the builder in advance.
413 /// If you know a reasonable upper bound of the number of the
414 /// edges to add to the back, using this function you can speed
416 void reserveBack(size_t r) {back.reserve(r);}
421 Container front, back;
432 #endif // LEMON_PATH_H