C++ 以分布式方式枚举组合

C++ 以分布式方式枚举组合,c++,algorithm,distributed,combinatorics,hpc,C++,Algorithm,Distributed,Combinatorics,Hpc,我有一个问题,我必须分析500C5组合(255244687600)的东西。将其分布在10个节点的集群上,每个集群每秒处理大约10^6个组合,这意味着作业将在大约7小时内完成 我遇到的问题是将255244687600个组合分布在10个节点上。我想用25524468760表示每个节点,但是我使用的算法只能按顺序生成组合,我希望能够传递元素集和一系列组合标记,例如,[0-10^7],[10^7,2.0 10^7),并让节点自己计算出组合 我目前使用的算法如下: 堆栈溢出问题 我考虑过使用主节点,

我有一个问题,我必须分析500C5组合(255244687600)的东西。将其分布在10个节点的集群上,每个集群每秒处理大约10^6个组合,这意味着作业将在大约7小时内完成

我遇到的问题是将255244687600个组合分布在10个节点上。我想用25524468760表示每个节点,但是我使用的算法只能按顺序生成组合,我希望能够传递元素集和一系列组合标记,例如,[0-10^7],[10^7,2.0 10^7),并让节点自己计算出组合

我目前使用的算法如下:

  • 堆栈溢出问题

我考虑过使用主节点,它枚举每个组合并向每个节点发送工作。但是,从单个节点迭代组合并来回通信工作所产生的开销是巨大的,它将导致主节点成为瓶颈


有什么好的组合迭代算法可以用于高效/最优的分布式枚举吗?

您可能会获得一些成功,它允许您使用一个简单的算法检索第N(N/10)个k组合;然后在十个节点中的每个节点上运行
下一个组合
算法N/10次以进行迭代


样本代码(C++中,但C++程序员相当可读)。< /P> < P>节点数n每第十个组合处理,从第n个开始。

< p>我知道这个问题是旧的,但这里是如何有效地完成。< /P>

目前在python中的所有代码,我确信它将很容易翻译成C++。
-你可能会想从使用特征向量的整数移动到使用一个比特数组,因为所使用的整数需要500位(不是Python中的问题)
-随时更新C++的任何人。


  • 将其组合范围(
    start
    number和
    length
    to process)、要从中选择组合的
    项集
    ,以及要选择的项数
    k
    )分配给节点
  • 通过让每个节点直接从
    start
    items
    中找到其起始组合来初始化每个节点
  • 运行每个节点,让它为第一个组合执行工作,然后迭代其其余组合,并执行相关工作

  • 要执行1请按照您的建议执行,找到n-choose-k并将其划分为多个范围-在您的示例中,500-choose-5是255244687600,正如您所说的那样,对于节点=0到9,您分配:
    (start=node*25524468760,length=25524468760,items=items,k=5)

    要执行2,您可以使用组合数制直接找到起始组合(无需迭代),同时找到组合特征向量的整数表示(用于3中的迭代):

    def getCombination(index, items, k):
        '''Returns (combination, characteristicVector)
        combination - The single combination, of k elements of items, that would be at
        the provided index if all possible combinations had each been sorted in
        descending order (as defined by the order of items) and then placed in a
        sorted list.
        characteristicVector - an integer with chosen item's bits set.
        '''
        combination = []
        characteristicVector = 0
        n = len(items)
        nCk = 1
        for nMinusI, iPlus1 in zip(range(n, n - k, -1), range(1, k + 1)):
            nCk *= nMinusI
            nCk //= iPlus1
        curIndex = nCk
        for k in range(k, 0, -1):
            nCk *= k
            nCk //= n
            while curIndex - nCk > index:
                curIndex -= nCk
                nCk *= (n - k)
                nCk -= nCk % k
                n -= 1
                nCk //= n
            n -= 1
            combination .append(items[n])
            characteristicVector += 1 << n
        return combination, characteristicVector 
    
    重复此
    length-1
    次(因为您已经直接找到了第一个)


    例如:

    五个节点处理7-choose-3个字母:

    >>> items = ('A','B','C','D','E','F','G')
    >>> k = 3
    >>> nodes = 5
    >>> n =  len(items)
    >>> for nmip1, i in zip(range(n - 1, n - k, -1), range(2, k + 1)):
    ...     n = n * nmip1 // i
    ...
    >>> for node in range(nodes):
    ...     length = n // nodes
    ...     start = node * length
    ...     print("Node {0} initialised".format(node))
    ...     combination, cv = getCombination(start, items, k)
    ...     doWork(combination)
    ...     for i in range(length-1):
    ...             combination, cv = nextCombination(items, cv)
    ...             doWork(combination)
    ...
    Node 0 initialised
    Doing work with: C B A
    Doing work with: D B A
    Doing work with: D C A
    Doing work with: D C B
    Doing work with: E B A
    Doing work with: E C A
    Doing work with: E C B
    Node 1 initialised
    Doing work with: E D A
    Doing work with: E D B
    Doing work with: E D C
    Doing work with: F B A
    Doing work with: F C A
    Doing work with: F C B
    Doing work with: F D A
    Node 2 initialised
    Doing work with: F D B
    Doing work with: F D C
    Doing work with: F E A
    Doing work with: F E B
    Doing work with: F E C
    Doing work with: F E D
    Doing work with: G B A
    Node 3 initialised
    Doing work with: G C A
    Doing work with: G C B
    Doing work with: G D A
    Doing work with: G D B
    Doing work with: G D C
    Doing work with: G E A
    Doing work with: G E B
    Node 4 initialised
    Doing work with: G E C
    Doing work with: G E D
    Doing work with: G F A
    Doing work with: G F B
    Doing work with: G F C
    Doing work with: G F D
    Doing work with: G F E
    >>>
    

    在这方面没有太多经验,但谷歌MapReduce似乎可以解决这个问题。MapReduce在这里并不重要,因为问题是关于术语的“映射”部分:如何在不需要中央分发服务器的情况下有效地将一个n-choose-k空间问题映射为m个部分。@Reyzooti:因此“没有太多经验”。不过,很高兴被更正。排列可以使用阶乘数字系统进行系统编号。在您的情况下,495!*5!每个排列中只有一个是相关的组合。因此,我推测,您可能可以计算每个节点的开始排列=组合,然后从那里继续。这个想法可能会成功或失败。这取决于关于细节;这只是一个想法。-)干杯,谢谢,@Alf:你能提供一个更详细的pdeth解释吗?仍然要求每个节点迭代每个n-choose-k组合,这会导致每个节点90%的迭代冗余,比主节点解决方案的开销要少,但仍然比分配组合范围要多McCaffrey在一篇文章中描述了一种获取第n个组合的方法,这种方法太昂贵了对原始范围进行变异,可能是可以确定第n个组合的范围的东西,因为可以将该特定范围传递给计算节点。为什么它太昂贵?您只需要在主节点上运行10次,然后在计算节点上运行下一个组合。@Reyzooti:如果您有基于索引的然后将其转换为RandomAccessIterator很容易-->在迭代器中保留指向序列的指针和索引:)
    >>> items = ('A','B','C','D','E','F','G')
    >>> k = 3
    >>> nodes = 5
    >>> n =  len(items)
    >>> for nmip1, i in zip(range(n - 1, n - k, -1), range(2, k + 1)):
    ...     n = n * nmip1 // i
    ...
    >>> for node in range(nodes):
    ...     length = n // nodes
    ...     start = node * length
    ...     print("Node {0} initialised".format(node))
    ...     combination, cv = getCombination(start, items, k)
    ...     doWork(combination)
    ...     for i in range(length-1):
    ...             combination, cv = nextCombination(items, cv)
    ...             doWork(combination)
    ...
    Node 0 initialised
    Doing work with: C B A
    Doing work with: D B A
    Doing work with: D C A
    Doing work with: D C B
    Doing work with: E B A
    Doing work with: E C A
    Doing work with: E C B
    Node 1 initialised
    Doing work with: E D A
    Doing work with: E D B
    Doing work with: E D C
    Doing work with: F B A
    Doing work with: F C A
    Doing work with: F C B
    Doing work with: F D A
    Node 2 initialised
    Doing work with: F D B
    Doing work with: F D C
    Doing work with: F E A
    Doing work with: F E B
    Doing work with: F E C
    Doing work with: F E D
    Doing work with: G B A
    Node 3 initialised
    Doing work with: G C A
    Doing work with: G C B
    Doing work with: G D A
    Doing work with: G D B
    Doing work with: G D C
    Doing work with: G E A
    Doing work with: G E B
    Node 4 initialised
    Doing work with: G E C
    Doing work with: G E D
    Doing work with: G F A
    Doing work with: G F B
    Doing work with: G F C
    Doing work with: G F D
    Doing work with: G F E
    >>>