dictionary - Summing Python Objects with MPI's Allreduce -


i using sparse tensor array manipulation built using dictionaries , counters in python. make possible use array manipulation in parallel. bottom line have ended having counters on each node add using mpi.allreduce (or nice solution). instance counters 1 can this

a = counter({a:1, b:2, c:3}) b = counter({b:1, c:2, d:3}) 

such that

c = a+b = counter({a:1, b:3, c:5, d:3}). 

i same operation relevant nodes,

mpi.allreduce(send_counter, recv_counter, mpi.sum) 

however, mpi doesn't seem recognize operation on dictionaries/counters, throwing error expecting buffer or list/tuple. best option `user-defined operation,' or there way allreduce add counters? thanks,

edit (7/14/15): have attempted create user operation dictionaries there have been discrepancies. wrote following

def dict_sum(dict1, dict2, datatype):     key in dict2:         try:             dict1[key] += dict2[key]         except keyerror:             dict1[key] = dict2[key] 

and when told mpi function did this:

dictsumop = mpi.op.create(dict_sum, commute=true) 

and in code used as

the_result = comm.allreduce(mydict, dictsumop) 

however, threw unsupported operand '+' type dict. wrote

the_result = comm.allreduce(mydict, op=dictsumop) 

and throws dict1[key] += dict2[key] typeerror: 'nonetype' object has no attribute '__getitem__' apparently wants know things dictionaries? how tell have type dictionary?

neither mpi nor mpi4py knows counters in particular, need create own reduction operation work; same other sort of python object:

#!/usr/bin/env python mpi4py import mpi import collections  def addcounter(counter1, counter2, datatype):     item in counter2:         counter1[item] += counter2[item]     return counter1  if __name__=="__main__":      comm = mpi.comm_world      if comm.rank == 0:         mycounter = collections.counter({'a':1, 'b':2, 'c':3})     else:         mycounter = collections.counter({'b':1, 'c':2, 'd':3})       countersumop = mpi.op.create(addcounter, commute=true)      totcounter = comm.allreduce(mycounter, op=countersumop)     print comm.rank, totcounter 

here we've taken function sums 2 counter objects , created mpi operator out of them mpi.op.create; mpi4py unpickle objects, run function combine these items pairwise, pickle partial result , send off next task.

note we're using (lowercase) allreduce, works on arbitrary python objects, rather (uppercase) allreduce, works on numpy arrays or moral equivalents (buffers, map onto fortran/c arrays mpi api designed on).

running gives:

$ mpirun -np 2 python ./counter_reduce.py  0 counter({'c': 5, 'b': 3, 'd': 3, 'a': 1}) 1 counter({'c': 5, 'b': 3, 'd': 3, 'a': 1})  $ mpirun -np 4 python ./counter_reduce.py  0 counter({'c': 9, 'd': 9, 'b': 5, 'a': 1}) 2 counter({'c': 9, 'd': 9, 'b': 5, 'a': 1}) 1 counter({'c': 9, 'd': 9, 'b': 5, 'a': 1}) 3 counter({'c': 9, 'd': 9, 'b': 5, 'a': 1}) 

and modest changes works generic dictionary:

#!/usr/bin/env python mpi4py import mpi  def addcounter(counter1, counter2, datatype):     item in counter2:         if item in counter1:             counter1[item] += counter2[item]         else:             counter1[item] = counter2[item]     return counter1  if __name__=="__main__":      comm = mpi.comm_world      if comm.rank == 0:         mydict = {'a':1, 'c':"hello "}     else:         mydict = {'c':"world!", 'd':3}      countersumop = mpi.op.create(addcounter, commute=true)      totdict = comm.allreduce(mydict, op=countersumop)     print comm.rank, totdict 

running giving

$ mpirun -np 2 python dict_reduce.py  0 {'a': 1, 'c': 'hello world!', 'd': 3} 1 {'a': 1, 'c': 'hello world!', 'd': 3} 

Comments

Popular posts from this blog

javascript - Using jquery append to add option values into a select element not working -

Android soft keyboard reverts to default keyboard on orientation change -

Rendering JButton to get the JCheckBox behavior in a JTable by using images does not update my table -