Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

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

## [v0.39.1]
Release date: 2025-11-19
Expand Down Expand Up @@ -381,3 +382,4 @@ Release date: 2024-11-13
[#589]: https://github.com/qutip/QuantumToolbox.jl/issues/589
[#591]: https://github.com/qutip/QuantumToolbox.jl/issues/591
[#596]: https://github.com/qutip/QuantumToolbox.jl/issues/596
[#603]: https://github.com/qutip/QuantumToolbox.jl/issues/603
10 changes: 7 additions & 3 deletions src/qobj/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ _Jordan_Wigner(N::Int, j::Int, op::QuantumObject{Operator}) = _Jordan_Wigner(Val

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

σz = sigmaz().data
Z_tensor = kron(1, 1, fill(σz, j - 1)...)
Expand All @@ -493,8 +493,12 @@ end

Generates the projection operator ``\hat{O} = |i \rangle\langle j|`` with Hilbert space dimension `N`.
"""
projection(N::Int, i::Int, j::Int) =
QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N), type = Operator(), dims = N)
function projection(N::Int, i::Int, j::Int)
(0 <= i < N) || throw(ArgumentError("Invalid argument i, must satisfy: 0 ≤ i ≤ N-1"))
(0 <= j < N) || throw(ArgumentError("Invalid argument j, must satisfy: 0 ≤ j ≤ N-1"))

return QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N), type = Operator(), dims = N)
end

@doc raw"""
tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))
Expand Down
26 changes: 12 additions & 14 deletions src/qobj/states.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Functions for generating (common) quantum states.
=#

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

@doc raw"""
fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))
basis(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))

Generates a fock state ``\ket{\psi}`` of dimension `N`.

It is also possible to specify the list of dimensions `dims` if different subsystems are present.

!!! warning "Beware of type-stability!"
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.

!!! note
`basis(N, j; dims = dims, sparse = sparse)` is a synonym of `fock(N, j; dims = dims, sparse = sparse)`.
"""
function fock(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N, sparse::Union{Bool,Val} = Val(false))
(0 <= j < N) || throw(ArgumentError("Invalid argument j, must satisfy: 0 ≤ j ≤ N-1"))
if getVal(sparse)
array = sparsevec([j + 1], [1.0 + 0im], N)
else
Expand All @@ -42,18 +47,6 @@ function fock(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N
return QuantumObject(array; type = Ket(), dims = dims)
end

@doc raw"""
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)

Generates a fock state like [`fock`](@ref).

It is also possible to specify the list of dimensions `dims` if different subsystems are present.

!!! warning "Beware of type-stability!"
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.
"""
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N) = fock(N, j, dims = dims)

@doc raw"""
coherent(N::Int, α::Number)

Expand Down Expand Up @@ -203,7 +196,7 @@ function spin_state(j::Real, m::Real)
throw(ArgumentError("Invalid eigenvalue m: (j - m) must be a non-negative integer."))
(m < (-j)) && throw(ArgumentError("Invalid eigenvalue m, must satisfy: -j ≤ m ≤ j"))

return basis(Int(J), Int(Δ))
return fock(Int(J), Int(Δ))
end

@doc raw"""
Expand Down Expand Up @@ -318,6 +311,8 @@ Returns the `n`-qubit [W-state](https://en.wikipedia.org/wiki/W_state):
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.
"""
function w_state(::Val{n}) where {n}
(n >= 2) || throw(ArgumentError("Invalid argument n, must satisfy: n ≥ 2"))

nzind = 2 .^ (0:(n-1)) .+ 1
nzval = fill(ComplexF64(1 / sqrt(n)), n)
data = zeros(ComplexF64, 2^n)
Expand All @@ -341,6 +336,9 @@ Here, `d` specifies the dimension of each qudit. Default to `d=2` (qubit).
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.
"""
function ghz_state(::Val{n}; d::Int = 2) where {n}
(n >= 2) || throw(ArgumentError("Invalid argument n, must satisfy: n ≥ 2"))
(d >= 2) || throw(ArgumentError("Invalid argument d, must satisfy: d ≥ 2"))

nzind = collect((0:(d-1)) .* Int((d^n - 1) / (d - 1)) .+ 1)
nzval = fill(ComplexF64(1 / sqrt(d)), d)
data = zeros(ComplexF64, d^n)
Expand Down
3 changes: 3 additions & 0 deletions src/qobj/synonyms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Synonyms of the functions for QuantumObject

export Qobj, QobjEvo, shape, isherm
export trans, dag, matrix_element, unit
export basis
export tensor, ⊗
export qeye, qeye_like, qzero_like
export vector_to_operator, operator_to_vector
Expand Down Expand Up @@ -33,6 +34,8 @@ const trans = transpose

const dag = adjoint

const basis = fock

@doc raw"""
matrix_element(i::QuantumObject, A::QuantumObject, j::QuantumObject)

Expand Down
9 changes: 9 additions & 0 deletions test/core-test/states_and_operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# fock, basis, and fock_dm
@test fock_dm(4; dims = (2, 2), sparse = true) ≈ ket2dm(basis(4; dims = (2, 2)))
@test_throws DimensionMismatch fock(4; dims = 2)
@test_throws ArgumentError fock(4, 4)
end

@testset "coherent state" begin
Expand Down Expand Up @@ -121,23 +122,31 @@
@test_throws ArgumentError bell_state(0, 2)
@test_throws ArgumentError bell_state(3, 1)
@test_throws ArgumentError bell_state(2, 3)
@test_throws ArgumentError w_state(1)
@test_throws ArgumentError ghz_state(1)
@test_throws ArgumentError ghz_state(2; d = 1)
end

@testset "bosonic operators" begin
# destroy, create, num, position, momentum
n = 10
i, j = rand(0:(n-1), 2)
a = destroy(n)
ad = create(n)
N = num(n)
x = position(n)
p = momentum(n)
Pij = projection(n, i, j)
@test isoper(x)
@test isoper(p)
@test a.dims == ad.dims == N.dims == x.dims == p.dims == [n]
@test eigenenergies(ad * a) ≈ 0:(n-1)
@test commutator(N, a) ≈ -a
@test commutator(N, ad) ≈ ad
@test all(diag(commutator(x, p))[1:(n-1)] .≈ 1.0im)
@test fock(n, i) == Pij * fock(n, j)
@test_throws ArgumentError projection(n, n, 0)
@test_throws ArgumentError projection(n, 0, n)
end

@testset "displacement and squeezing operators" begin
Expand Down
Loading