简体   繁体   English

如何利用这个循环中的置换对称性?

[英]How to exploit permutational symmetry in this loop?

I have a scalar function f(a,b,c,d) that has the following permutational symmetry 我有一个标量函数f(a,b,c,d) ,它具有以下排列对称性

f(a,b,c,d) = f(c,d,a,b) = -f(b,a,d,c) = -f(d,c,b,a)

I'm using it to fully populate a 4D array. 我用它来完全填充4D阵列。 This code (using python/NumPy) below works: 下面的代码(使用python / NumPy)有效:

A = np.zeros((N,N,N,N))
for a in range(N):
    for b in range(N):
        for c in range(N):
            for d in range(N):
                A[a,b,c,d] = f(a,b,c,d)

But obviously I'd like to exploit symmetry to cut down on the execution time of this section of code. 但显然我想利用对称性来减少这部分代码的执行时间。 I've tried: 我试过了:

A = np.zeros((N,N,N,N))
ab = 0
for a in range(N):
    for b in range(N):
        ab += 1
        cd  = 0
        for c in range(N):
            for d in range(N):
                cd += 1
                if ab >= cd:
                    A[a,b,c,d] = A[c,d,a,b] = f(a,b,c,d)

Which cuts the execution time in half. 这将执行时间缩短了一半。 But for the last symmetry I tried: 但是为了最后的对称,我尝试了:

A = np.zeros((N,N,N,N))
ab = 0
for a in range(N):
    for b in range(N):
        ab += 1
        cd  = 0
        for c in range(N):
            for d in range(N):
                cd += 1
                if ab >= cd:
                    if ((a >= b) or (c >= d)):
                        A[a,b,c,d] = A[c,d,a,b] = f(a,b,c,d)
                        A[b,a,d,c] = A[d,c,b,a] = -A[a,b,c,d]

Which works, but doesn't give me near another factor of two speed-up. 哪个有效,但不会让我接近另外两个加速的因素。 I don't think it is right for the right reasons, but can't see why. 我不认为这是正确的理由,但不明白为什么。

How can I better exploit this particular permutational symmetry here? 我怎样才能更好地利用这种特定的排列对称?

Interesting problem! 有趣的问题!

For N=3 , there should be 81 combinations with 4 elements. 对于N=3 ,应该有81个具有4个元素的组合。 With your loops, you create 156. 使用循环,您可以创建156。

It looks like the main source of duplicates is the or in (a >= b) or (c >= d) , it is too permissive. 看起来重复的主要来源是or(a >= b) or (c >= d) ,它太宽容了。 (a >= b) and (c >= d) would be too restrictive, though. (a >= b) and (c >= d)限制性太强。

You could compare a + c >= b + d , though. 但是你可以比较a + c >= b + d To gain a few ms (if anything), you could save a + c as ac inside the 3rd loop : 要获得几毫秒(如果有的话),你可以在第三个循环中保存a + c作为ac

A = np.zeros((N,N,N,N))
ab = 0
for a in range(N):
    for b in range(N):
        ab += 1
        cd  = 0
        for c in range(N):
            ac = a + c
            for d in range(N):
                cd += 1
                if (ab >= cd and ac >= b+d):
                    A[a,b,c,d] = A[c,d,a,b] = f(a,b,c,d)
                    A[b,a,d,c] = A[d,c,b,a] = -A[a,b,c,d]

With this code, we create 112 combinations, so there are less duplicates than with your method, but there might still be some optimizations left. 使用此代码,我们创建了112个组合,因此与您的方法相比,重复次数更少,但可能仍会有一些优化。

Update 更新

Here's the code I used to calculate the number of created combinations : 这是我用来计算创建组合数的代码:

from itertools import product

N = 3
ab = 0

all_combinations = set(product(range(N), repeat=4))
zeroes = ((x, x, y, y) for x, y in product(range(N), repeat=2))
calculated = list()

for a in range(N):
    for b in range(N):
        ab += 1
        cd = 0
        for c in range(N):
            ac = a + c
            for d in range(N):
                cd += 1
                if (ab >= cd and ac >= b + d) and not (a == b and c == d):
                    calculated.append((a, b, c, d))
                    calculated.append((c, d, a, b))
                    calculated.append((b, a, d, c))
                    calculated.append((d, c, b, a))

missing = all_combinations - set(calculated) - set(zeroes)

if missing:
    print "Some sets weren't calculated :"
    for s in missing:
        print s
else:
    print "All cases were covered"
    print len(calculated)

With and not (a==b and c==d) , the number is down to 88. and not (a==b and c==d) ,数字下降到88。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM