我在reddit上看到一个post关于Euler猜想的反例。我决定自己尝试蛮力计算。
我的代码是
import numpy as np
fifths1 = np.arange(1,151)
fifths = fifths1**5
for x in fifths1:
for y in fifths1:
for z in fifths1:
for w in fifths1:
lambdas=[x,y,z,w]
if sum(np.array(lambdas)**5) in fifths:
print((x,y,z,w))
但是,代码需要很长时间,因为它会检查三重检查。
从我链接的论文中,反例是
27^5 + 84^5 + 110^5 + 113^5 = 144^5
我的代码返回
(27, 84, 110, 133)
(27, 84, 133, 110)
(27, 110, 84, 133)
(27, 110, 133, 84)
(27, 133, 84, 110)
(27, 133, 110, 84)
如何优化强力搜索,使其不会多次检查相同的情况。
答案 0 :(得分:3)
我认为NumPy在这里使用的是错误的库。
这不是一个容易以当前形式进行矢量化的问题(使用该库的最大原因),而且,循环遍历NumPy数组要比循环遍历Python列表慢得多。
每次在内循环中构造一个新的NumPy数组并使用in
检查总和(复杂度为O(n)
),也会导致性能下降。
正如其他人所说,itertools
允许您只测试四个五次幂的每个组合。使用set-membership(O(1)
复杂度)检查这些幂的总和是否也是第五次幂也将提高性能:
import itertools
fifths = [x**5 for x in range(1, 151)]
f_set = set(fifths)
[x for x in itertools.combinations(fifths, 4) if sum(x) in f_set]
快速返回:
[(14348907, 4182119424, 16105100000, 41615795893)]
然后你可以从那里恢复第五根(27, 84, 110, 133)
。
答案 1 :(得分:2)
只需使用itertools.combinations
而不是手动循环:
import itertools
for x, y, z, w in itertools.combinations(fifths, 4):
#etc.
答案 2 :(得分:1)
您可以通过计算每个循环中的当前位置并且仅在以后的循环中从该位置开始来避免多次执行该操作:
import numpy as np
fifths1 = np.arange(1,151)
fifths = fifths1**5
for i, x in enumerate(fifths1):
for j, y in enumerate(fifths1[i:]):
for k, z in enumerate(fifths1[i+j:]):
for w in fifths1[i+j+k:]:
lambdas=[x,y,z,w]
if sum(np.array(lambdas)**5) in fifths:
print((x,y,z,w))
您可以使用预先计算的**5
值来进一步加快速度:
import numpy as np
fifths1 = np.arange(1,151)
fifths = fifths1**5
fifthsall = np.vstack([fifths1, fifths]).T
for i, (x1, x) in enumerate(fifthsall):
for j, (y1, y) in enumerate(fifthsall[i:, :]):
for k, (z1, z) in enumerate(fifthsall[i+j:, :]):
for w1, w in fifthsall[i+j+k:, :]):
if x+y+z+w in fifths:
print((x1,y1,z1,w1))