/* -*- C++ -*- * src/hugo/smart_graph.h - Part of HUGOlib, 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 HUGO_SMART_GRAPH_H #define HUGO_SMART_GRAPH_H ///\ingroup graphs ///\file ///\brief SmartGraph and SymSmartGraph classes. #include #include #include #include #include #include #include namespace hugo { /// \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(); } }; }; ///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 hugo #endif //HUGO_SMART_GRAPH_H