简体   繁体   English

使用 Boost,如何将自定义边缘属性作为结构放置/获取?

[英]Using Boost, how can I put/get custom edge properties as a struct?

I've been over the documentation ( https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/using_adjacency_list.html ) here and several stack overflow pages for two hours and am not making any forward progress here at all.我已经在这里阅读了文档( https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/using_adjacency_list.html )和几个堆栈溢出页面两个小时,并且没有取得任何进展在这里。 I have a graph where edges have both distance and number of potholes (vehicle breaks after hitting 3 potholes), so I was thinking I would use a custom struct and set edge properties.我有一个图表,其中边缘既有距离又有坑洞的数量(撞到 3 个坑洞后车辆中断),所以我想我会使用自定义结构并设置边缘属性。

Placed this above the class declaration:将其放在 class 声明上方:

struct road_details_t {
  typedef boost::edge_property_tag kind;
};
struct road_info {
  unsigned miles;
  bool pothole;
};
typedef boost::property<road_details_t, struct road_info> RoadDetailsProperty;

EDIT: I believe this is an alternative to the above and have not had luck with it either:编辑:我相信这是上述方法的替代方案,也没有运气:

namespace boost {
    enum road_details_t { road_details };
    BOOST_INSTALL_PROPERTY(edge, road_details);
}

The adjacency graph inside the class declaration: class 声明中的邻接图:

typedef boost::adjacency_list<boost::listS,       // store edges in lists
                              boost::vecS,        // store vertices in a vector
                              boost::undirectedS
                              RoadDetailsProperty
                              >
    Graph;
typedef boost::graph_traits<Graph> GraphTraits;
typedef GraphTraits::vertex_descriptor Vertex;
typedef GraphTraits::edge_descriptor Edge;

Graph roadMap;

Later in a function to add roads:后来在 function 中添加道路:

void City::addRoad(Intersection intersection1, Intersection intersection2, unsigned time, bool pothole) 
{
    unsigned nV = num_vertices(roadMap);
    while (intersection1 >= nV)
        nV = add_vertex(roadMap)+1;
    while (intersection2 >= nV)
        nV = add_vertex(roadMap)+1;
    add_edge(intersection1, intersection2, roadMap);

So now I'm trying to put/get the road info, which has multiple errors and I've tried a lot of variations:因此,现在我正在尝试输入/获取道路信息,该信息有多个错误,并且我尝试了很多变体:

// get the edge
std::pair<Edge, bool> edg = edge(intersection1, intersection2, roadMap);

// get the property map for road details. ERROR: no matching function call to get()
typename property_map<Graph, road_details_t>::type
  roadDetailMap = get(road_details_t(), roadMap);

// create struct from arguments passed in
struct road_info info = {time, pothole};

// attempt to add to roadDetailMap
put(roadDetailMap, edg, info);
// roadDetailMap[edg] = info; // also not working

// attempt to fetch information
cout << get(roadDetailMap, edg).miles << endl;
// cout << roadDetailMap[edg].miles << endl; // also not working

By commenting out various lines I've found the issue seems to be in how I'm getting the property map, but looking at examples online I feel like I'm doing the exact same thing they are.通过注释掉各种行,我发现问题似乎在于我如何获得属性 map,但是在网上查看示例时,我觉得我正在做与他们完全相同的事情。

The goal is ultimately just to figure out how to add the road information and how to get it later, so an entirely different approach is acceptible, what I have here is just what I've tried (unsuccessfully) but that I felt had the most promising results.目标最终只是弄清楚如何添加道路信息以及以后如何获取它,因此可以接受完全不同的方法,我在这里所拥有的只是我尝试过的(不成功)但我觉得最多的有希望的结果。

You can do as you suggest, which requires registering a property tag using BOOST_INSTALL_PROPERTY (see example/examples/edge_property.cpp for an example ).可以按照您的建议进行操作,这需要使用BOOST_INSTALL_PROPERTY注册一个属性标签(参见example/examples/edge_property.cpp 的示例)。 Relevant snippet:相关片段:

 namespace boost { enum edge_flow_t { edge_flow }; enum edge_capacity_t { edge_capacity }; BOOST_INSTALL_PROPERTY(edge, flow); BOOST_INSTALL_PROPERTY(edge, capacity); }

Now you can use your new property tag in the definition of properties just as you would one of the builtin tags.现在,您可以在属性定义中使用新的属性标记,就像使用内置标记之一一样。

 typedef property<capacity_t, int> Cap; typedef property<flow_t, int, Cap> EdgeProperty; typedef adjacency_list<vecS, vecS, no_property, EdgeProperty> Graph;

However, since your use case is so frequent, there's already a built-in tag for any user-define struct: vertex_bundle_t and edge_bundle_t :但是,由于您的用例如此频繁,因此任何用户定义的结构都已经有一个内置标签: vertex_bundle_tedge_bundle_t

Bundled Properties捆绑属性

Here's a sample using that.这是一个使用它的示例。 Documentation: https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/bundles.html文档: https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/bundles.html

Live On Coliru住在科利鲁

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>

struct road_info {
    unsigned miles;
    bool     pothole;
};

using Graph  = boost::adjacency_list<boost::listS, boost::vecS,
                                    boost::undirectedS, road_info>;
using Vertex = Graph::vertex_descriptor;
using Edge   = Graph::edge_descriptor;

int main() {
    Graph roadMap;

    Vertex road1     = add_vertex(road_info{15, false}, roadMap);
    Vertex road2     = add_vertex(road_info{3, true}, roadMap);
    /*Vertex road3 =*/ add_vertex(road_info{27, false}, roadMap);

    add_edge(road1, road2, roadMap);

    print_graph(roadMap);

    auto bmap = get(boost::vertex_bundle, roadMap);

    for (Vertex v : boost::make_iterator_range(vertices(roadMap))) {
        road_info& bundle = bmap[v];
        // or even easier
        // road_info& info = roadMap[v];
        auto& [miles, pothole] = roadMap[v]; // c++17

        std::cout << "Vertex #" << v << " " << miles << " miles, "
                  << "pothole:" << std::boolalpha << pothole << "\n";
    }

    // individual maps
    auto miles_map = get(&road_info::miles, roadMap);
    auto poth_map = get(&road_info::pothole, roadMap);

    for (Vertex v : boost::make_iterator_range(vertices(roadMap))) {
        std::cout << "Vertex #" << v << " " << miles_map[v] << " miles, "
                  << "pothole:" << std::boolalpha << poth_map[v] << "\n";

        put(poth_map, v, false); // reset pothole
    }
}

Prints印刷

0 <--> 1 
1 <--> 0 
2 <--> 
Vertex #0 15 miles, pothole:false
Vertex #1 3 miles, pothole:true
Vertex #2 27 miles, pothole:false
Vertex #0 15 miles, pothole:false
Vertex #1 3 miles, pothole:true
Vertex #2 27 miles, pothole:false

UPDATE: Edge Bundles更新:边缘捆绑

To the comments, making it an edge bundle is superficial modifications:对于评论,使其成为边缘捆绑是肤浅的修改:

Live On Coliru住在科利鲁

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>

struct road_info {
    unsigned miles;
    bool     pothole;
};

using Graph =
    boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS,
                          boost::no_property, road_info>;
using Vertex = Graph::vertex_descriptor;
using Edge   = Graph::edge_descriptor;

int main() {
    Graph roadMap(3);

    add_edge(0, 1, road_info{15, false}, roadMap);
    add_edge(1, 2, road_info{3, true}, roadMap);

    print_graph(roadMap);

    auto bmap = get(boost::edge_bundle, roadMap);

    for (Edge e : boost::make_iterator_range(edges(roadMap))) {
        road_info& bundle = bmap[e];
        // or even easier
        // road_info& info = roadMap[e];
        auto& [miles, pothole] = roadMap[e]; // c++17

        std::cout << "Edge " << e << " " << miles << " miles, "
                  << "pothole:" << std::boolalpha << pothole << "\n";
    }

    // individual maps
    auto miles_map = get(&road_info::miles, roadMap);
    auto poth_map = get(&road_info::pothole, roadMap);

    for (Edge e : boost::make_iterator_range(edges(roadMap))) {
        std::cout << "Edge " << e << " " << miles_map[e] << " miles, "
                  << "pothole:" << std::boolalpha << poth_map[e] << "\n";

        put(poth_map, e, false); // reset pothole
    }
}

Printing:印刷:

0 <--> 1 
1 <--> 0 2 
2 <--> 1 
Edge (0,1) 15 miles, pothole:false
Edge (1,2) 3 miles, pothole:true
Edge (0,1) 15 miles, pothole:false
Edge (1,2) 3 miles, pothole:true

For Masochists对于受虐狂

If you insist you can of course install a property tag.如果您坚持,您当然可以安装属性标签。 It will be uncomfortable (and potentially inefficient) to get to the individual members, but you do you:接触个别成员会很不舒服(并且可能效率低下),但你这样做:

Live On Coliru住在科利鲁

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/property_map/transform_value_property_map.hpp>

struct road_info {
    unsigned miles;
    bool     pothole;
};

namespace boost {
    struct edge_road_info_t {};
    BOOST_INSTALL_PROPERTY(edge, road_info);
    static inline constexpr edge_road_info_t road_info{};
}

using Graph =
    boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS,
                          boost::no_property, 
                          boost::property<boost::edge_road_info_t, road_info> >;
using Vertex = Graph::vertex_descriptor;
using Edge   = Graph::edge_descriptor;

int main() {
    Graph roadMap(3);

    add_edge(0, 1, road_info{15, false}, roadMap);
    add_edge(1, 2, road_info{3, true}, roadMap);

    print_graph(roadMap);

    auto info_map = get(boost::road_info, roadMap);

    for (Edge e : boost::make_iterator_range(edges(roadMap))) {
        road_info& info = info_map[e];
        // or even easier
        // road_info& info = roadMap[e];
        auto& [miles, pothole] = info; // c++17

        std::cout << "Edge " << e << " " << miles << " miles, "
                  << "pothole:" << std::boolalpha << pothole << "\n";
    }

    // individual maps
    auto miles_map = boost::make_transform_value_property_map(
        std::mem_fn(&road_info::miles), info_map);
    auto poth_map = boost::make_transform_value_property_map(
        std::mem_fn(&road_info::pothole), info_map);

    for (Edge e : boost::make_iterator_range(edges(roadMap))) {
        std::cout << "Edge " << e << " " << miles_map[e] << " miles, "
                  << "pothole:" << std::boolalpha << poth_map[e] << "\n";

        put(poth_map, e, false); // reset pothole
    }
}

Again printing the same output.再次打印相同的 output。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM