I'm trying to use multiprocessing to split a for loop over multiple processes. Thus speeding up a QuTiP's library solver, here's my target function:
def solve_entropy(t):
# Parameters
k = 0.5
n = 2
N = 5
r = 1.0
alpha = 2.0
beta = 2.0
gamma = 0.2
wm = 1
w0 = r * wm
g = k * wm
# Operators
a = tensor(destroy(N), identity(N), identity(N))
b = tensor(identity(N), destroy(N), identity(N))
c = tensor(identity(N), identity(N), destroy(N))
# result = mesolve(H,psi0,t,c_ops)
result = mesolve(
w0 * a.dag() * a
+ w0 * b.dag() * b
+ wm * c.dag() * c
- g * a.dag() * a * (c + c.dag())
- g * b.dag() * b * (c + c.dag()),
tensor(coherent(N, alpha), coherent(N, alpha), coherent(N, beta)),
t,
sqrt(gamma) * c,
)
S = [entropy_linear(ptrace(i, n)) for i in result.states]
return S
where mesolve takes a list of times (t) as argument, here's my multiprocessing code:
if __name__ == "__main__":
t = np.linspace(0, 25, 100) # list of times t
pool = mp.Pool(mp.cpu_count())
result = pool.map(solve_entropy, t)
pool.close()
pool.join()
data = list(zip(t, result))
np.savetxt("entropy.dat", data, fmt="%.8f")
However when I run this code I get the following error "object of type 'numpy.float64' has no len()".
It seems like mp.Pool splits my list t in float points instead of a smaller list, and since mesolve needs a list as argument I get an error. Is there a way to keep "t" as a list over multiple processes? Since it won't work if "t" is a number.
First, define function
split
, which takes an iterable and splits it into n lists:Then:
Update: Seeing the
split
Function In ActionI have converted the
split
function into a generator function to better see what happens on each iteration. With a list of 93 elements being split into 10 sublists, the algorithm attempts to make each list as close to the same size it can. The code is very clever (I did not write it, but found it). In this case the statementk, m = divmod(l, n)
withl
-> 93 andn
-> 10, it results ink
-> 9 andm
-> 3. Sincem
is not 0, it will createm
lists of sizek+1
andn-m
lists of sizek
.Prints:
Explanation
When
m
is 0 (the iterable of lengthl
can be divided inton
sublists of sizel // n
, then the ith starting slice index is:But when
m
is not 0,min(i, m)
is justi
for the firstm
sublists, so the starting index isand the ending index is
So the first
m
sublists are lengthk + 1
. The starting index of ith sublist fori == m
isand the ending index is
The difference between the ending and starting indices is just
k
.Update 2 Here is
split
rewritten as a generator function, which makes the logic clearer: