微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我已经在这里阅读了文档 (https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/using_adjacency_list.html) 和几个堆栈溢出页面两个小时,但在这里根本没有取得任何进展。我有一个图表,其中边有距离和坑洞数量(撞到 3 个坑洞后车辆中断),所以我想我会使用自定义结构并设置边缘属性

将其放在类声明之上:

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;

编辑:我相信这是上述的替代方案,并且也没有运气:

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

类声明中的邻接图:

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;

稍后在添加道路的函数中:

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

所以现在我正在尝试输入/获取道路信息,该信息有多个错误并且我尝试了很多变体:

// get the edge
std::pair<Edge,bool> edg = edge(intersection1,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

通过注释掉各种行,我发现问题似乎出在我如何获取属性图上,但查看在线示例时,我觉得我正在做与它们完全相同的事情。

目标最终只是弄清楚如何添加道路信息以及如何在以后获取它,因此可以接受完全不同的方法,我在这里所拥有的只是我尝试过的(未成功)但我觉得取得了最有希望的结果。

解决方法

可以按照您的建议进行操作,这需要使用 BOOST_INSTALL_PROPERTY 注册属性标记(请参阅 example/examples/edge_property.cpp for an example)。相关片段:

namespace boost {
  enum edge_flow_t { edge_flow };
  enum edge_capacity_t { edge_capacity };

  BOOST_INSTALL_PROPERTY(edge,flow);
  BOOST_INSTALL_PROPERTY(edge,capacity);
}

现在您可以在属性定义中使用新的属性标签 就像您使用内置标签之一一样。

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

然而,由于您的用例如此频繁,任何用户定义的结构都已经有一个内置标签:vertex_bundle_tedge_bundle_t:

捆绑属性

这是一个使用它的示例。文档: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,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
    }
}

印刷品

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

更新:边缘包

对于评论,将其设为边包是肤浅的修改:

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::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,roadMap);
    add_edge(1,2,road_info{3,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,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
    }
}

印刷:

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

对于受虐狂

如果你坚持,你当然可以安装一个属性标签。接触单个成员会让人不舒服(并且可能效率低下),但您做到了:

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::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,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,false); // reset pothole
    }
}

再次打印相同的输出。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。