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