COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/full_graph.h @ 2229:4dbb6dd2dd4b

Last change on this file since 2229:4dbb6dd2dd4b was 2223:590c1b663a27, checked in by Balazs Dezso, 18 years ago

Exporting interface to the Graph class
Some documentation improvements

File size: 21.1 KB
Line 
1/* -*- C++ -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_FULL_GRAPH_H
20#define LEMON_FULL_GRAPH_H
21
22#include <cmath>
23
24#include <lemon/bits/base_extender.h>
25#include <lemon/bits/graph_extender.h>
26
27#include <lemon/bits/invalid.h>
28#include <lemon/bits/utility.h>
29
30
31///\ingroup graphs
32///\file
33///\brief FullGraph and FullUGraph classes.
34
35
36namespace lemon {
37
38  class FullGraphBase {
39    int _nodeNum;
40    int _edgeNum;
41  public:
42
43    typedef FullGraphBase Graph;
44
45    class Node;
46    class Edge;
47
48  protected:
49
50    FullGraphBase() {}
51
52    void construct(int n) { _nodeNum = n; _edgeNum = n * n; }
53
54  public:
55   
56    typedef True NodeNumTag;
57    typedef True EdgeNumTag;
58
59    Node operator()(int index) const { return Node(index); }
60    int index(const Node& node) const { return node.id; }
61
62    Edge edge(const Node& u, const Node& v) const {
63      return Edge(*this, u.id, v.id);
64    }
65
66    int nodeNum() const { return _nodeNum; }
67    int edgeNum() const { return _edgeNum; }
68
69    int maxNodeId() const { return _nodeNum-1; }
70    int maxEdgeId() const { return _edgeNum-1; }
71
72    Node source(Edge e) const { return e.id % _nodeNum; }
73    Node target(Edge e) const { return e.id / _nodeNum; }
74
75
76    static int id(Node v) { return v.id; }
77    static int id(Edge e) { return e.id; }
78
79    static Node nodeFromId(int id) { return Node(id);}
80   
81    static Edge edgeFromId(int id) { return Edge(id);}
82
83    typedef True FindEdgeTag;
84
85    Edge findEdge(Node u,Node v, Edge prev = INVALID) const {
86      return prev.id == -1 ? Edge(*this, u.id, v.id) : INVALID;
87    }
88   
89     
90    class Node {
91      friend class FullGraphBase;
92
93    protected:
94      int id;
95      Node(int _id) : id(_id) {}
96    public:
97      Node() {}
98      Node (Invalid) : id(-1) {}
99      bool operator==(const Node node) const {return id == node.id;}
100      bool operator!=(const Node node) const {return id != node.id;}
101      bool operator<(const Node node) const {return id < node.id;}
102    };
103   
104
105
106    class Edge {
107      friend class FullGraphBase;
108     
109    protected:
110      int id;  // _nodeNum * target + source;
111
112      Edge(int _id) : id(_id) {}
113
114      Edge(const FullGraphBase& _graph, int source, int target)
115        : id(_graph._nodeNum * target+source) {}
116    public:
117      Edge() { }
118      Edge (Invalid) { id = -1; }
119      bool operator==(const Edge edge) const {return id == edge.id;}
120      bool operator!=(const Edge edge) const {return id != edge.id;}
121      bool operator<(const Edge edge) const {return id < edge.id;}
122    };
123
124    void first(Node& node) const {
125      node.id = _nodeNum-1;
126    }
127
128    static void next(Node& node) {
129      --node.id;
130    }
131
132    void first(Edge& edge) const {
133      edge.id = _edgeNum-1;
134    }
135
136    static void next(Edge& edge) {
137      --edge.id;
138    }
139
140    void firstOut(Edge& edge, const Node& node) const {
141      edge.id = _edgeNum + node.id - _nodeNum;
142    }
143
144    void nextOut(Edge& edge) const {
145      edge.id -= _nodeNum;
146      if (edge.id < 0) edge.id = -1;
147    }
148
149    void firstIn(Edge& edge, const Node& node) const {
150      edge.id = node.id * _nodeNum;
151    }
152   
153    void nextIn(Edge& edge) const {
154      ++edge.id;
155      if (edge.id % _nodeNum == 0) edge.id = -1;
156    }
157
158  };
159
160  typedef GraphExtender<FullGraphBase> ExtendedFullGraphBase;
161
162  /// \ingroup graphs
163  ///
164  /// \brief A full graph class.
165  ///
166  /// This is a simple and fast directed full graph implementation.
167  /// It is completely static, so you can neither add nor delete either
168  /// edges or nodes.
169  /// Thus it conforms to
170  /// the \ref concept::Graph "Graph" concept
171  /// \sa concept::Graph.
172  ///
173  /// \sa FullUGraph
174  ///
175  /// \author Alpar Juttner
176  class FullGraph : public ExtendedFullGraphBase {
177  public:
178
179    typedef ExtendedFullGraphBase Parent;
180
181    /// \brief Constructor
182    FullGraph() { construct(0); }
183
184    /// \brief Constructor
185    ///
186    FullGraph(int n) { construct(n); }
187
188    /// \brief Resize the graph
189    ///
190    /// Resize the graph. The function will fully destroy and build the graph.
191    /// This cause that the maps of the graph will reallocated
192    /// automatically and the previous values will be lost.
193    void resize(int n) {
194      Parent::getNotifier(Edge()).clear();
195      Parent::getNotifier(Node()).clear();
196      construct(n);
197      Parent::getNotifier(Node()).build();
198      Parent::getNotifier(Edge()).build();
199    }
200
201    /// \brief Returns the node with the given index.
202    ///
203    /// Returns the node with the given index. Because it is a
204    /// static size graph the node's of the graph can be indiced
205    /// by the range from 0 to \e nodeNum()-1 and the index of
206    /// the node can accessed by the \e index() member.
207    Node operator()(int index) const { return Parent::operator()(index); }
208
209    /// \brief Returns the index of the node.
210    ///
211    /// Returns the index of the node. Because it is a
212    /// static size graph the node's of the graph can be indiced
213    /// by the range from 0 to \e nodeNum()-1 and the index of
214    /// the node can accessed by the \e index() member.
215    int index(const Node& node) const { return Parent::index(node); }
216
217    /// \brief Returns the edge connects the given nodes.
218    ///
219    /// Returns the edge connects the given nodes.
220    Edge edge(const Node& u, const Node& v) const {
221      return Parent::edge(u, v);
222    }
223
224    /// \brief Number of nodes.
225    int nodeNum() const { return Parent::nodeNum(); }
226    /// \brief Number of edges.
227    int edgeNum() const { return Parent::edgeNum(); }
228  };
229
230
231  class FullUGraphBase {
232    int _nodeNum;
233    int _edgeNum;
234  public:
235
236    typedef FullUGraphBase Graph;
237
238    class Node;
239    class Edge;
240
241  protected:
242
243    FullUGraphBase() {}
244
245    void construct(int n) { _nodeNum = n; _edgeNum = n * (n - 1) / 2; }
246
247  public:
248
249
250    Node operator()(int index) const { return Node(index); }
251    int index(const Node& node) const { return node.id; }
252
253    Edge edge(const Node& u, const Node& v) const {
254      return Edge(u.id * (u.id - 1) / 2 + v.id);
255    }
256
257    typedef True NodeNumTag;
258    typedef True EdgeNumTag;
259
260    int nodeNum() const { return _nodeNum; }
261    int edgeNum() const { return _edgeNum; }
262
263    int maxNodeId() const { return _nodeNum-1; }
264    int maxEdgeId() const { return _edgeNum-1; }
265
266    static Node nodeFromId(int id) { return Node(id);}
267    static Edge edgeFromId(int id) { return Edge(id);}
268
269    Node source(Edge e) const {
270      /// \todo we may do it faster
271      return Node(((int)sqrt((double)(1 + 8 * e.id)) + 1) / 2);
272    }
273
274    Node target(Edge e) const {
275      int source = ((int)sqrt((double)(1 + 8 * e.id)) + 1) / 2;;
276      return Node(e.id - (source) * (source - 1) / 2);
277    }
278
279    static int id(Node v) { return v.id; }
280    static int id(Edge e) { return e.id; }
281
282    Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
283      if (prev.id != -1 || u.id <= v.id) return Edge(-1);
284      return Edge(u.id * (u.id - 1) / 2 + v.id);
285    }
286
287    typedef True FindEdgeTag;
288   
289     
290    class Node {
291      friend class FullUGraphBase;
292
293    protected:
294      int id;
295      Node(int _id) { id = _id;}
296    public:
297      Node() {}
298      Node (Invalid) { id = -1; }
299      bool operator==(const Node node) const {return id == node.id;}
300      bool operator!=(const Node node) const {return id != node.id;}
301      bool operator<(const Node node) const {return id < node.id;}
302    };
303   
304
305
306    class Edge {
307      friend class FullUGraphBase;
308     
309    protected:
310      int id;  // _nodeNum * target + source;
311
312      Edge(int _id) : id(_id) {}
313
314    public:
315      Edge() { }
316      Edge (Invalid) { id = -1; }
317      bool operator==(const Edge edge) const {return id == edge.id;}
318      bool operator!=(const Edge edge) const {return id != edge.id;}
319      bool operator<(const Edge edge) const {return id < edge.id;}
320    };
321
322    void first(Node& node) const {
323      node.id = _nodeNum - 1;
324    }
325
326    static void next(Node& node) {
327      --node.id;
328    }
329
330    void first(Edge& edge) const {
331      edge.id = _edgeNum - 1;
332    }
333
334    static void next(Edge& edge) {
335      --edge.id;
336    }
337
338    void firstOut(Edge& edge, const Node& node) const {     
339      int src = node.id;
340      int trg = 0;
341      edge.id = (trg < src ? src * (src - 1) / 2 + trg : -1);
342    }
343
344    /// \todo with specialized iterators we can make faster iterating
345    void nextOut(Edge& edge) const {
346      int src = source(edge).id;
347      int trg = target(edge).id;
348      ++trg;
349      edge.id = (trg < src ? src * (src - 1) / 2 + trg : -1);
350    }
351
352    void firstIn(Edge& edge, const Node& node) const {
353      int src = node.id + 1;
354      int trg = node.id;
355      edge.id = (src < _nodeNum ? src * (src - 1) / 2 + trg : -1);
356    }
357   
358    void nextIn(Edge& edge) const {
359      int src = source(edge).id;
360      int trg = target(edge).id;
361      ++src;
362      edge.id = (src < _nodeNum ? src * (src - 1) / 2 + trg : -1);
363    }
364
365  };
366
367  typedef UGraphExtender<UndirGraphExtender<FullUGraphBase> >
368  ExtendedFullUGraphBase;
369
370  /// \ingroup graphs
371  ///
372  /// \brief An undirected full graph class.
373  ///
374  /// This is a simple and fast undirected full graph implementation.
375  /// It is completely static, so you can neither add nor delete either
376  /// edges or nodes.
377  ///
378  /// The main difference beetween the \e FullGraph and \e FullUGraph class
379  /// is that this class conforms to the undirected graph concept and
380  /// it does not contain the loop edges.
381  ///
382  /// \sa FullGraph
383  ///
384  /// \author Balazs Dezso
385  class FullUGraph : public ExtendedFullUGraphBase {
386  public:
387
388    typedef ExtendedFullUGraphBase Parent;
389
390    /// \brief Constructor
391    FullUGraph() { construct(0); }
392
393    /// \brief Constructor
394    FullUGraph(int n) { construct(n); }
395
396    /// \brief Resize the graph
397    ///
398    /// Resize the graph. The function will fully destroy and build the graph.
399    /// This cause that the maps of the graph will reallocated
400    /// automatically and the previous values will be lost.
401    void resize(int n) {
402      Parent::getNotifier(Edge()).clear();
403      Parent::getNotifier(UEdge()).clear();
404      Parent::getNotifier(Node()).clear();
405      construct(n);
406      Parent::getNotifier(Node()).build();
407      Parent::getNotifier(UEdge()).build();
408      Parent::getNotifier(Edge()).build();
409    }
410
411    /// \brief Returns the node with the given index.
412    ///
413    /// Returns the node with the given index. Because it is a
414    /// static size graph the node's of the graph can be indiced
415    /// by the range from 0 to \e nodeNum()-1 and the index of
416    /// the node can accessed by the \e index() member.
417    Node operator()(int index) const { return Parent::operator()(index); }
418
419    /// \brief Returns the index of the node.
420    ///
421    /// Returns the index of the node. Because it is a
422    /// static size graph the node's of the graph can be indiced
423    /// by the range from 0 to \e nodeNum()-1 and the index of
424    /// the node can accessed by the \e index() member.
425    int index(const Node& node) const { return Parent::index(node); }
426
427    /// \brief Number of nodes.
428    int nodeNum() const { return Parent::nodeNum(); }
429    /// \brief Number of edges.
430    int edgeNum() const { return Parent::edgeNum(); }
431    /// \brief Number of undirected edges.
432    int uEdgeNum() const { return Parent::uEdgeNum(); }
433
434    /// \brief Returns the edge connects the given nodes.
435    ///
436    /// Returns the edge connects the given nodes.
437    Edge edge(const Node& u, const Node& v) const {
438      if (Parent::index(u) > Parent::index(v)) {
439        return Parent::direct(Parent::edge(u, v), true);
440      } else if (Parent::index(u) == Parent::index(v)) {
441        return INVALID;
442      } else {
443        return Parent::direct(Parent::edge(v, u), false);
444      }
445    }
446
447    /// \brief Returns the undirected edge connects the given nodes.
448    ///
449    /// Returns the undirected edge connects the given nodes.
450    UEdge uEdge(const Node& u, const Node& v) const {
451      if (Parent::index(u) > Parent::index(v)) {
452        return Parent::edge(u, v);
453      } else if (Parent::index(u) == Parent::index(v)) {
454        return INVALID;
455      } else {
456        return Parent::edge(v, u);
457      }
458    }
459  };
460
461
462  class FullBpUGraphBase {
463  protected:
464
465    int _aNodeNum;
466    int _bNodeNum;
467
468    int _edgeNum;
469
470  protected:
471
472    FullBpUGraphBase() {}
473
474    void construct(int aNodeNum, int bNodeNum) {
475      _aNodeNum = aNodeNum;
476      _bNodeNum = bNodeNum;
477      _edgeNum = aNodeNum * bNodeNum;
478    }
479
480  public:
481
482    class NodeSetError : public LogicError {
483    public:
484      virtual const char* what() const throw() {
485        return "lemon::FullBpUGraph::NodeSetError";
486      }
487    };
488 
489    class Node {
490      friend class FullBpUGraphBase;
491    protected:
492      int id;
493
494      Node(int _id) : id(_id) {}
495    public:
496      Node() {}
497      Node(Invalid) { id = -1; }
498      bool operator==(const Node i) const {return id==i.id;}
499      bool operator!=(const Node i) const {return id!=i.id;}
500      bool operator<(const Node i) const {return id<i.id;}
501    };
502
503    class UEdge {
504      friend class FullBpUGraphBase;
505    protected:
506      int id;
507
508      UEdge(int _id) { id = _id;}
509    public:
510      UEdge() {}
511      UEdge (Invalid) { id = -1; }
512      bool operator==(const UEdge i) const {return id==i.id;}
513      bool operator!=(const UEdge i) const {return id!=i.id;}
514      bool operator<(const UEdge i) const {return id<i.id;}
515    };
516
517    Node aNode(int index) const { return Node(index << 1); }
518    Node bNode(int index) const { return Node((index << 1) + 1); }
519
520    int aNodeIndex(const Node& node) const { return node.id >> 1; }
521    int bNodeIndex(const Node& node) const { return node.id >> 1; }
522
523    UEdge uEdge(const Node& u, const Node& v) const {
524      if (((u.id ^ v.id) & 1) != 1) {
525        return UEdge(-1);
526      } else if ((u.id & 1) == 0) {
527        return UEdge((u.id >> 1) * _bNodeNum + (v.id >> 1));
528      } else {
529        return UEdge((v.id >> 1) * _bNodeNum + (u.id >> 1));
530      }
531    }
532
533    void firstANode(Node& node) const {
534      node.id = 2 * _aNodeNum - 2;
535      if (node.id < 0) node.id = -1;
536    }
537    void nextANode(Node& node) const {
538      node.id -= 2;
539      if (node.id < 0) node.id = -1;
540    }
541
542    void firstBNode(Node& node) const {
543      node.id = 2 * _bNodeNum - 1;
544    }
545    void nextBNode(Node& node) const {
546      node.id -= 2;
547    }
548
549    void first(Node& node) const {
550      if (_aNodeNum > 0) {
551        node.id = 2 * _aNodeNum - 2;
552      } else {
553        node.id = 2 * _bNodeNum - 1;
554      }
555    }
556    void next(Node& node) const {
557      node.id -= 2;
558      if (node.id == -2) {
559        node.id = 2 * _bNodeNum - 1;
560      }
561    }
562 
563    void first(UEdge& edge) const {
564      edge.id = _edgeNum - 1;
565    }
566    void next(UEdge& edge) const {
567      --edge.id;
568    }
569
570    void firstFromANode(UEdge& edge, const Node& node) const {
571      LEMON_ASSERT((node.id & 1) == 0, NodeSetError());
572      edge.id = (node.id >> 1) * _bNodeNum;
573    }
574    void nextFromANode(UEdge& edge) const {
575      ++(edge.id);
576      if (edge.id % _bNodeNum == 0) edge.id = -1;
577    }
578
579    void firstFromBNode(UEdge& edge, const Node& node) const {
580      LEMON_ASSERT((node.id & 1) == 1, NodeSetError());
581      edge.id = (node.id >> 1);
582    }
583    void nextFromBNode(UEdge& edge) const {
584      edge.id += _bNodeNum;
585      if (edge.id >= _edgeNum) edge.id = -1;
586    }
587
588    static int id(const Node& node) {
589      return node.id;
590    }
591    static Node nodeFromId(int id) {
592      return Node(id);
593    }
594    int maxNodeId() const {
595      return _aNodeNum > _bNodeNum ?
596        _aNodeNum * 2 - 2 : _bNodeNum * 2 - 1;
597    }
598 
599    static int id(const UEdge& edge) {
600      return edge.id;
601    }
602    static UEdge uEdgeFromId(int id) {
603      return UEdge(id);
604    }
605    int maxUEdgeId() const {
606      return _edgeNum - 1;
607    }
608 
609    static int aNodeId(const Node& node) {
610      return node.id >> 1;
611    }
612    static Node fromANodeId(int id) {
613      return Node(id << 1);
614    }
615    int maxANodeId() const {
616      return _aNodeNum;
617    }
618
619    static int bNodeId(const Node& node) {
620      return node.id >> 1;
621    }
622    static Node fromBNodeId(int id) {
623      return Node((id << 1) + 1);
624    }
625    int maxBNodeId() const {
626      return _bNodeNum;
627    }
628
629    Node aNode(const UEdge& edge) const {
630      return Node((edge.id / _bNodeNum) << 1);
631    }
632    Node bNode(const UEdge& edge) const {
633      return Node(((edge.id % _bNodeNum) << 1) + 1);
634    }
635
636    static bool aNode(const Node& node) {
637      return (node.id & 1) == 0;
638    }
639
640    static bool bNode(const Node& node) {
641      return (node.id & 1) == 1;
642    }
643
644
645    typedef True NodeNumTag;
646    int nodeNum() const { return _aNodeNum + _bNodeNum; }
647    int aNodeNum() const { return _aNodeNum; }
648    int bNodeNum() const { return _bNodeNum; }
649
650    typedef True EdgeNumTag;
651    int uEdgeNum() const { return _edgeNum; }
652
653
654    typedef True FindEdgeTag;
655    UEdge findUEdge(Node u, Node v, UEdge prev = INVALID) const {
656      if (prev.id != -1 || ((u.id ^ v.id) & 1) != 1) {
657        return UEdge(-1);
658      } else if ((u.id & 1) == 0) {
659        return UEdge((u.id >> 1) * _bNodeNum + (v.id >> 1));
660      } else {
661        return UEdge((v.id >> 1) * _bNodeNum + (u.id >> 1));
662      }
663    }
664
665  };
666
667
668  typedef BpUGraphExtender<FullBpUGraphBase> ExtendedFullBpUGraphBase;
669
670
671  /// \ingroup graphs
672  ///
673  /// \brief An undirected full bipartite graph class.
674  ///
675  /// This is a simple and fast bipartite undirected full graph implementation.
676  /// It is completely static, so you can neither add nor delete either
677  /// edges or nodes.
678  ///
679  /// \author Balazs Dezso
680  class FullBpUGraph :
681    public ExtendedFullBpUGraphBase {
682  public:
683
684    typedef ExtendedFullBpUGraphBase Parent;
685
686    FullBpUGraph() {
687      Parent::construct(0, 0);
688    }
689
690    FullBpUGraph(int aNodeNum, int bNodeNum) {
691      Parent::construct(aNodeNum, bNodeNum);
692    }
693
694    /// \brief Resize the graph
695    ///
696    /// Resize the graph
697    void resize(int n, int m) {
698      Parent::getNotifier(Edge()).clear();
699      Parent::getNotifier(UEdge()).clear();
700      Parent::getNotifier(Node()).clear();
701      Parent::getNotifier(ANode()).clear();
702      Parent::getNotifier(BNode()).clear();
703      construct(n, m);
704      Parent::getNotifier(ANode()).build();
705      Parent::getNotifier(BNode()).build();
706      Parent::getNotifier(Node()).build();
707      Parent::getNotifier(UEdge()).build();
708      Parent::getNotifier(Edge()).build();
709    }
710
711    /// \brief Number of nodes.
712    int nodeNum() const { return Parent::nodeNum(); }
713    /// \brief Number of A-nodes.
714    int aNodeNum() const { return Parent::aNodeNum(); }
715    /// \brief Number of B-nodes.
716    int bNodeNum() const { return Parent::bNodeNum(); }
717    /// \brief Number of edges.
718    int edgeNum() const { return Parent::edgeNum(); }
719    /// \brief Number of undirected edges.
720    int uEdgeNum() const { return Parent::uEdgeNum(); }
721
722
723    using Parent::aNode;
724    using Parent::bNode;
725
726    /// \brief Returns the A-node with the given index.
727    ///
728    /// Returns the A-node with the given index. Because it is a
729    /// static size graph the node's of the graph can be indiced
730    /// by the range from 0 to \e aNodeNum()-1 and the index of
731    /// the node can accessed by the \e aNodeIndex() member.
732    Node aNode(int index) const { return Parent::aNode(index); }
733
734    /// \brief Returns the B-node with the given index.
735    ///
736    /// Returns the B-node with the given index. Because it is a
737    /// static size graph the node's of the graph can be indiced
738    /// by the range from 0 to \e bNodeNum()-1 and the index of
739    /// the node can accessed by the \e bNodeIndex() member.
740    Node bNode(int index) const { return Parent::bNode(index); }
741
742    /// \brief Returns the index of the A-node.
743    ///
744    /// Returns the index of the A-node. Because it is a
745    /// static size graph the node's of the graph can be indiced
746    /// by the range from 0 to \e aNodeNum()-1 and the index of
747    /// the node can accessed by the \e aNodeIndex() member.
748    int aNodeIndex(const Node& node) const { return Parent::aNodeIndex(node); }
749
750    /// \brief Returns the index of the B-node.
751    ///
752    /// Returns the index of the B-node. Because it is a
753    /// static size graph the node's of the graph can be indiced
754    /// by the range from 0 to \e bNodeNum()-1 and the index of
755    /// the node can accessed by the \e bNodeIndex() member.
756    int bNodeIndex(const Node& node) const { return Parent::bNodeIndex(node); }
757
758    /// \brief Returns the edge connects the given nodes.
759    ///
760    /// Returns the edge connects the given nodes.
761    Edge edge(const Node& u, const Node& v) const {
762      UEdge uedge = Parent::uEdge(u, v);
763      if (uedge != INVALID) {
764        return Parent::direct(uedge, Parent::aNode(u));
765      } else {
766        return INVALID;
767      }
768    }
769
770    /// \brief Returns the undirected edge connects the given nodes.
771    ///
772    /// Returns the undirected edge connects the given nodes.
773    UEdge uEdge(const Node& u, const Node& v) const {
774      return Parent::uEdge(u, v);
775    }
776  };
777
778} //namespace lemon
779
780
781#endif //LEMON_FULL_GRAPH_H
Note: See TracBrowser for help on using the repository browser.