| // Copyright (C) 2004-2006 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 |
| #ifndef BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP |
| #define BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP |
| |
| #ifndef BOOST_GRAPH_USE_MPI |
| #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" |
| #endif |
| |
| #include <boost/graph/graph_traits.hpp> |
| #include <boost/graph/distributed/concepts.hpp> |
| #include <boost/property_map/property_map.hpp> |
| #include <boost/graph/graphviz.hpp> |
| #include <boost/type_traits/is_base_and_derived.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <fstream> |
| #include <sstream> |
| #include <iostream> |
| #include <string> |
| #include <boost/graph/parallel/container_traits.hpp> |
| #include <boost/graph/parallel/process_group.hpp> |
| #include <boost/property_map/parallel/global_index_map.hpp> |
| |
| namespace boost { |
| |
| template<typename Graph> |
| struct graph_id_writer |
| { |
| explicit graph_id_writer(const Graph& g) : g(g) { } |
| |
| void operator()(std::ostream& out) |
| { |
| out << " label=\"p" << process_id(g.process_group()) << "\";\n"; |
| } |
| |
| private: |
| const Graph& g; |
| }; |
| |
| template<typename NumberMap> |
| struct paint_by_number_writer |
| { |
| explicit paint_by_number_writer(NumberMap number) : number(number) { } |
| |
| template<typename Descriptor> |
| void operator()(std::ostream& out, Descriptor k) |
| { |
| static const char* color_names[] = { |
| "blue", |
| "brown", |
| "cyan", |
| "darkgreen", |
| "darkorchid", |
| "darksalmon", |
| "darkviolet", |
| "deeppink", |
| "gold3", |
| "green", |
| "magenta", |
| "navy", |
| "red", |
| "yellow", |
| "palegreen", |
| "gray65", |
| "gray21", |
| "bisque2", |
| "greenyellow", |
| "indianred4", |
| "lightblue2", |
| "mediumspringgreen", |
| "orangered", |
| "orange" |
| }; |
| const int colors = sizeof(color_names) / sizeof(color_names[0]); |
| if (get(number, k) < colors) { |
| out << " [ style=\"filled\", fillcolor=\"" << color_names[get(number, k)] |
| << "\" ]"; |
| } else { |
| out << " [ label=\"(" << get(number, k) << ")\" ]"; |
| } |
| } |
| |
| private: |
| NumberMap number; |
| }; |
| |
| template<typename NumberMap> |
| inline paint_by_number_writer<NumberMap> |
| paint_by_number(NumberMap number) |
| { return paint_by_number_writer<NumberMap>(number); } |
| |
| template<typename Graph, typename VertexPropertiesWriter, |
| typename EdgePropertiesWriter, typename GraphPropertiesWriter> |
| void |
| write_graphviz(std::ostream& out, |
| const Graph& g, |
| VertexPropertiesWriter vpw, |
| EdgePropertiesWriter epw, |
| GraphPropertiesWriter gpw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| typedef typename graph_traits<Graph>::directed_category directed_category; |
| typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; |
| typedef typename boost::graph::parallel::process_group_type<Graph>::type |
| process_group_type; |
| typedef typename process_group_type::process_id_type process_id_type; |
| typedef typename property_map<Graph, vertex_index_t>::const_type |
| VertexIndexMap; |
| typedef typename property_map<Graph, vertex_global_t>::const_type |
| VertexGlobalMap; |
| |
| static const bool is_undirected |
| = (is_base_and_derived<undirected_tag, directed_category>::value |
| || is_same<undirected_tag, directed_category>::value); |
| static const char* graph_kind = is_undirected? "graph" : "digraph"; |
| static const char* edge_kind = is_undirected? "--" : "->"; |
| |
| using boost::graph::parallel::process_group; |
| process_group_type pg = process_group(g); |
| |
| parallel::global_index_map<VertexIndexMap, VertexGlobalMap> |
| global_index(pg, num_vertices(g), get(vertex_index, g), |
| get(vertex_global, g)); |
| |
| std::ostringstream local_graph_out; |
| |
| local_graph_out << " subgraph cluster_" << process_id(pg) << " {\n"; |
| gpw(local_graph_out); |
| |
| typename graph_traits<Graph>::vertex_iterator vi, vi_end; |
| for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { |
| |
| int global_idx = get(global_index, *vi); |
| local_graph_out << " n" << global_idx; |
| vpw(local_graph_out, *vi); |
| local_graph_out << ";\n"; |
| } |
| local_graph_out << " }\n\n"; |
| |
| |
| typename graph_traits<Graph>::edge_iterator ei, ei_end; |
| for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { |
| int source_idx = get(global_index, source(*ei, g)); |
| int target_idx = get(global_index, target(*ei, g)); |
| local_graph_out << " n" << source_idx << " " << edge_kind << " n" |
| << target_idx; |
| epw(local_graph_out, *ei); |
| local_graph_out << ";\n"; |
| } |
| |
| if (process_id(pg) == 0) { |
| out << graph_kind << " g {\n"; |
| out << local_graph_out.str(); |
| |
| synchronize(pg); |
| for (int i = 1; i < num_processes(pg); ++i) { |
| int len; |
| receive(pg, i, 0, len); |
| char* data = new char [len+1]; |
| data[len] = 0; |
| receive(pg, i, 1, data, len); |
| out << std::endl << data; |
| delete [] data; |
| } |
| out << "}\n"; |
| } else { |
| std::string result_str = local_graph_out.str(); |
| const char* data = result_str.c_str(); |
| |
| int len = result_str.length(); |
| send(pg, 0, 0, len); |
| send(pg, 0, 1, data, len); |
| synchronize(pg); |
| } |
| synchronize(pg); |
| synchronize(pg); |
| synchronize(pg); |
| } |
| |
| template<typename Graph, typename VertexPropertiesWriter, |
| typename EdgePropertiesWriter> |
| inline void |
| write_graphviz(std::ostream& out, |
| const Graph& g, |
| VertexPropertiesWriter vpw, |
| EdgePropertiesWriter epw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| write_graphviz(out, g, vpw, epw, graph_id_writer<Graph>(g)); |
| } |
| |
| template<typename Graph, typename VertexPropertiesWriter> |
| inline void |
| write_graphviz(std::ostream& out, |
| const Graph& g, |
| VertexPropertiesWriter vpw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| write_graphviz(out, g, vpw, default_writer()); |
| } |
| |
| template<typename Graph> |
| inline void |
| write_graphviz(std::ostream& out, const Graph& g |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| write_graphviz(out, g, default_writer()); |
| } |
| |
| template<typename Graph, typename VertexPropertiesWriter, |
| typename EdgePropertiesWriter, typename GraphPropertiesWriter> |
| void |
| write_graphviz(const std::string& filename, |
| const Graph& g, |
| VertexPropertiesWriter vpw, |
| EdgePropertiesWriter epw, |
| GraphPropertiesWriter gpw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| if (process_id(g.process_group()) == 0) { |
| std::ofstream out(filename.c_str()); |
| write_graphviz(out, g, vpw, epw, gpw); |
| } else { |
| write_graphviz(std::cout, g, vpw, epw, gpw); |
| } |
| } |
| |
| template<typename Graph, typename VertexPropertiesWriter, |
| typename EdgePropertiesWriter> |
| void |
| write_graphviz(const std::string& filename, |
| const Graph& g, |
| VertexPropertiesWriter vpw, |
| EdgePropertiesWriter epw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| if (process_id(g.process_group()) == 0) { |
| std::ofstream out(filename.c_str()); |
| write_graphviz(out, g, vpw, epw); |
| } else { |
| write_graphviz(std::cout, g, vpw, epw); |
| } |
| } |
| |
| template<typename Graph, typename VertexPropertiesWriter> |
| void |
| write_graphviz(const std::string& filename, |
| const Graph& g, |
| VertexPropertiesWriter vpw |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| if (process_id(g.process_group()) == 0) { |
| std::ofstream out(filename.c_str()); |
| write_graphviz(out, g, vpw); |
| } else { |
| write_graphviz(std::cout, g, vpw); |
| } |
| } |
| |
| template<typename Graph> |
| void |
| write_graphviz(const std::string& filename, const Graph& g |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| if (process_id(g.process_group()) == 0) { |
| std::ofstream out(filename.c_str()); |
| write_graphviz(out, g); |
| } else { |
| write_graphviz(std::cout, g); |
| } |
| } |
| |
| template<typename Graph> |
| void |
| write_graphviz(std::ostream& out, const Graph& g, |
| const dynamic_properties& dp, |
| const std::string& node_id = "node_id" |
| BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) |
| { |
| write_graphviz |
| (out, g, |
| /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id), |
| /*edge_writer=*/dynamic_properties_writer(dp)); |
| } |
| |
| } // end namespace boost |
| |
| #endif // BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP |