// Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #include "basic_graph.hpp" #include namespace boost { inline std::ostream& operator<<(std::ostream& out, default_color_type c) { switch (c) { case white_color: return out << "white"; case gray_color: return out << "gray"; case green_color: return out << "green"; case red_color: return out << "red"; case black_color: return out << "black"; } return out; } inline std::istream& operator>>(std::istream& in, default_color_type& c) { std::string text; if (in >> text) { if (text == "white") c = white_color; else if (text == "gray") c = gray_color; else if (text == "green") c = green_color; else if (text == "red") c = red_color; else if (text == "black") c = black_color; else { in.setstate(std::ios_base::failbit); return in; } } return in; } 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::value_type> 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 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))); } virtual std::string get_string(const any& key) { using boost::python::extract; using boost::python::str; return std::string( extract(str(boost::get(this->base(), any_cast(key))))); } }; 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(boost::python::object l, const std::string& name_map) : inherited() { using boost::python::object; std::map verts; int len = ::boost::python::extract(l.attr("__len__")()); vector_property_map name; if (!name_map.empty()) name = get_vertex_map(name_map); for (int i = 0; i < len; ++i) { vertex_descriptor u, v; object up = l[i][0]; object vp = l[i][1]; typename std::map::iterator pos; pos = verts.find(up); if (pos == verts.end()) { u = verts[up] = add_vertex(); if (!name_map.empty()) name[u] = up; } else u = pos->second; pos = verts.find(vp); if (pos == verts.end()) { v = verts[vp] = add_vertex(); if (!name_map.empty()) name[v] = vp; } else v = pos->second; add_edge(u, v); } } 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; } } template basic_graph::basic_graph(erdos_renyi er, int seed) : stored_minstd_rand(seed), inherited(er_iterator(this->gen, er.n, er.p), er_iterator(), er.n) { renumber_vertices(); renumber_edges(); } template basic_graph::basic_graph(power_law_out_degree plod, int seed) : stored_minstd_rand(seed), inherited(sf_iterator(this->gen, plod.n, plod.alpha, plod.beta), sf_iterator(), plod.n) { renumber_vertices(); renumber_edges(); } template basic_graph::basic_graph(small_world sw, int seed) : stored_minstd_rand(seed), inherited(sw_iterator(this->gen, sw.n, sw.k, sw.p), sw_iterator(), sw.n) { renumber_vertices(); renumber_edges(); } // ---------------------------------------------------------- // 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 basic_graph::renumber_vertices() { using boost::vertices; BGL_FORALL_VERTICES_T(v, base(), inherited) { put(vertex_index, base(), v, index_to_vertex.size()); index_to_vertex.push_back(v); } } template void basic_graph::renumber_edges() { using boost::edges; BGL_FORALL_EDGES_T(e, base(), inherited) { put(edge_index, base(), e, index_to_edge.size()); index_to_edge.push_back(e); } } template void export_in_graph(); template void export_basic_graph(const char* name) { using boost::python::arg; using boost::python::class_; using boost::python::init; using boost::python::object; using boost::python::range; using boost::python::scope; using boost::python::self; using boost::python::tuple; 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()) .def(init()) .def(init()) .def(init( (arg("generator"), arg("seed") = 1))) .def(init( (arg("generator"), arg("seed") = 1))) .def(init( (arg("generator"), arg("seed") = 1))) .def("is_directed", &Graph::is_directed) // 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_color_map", &Graph::get_vertex_color_map) .def("get_vertex_double_map", &Graph::get_vertex_double_map) .def("get_vertex_int_map", &Graph::get_vertex_int_map) .def("get_vertex_string_map", &Graph::get_vertex_string_map) .def("get_vertex_object_map", &Graph::get_vertex_object_map) .def("get_vertex_point2d_map", &Graph::get_vertex_point2d_map) // Edge property maps .def("has_edge_map", &Graph::has_edge_map) .def("get_edge_index_map", &Graph::get_edge_index_map) .def("get_edge_color_map", &Graph::get_edge_color_map) .def("get_edge_double_map", &Graph::get_edge_double_map) .def("get_edge_int_map", &Graph::get_edge_int_map) .def("get_edge_string_map", &Graph::get_edge_string_map) .def("get_edge_object_map", &Graph::get_edge_object_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_vertex_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"); declare_property_map > ::declare("vertex_color_map"); declare_property_map > ::declare("vertex_point2d_map"); // Edge property maps declare_readable_property_map ::declare("edge_index_map"); declare_property_map > ::declare("edge_edge_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"); declare_property_map > ::declare("edge_color_map"); } } } } // end namespace boost::graph::python