Skip to content

Commit 2ac69c8

Browse files
committed
Implement a bases api and rework abstract types
1 parent 3d63b38 commit 2ac69c8

7 files changed

+121
-71
lines changed

src/abstract_types.jl

+29-29
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
11
"""
2-
Abstract base class for `Bra` and `Ket` states.
2+
Abstract type for `Bra` and `Ket` states.
33
4-
The state vector class stores the coefficients of an abstract state
5-
in respect to a certain basis. These coefficients are stored in the
6-
`data` field and the basis is defined in the `basis`
7-
field.
4+
The state vector type stores an abstract state with respect to a certain
5+
Hilbert space basis.
6+
All deriving types must define the `fullbasis` function which
7+
returns the state vector's underlying `Basis`.
88
"""
9-
abstract type StateVector{B,T} end
10-
abstract type AbstractKet{B,T} <: StateVector{B,T} end
11-
abstract type AbstractBra{B,T} <: StateVector{B,T} end
9+
abstract type StateVector{B<:Basis} end
10+
abstract type AbstractKet{B} <: StateVector{B} end
11+
abstract type AbstractBra{B} <: StateVector{B} end
1212

1313
"""
14-
Abstract base class for all operators.
14+
Abstract type for all operators which represent linear maps between two
15+
Hilbert spaces with respect to a given basis in each space.
1516
16-
All deriving operator classes have to define the fields
17-
`basis_l` and `basis_r` defining the left and right side bases.
17+
All deriving operator types must define the `fullbasis` function which
18+
returns the operator's underlying `OperatorBasis`.
1819
1920
For fast time evolution also at least the function
2021
`mul!(result::Ket,op::AbstractOperator,x::Ket,alpha,beta)` should be
2122
implemented. Many other generic multiplication functions can be defined in
2223
terms of this function and are provided automatically.
24+
25+
See [TODO: reference operators.md in docs]
2326
"""
24-
abstract type AbstractOperator{BL,BR} end
27+
abstract type AbstractOperator{B<:OperatorBasis} end
2528

2629
"""
27-
Base class for all super operator classes.
28-
29-
Super operators are bijective mappings from operators given in one specific
30-
basis to operators, possibly given in respect to another, different basis.
31-
To embed super operators in an algebraic framework they are defined with a
32-
left hand basis `basis_l` and a right hand basis `basis_r` where each of
33-
them again consists of a left and right hand basis.
34-
```math
35-
A_{bl_1,bl_2} = S_{(bl_1,bl_2) ↔ (br_1,br_2)} B_{br_1,br_2}
36-
\\\\
37-
A_{br_1,br_2} = B_{bl_1,bl_2} S_{(bl_1,bl_2) ↔ (br_1,br_2)}
30+
Abstract type for all super-operators which represent linear maps between two
31+
operator spaces with respect to a given basis for each space.
32+
33+
All deriving operator types must define the `fullbasis` function which
34+
returns the operator's underlying `SuperOperatorBasis`.
35+
36+
See [TODO: reference superoperators.md in docs]
3837
```
3938
"""
40-
abstract type AbstractSuperOperator{B1,B2} end
39+
abstract type AbstractSuperOperator{B<:SuperOperatorBasis} end
4140

4241
function summary(stream::IO, x::AbstractOperator)
43-
print(stream, "$(typeof(x).name.name)(dim=$(length(x.basis_l))x$(length(x.basis_r)))\n")
44-
if samebases(x)
42+
b = fullbasis(x)
43+
print(stream, "$(typeof(x).name.name)(dim=$(length(b.left))x$(length(b.right)))\n")
44+
if samebases(b)
4545
print(stream, " basis: ")
46-
show(stream, basis(x))
46+
show(stream, basis(b))
4747
else
4848
print(stream, " basis left: ")
49-
show(stream, x.basis_l)
49+
show(stream, b.left)
5050
print(stream, "\n basis right: ")
51-
show(stream, x.basis_r)
51+
show(stream, b.right)
5252
end
5353
end
5454

src/bases.jl

+55-13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""
2-
Abstract base class for all specialized bases.
2+
Abstract type for all specialized bases.
33
4-
The Basis class is meant to specify a basis of the Hilbert space of the
5-
studied system. Besides basis specific information all subclasses must
6-
implement a shape variable which indicates the dimension of the used
4+
The `Basis` type is meant to specify a basis of the Hilbert space of the
5+
studied system. Besides basis specific information, all concrete subtypes must
6+
implement a shape field which indicates the dimension of the used
77
Hilbert space. For a spin-1/2 Hilbert space this would be the
88
vector `[2]`. A system composed of two spins would then have a
99
shape vector `[2 2]`.
@@ -13,6 +13,26 @@ class.
1313
"""
1414
abstract type Basis end
1515

16+
"""
17+
Parametric composite type for all operator bases.
18+
19+
See [TODO: reference operators.md in docs]
20+
"""
21+
struct OperatorBasis{BL<:Basis,BR<:Basis}
22+
left::BL
23+
right::BR
24+
end
25+
26+
"""
27+
Parametric composite type for all superoperator bases.
28+
29+
See [TODO: reference superoperators.md in docs]
30+
"""
31+
struct SuperOperatorBasis{BL<:OperatorBasis,BR<:OperatorBasis}
32+
left::BL
33+
right::BR
34+
end
35+
1636
"""
1737
length(b::Basis)
1838
@@ -25,11 +45,24 @@ Base.length(b::Basis) = prod(b.shape)
2545
2646
Return the basis of an object.
2747
28-
If it's ambiguous, e.g. if an operator has a different left and right basis,
29-
an [`IncompatibleBases`](@ref) error is thrown.
48+
If it's ambiguous, e.g. if an operator or superoperator has a different
49+
left and right basis, an [`IncompatibleBases`](@ref) error is thrown.
3050
"""
3151
function basis end
3252

53+
basis(b::OperatorBasis) = (check_samebases(b); b.left)
54+
basis(b::SuperOperatorBasis) = (check_samebases(b); b.left.left)
55+
56+
"""
57+
fullbasis(a)
58+
59+
60+
Returns B where B<:Basis when typeof(a)<:StateVector.
61+
Returns B where B<:OperatorBasis when typeof(a)<:AbstractOperator.
62+
Returns B where B<:SuperOperatorBasis for typeof(a)<:AbstractSuperOperator.
63+
"""
64+
function fullbasis end
65+
3366

3467
"""
3568
GenericBasis(N)
@@ -80,13 +113,11 @@ contains another CompositeBasis.
80113
tensor(b1::Basis, b2::Basis) = CompositeBasis([length(b1); length(b2)], (b1, b2))
81114
tensor(b1::CompositeBasis, b2::CompositeBasis) = CompositeBasis([b1.shape; b2.shape], (b1.bases..., b2.bases...))
82115
function tensor(b1::CompositeBasis, b2::Basis)
83-
N = length(b1.bases)
84116
shape = vcat(b1.shape, length(b2))
85117
bases = (b1.bases..., b2)
86118
CompositeBasis(shape, bases)
87119
end
88120
function tensor(b1::Basis, b2::CompositeBasis)
89-
N = length(b2.bases)
90121
shape = vcat(length(b1), b2.shape)
91122
bases = (b1, b2.bases...)
92123
CompositeBasis(shape, bases)
@@ -160,24 +191,35 @@ macro samebases(ex)
160191
end
161192

162193
"""
194+
samebases(a)
163195
samebases(a, b)
164196
165-
Test if two objects have the same bases.
197+
Test if one object has the same left and right bases or
198+
if two objects have the same bases
166199
"""
167-
samebases(b1::Basis, b2::Basis) = b1==b2
168-
samebases(b1::Tuple{Basis, Basis}, b2::Tuple{Basis, Basis}) = b1==b2 # for checking superoperators
200+
samebases(b1::Basis, b2::Basis) = (b1 == b2)
201+
samebases(b::OperatorBasis) = (b.left == b.right)
202+
samebases(b1::OperatorBasis, b2::OperatorBasis) = ((b1.left == b2.left) && (b1.right == b2.right))
203+
samebases(b::SuperOperatorBasis) = samebases(b.left, b.right)
204+
samebases(b1::SuperOperatorBasis, b2::SuperOperatorBasis) = (samebases(b1.left, b2.left) && samebases(b1.right, b2.right))
169205

170206
"""
207+
check_samebases(a)
171208
check_samebases(a, b)
172209
173-
Throw an [`IncompatibleBases`](@ref) error if the objects don't have
174-
the same bases.
210+
Throw an [`IncompatibleBases`](@ref) error if the two objects don't have
211+
the same bases or the one object doesn't have the same left and right bases.
175212
"""
176213
function check_samebases(b1, b2)
177214
if BASES_CHECK[] && !samebases(b1, b2)
178215
throw(IncompatibleBases())
179216
end
180217
end
218+
function check_samebases(b)
219+
if BASES_CHECK[] && !samebases(b)
220+
throw(IncompatibleBases())
221+
end
222+
end
181223

182224

183225
"""

src/expect_variance.jl

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,33 @@
33
44
If an `index` is given, it assumes that `op` is defined in the subsystem specified by this number.
55
"""
6-
function expect(indices, op::AbstractOperator{B1,B2}, state::AbstractOperator{B3,B3}) where {B1,B2,B3<:CompositeBasis}
7-
N = length(state.basis_l.shape)
6+
function expect(indices, op::AbstractOperator{OperatorBasis{B1,B2}}, state::AbstractOperator{OperatorBasis{B3,B3}}) where {B1,B2,B3<:CompositeBasis}
7+
N = length(fullbasis(state).left.shape)
88
indices_ = complement(N, indices)
99
expect(op, ptrace(state, indices_))
1010
end
1111

12-
expect(index::Integer, op::AbstractOperator{B1,B2}, state::AbstractOperator{B3,B3}) where {B1,B2,B3<:CompositeBasis} = expect([index], op, state)
12+
expect(index::Integer, op::AbstractOperator{OperatorBasis{B1,B2}}, state::AbstractOperator{OperatorBasis{B3,B3}}) where {B1,B2,B3<:CompositeBasis} = expect([index], op, state)
1313
expect(op::AbstractOperator, states::Vector) = [expect(op, state) for state=states]
1414
expect(indices, op::AbstractOperator, states::Vector) = [expect(indices, op, state) for state=states]
1515

16-
expect(op::AbstractOperator{B1,B2}, state::AbstractOperator{B2,B2}) where {B1,B2} = tr(op*state)
16+
expect(op::AbstractOperator{OperatorBasis{B1,B2}}, state::AbstractOperator{OperatorBasis{B2,B2}}) where {B1,B2} = tr(op*state)
1717

1818
"""
1919
variance(index, op, state)
2020
2121
If an `index` is given, it assumes that `op` is defined in the subsystem specified by this number
2222
"""
23-
function variance(indices, op::AbstractOperator{B,B}, state::AbstractOperator{BC,BC}) where {B,BC<:CompositeBasis}
24-
N = length(state.basis_l.shape)
23+
function variance(indices, op::AbstractOperator{OperatorBasis{B,B}}, state::AbstractOperator{OperatorBasis{BC,BC}}) where {B,BC<:CompositeBasis}
24+
N = length(fullbasis(state).left.shape)
2525
indices_ = complement(N, indices)
2626
variance(op, ptrace(state, indices_))
2727
end
2828

29-
variance(index::Integer, op::AbstractOperator{B,B}, state::AbstractOperator{BC,BC}) where {B,BC<:CompositeBasis} = variance([index], op, state)
29+
variance(index::Integer, op::AbstractOperator{OperatorBasis{B,B}}, state::AbstractOperator{OperatorBasis{BC,BC}}) where {B,BC<:CompositeBasis} = variance([index], op, state)
3030
variance(op::AbstractOperator, states::Vector) = [variance(op, state) for state=states]
3131
variance(indices, op::AbstractOperator, states::Vector) = [variance(indices, op, state) for state=states]
3232

33-
function variance(op::AbstractOperator{B,B}, state::AbstractOperator{B,B}) where B
33+
function variance(op::AbstractOperator{OperatorBasis{B,B}}, state::AbstractOperator{OperatorBasis{B,B}}) where B
3434
expect(op*op, state) - expect(op, state)^2
3535
end

src/identityoperator.jl

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ type which has to a subtype of [`AbstractOperator`](@ref) as well as the number
1111
to be used in the identity matrix.
1212
"""
1313
identityoperator(::Type{T}, ::Type{S}, b1::Basis, b2::Basis) where {T<:AbstractOperator,S} = throw(ArgumentError("Identity operator not defined for operator type $T."))
14+
identityoperator(::Type{T}, ::Type{S}, b::OperatorBasis) where {T<:AbstractOperator,S} = identityoperator(T,S,b.left,b.right)
1415
identityoperator(::Type{T}, ::Type{S}, b::Basis) where {T<:AbstractOperator,S} = identityoperator(T,S,b,b)
15-
identityoperator(::Type{T}, bases::Basis...) where T<:AbstractOperator = identityoperator(T,eltype(T),bases...)
16+
identityoperator(::Type{T}, b::OperatorBasis) where {T<:AbstractOperator} = identityoperator(T,eltype(T),b)
17+
identityoperator(::Type{T}, bases::Basis...) where {T<:AbstractOperator} = identityoperator(T,eltype(T),bases...)
1618
identityoperator(b::Basis) = identityoperator(ComplexF64,b)
17-
identityoperator(op::T) where {T<:AbstractOperator} = identityoperator(T, op.basis_l, op.basis_r)
19+
identityoperator(op::T) where {T<:AbstractOperator} = identityoperator(T, fullbasis(op))
1820

1921
# Catch case where eltype cannot be inferred from type; this is a bit hacky
2022
identityoperator(::Type{T}, ::Type{Any}, b1::Basis, b2::Basis) where T<:AbstractOperator = identityoperator(T, ComplexF64, b1, b2)
2123

2224
identityoperator(b1::Basis, b2::Basis) = identityoperator(ComplexF64, b1, b2)
2325

2426
"""Prepare the identity superoperator over a given space."""
25-
function identitysuperoperator end
27+
function identitysuperoperator end

src/julia_base.jl

+12-12
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ addnumbererror() = throw(ArgumentError("Can't add or subtract a number and an op
88
# States
99
##
1010

11-
-(a::T) where {T<:StateVector} = T(a.basis, -a.data)
11+
-(a::T) where {T<:StateVector} = T(a.basis, -a.data) # FIXME
1212
*(a::StateVector, b::Number) = b*a
13-
copy(a::T) where {T<:StateVector} = T(a.basis, copy(a.data))
14-
length(a::StateVector) = length(a.basis)::Int
15-
basis(a::StateVector) = a.basis
13+
copy(a::T) where {T<:StateVector} = T(a.basis, copy(a.data)) # FIXME
14+
length(a::StateVector) = length(basis(a))::Int
15+
basis(a::StateVector) = fullbasis(a)
1616
directsum(x::StateVector...) = reduce(directsum, x)
1717

1818
# Array-like functions
19-
Base.size(x::StateVector) = size(x.data)
20-
@inline Base.axes(x::StateVector) = axes(x.data)
19+
Base.size(x::StateVector) = size(x.data) # FIXME
20+
@inline Base.axes(x::StateVector) = axes(x.data) #FIXME
2121
Base.ndims(x::StateVector) = 1
2222
Base.ndims(::Type{<:StateVector}) = 1
23-
Base.eltype(x::StateVector) = eltype(x.data)
23+
Base.eltype(x::StateVector) = eltype(x.data) # FIXME
2424

2525
# Broadcasting
2626
Base.broadcastable(x::StateVector) = x
@@ -32,9 +32,9 @@ Base.adjoint(a::StateVector) = dagger(a)
3232
# Operators
3333
##
3434

35-
length(a::AbstractOperator) = length(a.basis_l)::Int*length(a.basis_r)::Int
36-
basis(a::AbstractOperator) = (check_samebases(a); a.basis_l)
37-
basis(a::AbstractSuperOperator) = (check_samebases(a); a.basis_l[1])
35+
length(a::AbstractOperator) = (b=fullbasis(a); length(b.left)::Int*length(b.right)::Int)
36+
basis(a::AbstractOperator) = (b=fullbasis(a); check_samebases(b); b.left)
37+
basis(a::AbstractSuperOperator) = (b=fullbasis(a); check_samebases(b); b.left.left)
3838

3939
# Ensure scalar broadcasting
4040
Base.broadcastable(x::AbstractOperator) = Ref(x)
@@ -60,11 +60,11 @@ Operator exponential.
6060
"""
6161
exp(op::AbstractOperator) = throw(ArgumentError("exp() is not defined for this type of operator: $(typeof(op)).\nTry to convert to dense operator first with dense()."))
6262

63-
Base.size(op::AbstractOperator) = (length(op.basis_l),length(op.basis_r))
63+
Base.size(op::AbstractOperator) = (b=fullbasis(op); (length(b.left),length(b.right)))
6464
function Base.size(op::AbstractOperator, i::Int)
6565
i < 1 && throw(ErrorException("dimension index is < 1"))
6666
i > 2 && return 1
67-
i==1 ? length(op.basis_l) : length(op.basis_r)
67+
i==1 ? length(fullbasis(op).left) : length(fullbasis(op).right)
6868
end
6969

7070
Base.adjoint(a::AbstractOperator) = dagger(a)

src/julia_linalg.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ tr(x::AbstractOperator) = arithmetic_unary_error("Trace", x)
1717
1818
Norm of the given bra or ket state.
1919
"""
20-
norm(x::StateVector) = norm(x.data)
20+
norm(x::StateVector) = norm(x.data) # FIXME
2121

2222
"""
2323
normalize(x::StateVector)
@@ -31,7 +31,7 @@ normalize(x::StateVector) = x/norm(x)
3131
3232
In-place normalization of the given bra or ket so that `norm(x)` is one.
3333
"""
34-
normalize!(x::StateVector) = (normalize!(x.data); x)
34+
normalize!(x::StateVector) = (normalize!(x.data); x) # FIXME
3535

3636
"""
3737
normalize(op)

src/linalg.jl

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
samebases(a::AbstractOperator) = samebases(a.basis_l, a.basis_r)::Bool
2-
samebases(a::AbstractOperator, b::AbstractOperator) = samebases(a.basis_l, b.basis_l)::Bool && samebases(a.basis_r, b.basis_r)::Bool
3-
check_samebases(a::Union{AbstractOperator, AbstractSuperOperator}) = check_samebases(a.basis_l, a.basis_r)
4-
multiplicable(a::AbstractOperator, b::AbstractOperator) = multiplicable(a.basis_r, b.basis_l)
1+
samebases(a::AbstractOperator) = samebases(fullbasis(a))::Bool
2+
samebases(a::AbstractSuperOperator) = samebases(fullbasis(a))::Bool
3+
samebases(a::AbstractOperator, b::AbstractOperator) = samebases(fullbasis(a), fullbasis(b))::Bool
4+
samebases(a::AbstractSuperOperator, b::AbstractSuperOperator) = samebases(fullbasis(a), fullbasis(b))::Bool
5+
check_samebases(a::AbstractOperator) = check_samebases(fullbasis(a))::Bool
6+
check_samebases(a::AbstractSuperOperator) = check_samebases(fullbasis(a))::Bool
7+
check_samebases(a::AbstractOperator, b::AbstractOperator) = check_samebases(fullbasis(a), fullbasis(b))::Bool
8+
check_samebases(a::AbstractSuperOperator, b::AbstractSuperOperator) = check_samebases(fullbasis(a), fullbasis(b))::Bool
9+
10+
multiplicable(a::AbstractOperator, b::AbstractOperator) = multiplicable(fullbasis(a).right, fullbasis(b).left)
511
dagger(a::AbstractOperator) = arithmetic_unary_error("Hermitian conjugate", a)
612
transpose(a::AbstractOperator) = arithmetic_unary_error("Transpose", a)
713
directsum(a::AbstractOperator...) = reduce(directsum, a)

0 commit comments

Comments
 (0)