[英]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.