# HG changeset patch # User Balazs Dezso # Date 1289761583 -3600 # Node ID 4c89e925cfe2598cf0d74a2bd157b5820c718521 # Parent 2e959a5a0c2d1597ddc731f8a3cc558d5787ba31 SmartBpGraph implementation (#69) diff -r 2e959a5a0c2d -r 4c89e925cfe2 lemon/bits/graph_extender.h --- a/lemon/bits/graph_extender.h Sun Nov 14 16:35:31 2010 +0100 +++ b/lemon/bits/graph_extender.h Sun Nov 14 20:06:23 2010 +0100 @@ -746,6 +746,610 @@ }; + // \ingroup _graphbits + // + // \brief Extender for the BpGraphs + template + class BpGraphExtender : public Base { + typedef Base Parent; + + public: + + typedef BpGraphExtender BpGraph; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + // BpGraph extension + + class RedNode : public Node { + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + RedNode(const Node& node) : Node(node) {} + }; + class BlueNode : public Node { + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + BlueNode(const Node& node) : Node(node) {} + }; + + using Parent::first; + using Parent::next; + + void first(RedNode& node) const { + Parent::firstRed(node); + } + + void next(RedNode& node) const { + Parent::nextRed(node); + } + + void first(BlueNode& node) const { + Parent::firstBlue(node); + } + + void next(BlueNode& node) const { + Parent::nextBlue(node); + } + + using Parent::id; + + int id(const RedNode& node) const { + return Parent::redId(node); + } + + int id(const BlueNode& node) const { + return Parent::blueId(node); + } + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(RedNode) const { + return Parent::maxRedId(); + } + + int maxId(BlueNode) const { + return Parent::maxBlueId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + static Node fromId(int id, Node) { + return Parent::nodeFromId(id); + } + + static Arc fromId(int id, Arc) { + return Parent::arcFromId(id); + } + + static Edge fromId(int id, Edge) { + return Parent::edgeFromId(id); + } + + 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); + else + return INVALID; + } + + Arc oppositeArc(const Arc &arc) const { + return Parent::direct(arc, !Parent::direction(arc)); + } + + using Parent::direct; + Arc direct(const Edge &edge, const Node &node) const { + return Parent::direct(edge, Parent::u(edge) == node); + } + + // Alterable extension + + typedef AlterationNotifier NodeNotifier; + typedef AlterationNotifier RedNodeNotifier; + typedef AlterationNotifier BlueNodeNotifier; + typedef AlterationNotifier ArcNotifier; + typedef AlterationNotifier EdgeNotifier; + + + protected: + + mutable NodeNotifier node_notifier; + mutable RedNodeNotifier red_node_notifier; + mutable BlueNodeNotifier blue_node_notifier; + mutable ArcNotifier arc_notifier; + mutable EdgeNotifier edge_notifier; + + public: + + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + RedNodeNotifier& notifier(RedNode) const { + return red_node_notifier; + } + + BlueNodeNotifier& notifier(BlueNode) const { + return blue_node_notifier; + } + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + + + class NodeIt : public Node { + const BpGraph* _graph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + NodeIt(const BpGraph& graph, const Node& node) + : Node(node), _graph(&graph) {} + + NodeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class RedIt : public Node { + const BpGraph* _graph; + public: + + RedIt() {} + + RedIt(Invalid i) : Node(i) { } + + explicit RedIt(const BpGraph& graph) : _graph(&graph) { + _graph->firstRed(static_cast(*this)); + } + + RedIt(const BpGraph& graph, const Node& node) + : Node(node), _graph(&graph) { + LEMON_DEBUG(_graph->red(node), "Node has to be red."); + } + + RedIt& operator++() { + _graph->nextRed(*this); + return *this; + } + + }; + + class BlueIt : public Node { + const BpGraph* _graph; + public: + + BlueIt() {} + + BlueIt(Invalid i) : Node(i) { } + + explicit BlueIt(const BpGraph& graph) : _graph(&graph) { + _graph->firstBlue(static_cast(*this)); + } + + BlueIt(const BpGraph& graph, const Node& node) + : Node(node), _graph(&graph) { + LEMON_DEBUG(_graph->blue(node), "Node has to be blue."); + } + + BlueIt& operator++() { + _graph->nextBlue(*this); + return *this; + } + + }; + + + class ArcIt : public Arc { + const BpGraph* _graph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + ArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) { } + + ArcIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const BpGraph* _graph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstOut(*this, node); + } + + OutArcIt(const BpGraph& graph, const Arc& arc) + : Arc(arc), _graph(&graph) {} + + OutArcIt& operator++() { + _graph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const BpGraph* _graph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstIn(*this, node); + } + + InArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) {} + + InArcIt& operator++() { + _graph->nextIn(*this); + return *this; + } + + }; + + + class EdgeIt : public Parent::Edge { + const BpGraph* _graph; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + EdgeIt(const BpGraph& graph, const Edge& edge) : + Edge(edge), _graph(&graph) { } + + EdgeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Parent::Edge { + friend class BpGraphExtender; + const BpGraph* _graph; + bool _direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } + + IncEdgeIt(const BpGraph& graph, const Node &node) : _graph(&graph) { + _graph->firstInc(*this, _direction, node); + } + + IncEdgeIt(const BpGraph& graph, const Edge &edge, const Node &node) + : _graph(&graph), Edge(edge) { + _direction = (_graph->source(edge) == node); + } + + IncEdgeIt& operator++() { + _graph->nextInc(*this, _direction); + return *this; + } + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + // Base node of the iterator + // + // Returns the base node of the iterator + Node baseNode(const IncEdgeIt &edge) const { + return edge._direction ? this->u(edge) : this->v(edge); + } + // Running node of the iterator + // + // Returns the running node of the iterator + Node runningNode(const IncEdgeIt &edge) const { + return edge._direction ? this->v(edge) : this->u(edge); + } + + // Mappable extension + + template + class NodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit NodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + NodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class RedMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit RedMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + RedMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + RedMap& operator=(const RedMap& cmap) { + return operator=(cmap); + } + + template + RedMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class BlueMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit BlueMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + BlueMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + BlueMap& operator=(const BlueMap& cmap) { + return operator=(cmap); + } + + template + BlueMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const BpGraph& graph) + : Parent(graph) {} + ArcMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + template + class EdgeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit EdgeMap(const BpGraph& graph) + : Parent(graph) {} + + EdgeMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + // Alteration extension + + Node addRedNode() { + Node node = Parent::addRedNode(); + notifier(RedNode()).add(node); + notifier(Node()).add(node); + return node; + } + + Node addBlueNode() { + Node node = Parent::addBlueNode(); + notifier(BlueNode()).add(node); + notifier(Node()).add(node); + return node; + } + + Edge addEdge(const Node& from, const Node& to) { + Edge edge = Parent::addEdge(from, to); + notifier(Edge()).add(edge); + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).add(av); + return edge; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Edge()).clear(); + notifier(Node()).clear(); + notifier(BlueNode()).clear(); + notifier(RedNode()).clear(); + Parent::clear(); + } + + template + void build(const BpGraph& graph, NodeRefMap& nodeRef, + EdgeRefMap& edgeRef) { + Parent::build(graph, nodeRef, edgeRef); + notifier(RedNode()).build(); + notifier(BlueNode()).build(); + notifier(Node()).build(); + notifier(Edge()).build(); + notifier(Arc()).build(); + } + + void erase(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + + if (Parent::red(node)) { + notifier(RedNode()).erase(node); + } else { + notifier(BlueNode()).erase(node); + } + + notifier(Node()).erase(node); + Parent::erase(node); + } + + void erase(const Edge& edge) { + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).erase(av); + notifier(Edge()).erase(edge); + Parent::erase(edge); + } + + BpGraphExtender() { + red_node_notifier.setContainer(*this); + blue_node_notifier.setContainer(*this); + node_notifier.setContainer(*this); + arc_notifier.setContainer(*this); + edge_notifier.setContainer(*this); + } + + ~BpGraphExtender() { + edge_notifier.clear(); + arc_notifier.clear(); + node_notifier.clear(); + blue_node_notifier.clear(); + red_node_notifier.clear(); + } + + }; + } #endif diff -r 2e959a5a0c2d -r 4c89e925cfe2 lemon/bits/traits.h --- a/lemon/bits/traits.h Sun Nov 14 16:35:31 2010 +0100 +++ b/lemon/bits/traits.h Sun Nov 14 20:06:23 2010 +0100 @@ -151,6 +151,88 @@ }; + template + struct RedNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct RedNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::RedNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::RedNode Item; + typedef typename GR::RedIt ItemIt; + + typedef typename RedNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template RedMap { + typedef typename GR::template RedMap Parent; + + public: + typedef typename GR::template RedMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + + template + struct BlueNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct BlueNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::BlueNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::BlueNode Item; + typedef typename GR::BlueIt ItemIt; + + typedef typename BlueNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template BlueMap { + typedef typename GR::template BlueMap Parent; + + public: + typedef typename GR::template BlueMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + template struct MapTraits { typedef False ReferenceMapTag; diff -r 2e959a5a0c2d -r 4c89e925cfe2 lemon/core.h --- a/lemon/core.h Sun Nov 14 16:35:31 2010 +0100 +++ b/lemon/core.h Sun Nov 14 20:06:23 2010 +0100 @@ -148,6 +148,48 @@ typedef typename Graph::template EdgeMap IntEdgeMap; \ typedef typename Graph::template EdgeMap DoubleEdgeMap + ///Create convenience typedefs for the bipartite graph types and iterators + + ///This \c \#define creates the same convenient type definitions as defined + ///by \ref GRAPH_TYPEDEFS(BpGraph) and ten more, namely it creates + ///\c RedNode, \c RedIt, \c BoolRedMap, \c IntRedMap, \c DoubleRedMap, + ///\c BlueNode, \c BlueIt, \c BoolBlueMap, \c IntBlueMap, \c DoubleBlueMap. + /// + ///\note If the graph type is a dependent type, ie. the graph type depend + ///on a template parameter, then use \c TEMPLATE_BPGRAPH_TYPEDEFS() + ///macro. +#define BPGRAPH_TYPEDEFS(BpGraph) \ + GRAPH_TYPEDEFS(BpGraph); \ + typedef BpGraph::RedNode RedNode; \ + typedef BpGraph::RedIt RedIt; \ + typedef BpGraph::RedMap BoolRedMap; \ + typedef BpGraph::RedMap IntRedMap; \ + typedef BpGraph::RedMap DoubleRedMap \ + typedef BpGraph::BlueNode BlueNode; \ + typedef BpGraph::BlueIt BlueIt; \ + typedef BpGraph::BlueMap BoolBlueMap; \ + typedef BpGraph::BlueMap IntBlueMap; \ + typedef BpGraph::BlueMap DoubleBlueMap + + ///Create convenience typedefs for the bipartite graph types and iterators + + ///\see BPGRAPH_TYPEDEFS + /// + ///\note Use this macro, if the graph type is a dependent type, + ///ie. the graph type depend on a template parameter. +#define TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph) \ + TEMPLATE_GRAPH_TYPEDEFS(BpGraph); \ + typedef typename BpGraph::RedNode RedNode; \ + typedef typename BpGraph::RedIt RedIt; \ + typedef typename BpGraph::template RedMap BoolRedMap; \ + typedef typename BpGraph::template RedMap IntRedMap; \ + typedef typename BpGraph::template RedMap DoubleRedMap; \ + typedef typename BpGraph::BlueNode BlueNode; \ + typedef typename BpGraph::BlueIt BlueIt; \ + typedef typename BpGraph::template BlueMap BoolBlueMap; \ + typedef typename BpGraph::template BlueMap IntBlueMap; \ + typedef typename BpGraph::template BlueMap DoubleBlueMap + /// \brief Function to count the items in a graph. /// /// This function counts the items (nodes, arcs etc.) in a graph. @@ -199,6 +241,74 @@ return _core_bits::CountNodesSelector::count(g); } + namespace _graph_utils_bits { + + template + struct CountRedNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountRedNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.redNum(); + } + }; + } + + /// \brief Function to count the red nodes in the graph. + /// + /// This function counts the red nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e redNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countRedNodes(const Graph& g) { + return _graph_utils_bits::CountRedNodesSelector::count(g); + } + + namespace _graph_utils_bits { + + template + struct CountBlueNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountBlueNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.blueNum(); + } + }; + } + + /// \brief Function to count the blue nodes in the graph. + /// + /// This function counts the blue nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e blueNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countBlueNodes(const Graph& g) { + return _graph_utils_bits::CountBlueNodesSelector::count(g); + } + // Arc counting: namespace _core_bits { @@ -1257,7 +1367,7 @@ /// The Digraph type typedef GR Digraph; - + protected: class AutoNodeMap : public ItemSetTraits::template Map::Type diff -r 2e959a5a0c2d -r 4c89e925cfe2 lemon/smart_graph.h --- a/lemon/smart_graph.h Sun Nov 14 16:35:31 2010 +0100 +++ b/lemon/smart_graph.h Sun Nov 14 20:06:23 2010 +0100 @@ -405,8 +405,6 @@ std::vector nodes; std::vector arcs; - int first_free_arc; - public: typedef SmartGraphBase Graph; @@ -811,6 +809,514 @@ }; }; + class SmartBpGraphBase { + + protected: + + struct NodeT { + int first_out; + int partition_next; + int partition_index; + bool red; + }; + + struct ArcT { + int target; + int next_out; + }; + + std::vector nodes; + std::vector arcs; + + int first_red, first_blue; + + public: + + typedef SmartBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class SmartBpGraphBase; + 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 SmartBpGraphBase; + 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 SmartBpGraphBase; + 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;} + }; + + + + SmartBpGraphBase() + : nodes(), arcs(), first_red(-1), first_blue(-1) {} + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return nodes.size(); } + int redNum() const { + return first_red == -1 ? 0 : nodes[first_red].partition_index + 1; + } + int blueNum() const { + return first_blue == -1 ? 0 : nodes[first_blue].partition_index + 1; + } + int edgeNum() const { return arcs.size() / 2; } + int arcNum() const { return arcs.size(); } + + int maxNodeId() const { return nodes.size()-1; } + int maxRedId() const { + return first_red == -1 ? -1 : nodes[first_red].partition_index; + } + int maxBlueId() const { + return first_blue == -1 ? -1 : nodes[first_blue].partition_index; + } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + bool red(Node n) const { return nodes[n._id].red; } + bool blue(Node n) const { return !nodes[n._id].red; } + + Node source(Arc a) const { return Node(arcs[a._id ^ 1].target); } + Node target(Arc a) const { return Node(arcs[a._id].target); } + + 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; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = nodes.size() - 1; + } + + static void next(Node& node) { + --node._id; + } + + void firstRed(Node& node) const { + node._id = first_red; + } + + void nextRed(Node& node) const { + node._id = nodes[node._id].partition_next; + } + + void firstBlue(Node& node) const { + node._id = first_blue; + } + + void nextBlue(Node& node) const { + node._id = nodes[node._id].partition_next; + } + + void first(Arc& arc) const { + arc._id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = arcs.size() / 2 - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &arc, const Node& v) const { + arc._id = nodes[v._id].first_out; + } + void nextOut(Arc &arc) const { + arc._id = arcs[arc._id].next_out; + } + + void firstIn(Arc &arc, const Node& v) const { + arc._id = ((nodes[v._id].first_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + void nextIn(Arc &arc) const { + arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + + void firstInc(Edge &arc, bool& d, const Node& v) const { + int de = nodes[v._id].first_out; + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + void nextInc(Edge &arc, bool& d) const { + int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + + static int id(Node v) { return v._id; } + int redId(Node v) const { + LEMON_DEBUG(nodes[v._id].red, "Node has to be red"); + return nodes[v._id].partition_index; + } + int blueId(Node v) const { + LEMON_DEBUG(nodes[v._id].red, "Node has to be blue"); + return nodes[v._id].partition_index; + } + 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 < static_cast(nodes.size()); + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < static_cast(arcs.size()); + } + bool valid(Edge e) const { + return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); + } + + Node addRedNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = true; + if (first_red == -1) { + nodes[n].partition_index = 0; + } else { + nodes[n].partition_index = nodes[first_red].partition_index + 1; + } + nodes[n].partition_next = first_red; + first_red = n; + + return Node(n); + } + + Node addBlueNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = false; + if (first_blue == -1) { + nodes[n].partition_index = 0; + } else { + nodes[n].partition_index = nodes[first_blue].partition_index + 1; + } + nodes[n].partition_next = first_blue; + first_blue = n; + + return Node(n); + } + + Edge addEdge(Node u, Node v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + + arcs[n].target = u._id; + arcs[n | 1].target = v._id; + + arcs[n].next_out = nodes[v._id].first_out; + nodes[v._id].first_out = n; + + arcs[n | 1].next_out = nodes[u._id].first_out; + nodes[u._id].first_out = (n | 1); + + return Edge(n / 2); + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_red = -1; + first_blue = -1; + } + + }; + + typedef BpGraphExtender ExtendedSmartBpGraphBase; + + /// \ingroup graphs + /// + /// \brief A smart undirected graph class. + /// + /// \ref SmartBpGraph is a simple and fast 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" + /// 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 + class SmartBpGraph : public ExtendedSmartBpGraphBase { + typedef ExtendedSmartBpGraphBase Parent; + + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + SmartBpGraph(const SmartBpGraph &) : ExtendedSmartBpGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const SmartBpGraph &) {} + + public: + + /// Constructor + + /// Constructor. + /// + SmartBpGraph() {} + + /// \brief Add a new red node to the graph. + /// + /// This function adds a red new node to the graph. + /// \return The new node. + Node addRedNode() { return Parent::addRedNode(); } + + /// \brief Add a new blue node to the graph. + /// + /// This function adds a blue new node to the graph. + /// \return The new node. + Node addBlueNode() { return Parent::addBlueNode(); } + + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(Node red, Node blue) { + LEMON_DEBUG(Parent::red(red) && Parent::blue(blue), + "Edge has to be formed by a red and a blue nodes"); + return Parent::addEdge(red, blue); + } + + /// \brief Node validity check + /// + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \warning A removed node (using Snapshot) could become valid again + /// if new nodes are added to the graph. + bool valid(Node n) const { return Parent::valid(n); } + + /// \brief Edge validity check + /// + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + + /// \brief Arc validity check + /// + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \warning A removed arc (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + + public: + + class Snapshot; + + protected: + + void saveSnapshot(Snapshot &s) + { + s._graph = this; + s.node_num = nodes.size(); + s.arc_num = arcs.size(); + } + + void restoreSnapshot(const Snapshot &s) + { + while(s.arc_num dir; + dir.push_back(arcFromId(n)); + dir.push_back(arcFromId(n-1)); + Parent::notifier(Arc()).erase(dir); + nodes[arcs[n-1].target].first_out=arcs[n].next_out; + nodes[arcs[n].target].first_out=arcs[n-1].next_out; + arcs.pop_back(); + arcs.pop_back(); + } + while(s.node_numrestoreSnapshot(*this); + } + }; + }; + } //namespace lemon diff -r 2e959a5a0c2d -r 4c89e925cfe2 test/bpgraph_test.cc --- a/test/bpgraph_test.cc Sun Nov 14 16:35:31 2010 +0100 +++ b/test/bpgraph_test.cc Sun Nov 14 20:06:23 2010 +0100 @@ -18,10 +18,8 @@ #include //#include -//#include +#include //#include -//#include -//#include #include "test_tools.h" #include "graph_test.h" @@ -29,6 +27,192 @@ using namespace lemon; using namespace lemon::concepts; +template +void checkBpGraphBuild() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + checkGraphNodeList(G, 0); + checkGraphRedNodeList(G, 0); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + G.reserveNode(3); + G.reserveEdge(3); + + Node + rn1 = G.addRedNode(); + checkGraphNodeList(G, 1); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + Node + bn1 = G.addBlueNode(), + bn2 = G.addBlueNode(); + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + Edge e1 = G.addEdge(rn1, bn2); + check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge"); + check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge"); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 1); + checkGraphArcList(G, 2); + + checkGraphIncEdgeArcLists(G, rn1, 1); + checkGraphIncEdgeArcLists(G, bn1, 0); + checkGraphIncEdgeArcLists(G, bn2, 1); + + checkGraphConEdgeList(G, 1); + checkGraphConArcList(G, 2); + + Edge + e2 = G.addEdge(rn1, bn1), + e3 = G.addEdge(rn1, bn2); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, rn1, 3); + checkGraphIncEdgeArcLists(G, bn1, 1); + checkGraphIncEdgeArcLists(G, bn2, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedMap(G); + checkGraphBlueMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + +template +void checkBpGraphSnapshot() { + TEMPLATE_BPGRAPH_TYPEDEFS(Graph); + + Graph G; + Node + n1 = G.addRedNode(), + n2 = G.addBlueNode(), + n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), + e2 = G.addEdge(n1, n3); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + typename Graph::Snapshot snapshot(G); + + Node n4 = G.addRedNode(); + G.addEdge(n4, n2); + G.addEdge(n4, n3); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + snapshot.restore(); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 1); + checkGraphIncEdgeArcLists(G, n3, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedMap(G); + checkGraphBlueMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + G.addRedNode(); + snapshot.save(G); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); +} + +template +void checkBpGraphValidity() { + TEMPLATE_GRAPH_TYPEDEFS(Graph); + Graph g; + + Node + n1 = g.addRedNode(), + n2 = g.addBlueNode(), + n3 = g.addBlueNode(); + + Edge + e1 = g.addEdge(n1, n2), + e2 = g.addEdge(n1, n3); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + check(g.valid(g.direct(e1, true)), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + void checkConcepts() { { // Checking graph components checkConcept(); @@ -51,16 +235,27 @@ checkConcept, ErasableBpGraphComponent<> >(); - checkConcept, - ClearableGraphComponent<> >(); + checkConcept, + ClearableBpGraphComponent<> >(); } { // Checking skeleton graph checkConcept(); } + { // Checking SmartBpGraph + checkConcept(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + } } void checkGraphs() { + { // Checking SmartGraph + checkBpGraphBuild(); + checkBpGraphSnapshot(); + checkBpGraphValidity(); + } } int main() { diff -r 2e959a5a0c2d -r 4c89e925cfe2 test/graph_test.h --- a/test/graph_test.h Sun Nov 14 16:35:31 2010 +0100 +++ b/test/graph_test.h Sun Nov 14 20:06:23 2010 +0100 @@ -41,6 +41,30 @@ } template + void checkGraphRedNodeList(const Graph &G, int cnt) + { + typename Graph::RedIt n(G); + for(int i=0;i + void checkGraphBlueNodeList(const Graph &G, int cnt) + { + typename Graph::BlueIt n(G); + for(int i=0;i void checkGraphArcList(const Graph &G, int cnt) { typename Graph::ArcIt e(G); @@ -166,6 +190,7 @@ template void checkNodeIds(const Graph& G) { + typedef typename Graph::Node Node; std::set values; for (typename Graph::NodeIt n(G); n != INVALID; ++n) { check(G.nodeFromId(G.id(n)) == n, "Wrong id"); @@ -173,10 +198,40 @@ check(G.id(n) <= G.maxNodeId(), "Wrong maximum id"); values.insert(G.id(n)); } + check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id"); + } + + template + void checkRedNodeIds(const Graph& G) { + typedef typename Graph::RedNode RedNode; + std::set values; + for (typename Graph::RedIt n(G); n != INVALID; ++n) { + check(G.red(n), "Wrong partition"); + check(G.redId(n) == G.id(RedNode(n)), "Wrong id"); + check(values.find(G.redId(n)) == values.end(), "Wrong id"); + check(G.redId(n) <= G.maxRedId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id"); + } + + template + void checkBlueNodeIds(const Graph& G) { + typedef typename Graph::BlueNode BlueNode; + std::set values; + for (typename Graph::BlueIt n(G); n != INVALID; ++n) { + check(G.blue(n), "Wrong partition"); + check(G.blueId(n) == G.id(BlueNode(n)), "Wrong id"); + check(values.find(G.blueId(n)) == values.end(), "Wrong id"); + check(G.blueId(n) <= G.maxBlueId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id"); } template void checkArcIds(const Graph& G) { + typedef typename Graph::Arc Arc; std::set values; for (typename Graph::ArcIt a(G); a != INVALID; ++a) { check(G.arcFromId(G.id(a)) == a, "Wrong id"); @@ -184,10 +239,12 @@ check(G.id(a) <= G.maxArcId(), "Wrong maximum id"); values.insert(G.id(a)); } + check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id"); } template void checkEdgeIds(const Graph& G) { + typedef typename Graph::Edge Edge; std::set values; for (typename Graph::EdgeIt e(G); e != INVALID; ++e) { check(G.edgeFromId(G.id(e)) == e, "Wrong id"); @@ -195,6 +252,7 @@ check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id"); values.insert(G.id(e)); } + check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id"); } template @@ -228,6 +286,66 @@ } template + void checkGraphRedMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::RedIt RedIt; + + typedef typename Graph::template RedMap IntRedMap; + IntRedMap map(G, 42); + for (RedIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (RedIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (RedIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphBlueMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::BlueIt BlueIt; + + typedef typename Graph::template BlueMap IntBlueMap; + IntBlueMap map(G, 42); + for (BlueIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (BlueIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (BlueIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template void checkGraphArcMap(const Graph& G) { typedef typename Graph::Arc Arc; typedef typename Graph::ArcIt ArcIt;