簡體   English   中英

如何在 rdkit 分子鍵圖邊緣和 BGL 雙連接組件標識符之間創建提升屬性映射?

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

rdkit 庫提供了一個分子類ROMol ,它提供了一個成員函數getTopology ,它返回一個 adjacency_list adjacency_list<vecS, vecS, undirectedS, Atom *, Bond *>類型的 BGL 圖。 我了解 rdkit 類型Bond定義了圖形的邊緣屬性。 我知道Bond提供了一個成員函數getIdx ,它返回一個唯一的整數來標識該鍵,因此該圖必須具有邊編號的概念。

要對biconnected_components使用 BGL 算法,需要一個組件屬性映射,該映射將圖形的邊緣描述符類型的對象(我理解這種類型是Bond ?)映射到組件標識整數。 由於 rdkit 不處理雙連接組件,因此我得出結論,此屬性映射必須在圖形外部。 在這種情況下,BGL 文檔建議使用iterator_property_map適配器類(參見“外部屬性”部分)。 我很難確定iterator_property_map的正確模板參數以獲取所需的屬性映射。 如果這是正確的方法,缺少的模板參數是什么?

不幸的是,在迷失在 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, ?);
}

一個需要一個組件屬性映射來映射圖形的邊緣描述符類型的對象(我知道這種類型是 Bond?)

邊緣描述符是內部描述符,有點像穩定的迭代器。 例如

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

邊緣屬性是完全獨立的概念。 您可以從邊緣描述符中獲取邊緣屬性,如下所示:

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

毫不奇怪,頂點描述符與屬性也是如此:

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

並發症

兩種描述符類型之間的一個顯着區別是 -僅因為圖形類型使用vecS作為頂點容器選擇器- 頂點描述符保證是整數,其中邊描述符是不透明的(類似於void* )。

因此,邊緣描述符不能是基於向量的屬性映射的鍵類型(因為它需要一個完整的索引器)。

而是制作一個關聯屬性映射:

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

樣本

住在科利魯

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

}

印刷

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 

高級示例

可以強制使用向量作為映射存儲,但這需要您將邊()映射到連續的整數范圍 [0..num_edges(g))。

我不能假設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);

讓我們將其應用於文檔中的圖表:

在此處輸入圖像描述

住在科利魯

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

哪個打印打印預期的映射

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

事實上,如果我們添加一點額外的魔法,我們可以渲染:

在此處輸入圖像描述

暫無
暫無

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

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