lemon/euler.h
author Peter Kovacs <kpeter@inf.elte.hu>
Wed, 15 Apr 2009 11:41:25 +0200
changeset 583 493533ead9df
parent 578 7c12061bd271
child 584 2ebfdb89ec66
permissions -rw-r--r--
Bug fix in the Euler iterators (#264)
Handle the case when the first node is isolated.
alpar@504
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@504
     2
 *
alpar@504
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@504
     4
 *
alpar@504
     5
 * Copyright (C) 2003-2009
alpar@504
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@504
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@504
     8
 *
alpar@504
     9
 * Permission to use, modify and distribute this software is granted
alpar@504
    10
 * provided that this copyright notice appears in all copies. For
alpar@504
    11
 * precise terms see the accompanying LICENSE file.
alpar@504
    12
 *
alpar@504
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@504
    14
 * express or implied, and with no claim as to its suitability for any
alpar@504
    15
 * purpose.
alpar@504
    16
 *
alpar@504
    17
 */
alpar@504
    18
alpar@504
    19
#ifndef LEMON_EULER_H
alpar@504
    20
#define LEMON_EULER_H
alpar@504
    21
alpar@504
    22
#include<lemon/core.h>
alpar@504
    23
#include<lemon/adaptors.h>
alpar@504
    24
#include<lemon/connectivity.h>
alpar@504
    25
#include <list>
alpar@504
    26
kpeter@578
    27
/// \ingroup graph_properties
alpar@504
    28
/// \file
alpar@504
    29
/// \brief Euler tour
alpar@504
    30
///
alpar@504
    31
///This file provides an Euler tour iterator and ways to check
alpar@504
    32
///if a digraph is euler.
alpar@504
    33
alpar@504
    34
alpar@504
    35
namespace lemon {
alpar@504
    36
alpar@504
    37
  ///Euler iterator for digraphs.
alpar@504
    38
kpeter@578
    39
  /// \ingroup graph_properties
alpar@504
    40
  ///This iterator converts to the \c Arc type of the digraph and using
alpar@504
    41
  ///operator ++, it provides an Euler tour of a \e directed
alpar@504
    42
  ///graph (if there exists).
alpar@504
    43
  ///
alpar@504
    44
  ///For example
alpar@504
    45
  ///if the given digraph is Euler (i.e it has only one nontrivial component
alpar@504
    46
  ///and the in-degree is equal to the out-degree for all nodes),
alpar@504
    47
  ///the following code will put the arcs of \c g
alpar@504
    48
  ///to the vector \c et according to an
alpar@504
    49
  ///Euler tour of \c g.
alpar@504
    50
  ///\code
alpar@504
    51
  ///  std::vector<ListDigraph::Arc> et;
alpar@504
    52
  ///  for(DiEulerIt<ListDigraph> e(g),e!=INVALID;++e)
alpar@504
    53
  ///    et.push_back(e);
alpar@504
    54
  ///\endcode
alpar@504
    55
  ///If \c g is not Euler then the resulted tour will not be full or closed.
alpar@504
    56
  ///\sa EulerIt
kpeter@550
    57
  template<typename GR>
alpar@504
    58
  class DiEulerIt
alpar@504
    59
  {
kpeter@550
    60
    typedef typename GR::Node Node;
kpeter@550
    61
    typedef typename GR::NodeIt NodeIt;
kpeter@550
    62
    typedef typename GR::Arc Arc;
kpeter@550
    63
    typedef typename GR::ArcIt ArcIt;
kpeter@550
    64
    typedef typename GR::OutArcIt OutArcIt;
kpeter@550
    65
    typedef typename GR::InArcIt InArcIt;
alpar@504
    66
kpeter@550
    67
    const GR &g;
kpeter@550
    68
    typename GR::template NodeMap<OutArcIt> nedge;
alpar@504
    69
    std::list<Arc> euler;
alpar@504
    70
alpar@504
    71
  public:
alpar@504
    72
alpar@504
    73
    ///Constructor
alpar@504
    74
kpeter@550
    75
    ///\param gr A digraph.
alpar@504
    76
    ///\param start The starting point of the tour. If it is not given
alpar@504
    77
    ///       the tour will start from the first node.
kpeter@550
    78
    DiEulerIt(const GR &gr, typename GR::Node start = INVALID)
kpeter@550
    79
      : g(gr), nedge(g)
alpar@504
    80
    {
kpeter@583
    81
      if (start==INVALID) {
kpeter@583
    82
        NodeIt n(g);
kpeter@583
    83
        while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
kpeter@583
    84
        start=n;
kpeter@583
    85
      }
kpeter@583
    86
      if (start!=INVALID) {
kpeter@583
    87
        for (NodeIt n(g); n!=INVALID; ++n) nedge[n]=OutArcIt(g,n);
kpeter@583
    88
        while (nedge[start]!=INVALID) {
kpeter@583
    89
          euler.push_back(nedge[start]);
kpeter@583
    90
          Node next=g.target(nedge[start]);
kpeter@583
    91
          ++nedge[start];
kpeter@583
    92
          start=next;
kpeter@583
    93
        }
alpar@504
    94
      }
alpar@504
    95
    }
alpar@504
    96
alpar@504
    97
    ///Arc Conversion
alpar@504
    98
    operator Arc() { return euler.empty()?INVALID:euler.front(); }
alpar@504
    99
    bool operator==(Invalid) { return euler.empty(); }
alpar@504
   100
    bool operator!=(Invalid) { return !euler.empty(); }
alpar@504
   101
alpar@504
   102
    ///Next arc of the tour
alpar@504
   103
    DiEulerIt &operator++() {
alpar@504
   104
      Node s=g.target(euler.front());
alpar@504
   105
      euler.pop_front();
alpar@504
   106
      //This produces a warning.Strange.
alpar@504
   107
      //std::list<Arc>::iterator next=euler.begin();
alpar@504
   108
      typename std::list<Arc>::iterator next=euler.begin();
alpar@504
   109
      while(nedge[s]!=INVALID) {
alpar@504
   110
        euler.insert(next,nedge[s]);
alpar@504
   111
        Node n=g.target(nedge[s]);
alpar@504
   112
        ++nedge[s];
alpar@504
   113
        s=n;
alpar@504
   114
      }
alpar@504
   115
      return *this;
alpar@504
   116
    }
alpar@504
   117
    ///Postfix incrementation
alpar@504
   118
alpar@504
   119
    ///\warning This incrementation
alpar@504
   120
    ///returns an \c Arc, not an \ref DiEulerIt, as one may
alpar@504
   121
    ///expect.
alpar@504
   122
    Arc operator++(int)
alpar@504
   123
    {
alpar@504
   124
      Arc e=*this;
alpar@504
   125
      ++(*this);
alpar@504
   126
      return e;
alpar@504
   127
    }
alpar@504
   128
  };
alpar@504
   129
alpar@504
   130
  ///Euler iterator for graphs.
alpar@504
   131
kpeter@578
   132
  /// \ingroup graph_properties
alpar@504
   133
  ///This iterator converts to the \c Arc (or \c Edge)
alpar@504
   134
  ///type of the digraph and using
alpar@504
   135
  ///operator ++, it provides an Euler tour of an undirected
alpar@504
   136
  ///digraph (if there exists).
alpar@504
   137
  ///
alpar@504
   138
  ///For example
alpar@504
   139
  ///if the given digraph if Euler (i.e it has only one nontrivial component
alpar@504
   140
  ///and the degree of each node is even),
alpar@504
   141
  ///the following code will print the arc IDs according to an
alpar@504
   142
  ///Euler tour of \c g.
alpar@504
   143
  ///\code
alpar@504
   144
  ///  for(EulerIt<ListGraph> e(g),e!=INVALID;++e) {
alpar@504
   145
  ///    std::cout << g.id(Edge(e)) << std::eol;
alpar@504
   146
  ///  }
alpar@504
   147
  ///\endcode
alpar@504
   148
  ///Although the iterator provides an Euler tour of an graph,
alpar@504
   149
  ///it still returns Arcs in order to indicate the direction of the tour.
alpar@504
   150
  ///(But Arc will convert to Edges, of course).
alpar@504
   151
  ///
alpar@504
   152
  ///If \c g is not Euler then the resulted tour will not be full or closed.
alpar@504
   153
  ///\sa EulerIt
kpeter@550
   154
  template<typename GR>
alpar@504
   155
  class EulerIt
alpar@504
   156
  {
kpeter@550
   157
    typedef typename GR::Node Node;
kpeter@550
   158
    typedef typename GR::NodeIt NodeIt;
kpeter@550
   159
    typedef typename GR::Arc Arc;
kpeter@550
   160
    typedef typename GR::Edge Edge;
kpeter@550
   161
    typedef typename GR::ArcIt ArcIt;
kpeter@550
   162
    typedef typename GR::OutArcIt OutArcIt;
kpeter@550
   163
    typedef typename GR::InArcIt InArcIt;
alpar@504
   164
kpeter@550
   165
    const GR &g;
kpeter@550
   166
    typename GR::template NodeMap<OutArcIt> nedge;
kpeter@550
   167
    typename GR::template EdgeMap<bool> visited;
alpar@504
   168
    std::list<Arc> euler;
alpar@504
   169
alpar@504
   170
  public:
alpar@504
   171
alpar@504
   172
    ///Constructor
alpar@504
   173
kpeter@550
   174
    ///\param gr An graph.
alpar@504
   175
    ///\param start The starting point of the tour. If it is not given
alpar@504
   176
    ///       the tour will start from the first node.
kpeter@550
   177
    EulerIt(const GR &gr, typename GR::Node start = INVALID)
kpeter@550
   178
      : g(gr), nedge(g), visited(g, false)
alpar@504
   179
    {
kpeter@583
   180
      if (start==INVALID) {
kpeter@583
   181
        NodeIt n(g);
kpeter@583
   182
        while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
kpeter@583
   183
        start=n;
kpeter@583
   184
      }
kpeter@583
   185
      if (start!=INVALID) {
kpeter@583
   186
        for (NodeIt n(g); n!=INVALID; ++n) nedge[n]=OutArcIt(g,n);
kpeter@583
   187
        while(nedge[start]!=INVALID) {
kpeter@583
   188
          euler.push_back(nedge[start]);
kpeter@583
   189
          visited[nedge[start]]=true;
kpeter@583
   190
          Node next=g.target(nedge[start]);
kpeter@583
   191
          ++nedge[start];
kpeter@583
   192
          start=next;
kpeter@583
   193
          while(nedge[start]!=INVALID && visited[nedge[start]]) ++nedge[start];
kpeter@583
   194
        }
alpar@504
   195
      }
alpar@504
   196
    }
alpar@504
   197
alpar@504
   198
    ///Arc Conversion
alpar@504
   199
    operator Arc() const { return euler.empty()?INVALID:euler.front(); }
alpar@504
   200
    ///Arc Conversion
alpar@504
   201
    operator Edge() const { return euler.empty()?INVALID:euler.front(); }
alpar@504
   202
    ///\e
alpar@504
   203
    bool operator==(Invalid) const { return euler.empty(); }
alpar@504
   204
    ///\e
alpar@504
   205
    bool operator!=(Invalid) const { return !euler.empty(); }
alpar@504
   206
alpar@504
   207
    ///Next arc of the tour
alpar@504
   208
    EulerIt &operator++() {
alpar@504
   209
      Node s=g.target(euler.front());
alpar@504
   210
      euler.pop_front();
alpar@504
   211
      typename std::list<Arc>::iterator next=euler.begin();
alpar@504
   212
alpar@504
   213
      while(nedge[s]!=INVALID) {
alpar@504
   214
        while(nedge[s]!=INVALID && visited[nedge[s]]) ++nedge[s];
alpar@504
   215
        if(nedge[s]==INVALID) break;
alpar@504
   216
        else {
alpar@504
   217
          euler.insert(next,nedge[s]);
alpar@504
   218
          visited[nedge[s]]=true;
alpar@504
   219
          Node n=g.target(nedge[s]);
alpar@504
   220
          ++nedge[s];
alpar@504
   221
          s=n;
alpar@504
   222
        }
alpar@504
   223
      }
alpar@504
   224
      return *this;
alpar@504
   225
    }
alpar@504
   226
alpar@504
   227
    ///Postfix incrementation
alpar@504
   228
alpar@504
   229
    ///\warning This incrementation
alpar@504
   230
    ///returns an \c Arc, not an \ref EulerIt, as one may
alpar@504
   231
    ///expect.
alpar@504
   232
    Arc operator++(int)
alpar@504
   233
    {
alpar@504
   234
      Arc e=*this;
alpar@504
   235
      ++(*this);
alpar@504
   236
      return e;
alpar@504
   237
    }
alpar@504
   238
  };
alpar@504
   239
alpar@504
   240
alpar@505
   241
  ///Checks if the graph is Eulerian
alpar@504
   242
kpeter@578
   243
  /// \ingroup graph_properties
alpar@505
   244
  ///Checks if the graph is Eulerian. It works for both directed and undirected
alpar@504
   245
  ///graphs.
alpar@505
   246
  ///\note By definition, a digraph is called \e Eulerian if
alpar@504
   247
  ///and only if it is connected and the number of its incoming and outgoing
alpar@504
   248
  ///arcs are the same for each node.
alpar@505
   249
  ///Similarly, an undirected graph is called \e Eulerian if
alpar@504
   250
  ///and only if it is connected and the number of incident arcs is even
alpar@505
   251
  ///for each node. <em>Therefore, there are digraphs which are not Eulerian,
alpar@505
   252
  ///but still have an Euler tour</em>.
kpeter@550
   253
  template<typename GR>
alpar@504
   254
#ifdef DOXYGEN
alpar@504
   255
  bool
alpar@504
   256
#else
kpeter@550
   257
  typename enable_if<UndirectedTagIndicator<GR>,bool>::type
kpeter@550
   258
  eulerian(const GR &g)
alpar@504
   259
  {
kpeter@550
   260
    for(typename GR::NodeIt n(g);n!=INVALID;++n)
alpar@504
   261
      if(countIncEdges(g,n)%2) return false;
alpar@504
   262
    return connected(g);
alpar@504
   263
  }
kpeter@550
   264
  template<class GR>
kpeter@550
   265
  typename disable_if<UndirectedTagIndicator<GR>,bool>::type
alpar@504
   266
#endif
kpeter@550
   267
  eulerian(const GR &g)
alpar@504
   268
  {
kpeter@550
   269
    for(typename GR::NodeIt n(g);n!=INVALID;++n)
alpar@504
   270
      if(countInArcs(g,n)!=countOutArcs(g,n)) return false;
kpeter@550
   271
    return connected(Undirector<const GR>(g));
alpar@504
   272
  }
alpar@504
   273
alpar@504
   274
}
alpar@504
   275
alpar@504
   276
#endif