我目前正在将代码库移植到Python中,我最初是在Perl中实现的。当我在整个数据集上运行时,以下短代码占据了重要运行时的大约90%。
def equate():
for i in range(row):
for j in range(row):
if adj_matrix[i][j] != adj_matrix[mapping[i]][mapping[j]]:
return False
return True
其中equate是另一个方法内的闭包,row是整数,adj_matrix是表示矩阵的列表列表,mapping是表示向量的列表。
等效的Perl代码如下:
sub equate
{
for ( 0..$row)
{
my ($smrow, $omrow) = ($$adj_matrix[$_], $$adj_matrix[$$mapping[$_]]); #DEREF LINE
for (0..$row)
{
return 0 if $$smrow[$_] != $$omrow[$$mapping[$_]];
}
}
return 1;
}
这被封装为外部子例程中的子引用,因此我不必将变量传递给子例程。
简而言之,Perl版本要快得多,我的测试表明它是由于“DEREF LINE”中的解除引用。我已经尝试过我认为相当于Python的东西:
def equate():
for i in range(row):
row1 = adj_matrix[i]
row2 = adj_matrix[mapping[i]]
for j in range(row):
if row1[j] != row2[mapping[j]]:
return False
return True
但这是一个微不足道的改进。另外,我尝试使用NumPy矩阵来表示adj_matrix,但这又是一个很小的改进,可能是因为adj_matrix通常是一个小矩阵,所以NumPy的开销要大得多,而且我实际上并没有做任何矩阵数学操作
我欢迎任何改进Python equate
方法的运行时的建议,并解释为什么我的“改进的”Python equate
方法不是更好。虽然我认为自己是一名称职的Perl程序员,但我是一名Python新手。
其他细节:
我使用的是Python 3.4,尽管我最初在2.7中实现了类似的行为。因为我工作的实验室使用3.4,所以我切换到3.4。
关于向量的内容,请允许我提供一些背景,以便以下细节有意义。这是识别分别由图A和B表示的两种化合物(a和b)之间的子图同构的算法的一部分,其中每个原子是节点并且每个键合是边缘。上面的代码是针对简化的情况,其中A = B,所以我正在寻找化合物的对称变换(对称平面),并且原子数中A的大小是N.每个原子被分配一个唯一的索引,从零。
映射是维度为1xN的一维向量,其中映射中的每个元素都是整数。 mapping[i] = j
表示具有索引i的原子(将称为原子i或通常原子'索引')当前映射到原子j。没有映射由j = -1表示。
Adj_matrix是尺寸为NxN的2D矩阵,其中每个元素adj_matrix [i] [j] = k是自然数,并且表示化合物A中原子i和j之间的边缘的存在和顺序。如果k = 0,没有这样的边缘(在i和j之间没有AKA)否则k> 0和k表示原子i和j之间键的顺序。
当A!= B时,有两个不同的adj_matrices在equate
中进行比较,原子中a和b的大小是Na和Nb。 Na不必等于Nb,但Na =<铌。我只提到这一点,因为在一般情况下无效的特殊情况可以进行优化,但任何建议都会有所帮助。
答案 0 :(得分:3)
使用numpy,您可以按如下方式对整个代码进行矢量化,假设adj_matrix
和mapping
是numpy数组:
def equate():
row1 = adj_matrix[:row]
row2 = adj_matrix[mapping[:row]]
return np.all(row1 == row2)
如果发现不匹配,它不会在循环早期爆发,但除非你的阵列很大,否则NumPy的速度将占主导地位。