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