2011-01-15 33 views
16

Tôi gặp vấn đề khi tôi phải phân tích các kết hợp 500C5 (255244687600) của một cái gì đó. Phân phối nó trên một cụm 10 nút trong đó mỗi cụm xử lý khoảng 10^6 kết hợp mỗi giây nghĩa là công việc sẽ hoàn thành trong khoảng bảy giờ.Đếm các kết hợp theo cách phân phối

Sự cố tôi đang phân phối các kết hợp 255244687600 trong 10 nút. Tôi muốn trình bày mỗi nút với 25524468760, tuy nhiên các thuật toán tôi đang sử dụng chỉ có thể tạo ra các kết hợp tuần tự, tôi muốn có thể vượt qua tập hợp các phần tử và một loạt các chỉ báo kết hợp, ví dụ, [0 -10^7), [10^7,2.0 10^7), v.v ... và có các nút tự tìm ra các kết hợp.

Các thuật toán Tôi đang sử dụng tại thời điểm này là từ sau:

tôi đã xem xét sử dụng một nút chính, liệt kê từng kết hợp và gửi công việc tới từng kết quả des. Tuy nhiên, chi phí phát sinh trong việc lặp lại các kết hợp từ một nút duy nhất và giao tiếp qua lại là rất lớn, và sau đó nó sẽ dẫn đến nút chính trở thành nút cổ chai.

Có bất kỳ thuật toán lặp kết hợp tốt nào được thiết lập để liệt kê phân bổ hiệu quả/tối ưu không?

+0

Không có nhiều kinh nghiệm trong lĩnh vực này, nhưng nó có vẻ như một vấn đề mà google MapReduce có thể là áp dụng cho. –

+7

MapReduce không liên quan ở đây, vì câu hỏi là về phần "Bản đồ" của thuật ngữ: Làm thế nào để ánh xạ hiệu quả một vấn đề không gian n-select-k vào các phần m mà không cần một nhà phân phối trung tâm. –

+0

@Reyzooti: Do đó "không có nhiều kinh nghiệm". Thật vui khi được sửa chữa. –

Trả lời

3

Bạn có thể có một số thành công với combinatorial numbers, cho phép bạn để lấy N 'th (n/10) k -combination với một thuật toán đơn giản; sau đó chạy thuật toán next_combinationn/10 lần trên mỗi nút trong số mười nút để lặp lại.

Mã mẫu (trong C#, nhưng khá dễ đọc đối với lập trình C++) có thể được tìm thấy trên MSDN.

+0

Bài viết của James McCaffrey, nơi ông mô tả một phương pháp để có được sự kết hợp thứ N là quá đắt. Sử dụng next_combination (liên kết) làm biến đổi phạm vi ban đầu, có lẽ một cái gì đó có thể xác định phạm vi trông như thế nào ở tổ hợp thứ N, bởi vì người ta có thể vượt qua phạm vi cụ thể đó cho một nút tính toán. –

+0

Tại sao nó quá đắt?Bạn chỉ cần chạy 10 lần trên master, sau đó chạy 'next_combination' trên các nút tính toán. –

+0

@Reyzooti: nếu bạn có một chỉ số dựa trên điều, sau đó biến nó thành một RandomAccessIterator là dễ dàng -> giữ một con trỏ đến trình tự và một chỉ số trong iterator :) –

0

Có số nút n xử lý mọi sự kết hợp thứ mười, bắt đầu từ phần thứ n.

+4

Vẫn yêu cầu mỗi nút lặp lại trên mỗi combo n-select-k, dẫn đến 90% redudancy lặp lại cho mỗi nút, ít chi phí hơn so với giải pháp nút chủ tuy nhiên vẫn còn nhiều hơn phân phối phạm vi kết hợp. –

0

Tôi biết câu hỏi này là cũ, nhưng đây là cách nó có thể được thực hiện hiệu quả.

Tất cả mã hiện tại bằng Python mà tôi chắc chắn sẽ đủ dễ dàng dịch sang C++.
- Có thể bạn sẽ muốn di chuyển từ việc sử dụng số nguyên cho vector đặc trưng để sử dụng mảng bit, vì số nguyên được sử dụng sẽ cần 500 bit (không phải là vấn đề trong Python)
- Hãy cập nhật lên C++ bất kỳ ai.


  1. Distribute to các nút phạm vi của họ kết hợp (start số và length để xử lý), các thiết lập của items từ tổ hợp để được lựa chọn, và số lượng, k, các mặt hàng để lựa chọn.
  2. Khởi tạo từng nút bằng cách tìm kết hợp bắt đầu trực tiếp từ startitems.
  3. Chạy từng nút bằng cách thực hiện công việc cho kết hợp đầu tiên sau đó lặp qua các kết hợp còn lại của nó và thực hiện công việc liên quan.

Thực hiện làm như bạn đề nghị tìm n-chọn-k và chia nó thành các dãy - trong trường hợp của bạn 500-Chọn-5 được, như bạn nói, 255.244.687.600 như vậy, cho node = 0-9 bạn phát hành:
(start=node*25524468760, length=25524468760, items=items, k=5)

thực hiện bạn có thể tìm thấy sự kết hợp bắt đầu trực tiếp (không lặp lại) bằng cách sử dụng hệ thống số tổ hợp và tìm ra đại diện nguyên của vector đặc trưng của sự kết hợp (được sử dụng cho các lần lặp trong) cùng một lúc:

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 

Biểu diễn số nguyên của vectơ đặc trưng có k bit được đặt ở vị trí của các mục tạo nên tổ hợp.

Thực hiện bạn có thể sử dụng Hack Gosper để lặp với vector đặc trưng tiếp theo cho sự kết hợp trong hệ thống cùng một số (sự kết hợp tiếp theo sẽ xuất hiện trong một danh sách được sắp xếp đảo ngược được sắp xếp kết hợp tương đối so với items) và, cùng một lúc, hãy tạo kết hợp:

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 

Lặp lại số này length-1 lần (vì bạn đã tìm thấy số đầu tiên trực tiếp).


Ví dụ:

Năm nút xử lý 7-chọn-3 chữ cái:

>>> 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 
>>> 
Các vấn đề liên quan