是否有一个Python相当于在Perl中解除引用?

时间:2014-12-27 20:00:34

标签: python perl numpy reference runtime

我目前正在将代码库移植到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 =<铌。我只提到这一点,因为在一般情况下无效的特殊情况可以进行优化,但任何建议都会有所帮助。

1 个答案:

答案 0 :(得分:3)

使用numpy,您可以按如下方式对整个代码进行矢量化,假设adj_matrixmapping是numpy数组:

def equate():
    row1 = adj_matrix[:row]
    row2 = adj_matrix[mapping[:row]]
    return np.all(row1 == row2)

如果发现不匹配,它不会在循环早期爆发,但除非你的阵列很大,否则NumPy的速度将占主导地位。