如何在C ++中阅读DIMACS顶点着色图?

时间:2015-05-23 17:04:19

标签: c++ boost graph boost-graph graph-coloring

我正在尝试重现在this paper中执行的实验,在DIMACS Vertex-Coloring基准图上测量算法的性能,可以找到here

图表是DIMACS标准格式,我想将它们解析为C ++ Boost Graph Library格式,因此我可以在它们上运行算法。

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

我想知道:

  1. 使用Boost解析函数我做错了什么? (见下面的例子)

  2. 是否有更好的或替代的C ++库可以轻松解析DIMACS标准图表格式?

  3. 这是我尝试解析和打印图表:

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

1 个答案:

答案 0 :(得分:6)

鹤鹤。这将是今天报告的第三个提升错误。

dimacs解析代码对我来说真的很邪恶。界面非常不方便和实施......好吧,你发现它是非常错误的:

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这样的解析器生成器:

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

输出

此图表中的两个版本都会产生结果:

enter image description here

相关问题