Skip to content

Commit 5c31a46

Browse files
authored
Add a charge basis (#170)
Add ChargeBasis --------- Co-authored-by: Arne Grimsmo
1 parent e43b8c3 commit 5c31a46

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

docs/src/api.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,31 @@ coherentstate
307307
coherentstate!
308308
```
309309

310+
### [Charge](@id API: Charge)
311+
312+
```@docs
313+
ChargeBasis
314+
```
315+
316+
```@docs
317+
ShiftedChargeBasis
318+
```
319+
320+
```@docs
321+
chargeop
322+
```
323+
324+
```@docs
325+
expiφ
326+
```
327+
328+
```@docs
329+
cosφ
330+
```
331+
332+
```@docs
333+
sinφ
334+
```
310335

311336
### [N-level](@id API: N-level)
312337

src/QuantumOpticsBase.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export Basis, GenericBasis, CompositeBasis, basis,
4242
fockstate, coherentstate, coherentstate!,
4343
displace, displace_analytical, displace_analytical!,
4444
squeeze,
45+
# charge
46+
ChargeBasis, ShiftedChargeBasis, chargestate, chargeop, expiφ, cosφ, sinφ,
4547
randstate, randoperator, thermalstate, coherentthermalstate, phase_average, passive_state,
4648
randstate_haar, randunitary_haar,
4749
#spin
@@ -82,6 +84,7 @@ include("states_lazyket.jl")
8284
include("superoperators.jl")
8385
include("spin.jl")
8486
include("fock.jl")
87+
include("charge.jl")
8588
include("state_definitions.jl")
8689
include("subspace.jl")
8790
include("particle.jl")

src/charge.jl

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
"""
2+
ChargeBasis(ncut) <: Basis
3+
4+
Basis spanning `-ncut, ..., ncut` charge states, which are the fourier modes
5+
(irreducible representations) of a continuous U(1) degree of freedom, truncated
6+
at `ncut`.
7+
8+
The charge basis is a natural representation for circuit-QED elements such as
9+
the "transmon", which has a hamiltonian of the form
10+
```julia
11+
b = ChargeBasis(ncut)
12+
H = 4E_C * (n_g * identityoperator(b) + chargeop(b))^2 - E_J * cosφ(b)
13+
```
14+
with energies periodic in the charge offset `n_g`.
15+
See e.g. https://arxiv.org/abs/2005.12667.
16+
"""
17+
struct ChargeBasis{T} <: Basis
18+
shape::Vector{T}
19+
dim::T
20+
ncut::T
21+
function ChargeBasis(ncut::T) where {T}
22+
if ncut < 0
23+
throw(DimensionMismatch())
24+
end
25+
dim = 2 * ncut + 1
26+
new{T}([dim], dim, ncut)
27+
end
28+
end
29+
30+
Base.:(==)(b1::ChargeBasis, b2::ChargeBasis) = (b1.ncut == b2.ncut)
31+
32+
"""
33+
ShiftedChargeBasis(nmin, nmax) <: Basis
34+
35+
Basis spanning `nmin, ..., nmax` charge states. See [`ChargeBasis`](@ref).
36+
"""
37+
struct ShiftedChargeBasis{T} <: Basis
38+
shape::Vector{T}
39+
dim::T
40+
nmin::T
41+
nmax::T
42+
function ShiftedChargeBasis(nmin::T, nmax::T) where {T}
43+
if nmax <= nmin
44+
throw(DimensionMismatch())
45+
end
46+
dim = nmax - nmin + 1
47+
new{T}([dim], dim, nmin, nmax)
48+
end
49+
end
50+
51+
Base.:(==)(b1::ShiftedChargeBasis, b2::ShiftedChargeBasis) =
52+
(b1.nmin == b2.nmin && b1.nmax == b2.nmax)
53+
54+
"""
55+
chargestate([T=ComplexF64,] b::ChargeBasis, n)
56+
chargestate([T=ComplexF64,] b::ShiftedChargeBasis, n)
57+
58+
Charge state ``|n⟩`` for given [`ChargeBasis`](@ref) or [`ShiftedChargeBasis`](@ref).
59+
"""
60+
chargestate(::Type{T}, b::ChargeBasis, n::Integer) where {T} =
61+
basisstate(T, b, n + b.ncut + 1)
62+
63+
chargestate(::Type{T}, b::ShiftedChargeBasis, n::Integer) where {T} =
64+
basisstate(T, b, n - b.nmin + 1)
65+
66+
chargestate(b, n) = chargestate(ComplexF64, b, n)
67+
68+
"""
69+
chargeop([T=ComplexF64,] b::ChargeBasis)
70+
chargeop([T=ComplexF64,] b::ShiftedChargeBasis)
71+
72+
Return diagonal charge operator ``N`` for given [`ChargeBasis`](@ref) or
73+
[`ShiftedChargeBasis`](@ref).
74+
"""
75+
function chargeop(::Type{T}, b::ChargeBasis) where {T}
76+
data = spdiagm(T.(-b.ncut:1:b.ncut))
77+
return SparseOperator(b, b, data)
78+
end
79+
80+
function chargeop(::Type{T}, b::ShiftedChargeBasis) where {T}
81+
data = spdiagm(T.(b.nmin:1:b.nmax))
82+
return SparseOperator(b, b, data)
83+
end
84+
85+
chargeop(b) = chargeop(ComplexF64, b)
86+
87+
"""
88+
expiφ([T=ComplexF64,] b::ChargeBasis, k=1)
89+
expiφ([T=ComplexF64,] b::ShiftedChargeBasis, k=1)
90+
91+
Return operator ``\\exp(i k φ)`` for given [`ChargeBasis`](@ref) or
92+
[`ShiftedChargeBasis`](@ref), representing the continous U(1) degree of
93+
freedom conjugate to the charge. This is a "shift" operator that shifts
94+
the charge by `k`.
95+
"""
96+
function expiφ(::Type{T}, b::ChargeBasis; k=1) where {T}
97+
if abs(k) > 2 * b.ncut
98+
data = spzeros(T, b.dim, b.dim)
99+
else
100+
v = ones(T, b.dim - abs(k))
101+
data = spdiagm(-k => v)
102+
end
103+
return SparseOperator(b, b, data)
104+
end
105+
106+
function expiφ(::Type{T}, b::ShiftedChargeBasis; k=1) where {T}
107+
if abs(k) > b.dim - 1
108+
data = spzeros(T, b.dim, b.dim)
109+
else
110+
v = ones(T, b.dim - abs(k))
111+
data = spdiagm(-k => v)
112+
end
113+
return SparseOperator(b, b, data)
114+
end
115+
116+
expiφ(b; kwargs...) = expiφ(ComplexF64, b; kwargs...)
117+
118+
"""
119+
cosφ([T=ComplexF64,] b::ChargeBasis; k=1)
120+
cosφ([T=ComplexF64,] b::ShiftedChargeBasis; k=1)
121+
122+
Return operator ``\\cos(k φ)`` for given charge basis. See [`expiφ`](@ref).
123+
"""
124+
function cosφ(::Type{T}, b::Union{ChargeBasis,ShiftedChargeBasis}; k=1) where {T}
125+
d = expiφ(b; k=k)
126+
return (d + d') / 2
127+
end
128+
129+
cosφ(b; kwargs...) = cosφ(ComplexF64, b; kwargs...)
130+
131+
"""
132+
sinφ([T=ComplexF64,] b::ChargeBasis; k=1)
133+
sinφ([T=ComplexF64,] b::ShiftedChargeBasis; k=1)
134+
135+
Return operator ``\\sin(k φ)`` for given charge basis. See [`expiφ`](@ref).
136+
"""
137+
function sinφ(::Type{T}, b::Union{ChargeBasis,ShiftedChargeBasis}; k=1) where {T}
138+
d = expiφ(b; k=k)
139+
return (d - d') / 2im
140+
end
141+
142+
sinφ(b; kwargs...) = sinφ(ComplexF64, b; kwargs...)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ names = [
1414
"test_time_dependent_operators.jl",
1515

1616
"test_fock.jl",
17+
"test_charge.jl",
1718
"test_spin.jl",
1819
"test_particle.jl",
1920
"test_manybody.jl",

test/test_charge.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Test
2+
using QuantumOpticsBase
3+
4+
@testset "charge" begin
5+
6+
@test_throws DimensionMismatch ChargeBasis(-1)
7+
8+
@test_throws DimensionMismatch ShiftedChargeBasis(2, 1)
9+
10+
ncut = rand(1:10)
11+
cb1 = ChargeBasis(ncut)
12+
cb2 = ChargeBasis(ncut)
13+
@test cb1 == cb2
14+
15+
n1 = rand(-10:-1)
16+
n2 = rand(1:10)
17+
cb1 = ShiftedChargeBasis(n1, n2)
18+
cb2 = ShiftedChargeBasis(n1, n2)
19+
@test cb1 == cb2
20+
21+
for cb in [ChargeBasis(5), ShiftedChargeBasis(-4, 5)]
22+
ψ = chargestate(cb, -3)
23+
eiφ = expiφ(cb)
24+
@test eiφ * ψ == chargestate(cb, -2)
25+
@test eiφ' * ψ == chargestate(cb, -4)
26+
@test expiφ(cb, k=3) * ψ == chargestate(cb, 0)
27+
@test expiφ(cb, k=9) * ψ == 0 * ψ
28+
@test expiφ(cb, k=-3) * ψ == 0 * ψ
29+
@test expiφ(cb, k=3) == eiφ^3
30+
@test expiφ(cb, k=11) == 0 * eiφ
31+
32+
@test eltype(chargeop(Float64, cb).data) == Float64
33+
@test eltype(chargeop(ComplexF64, cb).data) == ComplexF64
34+
@test eltype(expiφ(Float64, cb).data) == Float64
35+
@test eltype(expiφ(ComplexF64, cb).data) == ComplexF64
36+
37+
n = chargeop(cb)
38+
@test n * ψ == -3 * ψ
39+
@test n * eiφ - eiφ * n == eiφ
40+
41+
ei3φ = expiφ(cb, k=3)
42+
@test cosφ(cb, k=3) == (ei3φ + ei3φ') / 2
43+
@test sinφ(cb, k=3) == (ei3φ - ei3φ') / 2im
44+
end
45+
46+
end # testset

0 commit comments

Comments
 (0)