Skip to content

Commit

Permalink
1) Add more support of Permutation;
Browse files Browse the repository at this point in the history
2) Add more support of `LaTeX`.
  • Loading branch information
waltergu committed Sep 15, 2023
1 parent 21439ef commit 0afaeba
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 90 deletions.
30 changes: 29 additions & 1 deletion src/DegreesOfFreedom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ using ..Spatials: Bond, Point
using ..Toolkit: atol, efficientoperations, rtol, CompositeDict, CompositeTuple, Float, NamedContainer, VectorSpace, VectorSpaceCartesian, VectorSpaceDirectProducted, VectorSpaceDirectSummed, VectorSpaceStyle, commontype, concatenate, decimaltostr, fulltype, parametertype, rawtype, reparameter

import LaTeXStrings: latexstring
import ..QuantumLattices: , , expand, expand!, kind, id, ishermitian, rank, reset!, update!, value
import ..QuantumLattices: , , expand, expand!, id, ishermitian, kind, permute, rank, reset!, update!, value
import ..QuantumOperators: idtype, optype, script
import ..Spatials: icoordinate, rcoordinate
import ..Toolkit: contentnames, getcontent, isparameterbound, parameternames, shape
Expand Down Expand Up @@ -299,6 +299,20 @@ Get the adjoint of an index.
"""
@inline Base.adjoint(index::Index) = rawtype(typeof(index))(index.site, adjoint(index.iid))

"""
permute(index₁::Index, index₂::Index) -> Tuple{Vararg{Operator}}
Get the permutation of two indexes.
"""
function permute(index₁::Index, index₂::Index)
if index₁.site index₂.site
return (Operator(statistics(index₁)==:f && statistics(Index₂)==:f ? -1 : 1, index₂, index₁),)
else
site = index₁.site
return map(operator->Operator(value(operator), map(iid->Index(site, iid), id(operator))), permute(index₁.iid, index₂.iid))
end
end

"""
AbstractCompositeIndex{I<:Index} <: OperatorUnit
Expand Down Expand Up @@ -363,6 +377,20 @@ Get the adjoint of an operator id.
"""
@inline Base.adjoint(index::CompositeIndex) = CompositeIndex(index.index', index.rcoordinate, index.icoordinate)

"""
permute(index₁::CompositeIndex, index₂::CompositeIndex) -> Tuple{Vararg{Operator}}
Get the permutation of two composite indexes.
"""
function permute(index₁::CompositeIndex, index₂::CompositeIndex)
if index₁.rcoordinate index₂.rcoordinate || index₁.icoordinate index₂.icoordinate
return (Operator(statistics(index₁)==:f && statistics(index₂)==:f ? -1 : 1, index₂, index₁),)
else
rcoordinate, icoordinate = index₁.rcoordinate, index₁.icoordinate
return map(operator->Operator(value(operator), map(index->CompositeIndex(index, rcoordinate, icoordinate), id(operator))), permute(index₁.index, index₂.index))
end
end

"""
indextype(I::Type{<:SimpleInternal}, P::Type{<:Point}, ::Val)
Expand Down
17 changes: 9 additions & 8 deletions src/QuantumOperators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -683,18 +683,19 @@ Judge whether a set of operators as a whole is Hermitian.
LaTeX string representation of quantum operators.
"""
struct LaTeX{SP, SB, B, O}
struct LaTeX{SP, SB, B<:Function, O}
body::B
spdelimiter::String
sbdelimiter::String
options::O
function LaTeX{SP, SB}(body, spdelimiter::String=", ", sbdelimiter::String=", "; options...) where {SP, SB}
function LaTeX{SP, SB}(body::Function, spdelimiter::String=", ", sbdelimiter::String=", "; options...) where {SP, SB}
@assert isa(SP, Tuple{Vararg{Symbol}}) && isa(SB, Tuple{Vararg{Symbol}}) "LaTeX error: SP and SB must be tuple of symbols."
new{SP, SB, typeof(body), typeof(options)}(body, spdelimiter, sbdelimiter, options)
end
end
@inline superscript(::Type{<:LaTeX{SP}}) where SP = SP
@inline subscript(::Type{<:LaTeX{SP, SB} where SP}) where SB = SB
@inline LaTeX{SP, SB}(body, spdelimiter::String=", ", sbdelimiter::String=", "; options...) where {SP, SB} = LaTeX{SP, SB}(::OperatorUnit->body, spdelimiter, sbdelimiter; options...)

"""
latexname(T::Type{<:OperatorUnit}) -> Symbol
Expand All @@ -720,7 +721,7 @@ Get/Set the LaTeX format for a subtype of `OperatorUnit`.
Get the body/superscript/subscript of the LaTeX string representation of an operator unit.
"""
@inline script(::Val{:BD}, u::OperatorUnit, l::LaTeX) = l.body
@inline script(::Val{:BD}, u::OperatorUnit, l::LaTeX) = l.body(u)
@inline @generated script(::Val{:SP}, u::OperatorUnit, l::LaTeX) = Expr(:tuple, [:(script(Val($sup), u; l.options...)) for sup in QuoteNode.(l|>superscript)]...)
@inline @generated script(::Val{:SB}, u::OperatorUnit, l::LaTeX) = Expr(:tuple, [:(script(Val($sub), u; l.options...)) for sub in QuoteNode.(l|>subscript)]...)

Expand Down Expand Up @@ -927,7 +928,7 @@ end
@inline Base.valtype(P::Type{<:Permutation}, M::Type{<:OperatorSum}) = valtype(P, eltype(M))

"""
(permutation::Permutation)(m::OperatorProd; kwargs...) -> OperatorSum
(permutation::Permutation)(m::OperatorProd; rev::Bool=false, kwargs...) -> OperatorSum
Permute the operator units of an `OperatorProd` to the descending order according to the table contained in `permutation`.
Expand All @@ -938,12 +939,12 @@ Permute the operator units of an `OperatorProd` to the descending order accordin
```
Here, `u₁` and `u₂` are two arbitrary operator units contained in `id(m)`.
"""
@inline function (permutation::Permutation)(m::OperatorProd; kwargs...)
@inline function (permutation::Permutation)(m::OperatorProd; rev::Bool=false, kwargs...)
result = zero(permutation, m)
cache = eltype(result)[m]
while length(cache) > 0
current = pop!(cache)
pos = operatorprodcommuteposition(sequence(current, permutation.table))
pos = operatorprodcommuteposition(sequence(current, permutation.table); rev=rev)
if isnothing(pos)
add!(result, current)
else
Expand All @@ -957,10 +958,10 @@ Permute the operator units of an `OperatorProd` to the descending order accordin
end
return result
end
function operatorprodcommuteposition(sequences)
function operatorprodcommuteposition(sequences; rev::Bool)
pos = 1
while pos < length(sequences)
(sequences[pos] < sequences[pos+1]) && return pos
((rev && sequences[pos]>sequences[pos+1]) || (!rev && sequences[pos]<sequences[pos+1])) && return pos
pos += 1
end
return nothing
Expand Down
139 changes: 59 additions & 80 deletions src/QuantumSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -211,53 +211,44 @@ function isnormalordered(opt::Operator{<:Number, <:ID{AbstractCompositeIndex{<:I
end

"""
*(
f1::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}},
f2::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}
) -> Union{Nothing, Operator}
*(f₁::Operator{<:Number, <:ID{FID{:f}}}, f₂::Operator{<:Number, <:ID{FID{:f}}}) -> Union{typeof(0), Operator}
*(f₁::Operator{<:Number, <:ID{Index{Int, <:FID{:f}}}}, f₂::Operator{<:Number, <:ID{Index{Int, <:FID{:f}}}}) -> Union{typeof(0), Operator}
*(f₁::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}, f₂::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}) -> Union{typeof(0), Operator}
Get the multiplication of two fermionic Fock operators.
"""
@inline function Base.:*(
f1::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}},
f2::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}
)
rank(f1)>0 && rank(f2)>0 && f1.id[end]==f2.id[1] && return nothing
return invoke(*, Tuple{OperatorProd, OperatorProd}, f1, f2)
const block = quote
rank(f₁)>0 && rank(f₂)>0 && f₁.id[end]==f₂.id[1] && return 0
return invoke(*, Tuple{OperatorProd, OperatorProd}, f₁, f₂)
end
@eval @inline Base.:*(f₁::Operator{<:Number, <:ID{FID{:f}}}, f₂::Operator{<:Number, <:ID{FID{:f}}}) = $block
@eval @inline Base.:*(f₁::Operator{<:Number, <:ID{Index{Int, <:FID{:f}}}}, f₂::Operator{<:Number, <:ID{Index{Int, <:FID{:f}}}}) = $block
@eval @inline Base.:*(f₁::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}, f₂::Operator{<:Number, <:ID{AbstractCompositeIndex{<:Index{Int, <:FID{:f}}}}}) = $block
@inline Base.:*(m₁::Operator{<:Number, Tuple{}}, m₂::Operator{<:Number, Tuple{}}) = Operator(m₁.value*m₂.value)

## Permutation
"""
permute(id₁::CompositeIndex{<:Index{Int, <:FID{:f}}}, id₂::CompositeIndex{<:Index{Int, <:FID{:f}}}) -> Tuple{Vararg{Operator}}
permute(id₁::FID, id₂::FID) -> Tuple{Vararg{Operator}}
Permute two fermionic indexes and get the result.
Permute two Fock indexes and get the result.
"""
function permute(id₁::CompositeIndex{<:Index{Int, <:FID{:f}}}, id₂::CompositeIndex{<:Index{Int, <:FID{:f}}})
@assert id₁.indexid₂.index || id₁.rcoordinateid₂.rcoordinate || id₁.icoordinateid₂.icoordinate "permute error: permuted ids should not be equal to each other."
if id₁.index'==id₂.index && id₁.rcoordinate==id₂.rcoordinate && id₁.icoordinate==id₂.icoordinate
function permute(id₁::FID{:f}, id₂::FID{:f})
@assert id₁ id₂ "permute error: two identical fermionic indexes should vanish due to the fermionic statistics."
if id₁' == id₂
return (Operator(1), Operator(-1, id₂, id₁))
else
return (Operator(-1, id₂, id₁),)
end
end

"""
permute(id₁::CompositeIndex{<:Index{Int, <:FID{:b}}}, id₂::CompositeIndex{<:Index{Int, <:FID{:b}}}) -> Tuple{Vararg{Operator}}
Permute two bosonic indexes and get the result.
"""
function permute(id₁::CompositeIndex{<:Index{Int, <:FID{:b}}}, id₂::CompositeIndex{<:Index{Int, <:FID{:b}}})
@assert id₁.indexid₂.index || id₁.rcoordinateid₂.rcoordinate || id₁.icoordinateid₂.icoordinate "permute error: permuted ids should not be equal to each other."
if id₁.index'==id₂.index && id₁.rcoordinate==id₂.rcoordinate && id₁.icoordinate==id₂.icoordinate
if id₁.index.iid.nambu == creation
return (Operator(1), Operator(1, id₂, id₁))
else
return (Operator(-1), Operator(1, id₂, id₁))
end
function permute(id₁::FID{:b}, id₂::FID{:b})
if id₁'==id₂
return (Operator(id₁.nambu==creation ? 1 : -1), Operator(1, id₂, id₁))
else
return (Operator(1, id₂, id₁),)
end
end
@inline permute(id₁::FID{:b}, id₂::FID{:f}) = (Operator(1, id₂, id₁),)
@inline permute(id₁::FID{:f}, id₂::FID{:b}) = (Operator(1, id₂, id₁),)

## Coupling
### requested by IIDSpace
Expand Down Expand Up @@ -598,44 +589,44 @@ latexformat(SID, LaTeX{(:tag,), ()}('S'))

## Permutation
"""
permute(id₁::CompositeIndex{<:Index{Int, SID{S, Char}}}, id₂::CompositeIndex{<:Index{Int, SID{S, Char}}}) where S -> Tuple{Vararg{Operator}}
permute(id₁::SID, id₂::SID) -> Tuple{Vararg{Operator}}
Permute two spin indexes and get the result.
"""
function permute(id₁::CompositeIndex{<:Index{Int, SID{S, Char}}}, id₂::CompositeIndex{<:Index{Int, SID{S, Char}}}) where S
@assert id₁.indexid₂.index || id₁.rcoordinateid₂.rcoordinate || id₁.icoordinateid₂.icoordinate "permute error: permuted ids should not be equal to each other."
if id₁.index.site==id₂.index.site && id₁.rcoordinate==id₂.rcoordinate && id₁.icoordinate==id₂.icoordinate
if id₁.index.iid.tag == 'x'
id₂.index.iid.tag=='y' && return (Operator(+1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='z' && return (Operator(-1im, permutespinindex(id₁, 'y')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='+' && return (Operator(-1, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='-' && return (Operator(+1, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
elseif id₁.index.iid.tag == 'y'
id₂.index.iid.tag=='x' && return (Operator(-1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='z' && return (Operator(+1im, permutespinindex(id₁, 'x')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='+' && return (Operator(-1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='-' && return (Operator(-1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
elseif id₁.index.iid.tag == 'z'
id₂.index.iid.tag=='x' && return (Operator(+1im, permutespinindex(id₁, 'y')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='y' && return (Operator(-1im, permutespinindex(id₁, 'x')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='+' && return (Operator(+1, id₂), Operator(1, id₂, id₁))
id₂.index.iid.tag=='-' && return (Operator(-1, id₂), Operator(1, id₂, id₁))
elseif id₁.index.iid.tag == '+'
id₂.index.iid.tag=='x' && return (Operator(+1, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='y' && return (Operator(+1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='z' && return (Operator(-1, id₁), Operator(1, id₂, id₁))
id₂.index.iid.tag=='-' && return (Operator(+2, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
elseif id₁.index.iid.tag == '-'
id₂.index.iid.tag=='x' && return (Operator(-1, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='y' && return (Operator(1im, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
id₂.index.iid.tag=='z' && return (Operator(+1, id₁), Operator(1, id₂, id₁))
id₂.index.iid.tag=='+' && return (Operator(-2, permutespinindex(id₁, 'z')), Operator(1, id₂, id₁))
function permute(id₁::SID, id₂::SID)
if id₁ id₂
S = totalspin(id₁)
if id₁.tag == 'x'
id₂.tag=='y' && return (Operator(+1im, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='z' && return (Operator(-1im, SID{S}('y')), Operator(1, id₂, id₁))
id₂.tag=='+' && return (Operator(-1, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='-' && return (Operator(+1, SID{S}('z')), Operator(1, id₂, id₁))
elseif id₁.tag == 'y'
id₂.tag=='x' && return (Operator(-1im, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='z' && return (Operator(+1im, SID{S}('x')), Operator(1, id₂, id₁))
id₂.tag=='+' && return (Operator(-1im, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='-' && return (Operator(-1im, SID{S}('z')), Operator(1, id₂, id₁))
elseif id₁.tag == 'z'
id₂.tag=='x' && return (Operator(+1im, SID{S}('y')), Operator(1, id₂, id₁))
id₂.tag=='y' && return (Operator(-1im, SID{S}('x')), Operator(1, id₂, id₁))
id₂.tag=='+' && return (Operator(+1, SID{S}('+')), Operator(1, id₂, id₁))
id₂.tag=='-' && return (Operator(-1, SID{S}('-')), Operator(1, id₂, id₁))
elseif id₁.tag == '+'
id₂.tag=='x' && return (Operator(+1, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='y' && return (Operator(+1im, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='z' && return (Operator(-1, SID{S}('+')), Operator(1, id₂, id₁))
id₂.tag=='-' && return (Operator(+2, SID{S}('z')), Operator(1, id₂, id₁))
elseif id₁.tag == '-'
id₂.tag=='x' && return (Operator(-1, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='y' && return (Operator(1im, SID{S}('z')), Operator(1, id₂, id₁))
id₂.tag=='z' && return (Operator(+1, SID{S}('-')), Operator(1, id₂, id₁))
id₂.tag=='+' && return (Operator(-2, SID{S}('z')), Operator(1, id₂, id₁))
end
error("permute error: not supported spin indexes.")
else
return (Operator(1, id₂, id₁),)
end
end
@inline permutespinindex(id::CompositeIndex{<:Index{Int, <:SID}}, tag::Char) = replace(id, index=replace(id.index, iid=replace(id.index.iid, tag=tag)))

## Coupling
### requested by IIDSpace
Expand Down Expand Up @@ -772,43 +763,31 @@ Get the requested script of an pid.
"""
@inline script(::Val{:direction}, pid::PID; kwargs...) = pid.direction==(:) ? ":" : string(pid.direction)

"""
script(::Val{:BD}, pid::PID, l::LaTeX) -> String
script(::Val{:BD}, index::Index{<:Union{Int, Colon}, <:PID}, l::LaTeX) -> String
script(::Val{:BD}, index::AbstractCompositeIndex{<:Index{<:Union{Int, Colon}, <:PID}}, l::LaTeX) -> String
Get the requested script of a phonon index.
"""
@inline script(::Val{:BD}, pid::PID, l::LaTeX) = l.body[pid.tag]
@inline script(::Val{:BD}, index::Index{<:Union{Int, Colon}, <:PID}, l::LaTeX) = l.body[index.iid.tag]
@inline script(::Val{:BD}, index::AbstractCompositeIndex{<:Index{<:Union{Int, Colon}, <:PID}}, l::LaTeX) = l.body[getcontent(index, :index).iid.tag]

@inline body(pid::PID) = string(pid.tag)
@inline body(index::Index{<:Union{Int, Colon}, <:PID}) = string(index.iid.tag)
@inline body(index::AbstractCompositeIndex{<:Index{<:Union{Int, Colon}, <:PID}}) = string(getcontent(index, :index).iid.tag)
"""
latexofphonons
The default LaTeX format of a phonon index.
"""
const latexofphonons = LaTeX{(:direction,), (:site,)}(Dict('p'=>"p", 'u'=>"u"), "", "")
const latexofphonons = LaTeX{(:direction,), (:site,)}(body, "", "")
@inline latexname(::Type{<:Index{<:Union{Int, Colon}, <:PID}}) = Symbol("Index{Union{Int, Colon}, PID}")
@inline latexname(::Type{<:AbstractCompositeIndex{<:Index{<:Union{Int, Colon}, <:PID}}}) = Symbol("AbstractCompositeIndex{Index{Union{Int, Colon}, PID}}")
latexformat(Index{<:Union{Int, Colon}, <:PID}, latexofphonons)
latexformat(AbstractCompositeIndex{<:Index{<:Union{Int, Colon}, <:PID}}, latexofphonons)
@inline latexname(::Type{<:PID}) = Symbol("PID")
latexformat(PID, LaTeX{(:direction,), ()}(Dict('p'=>"p", 'u'=>"u"), "", ""))
latexformat(PID, LaTeX{(:direction,), ()}(body, "", ""))

## Permutation
"""
permute(id₁::CompositeIndex{<:Index{Int, PID{Char}}}, id₂::CompositeIndex{<:Index{Int, PID{Char}}}) -> Tuple{Vararg{Operator}}
permute(id₁::PID, id₂::PID) -> Tuple{Vararg{Operator}}
Permute two phonon indexes and get the result.
"""
function permute(id₁::CompositeIndex{<:Index{Int, PID{Char}}}, id₂::CompositeIndex{<:Index{Int, PID{Char}}})
if id₁.index.iid.direction==id₂.index.iid.direction && id₁.index.iid.tagid₂.index.iid.tag && id₁.rcoordinate==id₂.rcoordinate && id₁.icoordinate==id₂.icoordinate
if id₁.index.iid.tag=='u'
return (Operator(1im), Operator(1, id₂, id₁))
else
return (Operator(-1im), Operator(1, id₂, id₁))
end
function permute(id₁::PID, id₂::PID)
if id₁.direction==id₂.direction && id₁.tagid₂.tag
return (Operator(id₁.tag=='u' ? 1im : -1im), Operator(1, id₂, id₁))
else
return (Operator(1, id₂, id₁),)
end
Expand Down
2 changes: 1 addition & 1 deletion test/QuantumSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ end

op₁ = Operator(1.5, id₁, id₂)
op₂ = Operator(2.0, id₂, id₁)
@test op₁*op₂ == nothing
@test op₁*op₂ == 0

op₁ = Operator(1.5, id₁, id₂)
op₂ = Operator(2.0, id₁, id₂)
Expand Down

0 comments on commit 0afaeba

Please sign in to comment.