1 // Copyright (C) 2004-2006 The Trustees of Indiana University.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  Authors: Douglas Gregor
8 //           Andrew Lumsdaine
9 #ifndef BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
10 #define BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
11 
12 #ifndef BOOST_GRAPH_USE_MPI
13 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
14 #endif
15 
16 #include <boost/graph/graph_traits.hpp>
17 #include <boost/graph/distributed/concepts.hpp>
18 #include <boost/property_map/property_map.hpp>
19 #include <boost/graph/graphviz.hpp>
20 #include <boost/type_traits/is_base_and_derived.hpp>
21 #include <boost/type_traits/is_same.hpp>
22 #include <fstream>
23 #include <sstream>
24 #include <iostream>
25 #include <string>
26 #include <boost/graph/parallel/container_traits.hpp>
27 #include <boost/graph/parallel/process_group.hpp>
28 #include <boost/property_map/parallel/global_index_map.hpp>
29 
30 namespace boost {
31 
32 template<typename Graph>
33 struct graph_id_writer
34 {
graph_id_writerboost::graph_id_writer35   explicit graph_id_writer(const Graph& g) : g(g) { }
36 
operator ()boost::graph_id_writer37   void operator()(std::ostream& out)
38   {
39     out << "    label=\"p" << process_id(g.process_group()) << "\";\n";
40   }
41 
42  private:
43   const Graph& g;
44 };
45 
46 template<typename NumberMap>
47 struct paint_by_number_writer
48 {
paint_by_number_writerboost::paint_by_number_writer49   explicit paint_by_number_writer(NumberMap number) : number(number) { }
50 
51   template<typename Descriptor>
operator ()boost::paint_by_number_writer52   void operator()(std::ostream& out, Descriptor k)
53   {
54     static const char* color_names[] = {
55       "blue",
56       "brown",
57       "cyan",
58       "darkgreen",
59       "darkorchid",
60       "darksalmon",
61       "darkviolet",
62       "deeppink",
63       "gold3",
64       "green",
65       "magenta",
66       "navy",
67       "red",
68       "yellow",
69       "palegreen",
70       "gray65",
71       "gray21",
72       "bisque2",
73       "greenyellow",
74       "indianred4",
75       "lightblue2",
76       "mediumspringgreen",
77       "orangered",
78       "orange"
79     };
80     const int colors = sizeof(color_names) / sizeof(color_names[0]);
81     if (get(number, k) < colors) {
82       out << " [ style=\"filled\", fillcolor=\"" << color_names[get(number, k)]
83           << "\" ]";
84     } else {
85       out << " [ label=\"(" << get(number, k) << ")\" ]";
86     }
87   }
88 
89  private:
90   NumberMap number;
91 };
92 
93 template<typename NumberMap>
94 inline paint_by_number_writer<NumberMap>
paint_by_number(NumberMap number)95 paint_by_number(NumberMap number)
96 { return paint_by_number_writer<NumberMap>(number); }
97 
98 template<typename Graph, typename VertexPropertiesWriter,
99          typename EdgePropertiesWriter, typename GraphPropertiesWriter>
100 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))101 write_graphviz(std::ostream& out,
102                const Graph& g,
103                VertexPropertiesWriter vpw,
104                EdgePropertiesWriter epw,
105                GraphPropertiesWriter gpw
106                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
107 {
108   typedef typename graph_traits<Graph>::directed_category directed_category;
109   typedef typename boost::graph::parallel::process_group_type<Graph>::type
110     process_group_type;
111   typedef typename property_map<Graph, vertex_index_t>::const_type
112     VertexIndexMap;
113   typedef typename property_map<Graph, vertex_global_t>::const_type
114     VertexGlobalMap;
115 
116   static const bool is_undirected
117     = (is_base_and_derived<undirected_tag, directed_category>::value
118        || is_same<undirected_tag, directed_category>::value);
119   static const char* graph_kind = is_undirected? "graph" : "digraph";
120   static const char* edge_kind = is_undirected? "--" : "->";
121 
122   using boost::graph::parallel::process_group;
123   process_group_type pg = process_group(g);
124 
125   parallel::global_index_map<VertexIndexMap, VertexGlobalMap>
126     global_index(pg, num_vertices(g), get(vertex_index, g),
127                  get(vertex_global, g));
128 
129   std::ostringstream local_graph_out;
130 
131   local_graph_out << "  subgraph cluster_" << process_id(pg) << " {\n";
132   gpw(local_graph_out);
133 
134   typename graph_traits<Graph>::vertex_iterator vi, vi_end;
135   for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
136 
137     int global_idx = get(global_index, *vi);
138     local_graph_out << "    n" << global_idx;
139     vpw(local_graph_out, *vi);
140     local_graph_out << ";\n";
141   }
142   local_graph_out << "  }\n\n";
143 
144 
145   typename graph_traits<Graph>::edge_iterator ei, ei_end;
146   for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
147     int source_idx = get(global_index, source(*ei, g));
148     int target_idx = get(global_index, target(*ei, g));
149     local_graph_out << "  n" << source_idx << " " << edge_kind << " n"
150                     << target_idx;
151     epw(local_graph_out, *ei);
152     local_graph_out << ";\n";
153   }
154 
155   if (process_id(pg) == 0) {
156     out << graph_kind << " g {\n";
157     out << local_graph_out.str();
158 
159     synchronize(pg);
160     for (int i = 1; i < num_processes(pg); ++i) {
161       int len;
162       receive(pg, i, 0, len);
163       char* data = new char [len+1];
164       data[len] = 0;
165       receive(pg, i, 1, data, len);
166       out << std::endl << data;
167       delete [] data;
168     }
169     out << "}\n";
170   } else {
171     std::string result_str = local_graph_out.str();
172     const char* data = result_str.c_str();
173 
174     int len = result_str.length();
175     send(pg, 0, 0, len);
176     send(pg, 0, 1, data, len);
177     synchronize(pg);
178   }
179   synchronize(pg);
180   synchronize(pg);
181   synchronize(pg);
182 }
183 
184 template<typename Graph, typename VertexPropertiesWriter,
185          typename EdgePropertiesWriter>
186 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexPropertiesWriter vpw,EdgePropertiesWriter epw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))187 write_graphviz(std::ostream& out,
188                const Graph& g,
189                VertexPropertiesWriter vpw,
190                EdgePropertiesWriter epw
191                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
192 {
193   write_graphviz(out, g, vpw, epw, graph_id_writer<Graph>(g));
194 }
195 
196 template<typename Graph, typename VertexPropertiesWriter>
197 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexPropertiesWriter vpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))198 write_graphviz(std::ostream& out,
199                const Graph& g,
200                VertexPropertiesWriter vpw
201                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
202 {
203   write_graphviz(out, g, vpw, default_writer());
204 }
205 
206 template<typename Graph>
207 inline void
write_graphviz(std::ostream & out,const Graph & g BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))208 write_graphviz(std::ostream& out, const Graph& g
209                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
210 {
211   write_graphviz(out, g, default_writer());
212 }
213 
214 template<typename Graph, typename VertexPropertiesWriter,
215          typename EdgePropertiesWriter, typename GraphPropertiesWriter>
216 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))217 write_graphviz(const std::string& filename,
218                const Graph& g,
219                VertexPropertiesWriter vpw,
220                EdgePropertiesWriter epw,
221                GraphPropertiesWriter gpw
222                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
223 {
224   if (process_id(g.process_group()) == 0) {
225     std::ofstream out(filename.c_str());
226     write_graphviz(out, g, vpw, epw, gpw);
227   } else {
228     write_graphviz(std::cout, g, vpw, epw, gpw);
229   }
230 }
231 
232 template<typename Graph, typename VertexPropertiesWriter,
233          typename EdgePropertiesWriter>
234 void
write_graphviz(const std::string & filename,const Graph & g,VertexPropertiesWriter vpw,EdgePropertiesWriter epw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))235 write_graphviz(const std::string& filename,
236                const Graph& g,
237                VertexPropertiesWriter vpw,
238                EdgePropertiesWriter epw
239                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
240 {
241   if (process_id(g.process_group()) == 0) {
242     std::ofstream out(filename.c_str());
243     write_graphviz(out, g, vpw, epw);
244   } else {
245     write_graphviz(std::cout, g, vpw, epw);
246   }
247 }
248 
249 template<typename Graph, typename VertexPropertiesWriter>
250 void
write_graphviz(const std::string & filename,const Graph & g,VertexPropertiesWriter vpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))251 write_graphviz(const std::string& filename,
252                const Graph& g,
253                VertexPropertiesWriter vpw
254                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
255 {
256   if (process_id(g.process_group()) == 0) {
257     std::ofstream out(filename.c_str());
258     write_graphviz(out, g, vpw);
259   } else {
260     write_graphviz(std::cout, g, vpw);
261   }
262 }
263 
264 template<typename Graph>
265 void
write_graphviz(const std::string & filename,const Graph & g BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,distributed_graph_tag))266 write_graphviz(const std::string& filename, const Graph& g
267                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
268 {
269   if (process_id(g.process_group()) == 0) {
270     std::ofstream out(filename.c_str());
271     write_graphviz(out, g);
272   } else {
273     write_graphviz(std::cout, g);
274   }
275 }
276 
277 template<typename Graph>
278 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))279 write_graphviz(std::ostream& out, const Graph& g,
280                const dynamic_properties& dp,
281                const std::string& node_id = "node_id"
282                BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
283 {
284   write_graphviz
285     (out, g,
286      /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id),
287      /*edge_writer=*/dynamic_properties_writer(dp));
288 }
289 
290 } // end namespace boost
291 
292 #endif // BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
293