我试图重现在this paper中进行的实验,以DIMACS Vertex-Coloring基准图(可在here中找到)测量算法的性能。

这些图采用DIMACS标准格式,我想将它们解析为C++ Boost Graph Library格式,因此我可以对它们运行算法。

我尝试使用现有的Boost DIMACS函数来解析它们,但是关于它们的文档相当稀疏,因此我不清楚如何确切使用这些函数。当我将图形打印到Graphviz时,结果似乎与DIMACS文件不匹配。

我很好奇:

  • 使用Boost解析函数我在做什么错? (请参见下面的示例)
  • 是否有一个更好的或替代的C++库可以轻松地解析DIMACS标准图形格式?

  • 这是我尝试分析和打印图形的尝试:
    #include <cstdlib>
    #include <iostream>
    
    #include <boost/property_map/property_map.hpp>
    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/dimacs.hpp>
    
    #include <fstream>
    
    using namespace boost::graph;
    
    typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS > Graph;
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
    
    
    int main()
    {
    std::ifstream inGraphFile;
    inGraphFile.open("myciel4.col");
    
    
    dimacs_basic_reader reader(inGraphFile, false);
    dimacs_basic_reader end;
    dimacs_edge_iterator<dimacs_basic_reader> dimacsStart(reader);
    dimacs_edge_iterator<dimacs_basic_reader> endIter(end);
    
    
    Graph g2(dimacsStart, endIter, reader.n_vertices());
    boost::write_graphviz(std::cout, g2);
    
    }
    

    最佳答案

    呵呵。这将是今天报告的第三个增强错误。

    dimacs的解析代码对我而言确实是邪恶的。接口(interface)非常不便,实现起来也很麻烦……您发现它是非常错误的:

    read_edge_line中,存在以下循环:

    if ('e' == linebuf[0]) {
        while (*tmp != '\n' && *tmp != '\0') {
            if (*tmp == ' ') {
                *tmp = '\0';
                ts = ++tmp;
                break;
            }
            tmp++;
        }
        *tmp = '\0';                                    /* LINE 156 */
        if (NULL == fs || NULL == ts) return false;
        from = atoi(fs); to = atoi(ts); weight = 0;
    
    } else // ...
    

    当然,从开始就通过c_str()书写char const*指针是未定义的行为(即使大多数库实现在此都可以完成预期的工作,也不建议强制使用(char*) buf.c_str()进行强制转换)。

    但是,第156行中的*tmp = '\0';破坏了目标顶点号。 atoi静默失败,并且to中有不确定数据

    手动解析器

    除了真正的困惑,我还是建议您自己编写解析文件。可以很简单:

    Live On Coliru
    #include <string>
    #include <istream>
    #include <sstream>
    
    template <typename Graph>
    bool read_coloring_problem(std::istream& dimacs, Graph& g) {
        size_t vertices = 0, edges = 0;
    
        std::string line;
        while (getline(dimacs, line))
        {
            std::istringstream iss(line);
            char ch;
            if (iss >> ch)
            {
                size_t from, to;
                std::string format;
    
                switch(ch) {
                    case 'c': break;
                    case 'p':
                        if (vertices||edges) return false;
                        if (iss >> format >> vertices >> edges) {
                            if ("edge" != format) return false;
                        }
                        break;
                    case 'e':
                        if (edges-- && (iss >> from >> to) && (add_edge(from-1, to-1, g).second))
                            break;
                    default:
                        return false;
                }
            }
        }
    
        return !(edges || !dimacs.eof());
    }
    

    Boost Spirit 分析器

    但是我更喜欢使用像Boost Spirit这样的解析器:

    Live On Coliru
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <boost/spirit/include/qi_match.hpp>
    
    template <typename Graph>
    bool read_coloring_problem(std::istream& dimacs, Graph& g) {
        auto add_edge_ = [&g](size_t from, size_t to) { add_edge(from, to, g); };
        size_t vertices = 0, edges = 0;
    
        using namespace boost::spirit::qi;
        namespace px = boost::phoenix;
        uint_parser<size_t> num_;
    
        auto eoil      = eol | eoi;
        auto comment   = boost::proto::deep_copy(lexeme["c " >> *(char_ - eol) >> eoil] | eol);
        auto vertices_ = px::ref(vertices);
        auto edges_    = px::ref(edges);
    
        dimacs >> std::noskipws >> phrase_match(
                *comment >>
                ("p" >> lit("edge") >> num_ [vertices_ = _1] >> num_ [edges_ = _1] >> eoil) >>
                repeat(edges_) [
                    *comment >> ("e" >> num_ >> num_ >> eoil) [ px::bind(add_edge_, _1-1, _2-1) ]
                ]
                >> *comment >> eoi
                , blank);
    
        return dimacs;
    }
    

    输出量

    两种版本均在此图中显示:

    关于c++ - 如何在C++中读取DIMACS顶点着色图?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30415388/

    10-15 00:31