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

グラフリテラル

C++

Gordon Woodhull: Introducing MPL.Graph(pdf)


BoostCon 2011のMPL.Graphの資料を見たら、GraphのEDSLの案が出ていたので、似たようなのを作ってみました。

edges = (
    vertex(A) >= vertex(B) &
    vertex(A) >= vertex(C) >= vertex(D)
);

のようにして、

A-B

C

D

のようなグラフを作ります。
operator>=()は辺を表していて、operator&()は辺の区切りに使用します(カンマ演算子がうまくいかなかった)。


Boost.Graphは辺の組み合わせを書いていかないといけないので、リテラルを書くのがめんどくさいと前から思っていて、
adjacency transformのようにして{A, B, C}から{(A,B), (B,C)}を作れば頂点のリストから辺のリストを生成できるな、と考えてそのようにして構築しました。


サンプルコード:

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

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

int main()
{
    typedef
        boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>
    graph_type;

    using shand::vertex;
    const shand::graph_converter edges = (
                vertex(A) >= vertex(B) &
                vertex(A) >= vertex(C) >= vertex(D)
            );

    graph_type g(edges.begin(), edges.end(), N);

    std::ofstream file("test.dot");
    boost::write_graphviz(file, g, boost::make_label_writer(name.c_str()));
}

出力されるGraphvizのデータ(test.dot):

digraph G {
0[label=A];
1[label=B];
2[label=C];
3[label=D];
0->1 ;
0->2 ;
2->3 ;
}

Graphvizから生成したグラフの画像:


ライブラリのコード:

shand/graph_literal.hpp
shand/fusion/adjacency_for_each.hpp


ちなみに現在のこのバージョンでは、1本の辺は書けません。
それと、頂点の総量がわかっているので、Nを自動的に計算してadjacency_listを直接構築できるようにしようと思ってます(MultiIndexを使って重複あり挿入順リストと、重複なし辞書順リストを同時に持つ予定)。


ちなみに、リテラルなので実際はそんなに使わないと思います。


追記:2011/07/25 19:17
adjacency_listの直接構築に対応しました。

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

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

int main()
{
    typedef
        boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>
    graph_type;

    using shand::vertex;
    graph_type g = (
                vertex(A) >= vertex(B) &
                vertex(A) >= vertex(C) >= vertex(D)
            );

    std::ofstream file("test.dot");
    boost::write_graphviz(file, g, boost::make_label_writer(name.c_str()));
}