首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何利用这个循环中的置换对称性?

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

Stack Overflow用户
提问于 2017-03-16 07:08:04
回答 1查看 106关注 0票数 5

我有一个标量函数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)

我正在使用它来完全填充一个4D数组。下面的代码(使用python/NumPy)可以工作:

代码语言:javascript
复制
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)

但很明显,我想利用对称性来减少这段代码的执行时间。我试过了:

代码语言:javascript
复制
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)

这会将执行时间减半。但对于最后一个对称性,我尝试了:

代码语言:javascript
复制
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]

这是可行的,但并没有给我带来接近两倍加速的另一个因素。我不认为这是正确的理由,但我看不出为什么。

在这里,我如何更好地利用这种特殊的排列对称性?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-16 08:11:29

有趣的问题!

对于N=3,应该有81个包含4个元素的组合。使用您的循环,可以创建156个。

看起来重复项的主要来源是(a >= b) or (c >= d)中的or,它太宽松了。不过,(a >= b) and (c >= d)的限制太大了。

不过,你可以比较一下a + c >= b + d。要获得几毫秒(如果有的话),您可以在第三个循环中将a + c保存为ac

代码语言:javascript
复制
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]

使用这段代码,我们创建了112个组合,因此与您的方法相比,重复的代码更少,但仍然可能会留下一些优化。

更新

下面是我用来计算创建的组合数量的代码:

代码语言:javascript
复制
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)

有了and not (a==b and c==d),这个数字就降到了88。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42822401

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档