293 lines
8.8 KiB
C++
293 lines
8.8 KiB
C++
|
// 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 boost::graph::parallel::process_group_type<Graph>::type
|
||
|
process_group_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 (boost::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 (boost::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
|