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