# HG changeset patch # User Alpar Juttner # Date 2008-11-06 15:40:32 # Node ID efbd0ab50a774de69ec772748d18ab5d56bc233a # Parent a637fb9d457b737f827ebc09b6aa350d0f4cc0e9 # Parent a12eef1f82b2eab399a67b84dcf026a87bc16361 Merge diff --git a/lemon/Makefile.am b/lemon/Makefile.am --- a/lemon/Makefile.am +++ b/lemon/Makefile.am @@ -31,6 +31,7 @@ lemon/full_graph.h \ lemon/graph_to_eps.h \ lemon/grid_graph.h \ + lemon/hypercube_graph.h \ lemon/kruskal.h \ lemon/lgf_reader.h \ lemon/lgf_writer.h \ diff --git a/lemon/hypercube_graph.h b/lemon/hypercube_graph.h new file mode 100644 --- /dev/null +++ b/lemon/hypercube_graph.h @@ -0,0 +1,439 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2008 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef HYPERCUBE_GRAPH_H +#define HYPERCUBE_GRAPH_H + +#include +#include +#include +#include + +///\ingroup graphs +///\file +///\brief HypercubeGraph class. + +namespace lemon { + + class HypercubeGraphBase { + + public: + + typedef HypercubeGraphBase Graph; + + class Node; + class Edge; + class Arc; + + public: + + HypercubeGraphBase() {} + + protected: + + void construct(int dim) { + LEMON_ASSERT(dim >= 1, "The number of dimensions must be at least 1."); + _dim = dim; + _node_num = 1 << dim; + _edge_num = dim * (1 << dim-1); + } + + public: + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + static Node nodeFromId(int id) { return Node(id); } + static Edge edgeFromId(int id) { return Edge(id); } + static Arc arcFromId(int id) { return Arc(id); } + + static int id(Node node) { return node._id; } + static int id(Edge edge) { return edge._id; } + static int id(Arc arc) { return arc._id; } + + Node u(Edge edge) const { + int base = edge._id & ((1 << _dim-1) - 1); + int k = edge._id >> _dim-1; + return ((base >> k) << k+1) | (base & ((1 << k) - 1)); + } + + Node v(Edge edge) const { + int base = edge._id & ((1 << _dim-1) - 1); + int k = edge._id >> _dim-1; + return ((base >> k) << k+1) | (base & ((1 << k) - 1)) | (1 << k); + } + + Node source(Arc arc) const { + return (arc._id & 1) == 1 ? u(arc) : v(arc); + } + + Node target(Arc arc) const { + return (arc._id & 1) == 1 ? v(arc) : u(arc); + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + if (prev != INVALID) return INVALID; + int d = u._id ^ v._id; + int k = 0; + if (d == 0) return INVALID; + for ( ; (d & 1) == 0; d >>= 1) ++k; + if (d >> 1 != 0) return INVALID; + return (k << _dim-1) | ((u._id >> k+1) << k) | (u._id & ((1 << k) - 1)); + } + + Arc findArc(Node u, Node v, Arc prev = INVALID) const { + Edge edge = findEdge(u, v, prev); + if (edge == INVALID) return INVALID; + int k = edge._id >> _dim-1; + return ((u._id >> k) & 1) == 1 ? edge._id << 1 : (edge._id << 1) | 1; + } + + class Node { + friend class HypercubeGraphBase; + + protected: + int _id; + Node(int id) : _id(id) {} + public: + Node() {} + Node (Invalid) : _id(-1) {} + bool operator==(const Node node) const {return _id == node._id;} + bool operator!=(const Node node) const {return _id != node._id;} + bool operator<(const Node node) const {return _id < node._id;} + }; + + class Edge { + friend class HypercubeGraphBase; + friend class Arc; + + protected: + int _id; + + Edge(int id) : _id(id) {} + + public: + Edge() {} + Edge (Invalid) : _id(-1) {} + bool operator==(const Edge edge) const {return _id == edge._id;} + bool operator!=(const Edge edge) const {return _id != edge._id;} + bool operator<(const Edge edge) const {return _id < edge._id;} + }; + + class Arc { + friend class HypercubeGraphBase; + + protected: + int _id; + + Arc(int id) : _id(id) {} + + public: + Arc() {} + Arc (Invalid) : _id(-1) {} + operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; } + bool operator==(const Arc arc) const {return _id == arc._id;} + bool operator!=(const Arc arc) const {return _id != arc._id;} + bool operator<(const Arc arc) const {return _id < arc._id;} + }; + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(Edge& edge) const { + edge._id = _edge_num - 1; + } + + static void next(Edge& edge) { + --edge._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void firstInc(Edge& edge, bool& dir, const Node& node) const { + edge._id = node._id >> 1; + dir = (node._id & 1) == 0; + } + + void nextInc(Edge& edge, bool& dir) const { + Node n = dir ? u(edge) : v(edge); + int k = (edge._id >> _dim-1) + 1; + if (k < _dim) { + edge._id = (k << _dim-1) | + ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1)); + dir = ((n._id >> k) & 1) == 0; + } else { + edge._id = -1; + dir = true; + } + } + + void firstOut(Arc& arc, const Node& node) const { + arc._id = ((node._id >> 1) << 1) | (~node._id & 1); + } + + void nextOut(Arc& arc) const { + Node n = (arc._id & 1) == 1 ? u(arc) : v(arc); + int k = (arc._id >> _dim) + 1; + if (k < _dim) { + arc._id = (k << _dim-1) | + ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1)); + arc._id = (arc._id << 1) | (~(n._id >> k) & 1); + } else { + arc._id = -1; + } + } + + void firstIn(Arc& arc, const Node& node) const { + arc._id = ((node._id >> 1) << 1) | (node._id & 1); + } + + void nextIn(Arc& arc) const { + Node n = (arc._id & 1) == 1 ? v(arc) : u(arc); + int k = (arc._id >> _dim) + 1; + if (k < _dim) { + arc._id = (k << _dim-1) | + ((n._id >> k+1) << k) | (n._id & ((1 << k) - 1)); + arc._id = (arc._id << 1) | ((n._id >> k) & 1); + } else { + arc._id = -1; + } + } + + static bool direction(Arc arc) { + return (arc._id & 1) == 1; + } + + static Arc direct(Edge edge, bool dir) { + return Arc((edge._id << 1) | (dir ? 1 : 0)); + } + + int dimension() const { + return _dim; + } + + bool projection(Node node, int n) const { + return static_cast(node._id & (1 << n)); + } + + int dimension(Edge edge) const { + return edge._id >> _dim-1; + } + + int dimension(Arc arc) const { + return arc._id >> _dim; + } + + int index(Node node) const { + return node._id; + } + + Node operator()(int ix) const { + return Node(ix); + } + + private: + int _dim; + int _node_num, _edge_num; + }; + + + typedef GraphExtender ExtendedHypercubeGraphBase; + + /// \ingroup graphs + /// + /// \brief Hypercube graph class + /// + /// This class implements a special graph type. The nodes of the graph + /// are indiced with integers with at most \c dim binary digits. + /// Two nodes are connected in the graph if and only if their indices + /// differ only on one position in the binary form. + /// + /// \note The type of the indices is chosen to \c int for efficiency + /// reasons. Thus the maximum dimension of this implementation is 26 + /// (assuming that the size of \c int is 32 bit). + /// + /// This graph type is fully conform to the \ref concepts::Graph + /// "Graph" concept, and it also has an important extra feature + /// that its maps are real \ref concepts::ReferenceMap + /// "reference map"s. + class HypercubeGraph : public ExtendedHypercubeGraphBase { + public: + + typedef ExtendedHypercubeGraphBase Parent; + + /// \brief Constructs a hypercube graph with \c dim dimensions. + /// + /// Constructs a hypercube graph with \c dim dimensions. + HypercubeGraph(int dim) { construct(dim); } + + /// \brief The number of dimensions. + /// + /// Gives back the number of dimensions. + int dimension() const { + return Parent::dimension(); + } + + /// \brief Returns \c true if the n'th bit of the node is one. + /// + /// Returns \c true if the n'th bit of the node is one. + bool projection(Node node, int n) const { + return Parent::projection(node, n); + } + + /// \brief The dimension id of an edge. + /// + /// Gives back the dimension id of the given edge. + /// It is in the [0..dim-1] range. + int dimension(Edge edge) const { + return Parent::dimension(edge); + } + + /// \brief The dimension id of an arc. + /// + /// Gives back the dimension id of the given arc. + /// It is in the [0..dim-1] range. + int dimension(Arc arc) const { + return Parent::dimension(arc); + } + + /// \brief The index of a node. + /// + /// Gives back the index of the given node. + /// The lower bits of the integer describes the node. + int index(Node node) const { + return Parent::index(node); + } + + /// \brief Gives back a node by its index. + /// + /// Gives back a node by its index. + Node operator()(int ix) const { + return Parent::operator()(ix); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + + /// \brief Linear combination map. + /// + /// This map makes possible to give back a linear combination + /// for each node. It works like the \c std::accumulate function, + /// so it accumulates the \c bf binary function with the \c fv first + /// value. The map accumulates only on that positions (dimensions) + /// where the index of the node is one. The values that have to be + /// accumulated should be given by the \c begin and \c end iterators + /// and the length of this range should be equal to the dimension + /// number of the graph. + /// + ///\code + /// const int DIM = 3; + /// HypercubeGraph graph(DIM); + /// dim2::Point base[DIM]; + /// for (int k = 0; k < DIM; ++k) { + /// base[k].x = rnd(); + /// base[k].y = rnd(); + /// } + /// HypercubeGraph::HyperMap > + /// pos(graph, base, base + DIM, dim2::Point(0.0, 0.0)); + ///\endcode + /// + /// \see HypercubeGraph + template > + class HyperMap { + public: + + /// \brief The key type of the map + typedef Node Key; + /// \brief The value type of the map + typedef T Value; + + /// \brief Constructor for HyperMap. + /// + /// Construct a HyperMap for the given graph. The values that have + /// to be accumulated should be given by the \c begin and \c end + /// iterators and the length of this range should be equal to the + /// dimension number of the graph. + /// + /// This map accumulates the \c bf binary function with the \c fv + /// first value on that positions (dimensions) where the index of + /// the node is one. + template + HyperMap(const Graph& graph, It begin, It end, + T fv = 0, const BF& bf = BF()) + : _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf) + { + LEMON_ASSERT(_values.size() == graph.dimension(), + "Wrong size of range"); + } + + /// \brief The partial accumulated value. + /// + /// Gives back the partial accumulated value. + Value operator[](const Key& k) const { + Value val = _first_value; + int id = _graph.index(k); + int n = 0; + while (id != 0) { + if (id & 1) { + val = _bin_func(val, _values[n]); + } + id >>= 1; + ++n; + } + return val; + } + + private: + const Graph& _graph; + std::vector _values; + T _first_value; + BF _bin_func; + }; + + }; + +} + +#endif diff --git a/test/digraph_test.cc b/test/digraph_test.cc --- a/test/digraph_test.cc +++ b/test/digraph_test.cc @@ -20,7 +20,6 @@ #include #include #include -//#include #include "test_tools.h" #include "graph_test.h" @@ -112,7 +111,6 @@ } - void checkConcepts() { { // Checking digraph components checkConcept(); @@ -145,9 +143,6 @@ { // Checking FullDigraph checkConcept(); } -// { // Checking HyperCubeDigraph -// checkConcept(); -// } } template diff --git a/test/graph_test.cc b/test/graph_test.cc --- a/test/graph_test.cc +++ b/test/graph_test.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "test_tools.h" #include "graph_test.h" @@ -104,9 +105,9 @@ checkGraphEdgeList(G, num * (num - 1) / 2); for (NodeIt n(G); n != INVALID; ++n) { - checkGraphOutArcList(G, n, num - 1); - checkGraphInArcList(G, n, num - 1); - checkGraphIncEdgeList(G, n, num - 1); + checkGraphOutArcList(G, n, num - 1); + checkGraphInArcList(G, n, num - 1); + checkGraphIncEdgeList(G, n, num - 1); } checkGraphConArcList(G, num * (num - 1)); @@ -121,7 +122,7 @@ checkGraphArcMap(G); checkGraphEdgeMap(G); - + for (int i = 0; i < G.nodeNum(); ++i) { check(G.index(G(i)) == i, "Wrong index"); } @@ -177,6 +178,9 @@ { // Checking GridGraph checkConcept(); } + { // Checking HypercubeGraph + checkConcept(); + } } template @@ -312,6 +316,54 @@ } +void checkHypercubeGraph(int dim) { + GRAPH_TYPEDEFS(HypercubeGraph); + + HypercubeGraph G(dim); + checkGraphNodeList(G, 1 << dim); + checkGraphEdgeList(G, dim * (1 << dim-1)); + checkGraphArcList(G, dim * (1 << dim)); + + Node n = G.nodeFromId(dim); + + for (NodeIt n(G); n != INVALID; ++n) { + checkGraphIncEdgeList(G, n, dim); + for (IncEdgeIt e(G, n); e != INVALID; ++e) { + check( (G.u(e) == n && + G.id(G.v(e)) == G.id(n) ^ (1 << G.dimension(e))) || + (G.v(e) == n && + G.id(G.u(e)) == G.id(n) ^ (1 << G.dimension(e))), + "Wrong edge or wrong dimension"); + } + + checkGraphOutArcList(G, n, dim); + for (OutArcIt a(G, n); a != INVALID; ++a) { + check(G.source(a) == n && + G.id(G.target(a)) == G.id(n) ^ (1 << G.dimension(a)), + "Wrong arc or wrong dimension"); + } + + checkGraphInArcList(G, n, dim); + for (InArcIt a(G, n); a != INVALID; ++a) { + check(G.target(a) == n && + G.id(G.source(a)) == G.id(n) ^ (1 << G.dimension(a)), + "Wrong arc or wrong dimension"); + } + } + + checkGraphConArcList(G, (1 << dim) * dim); + checkGraphConEdgeList(G, dim * (1 << dim-1)); + + checkArcDirections(G); + + checkNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + void checkGraphs() { { // Checking ListGraph checkGraph(); @@ -321,7 +373,7 @@ checkGraph(); checkGraphValidity(); } - { // Checking FullGraph + { // Checking FullGraph checkFullGraph(7); checkFullGraph(8); } @@ -332,6 +384,12 @@ checkGridGraph(0, 0); checkGridGraph(1, 1); } + { // Checking HypercubeGraph + checkHypercubeGraph(1); + checkHypercubeGraph(2); + checkHypercubeGraph(3); + checkHypercubeGraph(4); + } } int main() { diff --git a/tools/lemon-0.x-to-1.x.sh b/tools/lemon-0.x-to-1.x.sh --- a/tools/lemon-0.x-to-1.x.sh +++ b/tools/lemon-0.x-to-1.x.sh @@ -81,6 +81,7 @@ -e "s/\/SetStandardProcessedMap/g"\ -e "s/\/graphCopy/g"\ -e "s/\/digraphCopy/g"\ + -e "s/\/HypercubeGraph/g"\ -e "s/\/RangeMap/g"\ -e "s/\/rangeMap/g"\ -e "s/\<\([sS]\)tdMap\>/\1parseMap/g"\