lemon/hypercube_graph.h
author alpar
Tue, 18 Jul 2006 15:14:56 +0000
changeset 2152 ba87d27667cd
parent 1998 2ba916d7aae3
child 2207 75a29ac69c19
permissions -rw-r--r--
Bugfix
     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 HYPERCUBE_GRAPH_H
    20 #define HYPERCUBE_GRAPH_H
    21 
    22 #include <iostream>
    23 #include <vector>
    24 #include <lemon/bits/invalid.h>
    25 #include <lemon/bits/utility.h>
    26 #include <lemon/error.h>
    27 
    28 #include <lemon/bits/base_extender.h>
    29 #include <lemon/bits/graph_extender.h>
    30 
    31 ///\ingroup graphs
    32 ///\file
    33 ///\brief HyperCubeGraph class.
    34 
    35 namespace lemon {
    36 
    37   /// \brief Base graph for HyperCubeGraph.
    38   ///
    39   /// Base graph for hyper-cube graph. It describes some member functions
    40   /// which can be used in the HyperCubeGraph.
    41   ///
    42   /// \warning Always use the HyperCubeGraph instead of this.
    43   /// \see HyperCubeGraph
    44   class HyperCubeGraphBase {
    45 
    46   public:
    47 
    48     typedef HyperCubeGraphBase Graph;
    49 
    50     class Node;
    51     class Edge;
    52 
    53   public:
    54 
    55     HyperCubeGraphBase() {}
    56 
    57   protected:
    58 
    59     /// \brief Creates a hypercube graph with the given size.
    60     ///
    61     /// Creates a hypercube graph with the given size.
    62     void construct(int dim) {
    63       _dim = dim;
    64       _nodeNum = 1 << dim;
    65     }
    66 
    67   public:
    68     
    69 
    70     typedef True NodeNumTag;
    71     typedef True EdgeNumTag;
    72 
    73     ///Number of nodes.
    74     int nodeNum() const { return _nodeNum; }
    75     ///Number of edges.
    76     int edgeNum() const { return _nodeNum * _dim; }
    77 
    78     /// Maximum node ID.
    79     
    80     /// Maximum node ID.
    81     ///\sa id(Node)
    82     int maxNodeId() const { return nodeNum() - 1; }
    83     /// Maximum edge ID.
    84     
    85     /// Maximum edge ID.
    86     ///\sa id(Edge)
    87     int maxEdgeId() const { return edgeNum() - 1; }
    88 
    89     /// \brief Gives back the source node of an edge.
    90     ///    
    91     /// Gives back the source node of an edge.
    92     Node source(Edge e) const {
    93       return e.id / _dim;
    94     }
    95 
    96     /// \brief Gives back the target node of an edge.
    97     ///    
    98     /// Gives back the target node of an edge.
    99     Node target(Edge e) const {
   100       return (e.id / _dim) ^ ( 1 << (e.id % _dim));
   101     }
   102 
   103     /// Node ID.
   104     
   105     /// The ID of a valid Node is a nonnegative integer not greater than
   106     /// \ref maxNodeId(). The range of the ID's is not surely continuous
   107     /// and the greatest node ID can be actually less then \ref maxNodeId().
   108     ///
   109     /// The ID of the \ref INVALID node is -1.
   110     ///\return The ID of the node \c v. 
   111 
   112     static int id(Node v) { return v.id; }
   113     /// Edge ID.
   114     
   115     /// The ID of a valid Edge is a nonnegative integer not greater than
   116     /// \ref maxEdgeId(). The range of the ID's is not surely continuous
   117     /// and the greatest edge ID can be actually less then \ref maxEdgeId().
   118     ///
   119     /// The ID of the \ref INVALID edge is -1.
   120     ///\return The ID of the edge \c e. 
   121     static int id(Edge e) { return e.id; }
   122 
   123     static Node nodeFromId(int id) { return Node(id);}
   124     
   125     static Edge edgeFromId(int id) { return Edge(id);}
   126 
   127     class Node {
   128       friend class HyperCubeGraphBase;
   129 
   130     protected:
   131       int id;
   132       Node(int _id) { id = _id;}
   133     public:
   134       Node() {}
   135       Node (Invalid) { id = -1; }
   136       bool operator==(const Node node) const {return id == node.id;}
   137       bool operator!=(const Node node) const {return id != node.id;}
   138       bool operator<(const Node node) const {return id < node.id;}
   139     };
   140     
   141     class Edge {
   142       friend class HyperCubeGraphBase;
   143       
   144     protected:
   145       int id; 
   146 
   147       Edge(int _id) : id(_id) {}
   148 
   149     public:
   150       Edge() { }
   151       Edge (Invalid) { id = -1; }
   152       bool operator==(const Edge edge) const {return id == edge.id;}
   153       bool operator!=(const Edge edge) const {return id != edge.id;}
   154       bool operator<(const Edge edge) const {return id < edge.id;}
   155     };
   156 
   157     void first(Node& node) const {
   158       node.id = nodeNum() - 1;
   159     }
   160 
   161     static void next(Node& node) {
   162       --node.id;
   163     }
   164 
   165     void first(Edge& edge) const {
   166       edge.id = edgeNum() - 1;
   167     }
   168 
   169     static void next(Edge& edge) {
   170       --edge.id;
   171     }
   172 
   173     void firstOut(Edge& edge, const Node& node) const {
   174       edge.id = node.id * _dim;
   175     }
   176 
   177     void nextOut(Edge& edge) const {
   178       ++edge.id;
   179       if (edge.id % _dim == 0) edge.id = -1;
   180     }
   181 
   182     void firstIn(Edge& edge, const Node& node) const {
   183       edge.id = (node.id ^ 1) * _dim;
   184     }
   185     
   186     void nextIn(Edge& edge) const {
   187       int cnt = edge.id % _dim;
   188       if ((cnt + 1) % _dim == 0) {
   189 	edge.id = -1;
   190       } else {
   191 	edge.id = ((edge.id / _dim) ^ ((1 << cnt) * 3)) * _dim + cnt + 1; 
   192       }
   193     }
   194 
   195     /// \brief Gives back the number of the dimensions.
   196     ///
   197     /// Gives back the number of the dimensions.
   198     int dimension() const {
   199       return _dim;
   200     }
   201 
   202     /// \brief Returns true if the n'th bit of the node is one.
   203     ///
   204     /// Returns true if the n'th bit of the node is one. 
   205     bool projection(Node node, int n) const {
   206       return (bool)(node.id & (1 << n));
   207     }
   208 
   209     /// \brief The dimension id of the edge.
   210     ///
   211     /// It returns the dimension id of the edge. It can
   212     /// be in the ${0, 1, dim-1}$ intervall.
   213     int dimension(Edge edge) const {
   214       return edge.id % _dim;
   215     }
   216 
   217     /// \brief Gives back the index of the node.
   218     ///
   219     /// Gives back the index of the node. The lower bits of the
   220     /// integer describe the node.
   221     int index(Node node) const {
   222       return node.id;
   223     }
   224 
   225     /// \brief Gives back the node by its index.
   226     ///
   227     ///  Gives back the node by its index.
   228     Node operator()(int index) const {
   229       return Node(index);
   230     }
   231     
   232   private:
   233     int _dim, _nodeNum;
   234   };
   235 
   236 
   237   typedef GraphExtender<HyperCubeGraphBase> ExtendedHyperCubeGraphBase;
   238 
   239   /// \ingroup graphs
   240   ///
   241   /// \brief HyperCube graph class
   242   ///
   243   /// This class implements a special graph type. The nodes of the
   244   /// graph can be indiced with integers with at most \c dim binary length.
   245   /// Two nodes are connected in the graph if the indices differ only
   246   /// on one position in the binary form. 
   247   ///
   248   /// \note The type of the \c ids is chosen to \c int because efficiency
   249   /// reasons. This way the maximal dimension of this implementation
   250   /// is 26. 
   251   ///
   252   /// The graph type is fully conform to the \ref concept::Graph
   253   /// concept but it does not conform to the \ref concept::UGraph.
   254   ///
   255   /// \see HyperCubeGraphBase
   256   /// \author Balazs Dezso
   257   class HyperCubeGraph : public ExtendedHyperCubeGraphBase {
   258   public:
   259 
   260     /// \brief Construct a graph with \c dim dimension.
   261     ///
   262     /// Construct a graph with \c dim dimension.
   263     HyperCubeGraph(int dim) { construct(dim); }
   264 
   265     /// \brief Linear combination map.
   266     ///
   267     /// It makes possible to give back a linear combination
   268     /// for each node. This function works like the \c std::accumulate
   269     /// so it accumulates the \c bf binary function with the \c fv
   270     /// first value. The map accumulates only on that dimensions where
   271     /// the node's index is one. The accumulated values should be
   272     /// given by the \c begin and \c end iterators and this range's length
   273     /// should be the dimension number of the graph.
   274     /// 
   275     ///\code
   276     /// const int DIM = 3;
   277     /// HyperCubeGraph graph(DIM);
   278     /// xy<double> base[DIM];
   279     /// for (int k = 0; k < DIM; ++k) {
   280     ///   base[k].x = rand() / (RAND_MAX + 1.0);
   281     ///   base[k].y = rand() / (RAND_MAX + 1.0);
   282     /// } 
   283     /// HyperCubeGraph::HyperMap<xy<double> > 
   284     ///   pos(graph, base, base + DIM, xy<double>(0.0, 0.0));
   285     ///\endcode
   286     ///
   287     /// \see HyperCubeGraph
   288     template <typename T, typename BF = std::plus<T> >
   289     class HyperMap {
   290     public:
   291 
   292       typedef Node Key;
   293       typedef T Value;
   294     
   295       
   296       /// \brief Constructor for HyperMap. 
   297       ///
   298       /// Construct a HyperMap for the given graph. The accumulated values 
   299       /// should be given by the \c begin and \c end iterators and this 
   300       /// range's length should be the dimension number of the graph.
   301       ///
   302       /// This function accumulates the \c bf binary function with 
   303       /// the \c fv first value. The map accumulates only on that dimensions 
   304       /// where the node's index is one.           
   305       template <typename It>
   306       HyperMap(const Graph& graph, It begin, It end, 
   307 		   T fv = 0.0, const BF& bf = BF()) 
   308 	: _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf) {
   309 	LEMON_ASSERT(_values.size() == graph.dimension(), 
   310 		     "Wrong size of dimension");
   311       }
   312 
   313       /// \brief Gives back the partial accumulated value.
   314       ///
   315       /// Gives back the partial accumulated value.
   316       Value operator[](Key k) const {
   317 	Value val = _first_value;
   318 	int id = _graph.index(k); 
   319 	int n = 0;
   320 	while (id != 0) {
   321 	  if (id & 1) {
   322 	    val = _bin_func(val, _values[n]);
   323 	  }
   324 	  id >>= 1;
   325 	  ++n;
   326 	}
   327 	return val;
   328       }
   329       
   330     private:
   331       const Graph& _graph;
   332       std::vector<T> _values;
   333       T _first_value;
   334       BF _bin_func;
   335     };    
   336   };
   337 }
   338 #endif
   339