lemon/path.h
author deba
Fri, 03 Nov 2006 16:29:32 +0000
changeset 2293 1ee6e8788cc7
parent 2084 59769591eb60
child 2335 27aa03cd3121
permissions -rw-r--r--
First implementation of the static graph class
It could be improved to get better running times on benchmarks
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