2011-01-15 12 views
16

Ich habe ein Problem, wo ich 500C5 Kombinationen (255244687600) von etwas analysieren müssen. Die Verteilung über einen Cluster mit 10 Knoten, wobei jeder Cluster ungefähr 10^6 Kombinationen pro Sekunde verarbeitet, bedeutet, dass der Job in ungefähr sieben Stunden abgeschlossen sein wird.Enumerating Kombinationen in einer verteilten Art

Das Problem, das ich habe, ist die Verteilung der 255244687600 Kombinationen über die 10 Knoten. Ich möchte jeden Knoten mit 25524468760 darstellen, aber die Algorithmen, die ich verwende, können die Kombinationen nur nacheinander erzeugen. Ich würde gerne die Menge der Elemente und eine Reihe von Kombinationsindizes übergeben können, zum Beispiel [0 -10^7), [10^7,2.0 10^7) usw. und lassen die Knoten selbst die Kombinationen herausfinden.

Die Algorithmen Ich bin im Moment verwenden, sind aus den folgenden:

Ich habe als ein mit Master-Knoten, der jede der Kombinationen aufzählt und Arbeit an jede der Knoten sendet des. Der Overhead, der beim Iterieren der Kombinationen von einem einzelnen Knoten und beim Kommunizieren von Hin- und Herarbeit auftritt, ist jedoch enorm und wird in der Folge dazu führen, dass der Master-Knoten zum Engpass wird.

Gibt es gute Kombinations-Iterationsalgorithmen, die auf effiziente/optimale verteilte Aufzählung ausgerichtet sind?

+0

nicht viel Erfahrung in diesem Bereich, aber es klingt wie ein Problem, dass Google MapReduce sein könnte angewendet. –

+7

MapReduce ist hier irrelevant, da es sich um den "Map" -Teil des Begriffs handelt: Wie kann man ein n-choose-k-Raumproblem effizient in m Teile abbilden, ohne dass ein zentraler Verteiler benötigt wird? –

+0

@Reyzooti: Daher die "nicht viel Erfahrung". Glücklich, aber korrigiert zu werden. –

Antwort

3

Sie können einen gewissen Erfolg mit combinatorial numbers haben, mit denen Sie die N ‚th abzurufen (n/10.) k -combination mit einem einfachen Algorithmus; Führen Sie dann den next_combination Algorithmus n/10 Mal auf jedem der zehn Knoten zu iterieren.

Beispielcode (in C#, aber für einen C++ - Programmierer gut lesbar) finden Sie unter MSDN.

+0

Der James McCaffrey Artikel, wo er eine Methode beschreibt, um die N-te Kombination zu bekommen, ist zu teuer. Die Verwendung von next_combination (Links) mutiert den ursprünglichen Bereich, vielleicht etwas, das bestimmen kann, wie der Bereich bei der N-ten Kombination aussieht, weil man diesen bestimmten Bereich an einen Rechenknoten übergeben könnte. –

+0

Warum ist es zu teuer?Sie müssen dies nur 10 Mal auf dem Master ausführen und dann 'next_combination' auf den Rechenknoten ausführen. –

+0

@Reyzooti: Wenn Sie eine indexbasierte Sache haben, dann ist es leicht, sie in einen RandomAccessIterator umzuwandeln -> behalten Sie einen Zeiger auf die Sequenz und einen Index im Iterator bei. –

0

Lassen Sie die Knotennummer n jede zehnte Kombination verarbeiten, beginnend mit der n-ten.

+4

Noch erfordert jeder Knoten, über jede n-Auswahl-k Combos zu iterieren, was zu 90% iteration redudancy pro Knoten führt, weniger Overhead als die Master-Knotenlösung, aber immer noch mehr als die Verteilung von Kombinationen. –

0

Ich weiß, diese Frage ist alt, aber hier ist, wie es effizient getan werden kann.

Alle Code derzeit in Python, die ich sicher bin, wird einfach genug sein, um in C++ zu übersetzen.
- Sie werden wahrscheinlich von einer Ganzzahl für den Merkmalsvektor zur Verwendung eines Bit-Arrays wechseln wollen, da die verwendeten Ganzzahlen 500 Bits benötigen (in Python kein Problem)
- Fühlen Sie sich frei, auf C++ zu aktualisieren.


  1. die Knoten ihre Auswahl an Kombinationen (start Anzahl und length zu verarbeiten), um den Satz von items aus denen Kombinationen verteilen gewählt werden, und die Anzahl, k, die Elemente zu wählen.
  2. Initialisieren Sie jeden Knoten, indem Sie seine Startkombination direkt von start und items finden.
  3. Führen Sie jeden Knoten aus, indem Sie die Arbeit für die erste Kombination ausführen und dann den Rest der Kombinationen durchlaufen und die zugehörige Arbeit ausführen.

Um ausführen tun, wie Sie n-wählen-k vorschlagen finden und es in Bereiche unterteilen - in Ihrem Fall 500-Wählen-5 ist, wie Sie, die 255.244.687.600 so, für den Knoten = 0 bis 9 Sie verteilen:
(start=node*25524468760, length=25524468760, items=items, k=5)

auszuführen Sie die Start-Kombination direkt (ohne Iteration) finden können das kombinatorische Zahlensystem verwenden und die Ganzzahl-Darstellung der charakteristischen Vektors Kombination finden (um für die Iteration verwendet werden, in) zur gleichen Zeit:

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 

Die ganzzahlige Darstellung der Kennvektor k Bits in den Positionen der Elemente einstellen, die die Kombination bilden.

Zur Durchführung Sie Gospers Hack verwenden können, um den nächsten charakteristischen Vektor für die Kombination in dem gleichen Zahlensystem (die nächste Kombination, die in einer sortierten Liste des Reverse sortierte Kombinationen in Bezug auf items erscheinen würde) zu durchlaufen und, zur gleichen Zeit, erstellen Sie die Kombination:

def nextCombination(items, characteristicVector): 
    '''Returns the next (combination, characteristicVector). 
    combination - The next combination of items that would appear after the 
    combination defined by the provided characteristic vector 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. 
    ''' 
    u = characteristicVector & -characteristicVector 
    v = u + characteristicVector 
    if v <= 0: 
     raise OverflowError("Ran out of integers") # <- ready for C++ 
    characteristicVector = v + (((v^characteristicVector) // u) >> 2) 
    combination = [] 
    copiedVector = characteristicVector 
    index = len(items) - 1 
    while copiedVector > 0: 
     present, copiedVector = divmod(copiedVector, 1 << index) 
     if present: 
      combination.append(items[index]) 
     index -= 1 
    return combination, characteristicVector 

Wiederholen Sie diese length-1 mal (da Sie bereits die ersten direkt gefunden).


Zum Beispiel:

Fünf Knoten Verarbeitung 7-wählen-3 Buchstaben:

>>> 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 
>>> 
Verwandte Themen