22Abstract type for all specialized bases of a Hilbert space.
33
44This 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
88Composite 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
1012All 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"""
4143function 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+
4770Total 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
5477A vector containing the local dimensions of each Hilbert space in its tensor
5578product 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
7799end
78100Base.:(== )(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}
93115end
94- CompositeBasis (bases) = CompositeBasis ([length (b) for b in bases], bases)
116+ CompositeBasis (bases) = CompositeBasis ([dimension (b) for b in bases], bases)
95117CompositeBasis (bases:: Basis... ) = CompositeBasis ([bases... ])
96118CompositeBasis (bases:: Tuple ) = CompositeBasis ([bases... ])
97119
98120Base.:(== )(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)
101122Base. 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.
108131Any given CompositeBasis is expanded so that the resulting CompositeBasis never
109132contains 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])
112135tensor (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])
115138tensor (bases:: Basis... ) = reduce (tensor, bases)
116139tensor (basis:: Basis ) = basis
117140
@@ -126,23 +149,39 @@ struct SumBasis{S<:Integer,B<:Basis} <: Basis
126149 shape:: Vector{S}
127150 bases:: Vector{B}
128151end
129- SumBasis (bases) = SumBasis ([length (b) for b in bases], bases)
152+ SumBasis (bases) = SumBasis ([dimension (b) for b in bases], bases)
130153SumBasis (bases:: Basis... ) = SumBasis ([bases... ])
131154SumBasis (bases:: Tuple ) = SumBasis ([bases... ])
132155
133156Base.:(== )(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
140179Construct 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])
143182directsum (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])
146185directsum (bases:: Basis... ) = reduce (directsum, bases)
147186directsum (basis:: Basis ) = basis
148187
@@ -266,7 +305,7 @@ For a permutation vector `[2,1,3]` and a given object with basis `[b1, b2, b3]`
266305this function results in `[b2, b1, b3]`.
267306"""
268307function 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])
272311end
@@ -297,7 +336,7 @@ struct FockBasis{T<:Integer} <: Basis
297336end
298337
299338Base.:(== )(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
332371end
333372
334373Base.:(== )(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)
358397SpinBasis (spinnumber) = SpinBasis (convert (Rational{Int}, spinnumber))
359398
360399Base.:(== )(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).
370409spinnumber (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, " ]" )
423533end
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) )" )
442537end
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) " )
452541end
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) " )
472545end
473- _PauliBasis () = _PauliBasis (2 )
474- Base.:(== )(pb1:: _PauliBasis , pb2:: _PauliBasis ) = true
475- Base. length (b:: _PauliBasis ) = b. dim^ 2
0 commit comments