Skip to content

Commit

Permalink
Continue with sums
Browse files Browse the repository at this point in the history
  • Loading branch information
david-pl committed Dec 18, 2024
1 parent 0211b6c commit 944cc40
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 96 deletions.
1 change: 1 addition & 0 deletions src/QuantumCumulants.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export HilbertSpace, ProductSpace, ⊗, tensor,
scale,
transition_superscript,
Index, reorder, IndexedOperator, IndexedVariable, DoubleIndexedVariable,
Sum, Σ, change_index, has_index,
# DoubleSum, indexed_complete, IndexedCorrelationFunction, scale_term,
# scaleME, evalME, indexed_complete!, indexed_meanfield, subst_reds, AvgSums, plotME,
# IndexedAverageSum, IndexedAverageDoubleSum, SpecialIndexedTerm, find_missing_sums, Σ, ∑,
Expand Down
105 changes: 42 additions & 63 deletions src/indexing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -309,77 +309,56 @@ Examples
"""
function change_index(term::QMul, from::Index, to::Index)
arg_c = change_index(term.arg_c,from,to)
args_nc = [change_index(arg,from,to) for arg in copy(term.args_nc)]
return arg_c*prod(args_nc)
change_index(x,from::Index,to::Index) = x

function change_index(a::IndexedOperator, from::Index, to::Index)
if !isequal(a.ind, from)
return a
end

return IndexedOperator(a.op, to)
end
change_index(term::Average, from::Index,to::Index) = average(change_index(arguments(term)[1],from,to))
change_index(op::IndexedOperator,from::Index,to::Index) = isequal(op.ind,from) ? IndexedOperator(op.op,to) : op

function change_index(op::BasicSymbolic{IndexedVariable},from::Index,to::Index)
if SymbolicUtils.hasmetadata(op,IndexedVariable)
meta = SymbolicUtils.metadata(op)[IndexedVariable]
return isequal(meta.ind,from) ? IndexedVariable(meta.name,to) : op
function change_index(v::IndexedVariable, from::Index, to::Index)
if !isequal(v.ind, from)
return v
end
return IndexedVariable(v.name, to)
end
function change_index(op::BasicSymbolic{DoubleIndexedVariable},from::Index,to::Index)
if SymbolicUtils.hasmetadata(op,DoubleIndexedVariable)
meta = SymbolicUtils.metadata(op)[DoubleIndexedVariable]
if meta.ind1 == from
if meta.ind1 == meta.ind2 && meta.identical
return DoubleIndexedVariable(meta.name,to,to;identical=meta.identical)
elseif meta.ind1 == meta.ind2
return 0
else
return DoubleIndexedVariable(meta.name,to,meta.ind2;identical=meta.identical)
end
elseif meta.ind2 == from
return DoubleIndexedVariable(meta.name,meta.ind1,to;identical=meta.identical)
end

function change_index(v::DoubleIndexedVariable, from::Index, to::Index)
if isequal(v.ind1, from) && isequal(v.ind2, from)
return DoubleIndexedVariable(v.name, to, to; identical=v.identical)
elseif isequal(v.ind1, from)
return DoubleIndexedVariable(v.name, to, v.ind2; identical=v.identical)
elseif isequal(v.ind2, from)
return DoubleIndexedVariable(v.name, v.ind1, to; identical=v.identical)
end
return v
end
function change_index(term::BasicSymbolic{<:CNumber},from::Index,to::Index)
if iscall(term)
op = operation(term)
if op === +
args = arguments(term)
if length(args) == 1
return change_index(args[1],from,to)
end
return op([change_index(arg,from,to) for arg in args]...)
end
if op === *
args = arguments(term)
if length(args) == 1
return change_index(args[1],from,to)
end
return op([change_index(arg,from,to) for arg in args]...)
end
if op === ^
args = arguments(term)
return change_index(args[1],from,to)^change_index(args[2],from,to)
end
# issue 198
if op === /
args = arguments(term)
return change_index(args[1],from,to)/change_index(args[2],from,to)
end
if length(arguments(term)) == 1 # exp, sin, cos, ln, ...
return op(change_index(arguments(term)[1],from,to))
end

function change_index(t::SymbolicUtils.Symbolic, from::Index, to::Index)
isequal(from, to) && return t

if !TermInterface.iscall(t)
metadata = TermInterface.metadata(t)
metadata_ = change_index(metadata.value, from, to)
t_ = deepcopy(t)
t_ = SymbolicUtils.setmetadata(t_, typeof(metadata_), metadata_)
return t_
end
return term

f = SymbolicUtils.operation(t)
args = SymbolicUtils.arguments(t)
return f(change_index(args, from, to))
end
# # issue 196: TODO:test
# function change_index(S::SingleSum, i::Index, j::Index)
# (j ∈ S.non_equal_indices) && error("Index $(j) is in the non-equal index list.")
# if S.sum_index == i
# return SingleSum(change_index(S.term,i,j), j, replace(S.non_equal_indices, i=>j), S.metadata)
# end
# return S
# end
change_index(x,from::Index,to::Index) = x

function change_index(args::Vector, from::Index, to::Index)
isequal(from, to) && return args

return [change_index(arg, from, to) for arg in args]
end


getIndName(op::IndexedOperator) = op.ind.name
getIndName(ind::Index) = ind.name
Expand Down
56 changes: 40 additions & 16 deletions src/indexing_sums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ end

const Σ = Sum

# Basic methods
Base.isequal(s1::Sum, s2::Sum) = isequal(s1.index, s2.index) && isequal(s1.term, s2.term)
Base.adjoint(s::Sum) = Sum(adjoint(s.term), s.index, s.metadata)

# Symbolics interface
SymbolicUtils.operation(::Sum) = Sum
SymbolicUtils.arguments(s::Sum) = [s.term, s.index]
SymbolicUtils.maketerm(::Type{<:Sum}, ::typeof(Sum), args, metadata) = Sum(args; metadata)
SymbolicUtils.maketerm(::Type{<:Sum}, ::typeof(Sum), args, metadata) = Sum(args...; metadata)

# has_index
"""
Expand All @@ -22,22 +26,24 @@ Check if an expression has a specific index.
"""
has_index(x, i::Index) = false
has_index(v::IndexedVariable, i::Index) = isequal(v.ind, i)
has_index(v::DoubleIndexedVariable, i::Index) = isequal(v.ind1, i) || isequal(v.ind2, i)
has_index(op::IndexedOperator, i::Index) = isequal(op.ind, i)

# TODO: specialization for QAdd, QMul, etc.
function has_index(t::QTerm, i::Index)
for arg in SymbolicUtils.arguments(t)
if has_index(arg, i)
return true
end
has_index(s::Sum, i::Index) = isequal(s.index, i) || has_index(s.term, i)

function has_index(t::SymbolicUtils.Symbolic, i::Index)
if !TermInterface.iscall(t)
metadata = TermInterface.metadata(t)
return has_index(metadata.value, i)
end
return false
end

has_index(s::Sum, i::Index) = isequal(s.index, i) || has_index(s.term, i)
return has_index(SymbolicUtils.arguments(t), i)
end
# TODO: specialization for QAdd, QMul, etc.
has_index(t::QTerm, i::Index) = has_index(SymbolicUtils.arguments(t), i)

function has_index(t::SymbolicUtils.Term, i::Index)
for arg in SymbolicUtils.arguments(t)
function has_index(args::Vector, i::Index)
for arg in args
if has_index(arg, i)
return true
end
Expand All @@ -50,20 +56,19 @@ end
# Construction of sums with QSyms -- order should be QSym < QMul < Sum < QAdd
Sum(a::QSym, index::Index) = index.range * a

function Sum(a::T, index::I) where {T<:IndexedOperator, I<:Index}
function Sum(a::IndexedOperator, index::Index)
if !has_index(a, index)
return index.range * a
end
return Sum(a, index, nothing)
end


function Sum(t::T, index::I) where {T<:QMul, I<:Index}
if !has_index(t, index)
return index.range * t
end

if !has_index(t, t.args_nc)
if !has_index(t.args_nc, index)
return Sum(*(t.args_c...), index) * *(t.args_nc...)
end

Expand All @@ -75,6 +80,15 @@ function Sum(t::QAdd, index::Index)
return +(args...)
end

# CNumbers
function Sum(t::SymbolicUtils.Symbolic, index::Index)
if !has_index(t, index)
return index.range * t
end
return Sum(t, index, nothing)
end
Sum(t::Number, index::Index) = index.range * t

# Basic algebra
function +(s1::Sum, s2::Sum)
return QAdd([s1, s2])
Expand Down Expand Up @@ -142,4 +156,14 @@ end
*(s::Sum, v::SNuN) = v * s

# averaging
average(s::Sum) = Sum(average(s.term), s.index)
average(s::Sum) = Sum(average(s.term), s.index)
average(s::Sum, order) = Sum(average(s.term, order), s.index)


function Base.show(io::IO, s::Sum)
write(io, "Σ(")
show(io, s.term)
write(io, ", ")
show(io, s.index)
write(io, ")")
end
51 changes: 34 additions & 17 deletions test/test_index_basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const qc=QuantumCumulants
@test(isequal(0,σ12i*σ(1,2,i_ind)))
@test(isequal(σ(2,2,i_ind),σ(2,1,i_ind)*σ12i))

@test isequal(simplify(σ(2,2,i_ind)+σ(1,2,j_ind)),simplify(σ(1,2,j_ind)+σ(2,2,i_ind)))
# @test isequal(simplify(σ(2,2,i_ind)+σ(1,2,j_ind)),simplify(σ(1,2,j_ind)+σ(2,2,i_ind)))
@test(isequal(adjoint(σ(1,2,i_ind)),σ(2,1,i_ind)))

@test isequal(σ(2,1,i_ind)*σ(1,2,i_ind), σ(2,2, i_ind))
Expand All @@ -64,15 +64,32 @@ const qc=QuantumCumulants
end


@testset "sums" begin
sum1 = SingleSum(σ(1,2,i_ind)*a',i_ind)
sum2 = SingleSum(σ(2,1,i_ind)*a,i_ind)
# @testset "sums" begin

N = 10
ha = NLevelSpace(Symbol(:atom),2)
hf = FockSpace(:cavity)
h = hfha

indT(i) = Index(h,i,N,ha) #transition index
indF(i) = Index(h,i,N,hf) #fock index
i_ind = indT(:i)
j_ind = indT(:j)

ind(a) = indT(a)

a = Destroy(h,:a)
σ(i,j,k) = IndexedOperator(Transition(h,,i,j),k)
σ12i = σ(1,2,indT(:i))

sum1 = Sum(σ(1,2,i_ind)*a',i_ind)
sum2 = Sum(σ(2,1,i_ind)*a,i_ind)
@test(isequal(adjoint(sum1),sum2))

sum3 = SingleSum(a'*σ(1,2,i_ind) + a*σ(2,1,i_ind),i_ind)
sum3 = Sum(a'*σ(1,2,i_ind) + a*σ(2,1,i_ind),i_ind)
@test(isequal(sum3,(sum1+sum2)))
@test(isequal(acts_on(σ12i),2))
@test(i_ind < j_ind)
# @test(i_ind < j_ind)

@test isequal(0,Σ(0,i_ind))
@test isequal(0,Σ(σ(2,1,i_ind)*σ(2,1,i_ind),i_ind))
Expand All @@ -93,27 +110,27 @@ k_ind = indT(:k)
reorder(σ(1,2,k_ind)*σ(1,2,j_ind)*σ(1,2,i_ind),[(i_ind,j_ind)]),
SpecialIndexedTerm(σ(1,2,k_ind)*σ(1,2,i_ind)*σ(1,2,j_ind),[(i_ind,j_ind)])
))
@test(isequal(σ(1,2,k_ind) * sum1, simplify(SingleSum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind))
@test(isequal(σ(1,2,k_ind) * sum1, simplify(Sum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind))
))
σ(1,2,k_ind) * sum1
qqq = simplify(SingleSum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind))
# qqq = SingleSum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind)
qqq = simplify(Sum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind))
# qqq = Sum(σ(1,2,k_ind)*σ(1,2,i_ind)*a',i_ind)
QuantumCumulants.get_indices(qqq)
SymbolicUtils._iszero(a'*σ(1,2,i_ind)*σ(1,2,k_ind))

@test(isequal(simplify(σ(2,1,k_ind) * sum1), simplify(SingleSum(σ(2,1,k_ind)*σ(1,2,i_ind)*a',i_ind,[k_ind]) + a'*σ(2,2,k_ind))
@test(isequal(simplify(σ(2,1,k_ind) * sum1), simplify(Sum(σ(2,1,k_ind)*σ(1,2,i_ind)*a',i_ind,[k_ind]) + a'*σ(2,2,k_ind))
))
innerSum = SingleSum(σ(2,1,i_ind)*σ(1,2,j_ind),i_ind)
innerSum = Sum(σ(2,1,i_ind)*σ(1,2,j_ind),i_ind)
@test(isequal(
DoubleSum(innerSum,j_ind), DoubleSum(SingleSum(σ(2,1,i_ind)*σ(1,2,j_ind),i_ind,[j_ind]),j_ind) + SingleSum(σ(2,2,j_ind),j_ind)
DoubleSum(innerSum,j_ind), DoubleSum(Sum(σ(2,1,i_ind)*σ(1,2,j_ind),i_ind,[j_ind]),j_ind) + Sum(σ(2,2,j_ind),j_ind)
))
@test(isequal(SymbolicUtils.arguments(σ(1,2,indT(:i))*a'),SymbolicUtils.arguments(sum1)))

@test isequal(N*g(ind(:j)),Σ(g(ind(:j)),ind(:i)))
@test Σ(g(ind(:j)),ind(:j)) isa qc.SingleSum
@test Σ(g(ind(:j)),ind(:j)) isa qc.Sum

@test isequal(N*Γij,Σ(Γij,ind(:k)))
@test Σ(Γij,ind(:i)) isa qc.SingleSum
@test Σ(Γij,ind(:i)) isa qc.Sum

@test (sum1 + a') isa qc.QAdd
@test (sum1 + σ(1,2,i_ind)) isa qc.QAdd
Expand Down Expand Up @@ -313,9 +330,9 @@ arr = qc.create_index_arrays([i],[1:10])

# issue 188
gi = IndexedVariable(:g, i)
@test isa((5gi,i), SingleSum)
@test isa((gi*α,i), SingleSum)
@test isa((5gi,i), Sum)
@test isa((gi*α,i), Sum)
@test isequal((α,i), N*α)
@test isequal((5α,i), 5*N*α)

end
# end

0 comments on commit 944cc40

Please sign in to comment.