使用Bundled属性增强图形库

时间:2017-09-23 11:41:57

标签: c++11 generics boost graph boost-graph

我是BGL的新手,并尝试使用BGL设置一个简单的最短路径查找程序,其中无向图被定义为具有自定义EdgeProperty和VertexProperty的邻接List。我收到编译时错误,这归因于我在模板和Boost中的技能不足。 代码如下:

<app-my-component></app-my-component>

错误是从double到EdgeProperty的未知转换。看来我在调用dijkstra_shortest_paths函数的语法上有错误。

我还想用一个函数替换EdgeProperty的数据成员。

我的其他查询是关于通过顶点描述符维护节点的索引。目前,我正在使用VertexProperty :: id做一个字典到VertexProperty类型的对象。 Do Boost在内部维护我可以使用的任何字典。

我在Ubuntu 16.04上使用gcc5.4版本编译器 谢谢

尼丁

1 个答案:

答案 0 :(得分:1)

@llonesmiz是正确的。这是对代码和现场演示的一般清理。

我还使用make_transform_value_property_map来使用getWeight()并将所有数据成员设为私有。

  

注意怀疑,因为您使用捆绑属性(?),std::map实例不再具有实用性。在任何情况下,如果您不再需要它们,可以删除一些代码: Shorter Demo

     

注意您可能不了解print_graph Even Shorter ,稍微缩写输出

<强> Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <iostream>
#include <map>

enum class Node_type { STAIR, LEVEL, LIFT, OTHER, UNKNOWN };

static std::ostream& operator<<(std::ostream& os, Node_type type) {
    switch(type) {
        case Node_type::STAIR:   return os << "STAIR";
        case Node_type::LEVEL:   return os << "LEVEL";
        case Node_type::LIFT:    return os << "LIFT";
        case Node_type::OTHER:   return os << "OTHER";
        default:
        case Node_type::UNKNOWN: return os << "UNKNOWN";
    }
}

class VertexProperty {
  public:
    VertexProperty(int id = -1, Node_type type = Node_type::UNKNOWN, int level_id=254, int stair_id=254)
        : id(id), type(type), level_id(level_id), stair_id(stair_id) { }

    std::string toString() const {
        std::ostringstream oss;
        oss << *this;
        return oss.str();
    }

    int getVertexID() { return id; }

  private:
    friend std::ostream& operator<<(std::ostream& os, VertexProperty const& v) {
        return os << "id " << v.id << " type " << v.type << " level " << v.level_id << " stair_id " << v.stair_id;
    }

    int id;
    Node_type type;
    int level_id;
    int stair_id;
};

class EdgeProperty {
  public:
    EdgeProperty(int i = -1, double wt = 0) : id(i), weight(wt) {
        id = i;
        weight = wt;
    }
    double getWeight() { return weight; }
    int getID() { return id; }

    std::string toString() const {
        std::ostringstream oss;
        oss << *this;
        return oss.str();
    }

  private:
    friend std::ostream& operator<<(std::ostream& os, EdgeProperty const& e) {
        return os << "id " << e.id << " weight=" << std::fixed << e.weight;
    }

    int id;
    double weight;
};

class A {
  public:
    void undirected_graph_creation();
    void showEdges();
    void showVertices();
    void runDijstra();

  private:
    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperty, EdgeProperty> UndirectedGraph;
    UndirectedGraph g;

    using edge_iterator     = UndirectedGraph::edge_iterator;
    using vertex_iterator   = UndirectedGraph::vertex_iterator;
    using vertex_descriptor = UndirectedGraph::vertex_descriptor;
    using edge_descriptor   = UndirectedGraph::edge_descriptor;

    std::map<int, vertex_descriptor> map_id_vertex_desc;
    std::map<int, edge_descriptor>   map_id_edge_desc;
    std::map<int, Node_type>         map_node_id_type;
};

void A::undirected_graph_creation() {

    auto add_vertex = [this](int id, Node_type type) {
        // TODO: these maps are probably not required anymore
        map_node_id_type[id] = type;
        vertex_descriptor vd = boost::add_vertex(VertexProperty{id, type}, g);
        return map_id_vertex_desc[id] = vd;
    };

    auto v0 = add_vertex(0, Node_type::LEVEL);
    auto v1 = add_vertex(1, Node_type::STAIR);
    auto v2 = add_vertex(2, Node_type::STAIR);
    auto v3 = add_vertex(3, Node_type::STAIR);

    auto add_edge = [this](vertex_descriptor u, vertex_descriptor v, EdgeProperty prop) {
        auto ins = boost::add_edge(u, v, prop, g);

        if (ins.second)
            map_id_edge_desc[prop.getID()] = ins.first;

        return ins.first;
    };

    add_edge(v0, v1, {1, 8});
    add_edge(v0, v3, {2, 18});
    add_edge(v1, v2, {3, 20});
    add_edge(v2, v3, {4, 2});
    add_edge(v1, v3, {5, 7});
}

void A::showEdges() {
    for (auto e : boost::make_iterator_range(boost::edges(g)))
        std::cout << "Edge " << e << " " << g[e] << "\n";
}

void A::showVertices() {
    for (auto v : boost::make_iterator_range(boost::vertices(g)))
        std::cout << "Vertex " << v << " " << g[v] << "\n";
}

void A::runDijstra() {
    std::vector<vertex_descriptor> predecessors(num_vertices(g));
    std::vector<double>            distances(num_vertices(g));
    vertex_descriptor start = *(vertices(g).first);

    auto v_index = get(boost::vertex_index, g);
    auto weight = boost::make_transform_value_property_map(std::mem_fn(&EdgeProperty::getWeight), get(boost::edge_bundle, g));

    dijkstra_shortest_paths(
        g, start,
        predecessor_map(make_iterator_property_map(predecessors.begin(), v_index))
            .distance_map(make_iterator_property_map(distances.begin(), v_index))
            .weight_map(weight));

     std::cout << "distances and parents:\n";
     for (auto v : boost::make_iterator_range(boost::vertices(g))) {
         auto id = g[v].getVertexID();
         std::cout << "distance(" << id << ") = " << distances[v] << ", ";
         std::cout << "parent(" << id << ") = " << g[predecessors[v]] << "\n";
     }
}

int main() {
    A a;
    a.undirected_graph_creation();
    a.showEdges();
    a.showVertices();

    a.runDijstra();
}

打印:

Edge (0,1) id 1 weight=8.000000
Edge (0,3) id 2 weight=18.000000
Edge (1,2) id 3 weight=20.000000
Edge (2,3) id 4 weight=2.000000
Edge (1,3) id 5 weight=7.000000
Vertex 0 id 0 type LEVEL level 254 stair_id 254
Vertex 1 id 1 type STAIR level 254 stair_id 254
Vertex 2 id 2 type STAIR level 254 stair_id 254
Vertex 3 id 3 type STAIR level 254 stair_id 254
distances and parents:
distance(0) = 0.000000, parent(0) = id 0 type LEVEL level 254 stair_id 254
distance(1) = 8.000000, parent(1) = id 0 type LEVEL level 254 stair_id 254
distance(2) = 17.000000, parent(2) = id 3 type STAIR level 254 stair_id 254
distance(3) = 15.000000, parent(3) = id 1 type STAIR level 254 stair_id 254