diff --git a/src/QSymbolicsBase/QSymbolicsBase.jl b/src/QSymbolicsBase/QSymbolicsBase.jl index 04b7d17..f1859fb 100644 --- a/src/QSymbolicsBase/QSymbolicsBase.jl +++ b/src/QSymbolicsBase/QSymbolicsBase.jl @@ -6,7 +6,7 @@ using TermInterface import TermInterface: isexpr, head, iscall, children, operation, arguments, metadata using LinearAlgebra -import LinearAlgebra: eigvecs, ishermitian +import LinearAlgebra: eigvecs, ishermitian, inv import QuantumInterface: apply!, @@ -17,7 +17,7 @@ import QuantumInterface: AbstractKet, AbstractOperator, AbstractSuperOperator, AbstractBra export SymQObj,QObj, - AbstractRepresentation, AbstractUse, + AbstractRepresentation, AbstractUse, QuantumOpticsRepr, QuantumMCRepr, CliffordRepr, UseAsState, UseAsObservable, UseAsOperation, apply!, @@ -33,15 +33,14 @@ export SymQObj,QObj, SAddBra,SAddKet,SAddOperator, SScaledBra,SScaledOperator,SScaledKet, STensorBra,STensorKet,STensorOperator, - SProjector,MixedState,IdentityOp,SInverseOperator,SHermitianOperator,SUnitaryOperator,SCommutativeOperator, - SApplyKet,SApplyBra,SApplyOp,SApplyOpSuper,SCommutator,SAnticommutator,SDagger,SBraKet,SOuterKetBra, + SProjector,MixedState,IdentityOp,SInvOperator,SHermitianOperator,SUnitaryOperator,SHermitianUnitaryOperator, + SApplyKet,SApplyBra,SMulOperator,SApplySuperop,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, - circuit_simplify, commutator_simplify, anticommutator_simplify, - ishermitian, isunitary, iscommutative, - hermitian, unitary, commutative, inverse + XCXGate, XCYGate, XCZGate, YCXGate, YCYGate, YCZGate, ZCXGate, ZCYGate, ZCZGate, + pauli_simplify, commutator_simplify, anticommutator_simplify, + isunitary function countmap(samples) # A simpler version of StatsBase.countmap, because StatsBase is slow to import counts = Dict{Any,Any}() @@ -164,7 +163,7 @@ propsequal(x,y) = all(n->isequal(getproperty(x,n),getproperty(y,n)), propertynam # Most symbolic objects defined here ## -include("objects.jl") +include("literal_objects.jl") include("basic_ops_homogeneous.jl") include("basic_ops_inhomogeneous.jl") include("predefined.jl") diff --git a/src/QSymbolicsBase/basic_ops_homogeneous.jl b/src/QSymbolicsBase/basic_ops_homogeneous.jl index c8f02f8..8a29802 100644 --- a/src/QSymbolicsBase/basic_ops_homogeneous.jl +++ b/src/QSymbolicsBase/basic_ops_homogeneous.jl @@ -123,22 +123,22 @@ julia> A*B AB ``` """ -@withmetadata struct SApplyOp <: Symbolic{AbstractOperator} +@withmetadata struct SMulOperator <: Symbolic{AbstractOperator} terms - function SApplyOp(terms) + function SMulOperator(terms) coeff, cleanterms = prefactorscalings(terms) coeff*new(cleanterms) end end -isexpr(::SApplyOp) = true -iscall(::SApplyOp) = true -arguments(x::SApplyOp) = x.terms -operation(x::SApplyOp) = * -head(x::SApplyOp) = :* -children(x::SApplyOp) = pushfirst!(x.terms,:*) -Base.:(*)(xs::Symbolic{AbstractOperator}...) = SApplyOp(collect(xs)) -Base.show(io::IO, x::SApplyOp) = print(io, join(map(string, arguments(x)),"")) -basis(x::SApplyOp) = basis(x.terms) +isexpr(::SMulOperator) = true +iscall(::SMulOperator) = true +arguments(x::SMulOperator) = x.terms +operation(x::SMulOperator) = * +head(x::SMulOperator) = :* +children(x::SMulOperator) = pushfirst!(x.terms,:*) +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) """Tensor product of quantum objects (kets, operators, or bras) @@ -187,14 +187,8 @@ julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2)); julia> commutator(A, B) [A,B] -julia> expand(commutator(A, B)) -(AB+-1BA) - julia> commutator(A, A) 0 - -julia> commutator(commutative(A), B) -0 ``` """ @withmetadata struct SCommutator <: Symbolic{AbstractOperator} @@ -212,12 +206,9 @@ operation(x::SCommutator) = commutator head(x::SCommutator) = :commutator children(x::SCommutator) = [:commutator, x.op1, x.op2] commutator(o1::Symbolic{AbstractOperator}, o2::Symbolic{AbstractOperator}) = SCommutator(o1, o2) -commutator(o1::SCommutativeOperator, o2::Symbolic{AbstractOperator}) = 0 -commutator(o1::Symbolic{AbstractOperator}, o2::SCommutativeOperator) = 0 -commutator(o1::SCommutativeOperator, o2::SCommutativeOperator) = 0 Base.show(io::IO, x::SCommutator) = print(io, "[$(x.op1),$(x.op2)]") basis(x::SCommutator) = basis(x.op1) -expand(x::SCommutator) = x == 0 ? x : SApplyOp([x.op1, x.op2]) - SApplyOp([x.op2, x.op1]) +expand(x::SCommutator) = x == 0 ? x : SMulOperator([x.op1, x.op2]) - SMulOperator([x.op2, x.op1]) """Symbolic anticommutator of two operators @@ -226,12 +217,6 @@ julia> A = SOperator(:A, SpinBasis(1//2)); B = SOperator(:B, SpinBasis(1//2)); julia> anticommutator(A, B) {A,B} - -julia> expand(anticommutator(A, B)) -(AB+BA) - -julia> anticommutator(commutative(A), B) -2AB ``` """ @withmetadata struct SAnticommutator <: Symbolic{AbstractOperator} @@ -249,9 +234,6 @@ operation(x::SAnticommutator) = anticommutator head(x::SAnticommutator) = :anticommutator children(x::SAnticommutator) = [:anticommutator, x.op1, x.op2] anticommutator(o1::Symbolic{AbstractOperator}, o2::Symbolic{AbstractOperator}) = SAnticommutator(o1, o2) -anticommutator(o1::SCommutativeOperator, o2::Symbolic{AbstractOperator}) = 2*o1*o2 -anticommutator(o1::Symbolic{AbstractOperator}, o2::SCommutativeOperator) = 2*o1*o2 -anticommutator(o1::SCommutativeOperator, o2::SCommutativeOperator) = 2*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 : SApplyOp([x.op1, x.op2]) + SApplyOp([x.op2, x.op1]) +expand(x::SAnticommutator) = x == 0 ? x : SMulOperator([x.op1, x.op2]) + SMulOperator([x.op2, x.op1]) diff --git a/src/QSymbolicsBase/basic_ops_inhomogeneous.jl b/src/QSymbolicsBase/basic_ops_inhomogeneous.jl index 7072979..e90e0af 100644 --- a/src/QSymbolicsBase/basic_ops_inhomogeneous.jl +++ b/src/QSymbolicsBase/basic_ops_inhomogeneous.jl @@ -65,10 +65,6 @@ julia> b*k @withmetadata struct SBraKet <: Symbolic{Complex} bra ket - function SBraKet(b, k) - coeff, cleanterms = prefactorscalings([b k]) - coeff*new(cleanterms...) - end end isexpr(::SBraKet) = true iscall(::SBraKet) = true @@ -80,20 +76,20 @@ Base.:(*)(b::Symbolic{AbstractBra}, k::Symbolic{AbstractKet}) = SBraKet(b,k) Base.show(io::IO, x::SBraKet) = begin print(io,x.bra); print(io,x.ket) end """Symbolic application of a superoperator on an operator""" -@withmetadata struct SApplyOpSuper <: Symbolic{AbstractOperator} +@withmetadata struct SApplySuperop <: Symbolic{AbstractOperator} sop op end -isexpr(::SApplyOpSuper) = true -iscall(::SApplyOpSuper) = true -arguments(x::SApplyOpSuper) = [x.sop,x.op] -operation(x::SApplyOpSuper) = * -head(x::SApplyOpSuper) = :* -children(x::SApplyOpSuper) = [:*,x.sop,x.op] -Base.:(*)(sop::Symbolic{AbstractSuperOperator}, op::Symbolic{AbstractOperator}) = SApplyOpSuper(sop,op) -Base.:(*)(sop::Symbolic{AbstractSuperOperator}, k::Symbolic{AbstractKet}) = SApplyOpSuper(sop,SProjector(k)) -Base.show(io::IO, x::SApplyOpSuper) = begin print(io, x.sop); print(io, x.op) end -basis(x::SApplyOpSuper) = basis(x.op) +isexpr(::SApplySuperop) = true +iscall(::SApplySuperop) = true +arguments(x::SApplySuperop) = [x.sop,x.op] +operation(x::SApplySuperop) = * +head(x::SApplySuperop) = :* +children(x::SApplySuperop) = [:*,x.sop,x.op] +Base.:(*)(sop::Symbolic{AbstractSuperOperator}, op::Symbolic{AbstractOperator}) = SApplySuperop(sop,op) +Base.:(*)(sop::Symbolic{AbstractSuperOperator}, k::Symbolic{AbstractKet}) = SApplySuperop(sop,SProjector(k)) +Base.show(io::IO, x::SApplySuperop) = begin print(io, x.sop); print(io, x.op) end +basis(x::SApplySuperop) = basis(x.op) """Symbolic outer product of a ket and a bra ```jldoctest diff --git a/src/QSymbolicsBase/literal_objects.jl b/src/QSymbolicsBase/literal_objects.jl new file mode 100644 index 0000000..ad67c49 --- /dev/null +++ b/src/QSymbolicsBase/literal_objects.jl @@ -0,0 +1,52 @@ +## +# This file defines quantum objects (kets, bras, and operators) with various properties +## + +struct SKet <: Symbolic{AbstractKet} + name::Symbol + basis::Basis +end + +struct SBra <: Symbolic{AbstractBra} + name::Symbol + basis::Basis +end + +struct SOperator <: Symbolic{AbstractOperator} + name::Symbol + basis::Basis +end +ishermitian(x::SOperator) = false +isunitary(x::SOperator) = false + +struct SHermitianOperator <: Symbolic{AbstractOperator} + name::Symbol + basis::Basis +end +ishermitian(::SHermitianOperator) = true +isunitary(::SHermitianOperator) = false + +struct SUnitaryOperator <: Symbolic{AbstractOperator} + name::Symbol + basis::Basis +end +ishermitian(::SUnitaryOperator) = false +isunitary(::SUnitaryOperator) = true + +struct SHermitianUnitaryOperator <: Symbolic{AbstractOperator} + name::Symbol + basis::Basis +end +ishermitian(::SHermitianUnitaryOperator) = true +isunitary(::SHermitianUnitaryOperator) = true + +const SymQ = Union{SKet, SBra, SOperator, SHermitianOperator, SUnitaryOperator, SHermitianUnitaryOperator} +isexpr(::SymQ) = false +metadata(::SymQ) = nothing +symbollabel(x::SymQ) = x.name +basis(x::SymQ) = x.basis + +Base.show(io::IO, x::SKet) = print(io, "|$(symbollabel(x))⟩") +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 diff --git a/src/QSymbolicsBase/objects.jl b/src/QSymbolicsBase/objects.jl deleted file mode 100644 index a6caa14..0000000 --- a/src/QSymbolicsBase/objects.jl +++ /dev/null @@ -1,71 +0,0 @@ -"""This file defines quantum objects (kets, bras, and operators) with various properties""" -struct SKet <: Symbolic{AbstractKet} - name::Symbol - basis::Basis -end -struct SBra <: Symbolic{AbstractBra} - name::Symbol - basis::Basis -end -struct SOperator <: Symbolic{AbstractOperator} - name::Symbol - basis::Basis -end -const SymQ = Union{SKet, SBra, SOperator} -isexpr(::SymQ) = false -metadata(::SymQ) = nothing -basis(x::SymQ) = x.basis - -symbollabel(x::SymQ) = x.name -Base.show(io::IO, x::SKet) = print(io, "|$(symbollabel(x))⟩") -Base.show(io::IO, x::SBra) = 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 - -ishermitian(x::SOperator) = false -isunitary(x::SOperator) = false -iscommutative(x::SOperator) = false - -"""Inverse Operator""" -@withmetadata struct SInverseOperator <: Symbolic{AbstractOperator} - op::Symbolic{AbstractOperator} -end -isexpr(::SInverseOperator) = true -iscall(::SInverseOperator) = true -arguments(x::SInverseOperator) = [x.op] -operation(x::SInverseOperator) = inverse -head(x::SInverseOperator) = :inverse -children(x::SInverseOperator) = [:inverse, x.op] -basis(x::SInverseOperator) = basis(x.op) -Base.show(io::IO, x::SInverseOperator) = print(io, "$(x.op)⁻¹") -inverse(x::Symbolic{AbstractOperator}) = SInverseOperator(x) - -"""Hermitian Operator""" -struct SHermitianOperator <: Symbolic{AbstractOperator} - op::Symbolic{AbstractOperator} -end -isexpr(::SHermitianOperator) = false -basis(x::SHermitianOperator) = basis(x.op) -Base.show(io::IO, x::SHermitianOperator) = print(io, "$(x.op)") -hermitian(x::Symbolic{AbstractOperator}) = SHermitianOperator(x) -ishermitian(::SHermitianOperator) = true - -"""Unitary Operator""" -struct SUnitaryOperator <: Symbolic{AbstractOperator} - op::Symbolic{AbstractOperator} -end -isexpr(::SUnitaryOperator) = false -basis(x::SUnitaryOperator) = basis(x.op) -Base.show(io::IO, x::SUnitaryOperator) = print(io, "$(x.op)") -unitary(x::Symbolic{AbstractOperator}) = SUnitaryOperator(x) -isunitary(::SUnitaryOperator) = true - -"""Commutative Operator""" -struct SCommutativeOperator <: Symbolic{AbstractOperator} - op::Symbolic{AbstractOperator} -end -isexpr(::SCommutativeOperator) = false -basis(x::SCommutativeOperator) = basis(x.op) -Base.show(io::IO, x::SCommutativeOperator) = print(io, "$(x.op)") -commutative(x::Symbolic{AbstractOperator}) = SCommutativeOperator(x) -iscommutative(::SCommutativeOperator) = true diff --git a/src/QSymbolicsBase/predefined.jl b/src/QSymbolicsBase/predefined.jl index dde3f9d..f28dade 100644 --- a/src/QSymbolicsBase/predefined.jl +++ b/src/QSymbolicsBase/predefined.jl @@ -90,7 +90,7 @@ basis(::AbstractSingleQubitGate) = qubit_basis basis(::AbstractTwoQubitGate) = qubit_basis⊗qubit_basis Base.show(io::IO, x::AbstractSingleQubitOp) = print(io, "$(symbollabel(x))") Base.show(io::IO, x::AbstractTwoQubitOp) = print(io, "$(symbollabel(x))") -Base.:(*)(xs::AbstractSingleQubitGate...) = circuit_simplify(SApplyOp(collect(xs))) +Base.:(*)(xs::AbstractSingleQubitGate...) = pauli_simplify(SMulOperator(collect(xs))) commutator(o1::AbstractSingleQubitGate, o2::AbstractSingleQubitGate) = commutator_simplify(SCommutator(o1, o2)) anticommutator(o1::AbstractSingleQubitGate, o2::AbstractSingleQubitGate) = anticommutator_simplify(SAnticommutator(o1, o2)) @@ -107,51 +107,43 @@ eigvecs(g::XGate) = [X1,X2] symbollabel(::XGate) = "X" ishermitian(::XGate) = true isunitary(::XGate) = true -iscommutative(::XGate) = false @withmetadata struct YGate <: AbstractSingleQubitGate end eigvecs(g::YGate) = [Y1,Y2] symbollabel(::YGate) = "Y" ishermitian(::YGate) = true isunitary(::YGate) = true -iscommutative(::YGate) = false @withmetadata struct ZGate <: AbstractSingleQubitGate end eigvecs(g::ZGate) = [Z1,Z2] symbollabel(::ZGate) = "Z" ishermitian(::ZGate) = true isunitary(::ZGate) = true -iscommutative(::ZGate) = false @withmetadata struct PauliM <: AbstractSingleQubitGate end symbollabel(::PauliM) = "σ₋" ishermitian(::PauliM) = true isunitary(::PauliM) = true -iscommutative(::PauliM) = false @withmetadata struct PauliP <: AbstractSingleQubitGate end symbollabel(::PauliP) = "σ₊" ishermitian(::PauliP) = true isunitary(::PauliP) = true -iscommutative(::PauliP) = false @withmetadata struct HGate <: AbstractSingleQubitGate end symbollabel(::HGate) = "H" ishermitian(::HGate) = true isunitary(::HGate) = true -iscommutative(::HGate) = false @withmetadata struct CNOTGate <: AbstractTwoQubitGate end symbollabel(::CNOTGate) = "CNOT" ishermitian(::CNOTGate) = true isunitary(::CNOTGate) = true -iscommutative(::CNOTGate) = false @withmetadata struct CPHASEGate <: AbstractTwoQubitGate end symbollabel(::CPHASEGate) = "CPHASE" ishermitian(::CPHASEGate) = true isunitary(::CPHASEGate) = true -iscommutative(::CPHASEGate) = false const xyzsuplabeldict = Dict(:X=>"ˣ",:Y=>"ʸ",:Z=>"ᶻ") for control in (:X, :Y, :Z) @@ -254,11 +246,13 @@ julia> B = SOperator(:B, SpinBasis(1//2)); julia> dagger(A*B) B†A† -julia> dagger(hermitian(A)) -A +julia> ℋ = SHermitianOperator(:ℋ, SpinBasis(1//2)); U = SUnitaryOperator(:U, SpinBasis(1//2)); -julia> dagger(unitary(A)) -A⁻¹ +julia> dagger(ℋ) +ℋ + +julia> dagger(U) +U⁻¹ ``` """ @withmetadata struct SDagger{T<:QObj} <: Symbolic{T} @@ -279,14 +273,15 @@ dagger(x::SAddBra) = SAddKet(Dict(dagger(b)=>v for (b,v) in pairs(x.dict))) dagger(x::SOperator) = SDagger{AbstractOperator}(x) dagger(x::SAddOperator) = SAddOperator(Dict(dagger(o)=>v for (o,v) in pairs(x.dict))) dagger(x::SHermitianOperator) = x -dagger(x::SUnitaryOperator) = inverse(x) +dagger(x::SHermitianUnitaryOperator) = x +dagger(x::SUnitaryOperator) = inv(x) dagger(x::STensorBra) = STensorKet([dagger(i) for i in x.terms]) dagger(x::STensorKet) = STensorBra([dagger(i) for i in x.terms]) dagger(x::STensorOperator) = STensorOperator([dagger(i) for i in x.terms]) dagger(x::SScaledOperator) = SScaledOperator(conj(x.coeff), dagger(x.obj)) dagger(x::SApplyKet) = dagger(x.ket)*dagger(x.op) dagger(x::SApplyBra) = dagger(x.op)*dagger(x.bra) -dagger(x::SApplyOp) = SApplyOp([dagger(i) for i in reverse(x.terms)]) +dagger(x::SMulOperator) = SMulOperator([dagger(i) for i in reverse(x.terms)]) dagger(x::SBraKet) = SBraKet(dagger(x.ket), dagger(x.bra)) dagger(x::SOuterKetBra) = SOuterKetBra(dagger(x.bra), dagger(x.ket)) dagger(x::SDagger) = x.obj @@ -297,6 +292,33 @@ function Base.show(io::IO, x::SDagger{AbstractOperator}) end symbollabel(x::SDagger) = symbollabel(x.obj) +"""Inverse Operator + +```jldoctest +julia> A = SOperator(:A, SpinBasis(1//2)); + +julia> inv(A) +A⁻¹ + +julia> inv(A)*A +𝕀 +``` +""" +@withmetadata struct SInvOperator <: Symbolic{AbstractOperator} + op::Symbolic{AbstractOperator} +end +isexpr(::SInvOperator) = true +iscall(::SInvOperator) = true +arguments(x::SInvOperator) = [x.op] +operation(x::SInvOperator) = inv +head(x::SInvOperator) = :inv +children(x::SInvOperator) = [:inv, x.op] +basis(x::SInvOperator) = basis(x.op) +Base.show(io::IO, x::SInvOperator) = print(io, "$(x.op)⁻¹") +Base.:(*)(invop::SInvOperator, op::SOperator) = isequal(invop.op, op) ? IdentityOp(basis(op)) : SMulOperator(invop, op) +Base.:(*)(op::SOperator, invop::SInvOperator) = isequal(op, invop.op) ? IdentityOp(basis(op)) : SMulOperator(op, invop) +inv(x::Symbolic{AbstractOperator}) = SInvOperator(x) + """Completely depolarized state ```jldoctest @@ -348,7 +370,6 @@ basis(x::IdentityOp) = x.basis symbollabel(x::IdentityOp) = "𝕀" ishermitian(::IdentityOp) = true isunitary(::IdentityOp) = true -iscommutative(::IdentityOp) = true """Identity operator in qubit basis""" const I = IdentityOp(qubit_basis) \ No newline at end of file diff --git a/src/QSymbolicsBase/rules.jl b/src/QSymbolicsBase/rules.jl index 639910e..01f0aa2 100644 --- a/src/QSymbolicsBase/rules.jl +++ b/src/QSymbolicsBase/rules.jl @@ -6,10 +6,7 @@ function hasscalings(xs) operation(x) == * end end -_isH(x) = x isa HGate -_isX(x) = x isa XGate -_isY(x) = x isa YGate -_isZ(x) = x isa ZGate +_isa(T) = x->isa(x,T) """Flattening terms""" function prefactorscalings(xs) @@ -52,78 +49,47 @@ FLATTEN_RULES = [ tensor_simplify = Fixpoint(Chain(FLATTEN_RULES)) -"""Quantum circuit identities""" -_isXX(x) = x isa SApplyOp && x.terms == [X,X] # work on this with identity op -_isYY(x) = x isa SApplyOp && x.terms == [Y,Y] -_isZZ(x) = x isa SApplyOp && x.terms == [Z,Z] -_isXY(x) = x isa SApplyOp && x.terms == [X,Y] -_isYZ(x) = x isa SApplyOp && x.terms == [Y,Z] -_isZX(x) = x isa SApplyOp && x.terms == [Z,X] -_isYX(x) = x isa SApplyOp && x.terms == [Y,X] -_isZY(x) = x isa SApplyOp && x.terms == [Z,Y] -_isXZ(x) = x isa SApplyOp && x.terms == [X,Z] -_isHXH(x) = x isa SApplyOp && x.terms == [H,X,H] -_isHYH(x) = x isa SApplyOp && x.terms == [H,Y,H] -_isHZH(x) = x isa SApplyOp && x.terms == [H,Z,H] - - -CIRCUIT_RULES = [ - @rule(~x::_isXX => I), - @rule(~x::_isYY => I), - @rule(~x::_isZZ => I), - @rule(~x::_isXY => im*Z), - @rule(~x::_isYZ => im*X), - @rule(~x::_isZX => im*Y), - @rule(~x::_isYX => -im*Z), - @rule(~x::_isZY => -im*X), - @rule(~x::_isXZ => -im*Y), - @rule(~x::_isHXH => Z), - @rule(~x::_isHYH => -Y), - @rule(~x::_isHZH => X) +"""Pauli identities""" +PAULI_RULES = [ + @rule(~o1::_isa(XGate)*~o2::_isa(XGate) => I), + @rule(~o1::_isa(YGate)*~o2::_isa(YGate) => I), + @rule(~o1::_isa(ZGate)*~o2::_isa(ZGate) => I), + @rule(~o1::_isa(XGate)*~o2::_isa(YGate) => im*Z), + @rule(~o1::_isa(YGate)*~o2::_isa(ZGate) => im*X), + @rule(~o1::_isa(ZGate)*~o2::_isa(XGate) => im*Y), + @rule(~o1::_isa(YGate)*~o2::_isa(XGate) => -im*Z), + @rule(~o1::_isa(ZGate)*~o2::_isa(YGate) => -im*X), + @rule(~o1::_isa(XGate)*~o2::_isa(ZGate) => -im*Y), + @rule(~o1::_isa(HGate)*~o2::_isa(XGate)*~o3::_isa(HGate) => Z), + @rule(~o1::_isa(HGate)*~o2::_isa(YGate)*~o3::_isa(HGate) => -Y), + @rule(~o1::_isa(HGate)*~o2::_isa(ZGate)*~o3::_isa(HGate) => X) ] -circuit_simplify = Fixpoint(Chain(CIRCUIT_RULES)) +pauli_simplify = Fixpoint(Chain(PAULI_RULES)) """Commutator identities""" -_isXYcommutator(x) = x isa SCommutator && _isX(x.op1) && _isY(x.op2) -_isYZcommutator(x) = x isa SCommutator && _isY(x.op1) && _isZ(x.op2) -_isZXcommutator(x) = x isa SCommutator && _isZ(x.op1) && _isX(x.op2) -_isYXcommutator(x) = x isa SCommutator && _isY(x.op1) && _isX(x.op2) -_isZYcommutator(x) = x isa SCommutator && _isZ(x.op1) && _isY(x.op2) -_isXZcommutator(x) = x isa SCommutator && _isX(x.op1) && _isZ(x.op2) - COMMUTATOR_RULES = [ - @rule(~x::_isXYcommutator => 2*im*Z), - @rule(~x::_isYZcommutator => 2*im*X), - @rule(~x::_isZXcommutator => 2*im*Y), - @rule(~x::_isYXcommutator => -2*im*Z), - @rule(~x::_isZYcommutator => -2*im*X), - @rule(~x::_isXZcommutator => -2*im*Y) + @rule(commutator(~o1::_isa(XGate), ~o2::_isa(YGate)) => 2*im*Z), + @rule(commutator(~o1::_isa(YGate), ~o2::_isa(ZGate)) => 2*im*X), + @rule(commutator(~o1::_isa(ZGate), ~o2::_isa(XGate)) => 2*im*Y), + @rule(commutator(~o1::_isa(YGate), ~o2::_isa(XGate)) => -2*im*Z), + @rule(commutator(~o1::_isa(ZGate), ~o2::_isa(YGate)) => -2*im*X), + @rule(commutator(~o1::_isa(XGate), ~o2::_isa(ZGate)) => -2*im*Y) ] commutator_simplify = Fixpoint(Chain(COMMUTATOR_RULES)) """Anticommutator identities""" -_isXXanticommutator(x) = x isa SAnticommutator && _isX(x.op1) && _isX(x.op2) -_isYYanticommutator(x) = x isa SAnticommutator && _isY(x.op1) && _isY(x.op2) -_isZZanticommutator(x) = x isa SAnticommutator && _isZ(x.op1) && _isZ(x.op2) -_isXYanticommutator(x) = x isa SAnticommutator && _isX(x.op1) && _isY(x.op2) -_isYZanticommutator(x) = x isa SAnticommutator && _isY(x.op1) && _isZ(x.op2) -_isZXanticommutator(x) = x isa SAnticommutator && _isZ(x.op1) && _isX(x.op2) -_isYXanticommutator(x) = x isa SAnticommutator && _isY(x.op1) && _isX(x.op2) -_isZYanticommutator(x) = x isa SAnticommutator && _isZ(x.op1) && _isY(x.op2) -_isXZanticommutator(x) = x isa SAnticommutator && _isX(x.op1) && _isZ(x.op2) - ANTICOMMUTATOR_RULES = [ - @rule(~x::_isXXanticommutator => 2*I), - @rule(~x::_isYYanticommutator => 2*I), - @rule(~x::_isZZanticommutator => 2*I), - @rule(~x::_isXYanticommutator => 0), - @rule(~x::_isYZanticommutator => 0), - @rule(~x::_isZXanticommutator => 0), - @rule(~x::_isYXanticommutator => 0), - @rule(~x::_isZYanticommutator => 0), - @rule(~x::_isXZanticommutator => 0) + @rule(anticommutator(~o1::_isa(XGate), ~o2::_isa(XGate)) => 2*I), + @rule(anticommutator(~o1::_isa(YGate), ~o2::_isa(YGate)) => 2*I), + @rule(anticommutator(~o1::_isa(ZGate), ~o2::_isa(ZGate)) => 2*I), + @rule(anticommutator(~o1::_isa(XGate), ~o2::_isa(YGate))=> 0), + @rule(anticommutator(~o1::_isa(YGate), ~o2::_isa(ZGate)) => 0), + @rule(anticommutator(~o1::_isa(ZGate), ~o2::_isa(XGate)) => 0), + @rule(anticommutator(~o1::_isa(YGate), ~o2::_isa(XGate)) => 0), + @rule(anticommutator(~o1::_isa(ZGate), ~o2::_isa(YGate)) => 0), + @rule(anticommutator(~o1::_isa(XGate), ~o2::_isa(ZGate)) => 0) ] anticommutator_simplify = Fixpoint(Chain(ANTICOMMUTATOR_RULES)) \ No newline at end of file diff --git a/test/test_anticommutator.jl b/test/test_anticommutator.jl index 7202641..2118627 100644 --- a/test/test_anticommutator.jl +++ b/test/test_anticommutator.jl @@ -6,7 +6,6 @@ B = SOperator(:B, SpinBasis(1//2)) @testset "symbolic anticommutator tests" begin @test isequal(anticommutator(2*A, B), anticommutator(A, 2*B)) && isequal(2*anticommutator(A, B), anticommutator(2*A, B)) && isequal(2*anticommutator(A, B), anticommutator(2*A, B)) - @test isequal(anticommutator(commutative(A), B), 2*commutative(A)*B) && isequal(anticommutator(commutative(A), commutative(B)), 2*commutative(A)*commutative(B)) && isequal(anticommutator(A, commutative(B)), 2*A*commutative(B)) end @testset "anticommutator Pauli tests" begin diff --git a/test/test_commutator.jl b/test/test_commutator.jl index 55129cf..c2b7ae5 100644 --- a/test/test_commutator.jl +++ b/test/test_commutator.jl @@ -7,10 +7,6 @@ B = SOperator(:B, SpinBasis(1//2)) @testset "symbolic commutator tests" begin @test isequal(commutator(2*A, B), commutator(A, 2*B)) && isequal(2*commutator(A, B), commutator(2*A, B)) && isequal(commutator(A, 2*B), 2*commutator(A, B)) @test commutator(A, A) == 0 - - @test isequal(commutator(commutative(A), A), 0) - @test isequal(commutator(A, commutative(A)), 0) - @test isequal(commutator(commutative(A), commutative(A)), 0) end @testset "commutator Pauli tests" begin diff --git a/test/test_dagger.jl b/test/test_dagger.jl index 69484b0..8fbadde 100644 --- a/test/test_dagger.jl +++ b/test/test_dagger.jl @@ -11,6 +11,9 @@ A = SOperator(:A, SpinBasis(1//2)) B = SOperator(:B, SpinBasis(1//2)) C = SOperator(:C, SpinBasis(1//2)) +U = SUnitaryOperator(:U, SpinBasis(1//2)) +ℋ = SHermitianOperator(:ℋ, SpinBasis(1//2)) + @testset "symbolic dagger tests" begin @test isequal(dagger(k₁), SBra(:k₁, SpinBasis(1//2))) @test isequal(dagger(im*k₁), -im*SBra(:k₁, SpinBasis(1//2))) @@ -19,8 +22,8 @@ C = SOperator(:C, SpinBasis(1//2)) @test isequal(dagger(im*b₁), -im*SKet(:b₁, SpinBasis(1//2))) @test isequal(dagger(b₁+b₂), dagger(b₁)+dagger(b₂)) @test isequal(dagger(A+B), dagger(A) + dagger(B)) - @test isequal(dagger(hermitian(A)), hermitian(A)) - @test isequal(dagger(unitary(A)), inverse(unitary(A))) + @test isequal(dagger(ℋ), ℋ) + @test isequal(dagger(U), inv(U)) @test isequal(dagger(b₁⊗b₂), dagger(b₁)⊗dagger(b₂)) @test isequal(dagger(k₁⊗k₂), dagger(k₁)⊗dagger(k₂)) @test isequal(dagger(A⊗B), dagger(A)⊗dagger(B))