1 //=======================================================================
2 // Copyright 2001 University of Notre Dame.
3 // Copyright 2003 Jeremy Siek
4 // Authors: Lie-Quan Lee, Jeremy Siek, and Douglas Gregor
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //=======================================================================
10 #ifndef BOOST_GRAPHVIZ_HPP
11 #define BOOST_GRAPHVIZ_HPP
12
13 #include <boost/config.hpp>
14 #include <string>
15 #include <map>
16 #include <iostream>
17 #include <fstream>
18 #include <stdio.h> // for FILE
19 #include <boost/property_map/property_map.hpp>
20 #include <boost/tuple/tuple.hpp>
21 #include <boost/graph/graph_traits.hpp>
22 #include <boost/graph/properties.hpp>
23 #include <boost/graph/subgraph.hpp>
24 #include <boost/graph/adjacency_list.hpp>
25 #include <boost/property_map/dynamic_property_map.hpp>
26 #include <boost/graph/overloading.hpp>
27 #include <boost/graph/dll_import_export.hpp>
28 #include <boost/graph/compressed_sparse_row_graph.hpp>
29 #include <boost/graph/iteration_macros.hpp>
30 #include <boost/graph/detail/mpi_include.hpp>
31 #include <boost/spirit/include/classic_multi_pass.hpp>
32 #include <boost/lexical_cast.hpp>
33 #include <boost/static_assert.hpp>
34 #include <boost/algorithm/string/replace.hpp>
35 #include <boost/xpressive/xpressive_static.hpp>
36 #include <boost/foreach.hpp>
37
38 namespace boost {
39
40 template <typename directed_category>
41 struct graphviz_io_traits {
nameboost::graphviz_io_traits42 static std::string name() {
43 return "digraph";
44 }
delimiterboost::graphviz_io_traits45 static std::string delimiter() {
46 return "->";
47 } };
48
49 template <>
50 struct graphviz_io_traits <undirected_tag> {
nameboost::graphviz_io_traits51 static std::string name() {
52 return "graph";
53 }
delimiterboost::graphviz_io_traits54 static std::string delimiter() {
55 return "--";
56 }
57 };
58
59 struct default_writer {
operator ()boost::default_writer60 void operator()(std::ostream&) const {
61 }
62 template <class VorE>
operator ()boost::default_writer63 void operator()(std::ostream&, const VorE&) const {
64 }
65 };
66
67 template <typename T>
escape_dot_string(const T & obj)68 inline std::string escape_dot_string(const T& obj) {
69 using namespace boost::xpressive;
70 static sregex valid_unquoted_id = (((alpha | '_') >> *_w) | (!as_xpr('-') >> (('.' >> *_d) | (+_d >> !('.' >> *_d)))));
71 std::string s(boost::lexical_cast<std::string>(obj));
72 if (regex_match(s, valid_unquoted_id)) {
73 return s;
74 } else {
75 boost::algorithm::replace_all(s, "\"", "\\\"");
76 return "\"" + s + "\"";
77 }
78 }
79
80 template <class Name>
81 class label_writer {
82 public:
label_writer(Name _name)83 label_writer(Name _name) : name(_name) {}
84 template <class VertexOrEdge>
operator ()(std::ostream & out,const VertexOrEdge & v) const85 void operator()(std::ostream& out, const VertexOrEdge& v) const {
86 out << "[label=" << escape_dot_string(get(name, v)) << "]";
87 }
88 private:
89 Name name;
90 };
91 template <class Name>
92 inline label_writer<Name>
make_label_writer(Name n)93 make_label_writer(Name n) {
94 return label_writer<Name>(n);
95 }
96
97 enum edge_attribute_t { edge_attribute = 1111 };
98 enum vertex_attribute_t { vertex_attribute = 2222 };
99 enum graph_graph_attribute_t { graph_graph_attribute = 3333 };
100 enum graph_vertex_attribute_t { graph_vertex_attribute = 4444 };
101 enum graph_edge_attribute_t { graph_edge_attribute = 5555 };
102
103 BOOST_INSTALL_PROPERTY(edge, attribute);
104 BOOST_INSTALL_PROPERTY(vertex, attribute);
105 BOOST_INSTALL_PROPERTY(graph, graph_attribute);
106 BOOST_INSTALL_PROPERTY(graph, vertex_attribute);
107 BOOST_INSTALL_PROPERTY(graph, edge_attribute);
108
109
110 template <class Attribute>
write_attributes(const Attribute & attr,std::ostream & out)111 inline void write_attributes(const Attribute& attr, std::ostream& out) {
112 typename Attribute::const_iterator i, iend;
113 i = attr.begin();
114 iend = attr.end();
115
116 while ( i != iend ) {
117 out << i->first << "=" << escape_dot_string(i->second);
118 ++i;
119 if ( i != iend )
120 out << ", ";
121 }
122 }
123
124 template<typename Attributes>
write_all_attributes(Attributes attributes,const std::string & name,std::ostream & out)125 inline void write_all_attributes(Attributes attributes,
126 const std::string& name,
127 std::ostream& out)
128 {
129 typename Attributes::const_iterator i = attributes.begin(),
130 end = attributes.end();
131 if (i != end) {
132 out << name << " [\n";
133 write_attributes(attributes, out);
134 out << "];\n";
135 }
136 }
137
write_all_attributes(detail::error_property_not_found,const std::string &,std::ostream &)138 inline void write_all_attributes(detail::error_property_not_found,
139 const std::string&,
140 std::ostream&)
141 {
142 // Do nothing - no attributes exist
143 }
144
145
146
147
148 template <typename GraphGraphAttributes,
149 typename GraphNodeAttributes,
150 typename GraphEdgeAttributes>
151 struct graph_attributes_writer
152 {
graph_attributes_writerboost::graph_attributes_writer153 graph_attributes_writer(GraphGraphAttributes gg,
154 GraphNodeAttributes gn,
155 GraphEdgeAttributes ge)
156 : g_attributes(gg), n_attributes(gn), e_attributes(ge) { }
157
operator ()boost::graph_attributes_writer158 void operator()(std::ostream& out) const {
159 write_all_attributes(g_attributes, "graph", out);
160 write_all_attributes(n_attributes, "node", out);
161 write_all_attributes(e_attributes, "edge", out);
162 }
163 GraphGraphAttributes g_attributes;
164 GraphNodeAttributes n_attributes;
165 GraphEdgeAttributes e_attributes;
166 };
167
168 template <typename GAttrMap, typename NAttrMap, typename EAttrMap>
169 graph_attributes_writer<GAttrMap, NAttrMap, EAttrMap>
make_graph_attributes_writer(const GAttrMap & g_attr,const NAttrMap & n_attr,const EAttrMap & e_attr)170 make_graph_attributes_writer(const GAttrMap& g_attr, const NAttrMap& n_attr,
171 const EAttrMap& e_attr) {
172 return graph_attributes_writer<GAttrMap, NAttrMap, EAttrMap>
173 (g_attr, n_attr, e_attr);
174 }
175
176
177 template <typename Graph>
178 graph_attributes_writer
179 <typename graph_property<Graph, graph_graph_attribute_t>::type,
180 typename graph_property<Graph, graph_vertex_attribute_t>::type,
181 typename graph_property<Graph, graph_edge_attribute_t>::type>
make_graph_attributes_writer(const Graph & g)182 make_graph_attributes_writer(const Graph& g)
183 {
184 typedef typename graph_property<Graph, graph_graph_attribute_t>::type
185 GAttrMap;
186 typedef typename graph_property<Graph, graph_vertex_attribute_t>::type
187 NAttrMap;
188 typedef typename graph_property<Graph, graph_edge_attribute_t>::type
189 EAttrMap;
190 GAttrMap gam = get_property(g, graph_graph_attribute);
191 NAttrMap nam = get_property(g, graph_vertex_attribute);
192 EAttrMap eam = get_property(g, graph_edge_attribute);
193 graph_attributes_writer<GAttrMap, NAttrMap, EAttrMap> writer(gam, nam, eam);
194 return writer;
195 }
196
197 template <typename AttributeMap>
198 struct attributes_writer {
attributes_writerboost::attributes_writer199 attributes_writer(AttributeMap attr)
200 : attributes(attr) { }
201
202 template <class VorE>
operator ()boost::attributes_writer203 void operator()(std::ostream& out, const VorE& e) const {
204 this->write_attribute(out, attributes[e]);
205 }
206
207 private:
208 template<typename AttributeSequence>
write_attributeboost::attributes_writer209 void write_attribute(std::ostream& out,
210 const AttributeSequence& seq) const
211 {
212 if (!seq.empty()) {
213 out << "[";
214 write_attributes(seq, out);
215 out << "]";
216 }
217 }
218
write_attributeboost::attributes_writer219 void write_attribute(std::ostream&,
220 detail::error_property_not_found) const
221 {
222 }
223 AttributeMap attributes;
224 };
225
226 template <typename Graph>
227 attributes_writer
228 <typename property_map<Graph, edge_attribute_t>::const_type>
make_edge_attributes_writer(const Graph & g)229 make_edge_attributes_writer(const Graph& g)
230 {
231 typedef typename property_map<Graph, edge_attribute_t>::const_type
232 EdgeAttributeMap;
233 return attributes_writer<EdgeAttributeMap>(get(edge_attribute, g));
234 }
235
236 template <typename Graph>
237 attributes_writer
238 <typename property_map<Graph, vertex_attribute_t>::const_type>
make_vertex_attributes_writer(const Graph & g)239 make_vertex_attributes_writer(const Graph& g)
240 {
241 typedef typename property_map<Graph, vertex_attribute_t>::const_type
242 VertexAttributeMap;
243 return attributes_writer<VertexAttributeMap>(get(vertex_attribute, g));
244 }
245
246 template <typename Graph, typename VertexPropertiesWriter,
247 typename EdgePropertiesWriter, typename GraphPropertiesWriter,
248 typename VertexID>
249 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexPropertiesWriter vpw,EdgePropertiesWriter epw,GraphPropertiesWriter gpw,VertexID vertex_id BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))250 write_graphviz
251 (std::ostream& out, const Graph& g,
252 VertexPropertiesWriter vpw,
253 EdgePropertiesWriter epw,
254 GraphPropertiesWriter gpw,
255 VertexID vertex_id
256 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
257 {
258 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept<Graph>));
259
260 typedef typename graph_traits<Graph>::directed_category cat_type;
261 typedef graphviz_io_traits<cat_type> Traits;
262 std::string name = "G";
263 out << Traits::name() << " " << escape_dot_string(name) << " {" << std::endl;
264
265 gpw(out); //print graph properties
266
267 typename graph_traits<Graph>::vertex_iterator i, end;
268
269 for(boost::tie(i,end) = vertices(g); i != end; ++i) {
270 out << escape_dot_string(get(vertex_id, *i));
271 vpw(out, *i); //print vertex attributes
272 out << ";" << std::endl;
273 }
274 typename graph_traits<Graph>::edge_iterator ei, edge_end;
275 for(boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) {
276 out << escape_dot_string(get(vertex_id, source(*ei, g))) << Traits::delimiter() << escape_dot_string(get(vertex_id, target(*ei, g))) << " ";
277 epw(out, *ei); //print edge attributes
278 out << ";" << std::endl;
279 }
280 out << "}" << std::endl;
281 }
282
283 template <typename Graph, typename VertexPropertiesWriter,
284 typename EdgePropertiesWriter, typename GraphPropertiesWriter>
285 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexPropertiesWriter vpw,EdgePropertiesWriter epw,GraphPropertiesWriter gpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))286 write_graphviz(std::ostream& out, const Graph& g,
287 VertexPropertiesWriter vpw,
288 EdgePropertiesWriter epw,
289 GraphPropertiesWriter gpw
290 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
291 { write_graphviz(out, g, vpw, epw, gpw, get(vertex_index, g)); }
292
293 template <typename Graph>
294 inline void
write_graphviz(std::ostream & out,const Graph & g BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))295 write_graphviz(std::ostream& out, const Graph& g
296 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
297 {
298 default_writer dw;
299 default_writer gw;
300 write_graphviz(out, g, dw, dw, gw);
301 }
302
303 template <typename Graph, typename VertexWriter>
304 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexWriter vw BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))305 write_graphviz(std::ostream& out, const Graph& g, VertexWriter vw
306 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
307 {
308 default_writer dw;
309 default_writer gw;
310 write_graphviz(out, g, vw, dw, gw);
311 }
312
313 template <typename Graph, typename VertexWriter, typename EdgeWriter>
314 inline void
write_graphviz(std::ostream & out,const Graph & g,VertexWriter vw,EdgeWriter ew BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))315 write_graphviz(std::ostream& out, const Graph& g,
316 VertexWriter vw, EdgeWriter ew
317 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
318 {
319 default_writer gw;
320 write_graphviz(out, g, vw, ew, gw);
321 }
322
323 namespace detail {
324
325 template <class Graph_, class RandomAccessIterator, class VertexID>
write_graphviz_subgraph(std::ostream & out,const subgraph<Graph_> & g,RandomAccessIterator vertex_marker,RandomAccessIterator edge_marker,VertexID vertex_id)326 void write_graphviz_subgraph (std::ostream& out,
327 const subgraph<Graph_>& g,
328 RandomAccessIterator vertex_marker,
329 RandomAccessIterator edge_marker,
330 VertexID vertex_id)
331 {
332 typedef subgraph<Graph_> Graph;
333 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
334 typedef typename graph_traits<Graph>::directed_category cat_type;
335 typedef graphviz_io_traits<cat_type> Traits;
336
337 typedef typename graph_property<Graph, graph_name_t>::type NameType;
338 const NameType& g_name = get_property(g, graph_name);
339
340 if ( g.is_root() )
341 out << Traits::name() ;
342 else
343 out << "subgraph";
344
345 out << " " << escape_dot_string(g_name) << " {" << std::endl;
346
347 typename Graph::const_children_iterator i_child, j_child;
348
349 //print graph/node/edge attributes
350 make_graph_attributes_writer(g)(out);
351
352 //print subgraph
353 for ( boost::tie(i_child,j_child) = g.children();
354 i_child != j_child; ++i_child )
355 write_graphviz_subgraph(out, *i_child, vertex_marker, edge_marker,
356 vertex_id);
357
358 // Print out vertices and edges not in the subgraphs.
359
360 typename graph_traits<Graph>::vertex_iterator i, end;
361 typename graph_traits<Graph>::edge_iterator ei, edge_end;
362
363 for(boost::tie(i,end) = vertices(g); i != end; ++i) {
364 Vertex v = g.local_to_global(*i);
365 int pos = get(vertex_id, v);
366 if ( vertex_marker[pos] ) {
367 vertex_marker[pos] = false;
368 out << escape_dot_string(pos);
369 make_vertex_attributes_writer(g.root())(out, v);
370 out << ";" << std::endl;
371 }
372 }
373
374 for (boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) {
375 Vertex u = g.local_to_global(source(*ei,g)),
376 v = g.local_to_global(target(*ei, g));
377 int pos = get(get(edge_index, g.root()), g.local_to_global(*ei));
378 if ( edge_marker[pos] ) {
379 edge_marker[pos] = false;
380 out << escape_dot_string(get(vertex_id, u)) << " " << Traits::delimiter()
381 << " " << escape_dot_string(get(vertex_id, v));
382 make_edge_attributes_writer(g)(out, *ei); //print edge properties
383 out << ";" << std::endl;
384 }
385 }
386 out << "}" << std::endl;
387 }
388 } // namespace detail
389
390 // requires graph_name graph property
391 template <typename Graph>
write_graphviz(std::ostream & out,const subgraph<Graph> & g)392 void write_graphviz(std::ostream& out, const subgraph<Graph>& g) {
393 std::vector<bool> edge_marker(num_edges(g), true);
394 std::vector<bool> vertex_marker(num_vertices(g), true);
395
396 detail::write_graphviz_subgraph(out, g,
397 vertex_marker.begin(),
398 edge_marker.begin(),
399 get(vertex_index, g));
400 }
401
402 template <typename Graph>
write_graphviz(const std::string & filename,const subgraph<Graph> & g)403 void write_graphviz(const std::string& filename, const subgraph<Graph>& g) {
404 std::ofstream out(filename.c_str());
405 std::vector<bool> edge_marker(num_edges(g), true);
406 std::vector<bool> vertex_marker(num_vertices(g), true);
407
408 detail::write_graphviz_subgraph(out, g,
409 vertex_marker.begin(),
410 edge_marker.begin(),
411 get(vertex_index, g));
412 }
413
414 template <typename Graph, typename VertexID>
write_graphviz(std::ostream & out,const subgraph<Graph> & g,VertexID vertex_id)415 void write_graphviz(std::ostream& out, const subgraph<Graph>& g,
416 VertexID vertex_id)
417 {
418 std::vector<bool> edge_marker(num_edges(g), true);
419 std::vector<bool> vertex_marker(num_vertices(g), true);
420
421 detail::write_graphviz_subgraph(out, g,
422 vertex_marker.begin(),
423 edge_marker.begin(),
424 vertex_id);
425 }
426
427 template <typename Graph, typename VertexID>
write_graphviz(const std::string & filename,const subgraph<Graph> & g,VertexID vertex_id)428 void write_graphviz(const std::string& filename, const subgraph<Graph>& g,
429 VertexID vertex_id)
430 {
431 std::ofstream out(filename.c_str());
432 std::vector<bool> edge_marker(num_edges(g), true);
433 std::vector<bool> vertex_marker(num_vertices(g), true);
434
435 detail::write_graphviz_subgraph(out, g,
436 vertex_marker.begin(),
437 edge_marker.begin(),
438 vertex_id);
439 }
440
441 #if 0
442 // This interface has not worked for a long time
443 typedef std::map<std::string, std::string> GraphvizAttrList;
444
445 typedef property<vertex_attribute_t, GraphvizAttrList>
446 GraphvizVertexProperty;
447
448 typedef property<edge_attribute_t, GraphvizAttrList,
449 property<edge_index_t, int> >
450 GraphvizEdgeProperty;
451
452 typedef property<graph_graph_attribute_t, GraphvizAttrList,
453 property<graph_vertex_attribute_t, GraphvizAttrList,
454 property<graph_edge_attribute_t, GraphvizAttrList,
455 property<graph_name_t, std::string> > > >
456 GraphvizGraphProperty;
457
458 typedef subgraph<adjacency_list<vecS,
459 vecS, directedS,
460 GraphvizVertexProperty,
461 GraphvizEdgeProperty,
462 GraphvizGraphProperty> >
463 GraphvizDigraph;
464
465 typedef subgraph<adjacency_list<vecS,
466 vecS, undirectedS,
467 GraphvizVertexProperty,
468 GraphvizEdgeProperty,
469 GraphvizGraphProperty> >
470 GraphvizGraph;
471
472 // These four require linking the BGL-Graphviz library: libbgl-viz.a
473 // from the /src directory.
474 // Library has not existed for a while
475 extern void read_graphviz(const std::string& file, GraphvizDigraph& g);
476 extern void read_graphviz(FILE* file, GraphvizDigraph& g);
477
478 extern void read_graphviz(const std::string& file, GraphvizGraph& g);
479 extern void read_graphviz(FILE* file, GraphvizGraph& g);
480 #endif
481
482 class dynamic_properties_writer
483 {
484 public:
dynamic_properties_writer(const dynamic_properties & dp)485 dynamic_properties_writer(const dynamic_properties& dp) : dp(&dp) { }
486
487 template<typename Descriptor>
operator ()(std::ostream & out,Descriptor key) const488 void operator()(std::ostream& out, Descriptor key) const
489 {
490 bool first = true;
491 for (dynamic_properties::const_iterator i = dp->begin();
492 i != dp->end(); ++i) {
493 if (typeid(key) == i->second->key()) {
494 if (first) out << " [";
495 else out << ", ";
496 first = false;
497
498 out << i->first << "=" << escape_dot_string(i->second->get_string(key));
499 }
500 }
501
502 if (!first) out << "]";
503 }
504
505 private:
506 const dynamic_properties* dp;
507 };
508
509 class dynamic_vertex_properties_writer
510 {
511 public:
dynamic_vertex_properties_writer(const dynamic_properties & dp,const std::string & node_id)512 dynamic_vertex_properties_writer(const dynamic_properties& dp,
513 const std::string& node_id)
514 : dp(&dp), node_id(&node_id) { }
515
516 template<typename Descriptor>
operator ()(std::ostream & out,Descriptor key) const517 void operator()(std::ostream& out, Descriptor key) const
518 {
519 bool first = true;
520 for (dynamic_properties::const_iterator i = dp->begin();
521 i != dp->end(); ++i) {
522 if (typeid(key) == i->second->key()
523 && i->first != *node_id) {
524 if (first) out << " [";
525 else out << ", ";
526 first = false;
527
528 out << i->first << "=" << escape_dot_string(i->second->get_string(key));
529 }
530 }
531
532 if (!first) out << "]";
533 }
534
535 private:
536 const dynamic_properties* dp;
537 const std::string* node_id;
538 };
539
540 template <typename Graph>
541 class dynamic_graph_properties_writer
542 {
543 public:
dynamic_graph_properties_writer(const dynamic_properties & dp,const Graph & g)544 dynamic_graph_properties_writer(const dynamic_properties& dp, const Graph& g) : g(&g), dp(&dp) { }
545
operator ()(std::ostream & out) const546 void operator()(std::ostream& out) const
547 {
548 for (dynamic_properties::const_iterator i = dp->begin();
549 i != dp->end(); ++i) {
550 if (typeid(Graph*) == i->second->key()) {
551 // const_cast here is to match interface used in read_graphviz
552 out << i->first << "=" << escape_dot_string(i->second->get_string(const_cast<Graph*>(g))) << ";\n";
553 }
554 }
555 }
556
557 private:
558 const Graph* g;
559 const dynamic_properties* dp;
560 };
561
562 namespace graph { namespace detail {
563
564 template<typename Vertex>
565 struct node_id_property_map
566 {
567 typedef std::string value_type;
568 typedef value_type reference;
569 typedef Vertex key_type;
570 typedef readable_property_map_tag category;
571
node_id_property_mapboost::graph::detail::node_id_property_map572 node_id_property_map() {}
573
node_id_property_mapboost::graph::detail::node_id_property_map574 node_id_property_map(const dynamic_properties& dp,
575 const std::string& node_id)
576 : dp(&dp), node_id(&node_id) { }
577
578 const dynamic_properties* dp;
579 const std::string* node_id;
580 };
581
582 template<typename Vertex>
583 inline std::string
get(node_id_property_map<Vertex> pm,typename node_id_property_map<Vertex>::key_type v)584 get(node_id_property_map<Vertex> pm,
585 typename node_id_property_map<Vertex>::key_type v)
586 { return get(*pm.node_id, *pm.dp, v); }
587
588 } } // end namespace graph::detail
589
590 template<typename Graph>
591 inline void
write_graphviz_dp(std::ostream & out,const Graph & g,const dynamic_properties & dp,const std::string & node_id="node_id"BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))592 write_graphviz_dp(std::ostream& out, const Graph& g,
593 const dynamic_properties& dp,
594 const std::string& node_id = "node_id"
595 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
596 {
597 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
598 write_graphviz_dp(out, g, dp, node_id,
599 graph::detail::node_id_property_map<Vertex>(dp, node_id));
600 }
601
602 template<typename Graph, typename VertexID>
603 void
write_graphviz_dp(std::ostream & out,const Graph & g,const dynamic_properties & dp,const std::string & node_id,VertexID id BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))604 write_graphviz_dp(std::ostream& out, const Graph& g,
605 const dynamic_properties& dp, const std::string& node_id,
606 VertexID id
607 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
608 {
609 write_graphviz
610 (out, g,
611 /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id),
612 /*edge_writer=*/dynamic_properties_writer(dp),
613 /*graph_writer=*/dynamic_graph_properties_writer<Graph>(dp, g),
614 id);
615 }
616
617 /////////////////////////////////////////////////////////////////////////////
618 // Graph reader exceptions
619 /////////////////////////////////////////////////////////////////////////////
620 struct BOOST_SYMBOL_VISIBLE graph_exception : public std::exception {
~graph_exceptionboost::graph_exception621 virtual ~graph_exception() throw() {}
622 virtual const char* what() const throw() = 0;
623 };
624
625 struct BOOST_SYMBOL_VISIBLE bad_parallel_edge : public graph_exception {
626 std::string from;
627 std::string to;
628 mutable std::string statement;
bad_parallel_edgeboost::bad_parallel_edge629 bad_parallel_edge(const std::string& i, const std::string& j) :
630 from(i), to(j) {}
631
~bad_parallel_edgeboost::bad_parallel_edge632 virtual ~bad_parallel_edge() throw() {}
whatboost::bad_parallel_edge633 const char* what() const throw() {
634 if(statement.empty())
635 statement =
636 std::string("Failed to add parallel edge: (")
637 + from + "," + to + ")\n";
638
639 return statement.c_str();
640 }
641 };
642
643 struct BOOST_SYMBOL_VISIBLE directed_graph_error : public graph_exception {
~directed_graph_errorboost::directed_graph_error644 virtual ~directed_graph_error() throw() {}
whatboost::directed_graph_error645 virtual const char* what() const throw() {
646 return
647 "read_graphviz: "
648 "Tried to read a directed graph into an undirected graph.";
649 }
650 };
651
652 struct BOOST_SYMBOL_VISIBLE undirected_graph_error : public graph_exception {
~undirected_graph_errorboost::undirected_graph_error653 virtual ~undirected_graph_error() throw() {}
whatboost::undirected_graph_error654 virtual const char* what() const throw() {
655 return
656 "read_graphviz: "
657 "Tried to read an undirected graph into a directed graph.";
658 }
659 };
660
661 struct BOOST_SYMBOL_VISIBLE bad_graphviz_syntax: public graph_exception {
662 std::string errmsg;
bad_graphviz_syntaxboost::bad_graphviz_syntax663 bad_graphviz_syntax(const std::string& errmsg)
664 : errmsg(errmsg) {}
whatboost::bad_graphviz_syntax665 const char* what() const throw () {return errmsg.c_str();}
~bad_graphviz_syntaxboost::bad_graphviz_syntax666 ~bad_graphviz_syntax() throw () {};
667 };
668
669 namespace detail { namespace graph {
670
671 typedef std::string id_t;
672 typedef id_t node_t;
673
674 // edges are not uniquely determined by adjacent nodes
675 class edge_t {
676 int idx_;
edge_t(int i)677 explicit edge_t(int i) : idx_(i) {}
678 public:
new_edge()679 static edge_t new_edge() {
680 static int idx = 0;
681 return edge_t(idx++);
682 };
683
operator ==(const edge_t & rhs) const684 bool operator==(const edge_t& rhs) const {
685 return idx_ == rhs.idx_;
686 }
operator <(const edge_t & rhs) const687 bool operator<(const edge_t& rhs) const {
688 return idx_ < rhs.idx_;
689 }
690 };
691
692 class mutate_graph
693 {
694 public:
~mutate_graph()695 virtual ~mutate_graph() {}
696 virtual bool is_directed() const = 0;
697 virtual void do_add_vertex(const node_t& node) = 0;
698
699 virtual void
700 do_add_edge(const edge_t& edge, const node_t& source, const node_t& target)
701 = 0;
702
703 virtual void
704 set_node_property(const id_t& key, const node_t& node, const id_t& value) = 0;
705
706 virtual void
707 set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) = 0;
708
709 virtual void // RG: need new second parameter to support BGL subgraphs
710 set_graph_property(const id_t& key, const id_t& value) = 0;
711
712 virtual void
713 finish_building_graph() = 0;
714 };
715
716 template<typename MutableGraph>
717 class mutate_graph_impl : public mutate_graph
718 {
719 typedef typename graph_traits<MutableGraph>::vertex_descriptor bgl_vertex_t;
720 typedef typename graph_traits<MutableGraph>::edge_descriptor bgl_edge_t;
721
722 public:
mutate_graph_impl(MutableGraph & graph,dynamic_properties & dp,std::string node_id_prop)723 mutate_graph_impl(MutableGraph& graph, dynamic_properties& dp,
724 std::string node_id_prop)
725 : graph_(graph), dp_(dp), node_id_prop_(node_id_prop) { }
726
~mutate_graph_impl()727 ~mutate_graph_impl() {}
728
is_directed() const729 bool is_directed() const
730 {
731 return
732 boost::is_convertible<
733 typename boost::graph_traits<MutableGraph>::directed_category,
734 boost::directed_tag>::value;
735 }
736
do_add_vertex(const node_t & node)737 virtual void do_add_vertex(const node_t& node)
738 {
739 // Add the node to the graph.
740 bgl_vertex_t v = add_vertex(graph_);
741
742 // Set up a mapping from name to BGL vertex.
743 bgl_nodes.insert(std::make_pair(node, v));
744
745 // node_id_prop_ allows the caller to see the real id names for nodes.
746 put(node_id_prop_, dp_, v, node);
747 }
748
749 void
do_add_edge(const edge_t & edge,const node_t & source,const node_t & target)750 do_add_edge(const edge_t& edge, const node_t& source, const node_t& target)
751 {
752 std::pair<bgl_edge_t, bool> result =
753 add_edge(bgl_nodes[source], bgl_nodes[target], graph_);
754
755 if(!result.second) {
756 // In the case of no parallel edges allowed
757 boost::throw_exception(bad_parallel_edge(source, target));
758 } else {
759 bgl_edges.insert(std::make_pair(edge, result.first));
760 }
761 }
762
763 void
set_node_property(const id_t & key,const node_t & node,const id_t & value)764 set_node_property(const id_t& key, const node_t& node, const id_t& value)
765 {
766 put(key, dp_, bgl_nodes[node], value);
767 }
768
769 void
set_edge_property(const id_t & key,const edge_t & edge,const id_t & value)770 set_edge_property(const id_t& key, const edge_t& edge, const id_t& value)
771 {
772 put(key, dp_, bgl_edges[edge], value);
773 }
774
775 void
set_graph_property(const id_t & key,const id_t & value)776 set_graph_property(const id_t& key, const id_t& value)
777 {
778 /* RG: pointer to graph prevents copying */
779 put(key, dp_, &graph_, value);
780 }
781
finish_building_graph()782 void finish_building_graph() {}
783
784
785 protected:
786 MutableGraph& graph_;
787 dynamic_properties& dp_;
788 std::string node_id_prop_;
789 std::map<node_t, bgl_vertex_t> bgl_nodes;
790 std::map<edge_t, bgl_edge_t> bgl_edges;
791 };
792
793 template<typename Directed,
794 typename VertexProperty,
795 typename EdgeProperty,
796 typename GraphProperty,
797 typename Vertex,
798 typename EdgeIndex>
799 class mutate_graph_impl<compressed_sparse_row_graph<Directed, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex> >
800 : public mutate_graph
801 {
802 typedef compressed_sparse_row_graph<Directed, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex> CSRGraph;
803 typedef typename graph_traits<CSRGraph>::vertices_size_type bgl_vertex_t;
804 typedef typename graph_traits<CSRGraph>::edges_size_type bgl_edge_t;
805 typedef typename graph_traits<CSRGraph>::edge_descriptor edge_descriptor;
806
807 public:
mutate_graph_impl(CSRGraph & graph,dynamic_properties & dp,std::string node_id_prop)808 mutate_graph_impl(CSRGraph& graph, dynamic_properties& dp,
809 std::string node_id_prop)
810 : graph_(graph), dp_(dp), vertex_count(0), node_id_prop_(node_id_prop) { }
811
~mutate_graph_impl()812 ~mutate_graph_impl() {}
813
finish_building_graph()814 void finish_building_graph() {
815 typedef compressed_sparse_row_graph<directedS, no_property, bgl_edge_t, GraphProperty, Vertex, EdgeIndex> TempCSRGraph;
816 TempCSRGraph temp(edges_are_unsorted_multi_pass,
817 edges_to_add.begin(), edges_to_add.end(),
818 counting_iterator<bgl_edge_t>(0),
819 vertex_count);
820 set_property(temp, graph_all, get_property(graph_, graph_all));
821 graph_.assign(temp); // Copies structure, not properties
822 std::vector<edge_descriptor> edge_permutation_from_sorting(num_edges(temp));
823 BGL_FORALL_EDGES_T(e, temp, TempCSRGraph) {
824 edge_permutation_from_sorting[temp[e]] = e;
825 }
826 typedef boost::tuple<id_t, bgl_vertex_t, id_t> v_prop;
827 BOOST_FOREACH(const v_prop& t, vertex_props) {
828 put(boost::get<0>(t), dp_, boost::get<1>(t), boost::get<2>(t));
829 }
830 typedef boost::tuple<id_t, bgl_edge_t, id_t> e_prop;
831 BOOST_FOREACH(const e_prop& t, edge_props) {
832 put(boost::get<0>(t), dp_, edge_permutation_from_sorting[boost::get<1>(t)], boost::get<2>(t));
833 }
834 }
835
is_directed() const836 bool is_directed() const
837 {
838 return
839 boost::is_convertible<
840 typename boost::graph_traits<CSRGraph>::directed_category,
841 boost::directed_tag>::value;
842 }
843
do_add_vertex(const node_t & node)844 virtual void do_add_vertex(const node_t& node)
845 {
846 // Add the node to the graph.
847 bgl_vertex_t v = vertex_count++;
848
849 // Set up a mapping from name to BGL vertex.
850 bgl_nodes.insert(std::make_pair(node, v));
851
852 // node_id_prop_ allows the caller to see the real id names for nodes.
853 vertex_props.push_back(boost::make_tuple(node_id_prop_, v, node));
854 }
855
856 void
do_add_edge(const edge_t & edge,const node_t & source,const node_t & target)857 do_add_edge(const edge_t& edge, const node_t& source, const node_t& target)
858 {
859 bgl_edge_t result = edges_to_add.size();
860 edges_to_add.push_back(std::make_pair(bgl_nodes[source], bgl_nodes[target]));
861 bgl_edges.insert(std::make_pair(edge, result));
862 }
863
864 void
set_node_property(const id_t & key,const node_t & node,const id_t & value)865 set_node_property(const id_t& key, const node_t& node, const id_t& value)
866 {
867 vertex_props.push_back(boost::make_tuple(key, bgl_nodes[node], value));
868 }
869
870 void
set_edge_property(const id_t & key,const edge_t & edge,const id_t & value)871 set_edge_property(const id_t& key, const edge_t& edge, const id_t& value)
872 {
873 edge_props.push_back(boost::make_tuple(key, bgl_edges[edge], value));
874 }
875
876 void
set_graph_property(const id_t & key,const id_t & value)877 set_graph_property(const id_t& key, const id_t& value)
878 {
879 /* RG: pointer to graph prevents copying */
880 put(key, dp_, &graph_, value);
881 }
882
883
884 protected:
885 CSRGraph& graph_;
886 dynamic_properties& dp_;
887 bgl_vertex_t vertex_count;
888 std::string node_id_prop_;
889 std::vector<boost::tuple<id_t, bgl_vertex_t, id_t> > vertex_props;
890 std::vector<boost::tuple<id_t, bgl_edge_t, id_t> > edge_props;
891 std::vector<std::pair<bgl_vertex_t, bgl_vertex_t> > edges_to_add;
892 std::map<node_t, bgl_vertex_t> bgl_nodes;
893 std::map<edge_t, bgl_edge_t> bgl_edges;
894 };
895
896 } } } // end namespace boost::detail::graph
897
898 #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER
899 # ifndef BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS
900 # define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS
901 # endif
902 # include <boost/graph/detail/read_graphviz_spirit.hpp>
903 #else // New default parser
904 # include <boost/graph/detail/read_graphviz_new.hpp>
905 #endif // BOOST_GRAPH_USE_SPIRIT_PARSER
906
907 namespace boost {
908
909 // Parse the passed string as a GraphViz dot file.
910 template <typename MutableGraph>
read_graphviz(const std::string & data,MutableGraph & graph,dynamic_properties & dp,std::string const & node_id="node_id")911 bool read_graphviz(const std::string& data,
912 MutableGraph& graph,
913 dynamic_properties& dp,
914 std::string const& node_id = "node_id") {
915 #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER
916 return read_graphviz_spirit(data.begin(), data.end(), graph, dp, node_id);
917 #else // Non-Spirit parser
918 return read_graphviz_new(data,graph,dp,node_id);
919 #endif
920 }
921
922 // Parse the passed iterator range as a GraphViz dot file.
923 template <typename InputIterator, typename MutableGraph>
read_graphviz(InputIterator user_first,InputIterator user_last,MutableGraph & graph,dynamic_properties & dp,std::string const & node_id="node_id")924 bool read_graphviz(InputIterator user_first,
925 InputIterator user_last,
926 MutableGraph& graph,
927 dynamic_properties& dp,
928 std::string const& node_id = "node_id") {
929 #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER
930 typedef InputIterator is_t;
931 typedef boost::spirit::classic::multi_pass<is_t> iterator_t;
932
933 iterator_t first(boost::spirit::classic::make_multi_pass(user_first));
934 iterator_t last(boost::spirit::classic::make_multi_pass(user_last));
935
936 return read_graphviz_spirit(first, last, graph, dp, node_id);
937 #else // Non-Spirit parser
938 return read_graphviz_new(std::string(user_first, user_last), graph, dp, node_id);
939 #endif
940 }
941
942 // Parse the passed stream as a GraphViz dot file.
943 template <typename MutableGraph>
read_graphviz(std::istream & in,MutableGraph & graph,dynamic_properties & dp,std::string const & node_id="node_id")944 bool read_graphviz(std::istream& in, MutableGraph& graph,
945 dynamic_properties& dp,
946 std::string const& node_id = "node_id")
947 {
948 typedef std::istream_iterator<char> is_t;
949 in >> std::noskipws;
950 return read_graphviz(is_t(in), is_t(), graph, dp, node_id);
951 }
952
953 } // namespace boost
954
955 #include BOOST_GRAPH_MPI_INCLUDE(<boost/graph/distributed/graphviz.hpp>)
956
957 #endif // BOOST_GRAPHVIZ_HPP
958