-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
Added QuantumChannel (#53)
--------- Co-authored-by: Stefan Krastanov <stefan@krastanov.org>
Showing
10 changed files
with
219 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
""" | ||
Quantum channel for transmitting quantum states from one register to another. | ||
Delay and background noise processes are supported. | ||
The function `put!` is used to take the contents of a `RegRef` and put it in the channel. | ||
That state can can then be received by a register (after a delay) using the `take!` method. | ||
```jldoctest; filter = r"(\\d{4})\\d+" => s"at some memory address" | ||
julia> using QuantumSavory, ResumableFunctions, ConcurrentSim | ||
julia> regA = Register(1); regB = Register(1); | ||
julia> initialize!(regA[1], Z1); | ||
julia> sim = Simulation(); | ||
julia> qc = QuantumChannel(sim, 10.0) # a delay of 10 units | ||
QuantumChannel(Qubit(), DelayQueue{Register}(QueueStore{Register, Int64}, 10.0), nothing) | ||
julia> @resumable function alice_node(env, qc) | ||
println("Putting Alice's qubit in the channel at ", now(env)) | ||
put!(qc, regA[1]) | ||
end | ||
alice_node (generic function with 1 method) | ||
julia> @resumable function bob_node(env, qc) | ||
@yield take!(qc, regB[1]) | ||
println("Taking the qubit from alice at ", now(env)) | ||
end | ||
bob_node (generic function with 1 method) | ||
julia> @process alice_node(sim, qc); @process bob_node(sim, qc); | ||
julia> run(sim) | ||
Putting Alice's qubit in the channel at 0.0 | ||
Taking the qubit from alice at 10.0 | ||
julia> regA | ||
Register with 1 slots: [ Qubit ] | ||
Slots: | ||
nothing | ||
julia> regB | ||
Register with 1 slots: [ Qubit ] | ||
Slots: | ||
Subsystem 1 of QuantumOpticsBase.Ket 7474956998997307987 | ||
``` | ||
""" | ||
struct QuantumChannel{T} | ||
trait::T | ||
queue::ConcurrentSim.DelayQueue{Register} | ||
background::Any | ||
end | ||
|
||
QuantumChannel(queue::ConcurrentSim.DelayQueue{Register}, background=nothing, trait=Qubit()) = QuantumChannel(trait, queue, background) | ||
|
||
QuantumChannel(env::ConcurrentSim.Simulation, delay, background=nothing, trait=Qubit()) = QuantumChannel(ConcurrentSim.DelayQueue{Register}(env, delay), background, trait) | ||
Register(qc::QuantumChannel) = Register([qc.trait], [qc.background]) | ||
|
||
function Base.put!(qc::QuantumChannel, rref::RegRef) | ||
time = ConcurrentSim.now(qc.queue.store.env) | ||
channel_reg = Register(qc) | ||
swap!(rref, channel_reg[1]; time) | ||
uptotime!(channel_reg[1], time+qc.queue.delay) | ||
put!(qc.queue, channel_reg) | ||
end | ||
|
||
@resumable function post_take(env, take_event, rref) | ||
channel_reg = @yield take_event | ||
if isassigned(rref) | ||
error("A take! operation is being performed on a QuantumChannel in order to swap the state into a Register, but the target register slot is not empty (it is already initialized).") | ||
end | ||
swap!(channel_reg[1], rref; time=now(env)) | ||
end | ||
|
||
function Base.take!(qc::QuantumChannel, rref::RegRef) | ||
take_event = take!(qc.queue) | ||
@process post_take(qc.queue.store.env, take_event, rref) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
using QuantumSavory | ||
using ResumableFunctions | ||
using ConcurrentSim | ||
using Test | ||
|
||
bell = (Z1⊗Z1 + Z2⊗Z2)/sqrt(2.0) | ||
|
||
## Manually construct a QuantumChannel and test a simple put/take | ||
|
||
sim = Simulation() | ||
regA = Register(1) | ||
regB = Register(2) | ||
initialize!((regA[1], regB[2]), bell) | ||
# Delay queue for quantum channel | ||
queue = DelayQueue{Register}(sim, 10.0) | ||
qc = QuantumChannel(queue) | ||
|
||
@resumable function alice_node(env, qc) | ||
put!(qc, regA[1]) | ||
end | ||
|
||
@resumable function bob_node(env, qc) | ||
@yield take!(qc, regB[1]) | ||
end | ||
|
||
@process alice_node(sim, qc) | ||
@process bob_node(sim, qc) | ||
|
||
run(sim) | ||
|
||
# the above code puts both the qubits of the state in the same register | ||
sref = regB.staterefs[1] | ||
@test sref.registers[1] == sref.registers[2] | ||
@test !isassigned(regA, 1) | ||
|
||
## Test with the second constructor | ||
|
||
regA = Register(1) | ||
regB = Register(2) | ||
initialize!((regA[1], regB[2]), bell) | ||
sim = Simulation() | ||
qc = QuantumChannel(sim, 10.0) | ||
@resumable function alice_node(env, qc) | ||
put!(qc, regA[1]) | ||
end | ||
@resumable function bob_node(env, qc) | ||
@yield take!(qc, regB[1]) | ||
end | ||
@process alice_node(sim, qc) | ||
@process bob_node(sim, qc) | ||
run(sim) | ||
sref = regB.staterefs[1] | ||
@test sref.registers[1] == sref.registers[2] | ||
@test !isassigned(regA, 1) | ||
|
||
## Test with T1Decay | ||
|
||
regA = Register(1) | ||
regB = Register(2) | ||
initialize!((regA[1], regB[2]), bell) | ||
sim = Simulation() | ||
qc = QuantumChannel(sim, 10.0, T1Decay(0.1)) | ||
@resumable function alice_node(env, qc) | ||
put!(qc, regA[1]) | ||
end | ||
@resumable function bob_node(env, qc) | ||
@yield take!(qc, regB[1]) | ||
end | ||
@process alice_node(sim, qc) | ||
@process bob_node(sim, qc) | ||
run(sim) | ||
|
||
# compare against a stationary qubit experiencing the same T1 decay | ||
reg = Register([Qubit(), Qubit()], [T1Decay(0.1), nothing]) | ||
initialize!(reg[1:2], bell) | ||
uptotime!(reg[1], 10.0) | ||
|
||
@test observable(reg[1:2], projector(bell)) ≈ observable(regB[1:2], projector(bell)) | ||
|
||
## Test with T2Dephasing | ||
|
||
regA = Register(2) | ||
regB = Register(2) | ||
initialize!((regA[1], regB[2]), bell) | ||
sim = Simulation() | ||
qc = QuantumChannel(sim, 10.0, T2Dephasing(0.1)) | ||
@resumable function alice_node(env, qc) | ||
put!(qc, regA[1]) | ||
end | ||
@resumable function bob_node(env, qc) | ||
@yield take!(qc, regB[1]) | ||
end | ||
@process alice_node(sim, qc) | ||
@process bob_node(sim, qc) | ||
run(sim) | ||
|
||
reg = Register([Qubit(), Qubit()], [T2Dephasing(0.1), nothing]) | ||
initialize!(reg[1:2], bell) | ||
uptotime!(reg[1], 10.0) | ||
|
||
@test observable(reg[1:2], projector(bell)) == observable(regB[1:2], projector(bell)) | ||
|
||
## Test for slot availability | ||
|
||
sim = Simulation() | ||
qc = QuantumChannel(sim, 10.0, T2Dephasing(0.1)) | ||
regC = Register(1) | ||
initialize!(regC[1], Z1) | ||
put!(qc, regC[1]) | ||
take!(qc, regB[1]) | ||
@test_throws "A take! operation is being performed on a QuantumChannel in order to swap the state into a Register, but the target register slot is not empty (it is already initialized)." run(sim) |