lemon/hypercube_graph.h
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 06 Nov 2008 15:16:37 +0100
changeset 365 a12eef1f82b2
parent 364 b4a01426c0d9
child 372 7b6466ed488a
permissions -rw-r--r--
Rework hypercube graph implementation to be undirected (#57)
kpeter@364
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
kpeter@364
     2
 *
kpeter@364
     3
 * This file is a part of LEMON, a generic C++ optimization library.
kpeter@364
     4
 *
kpeter@364
     5
 * Copyright (C) 2003-2008
kpeter@364
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
kpeter@364
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
kpeter@364
     8
 *
kpeter@364
     9
 * Permission to use, modify and distribute this software is granted
kpeter@364
    10
 * provided that this copyright notice appears in all copies. For
kpeter@364
    11
 * precise terms see the accompanying LICENSE file.
kpeter@364
    12
 *
kpeter@364
    13
 * This software is provided "AS IS" with no warranty of any kind,
kpeter@364
    14
 * express or implied, and with no claim as to its suitability for any
kpeter@364
    15
 * purpose.
kpeter@364
    16
 *
kpeter@364
    17
 */
kpeter@364
    18
kpeter@364
    19
#ifndef HYPERCUBE_GRAPH_H
kpeter@364
    20
#define HYPERCUBE_GRAPH_H
kpeter@364
    21
kpeter@364
    22
#include <vector>
kpeter@364
    23
#include <lemon/core.h>
kpeter@365
    24
#include <lemon/assert.h>
kpeter@364
    25
#include <lemon/bits/graph_extender.h>
kpeter@364
    26
kpeter@364
    27
///\ingroup graphs
kpeter@364
    28
///\file
kpeter@365
    29
///\brief HypercubeGraph class.
kpeter@364
    30
kpeter@364
    31
namespace lemon {
kpeter@364
    32
kpeter@365
    33
  class HypercubeGraphBase {
kpeter@364
    34
kpeter@364
    35
  public:
kpeter@364
    36
kpeter@365
    37
    typedef HypercubeGraphBase Graph;
kpeter@364
    38
kpeter@364
    39
    class Node;
kpeter@365
    40
    class Edge;
kpeter@364
    41
    class Arc;
kpeter@364
    42
kpeter@364
    43
  public:
kpeter@364
    44
kpeter@365
    45
    HypercubeGraphBase() {}
kpeter@364
    46
kpeter@364
    47
  protected:
kpeter@364
    48
kpeter@364
    49
    void construct(int dim) {
kpeter@365
    50
      LEMON_ASSERT(dim >= 1, "The number of dimensions must be at least 1.");
kpeter@364
    51
      _dim = dim;
kpeter@365
    52
      _node_num = 1 << dim;
kpeter@365
    53
      _edge_num = dim * (1 << dim-1);
kpeter@364
    54
    }
kpeter@364
    55
kpeter@364
    56
  public:
kpeter@364
    57
kpeter@364
    58
    typedef True NodeNumTag;
kpeter@365
    59
    typedef True EdgeNumTag;
kpeter@364
    60
    typedef True ArcNumTag;
kpeter@364
    61
kpeter@365
    62
    int nodeNum() const { return _node_num; }
kpeter@365
    63
    int edgeNum() const { return _edge_num; }
kpeter@365
    64
    int arcNum() const { return 2 * _edge_num; }
kpeter@364
    65
kpeter@365
    66
    int maxNodeId() const { return _node_num - 1; }
kpeter@365
    67
    int maxEdgeId() const { return _edge_num - 1; }
kpeter@365
    68
    int maxArcId() const { return 2 * _edge_num - 1; }
kpeter@364
    69
kpeter@365
    70
    static Node nodeFromId(int id) { return Node(id); }
kpeter@365
    71
    static Edge edgeFromId(int id) { return Edge(id); }
kpeter@365
    72
    static Arc arcFromId(int id) { return Arc(id); }
kpeter@365
    73
kpeter@365
    74
    static int id(Node node) { return node._id; }
kpeter@365
    75
    static int id(Edge edge) { return edge._id; }
kpeter@365
    76
    static int id(Arc arc) { return arc._id; }
kpeter@365
    77
kpeter@365
    78
    Node u(Edge edge) const {
kpeter@365
    79
      int base = edge._id & ((1 << _dim-1) - 1);
kpeter@365
    80
      int k = edge._id >> _dim-1;
kpeter@365
    81
      return ((base >> k) << k+1) | (base & ((1 << k) - 1));
kpeter@364
    82
    }
kpeter@364
    83
kpeter@365
    84
    Node v(Edge edge) const {
kpeter@365
    85
      int base = edge._id & ((1 << _dim-1) - 1);
kpeter@365
    86
      int k = edge._id >> _dim-1;
kpeter@365
    87
      return ((base >> k) << k+1) | (base & ((1 << k) - 1)) | (1 << k);
kpeter@364
    88
    }
kpeter@364
    89
kpeter@365
    90
    Node source(Arc arc) const {
kpeter@365
    91
      return (arc._id & 1) == 1 ? u(arc) : v(arc);
kpeter@365
    92
    }
kpeter@364
    93
kpeter@365
    94
    Node target(Arc arc) const {
kpeter@365
    95
      return (arc._id & 1) == 1 ? v(arc) : u(arc);
kpeter@365
    96
    }
kpeter@364
    97
kpeter@365
    98
    typedef True FindEdgeTag;
kpeter@365
    99
    typedef True FindArcTag;
kpeter@365
   100
kpeter@365
   101
    Edge findEdge(Node u, Node v, Edge prev = INVALID) const {
kpeter@365
   102
      if (prev != INVALID) return INVALID;
kpeter@365
   103
      int d = u._id ^ v._id;
kpeter@365
   104
      int k = 0;
kpeter@365
   105
      if (d == 0) return INVALID;
kpeter@365
   106
      for ( ; (d & 1) == 0; d >>= 1) ++k;
kpeter@365
   107
      if (d >> 1 != 0) return INVALID;
kpeter@365
   108
      return (k << _dim-1) | ((u._id >> k+1) << k) | (u._id & ((1 << k) - 1));
kpeter@365
   109
    }
kpeter@365
   110
kpeter@365
   111
    Arc findArc(Node u, Node v, Arc prev = INVALID) const {
kpeter@365
   112
      Edge edge = findEdge(u, v, prev);
kpeter@365
   113
      if (edge == INVALID) return INVALID;
kpeter@365
   114
      int k = edge._id >> _dim-1;
kpeter@365
   115
      return ((u._id >> k) & 1) == 1 ? edge._id << 1 : (edge._id << 1) | 1;
kpeter@365
   116
    }
kpeter@364
   117
kpeter@364
   118
    class Node {
kpeter@365
   119
      friend class HypercubeGraphBase;
kpeter@365
   120
kpeter@364
   121
    protected:
kpeter@365
   122
      int _id;
kpeter@365
   123
      Node(int id) : _id(id) {}
kpeter@364
   124
    public:
kpeter@364
   125
      Node() {}
kpeter@365
   126
      Node (Invalid) : _id(-1) {}
kpeter@365
   127
      bool operator==(const Node node) const {return _id == node._id;}
kpeter@365
   128
      bool operator!=(const Node node) const {return _id != node._id;}
kpeter@365
   129
      bool operator<(const Node node) const {return _id < node._id;}
kpeter@365
   130
    };
kpeter@365
   131
kpeter@365
   132
    class Edge {
kpeter@365
   133
      friend class HypercubeGraphBase;
kpeter@365
   134
      friend class Arc;
kpeter@365
   135
kpeter@365
   136
    protected:
kpeter@365
   137
      int _id;
kpeter@365
   138
kpeter@365
   139
      Edge(int id) : _id(id) {}
kpeter@365
   140
kpeter@365
   141
    public:
kpeter@365
   142
      Edge() {}
kpeter@365
   143
      Edge (Invalid) : _id(-1) {}
kpeter@365
   144
      bool operator==(const Edge edge) const {return _id == edge._id;}
kpeter@365
   145
      bool operator!=(const Edge edge) const {return _id != edge._id;}
kpeter@365
   146
      bool operator<(const Edge edge) const {return _id < edge._id;}
kpeter@364
   147
    };
kpeter@364
   148
kpeter@364
   149
    class Arc {
kpeter@365
   150
      friend class HypercubeGraphBase;
kpeter@365
   151
kpeter@364
   152
    protected:
kpeter@365
   153
      int _id;
kpeter@365
   154
kpeter@365
   155
      Arc(int id) : _id(id) {}
kpeter@365
   156
kpeter@364
   157
    public:
kpeter@365
   158
      Arc() {}
kpeter@365
   159
      Arc (Invalid) : _id(-1) {}
kpeter@365
   160
      operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; }
kpeter@365
   161
      bool operator==(const Arc arc) const {return _id == arc._id;}
kpeter@365
   162
      bool operator!=(const Arc arc) const {return _id != arc._id;}
kpeter@365
   163
      bool operator<(const Arc arc) const {return _id < arc._id;}
kpeter@364
   164
    };
kpeter@364
   165
kpeter@364
   166
    void first(Node& node) const {
kpeter@365
   167
      node._id = _node_num - 1;
kpeter@364
   168
    }
kpeter@364
   169
kpeter@364
   170
    static void next(Node& node) {
kpeter@365
   171
      --node._id;
kpeter@365
   172
    }
kpeter@365
   173
kpeter@365
   174
    void first(Edge& edge) const {
kpeter@365
   175
      edge._id = _edge_num - 1;
kpeter@365
   176
    }
kpeter@365
   177
kpeter@365
   178
    static void next(Edge& edge) {
kpeter@365
   179
      --edge._id;
kpeter@364
   180
    }
kpeter@364
   181
kpeter@364
   182
    void first(Arc& arc) const {
kpeter@365
   183
      arc._id = 2 * _edge_num - 1;
kpeter@364
   184
    }
kpeter@364
   185
kpeter@364
   186
    static void next(Arc& arc) {
kpeter@365
   187
      --arc._id;
kpeter@365
   188
    }
kpeter@365
   189
kpeter@365
   190
    void firstInc(Edge& edge, bool& dir, const Node& node) const {
kpeter@365
   191
      edge._id = node._id >> 1;
kpeter@365
   192
      dir = (node._id & 1) == 0;
kpeter@365
   193
    }
kpeter@365
   194
kpeter@365
   195
    void nextInc(Edge& edge, bool& dir) const {
kpeter@365
   196
      Node n = dir ? u(edge) : v(edge);
kpeter@365
   197
      int k = (edge._id >> _dim-1) + 1;
kpeter@365
   198
      if (k < _dim) {
kpeter@365
   199
        edge._id = (k << _dim-1) |
kpeter@365
   200
                   ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1));
kpeter@365
   201
        dir = ((n._id >> k) & 1) == 0;
kpeter@365
   202
      } else {
kpeter@365
   203
        edge._id = -1;
kpeter@365
   204
        dir = true;
kpeter@365
   205
      }
kpeter@364
   206
    }
kpeter@364
   207
kpeter@364
   208
    void firstOut(Arc& arc, const Node& node) const {
kpeter@365
   209
      arc._id = ((node._id >> 1) << 1) | (~node._id & 1);
kpeter@364
   210
    }
kpeter@364
   211
kpeter@364
   212
    void nextOut(Arc& arc) const {
kpeter@365
   213
      Node n = (arc._id & 1) == 1 ? u(arc) : v(arc);
kpeter@365
   214
      int k = (arc._id >> _dim) + 1;
kpeter@365
   215
      if (k < _dim) {
kpeter@365
   216
        arc._id = (k << _dim-1) |
kpeter@365
   217
                  ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1));
kpeter@365
   218
        arc._id = (arc._id << 1) | (~(n._id >> k) & 1);
kpeter@365
   219
      } else {
kpeter@365
   220
        arc._id = -1;
kpeter@365
   221
      }
kpeter@364
   222
    }
kpeter@364
   223
kpeter@364
   224
    void firstIn(Arc& arc, const Node& node) const {
kpeter@365
   225
      arc._id = ((node._id >> 1) << 1) | (node._id & 1);
kpeter@364
   226
    }
kpeter@364
   227
kpeter@364
   228
    void nextIn(Arc& arc) const {
kpeter@365
   229
      Node n = (arc._id & 1) == 1 ? v(arc) : u(arc);
kpeter@365
   230
      int k = (arc._id >> _dim) + 1;
kpeter@365
   231
      if (k < _dim) {
kpeter@365
   232
        arc._id = (k << _dim-1) |
kpeter@365
   233
                  ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1));
kpeter@365
   234
        arc._id = (arc._id << 1) | ((n._id >> k) & 1);
kpeter@364
   235
      } else {
kpeter@365
   236
        arc._id = -1;
kpeter@364
   237
      }
kpeter@364
   238
    }
kpeter@364
   239
kpeter@365
   240
    static bool direction(Arc arc) {
kpeter@365
   241
      return (arc._id & 1) == 1;
kpeter@365
   242
    }
kpeter@365
   243
kpeter@365
   244
    static Arc direct(Edge edge, bool dir) {
kpeter@365
   245
      return Arc((edge._id << 1) | (dir ? 1 : 0));
kpeter@365
   246
    }
kpeter@365
   247
kpeter@364
   248
    int dimension() const {
kpeter@364
   249
      return _dim;
kpeter@364
   250
    }
kpeter@364
   251
kpeter@364
   252
    bool projection(Node node, int n) const {
kpeter@365
   253
      return static_cast<bool>(node._id & (1 << n));
kpeter@365
   254
    }
kpeter@365
   255
kpeter@365
   256
    int dimension(Edge edge) const {
kpeter@365
   257
      return edge._id >> _dim-1;
kpeter@364
   258
    }
kpeter@364
   259
kpeter@364
   260
    int dimension(Arc arc) const {
kpeter@365
   261
      return arc._id >> _dim;
kpeter@364
   262
    }
kpeter@364
   263
kpeter@364
   264
    int index(Node node) const {
kpeter@365
   265
      return node._id;
kpeter@364
   266
    }
kpeter@364
   267
kpeter@364
   268
    Node operator()(int ix) const {
kpeter@364
   269
      return Node(ix);
kpeter@364
   270
    }
kpeter@364
   271
kpeter@364
   272
  private:
kpeter@365
   273
    int _dim;
kpeter@365
   274
    int _node_num, _edge_num;
kpeter@364
   275
  };
kpeter@364
   276
kpeter@364
   277
kpeter@365
   278
  typedef GraphExtender<HypercubeGraphBase> ExtendedHypercubeGraphBase;
kpeter@364
   279
kpeter@365
   280
  /// \ingroup graphs
kpeter@364
   281
  ///
kpeter@365
   282
  /// \brief Hypercube graph class
kpeter@364
   283
  ///
kpeter@365
   284
  /// This class implements a special graph type. The nodes of the graph
kpeter@365
   285
  /// are indiced with integers with at most \c dim binary digits.
kpeter@365
   286
  /// Two nodes are connected in the graph if and only if their indices
kpeter@365
   287
  /// differ only on one position in the binary form.
kpeter@364
   288
  ///
kpeter@365
   289
  /// \note The type of the indices is chosen to \c int for efficiency
kpeter@365
   290
  /// reasons. Thus the maximum dimension of this implementation is 26
kpeter@365
   291
  /// (assuming that the size of \c int is 32 bit).
kpeter@364
   292
  ///
kpeter@365
   293
  /// This graph type is fully conform to the \ref concepts::Graph
kpeter@365
   294
  /// "Graph" concept, and it also has an important extra feature
kpeter@365
   295
  /// that its maps are real \ref concepts::ReferenceMap
kpeter@365
   296
  /// "reference map"s.
kpeter@365
   297
  class HypercubeGraph : public ExtendedHypercubeGraphBase {
kpeter@364
   298
  public:
kpeter@364
   299
kpeter@365
   300
    typedef ExtendedHypercubeGraphBase Parent;
kpeter@364
   301
kpeter@365
   302
    /// \brief Constructs a hypercube graph with \c dim dimensions.
kpeter@364
   303
    ///
kpeter@365
   304
    /// Constructs a hypercube graph with \c dim dimensions.
kpeter@365
   305
    HypercubeGraph(int dim) { construct(dim); }
kpeter@364
   306
kpeter@365
   307
    /// \brief The number of dimensions.
kpeter@364
   308
    ///
kpeter@365
   309
    /// Gives back the number of dimensions.
kpeter@364
   310
    int dimension() const {
kpeter@364
   311
      return Parent::dimension();
kpeter@364
   312
    }
kpeter@364
   313
kpeter@365
   314
    /// \brief Returns \c true if the n'th bit of the node is one.
kpeter@364
   315
    ///
kpeter@365
   316
    /// Returns \c true if the n'th bit of the node is one.
kpeter@364
   317
    bool projection(Node node, int n) const {
kpeter@364
   318
      return Parent::projection(node, n);
kpeter@364
   319
    }
kpeter@364
   320
kpeter@365
   321
    /// \brief The dimension id of an edge.
kpeter@364
   322
    ///
kpeter@365
   323
    /// Gives back the dimension id of the given edge.
kpeter@365
   324
    /// It is in the [0..dim-1] range.
kpeter@365
   325
    int dimension(Edge edge) const {
kpeter@365
   326
      return Parent::dimension(edge);
kpeter@365
   327
    }
kpeter@365
   328
kpeter@365
   329
    /// \brief The dimension id of an arc.
kpeter@365
   330
    ///
kpeter@365
   331
    /// Gives back the dimension id of the given arc.
kpeter@365
   332
    /// It is in the [0..dim-1] range.
kpeter@364
   333
    int dimension(Arc arc) const {
kpeter@364
   334
      return Parent::dimension(arc);
kpeter@364
   335
    }
kpeter@364
   336
kpeter@365
   337
    /// \brief The index of a node.
kpeter@364
   338
    ///
kpeter@365
   339
    /// Gives back the index of the given node.
kpeter@365
   340
    /// The lower bits of the integer describes the node.
kpeter@364
   341
    int index(Node node) const {
kpeter@364
   342
      return Parent::index(node);
kpeter@364
   343
    }
kpeter@364
   344
kpeter@365
   345
    /// \brief Gives back a node by its index.
kpeter@364
   346
    ///
kpeter@365
   347
    /// Gives back a node by its index.
kpeter@364
   348
    Node operator()(int ix) const {
kpeter@364
   349
      return Parent::operator()(ix);
kpeter@364
   350
    }
kpeter@364
   351
kpeter@364
   352
    /// \brief Number of nodes.
kpeter@364
   353
    int nodeNum() const { return Parent::nodeNum(); }
kpeter@365
   354
    /// \brief Number of edges.
kpeter@365
   355
    int edgeNum() const { return Parent::edgeNum(); }
kpeter@364
   356
    /// \brief Number of arcs.
kpeter@364
   357
    int arcNum() const { return Parent::arcNum(); }
kpeter@364
   358
kpeter@364
   359
    /// \brief Linear combination map.
kpeter@364
   360
    ///
kpeter@365
   361
    /// This map makes possible to give back a linear combination
kpeter@365
   362
    /// for each node. It works like the \c std::accumulate function,
kpeter@365
   363
    /// so it accumulates the \c bf binary function with the \c fv first
kpeter@365
   364
    /// value. The map accumulates only on that positions (dimensions)
kpeter@365
   365
    /// where the index of the node is one. The values that have to be
kpeter@365
   366
    /// accumulated should be given by the \c begin and \c end iterators
kpeter@365
   367
    /// and the length of this range should be equal to the dimension
kpeter@365
   368
    /// number of the graph.
kpeter@364
   369
    ///
kpeter@364
   370
    ///\code
kpeter@364
   371
    /// const int DIM = 3;
kpeter@365
   372
    /// HypercubeGraph graph(DIM);
kpeter@364
   373
    /// dim2::Point<double> base[DIM];
kpeter@364
   374
    /// for (int k = 0; k < DIM; ++k) {
kpeter@364
   375
    ///   base[k].x = rnd();
kpeter@364
   376
    ///   base[k].y = rnd();
kpeter@364
   377
    /// }
kpeter@365
   378
    /// HypercubeGraph::HyperMap<dim2::Point<double> >
kpeter@365
   379
    ///   pos(graph, base, base + DIM, dim2::Point<double>(0.0, 0.0));
kpeter@364
   380
    ///\endcode
kpeter@364
   381
    ///
kpeter@365
   382
    /// \see HypercubeGraph
kpeter@364
   383
    template <typename T, typename BF = std::plus<T> >
kpeter@364
   384
    class HyperMap {
kpeter@364
   385
    public:
kpeter@364
   386
kpeter@365
   387
      /// \brief The key type of the map
kpeter@364
   388
      typedef Node Key;
kpeter@365
   389
      /// \brief The value type of the map
kpeter@364
   390
      typedef T Value;
kpeter@364
   391
kpeter@364
   392
      /// \brief Constructor for HyperMap.
kpeter@364
   393
      ///
kpeter@365
   394
      /// Construct a HyperMap for the given graph. The values that have
kpeter@365
   395
      /// to be accumulated should be given by the \c begin and \c end
kpeter@365
   396
      /// iterators and the length of this range should be equal to the
kpeter@365
   397
      /// dimension number of the graph.
kpeter@364
   398
      ///
kpeter@365
   399
      /// This map accumulates the \c bf binary function with the \c fv
kpeter@365
   400
      /// first value on that positions (dimensions) where the index of
kpeter@365
   401
      /// the node is one.
kpeter@364
   402
      template <typename It>
kpeter@365
   403
      HyperMap(const Graph& graph, It begin, It end,
kpeter@365
   404
               T fv = 0, const BF& bf = BF())
kpeter@365
   405
        : _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf)
kpeter@364
   406
      {
kpeter@365
   407
        LEMON_ASSERT(_values.size() == graph.dimension(),
kpeter@365
   408
                     "Wrong size of range");
kpeter@364
   409
      }
kpeter@364
   410
kpeter@365
   411
      /// \brief The partial accumulated value.
kpeter@364
   412
      ///
kpeter@364
   413
      /// Gives back the partial accumulated value.
kpeter@365
   414
      Value operator[](const Key& k) const {
kpeter@364
   415
        Value val = _first_value;
kpeter@364
   416
        int id = _graph.index(k);
kpeter@364
   417
        int n = 0;
kpeter@364
   418
        while (id != 0) {
kpeter@364
   419
          if (id & 1) {
kpeter@364
   420
            val = _bin_func(val, _values[n]);
kpeter@364
   421
          }
kpeter@364
   422
          id >>= 1;
kpeter@364
   423
          ++n;
kpeter@364
   424
        }
kpeter@364
   425
        return val;
kpeter@364
   426
      }
kpeter@364
   427
kpeter@364
   428
    private:
kpeter@365
   429
      const Graph& _graph;
kpeter@364
   430
      std::vector<T> _values;
kpeter@364
   431
      T _first_value;
kpeter@364
   432
      BF _bin_func;
kpeter@364
   433
    };
kpeter@364
   434
kpeter@364
   435
  };
kpeter@364
   436
kpeter@364
   437
}
kpeter@364
   438
kpeter@364
   439
#endif