lemon/path.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2084 59769591eb60
child 2335 27aa03cd3121
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

The tests have been modified to the current implementation
alpar@906
     1
/* -*- C++ -*-
alpar@906
     2
 *
alpar@1956
     3
 * This file is a part of LEMON, a generic C++ optimization library
alpar@1956
     4
 *
alpar@1956
     5
 * Copyright (C) 2003-2006
alpar@1956
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1359
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@906
     8
 *
alpar@906
     9
 * Permission to use, modify and distribute this software is granted
alpar@906
    10
 * provided that this copyright notice appears in all copies. For
alpar@906
    11
 * precise terms see the accompanying LICENSE file.
alpar@906
    12
 *
alpar@906
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@906
    14
 * express or implied, and with no claim as to its suitability for any
alpar@906
    15
 * purpose.
alpar@906
    16
 *
alpar@906
    17
 */
hegyi@819
    18
hegyi@819
    19
hegyi@819
    20
///\ingroup paths
hegyi@819
    21
///\file
hegyi@819
    22
///\brief Classes for representing paths in graphs.
alpar@1151
    23
///
hegyi@819
    24
alpar@921
    25
#ifndef LEMON_PATH_H
alpar@921
    26
#define LEMON_PATH_H
hegyi@819
    27
hegyi@819
    28
#include <vector>
hegyi@819
    29
#include <algorithm>
hegyi@819
    30
deba@2247
    31
#include <lemon/error.h>
deba@1993
    32
#include <lemon/bits/invalid.h>
hegyi@819
    33
alpar@921
    34
namespace lemon {
hegyi@819
    35
hegyi@819
    36
  /// \addtogroup paths
hegyi@819
    37
  /// @{
hegyi@819
    38
hegyi@819
    39
hegyi@819
    40
  //! \brief A structure for representing directed paths in a graph.
hegyi@819
    41
  //!
hegyi@819
    42
  //! A structure for representing directed path in a graph.
hegyi@819
    43
  //! \param Graph The graph type in which the path is.
hegyi@837
    44
  //!
hegyi@819
    45
  //! In a sense, the path can be treated as a graph, for is has \c NodeIt
hegyi@819
    46
  //! and \c EdgeIt with the same usage. These types converts to the \c Node
hegyi@819
    47
  //! and \c Edge of the original graph.
hegyi@819
    48
  //!
hegyi@819
    49
  //! \todo Thoroughfully check all the range and consistency tests.
hegyi@831
    50
  template<typename Graph>
deba@2247
    51
  class Path {
hegyi@819
    52
  public:
hegyi@819
    53
    /// Edge type of the underlying graph.
deba@2247
    54
    typedef typename Graph::Edge Edge;
hegyi@819
    55
    /// Node type of the underlying graph.
deba@2247
    56
    typedef typename Graph::Node Node;
deba@2247
    57
hegyi@819
    58
    class NodeIt;
hegyi@819
    59
    class EdgeIt;
hegyi@819
    60
deba@2247
    61
    struct PathError : public LogicError {
deba@2247
    62
      virtual const char* what() const throw() {
deba@2247
    63
        return "lemon::PathError";
deba@2247
    64
      }      
deba@2247
    65
    };
hegyi@819
    66
hegyi@819
    67
  public:
hegyi@819
    68
deba@2247
    69
    /// \brief Constructor
deba@2247
    70
    ///
deba@2247
    71
    /// Constructor 
hegyi@819
    72
    /// \param _G The graph in which the path is.
deba@2247
    73
    Path(const Graph &_graph) : graph(&_graph), start(INVALID) {}
deba@2247
    74
    
hegyi@819
    75
    /// \brief Subpath constructor.
hegyi@819
    76
    ///
hegyi@819
    77
    /// Subpath defined by two nodes.
hegyi@819
    78
    /// \warning It is an error if the two edges are not in order!
deba@2247
    79
    Path(const Path &other, const NodeIt &a, const NodeIt &b) {
deba@2247
    80
      graph = other.graph; 
deba@2247
    81
      start = a;
deba@2247
    82
      edges.insert(edges.end(), 
deba@2247
    83
                   other.edges.begin() + a.id, other.edges.begin() + b.id);
hegyi@819
    84
    }
hegyi@819
    85
hegyi@819
    86
    /// \brief Subpath constructor.
hegyi@819
    87
    ///
hegyi@819
    88
    /// Subpath defined by two edges. Contains edges in [a,b)
hegyi@819
    89
    /// \warning It is an error if the two edges are not in order!
deba@2247
    90
    Path(const Path &other, const EdgeIt &a, const EdgeIt &b) {
deba@2247
    91
      graph = other.graph;
deba@2247
    92
      start = graph->source(a);
deba@2247
    93
      edges.insert(edges.end(), 
deba@2247
    94
                   other.edges.begin() + a.id, other.edges.begin() + b.id);
hegyi@819
    95
    }
hegyi@819
    96
deba@2247
    97
    /// \brief Length of the path.
deba@2247
    98
    ///
deba@2247
    99
    /// The number of the edges in the path. It can be zero if the
deba@2247
   100
    /// path has only one node or it is empty.
alpar@1282
   101
    int length() const { return edges.size(); }
hegyi@819
   102
deba@2247
   103
    /// \brief Returns whether the path is empty.
deba@2247
   104
    ///
deba@2247
   105
    /// Returns true when the path does not contain neither edge nor
deba@2247
   106
    /// node.
deba@2247
   107
    bool empty() const { return start == INVALID; }
deba@2247
   108
deba@2247
   109
    /// \brief Resets the path to an empty path.
deba@2247
   110
    ///
hegyi@819
   111
    /// Resets the path to an empty path.
deba@2247
   112
    void clear() { edges.clear(); start = INVALID; }
hegyi@819
   113
hegyi@819
   114
    /// \brief Starting point of the path.
hegyi@819
   115
    ///
hegyi@819
   116
    /// Starting point of the path.
hegyi@819
   117
    /// Returns INVALID if the path is empty.
deba@2247
   118
    Node source() const {
deba@2247
   119
      return start;
hegyi@819
   120
    }
hegyi@819
   121
    /// \brief End point of the path.
hegyi@819
   122
    ///
hegyi@819
   123
    /// End point of the path.
hegyi@819
   124
    /// Returns INVALID if the path is empty.
deba@2247
   125
    Node target() const {
deba@2247
   126
      return length() == 0 ? start : graph->target(edges[length()-1]);
hegyi@819
   127
    }
hegyi@819
   128
deba@2247
   129
    /// \brief Gives back a node iterator to point to the node of a
deba@2247
   130
    /// given index.
hegyi@819
   131
    ///
deba@2247
   132
    /// Gives back a node iterator to point to the node of a given
deba@2247
   133
    /// index.
deba@2247
   134
    /// \pre n should less or equal to \c length()
deba@2247
   135
    NodeIt nthNode(int n) const {
deba@2247
   136
      return NodeIt(*this, n);
hegyi@819
   137
    }
hegyi@819
   138
deba@2247
   139
    /// \brief Gives back an edge iterator to point to the edge of a
deba@2247
   140
    /// given index.
deba@2247
   141
    ///
deba@2247
   142
    /// Gives back an edge iterator to point to the node of a given
deba@2247
   143
    /// index.  
deba@2247
   144
    /// \pre n should less than \c length()
deba@2247
   145
    EdgeIt nthEdge(int n) const {
deba@2247
   146
      return EdgeIt(*this, n);
deba@2247
   147
    }
deba@2247
   148
deba@2247
   149
    /// \brief Returns node iterator pointing to the source node of the
deba@2247
   150
    /// given edge iterator.
deba@2247
   151
    ///
deba@2247
   152
    /// Returns node iterator pointing to the source node of the given
deba@2247
   153
    /// edge iterator.
deba@2247
   154
    NodeIt source(const EdgeIt& e) const {
deba@2247
   155
      return NodeIt(*this, e.id);
hegyi@819
   156
    }
hegyi@819
   157
alpar@986
   158
    /// \brief Returns node iterator pointing to the target node of the
hegyi@819
   159
    /// given edge iterator.
deba@2247
   160
    ///
deba@2247
   161
    /// Returns node iterator pointing to the target node of the given
deba@2247
   162
    /// edge iterator.
alpar@986
   163
    NodeIt target(const EdgeIt& e) const {
deba@2247
   164
      return NodeIt(*this, e.id + 1);
hegyi@819
   165
    }
hegyi@819
   166
hegyi@819
   167
deba@2247
   168
    /// \brief Iterator class to iterate on the nodes of the paths
deba@2247
   169
    ///
deba@2247
   170
    /// This class is used to iterate on the nodes of the paths
deba@2247
   171
    ///
deba@2247
   172
    /// Of course it converts to Graph::Node
deba@2247
   173
    class NodeIt {
deba@2247
   174
      friend class Path;
deba@2247
   175
    public:
hegyi@819
   176
deba@2247
   177
      /// \brief Default constructor
deba@2247
   178
      ///
deba@2247
   179
      /// Default constructor
deba@2247
   180
      NodeIt() {}
hegyi@819
   181
deba@2247
   182
      /// \brief Invalid constructor
deba@2247
   183
      ///
deba@2247
   184
      /// Invalid constructor
deba@2247
   185
      NodeIt(Invalid) : id(-1), path(0) {}
deba@2247
   186
deba@2247
   187
      /// \brief Constructor with starting point
deba@2247
   188
      /// 
deba@2247
   189
      /// Constructor with starting point
deba@2247
   190
      NodeIt(const Path &_path, int _id = 0) : id(_id), path(&_path) { 
deba@2247
   191
        if (id > path->length()) id = -1; 
deba@2247
   192
      }
deba@2247
   193
deba@2247
   194
      /// \brief Conversion to Graph::Node
deba@2247
   195
      ///
deba@2247
   196
      /// Conversion to Graph::Node
deba@2247
   197
      operator Node() const {
deba@2247
   198
	if (id > 0) {
deba@2247
   199
	  return path->graph->target(path->edges[id - 1]);
deba@2247
   200
	} else if (id == 0) {
deba@2247
   201
	  return path->start;
deba@2247
   202
	} else {
deba@2247
   203
	  return INVALID;
deba@2247
   204
        }
deba@2247
   205
      }
deba@2247
   206
deba@2247
   207
      /// \brief Steps to the next node
deba@2247
   208
      ///
deba@2247
   209
      /// Steps to the next node
deba@2247
   210
      NodeIt& operator++() { 
deba@2247
   211
        ++id; 
deba@2247
   212
        if (id > path->length()) id = -1; 
deba@2247
   213
        return *this; 
deba@2247
   214
      }
deba@2247
   215
deba@2247
   216
      /// \brief Comparison operator
deba@2247
   217
      ///
deba@2247
   218
      /// Comparison operator
deba@2247
   219
      bool operator==(const NodeIt& n) const { return id == n.id; }
deba@2247
   220
deba@2247
   221
      /// \brief Comparison operator
deba@2247
   222
      ///
deba@2247
   223
      /// Comparison operator
deba@2247
   224
      bool operator!=(const NodeIt& n) const { return id != n.id; }
deba@2247
   225
deba@2247
   226
      /// \brief Comparison operator
deba@2247
   227
      ///
deba@2247
   228
      /// Comparison operator
deba@2247
   229
      bool operator<(const NodeIt& n) const { return id < n.id; }
deba@2247
   230
deba@2247
   231
    private:
deba@2247
   232
      int id;
deba@2247
   233
      const Path *path;
deba@2247
   234
    };
deba@2247
   235
deba@2247
   236
    /// \brief Iterator class to iterate on the edges of the paths
deba@2247
   237
    ///
deba@2247
   238
    /// This class is used to iterate on the edges of the paths
deba@2247
   239
    /// Of course it converts to Graph::Edge
hegyi@819
   240
    class EdgeIt {
deba@2247
   241
      friend class Path;
deba@2247
   242
    public:
hegyi@819
   243
deba@2247
   244
      /// \brief Default constructor
deba@2247
   245
      ///
hegyi@819
   246
      /// Default constructor
hegyi@819
   247
      EdgeIt() {}
deba@2247
   248
deba@2247
   249
      /// \brief Invalid constructor
deba@2247
   250
      ///
hegyi@819
   251
      /// Invalid constructor
deba@2247
   252
      EdgeIt(Invalid) : id(-1), path(0) {}
deba@2247
   253
deba@2247
   254
      /// \brief Constructor with starting point
deba@2247
   255
      ///
hegyi@819
   256
      /// Constructor with starting point
deba@2247
   257
      EdgeIt(const Path &_path, int _id = 0) : id(_id), path(&_path) { 
deba@2247
   258
        if (id >= path->length()) id = -1;
hegyi@819
   259
      }
hegyi@819
   260
deba@2247
   261
      /// \brief Conversion to Graph::Edge
deba@2247
   262
      ///
deba@2247
   263
      /// Conversion to Graph::Edge
deba@2247
   264
      operator Edge() const {
deba@2247
   265
	return id != -1 ? path->edges[id] : INVALID;
deba@2247
   266
      }
hegyi@819
   267
deba@2247
   268
      /// \brief Steps to the next edge
deba@2247
   269
      ///
deba@2247
   270
      /// Steps to the next edge
deba@2247
   271
      EdgeIt& operator++() { 
deba@2247
   272
        ++id; 
deba@2247
   273
        if (id >= path->length()) id = -1;
deba@2247
   274
        return *this; 
deba@2247
   275
      }
deba@2247
   276
deba@2247
   277
      /// \brief Comparison operator
deba@2247
   278
      ///
hegyi@819
   279
      /// Comparison operator
deba@2247
   280
      bool operator==(const EdgeIt& e) const { return id == e.id; }
deba@2247
   281
deba@2247
   282
      /// \brief Comparison operator
deba@2247
   283
      ///
hegyi@819
   284
      /// Comparison operator
deba@2247
   285
      bool operator!=(const EdgeIt& e) const { return id != e.id; }
deba@2247
   286
deba@2247
   287
      /// \brief Comparison operator
deba@2247
   288
      ///
hegyi@819
   289
      /// Comparison operator
deba@2247
   290
      bool operator<(const EdgeIt& e) const { return id < e.id; }
hegyi@819
   291
hegyi@819
   292
    private:
deba@2247
   293
deba@2247
   294
      int id;
deba@2247
   295
      const Path *path;
hegyi@819
   296
    };
hegyi@819
   297
deba@2247
   298
  protected:
hegyi@819
   299
deba@2247
   300
    const Graph *graph;
hegyi@819
   301
deba@2247
   302
    typedef std::vector<Edge> Container;
deba@2247
   303
    Container edges;
deba@2247
   304
    Node start;
hegyi@819
   305
deba@2247
   306
  public:
hegyi@819
   307
hegyi@837
   308
    friend class Builder;
hegyi@819
   309
deba@2247
   310
    /// \brief Class to build paths
deba@2247
   311
    ///
deba@2247
   312
    /// This class is used to fill a path with edges.
deba@2247
   313
    ///
deba@2247
   314
    /// You can push new edges to the front and to the back of the
deba@2247
   315
    /// path in arbitrary order then you should commit these changes
deba@2247
   316
    /// to the graph.
deba@2247
   317
    ///
deba@2247
   318
    /// Fundamentally, for most "Paths" (classes fulfilling the
deba@2247
   319
    /// PathConcept) while the builder is active (after the first
deba@2247
   320
    /// modifying operation and until the commit()) the original Path
deba@2247
   321
    /// is in a "transitional" state (operations on it have undefined
deba@2247
   322
    /// result). But in the case of Path the original path remains
deba@2247
   323
    /// unchanged until the commit. However we don't recomend that you
deba@2247
   324
    /// use this feature.
hegyi@819
   325
    class Builder {
deba@2247
   326
    public:
deba@2247
   327
      /// \brief Constructor
deba@2247
   328
      ///
deba@2247
   329
      /// Constructor
deba@2247
   330
      /// \param _path the path you want to fill in.
deba@2247
   331
      Builder(Path &_path) : path(_path), start(INVALID) {}
hegyi@819
   332
deba@2247
   333
      /// \brief Destructor
hegyi@819
   334
      ///
deba@2247
   335
      /// Destructor
deba@2247
   336
      ~Builder() {
deba@2247
   337
        LEMON_ASSERT(front.empty() && back.empty() && start == INVALID, 
deba@2247
   338
                     PathError());
deba@2247
   339
      }
hegyi@819
   340
deba@2247
   341
      /// \brief Sets the starting node of the path.
deba@2247
   342
      ///
deba@2247
   343
      /// Sets the starting node of the path. Edge added to the path
deba@2247
   344
      /// afterwards have to be incident to this node.  It should be
deba@2247
   345
      /// called if and only if the path is empty and before any call
deba@2247
   346
      /// to \ref pushFront() or \ref pushBack()
deba@2247
   347
      void setStartNode(const Node &_start) {
deba@2247
   348
        LEMON_ASSERT(path.empty() && start == INVALID, PathError());
deba@2247
   349
        start = _start;
deba@2247
   350
      }
hegyi@837
   351
deba@2247
   352
      /// \brief Push a new edge to the front of the path
deba@2247
   353
      ///
deba@2247
   354
      /// Push a new edge to the front of the path.  
deba@2247
   355
      /// \sa setStartNode
deba@2247
   356
      void pushFront(const Edge& e) {
deba@2247
   357
        LEMON_ASSERT(front.empty() || 
deba@2247
   358
                     (path.graph->source(front.back()) == 
deba@2247
   359
                      path.graph->target(e)), PathError());
deba@2247
   360
        LEMON_ASSERT(path.empty() || 
deba@2247
   361
                     (path.source() == path.graph->target(e)), PathError());
deba@2247
   362
        LEMON_ASSERT(!path.empty() || !front.empty() ||
deba@2247
   363
                     (start == path.graph->target(e)), PathError());
hegyi@819
   364
	front.push_back(e);
hegyi@819
   365
      }
hegyi@819
   366
deba@2247
   367
      /// \brief Push a new edge to the back of the path
deba@2247
   368
      ///
deba@2247
   369
      /// Push a new edge to the back of the path.
deba@2247
   370
      /// \sa setStartNode
deba@2247
   371
      void pushBack(const Edge& e) {
deba@2247
   372
        LEMON_ASSERT(back.empty() || 
deba@2247
   373
                     (path.graph->target(back.back()) == 
deba@2247
   374
                      path.graph->source(e)), PathError());
deba@2247
   375
        LEMON_ASSERT(path.empty() || 
deba@2247
   376
                     (path.target() == path.graph->source(e)), PathError());
deba@2247
   377
        LEMON_ASSERT(!path.empty() || !back.empty() ||
deba@2247
   378
                     (start == path.graph->source(e)), PathError());
hegyi@819
   379
	back.push_back(e);
hegyi@819
   380
      }
hegyi@819
   381
deba@2247
   382
      /// \brief Commit the changes to the path.
deba@2247
   383
      ///
deba@2247
   384
      /// Commit the changes to the path.
hegyi@819
   385
      void commit() {
deba@2247
   386
	if( !front.empty() || !back.empty() || start != INVALID) {
hegyi@819
   387
	  Container tmp;
deba@2247
   388
	  tmp.reserve(front.size() + back.size() + path.length());
hegyi@819
   389
	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
deba@2247
   390
	  tmp.insert(tmp.end(), path.edges.begin(), path.edges.end());
hegyi@819
   391
	  tmp.insert(tmp.end(), back.begin(), back.end());
deba@2247
   392
	  path.edges.swap(tmp);
deba@2247
   393
          if (!front.empty()) {
deba@2247
   394
            path.start = path.graph->source(front.back());
deba@2247
   395
          } else {
deba@2247
   396
            path.start = start;
deba@2247
   397
          }
deba@2247
   398
          start = INVALID;
hegyi@819
   399
	  front.clear();
hegyi@819
   400
	  back.clear();
hegyi@819
   401
	}
hegyi@819
   402
      }
hegyi@819
   403
deba@2247
   404
      /// \brief Reserve storage for the builder in advance.
deba@2247
   405
      ///
deba@2247
   406
      /// If you know a reasonable upper bound of the number of the
deba@2247
   407
      /// edges to add to the front, using this function you can speed
deba@2247
   408
      /// up the building.
hegyi@837
   409
      void reserveFront(size_t r) {front.reserve(r);}
hegyi@837
   410
deba@2247
   411
      /// \brief Reserve storage for the builder in advance.
deba@2247
   412
      ///
deba@2247
   413
      /// If you know a reasonable upper bound of the number of the
deba@2247
   414
      /// edges to add to the back, using this function you can speed
deba@2247
   415
      /// up the building.
hegyi@837
   416
      void reserveBack(size_t r) {back.reserve(r);}
hegyi@831
   417
hegyi@819
   418
    private:
hegyi@819
   419
deba@2247
   420
      Path &path;
deba@2247
   421
      Container front, back;
deba@2247
   422
      Node start;
hegyi@819
   423
hegyi@819
   424
    };
hegyi@819
   425
hegyi@819
   426
  };
hegyi@819
   427
hegyi@819
   428
  ///@}
hegyi@819
   429
alpar@921
   430
} // namespace lemon
hegyi@819
   431
alpar@921
   432
#endif // LEMON_PATH_H