【发布时间】:2015-01-13 15:50:28
【问题描述】:
我有一些简单的代码可以执行以下操作。
它遍历所有可能长度为 n 的列表 F 和 +-1 个条目。对于每一个,它会遍历所有可能的长度 2n 列表 S 和 +-1 个条目,其中 $S$ 的前半部分只是后半部分的副本。该代码计算F 与长度为n 的每个S 子列表的内积。对于每个 F,S,它计算在第一个非零内积之前为零的内积。
这里是代码。
#!/usr/bin/python
from __future__ import division
import itertools
import operator
import math
n=14
m=n+1
def innerproduct(A, B):
assert (len(A) == len(B))
s = 0
for k in xrange(0,n):
s+=A[k]*B[k]
return s
leadingzerocounts = [0]*m
for S in itertools.product([-1,1], repeat = n):
S1 = S + S
for F in itertools.product([-1,1], repeat = n):
i = 0
while (i<m):
ip = innerproduct(F, S1[i:i+n])
if (ip == 0):
leadingzerocounts[i] +=1
i+=1
else:
break
print leadingzerocounts
n=14 的正确输出是
[56229888, 23557248, 9903104, 4160640, 1758240, 755392, 344800, 172320, 101312, 75776, 65696, 61216, 59200, 59200, 59200]
使用 pypy,对于 n = 14,这需要 1 分 18 秒。不幸的是,我真的很想运行 16、18、20、22、24、26。我不介意使用 numba 或 cython,但如果可能的话,我想靠近 python。
非常感谢任何帮助加快这一进程。
我会在这里记录最快的解决方案。 (如果我错过了更新的答案,请告诉我。)
- n = 22,时间为 9 分 35.081 秒,由 Eisenstat (C) 得出
- n = 18 在 1m16.344s 由 Eisenstat (pypy) 提供
- n = 18 在 2m54.998s 由 Tupteq (pypy) 提供
- n = 14 at 26s by Neil (numpy)
- n - 14 在 11m59.192s by kslote1 (pypy)
【问题讨论】:
-
你试过使用 Numpy 多维数组吗?
-
可能没有机会添加代码,但请注意
IP(A,B) = IP(A[:n/2 + 1], B[:n/2 + 1]) + IP(A[n/2 + 1:], B[n/2 + 1:])允许基于subset sum 使用的类似技术进行一些改进。这应该允许O(2^N)算法而不是O(2^(2N)),尽管它可能需要O(2^N)空间。这利用查找大小为N/2(其中有O(2^N)))对的所有IP,然后使用它来构建解决方案集。可以使用图表来处理在while循环中找到的状态转换。 -
经过一番测试,上面的方法可能不太实用。处理状态转换的问题似乎需要分支,这会引入先前已消除的数字以及重复的数字。基本上,我写的算法给出了第二个(i = 2及以上)之后的错误计数,并且简单地删除重复项并不足以修复它,尽管它有很大帮助,这表明这种方法可能存在缺陷,就获得 O( 2^N) 空间/时间性能。
-
@Nuclearman 我不得不承认这令人惊讶。
-
无论如何,您都可以自己尝试。 IP 匹配部分非常简单,并且对于获得第一个计数非常快。这是我无法正确处理班次的批处理,如果可能的话,我会质疑。我可能不会尝试实现算法的正确解决方案,因为没有它是
O(2^N),我认为这不太可能,它很有可能不会比 David Eisenstat 的答案更好。
标签: python performance algorithm cython numba