// Copyright (C) 2007 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_ #define DLIB_DIRECTED_GRAPH_KERNEl_1_ #include #include #include "../serialize.h" #include "../noncopyable.h" #include "../std_allocator.h" #include "../algs.h" #include "directed_graph_kernel_abstract.h" #include "../is_kind.h" namespace dlib { // ---------------------------------------------------------------------------------------- template struct directed_graph_checker_helper { /*! This object is used to check preconditions based on the value of is_checked !*/ static void check_parent_edge ( unsigned long edge_index, const node_type& self ) { // make sure requires clause is not broken DLIB_CASSERT(edge_index < self.number_of_parents(), "\tnode_type& directed_graph::node_type::parent_edge(edge_index)" << "\n\tYou have specified an invalid index" << "\n\tedge_index: " << edge_index << "\n\tnumber_of_parents(): " << self.number_of_parents() << "\n\tthis: " << &self ); } static void check_child_edge ( unsigned long edge_index, const node_type& self ) { // make sure requires clause is not broken DLIB_CASSERT(edge_index < self.number_of_children(), "\tnode_type& directed_graph::node_type::child_edge(edge_index)" << "\n\tYou have specified an invalid index" << "\n\tedge_index: " << edge_index << "\n\tnumber_of_children(): " << self.number_of_children() << "\n\tthis: " << &self ); } static void check_parent ( unsigned long edge_index, const node_type& self ) { // make sure requires clause is not broken DLIB_CASSERT(edge_index < self.number_of_parents(), "\tnode_type& directed_graph::node_type::parent(edge_index)" << "\n\tYou have specified an invalid index" << "\n\tedge_index: " << edge_index << "\n\tnumber_of_parents(): " << self.number_of_parents() << "\n\tthis: " << &self ); } static void check_child ( unsigned long edge_index, const node_type& self ) { // make sure requires clause is not broken DLIB_CASSERT(edge_index < self.number_of_children(), "\tnode_type& directed_graph::node_type::child(edge_index)" << "\n\tYou have specified an invalid index" << "\n\tedge_index: " << edge_index << "\n\tnumber_of_children(): " << self.number_of_children() << "\n\tthis: " << &self ); } static void check_node ( unsigned long index, const directed_graph& self ) { // make sure requires clause is not broken DLIB_CASSERT(index < self.number_of_nodes(), "\tnode_type& directed_graph::node(index)" << "\n\tYou have specified an invalid index" << "\n\tindex: " << index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); } static void check_has_edge ( unsigned long parent_node_index, unsigned long child_node_index, const directed_graph& self ) { // make sure requires clause is not broken DLIB_CASSERT(parent_node_index < self.number_of_nodes() && child_node_index < self.number_of_nodes(), "\tvoid directed_graph::has_edge(parent_node_index, child_node_index)" << "\n\tYou have specified an invalid index" << "\n\tparent_node_index: " << parent_node_index << "\n\tchild_node_index: " << child_node_index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); } static void check_add_edge ( unsigned long parent_node_index, unsigned long child_node_index, const directed_graph& self ) { DLIB_CASSERT(parent_node_index < self.number_of_nodes() && child_node_index < self.number_of_nodes(), "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)" << "\n\tYou have specified an invalid index" << "\n\tparent_node_index: " << parent_node_index << "\n\tchild_node_index: " << child_node_index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == false, "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)" << "\n\tYou can't add an edge if it already exists in the graph" << "\n\tparent_node_index: " << parent_node_index << "\n\tchild_node_index: " << child_node_index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); } static void check_remove_edge ( unsigned long parent_node_index, unsigned long child_node_index, const directed_graph& self ) { DLIB_CASSERT(parent_node_index < self.number_of_nodes() && child_node_index < self.number_of_nodes(), "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)" << "\n\tYou have specified an invalid index" << "\n\tparent_node_index: " << parent_node_index << "\n\tchild_node_index: " << child_node_index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == true, "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)" << "\n\tYou can't remove an edge if it isn't in the graph" << "\n\tparent_node_index: " << parent_node_index << "\n\tchild_node_index: " << child_node_index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); } static void check_remove_node ( unsigned long index, const directed_graph& self ) { // make sure requires clause is not broken DLIB_CASSERT(index < self.number_of_nodes(), "\tvoid directed_graph::remove_node(index)" << "\n\tYou have specified an invalid index" << "\n\tindex: " << index << "\n\tnumber_of_nodes(): " << self.number_of_nodes() << "\n\tthis: " << &self ); } }; template struct directed_graph_checker_helper { static inline void check_parent ( unsigned long , const node_type&) { } static inline void check_child ( unsigned long , const node_type& ) { } static inline void check_parent_edge ( unsigned long , const node_type&) { } static inline void check_child_edge ( unsigned long , const node_type& ) { } static inline void check_node ( unsigned long , const directed_graph& ) { } static inline void check_has_edge ( unsigned long , unsigned long , const directed_graph& ) { } static inline void check_add_edge ( unsigned long , unsigned long , const directed_graph& ) { } static inline void check_remove_edge ( unsigned long , unsigned long , const directed_graph& ) { } static inline void check_remove_node ( unsigned long , const directed_graph& ) { } }; // ---------------------------------------------------------------------------------------- template < typename T, typename E = char, typename mem_manager = default_memory_manager, bool is_checked = true > class directed_graph_kernel_1 : noncopyable { /*! INITIAL VALUE - nodes.size() == 0 CONVENTION - nodes.size() == number_of_nodes() - for all valid i: - *nodes[i] == node(i) - nodes[i]->parents.size() == nodes[i]->number_of_parents(i) - nodes[i]->children.size() == nodes[i]->number_of_children(i) - nodes[i]->edge_parents.size() == nodes[i]->number_of_parents(i) - nodes[i]->edge_children.size() == nodes[i]->number_of_children(i) - nodes[i]->idx == i == nodes[i]->index() - for all valid p: - nodes[i]->parents[p] == pointer to the p'th parent node of i - *nodes[i]->parents[p] == nodes[i]->parent(p) - *nodes[i]->edge_parents[p] == nodes[i]->parent_edge(p) - for all valid c: - nodes[i]->children[c] == pointer to the c'th child node of i - *nodes[i]->children[c] == nodes[i]->child(c) - *nodes[i]->edge_children[c] == nodes[i]->child_edge(c) !*/ public: struct node_type; private: typedef directed_graph_checker_helper checker; public: typedef T type; typedef E edge_type; typedef mem_manager mem_manager_type; template struct rebind { typedef directed_graph_kernel_1 other; }; directed_graph_kernel_1( ) {} virtual ~directed_graph_kernel_1( ) {} void clear( ) { nodes.clear(); } void set_number_of_nodes ( unsigned long new_size ); unsigned long number_of_nodes ( ) const { return nodes.size(); } node_type& node ( unsigned long index ) { checker::check_node(index,*this); return *nodes[index]; } const node_type& node ( unsigned long index ) const { checker::check_node(index,*this); return *nodes[index]; } bool has_edge ( unsigned long parent_node_index, unsigned long child_node_index ) const; void add_edge ( unsigned long parent_node_index, unsigned long child_node_index ); void remove_edge ( unsigned long parent_node_index, unsigned long child_node_index ); unsigned long add_node ( ); void remove_node ( unsigned long index ); void swap ( directed_graph_kernel_1& item ) { nodes.swap(item.nodes); } private: public: struct node_type { T data; typedef directed_graph_kernel_1 graph_type; unsigned long index( ) const { return idx; } unsigned long number_of_parents ( ) const { return parents.size(); } unsigned long number_of_children ( ) const { return children.size(); } const node_type& parent ( unsigned long edge_index ) const { checker::check_parent(edge_index,*this); return *parents[edge_index]; } node_type& parent ( unsigned long edge_index ) { checker::check_parent(edge_index,*this); return *parents[edge_index]; } const node_type& child ( unsigned long edge_index ) const { checker::check_child(edge_index,*this); return *children[edge_index]; } node_type& child ( unsigned long edge_index ) { checker::check_child(edge_index,*this); return *children[edge_index]; } const E& parent_edge ( unsigned long edge_index ) const { checker::check_parent_edge(edge_index,*this); return *edge_parents[edge_index]; } E& parent_edge ( unsigned long edge_index ) { checker::check_parent_edge(edge_index,*this); return *edge_parents[edge_index]; } const E& child_edge ( unsigned long edge_index ) const { checker::check_child_edge(edge_index,*this); return *edge_children[edge_index]; } E& child_edge ( unsigned long edge_index ) { checker::check_child_edge(edge_index,*this); return *edge_children[edge_index]; } private: friend class directed_graph_kernel_1; typedef std_allocator alloc_type; typedef std_allocator,mem_manager> alloc_edge_type; std::vector parents; std::vector children; std::vector,alloc_edge_type> edge_parents; std::vector,alloc_edge_type> edge_children; unsigned long idx; }; private: typedef std_allocator,mem_manager> alloc_type; typedef std::vector, alloc_type> vector_type; vector_type nodes; }; // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > struct is_directed_graph > { static const bool value = true; }; // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > inline void swap ( directed_graph_kernel_1& a, directed_graph_kernel_1& b ) { a.swap(b); } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void serialize ( const directed_graph_kernel_1& item, std::ostream& out ) { try { serialize(item.number_of_nodes(), out); // serialize each node for (unsigned long i = 0; i < item.number_of_nodes(); ++i) { serialize(item.node(i).data, out); // serialize all the child edges serialize(item.node(i).number_of_children(), out); for (unsigned long c = 0; c < item.node(i).number_of_children(); ++c) { serialize(item.node(i).child(c).index(), out); serialize(item.node(i).child_edge(c), out); } } } catch (serialization_error& e) { throw serialization_error(e.info + "\n while serializing object of type directed_graph_kernel_1"); } } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void deserialize ( directed_graph_kernel_1& item, std::istream& in ) { try { unsigned long size; deserialize(size, in); item.clear(); item.set_number_of_nodes(size); // deserialize each node for (unsigned long i = 0; i < item.number_of_nodes(); ++i) { deserialize(item.node(i).data, in); unsigned long num_children; deserialize(num_children, in); // Add all the edges going to this nodes children nodes for (unsigned long c = 0; c < num_children; ++c) { unsigned long child_index; deserialize(child_index, in); item.add_edge(i, child_index); // find the edge we just added for (unsigned long j = 0; j < item.node(i).number_of_children(); ++j) { if (item.node(i).child(j).index() == child_index) { deserialize(item.node(i).child_edge(j), in); break; } } } } } catch (serialization_error& e) { throw serialization_error(e.info + "\n while deserializing object of type directed_graph_kernel_1"); } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void directed_graph_kernel_1:: set_number_of_nodes ( unsigned long new_size ) { try { nodes.resize(new_size); for (unsigned long i = 0; i < nodes.size(); ++i) { nodes[i].reset(new node_type); nodes[i]->idx = i; } } catch (...) { clear(); throw; } } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > bool directed_graph_kernel_1:: has_edge ( unsigned long parent_node_index, unsigned long child_node_index ) const { checker::check_has_edge(parent_node_index, child_node_index, *this); node_type& n = *nodes[parent_node_index]; // search all the child nodes to see if there is a link to the right node for (unsigned long i = 0; i < n.children.size(); ++i) { if (n.children[i]->idx == child_node_index) return true; } return false; } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void directed_graph_kernel_1:: add_edge ( unsigned long parent_node_index, unsigned long child_node_index ) { checker::check_add_edge(parent_node_index, child_node_index, *this); try { node_type& p = *nodes[parent_node_index]; node_type& c = *nodes[child_node_index]; p.children.push_back(&c); c.parents.push_back(&p); p.edge_children.push_back(std::shared_ptr(new E)); c.edge_parents.push_back(p.edge_children.back()); } catch (...) { clear(); throw; } } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void directed_graph_kernel_1:: remove_edge ( unsigned long parent_node_index, unsigned long child_node_index ) { checker::check_remove_edge(parent_node_index, child_node_index, *this); node_type& p = *nodes[parent_node_index]; node_type& c = *nodes[child_node_index]; // remove the record of the link from the parent node unsigned long pos = static_cast(find( p.children.begin(), p.children.end(), &c) - p.children.begin()); p.children.erase(p.children.begin()+pos); p.edge_children.erase(p.edge_children.begin()+pos); // remove the record of the link from the child node pos = static_cast(find( c.parents.begin(), c.parents.end(), &p) - c.parents.begin()); c.parents.erase(c.parents.begin() + pos); c.edge_parents.erase(c.edge_parents.begin() + pos); } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > unsigned long directed_graph_kernel_1:: add_node ( ) { try { std::shared_ptr n(new node_type); n->idx = nodes.size(); nodes.push_back(n); return n->idx; } catch (...) { clear(); throw; } } // ---------------------------------------------------------------------------------------- template < typename T, typename E, typename mem_manager, bool is_checked > void directed_graph_kernel_1:: remove_node ( unsigned long index ) { checker::check_remove_node(index,*this); node_type& n = *nodes[index]; // remove all edges pointing to this node from its parents for (unsigned long i = 0; i < n.parents.size(); ++i) { // remove the edge from this specific parent unsigned long pos = static_cast(find(n.parents[i]->children.begin(), n.parents[i]->children.end(), &n) - n.parents[i]->children.begin()); n.parents[i]->children.erase(n.parents[i]->children.begin() + pos); n.parents[i]->edge_children.erase(n.parents[i]->edge_children.begin() + pos); } // remove all edges pointing to this node from its children for (unsigned long i = 0; i < n.children.size(); ++i) { // remove the edge from this specific child unsigned long pos = static_cast(find(n.children[i]->parents.begin(), n.children[i]->parents.end(), &n) - n.children[i]->parents.begin()); n.children[i]->parents.erase(n.children[i]->parents.begin() + pos); n.children[i]->edge_parents.erase(n.children[i]->edge_parents.begin() + pos); } // now remove this node by replacing it with the last node in the nodes vector nodes[index] = nodes[nodes.size()-1]; // update the index for the node we just moved nodes[index]->idx = index; // now remove the duplicated node at the end of the vector nodes.pop_back(); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_DIRECTED_GRAPH_KERNEl_1_