src/work/marci/graph_concept.h
author deba
Wed, 08 Sep 2004 12:06:45 +0000 (2004-09-08)
changeset 822 88226d9fe821
parent 651 a56e043aeab1
child 826 056fbb112b30
permissions -rw-r--r--
The MapFactories have been removed from the code because
if we use macros then they increases only the complexity.

The pair iterators of the maps are separeted from the maps.

Some macros and comments has been changed.
marci@325
     1
// -*- c++ -*-
marci@325
     2
#ifndef HUGO_GRAPH_H
marci@325
     3
#define HUGO_GRAPH_H
marci@325
     4
marci@325
     5
///\file
marci@651
     6
///\brief Declaration of GraphConcept.
marci@325
     7
marci@651
     8
#include <hugo/invalid.h>
marci@325
     9
marci@325
    10
namespace hugo {
marci@325
    11
marci@651
    12
  /// @defgroup empty_graph The GraphConcept class
marci@332
    13
  /// @{
marci@325
    14
marci@325
    15
  /// An empty graph class.
marci@325
    16
  
marci@325
    17
  /// This class provides all the common features of a graph structure,
marci@325
    18
  /// however completely without implementations and real data structures
marci@325
    19
  /// behind the interface.
marci@325
    20
  /// All graph algorithms should compile with this class, but it will not
marci@325
    21
  /// run properly, of course.
marci@325
    22
  ///
marci@325
    23
  /// It can be used for checking the interface compatibility,
marci@325
    24
  /// or it can serve as a skeleton of a new graph structure.
marci@325
    25
  /// 
marci@325
    26
  /// Also, you will find here the full documentation of a certain graph
marci@325
    27
  /// feature, the documentation of a real graph imlementation
marci@325
    28
  /// like @ref ListGraph or
marci@325
    29
  /// @ref SmartGraph will just refer to this structure.
marci@651
    30
  class GraphConcept
marci@325
    31
  {
marci@325
    32
  public:
marci@325
    33
    /// Defalult constructor.
marci@651
    34
    GraphConcept() { }
marci@325
    35
marci@651
    36
    /// \brief Copy consructor.
marci@651
    37
    /// 
marci@651
    38
    /// \todo It is not clear, what we expect from a copy constructor.
marci@651
    39
    /// E.g. How to assign the nodes/edges to each other? What about maps?
marci@651
    40
    GraphConcept(const GraphConcept&) { }
marci@325
    41
marci@651
    42
    /// \brief The base type of the node iterators.
marci@651
    43
    ///
marci@325
    44
    /// This is the base type of each node iterators,
marci@325
    45
    /// thus each kind of node iterator will convert to this.
marci@651
    46
    /// Sometimes it is said to be a trivial iterator.
marci@325
    47
    class Node {
marci@325
    48
    public:
marci@325
    49
      /// @warning The default constructor sets the iterator
marci@325
    50
      /// to an undefined value.
marci@651
    51
      Node() { }   //FIXME
marci@325
    52
marci@651
    53
      // /// Copy constructor.
marci@651
    54
      // Node(const Node&) { }
marci@651
    55
marci@651
    56
      /// \brief Invalid constructor \& conversion.
marci@651
    57
      /// 
marci@325
    58
      /// This constructor initializes the iterator to be invalid.
marci@325
    59
      /// \sa Invalid for more details.
marci@651
    60
      Node(const Invalid&) { }
marci@651
    61
      
marci@325
    62
      /// Two iterators are equal if and only if they point to the
marci@325
    63
      /// same object or both are invalid.
marci@325
    64
      bool operator==(Node n) const { return true; }
marci@325
    65
marci@325
    66
      /// \sa \ref operator==(Node n)
marci@325
    67
      ///
marci@325
    68
      bool operator!=(Node n) const { return true; }
marci@325
    69
marci@325
    70
      bool operator<(Node n) const { return true; }
marci@325
    71
    };
marci@325
    72
    
marci@325
    73
    /// The base type of the edge iterators.
marci@325
    74
    class Edge {
marci@325
    75
    public:
marci@325
    76
      /// @warning The default constructor sets the iterator
marci@325
    77
      /// to an undefined value.
marci@651
    78
      Edge() { }   //FIXME
marci@651
    79
marci@651
    80
      // /// Copy constructor.
marci@651
    81
      // Edge(const Edge&) { }
marci@651
    82
marci@325
    83
      /// Initialize the iterator to be invalid
marci@651
    84
      Edge(const Invalid&) { }
marci@325
    85
      /// Two iterators are equal if and only if they point to the
marci@325
    86
      /// same object or both are invalid.
marci@325
    87
      bool operator==(Edge n) const { return true; }
marci@325
    88
      bool operator!=(Edge n) const { return true; }
marci@325
    89
      bool operator<(Edge n) const { return true; }
marci@325
    90
    };
marci@325
    91
    
marci@325
    92
    //  class SymEdgeIt : public Edge {};
marci@325
    93
marci@325
    94
marci@325
    95
    //  SymEdgeIt &first(SymEdgeIt &, Node) const { return i;}
marci@325
    96
marci@325
    97
//     Node getNext(Node) const {}
marci@325
    98
//     InEdgeIt getNext(InEdgeIt) const {}
marci@325
    99
//     OutEdgeIt getNext(OutEdgeIt) const {}
marci@325
   100
//     //SymEdgeIt getNext(SymEdgeIt) const {}
marci@325
   101
//     EdgeIt getNext(EdgeIt) const {}
marci@325
   102
marci@325
   103
    //SymEdgeIt &next(SymEdgeIt &) const {}
marci@325
   104
marci@651
   105
marci@651
   106
    /// Gives back the head node of an edge.
marci@651
   107
    Node head(const Edge&) const { return INVALID; }
marci@651
   108
    /// Gives back the tail node of an edge.
marci@651
   109
    Node tail(const Edge&) const { return INVALID; }
marci@325
   110
  
marci@325
   111
    //   Node aNode(SymEdgeIt) const {}
marci@325
   112
    //   Node bNode(SymEdgeIt) const {}
marci@325
   113
marci@651
   114
    /// \brief Checks if a node iterator is valid
marci@651
   115
    /// 
marci@651
   116
    /// \todo Maybe, it would be better if iterator converted to
marci@651
   117
    /// bool directly, as Jacint prefers.
marci@651
   118
    bool valid(const Node&) const { return true; }
marci@651
   119
    /// \brief Checks if an edge iterator is valid
marci@651
   120
    /// 
marci@651
   121
    /// \todo Maybe, it would be better if iterator converted to
marci@651
   122
    /// bool directly, as Jacint prefers.
marci@651
   123
    bool valid(const Edge&) const { return true; }
marci@325
   124
marci@651
   125
    /// \brief Gives back the \e id of a node.
marci@651
   126
    /// 
marci@651
   127
    /// \warning Not all graph structures provide this feature.
marci@325
   128
    ///
marci@651
   129
    int id(const Node&) const { return 0; }
marci@651
   130
    /// \brief Gives back the \e id of an edge.
marci@325
   131
    ///
marci@651
   132
    /// \warning Not all graph structures provide this feature.
marci@651
   133
    ///
marci@651
   134
    int id(const Edge&) const { return 0; }
marci@325
   135
marci@325
   136
    //void setInvalid(Node &) const {};
marci@325
   137
    //void setInvalid(Edge &) const {};
marci@325
   138
  
marci@651
   139
    /// \brief Add a new node to the graph.
marci@651
   140
    ///
marci@325
   141
    /// \return the new node.
marci@651
   142
    Node addNode() { return INVALID; }
marci@651
   143
    /// \brief Add a new edge to the graph.
marci@325
   144
    ///
marci@651
   145
    /// Add a new edge to the graph with tail node \c tail
marci@651
   146
    /// and head node \c head.
marci@651
   147
    /// \return the new edge.
marci@651
   148
    Edge addEdge(const Node& tail, const Node& head) { return INVALID; }
marci@325
   149
    
marci@651
   150
    /// \brief Resets the graph.
marci@651
   151
    /// 
marci@325
   152
    /// This function deletes all edges and nodes of the graph.
marci@325
   153
    /// It also frees the memory allocated to store them.
marci@651
   154
    /// \todo What happens with the maps?
marci@651
   155
    void clear() { }
marci@325
   156
marci@651
   157
    /// Read/write/reference map of the nodes to type \c T.
marci@325
   158
marci@651
   159
    /// Read/write/reference map of the nodes to type \c T.
marci@651
   160
    /// \sa MemoryMapConcept
marci@325
   161
    /// \todo We may need copy constructor
marci@325
   162
    /// \todo We may need conversion from other nodetype
marci@325
   163
    /// \todo We may need operator=
marci@325
   164
    /// \warning Making maps that can handle bool type (NodeMap<bool>)
marci@325
   165
    /// needs extra attention!
marci@325
   166
marci@325
   167
    template<class T> class NodeMap
marci@325
   168
    {
marci@325
   169
    public:
marci@325
   170
      typedef T ValueType;
marci@325
   171
      typedef Node KeyType;
marci@325
   172
marci@651
   173
      NodeMap(const GraphConcept& g) { }
marci@651
   174
      NodeMap(const GraphConcept& g, T t) { }
marci@325
   175
marci@651
   176
      template<typename TT> NodeMap(const NodeMap<TT>& m) { }
marci@325
   177
marci@325
   178
      /// Sets the value of a node.
marci@325
   179
marci@325
   180
      /// Sets the value associated with node \c i to the value \c t.
marci@325
   181
      ///
marci@325
   182
      void set(Node i, T t) {}
marci@325
   183
      /// Gets the value of a node.
marci@325
   184
      T get(Node i) const {return *(T*)0;}  //FIXME: Is it necessary
marci@325
   185
      T &operator[](Node i) {return *(T*)0;}
marci@325
   186
      const T &operator[](Node i) const {return *(T*)0;}
marci@325
   187
marci@325
   188
      /// Updates the map if the graph has been changed
marci@325
   189
marci@325
   190
      /// \todo Do we need this?
marci@325
   191
      ///
marci@651
   192
      void update() { }
marci@651
   193
      //void update(T a) { }   //FIXME: Is it necessary
marci@325
   194
    };
marci@325
   195
marci@325
   196
    ///Read/write/reference map of the edges to type \c T.
marci@325
   197
marci@651
   198
    /// Read/write/reference map of the edges to type \c T.
marci@651
   199
    /// It behaves exactly in the same way as \ref NodeMap.
marci@325
   200
    /// \sa NodeMap
marci@651
   201
    /// \sa MemoryMapConcept
marci@325
   202
    /// \todo We may need copy constructor
marci@325
   203
    /// \todo We may need conversion from other edgetype
marci@325
   204
    /// \todo We may need operator=
marci@325
   205
    template<class T> class EdgeMap
marci@325
   206
    {
marci@325
   207
    public:
marci@325
   208
      typedef T ValueType;
marci@325
   209
      typedef Edge KeyType;
marci@325
   210
marci@651
   211
      EdgeMap(const GraphConcept& g) {}
marci@651
   212
      EdgeMap(const GraphConcept& g, T t) {}
marci@325
   213
    
marci@325
   214
      void set(Edge i, T t) {}
marci@325
   215
      T get(Edge i) const {return *(T*)0;}
marci@325
   216
      T &operator[](Edge i) {return *(T*)0;}
marci@325
   217
    
marci@651
   218
      void update() { }
marci@651
   219
      //void update(T a) { }   //FIXME: Is it necessary
marci@325
   220
    };
marci@325
   221
  };
marci@325
   222
marci@651
   223
marci@651
   224
  /// \brief Node-iterable graph concept.
marci@325
   225
  ///
marci@651
   226
  /// A graph class which provides functions to 
marci@651
   227
  /// iterate on its nodes.
marci@651
   228
  class NodeIterableGraphConcept : virtual public GraphConcept
marci@334
   229
  {
marci@334
   230
  public:
marci@334
   231
marci@651
   232
    /// \brief This iterator goes trough the nodes of the graph.
marci@651
   233
    ///
marci@651
   234
    /// This iterator goes trough the \e nodes of the graph.
marci@651
   235
    /// Its usage is quite simple, for example you can count the number
marci@651
   236
    /// of nodes in graph \c g of type \c Graph as follows.
marci@651
   237
    /// \code
marci@651
   238
    /// int count=0;
marci@651
   239
    /// for(Graph::NodeIt n(g); g.valid(n); g.next(n)) ++count;
marci@651
   240
    /// \endcode
marci@651
   241
    class NodeIt : public Node {
marci@651
   242
    public:
marci@651
   243
      /// @warning The default constructor sets the iterator.
marci@651
   244
      /// to an undefined value.
marci@651
   245
      NodeIt() { }
marci@651
   246
      // /// Copy constructor
marci@651
   247
      //NodeIt(const NodeIt& n) { }
marci@651
   248
      /// Initialize the iterator to be invalid.
marci@651
   249
      NodeIt(const Invalid&) { }
marci@651
   250
      /// \brief This constructor sets the iterator to first node.
marci@651
   251
      ///
marci@651
   252
      /// This constructor set the iterator to the first 
marci@651
   253
      /// node of the graph \c g.
marci@651
   254
      ///
marci@651
   255
      ///@param g the graph
marci@651
   256
      NodeIt(const GraphConcept& g) { }
marci@651
   257
    };
marci@334
   258
marci@651
   259
    /// The first node.
marci@651
   260
    NodeIt &first(NodeIt &i) const { return i; }
marci@651
   261
marci@651
   262
    /// Go to the next node.
marci@651
   263
    NodeIt &next(NodeIt &i) const { return i; }
marci@651
   264
  };
marci@651
   265
marci@651
   266
marci@651
   267
  /// \brief Edge-iterable graph concept.
marci@651
   268
  ///
marci@651
   269
  /// A graph class which provides functions to 
marci@651
   270
  /// iterate on its edges.
marci@651
   271
  class EdgeIterableGraphConcept : virtual public GraphConcept
marci@651
   272
  {
marci@651
   273
  public:
marci@651
   274
marci@651
   275
    /// \brief This iterator goes trough the edges of the graph.
marci@651
   276
    ///
marci@651
   277
    /// This iterator goes trough the \e edges of the graph.
marci@651
   278
    /// Its usage is quite simple, for example you can count the number
marci@651
   279
    /// of edges in graph \c g of type \c Graph as follows.
marci@651
   280
    /// \code
marci@651
   281
    /// int count=0;
marci@651
   282
    /// for(Graph::EdgeIt e(g); g.valid(e); g.next(e)) ++count;
marci@651
   283
    /// \endcode
marci@651
   284
    class EdgeIt : public Edge {
marci@651
   285
    public:
marci@651
   286
      /// @warning The default constructor sets the iterator.
marci@651
   287
      /// to an undefined value.
marci@651
   288
      EdgeIt() { }
marci@651
   289
      // /// Copy constructor
marci@651
   290
      // EdgeIt(const EdgeIt&) { }
marci@651
   291
      /// Initialize the iterator to be invalid.
marci@651
   292
      EdgeIt(const Invalid&) { }
marci@651
   293
      /// \brief This constructor sets the iterator to first edge.
marci@651
   294
      ///
marci@651
   295
      /// This constructor set the iterator to the first 
marci@651
   296
      /// edge of the graph \c g.
marci@651
   297
      ///
marci@651
   298
      ///@param g the graph
marci@651
   299
      EdgeIt(const GraphConcept& g) { }
marci@651
   300
    };
marci@651
   301
marci@651
   302
    /// The first edge.
marci@651
   303
    EdgeIt &first(EdgeIt &i) const { return i; }
marci@651
   304
marci@651
   305
    /// Go to the next edge.
marci@651
   306
    EdgeIt &next(EdgeIt &i) const { return i; }
marci@651
   307
  };
marci@651
   308
marci@651
   309
marci@651
   310
  /// \brief Out-edge-iterable graph concept.
marci@651
   311
  ///
marci@651
   312
  /// A graph class which provides functions to 
marci@651
   313
  /// iterate on out-edges of any node.
marci@651
   314
  class OutEdgeIterableGraphConcept : virtual public GraphConcept
marci@651
   315
  {
marci@651
   316
  public:
marci@651
   317
marci@651
   318
    /// \brief This iterator goes trough the outgoing edges of a node.
marci@651
   319
    ///
marci@334
   320
    /// This iterator goes trough the \e outgoing edges of a certain node
marci@334
   321
    /// of a graph.
marci@334
   322
    /// Its usage is quite simple, for example you can count the number
marci@334
   323
    /// of outgoing edges of a node \c n
marci@651
   324
    /// in graph \c g of type \c Graph as follows.
marci@334
   325
    /// \code
marci@651
   326
    /// int count=0;
marci@651
   327
    /// for(Graph::OutEdgeIt e(g, n); g.valid(e); g.next(e)) ++count;
marci@334
   328
    /// \endcode
marci@334
   329
    class OutEdgeIt : public Edge {
marci@334
   330
    public:
marci@651
   331
      /// @warning The default constructor sets the iterator.
marci@334
   332
      /// to an undefined value.
marci@651
   333
      OutEdgeIt() { }
marci@651
   334
      /// Initialize the iterator to be invalid.
marci@651
   335
      OutEdgeIt(const Invalid&) { }
marci@651
   336
      /// \brief This constructor sets the iterator to first outgoing edge.
marci@651
   337
      ///
marci@334
   338
      /// This constructor set the iterator to the first outgoing edge of
marci@334
   339
      /// node
marci@334
   340
      ///@param n the node
marci@651
   341
      ///@param g the graph
marci@651
   342
      OutEdgeIt(const GraphConcept& g, const Node& n) { }
marci@334
   343
    };
marci@651
   344
marci@651
   345
    /// The first outgoing edge.
marci@651
   346
    OutEdgeIt &first(OutEdgeIt &i, const Node& n) const { return i; }
marci@651
   347
marci@651
   348
    /// Go to the next outgoing edge.
marci@651
   349
    OutEdgeIt &next(OutEdgeIt &i) const { return i; }
marci@651
   350
marci@651
   351
    Node aNode(const OutEdgeIt&) const { return Node(); }
marci@651
   352
    Node bNode(const OutEdgeIt&) const { return Node(); }
marci@334
   353
  };
marci@334
   354
marci@651
   355
marci@651
   356
  /// \brief In-edge-iterable graph concept.
marci@651
   357
  ///
marci@651
   358
  /// A Graph class which provides a function to 
marci@334
   359
  /// iterate on in-edges of any node.
marci@651
   360
  class InEdgeIterableGraphConcept : virtual public GraphConcept
marci@334
   361
  {
marci@334
   362
  public:
marci@334
   363
marci@651
   364
    /// \brief This iterator goes trough the incoming edges of a node.
marci@651
   365
    /// 
marci@334
   366
    /// This iterator goes trough the \e incoming edges of a certain node
marci@334
   367
    /// of a graph.
marci@334
   368
    /// Its usage is quite simple, for example you can count the number
marci@334
   369
    /// of incoming edges of a node \c n
marci@651
   370
    /// in graph \c g of type \c Graph as follows.
marci@334
   371
    /// \code
marci@651
   372
    /// int count=0;
marci@651
   373
    /// for(Graph::InEdgeIt e(g, n); g.valid(e); g.next(e)) ++count;
marci@334
   374
    /// \endcode
marci@334
   375
    class InEdgeIt : public Edge {
marci@334
   376
    public:
marci@334
   377
      /// @warning The default constructor sets the iterator
marci@334
   378
      /// to an undefined value.
marci@651
   379
      InEdgeIt() { }
marci@334
   380
      /// Initialize the iterator to be invalid
marci@651
   381
      InEdgeIt(const Invalid&) { }
marci@651
   382
      /// \brief This constructor sets the iterator to first incomig edge.
marci@651
   383
      /// 
marci@334
   384
      /// This constructor set the iterator to the first incomig edge of
marci@334
   385
      /// node
marci@334
   386
      ///@param n the node
marci@651
   387
      ///@param g the graph
marci@651
   388
      InEdgeIt(const GraphConcept& g, const Node& n) { }
marci@334
   389
    };
marci@651
   390
marci@651
   391
    /// The first incoming edge.
marci@651
   392
    InEdgeIt &first(InEdgeIt &i, const Node& n) const { return i; }
marci@651
   393
marci@651
   394
    /// Go to the next incoming edge.
marci@651
   395
    InEdgeIt &next(InEdgeIt &i) const { return i; }
marci@651
   396
marci@651
   397
    Node aNode(const InEdgeIt&) const { return Node(); }
marci@651
   398
    Node bNode(const InEdgeIt&) const { return Node(); }
marci@334
   399
  };
marci@334
   400
marci@334
   401
marci@651
   402
  /// \brief Node-eraseable graph concept.
marci@651
   403
  ///
marci@651
   404
  /// A graph class which provides a function to 
marci@333
   405
  /// delete any of its nodes.
marci@651
   406
  class NodeEraseableGraphConcept : virtual public GraphConcept
marci@333
   407
  {
marci@333
   408
  public:
marci@333
   409
    /// Deletes a node.
marci@651
   410
    void erase(const Node& n) { }
marci@333
   411
  };
marci@333
   412
marci@651
   413
marci@651
   414
  /// \brief Edge-eraseable graph concept.
marci@651
   415
  /// 
marci@651
   416
  /// A graph class which provides a function to delete any 
marci@333
   417
  /// of its edges.
marci@651
   418
  class EdgeEraseableGraphConcept : virtual public GraphConcept
marci@333
   419
  {
marci@333
   420
  public:
marci@333
   421
    /// Deletes a node.
marci@651
   422
    void erase(const Edge& n) { }
marci@333
   423
  };
marci@333
   424
marci@651
   425
marci@651
   426
  /// \brief An empty graph class which provides a function to 
marci@651
   427
  /// get the number of its nodes.
marci@651
   428
  /// 
marci@325
   429
  /// This graph class provides a function for getting the number of its 
marci@325
   430
  /// nodes. 
marci@325
   431
  /// Clearly, for physical graph structures it can be expected to have such a 
marci@325
   432
  /// function. For wrappers or graphs which are given in an implicit way, 
marci@325
   433
  /// the implementation can be circumstantial, that is why this composes a 
marci@325
   434
  /// separate concept.
marci@651
   435
  class NodeCountingGraphConcept : virtual public GraphConcept
marci@325
   436
  {
marci@325
   437
  public:
marci@325
   438
    /// Returns the number of nodes.
marci@651
   439
    int nodeNum() const { return 0; }
marci@325
   440
  };
marci@325
   441
marci@651
   442
marci@651
   443
  /// \brief An empty graph class which provides a function to 
marci@651
   444
  /// get the number of its edges.
marci@651
   445
  /// 
marci@325
   446
  /// This graph class provides a function for getting the number of its 
marci@325
   447
  /// edges. 
marci@325
   448
  /// Clearly, for physical graph structures it can be expected to have such a 
marci@325
   449
  /// function. For wrappers or graphs which are given in an implicit way, 
marci@325
   450
  /// the implementation can be circumstantial, that is why this composes a 
marci@325
   451
  /// separate concept.
marci@651
   452
  class EdgeCountingGraphConcept : virtual public GraphConcept
marci@325
   453
  {
marci@325
   454
  public:
marci@325
   455
    /// Returns the number of edges.
marci@651
   456
    int edgeNum() const { return 0; }
marci@651
   457
  };
marci@651
   458
marci@652
   459
  class FullFeatureGraphConcept : virtual public NodeIterableGraphConcept,
marci@652
   460
				  virtual public EdgeIterableGraphConcept, 
marci@652
   461
				  virtual public OutEdgeIterableGraphConcept, 
marci@652
   462
				  virtual public InEdgeIterableGraphConcept, 
marci@652
   463
				  virtual public NodeCountingGraphConcept {
marci@651
   464
  public:
marci@651
   465
    FullFeatureGraphConcept() { }
marci@652
   466
    using EdgeIterableGraphConcept::next;
marci@652
   467
    using NodeIterableGraphConcept::next;
marci@652
   468
    using OutEdgeIterableGraphConcept::next;    
marci@652
   469
    using InEdgeIterableGraphConcept::next;
marci@325
   470
  };
marci@332
   471
  
marci@332
   472
  /// @}
marci@325
   473
marci@325
   474
} //namespace hugo
marci@325
   475
marci@325
   476
marci@332
   477
marci@651
   478
// class EmptyBipGraph : public Graph Concept
marci@325
   479
// {
marci@325
   480
//   class ANode {};
marci@325
   481
//   class BNode {};
marci@325
   482
marci@325
   483
//   ANode &next(ANode &) {}
marci@325
   484
//   BNode &next(BNode &) {}
marci@325
   485
marci@325
   486
//   ANode &getFirst(ANode &) const {}
marci@325
   487
//   BNode &getFirst(BNode &) const {}
marci@325
   488
marci@325
   489
//   enum NodeClass { A = 0, B = 1 };
marci@325
   490
//   NodeClass getClass(Node n) {}
marci@325
   491
marci@325
   492
// }
marci@325
   493
marci@325
   494
#endif // HUGO_GRAPH_H