[英]Distribute elements between equivalent arrays to achieve balanced sums
我給了一組元素,比如10到21( 總是順序的 ),我生成相同大小的數組,其中大小是運行時確定的。
3個生成數組的示例( 數組#是動態的,以及所有數組中的元素數,其中一些元素可以是0 - 未使用 ):
A1 = [10,11,12,13]
A2 = [14,15,16,17]
A3 = [18,19,20,21]
這些生成的數組將被賦予不同的進程,以對元素進行一些計算。 我的目標是平衡每個獲得陣列的進程的負載。 我的意思是:
舉個例子,有
A1 = 46
A2 = 62
A3 = 78
對每個線程給出的元素的潛在迭代。
我想重新排列初始數組,為每個進程提供相同數量的工作,例如:
A1 = [21,11,12,13] = 57
A2 = [14,15,16,17] = 62
A3 = [18,19,20,10] = 67
( 不是平等分配,但比初始更公平 )。 分布可以是不同的,只要它們接近某個最佳分布並且優於第一個和最后一個數組的最差(初始)情況。 在我看來,使用不同的索引可以實現不同的分布[在這里進行數組的拆分{可以是不均勻的}]
這適用於給定的例子,但可能有奇怪的情況..
所以,我認為這是一個反射問題( 由於缺乏正確定義的知識 ),其中應該通過對角線看到數組,例如:
10 | 111213
1415 | 1617
181920 | 21
然后可以做一個明顯的替代..
我嘗試實現如下:
if(rest == 0)
payload_size = (upper-lower)/(processes-1);
else
payload_size = (upper-lower)/(processes-1) + 1;
//printf("payload size: %d\n", payload_size);
long payload[payload_size];
int m = 0;
int k = payload_size/2;
int added = 0; //track what been added so far (to skip over already added elements)
int added2 = 0; // same as 'added'
int p = 0;
for (i = lower; i <= upper; i=i+payload_size){
for(j = i; j<(i+payload_size); j++){
if(j <= upper){
if((j-i) > k){
if(added2 > j){
added = j;
payload[(j-i)] = j;
printf("1 adding data: %d at location: %d\n", payload[(j-i)], (j-i));
}else{
printf("else..\n");
}
}else{
if(added < upper - (m+1)){
payload[(j-i)] = upper - (p*payload_size) - (m++);
added2 = payload[(j-i)];
printf("2 adding data: %d at location: %d\n", payload[(j-i)], (j-i));
}else{
payload[(j-i)] = j;
printf("2.5 adding data: %d at location: %d\n", payload[(j-i)], (j-i));
}
}
}else{ payload[(j-i)] = '\0'; }
}
p++;
k=k/2;
//printf("send to proc: %d\n", ((i)/payload_size)%(processes-1)+1);
}
但是失敗了。
你肯定可以在實現中看到問題,因為它的可擴展性很差,不完整,雜亂,寫得不好等等等等等等......
因此,在給出描述的情況下,我需要幫助實現或者想要更好的方法來實現我想要實現的目標。
PS我需要解決方案盡可能' in-liney '( 避免循環嵌套 ) - 這就是為什么我使用一堆標志和全局索引。
當然,這可以通過額外的循環和不必要的迭代來完成。 我邀請那些能夠並且在數組方面欣賞索引藝術的人。
我確信那里有一個解決方案,但我無法通過合適的Google查詢來查找它。
暗示? 我想到使用索引%size_of_my_data來完成這個任務..
PS應用: 這里描述
通過簡單的分配順序,您可以依次迭代地將min和max元素添加到每個列表中。 有一些終止細節要修復,但這是一般的想法。 應用於您的示例,輸出將如下所示:
john-schultzs-macbook-pro:~ jschultz$ ./a.out
10 21 13 18 = 62
11 20 14 17 = 62
12 19 15 16 = 62
當num_procs均勻地划分num_elems時,這樣的簡單反射分配將是最佳的。 當它不是時,它將是次優的,但仍然是體面的:
#include <stdio.h>
int compute_dist(int lower, int upper, int num_procs)
{
if (lower > upper || num_procs <= 0)
return -1;
int num_elems = upper - lower + 1;
int num_elems_per_proc_floor = num_elems / num_procs;
int num_elems_per_proc_ceil = num_elems_per_proc_floor + (num_elems % num_procs != 0);
int procs[num_procs][num_elems_per_proc_ceil];
int i, j, sum;
// assign pairs of (lower, upper) to each process until we can't anymore
for (i = 0; i + 2 <= num_elems_per_proc_floor; i += 2)
for (j = 0; j < num_procs; ++j)
{
procs[j][i] = lower++;
procs[j][i+1] = upper--;
}
// handle left overs similarly to the above
// NOTE: actually you could use just this loop alone if you set i = 0 here, but the above loop is more understandable
for (; i < num_elems_per_proc_ceil; ++i)
for (j = 0; j < num_procs; ++j)
if (lower <= upper)
procs[j][i] = ((0 == i % 2) ? lower++ : upper--);
else
procs[j][i] = 0;
// print assignment results
for (j = 0; j < num_procs; ++j)
{
for (i = 0, sum = 0; i < num_elems_per_proc_ceil; ++i)
{
printf("%d ", procs[j][i]);
sum += procs[j][i];
}
printf(" = %d\n", sum);
}
return 0;
}
int main()
{
compute_dist(10, 21, 3);
return 0;
}
這是我用deque編寫的O(n)解決方案(雙端隊列,不需要deque,可以使用簡單的數組,但是deque因為popRight和popLeft而使代碼干凈)。 代碼是Python,而不是偽代碼,但它應該很容易理解(因為它是Python):
def balancingSumProblem(seqStart = None, seqStop = None, numberOfArrays = None):
from random import randint
from collections import deque
seq = deque(xrange(seqStart or randint(1, 10),
seqStop and seqStop + 1 or randint(11,30)))
arrays = [[] for _ in xrange(numberOfArrays or randint(1,6))]
print "# of elements: {}".format(len(seq))
print "# of arrays: {}".format(len(arrays))
averageNumElements = float(len(seq)) / len(arrays)
print "average number of elements per array: {}".format(averageNumElements)
oddIteration = True
try:
while seq:
for array in arrays:
if len(array) < averageNumElements and oddIteration:
array.append(seq.pop()) # pop() is like popright()
elif len(array) < averageNumElements:
array.append(seq.popleft())
oddIteration = not oddIteration
except IndexError:
pass
print arrays
print [sum(array) for array in arrays]
balancingSumProblem(10,21,3) # Given Example
print "\n---------\n"
balancingSumProblem() # Randomized Test
基本上,從迭代到迭代,它在抓取大元素並在數組中均勻分布它們並抓取小元素並將它們均勻地分布在數組中之間交替。 它從out到in(雖然你可以從里到外)並嘗試使用每個陣列的平均元素數來進一步平衡它。
所有測試都不是100%准確,但它對大多數隨機測試都做得很好。 您可以嘗試在此處運行代碼: http : //repl.it/cJg
我已經使用了這個實現,我在本報告中提到過(實現適用於我用於測試(1-15K)(1-30K)和(1-100K)數據集的情況。我並不是說它會有效對於所有情況):
int aFunction(long lower, long upper, int payload_size, int processes)
{
long result, i, j;
MPI_Status status;
long payload[payload_size];
int m = 0;
int k = (payload_size/2)+(payload_size%2)+1;
int lastAdded1 = 0;
int lastAdded2 = 0;
int p = 0;
int substituted = 0;
int allowUpdate = 1;
int s;
int times = 1;
int times2 = 0;
for (i = lower; i <= upper; i=i+payload_size){
for(j = i; j<(i+payload_size); j++){
if(j <= upper){
if(k != 0){
if((j-i) >= k){
payload[(j-i)] = j- (m);
lastAdded2 = payload[(j-i)];
}else{
payload[(j-i)] = upper - (p*payload_size) - (m++) + (p*payload_size);
if(allowUpdate){
lastAdded1 = payload[(j-i)];
allowUpdate = 0;
}
}
}else{
int n;
int from = lastAdded1 > lastAdded2 ? lastAdded2 : lastAdded1;
from = from + 1;
int to = lastAdded1 > lastAdded2 ? lastAdded1 : lastAdded2;
int tempFrom = (to-from)/payload_size + ((to-from)%payload_size>0 ? 1 : 0);
for(s = 0; s < tempFrom; s++){
int restIndex = -1;
for(n = from; n < from+payload_size; n++){
restIndex = restIndex + 1;
payload[restIndex] = '\0';
if(n < to && n >= from){
payload[restIndex] = n;
}else{
payload[restIndex] = '\0';
}
}
from = from + payload_size;
}
return 0;
}
}else{ payload[(j-i)] = '\0'; }
}
p++;
k=(k/2)+(k%2)+1;
allowUpdate = 1;
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.