Skip to content

Commit fd0dcd5

Browse files
author
alexander papageorge
committed
perform embedding of an operator in a joint hilbert space
1 parent c2182c3 commit fd0dcd5

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/operators.jl

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ export AbstractOperator, DataOperator, length, basis, dagger, ishermitian, tenso
66

77
import Base: ==, +, -, *, /, ^, length, one, exp, conj, conj!, transpose
88
import LinearAlgebra: tr, ishermitian
9+
import SparseArrays: sparse
910
import ..bases: basis, tensor, ptrace, permutesystems,
1011
samebases, check_samebases, multiplicable
12+
# import ..operators_sparse: SparseOperator
1113
import ..states: dagger, normalize, normalize!
1214

1315
using ..sortedindices, ..bases, ..states
@@ -131,11 +133,72 @@ function embed(basis_l::CompositeBasis, basis_r::CompositeBasis,
131133

132134
return tensor(out...)
133135
end
136+
137+
138+
"""
139+
embed(basis1[, basis2], indices::Vector, operators::Vector)
140+
141+
Embed operator acting on a joint Hilbert space where missing indices are filled up with identity operators.
142+
"""
143+
function embed(basis_l::CompositeBasis, basis_r::CompositeBasis,
144+
indices::Vector{Int}, op::T) where T<:AbstractOperator
145+
N = length(basis_l.bases)
146+
@assert length(basis_r.bases) == N
147+
148+
@assert reduce(tensor, basis_l.bases[indices]) == op.basis_l
149+
@assert reduce(tensor, basis_r.bases[indices]) == op.basis_r
150+
151+
index_order = [idx for idx in 1:length(basis_l.bases) if idx indices]
152+
all_operators = AbstractOperator[identityoperator(T, basis_l.bases[i], basis_r.bases[i]) for i in index_order]
153+
154+
for idx in indices[end:-1:1]
155+
pushfirst!(index_order, idx)
156+
end
157+
pushfirst!(all_operators, op)
158+
159+
sortedindices.check_indices(N, indices)
160+
161+
# Create the operator.
162+
permuted_op = tensor(all_operators...)
163+
164+
# Create a copy to fill with correctly-ordered objects (basis and data).
165+
unpermuted_op = copy(permuted_op)
166+
167+
# Create the correctly ordered basis.
168+
unpermuted_op.basis_l = permutesystems(permuted_op.basis_l, index_order)
169+
unpermuted_op.basis_r = permutesystems(permuted_op.basis_r, index_order)
170+
171+
# Reorient the matrix to act in the correctly ordered basis.
172+
# Get the dimensions necessary for index permuting.
173+
dims_l = [b.shape[1] for b in basis_l.bases]
174+
dims_r = [b.shape[1] for b in basis_r.bases]
175+
176+
# Get the order of indices to use in the first reshape. Julia indices go in
177+
# reverse order.
178+
expand_order = index_order[end:-1:1]
179+
# Get the dimensions associated with those indices.
180+
expand_dims_l = dims_l[expand_order]
181+
expand_dims_r = dims_r[expand_order]
182+
183+
# Prepare the permutation to the correctly ordered basis.
184+
perm_order_l = [indexin(idx, length(dims_l):-1:1)[1] for idx in expand_order]
185+
perm_order_r = [indexin(idx, length(dims_r):-1:1)[1] for idx in expand_order]
186+
187+
# Perform the index expansion, the permutation, and the index collapse.
188+
M = (reshape(permuted_op.data, tuple([expand_dims_l; expand_dims_r]...)) |>
189+
x -> permutedims(x, [perm_order_l; perm_order_r .+ length(dims_l)]) |>
190+
x -> sparse(reshape(x, (prod(dims_l), prod(dims_r)))))
191+
192+
unpermuted_op.data = M
193+
194+
return unpermuted_op
195+
end
134196
embed(basis_l::CompositeBasis, basis_r::CompositeBasis, index::Int, op::AbstractOperator) = embed(basis_l, basis_r, Int[index], [op])
135197
embed(basis_l::CompositeBasis, basis_r::CompositeBasis, index::Vector{Int}, op::AbstractOperator) = embed(basis_l, basis_r, index, [op])
136198
embed(basis::CompositeBasis, index::Int, op::AbstractOperator) = embed(basis, basis, Int[index], [op])
137199
embed(basis::CompositeBasis, indices::Vector{Int}, operators::Vector{T}) where {T<:AbstractOperator} = embed(basis, basis, indices, operators)
138200
embed(basis::CompositeBasis, index::Vector{Int}, op::AbstractOperator) = embed(basis, basis, index, [op])
201+
embed(basis::CompositeBasis, indices::Vector{Int}, op::AbstractOperator) = embed(basis, basis, indices, op)
139202

140203
"""
141204
embed(basis1[, basis2], operators::Dict)
@@ -202,7 +265,31 @@ normalize!(op::AbstractOperator) = throw(ArgumentError("normalize! is not define
202265

203266
"""
204267
expect(op, state)
268+
index_order = [idx for idx in 1:length(dims) if idx ∉ indices]
269+
270+
eyedim = prod(dims[index_order])
271+
272+
for idx in indices[end:-1:1]
273+
pushfirst!(index_order, idx)
274+
end
275+
276+
alldim = prod(dims[index_order])
277+
278+
index_order
279+
280+
expand_order = [dims[idx] for idx in index_order][end:-1:1]
281+
282+
perm_order = [indexin(idx, expand_order)[1] for idx in dims[end:-1:1]]
283+
284+
println(index_order)
285+
println(expand_order)
286+
println(perm_order)
287+
288+
my_matrix = kron(m, eye(eltype(m), eyedim))
205289
290+
M = (reshape(my_matrix, tuple([expand_order; expand_order]...)) |>
291+
x -> permutedims(x, [perm_order; perm_order .+ length(dims)]) |>
292+
x -> sparse(reshape(x, (prod(dims), prod(dims)))))
206293
Expectation value of the given operator `op` for the specified `state`.
207294
208295
`state` can either be a (density) operator or a ket.

test/test_operators.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ op_test3 = test_operators(b1 ⊗ b2, b2 ⊗ b1, randoperator(b, b).data)
6262

6363
@test embed(b, b, [1,2], op) == embed(b, [1,2], op)
6464
@test embed(b, Dict{Vector{Int}, SparseOperator}()) == identityoperator(b)
65+
@test_throws AssertionError embed(b1b2, [2], [op1])
6566

6667
b_comp = bb
6768
@test embed(b_comp, [1,3,4], [op1,op]) == dense(op1 one(b2) op)

0 commit comments

Comments
 (0)