如何根据索引计算第N个组合。 有(n+k-1)!/(k!(n-1)!)种带重复的组合。
with n=2, k=5 you get:
0|{0,0,0,0,0}
1|{0,0,0,0,1}
2|{0,0,0,1,1}
3|{0,0,1,1,1}
4|{0,1,1,1,1}
5|{1,1,1,1,1}
因此,black_magic_function(3) 应该产生 {0,0,1,1,1}。
这将要传入 GPU 着色器,所以我希望每个工作组/线程能够在不必全局存储序列的情况下,找出它们的排列子集。
with n=3, k=5 you get:
i=0, {0,0,0,0,0}
i=1, {0,0,0,0,1}
i=2, {0,0,0,0,2}
i=3, {0,0,0,1,1}
i=4, {0,0,0,1,2}
i=5, {0,0,0,2,2}
i=6, {0,0,1,1,1}
i=7, {0,0,1,1,2}
i=8, {0,0,1,2,2}
i=9, {0,0,2,2,2}
i=10, {0,1,1,1,1}
i=11, {0,1,1,1,2}
i=12, {0,1,1,2,2}
i=13, {0,1,2,2,2}
i=14, {0,2,2,2,2}
i=15, {1,1,1,1,1}
i=16, {1,1,1,1,2}
i=17, {1,1,1,2,2}
i=18, {1,1,2,2,2}
i=19, {1,2,2,2,2}
i=20, {2,2,2,2,2}
生成它的算法可以在http://www.martinbroadhurst.com/combinatorial-algorithms.html上看到,算法名称为
MBnext_multicombination
。更新:
所以我想用
(n+k-1)!/(k!(n-1)!)
替换帕斯卡三角形中的二项式系数,看看效果如何。(* Mathematica code to display pascal and other triangle *)
t1 = Table[Binomial[n, k], {n, 0, 8}, {k, 0, n}];
t2 = Table[(n + k - 1)!/(k! (n - 1)!), {n, 0, 8}, {k, 0, n}];
(*display*)
{Row[#, "\t"]} & /@ t1 // Grid
{Row[#, "\t"]} & /@ t2 // Grid
T1:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
T2:
Indeterminate
1 1
1 2 3
1 3 6 10
1 4 10 20 35
1 5 15 35 70 126
1 6 21 56 126 252 462
1 7 28 84 210 462 924 1716
1 8 36 120 330 792 1716 3432 6435
与本文开头的
n=3,k=5
的控制台输出相比较:第三条对角线{3,6,10,15,21,28,36}
给出了每个翻转点{0,0,0,1,1} -> {0,0,1,1,1} -> {0,1,1,1,1}
的索引,等等。左边的对角线似乎显示了前一个块中包含多少值(diagonal[2][i]==diagonal[3][i]-diagonal[3][i-1]
)。如果你横向阅读金字塔的第五行,你会得到递增N的最大组合数,公式为 (n+k-1)!/(k!(n-1)!)
,其中K=5
。可能有一种方法可以利用这些信息来确定任意索引的确切组合,而无需枚举整个集合,但我不确定是否需要走这么远。最初的问题只是将完整的组合空间分解成相等的子集,这些子集可以在GPU上本地生成,并通过并行处理。因此,上面的三角形给出了每个块的起始索引,其组合可以轻松地派生出来,所有连续的元素都可以逐步枚举。它还告诉我们块的大小以及总组合数。现在,问题变成将不均匀大小的块放入平均工作负载的X个线程的组中的装箱问题。