src/work/marci/bipartite_graph_wrapper.h
author marci
Mon, 20 Sep 2004 17:53:33 +0000
changeset 890 3a48bc350e0f
parent 762 511200bdb71f
child 902 309d81806228
permissions -rw-r--r--
Specialized ConstMap for defining constant maps at compile time, by klao.
Time comparision of the generic and specialized maps.
marci@174
     1
// -*- c++ -*-
marci@496
     2
#ifndef HUGO_BIPARTITE_GRAPH_WRAPPER_H
marci@496
     3
#define HUGO_BIPARTITE_GRAPH_WRAPPER_H
marci@76
     4
klao@491
     5
///\ingroup gwrappers
alpar@457
     6
///\file
alpar@457
     7
///\brief Several graph wrappers.
alpar@457
     8
///
alpar@457
     9
///This file contains several useful graph wrapper functions.
alpar@457
    10
///
alpar@457
    11
///\author Marton Makai
alpar@457
    12
marci@555
    13
#include <hugo/invalid.h>
marci@368
    14
#include <iter_map.h>
marci@557
    15
#include <hugo/graph_wrapper.h>
marci@762
    16
#include <for_each_macros.h>
marci@174
    17
alpar@105
    18
namespace hugo {
marci@76
    19
marci@641
    20
  /// \brief A wrapper for composing a bipartite graph from a graph 
marci@641
    21
  /// and from a node-map showing for any node which color class it belongs to.
marci@641
    22
  ///
marci@368
    23
  /// A wrapper for composing a bipartite graph.
marci@371
    24
  /// \c _graph have to be a reference to a graph of type \c Graph 
marci@371
    25
  /// and \c _s_false_t_true_map is an \c IterableBoolMap 
marci@368
    26
  /// reference containing the elements for the 
marci@371
    27
  /// color classes S and T. \c _graph is to be referred to an undirected 
marci@371
    28
  /// graph or a directed graph with edges oriented from S to T.
alpar@457
    29
  ///
marci@641
    30
  /// \author Marton Makai
marci@368
    31
  template<typename Graph> 
marci@368
    32
  class BipartiteGraphWrapper : public GraphWrapper<Graph> {
marci@768
    33
  public:
marci@389
    34
    typedef IterableBoolMap< typename Graph::template NodeMap<int> > 
marci@389
    35
    SFalseTTrueMap;
marci@768
    36
  protected:
marci@368
    37
    SFalseTTrueMap* s_false_t_true_map;
marci@393
    38
marci@501
    39
    BipartiteGraphWrapper() : GraphWrapper<Graph>()/*, 
marci@501
    40
						     S_CLASS(false), T_CLASS(true)*/ { }
marci@497
    41
    void setSFalseTTrueMap(SFalseTTrueMap& _s_false_t_true_map) { 
marci@499
    42
      s_false_t_true_map=&_s_false_t_true_map;
marci@497
    43
    }
marci@497
    44
marci@368
    45
  public:
marci@409
    46
    //marci
marci@409
    47
    //FIXME vhogy igy kellene, csak az en forditom nem eszi meg
marci@502
    48
    static const bool S_CLASS;
marci@502
    49
    static const bool T_CLASS;
marci@768
    50
marci@768
    51
    /// This method is to reach the iterable maps of the bipartite graph or 
marci@768
    52
    /// bipartite graph wrapper.
marci@768
    53
    const SFalseTTrueMap& sFalseTTrueMap() const { 
marci@768
    54
      return *s_false_t_true_map; 
marci@768
    55
    }
marci@379
    56
    
marci@501
    57
    //bool S_CLASS;
marci@501
    58
    //bool T_CLASS;
marci@409
    59
marci@368
    60
    BipartiteGraphWrapper(Graph& _graph, SFalseTTrueMap& _s_false_t_true_map) 
marci@500
    61
      : GraphWrapper<Graph>(_graph), 
marci@501
    62
	s_false_t_true_map(&_s_false_t_true_map)/*, 
marci@501
    63
						  S_CLASS(false), T_CLASS(true)*/ { }
marci@368
    64
    typedef typename GraphWrapper<Graph>::Node Node;
marci@368
    65
    //using GraphWrapper<Graph>::NodeIt;
marci@368
    66
    typedef typename GraphWrapper<Graph>::Edge Edge;
marci@368
    67
    //using GraphWrapper<Graph>::EdgeIt;
marci@393
    68
    class ClassNodeIt;
marci@393
    69
    friend class ClassNodeIt;
marci@393
    70
    class OutEdgeIt;
marci@393
    71
    friend class OutEdgeIt;
marci@393
    72
    class InEdgeIt;
marci@393
    73
    friend class InEdgeIt;
marci@379
    74
    class ClassNodeIt {
marci@393
    75
      friend class BipartiteGraphWrapper<Graph>;
marci@393
    76
    protected:
marci@368
    77
      Node n;
marci@368
    78
    public:
marci@379
    79
      ClassNodeIt() { }
marci@379
    80
      ClassNodeIt(const Invalid& i) : n(i) { }
marci@379
    81
      ClassNodeIt(const BipartiteGraphWrapper<Graph>& _G, bool _class) { 
marci@379
    82
	_G.s_false_t_true_map->first(n, _class); 
marci@368
    83
      }
marci@381
    84
      //FIXME needed in new concept, important here
marci@381
    85
      ClassNodeIt(const Node& _n) : n(_n) { }
marci@368
    86
      operator Node() const { return n; }
marci@368
    87
    };
marci@379
    88
//     class SNodeIt {
marci@379
    89
//       Node n;
marci@379
    90
//     public:
marci@379
    91
//       SNodeIt() { }
marci@379
    92
//       SNodeIt(const Invalid& i) : n(i) { }
marci@379
    93
//       SNodeIt(const BipartiteGraphWrapper<Graph>& _G) { 
marci@379
    94
// 	_G.s_false_t_true_map->first(n, false); 
marci@379
    95
//       }
marci@379
    96
//       operator Node() const { return n; }
marci@379
    97
//     };
marci@379
    98
//     class TNodeIt {
marci@379
    99
//       Node n;
marci@379
   100
//     public:
marci@379
   101
//       TNodeIt() { }
marci@379
   102
//       TNodeIt(const Invalid& i) : n(i) { }
marci@379
   103
//       TNodeIt(const BipartiteGraphWrapper<Graph>& _G) { 
marci@379
   104
// 	_G.s_false_t_true_map->first(n, true); 
marci@379
   105
//       }
marci@379
   106
//       operator Node() const { return n; }
marci@379
   107
//     };
marci@368
   108
    class OutEdgeIt { 
marci@393
   109
      friend class BipartiteGraphWrapper<Graph>;
marci@393
   110
    protected:
marci@368
   111
      typename Graph::OutEdgeIt e;
marci@368
   112
    public:
marci@368
   113
      OutEdgeIt() { }
marci@368
   114
      OutEdgeIt(const Invalid& i) : e(i) { }
marci@368
   115
      OutEdgeIt(const BipartiteGraphWrapper<Graph>& _G, const Node& _n) {
marci@368
   116
	if (!(*(_G.s_false_t_true_map))[_n]) 
marci@379
   117
	  e=typename Graph::OutEdgeIt(*(_G.graph), typename Graph::Node(_n));
marci@368
   118
	else 
marci@368
   119
	  e=INVALID;
marci@368
   120
      }
marci@368
   121
      operator Edge() const { return Edge(typename Graph::Edge(e)); }
marci@368
   122
    };
marci@368
   123
    class InEdgeIt { 
marci@393
   124
      friend class BipartiteGraphWrapper<Graph>;
marci@393
   125
    protected:
marci@368
   126
      typename Graph::InEdgeIt e;
marci@368
   127
    public:
marci@368
   128
      InEdgeIt() { }
marci@368
   129
      InEdgeIt(const Invalid& i) : e(i) { }
marci@368
   130
      InEdgeIt(const BipartiteGraphWrapper<Graph>& _G, const Node& _n) {
marci@368
   131
	if ((*(_G.s_false_t_true_map))[_n]) 
marci@379
   132
	  e=typename Graph::InEdgeIt(*(_G.graph), typename Graph::Node(_n));
marci@368
   133
	else 
marci@368
   134
	  e=INVALID;
marci@368
   135
      }
marci@368
   136
      operator Edge() const { return Edge(typename Graph::Edge(e)); }
marci@368
   137
    };
marci@368
   138
marci@368
   139
    using GraphWrapper<Graph>::first;
marci@379
   140
    ClassNodeIt& first(ClassNodeIt& n, bool _class) const { 
marci@393
   141
      n=ClassNodeIt(*this, _class) ; return n; }
marci@379
   142
//    SNodeIt& first(SNodeIt& n) const { n=SNodeIt(*this); return n; }
marci@379
   143
//    TNodeIt& first(TNodeIt& n) const { n=TNodeIt(*this); return n; }
marci@379
   144
    OutEdgeIt& first(OutEdgeIt& i, const Node& p) const { 
marci@379
   145
      i=OutEdgeIt(*this, p); return i;
marci@379
   146
    }
marci@379
   147
    InEdgeIt& first(InEdgeIt& i, const Node& p) const { 
marci@379
   148
      i=InEdgeIt(*this, p); return i;
marci@379
   149
    }
marci@368
   150
marci@368
   151
    using GraphWrapper<Graph>::next;
marci@379
   152
    ClassNodeIt& next(ClassNodeIt& n) const { 
marci@393
   153
      this->s_false_t_true_map->next(n.n); return n; 
marci@368
   154
    }
marci@379
   155
//     SNodeIt& next(SNodeIt& n) const { 
marci@379
   156
//       this->s_false_t_true_map->next(n); return n; 
marci@379
   157
//     }
marci@379
   158
//     TNodeIt& next(TNodeIt& n) const { 
marci@379
   159
//       this->s_false_t_true_map->next(n); return n; 
marci@379
   160
//     }
marci@389
   161
    OutEdgeIt& next(OutEdgeIt& i) const { this->graph->next(i.e); return i; }
marci@389
   162
    InEdgeIt& next(InEdgeIt& i) const { this->graph->next(i.e); return i; }
marci@368
   163
marci@368
   164
    Node tail(const Edge& e) { 
marci@368
   165
      if (!(*(this->s_false_t_true_map))[this->graph->tail(e)]) 
marci@368
   166
	return Node(this->graph->tail(e));
marci@368
   167
      else
marci@368
   168
	return Node(this->graph->head(e));	
marci@368
   169
    }
marci@368
   170
    Node head(const Edge& e) { 
marci@368
   171
      if (!(*(this->s_false_t_true_map))[this->graph->tail(e)]) 
marci@368
   172
	return Node(this->graph->head(e));
marci@368
   173
      else
marci@368
   174
	return Node(this->graph->tail(e));	
marci@368
   175
    }
marci@368
   176
marci@368
   177
    Node aNode(const OutEdgeIt& e) const { 
marci@368
   178
      return Node(this->graph->aNode(e.e)); 
marci@368
   179
    }
marci@368
   180
    Node aNode(const InEdgeIt& e) const { 
marci@368
   181
      return Node(this->graph->aNode(e.e)); 
marci@368
   182
    }
marci@368
   183
    Node bNode(const OutEdgeIt& e) const { 
marci@368
   184
      return Node(this->graph->bNode(e.e)); 
marci@368
   185
    }
marci@368
   186
    Node bNode(const InEdgeIt& e) const { 
marci@368
   187
      return Node(this->graph->bNode(e.e)); 
marci@368
   188
    }
marci@379
   189
marci@641
   190
    /// Returns true iff \c n is in S.
marci@379
   191
    bool inSClass(const Node& n) const {
marci@381
   192
      return !(*(this->s_false_t_true_map))[n];
marci@379
   193
    }
marci@641
   194
marci@641
   195
    /// Returns true iff \c n is in T.
marci@379
   196
    bool inTClass(const Node& n) const {
marci@381
   197
      return (*(this->s_false_t_true_map))[n];
marci@379
   198
    }
marci@368
   199
  };
marci@368
   200
marci@502
   201
marci@502
   202
  template<typename G>
marci@502
   203
  const bool BipartiteGraphWrapper<G>::S_CLASS=false;
marci@502
   204
  template<typename G>
marci@502
   205
  const bool BipartiteGraphWrapper<G>::T_CLASS=true;
marci@502
   206
marci@641
   207
  /// \brief A bipartite graph template class
marci@641
   208
  ///
marci@641
   209
  /// This class composes a bipartite graph over a directed or undirected 
marci@641
   210
  /// graph structure of type \c Graph.
marci@641
   211
  /// \c _graph have to be a reference to a graph of type \c Graph 
marci@641
   212
  /// and \c _s_false_t_true_map is an \c IterableBoolMap 
marci@641
   213
  /// reference containing the elements for the 
marci@641
   214
  /// color classes S and T. \c _graph is to be referred to an undirected 
marci@641
   215
  /// graph or a directed graph with edges oriented from S to T.
marci@641
   216
  ///
marci@641
   217
  ///\bug experimental. Do not use this while the bipartitemap augmentation 
marci@497
   218
  /// does not work well.
marci@497
   219
  template<typename Graph>
marci@497
   220
  class BipartiteGraph : public BipartiteGraphWrapper<Graph> {
marci@768
   221
//     typedef IterableBoolMap< typename Graph::template NodeMap<int> > 
marci@768
   222
//     SFalseTTrueMap;
marci@497
   223
    typedef BipartiteGraphWrapper<Graph> Parent;
marci@497
   224
  protected:
marci@497
   225
    Graph gr;
marci@497
   226
    typename Graph::template NodeMap<int> bipartite_map;
marci@768
   227
    typename Parent::SFalseTTrueMap s_false_t_true_map;
marci@497
   228
  public:
marci@497
   229
    typedef typename Parent::Node Node;
marci@497
   230
    typedef typename Parent::Edge Edge;
marci@499
   231
    BipartiteGraph() : BipartiteGraphWrapper<Graph>(), 
marci@500
   232
		       gr(), bipartite_map(gr, -1), 
marci@497
   233
		       s_false_t_true_map(bipartite_map) { 
marci@497
   234
      Parent::setGraph(gr); 
marci@499
   235
      Parent::setSFalseTTrueMap(s_false_t_true_map);
marci@497
   236
    }
marci@497
   237
marci@497
   238
    /// the \c bool parameter which can be \c S_Class or \c T_Class shows 
marci@497
   239
    /// the color class where the new node is to be inserted.
marci@498
   240
    Node addNode(bool b) {
marci@498
   241
      Node n=Parent::graph->addNode();
marci@498
   242
      bipartite_map.update();
marci@501
   243
      //bipartite_map.set(n, -1);
marci@498
   244
      s_false_t_true_map.insert(n, b);
marci@498
   245
      return n;
marci@498
   246
    }
marci@497
   247
marci@497
   248
    /// A new edge is inserted.
marci@497
   249
    ///\pre \c tail have to be in \c S_Class and \c head in \c T_Class.
marci@498
   250
    Edge addEdge(const Node& tail, const Node& head) {
marci@498
   251
      return Parent::graph->addEdge(tail, head);
marci@498
   252
    }
marci@497
   253
marci@498
   254
    void erase(const Node& n) {
marci@498
   255
      s_false_t_true_map.remove(n);
marci@498
   256
      Parent::graph->erase(n);
marci@498
   257
    }
marci@498
   258
    void erase(const Edge& e) {
marci@498
   259
      Parent::graph->erase(e);
marci@498
   260
    }
marci@497
   261
    
marci@497
   262
    void clear() {
marci@558
   263
      FOR_EACH_LOC(typename Parent::EdgeIt, e, *this) erase(e);
marci@558
   264
      FOR_EACH_LOC(typename Parent::NodeIt, n, *this) erase(n);
marci@497
   265
    }
marci@497
   266
  };
marci@497
   267
marci@768
   268
  template<typename Graph, typename sIterableMap, typename tIterableMap>
marci@768
   269
  class stGraphWrapper;
marci@497
   270
marci@768
   271
  /// Easier stuff for bipartite graphs.
marci@435
   272
  template<typename Graph>
marci@768
   273
  class stBipartiteGraphWrapper : public 
marci@768
   274
  stGraphWrapper<Graph, typename Graph::SFalseTTrueMap, 
marci@768
   275
		 typename Graph::SFalseTTrueMap> {
marci@768
   276
  public:
marci@768
   277
    typedef stGraphWrapper<Graph, typename Graph::SFalseTTrueMap, 
marci@768
   278
			   typename Graph::SFalseTTrueMap> Parent;
marci@768
   279
    stBipartiteGraphWrapper(Graph& _graph) : 
marci@768
   280
      Parent(_graph, _graph.sFalseTTrueMap(), _graph.sFalseTTrueMap()) { }
marci@768
   281
  };
marci@435
   282
marci@435
   283
//   template<typename Graph> 
marci@435
   284
//   std::ostream& 
marci@435
   285
//   operator<<(std::ostream& os, const typename stGraphWrapper<Graph>::Node& i) { 
marci@435
   286
//     os << "(node: " << typename Graph::Node(i) << " spec: " << i.spec <<")"; 
marci@435
   287
//     return os; 
marci@435
   288
//   }
marci@435
   289
//   template<typename Graph> 
marci@435
   290
//   std::ostream& 
marci@435
   291
//   operator<<(std::ostream& os, const typename stGraphWrapper<Graph>::Edge& i) { 
marci@435
   292
//     os << "(edge: " << typename Graph::Edge(i) << " spec: " << i.spec << 
marci@435
   293
//       " node: " << i.n << ")"; 
marci@435
   294
//     return os; 
marci@435
   295
//   }
marci@341
   296
marci@641
   297
  /// \brief A wrapper for adding extra nodes s and t to a bipartite graph
marci@641
   298
  /// and edges from s to each node of S and form each node of T to t.
marci@641
   299
  /// 
marci@641
   300
  /// A wrapper for adding extra nodes s and t to a bipartite graph
marci@641
   301
  /// and edges from s to each node of S and form each node of T to t.
marci@641
   302
  /// This class is very useful to reduce some matching or more
marci@641
   303
  /// generally, capacitataed b-matching problem to a flow problem.
marci@641
   304
  /// According to the bipartite graph concepts the bipartite 
marci@641
   305
  /// graph have to be oriented from S to T.
alpar@457
   306
  ///
marci@641
   307
  /// \author Marton Makai
marci@768
   308
  template<typename Graph, typename sIterableMap, typename tIterableMap>
marci@379
   309
  class stGraphWrapper : public GraphWrapper<Graph> {
marci@768
   310
  protected:    
marci@768
   311
    const sIterableMap* s_iterable_map;
marci@768
   312
    const tIterableMap* t_iterable_map;
marci@379
   313
  public:
marci@379
   314
    class Node; 
marci@381
   315
    friend class Node;
marci@379
   316
//GN, int
marci@768
   317
//0 normalis, 1 s, 2 t, ez az iteralasi sorrend, 
marci@379
   318
//es a vege a false azaz (invalid, 3)    
marci@379
   319
    class NodeIt;
marci@381
   320
    friend class NodeIt;
marci@379
   321
//GNI, int
marci@379
   322
    class Edge;
marci@381
   323
    friend class Edge;
marci@379
   324
//GE, int, GN
marci@379
   325
//0 normalis, 1 s->vmi, 2 vmi->t, ez a sorrend,
marci@379
   326
//invalid: (invalid, 3, invalid)
marci@379
   327
    class OutEdgeIt;
marci@381
   328
    friend class OutEdgeIt;
marci@379
   329
//GO, int, GNI
marci@379
   330
//normalis pontbol (first, 0, invalid), ..., (invalid, 2, vmi), ... (invalid, 3, invalid)
marci@379
   331
//s-bol (invalid, 1, first), ... (invalid, 3, invalid)
marci@379
   332
//t-bol (invalid, 3, invalid)
marci@379
   333
    class InEdgeIt;
marci@381
   334
    friend class InEdgeIt;
marci@379
   335
//GI, int, GNI
marci@379
   336
//normalis pontbol (first, 0, invalid), ..., (invalid, 1, vmi), ... (invalid, 3, invalid)
marci@379
   337
//s-be (invalid, 3, invalid)
marci@379
   338
//t-be (invalid, 2, first), ... (invalid, 3, invalid)
marci@379
   339
    class EdgeIt;
marci@381
   340
    friend class EdgeIt;
marci@379
   341
//(first, 0, invalid) ...
marci@379
   342
//(invalid, 1, vmi)
marci@379
   343
//(invalid, 2, vmi)
marci@379
   344
//invalid, 3, invalid)
marci@379
   345
    template <typename T> class NodeMap;
marci@510
   346
    template <typename T> class EdgeMap;
marci@341
   347
marci@379
   348
//    template <typename T> friend class NodeMap;
marci@379
   349
//    template <typename T> friend class EdgeMap;
marci@341
   350
marci@502
   351
    ///\todo FIXME ezt majd static-ra kell javitani
marci@379
   352
    const Node S_NODE;
marci@379
   353
    const Node T_NODE;
marci@341
   354
marci@379
   355
    static const bool S_CLASS=false;
marci@379
   356
    static const bool T_CLASS=true;
marci@341
   357
marci@768
   358
    // \bug not too nice constructor.
marci@768
   359
    stGraphWrapper(Graph& _graph, 
marci@768
   360
		   const sIterableMap& _s_iterable_map, 
marci@768
   361
		   const tIterableMap& _t_iterable_map) : 
marci@768
   362
      GraphWrapper<Graph>(_graph), 
marci@768
   363
      s_iterable_map(&_s_iterable_map), 
marci@768
   364
      t_iterable_map(&_t_iterable_map), 
marci@768
   365
      S_NODE(INVALID, 1), 
marci@768
   366
      T_NODE(INVALID, 2) { }
marci@341
   367
marci@435
   368
    
marci@435
   369
//    std::ostream& 
marci@435
   370
//    operator<<(std::ostream& os, const /*typename stGraphWrapper<Graph>::*/Node& i);
marci@435
   371
//    friend std::ostream& 
marci@435
   372
//    operator<<(std::ostream& os, const /*typename stGraphWrapper<Graph>::*/Node& i);
marci@435
   373
//    friend std::ostream& 
marci@435
   374
//    operator<<(std::ostream& os, const /*typename stGraphWrapper<Graph>::*/Edge& i);
marci@435
   375
marci@379
   376
    class Node : public Graph::Node {
marci@379
   377
    protected:
marci@379
   378
      friend class GraphWrapper<Graph>;
marci@768
   379
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@389
   380
      template <typename T> friend class NodeMap;
marci@380
   381
      friend class Edge;
marci@380
   382
      friend class OutEdgeIt;
marci@380
   383
      friend class InEdgeIt;
marci@380
   384
      friend class EdgeIt;
marci@379
   385
      int spec; 
marci@379
   386
    public:
marci@379
   387
      Node() { }
marci@379
   388
      Node(const typename Graph::Node& _n, int _spec=0) : 
marci@379
   389
	Graph::Node(_n), spec(_spec) { }
marci@379
   390
      Node(const Invalid& i) : Graph::Node(i), spec(3) { }
marci@379
   391
      friend bool operator==(const Node& u, const Node& v) { 
marci@379
   392
	return (u.spec==v.spec && 
marci@379
   393
		static_cast<typename Graph::Node>(u)==
marci@379
   394
		static_cast<typename Graph::Node>(v));
marci@379
   395
      } 
marci@379
   396
      friend bool operator!=(const Node& u, const Node& v) { 
marci@379
   397
	return (v.spec!=u.spec || 
marci@379
   398
		static_cast<typename Graph::Node>(u)!=
marci@379
   399
		static_cast<typename Graph::Node>(v));
marci@409
   400
      }
marci@435
   401
//      template<typename G> 
marci@435
   402
//      friend std::ostream& 
marci@435
   403
//      operator<<(std::ostream& os, const typename stGraphWrapper<G>::Node& i); 
marci@435
   404
      friend std::ostream& operator<< (std::ostream& os, const Node& i);
marci@379
   405
      int getSpec() const { return spec; }
marci@379
   406
    };
marci@409
   407
marci@379
   408
    class NodeIt { 
marci@379
   409
      friend class GraphWrapper<Graph>;
marci@768
   410
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@379
   411
      typename Graph::NodeIt n;
marci@379
   412
      int spec; 
marci@379
   413
     public:
marci@379
   414
      NodeIt() { }
marci@379
   415
      NodeIt(const typename Graph::NodeIt& _n, int _spec) : 
marci@379
   416
	n(_n), spec(_spec) { }
marci@379
   417
      NodeIt(const Invalid& i) : n(i), spec(3) { }
marci@768
   418
      NodeIt(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G) 
marci@768
   419
	: n(*(_G.graph)), spec(0) { 
marci@409
   420
	if (!_G.graph->valid(n)) spec=1;
marci@379
   421
      }
marci@379
   422
      operator Node() const { return Node(n, spec); }
marci@379
   423
    };
marci@409
   424
marci@379
   425
    class Edge : public Graph::Edge {
marci@379
   426
      friend class GraphWrapper<Graph>;
marci@768
   427
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@510
   428
      template <typename T> friend class EdgeMap;
marci@379
   429
      int spec;
marci@379
   430
      typename Graph::Node n;
marci@379
   431
    public:
marci@379
   432
      Edge() { }
marci@379
   433
      Edge(const typename Graph::Edge& _e, int _spec, 
marci@379
   434
	   const typename Graph::Node& _n) : 
marci@379
   435
	Graph::Edge(_e), spec(_spec), n(_n) { 
marci@379
   436
      }
marci@379
   437
      Edge(const Invalid& i) : Graph::Edge(i), spec(3), n(i) { }
marci@379
   438
      friend bool operator==(const Edge& u, const Edge& v) { 
marci@379
   439
	return (u.spec==v.spec && 
marci@379
   440
		static_cast<typename Graph::Edge>(u)==
marci@379
   441
		static_cast<typename Graph::Edge>(v) && 
marci@379
   442
		u.n==v.n);
marci@379
   443
      } 
marci@379
   444
      friend bool operator!=(const Edge& u, const Edge& v) { 
marci@379
   445
	return (v.spec!=u.spec || 
marci@379
   446
		static_cast<typename Graph::Edge>(u)!=
marci@379
   447
		static_cast<typename Graph::Edge>(v) || 
marci@379
   448
		u.n!=v.n);
marci@379
   449
      } 
marci@435
   450
//      template<typename G> 
marci@435
   451
//      friend std::ostream& 
marci@435
   452
//      operator<<(std::ostream& os, const typename stGraphWrapper<G>::Edge& i); 
marci@435
   453
      friend std::ostream& operator<< (std::ostream& os, const Edge& i);
marci@379
   454
      int getSpec() const { return spec; }
marci@510
   455
      typename Graph::Node getNode() const { return n; }
marci@379
   456
    };
marci@409
   457
marci@379
   458
    class OutEdgeIt { 
marci@379
   459
      friend class GraphWrapper<Graph>;
marci@768
   460
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@379
   461
      typename Graph::OutEdgeIt e;
marci@379
   462
      int spec;
marci@379
   463
      typename Graph::ClassNodeIt n;
marci@379
   464
    public:
marci@379
   465
      OutEdgeIt() { }
marci@379
   466
      OutEdgeIt(const typename Graph::OutEdgeIt& _e, int _spec, 
marci@379
   467
		const typename Graph::ClassNodeIt& _n) : 
marci@379
   468
	e(_e), spec(_spec), n(_n) { 
marci@379
   469
      }
marci@379
   470
      OutEdgeIt(const Invalid& i) : e(i), spec(3), n(i) { }
marci@768
   471
      OutEdgeIt(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G, 
marci@768
   472
		const Node& _n) {
marci@379
   473
	switch (_n.spec) {
marci@379
   474
	  case 0 : 
marci@381
   475
	    if (_G.graph->inSClass(_n)) { //S, van normalis kiel 
marci@379
   476
	      e=typename Graph::OutEdgeIt(*(_G.graph), 
marci@379
   477
					  typename Graph::Node(_n)); 
marci@379
   478
	      spec=0;
marci@379
   479
	      n=INVALID;
marci@379
   480
	      if (!_G.graph->valid(e)) spec=3;
marci@379
   481
	    } else { //T, specko kiel van
marci@379
   482
	      e=INVALID;
marci@379
   483
	      spec=2;
marci@379
   484
	      n=_n;
marci@379
   485
	    }
marci@379
   486
	    break;
marci@379
   487
	  case 1:
marci@379
   488
	    e=INVALID;
marci@379
   489
	    spec=1;
marci@379
   490
	    _G.graph->first(n, S_CLASS); //s->vmi;
marci@379
   491
	    if (!_G.graph->valid(n)) spec=3; //Ha S ures
marci@379
   492
	    break;
marci@379
   493
	  case 2:
marci@379
   494
	    e=INVALID;
marci@379
   495
	    spec=3;
marci@379
   496
	    n=INVALID;
marci@379
   497
	    break;
marci@379
   498
	}
marci@379
   499
      }
marci@379
   500
      operator Edge() const { return Edge(e, spec, n); }
marci@379
   501
    };
marci@409
   502
marci@379
   503
    class InEdgeIt { 
marci@379
   504
      friend class GraphWrapper<Graph>;
marci@768
   505
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@379
   506
      typename Graph::InEdgeIt e;
marci@379
   507
      int spec;
marci@379
   508
      typename Graph::ClassNodeIt n;
marci@379
   509
    public:
marci@379
   510
      InEdgeIt() { }
marci@379
   511
      InEdgeIt(const typename Graph::InEdgeIt& _e, int _spec, 
marci@379
   512
	       const typename Graph::ClassNodeIt& _n) : 
marci@379
   513
	e(_e), spec(_spec), n(_n) { 
marci@379
   514
      }
marci@379
   515
      InEdgeIt(const Invalid& i) : e(i), spec(3), n(i) { }
marci@768
   516
      InEdgeIt(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G, 
marci@768
   517
	       const Node& _n) {
marci@379
   518
	switch (_n.spec) {
marci@379
   519
	  case 0 : 
marci@381
   520
	    if (_G.graph->inTClass(_n)) { //T, van normalis beel 
marci@379
   521
	      e=typename Graph::InEdgeIt(*(_G.graph), 
marci@379
   522
					 typename Graph::Node(_n)); 
marci@379
   523
	      spec=0;
marci@379
   524
	      n=INVALID;
marci@379
   525
	      if (!_G.graph->valid(e)) spec=3;
marci@379
   526
	    } else { //S, specko beel van
marci@379
   527
	      e=INVALID;
marci@379
   528
	      spec=1;
marci@379
   529
	      n=_n;
marci@379
   530
	    }
marci@379
   531
	    break;
marci@379
   532
	  case 1:
marci@379
   533
	    e=INVALID;
marci@379
   534
	    spec=3;
marci@379
   535
	    n=INVALID;
marci@409
   536
	    break;
marci@379
   537
	  case 2:
marci@379
   538
	    e=INVALID;
marci@409
   539
	    spec=2;
marci@379
   540
	    _G.graph->first(n, T_CLASS); //vmi->t;
marci@379
   541
	    if (!_G.graph->valid(n)) spec=3; //Ha T ures
marci@379
   542
	    break;
marci@379
   543
	}
marci@379
   544
      }
marci@379
   545
      operator Edge() const { return Edge(e, spec, n); }
marci@379
   546
    };
marci@409
   547
marci@379
   548
    class EdgeIt { 
marci@379
   549
      friend class GraphWrapper<Graph>;
marci@768
   550
      friend class stGraphWrapper<Graph, sIterableMap, tIterableMap>;
marci@379
   551
      typename Graph::EdgeIt e;
marci@379
   552
      int spec;
marci@379
   553
      typename Graph::ClassNodeIt n;
marci@379
   554
    public:
marci@379
   555
      EdgeIt() { }
marci@379
   556
      EdgeIt(const typename Graph::EdgeIt& _e, int _spec, 
marci@379
   557
	     const typename Graph::ClassNodeIt& _n) : 
marci@379
   558
	e(_e), spec(_spec), n(_n) { }
marci@379
   559
      EdgeIt(const Invalid& i) : e(i), spec(3), n(i) { }
marci@768
   560
      EdgeIt(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G) : 
marci@379
   561
	e(*(_G.graph)), spec(0), n(INVALID) { 
marci@379
   562
	if (!_G.graph->valid(e)) {
marci@379
   563
	  spec=1;
marci@379
   564
	  _G.graph->first(n, S_CLASS);
marci@379
   565
	  if (!_G.graph->valid(n)) { //Ha S ures
marci@379
   566
	    spec=2;
marci@379
   567
	    _G.graph->first(n, T_CLASS);
marci@379
   568
	    if (!_G.graph->valid(n)) { //Ha T ures
marci@379
   569
	      spec=3;
marci@379
   570
	    }
marci@379
   571
	  }
marci@379
   572
	}
marci@379
   573
      }
marci@379
   574
      operator Edge() const { return Edge(e, spec, n); }
marci@379
   575
    };
marci@341
   576
   
marci@379
   577
    NodeIt& first(NodeIt& i) const { 
marci@379
   578
      i=NodeIt(*this); return i;
marci@379
   579
    }
marci@379
   580
    OutEdgeIt& first(OutEdgeIt& i, const Node& p) const { 
marci@379
   581
      i=OutEdgeIt(*this, p); return i;
marci@379
   582
    }
marci@379
   583
    InEdgeIt& first(InEdgeIt& i, const Node& p) const { 
marci@379
   584
      i=InEdgeIt(*this, p); return i;
marci@379
   585
    }
marci@379
   586
    EdgeIt& first(EdgeIt& i) const { 
marci@379
   587
      i=EdgeIt(*this); return i;
marci@379
   588
    }
marci@341
   589
marci@379
   590
    NodeIt& next(NodeIt& i) const { 
marci@379
   591
      switch (i.spec) {
marci@379
   592
	case 0:
marci@389
   593
	  this->graph->next(i.n);
marci@389
   594
	  if (!this->graph->valid(i.n)) {
marci@379
   595
	    i.spec=1;
marci@379
   596
	  }
marci@379
   597
	  break;
marci@379
   598
	case 1:
marci@379
   599
	  i.spec=2;
marci@379
   600
	  break;
marci@379
   601
	case 2:
marci@379
   602
	  i.spec=3;
marci@379
   603
	  break;
marci@379
   604
      }
marci@379
   605
      return i; 
marci@379
   606
    }
marci@379
   607
    OutEdgeIt& next(OutEdgeIt& i) const { 
marci@393
   608
      typename Graph::Node v;
marci@379
   609
      switch (i.spec) {
marci@379
   610
	case 0: //normal edge
marci@409
   611
	  v=this->graph->aNode(i.e);
marci@389
   612
	  this->graph->next(i.e);
marci@389
   613
	  if (!this->graph->valid(i.e)) { //Az igazi elek vegere ertunk
marci@389
   614
	    if (this->graph->inSClass(v)) { //S, nincs kiel
marci@379
   615
	      i.spec=3;
marci@379
   616
	      i.n=INVALID;
marci@379
   617
	    } else { //T, van kiel
marci@379
   618
	      i.spec=2; 
marci@379
   619
	      i.n=v;
marci@379
   620
	    }
marci@379
   621
	  }
marci@379
   622
	  break;
marci@379
   623
	case 1: //s->vmi
marci@389
   624
	  this->graph->next(i.n);
marci@389
   625
	  if (!this->graph->valid(i.n)) i.spec=3;
marci@379
   626
	  break;
marci@379
   627
	case 2: //vmi->t
marci@379
   628
	  i.spec=3;
marci@379
   629
	  i.n=INVALID;
marci@379
   630
	  break;
marci@379
   631
      }
marci@379
   632
      return i; 
marci@379
   633
    }
marci@379
   634
    InEdgeIt& next(InEdgeIt& i) const { 
marci@393
   635
      typename Graph::Node v;
marci@379
   636
      switch (i.spec) {
marci@379
   637
	case 0: //normal edge
marci@393
   638
	  v=this->graph->aNode(i.e);
marci@389
   639
	  this->graph->next(i.e);
marci@389
   640
	  if (!this->graph->valid(i.e)) { //Az igazi elek vegere ertunk
marci@389
   641
	    if (this->graph->inTClass(v)) { //S, nincs beel
marci@379
   642
	      i.spec=3;
marci@379
   643
	      i.n=INVALID;
marci@379
   644
	    } else { //S, van beel
marci@379
   645
	      i.spec=1; 
marci@379
   646
	      i.n=v;
marci@379
   647
	    }
marci@379
   648
	  }
marci@379
   649
	  break;
marci@379
   650
	case 1: //s->vmi
marci@379
   651
	  i.spec=3;
marci@379
   652
	  i.n=INVALID;
marci@379
   653
	  break;
marci@379
   654
	case 2: //vmi->t
marci@389
   655
	  this->graph->next(i.n);
marci@389
   656
	  if (!this->graph->valid(i.n)) i.spec=3;
marci@379
   657
	  break;
marci@379
   658
      }
marci@379
   659
      return i; 
marci@379
   660
    }
marci@341
   661
marci@379
   662
    EdgeIt& next(EdgeIt& i) const { 
marci@379
   663
      switch (i.spec) {
marci@379
   664
	case 0:
marci@389
   665
	  this->graph->next(i.e);
marci@389
   666
	  if (!this->graph->valid(i.e)) { 
marci@379
   667
	    i.spec=1;
marci@389
   668
	    this->graph->first(i.n, S_CLASS);
marci@389
   669
	    if (!this->graph->valid(i.n)) {
marci@379
   670
	      i.spec=2;
marci@389
   671
	      this->graph->first(i.n, T_CLASS);
marci@389
   672
	      if (!this->graph->valid(i.n)) i.spec=3;
marci@379
   673
	    }
marci@379
   674
	  }
marci@379
   675
	  break;
marci@379
   676
	case 1:
marci@389
   677
	  this->graph->next(i.n);
marci@389
   678
	  if (!this->graph->valid(i.n)) {
marci@379
   679
	    i.spec=2;
marci@389
   680
	    this->graph->first(i.n, T_CLASS);
marci@389
   681
	    if (!this->graph->valid(i.n)) i.spec=3;
marci@379
   682
	  }
marci@379
   683
	  break;
marci@379
   684
	case 2:
marci@389
   685
	  this->graph->next(i.n);
marci@389
   686
	  if (!this->graph->valid(i.n)) i.spec=3;
marci@379
   687
	  break;
marci@379
   688
      }
marci@379
   689
      return i; 
marci@379
   690
    }    
marci@341
   691
marci@379
   692
    Node tail(const Edge& e) const { 
marci@379
   693
      switch (e.spec) {
marci@393
   694
      case 0: 
marci@393
   695
	return Node(this->graph->tail(e));
marci@393
   696
	break;
marci@393
   697
      case 1:
marci@393
   698
	return S_NODE;
marci@393
   699
	break;
marci@393
   700
      case 2:
marci@393
   701
      default:
marci@393
   702
	return Node(e.n);
marci@393
   703
	break;
marci@379
   704
      }
marci@379
   705
    }
marci@379
   706
    Node head(const Edge& e) const { 
marci@379
   707
      switch (e.spec) {
marci@393
   708
      case 0: 
marci@393
   709
	return Node(this->graph->head(e));
marci@393
   710
	break;
marci@393
   711
      case 1:
marci@393
   712
	return Node(e.n);
marci@393
   713
	break;
marci@393
   714
      case 2:
marci@393
   715
      default:
marci@393
   716
	return T_NODE;
marci@393
   717
	break;
marci@379
   718
      }
marci@379
   719
    }
marci@341
   720
marci@379
   721
    bool valid(const Node& n) const { return (n.spec<3); }
marci@379
   722
    bool valid(const Edge& e) const { return (e.spec<3); }
marci@379
   723
marci@409
   724
    int nodeNum() const { return this->graph->nodeNum()+2; }
marci@409
   725
    int edgeNum() const { 
marci@409
   726
      return this->graph->edgeNum()+this->graph->nodeNum(); 
marci@409
   727
    }
marci@341
   728
  
marci@379
   729
    Node aNode(const OutEdgeIt& e) const { return tail(e); }
marci@379
   730
    Node aNode(const InEdgeIt& e) const { return head(e); }
marci@379
   731
    Node bNode(const OutEdgeIt& e) const { return head(e); }
marci@379
   732
    Node bNode(const InEdgeIt& e) const { return tail(e); }
marci@409
   733
marci@409
   734
    void addNode() const { }
marci@409
   735
    void addEdge() const { }
marci@409
   736
    
marci@389
   737
//    Node addNode() const { return Node(this->graph->addNode()); }
marci@379
   738
//    Edge addEdge(const Node& tail, const Node& head) const { 
marci@389
   739
//      return Edge(this->graph->addEdge(tail, head)); }
marci@341
   740
marci@389
   741
//    void erase(const Node& i) const { this->graph->erase(i); }
marci@389
   742
//    void erase(const Edge& i) const { this->graph->erase(i); }
marci@341
   743
  
marci@389
   744
//    void clear() const { this->graph->clear(); }
marci@341
   745
    
marci@389
   746
    template<typename T> class NodeMap : public GraphWrapper<Graph>::template NodeMap<T> { 
marci@389
   747
      typedef typename GraphWrapper<Graph>::template NodeMap<T> Parent;
marci@510
   748
    protected:
marci@379
   749
      T s_value, t_value;
marci@379
   750
    public:
marci@768
   751
      NodeMap(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G) : 
marci@768
   752
	Parent(_G), 
marci@768
   753
	s_value(), 
marci@768
   754
	t_value() { }
marci@768
   755
      NodeMap(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G, T a) 
marci@768
   756
	: Parent(_G, a), 
marci@768
   757
	  s_value(a), 
marci@768
   758
	  t_value(a) { }
marci@379
   759
      T operator[](const Node& n) const { 
marci@379
   760
	switch (n.spec) {
marci@393
   761
	case 0: 
marci@393
   762
	  return Parent::operator[](n);
marci@393
   763
	case 1:
marci@393
   764
	  return s_value;
marci@393
   765
	case 2: 
marci@393
   766
	default:
marci@393
   767
	  return t_value;
marci@379
   768
	}
marci@379
   769
      }
marci@379
   770
      void set(const Node& n, T t) { 
marci@379
   771
	switch (n.spec) {
marci@393
   772
	case 0: 
marci@393
   773
	  GraphWrapper<Graph>::template NodeMap<T>::set(n, t);
marci@393
   774
	  break;
marci@393
   775
	case 1:
marci@393
   776
	  s_value=t;
marci@393
   777
	  break;
marci@393
   778
	case 2:
marci@393
   779
	default:
marci@393
   780
	  t_value=t;
marci@393
   781
	  break;
marci@379
   782
	}
marci@379
   783
      }
marci@379
   784
    };
marci@341
   785
marci@510
   786
    /// This class is to wrap a node-map of \c Graph and two variables 
marci@510
   787
    /// storing values for \c S_NODE and \c T_NODE to a node-map of 
marci@768
   788
    /// stGraphWrapper<Graph, sIterableMap, tIterableMap>.
marci@510
   789
    template<typename NM> class NodeMapWrapper { 
marci@510
   790
    public:
marci@510
   791
      typedef Node KeyType;
marci@510
   792
      typedef typename NM::ValueType ValueType;
marci@510
   793
    protected:
marci@510
   794
      NM* nm;
marci@510
   795
      ValueType* s_value, t_value;
marci@510
   796
    public:
marci@510
   797
      NodeMapWrapper(NM& _nm, ValueType& _s_value, ValueType& _t_value) : 
marci@510
   798
	nm(&_nm), s_value(&_s_value), t_value(&_t_value) { }
marci@510
   799
      ValueType operator[](const Node& n) const { 
marci@510
   800
	switch (n.getSpec()) {
marci@510
   801
	case 0: 
marci@510
   802
	  return (*nm)[n];
marci@510
   803
	case 1:
marci@510
   804
	  return *s_value;
marci@510
   805
	case 2: 
marci@510
   806
	default:
marci@510
   807
	  return *t_value;
marci@510
   808
	}
marci@510
   809
      }
marci@510
   810
      void set(const Node& n, ValueType t) { 
marci@510
   811
	switch (n.getSpec()) {
marci@510
   812
	case 0: 
marci@510
   813
	  nm->set(n, t);
marci@510
   814
	  break;
marci@510
   815
	case 1:
marci@510
   816
	  *s_value=t;
marci@510
   817
	  break;
marci@510
   818
	case 2:
marci@510
   819
	default:
marci@510
   820
	  *t_value=t;
marci@510
   821
	  break;
marci@510
   822
	}
marci@510
   823
      }
marci@510
   824
    };
marci@510
   825
marci@510
   826
    template<typename T> 
marci@510
   827
    class EdgeMap : public GraphWrapper<Graph>::template EdgeMap<T> { 
marci@510
   828
      typedef typename GraphWrapper<Graph>::template EdgeMap<T> Parent;
marci@510
   829
    protected:
marci@389
   830
      typename GraphWrapper<Graph>::template NodeMap<T> node_value;
marci@379
   831
    public:
marci@768
   832
      EdgeMap(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G) 
marci@768
   833
	: Parent(_G), 
marci@768
   834
	  node_value(_G) { }
marci@768
   835
      EdgeMap(const stGraphWrapper<Graph, sIterableMap, tIterableMap>& _G, T a) 
marci@768
   836
	: Parent(_G, a), 
marci@768
   837
	  node_value(_G, a) { }
marci@379
   838
      T operator[](const Edge& e) const { 
marci@379
   839
	switch (e.spec) {
marci@393
   840
	case 0: 
marci@393
   841
	  return Parent::operator[](e);
marci@393
   842
	case 1:
marci@393
   843
	  return node_value[e.n];
marci@393
   844
	case 2:
marci@393
   845
	default:
marci@393
   846
	  return node_value[e.n];
marci@379
   847
	}
marci@379
   848
      }
marci@379
   849
      void set(const Edge& e, T t) { 
marci@379
   850
	switch (e.spec) {
marci@393
   851
	case 0: 
marci@409
   852
	  Parent::set(e, t);
marci@393
   853
	  break;
marci@393
   854
	case 1:
marci@393
   855
	  node_value.set(e.n, t);
marci@393
   856
	  break;
marci@393
   857
	case 2:
marci@393
   858
	default:
marci@393
   859
	  node_value.set(e.n, t);
marci@393
   860
	  break;
marci@379
   861
	}
marci@379
   862
      }
marci@379
   863
    };
marci@409
   864
marci@510
   865
    /// This class is to wrap an edge-map and a node-map of \c Graph 
marci@768
   866
    /// to an edge-map of stGraphWrapper<Graph, sIterableMap, tIterableMap>.
marci@510
   867
    template<typename EM, typename NM> 
marci@510
   868
    class EdgeMapWrapper {
marci@510
   869
    public: 
marci@510
   870
      typedef Edge KeyType;
marci@510
   871
      typedef typename EM::ValueType ValueType;
marci@510
   872
    protected:
marci@510
   873
      EM* em;
marci@510
   874
      NM* nm;
marci@510
   875
    public:
marci@510
   876
      EdgeMapWrapper(EM& _em, NM& _nm) : em(&_em), nm(&_nm) { }
marci@510
   877
      ValueType operator[](const Edge& e) const { 
marci@510
   878
	switch (e.getSpec()) {
marci@510
   879
	case 0: 
marci@510
   880
	  return (*em)[e];
marci@510
   881
	case 1:
marci@510
   882
	  return (*nm)[e.getNode()];
marci@510
   883
	case 2:
marci@510
   884
	default:
marci@510
   885
	  return (*nm)[e.getNode()];
marci@510
   886
	}
marci@510
   887
      }
marci@510
   888
      void set(const Edge& e, ValueType t) { 
marci@510
   889
	switch (e.getSpec()) {
marci@510
   890
	case 0: 
marci@510
   891
	  em->set(e, t);
marci@510
   892
	  break;
marci@510
   893
	case 1:
marci@510
   894
	  nm->set(e.getNode(), t);
marci@510
   895
	  break;
marci@510
   896
	case 2:
marci@510
   897
	default:
marci@510
   898
	  nm->set(e.getNode(), t);
marci@510
   899
	  break;
marci@510
   900
	}
marci@510
   901
      }
marci@510
   902
    };
marci@510
   903
marci@409
   904
marci@435
   905
//  template<typename G> 
marci@435
   906
    friend std::ostream& 
marci@435
   907
    operator<<(std::ostream& os, const /*typename stGraphWrapper<Graph>::*/Node& i) { 
marci@409
   908
      os << "(node: " << typename Graph::Node(i) << " spec: " << i.spec <<")"; 
marci@409
   909
      return os; 
marci@409
   910
    }
marci@435
   911
//  template<typename G> 
marci@435
   912
    friend std::ostream& 
marci@435
   913
    operator<<(std::ostream& os, const /*typename stGraphWrapper<Graph>::*/Edge& i) { 
marci@409
   914
      os << "(edge: " << typename Graph::Edge(i) << " spec: " << i.spec << 
marci@409
   915
	" node: " << i.n << ")"; 
marci@409
   916
      return os; 
marci@409
   917
    }
marci@409
   918
marci@379
   919
  };
marci@379
   920
alpar@406
   921
  ///@}
marci@341
   922
alpar@105
   923
} //namespace hugo
marci@76
   924
alpar@406
   925
marci@510
   926
#endif //HUGO_BIPARTITE_GRAPH_WRAPPER_H
marci@76
   927