【问题标题】:Odd Error Importing DOT files导入 DOT 文件时出现奇怪错误
【发布时间】:2015-12-24 13:53:10
【问题描述】:

对于我的 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,并且位于链的末端。我在读取和输出图表之间什么也没做

注意事项:

  • 当我尝试使用更复杂的 .DOT 文件时,图形的拓扑保持不变,只是节点由于某种奇怪的原因被置换了。

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

谁能帮我理解和解决这个问题?谢谢。

【问题讨论】:

    标签: c++ boost graphviz


    【解决方案1】:

    如果您阅读图表并再次打印结果(以 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);
    }
    

    根据您的意见:

    输出显然是同构的:

    注意您自己的问题中显示的输出也很简单!

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

    为此,您必须将顶点 ID(从 dot 文件中读取)显式存储到属性中。这是一个例子:

    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);
    }
    

    生成:

    【讨论】:

      【解决方案2】:

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

      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 解析点文件的方式非常愚蠢和不直观。

      【讨论】:

      • 请在这里自我接受。稍后我会找时间完整阅读这个问题。我可能会发现根本问题。同时,你可以search my existing answers,以防你发现你正在做的事情不同
      • 毕竟没有发生任何令人毛骨悚然的事情(我的回答中解释了“虚假”连接(节点 2 现在莫名其妙地连接到节点 10)。跨度>
      • +1-ed 因为我看到你几乎拥有了这里的所有成分。我只是不同意“这真的很愚蠢且不直观”-在阅读时,解析器无法知道节点ID的类型。顺便说一句,如果您有能力更改节点 ID 的格式(例如 0203),那么还有另一种选择:vimeo.com/channels/761265
      猜你喜欢
      • 2021-07-21
      • 1970-01-01
      • 2021-02-22
      • 2013-08-22
      • 1970-01-01
      • 2012-07-26
      • 2011-03-26
      • 2017-09-16
      • 2011-08-27
      相关资源
      最近更新 更多