我制定了一种算法,可以从一个原子列表(给出它们彼此之间的距离)中找出一个分子中连接的原子。在物理环境之外考虑这个问题,它只是一个封闭的网络问题,其中节点是原子,而边是连接原子的原子键。我有一个节点列表,以及一个连接这些节点的边的列表,我需要找出每个唯一分子的列表。我已经在下面的代码中做到了这一点,但是它有点慢而且很丑陋。有没有优化此算法的方法?
这是我的代码有效,并为您提供了相关信息(我将提供另一个原子列表尝试进行操作,命名为pair_1和selected_atom_1,只需将pair_1更改为pairs,然后将selected_atom_1更改为selected_atom即可正常工作) / p>
pairs = [[0, 1],
[0, 2],
[3, 4],
[3, 5],
[6, 7],
[6, 8],
[9, 10],
[9, 11],
[12, 13],
[12, 14],
[15, 16],
[15, 17],
[18, 19],
[18, 20],
[21, 22],
[21, 23],
[24, 25],
[24, 26],
[27, 28],
[27, 29],
[30, 31],
[30, 32],
[33, 34],
[33, 35],
[36, 37],
[36, 38],
[39, 40],
[39, 41],
[42, 43],
[42, 44],
[45, 46],
[45, 47]]
chosen_atom = [np.random.rand() for i in range(48)]
pairs_1 = [[0, 6],
[1, 7],
[2, 8],
[3, 9],
[4, 10],
[5, 6],
[5, 10],
[6, 7],
[7, 8],
[8, 9],
[9, 10]]
chosen_atom_1 = [np.random.rand() for i in range(11)]
# use list of lists to define unique molecules
molecule_list = []
for i in pairs:
temp_array = []
for ii in pairs:
temp_pair = [i[0], i[1]]
if temp_pair[0] == ii[0]:
temp_array.append(ii[1])
temp_array = set(temp_array)
temp_array = list(temp_array)
if temp_pair[1] == ii[1]:
temp_array.append(ii[0])
temp_array = set(temp_array)
temp_array = list(temp_array)
for iii in temp_array:
for j in pairs:
if iii == j[0]:
temp_array.append(j[1])
temp_array = set(temp_array)
temp_array = list(temp_array)
if iii == j[1]:
temp_array.append(j[0])
temp_array = set(temp_array)
temp_array = list(temp_array)
if len(temp_array) > len(chosen_atom):
break
molecule_list.append(temp_array)
molecule_list = [list(item) for item in set(tuple(row) for row in molecule_list)]
# the output of pairs should be
molecule_list = [[8, 6, 7],
[27, 28, 29],
[9, 10, 11],
[0, 1, 2],
[32, 30, 31],
[18, 19, 20],
[45, 46, 47],
[33, 34, 35],
[24, 25, 26],
[42, 43, 44],
[16, 17, 15],
[12, 13, 14],
[21, 22, 23],
[3, 4, 5],
[40, 41, 39],
[36, 37, 38]]
# the output of pairs_1 should be:
molecule_list = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
因此,在上面,我给出了我现在应该获得的输出-使此代码更好的任何想法将不胜感激。
答案 0 :(得分:3)
正如我在评论中所说,您需要连接组件算法,并且可以使用networkx
包轻松解决它:
import networkx as nx
G = nx.from_edgelist(pairs)
print([i for i in nx.connected_components(G)])
# jupyter notebook
%matplotlib inline
nx.draw(G, with_labels=True)
输出:
[{0, 1, 2}, {3, 4, 5}, {8, 6, 7}, {9, 10, 11}, {12, 13, 14}, {16, 17, 15}, {18, 19, 20}, {21, 22, 23}, {24, 25, 26}, {27, 28, 29}, {32, 30, 31}, {33, 34, 35}, {36, 37, 38}, {40, 41, 39}, {42, 43, 44}, {45, 46, 47}]
这是我的script,用于根据原子坐标构建和可视化分子图。
答案 1 :(得分:2)
这可以使用“联合查找”方法解决。
将每个原子的链接关联到同一分子中的另一个原子。链接可能无效。如果没有,它将导致另一个具有自身链接的原子。递归地遵循这些链接,您最终将到达一个具有无效链接的原子。我们称它为分子中的 main 原子。
该算法的工作原理如下:
依次轮流使用每个边缘,让a-b;
找到a的主原子,让main(a);
将main(a)链接到b,以将它们重新组合到同一分子中。
这样做,main(a)与main(b)相同,最后,给定分子的所有原子都具有相同的main。
第一次通过之后,您可以对原子进行一次遍历以枚举对应于不同分子的主干。
您还可以添加第三遍,以重新组织链接,以便每个主对象都将从该分子的所有原子开始一个链表。
变量和优化:
您可以将其链接到main(b)而不是将main(a)链接到b;
在查找main(a)时,可以将所有原子重新链接到main(a);这缩短了以后的搜索路径;
如果您还存储从a到main(a)的路径长度,则可以选择将main(a)附加到main(b)或将main(b)附加到main(a);
您可以让它自己链接,而不是让主原子链接到void。