簡體   English   中英

使用 Boost,如何將自定義邊緣屬性作為結構放置/獲取?

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

我已經在這里閱讀了文檔( https://www.boost.org/doc/libs/1_75_0/libs/graph/doc/using_adjacency_list.html )和幾個堆棧溢出頁面兩個小時,並且沒有取得任何進展在這里。 我有一個圖表,其中邊緣既有距離又有坑洞的數量(撞到 3 個坑洞后車輛中斷),所以我想我會使用自定義結構並設置邊緣屬性。

將其放在 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;

編輯:我相信這是上述方法的替代方案,也沒有運氣:

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

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;

后來在 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);

因此,現在我正在嘗試輸入/獲取道路信息,該信息有多個錯誤,並且我嘗試了很多變體:

// 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

通過注釋掉各種行,我發現問題似乎在於我如何獲得屬性 map,但是在網上查看示例時,我覺得我正在做與他們完全相同的事情。

目標最終只是弄清楚如何添加道路信息以及以后如何獲取它,因此可以接受完全不同的方法,我在這里所擁有的只是我嘗試過的(不成功)但我覺得最多的有希望的結果。

可以按照您的建議進行操作,這需要使用BOOST_INSTALL_PROPERTY注冊一個屬性標簽(參見example/examples/edge_property.cpp 的示例)。 相關片段:

 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

住在科利魯

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

印刷

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

更新:邊緣捆綁

對於評論,使其成為邊緣捆綁是膚淺的修改:

住在科利魯

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

印刷:

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

對於受虐狂

如果您堅持,您當然可以安裝屬性標簽。 接觸個別成員會很不舒服(並且可能效率低下),但你這樣做:

住在科利魯

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

再次打印相同的 output。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM