Chris@16: //======================================================================= Chris@16: // Copyright 2001 University of Notre Dame. Chris@16: // Copyright 2003 Jeremy Siek Chris@16: // Authors: Lie-Quan Lee, Jeremy Siek, and Douglas Gregor Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: //======================================================================= Chris@16: #ifndef BOOST_GRAPHVIZ_HPP Chris@16: #define BOOST_GRAPHVIZ_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // for FILE Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: template Chris@16: struct graphviz_io_traits { Chris@16: static std::string name() { Chris@16: return "digraph"; Chris@16: } Chris@16: static std::string delimiter() { Chris@16: return "->"; Chris@16: } }; Chris@16: Chris@16: template <> Chris@16: struct graphviz_io_traits { Chris@16: static std::string name() { Chris@16: return "graph"; Chris@16: } Chris@16: static std::string delimiter() { Chris@16: return "--"; Chris@16: } Chris@16: }; Chris@16: Chris@16: struct default_writer { Chris@16: void operator()(std::ostream&) const { Chris@16: } Chris@16: template Chris@16: void operator()(std::ostream&, const VorE&) const { Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: inline std::string escape_dot_string(const T& obj) { Chris@16: using namespace boost::xpressive; Chris@16: static sregex valid_unquoted_id = (((alpha | '_') >> *_w) | (!as_xpr('-') >> (('.' >> *_d) | (+_d >> !('.' >> *_d))))); Chris@16: std::string s(boost::lexical_cast(obj)); Chris@16: if (regex_match(s, valid_unquoted_id)) { Chris@16: return s; Chris@16: } else { Chris@16: boost::algorithm::replace_all(s, "\"", "\\\""); Chris@16: return "\"" + s + "\""; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: class label_writer { Chris@16: public: Chris@16: label_writer(Name _name) : name(_name) {} Chris@16: template Chris@16: void operator()(std::ostream& out, const VertexOrEdge& v) const { Chris@16: out << "[label=" << escape_dot_string(get(name, v)) << "]"; Chris@16: } Chris@16: private: Chris@16: Name name; Chris@16: }; Chris@16: template Chris@16: inline label_writer Chris@16: make_label_writer(Name n) { Chris@16: return label_writer(n); Chris@16: } Chris@16: Chris@16: enum edge_attribute_t { edge_attribute = 1111 }; Chris@16: enum vertex_attribute_t { vertex_attribute = 2222 }; Chris@16: enum graph_graph_attribute_t { graph_graph_attribute = 3333 }; Chris@16: enum graph_vertex_attribute_t { graph_vertex_attribute = 4444 }; Chris@16: enum graph_edge_attribute_t { graph_edge_attribute = 5555 }; Chris@16: Chris@16: BOOST_INSTALL_PROPERTY(edge, attribute); Chris@16: BOOST_INSTALL_PROPERTY(vertex, attribute); Chris@16: BOOST_INSTALL_PROPERTY(graph, graph_attribute); Chris@16: BOOST_INSTALL_PROPERTY(graph, vertex_attribute); Chris@16: BOOST_INSTALL_PROPERTY(graph, edge_attribute); Chris@16: Chris@16: Chris@16: template Chris@16: inline void write_attributes(const Attribute& attr, std::ostream& out) { Chris@16: typename Attribute::const_iterator i, iend; Chris@16: i = attr.begin(); Chris@16: iend = attr.end(); Chris@16: Chris@16: while ( i != iend ) { Chris@16: out << i->first << "=" << escape_dot_string(i->second); Chris@16: ++i; Chris@16: if ( i != iend ) Chris@16: out << ", "; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void write_all_attributes(Attributes attributes, Chris@16: const std::string& name, Chris@16: std::ostream& out) Chris@16: { Chris@16: typename Attributes::const_iterator i = attributes.begin(), Chris@16: end = attributes.end(); Chris@16: if (i != end) { Chris@16: out << name << " [\n"; Chris@16: write_attributes(attributes, out); Chris@16: out << "];\n"; Chris@16: } Chris@16: } Chris@16: Chris@16: inline void write_all_attributes(detail::error_property_not_found, Chris@16: const std::string&, Chris@16: std::ostream&) Chris@16: { Chris@16: // Do nothing - no attributes exist Chris@16: } Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: template Chris@16: struct graph_attributes_writer Chris@16: { Chris@16: graph_attributes_writer(GraphGraphAttributes gg, Chris@16: GraphNodeAttributes gn, Chris@16: GraphEdgeAttributes ge) Chris@16: : g_attributes(gg), n_attributes(gn), e_attributes(ge) { } Chris@16: Chris@16: void operator()(std::ostream& out) const { Chris@16: write_all_attributes(g_attributes, "graph", out); Chris@16: write_all_attributes(n_attributes, "node", out); Chris@16: write_all_attributes(e_attributes, "edge", out); Chris@16: } Chris@16: GraphGraphAttributes g_attributes; Chris@16: GraphNodeAttributes n_attributes; Chris@16: GraphEdgeAttributes e_attributes; Chris@16: }; Chris@16: Chris@16: template Chris@16: graph_attributes_writer Chris@16: make_graph_attributes_writer(const GAttrMap& g_attr, const NAttrMap& n_attr, Chris@16: const EAttrMap& e_attr) { Chris@16: return graph_attributes_writer Chris@16: (g_attr, n_attr, e_attr); Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: graph_attributes_writer Chris@16: ::type, Chris@16: typename graph_property::type, Chris@16: typename graph_property::type> Chris@16: make_graph_attributes_writer(const Graph& g) Chris@16: { Chris@16: typedef typename graph_property::type Chris@16: GAttrMap; Chris@16: typedef typename graph_property::type Chris@16: NAttrMap; Chris@16: typedef typename graph_property::type Chris@16: EAttrMap; Chris@16: GAttrMap gam = get_property(g, graph_graph_attribute); Chris@16: NAttrMap nam = get_property(g, graph_vertex_attribute); Chris@16: EAttrMap eam = get_property(g, graph_edge_attribute); Chris@16: graph_attributes_writer writer(gam, nam, eam); Chris@16: return writer; Chris@16: } Chris@16: Chris@16: template Chris@16: struct attributes_writer { Chris@16: attributes_writer(AttributeMap attr) Chris@16: : attributes(attr) { } Chris@16: Chris@16: template Chris@16: void operator()(std::ostream& out, const VorE& e) const { Chris@16: this->write_attribute(out, attributes[e]); Chris@16: } Chris@16: Chris@16: private: Chris@16: template Chris@16: void write_attribute(std::ostream& out, Chris@16: const AttributeSequence& seq) const Chris@16: { Chris@16: if (!seq.empty()) { Chris@16: out << "["; Chris@16: write_attributes(seq, out); Chris@16: out << "]"; Chris@16: } Chris@16: } Chris@16: Chris@16: void write_attribute(std::ostream&, Chris@16: detail::error_property_not_found) const Chris@16: { Chris@16: } Chris@16: AttributeMap attributes; Chris@16: }; Chris@16: Chris@16: template Chris@16: attributes_writer Chris@16: ::const_type> Chris@16: make_edge_attributes_writer(const Graph& g) Chris@16: { Chris@16: typedef typename property_map::const_type Chris@16: EdgeAttributeMap; Chris@16: return attributes_writer(get(edge_attribute, g)); Chris@16: } Chris@16: Chris@16: template Chris@16: attributes_writer Chris@16: ::const_type> Chris@16: make_vertex_attributes_writer(const Graph& g) Chris@16: { Chris@16: typedef typename property_map::const_type Chris@16: VertexAttributeMap; Chris@16: return attributes_writer(get(vertex_attribute, g)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz Chris@16: (std::ostream& out, const Graph& g, Chris@16: VertexPropertiesWriter vpw, Chris@16: EdgePropertiesWriter epw, Chris@16: GraphPropertiesWriter gpw, Chris@16: VertexID vertex_id Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: BOOST_CONCEPT_ASSERT((EdgeListGraphConcept)); Chris@16: Chris@16: typedef typename graph_traits::directed_category cat_type; Chris@16: typedef graphviz_io_traits Traits; Chris@16: std::string name = "G"; Chris@16: out << Traits::name() << " " << escape_dot_string(name) << " {" << std::endl; Chris@16: Chris@16: gpw(out); //print graph properties Chris@16: Chris@16: typename graph_traits::vertex_iterator i, end; Chris@16: Chris@16: for(boost::tie(i,end) = vertices(g); i != end; ++i) { Chris@16: out << escape_dot_string(get(vertex_id, *i)); Chris@16: vpw(out, *i); //print vertex attributes Chris@16: out << ";" << std::endl; Chris@16: } Chris@16: typename graph_traits::edge_iterator ei, edge_end; Chris@16: for(boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { Chris@16: out << escape_dot_string(get(vertex_id, source(*ei, g))) << Traits::delimiter() << escape_dot_string(get(vertex_id, target(*ei, g))) << " "; Chris@16: epw(out, *ei); //print edge attributes Chris@16: out << ";" << std::endl; Chris@16: } Chris@16: out << "}" << std::endl; Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz(std::ostream& out, const Graph& g, Chris@16: VertexPropertiesWriter vpw, Chris@16: EdgePropertiesWriter epw, Chris@16: GraphPropertiesWriter gpw Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { write_graphviz(out, g, vpw, epw, gpw, get(vertex_index, g)); } Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz(std::ostream& out, const Graph& g Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: default_writer dw; Chris@16: default_writer gw; Chris@16: write_graphviz(out, g, dw, dw, gw); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz(std::ostream& out, const Graph& g, VertexWriter vw Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: default_writer dw; Chris@16: default_writer gw; Chris@16: write_graphviz(out, g, vw, dw, gw); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz(std::ostream& out, const Graph& g, Chris@16: VertexWriter vw, EdgeWriter ew Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: default_writer gw; Chris@16: write_graphviz(out, g, vw, ew, gw); Chris@16: } Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: void write_graphviz_subgraph (std::ostream& out, Chris@16: const subgraph& g, Chris@16: RandomAccessIterator vertex_marker, Chris@16: RandomAccessIterator edge_marker, Chris@16: VertexID vertex_id) Chris@16: { Chris@16: typedef subgraph Graph; Chris@16: typedef typename graph_traits::vertex_descriptor Vertex; Chris@16: typedef typename graph_traits::directed_category cat_type; Chris@16: typedef graphviz_io_traits Traits; Chris@16: Chris@16: typedef typename graph_property::type NameType; Chris@16: const NameType& g_name = get_property(g, graph_name); Chris@16: Chris@16: if ( g.is_root() ) Chris@16: out << Traits::name() ; Chris@16: else Chris@16: out << "subgraph"; Chris@16: Chris@16: out << " " << escape_dot_string(g_name) << " {" << std::endl; Chris@16: Chris@16: typename Graph::const_children_iterator i_child, j_child; Chris@16: Chris@16: //print graph/node/edge attributes Chris@16: make_graph_attributes_writer(g)(out); Chris@16: Chris@16: //print subgraph Chris@16: for ( boost::tie(i_child,j_child) = g.children(); Chris@16: i_child != j_child; ++i_child ) Chris@16: write_graphviz_subgraph(out, *i_child, vertex_marker, edge_marker, Chris@16: vertex_id); Chris@16: Chris@16: // Print out vertices and edges not in the subgraphs. Chris@16: Chris@16: typename graph_traits::vertex_iterator i, end; Chris@16: typename graph_traits::edge_iterator ei, edge_end; Chris@16: Chris@16: for(boost::tie(i,end) = vertices(g); i != end; ++i) { Chris@16: Vertex v = g.local_to_global(*i); Chris@16: int pos = get(vertex_id, v); Chris@16: if ( vertex_marker[pos] ) { Chris@16: vertex_marker[pos] = false; Chris@16: out << escape_dot_string(pos); Chris@16: make_vertex_attributes_writer(g.root())(out, v); Chris@16: out << ";" << std::endl; Chris@16: } Chris@16: } Chris@16: Chris@16: for (boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { Chris@16: Vertex u = g.local_to_global(source(*ei,g)), Chris@16: v = g.local_to_global(target(*ei, g)); Chris@16: int pos = get(get(edge_index, g.root()), g.local_to_global(*ei)); Chris@16: if ( edge_marker[pos] ) { Chris@16: edge_marker[pos] = false; Chris@16: out << escape_dot_string(get(vertex_id, u)) << " " << Traits::delimiter() Chris@16: << " " << escape_dot_string(get(vertex_id, v)); Chris@16: make_edge_attributes_writer(g)(out, *ei); //print edge properties Chris@16: out << ";" << std::endl; Chris@16: } Chris@16: } Chris@16: out << "}" << std::endl; Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: // requires graph_name graph property Chris@16: template Chris@16: void write_graphviz(std::ostream& out, const subgraph& g) { Chris@16: std::vector edge_marker(num_edges(g), true); Chris@16: std::vector vertex_marker(num_vertices(g), true); Chris@16: Chris@16: detail::write_graphviz_subgraph(out, g, Chris@16: vertex_marker.begin(), Chris@16: edge_marker.begin(), Chris@16: get(vertex_index, g)); Chris@16: } Chris@16: Chris@16: template Chris@16: void write_graphviz(const std::string& filename, const subgraph& g) { Chris@16: std::ofstream out(filename.c_str()); Chris@16: std::vector edge_marker(num_edges(g), true); Chris@16: std::vector vertex_marker(num_vertices(g), true); Chris@16: Chris@16: detail::write_graphviz_subgraph(out, g, Chris@16: vertex_marker.begin(), Chris@16: edge_marker.begin(), Chris@16: get(vertex_index, g)); Chris@16: } Chris@16: Chris@16: template Chris@16: void write_graphviz(std::ostream& out, const subgraph& g, Chris@16: VertexID vertex_id) Chris@16: { Chris@16: std::vector edge_marker(num_edges(g), true); Chris@16: std::vector vertex_marker(num_vertices(g), true); Chris@16: Chris@16: detail::write_graphviz_subgraph(out, g, Chris@16: vertex_marker.begin(), Chris@16: edge_marker.begin(), Chris@16: vertex_id); Chris@16: } Chris@16: Chris@16: template Chris@16: void write_graphviz(const std::string& filename, const subgraph& g, Chris@16: VertexID vertex_id) Chris@16: { Chris@16: std::ofstream out(filename.c_str()); Chris@16: std::vector edge_marker(num_edges(g), true); Chris@16: std::vector vertex_marker(num_vertices(g), true); Chris@16: Chris@16: detail::write_graphviz_subgraph(out, g, Chris@16: vertex_marker.begin(), Chris@16: edge_marker.begin(), Chris@16: vertex_id); Chris@16: } Chris@16: Chris@16: #if 0 Chris@16: // This interface has not worked for a long time Chris@16: typedef std::map GraphvizAttrList; Chris@16: Chris@16: typedef property Chris@16: GraphvizVertexProperty; Chris@16: Chris@16: typedef property > Chris@16: GraphvizEdgeProperty; Chris@16: Chris@16: typedef property > > > Chris@16: GraphvizGraphProperty; Chris@16: Chris@16: typedef subgraph > Chris@16: GraphvizDigraph; Chris@16: Chris@16: typedef subgraph > Chris@16: GraphvizGraph; Chris@16: Chris@16: // These four require linking the BGL-Graphviz library: libbgl-viz.a Chris@16: // from the /src directory. Chris@16: // Library has not existed for a while Chris@16: extern void read_graphviz(const std::string& file, GraphvizDigraph& g); Chris@16: extern void read_graphviz(FILE* file, GraphvizDigraph& g); Chris@16: Chris@16: extern void read_graphviz(const std::string& file, GraphvizGraph& g); Chris@16: extern void read_graphviz(FILE* file, GraphvizGraph& g); Chris@16: #endif Chris@16: Chris@16: class dynamic_properties_writer Chris@16: { Chris@16: public: Chris@16: dynamic_properties_writer(const dynamic_properties& dp) : dp(&dp) { } Chris@16: Chris@16: template Chris@16: void operator()(std::ostream& out, Descriptor key) const Chris@16: { Chris@16: bool first = true; Chris@16: for (dynamic_properties::const_iterator i = dp->begin(); Chris@16: i != dp->end(); ++i) { Chris@16: if (typeid(key) == i->second->key()) { Chris@16: if (first) out << " ["; Chris@16: else out << ", "; Chris@16: first = false; Chris@16: Chris@16: out << i->first << "=" << escape_dot_string(i->second->get_string(key)); Chris@16: } Chris@16: } Chris@16: Chris@16: if (!first) out << "]"; Chris@16: } Chris@16: Chris@16: private: Chris@16: const dynamic_properties* dp; Chris@16: }; Chris@16: Chris@16: class dynamic_vertex_properties_writer Chris@16: { Chris@16: public: Chris@16: dynamic_vertex_properties_writer(const dynamic_properties& dp, Chris@16: const std::string& node_id) Chris@16: : dp(&dp), node_id(&node_id) { } Chris@16: Chris@16: template Chris@16: void operator()(std::ostream& out, Descriptor key) const Chris@16: { Chris@16: bool first = true; Chris@16: for (dynamic_properties::const_iterator i = dp->begin(); Chris@16: i != dp->end(); ++i) { Chris@16: if (typeid(key) == i->second->key() Chris@16: && i->first != *node_id) { Chris@16: if (first) out << " ["; Chris@16: else out << ", "; Chris@16: first = false; Chris@16: Chris@16: out << i->first << "=" << escape_dot_string(i->second->get_string(key)); Chris@16: } Chris@16: } Chris@16: Chris@16: if (!first) out << "]"; Chris@16: } Chris@16: Chris@16: private: Chris@16: const dynamic_properties* dp; Chris@16: const std::string* node_id; Chris@16: }; Chris@16: Chris@101: template Chris@101: class dynamic_graph_properties_writer Chris@101: { Chris@101: public: Chris@101: dynamic_graph_properties_writer(const dynamic_properties& dp, const Graph& g) : g(&g), dp(&dp) { } Chris@101: Chris@101: void operator()(std::ostream& out) const Chris@101: { Chris@101: for (dynamic_properties::const_iterator i = dp->begin(); Chris@101: i != dp->end(); ++i) { Chris@101: if (typeid(Graph*) == i->second->key()) { Chris@101: // const_cast here is to match interface used in read_graphviz Chris@101: out << i->first << "=" << escape_dot_string(i->second->get_string(const_cast(g))) << ";\n"; Chris@101: } Chris@101: } Chris@101: } Chris@101: Chris@101: private: Chris@101: const Graph* g; Chris@101: const dynamic_properties* dp; Chris@101: }; Chris@101: Chris@16: namespace graph { namespace detail { Chris@16: Chris@16: template Chris@16: struct node_id_property_map Chris@16: { Chris@16: typedef std::string value_type; Chris@16: typedef value_type reference; Chris@16: typedef Vertex key_type; Chris@16: typedef readable_property_map_tag category; Chris@16: Chris@16: node_id_property_map() {} Chris@16: Chris@16: node_id_property_map(const dynamic_properties& dp, Chris@16: const std::string& node_id) Chris@16: : dp(&dp), node_id(&node_id) { } Chris@16: Chris@16: const dynamic_properties* dp; Chris@16: const std::string* node_id; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline std::string Chris@16: get(node_id_property_map pm, Chris@16: typename node_id_property_map::key_type v) Chris@16: { return get(*pm.node_id, *pm.dp, v); } Chris@16: Chris@16: } } // end namespace graph::detail Chris@16: Chris@16: template Chris@16: inline void Chris@16: write_graphviz_dp(std::ostream& out, const Graph& g, Chris@16: const dynamic_properties& dp, Chris@16: const std::string& node_id = "node_id" Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: typedef typename graph_traits::vertex_descriptor Vertex; Chris@16: write_graphviz_dp(out, g, dp, node_id, Chris@16: graph::detail::node_id_property_map(dp, node_id)); Chris@16: } Chris@16: Chris@16: template Chris@16: void Chris@16: write_graphviz_dp(std::ostream& out, const Graph& g, Chris@16: const dynamic_properties& dp, const std::string& node_id, Chris@16: VertexID id Chris@16: BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag)) Chris@16: { Chris@16: write_graphviz Chris@16: (out, g, Chris@16: /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id), Chris@16: /*edge_writer=*/dynamic_properties_writer(dp), Chris@101: /*graph_writer=*/dynamic_graph_properties_writer(dp, g), Chris@16: id); Chris@16: } Chris@16: Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: // Graph reader exceptions Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: struct graph_exception : public std::exception { Chris@16: virtual ~graph_exception() throw() {} Chris@16: virtual const char* what() const throw() = 0; Chris@16: }; Chris@16: Chris@16: struct bad_parallel_edge : public graph_exception { Chris@16: std::string from; Chris@16: std::string to; Chris@16: mutable std::string statement; Chris@16: bad_parallel_edge(const std::string& i, const std::string& j) : Chris@16: from(i), to(j) {} Chris@16: Chris@16: virtual ~bad_parallel_edge() throw() {} Chris@16: const char* what() const throw() { Chris@16: if(statement.empty()) Chris@16: statement = Chris@16: std::string("Failed to add parallel edge: (") Chris@16: + from + "," + to + ")\n"; Chris@16: Chris@16: return statement.c_str(); Chris@16: } Chris@16: }; Chris@16: Chris@16: struct directed_graph_error : public graph_exception { Chris@16: virtual ~directed_graph_error() throw() {} Chris@16: virtual const char* what() const throw() { Chris@16: return Chris@16: "read_graphviz: " Chris@16: "Tried to read a directed graph into an undirected graph."; Chris@16: } Chris@16: }; Chris@16: Chris@16: struct undirected_graph_error : public graph_exception { Chris@16: virtual ~undirected_graph_error() throw() {} Chris@16: virtual const char* what() const throw() { Chris@16: return Chris@16: "read_graphviz: " Chris@16: "Tried to read an undirected graph into a directed graph."; Chris@16: } Chris@16: }; Chris@16: Chris@16: struct bad_graphviz_syntax: public graph_exception { Chris@16: std::string errmsg; Chris@16: bad_graphviz_syntax(const std::string& errmsg) Chris@16: : errmsg(errmsg) {} Chris@16: const char* what() const throw () {return errmsg.c_str();} Chris@16: ~bad_graphviz_syntax() throw () {}; Chris@16: }; Chris@16: Chris@16: namespace detail { namespace graph { Chris@16: Chris@16: typedef std::string id_t; Chris@16: typedef id_t node_t; Chris@16: Chris@16: // edges are not uniquely determined by adjacent nodes Chris@16: class edge_t { Chris@16: int idx_; Chris@16: explicit edge_t(int i) : idx_(i) {} Chris@16: public: Chris@16: static edge_t new_edge() { Chris@16: static int idx = 0; Chris@16: return edge_t(idx++); Chris@16: }; Chris@16: Chris@16: bool operator==(const edge_t& rhs) const { Chris@16: return idx_ == rhs.idx_; Chris@16: } Chris@16: bool operator<(const edge_t& rhs) const { Chris@16: return idx_ < rhs.idx_; Chris@16: } Chris@16: }; Chris@16: Chris@16: class mutate_graph Chris@16: { Chris@16: public: Chris@16: virtual ~mutate_graph() {} Chris@16: virtual bool is_directed() const = 0; Chris@16: virtual void do_add_vertex(const node_t& node) = 0; Chris@16: Chris@16: virtual void Chris@16: do_add_edge(const edge_t& edge, const node_t& source, const node_t& target) Chris@16: = 0; Chris@16: Chris@16: virtual void Chris@16: set_node_property(const id_t& key, const node_t& node, const id_t& value) = 0; Chris@16: Chris@16: virtual void Chris@16: set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) = 0; Chris@16: Chris@16: virtual void // RG: need new second parameter to support BGL subgraphs Chris@16: set_graph_property(const id_t& key, const id_t& value) = 0; Chris@16: Chris@16: virtual void Chris@16: finish_building_graph() = 0; Chris@16: }; Chris@16: Chris@16: template Chris@16: class mutate_graph_impl : public mutate_graph Chris@16: { Chris@16: typedef typename graph_traits::vertex_descriptor bgl_vertex_t; Chris@16: typedef typename graph_traits::edge_descriptor bgl_edge_t; Chris@16: Chris@16: public: Chris@16: mutate_graph_impl(MutableGraph& graph, dynamic_properties& dp, Chris@16: std::string node_id_prop) Chris@16: : graph_(graph), dp_(dp), node_id_prop_(node_id_prop) { } Chris@16: Chris@16: ~mutate_graph_impl() {} Chris@16: Chris@16: bool is_directed() const Chris@16: { Chris@16: return Chris@16: boost::is_convertible< Chris@16: typename boost::graph_traits::directed_category, Chris@16: boost::directed_tag>::value; Chris@16: } Chris@16: Chris@16: virtual void do_add_vertex(const node_t& node) Chris@16: { Chris@16: // Add the node to the graph. Chris@16: bgl_vertex_t v = add_vertex(graph_); Chris@16: Chris@16: // Set up a mapping from name to BGL vertex. Chris@16: bgl_nodes.insert(std::make_pair(node, v)); Chris@16: Chris@16: // node_id_prop_ allows the caller to see the real id names for nodes. Chris@16: put(node_id_prop_, dp_, v, node); Chris@16: } Chris@16: Chris@16: void Chris@16: do_add_edge(const edge_t& edge, const node_t& source, const node_t& target) Chris@16: { Chris@16: std::pair result = Chris@16: add_edge(bgl_nodes[source], bgl_nodes[target], graph_); Chris@16: Chris@16: if(!result.second) { Chris@16: // In the case of no parallel edges allowed Chris@16: boost::throw_exception(bad_parallel_edge(source, target)); Chris@16: } else { Chris@16: bgl_edges.insert(std::make_pair(edge, result.first)); Chris@16: } Chris@16: } Chris@16: Chris@16: void Chris@16: set_node_property(const id_t& key, const node_t& node, const id_t& value) Chris@16: { Chris@16: put(key, dp_, bgl_nodes[node], value); Chris@16: } Chris@16: Chris@16: void Chris@16: set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) Chris@16: { Chris@16: put(key, dp_, bgl_edges[edge], value); Chris@16: } Chris@16: Chris@16: void Chris@16: set_graph_property(const id_t& key, const id_t& value) Chris@16: { Chris@16: /* RG: pointer to graph prevents copying */ Chris@16: put(key, dp_, &graph_, value); Chris@16: } Chris@16: Chris@16: void finish_building_graph() {} Chris@16: Chris@16: Chris@16: protected: Chris@16: MutableGraph& graph_; Chris@16: dynamic_properties& dp_; Chris@16: std::string node_id_prop_; Chris@16: std::map bgl_nodes; Chris@16: std::map bgl_edges; Chris@16: }; Chris@16: Chris@16: template Chris@16: class mutate_graph_impl > Chris@16: : public mutate_graph Chris@16: { Chris@16: typedef compressed_sparse_row_graph CSRGraph; Chris@16: typedef typename graph_traits::vertices_size_type bgl_vertex_t; Chris@16: typedef typename graph_traits::edges_size_type bgl_edge_t; Chris@16: typedef typename graph_traits::edge_descriptor edge_descriptor; Chris@16: Chris@16: public: Chris@16: mutate_graph_impl(CSRGraph& graph, dynamic_properties& dp, Chris@16: std::string node_id_prop) Chris@16: : graph_(graph), dp_(dp), vertex_count(0), node_id_prop_(node_id_prop) { } Chris@16: Chris@16: ~mutate_graph_impl() {} Chris@16: Chris@16: void finish_building_graph() { Chris@16: typedef compressed_sparse_row_graph TempCSRGraph; Chris@16: TempCSRGraph temp(edges_are_unsorted_multi_pass, Chris@16: edges_to_add.begin(), edges_to_add.end(), Chris@16: counting_iterator(0), Chris@16: vertex_count); Chris@16: set_property(temp, graph_all, get_property(graph_, graph_all)); Chris@16: graph_.assign(temp); // Copies structure, not properties Chris@16: std::vector edge_permutation_from_sorting(num_edges(temp)); Chris@16: BGL_FORALL_EDGES_T(e, temp, TempCSRGraph) { Chris@16: edge_permutation_from_sorting[temp[e]] = e; Chris@16: } Chris@16: typedef boost::tuple v_prop; Chris@16: BOOST_FOREACH(const v_prop& t, vertex_props) { Chris@16: put(boost::get<0>(t), dp_, boost::get<1>(t), boost::get<2>(t)); Chris@16: } Chris@16: typedef boost::tuple e_prop; Chris@16: BOOST_FOREACH(const e_prop& t, edge_props) { Chris@16: put(boost::get<0>(t), dp_, edge_permutation_from_sorting[boost::get<1>(t)], boost::get<2>(t)); Chris@16: } Chris@16: } Chris@16: Chris@16: bool is_directed() const Chris@16: { Chris@16: return Chris@16: boost::is_convertible< Chris@16: typename boost::graph_traits::directed_category, Chris@16: boost::directed_tag>::value; Chris@16: } Chris@16: Chris@16: virtual void do_add_vertex(const node_t& node) Chris@16: { Chris@16: // Add the node to the graph. Chris@16: bgl_vertex_t v = vertex_count++; Chris@16: Chris@16: // Set up a mapping from name to BGL vertex. Chris@16: bgl_nodes.insert(std::make_pair(node, v)); Chris@16: Chris@16: // node_id_prop_ allows the caller to see the real id names for nodes. Chris@16: vertex_props.push_back(boost::make_tuple(node_id_prop_, v, node)); Chris@16: } Chris@16: Chris@16: void Chris@16: do_add_edge(const edge_t& edge, const node_t& source, const node_t& target) Chris@16: { Chris@16: bgl_edge_t result = edges_to_add.size(); Chris@16: edges_to_add.push_back(std::make_pair(bgl_nodes[source], bgl_nodes[target])); Chris@16: bgl_edges.insert(std::make_pair(edge, result)); Chris@16: } Chris@16: Chris@16: void Chris@16: set_node_property(const id_t& key, const node_t& node, const id_t& value) Chris@16: { Chris@16: vertex_props.push_back(boost::make_tuple(key, bgl_nodes[node], value)); Chris@16: } Chris@16: Chris@16: void Chris@16: set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) Chris@16: { Chris@16: edge_props.push_back(boost::make_tuple(key, bgl_edges[edge], value)); Chris@16: } Chris@16: Chris@16: void Chris@16: set_graph_property(const id_t& key, const id_t& value) Chris@16: { Chris@16: /* RG: pointer to graph prevents copying */ Chris@16: put(key, dp_, &graph_, value); Chris@16: } Chris@16: Chris@16: Chris@16: protected: Chris@16: CSRGraph& graph_; Chris@16: dynamic_properties& dp_; Chris@16: bgl_vertex_t vertex_count; Chris@16: std::string node_id_prop_; Chris@16: std::vector > vertex_props; Chris@16: std::vector > edge_props; Chris@16: std::vector > edges_to_add; Chris@16: std::map bgl_nodes; Chris@16: std::map bgl_edges; Chris@16: }; Chris@16: Chris@16: } } } // end namespace boost::detail::graph Chris@16: Chris@16: #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER Chris@16: # ifndef BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS Chris@16: # define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS Chris@16: # endif Chris@16: # include Chris@16: #else // New default parser Chris@16: # include Chris@16: #endif // BOOST_GRAPH_USE_SPIRIT_PARSER Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: // Parse the passed string as a GraphViz dot file. Chris@16: template Chris@16: bool read_graphviz(const std::string& data, Chris@16: MutableGraph& graph, Chris@16: dynamic_properties& dp, Chris@16: std::string const& node_id = "node_id") { Chris@16: #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER Chris@16: return read_graphviz_spirit(data.begin(), data.end(), graph, dp, node_id); Chris@16: #else // Non-Spirit parser Chris@16: return read_graphviz_new(data,graph,dp,node_id); Chris@16: #endif Chris@16: } Chris@16: Chris@16: // Parse the passed iterator range as a GraphViz dot file. Chris@16: template Chris@16: bool read_graphviz(InputIterator user_first, Chris@16: InputIterator user_last, Chris@16: MutableGraph& graph, Chris@16: dynamic_properties& dp, Chris@16: std::string const& node_id = "node_id") { Chris@16: #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER Chris@16: typedef InputIterator is_t; Chris@16: typedef boost::spirit::classic::multi_pass iterator_t; Chris@16: Chris@16: iterator_t first(boost::spirit::classic::make_multi_pass(user_first)); Chris@16: iterator_t last(boost::spirit::classic::make_multi_pass(user_last)); Chris@16: Chris@16: return read_graphviz_spirit(first, last, graph, dp, node_id); Chris@16: #else // Non-Spirit parser Chris@16: return read_graphviz_new(std::string(user_first, user_last), graph, dp, node_id); Chris@16: #endif Chris@16: } Chris@16: Chris@16: // Parse the passed stream as a GraphViz dot file. Chris@16: template Chris@16: bool read_graphviz(std::istream& in, MutableGraph& graph, Chris@16: dynamic_properties& dp, Chris@16: std::string const& node_id = "node_id") Chris@16: { Chris@16: typedef std::istream_iterator is_t; Chris@16: in >> std::noskipws; Chris@16: return read_graphviz(is_t(in), is_t(), graph, dp, node_id); Chris@16: } Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #ifdef BOOST_GRAPH_USE_MPI Chris@16: # include Chris@16: #endif Chris@16: Chris@16: #endif // BOOST_GRAPHVIZ_HPP