【问题标题】:Boost C++ graph write_graphviz_dp提升 C++ 图 write_graphviz_dp
【发布时间】:2016-05-31 19:32:37
【问题描述】:

问题是,我无法使用write_graphviz_dp 编写自定义创建的图表。

我创建了一个带有自定义属性的图表:

typedef enum { UNSET = 0, RED = 1, GREEN = 2, BLUE = 3} Color;

enum vertex_one_t { vertex_one };
namespace boost {
  BOOST_INSTALL_PROPERTY(vertex, one);
}

enum vertex_two_t { vertex_two };
namespace boost {
  BOOST_INSTALL_PROPERTY(vertex, two);
}

enum vertex_three_t { vertex_three };
namespace boost {
  BOOST_INSTALL_PROPERTY(vertex, three);
}

typedef boost::property< boost::vertex_index_t, int,
          boost::property< vertex_one_t, Color*,
            boost::property< vertex_two_t, Color*, 
              boost::property< vertex_three_t, Color* > > > > DualVertexProperty;

我正在尝试使用

编写图表
// Graph structure with dynamic property output
template<typename Graph>
void
write_graphviz_dp(std::ostream& out, const Graph& g,
                  const dynamic_properties& dp,
                  const std::string& node_id = "node_id");

但我在boost::dynamic_properties creation 期间遇到错误。

boost::dynamic_properties dpDual;

boost::property_map<DualGraph, vertex_index_t>::type vIndex = get(boost::vertex_index, g);
    boost::property_map<DualGraph, vertex_one_t>::type vOne = get(vertex_one, g);

dpDual.property("node_id", vIndex);
dpDual.property("Color_1", get(vOne, g));

更具体地说,编译错误在最后一行。 我没有发布错误消息,因为它太长了。

【问题讨论】:

    标签: c++ boost graph


    【解决方案1】:

    首先,您必须将属性映射传递给 dynamic_properties:

    dpDual.property("Color_1", vOne); // or maaaaybe
    dpDual.property("Color_1", boost::get(vertex_one, g));
    

    其次,Graphviz 本质上是一种文本格式。您是否为Color* 定义了文本转换?如果没有,您希望如何呈现这些属性?

    简单的解决方案

    为什么是属性指针? Color*Color 更浪费(int 可能比指针小)。

    你可以抛开所有的生活问题,实现你的愿望:

    inline static std::ostream& operator<<(std::ostream& os, Color color) {
        return os << static_cast<int>(color);
    }
    
    inline static std::istream& operator>>(std::istream& is, Color& color) {
        int dummy;
        is >> dummy;
        color = static_cast<Color>(dummy);
        return is;
    }
    

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/random.hpp>
    #include <random>
    #include <iostream>
    
    typedef enum { UNSET = 0, RED = 1, GREEN = 2, BLUE = 3} Color;
    
    enum vertex_one_t { vertex_one };
    namespace boost { BOOST_INSTALL_PROPERTY(vertex, one); }
    
    enum vertex_two_t { vertex_two };
    namespace boost {
        BOOST_INSTALL_PROPERTY(vertex, two);
    }
    
    enum vertex_three_t { vertex_three };
    namespace boost {
        BOOST_INSTALL_PROPERTY(vertex, three);
    }
    
    typedef boost::property< boost::vertex_index_t, int,
            boost::property< vertex_one_t, Color,
            boost::property< vertex_two_t, Color, 
            boost::property< vertex_three_t, Color > > > > DualVertexProperty;
    
    inline static std::ostream& operator<<(std::ostream& os, Color color) {
        return os << static_cast<int>(color);
    }
    
    inline static std::istream& operator>>(std::istream& is, Color& color) {
        int dummy;
        is >> dummy;
        color = static_cast<Color>(dummy);
        return is;
    }
    
    int main() {
        using DualGraph = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, DualVertexProperty, boost::no_property>;
    
        boost::dynamic_properties dpDual;
        DualGraph g;
        std::mt19937 rng { std::random_device{}() };
        boost::generate_random_graph(g, 5, 5, rng);
    
        boost::property_map<DualGraph, boost::vertex_index_t>::type vIndex = boost::get(boost::vertex_index, g);
        boost::property_map<DualGraph, vertex_one_t>::type vOne = boost::get(vertex_one, g);
    
        dpDual.property("node_id", vIndex);
        dpDual.property("Color_1", vOne);
    
        boost::write_graphviz_dp(std::cout, g, dpDual);
    }
    

    更复杂

    您可以(尝试)使指针可流式传输,但您必须想办法让生命周期和所有权变得有意义。

    奖金:

    考虑捆绑属性。除非您有非常具体的要求,否则无需像您的代码那样继续使用过时的内部属性。

    Live On Coliru(编译超时)

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/random.hpp>
    #include <random>
    #include <iostream>
    
    typedef enum { UNSET = 0, RED = 1, GREEN = 2, BLUE = 3} Color;
    
    struct DualVertexProperty {
        Color one, two, three;
    };
    
    inline static std::ostream& operator<<(std::ostream& os, Color color) { return os << static_cast<int>(color); }
    inline static std::istream& operator>>(std::istream& is, Color& color) { int dummy; is >> dummy; color = static_cast<Color>(dummy); return is; }
    
    int main() {
        using DualGraph = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, DualVertexProperty, boost::no_property>;
    
        boost::dynamic_properties dpDual;
        DualGraph g;
        std::mt19937 rng { std::random_device{}() };
        boost::generate_random_graph(g, 5, 5, rng);
    
        for (auto v: boost::make_iterator_range(boost::vertices(g)))
            g[v] = DualVertexProperty { RED, GREEN, BLUE };
    
        dpDual.property("node_id", boost::get(boost::vertex_index, g));
        dpDual.property("Color_1", boost::get(&DualVertexProperty::one, g));
    
        boost::write_graphviz_dp(std::cout, g, dpDual);
    }
    

    这在很多方面都简单得多!

    【讨论】:

    • 我使用指针是因为相邻顶点具有共享属性,为了避免它们之间的同步,我使用了指针。
    • 好的。这将使阅读变得非常困难 - 如果可能的话,使用 read_graphviz。我想你可能正在寻找格子,你看到grid_graph.hpp了吗?
    • 我不需要超过两个维度,我也不会使用 read_graphviz,对于那个图,我只想导出它。我喜欢你的“新”语法,但我仍然不知道如何使用指针作为属性
    • 我的意思不是超过 2 个维度(我认为我没有暗示)。对于导出,您应该可以只对指针进行流式处理(例如通过取消引用它)
    • 我试过inline static std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, Color *color) { return os &lt;&lt; static_cast&lt;int&gt;(*color); },但没用
    猜你喜欢
    • 2014-06-11
    • 2015-04-07
    • 2013-09-04
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 2017-12-28
    • 2010-12-06
    相关资源
    最近更新 更多