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