Skip to content

Commit

Permalink
Convert qnumbers to lazy operators in to_numeric
Browse files Browse the repository at this point in the history
Remove commented out code
  • Loading branch information
david-pl committed Feb 21, 2024
1 parent 9420b78 commit f87003a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/index_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function to_numeric(op::NumberedOperator,b::QuantumOpticsBase.CompositeBasis; ra
end
end
start = 0
if !=(h,nothing) #this is fine here since there are assertions above
if h !== nothing #this is fine here since there are assertions above
aon_ = acts_on(op)
for i = 1:(aon_ - 1)
start = start + ranges[i]
Expand All @@ -64,7 +64,7 @@ function to_numeric(op::NumberedOperator,b::QuantumOpticsBase.CompositeBasis; ra
aon = op.numb + start
end
op_ = _to_numeric(op.op,b.bases[aon];kwargs...)
return QuantumOpticsBase.embed(b,aon,op_)
return QuantumOpticsBase.LazyTensor(b,[aon],(op_,))
end
#function that returns the conjugate of an average, but also preserving the correct ordering
function _inconj(v::Average)
Expand Down
31 changes: 29 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -375,20 +375,47 @@ function to_numeric(op::QSym, b::QuantumOpticsBase.CompositeBasis; kwargs...)
check_basis_match(op.hilbert, b; kwargs...)
aon = acts_on(op)
op_num = _to_numeric(op, b.bases[aon]; kwargs...)
return QuantumOpticsBase.embed(b, aon, op_num)
return QuantumOpticsBase.LazyTensor(b, aon, op_num)
end

# Symbolic expressions
function to_numeric(op::QTerm, b::QuantumOpticsBase.Basis; kwargs...)
f = SymbolicUtils.operation(op)
return _to_numeric_term(f, op, b; kwargs...)
end

function _to_numeric_term(f::Function, op, b; kwargs...)
args = SymbolicUtils.arguments(op)
return f((to_numeric(arg, b; kwargs...) for arg in args)...)
end

function _to_numeric_term(::typeof(*), op::QTerm, b::QuantumOpticsBase.Basis; kwargs...)
args = SymbolicUtils.arguments(op)
factor = 1
args_num = Any[]
for arg in args
if arg isa Number
factor *= arg
else
push!(args_num, to_numeric(arg, b; kwargs...))
end
end

if length(args_num) == 0
return factor * one(b)
end

return *(factor, args_num...)
end

function to_numeric(x::Number, b::QuantumOpticsBase.Basis; kwargs...)
op = one(b)*x
op = _lazy_one(b)*x
return op
end
_lazy_one(b::QuantumOpticsBase.Basis) = one(b)
function _lazy_one(b::QuantumOpticsBase.CompositeBasis)
LazyTensor(b, [1:length(b.bases);], Tuple(one(b_) for b_ in b.bases))
end


"""
Expand Down
95 changes: 87 additions & 8 deletions test/test_numeric_conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,65 @@ a = Destroy(hprod, :a)
σprod(i,j) = Transition(hprod, , i, j)
bprod = bfock bnlevel
for i=1:3, j=1:3
i == j == 1 && continue # rewritten as sum, see below
op1 = a*σprod(i,j)
op2 = a'*σprod(i,j)
@test to_numeric(op1, bprod) == destroy(bfock) transition(bnlevel, i, j)
@test to_numeric(op2, bprod) == create(bfock) transition(bnlevel, i, j)
@test to_numeric(op1, bprod) == LazyTensor(bprod, [1, 2], (destroy(bfock), transition(bnlevel, i, j)))
@test to_numeric(op2, bprod) == LazyTensor(bprod, [1, 2], (create(bfock), transition(bnlevel, i, j)))
end

@test to_numeric(a'*a, bprod) number(bfock) one(bnlevel)
op1_num = to_numeric(a*σprod(1, 1), bprod)
@test op1_num isa LazySum
@test sparse(op1_num) == destroy(bfock) transition(bnlevel, 1, 1)

op2_num = to_numeric(a'*σprod(1, 1), bprod)
@test op2_num isa LazySum
@test sparse(op2_num) == create(bfock) transition(bnlevel, 1, 1)

@test to_numeric(a'*a, bprod) == LazyTensor(bprod, [1,2], (create(bfock) * destroy(bfock), one(bnlevel)))

# Composite basis with symbolic levels
σsym_prod(i,j) = Transition(hfock hnlevel_sym, , i, j)
a = Destroy(hfock hnlevel_sym, :a)
@test_throws ArgumentError to_numeric(a*σsym_prod(:e,:g), bprod)
for i=1:3, j=1:3
i == j == 1 && continue # see below
op1 = a*σsym_prod(levels[i],levels[j])
op2 = a'*σsym_prod(levels[i],levels[j])
@test to_numeric(op1, bprod; level_map=level_map) == destroy(bfock) transition(bnlevel, i, j)
@test to_numeric(op2, bprod; level_map=level_map) == create(bfock) transition(bnlevel, i, j)
@test to_numeric(op1, bprod; level_map=level_map) == LazyTensor(bprod, [1,2], (destroy(bfock), transition(bnlevel, i, j)))
@test to_numeric(op2, bprod; level_map=level_map) == LazyTensor(bprod, [1,2], (create(bfock), transition(bnlevel, i, j)))
end

op1_num = to_numeric(a*σsym_prod(:g, :g), bprod; level_map=level_map)
@test op1_num isa LazySum
@test sparse(op1_num) == destroy(bfock) transition(bnlevel, 1, 1)

op2_num = to_numeric(a'*σsym_prod(:g, :g), bprod; level_map=level_map)
@test op2_num isa LazySum
@test sparse(op2_num) == create(bfock) transition(bnlevel, 1, 1)

# composite basis with a "gap"
hprod_gap = hfock hnlevel hnlevel
bprod_gap = bprod bnlevel
a = Destroy(hprod_gap, :a)
σprod_gap(i,j) = Transition(hprod_gap, , i, j, 3)
for i=1:3, j=1:3
i == j == 1 && continue
op1 = a*σprod_gap(i,j)
op2 = a'*σprod_gap(i,j)
@test to_numeric(op1, bprod_gap) == LazyTensor(bprod_gap, [1,3], (destroy(bfock), transition(bnlevel, i, j)))
@test to_numeric(op2, bprod_gap) == LazyTensor(bprod_gap, [1,3], (create(bfock), transition(bnlevel, i, j)))
end

op1_num = to_numeric(a*σprod_gap(1, 1), bprod_gap)
@test op1_num isa LazySum
@test sparse(op1_num) == destroy(bfock) one(bnlevel) transition(bnlevel, 1, 1)

op2_num = to_numeric(a'*σprod_gap(1, 1), bprod_gap)
@test op2_num isa LazySum
@test sparse(op2_num) == create(bfock) one(bnlevel) transition(bnlevel, 1, 1)


# Numeric average values
α = 0.1 + 0.2im
ψ = coherentstate(bfock, α)
Expand All @@ -79,6 +119,18 @@ for i=1:3, j=1:3
@test numeric_average(op_sym, ψprod; level_map=level_map) expect(op_num, ψprod)
end

# LazyKet
if isdefined(QuantumOpticsBase, :LazyKet)
ψlazy = LazyKet(bprod, (ψ, nlevelstate(bnlevel, 1)))
@test_throws ArgumentError numeric_average(σsym_prod(:e,:g), ψlazy)
for i=1:3, j=1:3
op = σprod(i, j)
op_sym = σsym_prod(levels[i],levels[j])
op_num = LazyTensor(bprod, [2], (transition(bnlevel, i, j),))
@test numeric_average(op, ψlazy) expect(op_num, ψlazy)
@test numeric_average(op_sym, ψlazy; level_map=level_map) expect(op_num, ψlazy)
end
end

# Initial values in actual equations
levels = (:g,:e)
Expand Down Expand Up @@ -106,6 +158,19 @@ u0 = initial_values(eqs, ψ0; level_map=level_map)
@test u0[4] expect(one(bcav) transition(batom, 2, 2), ψ0)
@test u0[5] expect(create(bcav) transition(batom, 1, 2), ψ0)


if isdefined(QuantumOpticsBase, :LazyKet)
ψlazy = LazyKet(b, (randstate(bcav), randstate(batom)))
ψfull = Ket(ψlazy)
u0 = initial_values(eqs, ψlazy; level_map=level_map)

@test u0[1] expect(destroy(bcav) one(batom), ψfull)
@test u0[2] expect(one(bcav) transition(batom, 1, 2), ψfull)
@test u0[3] expect(number(bcav) one(batom), ψfull)
@test u0[4] expect(one(bcav) transition(batom, 2, 2), ψfull)
@test u0[5] expect(create(bcav) transition(batom, 1, 2), ψfull)
end

# Test sufficiently large hilbert space; from issue #109
hfock = FockSpace(:fock)
@qnumbers a::Destroy(hfock)
Expand Down Expand Up @@ -135,8 +200,8 @@ b = tensor(bc, [ba for i=1:order]...)
ψc = fockstate(bc, 0)
ψa = normalize(nlevelstate(ba,1) + nlevelstate(ba,2))
ψ = tensor(ψc, [ψa for i=1:order]...)
a_ = QuantumOpticsBase.embed(b,1,destroy(bc))
σ_(i,j,k) = QuantumOpticsBase.embed(b,1+k,transition(ba,i,j))
a_ = LazyTensor(b, [1], (destroy(bc),))
σ_(i,j,k) = LazyTensor(b,[1+k],(transition(ba,i,j),))
ranges=[1,2]
@test to_numeric(σ(1,2,1),b; ranges=ranges) == σ_(1,2,1)
@test to_numeric(σ(2,2,2),b; ranges=ranges) == σ_(2,2,2)
Expand All @@ -147,6 +212,16 @@ ranges=[1,2]
@test numeric_average(average(a'a), ψ; ranges=ranges) 0.0
@test numeric_average(average(a*σ(2,2,1)), ψ; ranges=ranges) 0.0
@test_throws ArgumentError numeric_average(average(a'a), ψ)

if isdefined(QuantumOpticsBase, :LazyKet)
ψlazy = LazyKet(b, (ψc, (ψa for i=1:order)...,))
@test numeric_average(σ(2,2,2), ψlazy; ranges=ranges) 0.5
@test numeric_average(average(σ(2,2,1)), ψlazy; ranges=ranges) 0.5
@test numeric_average(average(a'a), ψlazy; ranges=ranges) 0.0
@test numeric_average(average(a*σ(2,2,1)), ψlazy; ranges=ranges) 0.0
@test_throws ArgumentError numeric_average(average(a'a), ψlazy)
end

# Hamiltonian
H = -Δ*a'a + g*(Σ(a'*σ(1,2,i),i) + Σ(a*σ(2,1,i),i))
J = [a,σ(1,2,i)]
Expand All @@ -157,7 +232,10 @@ eqs_c = complete(eqs)
eqs_sc = scale(eqs_c)
@named sys = ODESystem(eqs_sc)
@test_throws ArgumentError initial_values(eqs_sc, ψ)

u0 = initial_values(eqs_sc, ψ; ranges=ranges)
@test u0 initial_values(eqs_sc, ψlazy; ranges=ranges)

N_ = 2e5
Γ_ = 1.0 #Γ=1mHz
Δ_ = 2500Γ_ #Δ=2.5Hz
Expand All @@ -167,6 +245,7 @@ ps = [N, Δ, g, κ, Γ]
p0 = [N_, Δ_, g_, κ_, Γ_]

prob = ODEProblem(sys,u0,(0.0, 1e-4/Γ_), ps.=>p0)
@test solve(prob, Tsit5()) isa ODESolution
sol = solve(prob, Tsit5(); save_on=false, save_everystep=false)
@test sol.retcode == ReturnCode.Success

end # testset

0 comments on commit f87003a

Please sign in to comment.