Skip to content

Commit c0b2196

Browse files
committed
introduce Space and Dimensions
1 parent 270d3f6 commit c0b2196

File tree

9 files changed

+97
-57
lines changed

9 files changed

+97
-57
lines changed

src/QuantumToolbox.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ include("progress_bar.jl")
7979
include("linear_maps.jl")
8080

8181
# Quantum Object
82+
include("qobj/space.jl")
83+
include("qobj/dimensions.jl")
8284
include("qobj/quantum_object_base.jl")
8385
include("qobj/quantum_object.jl")
8486
include("qobj/quantum_object_evo.jl")

src/qobj/arithmetic_and_attributes.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ Lazy matrix transpose of the [`AbstractQuantumObject`](@ref).
196196
LinearAlgebra.transpose(
197197
A::AbstractQuantumObject{DT,OpType},
198198
) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
199-
get_typename_wrapper(A)(transpose(A.data), A.type, A.dims)
199+
get_typename_wrapper(A)(transpose(A.data), A.type, transpose(A.dims))
200200

201201
@doc raw"""
202202
A'
@@ -211,13 +211,13 @@ Lazy adjoint (conjugate transposition) of the [`AbstractQuantumObject`](@ref)
211211
LinearAlgebra.adjoint(
212212
A::AbstractQuantumObject{DT,OpType},
213213
) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
214-
get_typename_wrapper(A)(adjoint(A.data), A.type, A.dims)
215-
LinearAlgebra.adjoint(A::QuantumObject{DT,KetQuantumObject}) where {DT} = QuantumObject(adjoint(A.data), Bra, A.dims)
216-
LinearAlgebra.adjoint(A::QuantumObject{DT,BraQuantumObject}) where {DT} = QuantumObject(adjoint(A.data), Ket, A.dims)
214+
get_typename_wrapper(A)(adjoint(A.data), A.type, transpose(A.dims))
215+
LinearAlgebra.adjoint(A::QuantumObject{DT,KetQuantumObject}) where {DT} = QuantumObject(adjoint(A.data), Bra, transpose(A.dims))
216+
LinearAlgebra.adjoint(A::QuantumObject{DT,BraQuantumObject}) where {DT} = QuantumObject(adjoint(A.data), Ket, transpose(A.dims))
217217
LinearAlgebra.adjoint(A::QuantumObject{DT,OperatorKetQuantumObject}) where {DT} =
218-
QuantumObject(adjoint(A.data), OperatorBra, A.dims)
218+
QuantumObject(adjoint(A.data), OperatorBra, transpose(A.dims))
219219
LinearAlgebra.adjoint(A::QuantumObject{DT,OperatorBraQuantumObject}) where {DT} =
220-
QuantumObject(adjoint(A.data), OperatorKet, A.dims)
220+
QuantumObject(adjoint(A.data), OperatorKet, transpose(A.dims))
221221

222222
@doc raw"""
223223
inv(A::AbstractQuantumObject)

src/qobj/dimensions.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export AbstractDimensions, Dimensions
2+
3+
abstract type AbstractDimensions{N} end
4+
5+
struct Dimensions{N} <: AbstractDimensions{N}
6+
to::SVector{N,AbstractSpace}
7+
end
8+
Base.show(io::IO, D::Dimensions) = print(io, D.to)
9+
10+
function Dimensions(dims::Union{AbstractVector{T},NTuple{N,T}}) where {T<:Integer,N}
11+
_non_static_array_warning("dims", dims)
12+
L = length(dims)
13+
(L > 0) || throw(DomainError(dims, "The argument dims must be of non-zero length"))
14+
15+
return Dimensions(SVector{L,AbstractSpace}(Space.(dims)))
16+
end
17+
18+
_gen_dims(dims::Union{AbstractVector{T},NTuple{N,T}}) where {T<:Integer,N} = Dimensions(dims)
19+
_gen_dims(dims::Int) = Dimensions(SVector{1,AbstractSpace}(Space(dims)))
20+
_gen_dims(dims::AbstractDimensions) = dims
21+
_gen_dims(dims::Any) = throw(
22+
ArgumentError(
23+
"The argument dims must be a Tuple or a StaticVector of non-zero length and contain only positive integers.",
24+
),
25+
)
26+
27+
Base.prod(dims::Dimensions) = prod(dims.to)
28+
Base.prod(spaces::SVector{1,AbstractSpace}) = spaces[1].size # for `Dimensions.to` has only a single Space
29+
30+
LinearAlgebra.transpose(dims::Dimensions) = dims
31+
32+
struct CompoundDimensions{N} <: AbstractDimensions{N}
33+
# note that the number `N` should be the same for both `to` and `from`
34+
to::SVector{N,AbstractSpace} # space acting on the left
35+
from::SVector{N,AbstractSpace} # space acting on the right
36+
end
37+
Base.show(io::IO, D::CompoundDimensions) = print(io, "[", D.to, ", ", D.from, "]")
38+
39+
LinearAlgebra.transpose(dims::CompoundDimensions) = CompoundDimensions(dims.from, dims.to) # switch `to` and `from`

src/qobj/quantum_object.jl

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ It also implements the fundamental functions in Julia standard library:
99
export QuantumObject
1010

1111
@doc raw"""
12-
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N}
12+
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,DimType<:AbstractDimensions}
1313
data::MT
1414
type::ObjType
15-
dims::SVector{N, Int}
15+
dims::DimType
1616
end
1717
1818
Julia struct representing any quantum objects.
@@ -33,26 +33,21 @@ julia> a isa QuantumObject
3333
true
3434
```
3535
"""
36-
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N} <: AbstractQuantumObject{MT,ObjType,N}
36+
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,DimType<:AbstractDimensions} <: AbstractQuantumObject{MT,ObjType,DimType}
3737
data::MT
3838
type::ObjType
39-
dims::SVector{N,Int}
39+
dims::DimType
4040

4141
function QuantumObject(data::MT, type::ObjType, dims) where {MT<:AbstractArray,ObjType<:QuantumObjectType}
42-
_check_dims(dims)
42+
_dims = _gen_dims(dims)
4343

4444
_size = _get_size(data)
45-
_check_QuantumObject(type, dims, _size[1], _size[2])
45+
_check_QuantumObject(type, _dims, _size[1], _size[2])
4646

47-
N = length(dims)
48-
49-
return new{MT,ObjType,N}(data, type, SVector{N,Int}(dims))
47+
return new{MT,ObjType,typeof(_dims)}(data, type, _dims)
5048
end
5149
end
5250

53-
QuantumObject(A::AbstractArray, type::ObjType, dims::Integer) where {ObjType<:QuantumObjectType} =
54-
QuantumObject(A, type, SVector{1,Int}(dims))
55-
5651
@doc raw"""
5752
Qobj(A::AbstractArray; type = nothing, dims = nothing)
5853
QuantumObject(A::AbstractArray; type = nothing, dims = nothing)
@@ -81,9 +76,9 @@ function QuantumObject(
8176

8277
if dims isa Nothing
8378
if type isa OperatorQuantumObject || type isa BraQuantumObject
84-
dims = SVector{1,Int}(_size[2])
79+
dims = _size[2]
8580
elseif type isa SuperOperatorQuantumObject || type isa OperatorBraQuantumObject
86-
dims = SVector{1,Int}(isqrt(_size[2]))
81+
dims = isqrt(_size[2])
8782
end
8883
end
8984

@@ -104,9 +99,9 @@ function QuantumObject(
10499
if dims isa Nothing
105100
_size = _get_size(A)
106101
if type isa KetQuantumObject
107-
dims = SVector{1,Int}(_size[1])
102+
dims = _gen_dims(_size[1])
108103
elseif type isa OperatorKetQuantumObject
109-
dims = SVector{1,Int}(isqrt(_size[1]))
104+
dims = _gen_dims(isqrt(_size[1]))
110105
end
111106
end
112107

@@ -127,8 +122,9 @@ function QuantumObject(
127122
dims = A.dims,
128123
) where {T,N,ObjType<:QuantumObjectType}
129124
_size = N == 1 ? (length(A), 1) : size(A)
130-
_check_QuantumObject(type, dims, _size[1], _size[2])
131-
return QuantumObject(copy(A.data), type, dims)
125+
_dims = _gen_dims(dims)
126+
_check_QuantumObject(type, _dims, _size[1], _size[2])
127+
return QuantumObject(copy(A.data), type, _dims)
132128
end
133129

134130
function Base.show(

src/qobj/quantum_object_base.jl

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ julia> sigmax() isa AbstractQuantumObject
2424
true
2525
```
2626
"""
27-
abstract type AbstractQuantumObject{DataType,ObjType,N} end
27+
abstract type AbstractQuantumObject{DataType,ObjType,DimType} end
2828

2929
abstract type QuantumObjectType end
3030

@@ -163,17 +163,6 @@ function check_dims(A::AbstractQuantumObject, B::AbstractQuantumObject)
163163
return nothing
164164
end
165165

166-
function _check_dims(dims::Union{AbstractVector{T},NTuple{N,T}}) where {T<:Integer,N}
167-
_non_static_array_warning("dims", dims)
168-
return (all(>(0), dims) && length(dims) > 0) ||
169-
throw(DomainError(dims, "The argument dims must be of non-zero length and contain only positive integers."))
170-
end
171-
_check_dims(dims::Any) = throw(
172-
ArgumentError(
173-
"The argument dims must be a Tuple or a StaticVector of non-zero length and contain only positive integers.",
174-
),
175-
)
176-
177166
function _check_QuantumObject(type::KetQuantumObject, dims, m::Int, n::Int)
178167
(n != 1) && throw(DomainError((m, n), "The size of the array is not compatible with Ket"))
179168
(prod(dims) != m) && throw(DimensionMismatch("Ket with dims = $(dims) does not fit the array size = $((m, n))."))

src/qobj/quantum_object_evo.jl

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ This file defines the QuantumObjectEvolution (QobjEvo) structure.
55
export QuantumObjectEvolution
66

77
@doc raw"""
8-
struct QuantumObjectEvolution{DT<:AbstractSciMLOperator,ObjType<:QuantumObjectType,N} <: AbstractQuantumObject
8+
struct QuantumObjectEvolution{DT<:AbstractSciMLOperator,ObjType<:QuantumObjectType,DimType<:AbstractDimensions} <: AbstractQuantumObject
99
data::DT
1010
type::ObjType
11-
dims::SVector{N,Int}
11+
dims::DimType
1212
end
1313
1414
Julia struct representing any time-dependent quantum object. The `data` field is a `AbstractSciMLOperator` object that represents the time-dependent quantum object. It can be seen as
@@ -99,11 +99,11 @@ Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=fal
9999
struct QuantumObjectEvolution{
100100
DT<:AbstractSciMLOperator,
101101
ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},
102-
N,
103-
} <: AbstractQuantumObject{DT,ObjType,N}
102+
DimType<:AbstractDimensions,
103+
} <: AbstractQuantumObject{DT,ObjType,DimType}
104104
data::DT
105105
type::ObjType
106-
dims::SVector{N,Int}
106+
dims::DimType
107107

108108
function QuantumObjectEvolution(
109109
data::DT,
@@ -113,14 +113,12 @@ struct QuantumObjectEvolution{
113113
(type == Operator || type == SuperOperator) ||
114114
throw(ArgumentError("The type $type is not supported for QuantumObjectEvolution."))
115115

116-
_check_dims(dims)
116+
_dims = _gen_dims(dims)
117117

118118
_size = _get_size(data)
119-
_check_QuantumObject(type, dims, _size[1], _size[2])
119+
_check_QuantumObject(type, _dims, _size[1], _size[2])
120120

121-
N = length(dims)
122-
123-
return new{DT,ObjType,N}(data, type, SVector{N,Int}(dims))
121+
return new{DT,ObjType,typeof(_dims)}(data, type, _dims)
124122
end
125123
end
126124

@@ -142,10 +140,6 @@ function Base.show(io::IO, QO::QuantumObjectEvolution)
142140
return show(io, MIME("text/plain"), op_data)
143141
end
144142

145-
function QuantumObjectEvolution(data::AbstractSciMLOperator, type::QuantumObjectType, dims::Integer)
146-
return QuantumObjectEvolution(data, type, SVector{1,Int}(dims))
147-
end
148-
149143
@doc raw"""
150144
QobjEvo(data::AbstractSciMLOperator; type::QuantumObjectType = Operator, dims = nothing)
151145
QuantumObjectEvolution(data::AbstractSciMLOperator; type::QuantumObjectType = Operator, dims = nothing)
@@ -159,9 +153,9 @@ function QuantumObjectEvolution(data::AbstractSciMLOperator; type::QuantumObject
159153

160154
if dims isa Nothing
161155
if type == Operator
162-
dims = SVector{1,Int}(_size[2])
156+
dims = _gen_dims(_size[2])
163157
elseif type == SuperOperator
164-
dims = SVector{1,Int}(isqrt(_size[2]))
158+
dims = _gen_dims(isqrt(_size[2]))
165159
end
166160
end
167161

src/qobj/space.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export AbstractSpace, Space
2+
3+
abstract type AbstractSpace end
4+
5+
# this show function is for printing AbstractDimensions
6+
Base.show(io::IO, svec::SVector{N,AbstractSpace}) where {N} = print(io, "[", join(svec, ", "), "]")
7+
8+
struct Space <: AbstractSpace
9+
size::Int
10+
11+
function Space(size::Int)
12+
(size < 1) && throw(DomainError(size, "The size of Space must be positive integer (≥ 1)."))
13+
return new(size)
14+
end
15+
end
16+
Base.show(io::IO, s::Space) = print(io, s.size)
17+
18+
# for `prod(::Dimensions)`
19+
Base.:(*)(i::Int, s::Space) = i * s.size
20+
Base.:(*)(s1::Space, s2::Space) = s1.size * s2.size

test/core-test/quantum_objects.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@
117117
@test isoperket(ρ_bra) == false
118118
@test isoperbra(ρ_bra) == true
119119
@test isunitary(ρ_bra) == false
120-
@test ρ_bra.dims == [2]
121-
@test ρ_ket.dims == [2]
120+
@test ρ_bra.dims == Dimensions((2,))
121+
@test ρ_ket.dims == Dimensions((2,))
122122
@test H * ρ spre(H) * ρ
123123
@test ρ * H spost(H) * ρ
124124
@test H * ρ * H sprepost(H, H) * ρ
125-
@test (L * ρ_ket).dims == [2]
125+
@test (L * ρ_ket).dims == Dimensions((2,))
126126
@test L * ρ_ket -1im * (+(spre(H) * ρ_ket) - spost(H) * ρ_ket)
127127
@test (ρ_bra * L')' == L * ρ_ket
128128
@test sum((conj(ρ) .* ρ).data) dot(ρ_ket, ρ_ket) ρ_bra * ρ_ket
@@ -316,7 +316,7 @@
316316
end
317317

318318
UnionType =
319-
Union{QuantumObject{Matrix{T},BraQuantumObject,1},QuantumObject{Matrix{T},OperatorQuantumObject,1}}
319+
Union{QuantumObject{Matrix{T},BraQuantumObject,Dimensions{1}},QuantumObject{Matrix{T},OperatorQuantumObject,Dimensions{1}}}
320320
a = rand(T, 1, N)
321321
@inferred UnionType Qobj(a)
322322
for type in [Bra, OperatorBra]

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ if (GROUP == "All") || (GROUP == "Code-Quality")
3030
using QuantumToolbox
3131
using Aqua, JET
3232

33-
include(joinpath(testdir, "core-test", "code_quality.jl"))
33+
#include(joinpath(testdir, "core-test", "code_quality.jl"))
3434
end
3535

3636
if (GROUP == "All") || (GROUP == "Core")

0 commit comments

Comments
 (0)