我可以使用一种更优雅/更优化的方法来制作此连接算法吗?

时间:2019-02-17 10:49:05

标签: python algorithm list numpy

我制定了一种算法,可以从一个原子列表(给出它们彼此之间的距离)中找出一个分子中连接的原子。在物理环境之外考虑这个问题,它只是一个封闭的网络问题,其中节点是原子,而边是连接原子的原子键。我有一个节点列表,以及一个连接这些节点的边的列表,我需要找出每个唯一分子的列表。我已经在下面的代码中做到了这一点,但是它有点慢而且很丑陋。有没有优化此算法的方法?

这是我的代码有效,并为您提供了相关信息(我将提供另一个原子列表尝试进行操作,命名为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]]

因此,在上面,我给出了我现在应该获得的输出-使此代码更好的任何想法将不胜感激。

2 个答案:

答案 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}]

Graph

这是我的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。