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

adding Commutators, Anticommutator, Daggers #40

Merged
merged 24 commits into from
Jun 19, 2024
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Manifest.toml
.vscode
53 changes: 36 additions & 17 deletions src/QSymbolicsBase/QSymbolicsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import TermInterface: isexpr, head, iscall, children, operation, arguments, metadata

using LinearAlgebra
import LinearAlgebra: eigvecs
import LinearAlgebra: eigvecs, ishermitian, inv

import QuantumInterface:
apply!,
Expand All @@ -17,24 +17,30 @@
AbstractKet, AbstractOperator, AbstractSuperOperator, AbstractBra

export SymQObj,QObj,
AbstractRepresentation, AbstractUse,
QuantumOpticsRepr, QuantumMCRepr, CliffordRepr,
UseAsState, UseAsObservable, UseAsOperation,
AbstractRepresentation,AbstractUse,
QuantumOpticsRepr,QuantumMCRepr,CliffordRepr,
UseAsState,UseAsObservable,UseAsOperation,
apply!,
express,
tensor,⊗,
dagger,projector,
X,Y,Z,σˣ,σʸ,σᶻ,Pm,Pp,σ₋,σ₊,
dagger,projector,commutator,anticommutator,expand,
I,X,Y,Z,σˣ,σʸ,σᶻ,Pm,Pp,σ₋,σ₊,
H,CNOT,CPHASE,XCX,XCY,XCZ,YCX,YCY,YCZ,ZCX,ZCY,ZCZ,
X1,X2,Y1,Y2,Z1,Z2,X₁,X₂,Y₁,Y₂,Z₁,Z₂,L0,L1,Lp,Lm,Lpi,Lmi,L₀,L₁,L₊,L₋,L₊ᵢ,L₋ᵢ,
vac,F₀,F0,F₁,F1,
N,n̂,Create,âꜛ,Destroy,â,
SProjector,MixedState,IdentityOp,
STensorKet,STensorOperator,SScaledKet,SScaledOperator,SAddKet,SAddOperator,SScaledBra,SAddBra,STensorBra,SDagger,
HGate, XGate, YGate, ZGate, CPHASEGate, CNOTGate,
XBasisState, YBasisState, ZBasisState,
NumberOp, CreateOp, DestroyOp,
XCXGate, XCYGate, XCZGate, YCXGate, YCYGate, YCZGate, ZCXGate, ZCYGate, ZCZGate
N,n̂,Create,âꜛ,Destroy,â,SpinBasis,FockBasis,
SBra,SKet,SOperator,
SAdd,SAddBra,SAddKet,SAddOperator,
SScaled,SScaledBra,SScaledOperator,SScaledKet,
STensorBra,STensorKet,STensorOperator,
SProjector,MixedState,IdentityOp,SInvOperator,SHermitianOperator,SUnitaryOperator,SHermitianUnitaryOperator,
SApplyKet,SApplyBra,SMulOperator,SSuperOpApply,SCommutator,SAnticommutator,SDagger,SBraKet,SOuterKetBra,
HGate,XGate,YGate,ZGate,CPHASEGate,CNOTGate,
XBasisState,YBasisState,ZBasisState,
NumberOp,CreateOp,DestroyOp,
XCXGate,XCYGate,XCZGate,YCXGate,YCYGate,YCZGate,ZCXGate,ZCYGate,ZCZGate,
qsimplify,qsimplify_pauli,qsimplify_flatten,qsimplify_commutator,qsimplify_anticommutator,
isunitary

function countmap(samples) # A simpler version of StatsBase.countmap, because StatsBase is slow to import
counts = Dict{Any,Any}()
Expand Down Expand Up @@ -127,17 +133,29 @@
# Basic Types
##

const QObj = Union{AbstractKet,AbstractOperator,AbstractSuperOperator,AbstractBra}
const QObj = Union{AbstractBra,AbstractKet,AbstractOperator,AbstractSuperOperator}
const SymQObj = Symbolic{<:QObj} # TODO Should we use Sym or Symbolic... Sym has a lot of predefined goodies, including metadata support
Base.:(-)(x::SymQObj) = (-1)*x
Base.:(-)(x::SymQObj,y::SymQObj) = x + (-y)

function Base.isequal(x::X,y::Y) where {X<:SymQObj, Y<:SymQObj}
function _in(x::SymQObj, y::SymQObj)
for i in arguments(y)
if isequal(x, i)
return true
end
end
false

Check warning on line 147 in src/QSymbolicsBase/QSymbolicsBase.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/QSymbolicsBase.jl#L147

Added line #L147 was not covered by tests
end
function Base.isequal(x::X,y::Y) where {X<:Union{SymQObj, Symbolic{Complex}}, Y<:Union{SymQObj, Symbolic{Complex}}}
Krastanov marked this conversation as resolved.
Show resolved Hide resolved
if X==Y
if isexpr(x)
if operation(x)==operation(y)
ax,ay = arguments(x),arguments(y)
(length(ax) == length(ay)) && all(zip(ax,ay)) do xy isequal(xy...) end
if (operation(x) === +) && (length(ax) == length(ay))
all(x -> _in(x, y), ax)
else
all(zip(ax,ay)) do xy isequal(xy...) end
end
else
false
end
Expand All @@ -151,12 +169,13 @@

# TODO check that this does not cause incredibly bad runtime performance
# use a macro to provide specializations if that is indeed the case
propsequal(x,y) = all(n->getproperty(x,n)==getproperty(y,n), propertynames(x))
propsequal(x,y) = all(n->isequal(getproperty(x,n),getproperty(y,n)), propertynames(x))

##
# Most symbolic objects defined here
##

include("literal_objects.jl")
include("basic_ops_homogeneous.jl")
include("basic_ops_inhomogeneous.jl")
include("predefined.jl")
Expand Down
164 changes: 139 additions & 25 deletions src/QSymbolicsBase/basic_ops_homogeneous.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
"""This file defines the symbolic operations for quantum objects (kets, operators, and bras) that are homogeneous in their arguments."""
##
# This file defines the symbolic operations for quantum objects (kets, operators, and bras) that are homogeneous in their arguments.
##

struct SKet <: Symbolic{AbstractKet}
name::Symbol
basis::Basis
end
struct SOperator <: Symbolic{AbstractKet}
name::Symbol
basis::Basis
end
const SymQ = Union{SKet, SOperator}
isexpr(::SymQ) = false
metadata(::SymQ) = nothing
basis(x::SymQ) = x.basis
"""Scaling of a quantum object (ket, operator, or bra) by a number

```jldoctest
julia> k = SKet(:k, SpinBasis(1//2))
|k⟩

symbollabel(x::SymQ) = x.name
Base.show(io::IO, x::SKet) = print(io, "|$(symbollabel(x))⟩")
Base.show(io::IO, x::SOperator) = print(io, "$(symbollabel(x))")
Base.show(io::IO, x::SymQObj) = print(io, symbollabel(x)) # fallback that probably is not great
julia> 2*k
2|k⟩

"""Scaling of a quantum object (ket, operator, or bra) by a number."""
julia> A = SOperator(:A, SpinBasis(1//2))
A

julia> 2*A
2A
````
"""
@withmetadata struct SScaled{T<:QObj} <: Symbolic{T}
coeff
obj
Expand Down Expand Up @@ -54,13 +53,21 @@
const SScaledBra = SScaled{AbstractBra}
function Base.show(io::IO, x::SScaledBra)
if x.coeff isa Number
print(io, "$(x.obj)$(x.coeff)")
print(io, "$(x.coeff)$(x.obj)")
else
print(io, "$(x.obj)($(x.coeff))")
print(io, "($(x.coeff))$(x.obj)")

Check warning on line 58 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L58

Added line #L58 was not covered by tests
end
end

"""Addition of quantum objects (kets, operators, or bras)."""
"""Addition of quantum objects (kets, operators, or bras)

```jldoctest
julia> k₁ = SKet(:k₁, SpinBasis(1//2)); k₂ = SKet(:k₂, SpinBasis(1//2));

julia> k₁ + k₂
(|k₁⟩+|k₂⟩)
```
"""
@withmetadata struct SAdd{T<:QObj} <: Symbolic{T}
dict
SAdd{S}(d) where S = length(d)==1 ? SScaled{S}(reverse(first(d))...) : new{S}(d)
Expand All @@ -76,13 +83,61 @@
basis(x::SAdd) = basis(first(x.dict).first)

const SAddKet = SAdd{AbstractKet}
Base.show(io::IO, x::SAddKet) = print(io, "("*join(map(string, arguments(x)),"+")::String*")") # type assert to help inference
function Base.show(io::IO, x::SAddKet)
ordered_terms = sort([repr(i) for i in arguments(x)])
apkille marked this conversation as resolved.
Show resolved Hide resolved
print(io, "("*join(ordered_terms,"+")::String*")") # type assert to help inference
end
const SAddOperator = SAdd{AbstractOperator}
Base.show(io::IO, x::SAddOperator) = print(io, "("*join(map(string, arguments(x)),"+")::String*")") # type assert to help inference
function Base.show(io::IO, x::SAddOperator)
ordered_terms = sort([repr(i) for i in arguments(x)])
print(io, "("*join(ordered_terms,"+")::String*")") # type assert to help inference

Check warning on line 93 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L91-L93

Added lines #L91 - L93 were not covered by tests
end
const SAddBra = SAdd{AbstractBra}
Base.show(io::IO, x::SAddBra) = print(io, "("*join(map(string, arguments(x)),"+")::String*")") # type assert to help inference
function Base.show(io::IO, x::SAddBra)
ordered_terms = sort([repr(i) for i in arguments(x)])
print(io, "("*join(ordered_terms,"+")::String*")") # type assert to help inference

Check warning on line 98 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L96-L98

Added lines #L96 - L98 were not covered by tests
end

"""Symbolic application of operator on operator

```jldoctest
julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2));

"""Tensor product of quantum objects (kets, operators, or bras)."""
julia> A*B
AB
```
"""
@withmetadata struct SMulOperator <: Symbolic{AbstractOperator}
terms
function SMulOperator(terms)
coeff, cleanterms = prefactorscalings(terms)
coeff*new(cleanterms)
end
end
isexpr(::SMulOperator) = true
iscall(::SMulOperator) = true

Check warning on line 118 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L118

Added line #L118 was not covered by tests
arguments(x::SMulOperator) = x.terms
operation(x::SMulOperator) = *
head(x::SMulOperator) = :*
children(x::SMulOperator) = [:*;x.terms]

Check warning on line 122 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L121-L122

Added lines #L121 - L122 were not covered by tests
Base.:(*)(xs::Symbolic{AbstractOperator}...) = SMulOperator(collect(xs))
Base.show(io::IO, x::SMulOperator) = print(io, join(map(string, arguments(x)),""))
basis(x::SMulOperator) = basis(x.terms)

Check warning on line 125 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L125

Added line #L125 was not covered by tests

"""Tensor product of quantum objects (kets, operators, or bras)

```jldoctest
julia> k₁ = SKet(:k₁, SpinBasis(1//2)); k₂ = SKet(:k₂, SpinBasis(1//2));

julia> k₁ ⊗ k₂
|k₁⟩|k₂⟩

julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2));

julia> A ⊗ B
A⊗B
```
"""
@withmetadata struct STensor{T<:QObj} <: Symbolic{T}
terms
function STensor{S}(terms) where S
Expand All @@ -107,3 +162,62 @@
Base.show(io::IO, x::STensorSuperOperator) = print(io, join(map(string, arguments(x)),"⊗"))
const STensorBra = STensor{AbstractBra}
Base.show(io::IO, x::STensorBra) = print(io, join(map(string, arguments(x)),""))

"""Symbolic commutator of two operators

```jldoctest
julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2));

julia> commutator(A, B)
[A,B]

julia> commutator(A, A)
0
```
"""
@withmetadata struct SCommutator <: Symbolic{AbstractOperator}
op1
op2
function SCommutator(o1, o2)
coeff, cleanterms = prefactorscalings([o1 o2], scalar=true)
cleanterms[1] === cleanterms[2] ? 0 : coeff*new(cleanterms...)
end
end
isexpr(::SCommutator) = true
iscall(::SCommutator) = true
arguments(x::SCommutator) = [x.op1, x.op2]
operation(x::SCommutator) = commutator
head(x::SCommutator) = :commutator
children(x::SCommutator) = [:commutator, x.op1, x.op2]

Check warning on line 191 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L190-L191

Added lines #L190 - L191 were not covered by tests
commutator(o1::Symbolic{AbstractOperator}, o2::Symbolic{AbstractOperator}) = SCommutator(o1, o2)
Base.show(io::IO, x::SCommutator) = print(io, "[$(x.op1),$(x.op2)]")
basis(x::SCommutator) = basis(x.op1)
expand(x::SCommutator) = x == 0 ? x : x.op1*x.op2 - x.op2*x.op1

Check warning on line 195 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L194-L195

Added lines #L194 - L195 were not covered by tests

"""Symbolic anticommutator of two operators

```jldoctest
julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2));

julia> anticommutator(A, B)
{A,B}
```
"""
@withmetadata struct SAnticommutator <: Symbolic{AbstractOperator}
op1
op2
function SAnticommutator(o1, o2)
coeff, cleanterms = prefactorscalings([o1 o2], scalar=true)
coeff*new(cleanterms...)
end
end
isexpr(::SAnticommutator) = true
iscall(::SAnticommutator) = true
arguments(x::SAnticommutator) = [x.op1, x.op2]
operation(x::SAnticommutator) = anticommutator
head(x::SAnticommutator) = :anticommutator
children(x::SAnticommutator) = [:anticommutator, x.op1, x.op2]

Check warning on line 219 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L218-L219

Added lines #L218 - L219 were not covered by tests
anticommutator(o1::Symbolic{AbstractOperator}, o2::Symbolic{AbstractOperator}) = SAnticommutator(o1, o2)
Base.show(io::IO, x::SAnticommutator) = print(io, "{$(x.op1),$(x.op2)}")
basis(x::SAnticommutator) = basis(x.op1)
expand(x::SAnticommutator) = x == 0 ? x : x.op1*x.op2 + x.op2*x.op1

Check warning on line 223 in src/QSymbolicsBase/basic_ops_homogeneous.jl

View check run for this annotation

Codecov / codecov/patch

src/QSymbolicsBase/basic_ops_homogeneous.jl#L222-L223

Added lines #L222 - L223 were not covered by tests
Loading
Loading