Skip to content

Commit

Permalink
isequal and idiomatic changes
Browse files Browse the repository at this point in the history
  • Loading branch information
apkille committed Jun 20, 2024
1 parent 06fc564 commit a17f364
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 34 deletions.
8 changes: 6 additions & 2 deletions src/QSymbolicsBase/QSymbolicsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@ const QObj = Union{AbstractBra,AbstractKet,AbstractOperator,AbstractSuperOperato
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)
Base.hash(x::SymQObj, h::UInt) = isexpr(x) ? hash(arguments(x), h) : hash([typeof(x),basis(x)], h)
Base.hash(x::SymQObj, h::UInt) = isexpr(x) ? hash((head(x), arguments(x)), h) :
hash((typeof(x),symbollabel(x),basis(x)), h)

function Base.isequal(x::X,y::Y) where {X<:Union{SymQObj, Symbolic{Complex}}, Y<:Union{SymQObj, Symbolic{Complex}}}
function Base.isequal(x::X,y::Y) where {X<:SymQObj, Y<:SymQObj}
if X==Y
if isexpr(x)
if operation(x)==operation(y)
Expand All @@ -156,6 +157,9 @@ function Base.isequal(x::X,y::Y) where {X<:Union{SymQObj, Symbolic{Complex}}, Y<
false
end
end
Base.isequal(::SymQObj, ::Symbolic{Complex}) = false
Base.isequal(::Symbolic{Complex}, ::SymQObj) = false


# TODO check that this does not cause incredibly bad runtime performance
# use a macro to provide specializations if that is indeed the case
Expand Down
36 changes: 14 additions & 22 deletions src/QSymbolicsBase/basic_ops_homogeneous.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,9 @@ arguments(x::SScaled) = [x.coeff,x.obj]
operation(x::SScaled) = *
head(x::SScaled) = :*
children(x::SScaled) = [:*,x.coeff,x.obj]
function Base.:(*)(c, x::Symbolic{T}) where {T<:QObj}
if iszero(c) || isa(x,SymZeroObj)
first(filter(i->i<:Symbolic{T}, Base.uniontypes(SymZeroObj)))()
else
SScaled{T}(c, x)
end
end
function Base.:(*)(x::Symbolic{T}, c) where {T<:QObj}
if iszero(c) || isa(x,SymZeroObj)
first(filter(i->i<:Symbolic{T}, Base.uniontypes(SymZeroObj)))()
else
SScaled{T}(c, x)
end
end
Base.:(/)(x::Symbolic{T}, c) where {T<:QObj} = iszero(c) ? error("cannot divide by zero") : SScaled{T}(1/c,x)
Base.:(/)(x::SymZeroObj, c) = x
Base.:(*)(c, x::Symbolic{T}) where {T<:QObj} = iszero(c) || iszero(x) ? SZero{T}() : SScaled{T}(c, x)
Base.:(*)(x::Symbolic{T}, c) where {T<:QObj} = c*x
Base.:(/)(x::Symbolic{T}, c) where {T<:QObj} = iszero(c) ? throw(DomainError(c,"cannot divide QSymbolics expressions by zero")) : (1/c)*x
basis(x::SScaled) = basis(x.obj)

const SScaledKet = SScaled{AbstractKet}
Expand Down Expand Up @@ -86,7 +73,10 @@ julia> k₁ + k₂
dict
_set_precomputed
_arguments_precomputed
SAdd{S}(d,s,a) where S = length(d)==1 ? SScaled{S}(reverse(first(d))...) : new{S}(d,s,a)
end
function SAdd{S}(d) where S
xs = [c*obj for (c,obj) in d]
length(d)==1 ? SScaled{S}(reverse(first(d))...) : SAdd{S}(d,Set(xs),xs)
end
isexpr(::SAdd) = true
iscall(::SAdd) = true
Expand All @@ -95,8 +85,10 @@ operation(x::SAdd) = +
head(x::SAdd) = :+
children(x::SAdd) = [:+; x._arguments_precomputed]
function Base.:(+)(xs::Vararg{Symbolic{T},N}) where {T<:QObj,N}
nonzero_terms = filter!(x->!isa(x,SymZeroObj),collect(xs))
isempty(nonzero_terms) ? xs[1] : SAdd{T}(countmap_flatten(nonzero_terms, SScaled{T}), Set(collect(xs)), collect(xs))
xs = collect(xs)
f = first(xs)
nonzero_terms = filter!(x->!iszero(x),xs)
isempty(nonzero_terms) ? f : SAdd{T}(countmap_flatten(nonzero_terms, SScaled{T}))
end
Base.:(+)(xs::Vararg{Symbolic{<:QObj},0}) = 0 # to avoid undefined type parameters issue in the above method
basis(x::SAdd) = basis(first(x.dict).first)
Expand Down Expand Up @@ -140,7 +132,7 @@ operation(x::SMulOperator) = *
head(x::SMulOperator) = :*
children(x::SMulOperator) = [:*;x.terms]
function Base.:(*)(xs::Symbolic{AbstractOperator}...)
zero_ind = findfirst(x->isa(x,SZeroOperator), xs)
zero_ind = findfirst(x->iszero(x), xs)
isnothing(zero_ind) ? SMulOperator(collect(xs)) : SZeroOperator()
end
Base.show(io::IO, x::SMulOperator) = print(io, join(map(string, arguments(x)),""))
Expand Down Expand Up @@ -174,8 +166,8 @@ operation(x::STensor) = ⊗
head(x::STensor) = :
children(x::STensor) = pushfirst!(x.terms,:)
function (xs::Symbolic{T}...) where {T<:QObj}
zero_ind = findfirst(x->isa(x,SymZeroObj), xs)
isnothing(zero_ind) ? STensor{T}(collect(xs)) : xs[zero_ind]
zero_ind = findfirst(x->iszero(x), xs)
isnothing(zero_ind) ? STensor{T}(collect(xs)) : SZero{T}()
end
basis(x::STensor) = tensor(basis.(x.terms)...)

Expand Down
1 change: 1 addition & 0 deletions src/QSymbolicsBase/basic_ops_inhomogeneous.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Base.:(*)(b::SZeroBra, k::Symbolic{AbstractKet}) = 0
Base.:(*)(b::Symbolic{AbstractBra}, k::SZeroKet) = 0
Base.:(*)(b::SZeroBra, k::SZeroKet) = 0
Base.show(io::IO, x::SBraKet) = begin print(io,x.bra); print(io,x.ket) end
Base.isequal(x::SBraKet, y::SBraKet) = isequal(x.bra, y.bra) && isequal(x.ket, y.ket)

"""Symbolic application of a superoperator on an operator"""
@withmetadata struct SSuperOpApply <: Symbolic{AbstractOperator}
Expand Down
19 changes: 10 additions & 9 deletions src/QSymbolicsBase/literal_objects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,18 @@ Base.show(io::IO, x::SBra) = print(io, "⟨$(symbollabel(x))|")
Base.show(io::IO, x::Union{SOperator,SHermitianOperator,SUnitaryOperator,SHermitianUnitaryOperator}) = print(io, "$(symbollabel(x))")
Base.show(io::IO, x::SymQObj) = print(io, symbollabel(x)) # fallback that probably is not great

struct SZeroKet <: Symbolic{AbstractKet} end
struct SZero{T<:QObj} <: Symbolic{T} end

struct SZeroBra <: Symbolic{AbstractBra} end
const SZeroBra = SZero{AbstractBra}

struct SZeroOperator <: Symbolic{AbstractOperator} end
const SZeroKet = SZero{AbstractKet}

const SymZeroObj = Union{SZeroKet,SZeroBra,SZeroOperator}
const SZeroOperator = SZero{AbstractOperator}

isexpr(::SymZeroObj) = false
metadata(::SymZeroObj) = nothing
symbollabel(x::SymZeroObj) = "𝟎"
basis(x::SymZeroObj) = nothing
isexpr(::SZero) = false
metadata(::SZero) = nothing
symbollabel(x::SZero) = "𝟎"
basis(x::SZero) = nothing

Base.show(io::IO, x::SymZeroObj) = print(io, symbollabel(x))
Base.show(io::IO, x::SZero) = print(io, symbollabel(x))
Base.iszero(x::SymQObj) = isa(x, SZero)
3 changes: 2 additions & 1 deletion src/extensions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Ket(dim=2)
end
isexpr(::StabilizerState) = false
basis(x::StabilizerState) = SpinBasis(1//2)^nqubits(x.stabilizer)
Base.show(io::IO, x::StabilizerState) = print(io, "𝒮$(num_to_sub(nqubits(x.stabilizer)))")
symbollabel(x::StabilizerState) = "𝒮$(num_to_sub(nqubits(x.stabilizer)))"
Base.show(io::IO, x::StabilizerState) = print(io, symbollabel(x))

StabilizerState(s::T) where {T} = StabilizerState{T}(s) # TODO this is necessary because the @withmetadata macro is not very smart

0 comments on commit a17f364

Please sign in to comment.