Skip to content

Commit b314479

Browse files
Change SingleSiteOperator with MultiSiteOperator (#324)
* Change SingleSiteOperator with MultiSiteOperator * Update changelog
1 parent aee73e6 commit b314479

File tree

6 files changed

+82
-32
lines changed

6 files changed

+82
-32
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
- Change `SingleSiteOperator` with the more general `MultiSiteOperator`. ([#324])
11+
1012
## [v0.22.0] (2024-11-20)
1113

1214
- Change the parameters structure of `sesolve`, `mesolve` and `mcsolve` functions to possibly support automatic differentiation. ([#311])
@@ -33,3 +35,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3335
[#311]: https://github.com/qutip/QuantumToolbox.jl/issues/311
3436
[#315]: https://github.com/qutip/QuantumToolbox.jl/issues/315
3537
[#318]: https://github.com/qutip/QuantumToolbox.jl/issues/318
38+
[#324]: https://github.com/qutip/QuantumToolbox.jl/issues/324

docs/src/resources/api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ fidelity
248248

249249
```@docs
250250
Lattice
251-
SingleSiteOperator
251+
MultiSiteOperator
252252
DissipativeIsing
253253
```
254254

docs/src/tutorials/cluster.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ We will consider two examples:
1111

1212
### Monte Carlo Quantum Trajectories
1313

14-
Let's consider a 2-dimensional transferse field Ising model with 4x3 spins. The Hamiltonian is given by
14+
Let's consider a 2-dimensional transverse field Ising model with 4x3 spins. The Hamiltonian is given by
1515

1616
```math
1717
\hat{H} = \frac{J_z}{2} \sum_{\langle i,j \rangle} \hat{\sigma}_i^z \hat{\sigma}_j^z + h_x \sum_i \hat{\sigma}_i^x \, ,
@@ -91,9 +91,9 @@ hy = 0.0
9191
hz = 0.0
9292
γ = 1
9393

94-
Sx = mapreduce(i->SingleSiteOperator(sigmax(), i, latt), +, 1:latt.N)
95-
Sy = mapreduce(i->SingleSiteOperator(sigmay(), i, latt), +, 1:latt.N)
96-
Sz = mapreduce(i->SingleSiteOperator(sigmaz(), i, latt), +, 1:latt.N)
94+
Sx = mapreduce(i -> MultiSiteOperator(latt, i=>sigmax()), +, 1:latt.N)
95+
Sy = mapreduce(i -> MultiSiteOperator(latt, i=>sigmay()), +, 1:latt.N)
96+
Sz = mapreduce(i -> MultiSiteOperator(latt, i=>sigmaz()), +, 1:latt.N)
9797

9898
H, c_ops = DissipativeIsing(Jx, Jy, Jz, hx, hy, hz, γ, latt; boundary_condition = Val(:periodic_bc), order = 1)
9999
e_ops = [Sx, Sy, Sz]

docs/src/tutorials/lowrank.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ Define lr states. Take as initial state all spins up. All other N states are tak
4747
i = 1
4848
for j in 1:N_modes
4949
global i += 1
50-
i <= M && (ϕ[i] = SingleSiteOperator(sigmap(), j, latt) * ϕ[1])
50+
i <= M && (ϕ[i] = MultiSiteOperator(latt, j=>sigmap()) * ϕ[1])
5151
end
5252
for k in 1:N_modes-1
5353
for l in k+1:N_modes
5454
global i += 1
55-
i <= M && (ϕ[i] = SingleSiteOperator(sigmap(), k, latt) * SingleSiteOperator(sigmap(), l, latt) * ϕ[1])
55+
i <= M && (ϕ[i] = MultiSiteOperator(latt, k=>sigmap(), l=>sigmap()) * ϕ[1])
5656
end
5757
end
5858
for i in i+1:M
@@ -85,9 +85,9 @@ hy = 0.0
8585
hz = 0.0
8686
γ = 1
8787
88-
Sx = mapreduce(i->SingleSiteOperator(sigmax(), i, latt), +, 1:latt.N)
89-
Sy = mapreduce(i->SingleSiteOperator(sigmay(), i, latt), +, 1:latt.N)
90-
Sz = mapreduce(i->SingleSiteOperator(sigmaz(), i, latt), +, 1:latt.N)
88+
Sx = mapreduce(i->MultiSiteOperator(latt, i=>sigmax()), +, 1:latt.N)
89+
Sy = mapreduce(i->MultiSiteOperator(latt, i=>sigmay()), +, 1:latt.N)
90+
Sz = mapreduce(i->MultiSiteOperator(latt, i=>sigmaz()), +, 1:latt.N)
9191
9292
H, c_ops = DissipativeIsing(Jx, Jy, Jz, hx, hy, hz, γ, latt; boundary_condition = Val(:periodic_bc), order = 1)
9393
e_ops = (Sx, Sy, Sz)

src/spin_lattice.jl

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export Lattice, SingleSiteOperator, DissipativeIsing
1+
export Lattice, MultiSiteOperator, DissipativeIsing
22

33
@doc raw"""
44
Lattice
@@ -15,20 +15,60 @@ end
1515

1616
#Definition of many-body operators
1717
@doc raw"""
18-
SingleSiteOperator(O::QuantumObject, i::Integer, N::Integer)
18+
MultiSiteOperator(dims::Union{AbstractVector, Tuple}, pairs::Pair{<:Integer,<:QuantumObject}...)
1919
20-
A Julia constructor for a single-site operator. `s` is the operator acting on the site. `i` is the site index, and `N` is the total number of sites. The function returns a `QuantumObject` given by ``\\mathbb{1}^{\\otimes (i - 1)} \\otimes \hat{O} \\otimes \\mathbb{1}^{\\otimes (N - i)}``.
20+
A Julia function for generating a multi-site operator ``\\hat{O} = \\hat{O}_i \\hat{O}_j \\cdots \\hat{O}_k``. The function takes a vector of dimensions `dims` and a list of pairs `pairs` where the first element of the pair is the site index and the second element is the operator acting on that site.
21+
22+
# Arguments
23+
- `dims::Union{AbstractVector, Tuple}`: A vector of dimensions of the lattice.
24+
- `pairs::Pair{<:Integer,<:QuantumObject}...`: A list of pairs where the first element of the pair is the site index and the second element is the operator acting on that site.
25+
26+
# Returns
27+
`QuantumObject`: A `QuantumObject` representing the multi-site operator.
28+
29+
# Example
30+
```jldoctest
31+
julia> op = MultiSiteOperator(Val(8), 5=>sigmax(), 7=>sigmaz());
32+
33+
julia> op.dims
34+
8-element SVector{8, Int64} with indices SOneTo(8):
35+
2
36+
2
37+
2
38+
2
39+
2
40+
2
41+
2
42+
2
43+
```
2144
"""
22-
function SingleSiteOperator(O::QuantumObject{DT,OperatorQuantumObject}, i::Integer, N::Integer) where {DT}
23-
T = O.dims[1]
24-
return QuantumObject(kron(eye(T^(i - 1)), O, eye(T^(N - i))); dims = ntuple(j -> 2, Val(N)))
45+
function MultiSiteOperator(dims::Union{AbstractVector,Tuple}, pairs::Pair{<:Integer,<:QuantumObject}...)
46+
sites_unsorted = collect(first.(pairs))
47+
idxs = sortperm(sites_unsorted)
48+
_sites = sites_unsorted[idxs]
49+
_ops = collect(last.(pairs))[idxs]
50+
_dims = collect(dims) # Use this instead of a Tuple, to avoid type instability when indexing on a slice
51+
52+
sites, ops = _get_unique_sites_ops(_sites, _ops)
53+
54+
collect(dims)[sites] == [op.dims[1] for op in ops] || throw(ArgumentError("The dimensions of the operators do not match the dimensions of the lattice."))
55+
56+
data = kron(I(prod(_dims[1:sites[1]-1])), ops[1].data)
57+
for i in 2:length(sites)
58+
data = kron(data, I(prod(_dims[sites[i-1]+1:sites[i]-1])), ops[i].data)
59+
end
60+
data = kron(data, I(prod(_dims[sites[end]+1:end])))
61+
62+
return QuantumObject(data; type = Operator, dims = dims)
63+
end
64+
function MultiSiteOperator(N::Union{Integer,Val}, pairs::Pair{<:Integer,<:QuantumObject}...)
65+
dims = ntuple(j -> 2, makeVal(N))
66+
67+
return MultiSiteOperator(dims, pairs...)
68+
end
69+
function MultiSiteOperator(latt::Lattice, pairs::Pair{<:Integer,<:QuantumObject}...)
70+
return MultiSiteOperator(makeVal(latt.N), pairs...)
2571
end
26-
SingleSiteOperator(O::QuantumObject{DT,OperatorQuantumObject}, i::Integer, latt::Lattice) where {DT} =
27-
SingleSiteOperator(O, i, latt.N)
28-
SingleSiteOperator(O::QuantumObject{DT,OperatorQuantumObject}, row::Integer, col::Integer, latt::Lattice) where {DT} =
29-
SingleSiteOperator(O, latt.idx[row, col], latt.N)
30-
SingleSiteOperator(O::QuantumObject{DT,OperatorQuantumObject}, x::CartesianIndex, latt::Lattice) where {DT} =
31-
SingleSiteOperator(O, latt.idx[x], latt.N)
3272

3373
#Definition of nearest-neighbour sites on lattice
3474
periodic_boundary_conditions(i::Integer, N::Integer) = 1 + (i - 1 + N) % N
@@ -87,27 +127,34 @@ function DissipativeIsing(
87127
boundary_condition::Union{Symbol,Val} = Val(:periodic_bc),
88128
order::Integer = 1,
89129
)
90-
S = [SingleSiteOperator(sigmam(), i, latt) for i in 1:latt.N]
130+
S = [MultiSiteOperator(latt, i => sigmam()) for i in 1:latt.N]
91131
c_ops = sqrt(γ) .* S
92132

93133
op_sum(S, i::CartesianIndex) =
94134
S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nearest_neighbor(i, latt, makeVal(boundary_condition); order = order)]])
95135

96136
H = 0
97137
if (Jx != 0 || hx != 0)
98-
S = [SingleSiteOperator(sigmax(), i, latt) for i in 1:latt.N]
138+
S = [MultiSiteOperator(latt, i => sigmax()) for i in 1:latt.N]
99139
H += Jx / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx) #/2 because we are double counting
100140
H += hx * sum(S)
101141
end
102142
if (Jy != 0 || hy != 0)
103-
S = [SingleSiteOperator(sigmay(), i, latt) for i in 1:latt.N]
143+
S = [MultiSiteOperator(latt, i => sigmay()) for i in 1:latt.N]
104144
H += Jy / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx)
105145
H += hy * sum(S)
106146
end
107147
if (Jz != 0 || hz != 0)
108-
S = [SingleSiteOperator(sigmaz(), i, latt) for i in 1:latt.N]
148+
S = [MultiSiteOperator(latt, i => sigmaz()) for i in 1:latt.N]
109149
H += Jz / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx)
110150
H += hz * sum(S)
111151
end
112152
return H, c_ops
113153
end
154+
155+
function _get_unique_sites_ops(sites, ops)
156+
unique_sites = unique(sites)
157+
unique_ops = map(i -> prod(ops[findall(==(i), sites)]), unique_sites)
158+
159+
return unique_sites, unique_ops
160+
end

test/core-test/low_rank_dynamics.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
i = 1
1616
for j in 1:N_modes
1717
i += 1
18-
i <= M && (ϕ[i] = SingleSiteOperator(sigmap(), j, latt) * ϕ[1])
18+
i <= M && (ϕ[i] = MultiSiteOperator(latt, j => sigmap()) * ϕ[1])
1919
end
2020
for k in 1:N_modes-1
2121
for l in k+1:N_modes
2222
i += 1
23-
i <= M && (ϕ[i] = SingleSiteOperator(sigmap(), k, latt) * SingleSiteOperator(sigmap(), l, latt) * ϕ[1])
23+
i <= M && (ϕ[i] = MultiSiteOperator(latt, k => sigmap(), l => sigmap()) * ϕ[1])
2424
end
2525
end
2626
for i in i+1:M
@@ -43,11 +43,11 @@
4343
hz = 0.0
4444
γ = 1
4545

46-
Sx = mapreduce(i -> SingleSiteOperator(sigmax(), i, latt), +, 1:latt.N)
47-
Sy = mapreduce(i -> SingleSiteOperator(sigmay(), i, latt), +, 1:latt.N)
48-
Sz = mapreduce(i -> SingleSiteOperator(sigmaz(), i, latt), +, 1:latt.N)
46+
Sx = mapreduce(i -> MultiSiteOperator(latt, i => sigmax()), +, 1:latt.N)
47+
Sy = mapreduce(i -> MultiSiteOperator(latt, i => sigmay()), +, 1:latt.N)
48+
Sz = mapreduce(i -> MultiSiteOperator(latt, i => sigmaz()), +, 1:latt.N)
4949
SFxx = mapreduce(
50-
x -> SingleSiteOperator(sigmax(), x[1], latt) * SingleSiteOperator(sigmax(), x[2], latt),
50+
x -> MultiSiteOperator(latt, x[1] => sigmax(), x[2] => sigmax()),
5151
+,
5252
Iterators.product(1:latt.N, 1:latt.N),
5353
)

0 commit comments

Comments
 (0)