简体   繁体   English

如何在 rdkit 分子键图边缘和 BGL 双连接组件标识符之间创建提升属性映射?

[英]How to create a boost property map between rdkit molecular bond graph edges and BGL biconnected component identifiers?

The rdkit library provides a molecule class ROMol that provides a member function getTopology that returns a BGL graph of type adjacency_list<vecS, vecS, undirectedS, Atom *, Bond *> . rdkit 库提供了一个分子类ROMol ,它提供了一个成员函数getTopology ,它返回一个 adjacency_list adjacency_list<vecS, vecS, undirectedS, Atom *, Bond *>类型的 BGL 图。 I understand that the rdkit typeBond defines the edge properties of the graph.我了解 rdkit 类型Bond定义了图形的边缘属性。 I know that Bond provides a member function getIdx that returns a unique integer identifying the bond, so the graph must have a notion of edge numbering.我知道Bond提供了一个成员函数getIdx ,它返回一个唯一的整数来标识该键,因此该图必须具有边编号的概念。

To make use of the BGL algorithm for biconnected_components one requires a component property map that maps objects of the edge descriptor type of the graph (I understand this type is Bond ?) to component identifying integers.要对biconnected_components使用 BGL 算法,需要一个组件属性映射,该映射将图形的边缘描述符类型的对象(我理解这种类型是Bond ?)映射到组件标识整数。 As rdkit does not deal in biconnected components, I conclude this property map must be exterior to the graph.由于 rdkit 不处理双连接组件,因此我得出结论,此属性映射必须在图形外部。 In this case, the BGL documentation suggests to use the iterator_property_map adaptor class (see section "Exterior Properties").在这种情况下,BGL 文档建议使用iterator_property_map适配器类(参见“外部属性”部分)。 I struggle to determine the correct template arguments for iterator_property_map to get the required property map.我很难确定iterator_property_map的正确模板参数以获取所需的属性映射。 If this is the correct approach what are the missing template arguments?如果这是正确的方法,缺少的模板参数是什么?

Unfortunately I did not get very far with my code before getting lost in the BGL documentation:不幸的是,在迷失在 BGL 文档之前,我的代码并没有走得太远:

void my_function(const RDKit::ROMol& molecule) {
 const RDKit::MolGraph& molecule_graph{molecule.getTopology()};

  using EdgesSize =
      boost::graph_traits<RDKit::MolGraph>::edges_size_type; // map value type
  using Edge =
      boost::graph_traits<RDKit::MolGraph>::edge_descriptor; // map key type

  std::vector<EdgesSize> component_map(boost::num_edges(molecule_graph)
  ); // range, begin() yields random access iterator

  // boost::iterator_property_map<?>;
  // boost::biconnected_components(molecule_graph, ?);
}

one requires a component property map that maps objects of the edge descriptor type of the graph (I understand this type is Bond?)一个需要一个组件属性映射来映射图形的边缘描述符类型的对象(我知道这种类型是 Bond?)

Edge descriptors are internal descriptors, sort of like stable iterators.边缘描述符是内部描述符,有点像稳定的迭代器。 Eg例如

 edge_descriptor e = *edges(g).begin();

Edge properties are entirely separate notions.边缘属性是完全独立的概念。 You get the edge properties from an edge descriptor like so:您可以从边缘描述符中获取边缘属性,如下所示:

 Bond* e_props = g[e]; // equivalent to:
 e_props = get(boost::edge_bundle, g, e);

Unsurprisingly the same goes for vertex descriptors vs. properties:毫不奇怪,顶点描述符与属性也是如此:

  Atom* first_a_prop = g[vertex(0, g)];

The Complication并发症

A notable difference between the two descriptor types is that - only because the graph type is using vecS as the vertex container selector - the vertex descriptor is guaranteed to be integral, where edge descriptor is opaque (similar to a void* ).两种描述符类型之间的一个显着区别是 -仅因为图形类型使用vecS作为顶点容器选择器- 顶点描述符保证是整数,其中边描述符是不透明的(类似于void* )。

Hence, the edge-decriptor cannot be the key type to a vector-based property map (because it would require an integral indexer).因此,边缘描述符不能是基于向量的属性映射的键类型(因为它需要一个完整的索引器)。

Instead make an associative property-map:而是制作一个关联属性映射:

// OUT: ComponentMap c
// must be a model of Writable Property Map. The value type should be
// an integer type, preferably the same as the edges_size_type of the
// graph. The key type must be the graph's edge descriptor type.
std::map<edge_descriptor, int> component_map;
auto c = boost::make_assoc_property_map(component_map);

Sample样本

Live On Coliru住在科利鲁

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/biconnected_components.hpp>
#include <iostream>

struct Atom {
};

struct Bond {
    int idx_ = 42;
    int getIdx() const { return idx_; }
};

using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Atom*, Bond*>;
using vertex_descriptor = G::vertex_descriptor;
using edge_descriptor   = G::edge_descriptor;

int main() {
    std::array<Atom, 4> atoms;
    std::array<Bond, 2> bonds{Bond{111}, Bond{222}};

    G g;
    add_vertex(atoms.data()+0, g);
    add_vertex(atoms.data()+1, g);
    add_vertex(atoms.data()+2, g);
    add_vertex(atoms.data()+3, g);

    // using the fact that vertex_descriptor is 0..3 here:
    add_edge(0, 2, bonds.data()+0, g);
    add_edge(2, 3, bonds.data()+1, g);

    {
        // OUT: ComponentMap c
        // must be a model of Writable Property Map. The value type should be
        // an integer type, preferably the same as the edges_size_type of the
        // graph. The key type must be the graph's edge descriptor type.
        std::map<edge_descriptor, int> component_map;
        auto c = boost::make_assoc_property_map(component_map);

        // Now use it:
        size_t n = boost::biconnected_components(g, c);
        for (auto [e, component_id] : component_map) {
            std::cout << "Edge " << e << " (idx:" << g[e]->getIdx()
                      << ") mapped to component " << component_id << " out of "
                      << n << "\n";
        }
    }

    {
        std::map<edge_descriptor, int> component_map;
        auto c = boost::make_assoc_property_map(component_map);

        // also writing articulation points:
        [[maybe_unused]] auto [n, out] = boost::biconnected_components(
            g, c,
            std::ostream_iterator<vertex_descriptor>(
                std::cout << "articulation points: ", " "));

        std::cout << "\n";
    }

}

Prints印刷

Edge (0,2) (idx:111) mapped to component 1 out of 2
Edge (2,3) (idx:222) mapped to component 0 out of 2
articulation points: 2 

Advanced Example高级示例

You can force a vector as mapping storage, but that requires you to map the edges ( bonds ) to a contiguous integral range [0..num_edges(g)).可以强制使用向量作为映射存储,但这需要您将边()映射到连续的整数范围 [0..num_edges(g))。

I couldn't assume that getIdx() satisfies the criterion, but if it did:我不能假设getIdx()满足标准,但如果满足:

// first map edges to 0..num_edges using getIdx
auto edge_index = boost::make_function_property_map<edge_descriptor>(
    [&g](edge_descriptor e) { return g[e]->getIdx(); });

// provide num_edges storage for component-ids:
std::vector<int> component_ids(num_edges(g));

// project the vector through edge_index to make a Writable Property
// Map indexed by edge_descriptor;
auto c = boost::make_safe_iterator_property_map(component_ids.begin(),
        component_ids.size(), edge_index);

Let's apply it to the graph from the documentation :让我们将其应用于文档中的图表:

在此处输入图像描述

Live On Coliru住在科利鲁

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/biconnected_components.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <iostream>

enum letter : char { A, B, C, D, E, F, G, H, I };
struct Atom {
    Atom(letter) {}
};

struct Bond {
    int idx_;
    int getIdx() const { return idx_; }
};

using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Atom*, Bond*>;
using vertex_descriptor = Graph::vertex_descriptor;
using edge_descriptor   = Graph::edge_descriptor;

int main() {
    std::array<Atom, 9>  atoms{A, B, C, D, E, F, G, H, I};
    std::array<Bond, 11> bonds{
        {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}}};

    Graph g;
    for (auto& atom : atoms)
        add_vertex(&atom, g);

    // using the fact that vertex_descriptor is vertex index:
    add_edge(A, B, &bonds.at(0), g);
    add_edge(A, F, &bonds.at(1), g);
    add_edge(A, G, &bonds.at(2), g);
    add_edge(B, C, &bonds.at(3), g);
    add_edge(B, D, &bonds.at(4), g);
    add_edge(B, E, &bonds.at(5), g);
    add_edge(C, D, &bonds.at(6), g);
    add_edge(E, F, &bonds.at(7), g);
    add_edge(G, H, &bonds.at(8), g);
    add_edge(G, I, &bonds.at(9), g);
    add_edge(H, I, &bonds.at(10), g);

    // OUT: ComponentMap c
    // must be a model of Writable Property Map. The value type should be
    // an integer type, preferably the same as the edges_size_type of the
    // graph. The key type must be the graph's edge descriptor type.

    // first map edges to 0..10 using getIdx
    auto edge_index = boost::make_function_property_map<edge_descriptor>(
            [&g](edge_descriptor e) { return g[e]->getIdx(); });

    // provide num_edges storage for component-ids:
    std::vector<int> component_ids(num_edges(g));

    // project the vector through edge_index to make a Writable Property
    // Map indexed by edge_descriptor;
    auto c = boost::make_safe_iterator_property_map(component_ids.begin(),
            component_ids.size(), edge_index);

    // Now use it:
    size_t n = boost::biconnected_components(g, c);

    for (auto e : boost::make_iterator_range(edges(g))) {
        // edge_index or getIdx, equivalent here:
        assert(edge_index[e] == g[e]->getIdx());

        auto idx =edge_index[e];
        auto cid = component_ids.at(idx);

        std::cout << "Edge " << e << " (idx:" << idx << ") mapped to component "
                  << cid << " out of " << n << "\n";
    }
}

Which prints prints the expected mapping哪个打印打印预期的映射

Edge (0,1) (idx:0) mapped to component 1 out of 4
Edge (0,5) (idx:1) mapped to component 1 out of 4
Edge (0,6) (idx:2) mapped to component 3 out of 4
Edge (1,2) (idx:3) mapped to component 0 out of 4
Edge (1,3) (idx:4) mapped to component 0 out of 4
Edge (1,4) (idx:5) mapped to component 1 out of 4
Edge (2,3) (idx:6) mapped to component 0 out of 4
Edge (4,5) (idx:7) mapped to component 1 out of 4
Edge (6,7) (idx:8) mapped to component 2 out of 4
Edge (6,8) (idx:9) mapped to component 2 out of 4
Edge (7,8) (idx:10) mapped to component 2 out of 4

In fact, if we add a little bit of bonus wizardry , we can render that:事实上,如果我们添加一点额外的魔法,我们可以渲染:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM