Skip to content

Commit 662993f

Browse files
committed
Add test_bases from QuantumOpticsBase and reorganize a bit
1 parent f22adb7 commit 662993f

File tree

12 files changed

+415
-327
lines changed

12 files changed

+415
-327
lines changed

src/QuantumInterface.jl

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
11
module QuantumInterface
22

3-
import Base: ==, +, -, *, /, ^, length, one, exp, conj, conj!, transpose, copy
4-
import LinearAlgebra: tr, ishermitian, norm, normalize, normalize!
5-
import Base: show, summary
6-
import SparseArrays: sparse, spzeros, AbstractSparseMatrix # TODO move to an extension
3+
##
4+
# Basis specific
5+
##
6+
7+
"""
8+
basis(a)
9+
10+
Return the basis of an object.
11+
12+
If it's ambiguous, e.g. if an operator has a different left and right basis,
13+
an [`IncompatibleBases`](@ref) error is thrown.
14+
"""
15+
function basis end
16+
17+
"""
18+
Exception that should be raised for an illegal algebraic operation.
19+
"""
20+
mutable struct IncompatibleBases <: Exception end
21+
22+
23+
##
24+
# Standard methods
25+
##
726

827
function apply! end
928

1029
function dagger end
1130

31+
"""
32+
directsum(x, y, z...)
33+
34+
Direct sum of the given objects. Alternatively, the unicode
35+
symbol ⊕ (\\oplus) can be used.
36+
"""
1237
function directsum end
1338
const = directsum
1439
directsum() = GenericBasis(0)
@@ -86,8 +111,9 @@ function squeeze end
86111
function wigner end
87112

88113

89-
include("bases.jl")
90114
include("abstract_types.jl")
115+
include("bases.jl")
116+
include("show.jl")
91117

92118
include("linalg.jl")
93119
include("tensor.jl")

src/abstract_types.jl

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
"""
2+
Abstract base class for all specialized bases.
3+
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
7+
Hilbert space. For a spin-1/2 Hilbert space this would be the
8+
vector `[2]`. A system composed of two spins would then have a
9+
shape vector `[2 2]`.
10+
11+
Composite systems can be defined with help of the [`CompositeBasis`](@ref)
12+
class.
13+
"""
14+
abstract type Basis end
15+
116
"""
217
Abstract base class for `Bra` and `Ket` states.
318
@@ -38,20 +53,3 @@ A_{br_1,br_2} = B_{bl_1,bl_2} S_{(bl_1,bl_2) ↔ (br_1,br_2)}
3853
```
3954
"""
4055
abstract type AbstractSuperOperator{B1,B2} end
41-
42-
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)
45-
print(stream, " basis: ")
46-
show(stream, basis(x))
47-
else
48-
print(stream, " basis left: ")
49-
show(stream, x.basis_l)
50-
print(stream, "\n basis right: ")
51-
show(stream, x.basis_r)
52-
end
53-
end
54-
55-
show(stream::IO, x::AbstractOperator) = summary(stream, x)
56-
57-
traceout!(s::StateVector, i) = ptrace(s,i)

src/bases.jl

Lines changed: 6 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
1-
"""
2-
Abstract base class for all specialized bases.
3-
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
7-
Hilbert space. For a spin-1/2 Hilbert space this would be the
8-
vector `[2]`. A system composed of two spins would then have a
9-
shape vector `[2 2]`.
10-
11-
Composite systems can be defined with help of the [`CompositeBasis`](@ref)
12-
class.
13-
"""
14-
abstract type Basis end
1+
##
2+
# GenericBasis, CompositeBasis
3+
##
154

165
"""
176
length(b::Basis)
@@ -20,17 +9,6 @@ Total dimension of the Hilbert space.
209
"""
2110
Base.length(b::Basis) = prod(b.shape)
2211

23-
"""
24-
basis(a)
25-
26-
Return the basis of an object.
27-
28-
If it's ambiguous, e.g. if an operator has a different left and right basis,
29-
an [`IncompatibleBases`](@ref) error is thrown.
30-
"""
31-
function basis end
32-
33-
3412
"""
3513
GenericBasis(N)
3614
@@ -67,39 +45,6 @@ CompositeBasis(bases::Vector) = CompositeBasis((bases...,))
6745

6846
Base.:(==)(b1::T, b2::T) where T<:CompositeBasis = equal_shape(b1.shape, b2.shape)
6947

70-
tensor(b::Basis) = b
71-
72-
"""
73-
tensor(x::Basis, y::Basis, z::Basis...)
74-
75-
Create a [`CompositeBasis`](@ref) from the given bases.
76-
77-
Any given CompositeBasis is expanded so that the resulting CompositeBasis never
78-
contains another CompositeBasis.
79-
"""
80-
tensor(b1::Basis, b2::Basis) = CompositeBasis([length(b1); length(b2)], (b1, b2))
81-
tensor(b1::CompositeBasis, b2::CompositeBasis) = CompositeBasis([b1.shape; b2.shape], (b1.bases..., b2.bases...))
82-
function tensor(b1::CompositeBasis, b2::Basis)
83-
N = length(b1.bases)
84-
shape = vcat(b1.shape, length(b2))
85-
bases = (b1.bases..., b2)
86-
CompositeBasis(shape, bases)
87-
end
88-
function tensor(b1::Basis, b2::CompositeBasis)
89-
N = length(b2.bases)
90-
shape = vcat(length(b1), b2.shape)
91-
bases = (b1, b2.bases...)
92-
CompositeBasis(shape, bases)
93-
end
94-
tensor(bases::Basis...) = reduce(tensor, bases)
95-
96-
function Base.:^(b::Basis, N::Integer)
97-
if N < 1
98-
throw(ArgumentError("Power of a basis is only defined for positive integers."))
99-
end
100-
tensor([b for i=1:N]...)
101-
end
102-
10348
"""
10449
equal_shape(a, b)
10550
@@ -137,130 +82,6 @@ function equal_bases(a, b)
13782
return true
13883
end
13984

140-
"""
141-
Exception that should be raised for an illegal algebraic operation.
142-
"""
143-
mutable struct IncompatibleBases <: Exception end
144-
145-
const BASES_CHECK = Ref(true)
146-
147-
"""
148-
@samebases
149-
150-
Macro to skip checks for same bases. Useful for `*`, `expect` and similar
151-
functions.
152-
"""
153-
macro samebases(ex)
154-
return quote
155-
BASES_CHECK.x = false
156-
local val = $(esc(ex))
157-
BASES_CHECK.x = true
158-
val
159-
end
160-
end
161-
162-
"""
163-
samebases(a, b)
164-
165-
Test if two objects have the same bases.
166-
"""
167-
samebases(b1::Basis, b2::Basis) = b1==b2
168-
samebases(b1::Tuple{Basis, Basis}, b2::Tuple{Basis, Basis}) = b1==b2 # for checking superoperators
169-
170-
"""
171-
check_samebases(a, b)
172-
173-
Throw an [`IncompatibleBases`](@ref) error if the objects don't have
174-
the same bases.
175-
"""
176-
function check_samebases(b1, b2)
177-
if BASES_CHECK[] && !samebases(b1, b2)
178-
throw(IncompatibleBases())
179-
end
180-
end
181-
182-
183-
"""
184-
multiplicable(a, b)
185-
186-
Check if two objects are multiplicable.
187-
"""
188-
multiplicable(b1::Basis, b2::Basis) = b1==b2
189-
190-
function multiplicable(b1::CompositeBasis, b2::CompositeBasis)
191-
if !equal_shape(b1.shape,b2.shape)
192-
return false
193-
end
194-
for i=1:length(b1.shape)
195-
if !multiplicable(b1.bases[i], b2.bases[i])
196-
return false
197-
end
198-
end
199-
return true
200-
end
201-
202-
"""
203-
check_multiplicable(a, b)
204-
205-
Throw an [`IncompatibleBases`](@ref) error if the objects are
206-
not multiplicable.
207-
"""
208-
function check_multiplicable(b1, b2)
209-
if BASES_CHECK[] && !multiplicable(b1, b2)
210-
throw(IncompatibleBases())
211-
end
212-
end
213-
214-
"""
215-
reduced(a, indices)
216-
217-
Reduced basis, state or operator on the specified subsystems.
218-
219-
The `indices` argument, which can be a single integer or a vector of integers,
220-
specifies which subsystems are kept. At least one index must be specified.
221-
"""
222-
function reduced(b::CompositeBasis, indices)
223-
if length(indices)==0
224-
throw(ArgumentError("At least one subsystem must be specified in reduced."))
225-
elseif length(indices)==1
226-
return b.bases[indices[1]]
227-
else
228-
return CompositeBasis(b.shape[indices], b.bases[indices])
229-
end
230-
end
231-
232-
"""
233-
ptrace(a, indices)
234-
235-
Partial trace of the given basis, state or operator.
236-
237-
The `indices` argument, which can be a single integer or a vector of integers,
238-
specifies which subsystems are traced out. The number of indices has to be
239-
smaller than the number of subsystems, i.e. it is not allowed to perform a
240-
full trace.
241-
"""
242-
function ptrace(b::CompositeBasis, indices)
243-
J = [i for i in 1:length(b.bases) if i indices]
244-
length(J) > 0 || throw(ArgumentError("Tracing over all indices is not allowed in ptrace."))
245-
reduced(b, J)
246-
end
247-
248-
249-
"""
250-
permutesystems(a, perm)
251-
252-
Change the ordering of the subsystems of the given object.
253-
254-
For a permutation vector `[2,1,3]` and a given object with basis `[b1, b2, b3]`
255-
this function results in `[b2, b1, b3]`.
256-
"""
257-
function permutesystems(b::CompositeBasis, perm)
258-
@assert length(b.bases) == length(perm)
259-
@assert isperm(perm)
260-
CompositeBasis(b.shape[perm], b.bases[perm])
261-
end
262-
263-
26485
##
26586
# Common bases
26687
##
@@ -366,89 +187,6 @@ SumBasis(shape, bases::Vector) = (tmp = (bases...,); SumBasis(shape, tmp))
366187
SumBasis(bases::Vector) = SumBasis((bases...,))
367188
SumBasis(bases::Basis...) = SumBasis((bases...,))
368189

369-
==(b1::T, b2::T) where T<:SumBasis = equal_shape(b1.shape, b2.shape)
370-
==(b1::SumBasis, b2::SumBasis) = false
371-
length(b::SumBasis) = sum(b.shape)
372-
373-
"""
374-
directsum(b1::Basis, b2::Basis)
375-
376-
Construct the [`SumBasis`](@ref) out of two sub-bases.
377-
"""
378-
directsum(b1::Basis, b2::Basis) = SumBasis(Int[length(b1); length(b2)], Basis[b1, b2])
379-
directsum(b::Basis) = b
380-
directsum(b::Basis...) = reduce(directsum, b)
381-
function directsum(b1::SumBasis, b2::Basis)
382-
shape = [b1.shape;length(b2)]
383-
bases = [b1.bases...;b2]
384-
return SumBasis(shape, (bases...,))
385-
end
386-
function directsum(b1::Basis, b2::SumBasis)
387-
shape = [length(b1);b2.shape]
388-
bases = [b1;b2.bases...]
389-
return SumBasis(shape, (bases...,))
390-
end
391-
function directsum(b1::SumBasis, b2::SumBasis)
392-
shape = [b1.shape;b2.shape]
393-
bases = [b1.bases...;b2.bases...]
394-
return SumBasis(shape, (bases...,))
395-
end
396-
397-
embed(b::SumBasis, indices, ops) = embed(b, b, indices, ops)
398-
399-
##
400-
# show methods
401-
##
402-
403-
function show(stream::IO, x::GenericBasis)
404-
if length(x.shape) == 1
405-
write(stream, "Basis(dim=$(x.shape[1]))")
406-
else
407-
s = replace(string(x.shape), " " => "")
408-
write(stream, "Basis(shape=$s)")
409-
end
410-
end
411-
412-
function show(stream::IO, x::CompositeBasis)
413-
write(stream, "[")
414-
for i in 1:length(x.bases)
415-
show(stream, x.bases[i])
416-
if i != length(x.bases)
417-
write(stream, "")
418-
end
419-
end
420-
write(stream, "]")
421-
end
422-
423-
function show(stream::IO, x::SpinBasis)
424-
d = denominator(x.spinnumber)
425-
n = numerator(x.spinnumber)
426-
if d == 1
427-
write(stream, "Spin($n)")
428-
else
429-
write(stream, "Spin($n/$d)")
430-
end
431-
end
432-
433-
function show(stream::IO, x::FockBasis)
434-
if iszero(x.offset)
435-
write(stream, "Fock(cutoff=$(x.N))")
436-
else
437-
write(stream, "Fock(cutoff=$(x.N), offset=$(x.offset))")
438-
end
439-
end
440-
441-
function show(stream::IO, x::NLevelBasis)
442-
write(stream, "NLevel(N=$(x.N))")
443-
end
444-
445-
function show(stream::IO, x::SumBasis)
446-
write(stream, "[")
447-
for i in 1:length(x.bases)
448-
show(stream, x.bases[i])
449-
if i != length(x.bases)
450-
write(stream, "")
451-
end
452-
end
453-
write(stream, "]")
454-
end
190+
Base.:(==)(b1::T, b2::T) where T<:SumBasis = equal_shape(b1.shape, b2.shape)
191+
Base.:(==)(b1::SumBasis, b2::SumBasis) = false
192+
Base.length(b::SumBasis) = sum(b.shape)

0 commit comments

Comments
 (0)