/* -*- C++ -*- * src/lemon/smart_graph.h - Part of LEMON, a generic C++ optimization library * * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Combinatorial Optimization Research Group, 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 LEMON_SMART_GRAPH_H #define LEMON_SMART_GRAPH_H ///\ingroup graphs ///\file ///\brief SmartGraph and SymSmartGraph classes. #include #include #include #include #include #include namespace lemon { /// \addtogroup graphs /// @{ // class SymSmartGraph; ///A smart graph class. ///This 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. ///It conforms to ///the \ref skeleton::ExtendableGraph "ExtendableGraph" concept. ///\sa skeleton::ExtendableGraph. /// ///\todo Some member functions could be \c static. /// ///\todo A possibly useful functionality: a function saveState() would ///give back a data sturcture X and then the function restoreState(X) ///would remove the nodes and edges added after the call of saveState(). ///Of course it should be used as a stack. (Maybe X is not necessary.) /// ///\author Alpar Juttner class SmartGraph { struct NodeT { int first_in,first_out; NodeT() : first_in(-1), first_out(-1) {} }; struct EdgeT { int head, tail, next_in, next_out; //FIXME: is this necessary? EdgeT() : next_in(-1), next_out(-1) {} }; std::vector nodes; std::vector edges; public: typedef SmartGraph Graph; class Node; class Edge; class NodeIt; class EdgeIt; class OutEdgeIt; class InEdgeIt; // Create map registries. CREATE_MAP_REGISTRIES; // Create node and edge maps. CREATE_MAPS(ArrayMap); public: SmartGraph() : nodes(), edges() { } SmartGraph(const SmartGraph &_g) : nodes(_g.nodes), edges(_g.edges) { } ///Number of nodes. int nodeNum() const { return nodes.size(); } ///Number of edges. int edgeNum() const { return edges.size(); } /// Maximum node ID. /// Maximum node ID. ///\sa id(Node) int maxNodeId() const { return nodes.size()-1; } /// Maximum edge ID. /// Maximum edge ID. ///\sa id(Edge) int maxEdgeId() const { return edges.size()-1; } Node tail(Edge e) const { return edges[e.n].tail; } Node head(Edge e) const { return edges[e.n].head; } NodeIt& first(NodeIt& v) const { v=NodeIt(*this); return v; } EdgeIt& first(EdgeIt& e) const { e=EdgeIt(*this); return e; } OutEdgeIt& first(OutEdgeIt& e, const Node v) const { e=OutEdgeIt(*this,v); return e; } InEdgeIt& first(InEdgeIt& e, const Node v) const { e=InEdgeIt(*this,v); return e; } /// Node ID. /// The ID of a valid Node is a nonnegative integer not greater than /// \ref maxNodeId(). The range of the ID's is not surely continuous /// and the greatest node ID can be actually less then \ref maxNodeId(). /// /// The ID of the \ref INVALID node is -1. ///\return The ID of the node \c v. static int id(Node v) { return v.n; } /// Edge ID. /// The ID of a valid Edge is a nonnegative integer not greater than /// \ref maxEdgeId(). The range of the ID's is not surely continuous /// and the greatest edge ID can be actually less then \ref maxEdgeId(). /// /// The ID of the \ref INVALID edge is -1. ///\return The ID of the edge \c e. static int id(Edge e) { return e.n; } Node addNode() { Node n; n.n=nodes.size(); nodes.push_back(NodeT()); //FIXME: Hmmm... node_maps.add(n); return n; } Edge addEdge(Node u, Node v) { Edge e; e.n=edges.size(); edges.push_back(EdgeT()); //FIXME: Hmmm... edges[e.n].tail=u.n; edges[e.n].head=v.n; edges[e.n].next_out=nodes[u.n].first_out; edges[e.n].next_in=nodes[v.n].first_in; nodes[u.n].first_out=nodes[v.n].first_in=e.n; edge_maps.add(e); return e; } /// Finds an edge between two nodes. /// Finds an edge from node \c u to node \c v. /// /// If \c prev is \ref INVALID (this is the default value), then /// It finds the first edge from \c u to \c v. Otherwise it looks for /// the next edge from \c u to \c v after \c prev. /// \return The found edge or INVALID if there is no such an edge. Edge findEdge(Node u,Node v, Edge prev = INVALID) { int e = (prev.n==-1)? nodes[u.n].first_out : edges[prev.n].next_out; while(e!=-1 && edges[e].tail!=v.n) e = edges[e].next_out; prev.n=e; return prev; } void clear() { edge_maps.clear(); edges.clear(); node_maps.clear(); nodes.clear(); } class Node { friend class SmartGraph; template friend class NodeMap; friend class Edge; friend class OutEdgeIt; friend class InEdgeIt; friend class SymEdge; protected: int n; friend int SmartGraph::id(Node v); Node(int nn) {n=nn;} public: Node() {} Node (Invalid) { n=-1; } bool operator==(const Node i) const {return n==i.n;} bool operator!=(const Node i) const {return n!=i.n;} bool operator<(const Node i) const {return nnodes.size()+1)-1; return *this; } // ///Validity check // operator bool() { return Node::operator bool(); } }; class Edge { friend class SmartGraph; template friend class EdgeMap; friend class SymSmartGraph; friend class Node; friend class NodeIt; protected: int n; friend int SmartGraph::id(Edge e); Edge(int nn) {n=nn;} public: /// An Edge with id \c n. Edge() { } Edge (Invalid) { n=-1; } bool operator==(const Edge i) const {return n==i.n;} bool operator!=(const Edge i) const {return n!=i.n;} bool operator<(const Edge i) const {return nedges[n].next_out; return *this; } // ///Validity check // operator bool() { return Edge::operator bool(); } }; class InEdgeIt : public Edge { const SmartGraph *G; friend class SmartGraph; public: InEdgeIt() : Edge() { } InEdgeIt(const SmartGraph& _G, Edge e) : Edge(e), G(&_G) { } InEdgeIt (Invalid i) : Edge(i) { } InEdgeIt(const SmartGraph& _G,Node v) : Edge(_G.nodes[v.n].first_in), G(&_G) { } InEdgeIt &operator++() { n=G->edges[n].next_in; return *this; } // ///Validity check // operator bool() { return Edge::operator bool(); } }; }; class SymSmartGraph : public SmartGraph { typedef SmartGraph Parent; public: typedef SymSmartGraph Graph; typedef SmartGraph::Node Node; typedef SmartGraph::NodeIt NodeIt; class SymEdge; class SymEdgeIt; class Edge; class EdgeIt; class OutEdgeIt; class InEdgeIt; template class NodeMap : public Parent::NodeMap { public: NodeMap(const SymSmartGraph& g) : SymSmartGraph::Parent::NodeMap(g) {} NodeMap(const SymSmartGraph& g, Value v) : SymSmartGraph::Parent::NodeMap(g, v) {} template NodeMap(const NodeMap& copy) : SymSmartGraph::Parent::NodeMap(copy) { } }; template class SymEdgeMap : public Parent::EdgeMap { public: typedef SymEdge KeyType; SymEdgeMap(const SymSmartGraph& g) : SymSmartGraph::Parent::EdgeMap(g) {} SymEdgeMap(const SymSmartGraph& g, Value v) : SymSmartGraph::Parent::EdgeMap(g, v) {} template SymEdgeMap(const SymEdgeMap& copy) : SymSmartGraph::Parent::EdgeMap(copy) { } }; // Create edge map registry. CREATE_EDGE_MAP_REGISTRY; // Create edge maps. CREATE_EDGE_MAP(ArrayMap); class Edge { friend class SymSmartGraph; friend class SymSmartGraph::EdgeIt; friend class SymSmartGraph::OutEdgeIt; friend class SymSmartGraph::InEdgeIt; protected: int id; Edge(int pid) { id = pid; } public: /// An Edge with id \c n. Edge() { } Edge (Invalid) { id = -1; } operator SymEdge(){ return SymEdge(id >> 1);} bool operator==(const Edge i) const {return id == i.id;} bool operator!=(const Edge i) const {return id != i.id;} bool operator<(const Edge i) const {return id < i.id;} // ///Validity check // operator bool() { return n!=-1; } }; class SymEdge : public SmartGraph::Edge { friend class SymSmartGraph; friend class SymSmartGraph::Edge; typedef SmartGraph::Edge Parent; protected: SymEdge(int pid) : Parent(pid) {} public: SymEdge() { } SymEdge(const SmartGraph::Edge& i) : Parent(i) {} SymEdge (Invalid) : Parent(INVALID) {} }; class OutEdgeIt { Parent::OutEdgeIt out; Parent::InEdgeIt in; public: OutEdgeIt() {} OutEdgeIt(const SymSmartGraph& g, Edge e) { if ((e.id & 1) == 0) { out = Parent::OutEdgeIt(g, SymEdge(e)); in = Parent::InEdgeIt(g, g.tail(e)); } else { out = Parent::OutEdgeIt(INVALID); in = Parent::InEdgeIt(g, SymEdge(e)); } } OutEdgeIt (Invalid i) : out(INVALID), in(INVALID) { } OutEdgeIt(const SymSmartGraph& g, const Node v) : out(g, v), in(g, v) {} OutEdgeIt &operator++() { if (out != INVALID) { ++out; } else { ++in; } return *this; } operator Edge() const { if (out == INVALID && in == INVALID) return INVALID; return out != INVALID ? forward(out) : backward(in); } bool operator==(const Edge i) const {return Edge(*this) == i;} bool operator!=(const Edge i) const {return Edge(*this) != i;} bool operator<(const Edge i) const {return Edge(*this) < i;} }; class InEdgeIt { Parent::OutEdgeIt out; Parent::InEdgeIt in; public: InEdgeIt() {} InEdgeIt(const SymSmartGraph& g, Edge e) { if ((e.id & 1) == 0) { out = Parent::OutEdgeIt(g, SymEdge(e)); in = Parent::InEdgeIt(g, g.tail(e)); } else { out = Parent::OutEdgeIt(INVALID); in = Parent::InEdgeIt(g, SymEdge(e)); } } InEdgeIt (Invalid i) : out(INVALID), in(INVALID) { } InEdgeIt(const SymSmartGraph& g, const Node v) : out(g, v), in(g, v) {} InEdgeIt &operator++() { if (out != INVALID) { ++out; } else { ++in; } return *this; } operator Edge() const { if (out == INVALID && in == INVALID) return INVALID; return out != INVALID ? backward(out) : forward(in); } bool operator==(const Edge i) const {return Edge(*this) == i;} bool operator!=(const Edge i) const {return Edge(*this) != i;} bool operator<(const Edge i) const {return Edge(*this) < i;} }; class SymEdgeIt : public Parent::EdgeIt { public: SymEdgeIt() {} SymEdgeIt(const SymSmartGraph& g) : SymSmartGraph::Parent::EdgeIt(g) {} SymEdgeIt(const SymSmartGraph& g, SymEdge e) : SymSmartGraph::Parent::EdgeIt(g, e) {} SymEdgeIt(Invalid i) : SymSmartGraph::Parent::EdgeIt(INVALID) {} SymEdgeIt& operator++() { SymSmartGraph::Parent::EdgeIt::operator++(); return *this; } operator SymEdge() const { return SymEdge (static_cast(*this)); } bool operator==(const SymEdge i) const {return SymEdge(*this) == i;} bool operator!=(const SymEdge i) const {return SymEdge(*this) != i;} bool operator<(const SymEdge i) const {return SymEdge(*this) < i;} }; class EdgeIt { SymEdgeIt it; bool fw; public: EdgeIt(const SymSmartGraph& g) : it(g), fw(true) {} EdgeIt (Invalid i) : it(i) { } EdgeIt(const SymSmartGraph& g, Edge e) : it(g, SymEdge(e)), fw(id(e) & 1 == 0) { } EdgeIt() { } EdgeIt& operator++() { fw = !fw; if (fw) ++it; return *this; } operator Edge() const { if (it == INVALID) return INVALID; return fw ? forward(it) : backward(it); } bool operator==(const Edge i) const {return Edge(*this) == i;} bool operator!=(const Edge i) const {return Edge(*this) != i;} bool operator<(const Edge i) const {return Edge(*this) < i;} }; ///Number of nodes. int nodeNum() const { return Parent::nodeNum(); } ///Number of edges. int edgeNum() const { return 2*Parent::edgeNum(); } ///Number of symmetric edges. int symEdgeNum() const { return Parent::edgeNum(); } /// Maximum node ID. /// Maximum node ID. ///\sa id(Node) int maxNodeId() const { return Parent::maxNodeId(); } /// Maximum edge ID. /// Maximum edge ID. ///\sa id(Edge) int maxEdgeId() const { return 2*Parent::maxEdgeId(); } /// Maximum symmetric edge ID. /// Maximum symmetric edge ID. ///\sa id(SymEdge) int maxSymEdgeId() const { return Parent::maxEdgeId(); } Node tail(Edge e) const { return (e.id & 1) == 0 ? Parent::tail(SymEdge(e)) : Parent::head(SymEdge(e)); } Node head(Edge e) const { return (e.id & 1) == 0 ? Parent::head(SymEdge(e)) : Parent::tail(SymEdge(e)); } Node tail(SymEdge e) const { return Parent::tail(e); } Node head(SymEdge e) const { return Parent::head(e); } NodeIt& first(NodeIt& v) const { v=NodeIt(*this); return v; } EdgeIt& first(EdgeIt& e) const { e=EdgeIt(*this); return e; } SymEdgeIt& first(SymEdgeIt& e) const { e=SymEdgeIt(*this); return e; } OutEdgeIt& first(OutEdgeIt& e, const Node v) const { e=OutEdgeIt(*this,v); return e; } InEdgeIt& first(InEdgeIt& e, const Node v) const { e=InEdgeIt(*this,v); return e; } /// Node ID. /// The ID of a valid Node is a nonnegative integer not greater than /// \ref maxNodeId(). The range of the ID's is not surely continuous /// and the greatest node ID can be actually less then \ref maxNodeId(). /// /// The ID of the \ref INVALID node is -1. ///\return The ID of the node \c v. static int id(Node v) { return Parent::id(v); } /// Edge ID. /// The ID of a valid Edge is a nonnegative integer not greater than /// \ref maxEdgeId(). The range of the ID's is not surely continuous /// and the greatest edge ID can be actually less then \ref maxEdgeId(). /// /// The ID of the \ref INVALID edge is -1. ///\return The ID of the edge \c e. static int id(Edge e) { return e.id; } /// The ID of a valid SymEdge is a nonnegative integer not greater than /// \ref maxSymEdgeId(). The range of the ID's is not surely continuous /// and the greatest edge ID can be actually less then \ref maxSymEdgeId(). /// /// The ID of the \ref INVALID symmetric edge is -1. ///\return The ID of the edge \c e. static int id(SymEdge e) { return Parent::id(e); } /// Adds a new node to the graph. /// \warning It adds the new node to the front of the list. /// (i.e. the lastly added node becomes the first.) Node addNode() { return Parent::addNode(); } SymEdge addEdge(Node u, Node v) { SymEdge se = Parent::addEdge(u, v); edge_maps.add(forward(se)); edge_maps.add(backward(se)); return se; } /// Finds an edge between two nodes. /// Finds an edge from node \c u to node \c v. /// /// If \c prev is \ref INVALID (this is the default value), then /// It finds the first edge from \c u to \c v. Otherwise it looks for /// the next edge from \c u to \c v after \c prev. /// \return The found edge or INVALID if there is no such an edge. Edge findEdge(Node u, Node v, Edge prev = INVALID) { if (prev == INVALID || id(prev) & 1 == 0) { SymEdge se = Parent::findEdge(u, v, SymEdge(prev)); if (se != INVALID) return forward(se); } else { SymEdge se = Parent::findEdge(v, u, SymEdge(prev)); if (se != INVALID) return backward(se); } return INVALID; } // /// Finds an symmetric edge between two nodes. // /// Finds an symmetric edge from node \c u to node \c v. // /// // /// If \c prev is \ref INVALID (this is the default value), then // /// It finds the first edge from \c u to \c v. Otherwise it looks for // /// the next edge from \c u to \c v after \c prev. // /// \return The found edge or INVALID if there is no such an edge. // SymEdge findEdge(Node u, Node v, SymEdge prev = INVALID) // { // if (prev == INVALID || id(prev) & 1 == 0) { // SymEdge se = Parent::findEdge(u, v, SymEdge(prev)); // if (se != INVALID) return se; // } else { // SymEdge se = Parent::findEdge(v, u, SymEdge(prev)); // if (se != INVALID) return se; // } // return INVALID; // } public: void clear() { edge_maps.clear(); Parent::clear(); } static Edge opposite(Edge e) { return Edge(id(e) ^ 1); } static Edge forward(SymEdge e) { return Edge(id(e) << 1); } static Edge backward(SymEdge e) { return Edge((id(e) << 1) | 1); } }; ///Graph for bidirectional edges. ///The purpose of this graph structure is to handle graphs ///having bidirectional edges. Here the function \c addEdge(u,v) adds a pair ///of oppositely directed edges. ///There is a new edge map type called ///\ref SymSmartGraph::SymEdgeMap "SymEdgeMap" ///that complements this ///feature by ///storing shared values for the edge pairs. The usual ///\ref Graph::EdgeMap "EdgeMap" ///can be used ///as well. /// ///The oppositely directed edge can also be obtained easily ///using \ref opposite. ///\warning It shares the similarity with \ref SmartGraph that ///it is not possible to delete edges or nodes from the graph. //\sa SmartGraph. /* class SymSmartGraph : public SmartGraph { public: typedef SymSmartGraph Graph; // Create symmetric map registry. CREATE_SYM_EDGE_MAP_REGISTRY; // Create symmetric edge map. CREATE_SYM_EDGE_MAP(ArrayMap); SymSmartGraph() : SmartGraph() { } SymSmartGraph(const SmartGraph &_g) : SmartGraph(_g) { } ///Adds a pair of oppositely directed edges to the graph. Edge addEdge(Node u, Node v) { Edge e = SmartGraph::addEdge(u,v); Edge f = SmartGraph::addEdge(v,u); sym_edge_maps.add(e); sym_edge_maps.add(f); return e; } ///The oppositely directed edge. ///Returns the oppositely directed ///pair of the edge \c e. static Edge opposite(Edge e) { Edge f; f.n = e.n - 2*(e.n%2) + 1; return f; } };*/ /// @} } //namespace lemon #endif //LEMON_SMART_GRAPH_H