如何在块中生成组合

时间:2017-10-08 19:22:26

标签: algorithm combinations

我有算法,可以对输入元素的每个组合执行计算,例如对于100个元素集中的每个5元素子集。我将它移植到GPU,现在我准备好它的初始版本。为了加快速度,我想从本地内存加载数据,这是有限的(例如32KB)并且可以容纳20个输入元素中的100个。所以我必须以某种方式对我的工作进行分区并以块的形式生成组合。现在这是困难的部分,如何做到这一点。最有可能的是,我必须先为20个元素加载数据,然后对这20个元素的5个元素子集进行计算。在此之后,我将不得不用新的替换它们中的一些(或全部)并对它们进行计算,然后冲洗并重复。你能告诉我如何在本地内存中选择替换元素,以避免重复工作?到目前为止,我得出结论,我必须立即更换至少16个,以避免重复的工作问题。

编辑:这里是从5个元素中生成2元素组合的示例。以下是所有可能案例的完整列表:

1, 2
1, 3
1, 4
1, 5
2, 3
2, 4
2, 5
3, 4
3, 5
4, 5

GPU上的本地内存有限 - 假设它只能容纳3个元素。因此,我必须以某种方式将我的问题分成3个元素中的2个元素的组合。我必须重复多次,直到我从上面的列表中获得所有组合。作为第一步,我可以将元素1,2,3加载到本地内存中,因此我将得到以下组合:

1, 2
1, 3
2, 3

现在我必须加载另一组元素并为它们计算组合。它可以是1,4,5。它将产生以下组合:

1, 4
1, 5
4, 5

另一方面,设置1,2,4无效 - 这将导致重复组合:

1, 2 // duplicate
1, 4 // ok, new
2, 4 // ok, new

在此步骤之后,还有4个组合要生成(列表如下)。算法必须能够从3个元素中生成另一个2元素组合,并以某种方式处理最后(第10个)组合。

2, 4
2, 5
3, 4
3, 5

通过以这种方式分割工作,我将能够使用有限的本地存储器处理原始输入集的所有组合,该存储器只能容纳其中的一部分。

2 个答案:

答案 0 :(得分:3)

说,例如你有100个元素,你可以在内存中保存20个,你需要所有5个元素的组合,其中有C(100,5)= 75,287,520。

为了能够生成所有组合,5个元素的每个组合必须在某个时刻存在于内存中。这可以通过将元素分成20/5 = 4个元素的组来完成;输入中有25个这样的组,5个组的C(25,5)= 53,130个组合。

对于每个组的组合,我们将首先从五组中的每一组生成一个元素的组合;这给了我们53,130 x 4 5 = 54,405,120个独特的组合。

我们现在有了组合,其中每个元素来自不同的组,即分区[1,1,1,1,1]。我们仍然必须找到分区[2,1,1,1],[2,2,1],[3,1,1],[3,2]和[4,1]的组合。最简单的方法是在单独的阶段做到这一点,但最快的方法当然是将这些纳入[1,1,1,1,1]的第一阶段,因为我们所有的组合都是如此。在第一阶段的某个时刻,需要将内存加载到内存中。

对于分区[2,1,1,1],我们依次将每个组加载为具有2个元素的组,然后从剩余的24个组中加载3个组的每个组合并取一个元素来自他们每个人。这将需要25×C(24,3)= 50,600步,每次产生C(4,2)×4 3 = 384组合,或总共19,430,400。

像[2,2,1]这样的分区有点不同,因为我们依次将每个组加载为第一个包含2个元素的组,但只有作为第二个组后面的组才会加载有2个元素,以避免重复。然后,对于其中的每一个,我们将加载其他23个组中的每一个以获得最终元素。这将需要C(25,2)/ 2×23 = 6,900步,每个步骤产生C(4,2)×C(4,2)×C(4,1)= 144组合,总共993,600。

分区[3,1,1]需要25 x C(24,2)= 25 x 276 = 6,900步,每个步长为C(4,3)x 4 2 = 64组合,总计441,600。

分区[3,2]需要25 x 24 = 600步,每个步骤产生C(4,3)x C(4,2)= 24个组合,总共14,400。

分区[4,1]需要25×24 = 600步,每个步骤得到C(4,4)×C(4,1)= 4个组合,总共2,400个。

所以我们共有:

[1,1,1,1,1] -> 54,405,120
[2,1,1,1]   -> 19,430,400
[2,2,1]     ->    993,600
[3,1,1]     ->    441,600
[3,2]       ->     14,400
[4,1]       ->      2,400
               ----------
               75,287,520 combinations

正如您所注意到的,分区[3,2]和[4,1]都需要两组的每个组合,因此它们可以轻松集成到一个阶段中。当然,如果将它们全部集成到[1,1,1,1,1]的第一阶段,您只需要将53,130组的组合加载到内存中,这是绝对最小值。

(如果在每一步中只将一组新元素加载到内存中,而不是按字典顺序运行组的组合,请查看this answer。)

整合不同阶段

运行分区[1,1,1,1,1]的所有组合的最简单方法是将组1到21加载为组A,然后将A组之后的所有组加载到22组作为组B, B组后各组最多23组为C组,C组后各组最多为24组,D组后最多25组为E组。

 A  B  C  D  E
 1  2  3  4  5    <- ABCDE
 1  2  3  4  6    <- ABCDE
...
 1  2  3  4 25    <- ABCDE
 1  2  3  5  6    <- ABCDE
...
 1  2  3 24 25    <- ABCDE
 1  2  4  5  6    <- ABCDE
...
 1  2 23 24 25    <- ABCDE
 1  3  4  5  6    <- ABCDE
...
 1 22 23 24 25    <- ABCDE
 2  3  4  5  6    <- ABCDE
...
21 22 23 24 25    <- ABCDE

可以通过[2,1,1,1],[1,2,1,1],[1,1,2,1]和[1,1,1]来整合具有四个部分的分区。 2]来自这四组组合的元素:

 A  B  C  D  E
 1  2  3  4  5    <- ABCD ABCE ABDE ACDE BCDE
 1  2  3  4  6    <- ABCE ABDE ACDE BCDE
 ...        
 1  2  3  4 25    <- ABCE ABDE ACDE BCDE
 1  2  3  5  6    <- ABDE ACDE BCDE
 ...        
 1  2  3 24 25    <- ABDE ACDE BCDE
 1  2  4  5  6    <- ACDE BCDE
...
 1  2 23 24 25    <- ACDE BCDE
 1  3  4  5  6    <- BCDE
...
 1 22 23 24 25    <- BCDE
 2  3  4  5  6    <- none
...
21 22 23 24 25    <- none

通过考虑[2,2,1],[2,1,2],[1,2,2],[3,1,1],[1,3],可以整合三部分的分区。来自这三组组合的1]和[1,1,3]元素:

 A  B  C  D  E
 1  2  3  4  5    <- ABC ABD ACD BCD ABE ACE BCE ADE BDE CDE
 1  2  3  4  6    <- ABE ACE BCE ADE BDE CDE
...
 1  2  3  4 25    <- ABE ACE BCE ADE BDE CDE
 1  2  3  5  6    <- ADE BDE CDE
...     
 1  2  3 24 25    <- ADE BDE CDE
 1  2  4  5  6    <- CDE
...
 1  2 23 24 25    <- CDE
 1  3  4  5  6    <- none
...
21 22 23 24 25    <- none

通过从这两组的组合中取[2,3],[3,2],[4,1]和[1,4]元素,可以整合具有两个部分的分区:

 A  B  C  D  E
 1  2  3  4  5    <- AB AC BC AD BD CD AE BE CE DE
 1  2  3  4  6    <- AE BE CE DE
...
 1  2  3  4 25    <- AE BE CE DE
 1  2  3  5  6    <- DE
...
 1  2  3 24 25    <- DE
 1  2  4  5  6    <- none
...
21 22 23 24 25    <- none

一般

e 元素, m 元素可以加载到内存中,并且您需要 k 元素的所有组合。使用大小 g = m / k k 组。

使用限制为 g 的部分生成 k 的所有分区:

[1,1,1 ... 1] [2,1,1 ... 1] [2,2,1 ... 1] ... [k]        (if k <= g)
[1,1,1 ... 1] [2,1,1 ... 1] [2,2,1 ... 1] ... [g,k-g]    (if k > g)

对于这些中的每一个,生成所有唯一的排列,例如:

[3,2,2,1] -> [3,2,2,1] [3,2,1,2] [3,1,2,2]
             [2,3,2,1] [2,3,1,2] [1,3,2,2]
             [2,2,3,1] [2,1,3,2] [1,2,3,2]
             [2,2,1,3] [2,1,2,3] [1,2,2,3]

对每个零件数量的排列进行排序,例如:

k:   [1,1,1 ... 1]
k-1: [2,1 ... 1] [1,2 ... 1] ... [1,1 ... 2]
...
2:   [g,k-g] [k-g,g]

将第一个 k 组加载到内存中,例如:

A  B  C  D  E  F
1  2  3  4  5  6

对于每个分区长度 p ,生成大小 p 的每组,例如:

p=k:   ABCDEF                                 C(k,k)   sets
p=k-1: ABCDE ABCDF ABCEF ABDEF ACDEF BCDEF    C(k,k-1) sets
p=k-2: ABCD ABCE ABCF ABDE ABDF ... CDEF      C(k,k-2) sets
...
p=2:   AB AC AD AE AF BC BD BE BF ... EF      C(k,2)   sets

对于每个集合,生成具有相应部件数量的分区的组合,例如:

p=k-1: ABCDE [2,1,1,1,1] -> [a,a,b,c,d,e]    C(g,2)*C(g,1)^4 combinations
             [1,2,1,1,1] -> [a,b,b,c,d,e]
             [1,1,2,1,1] -> [a,b,c,c,d,e]
             [1,1,1,2,1] -> [a,b,c,d,d,e]
             [1,1,1,1,2] -> [a,b,c,d,e,e]
       ABCDE [2,1,1,1,1] -> [a,a,b,c,d,f]
             [1,2,1,1,1] -> [a,b,b,c,d,f]
             [1,1,2,1,1] -> [a,b,c,c,d,f]
             [1,1,1,2,1] -> [a,b,c,d,d,f]
             [1,1,1,1,2] -> [a,b,c,d,f,f]
       ...
       BCDEF [2,1,1,1,1] -> [b,b,c,d,e,f]
             [1,2,1,1,1] -> [b,c,c,d,e,f]
             [1,1,2,1,1] -> [b,c,d,d,e,f]
             [1,1,1,2,1] -> [b,c,d,e,e,f]
             [1,1,1,1,2] -> [b,c,d,e,f,f]

从集合列表中删除不包含最后一组(F)的集合:

p=k:   ABCDEF
p=k-1: ABCDF ABCEF ABDEF ACDEF BCDEF
p=k-2: ABCF ABDF ABEF ACDF ACEF ADEF BCDF BCEF BDEF CDEF
...
p=2:   AF BF CF DF EF

将下一组加载到 e / g 作为F组加载到内存中,例如:

A  B  C  D  E  F
1  2  3  4  5  7
...
1  2  3  4  5 e/g

同样,对于其中的每一个,并为每个集合生成具有相应数量的部分的分区的组合。

从集合列表中删除不包含最后两个组(EF)的集合:

p=k:   ABCDEF
p=k-1: ABCEF ABDEF ACDEF BCDEF
p=k-2: ABEF ACEF ADEF BCEF BDEF CDEF
...
p=2:   EF

将下一组加载到 e / g-1 作为组E加载到内存中,并且对于每个组,在E之后加载组到 e / g 作为F组进入记忆,例如:

A    B    C    D    E    F
1    2    3    4    6    7
...
1    2    3    4  e/g-1 e/g

同样,对于其中的每一个,并为每个集合生成具有相应数量的部分的分区的组合。

从集合列表中删除不包含最后三个组(DEF)的集合:

p=k:   ABCDEF
p=k-1: ABDEF ACDEF BCDEF
p=k-2: ADEF BDEF CDEF
...
p=2:   none

将下一组最多加载到 e / g-2 作为D组加载到内存中,并且对于每个组,将D之后的组加载到 e / g-1 作为E组进入内存,对于每一组,将E之后的组加载到 e / g 作为F组加载到内存中,例如:

A     B     C     D     E     F
1     2     3     5     6     7
...
1     2     3   e/g-2 e/g-1  e/g

同样,对于其中的每一个,并为每个集合生成具有相应数量的部分的分区的组合。

等等,直到你到达:

  A     B     C     D     E     F
e/g-5 e/g-4 e/g-3 e/g-2 e/g-1  e/g

仅限:

p=k:   ABCDEF

直播21,9,3

  

元素数量:e = 21
  要素:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]
  组合大小:k = 3个元素
  内存大小:m = 9个元素

准备工作:

number of groups in memory: 3 (k)  
group size: g = m/k = 3 elements  
number of groups: e/g = 7  
groups: 1:[1,2,3] 2:[4,5,6] 3:[7,8,9] 4:[10,11,12] 5:[13,14,15] 6:[16,17,18] 7:[19,20,21]  
number of element sets loaded into memory: C(e/g,k) = C(7,3) = 35  
partitions of k with max part g: [1,1,1] [2,1] [3]  
permutations: 3:{[1,1,1]} 2:{[1,2],[2,1]} 1:{[3]}  
group sets: 3:{[A,B,C]} 2:{[A,B],[A,C],[B,C]} 1:{[A],[B],[C]}  

阶段1:

group sets: 3:{[A,B,C]} 2:{[A,B],[A,C],[B,C]} 1:{[A],[B],[C]}  (all)

A B C
1 2 3 -> elements in memory: [1,2,3] [4,5,6] [7,8,9] -> 84 combinations

3: [1,1,1]:[A,B,C] -> [a,b,c] -> [1,4,7] [1,4,8] [1,4,9] [1,5,7] [1,5,8] [1,5,9] [1,6,7] [1,6,8] [1,6,9]
                                 [2,4,7] [2,4,8] [2,4,9] [2,5,7] [2,5,8] [2,5,9] [2,6,7] [2,6,8] [2,6,9]
                                 [3,4,7] [3,4,8] [3,4,9] [3,5,7] [3,5,8] [3,5,9] [3,6,7] [3,6,8] [3,6,9]

2: [1,2]:[A,B] -> [a,b,b] -> [1,4,5] [1,4,6] [1,5,6] [2,4,5] [2,4,6] [2,5,6] [3,4,5] [3,4,6] [3,5,6]
   [1,2]:[A,C] -> [a,c,c] -> [1,7,8] [1,7,9] [1,8,9] [2,7,8] [2,7,9] [2,8,9] [3,7,8] [3,7,9] [3,8,9]
   [1,2]:[B,C] -> [b,c,c] -> [4,7,8] [4,7,9] [4,8,9] [5,7,8] [5,7,9] [5,8,9] [6,7,8] [6,7,9] [6,8,9]
   [2,1]:[A,B] -> [a,a,b] -> [1,2,4] [1,3,4] [2,3,4] [1,2,5] [1,3,5] [2,3,5] [1,2,6] [1,3,6] [2,3,6]
   [2,1]:[A,C] -> [a,a,c] -> [1,2,7] [1,3,7] [2,3,7] [1,2,8] [1,3,8] [2,3,8] [1,2,9] [1,3,9] [2,3,9]
   [2,1]:[B,C] -> [b,b,c] -> [4,5,7] [4,6,7] [5,6,7] [4,5,8] [4,6,8] [5,6,8] [4,5,9] [4,6,9] [5,6,9]

1: [3]:[A] -> [a,a,a] -> [1,2,3]
   [3]:[B] -> [b,b,b] -> [4,5,6]
   [3]:[C] -> [c,c,c] -> [7,8,9]

阶段2:

group sets: 3:{[A,B,C]} 2:{[A,C],[B,C]} 1:{[C]}  (sets without C removed)

A B C
1 2 4 -> elements in memory: [1,2,3] [4,5,6] [10,11,12] -> 64 combinations

3: [1,1,1]:[A,B,C] -> [a,b,c] -> [1,4,10] [1,4,11] [1,4,12] [1,5,10] [1,5,11] [1,5,12] [1,6,10] [1,6,11] [1,6,12]
                                 [2,4,10] [2,4,11] [2,4,12] [2,5,10] [2,5,11] [2,5,12] [2,6,10] [2,6,11] [2,6,12]
                                 [3,4,10] [3,4,11] [3,4,12] [3,5,10] [3,5,11] [3,5,12] [3,6,10] [3,6,11] [3,6,12]

2: [1,2]:[A,C] -> [a,c,c] -> [1,10,11] [1,10,12] [1,11,12] [2,10,11] [2,10,12] [2,11,12] [3,10,11] [3,10,12] [3,11,12]
   [1,2]:[B,C] -> [b,c,c] -> [4,10,11] [4,10,12] [4,11,12] [5,10,11] [5,10,12] [5,11,12] [6,10,11] [6,10,12] [6,11,12]
   [2,1]:[A,C] -> [a,a,c] -> [1,2,10] [1,3,10] [2,3,10] [1,2,11] [1,3,11] [2,3,11] [1,2,12] [1,3,12] [2,3,12]
   [2,1]:[B,C] -> [b,b,c] -> [4,5,10] [4,6,10] [5,6,10] [4,5,11] [4,6,11] [5,6,11] [4,5,12] [4,6,12] [5,6,12]

1: [3]:[C] -> [c,c,c] -> [10,11,12]

A B C
1 2 5 -> elements in memory: [1,2,3] [4,5,6] [13,14,15] -> 64 combinations
1 2 6 -> elements in memory: [1,2,3] [4,5,6] [16,17,18] -> 64 combinations
1 2 7 -> elements in memory: [1,2,3] [4,5,6] [19,20,21] -> 64 combinations

阶段3:

group sets: 3:{[A,B,C]} 2:{[B,C]}  (sets without B removed)

A B C
1 3 4 -> elements in memory: [1,2,3] [7,8,9] [10,11,12] -> 45 combinations

3: [1,1,1]:[A,B,C] -> [a,b,c] -> [1,7,10] [1,7,11] [1,7,12] [1,8,10] [1,8,11] [1,8,12] [1,9,10] [1,9,11] [1,9,12]
                                 [2,7,10] [2,7,11] [2,7,12] [2,8,10] [2,8,11] [2,8,12] [2,9,10] [2,9,11] [2,9,12]
                                 [3,7,10] [3,7,11] [3,7,12] [3,8,10] [3,8,11] [3,8,12] [3,9,10] [3,9,11] [3,9,12]

2: [1,2]:[B,C] -> [b,c,c] -> [7,10,11] [7,10,12] [7,11,12] [8,10,11] [8,10,12] [8,11,12] [9,10,11] [9,10,12] [9,11,12]
   [2,1]:[B,C] -> [b,b,c] -> [7,8,10] [7,9,10] [8,9,10] [7,8,11] [7,9,11] [8,9,11] [7,8,12] [7,9,12] [8,9,12]

A B C
1 3 5 -> elements in memory: [1,2,3] [7,8,9] [13,14,15] -> 45 combinations
1 3 6 -> elements in memory: [1,2,3] [7,8,9] [16,17,18] -> 45 combinations
1 3 7 -> elements in memory: [1,2,3] [7,8,9] [19,20,21] -> 45 combinations
1 4 5 -> elements in memory: [1,2,3] [7,8,9] [13,14,15] -> 45 combinations
1 4 6 -> elements in memory: [1,2,3] [7,8,9] [16,17,18] -> 45 combinations
1 4 7 -> elements in memory: [1,2,3] [7,8,9] [19,20,21] -> 45 combinations
1 5 6 -> elements in memory: [1,2,3] [7,8,9] [16,17,18] -> 45 combinations
1 5 7 -> elements in memory: [1,2,3] [7,8,9] [19,20,21] -> 45 combinations
1 6 7 -> elements in memory: [1,2,3] [7,8,9] [19,20,21] -> 45 combinations

阶段4:

group sets: 3:{[A,B,C]}  (sets without A removed)

A B C
2 3 4 -> elements in memory: [4,5,6] [7,8,9] [10,11,12]       -> 27 combinations

3: [1,1,1]:[A,B,C] -> [a,b,c] -> [4,7,10] [4,7,11] [4,7,12] [4,8,10] [4,8,11] [4,8,12] [4,9,10] [4,9,11] [4,9,12]
                                 [5,7,10] [5,7,11] [5,7,12] [5,8,10] [5,8,11] [5,8,12] [5,9,10] [5,9,11] [5,9,12]
                                 [6,7,10] [6,7,11] [6,7,12] [6,8,10] [6,8,11] [6,8,12] [6,9,10] [6,9,11] [6,9,12]

A B C
2 3 5 -> elements in memory: [4,5,6] [7,8,9] [13,14,15]       -> 27 combinations
2 3 6 -> elements in memory: [4,5,6] [7,8,9] [16,17,18]       -> 27 combinations
2 3 7 -> elements in memory: [4,5,6] [7,8,9] [19,20,21]       -> 27 combinations
2 4 5 -> elements in memory: [4,5,6] [10,11,12] [13,14,15]    -> 27 combinations
2 4 6 -> elements in memory: [4,5,6] [10,11,12] [16,17,18]    -> 27 combinations
2 4 7 -> elements in memory: [4,5,6] [10,11,12] [19,20,21]    -> 27 combinations
2 5 6 -> elements in memory: [4,5,6] [13,14,15] [16,17,18]    -> 27 combinations
2 5 7 -> elements in memory: [4,5,6] [13,14,15] [19,20,21]    -> 27 combinations
2 6 7 -> elements in memory: [4,5,6] [16,17,18] [19,20,21]    -> 27 combinations
3 4 5 -> elements in memory: [7,8,9] [10,11,12] [13,14,15]    -> 27 combinations
3 4 6 -> elements in memory: [7,8,9] [10,11,12] [16,17,18]    -> 27 combinations
3 4 7 -> elements in memory: [7,8,9] [10,11,12] [19,20,21]    -> 27 combinations
3 5 6 -> elements in memory: [7,8,9] [13,14,15] [16,17,18]    -> 27 combinations
3 5 7 -> elements in memory: [7,8,9] [13,14,15] [19,20,21]    -> 27 combinations
3 6 7 -> elements in memory: [7,8,9] [16,17,18] [19,20,21]    -> 27 combinations
4 5 6 -> elements in memory: [10,11,12] [13,14,15] [16,17,18] -> 27 combinations
4 5 7 -> elements in memory: [10,11,12] [13,14,15] [19,20,21] -> 27 combinations
4 6 7 -> elements in memory: [10,11,12] [16,17,18] [19,20,21] -> 27 combinations
5 6 7 -> elements in memory: [13,14,15] [16,17,18] [19,20,21] -> 27 combinations

结果:

Phase 1:      84 =   84 combinations
Phase 2:  4 x 64 =  256 combinations
Phase 3: 10 x 45 =  450 combinations
Phase 4: 20 x 27 =  540 combinations
                   ----
                   1330 combinations = C(21,3)

答案 1 :(得分:0)

根据您为每个组合计算的重量,最快的方法可能是将范围0..C(n,k)划分为要并行处理的一组子范围,并在每个子范围内生成直接在GPU上的相应组合,使用unranking function生成第一个组合,使用经典算法查找下一个组合以生成后续组合。