From 6bf503fa56474d89a9a59376bd720fee519ac6cf Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 3 Mar 2005 14:06:42 +0000 Subject: [PATCH] Initial version [SVN r27536] --- src/python/basic_graph.cpp | 538 ++++++++++++++++++++++++++ src/python/basic_graph.hpp | 353 +++++++++++++++++ src/python/betweenness_centrality.cpp | 126 ++++++ src/python/breadth_first_search.cpp | 183 +++++++++ src/python/digraph.cpp | 10 + src/python/digraph.hpp | 10 + src/python/done.cpp | 24 ++ src/python/done.hpp | 15 + src/python/graph.cpp | 11 + src/python/graph.hpp | 28 ++ src/python/graphviz.cpp | 45 +++ src/python/module.cpp | 40 ++ src/python/queue.hpp | 58 +++ 13 files changed, 1441 insertions(+) create mode 100644 src/python/basic_graph.cpp create mode 100644 src/python/basic_graph.hpp create mode 100644 src/python/betweenness_centrality.cpp create mode 100644 src/python/breadth_first_search.cpp create mode 100644 src/python/digraph.cpp create mode 100644 src/python/digraph.hpp create mode 100644 src/python/done.cpp create mode 100644 src/python/done.hpp create mode 100644 src/python/graph.cpp create mode 100644 src/python/graph.hpp create mode 100644 src/python/graphviz.cpp create mode 100644 src/python/module.cpp create mode 100644 src/python/queue.hpp diff --git a/src/python/basic_graph.cpp b/src/python/basic_graph.cpp new file mode 100644 index 00000000..440e16e1 --- /dev/null +++ b/src/python/basic_graph.cpp @@ -0,0 +1,538 @@ +#include "basic_graph.hpp" + +namespace boost { namespace graph { namespace python { + +class copying_dynamic_property_map +{ + public: + virtual ~copying_dynamic_property_map() {} + + virtual void copy_value(const any& to, const any& from) = 0; +}; + +template +class copying_dynamic_adaptor + : public boost::detail::dynamic_property_map_adaptor, + public copying_dynamic_property_map +{ + typedef boost::detail::dynamic_property_map_adaptor inherited; + +public: + typedef typename property_traits::key_type key_type; + + explicit copying_dynamic_adaptor(const PropertyMap& property_map) + : inherited(property_map) { } + + virtual void copy_value(const any& to, const any& from) + { + boost::put(this->base(), any_cast(to), + boost::get(this->base(), any_cast(from))); + } +}; + +template +struct build_string_property_maps +{ + build_string_property_maps(basic_graph* g) : g(g) { } + + std::auto_ptr + operator()(const std::string& name, const boost::any& key, + const boost::any& value) + { + typedef typename basic_graph::VertexIndexMap VertexIndexMap; + typedef typename basic_graph::EdgeIndexMap EdgeIndexMap; + + std::auto_ptr result(0); + + if (key.type() == typeid(typename basic_graph::Vertex)) { + typedef vector_property_map + property_map_type; + typedef copying_dynamic_adaptor adaptor_type; + result.reset + (new adaptor_type(property_map_type(g->num_vertices(), + g->get_vertex_index_map()))); + } else if (key.type() == typeid(typename basic_graph::Edge)) { + typedef vector_property_map property_map_type; + typedef copying_dynamic_adaptor adaptor_type; + result.reset + (new adaptor_type(property_map_type(g->num_edges(), + g->get_edge_index_map()))); + } + return result; + } + +private: + basic_graph* g; +}; + +// ---------------------------------------------------------- +// Constructors +// ---------------------------------------------------------- +template +basic_graph::basic_graph() + : inherited(), dp(build_string_property_maps(this)) +{ } + +template +basic_graph::basic_graph(const std::string& filename, + graph_file_kind kind) + : inherited(), dp(build_string_property_maps(this)) +{ + switch (kind) { + case gfk_adjlist: + break; + case gfk_graphviz: + read_graphviz(filename); + break; + } +} + +// ---------------------------------------------------------- +// Incidence basic_graph concept +// ---------------------------------------------------------- +template +typename basic_graph::Vertex +basic_graph::source(Edge e) const +{ return Vertex(boost::source(e.base, base())); } + +template +typename basic_graph::Vertex +basic_graph::target(Edge e) const +{ return Vertex(boost::target(e.base, base())); } + + +template +std::pair::out_edge_iterator, + typename basic_graph::out_edge_iterator> +basic_graph::out_edges(Vertex u) const +{ + std::pair rng = + boost::out_edges(u.base, base()); + return std::make_pair(out_edge_iterator(rng.first, Edge::create()), + out_edge_iterator(rng.second, Edge::create())); +} + +template +simple_python_iterator::out_edge_iterator> +basic_graph::py_out_edges(Vertex u) const +{ + return simple_python_iterator(out_edges(u)); +} + +template +std::size_t +basic_graph::out_degree(Vertex u) const +{ + return boost::out_degree(u.base, base()); +} + +// ---------------------------------------------------------- +// Bidirectional basic_graph concept +// ---------------------------------------------------------- +template +std::pair::in_edge_iterator, + typename basic_graph::in_edge_iterator> +basic_graph::in_edges(Vertex u) const +{ + std::pair rng = + boost::in_edges(u.base, base()); + return std::make_pair(in_edge_iterator(rng.first, Edge::create()), + in_edge_iterator(rng.second, Edge::create())); +} + +template +simple_python_iterator::in_edge_iterator> +basic_graph::py_in_edges(Vertex u) const +{ + return simple_python_iterator(in_edges(u)); +} + +template +std::size_t +basic_graph::in_degree(Vertex u) const +{ + return boost::in_degree(u.base, base()); +} + +// ---------------------------------------------------------- +// Adjacency basic_graph concept +// ---------------------------------------------------------- +template +std::pair::adjacency_iterator, + typename basic_graph::adjacency_iterator> +basic_graph::adjacent_vertices(Vertex u) const +{ + std::pair rng = + boost::adjacent_vertices(u.base, base()); + return std::make_pair(adjacency_iterator(rng.first, Vertex::create()), + adjacency_iterator(rng.second, Vertex::create())); +} + +template +simple_python_iterator::adjacency_iterator> +basic_graph::py_adjacent_vertices(Vertex u) const +{ + return + simple_python_iterator(adjacent_vertices(u)); +} + +// ---------------------------------------------------------- +// Vertex properties +// ---------------------------------------------------------- +template +template +vector_property_map::VertexIndexMap> +basic_graph::get_vertex_map(const std::string& name) +{ + typedef vector_property_map result_type; + typedef copying_dynamic_adaptor adaptor_type; + + dynamic_properties::iterator i = dp.lower_bound(name); + while (i != dp.end() && i->first == name) { + if (i->second->key() == typeid(Vertex)) { + if (i->second->value() == typeid(T)) { + return dynamic_cast(*i->second).base(); + } else { + // Convert the property map element-by-element to the + // requested type. + result_type result(num_vertices(), get_vertex_index_map()); + for(vertex_iterator v = vertices().first; v != vertices().second; + ++v) { + put(result, *v, lexical_cast(i->second->get_string(*v))); + } + + // Replace the existing property map with the converted one + adaptor_type* adaptor = new adaptor_type(result); + delete i->second; + i->second = adaptor; + + // Return the new property map. + return result; + } + } + ++i; + } + + typedef vector_property_map property_map_type; + typedef copying_dynamic_adaptor adaptor_type; + property_map_type result(num_vertices(), get_vertex_index_map()); + dp.insert(name, + std::auto_ptr(new adaptor_type(result))); + return result; +} + +template +bool +basic_graph::has_vertex_map(const std::string& name) const +{ + dynamic_properties::const_iterator i = dp.lower_bound(name); + while (i != dp.end() && i->first == name) { + if (i->second->key() == typeid(Vertex)) + return true; + } + return false; +} + +// ---------------------------------------------------------- +// Edge properties +// ---------------------------------------------------------- +template +template +vector_property_map::EdgeIndexMap> +basic_graph::get_edge_map(const std::string& name) +{ + typedef vector_property_map result_type; + typedef copying_dynamic_adaptor adaptor_type; + + dynamic_properties::iterator i = dp.lower_bound(name); + while (i != dp.end() && i->first == name) { + if (i->second->key() == typeid(Edge)) { + if (i->second->value() == typeid(T)) { + return dynamic_cast(*i->second).base(); + } else { + // Convert the property map element-by-element to the + // requested type. + result_type result(num_vertices(), get_edge_index_map()); + for(edge_iterator e = edges().first; e != edges().second; ++e) { + put(result, *e, lexical_cast(i->second->get_string(*e))); + } + + // Replace the existing property map with the converted one + adaptor_type* adaptor = new adaptor_type(result); + delete i->second; + i->second = adaptor; + + // Return the new property map. + return result; + } + } + ++i; + } + + typedef vector_property_map property_map_type; + typedef copying_dynamic_adaptor adaptor_type; + property_map_type result(num_edges(), get_edge_index_map()); + dp.insert(name, + std::auto_ptr(new adaptor_type(result))); + return result; +} + +template +bool +basic_graph::has_edge_map(const std::string& name) const +{ + dynamic_properties::const_iterator i = dp.lower_bound(name); + while (i != dp.end() && i->first == name) { + if (i->second->key() == typeid(Edge)) + return true; + } + return false; +} + +// ---------------------------------------------------------- +// Mutable graph +// ---------------------------------------------------------- +template +typename basic_graph::Vertex basic_graph::add_vertex() +{ + using boost::add_vertex; + + base_vertex_descriptor v = add_vertex(base()); + put(vertex_index, base(), v, index_to_vertex.size()); + index_to_vertex.push_back(v); + return Vertex(v); +} + +template +void basic_graph::clear_vertex(Vertex vertex) +{ + // Remove all incoming and outgoing edges + while (out_degree(vertex) > 0) remove_edge(*out_edges(vertex).first); + while (in_degree(vertex) > 0) remove_edge(*in_edges(vertex).first); +} + +template +void basic_graph::remove_vertex(Vertex vertex) +{ + using boost::remove_vertex; + + // Update property maps + for (dynamic_properties::iterator i = dp.begin(); i != dp.end(); ++i) { + if (i->second->key() == typeid(Vertex)) { + dynamic_cast(*i->second). + copy_value(vertex, Vertex(index_to_vertex.back())); + } + } + + // Update vertex indices + std::size_t index = get(vertex_index, base(), vertex.base); + index_to_vertex[index] = index_to_vertex.back(); + put(vertex_index, base(), index_to_vertex[index], index); + index_to_vertex.pop_back(); + + // Remove the actual vertex + remove_vertex(vertex.base, base()); +} + +template +std::size_t basic_graph::num_vertices() const +{ + using boost::num_vertices; + return num_vertices(base()); +} + +template +typename basic_graph::vertex_iterator +basic_graph::vertices_begin() const +{ + return make_transform_iterator(boost::vertices(base()).first, + Vertex::create()); +} + +template +typename basic_graph::vertex_iterator +basic_graph::vertices_end() const +{ + return make_transform_iterator(boost::vertices(base()).second, + Vertex::create()); +} + +template +std::pair::vertex_iterator, + typename basic_graph::vertex_iterator> +basic_graph::vertices() const +{ + return std::make_pair(vertices_begin(), vertices_end()); +} + +template +typename basic_graph::Edge +basic_graph::add_edge(Vertex u, Vertex v) +{ + using boost::add_edge; + + base_edge_descriptor e = add_edge(u.base, v.base, base()).first; + put(edge_index, base(), e, index_to_edge.size()); + index_to_edge.push_back(e); + return Edge(e); +} + +template +void basic_graph::remove_edge(Edge edge) +{ + using boost::remove_edge; + + // Update property maps + for (dynamic_properties::iterator i = dp.begin(); i != dp.end(); ++i) { + if (i->second->key() == typeid(Edge)) { + dynamic_cast(*i->second). + copy_value(edge, Edge(index_to_edge.back())); + } + } + + // Update edge indices + std::size_t index = get(edge_index, base(), edge.base); + index_to_edge[index] = index_to_edge.back(); + put(edge_index, base(), index_to_edge[index], index); + index_to_edge.pop_back(); + + // Remove the actual edge + remove_edge(edge.base, base()); +} + +template +std::size_t basic_graph::num_edges() const +{ + using boost::num_edges; + return num_edges(base()); +} + +template +typename basic_graph::edge_iterator +basic_graph::edges_begin() const +{ + return make_transform_iterator(boost::edges(base()).first, + Edge::create()); +} + +template +typename basic_graph::edge_iterator +basic_graph::edges_end() const +{ + return make_transform_iterator(boost::edges(base()).second, + Edge::create()); +} + +template +std::pair::edge_iterator, + typename basic_graph::edge_iterator> +basic_graph::edges() const +{ + return std::make_pair(edges_begin(), edges_end()); +} + +template void export_in_graph(); + +template +void export_basic_graph(const char* name) +{ + typedef basic_graph Graph; + typedef typename Graph::Vertex Vertex; + typedef typename Graph::Edge Edge; + typedef typename Graph::VertexIndexMap VertexIndexMap; + typedef typename Graph::EdgeIndexMap EdgeIndexMap; + + { + scope s( + class_ >(name) + // Constructors + .def(init()) + // Vertex List Graph concept + .def("num_vertices", &Graph::num_vertices) + .add_property("vertices", range(&Graph::vertices_begin, + &Graph::vertices_end)) + // Edge List Graph concept + .def("num_edges", &Graph::num_edges) + .add_property("edges", range(&Graph::edges_begin, &Graph::edges_end)) + // Mutable Graph concept + .def("add_vertex", &Graph::add_vertex) + .def("clear_vertex", &Graph::clear_vertex) + .def("remove_vertex", &Graph::remove_vertex) + .def("add_edge", &Graph::add_edge) + .def("remove_edge", &Graph::remove_edge) + // Incidence Graph concept + .def("source", &Graph::source) + .def("target", &Graph::target) + .def("out_edges", &Graph::py_out_edges) + .def("out_degree", &Graph::out_degree) + .def("in_edges", &Graph::py_in_edges) + .def("in_degree", &Graph::in_degree) + .def("adjacent_vertices", &Graph::py_adjacent_vertices) + // Vertex property maps + .def("has_vertex_map", &Graph::has_vertex_map) + .def("get_vertex_index_map", &Graph::get_vertex_index_map) + .def("get_vertex_double_map", &Graph::template get_vertex_map) + .def("get_vertex_int_map", &Graph::template get_vertex_map) + .def("get_vertex_string_map", + &Graph::template get_vertex_map) + .def("get_vertex_object_map", &Graph::template get_vertex_map) + // Edge property maps + .def("has_edge_map", &Graph::has_vertex_map) + .def("get_edge_index_map", &Graph::get_edge_index_map) + .def("get_edge_double_map", &Graph::template get_edge_map) + .def("get_edge_int_map", &Graph::template get_edge_map) + .def("get_edge_string_map", &Graph::template get_edge_map) + .def("get_edge_object_map", &Graph::template get_edge_map) + // Graph I/O + .def("read_graphviz", &Graph::read_graphviz) + .def("write_graphviz", &Graph::write_graphviz) + .def("write_graphviz", &Graph::write_graphviz_def) + ); + + export_in_graph(); + } + + if (!type_already_registered()) + class_("Vertex") + .def(self == self) + .def(self != self); + + if (!type_already_registered()) + class_("Edge") + .def(self == self) + .def(self != self); + + // Iterators + simple_python_iterator + ::declare("out_edge_iterator"); + simple_python_iterator + ::declare("in_edge_iterator"); + simple_python_iterator + ::declare("adjacency_iterator"); + + // Vertex property maps + declare_readable_property_map + ::declare("vertex_index_map"); + declare_property_map > + ::declare("vertex_double_map"); + declare_property_map > + ::declare("vertex_int_map"); + declare_property_map > + ::declare("vertex_string_map"); + declare_property_map > + ::declare("vertex_object_map"); + + // Edge property maps + declare_readable_property_map + ::declare("edge_index_map"); + declare_property_map > + ::declare("edge_double_map"); + declare_property_map > + ::declare("edge_int_map"); + declare_property_map > + ::declare("edge_string_map"); + declare_property_map > + ::declare("edge_object_map"); +} + +} } } // end namespace boost::graph::python diff --git a/src/python/basic_graph.hpp b/src/python/basic_graph.hpp new file mode 100644 index 00000000..95116676 --- /dev/null +++ b/src/python/basic_graph.hpp @@ -0,0 +1,353 @@ +#ifndef BOOST_GRAPH_BASIC_GRAPH_HPP +#define BOOST_GRAPH_BASIC_GRAPH_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace graph { namespace python { + +using namespace boost::python; + +template bool type_already_registered() +{ + return objects::registered_class_object(python::type_id()).get() != 0; +} + +template +class simple_python_iterator +{ +public: + simple_python_iterator(std::pair p) + : first(p.first), last(p.second) { } + + typename std::iterator_traits::value_type next() + { + if (first == last) objects::stop_iteration_error(); + return *first++; + } + + static void declare(const char* name) + { + if (!type_already_registered()) + class_ >(name, no_init) + .def("__iter__", objects::identity_function()) + .def("next", &simple_python_iterator::next) + ; + } + +private: + Iterator first; + Iterator last; +}; + +template +struct declare_readable_property_map +{ + typedef typename property_traits::key_type key_type; + typedef typename property_traits::value_type value_type; + + static value_type getitem(const PropertyMap& pm, const key_type& key) + { return get(pm, key); } + + static void declare(const char* name) + { + if (!type_already_registered()) + class_(name, no_init) + .def("__getitem__", &getitem) + ; + } +}; + +template +struct declare_property_map +{ + typedef typename property_traits::key_type key_type; + typedef typename property_traits::value_type value_type; + + static value_type getitem(const PropertyMap& pm, const key_type& key) + { return get(pm, key); } + + static void + setitem(const PropertyMap& pm, const key_type& key,const value_type& value) + { return put(pm, key, value); } + + static void declare(const char* name) + { + if (!type_already_registered()) + class_(name, no_init) + .def("__getitem__", &getitem) + .def("__setitem__", &setitem) + ; + } +}; + +template +struct basic_descriptor +{ + basic_descriptor() {} + basic_descriptor(T base) : base(base) { } + + operator T() const { return base; } + + struct create + { + typedef basic_descriptor result_type; + basic_descriptor operator()(T base) const { return base; } + }; + + T base; +}; + +template +inline bool +operator==(const basic_descriptor& u, + const basic_descriptor& v) +{ return u.base == v.base; } + +template +inline bool +operator!=(const basic_descriptor& u, + const basic_descriptor& v) +{ return u.base != v.base; } + +template +struct basic_index_map +{ + typedef Key key_type; + typedef typename property_traits::value_type value_type; + typedef typename property_traits::reference reference; + typedef typename property_traits::category category; + + basic_index_map() {} + basic_index_map(const IndexMap& id = IndexMap()) + : id(id) { } + + IndexMap id; +}; + +template +inline typename basic_index_map::value_type +get(const basic_index_map& pm, + typename basic_index_map::key_type const& key) +{ return get(pm.id, key.base); } + +enum graph_file_kind { gfk_adjlist, gfk_graphviz }; + +template +class basic_graph + : public adjacency_list, + property > +{ + typedef adjacency_list, + property > inherited; + typedef graph_traits traits; + + typedef typename traits::vertex_iterator base_vertex_iterator; + typedef typename traits::edge_iterator base_edge_iterator; + typedef typename traits::out_edge_iterator base_out_edge_iterator; + typedef typename traits::in_edge_iterator base_in_edge_iterator; + typedef typename traits::adjacency_iterator base_adjacency_iterator; + typedef typename property_map::const_type + base_vertex_index_map; + typedef typename property_map::const_type + base_edge_index_map; + typedef typename traits::vertex_descriptor base_vertex_descriptor; + typedef typename traits::edge_descriptor base_edge_descriptor; + + public: + typedef basic_descriptor Vertex; + typedef Vertex vertex_descriptor; + typedef basic_descriptor Edge; + typedef Edge edge_descriptor; + typedef basic_index_map + VertexIndexMap; + typedef basic_index_map EdgeIndexMap; + typedef std::size_t vertices_size_type; + typedef std::size_t edges_size_type; + typedef std::size_t degree_size_type; + typedef typename traits::directed_category directed_category; + typedef typename traits::edge_parallel_category edge_parallel_category; + typedef typename traits::traversal_category traversal_category; + typedef transform_iterator + vertex_iterator; + typedef transform_iterator + edge_iterator; + typedef transform_iterator + out_edge_iterator; + typedef transform_iterator + in_edge_iterator; + typedef transform_iterator + adjacency_iterator; + + basic_graph(); + basic_graph(const std::string& filename, graph_file_kind kind); + + Vertex add_vertex(); + void clear_vertex(Vertex vertex); + void remove_vertex(Vertex vertex); + std::size_t num_vertices() const; + std::pair vertices() const; + vertex_iterator vertices_begin() const; + vertex_iterator vertices_end() const; + + Edge add_edge(Vertex u, Vertex v); + void remove_edge(Edge edge); + std::size_t num_edges() const; + std::pair edges() const; + edge_iterator edges_begin() const; + edge_iterator edges_end() const; + + // Incidence Graph concept + Vertex source(Edge e) const; + Vertex target(Edge e) const; + std::pair out_edges(Vertex u) const; + simple_python_iterator py_out_edges(Vertex u) const; + std::size_t out_degree(Vertex u) const; + + // Bidirectional Graph concept + std::pair in_edges(Vertex u) const; + simple_python_iterator py_in_edges(Vertex u) const; + std::size_t in_degree(Vertex u) const; + + // Adjacency Graph concept + std::pair + adjacent_vertices(Vertex u) const; + + simple_python_iterator + py_adjacent_vertices(Vertex u) const; + + // Vertex property maps + VertexIndexMap get_vertex_index_map() const + { return get(vertex_index, base()); } + + template + vector_property_map + get_vertex_map(const std::string& name); + + bool has_vertex_map(const std::string& name) const; + + // Edge property maps + EdgeIndexMap get_edge_index_map() const + { return get(edge_index, base()); } + + template + vector_property_map + get_edge_map(const std::string& name); + + bool has_edge_map(const std::string& name) const; + + // Graph I/O + void read_graphviz(const std::string& filename, + const std::string& node_id = std::string("node_id")); + + void write_graphviz(const std::string& filename, + const std::string& node_id = std::string("node_id")); + + void write_graphviz_def(const std::string& filename) + { write_graphviz(filename); } + + + inherited& base() { return *this; } + const inherited& base() const { return *this; } + + private: + std::vector index_to_vertex; + std::vector index_to_edge; + dynamic_properties dp; +}; + +// Vertex List Graph concept +template +inline std::pair::vertex_iterator, + typename basic_graph::vertex_iterator> +vertices(const basic_graph& g) +{ return g.vertices(); } + +template +inline std::size_t num_vertices(const basic_graph& g) +{ return g.num_vertices(); } + +// Edge List Graph concept +template +inline std::pair::edge_iterator, + typename basic_graph::edge_iterator> +edges(const basic_graph& g) +{ return g.edges(); } + +template +inline std::size_t num_edges(const basic_graph& g) +{ return g.num_edges(); } + +// Incidence Graph concept +template +inline typename basic_graph::vertex_descriptor +source(typename basic_graph::edge_descriptor e, + const basic_graph& g) +{ return g.source(e); } + +template +inline typename basic_graph::vertex_descriptor +target(typename basic_graph::edge_descriptor e, + const basic_graph& g) +{ return g.target(e); } + +template +inline std::pair::out_edge_iterator, + typename basic_graph::out_edge_iterator> +out_edges(typename basic_graph::vertex_descriptor u, + const basic_graph& g) +{ return g.out_edges(u); } + +template +inline std::size_t +out_degree(typename basic_graph::vertex_descriptor u, + const basic_graph& g) +{ return g.out_degree(u); } + +// Bidirectional Graph concept +template +inline std::pair::in_edge_iterator, + typename basic_graph::in_edge_iterator> +in_edges(typename basic_graph::vertex_descriptor u, + const basic_graph& g) +{ return g.in_edges(u); } + +template +inline std::size_t +in_degree(typename basic_graph::vertex_descriptor u, + const basic_graph& g) +{ return g.in_degree(u); } + +// Adjacency Graph concept +template +inline std::pair::adjacency_iterator, + typename basic_graph::adjacency_iterator> +adjacent_vertices(typename basic_graph::vertex_descriptor u, + const basic_graph& g) +{ return g.adjacent_vertices(u); } + +// Mutable basic_graph concept +template +inline typename basic_graph::vertex_descriptor +add_vertex(basic_graph& g) +{ return g.add_vertex(); } + +template +inline std::pair::edge_descriptor, bool> +add_edge(typename basic_graph::vertex_descriptor u, + typename basic_graph::vertex_descriptor v, + basic_graph& g) +{ return std::make_pair(g.add_edge(u, v), true); } + +template +void export_basic_graph(const char* name); + +} } } // end namespace boost::graph::python + +#endif // BOOST_GRAPH_BASIC_GRAPH_HPP diff --git a/src/python/betweenness_centrality.cpp b/src/python/betweenness_centrality.cpp new file mode 100644 index 00000000..268324df --- /dev/null +++ b/src/python/betweenness_centrality.cpp @@ -0,0 +1,126 @@ +#include "graph.hpp" +#include "digraph.hpp" +#include + +namespace boost { namespace graph { namespace python { + +template +void +brandes_betweenness_centrality_ve + (Graph& g, + const vector_property_map& vertex_centrality, + const vector_property_map& edge_centrality) +{ + brandes_betweenness_centrality + (g, + centrality_map(vertex_centrality). + edge_centrality_map(edge_centrality). + vertex_index_map(g.get_vertex_index_map())); +} + +template +inline void +brandes_betweenness_centrality_v + (Graph& g, + const vector_property_map& vertex_centrality) +{ + brandes_betweenness_centrality_ve(g, vertex_centrality, + g.template get_edge_map("centrality")); +} + +template +void +brandes_betweenness_centrality_wve + (Graph& g, + const vector_property_map& weight, + const vector_property_map& vertex_centrality, + const vector_property_map& edge_centrality) +{ + brandes_betweenness_centrality + (g, + weight_map(weight). + centrality_map(vertex_centrality). + edge_centrality_map(edge_centrality). + vertex_index_map(g.get_vertex_index_map())); +} + +template +inline void +brandes_betweenness_centrality_wv + (Graph& g, + const vector_property_map& weight, + const vector_property_map& vertex_centrality) +{ + brandes_betweenness_centrality_wve(g, weight, vertex_centrality, + g.template get_edge_map("centrality")); +} + +template +inline void +brandes_betweenness_centrality_w + (Graph& g, + const vector_property_map& weight) +{ + brandes_betweenness_centrality_wv(g, weight, + g.template get_vertex_map("centrality")); +} + +template +inline void +brandes_betweenness_centrality(Graph& g) +{ + brandes_betweenness_centrality_v(g, g.template get_vertex_map("centrality")); +} + +template +void +relative_betweenness_centrality + (Graph& g, + const vector_property_map& centrality) +{ relative_betweenness_centrality(g, centrality); } + +template +double +central_point_dominance + (Graph& g, + const vector_property_map& centrality) +{ return boost::central_point_dominance(g, centrality); } + +void export_betweenness_centrality() +{ + // Graph + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_v); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_ve); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_w); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_wv); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_wve); + def("relative_betweenness_centrality", + &relative_betweenness_centrality); + def("central_point_dominance", ¢ral_point_dominance); + + // Digraph + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_v); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_ve); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_w); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_wv); + def("brandes_betweenness_centrality", + &brandes_betweenness_centrality_wve); + def("relative_betweenness_centrality", + &relative_betweenness_centrality); + def("central_point_dominance", ¢ral_point_dominance); +} + +} } } // end namespace boost::graph::python diff --git a/src/python/breadth_first_search.cpp b/src/python/breadth_first_search.cpp new file mode 100644 index 00000000..6055076e --- /dev/null +++ b/src/python/breadth_first_search.cpp @@ -0,0 +1,183 @@ +#include +#include "graph.hpp" +#include "digraph.hpp" +#include "queue.hpp" + +namespace boost { namespace graph { namespace python { + +template +class bfs_visitor +{ + public: + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::edge_descriptor edge_descriptor; + + virtual ~bfs_visitor() {} + + virtual void initialize_vertex(vertex_descriptor s, const Graph& g) const {} + virtual void discover_vertex(vertex_descriptor u, const Graph& g) const {} + virtual void examine_vertex(vertex_descriptor s, const Graph& g) const {} + virtual void examine_edge(edge_descriptor e, const Graph& g) const {} + virtual void tree_edge(edge_descriptor e, const Graph& g) const {} + virtual void non_tree_edge(edge_descriptor e, const Graph& g) const {} + virtual void gray_target(edge_descriptor e, const Graph& g) const {} + virtual void black_target(edge_descriptor e, const Graph& g) const {} + virtual void finish_vertex(vertex_descriptor s, const Graph& g) const {} +}; + +template +class bfs_visitor_wrap + : public bfs_visitor, + public boost::python::wrapper > +{ + public: + typedef typename bfs_visitor::vertex_descriptor vertex_descriptor; + typedef typename bfs_visitor::edge_descriptor edge_descriptor; + +#define BGL_PYTHON_EVENT(Name,Descriptor) \ + void Name(Descriptor x, const Graph& g) const \ + { \ + if (override f = this->get_override(#Name)) \ + f(x, boost::cref(g)); \ + else bfs_visitor::Name(x, g); \ + } \ + \ + void default_##Name(Descriptor x, const Graph& g) const \ + { this->bfs_visitor::Name(x, g); } + + BGL_PYTHON_EVENT(initialize_vertex, vertex_descriptor) + BGL_PYTHON_EVENT(examine_vertex, vertex_descriptor) + BGL_PYTHON_EVENT(examine_edge, edge_descriptor) + BGL_PYTHON_EVENT(tree_edge, edge_descriptor) + BGL_PYTHON_EVENT(non_tree_edge, edge_descriptor) + BGL_PYTHON_EVENT(gray_target, edge_descriptor) + BGL_PYTHON_EVENT(black_target, edge_descriptor) + BGL_PYTHON_EVENT(finish_vertex, vertex_descriptor) + +#undef BGL_PYTHON_EVENT +}; + +template +struct wrap_bfs_visitor_ref +{ + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::edge_descriptor edge_descriptor; + + wrap_bfs_visitor_ref(const bfs_visitor& v) : v(v) { } + + void initialize_vertex(vertex_descriptor s, const Graph& g) const + { v.initialize_vertex(s, g); } + + void discover_vertex(vertex_descriptor u, const Graph& g) const + { v.discover_vertex(u, g); } + + void examine_vertex(vertex_descriptor u, const Graph& g) const + { v.examine_vertex(u, g); } + + void examine_edge(edge_descriptor e, const Graph& g) const + { v.examine_edge(e, g); } + + void tree_edge(edge_descriptor e, const Graph& g) const + { v.tree_edge(e, g); } + + void non_tree_edge(edge_descriptor e, const Graph& g) const + { v.non_tree_edge(e, g); } + + void gray_target(edge_descriptor e, const Graph& g) const + { v.gray_target(e, g); } + + void black_target(edge_descriptor e, const Graph& g) const + { v.black_target(e, g); } + + void finish_vertex(vertex_descriptor u, const Graph& g) const + { v.finish_vertex(u, g); } + + private: + const bfs_visitor& v; +}; + +template + class default_bfs_visitor : public bfs_visitor {}; + +template +void +breadth_first_search_v + (const Graph& g, + typename Graph::Vertex s, + const bfs_visitor& visitor) +{ + if (dynamic_cast*>(&visitor)) { + // No visitor. Do default BFS + boost::breadth_first_search(g, s, + vertex_index_map(g.get_vertex_index_map())); + } else { + boost::breadth_first_search + (g, s, + vertex_index_map(g.get_vertex_index_map()). + visitor(wrap_bfs_visitor_ref(visitor))); + } +} + +template +void +breadth_first_search_qv + (const Graph& g, + typename Graph::Vertex s, + const python_queue& Q) +// const bfs_visitor& visitor) +{ + boost::breadth_first_search(g, s, + vertex_index_map(g.get_vertex_index_map())); +} + + +void export_breadth_first_search() +{ + using boost::python::arg; + + // Breadth-first search algorithm + def("breadth_first_search", &breadth_first_search_v, + (arg("graph"), "root_vertex", + arg("visitor") = default_bfs_visitor())); + + def("breadth_first_search2", &breadth_first_search_qv); +// (arg("graph"), "root_vertex", +// arg("buffer") = python_queue::default_queue())); +} + +template +void export_breadth_first_search_in_graph() +{ + using boost::python::arg; + + // BFS visitor + class_, boost::noncopyable>("BFSVisitor") + .def("initialize_vertex", &bfs_visitor::initialize_vertex, + &bfs_visitor_wrap::default_initialize_vertex) + .def("examine_vertex", &bfs_visitor::examine_vertex, + &bfs_visitor_wrap::default_examine_vertex) + .def("examine_edge", &bfs_visitor::examine_edge, + &bfs_visitor_wrap::default_examine_edge) + .def("tree_edge", &bfs_visitor::tree_edge, + &bfs_visitor_wrap::default_tree_edge) + .def("non_tree_edge", &bfs_visitor::non_tree_edge, + &bfs_visitor_wrap::default_non_tree_edge) + .def("gray_target", &bfs_visitor::gray_target, + &bfs_visitor_wrap::default_gray_target) + .def("black_target", &bfs_visitor::black_target, + &bfs_visitor_wrap::default_black_target) + .def("finish_vertex", &bfs_visitor::finish_vertex, + &bfs_visitor_wrap::default_finish_vertex) + ; + + class_, bases > > + ("DefaultBFSVisitor", no_init); + + python_queue::declare("VertexQueue", + "DefaultVertexQueue"); +} + +template void export_breadth_first_search_in_graph(); +template void export_breadth_first_search_in_graph(); + +} } } // end namespace boost::graph::python diff --git a/src/python/digraph.cpp b/src/python/digraph.cpp new file mode 100644 index 00000000..f91f9934 --- /dev/null +++ b/src/python/digraph.cpp @@ -0,0 +1,10 @@ +#include "digraph.hpp" +#include "basic_graph.cpp" + +namespace boost { namespace graph { namespace python { + +void export_Digraph() +{ + export_basic_graph("Digraph"); +} +} } } // end namespace boost::graph::python diff --git a/src/python/digraph.hpp b/src/python/digraph.hpp new file mode 100644 index 00000000..c0cf5508 --- /dev/null +++ b/src/python/digraph.hpp @@ -0,0 +1,10 @@ +#ifndef BOOST_GRAPH_PYTHON_DIGRAPH_HPP +#define BOOST_GRAPH_PYTHON_DIGRAPH_HPP + +#include "basic_graph.hpp" + +namespace boost { namespace graph { namespace python { + typedef basic_graph Digraph; +} } } // end namespace boost::graph::python + +#endif // BOOST_GRAPH_PYTHON_DIGRAPH_HPP diff --git a/src/python/done.cpp b/src/python/done.cpp new file mode 100644 index 00000000..9ed56569 --- /dev/null +++ b/src/python/done.cpp @@ -0,0 +1,24 @@ +#include "done.hpp" +#include + +namespace boost { namespace graph { namespace python { + +using namespace boost::python; + +class done_wrap : public done, public wrapper +{ +public: + bool operator()() const + { + return this->get_override("__call__")(); + } +}; + +void export_done() +{ + class_("Done") + .def("__call__", pure_virtual(&done::operator())) + ; +} + +} } } // end namespace boost::graph::python diff --git a/src/python/done.hpp b/src/python/done.hpp new file mode 100644 index 00000000..a35c51ba --- /dev/null +++ b/src/python/done.hpp @@ -0,0 +1,15 @@ +#ifndef BOOST_GRAPH_PYTHON_DONE_HPP +#define BOOST_GRAPH_PYTHON_DONE_HPP + +namespace boost { namespace graph { namespace python { + +class done +{ + public: + virtual ~done() { } + virtual bool operator()() const = 0; +}; + +} } } // end namespace boost::graph::python + +#endif // BOOST_GRAPH_PYTHON_DONE_HPP diff --git a/src/python/graph.cpp b/src/python/graph.cpp new file mode 100644 index 00000000..9bc4986a --- /dev/null +++ b/src/python/graph.cpp @@ -0,0 +1,11 @@ +#include "graph.hpp" +#include "basic_graph.cpp" +#include + +namespace boost { namespace graph { namespace python { + +void export_Graph() +{ + export_basic_graph("Graph"); +} +} } } // end namespace boost::graph::python diff --git a/src/python/graph.hpp b/src/python/graph.hpp new file mode 100644 index 00000000..07259bf5 --- /dev/null +++ b/src/python/graph.hpp @@ -0,0 +1,28 @@ +#ifndef BOOST_GRAPH_PYTHON_GRAPH_HPP +#define BOOST_GRAPH_PYTHON_GRAPH_HPP + +#include "basic_graph.hpp" + +namespace boost { namespace graph { namespace python { + + typedef basic_graph Graph; + +#if 0 + class Graph : public basic_graph + { + typedef basic_graph inherited; + + public: + Graph() : inherited() { } + Graph(const std::string& filename, graph_file_kind kind) + : inherited(filename, kind) { } + + vertex_iterator vertices_begin() const; + vertex_iterator vertices_end() const; + edge_iterator edges_begin() const; + edge_iterator edges_end() const; + }; +#endif +} } } // end namespace boost::graph::python + +#endif // BOOST_GRAPH_PYTHON_GRAPH_HPP diff --git a/src/python/graphviz.cpp b/src/python/graphviz.cpp new file mode 100644 index 00000000..6b662e4b --- /dev/null +++ b/src/python/graphviz.cpp @@ -0,0 +1,45 @@ +#include "basic_graph.hpp" +#include +#include + +namespace boost { namespace graph { namespace python { + +template +void +basic_graph::read_graphviz(const std::string& filename, + const std::string& node_id) +{ + std::ifstream in(filename.c_str()); + boost::read_graphviz(in, *this, dp, node_id); +} + +template +void +basic_graph::write_graphviz(const std::string& filename, + const std::string& node_id) +{ + std::ofstream out(filename.c_str()); + boost::write_graphviz(out, *this, dp, node_id, + get_vertex_map("node_id")); +} + +// Explicit instantiations +template + void + basic_graph::read_graphviz(const std::string& filename, + const std::string& node_id); +template + void + basic_graph::write_graphviz(const std::string& filename, + const std::string& node_id); + +template + void + basic_graph::read_graphviz(const std::string& filename, + const std::string& node_id); +template + void + basic_graph::write_graphviz(const std::string& filename, + const std::string& node_id); + +} } } // end namespace boost::graph::python diff --git a/src/python/module.cpp b/src/python/module.cpp new file mode 100644 index 00000000..04045401 --- /dev/null +++ b/src/python/module.cpp @@ -0,0 +1,40 @@ +#include "basic_graph.cpp" +#include "graph.hpp" +#include "digraph.hpp" +#include + +namespace boost { namespace graph { namespace python { + +extern void export_Graph(); +extern void export_Digraph(); +extern void export_betweenness_centrality(); +extern void export_page_rank(); +extern void export_done(); +extern void export_breadth_first_search(); +template void export_breadth_first_search_in_graph(); + +template +void export_in_graph() +{ + export_breadth_first_search_in_graph(); +} + +BOOST_PYTHON_MODULE(bgl) +{ + enum_("file_kind") + .value("adjlist", gfk_adjlist) + .value("graphviz", gfk_graphviz) + ; + + export_Graph(); + export_Digraph(); + export_betweenness_centrality(); + export_page_rank(); + export_done(); + export_breadth_first_search(); +} + +template void export_in_graph(); +template void export_in_graph(); + +} } } // end namespace boost::graph::python diff --git a/src/python/queue.hpp b/src/python/queue.hpp new file mode 100644 index 00000000..6b00e4f3 --- /dev/null +++ b/src/python/queue.hpp @@ -0,0 +1,58 @@ +#ifndef BOOST_GRAPH_PYTHON_QUEUE_HPP +#define BOOST_GRAPH_PYTHON_QUEUE_HPP + +#include + +namespace boost { namespace graph { namespace python { + +template +class python_queue +{ + class wrap + : public python_queue, public boost::python::wrapper > + { + public: + bool empty() const { return this->get_override("empty")(); } + T top() const { return this->get_override("top")(); } + void pop() { this->get_override("pop")(); } + void push(const T& x) { this->get_override("push")(x); } + }; + + public: + class default_queue : public python_queue + { + bool empty() const { return true; } + T top() const { return T(); } + void pop() {} + void push(const T&) {} + }; + + virtual ~python_queue() {} + virtual bool empty() const = 0; + virtual T top() const = 0; + virtual void pop() = 0; + virtual void push(const T&) = 0; + + static void declare(const char* name, const char* default_name) + { + using namespace boost::python; + +// if (objects::registered_class_object(type_id()).get() == 0) { + class_(name) + .def("empty", pure_virtual(&python_queue::empty)) + .def("top", pure_virtual(&python_queue::top)) + .def("pop", pure_virtual(&python_queue::pop)) + .def("push", pure_virtual(&python_queue::push)) + ; +// } + +// if (objects::registered_class_object(type_id()).get() == 0) + { + class_ > >(default_name, no_init); + } + } +}; + +} } } // end namespace boost::graph::python + +#endif // BOOST_GRAPH_PYTHON_QUEUE_HPP