围绕Boost图库中的捆绑属性进行设计

Designing around bundled properties in the Boost Graph Library

本文关键字:属性 Boost 围绕      更新时间:2023-10-16

我正在将一些图形代码从Python(networkx)移植到C++(BGL)中。在我的Python代码中,图的顶点和边是实现已建立接口的客户端定义对象;我接着对它们调用了一堆方法。一切都很好。

简单地说,BGL似乎是为了支持具有"捆绑属性"的类似设计模式。这些基本上允许通过传递某些模板参数来定义顶点和边的自定义类型:

adjacency_list<OutEdgeList, VertexList,
Directed, VertexProperties,
EdgeProperties, GraphProperties,
EdgeList>

这里的自定义顶点和边类型由VertexPropertiesEdgeProperties给出。

在这个端口上工作时,我注意到有几件事让我认为,也许BGL的捆绑属性接口实际上只是为了支持(或多或少)不可变类型:

  • 边缘和顶点"描述符">

    如果你把一些东西放进图中,你会得到一个"描述符",从那时起你必须用它来引用它。边和顶点都有描述符,它们是图的"键"——实现为免疫表。因此,如果你有一个顶点,并且你想找到相邻的顶点,你必须(a)获得当前的顶点描述符,(b)使用BGL方法找到它的邻居的描述符,最后(c)通过它们各自的描述符引用每个邻居。

    所有这些记账的最终结果是,显然需要额外的容器——比如std::map——来提供从顶点和边(同样是类型VertexPropertyEdgeProperty)到其描述符的反向查找。

  • "BGL不是用来存储指针的。">

    我在一个类似的SO问题中发现了这一说法,但在任何地方的Boost文档中都无法验证。从接下来的讨论中,我只能推测约束实际上可能有点强:"BGL并不意味着直接引用堆。"不过,这似乎并不完全合理,因为容器类型是可配置的(上面的OutEdgeListVertexList),并且是默认的标准,如向量。

我是BGL n00b,很难理解捆绑属性的意图。(坦率地说,我对编程模型感到有点不知所措——"属性"、"概念"、"特征"、"描述符",AHHHH!)问题:

  1. BGL图是否有效地支持VertexPropertyEdgeProperty的复杂且可能是堆绑定类型?或者这些是不可变数据的轻量级容器?

  2. 如果是前者,有没有办法绕过所有的描述符记账?

  3. 如果是后者,处理我们可能想留在BGL图中的大型复杂事物的"正确方法"是什么?

  1. BGL图是否有效地支持VertexProperty和EdgeProperty的复杂且可能是堆绑定类型?或者这些是不可变数据的轻量级容器

当然。你可以做任何你想做的事。案例说明:您可以使bundle包含一个(不可变或可变)指针,指向堆分配的"复杂"类型,当然,该类型是完全可变的。现在,

我建议使用您喜欢的所有权适配器(unique_ptr、scoped_ptr、shared_ptr等等)。看看std::string:它也是"基于堆的",但您从未担心在属性捆绑包中使用它,是吗?

  1. 如果是前者,有没有办法绕过所有的描述符记账

没有严格意义上的"描述符记账"。其中可能取决于图形模型。但一般来说,描述符实际上是底层容器迭代器模型的抽象(并不是说这可以是跨多个容器的迭代器,例如edges(EdgeListgraph),而不是adjacency_list<>out_edges(v, IncidenceGraph)

重点是将逻辑与关于存储模型的假设解耦。即使传递了一些非常难看的void*,编译器也应该将其编译为与直接迭代器访问相同的代码。从这个意义上说,"记账"通常是感性的,你很可能会因为有额外的概念层而承受心理负担。

  • 如果是后者,处理我们可能想保留在BGL图中的大型复杂事物的"正确方法"是什么
  • 糟糕。我想我不小心在1下解决了这个问题。使用最简单的方法可能是引用计数共享。您的具体情况可能会提供更有效的解决方案。


    CAPITA SELECTA

    • "BGL不是用来存储指针的。">

    好吧,也许不是捆绑的。即使在这里,它也完全取决于您如何管理指针对象的所有权/生存期。

    我认为关联的答案非常好。这与我上面所说的产生了共鸣。

    • 所以,如果你有一个顶点,并且你想找到相邻的顶点,你必须(a)获得当前的顶点描述符,(b)使用BGL方法找到它的邻居的描述符,最后(c)通过它们各自的描述符引用每个邻居

    大多数BGL算法都依赖于vertex_index_t属性的存在(或需要指定一个属性作为参数)来确保这些操作是低成本的。事实上,如果使用vecS,那么顶点索引就是顶点向量的索引,因此反向和正向查找非常简单。(您可以随时查看启用了优化的生成程序集,以查看是否有任何意外)。

    这个答案可能很鼓舞人心:Boost图库:是否可以将捆绑属性与内部属性相结合?


    TL;DR/摘要

    我有一种来自Python的感觉,你可能低估了C++在模板密集的通用库代码中优化编译器,这是可以理解的。

    当你在实践中筛选通用机器的层时,出现的气泡会在编译时蒸发。当然,这样做的缺点是很难看穿抽象。但这也意味着权力和抽象级别不会受到损害。

    BGL是一个库,允许您切换到完全不同的图形模型、存储布局等,只需很少的代码更改。这里的目标不是"易用性"或"照我的意思做"(为此使用Java或python)。

    目标是通过将每一个实现细节硬编码到整个代码库中,来选择C++/不/消除所有灵活性。相反,在库概念的层面上工作,并随着需求的发展,从您保留的试验/更改方法的自由中受益。