Skip to content

Commit fa0b067

Browse files
TendonFFFcailixun
andauthored
Add error message for bad input in state/operator generating functions (#603)
Co-authored-by: cailixun <[email protected]>
1 parent c2df75a commit fa0b067

File tree

5 files changed

+33
-17
lines changed

5 files changed

+33
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main)
9+
- Add error message for bad input in state/operator generating functions ([#603])
910

1011
## [v0.39.1]
1112
Release date: 2025-11-19
@@ -381,3 +382,4 @@ Release date: 2024-11-13
381382
[#589]: https://github.com/qutip/QuantumToolbox.jl/issues/589
382383
[#591]: https://github.com/qutip/QuantumToolbox.jl/issues/591
383384
[#596]: https://github.com/qutip/QuantumToolbox.jl/issues/596
385+
[#603]: https://github.com/qutip/QuantumToolbox.jl/issues/603

src/qobj/operators.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ _Jordan_Wigner(N::Int, j::Int, op::QuantumObject{Operator}) = _Jordan_Wigner(Val
477477

478478
function _Jordan_Wigner(::Val{N}, j::Int, op::QuantumObject{Operator}) where {N}
479479
(N < 1) && throw(ArgumentError("The total number of sites (N) cannot be less than 1"))
480-
((j > N) || (j < 1)) && throw(ArgumentError("The site index (j) should satisfy: 1 ≤ j ≤ N"))
480+
(1 <= j <= N) || throw(ArgumentError("The site index (j) should satisfy: 1 ≤ j ≤ N"))
481481

482482
σz = sigmaz().data
483483
Z_tensor = kron(1, 1, fill(σz, j - 1)...)
@@ -493,8 +493,12 @@ end
493493
494494
Generates the projection operator ``\hat{O} = |i \rangle\langle j|`` with Hilbert space dimension `N`.
495495
"""
496-
projection(N::Int, i::Int, j::Int) =
497-
QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N), type = Operator(), dims = N)
496+
function projection(N::Int, i::Int, j::Int)
497+
(0 <= i < N) || throw(ArgumentError("Invalid argument i, must satisfy: 0 ≤ i ≤ N-1"))
498+
(0 <= j < N) || throw(ArgumentError("Invalid argument j, must satisfy: 0 ≤ j ≤ N-1"))
499+
500+
return QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N), type = Operator(), dims = N)
501+
end
498502

499503
@doc raw"""
500504
tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))

src/qobj/states.jl

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Functions for generating (common) quantum states.
33
=#
44

5-
export zero_ket, fock, basis, coherent, rand_ket
5+
export zero_ket, fock, coherent, rand_ket
66
export fock_dm, coherent_dm, thermal_dm, maximally_mixed_dm, rand_dm
77
export spin_state, spin_coherent
88
export bell_state, singlet_state, triplet_states, w_state, ghz_state
@@ -25,15 +25,20 @@ zero_ket(dimensions::Union{Dimensions,AbstractVector{Int},Tuple}) =
2525

2626
@doc raw"""
2727
fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))
28+
basis(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))
2829
2930
Generates a fock state ``\ket{\psi}`` of dimension `N`.
3031
3132
It is also possible to specify the list of dimensions `dims` if different subsystems are present.
3233
3334
!!! warning "Beware of type-stability!"
3435
If you want to keep type stability, it is recommended to use `fock(N, j, dims=dims, sparse=Val(sparse))` instead of `fock(N, j, dims=dims, sparse=sparse)`. Consider also to use `dims` as a `Tuple` or `SVector` from [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl) instead of `Vector`. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) about type stability for more details.
36+
37+
!!! note
38+
`basis(N, j; dims = dims, sparse = sparse)` is a synonym of `fock(N, j; dims = dims, sparse = sparse)`.
3539
"""
3640
function fock(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N, sparse::Union{Bool,Val} = Val(false))
41+
(0 <= j < N) || throw(ArgumentError("Invalid argument j, must satisfy: 0 ≤ j ≤ N-1"))
3742
if getVal(sparse)
3843
array = sparsevec([j + 1], [1.0 + 0im], N)
3944
else
@@ -42,18 +47,6 @@ function fock(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N
4247
return QuantumObject(array; type = Ket(), dims = dims)
4348
end
4449

45-
@doc raw"""
46-
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)
47-
48-
Generates a fock state like [`fock`](@ref).
49-
50-
It is also possible to specify the list of dimensions `dims` if different subsystems are present.
51-
52-
!!! warning "Beware of type-stability!"
53-
If you want to keep type stability, it is recommended to use `basis(N, j, dims=dims)` with `dims` as a `Tuple` or `SVector` from [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl) instead of `Vector`. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) about type stability for more details.
54-
"""
55-
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N) = fock(N, j, dims = dims)
56-
5750
@doc raw"""
5851
coherent(N::Int, α::Number)
5952
@@ -203,7 +196,7 @@ function spin_state(j::Real, m::Real)
203196
throw(ArgumentError("Invalid eigenvalue m: (j - m) must be a non-negative integer."))
204197
(m < (-j)) && throw(ArgumentError("Invalid eigenvalue m, must satisfy: -j ≤ m ≤ j"))
205198

206-
return basis(Int(J), Int(Δ))
199+
return fock(Int(J), Int(Δ))
207200
end
208201

209202
@doc raw"""
@@ -318,6 +311,8 @@ Returns the `n`-qubit [W-state](https://en.wikipedia.org/wiki/W_state):
318311
If you want to keep type stability, it is recommended to use `w_state(Val(n))` instead of `w_state(n)`. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) for more details.
319312
"""
320313
function w_state(::Val{n}) where {n}
314+
(n >= 2) || throw(ArgumentError("Invalid argument n, must satisfy: n ≥ 2"))
315+
321316
nzind = 2 .^ (0:(n-1)) .+ 1
322317
nzval = fill(ComplexF64(1 / sqrt(n)), n)
323318
data = zeros(ComplexF64, 2^n)
@@ -341,6 +336,9 @@ Here, `d` specifies the dimension of each qudit. Default to `d=2` (qubit).
341336
If you want to keep type stability, it is recommended to use `ghz_state(Val(n))` instead of `ghz_state(n)`. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) for more details.
342337
"""
343338
function ghz_state(::Val{n}; d::Int = 2) where {n}
339+
(n >= 2) || throw(ArgumentError("Invalid argument n, must satisfy: n ≥ 2"))
340+
(d >= 2) || throw(ArgumentError("Invalid argument d, must satisfy: d ≥ 2"))
341+
344342
nzind = collect((0:(d-1)) .* Int((d^n - 1) / (d - 1)) .+ 1)
345343
nzval = fill(ComplexF64(1 / sqrt(d)), d)
346344
data = zeros(ComplexF64, d^n)

src/qobj/synonyms.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Synonyms of the functions for QuantumObject
44

55
export Qobj, QobjEvo, shape, isherm
66
export trans, dag, matrix_element, unit
7+
export basis
78
export tensor,
89
export qeye, qeye_like, qzero_like
910
export vector_to_operator, operator_to_vector
@@ -33,6 +34,8 @@ const trans = transpose
3334

3435
const dag = adjoint
3536

37+
const basis = fock
38+
3639
@doc raw"""
3740
matrix_element(i::QuantumObject, A::QuantumObject, j::QuantumObject)
3841

test/core-test/states_and_operators.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# fock, basis, and fock_dm
2121
@test fock_dm(4; dims = (2, 2), sparse = true) ket2dm(basis(4; dims = (2, 2)))
2222
@test_throws DimensionMismatch fock(4; dims = 2)
23+
@test_throws ArgumentError fock(4, 4)
2324
end
2425

2526
@testset "coherent state" begin
@@ -121,23 +122,31 @@
121122
@test_throws ArgumentError bell_state(0, 2)
122123
@test_throws ArgumentError bell_state(3, 1)
123124
@test_throws ArgumentError bell_state(2, 3)
125+
@test_throws ArgumentError w_state(1)
126+
@test_throws ArgumentError ghz_state(1)
127+
@test_throws ArgumentError ghz_state(2; d = 1)
124128
end
125129

126130
@testset "bosonic operators" begin
127131
# destroy, create, num, position, momentum
128132
n = 10
133+
i, j = rand(0:(n-1), 2)
129134
a = destroy(n)
130135
ad = create(n)
131136
N = num(n)
132137
x = position(n)
133138
p = momentum(n)
139+
Pij = projection(n, i, j)
134140
@test isoper(x)
135141
@test isoper(p)
136142
@test a.dims == ad.dims == N.dims == x.dims == p.dims == [n]
137143
@test eigenenergies(ad * a) 0:(n-1)
138144
@test commutator(N, a) -a
139145
@test commutator(N, ad) ad
140146
@test all(diag(commutator(x, p))[1:(n-1)] .≈ 1.0im)
147+
@test fock(n, i) == Pij * fock(n, j)
148+
@test_throws ArgumentError projection(n, n, 0)
149+
@test_throws ArgumentError projection(n, 0, n)
141150
end
142151

143152
@testset "displacement and squeezing operators" begin

0 commit comments

Comments
 (0)