Skip to content

Commit 664c5a5

Browse files
committed
Change to basis api V3
1 parent f02f568 commit 664c5a5

File tree

7 files changed

+161
-129
lines changed

7 files changed

+161
-129
lines changed

src/abstract_types.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ of this function and are provided automatically.
5050
abstract type AbstractOperator end
5151

5252
function summary(stream::IO, x::AbstractOperator)
53-
print(stream, "$(typeof(x).name.name)(dim=$(length(x.basis_l))x$(length(x.basis_r)))\n")
53+
print(stream, "$(typeof(x).name.name)(dim=$(dimension(x.basis_l))x$(dimension(x.basis_r)))\n")
5454
if multiplicable(x,x)
5555
print(stream, " basis: ")
5656
show(stream, basis(x))

src/bases.jl

Lines changed: 141 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
Abstract type for all specialized bases of a Hilbert space.
33
44
This type specifies an orthonormal basis for the Hilbert space of the given
5-
system. All subtypes must implement `Base.:(==)` and `Base.length`, where the
6-
latter should return the total dimension of the Hilbert space
5+
system. All subtypes must implement `Base.:(==)` and `dimension`, where the
6+
latter should return the total dimension of the Hilbert space.
77
88
Composite systems can be defined with help of [`CompositeBasis`](@ref).
9+
Custom subtypes can also define composite systems by implementing
10+
`Base.length` and `Base.getindex`.
911
1012
All relevant properties of concrete subtypes of `Basis` defined in
1113
`QuantumInterface` should be accessed using their documented functions and
@@ -40,24 +42,44 @@ Return the right basis of an operator.
4042
"""
4143
function basis_r end
4244

43-
4445
"""
4546
length(b::Basis)
4647
48+
Return the number of subsystems of a quantum object in its tensor product
49+
decomposition.
50+
51+
See also [`CompositeBasis`](@ref).
52+
"""
53+
Base.length(b::Basis) = 1
54+
55+
"""
56+
getindex(b::Basis)
57+
58+
Get the i'th factor in the tensor product decomposition of the basis into
59+
subsystems.
60+
61+
See also [`CompositeBasis`](@ref).
62+
"""
63+
Base.getindex(b::Basis, i) = i==1 ? b : throw(BoundsError("attempted to access a nonexistent subsystem basis"))
64+
65+
Base.iterate(b::Basis, state=1) = state > length(b) ? nothing : (b[state], state+1)
66+
67+
"""
68+
dimension(b::Basis)
69+
4770
Total dimension of the Hilbert space.
4871
"""
49-
Base.length(b::Basis) = throw(ArgumentError("Base.length() is not defined for $(typeof(b))"))
72+
dimension(b::Basis) = throw(ArgumentError("dimesion() is not defined for $(typeof(b))"))
5073

5174
"""
52-
size(b::Basis)
75+
shape(b::Basis)
5376
5477
A vector containing the local dimensions of each Hilbert space in its tensor
5578
product decomposition into subsystems.
5679
57-
See also [`nsubsystems`](@ref) and [`CompositeBasis`](@ref).
80+
See also [`CompositeBasis`](@ref).
5881
"""
59-
Base.size(b::Basis) = [length(b)]
60-
82+
shape(b::Basis) = [dimension(b[i]) for i=1:length(b)]
6183

6284
##
6385
# GenericBasis, CompositeBasis, SumBasis
@@ -76,7 +98,7 @@ struct GenericBasis{S} <: Basis
7698
dim::S
7799
end
78100
Base.:(==)(b1::GenericBasis, b2::GenericBasis) = b1.dim == b2.dim
79-
Base.length(b::GenericBasis) = b.dim
101+
dimension(b::GenericBasis) = b.dim
80102

81103
"""
82104
CompositeBasis(b1, b2...)
@@ -91,14 +113,15 @@ struct CompositeBasis{B<:Basis,S<:Integer} <: Basis
91113
shape::Vector{S}
92114
bases::Vector{B}
93115
end
94-
CompositeBasis(bases) = CompositeBasis([length(b) for b in bases], bases)
116+
CompositeBasis(bases) = CompositeBasis([dimension(b) for b in bases], bases)
95117
CompositeBasis(bases::Basis...) = CompositeBasis([bases...])
96118
CompositeBasis(bases::Tuple) = CompositeBasis([bases...])
97119

98120
Base.:(==)(b1::CompositeBasis, b2::CompositeBasis) = all(((i, j),) -> i == j, zip(b1.bases, b2.bases))
99-
Base.length(b::CompositeBasis) = prod(b.shape)
100-
Base.size(b::CompositeBasis) = b.shape
121+
Base.length(b::CompositeBasis) = length(b.bases)
101122
Base.getindex(b::CompositeBasis, i) = getindex(b.bases, i)
123+
shape(b::CompositeBasis) = b.shape
124+
dimension(b::CompositeBasis) = prod(b.shape)
102125

103126
"""
104127
tensor(x::Basis, y::Basis, z::Basis...)
@@ -108,10 +131,10 @@ Create a [`CompositeBasis`](@ref) from the given bases.
108131
Any given CompositeBasis is expanded so that the resulting CompositeBasis never
109132
contains another CompositeBasis.
110133
"""
111-
tensor(b1::Basis, b2::Basis) = CompositeBasis([length(b1), length(b2)], [b1, b2])
134+
tensor(b1::Basis, b2::Basis) = CompositeBasis([dimension(b1), dimension(b2)], [b1, b2])
112135
tensor(b1::CompositeBasis, b2::CompositeBasis) = CompositeBasis([b1.shape; b2.shape], [b1.bases; b2.bases])
113-
tensor(b1::CompositeBasis, b2::Basis) = CompositeBasis([b1.shape; length(b2)], [b1.bases; b2])
114-
tensor(b1::Basis, b2::CompositeBasis) = CompositeBasis([length(b1); b2.shape], [b1; b2.bases])
136+
tensor(b1::CompositeBasis, b2::Basis) = CompositeBasis([b1.shape; dimension(b2)], [b1.bases; b2])
137+
tensor(b1::Basis, b2::CompositeBasis) = CompositeBasis([dimension(b1); b2.shape], [b1; b2.bases])
115138
tensor(bases::Basis...) = reduce(tensor, bases)
116139
tensor(basis::Basis) = basis
117140

@@ -126,23 +149,39 @@ struct SumBasis{S<:Integer,B<:Basis} <: Basis
126149
shape::Vector{S}
127150
bases::Vector{B}
128151
end
129-
SumBasis(bases) = SumBasis([length(b) for b in bases], bases)
152+
SumBasis(bases) = SumBasis([dimension(b) for b in bases], bases)
130153
SumBasis(bases::Basis...) = SumBasis([bases...])
131154
SumBasis(bases::Tuple) = SumBasis([bases...])
132155

133156
Base.:(==)(b1::SumBasis, b2::SumBasis) = all(((i, j),) -> i == j, zip(b1.bases, b2.bases))
134-
Base.length(b::SumBasis) = sum(b.shape)
135-
Base.getindex(b::SumBasis, i) = getindex(b.bases, i)
157+
dimension(b::SumBasis) = sum(b.shape)
158+
159+
160+
161+
"""
162+
nsubspaces(b)
163+
164+
Return the number of subspaces of a [`SumBasis`](@ref) in its direct sum
165+
decomposition.
166+
"""
167+
nsubspaces(b::SumBasis) = length(b.bases)
168+
169+
"""
170+
subspace(b, i)
171+
172+
Return the basis for the `i`th subspace of of a [`SumBasis`](@ref).
173+
"""
174+
subspace(b::SumBasis, i) = b.bases[i]
136175

137176
"""
138177
directsum(b1::Basis, b2::Basis)
139178
140179
Construct the [`SumBasis`](@ref) out of two sub-bases.
141180
"""
142-
directsum(b1::Basis, b2::Basis) = SumBasis([length(b1), length(b2)], [b1, b2])
181+
directsum(b1::Basis, b2::Basis) = SumBasis([dimension(b1), dimension(b2)], [b1, b2])
143182
directsum(b1::SumBasis, b2::SumBasis) = SumBasis([b1.shape, b2.shape], [b1.bases; b2.bases])
144-
directsum(b1::SumBasis, b2::Basis) = SumBasis([b1.shape; length(b2)], [b1.bases; b2])
145-
directsum(b1::Basis, b2::SumBasis) = SumBasis([length(b1); b2.shape], [b1; b2.bases])
183+
directsum(b1::SumBasis, b2::Basis) = SumBasis([b1.shape; dimension(b2)], [b1.bases; b2])
184+
directsum(b1::Basis, b2::SumBasis) = SumBasis([dimension(b1); b2.shape], [b1; b2.bases])
146185
directsum(bases::Basis...) = reduce(directsum, bases)
147186
directsum(basis::Basis) = basis
148187

@@ -266,7 +305,7 @@ For a permutation vector `[2,1,3]` and a given object with basis `[b1, b2, b3]`
266305
this function results in `[b2, b1, b3]`.
267306
"""
268307
function permutesystems(b::CompositeBasis, perm)
269-
(nsubsystems(b) == length(perm)) || throw(ArgumentError("Must have nsubsystems(b) == length(perm) in permutesystems"))
308+
(length(b) == length(perm)) || throw(ArgumentError("Must have length(b) == length(perm) in permutesystems"))
270309
isperm(perm) || throw(ArgumentError("Must pass actual permeutation to permutesystems"))
271310
CompositeBasis(b.shape[perm], b.bases[perm])
272311
end
@@ -297,7 +336,7 @@ struct FockBasis{T<:Integer} <: Basis
297336
end
298337

299338
Base.:(==)(b1::FockBasis, b2::FockBasis) = (b1.N==b2.N && b1.offset==b2.offset)
300-
Base.length(b::FockBasis) = b.N - b.offset + 1
339+
dimension(b::FockBasis) = b.N - b.offset + 1
301340

302341
"""
303342
cutoff(b::FockBasis)
@@ -332,7 +371,7 @@ struct NLevelBasis{T<:Integer} <: Basis
332371
end
333372

334373
Base.:(==)(b1::NLevelBasis, b2::NLevelBasis) = b1.N == b2.N
335-
Base.length(b::NLevelBasis) = b.N
374+
dimension(b::NLevelBasis) = b.N
336375

337376
"""
338377
SpinBasis(n)
@@ -358,7 +397,7 @@ end
358397
SpinBasis(spinnumber) = SpinBasis(convert(Rational{Int}, spinnumber))
359398

360399
Base.:(==)(b1::SpinBasis, b2::SpinBasis) = b1.spinnumber==b2.spinnumber
361-
Base.length(b::SpinBasis) = numerator(b.spinnumber*2 + 1)
400+
dimension(b::SpinBasis) = numerator(b.spinnumber*2 + 1)
362401

363402
"""
364403
spinnumber(b::SpinBasis)
@@ -370,6 +409,77 @@ See [`SpinBasis`](@ref).
370409
spinnumber(b::SpinBasis) = b.spinnumber
371410

372411

412+
##
413+
# Operator Bases
414+
##
415+
416+
"""
417+
KetBraBasis(BL,BR)
418+
419+
The "Ket-Bra" operator basis is the standard representation for the left and
420+
right bases of superoperators. This basis is formed by "vec'ing" the
421+
outer-product "Ket-Bra" basis for an operator with a left Bra basis and right
422+
Ket basis which practically means flipping the Bra to a Ket. The operator itself
423+
is then represented as a "Super-Bra" in this basis and corresponds to
424+
column-stacking its matrix.
425+
"""
426+
struct KetBraBasis{BL<:Basis, BR<:Basis} <: Basis
427+
left::BL
428+
right::BR
429+
end
430+
KetBraBasis(b::Basis) = KetBraBasis(b,b)
431+
basis_l(b::KetBraBasis) = b.left
432+
basis_r(b::KetBraBasis) = b.right
433+
Base.:(==)(b1::KetBraBasis, b2::KetBraBasis) = (b1.left == b2.left && b1.right == b2.right)
434+
dimension(b::KetBraBasis) = dimension(b.left)*dimension(b.right)
435+
436+
struct ChoiBasis{BL<:Basis, BR<:Basis} <: Basis
437+
ref::BL
438+
out::BR
439+
end
440+
basis_l(b::ChoiBasis) = b.ref
441+
basis_r(b::ChoiBasis) = b.out
442+
Base.:(==)(b1::ChoiBasis, b2::ChoiBasis) = (b1.ref == b2.ref && b1.out == b2.out)
443+
dimension(b::ChoiBasis) = dimension(b.ref)*dimension(b.out)
444+
445+
"""
446+
PauliBasis(N)
447+
448+
The standard Pauli operator basis for an `N` qubit space. This consists of
449+
tensor products of the Pauli matrices I, X, Y, Z, in that order for each qubit.
450+
The dimension of the basis is 2²ᴺ.
451+
"""
452+
struct PauliBasis{T<:Integer} <: Basis
453+
N::T
454+
end
455+
Base.:(==)(b1::PauliBasis, b2::PauliBasis) = b1.N == b2.N
456+
shape(b::PauliBasis) = fill(4, b.N)
457+
dimension(b::PauliBasis) = 4^b.N
458+
Base.length(b::PauliBasis) = b.N
459+
Base.getindex(b::PauliBasis, i) = PauliBasis(length(i))
460+
461+
"""
462+
HWPauliBasis(N)
463+
464+
The Hesienberg-Weyl Pauli operator basis consisting of the N represents the
465+
underlying Hilbert space dimension, not the operator basis dimension. For N>2,
466+
this representes the operator basis formed by the generalized Pauli matrices,
467+
also called the clock and shift matrices. The ordering is the usual one: when
468+
the index is written in base-N and thus has only two digits, the least
469+
significant bit gives powers of Z (the clock matrix), and most significant bit
470+
gives powers of X (the shfit matrix).
471+
"""
472+
struct HWPauliBasis{T<:Integer} <: Basis
473+
shape::Vector{T}
474+
end
475+
HWPauliBasis(N::Integer) = HWPauliBasis([N])
476+
Base.:(==)(b1::HWPauliBasis, b2::HWPauliBasis) = b1.shape == b2.shape
477+
shape(b::HWPauliBasis) = [n^2 for n in b.shape]
478+
dimension(b::HWPauliBasis) = prod([n^2 for n in b.shape])
479+
Base.length(b::HWPauliBasis) = length(b.shape)
480+
Base.getindex(b::HWPauliBasis, i) = HWPauliBasis([b.shape[i]...])
481+
482+
373483
##
374484
# show methods
375485
##
@@ -422,54 +532,14 @@ function show(stream::IO, x::SumBasis)
422532
write(stream, "]")
423533
end
424534

425-
##
426-
# Operator Bases
427-
##
428-
429-
"""
430-
KetBraBasis(BL,BR)
431-
432-
The "Ket-Bra" operator basis is the standard representation for the left and
433-
right bases of superoperators. This basis is formed by "vec'ing" the
434-
outer-product "Ket-Bra" basis for an operator with a left Bra basis and right
435-
Ket basis which practically means flipping the Bra to a Ket. The operator itself
436-
is then represented as a "Super-Bra" in this basis and corresponds to
437-
column-stacking its matrix.
438-
"""
439-
struct KetBraBasis{BL<:Basis, BR<:Basis} <: Basis
440-
left::BL
441-
right::BR
535+
function show(stream::IO, x::KetBraBasis)
536+
write(stream, "KetBra(left=$(x.left), right=$(x.right))")
442537
end
443-
KetBraBasis(b::Basis) = KetBraBasis(b,b)
444-
basis_l(b::KetBraBasis) = b.left
445-
basis_r(b::KetBraBasis) = b.right
446-
Base.:(==)(b1::KetBraBasis, b2::KetBraBasis) = (b1.left == b2.left && b1.right == b2.right)
447-
Base.length(b::KetBraBasis) = length(b.left)*length(b.right)
448538

449-
struct ChoiBasis{BL<:Basis, BR<:Basis} <: Basis
450-
ref::BL
451-
out::BR
539+
function show(stream::IO, x::PauliBasis)
540+
write(stream, "Pauli(N=$(x.N)")
452541
end
453-
basis_l(b::ChoiBasis) = b.ref
454-
basis_r(b::ChoiBasis) = b.out
455-
Base.:(==)(b1::ChoiBasis, b2::ChoiBasis) = (b1.ref == b2.ref && b1.out == b2.out)
456-
Base.length(b::ChoiBasis) = length(b.ref)*length(b.out)
457542

458-
"""
459-
_PauliBasis()
460-
_PauliBasis(N)
461-
462-
By default N=2 and this represents the Pauli operator basis consisting of the
463-
Pauli matrices I, Z, X, Y, in that order. N represents the underlying Hilbert
464-
space dimension, not the operator basis dimension. For N>2, this representes the
465-
operator basis formed by the generalized Pauli matrices, also called the clock
466-
and shift matrices. The ordering is the usual one: when the index is written in
467-
base-N and thus has only two digits, the least significant bit gives powers of Z
468-
(the clock matrix), and most significant bit gives powers of X (the shfit matrix).
469-
"""
470-
struct _PauliBasis(T<:Integer) <: Basis
471-
dim::T
543+
function show(stream::IO, x::HWPauliBasis)
544+
write(stream, "Pauli($(x.shape)")
472545
end
473-
_PauliBasis() = _PauliBasis(2)
474-
Base.:(==)(pb1::_PauliBasis, pb2::_PauliBasis) = true
475-
Base.length(b::_PauliBasis) = b.dim^2

src/deprecated.jl

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@ function equal_bases(a, b)
1111
return true
1212
end
1313

14-
struct PauliBasis{S,B} <: Basis
15-
shape::S
16-
bases::B
17-
function PauliBasis(num_qubits::T) where {T<:Integer}
18-
Base.depwarn("`PauliBasis` is currently not the Pauli operator basis and its behavior will be changed in future versions.", :PauliBasis)
19-
shape = [2 for _ in 1:num_qubits]
20-
bases = Tuple(SpinBasis(1//2) for _ in 1:num_qubits)
21-
return new{typeof(shape),typeof(bases)}(shape, bases)
22-
end
23-
end
24-
25-
Base.:(==)(pb1::PauliBasis, pb2::PauliBasis) = length(pb1.bases) == length(pb2.bases)
26-
Base.length(b::PauliBasis) = prod(b.shape)
27-
2814
# TODO: figure out how to deprecate abstract type
2915
abstract type AbstractSuperOperator end
3016

0 commit comments

Comments
 (0)