diff --git a/examples/repeater/swap_and_distil.py b/examples/repeater/swap_and_distil.py new file mode 100644 index 0000000..4412617 --- /dev/null +++ b/examples/repeater/swap_and_distil.py @@ -0,0 +1,119 @@ +from dataclasses import dataclass + +from qunetsim.components import Host +from qunetsim.objects import Logger, Qubit +from qunetsim.components import Network + +Logger.DISABLED = True + + +@dataclass() +class Ebit: + val: tuple[int, int] + + def __str__(self): + return { + (0, 0): "phi+", + (0, 1): "psi+", + (1, 0): "phi-", + (1, 1): "psi-", + }[self.val] + + @staticmethod + def from_bell_measurement(a: Qubit, b: Qubit): + a.cnot(b) + a.H() + return Ebit((a.measure(), b.measure())) + + +def send_epr(host, right_host_id): + a, b = Qubit(host), Qubit(host) + a.H() + a.cnot(b) + host.send_qubit(right_host_id, b) + return a + + +DATA_QUBITS = 10 + + +def boundary_protocol(host, left_host_id, right_host_id): + conn = None + qubit = [] + + # Send an EPR qubit right; receive an EPR qubit from the left. + for _ in range(DATA_QUBITS): + if left_host_id is not None: + conn = left_host_id + qubit.append(host.get_qubit(conn, wait=-1)) + elif right_host_id is not None: + conn = right_host_id + qubit.append(send_epr(host, conn)) + else: + raise ValueError('boundary node has no connection') + + for i in range(DATA_QUBITS): + # Apply local ops to transform |ab> into |Φ+> (modulo phase). + msg = host.get_next_classical(conn, wait=-1).content + + if left_host_id is None: + if msg == 'psi-': + qubit[i].Y() + elif right_host_id is None: + if msg == 'psi+': + qubit[i].X() + elif msg == 'phi-': + qubit[i].Z() + + # confirm that the boundaries are correlated + print(f"{host.host_id} measures {qubit[i].measure()}") + + +def repeater_protocol(host, left_host_id, right_host_id): + for _ in range(DATA_QUBITS): + # Swap. Send EPR right; receive from the left. + q_right = send_epr(host, right_host_id) + q_left = host.get_qubit(left_host_id, wait=-1) + + # measure and broadcast + ebit = Ebit.from_bell_measurement(q_left, q_right) + host.send_broadcast(str(ebit)) + + +def main(): + network = Network.get_instance() + nodes = ["Alice", "Polly", "Bob"] + + network.start(nodes) + network.delay = 0.1 + + alice = Host("Alice") + alice.add_connection("Polly") + alice.start() + + polly = Host("Polly") + polly.add_connection("Alice") + polly.add_connection("Bob") + polly.start() + + bob = Host("Bob") + bob.add_connection("Polly") + bob.start() + + network.add_host(alice) + network.add_host(polly) + network.add_host(bob) + network.start() + + t1 = alice.run_protocol(boundary_protocol, (None, polly.host_id)) + t2 = bob.run_protocol(boundary_protocol, (polly.host_id, None)) + _ = polly.run_protocol(repeater_protocol, (alice.host_id, bob.host_id)) + + t1.join() + t2.join() + + network.stop(True) + + +if __name__ == "__main__": + main()