dlib C++ Library - graph_kernel_1.h

// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_GRAPH_KERNEl_1_
#define DLIB_GRAPH_KERNEl_1_
#include <memory>
#include <vector>
#include "../serialize.h"
#include "../noncopyable.h"
#include "../std_allocator.h"
#include "../algs.h"
#include "graph_kernel_abstract.h"
#include "../is_kind.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
 template <typename node_type, typename graph, bool is_checked>
 struct graph_checker_helper 
 { 
 /*!
 This object is used to check preconditions based on the value of is_checked
 !*/
 static void check_neighbor (
 unsigned long edge_index,
 const node_type& self
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT(edge_index < self.number_of_neighbors(),
 "\tnode_type& graph::node_type::neighbor(edge_index)"
 << "\n\tYou have specified an invalid index"
 << "\n\tedge_index: " << edge_index 
 << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors() 
 << "\n\tthis: " << &self
 );
 }
 static void check_edge (
 unsigned long edge_index,
 const node_type& self
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT(edge_index < self.number_of_neighbors(),
 "\tE& graph::node_type::edge(edge_index)"
 << "\n\tYou have specified an invalid index"
 << "\n\tedge_index: " << edge_index 
 << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors() 
 << "\n\tthis: " << &self
 );
 }
 static void check_node (
 unsigned long index,
 const graph& self
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT(index < self.number_of_nodes(),
 "\tnode_type& 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 node_index1,
 unsigned long node_index2,
 const graph& self
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
 node_index2 < self.number_of_nodes(),
 "\tvoid graph::has_edge(node_index1, node_index2)"
 << "\n\tYou have specified an invalid index"
 << "\n\tnode_index1: " << node_index1 
 << "\n\tnode_index2: " << node_index2 
 << "\n\tnumber_of_nodes(): " << self.number_of_nodes() 
 << "\n\tthis: " << &self
 );
 }
 static void check_add_edge (
 unsigned long node_index1,
 unsigned long node_index2,
 const graph& self
 )
 {
 DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
 node_index2 < self.number_of_nodes(),
 "\tvoid graph::add_edge(node_index1, node_index2)" 
 << "\n\tYou have specified an invalid index"
 << "\n\tnode_index1: " << node_index1 
 << "\n\tnode_index2: " << node_index2 
 << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
 << "\n\tthis: " << &self
 );
 DLIB_CASSERT( self.has_edge(node_index1, node_index2) == false,
 "\tvoid graph::add_edge(node_index1, node_index2)"
 << "\n\tYou can't add an edge if it already exists in the graph"
 << "\n\tnode_index1: " << node_index1 
 << "\n\tnode_index2: " << node_index2 
 << "\n\tnumber_of_nodes(): " << self.number_of_nodes() 
 << "\n\tthis: " << &self
 );
 }
 static void check_remove_edge (
 unsigned long node_index1,
 unsigned long node_index2,
 const graph& self
 )
 {
 DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
 node_index2 < self.number_of_nodes(),
 "\tvoid graph::remove_edge(node_index1, node_index2)" 
 << "\n\tYou have specified an invalid index"
 << "\n\tnode_index1: " << node_index1 
 << "\n\tnode_index2: " << node_index2 
 << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
 << "\n\tthis: " << &self
 );
 DLIB_CASSERT( self.has_edge(node_index1, node_index2) == true,
 "\tvoid graph::remove_edge(node_index1, node_index2)"
 << "\n\tYou can't remove an edge if it isn't in the graph"
 << "\n\tnode_index1: " << node_index1 
 << "\n\tnode_index2: " << node_index2 
 << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
 << "\n\tthis: " << &self
 );
 }
 static void check_remove_node (
 unsigned long index,
 const graph& self
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT(index < self.number_of_nodes(),
 "\tvoid 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 graph>
 struct graph_checker_helper <node_type, graph, false>
 { 
 static inline void check_edge ( unsigned long , const node_type& ) { }
 static inline void check_neighbor ( unsigned long , const node_type& ) { }
 static inline void check_node ( unsigned long , const graph& ) { }
 static inline void check_has_edge ( unsigned long , unsigned long , const graph& ) { }
 static inline void check_add_edge ( unsigned long , unsigned long , const graph& ) { }
 static inline void check_remove_edge ( unsigned long , unsigned long , const graph& ) { }
 static inline void check_remove_node ( unsigned long , const graph& ) { }
 };
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E = char,
 typename mem_manager = default_memory_manager,
 bool is_checked = true 
 >
 class 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]->neighbors.size() == nodes[i]->number_of_neighbors(i)
 - nodes[i]->idx == i == nodes[i]->index()
 - for all valid n:
 - nodes[i]->neighbors[n] == pointer to the n'th parent node of i
 - *nodes[i]->neighbors[n] == node(i).neighbor(n)
 - *nodes[i]->edges[n] == node(i).edge(n)
 !*/
 public:
 struct node_type;
 private:
 typedef graph_checker_helper<node_type, graph_kernel_1, is_checked> checker;
 public:
 typedef T type;
 typedef E edge_type;
 typedef mem_manager mem_manager_type;
 graph_kernel_1(
 ) {}
 virtual ~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 node_index1,
 unsigned long node_index2
 ) const;
 void add_edge (
 unsigned long node_index1,
 unsigned long node_index2
 );
 void remove_edge (
 unsigned long node_index1,
 unsigned long node_index2
 );
 unsigned long add_node (
 );
 void remove_node (
 unsigned long index
 );
 void swap (
 graph_kernel_1& item
 ) { nodes.swap(item.nodes); }
 public:
 struct node_type
 {
 T data;
 typedef graph_kernel_1 graph_type;
 unsigned long index(
 ) const { return idx; }
 unsigned long number_of_neighbors (
 ) const { return neighbors.size(); }
 const node_type& neighbor (
 unsigned long edge_index
 ) const { checker::check_neighbor(edge_index,*this); return *neighbors[edge_index]; }
 node_type& neighbor (
 unsigned long edge_index
 ) { checker::check_neighbor(edge_index,*this); return *neighbors[edge_index]; }
 const E& edge (
 unsigned long edge_index
 ) const { checker::check_edge(edge_index,*this); return *edges[edge_index]; }
 E& edge (
 unsigned long edge_index
 ) { checker::check_edge(edge_index,*this); return *edges[edge_index]; }
 private:
 friend class 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> neighbors;
 std::vector<std::shared_ptr<E>,alloc_edge_type> edges;
 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
 >
 inline void swap (
 graph_kernel_1<T,E,mem_manager,is_checked>& a, 
 graph_kernel_1<T,E,mem_manager,is_checked>& b 
 ) { a.swap(b); } 
// ----------------------------------------------------------------------------------------
 template <
 typename T, 
 typename E, 
 typename mem_manager,
 bool is_checked
 >
 struct is_graph<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
 >
 void serialize (
 const graph_kernel_1<T,E,mem_manager,is_checked>& 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 edges
 for (unsigned long n = 0; n < item.node(i).number_of_neighbors(); ++n)
 {
 // only serialize edges that we haven't already serialized 
 if (item.node(i).neighbor(n).index() >= i)
 {
 serialize(item.node(i).neighbor(n).index(), out);
 serialize(item.node(i).edge(n), out);
 }
 }
 const unsigned long stop_mark = 0xFFFFFFFF;
 serialize(stop_mark, out);
 }
 }
 catch (serialization_error& e)
 {
 throw serialization_error(e.info + "\n while serializing object of type graph_kernel_1"); 
 }
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E,
 typename mem_manager,
 bool is_checked
 >
 void deserialize (
 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);
 // deserialize each node
 for (unsigned long i = 0; i < item.number_of_nodes(); ++i)
 {
 deserialize(item.node(i).data, in);
 const unsigned long stop_mark = 0xFFFFFFFF;
 // Add all the edges going to this node's neighbors
 unsigned long index;
 deserialize(index, in);
 while (index != stop_mark)
 {
 item.add_edge(i, index);
 // find the edge
 unsigned long j = 0;
 for (j = 0; j < item.node(i).number_of_neighbors(); ++j)
 if (item.node(i).neighbor(j).index() == index)
 break;
 deserialize(item.node(i).edge(j), in);
 deserialize(index, in);
 }
 }
 }
 catch (serialization_error& e)
 {
 throw serialization_error(e.info + "\n while deserializing object of type graph_kernel_1"); 
 }
 }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E,
 typename mem_manager,
 bool is_checked
 >
 void 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 graph_kernel_1<T,E,mem_manager,is_checked>::
 has_edge (
 unsigned long node_index1,
 unsigned long node_index2
 ) const
 {
 checker::check_has_edge(node_index1, node_index2, *this);
 node_type& n = *nodes[node_index1];
 // search all the child nodes to see if there is a link to the right node
 for (unsigned long i = 0; i < n.neighbors.size(); ++i)
 {
 if (n.neighbors[i]->idx == node_index2)
 return true;
 }
 return false;
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E,
 typename mem_manager,
 bool is_checked
 >
 void graph_kernel_1<T,E,mem_manager,is_checked>::
 add_edge (
 unsigned long node_index1,
 unsigned long node_index2
 )
 {
 checker::check_add_edge(node_index1, node_index2, *this);
 try
 {
 node_type& n1 = *nodes[node_index1];
 node_type& n2 = *nodes[node_index2];
 n1.neighbors.push_back(&n2);
 std::shared_ptr<E> e(new E);
 n1.edges.push_back(e);
 // don't add this twice if this is an edge from node_index1 back to itself
 if (node_index1 != node_index2)
 {
 n2.neighbors.push_back(&n1);
 n2.edges.push_back(e);
 }
 }
 catch (...)
 {
 clear();
 throw;
 }
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E,
 typename mem_manager,
 bool is_checked
 >
 void graph_kernel_1<T,E,mem_manager,is_checked>::
 remove_edge (
 unsigned long node_index1,
 unsigned long node_index2
 )
 {
 checker::check_remove_edge(node_index1, node_index2, *this);
 node_type& n1 = *nodes[node_index1];
 node_type& n2 = *nodes[node_index2];
 // remove the record of the link from n1 
 unsigned long pos = static_cast<unsigned long>(find(n1.neighbors.begin(), n1.neighbors.end(), &n2) - n1.neighbors.begin());
 n1.neighbors.erase(n1.neighbors.begin() + pos); 
 n1.edges.erase(n1.edges.begin() + pos); 
 // check if this is an edge that goes from node_index1 back to itself
 if (node_index1 != node_index2)
 {
 // remove the record of the link from n2 
 unsigned long pos = static_cast<unsigned long>(find(n2.neighbors.begin(), n2.neighbors.end(), &n1) - n2.neighbors.begin());
 n2.neighbors.erase(n2.neighbors.begin() + pos); 
 n2.edges.erase(n2.edges.begin() + pos); 
 }
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T,
 typename E,
 typename mem_manager,
 bool is_checked
 >
 unsigned long 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 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];
 // remove all edges pointing to this node from its neighbors 
 for (unsigned long i = 0; i < n.neighbors.size(); ++i)
 {
 // remove the edge from this specific parent
 unsigned long pos = static_cast<unsigned long>(find(n.neighbors[i]->neighbors.begin(), n.neighbors[i]->neighbors.end(), &n) - 
 n.neighbors[i]->neighbors.begin());
 n.neighbors[i]->neighbors.erase(n.neighbors[i]->neighbors.begin() + pos); 
 n.neighbors[i]->edges.erase(n.neighbors[i]->edges.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_GRAPH_KERNEl_1_

AltStyle によって変換されたページ (->オリジナル) /