|
|
|
|
|
#ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_ |
|
#define DLIB_DIRECTED_GRAPH_KERNEl_1_ |
|
|
|
#include <memory> |
|
#include <vector> |
|
|
|
#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 <typename node_type, typename directed_graph, bool is_checked> |
|
struct directed_graph_checker_helper |
|
{ |
|
|
|
|
|
|
|
|
|
static void check_parent_edge ( |
|
unsigned long edge_index, |
|
const node_type& self |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 |
|
) |
|
{ |
|
|
|
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 <typename node_type, typename directed_graph> |
|
struct directed_graph_checker_helper <node_type, directed_graph, false> |
|
{ |
|
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 |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
struct node_type; |
|
|
|
private: |
|
typedef directed_graph_checker_helper<node_type, directed_graph_kernel_1, is_checked> checker; |
|
|
|
|
|
public: |
|
|
|
typedef T type; |
|
typedef E edge_type; |
|
typedef mem_manager mem_manager_type; |
|
|
|
template <typename Tr, typename Er, typename MMr> |
|
struct rebind { |
|
typedef directed_graph_kernel_1<Tr,Er,MMr> 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<node_type*,mem_manager> alloc_type; |
|
typedef std_allocator<std::shared_ptr<E>,mem_manager> alloc_edge_type; |
|
std::vector<node_type*,alloc_type> parents; |
|
std::vector<node_type*,alloc_type> children; |
|
std::vector<std::shared_ptr<E>,alloc_edge_type> edge_parents; |
|
std::vector<std::shared_ptr<E>,alloc_edge_type> edge_children; |
|
unsigned long idx; |
|
}; |
|
|
|
private: |
|
|
|
typedef std_allocator<std::shared_ptr<node_type>,mem_manager> alloc_type; |
|
typedef std::vector<std::shared_ptr<node_type>, alloc_type> vector_type; |
|
vector_type nodes; |
|
}; |
|
|
|
|
|
|
|
template < |
|
typename T, |
|
typename E, |
|
typename mem_manager, |
|
bool is_checked |
|
> |
|
struct is_directed_graph<directed_graph_kernel_1<T,E,mem_manager, is_checked> > |
|
{ |
|
static const bool value = true; |
|
}; |
|
|
|
|
|
|
|
template < |
|
typename T, |
|
typename E, |
|
typename mem_manager, |
|
bool is_checked |
|
> |
|
inline void swap ( |
|
directed_graph_kernel_1<T,E,mem_manager,is_checked>& a, |
|
directed_graph_kernel_1<T,E,mem_manager,is_checked>& b |
|
) { a.swap(b); } |
|
|
|
|
|
|
|
template < |
|
typename T, |
|
typename E, |
|
typename mem_manager, |
|
bool is_checked |
|
> |
|
void serialize ( |
|
const directed_graph_kernel_1<T,E,mem_manager,is_checked>& item, |
|
std::ostream& out |
|
) |
|
{ |
|
try |
|
{ |
|
serialize(item.number_of_nodes(), out); |
|
|
|
|
|
for (unsigned long i = 0; i < item.number_of_nodes(); ++i) |
|
{ |
|
serialize(item.node(i).data, out); |
|
|
|
|
|
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<T,E,mem_manager,is_checked>& item, |
|
std::istream& in |
|
) |
|
{ |
|
try |
|
{ |
|
unsigned long size; |
|
deserialize(size, in); |
|
|
|
item.clear(); |
|
item.set_number_of_nodes(size); |
|
|
|
|
|
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); |
|
|
|
|
|
for (unsigned long c = 0; c < num_children; ++c) |
|
{ |
|
unsigned long child_index; |
|
deserialize(child_index, in); |
|
|
|
item.add_edge(i, child_index); |
|
|
|
|
|
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"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename T, |
|
typename E, |
|
typename mem_manager, |
|
bool is_checked |
|
> |
|
void directed_graph_kernel_1<T,E,mem_manager,is_checked>:: |
|
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<T,E,mem_manager,is_checked>:: |
|
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]; |
|
|
|
|
|
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<T,E,mem_manager,is_checked>:: |
|
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<E>(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<T,E,mem_manager,is_checked>:: |
|
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]; |
|
|
|
|
|
unsigned long pos = static_cast<unsigned long>(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); |
|
|
|
|
|
pos = static_cast<unsigned long>(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<T,E,mem_manager,is_checked>:: |
|
add_node ( |
|
) |
|
{ |
|
try |
|
{ |
|
std::shared_ptr<node_type> 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<T,E,mem_manager,is_checked>:: |
|
remove_node ( |
|
unsigned long index |
|
) |
|
{ |
|
checker::check_remove_node(index,*this); |
|
|
|
node_type& n = *nodes[index]; |
|
|
|
|
|
for (unsigned long i = 0; i < n.parents.size(); ++i) |
|
{ |
|
|
|
unsigned long pos = static_cast<unsigned long>(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); |
|
} |
|
|
|
|
|
for (unsigned long i = 0; i < n.children.size(); ++i) |
|
{ |
|
|
|
unsigned long pos = static_cast<unsigned long>(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); |
|
} |
|
|
|
|
|
nodes[index] = nodes[nodes.size()-1]; |
|
|
|
|
|
nodes[index]->idx = index; |
|
|
|
|
|
nodes.pop_back(); |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|