読者です 読者をやめる 読者になる 読者になる

Boost.Graph Graphviz形式で重みを出力

C++

boost::dynamic_propertiesでもできそうでしたが、
今回はboost::label_writerに習って、重みを出力するためのPropertyWriterを用意してみました。


まず、重みのみを出力するPropertyWriter。

template <class Graph>
struct weight_writer {
    weight_writer(const Graph& g) : graph_(g) {}

    template <class Edge>
    void operator()(std::ostream& out, Edge edge) const
    {
        out << "[weight=" << boost::get(boost::edge_weight, graph_, edge) << "]";
    }

private:
    const Graph& graph_;
};

template <class Graph>
inline weight_writer<Graph> make_weight_writer(const Graph& g)
{
    return weight_writer<Graph>(g);
}

これを使用してdotファイルを出力し、その後pngに変換します。

#include <fstream>
#include <vector>
#include <string>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

typedef
    boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
        boost::no_property, boost::property<boost::edge_weight_t, int>>
Graph;

typedef std::pair<int, int> Edge;

enum { A, B, C, D, E, N };
const std::string name = "ABCDE";

int main()
{
    const std::vector<Edge> edges = {
        {A, B}, {A, C}, {A, D},
        {B, E}, {C, E}, {D, E}
    };

    const std::vector<int> weights = {
        3, 1, 4,
        5, 2, 6
    };

    const Graph g(edges.begin(), edges.end(), weights.begin(), N);

    std::ofstream file("test.dot");
    boost::write_graphviz(file, g,
            boost::make_label_writer(name.c_str()),
            make_weight_writer(g));
}
digraph G {
0[label="A"];
1[label="B"];
2[label="C"];
3[label="D"];
4[label="E"];
0->1 [weight=3];
0->2 [weight=1];
0->3 [weight=4];
1->4 [weight=5];
2->4 [weight=2];
3->4 [weight=6];
}

以下のようになります。
辺の長さのみが変わり、重みは値としては出力されません。


次に、重みと、その値を出力するPropertyWriter。

template <class Graph>
struct weight_label_writer {
    weight_label_writer(const Graph& g) : graph_(g) {}

    template <class Edge>
    void operator()(std::ostream& out, const Edge& edge) const
    {
        write(out, edge, boost::get(boost::edge_weight, graph_, edge));
    }

private:
    template <class Edge, class Weight>
    void write(std::ostream& out, const Edge& edge, const Weight& weight) const
    {
        out << "[weight="
            << weight
            << ", label="
            << weight
            << "]";
    }

    const Graph& graph_;
};

template <class Graph>
inline weight_label_writer<Graph> make_weight_label_writer(const Graph& g)
{
    return weight_label_writer<Graph>(g);
}

これを使用してdotファイルを出力し、その後pngに変換します。

#include <fstream>
#include <vector>
#include <string>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

typedef
    boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
        boost::no_property, boost::property<boost::edge_weight_t, int>>
Graph;

typedef std::pair<int, int> Edge;

enum { A, B, C, D, E, N };
const std::string name = "ABCDE";

int main()
{
    const std::vector<Edge> edges = {
        {A, B}, {A, C}, {A, D},
        {B, E}, {C, E}, {D, E}
    };

    const std::vector<int> weights = {
        3, 1, 4,
        5, 2, 6
    };

    const Graph g(edges.begin(), edges.end(), weights.begin(), N);

    std::ofstream file("test.dot");
    boost::write_graphviz(file, g,
            boost::make_label_writer(name.c_str()),
            make_weight_label_writer(g));
}
digraph G {
0[label="A"];
1[label="B"];
2[label="C"];
3[label="D"];
4[label="E"];
0->1 [weight=3, label=3];
0->2 [weight=1, label=1];
0->3 [weight=4, label=4];
1->4 [weight=5, label=5];
2->4 [weight=2, label=2];
3->4 [weight=6, label=6];
}

以下のようになります。今度は重みが値としても出力されています。


これらのPropertyWriterは、用途に応じて使い分けてください。
C++0xの可変引数テンプレートやmpl::vectorを使用して、PropertyWriterの合成ができるとおもしろいかもしれません。