Quantum memory: the device to store qubits
Quantum memory has two modes: the synchronous and asynchronous mode. In synchronous model, it can not describe the time delay in writing and reading qubits. Users may use write
and read
functions to operate the memory directly. However, in asynchronous mode, quantum memory works as an independent entity. Quantum nodes uses events to control the memories and get the results.
Synchronous mode
Quantum memory is an entity that can store qubits. It can be equipped to a quantum nodes:
from qns.entity.node.node import QNode
from qns.entity.memory.memory import QuantumMemory
n1 = QNode("n1") # a quantum node named "n1"
m = QuantumMemory("m1")
n1.add_memory(m)
read
and write
methods are used to store and get a qubit. The read
methods will use the qubit’s name or reference as the keyword to search the qubit.
q1 = Qubit()
m.write(q1)
q2 = m.read()
The memory can have a limited size. is_full
function returns whether the memory is full:
from qns.entity.node.node import QNode
from qns.entity.memory.memory import QuantumMemory
n1 = QNode("n1") # a quantum node named "n1"
m2 = QuantumMemory("m2", capacity = 10) # a memory can store 10 qubits
n1.add_memory(m2)
m2.is_full() # check if the memory is full
Asynchronous mode
In this mode, quantum nodes (or applications) needs to use MemoryWriteRequestEvent
and MemoryReadRequestEvent
events to send requests to the quantum memories and collect the results by listening to MemoryWriteResponseEvent
and MemoryReadResponseEvent
events. In this way, users can model the time delay in reading and writing quantum memories. In asynchronous mode, the quantum memories have an additional input parameter called delay
to set the read/write time delay. delay
can be a float or a DelayModel
.
Here, we give an example of asynchronous mode. The quantum node first install a MemoryResponseApp
application to handle the read/write result. During the simulation, the node generates MemoryWriteRequestEvent
to save a qubit and use MemoryReadRequestEvent
to get the qubit one second later.
class MemoryResponseApp(Application):
def __init__(self):
super().__init__()
self.add_handler(self.MemoryReadhandler, [MemoryReadResponseEvent], [])
self.add_handler(self.MemoryWritehandler, [MemoryWriteResponseEvent], [])
def MemoryReadhandler(self, node, event: Event) -> Optional[bool]:
result = event.result # the saving qubit
print("self._simulator.tc.sec: {}".format(self._simulator.tc))
print("result: {}".format(result))
assert (self._simulator.tc.sec == 1.5)
assert (result is not None)
def MemoryWritehandler(self, node, event: Event) -> Optional[bool]:
result = event.result # if the qubit is saved successfully
print("self._simulator.tc.sec: {}".format(self._simulator.tc))
print("result: {}".format(result))
assert (self._simulator.tc.sec == 0.5)
assert (result)
n1 = QNode("n1")
app = MemoryReadResponseApp()
n1.add_apps(app)
m = QuantumMemory("m1", delay=0.5)
n1.add_memory(m)
s = Simulator(0, 10, 1000)
n1.install(s)
q1 = Qubit(name="q1")
write_request = MemoryWriteRequestEvent(memory=m, qubit=q1, t=s.time(sec=0), by=n1)
read_request = MemoryReadRequestEvent(memory=m, key="q1", t=s.time(sec=1), by=n1)
s.add_event(write_request)
s.add_event(read_request)
s.run()
Error models in a quantum memory
Also, storage error can be introduced during storage a qubit. The error is handled in function storage_error_model
, which takes the storage time and other parameters as the input. Those parameters shows the memory attributions (such as the coherence time), and they can be set using decoherence_rate
and store_error_model_args
. decoherence_rate
is the decoherence rate, while store_error_model_args
is a directory that contains other parameters for the error model
from qns.entity.memory.memory import QuantumMemory
from qns.models.epr import WernerStateEntanglement
class ErrorEntanglement(WernerStateEntanglement):
def storage_error_model(self, t: float, **kwargs):
# storage error will reduce the fidelity
t_coh = kwargs.get("t_coh", 1)
self.w = self.w * np.exp(- t / t_coh)
# memory error attributions: coherence time is 1 second
m3 = QuantumMemory("m3", capacity = 10, decoherence_rate=0.2, store_error_model_args = {"t_coh": 1})
# generate an entanglement and store it
epr1 = ErrorEntanglement(name="epr1")
m3.write(epr1)
# after a while, the fidelity will drop
epr2 = m3.read("epr1")