Skip to content

Commit 8f16def

Browse files
[WIP] Improve generation performance in manybody.jl (#121)
* Improve generation performance in manybody.jl --------- Co-authored-by: Stefan Krastanov <[email protected]>
1 parent 1d4ad57 commit 8f16def

File tree

2 files changed

+56
-56
lines changed

2 files changed

+56
-56
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "QuantumOpticsBase"
22
uuid = "4f57444f-1401-5e15-980d-4471b28d5678"
3-
version = "0.4.9"
3+
version = "0.4.10"
44

55
[deps]
66
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

src/manybody.jl

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ end
8181
Creation operator for the i-th mode of the many-body basis `b`.
8282
"""
8383
function create(::Type{T}, b::ManyBodyBasis, index) where T
84-
result = SparseOperator(T, b)
84+
Is = Int[]
85+
Js = Int[]
86+
Vs = T[]
8587
# <{m}_i| at |{m}_j>
8688
for i=1:length(b)
8789
occ_i = b.occupations[i]
@@ -90,11 +92,13 @@ function create(::Type{T}, b::ManyBodyBasis, index) where T
9092
end
9193
for j=1:length(b)
9294
if isnonzero(occ_i, b.occupations[j], index)
93-
result.data[i, j] = sqrt(occ_i[index])
95+
push!(Is, i)
96+
push!(Js, j)
97+
push!(Vs, sqrt(occ_i[index]))
9498
end
9599
end
96100
end
97-
result
101+
return SparseOperator(b, sparse(Is, Js, Vs, length(b), length(b)))
98102
end
99103
create(b::ManyBodyBasis, index) = create(ComplexF64, b, index)
100104

@@ -104,7 +108,9 @@ create(b::ManyBodyBasis, index) = create(ComplexF64, b, index)
104108
Annihilation operator for the i-th mode of the many-body basis `b`.
105109
"""
106110
function destroy(::Type{T}, b::ManyBodyBasis, index) where T
107-
result = SparseOperator(T, b)
111+
Is = Int[]
112+
Js = Int[]
113+
Vs = T[]
108114
# <{m}_j| a |{m}_i>
109115
for i=1:length(b)
110116
occ_i = b.occupations[i]
@@ -113,11 +119,13 @@ function destroy(::Type{T}, b::ManyBodyBasis, index) where T
113119
end
114120
for j=1:length(b)
115121
if isnonzero(occ_i, b.occupations[j], index)
116-
result.data[j, i] = sqrt(occ_i[index])
122+
push!(Is, j)
123+
push!(Js, i)
124+
push!(Vs, sqrt(occ_i[index]))
117125
end
118126
end
119127
end
120-
result
128+
return SparseOperator(b, sparse(Is, Js, Vs, length(b), length(b)))
121129
end
122130
destroy(b::ManyBodyBasis, index) = destroy(ComplexF64, b, index)
123131

@@ -127,11 +135,7 @@ destroy(b::ManyBodyBasis, index) = destroy(ComplexF64, b, index)
127135
Particle number operator for the i-th mode of the many-body basis `b`.
128136
"""
129137
function number(::Type{T}, b::ManyBodyBasis, index) where T
130-
result = SparseOperator(T, b)
131-
for i=1:length(b)
132-
result.data[i, i] = b.occupations[i][index]
133-
end
134-
result
138+
diagonaloperator(b, T[b.occupations[i][index] for i in 1:length(b)])
135139
end
136140
number(b::ManyBodyBasis, index) = number(ComplexF64, b, index)
137141

@@ -141,11 +145,7 @@ number(b::ManyBodyBasis, index) = number(ComplexF64, b, index)
141145
Total particle number operator.
142146
"""
143147
function number(::Type{T}, b::ManyBodyBasis) where T
144-
result = SparseOperator(T, b)
145-
for i=1:length(b)
146-
result.data[i, i] = sum(b.occupations[i])
147-
end
148-
result
148+
diagonaloperator(b, T[sum(b.occupations[i]) for i in 1:length(b)])
149149
end
150150
number(b::ManyBodyBasis) = number(ComplexF64, b)
151151

@@ -178,7 +178,9 @@ end
178178
Operator ``|\\mathrm{to}⟩⟨\\mathrm{from}|`` transferring particles between modes.
179179
"""
180180
function transition(::Type{T}, b::ManyBodyBasis, to, from) where T
181-
result = SparseOperator(T, b)
181+
Is = Int[]
182+
Js = Int[]
183+
Vs = T[]
182184
# <{m}_j| at_to a_from |{m}_i>
183185
for i=1:length(b)
184186
occ_i = b.occupations[i]
@@ -188,11 +190,13 @@ function transition(::Type{T}, b::ManyBodyBasis, to, from) where T
188190
for j=1:length(b)
189191
occ_j = b.occupations[j]
190192
if isnonzero(occ_j, occ_i, to, from)
191-
result.data[j, i] = sqrt(occ_i[from])*sqrt(occ_j[to])
193+
push!(Is, j)
194+
push!(Js, i)
195+
push!(Vs, sqrt(occ_i[from]) * sqrt(occ_j[to]))
192196
end
193197
end
194198
end
195-
result
199+
return SparseOperator(b, sparse(Is, Js, Vs, length(b), length(b)))
196200
end
197201
transition(b::ManyBodyBasis, to, from) = transition(ComplexF64, b, to, from)
198202

@@ -240,7 +244,7 @@ function manybodyoperator_1(basis::ManyBodyBasis, op::Operator)
240244
result = DenseOperator(basis)
241245
@inbounds for n=1:N, m=1:N
242246
for j=1:S, i=1:S
243-
C = coefficient(basis.occupations[m], basis.occupations[n], [i], [j])
247+
C = coefficient(basis.occupations[m], basis.occupations[n], i, j)
244248
if C != 0.
245249
result.data[m,n] += C*op.data[i,j]
246250
end
@@ -252,22 +256,25 @@ manybodyoperator_1(basis::ManyBodyBasis, op::AdjointOperator) = dagger(manybodyo
252256

253257
function manybodyoperator_1(basis::ManyBodyBasis, op::SparseOpPureType)
254258
N = length(basis)
255-
S = length(basis.onebodybasis)
256-
result = SparseOperator(basis)
257259
M = op.data
260+
Is = Int[]
261+
Js = Int[]
262+
Vs = ComplexF64[]
258263
@inbounds for colindex = 1:M.n
259264
for i=M.colptr[colindex]:M.colptr[colindex+1]-1
260265
row = M.rowval[i]
261266
value = M.nzval[i]
262267
for m=1:N, n=1:N
263-
C = coefficient(basis.occupations[m], basis.occupations[n], [row], [colindex])
268+
C = coefficient(basis.occupations[m], basis.occupations[n], row, colindex)
264269
if C != 0.
265-
result.data[m, n] += C*value
270+
push!(Is, m)
271+
push!(Js, n)
272+
push!(Vs, C * value)
266273
end
267274
end
268275
end
269276
end
270-
return result
277+
return SparseOperator(basis, sparse(Is, Js, Vs, N, N))
271278
end
272279

273280
function manybodyoperator_2(basis::ManyBodyBasis, op::Operator)
@@ -280,7 +287,7 @@ function manybodyoperator_2(basis::ManyBodyBasis, op::Operator)
280287
occupations = basis.occupations
281288
@inbounds for m=1:N, n=1:N
282289
for l=1:S, k=1:S, j=1:S, i=1:S
283-
C = coefficient(occupations[m], occupations[n], [i, j], [k, l])
290+
C = coefficient(occupations[m], occupations[n], (i, j), (k, l))
284291
result.data[m,n] += C*op_data[i, j, k, l]
285292
end
286293
end
@@ -290,7 +297,9 @@ end
290297
function manybodyoperator_2(basis::ManyBodyBasis, op::SparseOpType)
291298
N = length(basis)
292299
S = length(basis.onebodybasis)
293-
result = SparseOperator(basis)
300+
Is = Int[]
301+
Js = Int[]
302+
Vs = ComplexF64[]
294303
occupations = basis.occupations
295304
rows = rowvals(op.data)
296305
values = nonzeros(op.data)
@@ -302,11 +311,13 @@ function manybodyoperator_2(basis::ManyBodyBasis, op::SparseOpType)
302311
index = Tuple(CartesianIndices((S, S, S, S))[(column-1)*S^2 + row])
303312
C = coefficient(occupations[m], occupations[n], index[1:2], index[3:4])
304313
if C!=0.
305-
result.data[m,n] += C*value
314+
push!(Is, m)
315+
push!(Js, n)
316+
push!(Vs, C * value)
306317
end
307318
end
308319
end
309-
return result
320+
return SparseOperator(basis, sparse(Is, Js, Vs, N, N))
310321
end
311322

312323

@@ -354,7 +365,7 @@ function onebodyexpect_1(op::Operator, state::Ket)
354365
for m=1:N, n=1:N
355366
value = conj(state.data[m])*state.data[n]
356367
for i=1:S, j=1:S
357-
C = coefficient(occupations[m], occupations[n], [i], [j])
368+
C = coefficient(occupations[m], occupations[n], i, j)
358369
if C != 0.
359370
result += C*op.data[i,j]*value
360371
end
@@ -371,7 +382,7 @@ function onebodyexpect_1(op::Operator, state::Operator)
371382
@inbounds for s=1:N, t=1:N
372383
value = state.data[t,s]
373384
for i=1:S, j=1:S
374-
C = coefficient(occupations[s], occupations[t], [i], [j])
385+
C = coefficient(occupations[s], occupations[t], i, j)
375386
if !iszero(C)
376387
result += C*op.data[i,j]*value
377388
end
@@ -391,7 +402,7 @@ function onebodyexpect_1(op::SparseOpPureType, state::Ket)
391402
row = M.rowval[i]
392403
value = M.nzval[i]
393404
for m=1:N, n=1:N
394-
C = coefficient(occupations[m], occupations[n], [row], [colindex])
405+
C = coefficient(occupations[m], occupations[n], row, colindex)
395406
if C != 0.
396407
result += C*value*conj(state.data[m])*state.data[n]
397408
end
@@ -412,7 +423,7 @@ function onebodyexpect_1(op::SparseOpPureType, state::Operator)
412423
row = M.rowval[i]
413424
value = M.nzval[i]
414425
for s=1:N, t=1:N
415-
C = coefficient(occupations[s], occupations[t], [row], [colindex])
426+
C = coefficient(occupations[s], occupations[t], row, colindex)
416427
if C != 0.
417428
result += C*value*state.data[t,s]
418429
end
@@ -426,29 +437,18 @@ end
426437
"""
427438
Calculate the matrix element <{m}|at_1...at_n a_1...a_n|{n}>.
428439
"""
429-
function coefficient(occ_m, occ_n, at_indices, a_indices)
430-
occ_m = copy(occ_m)
431-
occ_n = copy(occ_n)
432-
C = 1.
433-
for i=at_indices
434-
if occ_m[i] == 0
435-
return 0.
436-
end
437-
C *= sqrt(occ_m[i])
438-
occ_m[i] -= 1
439-
end
440-
for i=a_indices
441-
if occ_n[i] == 0
442-
return 0.
443-
end
444-
C *= sqrt(occ_n[i])
445-
occ_n[i] -= 1
446-
end
447-
if occ_m == occ_n
448-
return C
449-
else
450-
return 0.
440+
Base.@propagate_inbounds function coefficient(occ_m, occ_n, at_indices, a_indices)
441+
any(==(0), (occ_m[m] for m in at_indices)) && return 0.
442+
any(==(0), (occ_n[n] for n in a_indices)) && return 0.
443+
C = prod(, (occ_m[m] for m in at_indices)) * prod(, (occ_n[n] for n in a_indices))
444+
for i in 1:length(occ_m)
445+
vm = occ_m[i]
446+
vn = occ_n[i]
447+
i in at_indices && (vm -= 1)
448+
i in a_indices && (vn -= 1)
449+
vm != vn && return zero(C)
451450
end
451+
return C
452452
end
453453

454454
function _distribute_bosons(Nparticles, Nmodes, index, occupations, results)

0 commit comments

Comments
 (0)