Skip to content

Commit 4784a58

Browse files
Fix ptrace and operators
1 parent 8b63d69 commit 4784a58

File tree

7 files changed

+205
-60
lines changed

7 files changed

+205
-60
lines changed

src/qobj/arithmetic_and_attributes.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ function ptrace(QO::QuantumObject{<:AbstractArray,KetQuantumObject}, sel::Union{
515515
length(QO.dims) == 1 && return QO
516516

517517
ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, SVector(sel))
518-
return QuantumObject(ρtr, dims = dkeep)
518+
return QuantumObject(ρtr, type=Operator, dims = dkeep)
519519
end
520520

521521
ptrace(QO::QuantumObject{<:AbstractArray,BraQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) = ptrace(QO', sel)
@@ -524,7 +524,7 @@ function ptrace(QO::QuantumObject{<:AbstractArray,OperatorQuantumObject}, sel::U
524524
length(QO.dims) == 1 && return QO
525525

526526
ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, SVector(sel))
527-
return QuantumObject(ρtr, dims = dkeep)
527+
return QuantumObject(ρtr, type=Operator, dims = dkeep)
528528
end
529529
ptrace(QO::QuantumObject, sel::Int) = ptrace(QO, SVector(sel))
530530

@@ -547,7 +547,7 @@ function _ptrace_ket(QO::AbstractArray, dims::Union{SVector,MVector}, sel)
547547

548548
vmat = reshape(QO, reverse(dims)...)
549549
topermute = nd + 1 .- sel_qtrace
550-
vmat = PermutedDimsArray(vmat, topermute)
550+
vmat = permutedims(vmat, topermute) # TODO: use PermutedDimsArray when Julia v1.11.0 is released
551551
vmat = reshape(vmat, prod(dkeep), prod(dtrace))
552552

553553
return vmat * vmat', dkeep
@@ -576,14 +576,14 @@ function _ptrace_oper(QO::AbstractArray, dims::Union{SVector,MVector}, sel)
576576

577577
ρmat = reshape(QO, reverse(vcat(dims, dims))...)
578578
topermute = 2 * nd + 1 .- qtrace_sel
579-
ρmat = PermutedDimsArray(ρmat, reverse(topermute))
579+
ρmat = permutedims(ρmat, reverse(topermute)) # TODO: use PermutedDimsArray when Julia v1.11.0 is released
580580

581581
## TODO: Check if it works always
582582

583583
# ρmat = row_major_reshape(ρmat, prod(dtrace), prod(dtrace), prod(dkeep), prod(dkeep))
584584
# res = dropdims(mapslices(tr, ρmat, dims=(1,2)), dims=(1,2))
585585
ρmat = reshape(ρmat, prod(dkeep), prod(dkeep), prod(dtrace), prod(dtrace))
586-
res = dropdims(mapslices(tr, ρmat, dims = (3, 4)), dims = (3, 4))
586+
res = map(tr, eachslice(ρmat, dims = (1, 2)))
587587

588588
return res, dkeep
589589
end

src/qobj/operators.jl

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export tunneling
1313
export qft
1414

1515
@doc raw"""
16-
rand_unitary(dimensions, distribution=:haar)
16+
rand_unitary(dimensions, distribution=Val(:haar))
1717
1818
Returns a random unitary [`QuantumObject`](@ref).
1919
@@ -27,10 +27,13 @@ The `distribution` specifies which of the method used to obtain the unitary matr
2727
2828
# References
2929
1. [F. Mezzadri, How to generate random matrices from the classical compact groups, arXiv:math-ph/0609050 (2007)](https://arxiv.org/abs/math-ph/0609050)
30+
31+
!!! warning "Beware of type-stability!"
32+
If you want to keep type stability, it is recommended to use `rand_unitary(dimensions, Val(distribution))` instead of `rand_unitary(dimensions, distribution)`. Also, put `dimensions` as `Tuple` or `SVector`. 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.
3033
"""
31-
rand_unitary(dimensions::Int, distribution::Symbol = :haar) = rand_unitary(SVector(dimensions), Val(distribution))
32-
rand_unitary(dimensions::Union{AbstractVector{Int},Tuple}, distribution::Symbol = :haar) =
33-
rand_unitary(dimensions, Val(distribution))
34+
rand_unitary(dimensions::Int, distribution::Union{Symbol,Val} = Val(:haar)) = rand_unitary(SVector(dimensions), makeVal(distribution))
35+
rand_unitary(dimensions::Union{AbstractVector{Int},Tuple}, distribution::Union{Symbol,Val} = Val(:haar)) =
36+
rand_unitary(dimensions, makeVal(distribution))
3437
function rand_unitary(dimensions::Union{AbstractVector{Int},Tuple}, ::Val{:haar})
3538
N = prod(dimensions)
3639

@@ -224,7 +227,7 @@ function phase(N::Int, ϕ0::Real = 0)
224227
end
225228

226229
@doc raw"""
227-
jmat(j::Real, which::Symbol)
230+
jmat(j::Real, which::Union{Symbol,Val})
228231
229232
Generate higher-order Spin-`j` operators, where `j` is the spin quantum number and can be a non-negative integer or half-integer
230233
@@ -250,7 +253,18 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false
250253
2×2 SparseMatrixCSC{ComplexF64, Int64} with 1 stored entry:
251254
⋅ ⋅
252255
1.0+0.0im ⋅
256+
257+
julia> jmat(1.5, Val(:z))
258+
Quantum Object: type=Operator dims=[4] size=(4, 4) ishermitian=true
259+
4×4 SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
260+
1.5+0.0im ⋅ ⋅ ⋅
261+
⋅ 0.5+0.0im ⋅ ⋅
262+
⋅ ⋅ -0.5+0.0im ⋅
263+
⋅ ⋅ ⋅ -1.5+0.0im
253264
```
265+
266+
!!! warning "Beware of type-stability!"
267+
If you want to keep type stability, it is recommended to use `jmat(j, Val(which))` instead of `jmat(j, which)`. 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.
254268
"""
255269
jmat(j::Real, which::Symbol) = jmat(j, Val(which))
256270
jmat(j::Real) = (jmat(j, Val(:x)), jmat(j, Val(:y)), jmat(j, Val(:z)))
@@ -427,8 +441,8 @@ d_j = \sigma_z^{\otimes j} \otimes \sigma_{-} \otimes I^{\otimes N-j-1}
427441
428442
Note that the site index `j` should satisfy: `0 ≤ j ≤ N - 1`.
429443
430-
> [!IMPORTANT]
431-
> If you want to keep type stability, it is recommended to use `fdestroy(Val(N), j)` instead of `fdestroy(N, j)`. 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.
444+
!!! warning "Beware of type-stability!"
445+
If you want to keep type stability, it is recommended to use `fdestroy(Val(N), j)` instead of `fdestroy(N, j)`. 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.
432446
"""
433447
fdestroy(N::Union{Int,Val}, j::Int) = _Jordan_Wigner(N, j, sigmam())
434448

@@ -444,8 +458,8 @@ d_j^\dagger = \sigma_z^{\otimes j} \otimes \sigma_{+} \otimes I^{\otimes N-j-1}
444458
445459
Note that the site index `j` should satisfy: `0 ≤ j ≤ N - 1`.
446460
447-
> [!IMPORTANT]
448-
> If you want to keep type stability, it is recommended to use `fcreate(Val(N), j)` instead of `fcreate(N, j)`. 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.
461+
!!! warning "Beware of type-stability!"
462+
If you want to keep type stability, it is recommended to use `fcreate(Val(N), j)` instead of `fcreate(N, j)`. 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.
449463
"""
450464
fcreate(N::Union{Int,Val}, j::Int) = _Jordan_Wigner(N, j, sigmap())
451465

@@ -470,7 +484,7 @@ end
470484
471485
Generates the projection operator ``\hat{O} = \dyad{i}{j}`` with Hilbert space dimension `N`.
472486
"""
473-
projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N))
487+
projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N), type=Operator)
474488

475489
@doc raw"""
476490
tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))
@@ -485,8 +499,8 @@ where ``N`` is the number of basis states in the Hilbert space, and ``m`` is the
485499
486500
If `sparse=true`, the operator is returned as a sparse matrix, otherwise a dense matrix is returned.
487501
488-
> [!IMPORTANT]
489-
> If you want to keep type stability, it is recommended to use `tunneling(N, m, Val(sparse))` instead of `tunneling(N, m, sparse)`. 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.
502+
!!! warning "Beware of type-stability!"
503+
If you want to keep type stability, it is recommended to use `tunneling(N, m, Val(sparse))` instead of `tunneling(N, m, sparse)`. 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.
490504
"""
491505
function tunneling(N::Int, m::Int = 1; sparse::Union{Bool,Val} = Val(false))
492506
(m < 1) && throw(ArgumentError("The number of excitations (m) cannot be less than 1"))
@@ -522,6 +536,9 @@ The `dimensions` can be either the following types:
522536
```
523537
524538
where ``\omega = \exp(\frac{2 \pi i}{N})``.
539+
540+
!!! warning "Beware of type-stability!"
541+
It is highly recommended to use `qft(dimensions)` with `dimensions` as `Tuple` or `SVector` to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details.
525542
"""
526543
qft(dimensions::Int) = QuantumObject(_qft_op(dimensions), Operator, dimensions)
527544
qft(dimensions::Union{AbstractVector{T},Tuple}) where {T} =

src/qobj/states.jl

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,50 @@ Returns a zero [`Ket`](@ref) vector with given argument `dimensions`.
1515
The `dimensions` can be either the following types:
1616
- `dimensions::Int`: Number of basis states in the Hilbert space.
1717
- `dimensions::Union{AbstractVector{Int}, Tuple}`: list of dimensions representing the each number of basis in the subsystems.
18+
19+
!!! warning "Beware of type-stability!"
20+
It is highly recommended to use `zero_ket(dimensions)` with `dimensions` as `Tuple` or `SVector` to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details.
1821
"""
1922
zero_ket(dimensions::Int) = QuantumObject(zeros(ComplexF64, dimensions), Ket, dimensions)
2023
zero_ket(dimensions::Union{AbstractVector{Int},Tuple}) =
2124
QuantumObject(zeros(ComplexF64, prod(dimensions)), Ket, dimensions)
2225

2326
@doc raw"""
24-
fock(N::Int, pos::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))
27+
fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))
2528
2629
Generates a fock state ``\ket{\psi}`` of dimension `N`.
2730
2831
It is also possible to specify the list of dimensions `dims` if different subsystems are present.
32+
33+
!!! warning "Beware of type-stability!"
34+
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` 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.
2935
"""
3036
function fock(
3137
N::Int,
32-
pos::Int = 0;
38+
j::Int = 0;
3339
dims::Union{Int,AbstractVector{Int},Tuple} = N,
3440
sparse::Union{Bool,Val} = Val(false),
3541
)
3642
if getVal(makeVal(sparse))
37-
array = sparsevec([pos + 1], [1.0 + 0im], N)
43+
array = sparsevec([j + 1], [1.0 + 0im], N)
3844
else
3945
array = zeros(ComplexF64, N)
40-
array[pos+1] = 1
46+
array[j+1] = 1
4147
end
4248
return QuantumObject(array; type = Ket, dims = dims)
4349
end
4450

4551
@doc raw"""
46-
basis(N::Int, pos::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)
52+
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)
4753
4854
Generates a fock state like [`fock`](@ref).
4955
5056
It is also possible to specify the list of dimensions `dims` if different subsystems are present.
57+
58+
!!! warning "Beware of type-stability!"
59+
If you want to keep type stability, it is recommended to use `basis(N, j, dims=dims)` with `dims` as a `Tuple` or `SVector` 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.
5160
"""
52-
basis(N::Int, pos::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N) = fock(N, pos, dims = dims)
61+
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple} = N) = fock(N, j, dims = dims)
5362

5463
@doc raw"""
5564
coherent(N::Int, α::Number)
@@ -68,6 +77,9 @@ Generate a random normalized [`Ket`](@ref) vector with given argument `dimension
6877
The `dimensions` can be either the following types:
6978
- `dimensions::Int`: Number of basis states in the Hilbert space.
7079
- `dimensions::Union{AbstractVector{Int},Tuple}`: list of dimensions representing the each number of basis in the subsystems.
80+
81+
!!! warning "Beware of type-stability!"
82+
If you want to keep type stability, it is recommended to use `rand_ket(dimensions)` with `dimensions` as `Tuple` or `SVector` to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details.
7183
"""
7284
rand_ket(dimensions::Int) = rand_ket(SVector(dimensions))
7385
function rand_ket(dimensions::Union{AbstractVector{Int},Tuple})
@@ -82,6 +94,9 @@ end
8294
Density matrix representation of a Fock state.
8395
8496
Constructed via outer product of [`fock`](@ref).
97+
98+
!!! warning "Beware of type-stability!"
99+
If you want to keep type stability, it is recommended to use `fock_dm(N, pos, dims=dims, sparse=Val(sparse))` instead of `fock_dm(N, pos, dims=dims, sparse=sparse)`. Consider also to use `dims` as a `Tuple` or `SVector` 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.
85100
"""
86101
function fock_dm(
87102
N::Int,
@@ -113,8 +128,8 @@ Density matrix for a thermal state (generating thermal state probabilities) with
113128
- `n::Real`: Expectation value for number of particles in the thermal state.
114129
- `sparse::Union{Bool,Val}`: If `true`, return a sparse matrix representation.
115130
116-
> [!IMPORTANT]
117-
> If you want to keep type stability, it is recommended to use `thermal_dm(N, n, Val(sparse))` instead of `thermal_dm(N, n, sparse)`. 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.
131+
!!! warning "Beware of type-stability!"
132+
If you want to keep type stability, it is recommended to use `thermal_dm(N, n, sparse=Val(sparse))` instead of `thermal_dm(N, n, sparse=sparse)`. 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.
118133
"""
119134
function thermal_dm(N::Int, n::Real; sparse::Union{Bool,Val} = Val(false))
120135
β = log(1.0 / n + 1.0)
@@ -135,6 +150,9 @@ Returns the maximally mixed density matrix with given argument `dimensions`.
135150
The `dimensions` can be either the following types:
136151
- `dimensions::Int`: Number of basis states in the Hilbert space.
137152
- `dimensions::Union{AbstractVector{Int},Tuple}`: list of dimensions representing the each number of basis in the subsystems.
153+
154+
!!! warning "Beware of type-stability!"
155+
If you want to keep type stability, it is recommended to use `maximally_mixed_dm(dimensions)` with `dimensions` as `Tuple` or `SVector` to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details.
138156
"""
139157
maximally_mixed_dm(dimensions::Int) = QuantumObject(I(dimensions) / complex(dimensions), Operator, SVector(dimensions))
140158
function maximally_mixed_dm(dimensions::Union{AbstractVector{Int},Tuple})
@@ -153,6 +171,9 @@ The `dimensions` can be either the following types:
153171
154172
The default keyword argument `rank = prod(dimensions)` (full rank).
155173
174+
!!! warning "Beware of type-stability!"
175+
If you want to keep type stability, it is recommended to use `rand_dm(dimensions; rank=rank)` with `dimensions` as `Tuple` or `SVector` 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.
176+
156177
# References
157178
- [J. Ginibre, Statistical ensembles of complex, quaternion, and real matrices, Journal of Mathematical Physics 6.3 (1965): 440-449](https://doi.org/10.1063/1.1704292)
158179
- [K. Życzkowski, et al., Generating random density matrices, Journal of Mathematical Physics 52, 062201 (2011)](http://dx.doi.org/10.1063/1.3595693)
@@ -284,8 +305,8 @@ Returns the `n`-qubit [W-state](https://en.wikipedia.org/wiki/W_state):
284305
\frac{1}{\sqrt{n}} \left( |100...0\rangle + |010...0\rangle + \cdots + |00...01\rangle \right)
285306
```
286307
287-
> [!IMPORTANT]
288-
> 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.
308+
!!! warning "Beware of type-stability!"
309+
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.
289310
"""
290311
function w_state(::Val{n}) where {n}
291312
nzind = 2 .^ (0:(n-1)) .+ 1
@@ -305,8 +326,8 @@ Returns the generalized `n`-qudit [Greenberger–Horne–Zeilinger (GHZ) state](
305326
306327
Here, `d` specifies the dimension of each qudit. Default to `d=2` (qubit).
307328
308-
> [!IMPORTANT]
309-
> If you want to keep type stability, it is recommended to use `ghz_state(Val(n); kwargs...)` instead of `ghz_state(n; kwargs...)`. 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.
329+
!!! warning "Beware of type-stability!"
330+
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.
310331
"""
311332
function ghz_state(::Val{n}; d::Int = 2) where {n}
312333
nzind = collect((0:(d-1)) .* Int((d^n - 1) / (d - 1)) .+ 1)

0 commit comments

Comments
 (0)