您可以编写一个更快的 brute-force 实现。
首先,您可以通过处理大量排列来使用矩阵乘法,而不是许多点积。矩阵乘法内核经过高度优化,因此比许多点积运行得更快。
此外,您可以部分地预先计算排列,通过将排列分成两部分来进一步加快计算速度。这个想法是首先建立一个索引,其中包含包含在 12 个元素中选择 5 个元素的所有排列。然后,这个想法是找到一个包含 7 个项目的数组的所有排列(索引而不是值本身)。最后,所有排列都可以从两个索引构建。
请注意,当上述两种优化一起应用时,可能会进一步优化:如果一个排列的一部分是常数,则可以更有效地计算矩阵乘法。
生成的算法很复杂,但比原始算法更有效。代码如下:
def computeOptim(A):
mini = 1000000
permValues = np.array([2433, 2057, 1935, 1927, 1870, 1841, 1818, 1770, 1680, 1497, 1435, 1289])
# Precompute partial permutations: high and low part of all the permutations.
loPerms = np.array(list(itertools.permutations(range(7))))
hiPerms = np.array(list(itertools.permutations(range(12), 5)))
# Iterate over chunks (of 7!=5040 permutations)
for hiPerm in hiPerms:
# Find the remaining index to include in the low-part permutations
loPermIndices = np.array(list(set(range(12))-set(hiPerm)))
# Find all the possible low-part permutations for the current
# high-part permutation by reindexing the values.
curLoPerms = loPermIndices[loPerms]
# Compute the chunks of possible x values
loPermValues = permValues[curLoPerms]
hiPermValues = permValues[hiPerm]
# A matrix multiplcation is used to compute many dot product in a row.
# Compute effciently B = A @ X with X the matrix containing all the permutations
hiB = A[:,:len(hiPermValues)] @ hiPermValues[None,:].T
loB = A[:,len(hiPermValues):] @ loPermValues.T
B = hiB + loB
multiCur = np.std(B, axis=0)
minPos = np.argmin(multiCur)
if multiCur[0,minPos] < mini:
mini = multiCur[0,minPos]
res = np.concatenate((hiPermValues, loPermValues[minPos]))
A = np.matrix('0,3,1,2,2,2,2,2,2,1,2,2;3,0,3,1,2,3,1,1,2,2,1,2;1,3,0,2,2,2,2,2,2,1,2,2;2,1,2,0,2,1,2,2,2,2,3,2;2,2,2,2,0,2,1,2,2,3,2,1;2,3,2,1,2,0,3,2,1,2,1,2;2,1,2,2,1,3,0,2,1,1,3,3;2,1,2,2,2,2,2,0,3,2,2,1;2,2,2,2,2,1,1,3,0,3,1,2;1,2,1,2,3,2,1,2,3,0,2,2;2,1,2,3,2,1,3,2,1,2,0,2;2,2,2,2,1,2,3,1,2,2,2,0')
computeOptim(A)
在我的机器上,它在 50 秒内成功找到了最佳解决方案,而原始代码大约需要 5h30。因此,这段代码的速度快了大约 400。
找到的最优解是:
mini = 291.80729942892106
res = [2433 1841 1289 1818 2057 1927 1770 1870 1497 1680 1935 1435]