奇怪的错误导入DOT文件

时间:2015-09-27 02:48:45

标签: c++ boost graphviz

对于我的C ++程序,我需要使用Boost Graph读取DOT文件,然后输出另一个DOT文件。但是,我在读入阶段遇到了一个奇怪的错误,这真的搞砸了我的程序。

我的读入代码(图形类型是双向Boost图的typedef)

void readGraph(Graph& graph, string filename) {

    boost::dynamic_properties dp(boost::ignore_other_properties);

    ifstream fin(filename.c_str());
    boost::read_graphviz(fin, graph, dp);

}

好的,问题是.DOT文件中的节点是以错误的顺序在中读取的!我用一个简单的例子尝试了它.DOT文件:

digraph G {
0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10;
0->1; 1->0;
1->2; 2->1;
2->3; 3->2;
3->4; 4->3;
4->5; 5->4;
5->6; 6->5;
6->7; 7->6;
7->8; 8->7;
8->9; 9->8;
9->10; 10->9;
}

这是从节点0到节点10的双向链。但是,如果我使用Boost Graph读取此文件并立即输出而不进行更改,则会变为:

digraph G {
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
0->1 ;
1->3 ;
3->4 ;
4->5 ;
5->6 ;
6->7 ;
7->8 ;
8->9 ;
9->10 ;
10->2 ;
1->0 ;
3->1 ;
4->3 ;
5->4 ;
6->5 ;
7->6 ;
8->7 ;
9->8 ;
10->9 ;
2->10 ;
}

注意,节点2现在莫名其妙地连接到节点10,并且位于链的末尾。我在阅读和输出图表之间完成了 nothing

注意:

  • 当我尝试使用更复杂的.DOT文件时,图表的拓扑结构保持不变,只是因为某些奇怪的原因而对节点进行了置换。

  • 我知道这是一个读,而不是写错误,因为当我在程序中输出顶点和边时,它们已经被搞砸了。

任何人都可以帮助我理解和解决这个问题吗?感谢。

2 个答案:

答案 0 :(得分:2)

如果您阅读图表并再次打印结果(以graphviz格式),您会发现图表是等效的(或同构):

<强> Live On Coliru

#include <boost/graph/graphviz.hpp>
#include "/Archive2/45/a4410ef1bd3024/main.cpp" // alias <libs/graph/src/read_graphviz_new.

using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS>;

void readGraph(Graph &graph, std::string filename) {
    boost::dynamic_properties dp(boost::ignore_other_properties);

    std::ifstream fin(filename.c_str());
    boost::read_graphviz(fin, graph, dp);
}

int main() {
    Graph g;
    readGraph(g, "input.dot");

    boost::write_graphviz(std::cout, g);
}

输入您的信息:

enter image description here

输出显然是等形的:

enter image description here

  

注意您自己问题中显示的输出也就是这样!

您真正想要的是保留顶点ID。

为了做到这一点,你必须明确地将顶点ID(从点文件中读取)存储到属性中。这是一个例子:

<强> Live On Coliru

#include <boost/graph/graphviz.hpp>
#include "/Archive2/45/a4410ef1bd3024/main.cpp" // alias <libs/graph/src/read_graphviz_new.

using namespace boost;

struct MyVertex {
    int id;
};

using Graph = adjacency_list<
    vecS, vecS, directedS, 
    MyVertex
>;

void readGraph(Graph &graph, std::string filename) {
    boost::dynamic_properties dp(boost::ignore_other_properties);
    dp.property("node_id", boost::get(&MyVertex::id, graph));

    std::ifstream fin(filename.c_str());
    boost::read_graphviz(fin, graph, dp);
}

int main() {
    Graph g;
    readGraph(g, "input.dot");

    boost::dynamic_properties dp(boost::ignore_other_properties);
    dp.property("node_id", boost::get(&MyVertex::id, g));
    boost::write_graphviz_dp(std::cout, g, dp);
}

生成:

enter image description here

答案 1 :(得分:1)

好的,所以我做了更多调查。我修改了我的读入函数:

void readGraph(Graph& graph, string filename) {

    boost::dynamic_properties dp(boost::ignore_other_properties);

    ifstream fin(filename.c_str());

    dp.property("node_id", boost::get(&vert::id, graph));
    boost::read_graphviz(fin, graph, dp, "node_id");

}

我在哪里创建了结构

vert {
    int id;
}

作为我的图表中顶点的捆绑属性:

typedef boost::adjacency_list<boost::listS, boost::vecS, boost::bidirectionalS, vert, edge> Graph;

如果我现在使用.id包打印出读入图的所有顶点和边缘:

Graph h;
readGraph(h, "InputGraph.dot");
for(pair<vertexIt, vertexIt> it = boost::vertices(h); it.first != it.second; ++it.first) {
    cout << h[*it.first].id << endl;
}
for(pair<edgeIt, edgeIt> it = boost::edges(h); it.first != it.second; ++it.first) {
    cout << h[source(*it.first,h)].id << " -> " << h[target(*it.first,h)].id << endl;
}

我明白了:

0
1
10
2
3
4
5
6
7
8
9
0 -> 1
1 -> 0
1 -> 2
2 -> 1
2 -> 3
3 -> 2
3 -> 4
4 -> 3
4 -> 5
5 -> 4
5 -> 6
6 -> 5
6 -> 7
7 -> 6
7 -> 8
8 -> 7
8 -> 9
9 -> 8
9 -> 10
10 -> 9

所以我们看到一个潜在的问题 - 节点已按字母顺序读取。我不知道这是如何解释我之前看到的奇怪的2-> 10连接。值得庆幸的是,.id包存储了节点的真实信息,因此我们只使用它来访问图。 我仍然认为read_graphviz解析点文件是多么愚蠢和不直观。