// -*- mode:C++ -*- #ifndef HUGO_SMART_GRAPH_H #define HUGO_SMART_GRAPH_H ///\file ///\brief SmartGraph and SymSmartGraph classes. #include #include #include "invalid.h" namespace hugo { 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 graph interface documented under ///the description of \ref GraphSkeleton. ///\sa \ref GraphSkeleton. 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; protected: template class DynMapBase { protected: const SmartGraph* G; public: virtual void add(const Key k) = NULL; virtual void erase(const Key k) = NULL; DynMapBase(const SmartGraph &_G) : G(&_G) {} virtual ~DynMapBase() {} friend class SmartGraph; }; public: template class EdgeMap; template class EdgeMap; class Node; class Edge; // protected: // HELPME: protected: ///\bug It must be public because of SymEdgeMap. /// mutable std::vector * > dyn_node_maps; ///\bug It must be public because of SymEdgeMap. /// mutable std::vector * > dyn_edge_maps; public: class NodeIt; class EdgeIt; class OutEdgeIt; class InEdgeIt; template class NodeMap; template class EdgeMap; public: SmartGraph() : nodes(), edges() { } SmartGraph(const SmartGraph &_g) : nodes(_g.nodes), edges(_g.edges) { } ~SmartGraph() { for(std::vector * >::iterator i=dyn_node_maps.begin(); i!=dyn_node_maps.end(); ++i) (**i).G=NULL; for(std::vector * >::iterator i=dyn_edge_maps.begin(); i!=dyn_edge_maps.end(); ++i) (**i).G=NULL; } int nodeNum() const { return nodes.size(); } //FIXME: What is this? int edgeNum() const { return edges.size(); } //FIXME: What is this? ///\bug This function does something different than ///its name would suggests... int maxNodeId() const { return nodes.size(); } //FIXME: What is this? ///\bug This function does something different than ///its name would suggests... int maxEdgeId() const { return edges.size(); } //FIXME: What is this? Node tail(Edge e) const { return edges[e.n].tail; } Node head(Edge e) const { return edges[e.n].head; } Node aNode(OutEdgeIt e) const { return edges[e.n].tail; } Node aNode(InEdgeIt e) const { return edges[e.n].head; } Node bNode(OutEdgeIt e) const { return edges[e.n].head; } Node bNode(InEdgeIt e) const { return edges[e.n].tail; } 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; } // template< typename It > // It first() const { It e; first(e); return e; } // template< typename It > // It first(Node v) const { It e; first(e,v); return e; } bool valid(Edge e) const { return e.n!=-1; } bool valid(Node n) const { return n.n!=-1; } void setInvalid(Edge &e) { e.n=-1; } void setInvalid(Node &n) { n.n=-1; } template It getNext(It it) const { It tmp(it); return next(tmp); } NodeIt& next(NodeIt& it) const { it.n=(it.n+2)%(nodes.size()+1)-1; return it; } OutEdgeIt& next(OutEdgeIt& it) const { it.n=edges[it.n].next_out; return it; } InEdgeIt& next(InEdgeIt& it) const { it.n=edges[it.n].next_in; return it; } EdgeIt& next(EdgeIt& it) const { --it.n; return it; } int id(Node v) const { return v.n; } int id(Edge e) const { return e.n; } Node addNode() { Node n; n.n=nodes.size(); nodes.push_back(NodeT()); //FIXME: Hmmm... for(std::vector * >::iterator i=dyn_node_maps.begin(); i!=dyn_node_maps.end(); ++i) (**i).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; for(std::vector * >::iterator i=dyn_edge_maps.begin(); i!=dyn_edge_maps.end(); ++i) (**i).add(e); return e; } void clear() {nodes.clear();edges.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) const; Node(int nn) {n=nn;} public: Node() {} Node (Invalid i) { 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 n friend class EdgeMap; //template friend class SymSmartGraph::SymEdgeMap; //friend Edge SymSmartGraph::opposite(Edge) const; friend class Node; friend class NodeIt; protected: int n; friend int SmartGraph::id(Edge e) const; Edge(int nn) {n=nn;} public: 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 n class NodeMap : public DynMapBase { std::vector container; public: typedef T ValueType; typedef Node KeyType; NodeMap(const SmartGraph &_G) : DynMapBase(_G), container(_G.maxNodeId()) { G->dyn_node_maps.push_back(this); } NodeMap(const SmartGraph &_G,const T &t) : DynMapBase(_G), container(_G.maxNodeId(),t) { G->dyn_node_maps.push_back(this); } NodeMap(const NodeMap &m) : DynMapBase(*m.G), container(m.container) { G->dyn_node_maps.push_back(this); } template friend class NodeMap; ///\todo It can copy between different types. /// template NodeMap(const NodeMap &m) : DynMapBase(*m.G) { G->dyn_node_maps.push_back(this); typename std::vector::const_iterator i; for(typename std::vector::const_iterator i=m.container.begin(); i!=m.container.end(); i++) container.push_back(*i); } ~NodeMap() { if(G) { std::vector* >::iterator i; for(i=G->dyn_node_maps.begin(); i!=G->dyn_node_maps.end() && *i!=this; ++i) ; //if(*i==this) G->dyn_node_maps.erase(i); //FIXME: Way too slow... //A better way to do that: (Is this really important?) if(*i==this) { *i=G->dyn_node_maps.back(); G->dyn_node_maps.pop_back(); } } } void add(const Node k) { if(k.n>=int(container.size())) container.resize(k.n+1); } void erase(const Node) { } void set(Node n, T a) { container[n.n]=a; } //'T& operator[](Node n)' would be wrong here typename std::vector::reference operator[](Node n) { return container[n.n]; } //'const T& operator[](Node n)' would be wrong here typename std::vector::const_reference operator[](Node n) const { return container[n.n]; } ///\warning There is no safety check at all! ///Using operator = between maps attached to different graph may ///cause serious problem. ///\todo Is this really so? ///\todo It can copy between different types. const NodeMap& operator=(const NodeMap &m) { container = m.container; return *this; } template const NodeMap& operator=(const NodeMap &m) { copy(m.container.begin(), m.container.end(), container.begin()); return *this; } void update() {} //Useless for Dynamic Maps void update(T a) {} //Useless for Dynamic Maps }; template class EdgeMap : public DynMapBase { std::vector container; public: typedef T ValueType; typedef Edge KeyType; EdgeMap(const SmartGraph &_G) : DynMapBase(_G), container(_G.maxEdgeId()) { //FIXME: What if there are empty Id's? //FIXME: Can I use 'this' in a constructor? G->dyn_edge_maps.push_back(this); } EdgeMap(const SmartGraph &_G,const T &t) : DynMapBase(_G), container(_G.maxEdgeId(),t) { G->dyn_edge_maps.push_back(this); } EdgeMap(const EdgeMap &m) : DynMapBase(*m.G), container(m.container) { G->dyn_node_maps.push_back(this); } template friend class EdgeMap; ///\todo It can copy between different types. /// template EdgeMap(const EdgeMap &m) : DynMapBase(*m.G) { G->dyn_node_maps.push_back(this); typename std::vector::const_iterator i; for(typename std::vector::const_iterator i=m.container.begin(); i!=m.container.end(); i++) container.push_back(*i); } ~EdgeMap() { if(G) { std::vector* >::iterator i; for(i=G->dyn_edge_maps.begin(); i!=G->dyn_edge_maps.end() && *i!=this; ++i) ; //if(*i==this) G->dyn_edge_maps.erase(i); //Way too slow... //A better way to do that: (Is this really important?) if(*i==this) { *i=G->dyn_edge_maps.back(); G->dyn_edge_maps.pop_back(); } } } void add(const Edge k) { if(k.n>=int(container.size())) container.resize(k.n+1); } void erase(const Edge) { } void set(Edge n, T a) { container[n.n]=a; } //T get(Edge n) const { return container[n.n]; } typename std::vector::reference operator[](Edge n) { return container[n.n]; } typename std::vector::const_reference operator[](Edge n) const { return container[n.n]; } ///\warning There is no safety check at all! ///Using operator = between maps attached to different graph may ///cause serious problem. ///\todo Is this really so? ///\todo It can copy between different types. const EdgeMap& operator=(const EdgeMap &m) { container = m.container; return *this; } template const EdgeMap& operator=(const EdgeMap &m) { copy(m.container.begin(), m.container.end(), container.begin()); return *this; } void update() {} //Useless for DynMaps void update(T a) {} //Useless for DynMaps }; }; ///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 GraphSkeleton::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 \ref SmartGraph. class SymSmartGraph : public SmartGraph { public: template class SymEdgeMap; template friend class SymEdgeMap; 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); SmartGraph::addEdge(v,u); return e; } ///The oppositely directed edge. ///Returns the oppositely directed ///pair of the edge \c e. Edge opposite(Edge e) const { Edge f; f.idref() = e.idref() - 2*(e.idref()%2) + 1; return f; } ///Common data storage for the edge pairs. ///This map makes it possible to store data shared by the oppositely ///directed pairs of edges. template class SymEdgeMap : public DynMapBase { std::vector container; public: typedef T ValueType; typedef Edge KeyType; SymEdgeMap(const SymSmartGraph &_G) : DynMapBase(_G), container(_G.maxEdgeId()/2) { static_cast(G)->dyn_edge_maps.push_back(this); } SymEdgeMap(const SymSmartGraph &_G,const T &t) : DynMapBase(_G), container(_G.maxEdgeId()/2,t) { G->dyn_edge_maps.push_back(this); } SymEdgeMap(const SymEdgeMap &m) : DynMapBase(*m.G), container(m.container) { G->dyn_node_maps.push_back(this); } // template friend class SymEdgeMap; ///\todo It can copy between different types. /// template SymEdgeMap(const SymEdgeMap &m) : DynMapBase(*m.G) { G->dyn_node_maps.push_back(this); typename std::vector::const_iterator i; for(typename std::vector::const_iterator i=m.container.begin(); i!=m.container.end(); i++) container.push_back(*i); } ~SymEdgeMap() { if(G) { std::vector* >::iterator i; for(i=static_cast(G)->dyn_edge_maps.begin(); i!=static_cast(G)->dyn_edge_maps.end() && *i!=this; ++i) ; //if(*i==this) G->dyn_edge_maps.erase(i); //Way too slow... //A better way to do that: (Is this really important?) if(*i==this) { *i=static_cast(G)->dyn_edge_maps.back(); static_cast(G)->dyn_edge_maps.pop_back(); } } } void add(const Edge k) { if(!k.idref()%2&&k.idref()/2>=int(container.size())) container.resize(k.idref()/2+1); } void erase(const Edge k) { } void set(Edge n, T a) { container[n.idref()/2]=a; } //T get(Edge n) const { return container[n.idref()/2]; } typename std::vector::reference operator[](Edge n) { return container[n.idref()/2]; } typename std::vector::const_reference operator[](Edge n) const { return container[n.idref()/2]; } ///\warning There is no safety check at all! ///Using operator = between maps attached to different graph may ///cause serious problem. ///\todo Is this really so? ///\todo It can copy between different types. const SymEdgeMap& operator=(const SymEdgeMap &m) { container = m.container; return *this; } template const SymEdgeMap& operator=(const SymEdgeMap &m) { copy(m.container.begin(), m.container.end(), container.begin()); return *this; } void update() {} //Useless for DynMaps void update(T a) {} //Useless for DynMaps }; }; } //namespace hugo #endif //SMART_GRAPH_H