Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate type parameters from abstract types and add fullbasis function #38

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# News

## v0.4.0 - 2024-11-26

- Add `OperatorBasis` and `SuperOperatorBasis` abstract types along with corresponding `fullbasis` function to obtain these from instances of subtypes of `AbstractOperator` and `AbstractSuperOperator`.
- Change type parameters for `StateVector`, `AbstractKet` `AbstractBra` `AbstractOperator` `AbstractSuperOperator` to elimitate all type parameters.


## v0.3.6 - 2024-09-08

- Add `coherentstate`, `thermalstate`, `displace`, `squeeze`, `wigner`, previously from QuantumOptics.
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "QuantumInterface"
uuid = "5717a53b-5d69-4fa3-b976-0bf2f97ca1e5"
authors = ["QuantumInterface.jl contributors"]
version = "0.3.6"
version = "0.4.0"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
141 changes: 136 additions & 5 deletions src/QuantumInterface.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,144 @@
module QuantumInterface

import Base: ==, +, -, *, /, ^, length, one, exp, conj, conj!, transpose, copy
import LinearAlgebra: tr, ishermitian, norm, normalize, normalize!
import Base: show, summary
import SparseArrays: sparse, spzeros, AbstractSparseMatrix # TODO move to an extension
##
# Basis specific
##

"""
basis(a)

Return the basis of an object.

If it's ambiguous, e.g. if an operator or superoperator has a different
left and right basis, an [`IncompatibleBases`](@ref) error is thrown.
"""
function basis end

"""
fullbasis(a)

Return the full basis of an object.

Returns subtype of `Basis` when a is a subtype of `StateVector`.
Returns a subtype of `OperatorBasis` a is a subtype of `AbstractOperator`.
Returns a subtype of `SuperOperatorBasis` when a is a subtype of `AbstractSuperOperator`.
"""
function fullbasis end

"""
length(b::Basis)

Total dimension of the Hilbert space.
"""
function length end

function bases end

function spinnumber end

function cutoff end

function offset end

##
# Standard methods
##

"""
multiplicable(a, b)

Check if any two subtypes of `StateVector`, `AbstractOperator`,
or `AbstractSuperOperator` can be multiplied in the given order.

Spcefically this checks whether the right basis of a is equal
to the left basis of b
"""
function multiplicable end

"""
check_multiplicable(a, b)

Throw an [`IncompatibleBases`](@ref) error if the objects are
not multiplicable as determined by `multiplicable(a, b)`.

If the macro `@compatiblebases` is used anywhere up the call stack,
this check is disabled.
"""
function check_multiplicable end

"""
addible(a, b)

Check if any two subtypes of `StateVector`, `AbstractOperator`,
or `AbstractSuperOperator` can be added together.

Spcefically this checks whether the left basis of a is equal
to the left basis of b and whether the right basis of a is equal
to the right basis of b.
"""
function addible end

"""
check_addible(a, b)

Throw an [`IncompatibleBases`](@ref) error if the objects are
not addible as determined by `addible(a, b)`.

If the macro `@compatiblebases` is used anywhere up the call stack,
this check is disabled.
"""
function check_addible end

"""
issquare(a)

Check if any two subtypes of `StateVector`, `AbstractOperator`,
or `AbstractSuperOperator` are square.

Spcefically this checks whether the left basis of a is equal
to the right basis of a.
For subtypes of `StateVector` this is always false.
"""
function addible end

"""
check_issquare(a, b)

Throw an [`IncompatibleBases`](@ref) error if the objects are
not addible as determined by `addible(a, b)`.

If the macro `@compatiblebases` is used anywhere up the call stack,
this check is disabled.
"""
function check_addible end

const BASES_CHECK = Ref(true)

"""
@compatiblebases

Macro to skip checks for compatible bases. Useful for `*`, `expect` and similar
functions.
"""
macro compatiblebases(ex)
return quote
BASES_CHECK.x = false
local val = $(esc(ex))
BASES_CHECK.x = true
val
end
end

function apply! end

function dagger end

"""
directsum(x, y, z...)

Direct sum of the given objects. Alternatively, the unicode
symbol ⊕ (\\oplus) can be used.
"""
function directsum end
const ⊕ = directsum
directsum() = GenericBasis(0)
Expand Down Expand Up @@ -86,8 +216,9 @@ function squeeze end
function wigner end


include("bases.jl")
include("abstract_types.jl")
include("bases.jl")
include("show.jl")

include("linalg.jl")
include("tensor.jl")
Expand Down
42 changes: 20 additions & 22 deletions src/abstract_types.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
"""
Abstract base class for all specialized bases.

The Basis class is meant to specify a basis of the Hilbert space of the
studied system. Besides basis specific information all subclasses must
implement a shape variable which indicates the dimension of the used
Hilbert space. For a spin-1/2 Hilbert space this would be the
vector `[2]`. A system composed of two spins would then have a
shape vector `[2 2]`.

Composite systems can be defined with help of the [`CompositeBasis`](@ref)
class.
"""
abstract type Basis end

"""
Abstract base class for `Bra` and `Ket` states.

Expand All @@ -6,9 +21,9 @@ in respect to a certain basis. These coefficients are stored in the
`data` field and the basis is defined in the `basis`
field.
"""
abstract type StateVector{B,T} end
abstract type AbstractKet{B,T} <: StateVector{B,T} end
abstract type AbstractBra{B,T} <: StateVector{B,T} end
abstract type StateVector end
abstract type AbstractKet <: StateVector end
abstract type AbstractBra <: StateVector end

"""
Abstract base class for all operators.
Expand All @@ -21,7 +36,7 @@ For fast time evolution also at least the function
implemented. Many other generic multiplication functions can be defined in
terms of this function and are provided automatically.
"""
abstract type AbstractOperator{BL,BR} end
abstract type AbstractOperator end

"""
Base class for all super operator classes.
Expand All @@ -37,21 +52,4 @@ A_{bl_1,bl_2} = S_{(bl_1,bl_2) ↔ (br_1,br_2)} B_{br_1,br_2}
A_{br_1,br_2} = B_{bl_1,bl_2} S_{(bl_1,bl_2) ↔ (br_1,br_2)}
```
"""
abstract type AbstractSuperOperator{B1,B2} end

function summary(stream::IO, x::AbstractOperator)
print(stream, "$(typeof(x).name.name)(dim=$(length(x.basis_l))x$(length(x.basis_r)))\n")
if samebases(x)
print(stream, " basis: ")
show(stream, basis(x))
else
print(stream, " basis left: ")
show(stream, x.basis_l)
print(stream, "\n basis right: ")
show(stream, x.basis_r)
end
end

show(stream::IO, x::AbstractOperator) = summary(stream, x)

traceout!(s::StateVector, i) = ptrace(s,i)
abstract type AbstractSuperOperator end
96 changes: 7 additions & 89 deletions src/bases.jl
Original file line number Diff line number Diff line change
@@ -1,35 +1,10 @@
"""
Abstract base class for all specialized bases.

The Basis class is meant to specify a basis of the Hilbert space of the
studied system. Besides basis specific information all subclasses must
implement a shape variable which indicates the dimension of the used
Hilbert space. For a spin-1/2 Hilbert space this would be the
vector `[2]`. A system composed of two spins would then have a
shape vector `[2 2]`.

Composite systems can be defined with help of the [`CompositeBasis`](@ref)
class.
"""
abstract type Basis end

"""
length(b::Basis)

Total dimension of the Hilbert space.
"""
Base.length(b::Basis) = prod(b.shape)

"""
basis(a)

Return the basis of an object.

If it's ambiguous, e.g. if an operator has a different left and right basis,
an [`IncompatibleBases`](@ref) error is thrown.
"""
function basis end


"""
GenericBasis(N)
Expand Down Expand Up @@ -64,6 +39,7 @@ end
CompositeBasis(bases) = CompositeBasis([length(b) for b ∈ bases], bases)
CompositeBasis(bases::Basis...) = CompositeBasis((bases...,))
CompositeBasis(bases::Vector) = CompositeBasis((bases...,))
bases(b::CompositeBasis) = b.bases

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

Expand Down Expand Up @@ -142,8 +118,6 @@ Exception that should be raised for an illegal algebraic operation.
"""
mutable struct IncompatibleBases <: Exception end

const BASES_CHECK = Ref(true)

"""
@samebases

Expand Down Expand Up @@ -283,6 +257,8 @@ struct FockBasis{T} <: Basis
new{T}([N-offset+1], N, offset)
end
end
cutoff(b::FockBasis) = b.N
offset(b::FockBasis) = b.offset

Base.:(==)(b1::FockBasis, b2::FockBasis) = (b1.N==b2.N && b1.offset==b2.offset)

Expand Down Expand Up @@ -348,6 +324,7 @@ struct SpinBasis{S,T} <: Basis
end
SpinBasis(spinnumber::Rational) = SpinBasis{spinnumber}(spinnumber)
SpinBasis(spinnumber) = SpinBasis(convert(Rational{Int}, spinnumber))
spinnumber(b::SpinBasis) = b.spinnumber

Base.:(==)(b1::SpinBasis, b2::SpinBasis) = b1.spinnumber==b2.spinnumber

Expand All @@ -366,9 +343,9 @@ SumBasis(shape, bases::Vector) = (tmp = (bases...,); SumBasis(shape, tmp))
SumBasis(bases::Vector) = SumBasis((bases...,))
SumBasis(bases::Basis...) = SumBasis((bases...,))

==(b1::T, b2::T) where T<:SumBasis = equal_shape(b1.shape, b2.shape)
==(b1::SumBasis, b2::SumBasis) = false
length(b::SumBasis) = sum(b.shape)
Base.:(==)(b1::T, b2::T) where T<:SumBasis = equal_shape(b1.shape, b2.shape)
Base.:(==)(b1::SumBasis, b2::SumBasis) = false
Base.length(b::SumBasis) = sum(b.shape)

"""
directsum(b1::Basis, b2::Basis)
Expand All @@ -393,62 +370,3 @@ function directsum(b1::SumBasis, b2::SumBasis)
bases = [b1.bases...;b2.bases...]
return SumBasis(shape, (bases...,))
end

embed(b::SumBasis, indices, ops) = embed(b, b, indices, ops)

##
# show methods
##

function show(stream::IO, x::GenericBasis)
if length(x.shape) == 1
write(stream, "Basis(dim=$(x.shape[1]))")
else
s = replace(string(x.shape), " " => "")
write(stream, "Basis(shape=$s)")
end
end

function show(stream::IO, x::CompositeBasis)
write(stream, "[")
for i in 1:length(x.bases)
show(stream, x.bases[i])
if i != length(x.bases)
write(stream, " ⊗ ")
end
end
write(stream, "]")
end

function show(stream::IO, x::SpinBasis)
d = denominator(x.spinnumber)
n = numerator(x.spinnumber)
if d == 1
write(stream, "Spin($n)")
else
write(stream, "Spin($n/$d)")
end
end

function show(stream::IO, x::FockBasis)
if iszero(x.offset)
write(stream, "Fock(cutoff=$(x.N))")
else
write(stream, "Fock(cutoff=$(x.N), offset=$(x.offset))")
end
end

function show(stream::IO, x::NLevelBasis)
write(stream, "NLevel(N=$(x.N))")
end

function show(stream::IO, x::SumBasis)
write(stream, "[")
for i in 1:length(x.bases)
show(stream, x.bases[i])
if i != length(x.bases)
write(stream, " ⊕ ")
end
end
write(stream, "]")
end
Loading
Loading