# HG changeset patch # User Balazs Dezso # Date 1289771312 -3600 # Node ID 5ef0ab7b61cdc2c8bb4515605e294f3a7dfe0f01 # Parent 4c89e925cfe2598cf0d74a2bd157b5820c718521 FullBpGraph implementation (#69) diff -r 4c89e925cfe2 -r 5ef0ab7b61cd lemon/bits/graph_extender.h --- a/lemon/bits/graph_extender.h Sun Nov 14 20:06:23 2010 +0100 +++ b/lemon/bits/graph_extender.h Sun Nov 14 22:48:32 2010 +0100 @@ -841,11 +841,14 @@ return Parent::edgeFromId(id); } + Node u(Edge e) const { return this->redNode(e); } + Node v(Edge e) const { return this->blueNode(e); } + Node oppositeNode(const Node &n, const Edge &e) const { - if( n == Parent::u(e)) - return Parent::v(e); - else if( n == Parent::v(e)) - return Parent::u(e); + if( n == u(e)) + return v(e); + else if( n == v(e)) + return u(e); else return INVALID; } @@ -856,7 +859,7 @@ using Parent::direct; Arc direct(const Edge &edge, const Node &node) const { - return Parent::direct(edge, Parent::u(edge) == node); + return Parent::direct(edge, Parent::redNode(edge) == node); } // Alterable extension diff -r 4c89e925cfe2 -r 5ef0ab7b61cd lemon/core.h --- a/lemon/core.h Sun Nov 14 20:06:23 2010 +0100 +++ b/lemon/core.h Sun Nov 14 22:48:32 2010 +0100 @@ -164,7 +164,7 @@ typedef BpGraph::RedIt RedIt; \ typedef BpGraph::RedMap BoolRedMap; \ typedef BpGraph::RedMap IntRedMap; \ - typedef BpGraph::RedMap DoubleRedMap \ + typedef BpGraph::RedMap DoubleRedMap; \ typedef BpGraph::BlueNode BlueNode; \ typedef BpGraph::BlueIt BlueIt; \ typedef BpGraph::BlueMap BoolBlueMap; \ diff -r 4c89e925cfe2 -r 5ef0ab7b61cd lemon/full_graph.h --- a/lemon/full_graph.h Sun Nov 14 20:06:23 2010 +0100 +++ b/lemon/full_graph.h Sun Nov 14 22:48:32 2010 +0100 @@ -621,6 +621,436 @@ }; + class FullBpGraphBase { + + protected: + + int _red_num, _blue_num; + int _node_num, _edge_num; + + public: + + typedef FullBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class FullBpGraphBase; + protected: + + int _id; + explicit 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 FullBpGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + Arc() {} + Arc (Invalid) { _id = -1; } + 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;} + }; + + + protected: + + FullBpGraphBase() + : _red_num(0), _blue_num(0), _node_num(0), _edge_num(0) {} + + void construct(int redNum, int blueNum) { + _red_num = redNum; _blue_num = blueNum; + _node_num = redNum + blueNum; _edge_num = redNum * blueNum; + } + + public: + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int redNum() const { return _red_num; } + int blueNum() const { return _blue_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxRedId() const { return _red_num - 1; } + int maxBlueId() const { return _blue_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + bool red(Node n) const { return n._id < _red_num; } + bool blue(Node n) const { return n._id >= _red_num; } + + Node source(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) % _red_num); + } else { + return Node((a._id >> 1) / _red_num + _red_num); + } + } + Node target(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) / _red_num + _red_num); + } else { + return Node((a._id >> 1) % _red_num); + } + } + + Node redNode(Edge e) const { + return Node(e._id % _red_num); + } + Node blueNode(Edge e) const { + return Node(e._id / _red_num + _red_num); + } + + static bool direction(Arc a) { + return (a._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void firstRed(Node& node) const { + node._id = _red_num - 1; + } + + static void nextRed(Node& node) { + --node._id; + } + + void firstBlue(Node& node) const { + if (_red_num == _node_num) node._id = -1; + else node._id = _node_num - 1; + } + + void nextBlue(Node& node) const { + if (node._id == _red_num) node._id = -1; + else --node._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = _edge_num - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)) + 1; + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)); + } + } + void nextOut(Arc &a) const { + if (a._id & 1) { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } else { + if (a._id % (2 * _red_num) == 0) a._id = -1; + else a._id -= 2; + } + } + + void firstIn(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)); + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)) + 1; + } + } + void nextIn(Arc &a) const { + if (a._id & 1) { + if (a._id % (2 * _red_num) == 1) a._id = -1; + else a._id -= 2; + } else { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + if (v._id < _red_num) { + d = true; + e._id = v._id + _red_num * (_blue_num - 1); + } else { + d = false; + e._id = _red_num - 1 + _red_num * (v._id - _red_num); + } + } + void nextInc(Edge &e, bool& d) const { + if (d) { + e._id -= _red_num; + if (e._id < 0) e._id = -1; + } else { + if (e._id % _red_num == 0) e._id = -1; + else --e._id; + } + } + + static int id(Node v) { return v._id; } + int redId(Node v) const { + LEMON_DEBUG(v._id < _red_num, "Node has to be red"); + return v._id; + } + int blueId(Node v) const { + LEMON_DEBUG(v._id >= _red_num, "Node has to be blue"); + return v._id - _red_num; + } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < _node_num; + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < 2 * _edge_num; + } + bool valid(Edge e) const { + return e._id >= 0 && e._id < _edge_num; + } + + Node redNode(int index) const { + return Node(index); + } + + int redIndex(Node n) const { + return n._id; + } + + Node blueNode(int index) const { + return Node(index + _red_num); + } + + int blueIndex(Node n) const { + return n._id - _red_num; + } + + void clear() { + _red_num = 0; _blue_num = 0; + _node_num = 0; _edge_num = 0; + } + + Edge edge(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Edge(-1); + } else { + return Edge(u._id + _red_num * (v._id - _red_num)); + } + } else { + if (v._id < _red_num) { + return Edge(v._id + _red_num * (u._id - _red_num)); + } else { + return Edge(-1); + } + } + } + + Arc arc(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Arc(-1); + } else { + return Arc(2 * (u._id + _red_num * (v._id - _red_num)) + 1); + } + } else { + if (v._id < _red_num) { + return Arc(2 * (v._id + _red_num * (u._id - _red_num))); + } else { + return Arc(-1); + } + } + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + return prev != INVALID ? INVALID : edge(u, v); + } + + Arc findArc(Node s, Node t, Arc prev = INVALID) const { + return prev != INVALID ? INVALID : arc(s, t); + } + + }; + + typedef BpGraphExtender ExtendedFullBpGraphBase; + + /// \ingroup graphs + /// + /// \brief An undirected full bipartite graph class. + /// + /// FullBpGraph is a simple and fast implmenetation of undirected + /// full bipartite graphs. It contains an edge between every + /// red-blue pairs of nodes, therefore the number of edges is + /// nr*nb. This class is completely static and it needs + /// constant memory space. Thus you can neither add nor delete + /// nodes or edges, however the structure can be resized using + /// resize(). + /// + /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \sa FullGraph + class FullBpGraph : public ExtendedFullBpGraphBase { + public: + + typedef ExtendedFullBpGraphBase Parent; + + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and edges will be zero. + FullBpGraph() { construct(0, 0); } + + /// \brief Constructor + /// + /// Constructor. + /// \param redNum The number of the red nodes. + /// \param blueNum The number of the blue nodes. + FullBpGraph(int redNum, int blueNum) { construct(redNum, blueNum); } + + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int redNum, int blueNum) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + Parent::notifier(BlueNode()).clear(); + Parent::notifier(RedNode()).clear(); + construct(redNum, blueNum); + Parent::notifier(RedNode()).build(); + Parent::notifier(BlueNode()).build(); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + /// \brief Returns the red node with the given index. + /// + /// Returns the red node with the given index. Since this + /// structure is completely static, the red nodes can be indexed + /// with integers from the range [0..redNum()-1]. + /// \sa redIndex() + Node redNode(int index) const { return Parent::redNode(index); } + + /// \brief Returns the index of the given red node. + /// + /// Returns the index of the given red node. Since this structure + /// is completely static, the red nodes can be indexed with + /// integers from the range [0..redNum()-1]. + /// + /// \sa operator()() + int redIndex(Node node) const { return Parent::redIndex(node); } + + /// \brief Returns the blue node with the given index. + /// + /// Returns the blue node with the given index. Since this + /// structure is completely static, the blue nodes can be indexed + /// with integers from the range [0..blueNum()-1]. + /// \sa blueIndex() + Node blueNode(int index) const { return Parent::blueNode(index); } + + /// \brief Returns the index of the given blue node. + /// + /// Returns the index of the given blue node. Since this structure + /// is completely static, the blue nodes can be indexed with + /// integers from the range [0..blueNum()-1]. + /// + /// \sa operator()() + int blueIndex(Node node) const { return Parent::blueIndex(node); } + + /// \brief Returns the edge which connects the given nodes. + /// + /// Returns the edge which connects the given nodes. + Edge edge(const Node& u, const Node& v) const { + return Parent::edge(u, v); + } + + /// \brief Returns the arc which connects the given nodes. + /// + /// Returns the arc which connects the given nodes. + Arc arc(const Node& u, const Node& v) const { + return Parent::arc(u, v); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of red nodes. + int redNum() const { return Parent::redNum(); } + /// \brief Number of blue nodes. + int blueNum() const { return Parent::blueNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + }; + } //namespace lemon diff -r 4c89e925cfe2 -r 5ef0ab7b61cd lemon/smart_graph.h --- a/lemon/smart_graph.h Sun Nov 14 20:06:23 2010 +0100 +++ b/lemon/smart_graph.h Sun Nov 14 22:48:32 2010 +0100 @@ -925,9 +925,6 @@ Node redNode(Edge e) const { return Node(arcs[2 * e._id].target); } Node blueNode(Edge e) const { return Node(arcs[2 * e._id + 1].target); } - Node u(Edge e) const { return redNode(e); } - Node v(Edge e) const { return blueNode(e); } - static bool direction(Arc a) { return (a._id & 1) == 1; } @@ -1101,22 +1098,22 @@ /// \ingroup graphs /// - /// \brief A smart undirected graph class. + /// \brief A smart undirected bipartite graph class. /// - /// \ref SmartBpGraph is a simple and fast graph implementation. + /// \ref SmartBpGraph is a simple and fast bipartite graph implementation. /// It is also quite memory efficient but at the price /// that it does not support node and edge deletion /// (except for the Snapshot feature). /// - /// This type fully conforms to the \ref concepts::Graph "Graph concept" + /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept" /// and it also provides some additional functionalities. /// Most of its member functions and nested classes are documented /// only in the concept class. /// /// This class provides constant time counting for nodes, edges and arcs. /// - /// \sa concepts::Graph - /// \sa SmartDigraph + /// \sa concepts::BpGraph + /// \sa SmartGraph class SmartBpGraph : public ExtendedSmartBpGraphBase { typedef ExtendedSmartBpGraphBase Parent; diff -r 4c89e925cfe2 -r 5ef0ab7b61cd test/bpgraph_test.cc --- a/test/bpgraph_test.cc Sun Nov 14 20:06:23 2010 +0100 +++ b/test/bpgraph_test.cc Sun Nov 14 22:48:32 2010 +0100 @@ -19,7 +19,7 @@ #include //#include #include -//#include +#include #include "test_tools.h" #include "graph_test.h" @@ -250,12 +250,90 @@ } } +void checkFullBpGraph(int redNum, int blueNum) { + typedef FullBpGraph BpGraph; + BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + G.resize(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + for (RedIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, blueNum); + checkGraphInArcList(G, n, blueNum); + checkGraphIncEdgeList(G, n, blueNum); + } + + for (BlueIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, redNum); + checkGraphInArcList(G, n, redNum); + checkGraphIncEdgeList(G, n, redNum); + } + + checkGraphConArcList(G, 2 * redNum * blueNum); + checkGraphConEdgeList(G, redNum * blueNum); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedMap(G); + checkGraphBlueMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + for (int i = 0; i < G.redNum(); ++i) { + check(G.red(G.redNode(i)), "Wrong node"); + check(G.redIndex(G.redNode(i)) == i, "Wrong index"); + } + + for (int i = 0; i < G.blueNum(); ++i) { + check(G.blue(G.blueNode(i)), "Wrong node"); + check(G.blueIndex(G.blueNode(i)) == i, "Wrong index"); + } + + for (NodeIt u(G); u != INVALID; ++u) { + for (NodeIt v(G); v != INVALID; ++v) { + Edge e = G.edge(u, v); + Arc a = G.arc(u, v); + if (G.red(u) == G.red(v)) { + check(e == INVALID, "Wrong edge lookup"); + check(a == INVALID, "Wrong arc lookup"); + } else { + check((G.u(e) == u && G.v(e) == v) || + (G.u(e) == v && G.v(e) == u), "Wrong edge lookup"); + check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup"); + } + } + } + +} + void checkGraphs() { { // Checking SmartGraph checkBpGraphBuild(); checkBpGraphSnapshot(); checkBpGraphValidity(); } + { // Checking FullBpGraph + checkFullBpGraph(6, 8); + checkFullBpGraph(7, 4); + } } int main() {