将Boost图形库与顶点的自定义类一起使用

马塞洛90

我目前正在尝试在现有的c ++项目中使用提升图库。我想将自定义类的对象存储在增强图中。下面是一个带有两个成员(一个字符串和一个int)及其对应的getter方法的自定义类定义的小示例。

我有几个问题:

  1. 如何在Graphviz输出中包括字符串和int值?我找到了使用类似问题的答案boost::make_label_writer但我不确定我的示例是否可以用于此(我正在使用自定义类和共享指针)。
  2. 在一个图形中,一个相同的对象(相同的字符串和int值)不能多次存储。因此,我在自定义类中重载了两个比较运算符。我还读到我必须将图形类型定义的第二个模板参数更改为,boost::setS但这会导致编译器出现非常长的错误消息...
  3. 假设我创建了一个自定义类的新对象:如何检查它是否已存储在图形中?

    #include <iostream>
    #include <boost/graph/graphviz.hpp>
    
    class my_custom_class {
        public:
    
        my_custom_class(const std::string &my_string,
                        int my_int) : my_string(my_string),
                                      my_int(my_int) {}
    
        virtual ~my_custom_class() {
        }
    
        std::string get_my_string() const {
            return my_string;
        }
    
        int get_int() const {
            return my_int;
        }
    
        bool operator==(const my_custom_class &rhs) const {
            return my_string == rhs.my_string &&
                   my_int == rhs.my_int;
        }
    
        bool operator!=(const my_custom_class &rhs) const {
            return !(rhs == *this);
        }
    
        private:
    
        std::string my_string;
    
        int my_int;
    };
    
    namespace boost {
        enum vertex_my_custom_class_t {
            vertex_my_custom_class = 123
        };
        BOOST_INSTALL_PROPERTY(vertex,
                               my_custom_class);
    }
    
    int main() {
        typedef boost::adjacency_list<boost::vecS,
                boost::vecS,
                boost::directedS,
                boost::property<boost::vertex_my_custom_class_t,
                                std::shared_ptr<my_custom_class>>> graph_t;
    
        typedef boost::graph_traits<graph_t>::vertex_descriptor vertex_t;
    
        std::shared_ptr<my_custom_class> object_one = std::make_shared<my_custom_class>("Lorem", 123);
        std::shared_ptr<my_custom_class> object_two = std::make_shared<my_custom_class>("ipsum", 456);
        std::shared_ptr<my_custom_class> object_three = std::make_shared<my_custom_class>("Lorem", 123);
    
        std::cout << "object one: " << object_one->get_int() << "; " << object_one->get_my_string() << std::endl;
        std::cout << "object two: " << object_two->get_int() << "; " << object_two->get_my_string() << std::endl;
        std::cout << "object three: " << object_three->get_int() << "; " << object_three->get_my_string() << std::endl;
    
        std::cout << std::endl;
    
        std::cout << "object one == object two: " << (*object_one == *object_two) << std::endl;
        std::cout << "object one == object three: " << (*object_one == *object_three) << std::endl;
    
        std::cout << std::endl;
    
        graph_t graph;
    
        vertex_t vertex_one = boost::add_vertex(object_one, graph);
        vertex_t vertex_two = boost::add_vertex(object_two, graph);
        vertex_t vertex_three = boost::add_vertex(object_three, graph);
    
        boost::add_edge(vertex_one, vertex_two, graph);
        boost::add_edge(vertex_one, vertex_three, graph);
    
        boost::write_graphviz(std::cout, graph);
    
        return 0;
    }
    

程序输出:

object one: 123; Lorem
object two: 456; ipsum
object three: 123; Lorem

object one == object two: 0
object one == object three: 1

digraph G {
0;
1;
2;
0->1 ;
0->2 ;
}
看到
  1. 在不更改声明的情况下,这有点痛苦,但是可能:

    {
        boost::dynamic_properties dp;
        boost::property_map<graph_t, boost::vertex_my_custom_class_t>::type custom = get(boost::vertex_my_custom_class, graph);
        dp.property("node_id", boost::make_transform_value_property_map(std::mem_fn(&my_custom_class::get_int), custom));
        dp.property("label", boost::make_transform_value_property_map(std::mem_fn(&my_custom_class::get_my_string), custom));
        boost::write_graphviz_dp(std::cout, graph, dp);
    }
    

    印刷: Live On Coliru

    digraph G {
    123 [label=Lorem];
    456 [label=ipsum];
    123 [label=Lorem];
    123->456 ;
    123->123 ;
    }
    
  2. 您将需要在外部进行处理。为什么不拥有一组侵入性节点,并以此方式验证约束。如您所说,更改“顶点容器选择器”没有任何效果(它最终只会以升序存储顶点描述符,而它们却像以前一样保持唯一性)。

    副作用是从连续分配的顶点存储变为基于节点的(pro:迭代器/引用稳定性,con:分配开销,减少的引用局部性,非隐式vertex_index)。后者是罪魁祸首:BGL中的许多东西都需要一个顶点索引,如果没有隐含一个顶点索引(通过使用vecS例如),则必须传递一个。

    有趣的是,因为我曾经write_graphviz_dp与一个特定的node_id属性没有必要为隐顶点指数刚才,所以你可以改变vecSsetS并观察行为:Live On Coliru

  3. 我认为这不是检查的正确时间。除了访问外部顶点,没有比访问所有顶点更好的方法了。

样式/简化

由于std::shared_ptr暗示您拥有c ++ 11,因此让我们使用它。

同样,带有自定义属性的整个舞蹈在很大程度上更笨拙地进行了属性捆绑:从语法上讲,这些捆绑更容易获得更好的支持。

看到不同:

请注意,我有一秒钟的热情,使用shared-ptr,您仍然需要transform-value-property-map:

Live On Coliru

#include <boost/graph/graphviz.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <iostream>

struct MyVertex {
    MyVertex(std::string label, int id) : _label(std::move(label)), _id(id) {}

    std::string label() const { return _label; }
    int         id()    const { return _id;    }

    bool operator<(const MyVertex &rhs) const { return std::tie(_id, _label) < std::tie(rhs._id, rhs._label); }
  private:
    std::string _label;
    int _id;
};

using graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, std::shared_ptr<MyVertex>>;

int main() {
    graph_t graph;

    auto v1 = add_vertex(std::make_shared<MyVertex>("Lorem", 123), graph);
    auto v2 = add_vertex(std::make_shared<MyVertex>("ipsum", 456), graph);
    auto v3 = add_vertex(std::make_shared<MyVertex>("Lorem", 123), graph);

    add_edge(v1, v2, graph);
    add_edge(v1, v3, graph);

    {
        boost::dynamic_properties dp;
        auto bundle = get(boost::vertex_bundle, graph);
        dp.property("node_id", make_transform_value_property_map(std::mem_fn(&MyVertex::id), bundle));
        dp.property("label", make_transform_value_property_map(std::mem_fn(&MyVertex::label), bundle));

        write_graphviz_dp(std::cout, graph, dp);
    }
}

比较:没有共享指针

我并不是说您一定不要使用它,但是我也不确信您需要它。因此,我们将其删除,以便您看到不同之处:

Live On Coliru

#include <boost/graph/graphviz.hpp>
#include <iostream>

struct MyVertex {
    std::string label;
    int id;
    bool operator<(const MyVertex &rhs) const { return std::tie(id, label) < std::tie(rhs.id, rhs.label); }
};

using graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, MyVertex>;

int main() {
    graph_t graph;

    auto v1 = add_vertex({"Lorem", 123}, graph);
    auto v2 = add_vertex({"ipsum", 456}, graph);
    auto v3 = add_vertex({"Lorem", 123}, graph);

    add_edge(v1, v2, graph);
    add_edge(v1, v3, graph);

    boost::dynamic_properties dp;
    dp.property("node_id", boost::get(&MyVertex::id, graph));
    dp.property("label", boost::get(&MyVertex::label, graph));

    write_graphviz_dp(std::cout, graph, dp);
}

这大约是一半的代码。从这里我们可以探索如何添加所需的功能

独特性:让我们尝试一下

最简单的操作是在添加新节点之前检查现有节点:

Live On Coliru

#include <boost/graph/graphviz.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

struct MyVertex {
    std::string label;
    int id;

    auto key() const { return std::tie(id,label); }
    bool operator< (const MyVertex &rhs) const { return key() <  rhs.key(); }
    bool operator==(const MyVertex &rhs) const { return key() == rhs.key(); }
    bool operator!=(const MyVertex &rhs) const { return key() != rhs.key(); }
};

using graph_t = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, MyVertex>;

int main() {
    graph_t graph;

    auto node = [&graph](std::string name, int id) {
        for (auto&& v : boost::make_iterator_range(vertices(graph)))
            if (graph[v] == MyVertex{name, id})
                return v;
        return add_vertex({name, id}, graph);
    };

    auto v1 = node("Lorem", 123);
    auto v2 = node("ipsum", 456);
    auto v3 = node("Lorem", 123);

    assert(v3==v1);

    add_edge(v1, v2, graph);
    add_edge(v1, v3, graph);

    boost::dynamic_properties dp;
    dp.property("node_id", boost::get(&MyVertex::id, graph));
    dp.property("label", boost::get(&MyVertex::label, graph));

    write_graphviz_dp(std::cout, graph, dp);
}

注意v3现在等于v1

digraph G {
123 [label=Lorem];
456 [label=ipsum];
123->456 ;
123->123 ;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

无法使BOOST_FOREACH与我的自定义类一起使用

如何将boost :: assign与扩展STL容器的自定义容器一起使用?

iOS-将AFNetworking与自定义NSURLProtocol类一起使用

将 OpenGL VBO 与自定义类/数据结构一起使用

如何将MultiDex与自定义Application类一起使用?

将 exrtk 与自定义类的对象一起使用

将标识与自定义属性一起使用

将咖啡与自定义EditText一起使用

将SqlCommandProvider与自定义超时一起使用

将%dopar%与自定义函数一起使用

将自定义顶点着色器与THREE.Points一起使用

将自定义类与自定义模板容器一起使用

将预定义的vue.js指令与自定义指令一起使用

将ValidateScript与稍后在脚本中定义的自定义函数一起使用

在MVC / WAPI中将OAuth与自定义数据库架构一起使用

在Composer中与Packagist一起使用自定义Git存储库

C ++:如何使#define与自定义类一起使用?

NsArray ContainsObject无法与自定义NsObject类一起使用

如何使自定义类与 Python 中的“for in”循环一起使用?

将自定义 Python 类与 Django 应用程序一起使用

是否可以将await与使用自定义功能的查询一起使用

将boost odeint与std :: map和自定义向量空间代数一起使用时,没有可行的重载'='

如何将Boost.Python中的map_indexing_suite与自定义的非std对象一起使用?

将Kentor Authservices与自定义Roleprovider一起使用

将expo与RN与自定义本机模块一起使用

无法将 pkcs11-tool 与自定义 hsm 角色一起使用

将ng-option与排序和自定义文本一起使用

如何:将异步方法与LINQ自定义扩展方法一起使用

将实体的自定义字段与NSPredicate一起使用